From fb5ef3bb4e7db77d18b9ce8097536bb77af76a5a Mon Sep 17 00:00:00 2001 From: aschwinn <al.schwinn@gsi.de> Date: Wed, 27 Jul 2016 15:57:08 +0200 Subject: [PATCH] initial commit of all silecs-gsi projects --- silecs-codegen/.project | 11 + silecs-codegen/LICENSE | 674 ++++++ silecs-codegen/README.md | 19 + silecs-codegen/install.sh | 10 + .../src/xml/__init__.py | 0 .../src/xml/fesa/__init__.py | 0 silecs-codegen/src/xml/fesa/__init__.pyc | Bin 0 -> 106 bytes .../src/xml/fesa/fesa_3_0_0/__init__.py | 0 .../src/xml/fesa/fesa_3_0_0/__init__.pyc | Bin 0 -> 117 bytes .../fesa/fesa_3_0_0/fesaTemplates$py.class | Bin 0 -> 46258 bytes .../src/xml/fesa/fesa_3_0_0/fesaTemplates.py | 840 ++++++++ .../src/xml/fesa/fesa_3_0_0/fesaTemplates.pyc | Bin 0 -> 40712 bytes .../xml/fesa/fesa_3_0_0/fillFESADeployUnit.py | 75 + .../fesa/fesa_3_0_0/fillFESADeployUnit.pyc | Bin 0 -> 2932 bytes .../generateBuildEnvironment$py.class | Bin 0 -> 6226 bytes .../fesa_3_0_0/generateBuildEnvironment.py | 70 + .../fesa_3_0_0/generateBuildEnvironment.pyc | Bin 0 -> 2199 bytes .../fesa_3_0_0/generateFesaDesign$py.class | Bin 0 -> 39292 bytes .../xml/fesa/fesa_3_0_0/generateFesaDesign.py | 523 +++++ .../fesa/fesa_3_0_0/generateFesaDesign.pyc | Bin 0 -> 24100 bytes .../fesa_3_0_0/generateSourceCode$py.class | Bin 0 -> 22768 bytes .../xml/fesa/fesa_3_0_0/generateSourceCode.py | 356 ++++ .../fesa/fesa_3_0_0/generateSourceCode.pyc | Bin 0 -> 8950 bytes .../src/xml/fesa/fesa_3_1_0/__init__.py | 0 .../src/xml/fesa/fesa_3_1_0/__init__.pyc | Bin 0 -> 188 bytes .../xml/fesa/fesa_3_1_0/fillFESADeployUnit.py | 23 + .../fesa/fesa_3_1_0/fillFESADeployUnit.pyc | Bin 0 -> 807 bytes .../fesa_3_1_0/generateBuildEnvironment.py | 26 + .../fesa_3_1_0/generateBuildEnvironment.pyc | Bin 0 -> 1257 bytes .../xml/fesa/fesa_3_1_0/generateFesaDesign.py | 99 + .../fesa/fesa_3_1_0/generateFesaDesign.pyc | Bin 0 -> 2880 bytes .../xml/fesa/fesa_3_1_0/generateSourceCode.py | 26 + .../fesa/fesa_3_1_0/generateSourceCode.pyc | Bin 0 -> 1243 bytes .../src/xml/fesa/fillDesignFileBase.pyc | Bin 0 -> 1238 bytes .../src/xml/fesa/fillFesaDeployUnitBase.py | 35 + .../src/xml/fesa/fillFesaDeployUnitBase.pyc | Bin 0 -> 1254 bytes .../src/xml/fesa/fillFesaDesignBase.py | 38 + .../src/xml/fesa/fillFesaDesignBase.pyc | Bin 0 -> 1285 bytes silecs-codegen/src/xml/genduwrapper$py.class | Bin 0 -> 13208 bytes silecs-codegen/src/xml/genduwrapper.py | 144 ++ silecs-codegen/src/xml/genduwrapper.pyc | Bin 0 -> 5869 bytes .../src/xml/genduwrappertemplate$py.class | Bin 0 -> 39006 bytes .../src/xml/genduwrappertemplate.py | 740 +++++++ .../src/xml/genduwrappertemplate.pyc | Bin 0 -> 21891 bytes silecs-codegen/src/xml/genparam$py.class | Bin 0 -> 41492 bytes silecs-codegen/src/xml/genparam.py | 980 +++++++++ silecs-codegen/src/xml/genparam.pyc | Bin 0 -> 20502 bytes silecs-codegen/src/xml/genplcsrc$py.class | Bin 0 -> 38245 bytes silecs-codegen/src/xml/genplcsrc.py | 723 +++++++ silecs-codegen/src/xml/genplcsrc.pyc | Bin 0 -> 19874 bytes silecs-codegen/src/xml/iecommon$py.class | Bin 0 -> 22715 bytes silecs-codegen/src/xml/iecommon.py | 266 +++ silecs-codegen/src/xml/iecommon.pyc | Bin 0 -> 9484 bytes silecs-codegen/src/xml/iefiles$py.class | Bin 0 -> 17145 bytes silecs-codegen/src/xml/iefiles.py | 140 ++ silecs-codegen/src/xml/iefiles.pyc | Bin 0 -> 6435 bytes .../src/xml/migration/0_10_0to1_0_0.py | 92 + .../src/xml/migration/0_9_0to0_10_0.py | 44 + silecs-codegen/src/xml/migration/FileUtils.py | 39 + .../src/xml/migration/FileUtils.pyc | Bin 0 -> 1729 bytes silecs-codegen/src/xml/migration/__init__.py | 0 silecs-codegen/src/xml/migration/__init__.pyc | Bin 0 -> 182 bytes .../DeviceData_PneuDriveDU.instance | 192 ++ .../migration0_10_0to1_0_0/__init__.py | 0 .../migration0_10_0to1_0_0/__init__.pyc | Bin 0 -> 205 bytes .../migration0_10_0to1_0_0/migrators.py | 110 + .../migration0_10_0to1_0_0/migrators.pyc | Bin 0 -> 4352 bytes .../migration0_10_0to1_0_0/testMigration.py | 148 ++ .../migration0_10_0to1_0_0/testMigration.pyc | Bin 0 -> 6996 bytes .../src/xml/migration/migrationBase.py | 115 + .../src/xml/migration/migrationBase.pyc | Bin 0 -> 4434 bytes .../migration_0_9_0to0_10_0/__init__.py | 0 .../migration_0_9_0to0_10_0/__init__.pyc | Bin 0 -> 201 bytes .../migrateDeployDeviceNumber.py | 58 + .../migrateDeployDeviceNumber.pyc | Bin 0 -> 2351 bytes .../migrateDeployDomain.py | 34 + .../migrateDeployDomain.pyc | Bin 0 -> 1419 bytes .../migration_0_9_0to0_10_0/testMigration.py | 91 + .../migration_0_9_0to0_10_0/testMigration.pyc | Bin 0 -> 3670 bytes silecs-codegen/src/xml/migration/runTests.py | 49 + silecs-codegen/src/xml/migration/runTests.pyc | Bin 0 -> 999 bytes .../src/xml/rabbitTemplate$py.class | Bin 0 -> 18417 bytes silecs-codegen/src/xml/rabbitTemplate.py | 410 ++++ silecs-codegen/src/xml/rabbitTemplate.pyc | Bin 0 -> 11292 bytes silecs-codegen/src/xml/runTests.py | 47 + silecs-codegen/src/xml/s7template$py.class | Bin 0 -> 14472 bytes silecs-codegen/src/xml/s7template.py | 252 +++ silecs-codegen/src/xml/s7template.pyc | Bin 0 -> 6909 bytes .../src/xml/test/AllTypes.silecsdesign | 77 + .../src/xml/test/AllTypesDU.silecsdeploy | 103 + .../src/xml/test/AllTypesFESA.silecsdesign | 77 + silecs-codegen/src/xml/test/__init__.py | 0 silecs-codegen/src/xml/test/__init__.pyc | Bin 0 -> 177 bytes .../fesa/DeploymentUnitTemplateFESA300.xml | 28 + .../xml/test/fesa/GSIClassTemplateFESA300.xml | 657 ++++++ silecs-codegen/src/xml/test/fesa/__init__.py | 0 silecs-codegen/src/xml/test/fesa/__init__.pyc | Bin 0 -> 188 bytes .../xml/test/fesa/emptyTemplateFESA300.xml | 96 + .../xml/test/fesa/fillFESADeployUnitTest.py | 68 + .../xml/test/fesa/fillFESADeployUnitTest.pyc | Bin 0 -> 2413 bytes .../xml/test/fesa/generateFesaDesignTest.py | 115 + .../xml/test/fesa/generateFesaDesignTest.pyc | Bin 0 -> 5931 bytes .../xml/test/fesa/generateSourceCodeTest.py | 48 + .../xml/test/fesa/generateSourceCodeTest.pyc | Bin 0 -> 1921 bytes .../src/xml/test/general/__init__.py | 0 .../src/xml/test/general/__init__.pyc | Bin 0 -> 185 bytes .../src/xml/test/general/genDuWrapperTest.py | 52 + .../src/xml/test/general/genDuWrapperTest.pyc | Bin 0 -> 2277 bytes .../src/xml/test/general/genParamTest.py | 75 + .../src/xml/test/general/genParamTest.pyc | Bin 0 -> 3729 bytes .../src/xml/test/general/genplcsrcTest.py | 77 + .../src/xml/test/general/genplcsrcTest.pyc | Bin 0 -> 3323 bytes .../src/xml/test/general/iecommonTest.py | 51 + .../src/xml/test/general/iecommonTest.pyc | Bin 0 -> 1664 bytes .../xml/test/generated_correct/AllTypes.cpp | 738 +++++++ .../src/xml/test/generated_correct/AllTypes.h | 146 ++ .../generated_correct/AllTypesFESA.design | 657 ++++++ .../client/Beckhoff_BC9020.silecsparam | 80 + .../client/Beckhoff_CX9020.silecsparam | 80 + .../client/Rabbit_BlockMode.silecsparam | 80 + .../client/Rabbit_DeviceMode.silecsparam | 80 + .../client/Schneider_M340.silecsparam | 80 + .../Schneider_PremiumQuantum.silecsparam | 80 + .../client/Siemens_Step7Block.silecsparam | 80 + .../client/Siemens_Step7Device.silecsparam | 80 + .../client/Siemens_TiaBlock.silecsparam | 80 + .../client/Siemens_TiaDevice.silecsparam | 80 + .../controller/Beckhoff_BC9020.exp | 328 +++ .../controller/Beckhoff_CX9020.exp | 328 +++ .../controller/Rabbit_BlockMode.h | 202 ++ .../controller/Rabbit_DeviceMode.h | 195 ++ .../controller/Schneider_M340.xsy | 326 +++ .../controller/Schneider_PremiumQuantum.xsy | 326 +++ .../controller/Siemens_Step7Block.scl | 150 ++ .../controller/Siemens_Step7Block.sdf | 7 + .../controller/Siemens_Step7Device.scl | 162 ++ .../controller/Siemens_Step7Device.sdf | 8 + .../controller/Siemens_TiaBlock.scl | 158 ++ .../controller/Siemens_TiaBlock.sdf | 8 + .../controller/Siemens_TiaDevice.scl | 147 ++ .../controller/Siemens_TiaDevice.sdf | 7 + .../test/generated_correct/wrapper/AllTypes.h | 38 + .../wrapper/Beckhoff_BC9020.h | 153 ++ .../wrapper/Beckhoff_CX9020.h | 153 ++ .../test/generated_correct/wrapper/Makefile | 59 + .../wrapper/Rabbit_BlockMode.h | 153 ++ .../wrapper/Rabbit_DeviceMode.h | 153 ++ .../wrapper/Schneider_M340.h | 153 ++ .../wrapper/Schneider_PremiumQuantum.h | 153 ++ .../wrapper/Siemens_Step7Block.h | 153 ++ .../wrapper/Siemens_Step7Device.h | 153 ++ .../wrapper/Siemens_TiaBlock.h | 153 ++ .../wrapper/Siemens_TiaDevice.h | 153 ++ .../xml/test/generated_correct/wrapper/Test | Bin 0 -> 2479440 bytes .../wrapper/Virtual_SiemensBlock.h | 153 ++ .../wrapper/Virtual_SiemensDevice.h | 153 ++ .../test/generated_correct/wrapper/main.cpp | 14 + .../xml/test/generated_correct/wrapper/main.o | Bin 0 -> 353312 bytes .../src/xml/test/generated_temp/AllTypes.cpp | 738 +++++++ .../src/xml/test/generated_temp/AllTypes.h | 146 ++ .../test/generated_temp/AllTypesFESA.design | 657 ++++++ .../client/Beckhoff_BC9020.silecsparam | 80 + .../client/Beckhoff_CX9020.silecsparam | 80 + .../client/Rabbit_BlockMode.silecsparam | 80 + .../client/Rabbit_DeviceMode.silecsparam | 80 + .../client/Schneider_M340.silecsparam | 80 + .../Schneider_PremiumQuantum.silecsparam | 80 + .../client/Siemens_Step7Block.silecsparam | 80 + .../client/Siemens_Step7Device.silecsparam | 80 + .../client/Siemens_TiaBlock.silecsparam | 80 + .../client/Siemens_TiaDevice.silecsparam | 80 + .../client/Virtual_SiemensBlock.silecsparam | 80 + .../client/Virtual_SiemensDevice.silecsparam | 80 + .../controller/Beckhoff_BC9020.exp | 328 +++ .../controller/Beckhoff_CX9020.exp | 328 +++ .../controller/Rabbit_BlockMode.h | 202 ++ .../controller/Rabbit_DeviceMode.h | 195 ++ .../controller/Schneider_M340.xsy | 326 +++ .../controller/Schneider_PremiumQuantum.xsy | 326 +++ .../controller/Siemens_Step7Block.scl | 150 ++ .../controller/Siemens_Step7Block.sdf | 7 + .../controller/Siemens_Step7Device.scl | 162 ++ .../controller/Siemens_Step7Device.sdf | 8 + .../controller/Siemens_TiaBlock.scl | 158 ++ .../controller/Siemens_TiaBlock.sdf | 8 + .../controller/Siemens_TiaDevice.scl | 147 ++ .../controller/Siemens_TiaDevice.sdf | 7 + .../Virtual_SiemensBlock.AllTypes.h | 1272 +++++++++++ .../Virtual_SiemensBlock.SilecsHeader.h | 203 ++ .../controller/Virtual_SiemensBlock.cpp | 33 + .../controller/Virtual_SiemensBlock.h | 53 + .../Virtual_SiemensDevice.AllTypes.h | 1272 +++++++++++ .../Virtual_SiemensDevice.SilecsHeader.h | 203 ++ .../controller/Virtual_SiemensDevice.cpp | 33 + .../controller/Virtual_SiemensDevice.h | 53 + .../test/generated_temp/wrapper/AllTypes.h | 38 + .../generated_temp/wrapper/Beckhoff_BC9020.h | 153 ++ .../generated_temp/wrapper/Beckhoff_CX9020.h | 153 ++ .../generated_temp/wrapper/Rabbit_BlockMode.h | 153 ++ .../wrapper/Rabbit_DeviceMode.h | 153 ++ .../generated_temp/wrapper/Schneider_M340.h | 153 ++ .../wrapper/Schneider_PremiumQuantum.h | 153 ++ .../wrapper/Siemens_Step7Block.h | 153 ++ .../wrapper/Siemens_Step7Device.h | 153 ++ .../generated_temp/wrapper/Siemens_TiaBlock.h | 153 ++ .../wrapper/Siemens_TiaDevice.h | 153 ++ .../wrapper/Virtual_SiemensBlock.h | 153 ++ .../wrapper/Virtual_SiemensDevice.h | 153 ++ silecs-codegen/src/xml/test/testBase.py | 96 + silecs-codegen/src/xml/test/testBase.pyc | Bin 0 -> 4945 bytes silecs-codegen/src/xml/virtualS7Template.py | 498 +++++ silecs-codegen/src/xml/virtualS7Template.pyc | Bin 0 -> 13802 bytes silecs-codegen/src/xml/xmltemplate$py.class | Bin 0 -> 5708 bytes silecs-codegen/src/xml/xmltemplate.py | 92 + silecs-codegen/src/xml/xmltemplate.pyc | Bin 0 -> 3346 bytes silecs-communication-cpp/.cproject | 162 ++ silecs-communication-cpp/.project | 33 + silecs-communication-cpp/LICENSE | 674 ++++++ silecs-communication-cpp/Makefile | 32 + silecs-communication-cpp/Makefile.dep | 9 + silecs-communication-cpp/README.md | 19 + silecs-communication-cpp/docs/Doxyfile | 1519 ++++++++++++++ silecs-communication-cpp/install.sh | 11 + silecs-communication-cpp/make-ctb.py | 29 + silecs-communication-cpp/releaseSilecs.sh | 87 + .../src/demo/Cfp774Simatic400_1_0_0.h | 108 + silecs-communication-cpp/src/demo/Doxyfile | 1519 ++++++++++++++ .../src/demo/SilecsHeader_1_0_0.h | 269 +++ .../src/demo/SilecsValid_1_0_0.h | 1859 +++++++++++++++++ silecs-communication-cpp/src/demo/main.cpp | 63 + .../interface/communication/CNVConnection.cpp | 146 ++ .../interface/communication/CNVConnection.h | 111 + .../interface/communication/MBConnection.cpp | 121 ++ .../interface/communication/MBConnection.h | 50 + .../communication/SNAP7Connection.cpp | 201 ++ .../interface/communication/SNAP7Connection.h | 58 + .../communication/SilecsConnection.cpp | 387 ++++ .../communication/SilecsConnection.h | 175 ++ .../interface/core/CNVRecvAction.cpp | 171 ++ .../interface/core/CNVRecvAction.h | 95 + .../interface/core/CNVSendAction.cpp | 175 ++ .../interface/core/CNVSendAction.h | 81 + .../interface/core/Context.cpp | 35 + .../interface/core/Context.h | 54 + .../interface/core/Diagnostic.cpp | 32 + .../interface/core/Diagnostic.h | 67 + .../interface/core/PLCAction.h | 63 + .../interface/core/PLCRecvAction.cpp | 274 +++ .../interface/core/PLCRecvAction.h | 76 + .../interface/core/PLCSendAction.cpp | 253 +++ .../interface/core/PLCSendAction.h | 76 + .../interface/core/SilecsAction.h | 54 + .../interface/core/SilecsService.cpp | 283 +++ .../interface/core/SilecsService.h | 182 ++ .../interface/core/WrapperAction.h | 55 + .../interface/equipment/CNVBlock.cpp | 346 +++ .../interface/equipment/CNVBlock.h | 109 + .../interface/equipment/CNVRegister.cpp | 784 +++++++ .../interface/equipment/CNVRegister.h | 151 ++ .../interface/equipment/PLCBlock.cpp | 92 + .../interface/equipment/PLCBlock.h | 71 + .../interface/equipment/PLCRegister.cpp | 505 +++++ .../interface/equipment/PLCRegister.h | 195 ++ .../interface/equipment/SilecsBlock.cpp | 114 + .../interface/equipment/SilecsBlock.h | 122 ++ .../interface/equipment/SilecsCluster.cpp | 250 +++ .../interface/equipment/SilecsCluster.h | 202 ++ .../interface/equipment/SilecsDevice.cpp | 284 +++ .../interface/equipment/SilecsDevice.h | 184 ++ .../interface/equipment/SilecsPLC.cpp | 725 +++++++ .../interface/equipment/SilecsPLC.h | 553 +++++ .../interface/equipment/SilecsRegister.cpp | 890 ++++++++ .../interface/equipment/SilecsRegister.h | 1727 +++++++++++++++ .../interface/utility/Condition.cpp | 81 + .../interface/utility/Condition.h | 54 + .../interface/utility/Mutex.cpp | 92 + .../interface/utility/Mutex.h | 55 + .../interface/utility/SilecsException.cpp | 331 +++ .../interface/utility/SilecsException.h | 185 ++ .../interface/utility/SilecsLog.cpp | 169 ++ .../interface/utility/SilecsLog.h | 115 + .../interface/utility/StringUtilities.cpp | 120 ++ .../interface/utility/StringUtilities.h | 74 + .../interface/utility/Thread.h | 250 +++ .../interface/utility/TimeStamp.cpp | 126 ++ .../interface/utility/TimeStamp.h | 91 + .../interface/utility/XMLParser.cpp | 242 +++ .../interface/utility/XMLParser.h | 191 ++ .../protocol/core/ietype.h | 166 ++ .../protocol/core/silecs.cpp | 360 ++++ .../protocol/core/silecs.h | 114 + .../protocol/modbus/iemdb.cpp | 441 ++++ .../protocol/modbus/iemdb.h | 156 ++ .../protocol/modbus/mb_addr.h | 111 + .../protocol/modbus/mb_layer1.h | 127 ++ .../protocol/modbus/mb_master.cpp | 483 +++++ .../protocol/modbus/mb_master.h | 157 ++ .../protocol/modbus/mb_master_private.h | 43 + .../protocol/modbus/mb_tcp.cpp | 1407 +++++++++++++ .../protocol/modbus/mb_tcp_private.h | 84 + .../protocol/modbus/mb_time_util.h | 159 ++ .../protocol/modbus/mb_util.h | 92 + .../protocol/modbus/sin_util.cpp | 229 ++ .../protocol/modbus/sin_util.h | 59 + .../src/silecs-communication/wrapper/Block.h | 46 + .../wrapper/Controller.cpp | 52 + .../silecs-communication/wrapper/Controller.h | 64 + .../wrapper/DeployUnit.cpp | 98 + .../silecs-communication/wrapper/DeployUnit.h | 72 + .../silecs-communication/wrapper/Design.cpp | 77 + .../src/silecs-communication/wrapper/Design.h | 65 + .../src/silecs-communication/wrapper/Device.h | 65 + silecs-diagnostic-cpp/.cproject | 160 ++ silecs-diagnostic-cpp/.project | 27 + silecs-diagnostic-cpp/LICENSE | 674 ++++++ silecs-diagnostic-cpp/Makefile | 63 + silecs-diagnostic-cpp/Makefile.dep | 27 + silecs-diagnostic-cpp/README.md | 19 + silecs-diagnostic-cpp/SILECS.pro | 106 + silecs-diagnostic-cpp/SILECS.pro.user | 434 ++++ silecs-diagnostic-cpp/install.sh | 11 + .../src/silecs-diagnostic/constants.h | 59 + .../diagnostictoolmainview.cpp | 1095 ++++++++++ .../diagnostictoolmainview.h | 120 ++ .../silecs-diagnostic/displayarraydialog.cpp | 87 + .../silecs-diagnostic/displayarraydialog.h | 47 + .../silecs-diagnostic/headerinformations.cpp | 63 + .../silecs-diagnostic/headerinformations.h | 46 + .../src/silecs-diagnostic/item.cpp | 33 + .../src/silecs-diagnostic/item.h | 37 + .../src/silecs-diagnostic/logindialog.cpp | 59 + .../src/silecs-diagnostic/logindialog.h | 54 + .../src/silecs-diagnostic/loginhandler.cpp | 71 + .../src/silecs-diagnostic/loginhandler.h | 46 + .../src/silecs-diagnostic/main.cpp | 88 + .../resources/gui/ArrayVisualizationDialog.ui | 67 + .../resources/gui/diagnostictoolmainview.ui | 684 ++++++ .../resources/gui/displayarraydialog.ui | 67 + .../resources/gui/logindialog.ui | 99 + .../silecs-diagnostic/resources/images.qrc | 17 + .../resources/images/DEV.png | Bin 0 -> 2454 bytes .../resources/images/PLC.png | Bin 0 -> 2373 bytes .../resources/images/REG.png | Bin 0 -> 2524 bytes .../resources/images/array.png | Bin 0 -> 1689 bytes .../resources/images/connect.png | Bin 0 -> 2880 bytes .../resources/images/copy.png | Bin 0 -> 23145 bytes .../resources/images/disconnect.png | Bin 0 -> 3337 bytes .../resources/images/glasses.png | Bin 0 -> 5252 bytes .../resources/images/glasses1.png | Bin 0 -> 5504 bytes .../resources/images/send.png | Bin 0 -> 2195 bytes .../resources/images/send1.png | Bin 0 -> 2083 bytes .../resources/images/splash-silecs.png | Bin 0 -> 585383 bytes .../resources/images/stop.png | Bin 0 -> 6061 bytes .../src/silecs-diagnostic/silecsmodule.cpp | 989 +++++++++ .../src/silecs-diagnostic/silecsmodule.h | 131 ++ .../src/silecs-diagnostic/stderrredirect.cpp | 84 + .../src/silecs-diagnostic/stderrredirect.h | 49 + .../src/silecs-diagnostic/utils.cpp | 336 +++ .../src/silecs-diagnostic/utils.h | 110 + silecs-eclipse-plugin-feature/.project | 17 + .../build.properties | 1 + silecs-eclipse-plugin-feature/feature.xml | 746 +++++++ silecs-eclipse-plugin-update-site/.project | 17 + .../artifacts.jar | Bin 0 -> 643 bytes silecs-eclipse-plugin-update-site/content.jar | Bin 0 -> 28454 bytes .../deliverToWebDav.sh | 29 + silecs-eclipse-plugin-update-site/index.html | 60 + silecs-eclipse-plugin-update-site/install.sh | 10 + silecs-eclipse-plugin-update-site/site.xml | 15 + silecs-eclipse-plugin-update-site/test.txt | 1 + .../web/site.css | 12 + .../web/site.xsl | 214 ++ silecs-eclipse-plugin/.classpath | 9 + silecs-eclipse-plugin/.project | 41 + silecs-eclipse-plugin/.pydevproject | 8 + .../org.eclipse.core.resources.prefs | 3 + .../.settings/org.eclipse.jdt.core.prefs | 12 + .../org.eclipse.ltk.core.refactoring.prefs | 2 + .../.settings/org.eclipse.m2e.core.prefs | 4 + .../JNLP-INF/APPLICATION_TEMPLATE.JNLP | 69 + silecs-eclipse-plugin/LICENSE | 674 ++++++ silecs-eclipse-plugin/META-INF/MANIFEST.MF | 134 ++ .../OSGI-INF/l10n/bundle.properties | 2 + silecs-eclipse-plugin/README.md | 40 + silecs-eclipse-plugin/build.properties | 16 + .../icons/class-document.png | Bin 0 -> 1035 bytes .../icons/deploy-document.png | Bin 0 -> 1028 bytes silecs-eclipse-plugin/icons/diag-tool.gif | Bin 0 -> 197 bytes .../icons/generated-code.gif | Bin 0 -> 591 bytes silecs-eclipse-plugin/icons/silecs-logo.ico | Bin 0 -> 15086 bytes .../icons/validate-document.gif | Bin 0 -> 76 bytes silecs-eclipse-plugin/plugin.xml | 874 ++++++++ silecs-eclipse-plugin/pom.xml | 100 + silecs-eclipse-plugin/project.properties | 3 + .../java/cern/silecs/activator/Activator.java | 70 + .../silecs/activator/WebStartLauncher.java | 52 + .../control/core/DeployProjectNature.java | 103 + .../control/core/DesignProjectNature.java | 110 + .../control/core/SilecsProjectNature.java | 162 ++ .../control/handlers/AboutSilecsHandler.java | 68 + .../silecs/control/handlers/BaseHandler.java | 175 ++ .../handlers/DiagnosticToolHandler.java | 76 + .../control/handlers/ExpandAllHandler.java | 60 + .../control/handlers/GenerateCodeHandler.java | 154 ++ .../silecs/control/handlers/SilecsWikis.java | 54 + .../handlers/UpdateSilecsProjectHandler.java | 77 + .../control/handlers/ValidateHandler.java | 52 + .../silecs/control/validation/Validator.java | 103 + .../control/validation/internal/Handler.java | 91 + .../control/validation/internalRules.java | 201 ++ .../model/document/SilecsDocumentError.java | 106 + .../model/document/XmlBasedDocument.java | 234 +++ .../model/exception/SilecsException.java | 95 + .../src/java/cern/silecs/utils/OSExecute.java | 142 ++ .../cern/silecs/utils/SilecsConstants.java | 103 + .../java/cern/silecs/utils/SilecsUtils.java | 311 +++ .../src/java/cern/silecs/utils/XmlUtils.java | 188 ++ .../java/cern/silecs/view/Application.java | 68 + .../view/ApplicationActionBarAdvisor.java | 27 + .../view/ApplicationWorkbenchAdvisor.java | 120 ++ .../ApplicationWorkbenchWindowAdvisor.java | 179 ++ .../java/cern/silecs/view/Perspective.java | 28 + .../silecs/view/console/ConsoleHandler.java | 109 + .../view/dialogs/SilecsMessageDialog.java | 48 + .../view/editor/DeployMultiPageEditor.java | 25 + .../view/editor/DesignMultiPageEditor.java | 25 + .../view/editor/XMLMultiPageEditor.java | 169 ++ .../view/editor/internal/SchemaHelper.java | 58 + .../SilecsTableColumnViewerLabelProvider.java | 181 ++ .../SilecsXMLTableTreeContentProvider.java | 111 + ...MLTableTreePropertyDescriptionFactory.java | 194 ++ .../internal/SilecsXMLTableTreeViewer.java | 176 ++ .../silecs/view/explorer/ContentSorter.java | 64 + .../silecs/view/explorer/ProjectContent.java | 137 ++ .../view/explorer/SilecsProjectExplorer.java | 198 ++ .../cern/silecs/view/job/BaseFileJob.java | 79 + .../cern/silecs/view/job/BaseProjectJob.java | 76 + .../silecs/view/job/GenerateClassJob.java | 99 + .../silecs/view/job/GenerateDeployJob.java | 107 + .../silecs/view/job/UpdateVersionJob.java | 115 + .../cern/silecs/view/job/ValidationJob.java | 223 ++ .../cern/silecs/view/marker/SilecsMarker.java | 64 + .../view/marker/SilecsMarkerUpdater.java | 48 + .../preferences/EditorPreferencePage.java | 232 ++ .../preferences/LoggingPreferencePage.java | 121 ++ .../view/preferences/MainPreferencePage.java | 344 +++ .../preferences/PreferenceInitializer.java | 59 + .../view/wizards/GenerateCodeWizard.java | 70 + .../view/wizards/ImportDeployFileWizard.java | 79 + .../view/wizards/ImportDesignFileWizard.java | 76 + .../view/wizards/NewSilecsDeployWizard.java | 113 + .../view/wizards/NewSilecsDesignWizard.java | 115 + .../wizards/UpdateSilecsProjectWizard.java | 52 + .../view/wizards/page/ChooseFilePage.java | 136 ++ .../view/wizards/page/PickTemplatePage.java | 58 + .../view/wizards/page/PickVersionPage.java | 72 + .../view/wizards/page/SilecsProjectPage.java | 152 ++ silecs-model/.project | 11 + .../org.eclipse.core.resources.prefs | 2 + silecs-model/LICENSE | 674 ++++++ silecs-model/README.md | 19 + silecs-model/install.sh | 10 + silecs-model/src/xml/DeploySchema.xsd | 518 +++++ silecs-model/src/xml/DesignSchema.xsd | 355 ++++ silecs-model/src/xml/shared.xsd | 33 + snap7/.project | 11 + snap7/build.sh | 12 + snap7/install.sh | 10 + 468 files changed, 68094 insertions(+) create mode 100644 silecs-codegen/.project create mode 100644 silecs-codegen/LICENSE create mode 100644 silecs-codegen/README.md create mode 100755 silecs-codegen/install.sh rename silecs-model/dummy => silecs-codegen/src/xml/__init__.py (100%) rename test => silecs-codegen/src/xml/fesa/__init__.py (100%) create mode 100644 silecs-codegen/src/xml/fesa/__init__.pyc create mode 100644 silecs-codegen/src/xml/fesa/fesa_3_0_0/__init__.py create mode 100644 silecs-codegen/src/xml/fesa/fesa_3_0_0/__init__.pyc create mode 100644 silecs-codegen/src/xml/fesa/fesa_3_0_0/fesaTemplates$py.class create mode 100644 silecs-codegen/src/xml/fesa/fesa_3_0_0/fesaTemplates.py create mode 100644 silecs-codegen/src/xml/fesa/fesa_3_0_0/fesaTemplates.pyc create mode 100644 silecs-codegen/src/xml/fesa/fesa_3_0_0/fillFESADeployUnit.py create mode 100644 silecs-codegen/src/xml/fesa/fesa_3_0_0/fillFESADeployUnit.pyc create mode 100644 silecs-codegen/src/xml/fesa/fesa_3_0_0/generateBuildEnvironment$py.class create mode 100644 silecs-codegen/src/xml/fesa/fesa_3_0_0/generateBuildEnvironment.py create mode 100644 silecs-codegen/src/xml/fesa/fesa_3_0_0/generateBuildEnvironment.pyc create mode 100644 silecs-codegen/src/xml/fesa/fesa_3_0_0/generateFesaDesign$py.class create mode 100644 silecs-codegen/src/xml/fesa/fesa_3_0_0/generateFesaDesign.py create mode 100644 silecs-codegen/src/xml/fesa/fesa_3_0_0/generateFesaDesign.pyc create mode 100644 silecs-codegen/src/xml/fesa/fesa_3_0_0/generateSourceCode$py.class create mode 100644 silecs-codegen/src/xml/fesa/fesa_3_0_0/generateSourceCode.py create mode 100644 silecs-codegen/src/xml/fesa/fesa_3_0_0/generateSourceCode.pyc create mode 100644 silecs-codegen/src/xml/fesa/fesa_3_1_0/__init__.py create mode 100644 silecs-codegen/src/xml/fesa/fesa_3_1_0/__init__.pyc create mode 100644 silecs-codegen/src/xml/fesa/fesa_3_1_0/fillFESADeployUnit.py create mode 100644 silecs-codegen/src/xml/fesa/fesa_3_1_0/fillFESADeployUnit.pyc create mode 100644 silecs-codegen/src/xml/fesa/fesa_3_1_0/generateBuildEnvironment.py create mode 100644 silecs-codegen/src/xml/fesa/fesa_3_1_0/generateBuildEnvironment.pyc create mode 100644 silecs-codegen/src/xml/fesa/fesa_3_1_0/generateFesaDesign.py create mode 100644 silecs-codegen/src/xml/fesa/fesa_3_1_0/generateFesaDesign.pyc create mode 100644 silecs-codegen/src/xml/fesa/fesa_3_1_0/generateSourceCode.py create mode 100644 silecs-codegen/src/xml/fesa/fesa_3_1_0/generateSourceCode.pyc create mode 100644 silecs-codegen/src/xml/fesa/fillDesignFileBase.pyc create mode 100644 silecs-codegen/src/xml/fesa/fillFesaDeployUnitBase.py create mode 100644 silecs-codegen/src/xml/fesa/fillFesaDeployUnitBase.pyc create mode 100644 silecs-codegen/src/xml/fesa/fillFesaDesignBase.py create mode 100644 silecs-codegen/src/xml/fesa/fillFesaDesignBase.pyc create mode 100644 silecs-codegen/src/xml/genduwrapper$py.class create mode 100644 silecs-codegen/src/xml/genduwrapper.py create mode 100644 silecs-codegen/src/xml/genduwrapper.pyc create mode 100644 silecs-codegen/src/xml/genduwrappertemplate$py.class create mode 100644 silecs-codegen/src/xml/genduwrappertemplate.py create mode 100644 silecs-codegen/src/xml/genduwrappertemplate.pyc create mode 100644 silecs-codegen/src/xml/genparam$py.class create mode 100644 silecs-codegen/src/xml/genparam.py create mode 100644 silecs-codegen/src/xml/genparam.pyc create mode 100644 silecs-codegen/src/xml/genplcsrc$py.class create mode 100644 silecs-codegen/src/xml/genplcsrc.py create mode 100644 silecs-codegen/src/xml/genplcsrc.pyc create mode 100644 silecs-codegen/src/xml/iecommon$py.class create mode 100644 silecs-codegen/src/xml/iecommon.py create mode 100644 silecs-codegen/src/xml/iecommon.pyc create mode 100644 silecs-codegen/src/xml/iefiles$py.class create mode 100644 silecs-codegen/src/xml/iefiles.py create mode 100644 silecs-codegen/src/xml/iefiles.pyc create mode 100644 silecs-codegen/src/xml/migration/0_10_0to1_0_0.py create mode 100644 silecs-codegen/src/xml/migration/0_9_0to0_10_0.py create mode 100644 silecs-codegen/src/xml/migration/FileUtils.py create mode 100644 silecs-codegen/src/xml/migration/FileUtils.pyc create mode 100644 silecs-codegen/src/xml/migration/__init__.py create mode 100644 silecs-codegen/src/xml/migration/__init__.pyc create mode 100644 silecs-codegen/src/xml/migration/migration0_10_0to1_0_0/DeviceData_PneuDriveDU.instance create mode 100644 silecs-codegen/src/xml/migration/migration0_10_0to1_0_0/__init__.py create mode 100644 silecs-codegen/src/xml/migration/migration0_10_0to1_0_0/__init__.pyc create mode 100644 silecs-codegen/src/xml/migration/migration0_10_0to1_0_0/migrators.py create mode 100644 silecs-codegen/src/xml/migration/migration0_10_0to1_0_0/migrators.pyc create mode 100644 silecs-codegen/src/xml/migration/migration0_10_0to1_0_0/testMigration.py create mode 100644 silecs-codegen/src/xml/migration/migration0_10_0to1_0_0/testMigration.pyc create mode 100644 silecs-codegen/src/xml/migration/migrationBase.py create mode 100644 silecs-codegen/src/xml/migration/migrationBase.pyc create mode 100644 silecs-codegen/src/xml/migration/migration_0_9_0to0_10_0/__init__.py create mode 100644 silecs-codegen/src/xml/migration/migration_0_9_0to0_10_0/__init__.pyc create mode 100644 silecs-codegen/src/xml/migration/migration_0_9_0to0_10_0/migrateDeployDeviceNumber.py create mode 100644 silecs-codegen/src/xml/migration/migration_0_9_0to0_10_0/migrateDeployDeviceNumber.pyc create mode 100644 silecs-codegen/src/xml/migration/migration_0_9_0to0_10_0/migrateDeployDomain.py create mode 100644 silecs-codegen/src/xml/migration/migration_0_9_0to0_10_0/migrateDeployDomain.pyc create mode 100644 silecs-codegen/src/xml/migration/migration_0_9_0to0_10_0/testMigration.py create mode 100644 silecs-codegen/src/xml/migration/migration_0_9_0to0_10_0/testMigration.pyc create mode 100644 silecs-codegen/src/xml/migration/runTests.py create mode 100644 silecs-codegen/src/xml/migration/runTests.pyc create mode 100644 silecs-codegen/src/xml/rabbitTemplate$py.class create mode 100644 silecs-codegen/src/xml/rabbitTemplate.py create mode 100644 silecs-codegen/src/xml/rabbitTemplate.pyc create mode 100644 silecs-codegen/src/xml/runTests.py create mode 100644 silecs-codegen/src/xml/s7template$py.class create mode 100644 silecs-codegen/src/xml/s7template.py create mode 100644 silecs-codegen/src/xml/s7template.pyc create mode 100644 silecs-codegen/src/xml/test/AllTypes.silecsdesign create mode 100644 silecs-codegen/src/xml/test/AllTypesDU.silecsdeploy create mode 100644 silecs-codegen/src/xml/test/AllTypesFESA.silecsdesign create mode 100644 silecs-codegen/src/xml/test/__init__.py create mode 100644 silecs-codegen/src/xml/test/__init__.pyc create mode 100644 silecs-codegen/src/xml/test/fesa/DeploymentUnitTemplateFESA300.xml create mode 100644 silecs-codegen/src/xml/test/fesa/GSIClassTemplateFESA300.xml create mode 100644 silecs-codegen/src/xml/test/fesa/__init__.py create mode 100644 silecs-codegen/src/xml/test/fesa/__init__.pyc create mode 100644 silecs-codegen/src/xml/test/fesa/emptyTemplateFESA300.xml create mode 100644 silecs-codegen/src/xml/test/fesa/fillFESADeployUnitTest.py create mode 100644 silecs-codegen/src/xml/test/fesa/fillFESADeployUnitTest.pyc create mode 100644 silecs-codegen/src/xml/test/fesa/generateFesaDesignTest.py create mode 100644 silecs-codegen/src/xml/test/fesa/generateFesaDesignTest.pyc create mode 100644 silecs-codegen/src/xml/test/fesa/generateSourceCodeTest.py create mode 100644 silecs-codegen/src/xml/test/fesa/generateSourceCodeTest.pyc create mode 100644 silecs-codegen/src/xml/test/general/__init__.py create mode 100644 silecs-codegen/src/xml/test/general/__init__.pyc create mode 100644 silecs-codegen/src/xml/test/general/genDuWrapperTest.py create mode 100644 silecs-codegen/src/xml/test/general/genDuWrapperTest.pyc create mode 100644 silecs-codegen/src/xml/test/general/genParamTest.py create mode 100644 silecs-codegen/src/xml/test/general/genParamTest.pyc create mode 100644 silecs-codegen/src/xml/test/general/genplcsrcTest.py create mode 100644 silecs-codegen/src/xml/test/general/genplcsrcTest.pyc create mode 100644 silecs-codegen/src/xml/test/general/iecommonTest.py create mode 100644 silecs-codegen/src/xml/test/general/iecommonTest.pyc create mode 100644 silecs-codegen/src/xml/test/generated_correct/AllTypes.cpp create mode 100644 silecs-codegen/src/xml/test/generated_correct/AllTypes.h create mode 100644 silecs-codegen/src/xml/test/generated_correct/AllTypesFESA.design create mode 100644 silecs-codegen/src/xml/test/generated_correct/client/Beckhoff_BC9020.silecsparam create mode 100644 silecs-codegen/src/xml/test/generated_correct/client/Beckhoff_CX9020.silecsparam create mode 100644 silecs-codegen/src/xml/test/generated_correct/client/Rabbit_BlockMode.silecsparam create mode 100644 silecs-codegen/src/xml/test/generated_correct/client/Rabbit_DeviceMode.silecsparam create mode 100644 silecs-codegen/src/xml/test/generated_correct/client/Schneider_M340.silecsparam create mode 100644 silecs-codegen/src/xml/test/generated_correct/client/Schneider_PremiumQuantum.silecsparam create mode 100644 silecs-codegen/src/xml/test/generated_correct/client/Siemens_Step7Block.silecsparam create mode 100644 silecs-codegen/src/xml/test/generated_correct/client/Siemens_Step7Device.silecsparam create mode 100644 silecs-codegen/src/xml/test/generated_correct/client/Siemens_TiaBlock.silecsparam create mode 100644 silecs-codegen/src/xml/test/generated_correct/client/Siemens_TiaDevice.silecsparam create mode 100644 silecs-codegen/src/xml/test/generated_correct/controller/Beckhoff_BC9020.exp create mode 100644 silecs-codegen/src/xml/test/generated_correct/controller/Beckhoff_CX9020.exp create mode 100644 silecs-codegen/src/xml/test/generated_correct/controller/Rabbit_BlockMode.h create mode 100644 silecs-codegen/src/xml/test/generated_correct/controller/Rabbit_DeviceMode.h create mode 100644 silecs-codegen/src/xml/test/generated_correct/controller/Schneider_M340.xsy create mode 100644 silecs-codegen/src/xml/test/generated_correct/controller/Schneider_PremiumQuantum.xsy create mode 100644 silecs-codegen/src/xml/test/generated_correct/controller/Siemens_Step7Block.scl create mode 100644 silecs-codegen/src/xml/test/generated_correct/controller/Siemens_Step7Block.sdf create mode 100644 silecs-codegen/src/xml/test/generated_correct/controller/Siemens_Step7Device.scl create mode 100644 silecs-codegen/src/xml/test/generated_correct/controller/Siemens_Step7Device.sdf create mode 100644 silecs-codegen/src/xml/test/generated_correct/controller/Siemens_TiaBlock.scl create mode 100644 silecs-codegen/src/xml/test/generated_correct/controller/Siemens_TiaBlock.sdf create mode 100644 silecs-codegen/src/xml/test/generated_correct/controller/Siemens_TiaDevice.scl create mode 100644 silecs-codegen/src/xml/test/generated_correct/controller/Siemens_TiaDevice.sdf create mode 100644 silecs-codegen/src/xml/test/generated_correct/wrapper/AllTypes.h create mode 100644 silecs-codegen/src/xml/test/generated_correct/wrapper/Beckhoff_BC9020.h create mode 100644 silecs-codegen/src/xml/test/generated_correct/wrapper/Beckhoff_CX9020.h create mode 100644 silecs-codegen/src/xml/test/generated_correct/wrapper/Makefile create mode 100644 silecs-codegen/src/xml/test/generated_correct/wrapper/Rabbit_BlockMode.h create mode 100644 silecs-codegen/src/xml/test/generated_correct/wrapper/Rabbit_DeviceMode.h create mode 100644 silecs-codegen/src/xml/test/generated_correct/wrapper/Schneider_M340.h create mode 100644 silecs-codegen/src/xml/test/generated_correct/wrapper/Schneider_PremiumQuantum.h create mode 100644 silecs-codegen/src/xml/test/generated_correct/wrapper/Siemens_Step7Block.h create mode 100644 silecs-codegen/src/xml/test/generated_correct/wrapper/Siemens_Step7Device.h create mode 100644 silecs-codegen/src/xml/test/generated_correct/wrapper/Siemens_TiaBlock.h create mode 100644 silecs-codegen/src/xml/test/generated_correct/wrapper/Siemens_TiaDevice.h create mode 100755 silecs-codegen/src/xml/test/generated_correct/wrapper/Test create mode 100644 silecs-codegen/src/xml/test/generated_correct/wrapper/Virtual_SiemensBlock.h create mode 100644 silecs-codegen/src/xml/test/generated_correct/wrapper/Virtual_SiemensDevice.h create mode 100644 silecs-codegen/src/xml/test/generated_correct/wrapper/main.cpp create mode 100644 silecs-codegen/src/xml/test/generated_correct/wrapper/main.o create mode 100644 silecs-codegen/src/xml/test/generated_temp/AllTypes.cpp create mode 100644 silecs-codegen/src/xml/test/generated_temp/AllTypes.h create mode 100644 silecs-codegen/src/xml/test/generated_temp/AllTypesFESA.design create mode 100644 silecs-codegen/src/xml/test/generated_temp/client/Beckhoff_BC9020.silecsparam create mode 100644 silecs-codegen/src/xml/test/generated_temp/client/Beckhoff_CX9020.silecsparam create mode 100644 silecs-codegen/src/xml/test/generated_temp/client/Rabbit_BlockMode.silecsparam create mode 100644 silecs-codegen/src/xml/test/generated_temp/client/Rabbit_DeviceMode.silecsparam create mode 100644 silecs-codegen/src/xml/test/generated_temp/client/Schneider_M340.silecsparam create mode 100644 silecs-codegen/src/xml/test/generated_temp/client/Schneider_PremiumQuantum.silecsparam create mode 100644 silecs-codegen/src/xml/test/generated_temp/client/Siemens_Step7Block.silecsparam create mode 100644 silecs-codegen/src/xml/test/generated_temp/client/Siemens_Step7Device.silecsparam create mode 100644 silecs-codegen/src/xml/test/generated_temp/client/Siemens_TiaBlock.silecsparam create mode 100644 silecs-codegen/src/xml/test/generated_temp/client/Siemens_TiaDevice.silecsparam create mode 100644 silecs-codegen/src/xml/test/generated_temp/client/Virtual_SiemensBlock.silecsparam create mode 100644 silecs-codegen/src/xml/test/generated_temp/client/Virtual_SiemensDevice.silecsparam create mode 100644 silecs-codegen/src/xml/test/generated_temp/controller/Beckhoff_BC9020.exp create mode 100644 silecs-codegen/src/xml/test/generated_temp/controller/Beckhoff_CX9020.exp create mode 100644 silecs-codegen/src/xml/test/generated_temp/controller/Rabbit_BlockMode.h create mode 100644 silecs-codegen/src/xml/test/generated_temp/controller/Rabbit_DeviceMode.h create mode 100644 silecs-codegen/src/xml/test/generated_temp/controller/Schneider_M340.xsy create mode 100644 silecs-codegen/src/xml/test/generated_temp/controller/Schneider_PremiumQuantum.xsy create mode 100644 silecs-codegen/src/xml/test/generated_temp/controller/Siemens_Step7Block.scl create mode 100644 silecs-codegen/src/xml/test/generated_temp/controller/Siemens_Step7Block.sdf create mode 100644 silecs-codegen/src/xml/test/generated_temp/controller/Siemens_Step7Device.scl create mode 100644 silecs-codegen/src/xml/test/generated_temp/controller/Siemens_Step7Device.sdf create mode 100644 silecs-codegen/src/xml/test/generated_temp/controller/Siemens_TiaBlock.scl create mode 100644 silecs-codegen/src/xml/test/generated_temp/controller/Siemens_TiaBlock.sdf create mode 100644 silecs-codegen/src/xml/test/generated_temp/controller/Siemens_TiaDevice.scl create mode 100644 silecs-codegen/src/xml/test/generated_temp/controller/Siemens_TiaDevice.sdf create mode 100644 silecs-codegen/src/xml/test/generated_temp/controller/Virtual_SiemensBlock.AllTypes.h create mode 100644 silecs-codegen/src/xml/test/generated_temp/controller/Virtual_SiemensBlock.SilecsHeader.h create mode 100644 silecs-codegen/src/xml/test/generated_temp/controller/Virtual_SiemensBlock.cpp create mode 100644 silecs-codegen/src/xml/test/generated_temp/controller/Virtual_SiemensBlock.h create mode 100644 silecs-codegen/src/xml/test/generated_temp/controller/Virtual_SiemensDevice.AllTypes.h create mode 100644 silecs-codegen/src/xml/test/generated_temp/controller/Virtual_SiemensDevice.SilecsHeader.h create mode 100644 silecs-codegen/src/xml/test/generated_temp/controller/Virtual_SiemensDevice.cpp create mode 100644 silecs-codegen/src/xml/test/generated_temp/controller/Virtual_SiemensDevice.h create mode 100644 silecs-codegen/src/xml/test/generated_temp/wrapper/AllTypes.h create mode 100644 silecs-codegen/src/xml/test/generated_temp/wrapper/Beckhoff_BC9020.h create mode 100644 silecs-codegen/src/xml/test/generated_temp/wrapper/Beckhoff_CX9020.h create mode 100644 silecs-codegen/src/xml/test/generated_temp/wrapper/Rabbit_BlockMode.h create mode 100644 silecs-codegen/src/xml/test/generated_temp/wrapper/Rabbit_DeviceMode.h create mode 100644 silecs-codegen/src/xml/test/generated_temp/wrapper/Schneider_M340.h create mode 100644 silecs-codegen/src/xml/test/generated_temp/wrapper/Schneider_PremiumQuantum.h create mode 100644 silecs-codegen/src/xml/test/generated_temp/wrapper/Siemens_Step7Block.h create mode 100644 silecs-codegen/src/xml/test/generated_temp/wrapper/Siemens_Step7Device.h create mode 100644 silecs-codegen/src/xml/test/generated_temp/wrapper/Siemens_TiaBlock.h create mode 100644 silecs-codegen/src/xml/test/generated_temp/wrapper/Siemens_TiaDevice.h create mode 100644 silecs-codegen/src/xml/test/generated_temp/wrapper/Virtual_SiemensBlock.h create mode 100644 silecs-codegen/src/xml/test/generated_temp/wrapper/Virtual_SiemensDevice.h create mode 100644 silecs-codegen/src/xml/test/testBase.py create mode 100644 silecs-codegen/src/xml/test/testBase.pyc create mode 100644 silecs-codegen/src/xml/virtualS7Template.py create mode 100644 silecs-codegen/src/xml/virtualS7Template.pyc create mode 100644 silecs-codegen/src/xml/xmltemplate$py.class create mode 100644 silecs-codegen/src/xml/xmltemplate.py create mode 100644 silecs-codegen/src/xml/xmltemplate.pyc create mode 100644 silecs-communication-cpp/.cproject create mode 100644 silecs-communication-cpp/.project create mode 100644 silecs-communication-cpp/LICENSE create mode 100644 silecs-communication-cpp/Makefile create mode 100644 silecs-communication-cpp/Makefile.dep create mode 100644 silecs-communication-cpp/README.md create mode 100644 silecs-communication-cpp/docs/Doxyfile create mode 100755 silecs-communication-cpp/install.sh create mode 100644 silecs-communication-cpp/make-ctb.py create mode 100755 silecs-communication-cpp/releaseSilecs.sh create mode 100644 silecs-communication-cpp/src/demo/Cfp774Simatic400_1_0_0.h create mode 100644 silecs-communication-cpp/src/demo/Doxyfile create mode 100644 silecs-communication-cpp/src/demo/SilecsHeader_1_0_0.h create mode 100644 silecs-communication-cpp/src/demo/SilecsValid_1_0_0.h create mode 100644 silecs-communication-cpp/src/demo/main.cpp create mode 100644 silecs-communication-cpp/src/silecs-communication/interface/communication/CNVConnection.cpp create mode 100644 silecs-communication-cpp/src/silecs-communication/interface/communication/CNVConnection.h create mode 100644 silecs-communication-cpp/src/silecs-communication/interface/communication/MBConnection.cpp create mode 100644 silecs-communication-cpp/src/silecs-communication/interface/communication/MBConnection.h create mode 100644 silecs-communication-cpp/src/silecs-communication/interface/communication/SNAP7Connection.cpp create mode 100644 silecs-communication-cpp/src/silecs-communication/interface/communication/SNAP7Connection.h create mode 100644 silecs-communication-cpp/src/silecs-communication/interface/communication/SilecsConnection.cpp create mode 100644 silecs-communication-cpp/src/silecs-communication/interface/communication/SilecsConnection.h create mode 100644 silecs-communication-cpp/src/silecs-communication/interface/core/CNVRecvAction.cpp create mode 100644 silecs-communication-cpp/src/silecs-communication/interface/core/CNVRecvAction.h create mode 100644 silecs-communication-cpp/src/silecs-communication/interface/core/CNVSendAction.cpp create mode 100644 silecs-communication-cpp/src/silecs-communication/interface/core/CNVSendAction.h create mode 100644 silecs-communication-cpp/src/silecs-communication/interface/core/Context.cpp create mode 100644 silecs-communication-cpp/src/silecs-communication/interface/core/Context.h create mode 100644 silecs-communication-cpp/src/silecs-communication/interface/core/Diagnostic.cpp create mode 100644 silecs-communication-cpp/src/silecs-communication/interface/core/Diagnostic.h create mode 100644 silecs-communication-cpp/src/silecs-communication/interface/core/PLCAction.h create mode 100644 silecs-communication-cpp/src/silecs-communication/interface/core/PLCRecvAction.cpp create mode 100644 silecs-communication-cpp/src/silecs-communication/interface/core/PLCRecvAction.h create mode 100644 silecs-communication-cpp/src/silecs-communication/interface/core/PLCSendAction.cpp create mode 100644 silecs-communication-cpp/src/silecs-communication/interface/core/PLCSendAction.h create mode 100644 silecs-communication-cpp/src/silecs-communication/interface/core/SilecsAction.h create mode 100644 silecs-communication-cpp/src/silecs-communication/interface/core/SilecsService.cpp create mode 100644 silecs-communication-cpp/src/silecs-communication/interface/core/SilecsService.h create mode 100644 silecs-communication-cpp/src/silecs-communication/interface/core/WrapperAction.h create mode 100644 silecs-communication-cpp/src/silecs-communication/interface/equipment/CNVBlock.cpp create mode 100644 silecs-communication-cpp/src/silecs-communication/interface/equipment/CNVBlock.h create mode 100644 silecs-communication-cpp/src/silecs-communication/interface/equipment/CNVRegister.cpp create mode 100644 silecs-communication-cpp/src/silecs-communication/interface/equipment/CNVRegister.h create mode 100644 silecs-communication-cpp/src/silecs-communication/interface/equipment/PLCBlock.cpp create mode 100644 silecs-communication-cpp/src/silecs-communication/interface/equipment/PLCBlock.h create mode 100644 silecs-communication-cpp/src/silecs-communication/interface/equipment/PLCRegister.cpp create mode 100644 silecs-communication-cpp/src/silecs-communication/interface/equipment/PLCRegister.h create mode 100644 silecs-communication-cpp/src/silecs-communication/interface/equipment/SilecsBlock.cpp create mode 100644 silecs-communication-cpp/src/silecs-communication/interface/equipment/SilecsBlock.h create mode 100644 silecs-communication-cpp/src/silecs-communication/interface/equipment/SilecsCluster.cpp create mode 100644 silecs-communication-cpp/src/silecs-communication/interface/equipment/SilecsCluster.h create mode 100644 silecs-communication-cpp/src/silecs-communication/interface/equipment/SilecsDevice.cpp create mode 100644 silecs-communication-cpp/src/silecs-communication/interface/equipment/SilecsDevice.h create mode 100644 silecs-communication-cpp/src/silecs-communication/interface/equipment/SilecsPLC.cpp create mode 100644 silecs-communication-cpp/src/silecs-communication/interface/equipment/SilecsPLC.h create mode 100644 silecs-communication-cpp/src/silecs-communication/interface/equipment/SilecsRegister.cpp create mode 100644 silecs-communication-cpp/src/silecs-communication/interface/equipment/SilecsRegister.h create mode 100644 silecs-communication-cpp/src/silecs-communication/interface/utility/Condition.cpp create mode 100644 silecs-communication-cpp/src/silecs-communication/interface/utility/Condition.h create mode 100644 silecs-communication-cpp/src/silecs-communication/interface/utility/Mutex.cpp create mode 100644 silecs-communication-cpp/src/silecs-communication/interface/utility/Mutex.h create mode 100644 silecs-communication-cpp/src/silecs-communication/interface/utility/SilecsException.cpp create mode 100644 silecs-communication-cpp/src/silecs-communication/interface/utility/SilecsException.h create mode 100644 silecs-communication-cpp/src/silecs-communication/interface/utility/SilecsLog.cpp create mode 100644 silecs-communication-cpp/src/silecs-communication/interface/utility/SilecsLog.h create mode 100644 silecs-communication-cpp/src/silecs-communication/interface/utility/StringUtilities.cpp create mode 100644 silecs-communication-cpp/src/silecs-communication/interface/utility/StringUtilities.h create mode 100644 silecs-communication-cpp/src/silecs-communication/interface/utility/Thread.h create mode 100644 silecs-communication-cpp/src/silecs-communication/interface/utility/TimeStamp.cpp create mode 100644 silecs-communication-cpp/src/silecs-communication/interface/utility/TimeStamp.h create mode 100644 silecs-communication-cpp/src/silecs-communication/interface/utility/XMLParser.cpp create mode 100644 silecs-communication-cpp/src/silecs-communication/interface/utility/XMLParser.h create mode 100644 silecs-communication-cpp/src/silecs-communication/protocol/core/ietype.h create mode 100644 silecs-communication-cpp/src/silecs-communication/protocol/core/silecs.cpp create mode 100644 silecs-communication-cpp/src/silecs-communication/protocol/core/silecs.h create mode 100644 silecs-communication-cpp/src/silecs-communication/protocol/modbus/iemdb.cpp create mode 100644 silecs-communication-cpp/src/silecs-communication/protocol/modbus/iemdb.h create mode 100644 silecs-communication-cpp/src/silecs-communication/protocol/modbus/mb_addr.h create mode 100644 silecs-communication-cpp/src/silecs-communication/protocol/modbus/mb_layer1.h create mode 100644 silecs-communication-cpp/src/silecs-communication/protocol/modbus/mb_master.cpp create mode 100644 silecs-communication-cpp/src/silecs-communication/protocol/modbus/mb_master.h create mode 100644 silecs-communication-cpp/src/silecs-communication/protocol/modbus/mb_master_private.h create mode 100644 silecs-communication-cpp/src/silecs-communication/protocol/modbus/mb_tcp.cpp create mode 100644 silecs-communication-cpp/src/silecs-communication/protocol/modbus/mb_tcp_private.h create mode 100644 silecs-communication-cpp/src/silecs-communication/protocol/modbus/mb_time_util.h create mode 100644 silecs-communication-cpp/src/silecs-communication/protocol/modbus/mb_util.h create mode 100644 silecs-communication-cpp/src/silecs-communication/protocol/modbus/sin_util.cpp create mode 100644 silecs-communication-cpp/src/silecs-communication/protocol/modbus/sin_util.h create mode 100644 silecs-communication-cpp/src/silecs-communication/wrapper/Block.h create mode 100644 silecs-communication-cpp/src/silecs-communication/wrapper/Controller.cpp create mode 100644 silecs-communication-cpp/src/silecs-communication/wrapper/Controller.h create mode 100644 silecs-communication-cpp/src/silecs-communication/wrapper/DeployUnit.cpp create mode 100644 silecs-communication-cpp/src/silecs-communication/wrapper/DeployUnit.h create mode 100644 silecs-communication-cpp/src/silecs-communication/wrapper/Design.cpp create mode 100644 silecs-communication-cpp/src/silecs-communication/wrapper/Design.h create mode 100644 silecs-communication-cpp/src/silecs-communication/wrapper/Device.h create mode 100644 silecs-diagnostic-cpp/.cproject create mode 100644 silecs-diagnostic-cpp/.project create mode 100644 silecs-diagnostic-cpp/LICENSE create mode 100644 silecs-diagnostic-cpp/Makefile create mode 100644 silecs-diagnostic-cpp/Makefile.dep create mode 100644 silecs-diagnostic-cpp/README.md create mode 100644 silecs-diagnostic-cpp/SILECS.pro create mode 100644 silecs-diagnostic-cpp/SILECS.pro.user create mode 100755 silecs-diagnostic-cpp/install.sh create mode 100755 silecs-diagnostic-cpp/src/silecs-diagnostic/constants.h create mode 100755 silecs-diagnostic-cpp/src/silecs-diagnostic/diagnostictoolmainview.cpp create mode 100755 silecs-diagnostic-cpp/src/silecs-diagnostic/diagnostictoolmainview.h create mode 100755 silecs-diagnostic-cpp/src/silecs-diagnostic/displayarraydialog.cpp create mode 100755 silecs-diagnostic-cpp/src/silecs-diagnostic/displayarraydialog.h create mode 100755 silecs-diagnostic-cpp/src/silecs-diagnostic/headerinformations.cpp create mode 100755 silecs-diagnostic-cpp/src/silecs-diagnostic/headerinformations.h create mode 100755 silecs-diagnostic-cpp/src/silecs-diagnostic/item.cpp create mode 100755 silecs-diagnostic-cpp/src/silecs-diagnostic/item.h create mode 100755 silecs-diagnostic-cpp/src/silecs-diagnostic/logindialog.cpp create mode 100755 silecs-diagnostic-cpp/src/silecs-diagnostic/logindialog.h create mode 100755 silecs-diagnostic-cpp/src/silecs-diagnostic/loginhandler.cpp create mode 100755 silecs-diagnostic-cpp/src/silecs-diagnostic/loginhandler.h create mode 100755 silecs-diagnostic-cpp/src/silecs-diagnostic/main.cpp create mode 100755 silecs-diagnostic-cpp/src/silecs-diagnostic/resources/gui/ArrayVisualizationDialog.ui create mode 100755 silecs-diagnostic-cpp/src/silecs-diagnostic/resources/gui/diagnostictoolmainview.ui create mode 100755 silecs-diagnostic-cpp/src/silecs-diagnostic/resources/gui/displayarraydialog.ui create mode 100755 silecs-diagnostic-cpp/src/silecs-diagnostic/resources/gui/logindialog.ui create mode 100755 silecs-diagnostic-cpp/src/silecs-diagnostic/resources/images.qrc create mode 100755 silecs-diagnostic-cpp/src/silecs-diagnostic/resources/images/DEV.png create mode 100755 silecs-diagnostic-cpp/src/silecs-diagnostic/resources/images/PLC.png create mode 100755 silecs-diagnostic-cpp/src/silecs-diagnostic/resources/images/REG.png create mode 100755 silecs-diagnostic-cpp/src/silecs-diagnostic/resources/images/array.png create mode 100755 silecs-diagnostic-cpp/src/silecs-diagnostic/resources/images/connect.png create mode 100755 silecs-diagnostic-cpp/src/silecs-diagnostic/resources/images/copy.png create mode 100755 silecs-diagnostic-cpp/src/silecs-diagnostic/resources/images/disconnect.png create mode 100755 silecs-diagnostic-cpp/src/silecs-diagnostic/resources/images/glasses.png create mode 100755 silecs-diagnostic-cpp/src/silecs-diagnostic/resources/images/glasses1.png create mode 100755 silecs-diagnostic-cpp/src/silecs-diagnostic/resources/images/send.png create mode 100755 silecs-diagnostic-cpp/src/silecs-diagnostic/resources/images/send1.png create mode 100644 silecs-diagnostic-cpp/src/silecs-diagnostic/resources/images/splash-silecs.png create mode 100755 silecs-diagnostic-cpp/src/silecs-diagnostic/resources/images/stop.png create mode 100755 silecs-diagnostic-cpp/src/silecs-diagnostic/silecsmodule.cpp create mode 100755 silecs-diagnostic-cpp/src/silecs-diagnostic/silecsmodule.h create mode 100644 silecs-diagnostic-cpp/src/silecs-diagnostic/stderrredirect.cpp create mode 100644 silecs-diagnostic-cpp/src/silecs-diagnostic/stderrredirect.h create mode 100755 silecs-diagnostic-cpp/src/silecs-diagnostic/utils.cpp create mode 100755 silecs-diagnostic-cpp/src/silecs-diagnostic/utils.h create mode 100644 silecs-eclipse-plugin-feature/.project create mode 100644 silecs-eclipse-plugin-feature/build.properties create mode 100644 silecs-eclipse-plugin-feature/feature.xml create mode 100644 silecs-eclipse-plugin-update-site/.project create mode 100644 silecs-eclipse-plugin-update-site/artifacts.jar create mode 100644 silecs-eclipse-plugin-update-site/content.jar create mode 100755 silecs-eclipse-plugin-update-site/deliverToWebDav.sh create mode 100644 silecs-eclipse-plugin-update-site/index.html create mode 100755 silecs-eclipse-plugin-update-site/install.sh create mode 100644 silecs-eclipse-plugin-update-site/site.xml create mode 100644 silecs-eclipse-plugin-update-site/test.txt create mode 100644 silecs-eclipse-plugin-update-site/web/site.css create mode 100644 silecs-eclipse-plugin-update-site/web/site.xsl create mode 100644 silecs-eclipse-plugin/.classpath create mode 100644 silecs-eclipse-plugin/.project create mode 100644 silecs-eclipse-plugin/.pydevproject create mode 100644 silecs-eclipse-plugin/.settings/org.eclipse.core.resources.prefs create mode 100644 silecs-eclipse-plugin/.settings/org.eclipse.jdt.core.prefs create mode 100644 silecs-eclipse-plugin/.settings/org.eclipse.ltk.core.refactoring.prefs create mode 100644 silecs-eclipse-plugin/.settings/org.eclipse.m2e.core.prefs create mode 100644 silecs-eclipse-plugin/JNLP-INF/APPLICATION_TEMPLATE.JNLP create mode 100644 silecs-eclipse-plugin/LICENSE create mode 100644 silecs-eclipse-plugin/META-INF/MANIFEST.MF create mode 100644 silecs-eclipse-plugin/OSGI-INF/l10n/bundle.properties create mode 100644 silecs-eclipse-plugin/README.md create mode 100644 silecs-eclipse-plugin/build.properties create mode 100644 silecs-eclipse-plugin/icons/class-document.png create mode 100644 silecs-eclipse-plugin/icons/deploy-document.png create mode 100644 silecs-eclipse-plugin/icons/diag-tool.gif create mode 100644 silecs-eclipse-plugin/icons/generated-code.gif create mode 100644 silecs-eclipse-plugin/icons/silecs-logo.ico create mode 100644 silecs-eclipse-plugin/icons/validate-document.gif create mode 100644 silecs-eclipse-plugin/plugin.xml create mode 100644 silecs-eclipse-plugin/pom.xml create mode 100644 silecs-eclipse-plugin/project.properties create mode 100644 silecs-eclipse-plugin/src/java/cern/silecs/activator/Activator.java create mode 100644 silecs-eclipse-plugin/src/java/cern/silecs/activator/WebStartLauncher.java create mode 100644 silecs-eclipse-plugin/src/java/cern/silecs/control/core/DeployProjectNature.java create mode 100644 silecs-eclipse-plugin/src/java/cern/silecs/control/core/DesignProjectNature.java create mode 100644 silecs-eclipse-plugin/src/java/cern/silecs/control/core/SilecsProjectNature.java create mode 100644 silecs-eclipse-plugin/src/java/cern/silecs/control/handlers/AboutSilecsHandler.java create mode 100644 silecs-eclipse-plugin/src/java/cern/silecs/control/handlers/BaseHandler.java create mode 100644 silecs-eclipse-plugin/src/java/cern/silecs/control/handlers/DiagnosticToolHandler.java create mode 100644 silecs-eclipse-plugin/src/java/cern/silecs/control/handlers/ExpandAllHandler.java create mode 100644 silecs-eclipse-plugin/src/java/cern/silecs/control/handlers/GenerateCodeHandler.java create mode 100644 silecs-eclipse-plugin/src/java/cern/silecs/control/handlers/SilecsWikis.java create mode 100644 silecs-eclipse-plugin/src/java/cern/silecs/control/handlers/UpdateSilecsProjectHandler.java create mode 100644 silecs-eclipse-plugin/src/java/cern/silecs/control/handlers/ValidateHandler.java create mode 100644 silecs-eclipse-plugin/src/java/cern/silecs/control/validation/Validator.java create mode 100644 silecs-eclipse-plugin/src/java/cern/silecs/control/validation/internal/Handler.java create mode 100644 silecs-eclipse-plugin/src/java/cern/silecs/control/validation/internalRules.java create mode 100644 silecs-eclipse-plugin/src/java/cern/silecs/model/document/SilecsDocumentError.java create mode 100644 silecs-eclipse-plugin/src/java/cern/silecs/model/document/XmlBasedDocument.java create mode 100644 silecs-eclipse-plugin/src/java/cern/silecs/model/exception/SilecsException.java create mode 100644 silecs-eclipse-plugin/src/java/cern/silecs/utils/OSExecute.java create mode 100644 silecs-eclipse-plugin/src/java/cern/silecs/utils/SilecsConstants.java create mode 100644 silecs-eclipse-plugin/src/java/cern/silecs/utils/SilecsUtils.java create mode 100644 silecs-eclipse-plugin/src/java/cern/silecs/utils/XmlUtils.java create mode 100644 silecs-eclipse-plugin/src/java/cern/silecs/view/Application.java create mode 100644 silecs-eclipse-plugin/src/java/cern/silecs/view/ApplicationActionBarAdvisor.java create mode 100644 silecs-eclipse-plugin/src/java/cern/silecs/view/ApplicationWorkbenchAdvisor.java create mode 100644 silecs-eclipse-plugin/src/java/cern/silecs/view/ApplicationWorkbenchWindowAdvisor.java create mode 100644 silecs-eclipse-plugin/src/java/cern/silecs/view/Perspective.java create mode 100644 silecs-eclipse-plugin/src/java/cern/silecs/view/console/ConsoleHandler.java create mode 100644 silecs-eclipse-plugin/src/java/cern/silecs/view/dialogs/SilecsMessageDialog.java create mode 100644 silecs-eclipse-plugin/src/java/cern/silecs/view/editor/DeployMultiPageEditor.java create mode 100644 silecs-eclipse-plugin/src/java/cern/silecs/view/editor/DesignMultiPageEditor.java create mode 100644 silecs-eclipse-plugin/src/java/cern/silecs/view/editor/XMLMultiPageEditor.java create mode 100644 silecs-eclipse-plugin/src/java/cern/silecs/view/editor/internal/SchemaHelper.java create mode 100644 silecs-eclipse-plugin/src/java/cern/silecs/view/editor/internal/SilecsTableColumnViewerLabelProvider.java create mode 100644 silecs-eclipse-plugin/src/java/cern/silecs/view/editor/internal/SilecsXMLTableTreeContentProvider.java create mode 100644 silecs-eclipse-plugin/src/java/cern/silecs/view/editor/internal/SilecsXMLTableTreePropertyDescriptionFactory.java create mode 100644 silecs-eclipse-plugin/src/java/cern/silecs/view/editor/internal/SilecsXMLTableTreeViewer.java create mode 100644 silecs-eclipse-plugin/src/java/cern/silecs/view/explorer/ContentSorter.java create mode 100644 silecs-eclipse-plugin/src/java/cern/silecs/view/explorer/ProjectContent.java create mode 100644 silecs-eclipse-plugin/src/java/cern/silecs/view/explorer/SilecsProjectExplorer.java create mode 100644 silecs-eclipse-plugin/src/java/cern/silecs/view/job/BaseFileJob.java create mode 100644 silecs-eclipse-plugin/src/java/cern/silecs/view/job/BaseProjectJob.java create mode 100644 silecs-eclipse-plugin/src/java/cern/silecs/view/job/GenerateClassJob.java create mode 100644 silecs-eclipse-plugin/src/java/cern/silecs/view/job/GenerateDeployJob.java create mode 100644 silecs-eclipse-plugin/src/java/cern/silecs/view/job/UpdateVersionJob.java create mode 100644 silecs-eclipse-plugin/src/java/cern/silecs/view/job/ValidationJob.java create mode 100644 silecs-eclipse-plugin/src/java/cern/silecs/view/marker/SilecsMarker.java create mode 100644 silecs-eclipse-plugin/src/java/cern/silecs/view/marker/SilecsMarkerUpdater.java create mode 100644 silecs-eclipse-plugin/src/java/cern/silecs/view/preferences/EditorPreferencePage.java create mode 100644 silecs-eclipse-plugin/src/java/cern/silecs/view/preferences/LoggingPreferencePage.java create mode 100644 silecs-eclipse-plugin/src/java/cern/silecs/view/preferences/MainPreferencePage.java create mode 100644 silecs-eclipse-plugin/src/java/cern/silecs/view/preferences/PreferenceInitializer.java create mode 100644 silecs-eclipse-plugin/src/java/cern/silecs/view/wizards/GenerateCodeWizard.java create mode 100644 silecs-eclipse-plugin/src/java/cern/silecs/view/wizards/ImportDeployFileWizard.java create mode 100644 silecs-eclipse-plugin/src/java/cern/silecs/view/wizards/ImportDesignFileWizard.java create mode 100644 silecs-eclipse-plugin/src/java/cern/silecs/view/wizards/NewSilecsDeployWizard.java create mode 100644 silecs-eclipse-plugin/src/java/cern/silecs/view/wizards/NewSilecsDesignWizard.java create mode 100644 silecs-eclipse-plugin/src/java/cern/silecs/view/wizards/UpdateSilecsProjectWizard.java create mode 100644 silecs-eclipse-plugin/src/java/cern/silecs/view/wizards/page/ChooseFilePage.java create mode 100644 silecs-eclipse-plugin/src/java/cern/silecs/view/wizards/page/PickTemplatePage.java create mode 100644 silecs-eclipse-plugin/src/java/cern/silecs/view/wizards/page/PickVersionPage.java create mode 100644 silecs-eclipse-plugin/src/java/cern/silecs/view/wizards/page/SilecsProjectPage.java create mode 100644 silecs-model/.project create mode 100644 silecs-model/.settings/org.eclipse.core.resources.prefs create mode 100644 silecs-model/LICENSE create mode 100644 silecs-model/README.md create mode 100755 silecs-model/install.sh create mode 100644 silecs-model/src/xml/DeploySchema.xsd create mode 100644 silecs-model/src/xml/DesignSchema.xsd create mode 100644 silecs-model/src/xml/shared.xsd create mode 100644 snap7/.project create mode 100755 snap7/build.sh create mode 100755 snap7/install.sh diff --git a/silecs-codegen/.project b/silecs-codegen/.project new file mode 100644 index 0000000..d8a27b4 --- /dev/null +++ b/silecs-codegen/.project @@ -0,0 +1,11 @@ +<?xml version="1.0" encoding="UTF-8"?> +<projectDescription> + <name>silecs-codegen</name> + <comment></comment> + <projects> + </projects> + <buildSpec> + </buildSpec> + <natures> + </natures> +</projectDescription> diff --git a/silecs-codegen/LICENSE b/silecs-codegen/LICENSE new file mode 100644 index 0000000..20d40b6 --- /dev/null +++ b/silecs-codegen/LICENSE @@ -0,0 +1,674 @@ + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/> + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + <one line to give the program's name and a brief idea of what it does.> + Copyright (C) <year> <name of author> + + 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 3 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, see <http://www.gnu.org/licenses/>. + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + <program> Copyright (C) <year> <name of author> + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +<http://www.gnu.org/licenses/>. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +<http://www.gnu.org/philosophy/why-not-lgpl.html>. \ No newline at end of file diff --git a/silecs-codegen/README.md b/silecs-codegen/README.md new file mode 100644 index 0000000..a5e382f --- /dev/null +++ b/silecs-codegen/README.md @@ -0,0 +1,19 @@ +# silecs-codegen + +This component of the SILECS PLC-framework generates FESA and stand-alone C++ code from an existing silecs-project in order to ease the usage of the package silecs-communication-cpp + +## Getting Started + +Please check the lab-specific SILECS-Wikis for more information: + +[CERN SILECS Wiki Page][CERN_Wiki] + +[GSI SILECS Wiki Page][GSI_Wiki] + +## License + +Licensed under the GNU GENERAL PUBLIC LICENSE Version 3. See the [LICENSE file][license] for details. + +[license]: LICENSE +[CERN_Wiki]: https://wikis.cern.ch/display/SIL/SILECs+Home +[GSI_Wiki]: https://www-acc.gsi.de/wiki/Frontend/SILECS \ No newline at end of file diff --git a/silecs-codegen/install.sh b/silecs-codegen/install.sh new file mode 100755 index 0000000..e8e33e9 --- /dev/null +++ b/silecs-codegen/install.sh @@ -0,0 +1,10 @@ +#!/bin/sh +set -e + +INSTALL_DIR=$1 + +SCRIPT=$(readlink -f "$0") +SCRIPTPATH=$(dirname "$SCRIPT") # path where this script is located in + +mkdir -p ${INSTALL_DIR} +cp -r ${SCRIPTPATH}/src/xml ${INSTALL_DIR} \ No newline at end of file diff --git a/silecs-model/dummy b/silecs-codegen/src/xml/__init__.py similarity index 100% rename from silecs-model/dummy rename to silecs-codegen/src/xml/__init__.py diff --git a/test b/silecs-codegen/src/xml/fesa/__init__.py similarity index 100% rename from test rename to silecs-codegen/src/xml/fesa/__init__.py diff --git a/silecs-codegen/src/xml/fesa/__init__.pyc b/silecs-codegen/src/xml/fesa/__init__.pyc new file mode 100644 index 0000000000000000000000000000000000000000..e9a909548eefa46b401ca6b0d4ceee202ccdedd3 GIT binary patch literal 106 zcmcckiI?kGm`ivv0~9a<X$K%KW&si@3=F{<AQ3+eAi;n}6bl2z^z`)8Qi~Jy<Kr{) dGE3s)^$IFWIDq0dx%nxjIjMFa-Niu6003wp5s?4@ literal 0 HcmV?d00001 diff --git a/silecs-codegen/src/xml/fesa/fesa_3_0_0/__init__.py b/silecs-codegen/src/xml/fesa/fesa_3_0_0/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/silecs-codegen/src/xml/fesa/fesa_3_0_0/__init__.pyc b/silecs-codegen/src/xml/fesa/fesa_3_0_0/__init__.pyc new file mode 100644 index 0000000000000000000000000000000000000000..e033898af1d4fd1d4863d78285b0c8806034345b GIT binary patch literal 117 zcmcckiI?kGm`ivv0~9a<X$K%KW&si@3=F{<AQ3+eAi;n}6w3j{^z`)8Qi~J8M7(jl lLA-%}e0*kJW=VX!UO{CE2T+MkZhlH>PO2Tqpkg3q003Mp6&e5l literal 0 HcmV?d00001 diff --git a/silecs-codegen/src/xml/fesa/fesa_3_0_0/fesaTemplates$py.class b/silecs-codegen/src/xml/fesa/fesa_3_0_0/fesaTemplates$py.class new file mode 100644 index 0000000000000000000000000000000000000000..1b65a8fcbd59c7ab6627091fb203ce597f934a2d GIT binary patch literal 46258 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 V{TBN#>E<%~t@dBjP0@ba{|910vG@Q0 literal 0 HcmV?d00001 diff --git a/silecs-codegen/src/xml/fesa/fesa_3_0_0/fesaTemplates.py b/silecs-codegen/src/xml/fesa/fesa_3_0_0/fesaTemplates.py new file mode 100644 index 0000000..2406e29 --- /dev/null +++ b/silecs-codegen/src/xml/fesa/fesa_3_0_0/fesaTemplates.py @@ -0,0 +1,840 @@ +#!/usr/bin/python +# Copyright 2016 CERN and GSI +# +# 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 3 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, see <http://www.gnu.org/licenses/>. + +import iecommon +import time + +#========================================================================= +# FESA .cproject file +#========================================================================= + +cproject = """<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<?fileVersion 4.0.0?><cproject storage_type_id="org.eclipse.cdt.core.XmlProjectDescriptionStorage"> + <storageModule moduleId="org.eclipse.cdt.core.settings"> + <cconfiguration id="cern.fesa.plugin.build.configuration.537108490"> + <storageModule buildSystemId="org.eclipse.cdt.managedbuilder.core.configurationDataProvider" id="cern.fesa.plugin.build.configuration.537108490" moduleId="org.eclipse.cdt.core.settings" name="FESA Make Build"> + <externalSettings/> + <extensions> + <extension id="org.eclipse.cdt.core.GASErrorParser" point="org.eclipse.cdt.core.ErrorParser"/> + <extension id="org.eclipse.cdt.core.GmakeErrorParser" point="org.eclipse.cdt.core.ErrorParser"/> + <extension id="org.eclipse.cdt.core.GLDErrorParser" point="org.eclipse.cdt.core.ErrorParser"/> + <extension id="org.eclipse.cdt.core.CWDLocator" point="org.eclipse.cdt.core.ErrorParser"/> + <extension id="org.eclipse.cdt.core.GCCErrorParser" point="org.eclipse.cdt.core.ErrorParser"/> + </extensions> + </storageModule> + <storageModule moduleId="cdtBuildSystem" version="4.0.0"> + <configuration buildProperties="" description="" id="cern.fesa.plugin.build.configuration.537108490" name="FESA Make Build" parent="cern.fesa.plugin.build.configuration"> + <folderInfo id="cern.fesa.plugin.build.configuration.537108490." name="/" resourcePath=""> + <toolChain id="cern.fesa.plugin.build.toolchain.1156032800" name="FESA Toolchain" superClass="cern.fesa.plugin.build.toolchain"> + <targetPlatform id="cern.fesa.plugin.build.targetplatform.67227612" isAbstract="false" superClass="cern.fesa.plugin.build.targetplatform"/> + <builder id="cern.fesa.plugin.build.builder.1302129891" name="Gnu Make Builder.FESA Make Build" superClass="cern.fesa.plugin.build.builder"/> + <tool id="cern.fesa.plugin.build.archiver.1068962328" name="GCC Archiver" superClass="cern.fesa.plugin.build.archiver"/> + <tool id="cern.fesa.plugin.build.compiler.648804671" name="GCC C++ Compiler" superClass="cern.fesa.plugin.build.compiler"> + <option id="gnu.cpp.compiler.option.include.paths.12841593" name="Include paths (-I)" superClass="gnu.cpp.compiler.option.include.paths" valueType="includePath"> + </option> + <inputType id="cdt.managedbuild.tool.gnu.cpp.compiler.input.2129597065" superClass="cdt.managedbuild.tool.gnu.cpp.compiler.input"/> + </tool> + <tool id="cdt.managedbuild.tool.gnu.c.compiler.base.662860517" name="GCC C Compiler" superClass="cdt.managedbuild.tool.gnu.c.compiler.base"> + <inputType id="cdt.managedbuild.tool.gnu.c.compiler.input.1388561052" superClass="cdt.managedbuild.tool.gnu.c.compiler.input"/> + </tool> + <tool id="cdt.managedbuild.tool.gnu.c.linker.base.365658250" name="GCC C Linker" superClass="cdt.managedbuild.tool.gnu.c.linker.base"/> + <tool id="cern.fesa.plugin.build.linker.884627432" name="GCC C++ Linker" superClass="cern.fesa.plugin.build.linker"> + <inputType id="cdt.managedbuild.tool.gnu.cpp.linker.input.2024588043" superClass="cdt.managedbuild.tool.gnu.cpp.linker.input"> + <additionalInput kind="additionalinputdependency" paths="$(USER_OBJS)"/> + <additionalInput kind="additionalinput" paths="$(LIBS)"/> + </inputType> + </tool> + <tool id="cern.fesa.plugin.build.assembler.838409637" name="GCC Assembler" superClass="cern.fesa.plugin.build.assembler"> + <inputType id="cdt.managedbuild.tool.gnu.assembler.input.1405521367" superClass="cdt.managedbuild.tool.gnu.assembler.input"/> + </tool> + </toolChain> + </folderInfo> + </configuration> + </storageModule> + <storageModule moduleId="org.eclipse.cdt.core.externalSettings"/> + </cconfiguration> + </storageModule> + <storageModule moduleId="cdtBuildSystem" version="4.0.0"> + <project id="" name=""/> + </storageModule> + <storageModule moduleId="org.eclipse.cdt.core.LanguageSettingsProviders"/> + <storageModule moduleId="org.eclipse.cdt.make.core.buildtargets"> + <buildTargets> + <target name="clean" path="" targetID="org.eclipse.cdt.build.MakeTargetBuilder"> + <buildCommand>make</buildCommand> + <buildArguments/> + <buildTarget>clean</buildTarget> + <stopOnError>true</stopOnError> + <useDefaultCommand>true</useDefaultCommand> + <runAllBuilders>true</runAllBuilders> + </target> + <target name="all x86_64" path="" targetID="org.eclipse.cdt.build.MakeTargetBuilder"> + <buildCommand>make</buildCommand> + <buildArguments/> + <buildTarget>-j16 CPU=x86_64 </buildTarget> + <stopOnError>true</stopOnError> + <useDefaultCommand>true</useDefaultCommand> + <runAllBuilders>true</runAllBuilders> + </target> + </buildTargets> + </storageModule> + <storageModule moduleId="scannerConfiguration"/> +</cproject> +""" + +#========================================================================= +# H Source template (.h file) +#========================================================================= +hTop = """/* + * %s.h + * + * Generated by SILECS framework tools + */ + +#ifndef %s_%s_H_ +#define %s_%s_H_ + +#include <SilecsService.h> +#include <fesa-core/Synchronization/MultiplexingContext.h> +#include <%s/GeneratedCode/ServiceLocator.h> + """ + +hTopBlock = """#include <%s/Server/%s.h> + """ + +hTop2 = """ +namespace %s +{ + + /*--------------------------------------------------------------------------------------------------------- + * SETUP + *--------------------------------------------------------------------------------------------------------- + * Setup the SILECS service by calling the setup() method from the RTDeviceClass::specificInit() + * Stop and cleanup the SILECS service by calling the cleanup() method if needed (eg.: from ~RTDeviceClass()) + * + * In order to make use of the different blocks, defined in the silecsdesign, please make use of the static, block related variables of the class, defined on the bottom of this file ! + * -------------------------------------------------------------------------------------------------------- + */ + + /*--------------------------------------------------------------------------------------------------------- + * COMMUNICATION + *--------------------------------------------------------------------------------------------------------- + * General methods to synchronize the FESA fields and related PLC registers of the FESA server with or without + * PLC side synchronization (send/recv) if requested. Each action is done for one particular block. + * In case of BLOCK_MODE configuration (see SILECS doc.), the transaction is optimal with the following + * 'AllDevices' and 'PLCDevices' methods. + * Each method can be called in the appropriate server-action (set) and rt-action (get) + * + * getAllDevices : [receive all devices of all connected PLCs +] update FESA fields with related SILECS registers + * setAllDevices : update SILECS registers with related FESA fields [+ send block to all connected PLCs] + * getPLCDevices : [receive all devices of one PLC +] update FESA fields with related SILECS registers + * setPLCDevices : update SILECS registers with related FESA fields [+ send block to the PLC] + * getSomeDevices : [receive each device of the device-collection +] update FESA fields with related SILECS registers + * setSomeDevices : update SILECS registers with related FESA fields [+ send block to each device of the device-collection] + * getOneDevice : [receive block of one PLC device +] update FESA fields with related SILECS registers + * setOneDevice : update SILECS registers with related FESA fields [+ send block to the PLC device] + * + * -------------------------------------------------------------------------------------------------------- + */ + + class Abstract%s + { + public: + static inline Silecs::Service* theService() { return pService_; } + static inline Silecs::Cluster* theCluster() { return pCluster_; } + inline std::string& getBlockName() { return blockName_; } + + static void setup(const ServiceLocator* serviceLocator); + static void cleanup(); + static void setPLCSlaveRegisters(Silecs::PLC* pPLC, const ServiceLocator* serviceLocator); + static void getPLCMasterRegisters(Silecs::PLC* pPLC, const ServiceLocator* serviceLocator); + + Abstract%s(std::string blockName); + virtual ~Abstract%s(); + + void getAllDevices(const ServiceLocator* serviceLocator, const bool recvNow, MultiplexingContext* pContext); + void getPLCDevices(Silecs::PLC* pPLC, const ServiceLocator* serviceLocator, const bool recvNow, MultiplexingContext* pContext); + void getSomeDevices(std::vector<Device*> deviceCol, const bool recvNow, MultiplexingContext* pContext); + virtual void getOneDevice(Device* pDevice, const bool recvNow, MultiplexingContext* pContext); + + void setAllDevices(const ServiceLocator* serviceLocator, const bool sendNow, MultiplexingContext* pContext); + void setPLCDevices(Silecs::PLC* pPLC, const ServiceLocator* serviceLocator, const bool sendNow, MultiplexingContext* pContext); + void setSomeDevices(std::vector<Device*> deviceCol, const bool sendNow, MultiplexingContext* pContext); + virtual void setOneDevice(Device* pDevice, const bool sendNow, MultiplexingContext* pContext); + + protected: + + static Silecs::Service* pService_; + static Silecs::Cluster* pCluster_; + static bool isInitialized_; + + // Name of the silecs-block which is addressed + std::string blockName_; + + // not copyable object + Abstract%s(const Abstract%s&); + Abstract%s& operator=(const Abstract%s&); + }; + + // ------------------------------------------------------------------------------------------------- + #define BLOCK_RO( name )\t\\ + class name##_Type : public Abstract%s\t\\ + {\t\\ + public:\t\\ + name##_Type(std::string name);\t\\ + ~name##_Type();\t\\ + void getOneDevice(Device* pDevice, const bool transmitNow, MultiplexingContext* pContext);\t\\ + } + + + #define BLOCK_WO( name )\t\\ + class name##_Type : public Abstract%s\t\\ + {\t\\ + public:\t\\ + name##_Type(std::string name);\t\\ + ~name##_Type();\t\\ + void setOneDevice(Device* pDevice, const bool transmitNow, MultiplexingContext* pContext);\t\\ + void setOneDevice(Device* pDevice, name##PropertyData& data, const bool transmitNow, MultiplexingContext* pContext);\t\\ + } + + #define BLOCK_RW( name )\t\\ + class name##_Type : public Abstract%s\t\\ + {\t\\ + public:\t\\ + name##_Type(std::string name);\t\\ + ~name##_Type();\t\\ + void getOneDevice(Device* pDevice, const bool transmitNow, MultiplexingContext* pContext);\t\\ + void setOneDevice(Device* pDevice, const bool transmitNow, MultiplexingContext* pContext);\t\\ + void setOneDevice(Device* pDevice, name##PropertyData& data, const bool transmitNow, MultiplexingContext* pContext);\t\\ + } + + """ + +hBlock = """BLOCK_%s( %s ); + """ + +hBottom = """ + /*--------------------------------------------------------------------------------------------------------- + * INTERFACE + *--------------------------------------------------------------------------------------------------------- + * This is the public interface used from the FESA code to access the PLC service. + */ + class %s + { + public: + static inline Silecs::Service* theService() { return Abstract%s::theService(); } + static inline Silecs::Cluster* theCluster() { return Abstract%s::theCluster(); } + static void setup(const ServiceLocator* serviceLocator) { Abstract%s::setup(serviceLocator); } + static void cleanup() { Abstract%s::cleanup(); } + + """ + +hDeclBlocks = """ static %s_Type %s; + """ + +hClosing = """ + }; + } + + #endif /* %s_%s_H_ */ + """ + +#========================================================================= +# C++ Source template (.cpp file) +#========================================================================= +cTop = """/* + * %s.cpp + * + * Generated by SILECS framework tools + */ + +#include <%s/Common/%s.h> +#include <fesa-core/Synchronization/NoneContext.h> +#include <fesa-core/Synchronization/MultiplexingContext.h> + +namespace %s +{ + //Global objects of the SILECS class + Silecs::Service* Abstract%s::pService_ = NULL; + Silecs::Cluster* Abstract%s::pCluster_ = NULL; + bool Abstract%s::isInitialized_ = false; + + """ + +cGlobal = """%s_Type\t%s::%s("%s"); + """ +cPart1 = """ + //------------------------------------------------------------------------------------------------------------- + // Constructor & Destructor methods + + Abstract%s::Abstract%s(std::string blockName): blockName_(blockName) {} + Abstract%s::~Abstract%s() {} + """ + +cBlockConstr = """ + %s_Type::%s_Type(std::string name): Abstract%s(name) {} + %s_Type::~%s_Type() {} + """ + +cPart2 = """ + //--------------------------------------------------------------------------------------------------------- + // Set-up the SILECS components for the Abstract%s class (service & cluster) + + void Abstract%s::setup(const ServiceLocator* serviceLocator) + { + try + { + // Instantiate the singleton of the SILECS Service + pService_ = Silecs::Service::getInstance(); + + // Enable the SILECS diagnostic with user topics if any + pService_->setArguments(serviceLocator->getUsrCmdArgs()); + + // Instantiate the SILECS Cluster object for the given Class/Version + GlobalDevice* pGlobalDevice = serviceLocator->getGlobalDevice(); + pCluster_ = pService_->getCluster( "%s", pGlobalDevice->plcClassVersion.get()); + isInitialized_ = true; + + // Connect each PLC of the Cluster that is referred from the FESA instance + std::vector<Device*> pDeviceCol = serviceLocator->getDeviceCollection(); + for(std::vector<Device*>::iterator pDeviceIter=pDeviceCol.begin(); pDeviceIter!= pDeviceCol.end(); pDeviceIter++) + { + Device* pDevice = *pDeviceIter; + + // Retrieve the PLC related to the current FESA device + // (from 'plcHostName' FESA field defined on that purpose). + Silecs::PLC* pPLC = pCluster_->getPLC(pDevice->plcHostName.get(),pDevice->parameterFile.get()); + + // Update the PLC Slave registers from related FESA fields just before synchronising done at connection time + setPLCSlaveRegisters(pPLC, serviceLocator); + + // Connect the PLC if not already connected + if (!pPLC->isEnabled()) + { pPLC->connect(/*synchroMode=*/Silecs::FULL_SYNCHRO, /*connectNow=*/true); + if (pPLC->isConnected()) + { // Update FESA fields from related PLC Master registers just after synchronising done at connection time + getPLCMasterRegisters(pPLC, serviceLocator); + } + } + } + } + catch (const Silecs::SilecsException& ex) + { + throw fesa::FesaException(__FILE__, __LINE__, ex.getMessage()); + } + } + + //--------------------------------------------------------------------------------------------------------- + // Release all the SILECS resources + void Abstract%s::cleanup() + { + // Attention! This method is responsible to stop all the PLC connections + // and to remove all the SILECS resources (Clusters and related components: PLCs, Devices, Registers, ..) + // Calling method must ensure that no process is currently accessing these resources before cleaning. + // + Silecs::Service::deleteInstance(); + } + + //--------------------------------------------------------------------------------------------------------- + // Synchronise PLC SLAVE/MASTER registers and related FESA fields (automatically called by the setup method @connection time) + void Abstract%s::setPLCSlaveRegisters(Silecs::PLC* pPLC, const ServiceLocator* serviceLocator) + { + fesa::NoneContext noneContext; + """ + +cSetPLC = """ + %s::%s.setPLCDevices(pPLC, serviceLocator, false, &noneContext);""" + +cPart3 = """ + } + + void Abstract%s::getPLCMasterRegisters(Silecs::PLC* pPLC, const ServiceLocator* serviceLocator) + { + fesa::NoneContext noneContext; //MASTER acquisition fields are not consistent, can be set with none-context + """ + +cGetPLC = """ + %s::%s.getPLCDevices(pPLC, serviceLocator, false, &noneContext);""" + +cPart4 = """ + } + + //--------------------------------------------------------------------------------------------------------- + // General methods to synchronize the FESA fields and related PLC registers of the FESA server + // with or without PLC side access (send/recv) if requested. + // get_ : [receive block from PLC +] update FESA fields with related PLC registers + // set_ : update PLC registers with related FESA fields [+ send block to PLC] + + //--------------------------------------------------------------------------------------------------------- + + void Abstract%s::getAllDevices(const ServiceLocator* serviceLocator, const bool recvNow, MultiplexingContext* pContext) + { + if (recvNow) theCluster()->recv(blockName_); + + std::vector<Device*> deviceCol = serviceLocator->getDeviceCollection(); + for(std::vector<Device*>::iterator pDeviceIter=deviceCol.begin(); pDeviceIter!= deviceCol.end(); pDeviceIter++) + { getOneDevice(*pDeviceIter, false, pContext); + } + } + + void Abstract%s::getPLCDevices(Silecs::PLC* pPLC, const ServiceLocator* serviceLocator, const bool recvNow, MultiplexingContext* pContext) + { + if (recvNow) pPLC->recv(blockName_); + + std::vector<Device*> deviceCol = serviceLocator->getDeviceCollection(); + for(std::vector<Device*>::iterator pDeviceIter=deviceCol.begin(); pDeviceIter!= deviceCol.end(); pDeviceIter++) + { if ((*pDeviceIter)->plcHostName.get() == pPLC->getName()) + { getOneDevice(*pDeviceIter, false, pContext); + } + } + } + + void Abstract%s::getSomeDevices(std::vector<Device*> deviceCol, const bool sendNow, MultiplexingContext* pContext) + { + for(std::vector<Device*>::iterator pDeviceIter=deviceCol.begin(); pDeviceIter!= deviceCol.end(); pDeviceIter++) + { getOneDevice(*pDeviceIter, sendNow, pContext); + } + } + + void Abstract%s::getOneDevice(Device* pDevice, const bool recvNow, MultiplexingContext* pContext) {}; + + //--------------------------------------------------------------------------------------------------------- + + void Abstract%s::setAllDevices(const ServiceLocator* serviceLocator, bool sendNow, MultiplexingContext* pContext) + { + std::vector<Device*> deviceCol = serviceLocator->getDeviceCollection(); + for(std::vector<Device*>::iterator pDeviceIter=deviceCol.begin(); pDeviceIter!= deviceCol.end(); pDeviceIter++) + { setOneDevice(*pDeviceIter, false, pContext); + } + + if (sendNow) theCluster()->send(blockName_); + } + + void Abstract%s::setPLCDevices(Silecs::PLC* pPLC, const ServiceLocator* serviceLocator, bool sendNow, MultiplexingContext* pContext) + { + std::vector<Device*> deviceCol = serviceLocator->getDeviceCollection(); + for(std::vector<Device*>::iterator pDeviceIter=deviceCol.begin(); pDeviceIter!= deviceCol.end(); pDeviceIter++) + { if ((*pDeviceIter)->plcHostName.get() == pPLC->getName()) + { setOneDevice(*pDeviceIter, false, pContext); + } + } + + if (sendNow) pPLC->send(blockName_); + } + + void Abstract%s::setSomeDevices(std::vector<Device*> deviceCol, bool sendNow, MultiplexingContext* pContext) + { + for(std::vector<Device*>::iterator pDeviceIter=deviceCol.begin(); pDeviceIter!= deviceCol.end(); pDeviceIter++) + { setOneDevice(*pDeviceIter, sendNow, pContext); + } + } + + void Abstract%s::setOneDevice(Device* pDevice, const bool sendNow, MultiplexingContext* pContext) {}; + + //--------------------------------------------------------------------------------------------------------- + """ + +cCommonGet = """ + void %s_Type::getOneDevice(Device* pDevice, const bool recvNow, MultiplexingContext* pContext) + { + if( !isInitialized_ ) + { + throw fesa::FesaException(__FILE__, __LINE__, "SILECS-Service not initialized yet - %s::setup needs to be called before any plc-interaction can be done"); + } + Silecs::PLC* pPLC = pCluster_->getPLC(pDevice->plcHostName.get(),pDevice->parameterFile.get()); + Silecs::Device* pPLCDevice = pPLC->getDevice(pDevice->plcDeviceLabel.get()); +""" + +cRegVar = """ Silecs::Register* pRegister = NULL; +""" + +cGetArrayVar = """ uint32_t dim1 = 1; +""" +cGetArray2DVar = """ uint32_t dim2 = 1; +""" +cSetArrayVar = """ uint32_t dim1 = 1; + uint32_t fesaDim1; +""" +cSetArray2DVar = """ uint32_t dim2 = 1; + uint32_t fesaDim2; +""" + +cRecv = """ if (recvNow) pPLCDevice -> recv(blockName_); + """ + +cGetStringReg = """ + pRegister = pPLCDevice->getRegister("%s"); + pDevice->%s.set(pRegister->getValString().c_str(), pContext); +""" + +cGetStringArrayReg = """ + { + pRegister = pPLCDevice->getRegister("%s"); + dim1 = pRegister->getDimension1(); + const std::string** stdStringArray = pRegister->getRefStringArray(dim1); + for (unsigned int i=0; i<dim1; i++) + { pDevice->%s.setString(stdStringArray[i]->c_str(), i, pContext); + } + } +""" + +cGetScalarReg = """ + pDevice->%s.set( pPLCDevice->getRegister("%s")->getVal%s(), pContext);""" + +cGetArrayReg = """ + pRegister = pPLCDevice->getRegister("%s"); + dim1 = pRegister->getDimension1(); + pDevice->%s.set(pRegister->getRef%sArray(dim1), dim1, pContext); + """ +cGetArray2DReg = """ + pRegister = pPLCDevice->getRegister("%s"); + dim1 = pRegister->getDimension1(); + dim2 = pRegister->getDimension2(); + pDevice->%s.set(pRegister->getRef%sArray2D(dim1, dim2), dim1, dim2, pContext); +""" +cGetUnsignedArrayReg = """ + pRegister = pPLCDevice->getRegister("%s"); + dim1 = pRegister->getDimension1(); + %s* %s = (%s*)calloc(dim1, sizeof(%s)); + pRegister->getVal%sArray(%s, dim1);\t//use automatic conversion for JAVA non-supported type + pDevice->%s.set(%s, dim1, pContext); + free(%s); + """ + +cGetUnsignedArray2DReg = """ + pRegister = pPLCDevice->getRegister("%s"); + dim1 = pRegister->getDimension1(); + dim2 = pRegister->getDimension2(); + %s* %s = (%s*)calloc(dim1*dim2, sizeof(%s)); + pRegister->getVal%sArray2D(%s, dim1, dim2);\t//use automatic conversion for JAVA non-supported type + pDevice->%s.set(%s, dim1, dim2, pContext); + free(%s); +""" + +cCommonSet = """ + void %s_Type::setOneDevice(Device* pDevice, const bool sendNow, MultiplexingContext* pContext) + { + if( !isInitialized_ ) + { + throw fesa::FesaException(__FILE__, __LINE__, "SILECS-Service not initialized yet - %s::setup needs to be called before any plc-interaction can be done"); + } + Silecs::PLC* pPLC = pCluster_->getPLC(pDevice->plcHostName.get(),pDevice->parameterFile.get()); + Silecs::Device* pPLCDevice = pPLC->getDevice(pDevice->plcDeviceLabel.get()); +""" + +cSend = """ + if (sendNow) pPLCDevice->send(blockName_); +""" + +cDatatypeSet = """ + void %s_Type::setOneDevice(Device* pDevice, %sPropertyData& data, bool sendNow, MultiplexingContext* pContext) + { + if( !isInitialized_ ) + { + throw fesa::FesaException(__FILE__, __LINE__, "SILECS-Service not initialized yet - %s::setup needs to be called before any plc-interaction can be done"); + } + Silecs::PLC* pPLC = pCluster_->getPLC(pDevice->plcHostName.get(),pDevice->parameterFile.get()); + Silecs::Device* pPLCDevice = pPLC->getDevice(pDevice->plcDeviceLabel.get()); +""" + +cSetStringReg = """ + pPLCDevice->getRegister("%s")->setValString(pDevice->%s.get(pContext)); +""" + +cSetStringArrayReg = """ + { + pRegister = pPLCDevice->getRegister("%s"); + dim1 = pRegister->getDimension1(); + std::string stdStringArray[dim1]; + const char** cStringArray = pDevice->%s.get(fesaDim1, pContext); + for (unsigned int i=0; i<dim1; i++) stdStringArray[i] = (const char*)cStringArray[i]; + pRegister->setValStringArray(stdStringArray, dim1); + } +""" + +cSetScalarReg = """ + pPLCDevice->getRegister("%s")->setVal%s( pDevice->%s.get(pContext));""" + +cSetScalarUReg = """ + pPLCDevice->getRegister("%s")->setVal%s( (%s)pDevice->%s.get(pContext));""" + +cSetArrayReg = """ + pRegister = pPLCDevice->getRegister("%s"); + dim1 = pRegister->getDimension1(); + pRegister->setVal%sArray(pDevice->%s.get(fesaDim1, pContext), dim1); + """ + +cSetArray2DReg = """ + pRegister = pPLCDevice->getRegister("%s"); + dim1 = pRegister->getDimension1(); + dim2 = pRegister->getDimension2(); + pRegister->setVal%sArray2D(pDevice->%s.get(fesaDim1, fesaDim2, pContext), dim1, dim2); +""" + +cSetUnsignedArrayReg = """ + pRegister = pPLCDevice->getRegister("%s"); + dim1 = pRegister->getDimension1(); + pRegister->setVal%sArray(pDevice->%s.get(fesaDim1, pContext), dim1);\t//use automatic conversion for JAVA non-supported type +""" + +cSetUnsignedArray2DReg = """ + pRegister = pPLCDevice->getRegister("%s"); + dim1 = pRegister->getDimension1(); + dim2 = pRegister->getDimension2(); + pRegister->setVal%sArray2D( pDevice->%s.get(fesaDim1, fesaDim2, pContext), dim1, dim2);\t//use automatic conversion for JAVA non-supported type +""" + +cSetStringRegData = """ + (data.is%sAvailable()) ? pPLCDevice->getRegister("%s")->setValString(data.%s.get()) : + pPLCDevice->getRegister("%s")->setValString(pDevice->%s.get(pContext));""" + +cSetStringArrayRegData = """ + { + pRegister = pPLCDevice->getRegister("%s"); + dim1 = pRegister->getDimension1(); + std::string stdStringArray[dim1]; + const char** cStringArray = (data.is%sAvailable() ? data.%s.get(fesaDim1) : pDevice->%s.get(fesaDim1, pContext)); + for (unsigned int i=0; i<dim1; i++) stdStringArray[i] = (const char*)cStringArray[i]; + pRegister->setValStringArray(stdStringArray, dim1); + } +""" +cSetScalarRegData = """ + (data.is%sAvailable()) ? pPLCDevice->getRegister("%s")->setVal%s( data.%s.get()) : + pPLCDevice->getRegister("%s")->setVal%s( pDevice->%s.get(pContext));""" + +cSetScalarURegData = """ + (data.is%sAvailable()) ? pPLCDevice->getRegister("%s")->setVal%s( (%s)data.%s.get()) : + pPLCDevice->getRegister("%s")->setVal%s( (%s)pDevice->%s.get(pContext));""" + +cSetArrayRegData = """ + pRegister = pPLCDevice->getRegister("%s"); + dim1 = pRegister->getDimension1(); + (data.is%sAvailable()) ? pRegister->setVal%sArray( data.%s.get(fesaDim1), dim1) : + pRegister->setVal%sArray( pDevice->%s.get(fesaDim1, pContext), dim1); + """ + +cSetUnsignedArrayRegData = """ + pRegister = pPLCDevice->getRegister("%s"); + dim1 = pRegister->getDimension1(); + (data.is%sAvailable()) ? pRegister->setVal%sArray( data.%s.get(fesaDim1), dim1) : + pRegister->setVal%sArray( pDevice->%s.get(fesaDim1, pContext), dim1); + """ + +cSetArray2DRegData = """ + pRegister = pPLCDevice->getRegister("%s"); + dim1 = pRegister->getDimension1(); + dim2 = pRegister->getDimension2(); + (data.is%sAvailable()) ? pRegister->setVal%sArray2D(data.%s.get(fesaDim1, fesaDim2), dim1, dim2) : + pRegister->setVal%sArray2D(pDevice->%s.get(fesaDim1, fesaDim2, pContext), dim1, dim2); +""" + +cSetUnsignedArray2DRegData = """ + pRegister = pPLCDevice->getRegister("%s"); + dim1 = pRegister->getDimension1(); + dim2 = pRegister->getDimension2(); + (data.is%sAvailable()) ? pRegister->setVal%sArray2D(data.%s.get(fesaDim1, fesaDim2), dim1, dim2) : + pRegister->setVal%sArray2D(pDevice->%s.get(fesaDim1, fesaDim2, pContext), dim1, dim2); +""" + +makeDesign = """# Include SILECS library path +SILECS_PATH ?= %s + +# Additional compiler warning flags +override WARNFLAGS += + +# Additional compiler flags +COMPILER_FLAGS += -I$(SILECS_PATH)/include -I$(SILECS_PATH)/include/silecs-communication/interface/core +COMPILER_FLAGS += +LINKER_FLAGS += + +# Additional headers (Custom.h Specific.h ...) which need to be installed +EXTRA_HEADERS += + + """ + +makeDeploy = """# Include SILECS library path +SILECS_PATH ?= %s + +SNAP7_BASE = %s + +# Additional compiler warning flags +override WARNFLAGS += + +# Additional libs and flags which are common to the Realtime and Server part +COMPILER_FLAGS += +LINKER_FLAGS += -L$(SILECS_PATH)/lib/$(CPU) -lsilecs-comm +LINKER_FLAGS += -L$(SNAP7_BASE)/bin/$(CPU)-linux -lsnap7 +#add default search path for dynamic snap7 library +LINKER_FLAGS += -Wl,-rpath,$(SNAP7_BASE)/bin/$(CPU)-linux,-rpath,/usr/lib +LINKER_FLAGS += + +# Additional libs and flags which are specific to the Realtime part +COMPILER_RT_FLAGS += +LINKER_RT_FLAGS += + +# Additional libs and flags which are specific to the Server part +COMPILER_SERVER_FLAGS += +LINKER_SERVER_FLAGS += + +# Additional headers (Custom.h Specific.h ...) which need to be released +EXTRA_HEADERS += + + """ + +#========================================================================= +# FESA .cproject file +#========================================================================= + +def genCProject(): + return cproject + +#========================================================================= +# Header file (.h) code generation sub-functions +#========================================================================= +def genHTop(className): + return hTop %(className, className, className, className, className, className) + +def genHTopBlock(className, blockName): + return hTopBlock %(className, blockName) + +def genHTop2(className): + return hTop2 %(className, className, className, className, className, className, className, className, className, className, className) + +def genHBlock(mode, blockName): + return hBlock %(mode, blockName) + +def genHBottom(className): + return hBottom %(className, className, className, className, className) + +def genHDeclBlocks(className): + return hDeclBlocks %(className, className) + +def genHClosing(className): + return hClosing %(className, className) + +#========================================================================= +# C++ file (.cpp) code generation sub-functions +#========================================================================= +def genCTop(className): + return cTop %(className, className, className, className, className, className, className) + +def genCGlobal(className, blockName): + return cGlobal %(blockName, className, blockName, blockName) + +def genCPart1(className): + return cPart1 %(className, className, className, className) + +def genCBlockConstr(blockName, className): + return cBlockConstr %(blockName, blockName, className, blockName, blockName) + +def genCPart2(className): + return cPart2 %(className, className, className, className, className) + +def genCSetPLC(className, blockName): + return cSetPLC %(className, blockName) + +def genCCommonGet(blockName,className): + return cCommonGet %(blockName,className) + +def genCPart3(className): + return cPart3 %(className) + +def genCGetPLC(className, blockName): + return cGetPLC %(className, blockName) + +def genCPart4(className): + return cPart4 %(className, className, className, className, className, className, className, className) + +def genCGetStringReg(regName): + return cGetStringReg %(regName, regName) + +def genCGetStringArrayReg(regName): + return cGetStringArrayReg %(regName, regName) + +def genCGetScalarReg(regName, regType): + return cGetScalarReg %(regName, regName, regType) + +def genCGetArrayReg(regName, regType): + return cGetArrayReg %(regName, regName, regType) + +def genCGetArray2DReg(regName, regType): + return cGetArray2DReg %(regName, regName, regType) + +def genCGetUnsignedArrayReg(regName, fesaType, regType): + return cGetUnsignedArrayReg %(regName, fesaType, regName, fesaType, fesaType, regType, regName, regName, regName, regName) + +def genCGetUnsignedArray2DReg(regName, fesaType, regType): + return cGetUnsignedArray2DReg %(regName, fesaType, regName, fesaType, fesaType, regType, regName, regName, regName, regName) + +def genCCommonSet(blockName,className): + return cCommonSet %(blockName,className) + +def genCDatatypeSet(blockName,className): + return cDatatypeSet %(blockName, blockName,className) + +def genCSetStringReg(regName): + return cSetStringReg %(regName, regName) + +def genCSetStringArrayReg(regName): + return cSetStringArrayReg %(regName, regName) + +def genCSetScalarReg(regName, regType): + return cSetScalarReg %(regName, regType, regName) + +def genCSetScalarUReg(regName, regType, lowerType): + return cSetScalarUReg %(regName, regType, lowerType, regName) + +def genCSetArrayReg(regName, regType): + return cSetArrayReg %(regName, regType, regName) + +def genCSetUnsignedArrayReg(regName, regType): + return cSetUnsignedArrayReg %(regName, regType, regName) + +def genCSetArray2DReg(regName, regType): + return cSetArray2DReg %(regName, regType, regName) + +def genCSetUnsignedArray2DReg(regName, regType): + return cSetUnsignedArray2DReg %(regName, regType, regName) + +def genCSetStringRegData(regName): + return cSetStringRegData %(iecommon.capitalizeString(regName), regName, regName, regName, regName) + +def genCSetStringArrayRegData(regName): + return cSetStringArrayRegData %(regName, iecommon.capitalizeString(regName), regName, regName) + +def genCSetScalarRegData(regName, regType): + return cSetScalarRegData %(iecommon.capitalizeString(regName), regName, regType, regName, regName, regType, regName) + +def genCSetScalarURegData(regName, regType, lowerType): + return cSetScalarURegData %(iecommon.capitalizeString(regName), regName, regType, lowerType, regName, regName, regType, lowerType, regName) + +def genCSetUnsignedArrayRegData(regName, regType): + return cSetUnsignedArrayRegData %(regName, iecommon.capitalizeString(regName), regType, regName, regType, regName) + +def genCSetUnsignedArray2DRegData(regName, fesaType, regType): + return cSetUnsignedArray2DRegData %(regName, iecommon.capitalizeString(regName), regType, regName, regType, regName) + +def genCSetArrayRegData(regName, regType): + return cSetArrayRegData %(regName, iecommon.capitalizeString(regName), regType, regName, regType, regName) + +def genCSetArray2DRegData(regName, fesaType, regType): + return cSetArray2DRegData %(regName, iecommon.capitalizeString(regName), regType, regName, regType, regName) + +def genMakeDesign(CentralMakefilePath): + return makeDesign %(CentralMakefilePath) + +def genMakeDeploy(silecsBasePath,snap7BasePath): + return makeDeploy %(silecsBasePath,snap7BasePath) diff --git a/silecs-codegen/src/xml/fesa/fesa_3_0_0/fesaTemplates.pyc b/silecs-codegen/src/xml/fesa/fesa_3_0_0/fesaTemplates.pyc new file mode 100644 index 0000000000000000000000000000000000000000..191a8f90d757ffd27d3abd43a113e417c614ff1e GIT binary patch literal 40712 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 literal 0 HcmV?d00001 diff --git a/silecs-codegen/src/xml/fesa/fesa_3_0_0/fillFESADeployUnit.py b/silecs-codegen/src/xml/fesa/fesa_3_0_0/fillFESADeployUnit.py new file mode 100644 index 0000000..5e900bc --- /dev/null +++ b/silecs-codegen/src/xml/fesa/fesa_3_0_0/fillFESADeployUnit.py @@ -0,0 +1,75 @@ +#!/usr/bin/python +# Copyright 2016 CERN and GSI +# +# 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 3 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, see <http://www.gnu.org/licenses/>. + +import libxml2 +import iecommon + +import fesa.fillFesaDeployUnitBase + +class FESADeployUnitGenerator3_0_0(object): + + def fillXML(self,fesaDeployParsed,silecsDeployParsed,deployName, deployUnitSchemaPath, fesaVersion,logTopics={'errorlog': True} ): + + fesaRoot = fesaDeployParsed.xpathEval("/*")[0] + fesaRoot.setProp("xsi:noNamespaceSchemaLocation",deployUnitSchemaPath) + + fesaVersionNode = fesaDeployParsed.xpathEval("/deploy-unit/information/fesa-version")[0] + fesaVersionNode.setContent(fesaVersion) + + fesaDUNameNode = fesaDeployParsed.xpathEval("/deploy-unit/information/deploy-unit-name")[0] + fesaDUNameNode.setContent(deployName) + + fesaOwnershipNode = fesaDeployParsed.xpathEval("/deploy-unit/ownership")[0] + + defaultClassTemplate = fesaDeployParsed.xpathEval('/deploy-unit/class[class-name/text()="class-name"]') + if len(defaultClassTemplate) > 0: + defaultClassTemplate[0].unlinkNode() + + silecsClasses = silecsDeployParsed.xpathEval("/SILECS-Deploy/Controller/SilecsDesign") + for silecsClass in silecsClasses: + + existingClassEntry = fesaDeployParsed.xpathEval('/deploy-unit/class/class-name[text()="' + silecsClass.prop('silecs-design-name') + '"]') + if len(existingClassEntry) > 0: + continue # dont overwrite existing entrys + + iecommon.logDebug("Adding class '" + silecsClass.prop('silecs-design-name') + "' to DeployUnit document", {'debuglog': True}) + fesaClassNode = libxml2.newNode("class") + + fesaClassName = libxml2.newNode("class-name") + fesaClassName.setContent(silecsClass.prop('silecs-design-name')) + fesaClassNode.addChild(fesaClassName) + + fesaClassMajorVersion = libxml2.newNode("class-major-version") + fesaClassMajorVersion.setContent('0') + fesaClassNode.addChild(fesaClassMajorVersion) + + fesaClassMinorVersion = libxml2.newNode("class-minor-version") + fesaClassMinorVersion.setContent('1') + fesaClassNode.addChild(fesaClassMinorVersion) + + fesaClassTinyVersion = libxml2.newNode("class-tiny-version") + fesaClassTinyVersion.setContent('0') + fesaClassNode.addChild(fesaClassTinyVersion) + + fesaClassDeviceInstance = libxml2.newNode("device-instance") + fesaClassDeviceInstance.setContent('required') + fesaClassNode.addChild(fesaClassDeviceInstance) + + fesaOwnershipNode.addNextSibling(fesaClassNode) + +def fillDeployUnit(fesaVersion, className, workspacePath,fesaDesignXSDPath,logTopics={'errorlog': True}): + generator = FESADeployUnitGenerator3_0_0() + fesa.fillFesaDeployUnitBase.fillFesaDeployUnitBase(generator,fesaVersion, className, workspacePath,fesaDesignXSDPath,logTopics) diff --git a/silecs-codegen/src/xml/fesa/fesa_3_0_0/fillFESADeployUnit.pyc b/silecs-codegen/src/xml/fesa/fesa_3_0_0/fillFESADeployUnit.pyc new file mode 100644 index 0000000000000000000000000000000000000000..cd840c04a96109d04746c91f2801fb261daf56c9 GIT binary patch literal 2932 zcmc&$>rNX-6h6CPo0~CU0!=THh1ABW>MSJ^KdQEBf@y_BD78tG5=GW}cWe)=cbuIu z7-{)M{`X1x4t<5bN?)Ko=j^U+Xw<(Tc0A{PnQzYSUw;=D{;2)_%7gSTkH0_QqkqB0 z$A1gX0Zzwz3r?+!Z^P*f_%?`H=pb_j-UHkK{C1jyo&_Qg{w(bJIe3po1@hFal6(0N z{vDZ5ar@(b^I2UC0(JE=l;$T9ipVu8dfM7<ZI4r$LB;3z=udDFn2g2lZAxPoy^{MG zXf&%f%FP@pMUjdE)%6NUJiv#-?%|`iP$#xPa$z@^v<(lh3lJATas}}$+}L2HDoCU% za}dvgv?0zBE0Z(9F6JSgXZg&uJU_Ny$f6dAb-f5?2I9q3d^QVe4V^A>IufG-SRsY6 zInz0|S%Oj9ikG1N_SCvAX8tg65o8Yh1yb7d7h#hEEOUV6sQ?AA-u(&W)#O3qaV*`j zEW#$98urg$hFxlc!HO2ZFLCq|q~r>dD-f@6y;H%tF(r_TBqJiVSY?Y<h*!zNUt?LE zD6%Y5EVJSo#A~d$KCPHor5+!!Vj1G{e?793%;N?tu0y=eiks6OQ}+uXu@hV*HRu(B zs#*OAv2vsdPtKQ!6$H*_xQw*?CR9gmU+97BiKf>RefLm#u8}I#pOd!FV6F`j&5jH^ zD(bV)=?LxCE<~hB^YQ;_PI;(>6l&wHwz|Y?qI+_nckYV3z}5N<uWalXF*4Q1-)&7; zTW|FjWY#=5+}~@~lH2F(snA3!2t?#GWgt9V7g~11M0F}9haDv=M|hJ(&}-;bvu(|1 z<0O4*BF0?CpJ%==!)}FLR32$+@}r7Tl_Uq602N<(!@dX&Ut?dihh4nJCWo4Ar5CbY z;=DX2`|g>FvJM*y`P+I*D#JU{uQ}hOEk=e{nW-+JsV^?1Cu%a(#tl8e$wcDaP)5S9 z7Eu9lh;SIVrni6L28PCr7Unoo149|&o*GJZ(C`XyL+oJ~$ng9~`NGU1IUsc!S5kPY z-$w%?u--b=%_=9+P_XwvwnzP7hxehlWFMsM`u<)|2EL*GB5{Q0-IQ&N)2-6rV=r0+ z9kYTIp)hIou^VaOo5`8oVpFoop%d86`k16MN??DCwVTD%=dTH{xht6ei5f^xb2SvP zp_DPyRw7bWE`W08lwML8X04{IpEHazH%Xx54g<4C2tN`1LEsu;=qwV<F<)p-X^O)Y zijmZK#$DFgN1$J^A%$iZ#~@b|4wX&)8*^R|zOp)RO9)$;gfbo5oFJ|;!REA}&iFb= z;Z;Qu@S+v&oCFL`PxXb<7J;L^-lYsfCkRK*rHamZ_|(#?*2jZ%(!Gbs>Wa|Ok>?;< zc<Aub;uosZkwI|#jr(M9#gHP&>lcS~BXyn9vCGy9KE>p*OIF!h!?gf;yMp_IUA0O` zZ=goWDt>US62=(>triWkR*Nq|tJPQjFhH_Fm}t;2oOIyc+R(r>fJQA({k+|v5#rI{ zp>GGe;QamY6>bcF<y_|g#|*yElCOf8zbo*C9pj4~-{5($_)S7?j;b^TI0D~C0*Ikl zd>}|n2H<m73;sxIJfui8W;{YX-$R1v7yx_$v+I&f>(|XXaT_0JrU-`QgKE;?dx02V zbcEQX&I3$Q6F|V4x2kja+n@o};NeQ&dDNpPAMQ_s4}p$Fwa<iSxUmVCc91!#_1?h5 WsQ)&>`S)~2nkrnfmh2^a<LSTL%;yyV literal 0 HcmV?d00001 diff --git a/silecs-codegen/src/xml/fesa/fesa_3_0_0/generateBuildEnvironment$py.class b/silecs-codegen/src/xml/fesa/fesa_3_0_0/generateBuildEnvironment$py.class new file mode 100644 index 0000000000000000000000000000000000000000..5c789754d31f9ea7d501313f62f7a65befd945d6 GIT binary patch literal 6226 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 literal 0 HcmV?d00001 diff --git a/silecs-codegen/src/xml/fesa/fesa_3_0_0/generateBuildEnvironment.py b/silecs-codegen/src/xml/fesa/fesa_3_0_0/generateBuildEnvironment.py new file mode 100644 index 0000000..b6e6ed5 --- /dev/null +++ b/silecs-codegen/src/xml/fesa/fesa_3_0_0/generateBuildEnvironment.py @@ -0,0 +1,70 @@ +#!/usr/bin/python +# Copyright 2016 CERN and GSI +# +# 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 3 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, see <http://www.gnu.org/licenses/>. + +import os +import sys +import time +import zlib +import glob +import re +import datetime +import socket + +import iecommon +import fesaTemplates +import iefiles + +from iecommon import * + +#------------------------------------------------------------------------- +# Generates two Makefile.specific, one for the class design +# and another for the deploy unit +#------------------------------------------------------------------------- +def genMakefileClass(projectPath, centralMakefilePath, logTopics={'errorlog': True} ): + # Generate makefile for class design + source = fesaTemplates.genMakeDesign(centralMakefilePath) + makefile = projectPath + "/" + "Makefile.specific" + if os.path.isfile(makefile): #dont overwrite + return + fdesc = open(makefile, "w") + iecommon.logInfo("Generate makefile.specific for class design: " + makefile, logTopics) + fdesc.write(source) + fdesc.close() + +def genMakefileDU(projectPath, silecsBasePath, snap7BasePath, logTopics={'errorlog': True}): + # Generate makefile for class design + source = fesaTemplates.genMakeDeploy(silecsBasePath,snap7BasePath) + # Write file and save + makefile = projectPath + "/" + "Makefile.specific" + if os.path.isfile(makefile): #dont overwrite + return + fdesc = open(makefile, "w") + iecommon.logInfo("Generate makefile.specific for deploy unit: " + makefile, logTopics) + fdesc.write(source) + fdesc.close() + +def genCProjectFile(projectPath, logTopics={'errorlog': True}): + # Generate makefile for class design + source = fesaTemplates.genCProject() + + # Write file and save + newFile = projectPath + "/" + ".cproject" + if os.path.isfile(newFile): #dont overwrite + return + fdesc = open(newFile, "w") + iecommon.logInfo("Generate .cproject", logTopics) + fdesc.write(source) + fdesc.close() diff --git a/silecs-codegen/src/xml/fesa/fesa_3_0_0/generateBuildEnvironment.pyc b/silecs-codegen/src/xml/fesa/fesa_3_0_0/generateBuildEnvironment.pyc new file mode 100644 index 0000000000000000000000000000000000000000..1c0a1031d4378963a6696790366150a8eadd39d5 GIT binary patch literal 2199 zcmd6o!EVz)5I|?0I8D>E1zM>{aL9o}gwz@d2_!%W(L%+63Yj7#Un+OKX_weu%ex^I zrKfV|U-%79{0ct+GvhcUfDkuG>+$UDdc8CAX8h&rYUk7T$JY|3zjeGn!pnX}k>J08 zAwV?K1w^8@dk}fG-hil4>rIH7weCaY*Ln-0R;@2Vv{dVDh}yNj4AF9}cOdGp?!mAP zho=J63M37<lQiK29;6F%CZA2K^QIP?*2ssK{U!8Af5YEFU!dwp+;nY}sw_>JniJW; zK?^Us@8V@G3Wtvgm<YHKaNd9khh!`9VC%dI&I8>5-GoV#=8X>mWA;)wpDcLP3lGkH za4pd2Eic=ecw`k5A9NcgxI|QgWw?Oq@xG7mJ>U}t_A=_v<DnYpRPES8Nj=b#=f-vi z=k`^u%Gjx1_Vc3Nz?40i#@6-{W%WsZuh;8$$fZ>j17+hwl@%#IYuR$5a(dAouSL%Q zjCD=C6|p--7cdZ(PQf-)sGOsxl{8sqaz_EiC_c*v2Hgi3m)a@TWNNJH(*|w@MNyhJ zO1c-c>jsV`?o`HU?Ihcm(T<xPnnFv<@3v-CO2x0NJ>|^@=$q{0a$sRcs0G!Lf>V>J z;8>-Bm8WB!=Rumk3&y4#+9H-}+oChlZf9|6gQ+e}qA(7DEoJa7O9P4$i=*2|w~lTF zILFa`Jkn|MB!8<*lV^DTo#M=0!Z%N2NMYKg$lpMlr3vuX#hTa<zE~HVVpT{AEQM?a z+glvWV5=ZO!sdBHkY>F3zwm}-R`J%F<IRUHLX3Dr29Y=Blm|ca7E;E4k6TEGwA(25 z|4dt=iqxF-M!9x1Y#}+i$QP{%35SpZ5K;|>l<<(?3<;62OM)=vx((M*b0n%XJ&vtn zOlXD8<Kk{@2`Sbg)l7JW1o8D>z(FUSgJbVifQBg<SG)x>C=XOXGcr;fRAgX>IQJHq zXv{Iey=0*WVN0%<z*aTuLD<TOhbHrY&4~IB4t~!A<z+`sOSa;G0z2biHpiW%N;YK> zecgRg75ZPNnw;iT|HvYDm0XRVVnO{s$)u0uoP%_@`)Hb`v)icCc?k=>Pm4JOj;rXb z>Zwj=RU>_$>SOMxC#gB+u3J`JF2TmktEf_}kwfLG0^x$<&l!Ids{IbjkqS5IRaZ$| lL-B+Af880W!XIQN8KvqW)uz3UqAM2uJRW(S*2c<4_dC*<>+Jvl literal 0 HcmV?d00001 diff --git a/silecs-codegen/src/xml/fesa/fesa_3_0_0/generateFesaDesign$py.class b/silecs-codegen/src/xml/fesa/fesa_3_0_0/generateFesaDesign$py.class new file mode 100644 index 0000000000000000000000000000000000000000..3a5ea7798548189be5e399cb855e51d69cd9bfda GIT binary patch literal 39292 zcmchA37izg6?awl>~6CRFtZH^$g%2zz_6@<2LhrC3$h9eVG#t4>mIW(usgHN%yM`| zgYh<(_k9PCXgpWqZ8YBTzC)r$jkocLXFR_Dd)3`jJw3A$zkFYQd31Nxt5>gHz4z+9 zs+#qY?{2$G2r((NP71TVY8NRMkDZ@NudM0Xm|c}h*0iS5@tQ>&=cb!G<I@8bOID@h z&25d@=4^cWxIpcqjSE{=$6K@0rP!_r$ueO|QI?5kI}*vb6rr*8<Cca+i6|`>AyFoU zk;+)2j}&%(`$T6~ndmD;AH1Z}*@e`4-q`u8o7XkhbTlVd)--0*iR8*4%kEg}d*L@M z`icJKA}j_-VG(nw*5(c=YPOBOGiVw}R8-JFY{)jV5hEFdA!ZYuaZ7B6x5GLTEtVLH zx0M|!yls#1rcpNny|zK53UibcrI}Rgnt0X{JD?^JC+y}9OYFp7t*Oq=RMHZorRdil z&onQIcXoB4HM-jwvQ5O>6CLz1&J$K`$F>hfO+3#^OiUn|R7){vLubdtcs3o6Pn^>c z?~Et2OYm-q8Y%jE^HG}#i%Ck1lQFP4ODwUg6czasxoBgV*j<Y7oX)PSqc0gLwm+!2 zHigAhv1cE#hnObCupqg)-O1K$B9$x?Gce-zCM7M<9M&7jnPTrgn5liF7?8;9+gR^P zv1*bO{S%qls}db;&R8um8-!QJvx>456AS1?ui7<7%q6wh7xM=)j&_ZJ?)S!Fz1WW$ z?GIxBf7N7k-I?k|=~P!do!w}O1yT$NN<*1JnOF!Bx2IE`^~r2Jos73_JJ*gOg~d<A z;&QP_G#2bfDSeqZ0Ap%ug1K}wHA&GK^d-8>C_dccHNDDcnK-aqEEUV4hfPh%RPwNR zIz@b#W5=xsi-W|$RQppH+>&%R^c6K_?M)rcnQTG|Ssxb7qJ^}eRf;IdxIUT4Y7&Nv zDVf{ckwMFqFoKowWIPQ+n+v0>i)RumlT}?%W{?_Efc@F2w)ph0m?hTq5vv6ZuyjTO z<Y!8;Iw&O1bM|5e#rh~vu6d-SNR^AdL>HWePtPrphL?smHo{x9X4It5k0)1VS5=Yu z?!K!fx}_L7w!U}zQL&!1bOU4#VwO0Jrvk6d*=)M0DJ+g4-Crt>l%hPtF1orS4)66d zDH?-v*fwSP0hKt0`ujP#;B49w$A(2#&B1XzhXn>~i4&w44xSgLXJdWK#+5W`)9L1o zOEz}JtEMPXxz&E>a59vtnNTO!S>jZ95BT4XT8uu?(#>A^S0ElV)Vc(Ft>!dT=r^=X zpd(A127d%bSjC#N&D6Uk&Vcf?r_!CxkndSEC%tG1twKq0PPzE4I2Tmg5}lJQalU$+ zY>5jo4a{t{s=1hYj&A_rOL^k3__-5zIjv<&#T8+3l9JzMxYXi8vcy$>DJdbc{ICv` zaIcp5J>~^nTjIK~xJJ>vUd@Xu-CR3M+z8v!x}02>o0Hx2kzi!EgvHH@-mOv$F5Jix zfArVo$YDux^s@nmYl%C;;&w&uE-40T<h&-9xF>JG@Pf^09`GKthV!Q-?hA`QDN29N z8>okGi3jsYv86DnsSsEqi3xfH946!I$)T@|!+2qug$%)|hwFJv{G}YL=HnpHv@$Ej z?m>I={7xZCju#1wC&g2w2~We-ccfO%NvBh=t7ow;%~`y7;o@nP^~uU~d}Shom8Q}X z&qJk>h#oERBHo&s+uFk7WkunyQdCz~S5B_0WNoNSwO7JM5w>M2lc{WFrn`$`yLek= zB3U_iPGjvvOZ*K>FFIY4>PoaCsCh+-<AcN4Hn&mSkrl7$RW8fKYb2L{(15!;5TLyg z77web{-=McXEkTyJezxl#oG$w9mr2pD;L8O?;&W?D!ADs#Ob9<RF?RVCN#b_EIv|F z{WvT>P&7YP-ov#dYHEqk{3<^;5$|YQ9B;3hgh)qsdJUMfHot5865b4fX>)ZuHL6a> z+b!`mdpP=}NmgawNO8&k&sq7=^YtCg*Y{!Z1<OlH{~WlYv83sDb+xT)5q@=c)o0_K zRg<th_HS-oTb-ez>IBLxSqe36OQezfAQH8tg(+Hiz!FQA!)AcXtt}a*_&k~2eb=U} zCHseEiDDz-H-5c0OIG-2>3}ZE6y|m`uT;!nX^M1nS#>)K9d-u6nX6L5%vciXhn4Cg z=8#B8N<p#|5lN&Vc1w4nBb!K8XQ3|Dj@OdNNh)~ixzw9#ISLIL7A~ouTR*#YN&Uix zrUMq$)h?N1$sNLSpc>9jQVi7;*w3*gk+<l}$n1?BaZ)`s9IO-rS~s?K#Fcg_;f{rH zxsdQIIUd}%u4+zOasmRCDU&TZF)VjheZx*DsBtYoCvHhh-1d2u+O%RpiKwpiiKS(R zOPwj)BP@4SUG3>#o2V;~nkA6~S807=PP-GC1Wmx~6g>EbtQs$toltus*=9)uhC`q! zE>?A`LUSe*c}l1umBi?0k@Y9zVOhu4FX!MJtF|SPUG#NT4Z*A>>k;$iSmz=n6Jbx1 zT!JjZZtc!wQ=QZ!MxM-4XkbYs5K*rrH~&9@V_Q&rVAJg7v**ugYN%Z>r)mD2hJBaJ zvt%RsYl$~^B1LJ9XEOD5mOMZy{FKS0@XKh4jj!#FCtKrGiKu-<p%LetjXVfisG&Hb zv*b_1auy|Ud&s7++)K?zvlKi0pu{bSSl_ptv&B|T!ir6cTV1@Rd!;4Yp`-h%a38Bv zWn(<OE}pKgW!!0%mRtqwHbO-cORmN!tD7CuN2DLkD124KE>b3eLn%s@(v#t1ds|mz zms|@!CDU-+eoDD%z;fQd+E;1GbtpqNt`hWS<%l+fWn75|fqB#?9))m(-(c7UQUp{r z34uqICWAU!2e`Ttv8cD;lQa;^_g&Sja^^IGdwGl$W3;}=Y}*#4<LeTs?o4B%1$#d$ z-P~Gkg4O_cZX%t@^6F#BUm#p$C9vf2VR@9||3v@1d5l^T0r*I*w?*@3&r4;p)F~rX zO@gKB9*5b{`}-yM@9JoETUqkgC}@jkTGI)3nU?&m6tz@M6F^Z*c2&F*{ovW0tt3lr zP9!s2nvT<6Oj~7R{rowz8!KCpY-TFkF!WZ~?&)E9sv6Ciepi&wvn9{=Ycmk)n8^I* zmUxF6*JL=m{@`1yu;h7COrrt1T;}luHeuqe@yhjy>?%ZA?m#-5ySgwdmb?Io@l;D* z6qe^IPA>^aSL=@%vE*e^RO&O(OuL7O2InHTba+Lu(XUG{x8(1n7`sR>a(O1njvYTS z!<i{J8fVEXVL)y1_U7&mxRR?eqZ23AsQ<fpd0S0uM*@3OHI_t{5!TyV@;bOlN<8KD zVR?lb*^Tf&y>e~Io23|~qs*T@n<g};Ta&S-gfRzRu_bSnV!A#9K22bSNsvZ#b)+_` zNSEe-bSRzb=!j!g`y*DhNm$ix56d3K>7D)<0P^wrb7tUfDRwNt=+byPgC)nA1H=jg zTwa|TOa4iUna+nR|Nolf`@`~H#pwfu1*Y?1$%p)cZ;WRVeyntNwyGv02pFSzp1gW? zKeMojwuXGqqbgd?nR7!byRhAof1%YJJEhIZw(2f-&rCjnQY@C#omTo(SU#fIf5z`A z@_M%9bAGF=&8^ot?h!GJ*SIf$;~xRCBw@*y;oh{BPUCJXmd$mD9a<6{3GDmHzq4~% z7w<@Q(N3%-Uxf;0x?9LywKTVMz|SBf>DviINnkP95JzzF26<H8$&&v>FqKMHBY;Y- z1nS!`D+)lcfoI8gv8*k2GC51WkFTaCgkZFfBR^D&(!cy}cxiJ-H-~PP{1|K~^d!O? zYVxUS@^6^lz7(N+F2$1G(}dnOHi`%RVX;hpNh{`8VfliZ$p84gR)I;d<hOpWg>Wcu zzN;o9JR7IYWe~+Tm4<*a0;hUWYCXaQS0yaNfY7Mip|911!t#6O*eLZIMX)Q&u>3J4 zPzsEzYBEBZYCqEj(EN<|br^K)RAaCo!ct;gBcas}fTB&Tsqu8ih=z@FH6Gh<DutP~ zj6r^jqpaVRTh(NQAm+rH@s=?JFWKgmmN5+K>KL$P3=bRIsm?~`MKKx`%c%5MdMaBr z8G*r0nxwoM7LGe8co_pJ4F!$l*8M56fo!IH9T|ZN)Qz2ysK+<ZHil)4gLJSN2m^8| zV<-TbRytguK*^|<V$a?!qPIX%EHi4L_6FjB5}0s&gJobjDyeUv)YI5CZ0x9{11&CJ z8BbCKS2YF519_JdKCqH9yvlY;?lYDFX@sc2GLXC={-KzqS{3X?sYEK-o><w99dN8D zma#W*nsffoGHPM}YUQZr)yXnu!+}6M*jHNy5|v0T($9?<>bZp+I3$a#r6kR+$Uwdl zYJwvR8~bx=W6VbvO-&FOrGaoLMuRFxYEqWjm~35@PFV&Ll1OeJ$|Z|jWRe%7W-3=T zuZvf<CEDBL5IZ)SRO4hK!-J{h3Cv8i4CE`JPTK!7kgW7sJg2s<dSS!-<(9D=)4HIx zamk#;mVu<C9A_{Y+VFz^HGYa^mBhpelv{`>Kh&_WVUA@q1AW=z`XzH5Qmq(q<NVsC zsEX6B4l-G|Xk#Vm1|Re}GEevos7U;5tO*-a)iifPEY37rMv6C}k}6iCJ;8K)b1QbT z5r_4`7KHk=j5MU@^s1F2yNEdRua&L?eU;KcSvJ5Tn-a;eahRHu!!h2*I1*XoNDNA4 zl$L?apq!=10<er@fVDW@y3R5-g^jg}ZAAOn@5<-YGLGlOAgPkBOw|;qc7<lF9w#SZ zMCq)Xe;KDB&q11%fL3cOzkwJ(>c#=Noht*8exK%UWWP{^R?GNp*f>#fb-J<{r+3RZ z6WR?f=d8n&gBgTUQH_~67hA?TWc|+jd8DPO?lf{?%eVk(HjZ~G?%?`rRbv?!p~Vue zu#8JELOKIZ=iwl{E&&c=L*ojB{Kz>I*g957puHJ_@|9V}RcOJiTE;baWulgGE#|Bn zr&-1yV3=uS;@GglgxwG}&Q^oI3DWQeX&JYWa>SF3t*hc~-ITOdO+je3y*BQQS5?`K z!!0ng1#NPr)lTVcFp<1c%eVu|Z~$6a2DaGyc~i*wvT+Y&kt<5V@v3r!t5M%zRq_4E zmHoxJCJ%&-Th;gwcp}%-24oqJpdV~etMfd{SL)lUrXYkH96Yg^58Ey?{(_loOEj-c zA{|V$=HfKt2?&pThvVy?!sjaBIG@kplU4=i^Ep_%a;Q$h3(z;DW?8rSOPJ{P^=qoL zwDIlW{1sz&_G<LvzoFQ%)@&L^?qI)yk+p2>Lb~GEhEx6;p<@8mIw{L|z1(=5j*LpO zskY{gmVr1?HdzMZLkk<v?W97MfdDZ)dgJKM(QTvWjb1Ri(J~MunoXlI@gL#^&fYRU zLi&<`T73e|rn4m6c`y(HhMFLpu<^Na7hi;p$JCsB1=Yx#0L%CfdX3XL1Lo8+zGcV8 z$#>ZJp3l-vgj(fv(01U0`BhV}!1YZe)e#vjPNs?4R?5`a)Gf0FeA8Wt>UAn1vdl6_ zA+;U{x|vmpu9{Xl_QR=$*$2h-IZ8DP3B@uIAC-`LfpkBRh7qN!o$mo*)8LVqQLyQ- zWSKSy(ML|Ps-_??D?=-yZ<&Lom=Ap;v%+zQ$9p9bmP(JYY9&CNBl39&(ndOV=J13f zrAlWwm7_D2mWd!Kcc7c=cTsb8m1QDuk~Nk&90RGzq+9Wdn5k@{B50Y2kp`)J+uv}S zW$p-tC)oumsz3|bIUI^PM$J$<mC9P?SnU70BUAJ%+fuFFl&m0@GRLFY`ZShw%bb90 zk;jpT#slQ}1O7w=EQnE%8@J(vsFk)B+i}{m(K2@ln}d|-u{Q9rYmP_DgsU1<=%U6_ zbQ&~n_ZG<#%Am?jOcm}B&{?XvXSq4moCXEX#5>v{;`#6(!FvGH!{!WgFC6uoGvNXA zuO*e4`#_^-zyi8E;xjFC7UYGqJh~$w#YJQ54=QkxDWAslAWr>?6$P>)-%zF(qFtc7 z`htgv>Jo!lXU@S%qB%DVtE1}-<~-Oork=tdb3a~8)bXEXB4(q5D%xr>8{qRexa1>M za}lhR&;2IXse;95NypIYYl-@rtiCWyWvEjh2Z9i{RG%xzSLO~+&4ayfReuQFJco3& z$F7PFg#+MS5DMXO`em6d<Pw~-FolCVG9ijIEfdomc7p{~w+ae|Xt$A$d>YlkuDKc$ zo!eh`OFMw+ZL#xVv1KMf&nv6L?z-6pqw?*QyUo+IetMhaZfO>>ahbKub@(Fo6l;jY z5QtMyo>2vdk>gdn(dH2(Ieu^KZn4axct#L}lNc=XXkHJqD#%fde-6Lpi}Y3Tu@vLx zc0^U-aiGRls;Hd+Mw}fwReusJoda^qJO#rdmTTJ)dd^n+GM4#ENSsP7lj5*0%9<DP z=WjvE@olQ$bWAZ};_6cZ@sxQc@Dmv)pSH}i;Uj43m^_?-w{vTr3&y>gIVv$T&xiEA zLbxjMRL>KCA;}rraKwpaUW_j<S2HgqE#oc8#q8!Thl_w;v&`QCjpBbb=qoY*YBjF& z%C5$6oUBzL{hk)RT=Jv}uk*wSw_usq!vb)uPEm(t-U#;%j&4SuD6`BS^rGVSTrXS5 z|8oX0TTj&#@!K%fUM#PQ?tl~&e!ZIzsEWH#p@xuGaStk-anQ8TJv7zgPY^-c(Id;e zACv8d;4YqJK0va?I-;ca5TvOhWkul;5|N6QRl#E*f}jJ-V<Q)<(#Ih<j%M}3C!w>n z8pAF*=ymMiX;9FM6@_PM3|`nu@u!3SJmMvPg=+93x^%||&!Gxm1{IyQSFsfn<6kW; z^Y5UL#GEeXkQ*baZ?nu-F}<y+Zj!uZ{sZ%xOs%)fHy|WJRTlM6*av-C=Gzbtk##m` zEc0E^)WQbE)%(D5LK#)?AuN!C3CsKl3a~zvUX$rUh^S(MPbfz5R`vrM>s0Z-VN8W$ z0n7XxBFZ&@;W&i8#8{A~FTg1XwsQ&|Zt+Tj;dC<2U|eAetZ(C%S|UL!?(XGSV!jWX zUz`8ITS$Ut{(?>9=BJw5;_0#wg1tdJ>Ubj`f6an<VhL*QD!93_Xd|-{+*hGuuj%w~ zs3cTc9twpJD3+zWlWJ_c1vhK_%?b`H9O@G)#{wEc7>R@`>uZ86zktAeDATb`l`nur z8y9yclN79YJeP$AV7n6ZX=0La@Nff=Lw748Tj(dQ`OzZbp-VAY507}yrog3cKPTZ( zG*nR@ii8l~_Jh53G_^a|Z|Oc?eW7UN|LP_=MI6{sTpikuu2S;bP`c2^Z`;$=G=3XF zm&y2T6kP-3w;kvP7r*U9H?a6^G+of)x1H%C4!@0~>ofcoql+Q@R!w&^_^pPnHSpUc zx@5p_Q|Jx=zwJh+&-{ja0de)VCmmUG*>pPY<F~!&IE~--rsF4mtEJ-|ew$6lC;T>t zP9peiU)sv%w|d$l=C}Q6bCur~(9S2nEu>vOe)|b+1o2xV?XB?J0kogNZ_6mj=eOmQ z4)fbVl!WoyPbrDvw<e0I`K`Ht+2ypZEQEcmO8<O!c0uvdHMNWC9XAEVE#W}S#7_>Y zuys%nf58&umeWgwkW2m%eqkPV?hB&1S`DJB@iPUw1Yff%)funBfoKgJ_xeOKS<{i+ zP~&;IYURbMJCUT+IPa~nas=?41L0PC4Y{+LDHC^@xJykiuAkVo5lrWso_5=;EQC!r zJLkzzm0HgkL<k#jA+jC#>G}ArLqm6GOFYfl1zbGh$ksIr$U~K@g^UJ=v<Ws%tJ_jK z?&*lvCb5e04rNB{0GBvb$WWWuSy+^6K%zrn9BcTATgLpvO;>*6#wI^;!;+u48Ocvv zY2+s^B=Qrt)%b}!Y5c@JGJfKI6g}yJ5<hXXho87*!%tj+;U}(M@Dq0o_=&T6e&Upy zpEyJ2Cr(`XiStZ;;<S*TICkSFPHp&!vk-bh|I`!P`}~cKY<^;=lb_f+<R>=k_=){1 zeqx`8pV(WVCuQdRM4E_a4Dy0IffUyYQTB)^!^LG$`fjYOM_3i*F=LB}G{h>(t9!&i z*$}g+bg)}G*eQ*aQt=SCc!*ofG={mw!`xyfGTbd5?iTkUA|u`6k#2E06<4~&m2Pog zD&Em8-q9`YN5xfcag|%#pNhx0#bey!0aQHJEgtI@N2qwbTRh$^uJDLVj70|0$1a33 z1@hU=#Tka;8*$csyVz@a>}FA0eWU1<w~DpE$+$Q>262vea87h_#s+b&ba1YAaV7<E zZg6mJa&e{xake-(x4AgAL7clCoO@lIc|n{99Gr(-oCQIgxAOT}8pL_m!Fk`Mb4U>9 z-ww{_E>2qjM;Z#pmLV5uRS+raBH1odDu`6&B6*6kE{HVAMVjJL`dJWZnu|2UL5hmw zf><psR-1=)eGuz#7wbq5>$V`)NiNnY9@f1<tg~FKb3Cj^gIJfkSeJWP&jqn=a<Ojl zuwDyd-Q{B4<6*rQ#Cp)hdf3DIEQs~2i}k#R^=%OA8yD+47fX`8`>oR`bFhp)9u}E) z9@an?%XN8CSrx<@<znsN(F)qAv4_joCmvQqkXF*A)#YLRCWv*Mi*<sBbzKna3>WJx z59_WV*3B+fkB9YS5bI$V>roHu)gac_F4i|5*2lmK-6@vBHU4&a30{_)w(;E-v7~W% zC{}T3k0~2(73WnqnN5v3=V?|rgv^01A!EBAMQDmk$aU4mEu!s4dFb_617#?Ue;*f9 z@Gn+B{PYq_AfOCj0r~*S0eu1e0Q~_201-e1U?5-^U`N1Mz$Cy_KrLV%U;$t$;1EC? zU=<(*SO@qS;5Y#BaU0-Xz@vcY0Ivbw1AGSf7HpzV1l~ec0nmqR0Q?4U9RNRIl}`d* z1$-<7LSaeCfm+waBN!Kr?1)%odx$SqQP(5pO^BI2Vtz#f=AcKc=n;pUBesi0hI9R) zsBegojH<7XMMmVeY4^7oS)k1*E`tm9=%9atB|VrWygj~$14aNw0!D>0__q=~?<&kP zu^N#`StyC3RsK&&sg5(Q8$gN1)g6oMg#Ielfv<)bEdU!4twhL1)gTY=5l2m^IGWks z#6z7Ni;QL#e~}YK9@Zw0)MjDEB4Y?W1d+LdLC0!970kp=_{P+T(SR{Lm<min3x?qi zh7?Ouex}&Rb>)84QVxto#xXCa<aqg|5^+PU#2w9eM)@_Plz@$#Ayu3XWVR#lIIrSN z8Z2{Kp+<DJJMK+nW0>q^u}Dnokf>E$;C5K*b~qs)<suiQ%tgUd$;9dD64g^ftdvMz zhU(wZL`-B#Co=0K!5#tGB0SVkY6yiG(WI*kb0iz$ILK~1AO@HKs0K^~)Ig%ha~*~F zL`hUU5{pdMxMxMb*5%%l=oCizUrBUVtwWaRAKVT-iSEWId2;ZJYIi~@C<kRWlQCv; zRJ#Ip1MH6RBfEDrYM!G}Lt>FVHFkLXL5-TmDF3VRPuDsuqER#QQGyz^7om`j^sZ4e z^U!(<E8gCOR#2KstM-Hhrvat|W&kLKoC(+)QpHY*qg7uxTJ=OMGD{ml5v`idDE}*| z)@dD9+)3sgRI53J^TRTmOK1g!p;T)Y20j~52bcqx3n5^W$PvPs_}x4C+I6u=y~Yy@ z;eJ=sJ=5BcQT{6-z$xV1)BZ(y?JsEOq#m#zV1Mw4?JGz9d$4Z9$;y3V5sImFnK%lv zoSlF5vRDNIUMzu{)Eo@*O`$E~iRz{v@r(o+tcwT7A`5vy>|YTCV=;LFW7eC$q%^Qc zY_0e^ziy?lM$C&<AV5O?^g5jGA|~=CzFjXDi~J;yQOAWUMt3R1sDlAUr-g{qp&@2< z8pZ-%N5>+IxtptbfHXhMCft6mQ>^%i0&Xgb0m-VRZ5T&Fh&04Pz#_m;0E+=jc!{fn zPVA>I(6S7%&Q*Ge5TEOxgdj)iCA27F<I$PJ6P-CkEV3+5H2+s~2)P`{qej-`#6Cf} zK<YlN`5#OMA}fd*Nm$WN4`z&q{22L5w>NnZy&gs_!}o!J<$x7{gL|2lv|s9X>z_Pt zZ|Nm8E!YKi%>PO!)ar^wplv=OIpIY^#lN8UWHz5TW&@GK0(w=nSfqt9-uI7QQ&x;g zjaM0d6TS}xw0IF#Lm<M!j<v(}!B8f0T5t$)?&mA7pNju@2K+7As}x$S)lSF-T_tv# zK`#zy7m{|wou0l#nm|208H*&ir(7&&%QAKdm_jc!UClVkKavlkV6IGMMY0dD5zX1M zFTa#jkZWmNUTVvJ^x}nZYqWmYj|JUuht>@ZCm1u@a)6I$C$%7IuCu_HR2-%ji3Gk^ z1J(dK0G*HmP6Lz_WIsm=Z^j~B8h7M`Y&jSm@x*#kSgWz;N+DAEgJKxM@+h<AFn+OY zIovmfwAM9|wdF{+Yj1(dXkGgyW6Me=iwW4#M>b1MdJ#<*#IY7Y*(BvMS%?P5BaUbm zDbdKvSY*A%pAyYDmp@N58#Mm@3(>@w_2Q!0sC7+bD}qt+VOr0A$+&rjEvtQkL6!j{ zR|-!p3WO*}0L7LyXqKNF97&A}N>znu>mkVvfQ^8|0EYvP02~SF;>gL7Zp2Z%w_{Op zw8oAS@9z2Hjf!I!$!~z$pn6k#mv2=3T<e?#95BkL*rfGcOu{~^jEZBaNkJ(ovpgCS zIR@}^z$U=4kPeRFlypkYhigJy6e8&yPn48c_NG9_mbEOMT(%3O6LQ_zayEP>+`63W zxb^LTfE>op56VuaGDi(m2a58FX`xtXD45?U@fH<O6xG(2h>M5=@_5SKadH|Jr)s2V z)XMdt5(G*#QokfT5@B&tzsf^lZ)(f^lu9fEKTraXZ&qJt%FtJ-))(!+abD~6#nzzQ zr^EGW8X?6ssf*&eOrvx<;Zgcqoa;04P#mu3=eS0e?{UqkbdGCF>+38+vvPd}xjsiD zq_`$0qPULe0yvit>9D64zOlRD$8i{Uc9}@r=WG2jHP;70-Vt3)7cebNP7d$nd>n~i zsMAuIi*n5Ca=3_zX@aojVqn^GNsihj8Z{+}r8#1KG@)L~#QO9qiOceF97#ANNfMW9 z{Y8jcMQ#ow<ywDNFs<@je~u&$%<;ZiqosIXk>kCuM(awZ)i+10fcagOkK^#}kR;xb zU3lsjA!<7BVXePwm{vH~Uy%1}HCl@IgLAz1(`a4CwEAhZD0H*sA+8*>U0oG4p2WMd z$HOC@05}nFGT;=zseoSseg*h706VGTG{EVAGXQ4-&H|hRI2Ujp;C#RZfC~W^0WJYt z3b+h#Ip7MwX26wzs{mI6t^r&NxXue$SL6q*bWOrp$KJqBGr~xDHbi^_i-l57Tdq`& zGJ%2eGJrHQ7t7gl4a%L3bTQA15ToKoO|s;Y9behW^4ba`!kKQh+AWO=q=T5!I*yQ) zp`?^tdnBSIq?U(*shc&5J|t}Ox%*sEaSLOq)s<~rXSUm6mZsX}m3CO8qKBF(s?OS^ zIM}4JAzM;Y-aL%BTaZz4EBB=WdvZ?B7}u*Y!lj@L={NYx4RwpoA9bknx6$E`8oK=P zUbu5!pfqboJ{!0JGkYW8Ccw>rTL3+PTLD|V8UG|O<G2pv%=lO}<KhF1|8{1}H{-Nt z%`@&Kgt=`7o#kTle+Ln?C4v$s`-Jd#D)&ck*iE9!W4%gz9Or!i)0QU`>79}#=X4+{ z?q;rYnN{&-Gz+R3#G}Nh_Rep|_Z@&c0e7?5qR2jb^3qYdI^;-gKPQ?VjB)%)jROn4 zGf2gNEq}u*fIi)*Ix6mCUR9{7T+L~W1VeCBgQ&P4NVYr!6)1%gcpKSK@#nnu?%IW@ z*0ZAr7)L2TDP(S<*!6L0=L?{t;z5lpHOWQLIX!=fxl$oCsiwx&!_=IHqls4~ZAwf3 z1hL)+xF7Imzyp8>0S^HlMx=;~SOw(z7*VxlP_E|(<@y(G07d2cIFI1MLUMf~uYDo8 zKFK)$m0X|F$QG09)6CVy%vGLTpP}Zx$n`PE?=OJI0Z#yM0w<mVJPmjTa>cbaN3M4} z`nn1F`aDrBB-hQZTyv`Uf;IqBMO%9Mnp3zJc?4JS2zZq4!An%Ul-E8d*PLR#%s5J} zB!F$u*S~6HS!RD=)_uzfmKQHVP^@3$B55nd-+*PyYf<B_YqnIxw$h5?*Ym$K$zQOc z+Y;*|4Bo-P`pCWwX$<*u%{X46M#MnCIL7m_?(>+e7XU8;UIM%f_$y#5;BSDx175*o z;$~t2Bl!nWFEp83c(6X_^E$Kt1J36SAldRZv<^6*H}l%(CNrlC|74v1%1GYQ$QCn_ zx0$Oun5#S^d54<!VkG~7{9XsV0eBPePrzG%w*l`!uDIt}K(6l-)k1Q;FDTa!v;h=# zJ|FT3{#;0||H^A$NUk3-&VMD>k2SKz<oXG7RnYl-O3izb>-&)32Y?R&{{nmj_!#gB z;8VyIw`Lu=?&}1V7M#!L%+wf|ju%uu2AOb2KPtrdf(RB0G1}4Fm#Pwu-&>lW<oWZh zw+J1G#IYWh6T&@RgfU<A@gE+L9(@#RRv`LNn<t+`VqXBh1bhYfj~9VFl^=oN0<sdS zxgUgzJr&~`4D&nY!6#IT(^T+qIEC(<K(T|`rnvok5VYlAK|>2HC?F~<>V>f=`KLS~ z2BNvY72%2G>3ERMVmfFcRe<Z(Wm>E$$<%W`655J(ej|xk&VKGI=$&Jq*Z8Hxmap>* z_O*HYb~$z}-{cYu{Vjfppza;@hDyeAcfX?&F5TVxc~50W9{`nPEI(@4EUIH_F9E}W z@sVg?YtTZnMBaRfRjfh*AIvFY)jjgFY1pWG@cReR2wsjF*<K@1M&c{6x==Yywj$<~ zBY&szDf#8d+Npd-emQbxD#!Ncya^;C$Pt|J1t?p7fsqu}p6aGhQ)9*9sIP7+X=-G< zt!^r9YP2OSuhmUuO^q1H*Tia=x*)3B%BQ04nS6oiJLvlNbj$<5KhgwH@(Hz;rOvYq zPYcioP!8w|2(x|EBT;?QpV$D?ciTmtElRxGFF5z3vq2&Mq#<z$ddGEsWmkxsI0F_p zVE_>tKn01~bykKX$&gq4G0sXxi6FEaag<6h4HNV*gIf46E7Z*7yCb8dNY^=cM1tfi zPJC7+BlwI0a1RLAx19kR?>deng#iu<4lqo;P`L7=1~@n{!2a$4b7s0-V1T3~wh<}P zH4V@U7v&J<Ss6Kn0u(O(KQr>7)EP;`mdePD3N;?r$kiSnL^(_iN*Ouv#c`m|$cdQW z$hTLGl#x>-$C!t!a?-pB>@1w}5vp7nxrRSdl`A9H%15bk&B&?pe`@5Fs*ARKR(GIs z>MdaW)941H90V8)*bXoRFcdJ%d2WyAaKH$_NWdsSC13|O{Bgp-)wKeKoeUZ_{U%2l zwmi!@*dLF{8cob8J9MUXXi!ZdeOP~n2S&J<1Kzt>2Ld~L1PsjKQ4O{+0tEEK=beEy zmauFCuGtAcSe1C&%iX<@;}s4J$HgJ<;viym^AIQayPOtMee&&#PjIrqyiu>%2q4dn zG|#0-3heK-M&TfEaB&Lt3V)()Hp$VLf-!)d0b>E<0TTe#fEu2fDYzVSvNj9w<k*(- z`(*q8$@9r2gdpkXQfiVyM=0lHo`rEtCLaCXw~9Ojar&d26U>IDLs=EizA+XAIW{Up zRf|i&&aTv&92E<CJCy9^mT0rIJNFUX@sjtT!5*qo4@aGJ8fOpM(Sw{CKs3g)g3<w$ zcB~-x3?feO5cSg&IgK#M9`lYl<aDY~(wInbOph^%Q1o8lS8%F=$OBFqLd5M(dWStQ zqE_r|c5d=t2^xi=??oi2m9Kl=c9k;&<T<I{X8M(&kLA=k_$koAK2+%o@R?DYr@!#b zgNk?dv{}qV53`7f9+VbsEne4Kqv>pFs*DiZ*wau_$He@Rs&gydyMJNqhM9CXfH#Xh z&}{BDG*j0$a&hXu+~#w(bW&d)uR6b?^G^~CEDCPGtIRhp+}9;9<lBB;D#(FP2226q zHmKYUusdK6z*NAVfN6l~fEj?j05bu51NH&T0?Y=~0p<es1<YeFvK}{XZ^`o-@8o$6 zW54`@U-?@YkK`ekc7DOWc?Ix9__?O?M15(;41uTh3dFvMMK}gh^5Vd0m>budQ>?p~ zP{=cRk=+coLqvADz^9SvoZ?B_HfAbg)#Dq4gU~aDMD}VM`?yHn0fIarfJEyL`}o}E zmRuUZn&n~T0;&TE%a-RbTaIDVkd~|R%k#@uP&qpcH;Aocsu*hSh(jKvTH_=Jszp?l z11X?eQF%y?qO%;&RTMeODqRwbsMAj{)kLWNMPVLrfq^daiEq_ssD)ZGnj6bWCt;gb z62oyP>=PFRO3+6uvu^B1tRp^u0>W|j`jAYK+Y6zv$5;SygTZMfo5c;WNZ+BbpN(kU z#{Cc`3JKp>r1-K8I`Jj1R)+q(dL|~e2GNF=@ui1pPy%?329R#|24C?Ur<?|z9v2zA zZK$JO_a3P7Kd&!SK9|ObAtU1~9a{R}_p?BK6*Hcbqiv}3-A&U<Y=e$ohn7J42sJ?I zkaOfIXp->8sstgMW09~ch}BeSOQp%|a8bzuTtO1(HxvVd#LGZu4b!2@fT(QaVCovO zpstlHa1bavsEL#7NBW^9=K=2JEtSaQ3YALaF#tNF<x6a;q|7!B<q|j9cO2$saWsf` z_Qp?3fS(0uk}SlJd!_D&*zr2YDWps>CFQVrWS-c_DoNzIiTm!io6X%&x|SI(GIwpn zuy5`zLX$K%VU1=bmRW7?5cO(v$16jzxyv%0B6CN-)CtaAH#PY&bLVc<7^~d5(>G-{ zi_<W!b-nQuoIBE`^*@#$PnU}DL({o|i5Htrngwk-f3{g--%=jVW6<VirZzW6P^D*A zz0M61Klr>Nb5mFrM^Td>GdG?rirCdpF|MP3EOBq*3lazAW0-O=DU&=kDc^zywB~rp z_*WOBWD}D(g%>Q6s%@->mZ>$hKawi?O;?n5iQzKT)@WpaSNscV>~2Fx`m>t@K{)Qc z(dam?HQ=+b7;-IeQRseQQE-=eq<k*f&4O~(6EwECsf&p{Y!?$~Cn*N*QA7tQ2FPKY ztSTPPs|ZANj|ht976BFm8UafH2LNc(>_EVBzzV=YfI|RHfEGY2pbgOOysyF&_jD!h z=}O$wl^uXiKoXDwP~BQU8jt~G0o{Ogfc1b40IEA2a0K8;z)^ss0k~wy<<$Qsz_EZ| z0FDEk05}P7GDVT{JN(IjO<IKK?*AF1MVXg?szR^o8BrRn68I~MMVpu(3oF<J1d-X| z=Yz%TPAN(<bZMXp88ap!^lqTS<-FwD;$4;Q)l1z$MM;*f4OA&MN{<UvxNMZw7w@X< zvR>-$El%=TEv{!VSVwBJs#vlv4-_Go$6s7g!F)-71oPNQ4h@1moJRKGi_|l0=DtY% zbj|3LFHl#1U~{>^`3$x!$Epd7^K08sSASs0xp@6djUENVYVRgLUOy{<RVZFRo3MNX zpc_MQA-?z<;k+BA7l^5iPqmo(Ttd|X=z@WtafB22i5P@<9yPHIZ1Rx{LsaI3_lgW1 zYHT)s4ZI6{cq}8{NAU3SWA6*8fxG<B0!U$<8%70>a8zK0V;Ww4a!Kz+-jMQxeJ5hy zMT^)kW+t8U87(r8@ein+6B?qJTSC6S4}-fzwHu>^z^k=7qq$U7V5@|rqg7m{D!lzz z9z6z$=nOwRw~eDPk@`$%$96!$$qR1m0tN4M_QI0HJDt85N2_uizYv#v{&G3>R%~8> zuJCgKy~tolSNs5j$Nmt5d^EHz{B0Ip=x=lH{i%Z}Z3qE@6zh*qqritQ4>AdF$^TXs z+tfG>i^u7JGXQ4-&H|hbI0tYp;5@(ufC~W^0WNl)xQ!_<1zZNW9B>6-GvFNF)Hqp` z;s7hR_364ytc>|<4wep_*A!i(_6Rg!w`iUkXri2>`E|Yrg>S^)pmO%bUxjZh1)E1= zI{rY@;m@v5rWsecBldx!lnEE}KDmvKn+eGzKj$8s=n1{}I(IgT{Q<Qt=_Y=?<(%SP zFwnz1e#N$>T=S`5(Kc8$$rA;30bs!}G_qbd!@pIdq1^GWXqds)w!xS9@L%x39zm%_ zVGC1G8+iFQOby!9<)dbQc0$<zNygK`@4gP|Am5mif53#?0Js@&3!n#ZD_{%YX4WU1 zg5XC`1@uY(#Xl<sW*dKJOwG2j#+mJJz{}k{26A8Cw${0MvyE^P3ZY_RUUH1{fx+um zZnp2$kkpLO9Xm$KEtdB&lA1P>vu#`qB-^-@QGJW${Q=a=8TEHAs<y@TK%nm{8H<AB zT;~rGR&jlN0j`v<c|#}<5h{DuZPLi|(FCD2grtV%Y%E{R3@dL*3Kq~w+xR{6xm77A zHn?)y`3Tc<bc=HO+#2ZJ;54p7^Ty@a*tniwN^RptdhzWf(6Bva`+h`F*(TB-6_IxX z?g88jxDRkY-~qscfQJAN10JDoSMl&Wy8?>$S^+nMKWpbHUYOjBAt11)cz`~|`y-gw z-OSUBqAT9*z{pd)X9=n3w8Eo#S1_<$w(V|4)`7?8nE~C++zAGHb2GMaH?!zWsqSxH z&_<*D&An<g`EKP!Ml9l1?n4`LE4{cncm6SemjZqMIoD^Irfx6meUfRCx;cjt#)CiH zr>Dwp=W2(MCdX60@74#EkFP(<r=VC*1D*vu2Y4Rv0^mi!OMsUF&$^0N*yFufK=JTb z6dlF;3TlUqe1jIR*TB>5#^cK)gPlu3bXSW#HC-@bbE5lUv`@&VJB@THXfT%`=^w{0 zbSbDzy`ge<^=8?IA{FUl8_%k;a@%-bz4f(?7u8$XHeOb5{cK~adh2f+e^+k<Y~xk+ z7O{<gsJEzXyrJGI)V=b?<q=ysPrMDZ4f2h68)O^gbQ*6p-qbIXyoC|d9=3iA@itF* zCH#H`{yEAvfW+s1dUEp)kZgl)KRH>AlSR0foWxe!_!nyNOAtNLd6#H&xWKod@P|;; zF&cyq0(sW@F;REU`d~G5bBcD;e@?%{!a_p3>F+Zep8}Egj7d9f<1?^Jn~Ic@pagp? zi-7q7kyjYb@A?dCrp_K{S?V#qg#REl_>fSkC`23iVk=0Oy1UUzd5Kq;h`T+$7L90R zo<4t%zt5L{B&M9{YtYxX0B-}{0lW)%4}j~E64xaqu1oUwyR6d(ix9Rx3OLiN1Hqgd zFdE|u$A89*pc&w=ExKm#F3f=ZZ#{;BZ8G;(%iesBU_ua>No0^1qO;NU1tHOzuWmHE z=UQf|Le1T9mJq9&*gQ-tfcb5p<8rrSZB74<uxNU`KIu}DN^o;)`uBvz%H#fw(WJXZ zN(G#?+oUT+q*y%fhCxkiqsxmOSyNfRRhDN!a|z>w;uvt>gn?8Yxg9YXpwX8w6#I_N z_=4XPa>0fXCe&>YHgL{h^i%yK3NF?^HXn(@M~h%=7DMnO7f>QTa|+#olBjC=4YwpC zc0@x)V^mNj6}q<_1hk27o6Vv>MJ7K7d;$0p@Gamw!1q8g0F=>?4@R_MgaQ2kxCF%C zxS?iLurcflV>qUOF&HMgl4YST1Ak3H-)uw6AqDVplMsI}*Kz+X*!T$naU_N?godEf z8*@9Q_;l}wLkM^WeYC?Ebvz_to7)qrnr5;G4njOTq5D6MF`4QNb}L&A+=^|EV)fGs zc2ETfPQCEi7#`$mC*q0%1yIqs8WBVtO{lI9)p18L?ruDSop}U`;3nG~N1wRop~uJu zmI4Sz$9Jgu_LXSM$5B}y9s2u)yg_d4L<qJykd=snGZu&1hfv1Jf9oQWYcZO89>bhE z(-JE-Dqwltqf5+-%O&aP*dV1EqNJt`6EX>3KACD>TwR@<jK4EPY9)+efb9XeiDrxd zi~>{wb^z=I7!4Q$7>gUM_zUSu-}-FDA8UfX_IYyrt>*OcH<^2z=ACBkf(a1GY|}Jv zM1hoMG$OW```%>MheBLy+UEX^6L8xsGK_KX7uJCz2}g8>N?e=;jT1t)xsWhVjO@sm zB^u`OC6<f%6UGF7iETDEPAIj_0~#lk+2%58dv#<iw=LD$URhEWY+G?BH(gGRZi-Ce zMrB%~8@92-+agoBt);cyQm8}QJSf-Wy^&gO718;;yQI|5=TCWzO~m3uk$I|t&f^0m zp7=bW&}bGYRGp=_3ZlLrS*lR`XxzVB5cTuOAqurzL;ZJ-<7S?fR^~Vkj&b!S(xzJU z&9#t5C~u4_(W2shZeT}NsRm)KL9~|!V<IWlpr6*DDwH?d+{3kyeZ?QRn<<fXs#Slj z)udj!nGyM!YA`@+FfA16@6J|&$4>p=uPN{(uOW?;QyV8(w%OS@fdcCo9?;Sh9w=Ok zM;}`*#iQIdGkEm1<qAB)w%LtGKigc-+_vEl+p69pTJJ4Zq>tPCM)Y3s5{dD2?)z}= z8>Q&xNRWbo{0tBDeGDEb+{A>BjEd_OVf@0uwMcn*Zt`KZut?Y$=JJ%NxJ@BfXvimp zJfr*tBSQ;el*f~-A@DLs;O9iey{fUTH9l+G8ebk2kE+H4wZ@m0M7&v6U7yHZg8>W| z43rTA7BN8MKbZ${OH@3kNDb0R-L!3d+!GbAsm6n~#&>O7<A<Z-J=J(St?`37>rt{k zmB;WaX7>50_)Ik!qBVK8)RVYsg2{%&(Ga8j4Nbf=Vc$i?x2pM2t@$^FdpwPLH2Os4 z0M%qzu8C1rioe}LUS9ceXoTM78Qdj0hFUFPDubhPprW$9MrB~BH(f!#&*FwV;4lBG zhQqanqe^p%uFMSGV8rL}h~acF;`6xs3)EC!q*VP9rRtZlEI)}#<=`VDG}3#NMk4OW zu3+`u4AK>^GUcn7@-<8u3PwtFt)fgSh0)%CM<13v8SqW`>T8>~-~j`^6%QCNlrhrZ zHvfpn0NcEsN7)sX4QiAlHCB?Pk#JE~uux%;cQY&Zf>wYPOo+zHefR<^YBo-Y%HOE& zMrqw0SDLe)z{o)j-JQza{aJPQAhUi}R9>fORcf@(D2<f+S${Yu#YdUeUzpYtiq=zj zfc`UhK#J&wSbvT?=!wd^R0lg~9o$@spFlVYsF>9{ctK+pE|6sNSJlDanB=2T`J^Jb zqek-Kk{rob$a`YWp;NE%%)ibg-z1)mPZi0x6v=m(<Tp|Isv^0QM)GUTA-~7UbRyFP zuiy!Mmr*Ae@dt|JzZA)j@lax*xH2j~R+Ou9l+6k&Ct#g2cmw6na+JSNl)qAx(IrvF z@JPU510C!ZHMUb7jMh4sg57w^Lg>GMqar;dJ@nr$z^U?$X8rYC+sFLI{MM=60Z|~; z4!T{eUT&M;-5L@-A!AF(8ownJR>b;*`i1&C==8UG>3^jatG9#(DsnP3C^T5rmyAOa zgEU6Y9Y3LZ`>PpM?!yoD7k{tB`|knN5{Cw23*ZjGJpk<I@=xs_!}Cc1w%WvtfUSU6 z0dD}XT_N5Fd<6J609l;)2L0i|zsW-OCJ`9(Z;A%ui2#{@qEU%w6<{o20$>-wu7Ih4 z89kvP*Y|{m0fqxc0xAJJ0;&LG0Am5;0TTcd0lNSu19k=M4wwp<2ABbu3D^fP3s47` z3z!Gk4=^9l09XWA3|InK3OEq30&p<k5Wt~;mg^-+Nm9;fK862y$L~3-#9tufzxb^E z@#pJ{RjA)I6lk%fSc^M~Roqjo;{IY44;8C;tXPHmnOp&O)!m8$6)zSewY6BqtHmnb zC|2=yv5NPLReV&e;@`z8zARSpO_2&HJZ&)qMFJ}*QlWlySfB;|U~OSikzy4Ci&YFM zRx!L-MP;#ys$vymi&ac0R<TR5id~CUOf6P1qgcg0#VYEGRA5so3-dNY9U)vQ6C;Ef Zio@93>q9F;tLSCFP$IO3UNWJM{{zix7Ty2= literal 0 HcmV?d00001 diff --git a/silecs-codegen/src/xml/fesa/fesa_3_0_0/generateFesaDesign.py b/silecs-codegen/src/xml/fesa/fesa_3_0_0/generateFesaDesign.py new file mode 100644 index 0000000..9aa76a3 --- /dev/null +++ b/silecs-codegen/src/xml/fesa/fesa_3_0_0/generateFesaDesign.py @@ -0,0 +1,523 @@ +#!/usr/bin/python +# Copyright 2016 CERN and GSI +# +# 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 3 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, see <http://www.gnu.org/licenses/>. + +import fesa.fillFesaDesignBase + +import os +import sys +import time +import zlib +import glob +import re +import datetime +import socket + +import iecommon +import fesaTemplates +import iefiles + +from iecommon import * + +import libxml2 + + +class FESADesignGenerator3_0_0(object): + + #========================================================================= + # Sub-functions + #========================================================================= + + def isGSITemplate(self,parent): + if isChildElement(parent,"GSI-Status-Property"): + return True + if isChildElement(parent,"GSI-Init-Property"): + return True + return False + + + def getSilecsStringLength(self,register): + strlen = '64'# check if custom length exists for string, otherwise use default length (64) + if(register.hasProp('string-len')): + strlen = str(register.prop('string-len')) + return strlen + + def getOrCreateStringArrayType(self,fieldNode,register): + array2DNode = getOrCreateChildElement(fieldNode,'array2D') + fillAttributes(array2DNode, {'type': iecommon.getFesaDataType(register.prop('format'))}) + dim1Node = getOrCreateChildElement(array2DNode,'dim1') + dim2Node = getOrCreateChildElement(array2DNode,'dim2') + dim1Node.setContent(register.prop('array-dim1')) # first dimension is the dimension of the array + dim2Node.setContent(self.getSilecsStringLength(register)) # first dimension is the dimension of the array + return array2DNode + + def getOrCreateStringType(self,fieldNode,register): + stringNode = getOrCreateChildElement(fieldNode,'array') + fillAttributes(stringNode, {'type': iecommon.getFesaDataType(register.prop('format'))}) + dimNode = getOrCreateChildElement(stringNode,'dim') + dimNode.setContent(self.getSilecsStringLength(register)) # first dimension is the dimension of the array + return stringNode + + def getOrCreate2DArrayType(self,fieldNode,register): + array2DNode = getOrCreateChildElement(fieldNode,'array2D') + fillAttributes(array2DNode, {'type': iecommon.getFesaDataType(register.prop('format'))}) + dim1Node = getOrCreateChildElement(array2DNode,'dim1') + dim2Node = getOrCreateChildElement(array2DNode,'dim2') + dim1Node.setContent(register.prop('array-dim1')) + dim2Node.setContent(register.prop('array-dim2')) + return array2DNode + + def getOrCreateArrayType(self,fieldNode,register): + arrayNode = getOrCreateChildElement(fieldNode,'array') + fillAttributes(arrayNode, {'type': iecommon.getFesaDataType(register.prop('format'))}) + dimNode = getOrCreateChildElement(arrayNode,'dim') + dimNode.setContent(register.prop('array-dim1')) + return arrayNode + + def getOrCreateScalarType(self,fieldNode,scalarType): + scalarNode = getOrCreateChildElement(fieldNode,'scalar') + fillAttributes(scalarNode, {'type': iecommon.getFesaDataType(scalarType)}) + return scalarNode + + def getOrCreateStringTypeBase(self,fieldNode,register): + if(register.prop('array-dim2')) and int(register.prop('array-dim2')) > 1: + iecommon.logError('ERROR: In register '+register.prop('name')+' - 2D array of strings not supported in FESA.', True, {'errorlog': True}) + return null + elif (register.prop('array-dim1')) and int(register.prop('array-dim1')) > 1: + return self.getOrCreateStringArrayType(fieldNode,register) + else: + return self.getOrCreateStringType(fieldNode,register) + + def getOrCreateBaseType(self,fieldNode,register): + if (register.prop('array-dim2')) and int(register.prop('array-dim2')) > 1: + return self.getOrCreate2DArrayType(fieldNode,register) + elif (register.prop('array-dim1')) and int(register.prop('array-dim1')) > 1: + return self.getOrCreateArrayType(fieldNode,register) + else: + return self.getOrCreateScalarType(fieldNode,register.prop('format')) + + def getOrCreateType(self,fieldNode,register): + if(register.prop('format') == 'string'): + return self.getOrCreateStringTypeBase(fieldNode,register) + else: + return self.getOrCreateBaseType(fieldNode,register) + + def getOrCreateFieldRef(self,valueItemNode,FieldNameRef): + fieldRefNode = getOrCreateNamedChildElement(valueItemNode,'data-field-ref',FieldNameRef,'field-name-ref') + return fieldRefNode + + def getOrCreateAcqStampItem(self,fieldNode): + item = getOrCreateChildElement(fieldNode,'acq-stamp-item') + fillAttributes(item, {'direction': 'OUT', 'name': 'acqStamp'}) + scalar = getOrCreateChildElement(item,'scalar') + fillAttributes(scalar, {'type': 'int64_t'}) + return item + + def getOrCreateUpdateFlagItem(self,fieldNode): + item = getOrCreateChildElement(fieldNode,'update-flag-item') + fillAttributes(item, {'direction': 'OUT', 'name': 'updateFlags', 'optional': 'true'}) + scalar = getOrCreateChildElement(item,'builtin-type-scalar') + fillAttributes(scalar, {'data-type-name-ref': 'NOTIFICATION_UPDATE'}) + return item + + def getOrCreateCyleNameItem(self,fieldNode): + item = getOrCreateChildElement(fieldNode,'cycle-name-item') + fillAttributes(item, {'direction': 'OUT', 'name': 'cycleName', 'optional': 'true'}) + array = getOrCreateChildElement(item,'array') + fillAttributes(array, {'type': 'char'}) + dim = getOrCreateChildElement(array,'dim') + dim.setContent('32') + return item + + def getOrCreateCyleStampItem(self,fieldNode): + item = getOrCreateChildElement(fieldNode,'cycle-stamp-item') + fillAttributes(item, {'direction': 'OUT', 'name': 'cycleStamp', 'optional': 'true'}) + scalar = getOrCreateChildElement(item,'scalar') + fillAttributes(scalar, {'type': 'int64_t'}) + return item + + def getOrCreateAcquisitionContextItem(self,propertyNode): + item = propertyNode.xpathEval('acquisition-context-item') + if item != None: + return item + + item = getOrCreateChildElement(propertyNode,'acquisition-context-item') + item.setProp("direction","OUT") + acqStamp = getOrCreateChildElement(item,'acqStamp') + acqStamp.setProp("direction","OUT") + acqStamp.setProp("name","acqStampGSI") + acqStampScalar = getOrCreateChildElement(acqStamp,'scalar') + acqStampScalar.setProp('type','int64_t') + + cycleStamp = getOrCreateChildElement(item,'cycleStamp') + cycleStamp.setProp("direction","OUT") + cycleStamp.setProp("name","cycleStampGSI") + cycleStampScalar = getOrCreateChildElement(cycleStamp,'scalar') + cycleStampScalar.setProp('type','int64_t') + + cycleName = getOrCreateChildElement(item,'cycleName') + cycleName.setProp("direction","OUT") + cycleName.setProp("name","cycleNameGSI") + cycleNameArray = getOrCreateChildElement(cycleName,'array') + cycleNameArray.setProp('type','char') + cycleNameDim = getOrCreateChildElement(cycleNameArray,'custom-constant-dim') + cycleNameDim.setProp('constant-name-ref', 'MAX_CYCLE_NAME_LENGTH') + + beamProcessID = getOrCreateChildElement(item,'beamProcessID') + beamProcessID.setProp("direction","OUT") + beamProcessID.setProp("name","beamProcessID") + beamProcessIDScalar = getOrCreateChildElement(beamProcessID,'scalar') + beamProcessIDScalar.setProp('type','int32_t') + + sequenceID = getOrCreateChildElement(item,'sequenceID') + sequenceID.setProp("direction","OUT") + sequenceID.setProp("name","sequenceID") + sequenceIDScalar = getOrCreateChildElement(sequenceID,'scalar') + sequenceIDScalar.setProp('type','int32_t') + + fieldRef = getOrCreateChildElement(item,'acquisition-context-field-ref') + fieldRef.setProp("field-name-ref","acquisitionContext") + + def getOrCreateAction(self,propNode,name,type,actionsNode,implementation): + iecommon.logDebug('Generating Server-Action: ' + name, {'debuglog': True}) + action = getOrCreateChildElement(propNode,type +'-action') + if not isChildElement(action,'server-action-ref'): + actionSub = getOrCreateChildElement(action,'server-action-ref') + fillAttributes(actionSub, {'server-action-name-ref': name}) + finalName = action.xpathEval("server-action-ref")[0].prop('server-action-name-ref') # could be different from name if already exists + getActionNode = getOrCreateNamedChildElement(actionsNode,type + '-server-action',finalName) + fillAttributes(getActionNode, {'implementation': implementation}) + + def getOrCreateFieldNode(self,parent,register): #in order to place them before any GSI-specifc fields (order matters!) + iecommon.logDebug('Generating Data-Field for register: ' + register.prop('name'), {'debuglog': True}) + if( hasChildren(parent) ): + return getOrCreateNamedPreviousSiblingElement(parent,getFirstChild(parent),'field',register.prop('name')) + else: + return getOrCreateNamedChildElement(parent,'field',register.prop('name')) + + def getOrCreatePLCHostNameField(self,configurationNode): + fieldNode = getOrCreateNamedFirstChild(configurationNode,'field','plcHostName') + descriptionNode = getOrCreateChildElement(fieldNode,'description') + descriptionNode.setContent('Hostname of the PLC that contains the related SILECS class device') + array = getOrCreateChildElement(fieldNode,'array') + fillAttributes(array, {'type': 'char'}) + dim = getOrCreateChildElement(array,'dim') + dim.setContent('128') + return fieldNode + + def getOrCreatePLCDeviceLabelField(self,configurationNode): + fieldNode = getOrCreateNamedFirstChild(configurationNode,'field','plcDeviceLabel') + descriptionNode = getOrCreateChildElement(fieldNode,'description') + descriptionNode.setContent('Name of the related SILECS instance within the PLC mapping') + array = getOrCreateChildElement(fieldNode,'array') + fillAttributes(array, {'type': 'char'}) + dim = getOrCreateChildElement(array,'dim') + dim.setContent('128') + return fieldNode + + def getOrCreateParameterFileField(self,configurationNode): + fieldNode = getOrCreateNamedFirstChild(configurationNode,'field','parameterFile') + descriptionNode = getOrCreateChildElement(fieldNode,'description') + descriptionNode.setContent('ParameterFile of the PLC (*.silecsparam)') + array = getOrCreateChildElement(fieldNode,'array') + fillAttributes(array, {'type': 'char'}) + dim = getOrCreateChildElement(array,'dim') + defaultNode = getOrCreateChildElement(fieldNode,'default') + defaultNode.setContent('../../../generated/client/MyControllerName.silecsparam') + dim.setContent('512') + return fieldNode + + def getOrCreatePLCClassVersionField(self,configurationNode,plcClassVersion): + fieldNode = getOrCreateNamedFirstChild(configurationNode,'field','plcClassVersion') + descriptionNode = getOrCreateChildElement(fieldNode,'description') + descriptionNode.setContent('Version of the SILECS class that needs to be deployed in the controller') + array = getOrCreateChildElement(fieldNode,'array') + fillAttributes(array, {'type': 'char'}) + dim = getOrCreateChildElement(array,'dim') + defaultNode = getOrCreateChildElement(fieldNode,'default') + defaultNode.setContent(plcClassVersion) + dim.setContent(str(len(defaultNode.getContent()))) + return fieldNode + + def getOrCreateRegisterValueItems(self,prop,block,isSetting): + for register in block.xpathEval('Register'): + if register.prop('generateFesaValueItem') == 'true': + self.getOrCreateValueItem(prop,register,isSetting) + + def getOrCreateSettingProperty(self,parent,block): + iecommon.logDebug('Generating SettingProperty for Block: ' + block.prop('name'), {'debuglog': True}) + if( hasChildren(parent)): + propsAfterCommand = parent.xpathEval("*[not(name()='command-property')]") + prop = getOrCreateNamedPreviousSiblingElement(parent,propsAfterCommand[0], 'setting-property',block.prop('name')) + else: + prop = getOrCreateNamedChildElement(parent,'setting-property',block.prop('name')) + self.getOrCreateRegisterValueItems(prop,block,True) + self.getOrCreateUpdateFlagItem(prop) + self.getOrCreateCyleNameItem(prop) + return prop + + def getOrCreateAcquisitionProperty(self,parent,actionsNode,block): + iecommon.logDebug('Generating AcquisitionProperty for Block: ' + block.prop('name'), {'debuglog': True}) + prop = "" + if( hasChildren(parent)): + prop = getOrCreateNamedPreviousSiblingElement(parent,getFirstChild(parent), 'acquisition-property',block.prop('name')) + else: + prop = getOrCreateNamedChildElement(parent,'acquisition-property',block.prop('name')) + fillAttributes(prop, {'visibility': 'development', 'subscribable': 'true', 'multiplexed': 'false', 'on-change': 'true'}) + self.getOrCreateRegisterValueItems(prop,block,False) + self.getOrCreateAcqStampItem(prop) + self.getOrCreateUpdateFlagItem(prop) + self.getOrCreateCyleNameItem(prop) + self.getOrCreateCyleStampItem(prop) + self.getOrCreateAction(prop,'Get'+block.prop('name'),'get',actionsNode,'default') + return prop + + + def getOrCreateGSISettingProperty(self,parent,block): + iecommon.logDebug('Generating GSISettingProperty for Block: ' + block.prop('name'), {'debuglog': True}) + powerProp = parent.xpathEval('GSI-Power-Property')[0] # template is used --> there has to be a power prop + prop = getOrCreateNamedPreviousSiblingElement(parent,powerProp, 'GSI-Setting-Property',block.prop('name')) + self.getOrCreateRegisterValueItems(prop,block,True) + self.getOrCreateUpdateFlagItem(prop) + self.getOrCreateCyleNameItem(prop) + return prop + + def getOrCreateGSIAcquisitionProperty(self,parent,actionsNode,block): + iecommon.logDebug('Generating GSIAcquisitionProperty for Block: ' + block.prop('name'), {'debuglog': True}) + versionProp = parent.xpathEval('GSI-Version-Property')[0] # template is used --> there has to be a version prop + prop = getOrCreateNamedPreviousSiblingElement(parent,versionProp, 'GSI-Acquisition-Property',block.prop('name')) + fillAttributes(prop, {'visibility': 'development', 'subscribable': 'true', 'multiplexed': 'false', 'on-change': 'true'}) + self.getOrCreateRegisterValueItems(prop,block,False) + self.getOrCreateAcqStampItem(prop) + self.getOrCreateUpdateFlagItem(prop) + self.getOrCreateCyleNameItem(prop) + self.getOrCreateCyleStampItem(prop) + self.getOrCreateAction(prop,'Get'+block.prop('name'),'get',actionsNode,'default') + self.getOrCreateAcquisitionContextItem(prop) + return prop + + # propertyType only used during creation ! If named property already exists, it is just returned, no matter which type + def getOrCreateFESAProperty(self,parent,actionsNode,block): + properties = parent.xpathEval("*") + if self.isGSITemplate(parent): + if parent.get_name() == 'setting': + return self.getOrCreateGSISettingProperty(parent,block) + else: + return self.getOrCreateGSIAcquisitionProperty(parent,actionsNode,block) + else: + if parent.get_name() == 'setting': + return self.getOrCreateSettingProperty(parent,block) + else: + return self.getOrCreateAcquisitionProperty(parent,actionsNode,block) + + def getOrCreateValueItem(self,propertyNode,register,isSetting): + iecommon.logDebug('Generating ValueItem for Register: ' + register.prop('name'), {'debuglog': True}) + result = propertyNode.xpathEval("value-item[@name='" + register.prop('name') + "']") + if len(result): + return result[0] + if( hasChildren(propertyNode)): + result = propertyNode.xpathEval("*[not(name()='description') and not(name()='export') and not(name()='filter-item')]") # skip possible first elements to get right position + valueItemNode = getOrCreateNamedPreviousSiblingElement(propertyNode,result[0],'value-item',register.prop('name')) + else: + valueItemNode = getOrCreateNamedChildElement(propertyNode,'value-item',register.prop('name')) + if isSetting: + fillAttributes(valueItemNode, {'direction': 'INOUT'}) + else: + fillAttributes(valueItemNode, {'direction': 'OUT'}) + self.getOrCreateType(valueItemNode,register) + self.getOrCreateFieldRef(valueItemNode,register.prop('name')) + + #------------------------------------------------------------------------- + # Generates the data node of the FESA design document + # parsing the SILECS class document + #------------------------------------------------------------------------- + def genData(self,silecsRoot, doc,logTopics): + iecommon.logDebug("Creating data fields", logTopics) + + dataNode = doc.xpathEval('/equipment-model/data')[0] + iecommon.logError("len(dataNode)" + dataNode.get_name(), logTopics) + deviceDataNode = getOrCreateChildElement(dataNode,'device-data') + configurationNode = getOrCreateChildElement(deviceDataNode,'configuration') + settingNode = getOrCreateChildElement(deviceDataNode,'setting') + acquisitionNode = getOrCreateChildElement(deviceDataNode,'acquisition') + self.getOrCreatePLCHostNameField(configurationNode) + self.getOrCreatePLCDeviceLabelField(configurationNode) + classNode = silecsRoot.xpathEval('//SILECS-Class')[0] + self.getOrCreateParameterFileField(configurationNode) + # parse the SILECS design document to find the blocks + for block in silecsRoot.xpathEval("//Block"): # loop over the blocks + iecommon.logDebug('Analysing block '+block.prop('name'), logTopics) + # Check that every register in the block has the same value for synchro + regList = block.xpathEval("Register") + for r in range (0, len(regList)-1): + if regList[r].prop('synchro') != regList[r+1].prop('synchro'): + # Return error and exit + iecommon.logError('ERROR: In block '+block.prop('name')+' registers have different synchronisation values.', True, logTopics) + + if block.prop('mode') == 'READ-ONLY': + for reg in regList: + fieldNode = self.getOrCreateFieldNode(acquisitionNode,reg) + if reg.prop('synchro') == 'MASTER': # the value of a master register never change, consistency is not required + fillAttributes(fieldNode, {'multiplexed': 'false', 'persistent': 'false'}) + elif reg.prop('synchro') == 'NONE': + fillAttributes(fieldNode, {'multiplexed': 'false', 'persistent': 'false'}) + self.getOrCreateType(fieldNode,reg) + + elif block.prop('mode') == 'WRITE-ONLY': + for reg in regList: + fieldNode = self.getOrCreateFieldNode(settingNode,reg) + if reg.prop('synchro') == 'SLAVE': + fillAttributes(fieldNode, {'multiplexed': 'false', 'persistent': 'true', 'shared': 'true'}) + elif reg.prop('synchro') == 'NONE': + fillAttributes(fieldNode, {'multiplexed': 'false', 'persistent': 'false', 'shared': 'true'}) + self.getOrCreateType(fieldNode,reg) + + else: # READ-WRITE block + for reg in regList: + fieldNode = self.getOrCreateFieldNode(settingNode,reg) + if reg.prop('synchro') == 'NONE': + fillAttributes(fieldNode, {'multiplexed': 'false', 'persistent': 'false'}) + else: #synchro SLAVE and MASTER + fillAttributes(fieldNode, {'multiplexed': 'false', 'persistent': 'true'}) + self.getOrCreateType(fieldNode,reg) + + globalDataNode = getOrCreateChildElement(dataNode,'global-data') + globalConfigurationNode = "" + if len(globalDataNode.xpathEval("configuration")) == 0: + if len( globalDataNode.xpathEval("*")) == 0: + globalConfigurationNode = getOrCreateChildElement(globalDataNode,'configuration') + else: + globalConfigurationNode = getOrCreatePreviousSiblingElement(getFirstChild(globalDataNode),'configuration') + else: + globalConfigurationNode = globalDataNode.xpathEval("configuration")[0] + self.getOrCreatePLCClassVersionField(globalConfigurationNode,classNode.prop('version')) + + #------------------------------------------------------------------------- + # Generates the interface/device-interface node of the + # FESA design document parsing the SILECS class document + #------------------------------------------------------------------------- + def genDeviceInterface(self,silecsRoot, doc,logTopics): + # parse the FESA design document to find the device-interface node and create children + interfaceNode = doc.xpathEval('/equipment-model/interface')[0] + globalInterfaceNode = getOrCreateChildElement(interfaceNode,'global-interface') + deviceInterfaceNode = getOrCreatePreviousSiblingElement(globalInterfaceNode,'device-interface') + settingNode = getOrCreateChildElement(deviceInterfaceNode,'setting') + acquisitionNode = getOrCreateChildElement(deviceInterfaceNode,'acquisition') + actionsNode = doc.xpathEval('/equipment-model/actions')[0] + for block in silecsRoot.xpathEval("//Block"): + + if block.prop('generateFesaProperty') == 'false': + continue #skip this block + + if block.prop('mode') in ('READ-ONLY'): + self.getOrCreateFESAProperty(acquisitionNode,actionsNode,block) + rtAction = getOrCreateNamedChildElement(actionsNode,'rt-action','Recv'+block.prop('name')) + notifiedProperty = getOrCreateNamedChildElement(rtAction,'notified-property',block.prop('name'),'property-name-ref') + fillAttributes(notifiedProperty, {'automatic': 'true'}) + self.genEvent(block,doc,logTopics) + self.genSchedulingUnit(block,doc,logTopics) + else: # setting property for both WO and RW blocks, w/get+set server action + settingPropertyNode = self.getOrCreateFESAProperty(settingNode, actionsNode, block) + fillAttributes(settingPropertyNode, {'visibility': 'development', 'multiplexed': 'false'}) + self.getOrCreateAction(settingPropertyNode,'Send'+block.prop('name'),'set',actionsNode,'custom') + if block.prop('mode') == 'READ-WRITE': + self.getOrCreateAction(settingPropertyNode,'Recv'+block.prop('name'),'get',actionsNode,'custom') + else: # WRITE-ONLY + self.getOrCreateAction(settingPropertyNode,'Get'+block.prop('name'),'get',actionsNode,'default') + + #------------------------------------------------------------------------- + # Generates the logical-events node of the FESA design + # document parsing the SILECS class document + #------------------------------------------------------------------------- + def genEvent(self,block, fesaRoot,logTopics): + iecommon.logDebug('Generating event', logTopics) + eqpModelNode = fesaRoot.xpathEval("/equipment-model")[0] + eventsNode = getOrCreateChildElement(eqpModelNode,'events') + sourcesNode = getOrCreateChildElement(eventsNode,'sources') + timingSourceNode = getOrCreateNamedChildElement(sourcesNode,'timing-event-source','Timing') + timerSourceNode = getOrCreateNamedChildElement(sourcesNode,'timer-event-source','Timer') + logicalEventsNode = getOrCreateChildElement(eventsNode,'logical-events') + logicalEventNode = getOrCreateNamedChildElement(logicalEventsNode,'logical-event','Recv'+block.prop('name')+'Event') + fillAttributes(logicalEventNode, {'type': 'timer', 'use': 'required'}) + + #------------------------------------------------------------------------- + # Generates the scheduling-units node of the FESA design + # document parsing the SILECS class document + #------------------------------------------------------------------------- + def genSchedulingUnit(self,block, fesaRoot,logTopics): + iecommon.logDebug('Generating scheduling unit', logTopics) + eqpModelNode = fesaRoot.xpathEval("/equipment-model")[0] + schedulingUnitsNode = getOrCreateChildElement(eqpModelNode,'scheduling-units') + schedulingUnitNode = getOrCreateNamedChildElement(schedulingUnitsNode,'scheduling-unit','Recv'+block.prop('name')+'Unit') + rtActionRefNode = getOrCreateChildElement(schedulingUnitNode,'rt-action-ref') + fillAttributes(rtActionRefNode, {'rt-action-name-ref': 'Recv'+block.prop('name')}) + logicalEventRefNode = getOrCreateChildElement(schedulingUnitNode,'logical-event-ref') + fillAttributes(logicalEventRefNode, {'logical-event-name-ref': 'Recv'+block.prop('name')+'Event'}) + + #------------------------------------------------------------------------- + # Generates the scheduling-units node of the FESA design + # document parsing the SILECS class document + #------------------------------------------------------------------------- + def addDesignFileId(self,fesaDesignFile,logTopics): + nodeRequiringId = ['setting-property','acquisition-property','diagnostic-property', + 'value-item','update-flag-item','cycle-name-item', 'acq-stamp-item', + 'cycle-stamp-item','mode-item','host-item','port-item','config-item', + 'state-item','fwk-topic-item','custom-topic-item','device-trace-item', + 'bypass-action-item','diag-custom-topic','field','timing-event-source', + 'timer-event-source','logical-event'] + counter = 0 + now = datetime.datetime.today() + id = '_' + now.strftime('%y%m%d%H%M%S') + '_%s' + for nodeName in nodeRequiringId: + for node in fesaDesignFile.xpathEval("//" + nodeName): + if node.hasProp("id"): + node.setProp("id", id%counter) + counter = counter +1 + + + def fillXML(self,fesaVersion, className, fesaRoot, silecsRoot,logTopics={'errorlog': True}): + + #print etree.tostring(silecsRoot, pretty_print=True) + #------------------------------------------------------------------------- + # Fill section <information> + #------------------------------------------------------------------------- + informationNode = fesaRoot.xpathEval("/equipment-model/information")[0] + informationNode.xpathEval("class-name")[0].setContent(className) + informationNode.xpathEval("fesa-version")[0].setContent(fesaVersion) + + #------------------------------------------------------------------------- + # Fill section <ownership> + #------------------------------------------------------------------------- + creatorNode = fesaRoot.xpathEval("//ownership/creator")[0] + owner = silecsRoot.xpathEval('//Information/Owner')[0] + + creatorNode.setProp('login', owner.prop('user-login')) # == Owner in SILECS design document + + # Generate data fields + self.genData(silecsRoot, fesaRoot,logTopics) + + # Generate properties, Actions, Events, Scheduling Units + self.genDeviceInterface(silecsRoot, fesaRoot,logTopics) + + self.addDesignFileId(fesaRoot,logTopics) + return fesaRoot + +#------------------------------------------------------------------------- +# Fill the FESA design document - entry point of the plugin +#------------------------------------------------------------------------- +def fillDesignFile(fesaVersion, className, workspacePath,fesaDesignXSDPath,logTopics={'errorlog': True}): + generator = FESADesignGenerator3_0_0() + fesa.fillFesaDesignBase.fillDesignFileBase(generator,fesaVersion, className, workspacePath,fesaDesignXSDPath,logTopics) + diff --git a/silecs-codegen/src/xml/fesa/fesa_3_0_0/generateFesaDesign.pyc b/silecs-codegen/src/xml/fesa/fesa_3_0_0/generateFesaDesign.pyc new file mode 100644 index 0000000000000000000000000000000000000000..c272814d893e20e5e63cef311e1ec38afc8153a3 GIT binary patch literal 24100 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 literal 0 HcmV?d00001 diff --git a/silecs-codegen/src/xml/fesa/fesa_3_0_0/generateSourceCode$py.class b/silecs-codegen/src/xml/fesa/fesa_3_0_0/generateSourceCode$py.class new file mode 100644 index 0000000000000000000000000000000000000000..8770643814912b44ab3d8ba0d73eba6c05f8f7e1 GIT binary patch literal 22768 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 literal 0 HcmV?d00001 diff --git a/silecs-codegen/src/xml/fesa/fesa_3_0_0/generateSourceCode.py b/silecs-codegen/src/xml/fesa/fesa_3_0_0/generateSourceCode.py new file mode 100644 index 0000000..2b520a9 --- /dev/null +++ b/silecs-codegen/src/xml/fesa/fesa_3_0_0/generateSourceCode.py @@ -0,0 +1,356 @@ +#!/usr/bin/python +# Copyright 2016 CERN and GSI +# +# 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 3 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, see <http://www.gnu.org/licenses/>. + +import os +import sys +import time +import zlib +import glob +import re +import datetime +import socket + +import iecommon +import fesaTemplates +import iefiles + +from iecommon import * +import libxml2 + +def findBlockServerSetActionName(fesaRoot, blockName): + properties = fesaRoot.xpathEval("/equipment-model/interface/device-interface/*/*[@name='" + blockName + "']") + for property in properties: + return property.xpathEval("set-action/server-action-ref")[0].prop("server-action-name-ref") + raise Exception("Error: Server Action for Block '" + blockName + "' not found") + +#------------------------------------------------------------------------- +# Generates the H source file containing general methods +# to synchronise the FESA fields and related PLC registers +# of the FESA server +#------------------------------------------------------------------------- +def genHSource(className, silecsRoot, fesaRoot, sourcePath,logTopics): + source = fesaTemplates.genHTop(className) + + for block in silecsRoot.xpathEval('//Block'): + if block.prop('mode') == 'WRITE-ONLY' or block.prop('mode') == 'READ-WRITE': + serverActionName = findBlockServerSetActionName(fesaRoot,block.prop('name')) + source += fesaTemplates.genHTopBlock(className, serverActionName) + + source += fesaTemplates.genHTop2(className) + + for block in silecsRoot.xpathEval('//Block'): + if block.prop('mode') == 'READ-ONLY': + source += fesaTemplates.genHBlock('RO', block.prop('name')) + elif block.prop('mode') == 'WRITE-ONLY': + source += fesaTemplates.genHBlock('WO', block.prop('name')) + else: # READ-WRITE + source += fesaTemplates.genHBlock('RW', block.prop('name')) + + source += fesaTemplates.genHBottom(className) + + for block in silecsRoot.xpathEval('//Block'): + source += fesaTemplates.genHDeclBlocks(block.prop('name')) + + source += fesaTemplates.genHClosing(className) + + # Create output directory if necessary + if not os.path.exists(sourcePath): + os.makedirs(sourcePath) + iecommon.logDebug("Create directory %s" %sourcePath, logTopics) + + # Write to file and save + sourceFile = sourcePath + "/"+ className + ".h" + iecommon.logInfo("Generate header file: " + sourceFile, logTopics) + fdesc = open(sourceFile, "w") + fdesc.write(source) + fdesc.close() + + iecommon.logInfo('Header file for '+className+' generated successfully', logTopics) + +#------------------------------------------------------------------------- +# Generates the C++ source file containing general +# methods to synchronise the FESA fields and related PLC +# registers of the FESA server +#------------------------------------------------------------------------- +def genCppSource(className, silecsRoot, fesaRoot, sourcePath,logTopics): + finalSource = fesaTemplates.genCTop(className) + blockList = silecsRoot.xpathEval('//Block') + for block in blockList: + finalSource += fesaTemplates.genCGlobal(className, block.prop('name')) + + finalSource += fesaTemplates.genCPart1(className) + + for block in blockList: + finalSource += fesaTemplates.genCBlockConstr(block.prop('name'), className) + + finalSource += fesaTemplates.genCPart2(className) + + for block in blockList: + regList = block.xpathEval('Register') + if (block.prop('mode') == 'WRITE-ONLY' or block.prop('mode') == 'READ-WRITE') and regList[0].prop('synchro') == 'SLAVE': + # just set the fields if block is WO or RW and register synchronisation is SLAVE + # WARNING: In order to have multiplexed FESA fields, the corresponding SILECS registers' synchro mode must be 'NONE' + finalSource += fesaTemplates.genCSetPLC(className, block.prop('name')) + + finalSource += fesaTemplates.genCPart3(className) + + for block in blockList: + regList = block.xpathEval('Register') + if (block.prop('mode') == 'READ-ONLY' or block.prop('mode') == 'READ-WRITE') and regList[0].prop('synchro') == 'MASTER': + # just get the fields if block is RO or RW and register synchronisation is MASTER + # WARNING: In order to have multiplexed FESA fields, the corresponding SILECS registers' synchro mode must be 'NONE' + finalSource += fesaTemplates.genCGetPLC(className, block.prop('name')) + + finalSource += fesaTemplates.genCPart4(className) + + for block in blockList: + + source = '' #compute one source at a time + flagReg = False + flagDim1 = False + flagDim2 = False + + if block.prop('mode') != 'WRITE-ONLY': + finalSource += fesaTemplates.genCCommonGet(block.prop('name'),className) + + regList = block.xpathEval('Register') + source += fesaTemplates.cRecv + + for reg in regList: + type = reg.prop('format') + if type == 'string': # string register + flagReg = True + if (reg.prop('array-dim1')) and int(reg.prop('array-dim1')) > 1: # string array + flagDim1 = True + source += fesaTemplates.genCGetStringArrayReg(reg.prop('name')) + else: # simple string + source += fesaTemplates.genCGetStringReg(reg.prop('name')) + + else: # not string register + # uppercasing of type + fesaType = iecommon.getFesaDataType(type) + type = iecommon.getSilecsDataType(type) + if type[0] == 'u': + type = type[:2].upper() + type[2:] # first two characters if unsigned + + if reg.prop('array-dim2') and int(reg.prop('array-dim2')) > 1: # 2D array + flagReg = True + flagDim2 = True + flagDim1 = True + source += fesaTemplates.genCGetUnsignedArray2DReg(reg.prop('name'), fesaType, type) + elif (reg.prop('array-dim1')) and int(reg.prop('array-dim1')) > 1: # array + flagReg = True + flagDim1 = True + source += fesaTemplates.genCGetUnsignedArrayReg(reg.prop('name'), fesaType, type) + else: # scalar + source += fesaTemplates.genCGetScalarReg(reg.prop('name'), type) + + elif type[0] == 'd': # date type + if reg.prop('array-dim2') and int(reg.prop('array-dim2')) > 1: + flagReg = True + flagDim2 = True + flagDim1 = True + source += fesaTemplates.genCGetArray2DReg(reg.prop('name'), 'Date') + elif (reg.prop('array-dim1')) and int(reg.prop('array-dim1')) > 1: # array + flagReg = True + flagDim1 = True + source += fesaTemplates.genCGetArrayReg(reg.prop('name'), 'Date') + else: # scalar + source += fesaTemplates.genCGetScalarReg(reg.prop('name'), 'Date') + + else: + type = type[:1].upper() + type[1:] # only first character if not unsigned + if reg.prop('array-dim2') and int(reg.prop('array-dim2')) > 1: # 2D array + flagReg = True + flagDim2 = True + flagDim1 = True + source += fesaTemplates.genCGetArray2DReg(reg.prop('name'), type) + elif (reg.prop('array-dim1')) and int(reg.prop('array-dim1')) > 1: # array + flagReg = True + flagDim1 = True + source += fesaTemplates.genCGetArrayReg(reg.prop('name'), type) + else: # scalar + source += fesaTemplates.genCGetScalarReg(reg.prop('name'), type) + + source += '\n\t}' # closing bracket for block + + #Add data declatation on top if needed and append the final source + if flagReg == True: + finalSource += fesaTemplates.cRegVar + if flagDim1 == True: + finalSource += fesaTemplates.cGetArrayVar + if flagDim2 == True: + finalSource += fesaTemplates.cGetArray2DVar + + finalSource += '\n' + source + + source = '' #compute one source at a time + flagReg = False + flagDim1 = False + flagDim2 = False + + if block.prop('mode') != 'READ-ONLY': + finalSource += fesaTemplates.genCCommonSet(block.prop('name'),className) + + regList = block.xpathEval('Register') + + for reg in regList: + type = reg.prop('format') + if type == 'string': + flagReg = True + if (reg.prop('array-dim1')) and int(reg.prop('array-dim1')) > 1: # string array + flagDim1 = True + source += fesaTemplates.genCSetStringArrayReg(reg.prop('name')) + else: # simple string + source += fesaTemplates.genCSetStringReg(reg.prop('name')) + + else: # not string register + # uppercasing of type + type = iecommon.getSilecsDataType(type) + lowerType = type+'_t' # store lowercase type for unsigned registers (fesa type) + if type[0] == 'u': # unsigned type + type = type[:2].upper() + type[2:] # first two characters if unsigned + + if reg.prop('array-dim2') and int(reg.prop('array-dim2')) > 1: # 2D array + flagReg = True + flagDim2 = True + flagDim1 = True + source += fesaTemplates.genCSetUnsignedArray2DReg(reg.prop('name'), type) + elif (reg.prop('array-dim1')) and int(reg.prop('array-dim1')) > 1: # array + flagReg = True + flagDim1 = True + source += fesaTemplates.genCSetUnsignedArrayReg(reg.prop('name'), type) + else: # scalar + source += fesaTemplates.genCSetScalarUReg(reg.prop('name'), type, lowerType) + + else: # signed type + type = type[:1].upper() + type[1:] # only first character if not unsigned + if reg.prop('array-dim2') and int(reg.prop('array-dim2')) > 1: # 2D array + flagReg = True + flagDim2 = True + flagDim1 = True + source += fesaTemplates.genCSetArray2DReg(reg.prop('name'), type) + elif (reg.prop('array-dim1')) and int(reg.prop('array-dim1')) > 1: # array + flagReg = True + flagDim1 = True + source += fesaTemplates.genCSetArrayReg(reg.prop('name'), type) + else: # scalar + source += fesaTemplates.genCSetScalarReg(reg.prop('name'), type) + + source += fesaTemplates.cSend + source += '\n\t}' # closing bracket for block + + #Add data declatation on top if needed and append the final source + if flagReg == True: + finalSource += fesaTemplates.cRegVar + if flagDim1 == True: + finalSource += fesaTemplates.cSetArrayVar + if flagDim2 == True: + finalSource += fesaTemplates.cSetArray2DVar + + finalSource += '\n' + source + + source = '' #compute one source at a time + flagReg = False + flagDim1 = False + flagDim2 = False + + finalSource += fesaTemplates.genCDatatypeSet(block.prop('name'),className) + + regList = block.xpathEval('Register') + + for reg in regList: + type = reg.prop('format') + if type == 'string': + flagReg = True + if (reg.prop('array-dim1')) and int(reg.prop('array-dim1')) > 1: # string array + flagDim1 = True + source += fesaTemplates.genCSetStringArrayRegData(reg.prop('name')) + else: # simple string + source += fesaTemplates.genCSetStringRegData(reg.prop('name')) + + else: # not string register + # uppercasing of type + fesaType = iecommon.getFesaDataType(type) + type = iecommon.getSilecsDataType(type) + lowerType = type+'_t' # store lowercase type for unsigned registers (fesa type) + if type[0] == 'u': # unsigned type + type = type[:2].upper() + type[2:] # first two characters if unsigned + if reg.prop('array-dim2') and int(reg.prop('array-dim2')) > 1: # 2D array + flagReg = True + flagDim2 = True + flagDim1 = True + source += fesaTemplates.genCSetUnsignedArray2DRegData(reg.prop('name'), fesaType, type) + elif (reg.prop('array-dim1')) and int(reg.prop('array-dim1')) > 1: # array + flagReg = True + flagDim1 = True + source += fesaTemplates.genCSetUnsignedArrayRegData(reg.prop('name'), type) + else: # scalar + source += fesaTemplates.genCSetScalarURegData(reg.prop('name'), type, lowerType) + + else: # signed type + type = type[:1].upper() + type[1:] # only first character if not unsigned + if reg.prop('array-dim2') and int(reg.prop('array-dim2')) > 1: # 2D array + flagReg = True + flagDim2 = True + flagDim1 = True + source += fesaTemplates.genCSetArray2DRegData(reg.prop('name'), fesaType, type) + elif (reg.prop('array-dim1')) and int(reg.prop('array-dim1')) > 1: # array + flagReg = True + flagDim1 = True + source += fesaTemplates.genCSetArrayRegData(reg.prop('name'), type) + else: # scalar + source += fesaTemplates.genCSetScalarRegData(reg.prop('name'), type) + + source += fesaTemplates.cSend + source += '\n\t}' # closing bracket for block + + #Add data declatation on top if needed and append the final source + if flagReg == True: + finalSource += fesaTemplates.cRegVar + if flagDim1 == True: + finalSource += fesaTemplates.cSetArrayVar + if flagDim2 == True: + finalSource += fesaTemplates.cSetArray2DVar + + finalSource += '\n' + source + + finalSource += '\n}\n' # closing bracket for class + + # Write to file and save + sourceFile = sourcePath + "/" + className + ".cpp" + iecommon.logInfo("Generate source file: " + sourceFile, logTopics) + fdesc = open(sourceFile, "w") + fdesc.write(finalSource) + fdesc.close() + + iecommon.logInfo('Source file for '+className+' generated successfully', logTopics) + +def genCppFiles(className, workspacePath, silecsDesignFilePath,logTopics={'errorlog': True}): + fesaCommonDirectory = iefiles.getFesa3CommonDirectory(workspacePath,className) + iecommon.logInfo("fesaCommonDirectory:" + fesaCommonDirectory,logTopics) + + if not os.path.exists(fesaCommonDirectory ): + os.makedirs(fesaCommonDirectory) + + silecsDesignFilePath = iefiles.getSilecsDesignFilePath(workspacePath,className) + fesaDesignFilePath = workspacePath + "/" + className + "/src/" + className + ".design" + silecsRoot = libxml2.parseFile(silecsDesignFilePath) + fesaRoot = libxml2.parseFile(fesaDesignFilePath) + + genHSource(className, silecsRoot, fesaRoot, fesaCommonDirectory,logTopics) + genCppSource(className, silecsRoot, fesaRoot, fesaCommonDirectory,logTopics) + diff --git a/silecs-codegen/src/xml/fesa/fesa_3_0_0/generateSourceCode.pyc b/silecs-codegen/src/xml/fesa/fesa_3_0_0/generateSourceCode.pyc new file mode 100644 index 0000000000000000000000000000000000000000..72312939377bf0c7ddf22596a94ccba4eda959ba GIT binary patch literal 8950 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 literal 0 HcmV?d00001 diff --git a/silecs-codegen/src/xml/fesa/fesa_3_1_0/__init__.py b/silecs-codegen/src/xml/fesa/fesa_3_1_0/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/silecs-codegen/src/xml/fesa/fesa_3_1_0/__init__.pyc b/silecs-codegen/src/xml/fesa/fesa_3_1_0/__init__.pyc new file mode 100644 index 0000000000000000000000000000000000000000..c41cdca279065f08f99af77fa3a90e539f978239 GIT binary patch literal 188 zcmZ9Gy$ZrW5QI;#5W)9I6IZbnv9Pugv|Qq5HAn6z+(r^#(B4<^3EW637v`H`n%Vbf zF@K#87c%2b)b}cxDoSHc+0Yy_h53W9c0kel7@&%t;mQt#s?LT0F7(jFR7+D3=VBd` w<i1D(W2RX0odZZB=)Hp*OYsA4aE&WKw86HB%jVh6bZP5j`Ea}&{t=b=0@DUC+W-In literal 0 HcmV?d00001 diff --git a/silecs-codegen/src/xml/fesa/fesa_3_1_0/fillFESADeployUnit.py b/silecs-codegen/src/xml/fesa/fesa_3_1_0/fillFESADeployUnit.py new file mode 100644 index 0000000..b7282c5 --- /dev/null +++ b/silecs-codegen/src/xml/fesa/fesa_3_1_0/fillFESADeployUnit.py @@ -0,0 +1,23 @@ +#!/usr/bin/python +# Copyright 2016 CERN and GSI +# +# 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 3 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, see <http://www.gnu.org/licenses/>. + +import fesa.fillFesaDeployUnitBase +import fesa.fesa_3_0_0.fillFESADeployUnit + +def fillDeployUnit(fesaVersion, className, workspacePath,fesaDesignXSDPath,logTopics={'errorlog': True}): + generator = fesa.fesa_3_0_0.fillFESADeployUnit.FESADeployUnitGenerator3_0_0() # identical with FESA 3.0.0 + fesa.fillFesaDeployUnitBase.fillFesaDeployUnitBase(generator,fesaVersion, className, workspacePath,fesaDesignXSDPath,logTopics) + diff --git a/silecs-codegen/src/xml/fesa/fesa_3_1_0/fillFESADeployUnit.pyc b/silecs-codegen/src/xml/fesa/fesa_3_1_0/fillFESADeployUnit.pyc new file mode 100644 index 0000000000000000000000000000000000000000..530c9b58ca9f47424022f8dd69bcdb8da4b6fb3e GIT binary patch literal 807 zcmc&x%}yIJ5FT$fKp|8DAujES(_Vsus`i9X3xVFEiU6&+M2mMwEWGQ;V+4_wQ@Ha~ zJOHo43()Z<AwoO=*3RsBe!dxh^YpyB{MdZ>t6+NS{Qt>9l2yi^fGdD=F|(s!4+LNh zvIu@;HMkdW9*4Yc5_64y;nVR;Y@&148QWI@bb)1&<$#60v+|rPKu4f!Fb24*SDqMj z3}qckfKosiL0N+`hVcRjo~D}!uIwZM(1&i9NU2|*8oh75R<GsP!&Mt|blCmX#-XvJ z(?WaymECV$zp+4<dg~^2o3lE`oY(EAgh?3QuY@?q&d`yzh5y8NWm2L}nxkLk+l_Ts zG)xu#N&UdDP4nAGx?lY3wkvO_Vopx%P%El1`m-?-4nd{JvL%(xb6d!P%~4*Uk)#GU zx+tV6ZslvMCTW9;ntAF-PHkl~WK>B`$=lq>Fm<Jvp`Bh!zGr89IP#ylXNb(-zQG;} zG=o?d6VktgB!=6rFy1kB9QNb4UXwUsvXx2x+l>U|6L*cr4L0VF|2PJgc#hrNX4eMy M!uG1SH$)@)4`NW*`v3p{ literal 0 HcmV?d00001 diff --git a/silecs-codegen/src/xml/fesa/fesa_3_1_0/generateBuildEnvironment.py b/silecs-codegen/src/xml/fesa/fesa_3_1_0/generateBuildEnvironment.py new file mode 100644 index 0000000..b218687 --- /dev/null +++ b/silecs-codegen/src/xml/fesa/fesa_3_1_0/generateBuildEnvironment.py @@ -0,0 +1,26 @@ +#!/usr/bin/python +# Copyright 2016 CERN and GSI +# +# 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 3 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, see <http://www.gnu.org/licenses/>. + +import fesa.fesa_3_0_0.generateBuildEnvironment + +def genMakefileClass(projectPath, centralMakefilePath, logTopics={'errorlog': True} ): + return fesa.fesa_3_0_0.generateBuildEnvironment.genMakefileClass(projectPath, centralMakefilePath, logTopics ) + +def genMakefileDU(projectPath, silecsBasePath, snap7BasePath, logTopics={'errorlog': True}): + return fesa.fesa_3_0_0.generateBuildEnvironment.genMakefileDU(projectPath, silecsBasePath, snap7BasePath, logTopics ) + +def genCProjectFile(projectPath, logTopics={'errorlog': True}): + return fesa.fesa_3_0_0.generateBuildEnvironment.genCProjectFile(projectPath, logTopics ) diff --git a/silecs-codegen/src/xml/fesa/fesa_3_1_0/generateBuildEnvironment.pyc b/silecs-codegen/src/xml/fesa/fesa_3_1_0/generateBuildEnvironment.pyc new file mode 100644 index 0000000000000000000000000000000000000000..c4c494f04d2525beb82cbe58647bfc3b5808f19d GIT binary patch literal 1257 zcmd5+&2AGh5T4ylC=|+%A|a6a0DDOsgaj9aP(zV8P*qDSq+TN9oi<Cn_R4nJBIOqD zeK1bEN?)MNI2%#amMdNDjAzF7c;@qrf1Piv|LmWAQP6%J8s8E5kHkv)6PN-VBrr(; zQz%n-Rc7!bfrIR_sS{0|%cgELb=kw`{0@1mF6i3{cS%I&tkd>LWu!3iu_Ge?oLHc> z2~;Um8O#CZ3CvSiWaK8H*`1sh2WE%pWms>8@yqdWJPglBJwk&{2Hcuey4*I$m9wTs z6T;)=<R>}B!%E{wOYd_&KintQIQtD%*p*=tdZa7b;-p@!j`n+Gr@;4YQz@U50+IO{ zNkZAWwnj{Bjp8e6;nn1%GDc`~Do(7M`bH}3dpcS9el49Bt*mT`6twV8iPKsOPAoD? z>cw~{Zc1p-d@mRXj@GBdAW^I{b%`RRn<QKd={$o)=Py(X2Do5HMMPzTBszPA!2A7( zeZj87Lt@MDx1`4i4lnmcHm_HfVvQ`f0wu1xryO335)VwAW<-f6ucEX_|B25d+C=z_ zc9)g&fo?XB=rKaKCwVSzZmc%>*o}d&h3jm<Y}q`6o9ZmqMQph}H^W$R1tVIp=Rfxw crT^Co@o9Ne+j6Gy?Gw(IpPdJ3FY9H$0W>N-!~g&Q literal 0 HcmV?d00001 diff --git a/silecs-codegen/src/xml/fesa/fesa_3_1_0/generateFesaDesign.py b/silecs-codegen/src/xml/fesa/fesa_3_1_0/generateFesaDesign.py new file mode 100644 index 0000000..0d778a5 --- /dev/null +++ b/silecs-codegen/src/xml/fesa/fesa_3_1_0/generateFesaDesign.py @@ -0,0 +1,99 @@ +#!/usr/bin/python +# Copyright 2016 CERN and GSI +# +# 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 3 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, see <http://www.gnu.org/licenses/>. + +import fesa.fillFesaDesignBase +import fesa.fesa_3_0_0.generateFesaDesign + +from iecommon import * + +def fillDesignFile(fesaVersion, className, workspacePath,fesaDesignXSDPath,logTopics={'errorlog': True}): + generator = FESADesignGenerator3_1_0() + fesa.fillFesaDesignBase.fillDesignFileBase(generator,fesaVersion, className, workspacePath,fesaDesignXSDPath,logTopics) + +class FESADesignGenerator3_1_0(fesa.fesa_3_0_0.generateFesaDesign.FESADesignGenerator3_0_0): + + #overwrite 3_0_0 version + def getOrCreateAcquisitionContextItem(self,propertyNode): + items = propertyNode.xpathEval('acquisition-context-item') + if items: + return items[0] + + item = getOrCreateChildElement(propertyNode,'acquisition-context-item') + item.setProp("direction","OUT") + + processIndex = getOrCreateChildElement(item,'processIndex') + processIndex.setProp("direction","OUT") + processIndex.setProp("name","processIndex") + processIndex = getOrCreateChildElement(processIndex,'scalar') + processIndex.setProp('type','int32_t') + + sequenceIndex = getOrCreateChildElement(item,'sequenceIndex') + sequenceIndex.setProp("direction","OUT") + sequenceIndex.setProp("name","sequenceIndex") + sequenceIndex = getOrCreateChildElement(sequenceIndex,'scalar') + sequenceIndex.setProp('type','int32_t') + + chainIndex = getOrCreateChildElement(item,'chainIndex') + chainIndex.setProp("direction","OUT") + chainIndex.setProp("name","chainIndex") + chainIndex = getOrCreateChildElement(chainIndex,'scalar') + chainIndex.setProp('type','int32_t') + + eventNumber = getOrCreateChildElement(item,'eventNumber') + eventNumber.setProp("direction","OUT") + eventNumber.setProp("name","eventNumber") + eventNumber = getOrCreateChildElement(eventNumber,'scalar') + eventNumber.setProp('type','int32_t') + + timingGroupID = getOrCreateChildElement(item,'timingGroupID') + timingGroupID.setProp("direction","OUT") + timingGroupID.setProp("name","timingGroupID") + timingGroupID = getOrCreateChildElement(timingGroupID,'scalar') + timingGroupID.setProp('type','int32_t') + + acquisitionStamp = getOrCreateChildElement(item,'acquisitionStamp') + acquisitionStamp.setProp("direction","OUT") + acquisitionStamp.setProp("name","acquisitionStamp") + acquisitionStamp = getOrCreateChildElement(acquisitionStamp,'scalar') + acquisitionStamp.setProp('type','int64_t') + + eventStamp = getOrCreateChildElement(item,'eventStamp') + eventStamp.setProp("direction","OUT") + eventStamp.setProp("name","eventStamp") + eventStamp = getOrCreateChildElement(eventStamp,'scalar') + eventStamp.setProp('type','int64_t') + + processStartStamp = getOrCreateChildElement(item,'processStartStamp') + processStartStamp.setProp("direction","OUT") + processStartStamp.setProp("name","processStartStamp") + processStartStamp = getOrCreateChildElement(processStartStamp,'scalar') + processStartStamp.setProp('type','int64_t') + + sequenceStartStamp = getOrCreateChildElement(item,'sequenceStartStamp') + sequenceStartStamp.setProp("direction","OUT") + sequenceStartStamp.setProp("name","sequenceStartStamp") + sequenceStartStamp = getOrCreateChildElement(sequenceStartStamp,'scalar') + sequenceStartStamp.setProp('type','int64_t') + + chainStartStamp = getOrCreateChildElement(item,'chainStartStamp') + chainStartStamp.setProp("direction","OUT") + chainStartStamp.setProp("name","chainStartStamp") + chainStartStamp = getOrCreateChildElement(chainStartStamp,'scalar') + chainStartStamp.setProp('type','int64_t') + + fieldRef = getOrCreateChildElement(item,'acquisition-context-field-ref') + fieldRef.setProp("field-name-ref","acquisitionContext") + diff --git a/silecs-codegen/src/xml/fesa/fesa_3_1_0/generateFesaDesign.pyc b/silecs-codegen/src/xml/fesa/fesa_3_1_0/generateFesaDesign.pyc new file mode 100644 index 0000000000000000000000000000000000000000..7d001a3edfe56845c61b913a78345a261be6cbe5 GIT binary patch literal 2880 zcmd6pOLN;c5XYC)Tb69++4rHnRMV+Ux9Q~6=``^p<BO7^+&1-v!;p}LF&_#5CH4$` zvhV$B?N{j+Xm=MPEi>)0lgcKD1^)OE*aa8-<IiFL_wjGPM6mj`@%|%T`Xv@I{yT66 zaN?A8x2(Hx)_~)=1EL9W10KgsxOU*A1#t_61F{XW1F{P<9NLC!fGdDsPkIELjyedJ zf8lR3a<FQs_{wy#6iVeP$xove8Z;S_?%}1s#=<b>vPC1L3$g)43krb3fx?9X%_dy6 z!NG}7nLHUaY1oHY93D)c><cYVvu7d`Dm1xz6nqox8dA)J4$WPv$Rs&L!z!PKT2#%p z=};zunnyG_v#}ccvrt;*ndzY&C85@nFcoHq*4td2=|vcc7onM(J1f0qy`1iID~-Z6 zALk1hX=a?3QygIzaG`Uoc~PFGdFIXYRCupM;^}DqR%V%(WanP>sIkULMtYovN_(q% zl*a<8o>q}}o+cixn2UhD;H{o0ZWh0@xG<aeOmfN1+8<(zCYOQJb9@)?)!v~fKE+GZ zDn+?#uCd~RZ{rcsfGxZlcyU-$tYP>hZ?!82E-{WS<UMfk7Q67#)WKk*0yoZ;3zrz< z2E`ut9Bw&m;chfq+})%taI1S|w^s_5<Cg8*mUkiUt<(D4jhm}gqgfkitY8}Mc}uJ0 zb=n5g+ECzIu|D;cjWkv;4Gl}H<aOGBX&or=1-nJFHUe0|v`$H@<aOGRX<aC~HJY`N z#tNq4SUa~$UZ-s`tp`P~Mzc23Siv+*29{RIk+wwu?#7sIGp!Frzeck*(pbUreo3q3 zb=n=KZ9uV6qgfkitYF$kNvq^_+Fhm%pcvF>)<zmDm^LVBmAp>7$Fw07!y3)nNMi-l zh9#|%*J<~ewh6^1(;h(lkXmeB`~Y9QiKdhoMz5DrOM{tf9AWkn=VmO8NbzOF+(ua` zmP$m_Z|H@6{?oA;;C-R;NN9bO#W;d;K}Ok*5~7a6BvjmHE*8RYqR-5uZv(^GP>a_~ zkwwA|?c<1O9?Hy`luX4Nk(tRdeI*nRFfx_d=`)ot7f1VM8x?Dlo|-USl+Sql9X^AI zjIdplh*p!u24!q3<@s_VYt59Fcs4g}`ZH`>dtl|InG{JpR$``Yh9rxeKuvsLtPR?; zo*j_~*{SCXJPHopgo&Y0oC@<??I{r&u{W1Ve2|C~eZb4Y)8~cC7bBV)J5`HhR)%1K zF1natS~ql7Qrt9asOHlM|2`EDsGzLv)6;y4yZ<p2pHT5B6|_n|eR)~Fn7!vy=X0FT znp>XSY}1u5k8p`JX|1pTXUpk0J$K95rVIc6>zWNEeXaxnMLh_3;{`#Q$IApw|4Zz< zapHSBzxjNoU~4*e+l>*uAH3`6_}_W=W5?%B`UR@209E*Xup8{|y!(B?J4OooMZ!Dp wSS^K534+~01Us1Dh<^b5>t`80kf;7Xa3QbqdmGpvD4%GG`@k8vefM7TZwJJNEdT%j literal 0 HcmV?d00001 diff --git a/silecs-codegen/src/xml/fesa/fesa_3_1_0/generateSourceCode.py b/silecs-codegen/src/xml/fesa/fesa_3_1_0/generateSourceCode.py new file mode 100644 index 0000000..973222d --- /dev/null +++ b/silecs-codegen/src/xml/fesa/fesa_3_1_0/generateSourceCode.py @@ -0,0 +1,26 @@ +#!/usr/bin/python +# Copyright 2016 CERN and GSI +# +# 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 3 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, see <http://www.gnu.org/licenses/>. + +import fesa.fesa_3_0_0.generateSourceCode + +def genHSource(className, silecsRoot, fesaRoot, sourcePath,logTopics): + return fesa.fesa_3_0_0.generateSourceCode.genHSource(className, silecsRoot, fesaRoot, sourcePath,logTopics) + +def genCppSource(className, silecsRoot, fesaRoot, sourcePath,logTopics): + return fesa.fesa_3_0_0.generateSourceCode.genCppSource(className, silecsRoot, fesaRoot, sourcePath,logTopics) + +def genCppFiles(className, workspacePath, silecsDesignFilePath,logTopics={'errorlog': True}): + return fesa.fesa_3_0_0.generateSourceCode.genCppFiles(className, workspacePath, silecsDesignFilePath,logTopics) diff --git a/silecs-codegen/src/xml/fesa/fesa_3_1_0/generateSourceCode.pyc b/silecs-codegen/src/xml/fesa/fesa_3_1_0/generateSourceCode.pyc new file mode 100644 index 0000000000000000000000000000000000000000..be18ac5b144058ae10d08bb59f4f9b49c2d3fbd5 GIT binary patch literal 1243 zcmd5*ON-P%5UxB%optx%13?f3Pji{+5z&)~Fe07?>0J=^GQ>_h6E;bQt{!%Ux$WNl zZ65q1{sH}}6MQY6JggyAsZ@78`m3)$e?8dyGX3<<(D3B=zJ%~os1k2NCq%~yl__1o zNU6-Ck<lh0n^T$7vvNci2_27Q_u=FkBCBtBmSzM~L|h99KZFWcPN+($%4kQlOK6wU z4t7rGBg7}zvz$mHLDUD!Mc5mR)sxkHH4nG(ySA<MMX-l%>y2Hw(#BnIzv*2QsT{^o zrY@M5Mbq!#s<wu;b0ORq(#9XD!7<s}B5Yz{?bb)Gs|-)DMp3bYrHpGD*Q$+cta@*2 z#b$F_wXLe#Gj;0x33r9D)4tNQDLkveHs}*AD)vU5HMNq{MTL_+Ud`3zQ_Z@MIz!Dn z5Kf^e`Bz-EWYL1NmV{v+3WXP4_X~1bz}JGImhtK9q6Dxj#zF>q4>Dj8XK1~59>X%y zvxu}E3HJcT-w1b}|HigIQMrlG9+lT%3`a&rP{ILLeoQ%%<t{w^gkM>%)~!Uy!v6r6 zoa4Uq*OMpS&+rHi;oeMCf2(Gfxz|G??9&2!ypKnIYqjM3$%8Aq7;*T|8&_^?`{EXQ MVxj7OI?l$~ck=2nZ~y=R literal 0 HcmV?d00001 diff --git a/silecs-codegen/src/xml/fesa/fillDesignFileBase.pyc b/silecs-codegen/src/xml/fesa/fillDesignFileBase.pyc new file mode 100644 index 0000000000000000000000000000000000000000..c9cc01785e13bc088ade97fe807d1d1772beb942 GIT binary patch literal 1238 zcmcgrOK;Oa5T11(c|bvwv?*Nh1u2)-Hx3m-JlaY~r9w>w6*t%3Br9xh<k>W>l$^qU z<IE4?!Y|;Pb<zOsnJBxS_k8nt{NvX~^ZVuD=Y;0J6+B<#a2wY^ktRxsUZje?Df*%) z4XE3ZAXmqw%hHya?I-I{?%}NAyu;z2xEzr|hN6k0?a3O=0#Ys@vqBU61JS4JBBN*< zdOKa2KUb+etu6A`XtECbJin@mwA#|PO2!Ax6q$9J5l!plDr1dcoHl6ESh$)rL5-S# zLeB}*I?YyT+FbO5Ygt?J>S90{H6IANfNk6W07KnQ6BD2CG43OiWv1wdrs&x+kDaka z7#C@1$AvC=V1~P~bEUZ$IUODycHe}lX45Z1L|6JH!X)WAhfbkj#KLRDWfE}>(q5Io zTaejgI^hFf0gd&?*bVmiF+4rZ@xS&burJ`vyQVf7<+^bDAwLuEAAlAvk1WYz=8#*6 z3454Ory-A$L^JnBS$5rNz~Ps|=)~r^Eu28ba=Zr(UN#zenw_jxU%T!d$gv(ohi6Xa z9mXYVpNQbnTIXeHeg5ItM~qA3bVv5iN%y`6zp=BW6O)YpsUp&QJ^qt8*KPyeu`R#y zFit#Q?$JEHqU*eSAT0VU;6JlNldzM)?;_i6{*?@NtD3S8Rs5-7e{d_xlO-s{-+`O_ z#n>i_Dhi{4&2@C4vxt+y*c3&S6<5&>_T8%fZVslRxt!Qkg9yJYS9ummgGfkQuEN`x z_1^Hh0)ERQA2;s^9MuXo)l=2Nb4xu`_k*3Fr8a_-j=Us%Uqol+NS|&)Si=9$Gt|-i OWp2|^reAsF(CIf%d_P?P literal 0 HcmV?d00001 diff --git a/silecs-codegen/src/xml/fesa/fillFesaDeployUnitBase.py b/silecs-codegen/src/xml/fesa/fillFesaDeployUnitBase.py new file mode 100644 index 0000000..670bbe2 --- /dev/null +++ b/silecs-codegen/src/xml/fesa/fillFesaDeployUnitBase.py @@ -0,0 +1,35 @@ +#!/usr/bin/python +# Copyright 2016 CERN and GSI +# +# 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 3 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, see <http://www.gnu.org/licenses/>. + +import libxml2 +import os + +import iefiles +import iecommon + +def fillFesaDeployUnitBase(generator,workspacePath,deployName, deployUnitSchemaPath, fesaVersion, logTopics): + iecommon.logDebug("deployUnitSchemaPath: " + deployUnitSchemaPath, {'debuglog': True}) + iecommon.logDebug("fesaVersion: " + fesaVersion, {'debuglog': True}) + fesaDeployFile = iefiles.getFesaDeployFilePath(workspacePath,deployName) + silecsDeployFile = iefiles.getSilecsDeployFilePath(workspacePath,deployName) + if (not os.path.isfile(fesaDeployFile)): + raise Exception( "FESA DeployUnit Missing: " + fesaDeployFile ) + if (not os.path.isfile(silecsDeployFile)): + raise Exception( "SILECS Deploy File Missing: " + silecsDeployFile ) + fesaDeployParsed = libxml2.parseFile(fesaDeployFile) + silecsDeployParsed = libxml2.parseFile(silecsDeployFile) + generator.fillXML(fesaDeployParsed,silecsDeployParsed,deployName, deployUnitSchemaPath, fesaVersion, logTopics) + iefiles.saveXMLToFile(fesaDeployFile,fesaDeployParsed) diff --git a/silecs-codegen/src/xml/fesa/fillFesaDeployUnitBase.pyc b/silecs-codegen/src/xml/fesa/fillFesaDeployUnitBase.pyc new file mode 100644 index 0000000000000000000000000000000000000000..163e6d9a446a2fe47fb2b5aecb63317674631103 GIT binary patch literal 1254 zcmc&!OK;Oa5T13?Bz;jRg@UL=j=8j!IB=){0c|58wN(|DhjMf6ZL+HEwY(eJO74a7 z7x-cP6%HJ@z&GnOX$yDk>|}Pnd401hfB&&K_w?7dj}eWZ8T`M-GA|)w`~;m4^(VTZ zzPPe`)c3CR8ue=wd-N5~b&d);HDpk~@$5$psB>6NtSv0_6T$*UE<t6DR)>Ntl6my} z(jzg3YE;($f@-AdR3geFxL!2K!ZLHs(j?m;)g;xTvO$-E@)cy9r5IriT7}_@piICv zacf?8L$2lxw>eVt<5U+dvenjwT+C7l77J9O7IcrfpyzUiE*mI-&K5ZmFw??3gAUJP z-#mnjWuEBs_nERmG?Zz05Zd8p+qN8ZG#Vs&U>31CmL~il3!`+l**1@1>Fxw?+S`-x z_MS3EWdopVK!bO?J6pjRZ+BH9rw*MvaBwA*jC7jn%xzF=TcV_`13oN9((+L$d5mCV zA3z^S+eIH$QO?QT+SLjPu#e0w%mb#4%b2q-6IX^a;xLGI&LWvxaB`&*b##^{&m5A6 zg^^ssAqYr5?d@8ggb6=O=!cro4&NvjFp!xnLaPhsbgGLJlZR2&Av;xr-Val0S0>w= zbGP#Vt_|Ad#Z(S;t|DW3YK%@P+Pg5BTfCid>UY3IV!M3Hvod#JB`3@fnqQrUKh&x8 zk7VMTXn3l!%ulj2e?n=!s<@savp?1&9ZO8WH$~)QhCbK#d1~EB!_4(<XyitIZu#c@ z8|A|^k03}q!Mlw2zF2W<Ni2yq(c!N{k0;gR>(S%O(i1HBQcel|2UaaK@FLamD3P!3 MK{sqz5DOl!Kj#lQ4*&oF literal 0 HcmV?d00001 diff --git a/silecs-codegen/src/xml/fesa/fillFesaDesignBase.py b/silecs-codegen/src/xml/fesa/fillFesaDesignBase.py new file mode 100644 index 0000000..a7362e2 --- /dev/null +++ b/silecs-codegen/src/xml/fesa/fillFesaDesignBase.py @@ -0,0 +1,38 @@ +#!/usr/bin/python +# Copyright 2016 CERN and GSI +# +# 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 3 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, see <http://www.gnu.org/licenses/>. + +import iecommon +import iefiles +import libxml2 + +def fillDesignFileBase(generator, fesaVersion, className, workspacePath,fesaDesignXSDPath,logTopics={'errorlog': True}): + iecommon.logInfo("Filling information and ownership-attribute FESA design for FESA version %s " %fesaVersion, logTopics) + + silecsDesignFilePath = iefiles.getSilecsDesignFilePath(workspacePath,className) + fesaDesignFilePath = workspacePath + "/" + className + "/src/" + className + ".design" + iecommon.logInfo("silecsDesignFilePath:" + silecsDesignFilePath, logTopics) + iecommon.logInfo("fesaDesignFilePath:" + fesaDesignFilePath, logTopics) + + silecsDesignParsed = libxml2.parseFile(silecsDesignFilePath) + fesaDesignParsed = libxml2.parseFile(fesaDesignFilePath) + + fesaDesignParsed = generator.fillXML(fesaVersion, className, fesaDesignParsed, silecsDesignParsed) + + iecommon.logInfo("Filling design document: " + fesaDesignFilePath, logTopics) + iefiles.saveXMLToFile(fesaDesignFilePath,fesaDesignParsed) + + #fesaDesignFile.write(sys.stdout) + iecommon.logInfo('FESA design document for class '+ className +' filled successfully', logTopics) diff --git a/silecs-codegen/src/xml/fesa/fillFesaDesignBase.pyc b/silecs-codegen/src/xml/fesa/fillFesaDesignBase.pyc new file mode 100644 index 0000000000000000000000000000000000000000..b1cea04fffaf5bc477d302baeb32f9ad40347763 GIT binary patch literal 1285 zcmcgr&2G~`5T13?CM{Hy5*pxwFG#txmN;-|5#py*LMm0&R8aNi+M8rm+Z%Z{{gKjB zc?BMf7vLc{a)EEwN!p^GalGr<nfd1D%j}O|ON*Pozkf|=^33D=7K=BrrFa#c5FO2A zMMr9?59lbMfg)X_G@w^$jlRKL7fiQP2j2X_v+J4=by?anv;9O8EMm=JeZb<M*c^Nj zR?%3|>UfT>0#Ys@Q=>87K+c!*A|p>5=QeUx-#WD~8&muojpw1C;H#K`HLi7aGT!M* z(Pfidb!?Cv7ibIw+)+h9V;q}wRTurFy2h<YsLm_k=&P-=H3i#F7iJkjVYegw?(z=y zZIflD=!d50*)orvu|*gcX=u+1UGl&T*J9^Nb3Af7-2T{o7p9s`zX;)7oloH=pcfoE zg@6$Ykr9_k#0^O66@VW@W|QfJw|oR7)_buVZ15vkdYa>Z^-rOnmN&_o+GLdL!fk~7 zT&y<=nworNNftAQ+=5ToLx(yId6XoYxi`wPi;fI{p8}&3o9DK0QYxn56KL?V(ZFeT zZRq>jb?>OW!kFXpJbURD;5Up**3y@^NZ!NGJ8lUUj!!k@11na~z6bO*NRFK?-90!7 z2VW{Sz126d8|T`GIJ4ym597p><{nP`E6xtPTSBErp@{=KGzmND{w~Jd$}O;z<k6zO z>AxrKq;C0^cctt=M}A|>6Gat?(ZJ?9I@Vdl$>7WsMU)li(X8;bD)?HCxY0yTY^uS6 z9~bZ#2?vodw>=w(_c81B;YC$7EZ1Wq7C%<2QjTf`E9#kQ;rl>62%ZEjwOs4SFzyGk p$^GA#%Z^J%bWo1;zA$v%%75;siR7<yn~pO5M*dEg+U_g-g1`KmO2hyF literal 0 HcmV?d00001 diff --git a/silecs-codegen/src/xml/genduwrapper$py.class b/silecs-codegen/src/xml/genduwrapper$py.class new file mode 100644 index 0000000000000000000000000000000000000000..3688309a9ae1caa7040815610c39c07f7c6ab4dc GIT binary patch literal 13208 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 Yzk$rZ?c(3@@8x4X|AC*Ek0QVDFB6D}&Hw-a literal 0 HcmV?d00001 diff --git a/silecs-codegen/src/xml/genduwrapper.py b/silecs-codegen/src/xml/genduwrapper.py new file mode 100644 index 0000000..c42a32a --- /dev/null +++ b/silecs-codegen/src/xml/genduwrapper.py @@ -0,0 +1,144 @@ +#!/usr/bin/python +# Copyright 2016 CERN and GSI +# +# 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 3 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, see <http://www.gnu.org/licenses/>. + +import os +import sys +import libxml2 +from collections import namedtuple + +import iecommon +import iefiles +import genduwrappertemplate + +from iecommon import * + +#========================================================================= +# Sub-functions +#========================================================================= + +def extractBlockList(designDOM): + blockList = [] + for blockNode in designDOM.xpathEval("//Block"): + blockList.append([blockNode.prop("name"), blockNode.prop("mode")]) + return blockList + +def getRegisterList(designFile,blockName): + '''Return the list of register included in a given block. + for each register a the following tuple is returned: [name,format,dim1,dim2] + ''' + registerList = [] + dom = libxml2.parseFile(designFile) + blockNodeList = dom.xpathEval("//Block") + for blockNode in blockNodeList: + if blockNode.prop("name")==blockName: + break #after the loop blockNode will point to the good node + + registerNodeList=blockNode.xpathEval("Register") + for registerNode in registerNodeList: + name = registerNode.prop("name") + format = registerNode.prop("format") + dim1 = 1 + dim2 = 1 + try: + dim1 = int(registerNode.prop("array-dim1")) + except: + pass #use 1 as default dimention + try: + dim2 = int(registerNode.prop("array-dim2")) + except: + pass #use 1 as default dimention + registerList.append([name,format,dim1,dim2]) + return registerList + +def genClassHeader(workspacePath, deployName, classNode, funcGetSilecsDesignFilePath, funcGetDuDesignWrapperFile, logTopics): + designName = classNode.prop("silecs-design-name") + designVersion = classNode.prop("silecs-design-version") + designFile = funcGetSilecsDesignFilePath(workspacePath, designName) + designDOM = libxml2.parseFile(designFile) + if(not os.path.isfile(designFile)): + raise Exception("File not found: " + designFile) + blockList = extractBlockList(designDOM) + classDeclarations = "" + + #construct Block class + for [blockName,blockMode] in blockList: + registerList = getRegisterList(designFile,blockName) + registerInitializerList = genduwrappertemplate.getBlockInitializerList(registerList) + registerGetterSetter = genduwrappertemplate.getRegisterGetterSetter(blockName,blockMode,registerList) + registersDimentionsDeclaration = genduwrappertemplate.getRegistersDimetionsDeclaration(registerList) + registersDeclaration = genduwrappertemplate.getRegistersDeclaration(registerList) + classDeclarations += genduwrappertemplate.getBlockClass(blockName,registerInitializerList,registerGetterSetter,registersDimentionsDeclaration,registersDeclaration) + + blockGetters = "" + sendRecvBlocks = genduwrappertemplate.getDeviceSendRecvBlocks(blockList) + for [blockName,mode] in blockList: + registerList = getRegisterList(designFile,blockName) + blockGetters += genduwrappertemplate.getDeviceBlockGetterSetter(blockName, mode, registerList) + + classDeclarations += genduwrappertemplate.getDeviceClass(blockGetters,sendRecvBlocks) + + sendRecvBlocks = genduwrappertemplate.getControllerSendRecvBlocks(blockList) + classDeclarations = genduwrappertemplate.getDesignClass(designName, designVersion) + designWrapper = genduwrappertemplate.designFileTemplate.substitute({'designNameCapitalized' : iecommon.capitalizeString(designName),'designNameUpper' : designName.upper(),'classDeclarations' : classDeclarations}) + + designWrapperFile = funcGetDuDesignWrapperFile(workspacePath, deployName, designName) + fdesc = open(designWrapperFile, "w") + fdesc.write(designWrapper) + iecommon.logInfo('Generated Wrapper for Design %s'%(designName), logTopics) + fdesc.close() + +def genDuWrapperBase(deployFile,funcGetDuWrapperFile,workspacePath,funcGetSilecsDesignFilePath, funcGetDuDesignWrapperFile,deployName,deployVersion,logTopics={'errorlog': True}): + deployDOM = libxml2.parseFile(deployFile) + + for controllerNode in deployDOM.xpathEval("/SILECS-Deploy/Controller"): + controllerName = controllerNode.prop("host-name") + controllerDomain = "" # GSI-Hack - No Support for domains at GSI + deployCustomInclude = constructorBody = destructorBody = designGetters = designMemberDeclarations = "" + for classNode in controllerNode.xpathEval("SilecsDesign"): + designName = classNode.prop("silecs-design-name") + designNameCapitalized = iecommon.capitalizeString(designName) + genClassHeader(workspacePath, deployName, classNode, funcGetSilecsDesignFilePath, funcGetDuDesignWrapperFile, logTopics) + deployCustomInclude += genduwrappertemplate.deployIncludeTemplate.substitute({'designNameCapitalized' : designNameCapitalized}) + constructorBody += genduwrappertemplate.designAllocation.substitute({'designName' : designName,'designNameCapitalized' : designNameCapitalized}) + destructorBody += genduwrappertemplate.designDeallocation.substitute({'designName' : designName}) + designGetters += genduwrappertemplate.designGetterTemplate.substitute({'designName' : designName,'designNameCapitalized' : designNameCapitalized}) + designMemberDeclarations += genduwrappertemplate.deployUnitMembersDeclaration.substitute({'designName' : designName,'designNameCapitalized' : designNameCapitalized}) + + controllerCtor = deviceGetter = '' + for deviceNode in controllerNode.xpathEval("*/Device"): + deviceName = deviceNode.prop("device-name") + controllerCtor += genduwrappertemplate.controllerDeviceInit.substitute({'deviceName' : deviceName}) + deviceGetter += genduwrappertemplate.deviceGetterTemplate.substitute({'deviceName' : deviceName, 'deviceNameCapitalizedNoUndercore' : iecommon.capitalizeString(deviceName.replace("-","_"))}) + controllerClass = genduwrappertemplate.getControllerClass(controllerCtor,deviceGetter,controllerName, controllerDomain) + code = genduwrappertemplate.generateControllerFile(deployName,deployVersion,deployCustomInclude,constructorBody,destructorBody,designGetters,designMemberDeclarations,controllerClass) + + fdesc = open(funcGetDuWrapperFile(workspacePath, deployName, controllerNode.prop("host-name")) , "w") + fdesc.write(code) + iecommon.logInfo('Generated Wrapper for Controller %s'%(controllerNode.prop("host-name")), logTopics) + fdesc.close() + +def genDuWrapper(workspacePath,deployName,deployVersion,logTopics={'errorlog': True}): + deployFile = iefiles.getSilecsDeployFilePath(workspacePath, deployName) + funcGetDuWrapperFile = iefiles.getDuWrapperFile + + # Create output directory if necessary + sourcePath = iefiles.getDuWrapperSourceDirectory(workspacePath, deployName) + if not os.path.exists(sourcePath): + os.makedirs(sourcePath) + + genDuWrapperBase(deployFile,funcGetDuWrapperFile,workspacePath,iefiles.getSilecsDesignFilePath, iefiles.getDuDesignWrapperFile,deployName,deployVersion,logTopics) + + diff --git a/silecs-codegen/src/xml/genduwrapper.pyc b/silecs-codegen/src/xml/genduwrapper.pyc new file mode 100644 index 0000000000000000000000000000000000000000..83bc1fef2f702755849f066f3d1011abce281399 GIT binary patch literal 5869 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 aNn;6B;Zm?#(%;fTb-p@(W&WKDZ~hnUI)@Vg literal 0 HcmV?d00001 diff --git a/silecs-codegen/src/xml/genduwrappertemplate$py.class b/silecs-codegen/src/xml/genduwrappertemplate$py.class new file mode 100644 index 0000000000000000000000000000000000000000..f1f4e6e13353ad97f875afa4d3532672694f86e5 GIT binary patch literal 39006 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 Q7v~!LP`kuM(YXKr0EOV(-~a#s literal 0 HcmV?d00001 diff --git a/silecs-codegen/src/xml/genduwrappertemplate.py b/silecs-codegen/src/xml/genduwrappertemplate.py new file mode 100644 index 0000000..8f58149 --- /dev/null +++ b/silecs-codegen/src/xml/genduwrappertemplate.py @@ -0,0 +1,740 @@ +#!/usr/bin/python +# Copyright 2016 CERN and GSI +# +# 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 3 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, see <http://www.gnu.org/licenses/>. + +import string +import iecommon + +#================================================================= +# Deploy Unit Class +#================================================================= +deployUnitFileTemplate = string.Template("""/* Copyright CERN 2015 + * + * WARNING: This code is automatically generated from your SILECS deploy unit document. + * You should never modify the content of this file as it would break consistency. + * Furthermore, any changes will be overwritten in the next code generation. + * Any modification shall be done using the SILECS development environment + * and regenerating this source code. + */ + +#ifndef ${deployNameUpper}_H_ +#define ${deployNameUpper}_H_ + +#include <silecs-communication/interface/equipment/SilecsCluster.h> +#include <silecs-communication/wrapper/DeployUnit.h> +#include <silecs-communication/wrapper/Design.h> + +${deployCustomInclude} +namespace ${deployNameCapitalized} +{ + +typedef SilecsWrapper::DeployConfig DeployConfig; +typedef SilecsWrapper::DesignConfig DesignConfig; + +class DeployUnit : public SilecsWrapper::DeployUnit +{ +public: + + /*! + * \\brief Use this method to create/get the unique instance of the Deploy Unit. + * + * \param logTopics This parameter can be used to enable/disable log topics + * valid topics are ERROR[,INFO,DEBUG,SETUP,ALLOC,RECV,SEND,COMM,DATA,LOCK]. + * + * \param globalConfig This parameter can be used to pass different parameters to + * the library. I.e. enabling automatic connection. + */ + static DeployUnit* getInstance(const std::string& logTopics = "", + const SilecsWrapper::DeployConfig& globalConfig = SilecsWrapper::DeployConfig()) + { + if (_instance == NULL) + { + _instance = new DeployUnit(logTopics, globalConfig); + } + else + { + if (logTopics.empty() == false) + { + _instance->getService()->setLogTopics(logTopics); + } + } + return dynamic_cast<DeployUnit*>(_instance); + } + + /*! + * \\brief Use this method to create/get the unique instance of the Deploy Unit. + * + * \param globalConfig This parameter can be used to pass different parameters to + * the library. I.e. enabling automatic connection. + */ + static DeployUnit* getInstance(const SilecsWrapper::DeployConfig& globalConfig) + { + return getInstance("", globalConfig); + } + +${designGetters}\ +private: + +${designMemberDeclarations}\ + + DeployUnit(const std::string& logTopics, const SilecsWrapper::DeployConfig& globalConfig) : + SilecsWrapper::DeployUnit("${deployNameCapitalized}", "${deployVersion}", logTopics, globalConfig) + { +${constructorBody}\ + } + + ~DeployUnit() + { +${destructorBody}\ + } +}; + +${controllerClass} + +} /* namespace ${deployNameCapitalized} */ + +#endif /* ${deployNameUpper}_H_ */ +""") + +deployIncludeTemplate = string.Template("""\ +#include "${designNameCapitalized}.h" +""") + +designGetterTemplate = string.Template("""\ + /*! + * \\brief Return pointer to the deployed design ${designName}. + */ + ${designNameCapitalized}::Design* get${designNameCapitalized}() + { + return _${designName}; + } + +""") + +designAllocation = string.Template("""\ + // Construct Design ${designNameCapitalized} + _${designName} = new ${designNameCapitalized}::Design((SilecsWrapper::DeployUnit*) this); + +""") + +designDeallocation = string.Template("""\ + delete _${designName}; +""") + +deployUnitMembersDeclaration = string.Template("""\ + ${designNameCapitalized}::Design* _${designName}; +""") + +def generateControllerFile(deployName, deployVersion, deployCustomInclude, constructorBody, destructorBody, designGetters, designMemberDeclarations, controllerClass): + deployMapping = {'deployVersion' : deployVersion, + 'deployNameCapitalized' : iecommon.capitalizeString(deployName), + 'deployNameUpper' : deployName.upper(), + 'deployCustomInclude' : deployCustomInclude, + 'constructorBody' : constructorBody, + 'destructorBody' : destructorBody, + 'designGetters' : designGetters, + 'designMemberDeclarations' : designMemberDeclarations, + 'controllerClass' : controllerClass + } + return deployUnitFileTemplate.substitute(deployMapping) + +#================================================================= +# Design Class +#================================================================= + +designFileTemplate = string.Template("""/* Copyright CERN 2015 + * + * WARNING: This code is automatically generated from your SILECS deploy unit document. + * You should never modify the content of this file as it would break consistency. + * Furthermore, any changes will be overwritten in the next code generation. + * Any modification shall be done using the SILECS development environment + * and regenerating this source code. + */ + +#ifndef ${designNameUpper}_H_ +#define ${designNameUpper}_H_ + +#include <silecs-communication/wrapper/Block.h> +#include <silecs-communication/wrapper/DeployUnit.h> +#include <silecs-communication/wrapper/Design.h> +#include <silecs-communication/wrapper/Device.h> + +namespace ${designNameCapitalized} +{ + +${classDeclarations} +} /* namespace ${designNameCapitalized} */ + +#endif /* ${designNameUpper}_H_ */ +""") + +designClassTemplate = string.Template(""" +class Design : public SilecsWrapper::Design +{ +public: + + Design(SilecsWrapper::DeployUnit *deployUnit) : + SilecsWrapper::Design("${designNameCapitalized}", "${designVersion}", deployUnit) + { + } + + ~Design() + { + } +}; +""") + +def getDesignClass(designName,designVersion): + text = "" + designClassmap = {'designName' : designName, + 'designNameCapitalized' : iecommon.capitalizeString(designName), + 'designVersion' : designVersion} + return designClassTemplate.substitute(designClassmap) + +designControllerInit = string.Template(""" + _controllerMap.insert( + std::pair<std::string, Controller*>("${controllerName}", + new Controller("${controllerName}", "${controllerDomain}", this))); +""") + +designReceiveTemplate = string.Template("""\ + /*! + * \\brief Receive ${blockName} blocks from all connected controllers. + */ + void receive${blockNameCapitalized}AllControllers() + { + _silecsCluster->recv("${blockName}"); + } + +""") + +designSendTemplate = string.Template("""\ + /*! + * \\brief Send ${blockName} blocks to all connected controllers. + */ + void send${blockNameCapitalized}AllControllers() + { + _silecsCluster->send("${blockName}"); + } + +""") + +def getDesignSendRecvBlocks(blockList): + text = "" + for [blockName,mode] in blockList: + map = {'blockName' : blockName, + 'blockNameCapitalized' : iecommon.capitalizeString(blockName)} + if mode == 'READ-ONLY' or mode == 'READ-WRITE': + text += designReceiveTemplate.substitute(map) + if mode == 'WRITE-ONLY' or mode == 'READ-WRITE': + text += designSendTemplate.substitute(map) + return text + +#================================================================= +# Controller Class +#================================================================= + +controllerClassTemplate = string.Template(""" +class Controller : public SilecsWrapper::Controller +{ +public: + Controller(SilecsWrapper::Design *design, const std::string parameterFile) : + SilecsWrapper::Controller("${controllerName}", "${controllerDomain}", design, parameterFile) + { +${constructorBody}\ + } + + ~Controller() + { + map<std::string, SilecsWrapper::Device*>::iterator it; + for (it = _deviceMap.begin(); it != _deviceMap.end(); it++) + { + delete it->second; + } + } + + /*! + * \\brief Return pointer to the requested device. + * \param label Device label. + */ + SilecsWrapper::Device* getDevice(const std::string& label) + { + if (_deviceMap.find(label) != _deviceMap.end()) + { + return _deviceMap[label]; + } + throw Silecs::SilecsException(__FILE__, __LINE__, Silecs::PARAM_UNKNOWN_DEVICE_NAME, label); + } + + std::map<std::string, SilecsWrapper::Device*>& getDeviceMap() + { + return _deviceMap; + } + +${deviceGetter}\ +private: + std::map<std::string, SilecsWrapper::Device*> _deviceMap; +}; +""") + +def getControllerClass(constructorBody,deviceGetter,controllerName,controllerDomain): + text = "" + designClassmap = {'constructorBody' : constructorBody, + 'deviceGetter' : deviceGetter, + 'controllerName' : controllerName, + 'controllerDomain' : controllerDomain} + return controllerClassTemplate.substitute(designClassmap) + +controllerDeviceInit = string.Template("""\ + _deviceMap.insert(std::pair<std::string, SilecsWrapper::Device*>("${deviceName}", new SilecsWrapper::Device("${deviceName}", this))); +""") + +deviceGetterTemplate = string.Template("""\ + /*! + * \\brief Get pointer to device ${deviceName}. + */ + SilecsWrapper::Device* get${deviceNameCapitalizedNoUndercore}() + { + return _deviceMap["${deviceName}"]; + } + +""") + +controllerReceiveTemplate = string.Template("""\ + /*! + * \\brief Receive ${blockName} blocks from all devices of current controller. + */ + void receive${blockNameCapitalized}AllDevices() + { + _silecsPLC->recv("${blockName}"); + } + +""") + +controllerSendTemplate = string.Template("""\ + /*! + * \\brief Send ${blockName} blocks to all devices of current controller. + */ + void send${blockNameCapitalized}AllDevices() + { + _silecsPLC->send("${blockName}"); + } + +""") + +def getControllerSendRecvBlocks(blockList): + text = "" + for [blockName,mode] in blockList: + map = {'blockName' : blockName, + 'blockNameCapitalized' : iecommon.capitalizeString(blockName)} + if mode == 'READ-ONLY' or mode == 'READ-WRITE': + text += controllerReceiveTemplate.substitute(map) + if mode == 'WRITE-ONLY' or mode == 'READ-WRITE': + text += controllerSendTemplate.substitute(map) + return text + +#================================================================= +# Device Class +#================================================================= + +deviceClassTemplate = string.Template("""\ +class Device : public SilecsWrapper::Device +{ +public: + Device(const std::string& label, SilecsWrapper::Controller *controller) : + SilecsWrapper::Device(label, controller) + { + } + + ~Device() + { + } + +${blockGetter} +${sendRecvBlocks} +}; +""") + +def getDeviceClass(blockGetter,sendRecvBlocks): + text = "" + designClassmap = {'blockGetter' : blockGetter, + 'sendRecvBlocks' : sendRecvBlocks} + return deviceClassTemplate.substitute(designClassmap) + + +blockGetterTemplate = string.Template("""\ + /*! + * \\brief Get ${blockName} block. + * \param block ${blockNameCapitalized} reference where to store returned value. + */ + void get${blockNameCapitalized}(${blockNameCapitalized} &block) + { +${blockInitialization}\ + } + +""") + +blockSetterTemplate = string.Template("""\ + /*! + * \\brief Set ${blockName} block. + * \param block ${blockNameCapitalized} reference from where value are copied. + */ + void set${blockNameCapitalized}(${blockNameCapitalized} &block) + { +${blockInitialization}\ + } + +""") + +matrixRegisterAssignementGetter = string.Template("""\ + // Copy register ${regName} + ${cType} *__${regName} = new ${cType}[block.${regName}Dim1 * block.${regName}Dim2]; + getSilecsDevice()->getRegister("${regName}")->getVal${silecsTypeCapitalized}Array2D(__${regName}, block.${regName}Dim1, block.${regName}Dim2); + block.set${regNameCapitalized}(__${regName}); + delete[] __${regName}; +""") +arrayRegisterAssignementGetter = string.Template("""\ + // Copy register ${regName} + ${cType} *__${regName} = new ${cType}[block.${regName}Dim1]; + getSilecsDevice()->getRegister("${regName}")->getVal${silecsTypeCapitalized}Array(__${regName}, block.${regName}Dim1); + block.set${regNameCapitalized}(__${regName}); + delete[] __${regName}; +""") +scalarRegisterAssignementGetter = string.Template("""\ + // Copy register ${regName} + block.set${regNameCapitalized}(getSilecsDevice()->getRegister("${regName}")->getVal${silecsTypeCapitalized}()); +""") + +matrixRegisterAssignementSetter = string.Template("""\ + // Copy register ${regName} + ${cType} *__${regName} = new ${cType}[block.${regName}Dim1 * block.${regName}Dim2]; + block.get${regNameCapitalized}(__${regName}); + getSilecsDevice()->getRegister("${regName}")->setVal${silecsTypeCapitalized}Array2D(__${regName}, block.${regName}Dim1, block.${regName}Dim2); + delete[] __${regName}; +""") +arrayRegisterAssignementSetter = string.Template("""\ + // Copy register ${regName} + ${cType} *__${regName} = new ${cType}[block.${regName}Dim1]; + block.get${regNameCapitalized}(__${regName}); + getSilecsDevice()->getRegister("${regName}")->setVal${silecsTypeCapitalized}Array(__${regName}, block.${regName}Dim1); + delete[] __${regName}; +""") +scalarRegisterAssignementSetter = string.Template("""\ + // Copy register ${regName} + getSilecsDevice()->getRegister("${regName}")->setVal${silecsTypeCapitalized}(block.get${regNameCapitalized}()); +""") + +def getDeviceBlockGetterSetter(blockName, blockMode, registerList): + text = "" + if blockMode == 'READ-ONLY' or blockMode == 'READ-WRITE': + blockInitialization = "" + for [name,format,dim1,dim2] in registerList: + silecsType = iecommon.getSilecsDataType(format) + if silecsType[0] == 'u': + silecsTypeCapitalized = silecsType[:2].upper() + silecsType[2:] + else: + silecsTypeCapitalized = iecommon.capitalizeString(silecsType) + + map = {'regName' : name, + 'regNameCapitalized' : iecommon.capitalizeString(name), + 'silecsTypeCapitalized' : silecsTypeCapitalized, + 'cType' : iecommon.getCDataType(format)} + if dim2 > 1: + #matrix + blockInitialization += matrixRegisterAssignementGetter.substitute(map) + elif dim1 > 1: + #array + blockInitialization += arrayRegisterAssignementGetter.substitute(map) + else: + #scalar + blockInitialization += scalarRegisterAssignementGetter.substitute(map) + + blockMap = {'blockName' : blockName, + 'blockInitialization' : blockInitialization, + 'blockNameCapitalized' : iecommon.capitalizeString(blockName)} + text += blockGetterTemplate.substitute(blockMap) + if blockMode == 'WRITE-ONLY' or blockMode == 'READ-WRITE': + blockInitialization = "" + for [name,format,dim1,dim2] in registerList: + silecsType = iecommon.getSilecsDataType(format) + if silecsType[0] == 'u': + silecsTypeCapitalized = silecsType[:2].upper() + silecsType[2:] + else: + silecsTypeCapitalized = iecommon.capitalizeString(silecsType) + + map = {'regName' : name, + 'regNameCapitalized' : iecommon.capitalizeString(name), + 'silecsTypeCapitalized' : silecsTypeCapitalized, + 'cType' : iecommon.getCDataType(format)} + if dim2 > 1: + #matrix + blockInitialization += matrixRegisterAssignementSetter.substitute(map) + elif dim1 > 1: + #array + blockInitialization += arrayRegisterAssignementSetter.substitute(map) + else: + #scalar + blockInitialization += scalarRegisterAssignementSetter.substitute(map) + + blockMap = {'blockName' : blockName, + 'blockInitialization' : blockInitialization, + 'blockNameCapitalized' : iecommon.capitalizeString(blockName)} + text += blockSetterTemplate.substitute(blockMap) + return text + +deviceReceiveTemplate = string.Template("""\ + /*! + * \\brief Receive ${blockName} block for current device. + */ + void receive${blockNameCapitalized}() + { + _silecsDevice->recv("${blockName}"); + } + +""") + +deviceSendTemplate = string.Template("""\ + /*! + * \\brief Send ${blockName} blocks to current device. + */ + void send${blockNameCapitalized}() + { + _silecsDevice->send("${blockName}"); + } + +""") + +def getDeviceSendRecvBlocks(blockList): + text = "" + for [blockName,mode] in blockList: + map = {'blockName' : blockName, + 'blockNameCapitalized' : iecommon.capitalizeString(blockName)} + if mode == 'READ-ONLY' or mode == 'READ-WRITE': + text += deviceReceiveTemplate.substitute(map) + if mode == 'WRITE-ONLY' or mode == 'READ-WRITE': + text += deviceSendTemplate.substitute(map) + return text + +#================================================================= +# Block Class +#================================================================= + +blockClassTemplate = string.Template(""" +class ${blockNameCapitalized} : public SilecsWrapper::Block +{ +public: + /*! + * \\brief ${blockName} constructor. It creates an empty block. + */ + ${blockNameCapitalized}() : + SilecsWrapper::Block("${blockName}")${registerInitializerList} + { + } + + ~${blockNameCapitalized}() + { + } +${registerGetterSetter}\ +${registersDimentionsDeclaration}\ +private: +${registersDeclaration} +}; +""") + +def getBlockClass(blockName,registerInitializerList,registerGetterSetter,registersDimentionsDeclaration,registersDeclaration): + map = {'blockName' : blockName, + 'registerInitializerList' : registerInitializerList, + 'blockNameCapitalized' : iecommon.capitalizeString(blockName), + 'registerGetterSetter' : registerGetterSetter, + 'registersDimentionsDeclaration' : registersDimentionsDeclaration, + 'registersDeclaration' : registersDeclaration} + return blockClassTemplate.substitute(map) + +registerInitializerListTemplate = string.Template("""\ +, + ${registerName}(0)""") + +def getBlockInitializerList(regList): + text = "" + for [name,format,dim1,dim2] in regList: + if format != 'string' and dim1 == 1 and dim2 == 1: + text += registerInitializerListTemplate.substitute({'registerName' : name}) + return text + + +matrixRegisterGetterTemplate = string.Template(""" + /*! + * \\brief Get 2D array ${registerName} register. + * \param value buffer where the value will be stored. + */ + void get${registerNameCapitalized}(${cType}* value) const + { + memcpy(value, static_cast<const void *>(${registerName}), ${registerName}Dim1 * ${registerName}Dim2); + } +""") + +matrixRegisterSetterTemplate = string.Template(""" + /*! + * \\brief Get array ${registerName} register. + * \param value buffer where the value will be stored. + */ + void set${registerNameCapitalized}(${cType}* value) const + { + memcpy((void *) ${registerName}, value, ${registerName}Dim1 * ${registerName}Dim2); + } +""") + +stringArrayRegisterGetterTemplate = string.Template(""" + /*! + * \\brief Get std::string ${registerName} register. + * \param value buffer where the value will be stored. + */ + void get${registerNameCapitalized}(std::string* value) const + { + for (std::size_t i = 0; i < ${registerName}Dim1; i++) + { + value[i] = ${registerName}[i]; + } + } +""") + +stringArrayRegisterSetterTemplate = string.Template(""" + /*! + * \\brief Set std::string ${registerName} register. + * \param value to be set. + */ + void set${registerNameCapitalized}(const std::string* value) + { + for (std::size_t i = 0; i < ${registerName}Dim1; i++) + { + ${registerName}[i] = value[i]; + } + } +""") + +arrayRegisterGetterTemplate = string.Template(""" + /*! + * \\brief Set array ${registerName} register. + * \param value to be set. + */ + void get${registerNameCapitalized}(${cType}* value) const + { + memcpy(value, (void *) ${registerName}, ${registerName}Dim1); + } +""") + +arrayRegisterSetterTemplate = string.Template(""" + /*! + * \\brief Set 2D array ${registerName} register. + * \param value to be set. + */ + void set${registerNameCapitalized}(${cType}* value) const + { + memcpy((void *) ${registerName}, value, ${registerName}Dim1); + } +""") + +scalarRegisterGetterTemplate = string.Template(""" + /*! + * \\brief Get ${registerName} register. + * \\return value. + */ + ${cType} get${registerNameCapitalized}() const + { + return ${registerName}; + } +""") + +scalarRegisterSetterTemplate = string.Template(""" + /*! + * \\brief Set ${registerName} register. + * \param value to be set. + */ + void set${registerNameCapitalized}(${cType} value) + { + ${registerName} = value; + } +""") + +def getRegisterGetterSetter(blockName,blockMode,regList): + text = "" + for [name,format,dim1,dim2] in regList: + cType = iecommon.getCDataType(format) + map = {'registerName' : name, + 'registerNameCapitalized' : iecommon.capitalizeString(name), + 'cType' : iecommon.getCDataType(format)} + + if dim2 > 1: + text += matrixRegisterGetterTemplate.substitute(map) + text += matrixRegisterSetterTemplate.substitute(map) + elif dim1 > 1: + if format == 'string': + text += stringArrayRegisterGetterTemplate.substitute(map) + text += stringArrayRegisterSetterTemplate.substitute(map) + else: + text += arrayRegisterGetterTemplate.substitute(map) + text += arrayRegisterSetterTemplate.substitute(map) + else: + if format == 'string': + map['cType'] = "const std::string&" + text += scalarRegisterGetterTemplate.substitute(map) + text += scalarRegisterSetterTemplate.substitute(map) + return text + +registersDimetionsDeclarationTemplate = string.Template("""\ + static const std::size_t ${registerName}Dim${index} = ${dimention}; +""") + +def getRegistersDimetionsDeclaration(regList): + text = "" + for [name,format,dim1,dim2] in regList: + map = {'registerName' : name} + if dim2 > 1: + map['index'] = "2" + map['dimention'] = dim2 + text += registersDimetionsDeclarationTemplate.substitute(map) + map['index'] = "1" + map['dimention'] = dim1 + text += registersDimetionsDeclarationTemplate.substitute(map) + elif dim1 > 1: + map['index'] = "1" + map['dimention'] = dim1 + text += registersDimetionsDeclarationTemplate.substitute(map) + return text + +matrixRegistersDeclarationTemplate = string.Template("""\ + ${cType} ${registerName}[${registerName}Dim1][${registerName}Dim2]; +""") + +arrayRegistersDeclarationTemplate = string.Template("""\ + ${cType} ${registerName}[${registerName}Dim1]; +""") + +scalarRegistersDeclarationTemplate = string.Template("""\ + ${cType} ${registerName}; +""") + +def getRegistersDeclaration(regList): + text = "" + for [name,format,dim1,dim2] in regList: + map = {'registerName' : name, + 'cType' : iecommon.getCDataType(format)} + if dim2 > 1: + text += matrixRegistersDeclarationTemplate.substitute(map) + elif dim1 > 1: + text += arrayRegistersDeclarationTemplate.substitute(map) + else: + text += scalarRegistersDeclarationTemplate.substitute(map) + return text diff --git a/silecs-codegen/src/xml/genduwrappertemplate.pyc b/silecs-codegen/src/xml/genduwrappertemplate.pyc new file mode 100644 index 0000000000000000000000000000000000000000..a5d8778482c22d55002484d44f47696c68ac4c56 GIT binary patch literal 21891 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 O|5v5nVHub3;`@I)A*rVT literal 0 HcmV?d00001 diff --git a/silecs-codegen/src/xml/genparam$py.class b/silecs-codegen/src/xml/genparam$py.class new file mode 100644 index 0000000000000000000000000000000000000000..192483cd4de2b7e09739209efbad6a48b30f5478 GIT binary patch literal 41492 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 X`O72oBMa!}fXKqgo^;b0+3WuSKRO&8 literal 0 HcmV?d00001 diff --git a/silecs-codegen/src/xml/genparam.py b/silecs-codegen/src/xml/genparam.py new file mode 100644 index 0000000..c7cf906 --- /dev/null +++ b/silecs-codegen/src/xml/genparam.py @@ -0,0 +1,980 @@ +#!/usr/bin/python +# Copyright 2016 CERN and GSI +# +# 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 3 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, see <http://www.gnu.org/licenses/>. + +import os +import sys +import time +import zlib +import glob +import datetime +import shutil +import libxml2 + +import iecommon +import xmltemplate +import iefiles + +from iecommon import * + +#------------------------------------------------------------------------- +# Global definitions +#------------------------------------------------------------------------- +msize = 0 # my regMemSize in the former PERL script +blkMemSize = 0 # my $blockMemSize = 0; in the former PERL script +blkAddr = 0 # my $blockAddress = 0; in the former PERL script +deviceMemSize = 0 # global memory-size of one class instance (sum of block-memory size) +nbBlock = 0 # number of block of the class +plcSize = 0 +plcLast = 0 +classMem = 0 +instAddr = 0 + +blockCounter = 0 # used for NI block address generation +regCounter = 0 # used for NI register address generation + + +#========================================================================= +# Sub-function +#========================================================================= + +#------------------------------------------------------------------------- +# Decode HTML mapping < , > , " , ' in the appropiate coding +def decode(html): + html = html.replace("<","<") + html = html.replace(">",">") + html = html.replace('"',""") + html = html.replace("'","'") + return html + +#------------------------------------------------------------------------- +# Trimming: remove new-line, tabulation and spaces of the string +# Used to compute CRC32 on significant data only +def trim (str): + str = str.replace(' ', '') + str = str.replace('\s', '') + str = str.replace('\t', '') + str = str.replace('\r', '') + str = str.replace('\n', '') + return str + +#------------------------------------------------------------------------- +# Return the highest bit-alignment of the given address +def whichDataAlignment(value): + if (value % 2 != 0): return 8 + if (value % 4 != 0): return 16 + if (value % 8 != 0): return 32 + return 64 + + +#------------------------------------------------------------------------- +# DATA ALIGNMENT depends on different conditions: PLC brand, model and also +# depends on type of data structure (scalar or array) +# These methods are used to compute the correct address of each register respecting +# this conditions. +# Attention!! $addr is the relative address of the register within the block including +# this alignment while $msize is still the useful memory of the data which does not include +# memory spaces because of alignment shifts of the following variables if any. +# This remark is not true for the block mem-size which naturally includes the alignment spaces. +# + +# Adjust the register address relying on the SCHNEIDER Premium/Quantum alignment constraints +# Unity Premium/Quantum is 16bits processor and base-address is interpreted as 16bit address +# Byte elements of array (including STRING) use 8bit alignment. +def alignPremiumRegAddress(addr, format, size, dim, dim2, strLen): + global msize + + # internal string/unicode to integer cast + size = int(size) + addr = int(addr) + dim = int(dim) + dim2 = int(dim2) + strLen = int(strLen) + + algnt = 16 + while(whichDataAlignment(addr) < algnt): + addr+=1 + msize = dim * dim2 * strLen * size #compute memory data size + if (format in ['int8', 'char']): #8bit signed type use word alignment (16bit) + msize = msize * 2 # while string and uint8-array use 8bit alignment + return addr + +# Adjust the register address relying on the SCHNEIDER M340 alignment constraints +# Unity M340 is 32bits processor but base-address is interpreted as 16bit address (required even address in the mapping) +# 32bits alignment except for 8/16bits (16bits alignment) +# Byte elements of array (including STRING) use 8bit alignment. +def alignM340RegAddress(addr, format, size, dim, dim2, strLen): + global msize + + # internal string/unicode to integer cast + size = int(size) + addr = int(addr) + dim = int(dim) + dim2 = int(dim2) + strLen = int(strLen) + + algnt = 16 + if (size > 2): + algnt = 32 + while(whichDataAlignment(addr) < algnt): + addr+=1 + msize = dim * dim2 * strLen * size #compute memory data size + if (format in ['int8', 'char']): #8bit signed type use word alignment (16bit) + msize = msize * 2 # while string and uint8-array use 8bit alignment + return addr + +# Adjust the register address relying on the DIGI-Rabbit RCMx alignment constraints +# Use 16bits processor and base-address is interpreted as 16bit address +def alignDIGIRegAddress(addr, format, size, dim, dim2, strLen): + global msize + + # internal string/unicode to integer cast + size = int(size) + addr = int(addr) + dim = int(dim) + dim2 = int(dim2) + strLen = int(strLen) + + algnt = 16 + while(whichDataAlignment(addr) < algnt): + addr+=1 + msize = dim * dim2 * strLen * size #compute memory data size + if (format != 'string'): + if (size == 1): #but it's a 8bit type + msize = msize * 2 #so, it's a word alignment (only string use byte alignment) + return addr + +def alignCNVRegAddress(addr, format, size, dim, dim2, strLen): + global regCounter + return regCounter + +# Adjust the register relying on the SIEMENS Simatic alignment constraints +# 8bits alignment except for array and >8bits data (16bits alignment) +# In case of string, its length has to be +2 to hold info on string +def alignSimaticRegAddress(addr, format, size, dim, dim2, strLen): + global msize + + # internal string/unicode to integer cast + size = int(size) + addr = int(addr) + dim = int(dim) + dim2 = int(dim2) + strLen = int(strLen) + + algnt = 8 + if ((size > 1) | (dim > 1) | (dim2 > 1) | (strLen > 1)): + algnt = 16 + while(whichDataAlignment(addr) < algnt): + addr+=1 + if strLen > 1: # register is a string, + if ((strLen % 2) != 0): strLen+=1 #adjusts the global size for byte type (word alignment) + strLen+=2 #add increment to strLen first two bytes for info on string (len, maxlen) + + msize = dim * dim2 * strLen * size #compute memory data size + return addr + +# Adjust the register address relying on the BECKHOFF Twincat BC9020 alignment constraints. +# TwinCAT BCxx PLCs are 16bits processor and base-address is interpreted as 16bit address +# 8bits alignment between elements of 8bit-data array (including strings). +# In case of string, its length has to be +1 to hold end-terminator. +def alignBCxxRegAddress(addr, format, size, dim, dim2, strLen): + global msize + + # internal string/unicode to integer cast + size = int(size) + addr = int(addr) + dim = int(dim) + dim2 = int(dim2) + strLen = int(strLen) + + algnt = 16 + while(whichDataAlignment(addr) < algnt): + addr+=1 + + if strLen > 1: # register is a string, + strLen += 1 #TwinCAT requires '\0' string terminator. + + msize = dim * dim2 * strLen * size #compute memory data size + return addr + +# Adjust the register address relying on the BECKHOFF Twincat CX9020 alignment constraints. +# TwinCAT CXxx PLCs are 32bits processor but base-address is interpreted as 16bit address (required even address in the mapping) +# 32bits alignment except for 8/16bits (16bits alignment). +# 8bits alignment between elements of 8bit-data array (including strings). +# In case of string, its length has to be +1 to hold end-terminator. +def alignCXxxRegAddress(addr, format, size, dim, dim2, strLen): + global msize + + # internal string/unicode to integer cast + size = int(size) + addr = int(addr) + dim = int(dim) + dim2 = int(dim2) + strLen = int(strLen) + + algnt = 16 + if (size > 2): + algnt = 32 + while(whichDataAlignment(addr) < algnt): + addr+=1 + + if strLen > 1: # register is a string, + strLen += 1 #TwinCAT requires '\0' string terminator. + + msize = dim * dim2 * strLen * size #compute memory data size + return addr + +#block-address = block DB-Number +def computeSiemensBlockBlkAddress(regAddr, classAddr, nbDev): + #Compute block mem-size at first: each block has a dedicated DB-number which contains an array of devices + #each element of the array is a structure which must be 16bits aligned! + global blkMemSize + global plcModel + global blkAddr + + # internal string/unicode to integer cast + regAddr = int(regAddr) + classAddr = int(classAddr) + nbDev = int(nbDev) + + nextBlockAddr = regAddr + algnt = whichBaseAlignment[plcModel] #get the base struct-alignment of that PLC (16bit here) + # then adjust the next block-address by respecting this base-alignment. + while(int(whichDataAlignment(nextBlockAddr)) < int(algnt)): + nextBlockAddr+=1 + blkMemSize = nextBlockAddr + # then compute the next block DB-number and return the current one + tmpblkAddr = blkAddr + blkAddr = blkAddr + 1 + + return tmpblkAddr + classAddr + +#block-address = offset in the device memory +def computeSiemensDeviceBlkAddress(regAddr, classAddr, nbDev): + #Compute block mem-size at first: each device has a dedicated DB-number which contains a sequence of blocks + #each block is a structure which must be 16bits aligned! + global blkMemSize + global plcModel + global blkAddr + + # internal string/unicode to integer cast + regAddr = int(regAddr) + classAddr = int(classAddr) + nbDev = int(nbDev) + + nextBlockAddr = regAddr + algnt = whichBaseAlignment[plcModel] #get the base struct-alignment of that PLC (16bit here) + #then adjust the next block-address by respecting this base-alignment. + while(int(whichDataAlignment(nextBlockAddr)) < int(algnt)): + nextBlockAddr+=1 + blkMemSize = nextBlockAddr + #then compute the next block DB-number and return the current one + tmpblkAddr = blkAddr + blkAddr = blkAddr + blkMemSize + return tmpblkAddr + + +# Block-address = absolute address in the PLC memory +def computeSchneiderBlockBlkAddress(regAddr, classAddr, nbDev): + global blkMemSize + global plcModel + global blkAddr + + # Internal string/unicode to integer cast + regAddr = int(regAddr) + classAddr = int(classAddr) + nbDev = int(nbDev) + + # Compute block mem-size at first: + # It corresponds to the next potential address that is 16bits or 32bits with SCHNEIDER. + nextBlockAddr = regAddr + + # Each data-block for each class and device will be aligned on the worst-case alignment + # of the given PLC. This logic allows having a unique address computing whatever the mode (DEVICE/BLOCK) + # and the PLC model (16bits or 32bits). + algnt = whichBaseAlignment[plcModel] # get the "worst-case" base-alignment of that PLC + #then adjust the next block-address by respecting this base-alignment. + while(whichDataAlignment(nextBlockAddr) < int(algnt)): + nextBlockAddr+=1 + blkMemSize = nextBlockAddr + # then compute the next block DB-number and return the current one + tmpblkAddr = blkAddr + # next absolute address: relies on the global class-address + blkAddr = blkAddr + (nbDev * blkMemSize) + return classAddr + tmpblkAddr + + +# Block-address = offset in the device memory +def computeSchneiderDeviceBlkAddress(regAddr, classAddr, nbDev): + global blkMemSize + global plcModel + global blkAddr + + # internal string/unicode to integer cast + regAddr = int(regAddr) + classAddr = int(classAddr) + nbDev = int(nbDev) + + #Compute block mem-size at first: + #it corresponds to the next potential address that is 16bits or 32bits with SCHNEIDER. + nextBlockAddr = regAddr + #Each data-block for each class and device will be aligned on the worst-case alignment + #of the given PLC. This logic allows having a unique adress computing whatever the mode (DEVICE/BLOCK) + #and the PLC model (16bits or 32bits). + algnt = whichBaseAlignment[plcModel] #get the "worst-case" base-alignment of that PLC + #then adjust the next block-address by respecting this base-alignment. + while(whichDataAlignment(nextBlockAddr) < int(algnt)): + nextBlockAddr+=1 + blkMemSize = nextBlockAddr + #then compute the next block DB-number and return the current one + tmpblkAddr = blkAddr + #next relative address: independent from the global class-address + blkAddr = blkAddr + blkMemSize + return tmpblkAddr + +def computeNiDeviceBlkAddress(regAddr, classAddr, nbDev): + global blockCounter + blockCounter = blockCounter + 1 + return blockCounter + +#------------------------------------------------------------------------- +# Compute the next register address relying on the data start-address and size. +def computeAnyNextRegAddress(brand, addr, dim, dim2=1): + global msize + + # internal string/unicode to integer cast + addr = int(addr) + dim = int (dim) + dim2 = int(dim2) + + addr = addr + msize; #compute the next address for any case + if (brand == 'SIEMENS'): + # SIEMENS requires specific treatment in case of array. + if ((dim > 1) | (dim2 > 1)): + #SIEMENS array is always followed by 16bits adressing + algnt = 16 + while(whichDataAlignment(addr) < algnt): + addr+=1 + elif (brand == 'NI'): + msize = 0 + return addr + + +#------------------------------------------------------------------------- +def computeAnyBlockInstAddress(classAddr, devSize): + global instAddr + tmpInstAddr = instAddr + instAddr = instAddr + 1 #device-index + return tmpInstAddr + +def computeSiemensDeviceInstAddress(classAddr, devSize): + global instAddr + tmpInstAddr = instAddr + instAddr = instAddr + 1 #device DB-number + return tmpInstAddr + classAddr + +def computeSchneiderDeviceInstAddress(classAddr, devSize): + global instAddr + tmpInstAddr = instAddr + instAddr = instAddr + devSize #absolute address + return tmpInstAddr + classAddr + +def computeNiDeviceInstAddress(classAddr, devSize): + return 0 +#------------------------------------------------------------------------- +# Compute the base DB-number of the next class in the SIEMENS PLC memory +# BLOCK mode requires 1 DB per class block +def computeSiemensBlockNextBaseAddress(classAddr, nbBlk, nbDev, devSize): + global classMem + global plcLast + global plcSize + + # internal string/unicode to integer cast + classAddr = int(classAddr) + nbBlk = int(nbBlk) + nbDev = int(nbDev) + devSize = int(devSize) + + byteSize = nbDev * devSize + plcSize = int(plcSize) + int(byteSize) #global size of the plc configuration + startDB = classAddr #first DB used for this class + plcLast = classAddr + nbBlk - 1 #last DB used + classMem = "DB%d..DB%d / %d bytes"%(startDB,plcLast,byteSize) + return plcLast + 1 #next DB number + +# Compute the base DB-number of the next instance in the SIEMENS PLC memory +# DEVICE mode requires 1 DB per class instance +def computeSiemensDeviceNextBaseAddress(classAddr, nbBlk, nbDev, devSize): + global classMem + global plcLast + global plcSize + classAddr = int(classAddr) + nbBlk = int(nbBlk) + nbDev = int(nbDev) + devSize = int(devSize) + + byteSize = nbDev * devSize + plcSize = plcSize + byteSize #global size of the plc configuration + startDB = classAddr #first DB used for this class + plcLast = classAddr + nbDev - 1 #last DB used + classMem = "DB%d..DB%d / %d bytes"%(startDB,plcLast,byteSize) + return plcLast + 1 #next DB number + +# Compute the base-address of the next class in the SCHNEIDER PLC memory +# DEVICE or BLOCK mode use the same memory size: next base address should be the same +# 'used-mem' info is expressed in words (/2) but address is computed in bytes +def computeSchneiderAnyNextBaseAddress(classAddr, nbBlk, nbDev, devSize): + global classMem + global plcLast + global plcSize + classAddr = int(classAddr) + nbBlk = int(nbBlk) + nbDev = int(nbDev) + devSize = int(devSize) + + wordSize = (nbDev * devSize) / 2 + plcSize = plcSize + wordSize #global size of the plc configuration + startAddr = classAddr / 2 #first word address used for this class + plcLast = startAddr + wordSize - 1 #LAST word address used for this class + classMem = "MW%d..MW%d / %d words"%(startAddr,plcLast,wordSize); + return (classAddr + (wordSize * 2)) #next word address expressed in bytes + +def computeNiAnyNextBaseAddress(classAddr, nbBlk, nbDev, devSize): + return 0 + +#------------------------------------------------------------------------- +# computeChecksumController +# checksum procedure: +# CRC = Major-number + PLC-base-address +# For each PLC-Class (cluster) of the controller mapping: +# CRC += class-name + class-version + class-access //DEVICE/BLOCK +# For each Block +# CRC += block-name + block-mode //R/W +# For each Register +# CRC += reg-name + reg-format + array-dim1 + array-dim2 + (string-length) optional +# CRC += nb-instance +# +def computeChecksumController( workspacePath, controllerNode, silecsVersion, PLCbaseAddress, funcGetSilecsDesignFilePath, logTopics={'errorlog': True}): + majorSilecsVersion = iecommon.getMajorSilecsVersion(silecsVersion) + CRC32 = zlib.crc32(trim(str(majorSilecsVersion)),0)& 0xffffffff + CRC32 = zlib.crc32(trim(str(PLCbaseAddress)),CRC32)& 0xffffffff + for silecsDesign in controllerNode.xpathEval("SilecsDesign"): + CRC32 = zlib.crc32(trim(silecsDesign.prop("silecs-design-name")),CRC32)& 0xffffffff + CRC32 = zlib.crc32(trim(silecsDesign.prop("silecs-design-version")),CRC32)& 0xffffffff + designDOM = loadSilecsDesignDOM(workspacePath, silecsDesign, silecsVersion, funcGetSilecsDesignFilePath) + CRC32 = computeChecksumClass(designDOM,CRC32,logTopics) + for device in silecsDesign.xpathEval("Device"): + CRC32 = zlib.crc32(trim(device.prop("device-name")),CRC32)& 0xffffffff + iecommon.logInfo("CRC32: %s" % str(CRC32),logTopics) + return CRC32 + +def computeChecksumClass(designDOM, CRC32, logTopics={'errorlog': True}): + blockList = designDOM.xpathEval("Block") + for blockNode in blockList: + blockName = blockNode.prop('name') + blockMode = blockNode.prop('mode') + registerList = blockNode.xpathEval("Register") + for register in registerList: + regName = register.prop("name") + CRC32 = zlib.crc32(trim(regName),CRC32)& 0xffffffff + + regFormat = register.prop("format") + CRC32 = zlib.crc32(trim(regFormat),CRC32)& 0xffffffff + + try: + # array-dim1 is an optional attribute!!! + regDim1 = register.prop("array-dim1") + except: + regDim1 = "1" + CRC32 = zlib.crc32(trim(regDim1),CRC32)& 0xffffffff + + try: + # array-dim2 is an optional attribute!!! + regDim2 = register.prop("array-dim2") + except: + regDim2 = "1" + CRC32 = zlib.crc32(trim(regDim2),CRC32)& 0xffffffff + + try: + # string-len is an optional attribute!!! + stringLength = register.prop("string-len") + CRC32 = zlib.crc32(trim(stringLength),CRC32)& 0xffffffff + except: + pass + return CRC32 + +#------------------------------------------------------------------------- +# Hash table +#------------------------------------------------------------------------- + +whichPLCBrand = { + 'SIMATIC_S7-300' : 'SIEMENS', + 'SIMATIC_S7-400' : 'SIEMENS', + 'SIMATIC_S7-1200' : 'SIEMENS', + 'SIMATIC_S7-1500' : 'SIEMENS', + 'SIMATIC_ET-200S' : 'SIEMENS', + 'SIMATIC_S7-VIRTUAL': 'SIEMENS', + 'Premium' : 'SCHNEIDER', + 'Quantum' : 'SCHNEIDER', + 'M340' : 'SCHNEIDER', + 'Compact_RIO' : 'NI', + 'PXI_RT' : 'NI', + 'PXI_Windows' : 'NI', + 'PC_Windows' : 'NI', + 'Other_Support_CNV' : 'NI', + 'Rabbit_RCM_4010' : 'DIGI', + 'Rabbit_RCM_2000' : 'DIGI', + 'BC9020' : 'BECKHOFF', + 'CX9020' : 'BECKHOFF' +} + +# The following constant are used to align the address of a device block {set of registers}. +# With SCHNEIDER PLC, block is aligned depending on his 'worst-case' alignement {16bits or 32bits}. +# This logic allows having a unique adress computing whatever the mode {DEVICE/BLOCK} and the PLC model. +# Concerning SIEMENS PLC, block alignment should respect the 16bits alignement constraint for Struct&Array. +whichBaseAlignment = { + 'SIMATIC_S7-300' : '16', + 'SIMATIC_S7-400' : '16', + 'SIMATIC_S7-1200' : '16', + 'SIMATIC_S7-1500' : '16', + 'SIMATIC_ET-200S' : '16', + 'SIMATIC_S7-VIRTUAL': '16', + 'Premium' : '16', + 'Quantum' : '16', + 'M340' : '32', # any data-block of M340 model will start on 32bits address + # even if the first register of the block is a 16bit data. + 'Rabbit_RCM_4010' : '16', + 'Rabbit_RCM_2000' : '16', + 'BC9020' : '16', + 'CX9020' : '32' +} + +whichDataSize = { + 'uint8' : '1', + 'int8' : '1', + 'uint16' : '2', + 'int16' : '2', + 'uint32' : '4', + 'int32' : '4', + 'float32' : '4', + 'uint64' : '8', + 'int64' : '8', + 'float64' : '8', + 'string' : '1', + 'date' : '8', + # deprecated formats + 'char' : '1', + 'byte' : '1', + 'word' : '2', + 'dword' : '4', + 'int' : '2', + 'dint' : '4', + 'real' : '4', + 'dt' : '8' +} + +whichRegAddressFunction = { + 'SIMATIC_S7-300' : alignSimaticRegAddress, + 'SIMATIC_S7-400' : alignSimaticRegAddress, + 'SIMATIC_S7-1200' : alignSimaticRegAddress, + 'SIMATIC_S7-1500' : alignSimaticRegAddress, + 'SIMATIC_ET-200S' : alignSimaticRegAddress, + 'SIMATIC_S7-VIRTUAL' : alignSimaticRegAddress, + 'Premium' : alignPremiumRegAddress, + 'Quantum' : alignPremiumRegAddress, + 'M340' : alignM340RegAddress, + 'Compact_RIO' : alignCNVRegAddress, + 'PXI_RT' : alignCNVRegAddress, + 'PXI_Windows' : alignCNVRegAddress, + 'PC_Windows' : alignCNVRegAddress, + 'Other_Support_CNV' : alignCNVRegAddress, + 'Rabbit_RCM_4010' : alignDIGIRegAddress, + 'Rabbit_RCM_2000' : alignDIGIRegAddress, + 'BC9020' : alignBCxxRegAddress, + 'CX9020' : alignCXxxRegAddress +} + +whichBlkAddressFunction = { + 'SIEMENS'+'BLOCK_MODE' : computeSiemensBlockBlkAddress, + 'SIEMENS'+'DEVICE_MODE' : computeSiemensDeviceBlkAddress, + 'SCHNEIDER'+'BLOCK_MODE' : computeSchneiderBlockBlkAddress, + 'SCHNEIDER'+'DEVICE_MODE' : computeSchneiderDeviceBlkAddress, + 'NI'+'DEVICE_MODE' : computeNiDeviceBlkAddress, + 'DIGI'+'BLOCK_MODE' : computeSchneiderBlockBlkAddress, + 'DIGI'+'DEVICE_MODE' : computeSchneiderDeviceBlkAddress, + 'BECKHOFF'+'BLOCK_MODE' : computeSchneiderBlockBlkAddress +} + +whichInstAddressFunction = { + 'SIEMENS'+'BLOCK_MODE' : computeAnyBlockInstAddress, + 'SIEMENS'+'DEVICE_MODE' : computeSiemensDeviceInstAddress, + 'SCHNEIDER'+'BLOCK_MODE' : computeAnyBlockInstAddress, + 'SCHNEIDER'+'DEVICE_MODE' : computeSchneiderDeviceInstAddress, + 'NI'+'DEVICE_MODE' : computeNiDeviceInstAddress, + 'DIGI'+'BLOCK_MODE' : computeAnyBlockInstAddress, + 'DIGI'+'DEVICE_MODE' : computeSchneiderDeviceInstAddress, + 'BECKHOFF'+'BLOCK_MODE' : computeAnyBlockInstAddress +} + +whichBaseAddressFunction = { + 'SIEMENS'+'BLOCK_MODE' : computeSiemensBlockNextBaseAddress, + 'SIEMENS'+'DEVICE_MODE' : computeSiemensDeviceNextBaseAddress, + 'SCHNEIDER'+'BLOCK_MODE' : computeSchneiderAnyNextBaseAddress, + 'SCHNEIDER'+'DEVICE_MODE' : computeSchneiderAnyNextBaseAddress, + 'NI'+'DEVICE_MODE' : computeNiAnyNextBaseAddress, + 'DIGI'+'BLOCK_MODE' : computeSchneiderAnyNextBaseAddress, + 'DIGI'+'DEVICE_MODE' : computeSchneiderAnyNextBaseAddress, + 'BECKHOFF'+'BLOCK_MODE' : computeSchneiderAnyNextBaseAddress +} + +#Base address provided by the user in the Deployment relies on the PLC model: +#Unity Premium/Quantum is interpreted as 16bit address +#Unity M340 is interpreted as 32bit address +#Factor is used to convert the base-address to byte-addressing for computation. +whichAddressFactor = { + 'SIMATIC_S7-300' : 1, # Simatic does not use absolute addressing {DB-number} + 'SIMATIC_S7-400' : 1, + 'SIMATIC_S7-1200' : 1, + 'SIMATIC_S7-1500' : 1, + 'SIMATIC_ET-200S' : 1, + 'SIMATIC_S7-VIRTUAL': 1, + 'Premium' : 2, # Premium/Quantum uses 16bit adressing for 32bit values + 'Quantum' : 2, + 'M340' : 2, + 'Compact_RIO' : 0, + 'PXI_RT' : 0, + 'PXI_Windows' : 0, + 'PC_Windows' : 0, + 'Other_Support_CNV' : 0, + 'Rabbit_RCM_4010' : 2, + 'Rabbit_RCM_2000' : 2, + 'BC9020' : 2, # BC90xx use 16 bit addressing + 'CX9020' : 1 +} + +def loadSilecsDesignDOM(workspacePath, classNode, silecsVersion, funcGetSilecsDesignFilePath): + if classNode.prop("silecs-design-name") == "SilecsHeader": + silecsHeader = xmltemplate.getSilecsHeader(silecsVersion) + return libxml2.parseDoc(silecsHeader) + else: + designPath = funcGetSilecsDesignFilePath(workspacePath, classNode.prop("silecs-design-name")) + return libxml2.parseFile(designPath) + +# Needed to encapsulate "genParam" in order to allow unit-testing (fake all file interactions) +def genParamBase( funcGetSilecsDesignFilePath, funcGetParameterFile, funcGetSilecsDeployFilePath, funcGetParameterFileDirectory, workspacePath, deployName, deployVersion, silecsVersion, logTopics={'errorlog': True}): + # Global variable links + global plcModel, plcBrand, plcSystem, plcProtocol, plcSize, plcLast + global PLCbaseAddress, checksumRef, owner, deviceMemSize, blkAddr, nbBlock, msize + global blkMemSize + global instAddr, classAddr + global classMem + + global blockCounter # used for NI block address generation + global regCounter # used for NI register address generation + + # Check the Deployment document exist for that PLC + deployPath = funcGetSilecsDeployFilePath(workspacePath, deployName) + if(not os.path.isfile(deployPath)): + iecommon.logError(deployName + "deployment file cannot be found in provided workspace",logTopics) + + # Create the Deployment DOM object + deployDOM = libxml2.parseFile(deployPath) + + # Check that Deployment data are consistent + deployUnitNode = deployDOM.xpathEval("/SILECS-Deploy/Deploy-Unit")[0] # only one Deploy-Unit + + if (deployUnitNode.prop('name') != deployName): + iecommon.logError("Deployment name is not consistent", True,logTopics) + + #------------------------------------------------------------------------- + # Extract information from the XML + #------------------------------------------------------------------------- + + # Extract Deployment owner from the Information node + owner = deployDOM.xpathEval("/SILECS-Deploy/Information/Owner")[0].prop('user-login') + + #------------------------------------------------------------------------- + # SECOND pass on each Design documents: Generate parameters + # For each class generate XML-ouput document relying on Design & Deployment + #------------------------------------------------------------------------- + iecommon.logDebug("------Processing for output file generation------",logTopics) + paramPath = funcGetParameterFileDirectory(workspacePath, deployName) + + #create output directory if necessary + if not os.path.exists(paramPath): + os.makedirs(paramPath) + iecommon.logDebug("create directory %s" %paramPath,logTopics) + + iecommon.addSilecsHeaderToClasses(deployDOM) + controllerNodes = deployDOM.xpathEval("/SILECS-Deploy/Controller") + for controllerNode in controllerNodes: + plcNode = controllerNode.xpathEval("*[@system]")[0] + # Extract PLC global information + plcSystem = plcNode.prop('system') + plcModel = plcNode.prop('model') + plcBrand = whichPLCBrand[plcModel] + plcProtocol = plcNode.prop('protocol') + addressFactor = whichAddressFactor[plcModel] + + if plcBrand == 'SIEMENS': + PLCbaseAddress = long(plcNode.prop('base-DB-number')) + + elif plcBrand == 'SCHNEIDER': + PLCbaseAddress = long(plcNode.prop('base-address')) + PLCbaseAddress = PLCbaseAddress * addressFactor + + elif plcBrand == 'BECKHOFF': + PLCbaseAddress = long(plcNode.prop('base-address')) + # Use plcModel to set appropriate initial offset + if plcModel == 'BC9020': + offset = 32768 + elif plcModel == 'CX9020': + offset = 24576 + PLCbaseAddress = (PLCbaseAddress * addressFactor) + offset + + elif plcBrand == 'DIGI': + PLCbaseAddress = long(plcNode.prop('base-address')) + PLCbaseAddress = PLCbaseAddress * addressFactor + + else: # plcBrand == 'NI' + PLCbaseAddress = 0 + + classBaseAddress = PLCbaseAddress + + # Messagges for debugging purpose + iecommon.logDebug("------ XML extracted informations ------",logTopics) + iecommon.logDebug("owner = "+owner,logTopics) + iecommon.logDebug("plcSystem = "+plcSystem,logTopics) + iecommon.logDebug("plcModel = "+plcModel,logTopics) + iecommon.logDebug("plcBrand = "+plcBrand,logTopics) + iecommon.logDebug("plcProtocol = "+plcProtocol,logTopics) + iecommon.logDebug("addressFactor = %d" %addressFactor,logTopics) + iecommon.logDebug("PLCbaseAddress = %d" %PLCbaseAddress,logTopics) + + paramFile = funcGetParameterFile(workspacePath, deployName, controllerNode.prop('host-name')) + iecommon.logInfo("Generate xml for parameters file: "+paramFile,logTopics) + + # Create the parameter DOM for the output file + paramDOM = libxml2.newDoc(version='1.0') + outputRoot = libxml2.newNode('SILECS-Param') + outputRoot.setProp("silecs-version", silecsVersion) + paramDOM.addChild(outputRoot) + + #------------------------------------------------------------------------- + # Generate section <Mapping-Info></Mapping-Infon> + #------------------------------------------------------------------------- + paramMappingInfoNode = libxml2.newNode("Mapping-Info") + outputRoot.addChild(paramMappingInfoNode) + + # Add Owner + paramOwnerNode = libxml2.newNode('Owner') + paramOwnerNode.setProp("user-login", owner) + paramMappingInfoNode.addChild(paramOwnerNode) + + # Add Generation + element2 = libxml2.newNode('Generation') + currentDate = str(datetime.datetime.now()) + element2.setProp("date",currentDate) + paramMappingInfoNode.addChild(element2) + + # Add Deployment + element2 = libxml2.newNode('Deployment') + CRC32 = computeChecksumController(workspacePath, controllerNode, silecsVersion, PLCbaseAddress, funcGetSilecsDesignFilePath, logTopics) + element2.setProp("checksum", str(CRC32)) + paramMappingInfoNode.addChild(element2) + + #------------------------------------------------------------------------- + # Generate section <SILECS-Mapping></SILECS-Mapping> + #------------------------------------------------------------------------- + paramSilecsMappingNode = libxml2.newNode("SILECS-Mapping") + paramSilecsMappingNode.setProp("plc-name", controllerNode.prop('host-name')) + paramSilecsMappingNode.setProp("plc-brand", plcBrand) + paramSilecsMappingNode.setProp("plc-system", plcSystem) + paramSilecsMappingNode.setProp("plc-model", plcModel) + paramSilecsMappingNode.setProp("protocol", plcProtocol) + paramSilecsMappingNode.setProp("address", str(PLCbaseAddress)) + paramSilecsMappingNode.setProp("domain", "NotUsed") + paramSilecsMappingNode.setProp("used-mem", "TODO") + outputRoot.addChild(paramSilecsMappingNode) + + classNodes = controllerNode.xpathEval('SilecsDesign') + for classNode in classNodes: + iecommon.logDebug("-----------------------------------------",logTopics) + iecommon.logDebug("------ Analysing Class %s ------"%classNode.prop("silecs-design-name"),logTopics) + iecommon.logDebug("-----------------------------------------",logTopics) + + designDOM = loadSilecsDesignDOM(workspacePath, classNode, silecsVersion, funcGetSilecsDesignFilePath) + + # Extract the number of devices ------------------------------------------ + + deviceLabelList=classNode.xpathEval('Device') + nbDevice = len(deviceLabelList) + iecommon.logDebug("Class %s uses device-list and has %s devices" %(classNode,nbDevice),logTopics) + + paramClassNode = libxml2.newNode("SILECS-Class") + paramSilecsMappingNode.addChild(paramClassNode) + paramClassNode.setProp("name", classNode.prop("silecs-design-name")) + paramClassNode.setProp("version", classNode.prop("silecs-design-version")) + + #------------------------------------------------------------------------- + # Generate section <Block></Block> + #------------------------------------------------------------------------- + blockCounter = 0 + + deviceMemSize = 0 # global memory-size of one class instance (sum of block-memory size) + blkAddr = 0 # memory address of the block (using byte addressing) + nbBlock = 0 # number of block of the class + + computeBlkAddress = whichBlkAddressFunction[plcBrand + plcProtocol] + + # INNER LOOP TO ACCESS AT BLOCK LEVEL (LOOP-2) + for block in designDOM.xpathEval("//Block"): #LOOP-2 + element3 = libxml2.newNode("Block") + element3.setProp("name", block.prop("name")) + element3.setProp("mode", block.prop("mode")) + iecommon.logDebug("----- Processing Block "+block.prop('name')+" from design -----",logTopics) + # Initialization for inner loop local variables + regAddress = 0 # memory address of the register (using byte addressing) + blockSize = 0 # block size (sum of the register size) + blockMemSize = 0 # block size (sum of the regist) + instAddr = 0 # initial class address BUG FIXED + regCounter = 0 # used for NI register address generation + alignRegAddress = whichRegAddressFunction [plcModel] + + #------------------------------------------------------------------------- + # Generate section <Register></Register> + #------------------------------------------------------------------------- + # INNER LOOP TO ACCESS AT REGISTER LEVEL (LOOP-3) + for register in block.xpathEval("Register"): + iecommon.logDebug("------ Processing Register "+register.prop('name')+" ------") + element4 = libxml2.newNode("Register") + # Set register name + element4.setProp("name", register.prop("name")) + # Set register format + regFormat = register.prop("format") + element4.setProp("format", regFormat) + + # Just get the register dimensions for next computation + regDimension1 = '1' #by default + if register.prop('array-dim1'): #possibly single array + regDimension1 = register.prop("array-dim1") + regDimension2 = '1' #by default + if register.prop('array-dim2'): #possibly double array + regDimension2 = register.prop('array-dim2') + + # Set length attribute only for string registers + strLen = '1' #not a string by default (no impact on data total-size) + if regFormat == 'string': + strLen = register.prop('string-len') + if strLen: #is string length defined? + if plcBrand == 'RABBIT': + # RABBIT has 8bit memory alignment but uses 16bit word communication protocol (MODBUS). + # String buffer (8bit elements) must have even number of bytes. + if ((int(regDimension1)*int(regDimension2)*int(strLen)) % 2 == 1): #XML CliX cannot check that constraint! + iecommon.logError("String length of %s register must be an even value." %register.prop("name"), False,logTopics) + sys.exit(2) + else: # if length not given, set default length for string (=64) + strLen = '64' + element4.setProp('string-len', strLen) + + # Set register dimensions + element4.setProp("array-dim1", regDimension1) + element4.setProp("array-dim2", regDimension2) + # Set register size + regSize = whichDataSize[regFormat] + element4.setProp("size", regSize) + # Set register address + regAddress = alignRegAddress(regAddress, regFormat, regSize, regDimension1, regDimension2, strLen) + element4.setProp("address", str(regAddress)) + regCounter = regCounter + 1 # used for NI register address generation + # Set register mem-size + element4.setProp("mem-size", str(msize)) + # Compute address for the next register + regAddress = computeAnyNextRegAddress(plcBrand, regAddress, regDimension1, regDimension2) + # Set register synchro + element4.setProp("synchro", register.prop("synchro")) + # Append register + element3.addChild(element4) + #iterativelly compute the block size (accumulator initialized outside the loop) + blockSize = blockSize + (int(regSize) * int(regDimension1) * int(regDimension2)) + # END OF INNER LOOP TO ACCESS AT REGISTER LEVEL (LOOP-3) + + # Set block size + element3.setProp("size", str(blockSize)) + # Set block address + element3.setProp("address",str(computeBlkAddress(regAddress, int(classBaseAddress) , nbDevice))) + # Set block mem-size + element3.setProp("mem-size", str(blkMemSize)) + # Append block + paramClassNode.addChild(element3) + # Count the number of devices + nbBlock = nbBlock+1 + # Accumulate blkMemSize to compute the total deviceMemSize + deviceMemSize = deviceMemSize + blkMemSize + + # END OF INNER LOOP TO ACCESS AT BLOCK LEVEL (LOOP-2) + # Set block Address + paramClassNode.setProp("address", str(classBaseAddress)) + + #------------------------------------------------------------------------- + # Devices + #------------------------------------------------------------------------- + computeInstAddress = whichInstAddressFunction[ plcBrand + plcProtocol ] + + for device in deviceLabelList: + element3 = libxml2.newNode("Instance") + element3.setProp("label", device.prop("device-name")) + element3.setProp("address", str(computeInstAddress(classBaseAddress, deviceMemSize))) + paramClassNode.addChild(element3) + + # Compute the memory address for the next class + computeBaseAddress = whichBaseAddressFunction [plcBrand+plcProtocol] + classBaseAddress = computeBaseAddress(classBaseAddress, nbBlock, nbDevice, deviceMemSize); + + # Set class used-memory + paramClassNode.setProp("used-mem", str(classMem)) + iecommon.logInfo("Used-memory for Class "+classNode.prop("silecs-design-version")+": "+str(classMem),logTopics) + + #------------------------------------------------------ + # Generate output XML + #------------------------------------------------------ + iefiles.saveXMLToFile(paramFile,paramDOM) + + iecommon.logDebug("---------------------------------------------------------",logTopics) + iecommon.logDebug("------GENERATED FILE: %s "%paramFile,logTopics) + iecommon.logDebug("---------------------------------------------------------",logTopics) + + # GSI-Fix there are more then two types now ... better say nothing than something which could be wrong for the else-case + #Display details about the PLC memory using for the global configuration + #if (plcBrand == 'SIEMENS'): + # # SIEMENS works with data-block addressing + # plcUsedMem = "DB"+str(PLCbaseAddress)+"..DB"+str(plcLast)+" / "+str(plcSize)+" bytes" + #else: + # # SCHNEIDER works with absolute addressing + # startAddr = PLCbaseAddress /2 #Memory info uses word-addressing + # lastAddr = plcLast #Already computed as byte-address + # plcUsedMem = "MW"+str(startAddr)+"..MW"+str(lastAddr)+" / "+str(plcSize)+" words" + + # print plc used memory + # iecommon.logInfo("Used-memory for PLC "+deployName+": "+str(plcUsedMem),logTopics) + + +#========================================================================= +# Entry point +#========================================================================= +def genParam(workspacePath, deployName, deployVersion, silecsVersion, logTopics={'errorlog': True}): + genParamBase( iefiles.getSilecsDesignFilePath, iefiles.getParameterFile, iefiles.getSilecsDeployFilePath, iefiles.getParameterFileDirectory, workspacePath, deployName, deployVersion, silecsVersion, logTopics) + + diff --git a/silecs-codegen/src/xml/genparam.pyc b/silecs-codegen/src/xml/genparam.pyc new file mode 100644 index 0000000000000000000000000000000000000000..9b261e4b82432c86678ae23805fb1f26038001e7 GIT binary patch literal 20502 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 A-v9sr literal 0 HcmV?d00001 diff --git a/silecs-codegen/src/xml/genplcsrc$py.class b/silecs-codegen/src/xml/genplcsrc$py.class new file mode 100644 index 0000000000000000000000000000000000000000..62f0355bd8a0b7b9373c3a56a58ffffc3b8e91c6 GIT binary patch literal 38245 zcmd6Q31C~r(f{r~%X)H@M3!<n2T@2u4%=}O0s)6BK9U#`C)g$-95sq9CnC1wN_G;5 z8(N^8E%)7W)!at_6B;O23xysOC}#__g+dF3a((oJ0{Q=D_PwX4%MSg%{{R1w$$Q$J zot>SXot>Q>iKoB*$xnq4^Nd%eFgm8qm7;0p@<eidRd-*{hD5xoEs=~?t?FBnjC4g8 z<y5q6NJb;=%{`Hx=%QIUwX6D8t~)l`*0V^8u?0wag&~DE747Ma#iLRb&1{&p+Aln! zxI`2QuM{egGKEiyP<H!RSGQLTlfs9WM6zckwO%%J`LU5rk*dx}e0^1OPcjx?pUbj6 zmWDz2^^4(RM2YZ=ky4n%T%s+~DMi(;(YFRo11S|j8b}DTP4!_UqcOyuSXa~(WAV1N zGq%nYWe~uYuFg5_i7r!2kRp&h2CtX|l&)Aj#we4eDA9vnl1y|-aa10zj{HV~II{4} z`Nb5mJ4s@y6eBGz=QylPm%`H>Nv1HK8Bz@6S1or_%!24*(e<5)b&*a}l=G*yL|0cL zZi-5bCl>99bw(kRDvT$!uqWEp-3c`^#XKoSBqQtA#d=ztvOS%NUfj9s6QPxsHEJ)h zH;rPU6yvfr$<|V@*jI|;1Z%7*ptIif(VjTeUWz$+L_Dba>@N<Wc|Q;Y>!RJAi9S;- zh6MEcG>ovMwY4kJ-rE^%Z8b$5s#;sAEBdqqn$ehuLlVoR7~am!S4Wen7)kD6G}T3o zKsUv5H0|zeTajpwLduO06FxQfr65jItkRV=$w<826iqZkoo%a<iJnAT0@y7mSQkk} z7q_=3qbbb9Y813>h_-D^^>#HyJ4|sn<~Ol99!;9!2-HCy9j&|;Qc_HuIj97V5=WB+ zz9of!eKd}KQ^~ez-F;qh45lEDzSUv`i~OQitn-P8Xp<tCJ5OGLx$t#GHb!eZBPs9@ z$ulp5D08812OY?Iv7tnCh?u=FdwXJ?Rg06!NMFh;He#-z#!$(bGu>;>G6Akt=rRgj zB3>doMFKL+9b;Xrtp_t5NkUZL#!6^zSh2XJp|-VoVdb84=b8ee&ZEJ4(RoEL#N7d_ z&=Bv5CgaieT~}SpT>8akv86<85`EDB=7#ze^^MJ@I4+Zs1;oe+FbFQ@=FO+Vld=l; zqQX;Lh4n3!Km^ItKz~&-+7;`CqJ9_C+FZM=vA&_MzR474pzhG#NW6#Yz6TMn*mD8s zoDCJMO>}if+Im`>8djR(T<i~x4W>9B%WT!*4XsTrruYGn=zUEr-k#VDrM?g=W>sza z^Tkq>uI$+mO|~}ocGK3;THCnV6qjPHG}W$XT`+eZy1E<`n-<s9G=SojRt@+@&DE%> zsoi((e7ye<H8u6Mhb&vUWQi%RMNRGDy5@Sk?+1h3bAS}PK{Ima*`*IRiXWGVr0B<L z-@GB#wqe!sT5HMPjP=(Wi}&nfid!Lunzb$Urnnt%y6jH8ty$SrXNtSgA0f`$+Z6Yp zk@b2X_ML`CjNyK(e$V-)cmVZvy4enmN~I5hRvqI$4C!}tCL%pl{3wc>>K89J#p586 z;yu+AKgWA>OH)JRQd2w$jCMBMPhmRh(Ah6h(zYRzG{vv+wyuwi`ZIXjoJhh9J&Qiu z_3QIs51g9f1){-kFX0U?1+3F6pw^DM-(%siSPp|Y`<5h<T@jSN2E1lw_YIf|u5Z~K zi?>C3Y>Ypld~s9L;<ZQ4oik^8`_bW*OTyEk4{u`rQ*9gK(O7#l*%V#ROW72Ek)q6n zUJ=f0^$uK+oL2KOoWDsiC5%7QQ?1kIF4)pKJr!Qu5}rPN#hU4<YLqS-UNXGI6z@ST z*TJ%GNOW|dQ&YSz#r(qUn3He@=N6%VKpZYY7WW@XvG1-?%N&?R^b^P`n<x$Lzogis zFj)+6|MUp|iB;~R(SX@9#phUj@#y9Tn4|U4B&~(KZkJUL`~NTTC0X0Aq!^#OW|s8E z**JQ|P8f`iR_$D*fLnNh`K6S~CyJzj<+UZ%2jR!CJ0_>i$Ku6?X1R8g@-t?wQok&g zUTkO5gvPe6?~!8fd`_~xrU&DuL=Gzv)zS}rz?PqgZ;d7st*szCbJh`lIYN%4+5m<J z-t_qVGRWS93~?Kj$FRG%w)*90O>2x4@<>yT!;)x?w72`^cwIgLRIy@BISE5;ZG{Wl zNj){^vhH@{3o}31HYq2|FmXNwyc})HsXWz#kRsn$PA8G>K_ZQQ+b?Hou4j??X~q8D z69cUVzbuy(G=G(O4-qZB-JMadtfH}}de`~oJWXYOiJVIowTRp-zuZfg?(LTzb}-~V zQXHEr2ip}~G>FB{Gbr|5@|4^9fWh7<t4lDPMVLaD5}I;<Y}oZ(-96Sx3A#LCkiPx$ zKzWc)bjZa}W+*}(>~0H=6VvvD!muXu;X=ZpgmwWT($kY9O<6)3R4tdnOyrK*J^Mq< zaRX6-4?3!@W$N@)rTw=WrU158F853Az)5(b<SyC_ni9U~I5>jQBv@{aMZ2Q$RCA&? z*%nPrTOfrnWiu-&RGS$-jNHd+36FFX$kcaIgPv4PUrS^?JH8UGslT~ld3|kjB|C$r zgoo;>fe<#D@+i=1h^KlY@wTWbwGY~}7_x}1>&0#);e!^DyKTyK(6&vMb1mU68J*F% zDLWv}XuP+Jxi#emxIevd_#GRYqu=h0f~XYx<jT>}o`zY2&f&3gBW#?6(`ee($dqwx zsU3QAligB`$+dpVVYj>zMwEB@y%(4gc8GR*dfjAi+Vo*diA<658?CXpUmmA*|9EuQ znOI++OeSCwPLyJ8eN)rQrs{A*Jlq~l#n#7p4@-rUmW9N}3P4zM6^<u*!YS=BMcb(` z+}4{+VphU!iFi*k(b*YIhOyY9opVfiG6dX`?1g|&mEw$CQMpyF@WT0bYKBnY?~qo( z-3+99I&I;vj&u^IXGn4F|4mK{k8X%De2>O(79`x6h_5&0IoM+(bRMZ}k9Ey6<$3PU z^G*4EEJfF7O?d$jv?o`|+J2D~ErSny5Op4c*Gq_3_|~4*7;jCNYh}CwtGBh47JEFp zrH3rkReHf+t(oO@d>EWb`9mt`>q-|~i-NlP)eW`vtt(d6)tmBqC^p7tE&Us%=o)-5 zh2>tjW{6St(<pDkC_5wTa1NKZuzA+T&f@DfJ&wBQrdV6FuEvyiz{Y@WU0}+)Xi}_k zQuQ_|Cc*O6I%~_amUXctB5H|bpDFK!3Uo($Hkfh%B8bCy=ug{W3#z84=A_!d%1`hC zr*CaEAH)aPfQEQS!jwOSMP6!I<nZD(%fl&ckI8E_<s%@T=q6+M81}8rru-R(w>gO^ zGvyO_ZR<=R>?40+_toBE%BS5Faf%6JK<g5n><63jS7f>3i1Wcf|HhBt2Hdg^`CGqi z(p&O#uzLA-2vhzJXJx0(<-D^imzuU0xPW?b6hq<&VRl8kDpRqoU=YWMP}<Nrw#}3{ zSE!1xDPNOf&wtCty#Wcew#PR4<)5@t|CtK9dOQ8{EnR>!g%3xgh@}GWKr7mCxao;n z`<W?mdhl(EBx8|v6bh3#C3xDBZ8&(z_YEO-?j(u`-uUH*nj-vsKjM+Dt?U!%P5SI% zO1SK1PhWRbPdJ=%MY9P%JlK=yPGIt5@B{6LkNg(|$7hw!c2j<Z3EI$}tm(uAp=ZC% z7`yUHf^e(7RVsMXo=t2wl?ShL=ion6dGXrXn?k%u`7p9pJD6muVN}D%L^T{MA<_-i zYOmc8L%(Vyn4riY_7YQ-Vz1RgYJp{F#C~F`5HzsLRHOa!MOGCx7A}8bbud*~zIxl; z*c<(~wnB=QbEGCxkhWS)!T{?MZP@jRkI7PuUTx1z{T7^O<LjeK5V15Bd|c0xNGH@^ z!O!KT2A|GU({t3{wV>1tbc-oSMtget5J)xEEWetdhg0tMjco0<*fkY7zV=|7I4)|B zWFZM|83OPm@VS`cHbh4es-^%E0wsDN^Dz-^_Eu-A1@zIerV7HC)TV6^#Spnddrmzu zrei9&%Cgl|)oik1l2V<pV04fe%z-X!N(<KvW@OcVYJZv}#8W1?_+{6xwVjPB`A4QY z2%$JVJ{pf6S;l}euxnsf(%AV%4_A7kt3x=nkqmOCLcDfl8?BMF7)`Z|_+)y_Ms6!O z(IdE(gJi1Z(7?9(EfGY*p<8gFJ!Hl=m}-?@RcTdef?DQP22-`5OS`Hj9cr*lBxcbU zi`sEywFYZF7CnrY>ROmc7>1>KFM#eeMN_?<kmZrQ2lS*&bu>7mb<Iw*!rYr^P#0a- zyWUh0=qG~8@Z?jtaG~A9`D>~+n6Z-uIt$~^%-N=bYwZcoo`sl*f?HiQbKc&wOm!?2 zc?R2%8K&xlzTp9fSk5#Rd|?TUq+hMp66isorr<D51xGli+FmdFf^P_v|C*`~oODHw zg*U8@qt_UAP*a_NS8StgkorkdG|ZeGF0cHb|DoZYf=JQq@bTf=IrVdz<}`*$-kTy7 z;pWY;9z+3fY1K|>r$L;ArVlsa%5Y76Rqe{kCG}MKU3jikxwtzS>kQAIJ8v&4Jp)%? z|9gCX4+n?YMD}dvq$%1N#U(+w+TsWiE~-42Iid3%%`DA2m7b6NW;Ukl2hi@}C94-V zwJu%0vS#ses=E*dP+x#lQYg<<7qemO;az|XeNA6_UsIRTl%NoX@^WZLePdlK$eHR& z%i>12bermGzuKa;;)hJj^0+MJcP!|&SfRGcIECakM(HpFO*Ykyux>zEh07D%Q_O=g zh0X10hP`h~X{O2cuOe?t!O<&@rRes`RPgk?6vrVSR^7%vth!x_z4RRoS>P}shT9@> zIzX+9!qw=Fw})f#aCb7X2{Fj_FoK~QQ#f6M+?`;GZ_y54vD{R5qa$1!(p`?ahmLdc zs9)X3o`8bOw@=zR3~xxJdMaskh7%oOM7P75X=Wgn;=>z`X(=)Ww7bDY^sMBI9R&xm zgqC(C`37-Q!ACT~n!Y1aa1uw*9Z_XnO(hP*>u9HeYv|`P+vQSl5lhM6TSqrd;okVh zIBtzh1($K+@<gQF%}l$s!?KsD;7LwldqF47iZD*>NeBrM<4TLRMuV4G)XC-@E~ZDH z_Z9rfk~Z=nNOxePegnqicxBH={T8(yv1CfCm#N@g`lwbP_7oh-048`<gzmL*4ADFL zix7Bp3pxV1m+`LM6jQwlVrhYz>JR8D?c2OA#iCm4+AL+uzdhE`5#{4C=2Q29qco{P zBpKC*X_V^W{SjBoEts<;q6={E+r!yS+7nSdhs>OA1aH%%tFU$q(o}Crv4lNtb~(b9 zw!@ZlS4239sn_TBM&8&XojCd97|8xkDokB>Ymeb=><2JT`pyn#{<gL#)O3oe{_0o# zdbzy|X*$crRDZ{=l;<jL)@msx=LRzDFm4NZy<YVXX!cCHEWc5GRH8mqA7ipp(N1g> zBbK8N=jw2gUwx|n3%7&nGYow{7zbRR9$>2f#u7w~nSyXq{BUN2`yQ^@N&?8fQeWh{ znX_;jjyNKZYm&k1qI|UTbk~qK$gOWU)fehti2kTA{n!=hu2X#tS>jw`-CG#6S>j_| ztjjbMhNj==n?{kYSdKH9QH*!Y9lx7sugy)}$`z(jg4NkZ*Q0eSYuP0-{6N+SrZEC% z5XauIIWq!ikG0>D=#I6eOe2VoIG1Xvn8qmj*w<x$90SqU)mWCm7>7!n((RAqX<1lZ zo5sZSC$O~}84Zfgfl19)7_4Z|%_-U)^q2szVPl#-6x(ev_CSel)2NM+F%wIZ={CgM zqgza4HhQ)DF^vk~Lx5!VlDgM9=z{BY7clfAZ3Ksn`QXehw8$>N=4BVLnD=&3)};1< z!rCbIWWs57C~3=M><2&HM#Cf{4vJMe&omCmSB_~v2tDf|TddSz1diNHqs|_X9^VoN zeL2S>jAamzM%M@j10kgkCVKvtrwiB$8jY~A9WbeFrm+gDgR>2cwrMnh5bely>}{Jy zi!*=ranitg*OTm&9B!Aah;}v8f!sL4C8m`f9XN-X#!;?WaGHJ#%1@`~dbpy-F<SZg zeH~~zT2k9oYZ~o9rQ24nhT-7jB!AdID=3lBHOFG4ZL|z+ZSKS_(AI*}avhRU&>k~^ z6%YqEZRF^uPgADRZL6l1ViLiM#u{rHoW{DY2ZCYO-Zmblu?g(s=8p%v1@C$SOk=A{ z7+B2f;a(WWqf9%0tx4^BnZ}9W+$w`eAjOlR=CqyZ9#6$6DaeBY)A$ZgI3=Cv`8^%< z^ztXSOXHl0(Qsmi{&*IeXo-RXByf&BSY3S{$m4QFfA~Idd4Ec2ZMgupKOF(K+$-Jl zMQDdjc10uxk&e%sFTzF<2EU7O#$+T>=vi7c3%B#f(C+X-iHI0i`i)DBOX=-u(9GUk zh#Yww(WKXaOE_9b5}J`N)fugU8l-xX5zJ(sOORE4%u4PVl!~3Ei~Pp5#&spej|{kv z-ehlFk8Q8qh+}56Jeve|JmW?KH~$?*zjj74n!qv2Bd`pVMN&-77Qm{$rrvm*Hdcpc zuW_psvoH@dUvW4ca2p|qUWy_j%Lg7V>Ai!FdujJpUQ6~oPi|i(Cw}90<Bk&JHUkdq zaK32lu<mN<zOf<S#`-@>D5T9(krLcPDMS2rAKmTo+x>J4#cvN#aFO43Q0$1`9-^=d zzdcN+YJPi^PM7@lIGrf??dRm|@Y|Dl6fG@hukn-=;mi?sbwkw2s>Q1stetBSj==)k z*@V1!E9eeykw*x5SmU4Hy$g4zdC~0o!@RFXUM8i|Rc%OgMXL~Vu0nDG@*m<=o$)PI z&IXSdC>>xbyO5(-WxcmSpW#+jAs?#>ai}WC#hTNN6Y+#>g>v20c#Y@065CM`%{^@7 za-?kPZJ0edSR^EZwryNNE38Bt0%92la_A&oOs<ZlV$jURbQEGAG$p3M0s2r#<7p)4 zndIL=PUA4S>-dSwM0(PtEkEtgh#2!{gaheGaWsA+NWxEq3iye`AwS`@;u!#4s1161 z0T+%P!izjp;eD<=Fmgbc!IE;dT?87-gC&&%Vw7ww4+N-qj9om&E-t0wadz=IyEsV2 z<L%<{c5#S`Cl);<c5AFOg5l;$!kC8l`PD_`!Ejj-b%xi#C_>!BV<FCLt}F`9&cdE) zV^<b&>)H0_^1v8sU19fLVfQ|kis#tHbL`@AR6N%%o@*DEQSp4cc)ndco{AUP#S84> zi4N_3$^$d-0fVfD{Pr6V2UWHjt<Axj%59>3yEv9cT4VECDYuL6^1$9`utOx*26jiQ zwMMXKyV%;iwkUW!KRv+{`B`jz_6ASp&!+V`P#ip!3j$ud#0-8%m-y_GlHlpOWLWS_ z{o)UvrC)~IB_o38=#r6kNg#NhE-4LuU%v!{7wDIeT{0?okuDi+my8KsqD#iwCF6pZ z>5?+LWPI=nT{0nfm42BRyhguFvP*Ug{z#Wh4qm5U!oeH#%M@L5zqkoPzQvw}gR|s# z8zUD5@8G8=co#p5gWLG&4c^O7)A|fK4sZeFxLv=P!Jp_CU+_WwQWE^Bei;^gM8Eih zkLj1;!Jp}u5y2<)%gEp_^h+T4w0<cK{z|_DgTK))A-nfc!QbkV(H6gfF~R3_$ygg_ zT<~|gq|D}LeDFnGGQs9~V(?{MGRfv}x8SR~WU|d+IQR!$GDY*F<@mZS$A~S*X<8o( z$?=a&<o_2rYHkAmFXf08Y|s5vJ@;C&f3_vt2gwHCg4m$8Z`*}isqnA5@Ljv`1S<Ty zF8shQJdp}N)P*10g(p$rr@HVntFTm@Or`&=OTTbR&q67irlRfQYc@<fko-`7uPmzE zCij*1%l#V5L-GIz|4QI*lQoSltd%y_p$^t{xmeHJSTEREvN#7zjkB<ny+xGDrMXxY zHkNI(OJy<_tJ%gn%<1uuxmdk6)@B<^&B?|3k&ShogVg~nw$Y|u6WTTxL0T`s#y79^ zST?h`JVX>x;<fCUiIT&(1Qy0JWL}g(Y6ms5euUHwPCwn~hi8a7!w!i3Af$ebdBlc* z&Q7x$WzC&>&*u1jixOg^bGFH6@4{X$jTiCnsUnPjM*;$XQa}(80*nHT0gMHV1C#;A z1117y0QLqP42S^w09yek08Rv)1UMOR7T`+2b?B}buoRF4{80!s2haiNhQ|SCRQnuq zBr@WQ(Bh@?V10QI(|!<k|MI|0jK4hCfR9)rhggFN%yO5muuEsVOIO;Z<?d2jNdpz` z(q<bM&vb9L;si(|93Ix#xK-}bwRY)Tcj=K<>40cW3w{sb!!Tz8W&vgc$^jLCN&ti- zssM9^B%fUi$2c8r;E<`y%1g!B)I;%r^fl^5J0OS4#sOJ+xjYoL=Wze856DsF25<)C z*pMuPx(vvPP?z0MUcrqA<nAa6$!WT-vD{lZAZNg}D;4Jwi6VCgvt{F2>OqWNQ|`&C z;PSC(b{;kJQf)aYTjgCSJKrW%T|~^56}1w#)kT`xI8Dt}Hyd?KaDO!ZJ`d$>u)IUg zwRE5PB2oi#Pg()gU-SKP!GK)o>h=O|`L5Nnm{(19OB#nm$WwsOMS1uq9*5*V4E`@> zF5FY$V)2qZly^xoOF;QjraZW0g6@uUMRYln_(mccj3P8vv00gq!-^1R1I_`Q3pfvO zKH&R+3jh}ZE(TlzxD;@?@e=;M0UCaRDDsMk7yla1dxZ3gYH?dekq~bRPZ~wz$f=oS zLUv|0lGkS<5MlX5W|@#*Wfl;UT9R1?`$eZ`y(Yy|!eoPWJ0|2RmgYDpTu9ar$YmAf zLHa=dEUOrhhhViemK)9ryBg>rxdKa%G&^7^D6Ln6ReLO{Hht6zijN-t=&@^y`D3yD z(aRsb_D7RHn%2k6)d5j!`(J{A2yqqQY77gZ06nbIDp4Ya2{B?KhIKvj*#bTr%T0&- z8(gJ<VyC#DWI(GbxCW!f88K~9ZpyAo6T6kF$k+_XHI4nlZYvM?a2k>`(EIIF6+neA zB(dO@RfOb`Y^`>;q*U!G50sRl%NY`{rQ(j<21n}#ggMNGd1o$WYZ}w<!n~U?OPGm> zW}+>PIoyT0Ef+JI#vI|oyq7RTay>MpqCDW|!S7Bij&vd2uaROJX_!WWkg7fX9)DS} zXS?jG_Lg~ZR)&xQWhP6(Ec4>{i-J<S0Akq=N+C(JSnVwj1j}GEAuum$9$=PB^9>G| zAs6OPT$t8eB&@*!bCe5nM+V=c(tLaSjbUXb^X)71f$x&?!00ka7R;2C`M@^{#@Gem z?m_NzOg`>><$<wf&<r&70rR0;%x_!V0dt%S^AX0xvh-E^cF5FPz4St|7wA}YA-S1f zJR#XfFZau>Wj^d#C!inRm)4=TM~Oyo4lnkTv`U-;WLnBzz10MUqXSyQff4+IsU6EN z#o&fs^qOS<4I4FWVgvH@HT}W>`6rnCd?tS;k=Kp&(mE0aXm%)R1?-A0qzM_2XG0W$ zGS^t2B0?c~uGXLoIi3%G*#p>}8jW`~db)6<A7nI|;A-?MYQ!U}_VIy-g@%n%3+-Br z>eq}C#7NO&P>=3H8Xa3dntGB@SqTM4G%36n(ffE^?xFVy`n{Om%k;Y!@A(ILvBNJ& znXS#FT9+|rSJJ41Jb-?&3EVwXh&%G`|7XnQ?G;_pI-zBAO|@BOKKbQeQS>ZvfraeD z;<QBcqqK-D<4PJ(W@<5!n&F+rM4E<o7E?&SvzSQaC?_!?YDeNH>*-7osz@~G^|CTA zH2q5S&3ussevZXLzGj-E>xd&33#Qy+falC&fSIuvU}k7Q=!Kcd&j5JKWFSz?1_c~E z&m3r(um@@L7;u;*LrHe?n(E@R;wQg&2d!`fv!rzxxUI%&z5%*W=E3-&l)x>$T#-_~ zM0g<?(<{U>#M;KHjoCJKqHR)b8#~D^0Hv2fDQ#nSbJ@dJsE>fQ-)pM9{S@HS))~!S z<;uJU7#bRKEwSG-Cj58T`uQ<Ug`NZ;qiR6joYwE%xHUQ<4$_*o^E4FwfvHVGlaRD_ zwOjRS!9)ipyV!q?Ff(=XcIr0Zqm{AiI?0X!%ogb`s{$E4TQ4W;cPL_cfQE?j03%Jr zhg^jXkTNqtnqERKtirGJNHbOVP8z^aDs1t@Ds1sO2up*g@Egnlk*M}&sxY>1Y+;xV z(!;b0e|2WRx&ftcQbR{OGduwG?QHEF)B|{nS;(tqS^NCkz)b6L*rf>XFb%y%SdTZA z2lNU6tAFLny!r$^p6t@&zcFT*=hZfHchh_T4TYK7e0o}&!?rdPA1-Y^0lmLRH2>2& zYMC_FQDWcG(fl^;o9O7@Stgk}de5%tsN2lCbu>RqgXrk{%)y{KO4{hs(NiIJ^4%-R z@D`O7J^AS}lzd2Zf^*q-xsPX+My1#43Veov!ogq)8tG8OM~shs8Rw?^Q6G{IaI3%+ zGz-Zcuu0rFBp>3|3lX#6vs7SrhsMWDL%U-SQ|pj?l-dOl;DAM3Xt`H6uK|Cb5N=35 zt_?mRgyhfJ@DX2A9h#pKUSKNMKgk@CdZA|`@?WmXr>GK+7?pp{j1(NqFLz}yUoee~ z!Th?=VE#q8yD*q9UHt071ZY;Q(R}5qb&W;}DyK7ONIv5X(iKJI<Gvh$2%Zqv18xBH z18xG`3b-9`2jEV?-GFU?dja<YwgVmj`~<KA@F3tJz$1W10Z#y)0z3`)72wx^X8?rz zEZ{l7^8liS`$|CpgqH!Y0A2<B-g^H7p05F32fP6wyf*=F0p13@1NbZ8Z`S*Jc>W#m zK7jCO93KKc0(=bk1n?<<Zel+Nd;$0u;7h<)I9Lk`WytptP2J>*93YZFp$viVae1BK zg)X$KREzNCt+Ek}UNLMC1P_9PMSmL-#dFjU-4x#_igUZcO)&oEmh-5*YlooeePRd% z--d$3eJAErA^rnd`mV{TutileWr+StE*b*C?=MK)KiL&qVone|dC?A@_-;k?i)8g` zd8ssM0a0Ybaj~qx0W6IZ|G+W?7Wpy`mgR^6%V*moSwdK}XdSFHE!@d#Ybr+)mVFk= zph;JNSnv1?vcsGP0e6E8@)-^MP6N8%cY4TZKv#-R55t`Xbj5Emo*6a(A0r$ry59%c zm^RCFkYG{>2o-NBE8>uWr_6(p0nX1O%g`^*{l#S-gbYv+unQn_y6V@*oNPf+c%?KQ zUXf#SG3}56FoP~kN(gYq%tt7Pw(A&;Mj=<DvcipA$7nPf<!UsMdEzs&XBUGLbfiIW z0+WsC{9%y5B%+ZSoS?g144$Qmi2v(6Qxh>ryM%5^_5HwUm;nUtxWbA@$Z+AIq_u>^ zJK8mrY1ByXnP6;RFgBeBM_#NQ@&XH^H48ef`6dw=V-x8Y2cXpqZbe=vZ{ylM9FT7l zyMwhxQ@#z-8<?efbf*f%qVq5AMX0y2c5lEhr>->qyV{MQ>sH_s;y4##B_RgKv(xec zI|l(8sU~}KNdANAe@xBFT+Qb3P$>KplAr1hXc33xXZV+bM^+e^XNrSI6yc!IFULTw zm=QcE_!@FgCZ<(IM_k;8TX76f7UcFv_rD?e1^$IXAD~wo(a@(y%Cn(&@*W)(cY-Kq z!<C}W`^8carxX<(rf~+dE5s4yvdDnOzPU8MWCp(`29dTyW`O$yay28vx$@ySui!ys z9_Qs1z*$5%?io}Hc-9P#cTL59OpI0p5yPP@lbDzdVj2gt>`a$JynSm(A+8RZBnU+7 z<o+3?N^(f;<KX0y(lf!%SdhXxj)aNu0U3n-c?oNr!3mS@XAnLxgYbwP!d2*8<Kz&A z)*MP&!#5hX1P)?)tk(*vLnk?E2(eotT1*HT(-LG6^1_<nnwA=-L@~aQMTuJ}s3lRQ zMHW(HxGh#cdcfa_t`gD?eL$ejF^t+=)`+@QTgSCynX1J&jl!y>Jqa6>KHPkMJl|<r z7wGz?>lV7Zl_mi9xv~T>5`fEeiOY0}i*$*Lbcu^}ITnD6bXf+N2$%#21Ev9{17-k- zRym*&Fb}XNU;zM^?Q&lL`HzbL`&qC*o&*P2a3G!p2LToXY5=u>I>0D)OGgU7JUEYA zs(z8<?T|ZZ)aNfgId5^%Yk7-3Q}P$TowvC7!2HFR<uCqg-eRvWfAPb)jvFPr>RYek zcSSMXdU@tRYYrj3;PBEKD4yP%-fpx?DhJeVbW4sacVGn(2^bYp_?J(Cu3Iv>lImGy zrQS}|?po{N`8bzma#c2#v^FVVIrnE+bfCp{!d@8G9?e?b<j}C!A9-e$8Y9!hb-!jv zEF<fFO|D_8nni1e%)MXpxz^|5)FAkx-Z#)edY8y_1YCD=xVR(MGdjtCCnt}{#ms*v zCyydbo}hx^T{#j{bTr{PZlw-g!3U-*H1SGy0ByJ(&9%e3BkTfD`WEx%3gVtYjwnWj z=$&lkZWN5(sEPoG6@5JM2wrhuoFs+!bd=twqx2(nIY$+T>vsxlQc{l`g$5LAqEX_N zqoL%M(L2R)K=U%PaKxA^8rErznkG%h!*`DFmwuE|4qrM94FSAmyV9s!$0M-)Z<nAD zuD&_@&ThDUMQ7jHjj#(qsqKGR7HZnA%YsJXlEuN+s9mxkrJx1j*!3?zK?$XD4IQ)! zIH#5MjE~JGJ7~p@liCBzoaZe!XjSUa*uXU0aUM03+F5S8J7|SzVKsi7^h+bSgH}O@ z=COpwUVTWWgH|Cm+p<oUMcC*<d&;UJRf<!&-lo$5pHi8iV!eLT#o2Kn<bF-YMso<D z5wH@l3UDZ(32+!-4d8IVTEG#2qX0((z6EHtp7a@6WfB?bvdwzZXKIg(F}WVF0T2Tm z3)l#V0}{N!?Ewq^$2=RH{9DeBV8;s7%ppPn_}=p1ff@C1{)mZsA*Y-YxZW+uiV+;5 zC!8<LyfGLKLm0oz=}(uxo@d{~S3C5+H}aPVS76`sp9cj<VWxHL-@T7*qWKRlAZ=Ik zNL{Rr5U)_EjLmGbi-2qQ+Tx<HXPN@pZcQN_4cY3ZkPd$w=PpjiJC1i3r=uDtQGZTK ziFqo{oA#D>3RQ8&#ULpquA~lmYHkD9_T@_IpiInc(yr~xmDwS`%b3Gq&7D&g9Rwi@ zIx+@a8}8}3n68u(cR1rr!gNwfXlJp=xg!~8YowSqB<U~<_CsSJdp``>+n>E3j<O4& zDwJiIz9t%-z9vGp0f~VQk~xFJRnr(3Cg%%Un3ntDN+}uZ!aP5NZ*tf%INHa({VJBd zJ&m(>BYS%)vkSmCrxbGLKn`~}_`32S<PUfpbOLuU?f4KdUC9sf0?pmITB;c>T=5|^ znwY)@lNT0l<cbfW(Ii(R&Kcw!2%Wq_dBI2rE|99yg7IET-Q<e~=@Xhe8l(?KD9MTj zWd?&TXR#1&-b{~+(B~D5LXjQH^w5T5FIx6?E(P^%CwdSiJJEwKd-2XUu5^`%ck+$w zfM({jIdO^Ifkqw?_G4Fa$7mK?zaS^zszMCugR0Id!StX@$Q%D6mj-?o<wBr9Qvw;% z!nAww)mbRIhAESTC_h3E6#<L%<uZ8$xF}>dkirdkXE%^y8+hlTlBDp?ZXjLg<=%Ja zUfkI?$C8$G+QIn}X|wWLVrmHQnB1Q0foH8@3Ng9N&J9Gt@tZU3gt*`v*@+v8(k@wp zA2TLI?-J#{yjgHO$_@wJ>?EmxV+fx7Z(=tsgPjo+-Grj_*miS`?Pl&r8%RC~r09N{ zLds}%3s-74ZV{Vg#2M&X+OYvva2`<xCr^e`>Ex~4l=Cx?K*LR}Kx>*~ofd+AhzS?R zC!^>#r@agy{`IvSPzTa>;O6~y#(|<EY-Ow4Vl5*QoX(v<Xo?eEuB6ubB-SraL=W4j zb^ckEhkT=1y_fme6&pVQ%=A9tN{hj5FKLE74>)J^&^$nJG!NUkGN0hFB2AY?e1H*I z>W;0c&DI*84n!W)YuZkYVJ^~Zdgn>#dk2%uRK$8slKRo%QCl5PPfxC+jwI*w<bHh< zXp%<)H(ke){+UF{Pq`P;6L?T`uB;?`gLn3YfWV20&MI!y8BBzPTzn4p6O~6@R4nte zRI^G-f=x1;>SNTv!fYT+9nRF|f;M6Ob|l^)Ft8KWr;C1(KzBdO?d}lW9f>PXcRzP^ zx8fUghrXWTz9^6ZF37^#L*dv75OmI=g+PMLMtH_efigC-5uS4)STb2jOzMopqO=Xg z*A~cvTL<$ZZNk~K7ikmD=DbLoaNgaDINy%ALR(5sf;)OycK@8Ew(H3f@<o;=W;XlW z$;lGx(8A|VCs{(i#5D4pJ1G|eVPaRZgnXHBht4mMudp1af`EPQbmbSwS6#JFk$82s zgnW(4vyYqE=SsPoSc>yq3a|;V8L$Pg6>uEjc)&@3Qvjy|P6K=wa5~^jz}WzN4MCm@ zz}FDu`2c(kLH+=60pLOazJ?$#1zZle0&o?8@U8(+`)dK$1CZY!Zv_0<dcO(Jn*p}~ zZnfTT!}E5)HUM%R<N)A)z;?g`*82`Tsh;@$Dc}*nqkzW%KLh+6@Du=f5Aqqna{%Nx z$QJ=G0bT~Y0(ceh8l8KU7vI|YeV%i#!p|_|Jusrp14A4(i>3{kOi=XlkSLzXLv-W0 zH~*=%cveByaS2msRK;HutnwaPxay6ZDxG8C-I-Hi#|_L=hZvao$q)#>r3H!mj>tZ; zBc;LhwHH3umz<kZB&1qxAMA&}g|BgVg%~y;rt;5NYI+wYTdFNOir-AHKr08-I)>WY z5XZUSBCL!whI|PMe<3W|t{hJ(O)Gt1f0wXqe?Eg|I)IGM(?|LD+zm3wXEaDBC~zvB z-9tu$0tpHqq#39E56NTJAryS16BIbFEsyWi*zddj8zm@wMBQcHu)5Cv?i2mTxtR6= z6po$ySpSJzNSU-<2T(L}Cn$VcxRL7sibn1Ph0k(%a?WA6=3fM*`e$Lf4l2hvoNNJo zkNP>2*1m0?`(1%NPx%Go*w?m)W507!x-oa9SBME~bbOR<b&qgYv&Xa$Bq(Q&@5{+M zb_?-KR8V#<l{<0*Ynr>A-1EPmnQ?u2sS-p(pT*Ttq-yquZ{b5o9Yg=hUCq_dX#fg4 zj7<|xCadqRQn1_^=O$Yf5iNV^WU5hmv5|P36b%f@lV(7zV+K?^1n>SX40%DE&OlBg zr!&wjH?KwN4o#(#*Fbk!%18A0K#eIxtm|uMhItAbfKoyz9K*Aml|4DZC^I!gCl5?? zC6+j;9{u7#Q1O2QDl}-PIogiowl<gR$?xJDuFTtL8g6EZcFJ*M9YYgTrO#<zKB0ni zkVx-ZZiy=;1vlg*lY*;9{Sc%_GmgD_a+4mA(W}O|MphpD0<Na}3ySH?6#f#ElbJ$O zNl`g`$GtrGXEd^Ni^hi3Mm^N#wPr|l;oX|<?4k2AQ)4q&%uS}i*Pqq6|0s)O{Q10S zC1hZ-^nNgLP{zwL7|%`Cfc3)tAkC51n*R;iLZq5g+P4PfZbAlkxfvgb4ycL$0q)Y- zB8A!OSGcpp1v<&5U^>%EpiCi@Z0*uJV)~oyR!SHSGnlxPRy|t1P99dj*aNht=F-Z* z0?Kseh~se{+7}!<L_5vpq6|9?1wg7ZE4i)%&G+Eu_GEuxEhLJ7t~D&XM_&&typA~9 zSx9UWSw%{x#$|DcuaJ9&=5RBb&&=TP<9}nR^H+{YHvC<D%wJjBoae6Z@1oDy8GU|c z_i2A?lDC5)#6shB_eqoBd=9`64Z;NWe{$rUNX%zT!Bd69ll|>{VSktXG5iXHkbefe z33v<e7r?uK_W(!~mmdH=1bhVe81M-I3F7iIz&`<>1HJ$tNnCyj*a^}^UIK~$9ssh3 z@Kb6+`2iyVK>#v`)M&sMz*xXIKp9{>U;<zwAPkrSm<pH<*aI*FFcUBveSt4k!55=1 z<7c!YuH%AzicvS@oIyDA$CIy^z7TKZPtY-H@-+}ed*m(ljLKiUDsOS|%{j$j1akAP zD^OvgF8A1r7UmBNRa}=-L2~ew<}Y55zql)3F-gt$V!j$tGBRH=H7NOBz8W!XSoXOP zCqDclpT5fVUXR}+7$!t98MrDabx3W60dysn1`&F}CGPRGU0{`2A5Y|uh$rjXlhd1t z>lRqerB%Wx!KZ<N!;zE2q~=o{hbjljmr@IurBlHY8aszjwHGz!U9mBwzJppjO2#M{ z%HD2-)AJxKbR(RZ2VoyK0{zHYb{G4)5zfhjQ0+!I4+vIBd0{rCMQ%j;i8P(Hg}_=i z=6-HW`VF;ggah0N7v(`%ObE_3xB62$vrE--TXMVyx#o7=_^3K+@Xa#2RDEtIuB&m^ zuPvx0xtOl2ao4XcsHKFdgM!$_C_H@$MvllbZO^WId9{og<~XLhj4-wPZ}4sexAO{a zb~80|UDB%t=41p5M#nrXOzyySNw1bOCf!d|d-!+f90!2+c>KPLS^*S&NTF_=d;5M- zi%L!p<ogY@zX9CjwqJ?%rN<zZnGc<=_DKI#P29hoafW=Y58yUf_f)ExDxGjdX1>-v z*%#tL`~KU$5D(b}=%$6cVL!!(-=NwI3sDiE{g}S=PA3@LuJY|A?YnsA+e_M~@y@rG z<g?+OZ!b9{&bP5_4p2-fY(yNdl){#EN$cgC9B@J7ab3e4WQ{+4i?S0x@1aQHoxS_3 z5K2}%+{1WWm1m8tC4?bE?4#_Em^y;-agNFkvGZk@x&~cXQLgOoBaU`x9LY5DgxKk# zH#5YJH~>%N<0N+deFk@G7k*Y#f3rt%CL?FWJ0W%wD;5SFnkflT-$;dUZ-T|3L+mO- z<wJ$o#WjMwhAIHO9W@_-ykoT&U~j-ez&?O|0o8y-fc*f-J64MUwSYQ6Jzxo7DPS3( z0k9mf0)Uh-wGz+-Xa=-cPx?$WRs+@ojsP49I0}GNFoo1G6(J8sJc<7a;y?3vFvh7l z@ndY<#$$O)U&`54vDe}+8tfb*T3dAIV7XUCx&1NOq8IXP*!baGy<x-OE5Vj6d>3E} zQ>-*Kqz9P1#`5&;+DkQL=23`$gZQ;Goq?=2W!50w(5dQUa&t+K)y-@kNe!&s0$+7a z@4s6a)1~q1R>rr~Ye3z>_HG_{JdRPdVso%bhlLgWj3y3TyfD(?q!S4{q_(kYTh!bh z#VJ(p-lA+%Z`tq+7lYHVtk{`l?nxLSbuagg5xHE7(}=RpmbQP~zzIfkEB-Pu_FHwo zb(cC9qx(+w=tAlNTJHMR&l;TdohWri4)gR?Wh}=u^L&v@5p>15Syl?Pwdp*hv8^e^ z&%{|%${AYh4cT#Ydw;S}@vC+g>N(8sEfBBP3%a_*x0)<G{Gy$OrxUVh0vwWBXvp1T zg~CtbS*SWAD+Bf63`X&bcor%rQgQQU^xMck<LZ)VF>a^T1;n8X=XlT}FUP*Y-VZnz z5{?se%;=iF#0`n!uf-^Sd5?PUmvv}(Q5JFA@pBWuxG?d@3lSIZfcPa@#IMW4`KA93 zaU>1FUC9)Sy>GcWzx>}JUJ2q?Qp1ddFZFXUpRL8fyxN8NFfI9zdXg~pQeEh*W}se^ zi~1B$T|r)Fmg!)@A4nZ3*vlUd;}6C91052qz=pe%YkA1(myQWcfBlty8Z*mQ(3j#_ zGXl=-lDeL-I0%Z|z{Y+9ftF!b;-|U+b?Jm4x665BMvdFY)G0~if`!yGVA}fTz}@6h zVpvF2QT^N{`;+Qfpj3N9l57p9h2W=VAWQ^{Du78DNodH#o(E<~y}<aCoC+-ZK`tEw zrQ9GJ(I!brpSdJ&abaeX9GOXy2IBIiYQPSsD{03_y#z)o*iT@Cu4C&+|H$xa(dIVl zFX-MXUg4H}SHLS3zd?B<5IIlDHvM)jQFGmIVPBzf!i9l!f3N9~UkN(o(%i+hRA8TA z)N6XmiH_^yM%_)Ajs+oi)Uv^jxqCx51Z8ULT<)Nkd#EjID4jM?8*G63WqRt<Y&;Hk z0Y~FQo-juAO%n3f?_+k!M|KcEkO*OqvA&&)ud}KF!pmHqe*$+*)A_nU_F_dB{bFyl z-k#g~O=@k4cwu%!G@&)&_{?8^gpwUhgk1x9AIqIx10K~1e8vur-8AhIKgjrbW}RGO znsv)VAUQph##Mh|+8iXMIn{FFtS0=tt+Q*<?txv4b3@@BfF%EttyYXmK5h_am3-JB zMl1QKLD7av%CW)NE(2|fc|6XYYxl%5Xz!482-mtUdxB7?6Zdagl&W8#IHdjt<eU)T z2Z9`4<e#Wsz$QQ+U@PD_z=?oU0LVR2rvbhLI0JAd0J$UT8~}1p6mn10_W>6GkaMCg z0$dEZ1aK+fGQj14D*;ynt^r&NxDIeV;0C~r0OX#ie!xut<en(xo^ToRPw+(rp^$r` z?f~2cxEpYf1^3}O0N4&7dOH9Q0v-Z90(czo1mG7OF5G}$0)Ecrxx%BCcV>Pz=4E|8 zFYEJrnV*Z6WqnR&e)b%m$GP|1S<qoGhUc6c<Ac);UW<>;@&4Hx_dc9MPUm@;yBDgM zUZ~=57yC@ye8)8a>nAE|T}a@|*Wvo?HGYR<jimo`i}ek}YsGM3fcuMQ->*KIeUJL5 zVc`FFu%ZG!^yh|QY(s&RMrlB7S6|(ucG|VUn!pUMElSslb}w!k(AEeUvbmxtWEjmA zo{-^bt|$%}-sTE#$nZ6TvOJ(voW-p@+*%TCxvzo5a%vs?10x+;Dz0RtVi(d%Gce8W zV;J`_ockEbeUx$^q2>xRWQ=Y`MqS7liwF8G!vlpA@bHC<NqCfmjLCQm3mH@J@P~}4 zcnl92)A1M)GG^d0GGxrcBM>sm@hA-$m3Rb0Mim~RkTDOBQ6XbbJVu9%z3><lG8W=7 zHe~FJ$GDKO2#>Omu|FQ;L&kx4Ob8i^@t7DgYVnv9GV1ZzEo3akV{*u7z#|+o4#8te z$XJ2L?jd6(9#cccp)8gcO2u_77OzVz&j-xFL|ZP+EEfz8vIlht0enLS=nx_}48%|b zfstGwE0PNh8gilDAr~4L<gx}2$Ym`akjs&HKrS>|$c07=xzK1K7aA?(LZgLTXqb=- z4HI%X8V|^&6%WWIf(PW%h6m&l#RGC#j|b!uqw%TnrLvgEXQs!e#+iYTJ-orE9fPOg zZNvk^qwX*~nr{pbBEj(F%Xs8WJIw}$N3((9(L`f-B!3K#<d5O8{M8)%I6U(gaOtJ0 z*k!#W8H2$tJiuTA4>0&`Jis6+0py>;0}S@!0r?a2kUudG2B+Ww2B+cy25H{FASo*t zoP`JEPs$4U(-<KCDm);6np4Q1rVsL`>4W@f`XGOrKFFV@4|++{2fd`}gI<y*LN7@! z(96wu<kw4e7=8|4%f+RbsyW~djJIbFLx52LDJUkmgA^cj2%(P^lQa@VAv{oa93KB! z#XJE$Krp1A5KJo`5KI)0vXI1lP*}25{!tIft&6>8V5~i&!FBN@5W|R0!6QAQUC_nT z&;V2YT|7nxN%=6-kdey*k+x!{X;v`Pq^6i@!o+~InqF6`=4jr1u66XI;=pK|_fpJ8 z5KS=|kU99o1c1#mcrq|BV*Pt~po}=dWSor$v~)Ng(9(19fR>(*2efoL9?(+KM6mt? zJkr+lLVSXjV){u-X>_5GdIJyeelbh>{ZiGfxh-*V`yQML+OFt-FQ&IE>wg%8U!B^f zcEa7jAD?lVak*7H1zVX!+2|c2vNmK~aldiZfN{-s<A&MWjhi$vpK-Hsi-jI!WNd!H z$ado{O->qj8{2ffyaPY9T?BIR*%g%&;PlX+4f=r?nh*#`ih}@kfMoy#9>ppE0*&Hu z00N5Q7(n}gaqnFN#sFYD;3t3w0Y3#i0(cDYGr$voU)&{$56K?U9Q>@)LA-n8dX9db zTo{h`flldH%kxxdpC?bn@<J_E6{=_{RG}S_JbfHhsKqgbD%uNGY$#Nre`h^U=gN2) kvQx&h#w&PE5(d7VDwU_f_?7W%dO6tmjqzK0Ng2=nADvk#IRF3v literal 0 HcmV?d00001 diff --git a/silecs-codegen/src/xml/genplcsrc.py b/silecs-codegen/src/xml/genplcsrc.py new file mode 100644 index 0000000..0c86eb8 --- /dev/null +++ b/silecs-codegen/src/xml/genplcsrc.py @@ -0,0 +1,723 @@ +#!/usr/bin/python +# Copyright 2016 CERN and GSI +# +# 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 3 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, see <http://www.gnu.org/licenses/>. + +import os +import sys +import time +import zlib +import libxml2 + +import iecommon +import iefiles +import xmltemplate +import s7template +import virtualS7Template +import rabbitTemplate + +from iecommon import * +#========================================================================= +# General remarks +#========================================================================= + +#XML input documents well-formed is not checked! +#This Python-script generates PLC sources document from XML Parameter documents +#which are supposed to be well-formed (generated with the 'genparam' script). + + +# Deploy global information +class Deploy(object): + plcModel = None # S7-300, .., Premium, .. + plcSystem = None # UNITY, STEP-7, TIA-PORTAL, ... + plcProtocol = None # DEVICE_MODE or BLOCK_MODE + address = None + checksum = None # checksum of the related parameter file + owner = None # onwer of the Deployment document + silecsVersion = None + +whichUnityFormat = { + 'uint8' : 'BYTE', + 'int8' : 'WORD', + 'uint16' : 'WORD', + 'int16' : 'INT', + 'uint32' : 'DWORD', + 'int32' : 'DINT', + 'float32' : 'REAL', + 'string' : 'STRING', +# 'uint64' : '8', not supported with PLC +# 'int64' : '8', not supported with PLC +# 'float64' : '8', not supported with PLC + 'date' : 'DT', + 'char' : 'WORD', + 'byte' : 'BYTE', + 'word' : 'WORD', + 'dword' : 'DWORD', + 'int' : 'INT', + 'dint' : 'DINT', + 'real' : 'REAL', + 'dt' : 'DT' +} + +whichTwincatFormat = { + 'uint8' : 'BYTE', + 'int8' : 'SINT', + 'uint16' : 'WORD', + 'int16' : 'INT', + 'uint32' : 'DWORD', + 'int32' : 'DINT', + 'float32' : 'REAL', + 'string' : 'STRING', +# 'uint64' not supported by PLCs +# 'int64' not supported by PLCs +# 'float64' not supported by PLCs + 'date' : 'DT', + 'char' : 'SINT', + 'byte' : 'BYTE', + 'word' : 'WORD', + 'dword' : 'DWORD', + 'int' : 'INT', + 'dint' : 'DINT', + 'real' : 'REAL', + 'dt' : 'DT', + 'string' : 'STRING' +} + +schneiderRegArray = """ARRAY[0..%d] OF %s""" +schneiderRegArray2d = """ARRAY[0..%d, 0..%d] OF %s""" + +# Beckhoff templates (using newlines \r\n because TwinCAT compiler complains with line feed character) +beckhoffReg = """ %s_%04x_%s AT %%MW%s: %s;\r\n\r\n""" +beckhoffRegArray = """ %s_%04x_%s AT %%MW%s: ARRAY [0..%d] OF %s;\r\n\r\n""" +beckhoffRegArray2d = """ %s_%04x_%s AT %%MW%s: ARRAY [0..%d, 0..%d] OF %s;\r\n\r\n""" +beckhoffRegInit = """ %s_%04x_%s AT %%MW%s: %s:= %s;\r\n\r\n""" + +#========================================================================= +# Sub-function +#========================================================================= + +#------------------------------------------------------------------------- +# Schneider registers +#------------------------------------------------------------------------- + +def xsyRegister(regFormat, regDim, regDim2, regLen=1): + if regLen > 1: # register is a string or an array of strings + strLen= whichUnityFormat[regFormat]+'['+str(regLen)+']' + if regDim == 1 and regDim2 ==1: # string + return strLen + elif regDim > 1 and regDim2 == 1: # string array + return schneiderRegArray %(regDim-1, strLen) + else: # dim1>=1 and for whatever dim2, use double array syntax + return schneiderRegArray2d %(regDim-1, regDim2-1, strLen) + else: + if regDim == 1 and regDim2 ==1: # scalar + return whichUnityFormat[regFormat] + elif regDim > 1 and regDim2 == 1: # array + return schneiderRegArray %(regDim-1, whichUnityFormat[regFormat]) + else: # dim1>=1 and for whatever dim2, use double array syntax + return schneiderRegArray2d %(regDim-1, regDim2-1, whichUnityFormat[regFormat]) + +def getDateTime(): + dt = time.localtime(time.time()) + return "DT#%s-%s-%s-%s:%s:%s" %(dt[0],dt[1],dt[2],dt[3],dt[4],dt[5]) + +#------------------------------------------------------------------------- +# SIEMENS PLC code generation +#------------------------------------------------------------------------- +def generateSiemensSources(paramDOM, sourceFolderPath ,logTopics): + stlString = '' + symString = '' # for .sdf Symbol file + + deploy = getDeploymentInformation(paramDOM) + + # Prepare the Simatic Symbols (<.sdf> file) + DBnumber = long(deploy.address) #first data-block (SilecsHeader) starts from the base-address + UDTnumber = long(deploy.address) #use base data-block address for UDT number as well (to be reserved by the developer) + + # Generate sources for each class that is deployed in the PLC + classNodes = paramDOM.xpathEval("/SILECS-Param/SILECS-Mapping/SILECS-Class") + for classNode in classNodes: + blockDOMList = classNode.xpathEval("Block") # get Blocks elements of that class + deviceDOMList = classNode.xpathEval("Instance") # get Device instances of that class + + className = classNode.prop('name') + classVersion = classNode.prop('version') + + deviceNumber = len(deviceDOMList) + + # Generate the Blocks definition + for blockIndex, blockDOM in enumerate(blockDOMList): + registerList = '' + blockName = blockDOM.prop('name') + registerDOMList = blockDOM.xpathEval("Register") # get registers of the current block + for registerIndex, registerDOM in enumerate(registerDOMList): + registerName = registerDOM.prop('name') + registerFormat = registerDOM.prop('format') + + # If PLC does not supports this register format abort this generation and log the error + if(registerFormat in ['uint64','int64','float64']): + iecommon.logError('ERROR: In design %s_%s register %s, %s format not supported for current controller model.' + %(className, classVersion, registerName, registerFormat) + , True,logTopics) + + #create register value if required (diagnostic registers assignment in particular) + registerValue = s7template.stlRegisterValue(registerName, deploy.owner, getDateTime(), deploy.checksum,deploy.silecsVersion) + + # Read register dimensions + registerDimension1 = long(registerDOM.prop('array-dim1')) + registerDimension2 = long(registerDOM.prop('array-dim2')) + + if registerFormat == 'string': + registerList += s7template.stlRegister(registerName, registerFormat, registerDimension1, registerDimension2, registerValue, long(registerDOM.prop('string-len'))) + else: + registerList += s7template.stlRegister(registerName, registerFormat, registerDimension1, registerDimension2, registerValue) + + stlString += s7template.stlBlockUDT(deploy.owner, className, classVersion, blockName, registerList, (blockIndex == 0)) + symString += s7template.symBlockUDT(className, classVersion, blockName, UDTnumber, (blockIndex == 0)) + UDTnumber += 1 + + if deploy.plcProtocol == 'DEVICE_MODE': + # Generate the Data-Blocks: one DB per Device instance + for deviceIndex, deviceDOM in enumerate(deviceDOMList): + blockList = '' + for blockDOM in blockDOMList: + blockName = blockDOM.prop('name') + blockList += s7template.stlBlock(className, blockName) + deviceLabel = deviceDOM.prop('label') + stlString += s7template.generateBlock(deploy.owner, className, classVersion, deploy.plcSystem, DBnumber, deviceLabel, blockList, (deviceIndex == 0),deploy.plcProtocol) + symString += s7template.symDeviceDB(className, classVersion, deviceLabel, DBnumber, (deviceIndex == 0)) + DBnumber += 1 + + else: # BLOCK_MODE + # Generate the Data-Blocks: one DB per Block of registers + for blockIndex, blockDOM in enumerate(blockDOMList): + blockName = blockDOM.prop('name') + + deviceList = '' + for deviceDOM in deviceDOMList: + deviceLabel = deviceDOM.prop('label') + deviceList += s7template.stlDevice(deviceLabel, className, blockName) + + stlString += s7template.generateBlock(deploy.owner, className, classVersion, deploy.plcSystem, DBnumber, blockName, deviceList, (blockIndex == 0),deploy.plcProtocol) + symString += s7template.symBlockDB(className, classVersion, blockName, DBnumber, (blockIndex == 0)) + DBnumber += 1 + + # write the String PLC generated code + generateControllerFiles(sourceFolderPath,deploy,".scl",stlString,logTopics); + + # Write the String PLC generated symbols into the <.sdf> symbols file + generateControllerFiles(sourceFolderPath,deploy,".sdf",symString,logTopics); + +#------------------------------------------------------------------------- +# SCHNEIDER PLC code generation +#------------------------------------------------------------------------- + +# ---------------------------------------------------- +def generateSchneiderRegisters(xsydoc, classDOM, deviceDOM, blockDOM, deviceIndex, modeDevice, deploy, logTopics): + + className = classDOM.prop('name') + deviceLabel = deviceDOM.prop('label') + blockName = blockDOM.prop('name') + + #Device and Block adresses come from the generated Paramerers file. Depends on the protocol mode: + #DEVICE_MODE: relative address of the element within it parent node + #BLOCK_MODE : absolute address in the entire PLC memory + deviceAddress = long(deviceDOM.prop('address')) + blockAddress = long(blockDOM.prop('address')) + blockMemSize = long(blockDOM.prop('mem-size')) + registerDOMList = blockDOM.xpathEval("Register") # get Registers of the current block + for registerIndex,registerDOM in enumerate(registerDOMList): + registerName = registerDOM.prop('name') + registerFormat = registerDOM.prop('format') + registerDimension1 = long(registerDOM.prop('array-dim1')) + registerDimension2 = long(registerDOM.prop('array-dim2')) + + # If PLC does not supports this register format abort this generation and log the error + if(registerFormat in ['uint64','int64','float64']): + iecommon.logError('ERROR: In register '+registerName+', '+registerFormat+' format not supported for current controller model.', True,logTopics) + + #register has relative address irrespective of the protocol mode. + registerOffset = long(registerDOM.prop('address')) + + # Compute the Register address relying on the Class Parameters file data + # Attention! Schneider uses WORD addressing while Parameters data are expressed in bytes to be PLC independent + if modeDevice: + registerAddress = (deviceAddress + blockAddress + registerOffset)/2 + else: + registerAddress = (blockAddress + (deviceIndex * blockMemSize) + registerOffset)/2 + + # then insert the corresponding DOM element + dataElt = xsydoc.xpathEval("//dataBlock")[0] #only one dataBlock node has been inserted so far + regElt = libxml2.newNode('variables') + # Compute the base checksum of the class name + classNameCRC = zlib.crc32(className,0) & 0xffff + # Create register name = regname_crc32(classname)_deviceid + # 24 char (register name) + 1 (underscore) + 4 char (CRC classname) + 1 (underscore) + n (device id) = 30 + n (device id) + # possible problem when device id (n)> 99 --> string > 32 not compatible with Schneider PLCs + regElt.setProp("name", "%s_%04x_%s" %(registerName, classNameCRC, deviceLabel)) + + if registerFormat == 'string': + regElt.setProp("typeName", "%s" %xsyRegister(registerFormat, registerDimension1, registerDimension2, registerDOM.prop('string-len'))) + else: + regElt.setProp("typeName", "%s" %xsyRegister(registerFormat, registerDimension1, registerDimension2)) + + + regElt.setProp("topologicalAddress", "%%MW%ld" %registerAddress) + if blockName == 'hdrBlk': + initElt = libxml2.newNode('variableInit') + if registerName == '_version': initElt.setProp("value", deploy.silecsVersion ) + if registerName == '_user' : initElt.setProp("value", deploy.owner) + if registerName == '_checksum': initElt.setProp("value", "%s" %deploy.checksum) + if registerName == '_date' : initElt.setProp("value", getDateTime()) + regElt.addChild(initElt) + commElt = libxml2.newNode('comment') + commElt.setContent(className+"/"+deviceLabel+"/"+blockName) + regElt.addChild(commElt) + dataElt.addChild(regElt) + +# ---------------------------------------------------- +def generateSchneiderSources(paramDOM,sourceFolderPath,logTopics): + #Base address provided by the user in the Deployment relies on the PLC model: + #Quantum, Premium and M340 Schneider PLCs are all interpreted as using 16-bit addressing, + #even though M340 addresses are later properly considered as 32-bit addresses + + deploy = getDeploymentInformation(paramDOM) + + # Create the Schneider DOM source (Unity <.XSY> XML document) + xsyDoc = libxml2.newDoc(version='1.0') + rootElt = libxml2.newNode('VariablesExchangeFile') + xsyDoc.addChild(rootElt) + dataElt = libxml2.newNode('dataBlock') + rootElt.addChild(dataElt) + + classNodes = paramDOM.xpathEval("/SILECS-Param/SILECS-Mapping/SILECS-Class") + for classNode in classNodes: + address = int(classNode.prop('address')) #address of the first register of the configuration + blockDOMList = classNode.xpathEval("Block") # get Blocks elements of that class + deviceDOMList = classNode.xpathEval("Instance") # get Device instances of that class + + for blockDOM in blockDOMList: + for deviceIndex,deviceDOM in enumerate(deviceDOMList): + if deploy.plcProtocol == 'DEVICE_MODE': #------------------- + generateSchneiderRegisters(xsyDoc, classNode, deviceDOM, blockDOM, deviceIndex, True, deploy, logTopics) + else: + generateSchneiderRegisters(xsyDoc, classNode, deviceDOM, blockDOM, deviceIndex, False, deploy, logTopics) + + # Finally, write the DOM object (PLC generated code) into the XSY source file + generateControllerFiles(sourceFolderPath,deploy,".xsy",rootElt.serialize(format = True),logTopics); + + xsyDoc.freeDoc() + +# ---------------------------------------------------- +def generateRabbitSources(paramDOM,sourceFolderPath,logTopics): + deviceLabel = '' + + deploy = getDeploymentInformation(paramDOM) + + # Prepare the source (<.h> file) with its diagnostic data-block header + cCodeString = rabbitTemplate.cHeader(deploy.address,deploy.silecsVersion) + cTypeDefinitions = '' + cDataAllocation = rabbitTemplate.cAllocationComment(deploy.plcProtocol) + + blockList = '' + classList = '' + NBdeviceDefinitionList = '' + + classNodes = paramDOM.xpathEval("/SILECS-Param/SILECS-Mapping/SILECS-Class") + for classNode in classNodes: + blockDOMList = classNode.xpathEval("Block") # get Blocks elements of that class + deviceDOMList = classNode.xpathEval("Instance") # get Device instances of that class + + className = classNode.prop('name') + classVersion = classNode.prop('version') + + deviceNumber = len(deviceDOMList) + + #==== Generate the Blocks definition ==== + for blockIndex, blockDOM in enumerate(blockDOMList): + registerList = '' + blockName = blockDOM.prop('name') + registerDOMList = blockDOM.xpathEval("Register") # get Registers of the current block + for registerIndex, registerDOM in enumerate(registerDOMList): + registerName = registerDOM.prop('name') + registerFormat = registerDOM.prop('format') + registerDimension1 = long(registerDOM.prop('array-dim1')) + registerDimension2 = long(registerDOM.prop('array-dim2')) + + # If PLC does not supports this register format abort this generation and log the error + if(registerFormat in ['float64']): + iecommon.logError('ERROR: In register '+registerName+', '+registerFormat+' format not supported for current controller model.', True,logTopics) + + if(registerFormat == 'string'): + registerList += rabbitTemplate.cRegister(registerName, registerFormat, registerDimension1, registerDimension2, long(registerDOM.prop('string-len'))) + else: + registerList += rabbitTemplate.cRegister(registerName, registerFormat, registerDimension1, registerDimension2) + + cTypeDefinitions += rabbitTemplate.cBlockUDT(className, classVersion, blockName, registerList, (blockIndex == 0)) + + #==== Memory allocation ==== + if deploy.plcProtocol == 'DEVICE_MODE': + # Generate the List of block in the class + blockList ='' + for blockIndex, blockDOM in enumerate(blockDOMList): + blockName = blockDOM.prop('name') + blockList += rabbitTemplate.cDeviceModeBlockInstantiation(className, blockName) + + deviceList = '' + for deviceDOM in deviceDOMList: + deviceLabel = className + "_" + deviceDOM.prop('label') + deviceList += deviceLabel + ', '; + deviceList = deviceList[:-2] # remove last comma space + classList += rabbitTemplate.cDeviceModeClass_deviceList(blockList, deviceList) + + + else: # BLOCK_MODE + # Generate the List of block in the class + for blockIndex, blockDOM in enumerate(blockDOMList): + # create instantation for current block + blockName = blockDOM.prop('name') + + deviceList = '' + for deviceDOM in deviceDOMList: + deviceLabel = deviceDOM.prop('label') + deviceList +=rabbitTemplate.cBlockModeDeviceInstantiation_deviceList(className, blockName, deviceLabel) + + blockList += rabbitTemplate.cBlockModeBlockInstantiation(deviceList, className, blockName) + + # Predefine number of devices constant + cDataAllocation += NBdeviceDefinitionList + + if deploy.plcProtocol == 'DEVICE_MODE': + cDataAllocation += rabbitTemplate.cDeviceModeDataInstantiation(classList) + cInitFunction = rabbitTemplate.cInitDeviceMode(deploy.silecsVersion,deploy.checksum,deploy.owner) + else: + cDataAllocation += rabbitTemplate.cBlockModeDataInstantiation(blockList) + cInitFunction = rabbitTemplate.cInitBlockMode(deploy.silecsVersion,deploy.checksum,deploy.owner) + + + # Append data definitions + cCodeString += cTypeDefinitions + + # Append data allocation + cCodeString += cDataAllocation + + # Append initialization function + cCodeString += cInitFunction + + # Generate and append sample example + cCodeString += rabbitTemplate.cExample(deploy.plcProtocol,True,className, blockName, registerName, deviceLabel) + + # Finally, write the String C generated code into the temporal output file + generateControllerFiles(sourceFolderPath,deploy,".h",cCodeString,logTopics); + + +# ---------------------------------------------------- +def generateVirtualS7Sources(paramDOM,sourceFolderPath,logTopics): + deploy = getDeploymentInformation(paramDOM) + includeDesign = '' + allocDesign = '' + deleteDesign = '' + getDesign = '' + + protocolMode = 'BlockMode'; + if deploy.plcProtocol == 'DEVICE_MODE': + protocolMode = 'DeviceMode'; + duConstructor = virtualS7Template.vs7DuConstructor(deploy.plcName, protocolMode, deploy.address) + + classNodes = paramDOM.xpathEval("/SILECS-Param/SILECS-Mapping/SILECS-Class") + + # Generate sources for each class that is deployed in the PLC + for classNode in classNodes: + + blocksCodeString = '' + + createBlockCodeString = '' + deleteBlockCodeString = '' + deviceCodeString = '' + + createDeviceCodeString = '' + deleteDeviceCodeString = '' + designCodeString = '' + + blockDOMList = classNode.xpathEval("Block") # get Blocks elements of that class + deviceDOMList = classNode.xpathEval("Instance") # get Device instances of that class + + className = classNode.prop('name') + classVersion = classNode.prop('version') + + #DEPLOY-UNIT code generation ============================ + includeDesign += virtualS7Template.vs7DuDesignInclude(className, classVersion) + allocDesign += virtualS7Template.vs7DuDesignAlloc(className, classVersion) + deleteDesign += virtualS7Template.vs7DuDesignDelete(className) + getDesign += virtualS7Template.vs7DuDesignGet(className, classVersion) + + #CLASSES code generation ================================ + for blockIndex, blockDOM in enumerate(blockDOMList): + getSetCodeString = '' + dimsCodeString = '' + dataCodeString = '' + + currentRegisterAddress = 0 #used to compute even/odd adress and insert align data by adding dummy registers + previousRegisterMemSize = 0 #... + dummyIndex = 0; + + blockName = blockDOM.prop('name') + blockOffset = blockDOM.prop('address') + registerDOMList = blockDOM.xpathEval("Register") # get Registers of the current block + + createBlockCodeString += virtualS7Template.vs7ClassCreateBlock(className, blockName) + deleteBlockCodeString += virtualS7Template.vs7ClassDeleteBlock(className, blockName) + + for registerIndex, registerDOM in enumerate(registerDOMList): + registerName = registerDOM.prop('name') + registerFormat = registerDOM.prop('format') + registerDimension1 = long(registerDOM.prop('array-dim1')) + registerDimension2 = long(registerDOM.prop('array-dim2')) + registerMemSize = long(registerDOM.prop('mem-size')) #store the reigster mem-size for next iteration + + registerLength = 1 #in case string + if(registerFormat == 'string'): + registerLength = long(registerDOM.prop('string-len')) + + getSetCodeString += virtualS7Template.vs7ClassGetSet(registerName, registerFormat, registerDimension1, registerDimension2,registerLength) + dimsCodeString += virtualS7Template.vs7ClassDimension(registerName, registerFormat, registerDimension1, registerDimension2,registerLength) + + #Specific code to force 16bit alignment if not scalar 8bit register (==> insert dummy register if needed) + dummyCodeString = virtualS7Template.vs7ClassDummyRegister(currentRegisterAddress, previousRegisterMemSize, registerMemSize, dummyIndex) + dataCodeString += dummyCodeString + currentRegisterAddress += registerMemSize + if dummyCodeString != "": + dummyIndex += 1 + currentRegisterAddress += 1 + #and now insert the normal data register + dataCodeString += virtualS7Template.vs7ClassDataRegister(registerName, registerFormat, registerDimension1, registerDimension2, registerLength) + previousRegisterMemSize = registerMemSize + + blocksCodeString += virtualS7Template.vs7ClassBlock(deploy.silecsVersion, deploy.owner, deploy.checksum, className, blockName, getSetCodeString, blockOffset, dimsCodeString, dataCodeString) + + for deviceIndex, deviceDOM in enumerate(deviceDOMList): + deviceLabel = deviceDOM.prop('label') + createDeviceCodeString += virtualS7Template.vs7ClassCreateDevice(className, deviceLabel, deviceIndex) + deleteDeviceCodeString += virtualS7Template.vs7ClassDeleteDevice(className, deviceLabel) + + deviceCodeString = virtualS7Template.vs7ClassDevice(createBlockCodeString, deleteBlockCodeString) + designCodeString = virtualS7Template.vs7ClassDesign(className, classVersion, createDeviceCodeString, deleteDeviceCodeString) + + classCodeString = virtualS7Template.vs7ClassHeader(className, classVersion, blocksCodeString, deviceCodeString, designCodeString) + + # write the CLASS generated code into the temporal output file + generateControllerFiles(sourceFolderPath,deploy, "." + className + ".h",classCodeString,logTopics); + + # Prepare the source (<.h> file) with its diagnostic data-block header + duCodeString = virtualS7Template.vs7DuHeader(deploy.plcName, duConstructor, includeDesign, allocDesign, deleteDesign, getDesign) + + # Write the DEPLOY-UNIT generated code into the temporal output file + generateControllerFiles(sourceFolderPath,deploy,".h",duCodeString,logTopics); + + # Prepare the source (<.h> file) with its diagnostic data-block header + mainCodeString = virtualS7Template.vs7MainCode(deploy.plcName) + + # write the DEPLOY-UNIT generated code into the temporal output file + generateControllerFiles(sourceFolderPath,deploy,".cpp",mainCodeString,logTopics); + +# ---------------------------------------------------- +def generateBeckhoffRegisters(classDOM, deviceDOM, blockDOM, deviceIndex, deploy, logTopics): + source = '' + className = classDOM.prop('name') + deviceLabel = deviceDOM.prop('label') + blockName = blockDOM.prop('name') + + #Device and Block adresses come from the generated Paramerers file. Depends on the protocol mode: + #DEVICE_MODE: relative address of the element within it parent node + #BLOCK_MODE : absolute address in the entire PLC memory + deviceAddress = long(deviceDOM.prop('address')) + blockAddress = long(blockDOM.prop('address')) + blockMemSize = long(blockDOM.prop('mem-size')) + + registerDOMList = blockDOM.xpathEval("Register") # get registers of the current block + + for registerIndex, registerDOM in enumerate(registerDOMList): + registerName = registerDOM.prop('name') + registerFormat = registerDOM.prop('format') + registerDimension1 = long(registerDOM.prop('array-dim1')) + registerDimension2 = long(registerDOM.prop('array-dim2')) + + if registerDOM.prop('string-len'): # only appears for string registers + registerLength = long(registerDOM.prop('string-len')) + + if blockName == 'hdrBlk': + if registerName == 'ieVersion' or registerName == 'ieUser': + registerFormat = 'string' + registerDimension1 = 1 + + # If PLC does not supports this register format abort this generation and log the error + if(registerFormat in ['uint64','int64','float64']): + iecommon.logError('ERROR: In register '+registerName+', '+registerFormat+' format not supported for current controller model.', True) + return + + #register has relative address irrespective of the protocol mode. + registerOffset = long(registerDOM.prop('address')) + iecommon.logDebug("Processing: %s %s %s %s" %(className, deviceLabel, blockName, registerName)) + + # Compute the register address relying on the Class Parameters file data + # Attention! Beckhoff uses WORD addressing while Parameters data are expressed in bytes to be PLC independent + if deploy.plcModel == 'BC9020': + registerAddress = (blockAddress - long(deploy.address) + (deviceIndex * blockMemSize) + registerOffset)/2 + elif deploy.plcModel == 'CX9020': + registerAddress = (blockAddress - long(deploy.address) + (deviceIndex * blockMemSize) + registerOffset) + else: + raise "PLC model not supported: " + deploy.plcModel + + # add comment to source to identify block + source += ' (*'+className+'/'+deviceLabel+'/'+blockName+' *)\r\n' + + # Compute the base checksum of the class name + classNameCRC = zlib.crc32(className,0) & 0xffff + + if blockName == 'hdrBlk': + if registerName == '_version': + source+=beckhoffRegInit %(registerName, classNameCRC, deviceLabel, registerAddress, whichTwincatFormat[registerFormat]+"(16)", deploy.silecsVersion ) + if registerName == '_user': + source+=beckhoffRegInit %(registerName, classNameCRC, deviceLabel, registerAddress, whichTwincatFormat[registerFormat]+"(16)", "'"+deploy.owner+"'") + if registerName == '_checksum': + source+=beckhoffRegInit %(registerName, classNameCRC, deviceLabel, registerAddress, whichTwincatFormat[registerFormat], deploy.checksum) + if registerName == '_date': + source+=beckhoffRegInit %(registerName, classNameCRC, deviceLabel, registerAddress, whichTwincatFormat[registerFormat], getDateTime()) + + else: # not header block + # set data type - for string with fixed value registerLength + if registerFormat == 'string': + format = whichTwincatFormat[registerFormat]+'('+str(registerLength)+')' + else: + format = whichTwincatFormat[registerFormat] + + if registerDimension1 == 1 and registerDimension2 == 1: # scalar + source += beckhoffReg %(registerName, classNameCRC, deviceLabel, registerAddress, format) + elif registerDimension1 > 1 and registerDimension2 == 1: # array + source += beckhoffRegArray %(registerName, classNameCRC, deviceLabel, registerAddress, registerDimension1-1, format) + else: # dim1>=1 and for whatever dim2, use double array syntax + source += beckhoffRegArray2d %(registerName, classNameCRC, deviceLabel, registerAddress, registerDimension1-1, registerDimension2-1, format) + + return source +# ---------------------------------------------------- +def generateBeckhoffSources(paramDOM, sourceFolderPath, logTopics): + deploy = getDeploymentInformation(paramDOM) + + # Prepare the global variables source (<.exp> file) with its diagnostic data-block header + source ="""(* +-------------------------------------------------------------------\r\n""" + source += """* | C.E.R.N Geneva, Switzerland\r\n""" + source += """* | SILECS - BE/CO-FE\r\n""" + source += """* | April 2015\r\n""" + source += """* +-------------------------------------------------------------------\r\n""" + source += """*\r\n""" + source += """* Release : SILECS_%s\r\n"""%(deploy.silecsVersion) + source += """*)""" + + source += '\r\nVAR_GLOBAL\r\n' + + classNodes = paramDOM.xpathEval("/SILECS-Param/SILECS-Mapping/SILECS-Class") + for classNode in classNodes: + address = int(classNode.prop('address')) # address of the first register of the configuration + blockDOMList = classNode.xpathEval("Block") # get Blocks elements of that class + deviceDOMList = classNode.xpathEval("Instance") # get Device instances of that class + + # Device mode is not supported for Beckhoff PLCs - Only block mode available + for blockDOM in blockDOMList: + for deviceIndex, deviceDOM in enumerate(deviceDOMList): + source += generateBeckhoffRegisters(classNode, deviceDOM, blockDOM, deviceIndex,deploy,logTopics) + + source += 'END_VAR' + + # Write the source into the EXP source file + generateControllerFiles(sourceFolderPath,deploy,".exp",source,logTopics); + +#------------------------------------------------------------------------- +# NI code generation +#------------------------------------------------------------------------- +def generateNISources(paramDOM, sourceFolderPath ,logTopics): + iecommon.logInfo("PLC source generation not available for National Instruments equipment",logTopics) + return + +def getDeploymentInformation(paramDOM): + deploy = Deploy() + mapping = paramDOM.xpathEval("/SILECS-Param/SILECS-Mapping")[0] + + deploy.plcModel = mapping.prop('plc-model') + deploy.plcSystem = mapping.prop('plc-system') + deploy.plcProtocol = mapping.prop('protocol') + deploy.plcName = mapping.prop('plc-name') + deploy.address = mapping.prop('address') + ownerNode = paramDOM.xpathEval("/SILECS-Param/Mapping-Info/Owner")[0] + deploy.owner = ownerNode.prop('user-login') + deploymentNode = paramDOM.xpathEval("/SILECS-Param/Mapping-Info/Deployment")[0] + deploy.checksum = long(deploymentNode.prop('checksum')) + rootNode = paramDOM.xpathEval("/SILECS-Param")[0] + deploy.silecsVersion = rootNode.prop("silecs-version") + return deploy + +def generateControllerFiles(sourceFolderPath,deploy,fileExtention,source,logTopics={'errorlog': True}): + fileName = deploy.plcName + fileExtention + fullFilePath = os.path.normpath(sourceFolderPath + "/" + fileName ) + + iecommon.logInfo("Generate PLC sources: %s" %fullFilePath,logTopics); + fdesc = open(fullFilePath, "w") + fdesc.write(source) + fdesc.close() + +# Needed for unit-testing +def generateControllerCode(controllerNode, paramsFile, sourceFolderPath, logTopics={'errorlog': True}): + paramDOM = libxml2.parseFile(paramsFile) + plcNode = controllerNode.xpathEval("*[@system]")[0] + if plcNode.get_name() == 'Siemens-PLC': + generateSiemensSources(paramDOM,sourceFolderPath,logTopics) + elif plcNode.get_name() == 'Virtual-Controller': + generateVirtualS7Sources(paramDOM,sourceFolderPath,logTopics) + elif plcNode.get_name() == 'Schneider-PLC': + generateSchneiderSources(paramDOM,sourceFolderPath,logTopics) + elif plcNode.get_name() == 'Rabbit-uC': + generateRabbitSources(paramDOM,sourceFolderPath,logTopics) + elif plcNode.get_name() == 'Beckhoff-PLC': + generateBeckhoffSources(paramDOM,sourceFolderPath,logTopics) + elif plcNode.get_name() == 'NI-Controller': + generateNISources(paramDOM,sourceFolderPath,logTopics) + else: + iecommon.logError("The PLC-Type %s is not supported" %plcNode.get_name(), True,logTopics) + paramDOM.freeDoc() + +#========================================================================= +# Entry Point +#========================================================================= +def genPlcSrc(workspacePath, deployName,silecsVersion,logTopics={'errorlog': True}): + deployFilePath = iefiles.getSilecsDeployFilePath(workspacePath,deployName) + deployDOM = libxml2.parseFile(deployFilePath) + iecommon.logInfo("Load Deployment document: %s" %deployFilePath,logTopics); + + # Create the source folder if needed + sourceFolderPath = iefiles.getControllerSourcesDirectory(workspacePath, deployName) + if not os.path.exists(sourceFolderPath): + os.makedirs(sourceFolderPath) + + # Add xml of the silecs-header + iecommon.addSilecsHeaderToClasses(deployDOM) + + controllerNodes = deployDOM.xpathEval("/SILECS-Deploy/Controller") + for controllerNode in controllerNodes: + paramsFile = iefiles.getParameterFile(workspacePath, deployName,controllerNode.prop("host-name")) + generateControllerCode(controllerNode,paramsFile,sourceFolderPath,logTopics) + + # Clean-up the memory before exit + deployDOM.freeDoc() + + return "Genplcsrc succeded!" + diff --git a/silecs-codegen/src/xml/genplcsrc.pyc b/silecs-codegen/src/xml/genplcsrc.pyc new file mode 100644 index 0000000000000000000000000000000000000000..b464d27d10be63c988e0e82997dbe55df623daa2 GIT binary patch literal 19874 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 literal 0 HcmV?d00001 diff --git a/silecs-codegen/src/xml/iecommon$py.class b/silecs-codegen/src/xml/iecommon$py.class new file mode 100644 index 0000000000000000000000000000000000000000..73bc5a4470b22842d905bddc5b49d97cb801ed16 GIT binary patch literal 22715 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 ZOhGuhufa3bQ%a4~J<~ihsFC!P{U2hmM~(mh literal 0 HcmV?d00001 diff --git a/silecs-codegen/src/xml/iecommon.py b/silecs-codegen/src/xml/iecommon.py new file mode 100644 index 0000000..ab625ff --- /dev/null +++ b/silecs-codegen/src/xml/iecommon.py @@ -0,0 +1,266 @@ +#!/usr/bin/python +# Copyright 2016 CERN and GSI +# +# 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 3 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, see <http://www.gnu.org/licenses/>. + +import time +import re +import os +import sys +import getpass +import codecs +import commands + +import iecommon +import libxml2 + +#================================================================== +# LOGGING +#================================================================== +def logHeader(level): + global project, program + _time = time.strftime("%Y/%m/%d-%H:%M:%S") + program = sys.argv[0] + return "[%s SILECS %s %s] " %(_time, program, level) + +def logError(msg, exit,logTopics={}): + if 'errorlog' in logTopics: + if logTopics['errorlog'] == True: + _logMsg = "%s%s" %(logHeader("ERROR"), msg) + print _logMsg + if exit: + raise Exception(_logMsg) + +def logInfo(msg,logTopics={}): + if 'infolog' in logTopics: + if logTopics['infolog'] == True: + _logMsg = "%s%s" %(logHeader("INFO"), msg) + print _logMsg + +def logDebug(msg,logTopics={}): + if 'debuglog' in logTopics: + if logTopics['debuglog'] == True: + _logMsg = "%s%s" %(logHeader("DEBUG"), msg) + print _logMsg + +# Append message to a text file +def logToFile(path,msg): + with open(path, "a") as logFile: + logFile.write(logHeader("CMD") + msg + "\n") +#------------------------------------------------------------------------- +# General XML Parsing +#------------------------------------------------------------------------- +def hasChildren(element): + children = element.xpathEval("*") + if len(children): + return True + return False + +def getFirstChild(element): + return element.xpathEval("*")[0] + +def isChildElement(node,elementName): + if not type(elementName) is str: + raise Exception("Error: Wrong Type Parsed") + for subnode in node: + if subnode.get_name() == elementName: + return True + return False + +def getChildElement(node,elementName): + for subnode in node: + if subnode.get_name() == elementName: + return subnode + return null + +def getOrCreateChildElement(node,elementName): + namedChilds = node.xpathEval(elementName) + if len(namedChilds): + return namedChilds[0] + newElement = libxml2.newNode(elementName) + node.addChild(newElement) + return newElement + +def getOrCreateNamedChildElement(node,elementName, attributeNameValue, attributeName="name"): + elements = node.xpathEval(elementName + "[@" + attributeName + "='" + attributeNameValue + "']") + if len(elements): + return elements[0] + newNode = libxml2.newNode(elementName) + node.addChild(newNode) + newNode.setProp(attributeName, attributeNameValue) + return newNode + +def getOrCreateNamedPreviousSiblingElement(parent,node,elementName, attributeNameValue): + alreadyAvailable = node.get_parent().xpathEval(elementName + "[@name='" + attributeNameValue + "']") + if len(alreadyAvailable): + return alreadyAvailable[0] + newNode = libxml2.newNode(elementName) + node.addPrevSibling(newNode) + newNode.setProp("name", attributeNameValue) + return newNode + +def getOrCreatePreviousSiblingElement(node,elementName): + alreadyAvailable = node.get_parent().xpathEval(elementName) + if len(alreadyAvailable): + return alreadyAvailable[0] + iecommon.logDebug("Not Found: Name:"+ elementName, {'debuglog': True}) + newNode = libxml2.newNode(elementName) + node.addPrevSibling(newNode) + return newNode + +def getOrCreateNamedFirstChild(parent,elementName, attributeNameValue): + elements = parent.xpathEval(elementName + "[@name='" + attributeNameValue + "']") + if len(elements): + return elements[0] + newNode = libxml2.newNode(elementName) + newNode.setProp('name', attributeNameValue) + if parent.get_children(): + firstChild = parent.xpathEval("*")[0] + firstChild.addPrevSibling(newNode) + else: + parent.addChild(newNode) + return newNode + +def fillAttributes(element, attrs): + for name,value in attrs.iteritems(): + if not type(value) is str: + raise Exception("Error: Wrong Type Parsed for attribute: " + name) + element.setProp(name, value) + return element + +#------------------------------------------------------------------------- +# Given an SILECS data type, returns the corresponding FESA data type +# For the time being FESA does not support unsigned data types in properties +# so here unsigned types are considered as signed to allow users to link +# any field to properties +#------------------------------------------------------------------------- +def getFesaDataType(type): + return { + 'int8' :'int8_t', + 'uint8' :'int16_t', + 'int16' :'int16_t', + 'uint16' :'int32_t', + 'int32' :'int32_t', + 'uint32' :'int64_t', + 'int64' :'int64_t', + 'uint64' :'uint64_t', # only for PXI, but not supported from Java! Not possible to use it in FESA properties + 'float32' :'float', + 'float64' :'double', + 'date' :'double', + 'char' :'int8_t', + 'byte' :'int16_t', + 'word' :'int32_t', + 'dword' :'int64_t', + 'int' :'int16_t', + 'dint' :'int32_t', + 'real' :'float', + 'dt' :'double', + 'string' :'char' + }[type] + +def getCDataType(type): + return { + 'int8' :'int8_t', + 'uint8' :'uint8_t', + 'int16' :'int16_t', + 'uint16' :'uint16_t', + 'int32' :'int32_t', + 'uint32' :'uint32_t', + 'int64' :'int64_t', + 'uint64' :'uint64_t', + 'float32' :'float', + 'float64' :'double', + 'date' :'double', + 'char' :'int8_t', + 'byte' :'int16_t', + 'word' :'int32_t', + 'dword' :'int64_t', + 'int' :'int16_t', + 'dint' :'int32_t', + 'real' :'float', + 'dt' :'double', + 'string' :'std::string' + }[type] +#------------------------------------------------------------------------- +# Given data type, returns the corresponding +# SILECS data type +#------------------------------------------------------------------------- +def getSilecsDataType(type): + return { + 'byte' :'uint8', + 'char' :'int8', + 'unsigned char' :'uint8', + 'short' :'int16', + 'unsigned short':'uint16', + 'long' :'int32', # conversion relies on 32-bit platform (FESA 3 does not support long type anymore) + 'unsigned long' :'uint32', + 'double' :'float64', + 'float' :'float32', + 'word' :'uint16', + 'dword' :'uint32', + 'int' :'int16', + 'dint' :'int32', + 'real' :'float32', + 'dt' :'date', + 'uint8' :'uint8', + 'int8' :'int8', + 'uint16' :'uint16', + 'int16' :'int16', + 'uint32' :'uint32', + 'int32' :'int32', + 'uint64' :'uint64', + 'int64' :'int64', + 'float32' :'float32', + 'float64' :'float64', + 'date' :'date', + 'string' : 'string' + }[type] + +def capitalizeString(text): + str = "" + if len(text) > 0: + str += text[0].upper() + str += text[1:] + return str + +def addSilecsHeaderToClasses(silecsDeployDOM): + controllers = silecsDeployDOM.xpathEval("/SILECS-Deploy/Controller") + for controller in controllers: + silecsHeaderDesign = libxml2.newNode("SilecsDesign") + silecsHeaderDesign.setProp("silecs-design-name","SilecsHeader") + silecsHeaderDesign.setProp("silecs-design-version","1.0.0") + silecsHeaderDevice = libxml2.newNode("Device") + silecsHeaderDevice.setProp("device-name","SilecsHeader") + silecsHeaderDesign.addChild(silecsHeaderDevice) + silecsDesigns = controller.xpathEval("SilecsDesign") + silecsDesigns[0].addPrevSibling(silecsHeaderDesign) + +#Major changes: Public API, database and PLC code generation may be impacted +def getMajorSilecsVersion(silecsVersionString): + firstDot = silecsVersionString.find('.') + return silecsVersionString[0:firstDot] + +#Minor changes: New functionality: backward-compatible +def getMinorSilecsVersion(silecsVersionString): + firstDot = silecsVersionString.find('.') + secondDot = silecsVersionString.find('.',firstDot) + return silecsVersionString[firstDot:secondDot] + +#Patches and bug fixes: backward compatible +def getPatchSilecsVersion(silecsVersionString): + firstDot = silecsVersionString.find('.') + secondDot = silecsVersionString.find('.',firstDot) + return silecsVersionString[secondDot:] + + diff --git a/silecs-codegen/src/xml/iecommon.pyc b/silecs-codegen/src/xml/iecommon.pyc new file mode 100644 index 0000000000000000000000000000000000000000..92d8bb839a079022be36fa9469b02be5aa5becaa GIT binary patch literal 9484 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 literal 0 HcmV?d00001 diff --git a/silecs-codegen/src/xml/iefiles$py.class b/silecs-codegen/src/xml/iefiles$py.class new file mode 100644 index 0000000000000000000000000000000000000000..7b345d46fd3c9e971520e54afcae82c16cefcc37 GIT binary patch literal 17145 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 literal 0 HcmV?d00001 diff --git a/silecs-codegen/src/xml/iefiles.py b/silecs-codegen/src/xml/iefiles.py new file mode 100644 index 0000000..6b52f87 --- /dev/null +++ b/silecs-codegen/src/xml/iefiles.py @@ -0,0 +1,140 @@ +#!/usr/bin/python +# Copyright 2016 CERN and GSI +# +# 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 3 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, see <http://www.gnu.org/licenses/>. + +import iecommon +import xmltemplate +import socket + +import os +import fnmatch +import shutil + +designFormat = '.silecsdesign' +deployFormat = '.silecsdeploy' +paramFormat = '.silecsparam' + +generatedDir = 'generated' +clientDir = 'client' +controllerDir = 'controller' +wrapperDir = 'wrapper' + +#================================================================== +# FILE ACCESS +#================================================================== + +def saveXMLToFile(filePath,xmlDoc): + with open(filePath, 'w') as fd: + xmlDoc.saveTo(fd,format = True) + #xmlDoc.saveTo(fd,"UTF-8",libxml2.XML_SAVE_NO_EMPTY) # it seems like there is a bug in libxml2 XML_SAVE_NO_EMPTY does the job of XML_SAVE_FORMAT + +#--- DESIGN --- + +def getSilecsDesignFileDir(workspacePath, projectName): + path = workspacePath + "/" + projectName + "/src" + return os.path.normpath(path) + +def getSilecsDesignFilePath(workspacePath, projectName): + path = getSilecsDesignFileDir(workspacePath, projectName) + "/" + projectName + designFormat; + return os.path.normpath(path) + +def newDesignProject(workspacePath, designName, schemaPath, silecsVersion ): + designDir = getSilecsDesignFileDir(workspacePath,designName) + designFile = getSilecsDesignFilePath(workspacePath,designName) + if(os.path.isfile(designFile)): + raise Exception("Design %s already exists in current workspace" % designFile) + + # create src directory + os.makedirs(designDir) + # create default design file + designText = xmltemplate.getDesignTemplate(designName, schemaPath, silecsVersion) + fdesc = open(designFile, "w") + fdesc.write(designText) + fdesc.close() + +#--- DEPLOY --- + +def getSilecsDeployFileDir(workspacePath, projectName): + path = workspacePath + "/" + projectName + "/src" + return os.path.normpath(path) + +def getSilecsDeployFilePath(workspacePath, projectName): + path = getSilecsDeployFileDir(workspacePath, projectName) + "/" + projectName + deployFormat; + return os.path.normpath(path) + +def newDeployProject(workspacePath, deployName, schemaPath, silecsVersion): + deployDir = getSilecsDeployFileDir(workspacePath, deployName) + deployFile = getSilecsDeployFilePath(workspacePath, deployName) + if(os.path.isfile(deployFile)): + raise Exception("Deploy %s already exists in current workspace" % deployFile) + + # create src directory + os.makedirs(deployDir) + # create default deploy file + deployText = xmltemplate.getDeployTemplate(deployName, schemaPath, silecsVersion) + fdesc = open(deployFile, "w") + fdesc.write(deployText) + fdesc.close() + +#--- PARAMETER --- +def getParameterFileName(controllerName): + return controllerName + paramFormat + +def getParameterFileDirectory(workspacePath, deployName): + paramPath = workspacePath + '/' + deployName + '/' + generatedDir + '/' + clientDir + paramPathNorm = os.path.normpath(paramPath) + return paramPathNorm + +def getParameterFile(workspacePath, deployName, controllerName): + paramPath = getParameterFileDirectory(workspacePath, deployName) + '/' + getParameterFileName(controllerName) + paramPathNorm = os.path.normpath(paramPath) + return paramPathNorm + +#--- CONTROLLER SOURCES --- +def getControllerSourcesDirectory(workspacePath, deployName): + controllerPath = workspacePath + '/' + deployName + '/' + generatedDir + '/' + controllerDir + controllerNorm = os.path.normpath(controllerPath) + return controllerNorm + +#--- DU WRAPPER --- +def getDuWrapperFileName( controllerName ): + return iecommon.capitalizeString(controllerName) + ".h" + +def getDuWrapperSourceDirectory(workspacePath, deployName): + wrapperPath = workspacePath + '/' + deployName + '/' + generatedDir + '/' + wrapperDir + wrapperPathNorm = os.path.normpath(wrapperPath) + return wrapperPathNorm + +def getDuWrapperFile(workspacePath, deployName, controllerName ): + return getDuWrapperSourceDirectory(workspacePath, deployName) + "/" + getDuWrapperFileName(controllerName) + +def getDuDesignWrapperFile(workspacePath, deployName, designName): + return getDuWrapperSourceDirectory(workspacePath, deployName) + "/" + getDuWrapperFileName(designName) + +#--- FESA --- +def getFesa3CommonDirectory(workspacePath, designName): + fesa3ClassPath = workspacePath + '/' + designName + '/src/' + designName + '/Common' + fesa3ClassPathNorm = os.path.normpath(fesa3ClassPath) + return fesa3ClassPathNorm + +def getProjectDirectory(workspacePath, designName): + path = workspacePath + '/' + designName + pathNorm = os.path.normpath(path) + return pathNorm + +def getFesaDeployFilePath(workspacePath, deployName): + path = workspacePath + '/' + deployName + '/src/' + deployName + '.deploy' + pathNorm = os.path.normpath(path) + return pathNorm diff --git a/silecs-codegen/src/xml/iefiles.pyc b/silecs-codegen/src/xml/iefiles.pyc new file mode 100644 index 0000000000000000000000000000000000000000..a345a8377c86cae2493acf6236c83962c70f5fc5 GIT binary patch literal 6435 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 literal 0 HcmV?d00001 diff --git a/silecs-codegen/src/xml/migration/0_10_0to1_0_0.py b/silecs-codegen/src/xml/migration/0_10_0to1_0_0.py new file mode 100644 index 0000000..775ffdb --- /dev/null +++ b/silecs-codegen/src/xml/migration/0_10_0to1_0_0.py @@ -0,0 +1,92 @@ +#!/usr/bin/python +# Copyright 2016 CERN and GSI +# +# 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 3 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, see <http://www.gnu.org/licenses/>. + +import os +import sys + +from migrationBase import MigrationBase +from migration0_10_0to1_0_0.migrators import * + +import libxml2 +import sys +import FileUtils +import shutil + +class Migration(MigrationBase): + def __init__(self, arguments): + super(Migration, self).__init__() + + def migrateClass(self, context, projectDir ): + modified = designGenerateFesaPropValueItemMigrator(context) + return modified + + def migrateDeployUnit(self, context, projectDir ): + modified = deploySwapStep7TiaMigrator(context) + modified = deployRemoveSilecsHeaderMigrator(context) + modified = deployReOrderControllerAndClassesMigrator(context) + self.removeGenCode() + self.migrateFESAInstanceFile() + return modified + + def backupOldFESAMakeSpecific(self): + results = self.parser.parse_args() + silecsDocument = results.silecsDocument + projectDir = FileUtils.getProjectDir(silecsDocument) + makeSpecific = projectDir + "/Makefile.specific" + if os.path.isfile(makeSpecific): + os.rename(makeSpecific, makeSpecific + ".backup") + print("Backed up old FESA Make.specific file: " + makeSpecific) + + def removeGenCode(self): + results = self.parser.parse_args() + silecsDocument = results.silecsDocument + projectDir = FileUtils.getProjectDir(silecsDocument) + clientFolder = projectDir + "/generated/client" + controllerFolder = projectDir + "/generated/controller" + wrapperFolder = projectDir + "/generated/wrapper" + if os.path.isdir(clientFolder): + shutil.rmtree(clientFolder) + print("removed generation folder: " + clientFolder) + if os.path.isdir(controllerFolder): + shutil.rmtree(controllerFolder) + print("removed generation folder: " + controllerFolder) + if os.path.isdir(wrapperFolder): + shutil.rmtree(wrapperFolder) + print("removed generation folder: " + wrapperFolder) + + def migrateFESAInstanceFile(self): + results = self.parser.parse_args() + silecsDocument = results.silecsDocument + projectDir = FileUtils.getProjectDir(silecsDocument) + testFolder = projectDir + "/src/test" + if not os.path.isdir(testFolder): + return + for f in os.listdir(testFolder): + fecFolder = os.path.join(testFolder, f) + if os.path.isdir( fecFolder ): + for subFile in os.listdir(fecFolder): + filename, file_extension = os.path.splitext(subFile) + if file_extension == ".instance": + instanceFile = os.path.join(fecFolder, subFile) + print("parsing FESA instancee file: " + instanceFile) + context = self._parse(instanceFile) + if fesaInstanceFileMigrator(context): + self._saveAndBackupFile(context,instanceFile) + +if __name__ == "__main__": + migration = Migration(sys.argv) + migration.migrate() + migration.backupOldFESAMakeSpecific() diff --git a/silecs-codegen/src/xml/migration/0_9_0to0_10_0.py b/silecs-codegen/src/xml/migration/0_9_0to0_10_0.py new file mode 100644 index 0000000..65707fc --- /dev/null +++ b/silecs-codegen/src/xml/migration/0_9_0to0_10_0.py @@ -0,0 +1,44 @@ +#!/usr/bin/python +# Copyright 2016 CERN and GSI +# +# 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 3 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, see <http://www.gnu.org/licenses/>. + +import os +import sys + +from migrationBase import MigrationBase +from migration_0_9_0to0_10_0.migrateDeployDeviceNumber import DeployDeviceNumberMigrator +from migration_0_9_0to0_10_0.migrateDeployDomain import DeployDomainMigrator + +import libxml2 +import sys + +class Migration(MigrationBase): + def __init__(self, arguments): + super(Migration, self).__init__() + self._deployDomainMigrator = DeployDomainMigrator() + self._migrateDeployDeviceNumber = DeployDeviceNumberMigrator() + + def migrateClass(self, context, projectDir ): + modified = False + return modified + + def migrateDeployUnit(self, context, projectDir ): + modified = self._deployDomainMigrator.migrate(context) + modified = self._migrateDeployDeviceNumber.migrate(context) + return modified + +if __name__ == "__main__": + migration = Migration(sys.argv) + migration.migrate() diff --git a/silecs-codegen/src/xml/migration/FileUtils.py b/silecs-codegen/src/xml/migration/FileUtils.py new file mode 100644 index 0000000..e1f3b78 --- /dev/null +++ b/silecs-codegen/src/xml/migration/FileUtils.py @@ -0,0 +1,39 @@ +#!/usr/bin/python +# Copyright 2016 CERN and GSI +# +# 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 3 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, see <http://www.gnu.org/licenses/>. + +import os +import shutil + +def fileExists(fileName): + return os.path.isfile(fileName) + +def write(string, filePath): + with open(filePath, 'w') as f: + f.write(string) + +def backupFile(fileName): + src = fileName + dst = fileName + ".backup" + print("Original file backed up by adding '.backup'") + shutil.copyfile(src, dst) + +def getExtension(fileName): + '''Returns the file extension, dot included''' + return fileName[fileName.rfind('.'):] + +def getProjectDir(fesaDocument): + absPath = os.path.abspath(fesaDocument) + return os.path.dirname(os.path.dirname(absPath)) diff --git a/silecs-codegen/src/xml/migration/FileUtils.pyc b/silecs-codegen/src/xml/migration/FileUtils.pyc new file mode 100644 index 0000000000000000000000000000000000000000..3944034d5cfcd9781c89f586bd6dd41b7f3928c1 GIT binary patch literal 1729 zcmcgs-EPw`82y~IWt}zz6KK-7AY8zTV2!v3gtU#Hn=&$?ArLBQ?6zk4Q|xFR>bM#A zJR7gV3ykwQ-6rt>jp8rIj(?7i&*wjX*H<rgejg>Yczk?cp_q3F60e|RqR&@Y&}Tu? zqhDzBNcs-=BwG%&NVXkllk7Oq;TaBlH!z#Nz%xh$AQum17scE{u=p)Vdo(9H=K<Vf z&|@~1I~K;a@F`<EwH*L$#yVB5mt8@fYlApbJz#Rdd;<!TBFl<AoEDi1M=A|XGCk3G z9;W#$JSnPUQ^twfF&Legoh+_QxWGvv)kNi?sgiJ(rD3KgRctlpdX3H>txiq9JhiJ> zgxB7mX=BYD)C|)lk?@BpGh4UK7XaAi9P$Y|_o#&pd)V<g(V0g-wrK9rPmj)gn){>? zof6^*hw$MO!eNi699UN7q{mY`Ns3bCPJ-c3&9og3Z5O{#$*rnTYjgKXTh$C<I>uHy zpIqs7z@qYe!!OUiy6MMDmN8<=o6L-9ka#4VOZfD;IQbp}K$0`T5ejZXH2Cn%+r~PO z75YI|;iTeW1H-QCkK*LGF3l6*_m!ULJWc~XvVeam8PsJkIt^kep-Hg4=)Ud5c2+af z8mH~lN{aH7hdN(IyoTifkGQWicFDpy|1}$ATi#<bD+nYyVpX&o8QCyQa~H+jMu32L zwUZIacE53!VeXN#b(NdIPE{k4npu?_`2J}i3mfP>No%R3vq`_nKXzC(*12?5C(E*B zSObNLvip~0AE4eOqUW5%nR6vUAC>>^8@OuG;$H(;3hLm!yp7nL5eh{tsbzP?BitZJ zAI4HwIbT7%m}N#|W#YXesWar_Wp7TlWvjCeE>P#7D!!}4?&<0w8WyRxA>7^EZ0jc4 vBezRV$Y_JZT@G6a*Q^~{&i%TAg`a1ItW))pt!r4<HL>P({cfw<>9+m>1H+!o literal 0 HcmV?d00001 diff --git a/silecs-codegen/src/xml/migration/__init__.py b/silecs-codegen/src/xml/migration/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/silecs-codegen/src/xml/migration/__init__.pyc b/silecs-codegen/src/xml/migration/__init__.pyc new file mode 100644 index 0000000000000000000000000000000000000000..c5029dcbd4d713167b91936ce5bee0a56e51fbcf GIT binary patch literal 182 zcmZ9GK?=e^3`Iw9A%gelrse`7E?m1Q=yDh{p&gvelu4!ag6_SFCoqMs4E&ey7ysw; z-EH63^9{{1E8QoRtQFpvrkb5gr7(XGs~%ux&I!8A1b2!c*o`42h-rc`mxuHYsg@84 trDj(ImK(FDmJ&!om^cE5wzwf^mbD>;!P<TQ8aCQ-;Ow7~j`Js?GC#H7FM$96 literal 0 HcmV?d00001 diff --git a/silecs-codegen/src/xml/migration/migration0_10_0to1_0_0/DeviceData_PneuDriveDU.instance b/silecs-codegen/src/xml/migration/migration0_10_0to1_0_0/DeviceData_PneuDriveDU.instance new file mode 100644 index 0000000..884e195 --- /dev/null +++ b/silecs-codegen/src/xml/migration/migration0_10_0to1_0_0/DeviceData_PneuDriveDU.instance @@ -0,0 +1,192 @@ +<?xml version="1.0" encoding="UTF-8"?> +<instantiation-unit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="file:/common/home/sd/apetit/lnx/workspace/PneuDriveDU/generated/xml/asl730-InstantiationSchemaFEC.xsd"> + <information> + <deploy-unit-name>PneuDriveDU</deploy-unit-name> + <deploy-unit-version>0.1.0</deploy-unit-version> + <fec-name>asl730</fec-name> + <server-name>PneuDriveDU.asl730</server-name> + <timestamp>22/03/2016 11:13</timestamp> + <fesa-version>3.0.0</fesa-version> + </information> + <prio-management> + <classes> + <PneuDrive> + <client-notification-threads> + <thread-default /> + </client-notification-threads> + </PneuDrive> + </classes> + <deploy-unit></deploy-unit> + </prio-management> + <classes> + <PneuDrive> + <rolling-buffer depth="3" /> + <events-mapping> + <RecvAcqEvent idref=""> + <event-configuration name="RecAcq"> + <Timer> + <timer-event period="1000" /> + </Timer> + </event-configuration> + <unused-event-configuration name="NONE" /> + </RecvAcqEvent> + </events-mapping> + <device-instance name="YR07DF2" state="development"> + <configuration> + <description value="" /> + <timingDomain value="NONE" /> + <accelerator value="NONE" /> + <acceleratorZone value="NONE" /> + <mainMuxCriterion value="NONE" /> + <parameterFile idref=""> + <value>../../../generated/client/PneuDrive.silecsparam</value> + </parameterFile> + <plcDeviceLabel idref=""> + <value>YR07DF2</value> + </plcDeviceLabel> + <plcHostName idref=""> + <value>sdaplc003</value> + </plcHostName> + </configuration> + <events-mapping> + <RecvAcqEvent idref=""> + <event-configuration-ref name="RecAcq" /> + </RecvAcqEvent> + </events-mapping> + </device-instance> + <device-instance name="YR07DC2" state="development"> + <configuration> + <description value="" /> + <timingDomain value="NONE" /> + <accelerator value="NONE" /> + <acceleratorZone value="NONE" /> + <mainMuxCriterion value="NONE" /> + <parameterFile idref=""> + <value> + ../../../generated/client/PneuDrive.silecsparam + </value> + </parameterFile> + <plcDeviceLabel idref=""> + <value>YR07DC2</value> + </plcDeviceLabel> + <plcHostName idref=""> + <value>sdaplc003</value> + </plcHostName> + </configuration> + <events-mapping> + <RecvAcqEvent idref=""> + <event-configuration-ref name="RecAcq" /> + </RecvAcqEvent> + </events-mapping> + </device-instance> + <device-instance name="YR11DF3" state="development"> + <configuration> + <description value="" /> + <timingDomain value="NONE" /> + <accelerator value="NONE" /> + <acceleratorZone value="NONE" /> + <mainMuxCriterion value="NONE" /> + <parameterFile idref=""> + <value>../../../generated/client/PneuDrive.silecsparam</value> + </parameterFile> + <plcDeviceLabel idref=""> + <value>YR11DF3</value> + </plcDeviceLabel> + <plcHostName idref=""> + <value>sdaplc003</value> + </plcHostName> + </configuration> + <events-mapping> + <RecvAcqEvent idref=""> + <event-configuration-ref name="RecAcq"></event-configuration-ref> + </RecvAcqEvent> + </events-mapping> + </device-instance> + <device-instance name="YR11DC3" state="development"> + <configuration> + <description value="" /> + <timingDomain value="NONE" /> + <accelerator value="NONE" /> + <acceleratorZone value="NONE" /> + <mainMuxCriterion value="NONE" /> + <parameterFile idref=""> + <value>../../../generated/client/PneuDrive.silecsparam</value> + </parameterFile> + <plcDeviceLabel idref=""> + <value>YR11DC3</value> + </plcDeviceLabel> + <plcHostName idref=""> + <value>sdaplc003</value> + </plcHostName> + </configuration> + <events-mapping> + <RecvAcqEvent idref=""> + <event-configuration-ref name="RecAcq" /> + </RecvAcqEvent> + </events-mapping> + </device-instance> + <device-instance name="YRE1DF1" state="development"> + <configuration> + <description value="" /> + <timingDomain value="NONE" /> + <accelerator value="NONE" /> + <acceleratorZone value="NONE" /> + <mainMuxCriterion value="NONE" /> + <parameterFile idref=""> + <value>../../../generated/client/PneuDrive.silecsparam</value> + </parameterFile> + <plcDeviceLabel idref=""> + <value>YRE1DF1</value> + </plcDeviceLabel> + <plcHostName idref=""> + <value>sdaplc003</value> + </plcHostName> + </configuration> + <events-mapping> + <RecvAcqEvent idref=""> + <event-configuration-ref name="RecAcq" /> + </RecvAcqEvent> + </events-mapping> + </device-instance> + <device-instance name="YRE1DC1" state="development"> + <configuration> + <description value="" /> + <timingDomain value="NONE" /> + <accelerator value="NONE" /> + <acceleratorZone value="NONE" /> + <mainMuxCriterion value="NONE" /> + <parameterFile idref=""> + <value>../../../generated/client/PneuDrive.silecsparam</value> + </parameterFile> + <plcDeviceLabel idref=""> + <value>YRE1DC1</value> + </plcDeviceLabel> + <plcHostName idref=""> + <value>sdaplc003</value> + </plcHostName> + </configuration> + <events-mapping> + <RecvAcqEvent idref=""> + <event-configuration-ref name="RecAcq" /> + </RecvAcqEvent> + </events-mapping> + </device-instance> + <global-instance name="PneuDrive_global" state="development"> + <configuration> + <description value="" /> + <timingDomain value="NONE" /> + <accelerator value="NONE" /> + <acceleratorZone value="NONE" /> + <mainMuxCriterion value="NONE" /> + <plcClassVersion idref=""> + <value></value> + </plcClassVersion> + <plcClassName idref=""> + <value></value> + </plcClassName> + </configuration> + </global-instance> + </PneuDrive> + </classes> +</instantiation-unit> diff --git a/silecs-codegen/src/xml/migration/migration0_10_0to1_0_0/__init__.py b/silecs-codegen/src/xml/migration/migration0_10_0to1_0_0/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/silecs-codegen/src/xml/migration/migration0_10_0to1_0_0/__init__.pyc b/silecs-codegen/src/xml/migration/migration0_10_0to1_0_0/__init__.pyc new file mode 100644 index 0000000000000000000000000000000000000000..b750faf20600d8f3cd94237fa58460b906506113 GIT binary patch literal 205 zcmZ9GO$x$5424H<A%bhK&`nLd7x4sc1h>POhIVj%%4D?lm|jIZfGHFg2Hy7`Z;|Bn z-mH21xuBY7A$}C`QqU-ME~e&G2-F|=Ast}!J_hKbC%BRW#%{17fD0oGG2OT~NF`fG z$fY-lVa^yEYAFCGgwZ?jwoN8m+4W16t}9*TSZguR+6J4o-u2JClGA%1o4cdK^dO7W E7s7rwUjP6A literal 0 HcmV?d00001 diff --git a/silecs-codegen/src/xml/migration/migration0_10_0to1_0_0/migrators.py b/silecs-codegen/src/xml/migration/migration0_10_0to1_0_0/migrators.py new file mode 100644 index 0000000..46f5f96 --- /dev/null +++ b/silecs-codegen/src/xml/migration/migration0_10_0to1_0_0/migrators.py @@ -0,0 +1,110 @@ +#!/usr/bin/python +# Copyright 2016 CERN and GSI +# +# 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 3 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, see <http://www.gnu.org/licenses/>. + +import libxml2 + +def deployRemoveSilecsHeaderMigrator(context): + modified = False + results = context.xpathEval('/SILECS-Deploy/Deploy-Classes/Class[name/text()="SilecsHeader"]') + if len(results) != 0: + silecsHeaderClassNode = results[0] + silecsHeaderClassNode.unlinkNode() + modified = True + return modified + +def deployReOrderControllerAndClassesMigrator(context): + modified = False + root = context.xpathEval("/SILECS-Deploy")[0] + deployInstances = root.xpathEval("Deploy-Instances")[0] + for controller in deployInstances.xpathEval("Controller"): + controller.unlinkNode() + root.addChild(controller) + modified = True + deployInstances.unlinkNode() + + deployUnitNode = root.xpathEval("Deploy-Unit")[0] + oldPLCTypeNodes = deployUnitNode.xpathEval("*[@system]") + if len(oldPLCTypeNodes) == 1: # Actually it is exactly one for a valid design + oldPLCTypeNode = oldPLCTypeNodes[0] + oldPLCTypeNode.unlinkNode() + for newController in root.xpathEval("Controller"): + newController.addChild(oldPLCTypeNode) + modified = True + + # In order to get fresh, empty element ( emty content ) + newDuNode = libxml2.newNode("Deploy-Unit") + newDuNode.newProp("name",deployUnitNode.prop("name")) + newDuNode.newProp("version",deployUnitNode.prop("version")) + deployUnitNode.replaceNode(newDuNode) + + deployClassesNodes = root.xpathEval("Deploy-Classes") + if len(deployClassesNodes) != 1:# Actually it is exactly one for a valid design + return modified + deployClassesNode = deployClassesNodes[0] + for oldClassNode in root.xpathEval("Deploy-Classes/Class"): + modified = True + className = oldClassNode.xpathEval("name")[0].getContent() + classVersion = oldClassNode.xpathEval("version")[0].getContent() + for newController in root.xpathEval("Controller"): + silecsDesign = libxml2.newNode("SilecsDesign") + newController.addChild(silecsDesign) + silecsDesign.newProp('silecs-design-name', className) + silecsDesign.newProp('silecs-design-version', classVersion) + for oldDevice in oldClassNode.xpathEval("device-list/Device"): + deviceName = oldDevice.prop("label") + newDevice = libxml2.newNode("Device") + newDevice.newProp('device-name', deviceName) + silecsDesign.addChild(newDevice) + deployClassesNode.unlinkNode() + return modified + +def deploySwapStep7TiaMigrator(context): + modified = False + for tiaEntry in context.xpathEval("/SILECS-Deploy/Deploy-Unit/Siemens-PLC[@system='TIA-PORTAL']"): + tiaEntry.setProp("system","STEP-7") + modified = True + for s7Entry in context.xpathEval("/SILECS-Deploy/Deploy-Unit/Siemens-PLC[@system='STEP-7']"): + s7Entry.setProp("system","TIA-PORTAL") + modified = True + return modified + +def designGenerateFesaPropValueItemMigrator(context): + modified = False + for block in context.xpathEval("//Block"): + if not block.hasProp("generateFesaProperty"): + block.newProp("generateFesaProperty","true") + modified = True + for register in context.xpathEval("//Register"): + if not register.hasProp("generateFesaValueItem"): + register.newProp("generateFesaValueItem","true") + modified = True + return modified + +def fesaInstanceFileMigrator(context): + modified = False + for classNode in context.xpathEval('/instantiation-unit/classes/*'): + className = classNode.get_name() + for deviceConfiguration in classNode.xpathEval('device-instance/configuration'): + result1 = deviceConfiguration.xpathEval('parameterFile/value') + result2 = deviceConfiguration.xpathEval('plcHostName/value') + if len(result1) == 1 and len(result2) == 1: + parameterFileValueNode = result1[0] + controllerValueNode = result2[0] + valueString = parameterFileValueNode.getContent() + valueString = valueString.replace(className, controllerValueNode.getContent()) + parameterFileValueNode.setContent(valueString) + modified = True + return modified diff --git a/silecs-codegen/src/xml/migration/migration0_10_0to1_0_0/migrators.pyc b/silecs-codegen/src/xml/migration/migration0_10_0to1_0_0/migrators.pyc new file mode 100644 index 0000000000000000000000000000000000000000..ae4511242e4437685bb96df9542e964e8546f983 GIT binary patch literal 4352 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 literal 0 HcmV?d00001 diff --git a/silecs-codegen/src/xml/migration/migration0_10_0to1_0_0/testMigration.py b/silecs-codegen/src/xml/migration/migration0_10_0to1_0_0/testMigration.py new file mode 100644 index 0000000..7192689 --- /dev/null +++ b/silecs-codegen/src/xml/migration/migration0_10_0to1_0_0/testMigration.py @@ -0,0 +1,148 @@ +#!/usr/bin/python +# Copyright 2016 CERN and GSI +# +# 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 3 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, see <http://www.gnu.org/licenses/>. + +from test.testBase import * + +import libxml2 +#from migration.0_10_0to1_0_0 import * +from migration.migration0_10_0to1_0_0.migrators import * +import inspect #get caller name + +SilecsDesignOld = '''<?xml version="1.0" encoding="UTF-8"?> +<SILECS-Design xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + silecs-version="0.10.0" created="03/21/16" updated="03/21/16" + xsi:noNamespaceSchemaLocation="/common/usr/cscofe/silecs/0.10.0/silecs-model/src/xml/DesignSchema.xsd"> + <Information> + <Owner user-login="apetit" /> + <Editor user-login="apetit" /> + </Information> + <SILECS-Class name="PneuDrive" version="0.1.0" domain="TEST"> + <Block name="Setting" mode="READ-WRITE"> + <Register name="ExecuteDrive" synchro="MASTER" format="int8" /> + <Register name="RequestControl" synchro="MASTER" format="int8" /> + <Register name="ErrorAck" synchro="MASTER" format="int8" /> + </Block> + <Block name="Acq" mode="READ-ONLY"> + <Register name="AirPressure" format="int8" synchro="MASTER" ></Register> + <Register name="HardwareILk" synchro="MASTER" format="int8" /> + <Register name="Maintenance" synchro="MASTER" format="int8" /> + <Register name="MotionTime" synchro="MASTER" format="int32" /> + <Register name="DriveCounter" synchro="MASTER" format="int32" /> + <Register name="Position" synchro="MASTER" format="int8" /> + <Register name="Warnings" synchro="MASTER" format="int8" /> + <Register name="Errors" synchro="MASTER" format="int8" /> + <Register name="OperationalMode" synchro="MASTER" format="int8"> + </Register> + </Block> + </SILECS-Class> +</SILECS-Design>''' +SilecsDesignOldParsed = libxml2.parseDoc(SilecsDesignOld) + +SilecsDeployOld = '''<?xml version="1.0" encoding="UTF-8"?> +<SILECS-Deploy xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" silecs-version="0.10.0" created="03/22/16" updated="03/22/16" xsi:noNamespaceSchemaLocation="/common/usr/cscofe/silecs/0.10.0/silecs-model/src/xml/DeploySchema.xsd"> + <Information> + <Owner user-login="apetit"/> + <Editor user-login="apetit"/> + </Information> + <Deploy-Unit name="PneuDriveDU" version="0.1.0"> + <Siemens-PLC system="STEP-7" model="SIMATIC_S7-300" protocol="DEVICE_MODE" base-DB-number="1"/> + </Deploy-Unit> + <Deploy-Instances> + <Controller host-name="sdaplc003"/> + <Controller host-name="ilkio001" /> + </Deploy-Instances> + <Deploy-Classes> + <Class> + <device-list><Device label="SilecsHeader"/></device-list><name>SilecsHeader</name> + <version>1.0.0</version> + </Class> + <Class> + <device-list> + <Device label="YR07DC2"/><Device label="YR07DF2"/><Device label="YR11DC3"/><Device label="YR11DF3"/><Device label="YRE1DC1"/><Device label="YRE1DF1"/> + </device-list> + + <name>PneuDrive</name> + <version>0.1.0</version> + </Class> + <Class> + <device-list> + <Device label="dgsdfg"/> + </device-list> + <name>Whatever</name> + <version>0.1.0</version> + </Class> + </Deploy-Classes> +</SILECS-Deploy>''' +SilecsDeployOldParsed = libxml2.parseDoc(SilecsDeployOld) + +fesaInstanceOldParsed = libxml2.parseFile("migration/migration0_10_0to1_0_0/DeviceData_PneuDriveDU.instance") + +def testdeployRemoveSilecsHeaderMigrator(deployDoc): + deployRemoveSilecsHeaderMigrator(deployDoc) + silecsHeaders = deployDoc.xpathEval('/SILECS-Deploy/Deploy-Classes/Class/name[text()="SilecsHeader"]') + assertEqual(len(silecsHeaders),0) + +def testdeployReOrderControllerAndClassesMigrator(deployDoc): + deployReOrderControllerAndClassesMigrator(deployDoc) + print deployDoc + oldClasses = deployDoc.xpathEval('/SILECS-Deploy/Deploy-Classes/Class') + assertEqual(len(oldClasses),0) + oldDeployInstances = deployDoc.xpathEval('/SILECS-Deploy/Deploy-Instances') + assertEqual(len(oldDeployInstances),0) + oldPLCNode = deployDoc.xpathEval('/SILECS-Deploy/Deploy-Unit/Siemens-PLC') + assertEqual(len(oldPLCNode),0) + + newContollers = deployDoc.xpathEval('/SILECS-Deploy/Controller') + assertEqual(len(newContollers),2) + for newController in newContollers: + assertTrue(newController.hasProp("host-name")) + plcNodes = newController.xpathEval('Siemens-PLC') + assertEqual(len(plcNodes),1) + classNodes = newController.xpathEval('SilecsDesign') + assertEqual(len(classNodes),2) + pneuDrive = newController.xpathEval("SilecsDesign[@silecs-design-name='PneuDrive']")[0] + pneuDriveDevices = pneuDrive.xpathEval('Device') + assertEqual(len(pneuDriveDevices),6) + whatever = newController.xpathEval('SilecsDesign[@silecs-design-name="Whatever"]')[0] + whateverDevices = whatever.xpathEval('Device') + assertEqual(len(whateverDevices),1) + +def testdeploySwapStep7TiaMigrator(deployDoc): + deploySwapStep7TiaMigrator(deployDoc) + plcEntries = deployDoc.xpathEval("/SILECS-Deploy/Deploy-Unit/Siemens-PLC[@system='TIA-PORTAL']") + assertEqual(len(plcEntries),1) + +def testdesignGenerateFesaPropValueItemMigrator(context): + designGenerateFesaPropValueItemMigrator(context) + updatedBlocks = context.xpathEval("//Block[@generateFesaProperty='true']") + updatedRegisters = context.xpathEval("//Register[@generateFesaValueItem='true']") + assertEqual(len(updatedBlocks),2) + assertEqual(len(updatedRegisters),12) + +def testfesaInstanceFileMigrator(context): + fesaInstanceFileMigrator(context) + newValues = context.xpathEval("//device-instance[@name='YR11DF3']/configuration/parameterFile/value") + assertEqual(len(newValues),1) + assertEqual(newValues[0].getContent(),"../../../generated/client/sdaplc003.silecsparam") + +def runTests(): + testdeploySwapStep7TiaMigrator(SilecsDeployOldParsed) + testdeployRemoveSilecsHeaderMigrator(SilecsDeployOldParsed) + testdeployReOrderControllerAndClassesMigrator(SilecsDeployOldParsed) + testdesignGenerateFesaPropValueItemMigrator(SilecsDesignOldParsed) + testfesaInstanceFileMigrator(fesaInstanceOldParsed) + + # print deployDoc # for debugging diff --git a/silecs-codegen/src/xml/migration/migration0_10_0to1_0_0/testMigration.pyc b/silecs-codegen/src/xml/migration/migration0_10_0to1_0_0/testMigration.pyc new file mode 100644 index 0000000000000000000000000000000000000000..e5cf20323c6fa0965e85099be6ba2a524a3453df GIT binary patch literal 6996 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 literal 0 HcmV?d00001 diff --git a/silecs-codegen/src/xml/migration/migrationBase.py b/silecs-codegen/src/xml/migration/migrationBase.py new file mode 100644 index 0000000..a35e2aa --- /dev/null +++ b/silecs-codegen/src/xml/migration/migrationBase.py @@ -0,0 +1,115 @@ +#!/usr/bin/python +# Copyright 2016 CERN and GSI +# +# 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 3 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, see <http://www.gnu.org/licenses/>. + +import fnmatch +import os +import sys +import libxml2 +from argparse import ArgumentParser +import FileUtils + +class MigrationBase(object): + def __init__(self): + self.parser = ArgumentParser(description='Migration script') + self.parser.add_argument("silecsDocument", action="store", help="The SILECS document to migrate") + self.parser.add_argument("xmlSchema", action="store", help="Path to the new schema") + self.parser.add_argument("versionOld", action="store", help="old silecs version") + self.parser.add_argument("versionNew", action="store", help="new silecs version") + results = self.parser.parse_args() + self.versionOld = results.versionOld + self.versionNew = results.versionNew + + def fixSilecsVersion(self, context): + root = context.xpathEval("/*")[0] + if root.prop("silecs-version") != self.versionOld: + raise IOError("Wrong Silecs Version - migration cancelled") + root.setProp("silecs-version",self.versionNew) + print("Info: Replaced old silecs-versiong string: " + self.versionOld + " with: " + self.versionNew) + + def fixXMLScheman(self, context,xmlSchema): + root = context.xpathEval("/*")[0] + root.setProp("xsi:noNamespaceSchemaLocation",xmlSchema) + print("Info: Replaced old silecs-xmlSchema") + + def migrate(self): + results = self.parser.parse_args() + silecsDocument = results.silecsDocument + xmlSchema = results.xmlSchema + print("INFO: Migration %s --> %s " % (self.versionOld, self.versionNew)) + + #project directory path + projectDir = FileUtils.getProjectDir(silecsDocument) + + # Design + extension = FileUtils.getExtension(silecsDocument) + modified = False + if extension == '.silecsdesign': + context = self._parse(silecsDocument) + modified = self.migrateClass(context, projectDir) + + # Deploy + elif extension == '.silecsdeploy': + context = self._parse(silecsDocument) + modified = self.migrateDeployUnit(context, projectDir) + + # Unknown + else: + raise IOError("Document type unknown: %r" % extension) + + # only chaning the version or the schema does not count as modification --> no backup needed + self.fixSilecsVersion(context) + self.fixXMLScheman(context,xmlSchema) + if modified: + self._saveAndBackupFile(context, silecsDocument) + else: + self._saveFile(context, silecsDocument) + + print('File %r successfully migrated' % silecsDocument) + + def migrateClass(self, context, projectDir): + return False + + def migrateDeployUnit(self, context, projectDir): + return False + + def _parse(self, silecsDocument): + if not FileUtils.fileExists(silecsDocument): + raise IOError("File not found: %r" % silecsDocument) + else: + print("Parsing file: %r" % silecsDocument) + return libxml2.parseFile(silecsDocument) + + def _saveFile(self, context, silecsDocument): + with open(silecsDocument, 'w') as fd: + context.saveTo(fd) + + def _saveAndBackupFile(self, context, silecsDocument): + FileUtils.backupFile(silecsDocument) + with open(silecsDocument, 'w') as fd: + context.saveTo(fd) + + +class MigrationAny(MigrationBase): + def __init__(self, arguments): + super(MigrationAny, self).__init__() + + def dummy(self): + #doNothing + print "dummy" + +if __name__ == "__main__": + migration = MigrationAny(sys.argv) + migration.migrate() \ No newline at end of file diff --git a/silecs-codegen/src/xml/migration/migrationBase.pyc b/silecs-codegen/src/xml/migration/migrationBase.pyc new file mode 100644 index 0000000000000000000000000000000000000000..da4d513d8d45c7fa577c10fe60254499cb998c4c GIT binary patch literal 4434 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 literal 0 HcmV?d00001 diff --git a/silecs-codegen/src/xml/migration/migration_0_9_0to0_10_0/__init__.py b/silecs-codegen/src/xml/migration/migration_0_9_0to0_10_0/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/silecs-codegen/src/xml/migration/migration_0_9_0to0_10_0/__init__.pyc b/silecs-codegen/src/xml/migration/migration_0_9_0to0_10_0/__init__.pyc new file mode 100644 index 0000000000000000000000000000000000000000..74e2cf898e15df7f2ef79185cb234abe13b389d8 GIT binary patch literal 201 zcmZ9GK?=e!5Je-n5W%%q=%!9w3Q|0Q8^P^R)6fQ!OvyxAkLgv!12{!-;lO`?_>1}T zc&?Vbew~f_&P@Cu;<=zv>Qqe0u@I;~aFPrRg+LKH3KlNb1DkGeF@ldH43w_i*T$CY zyfq9TD-AWawGlWO7=wr4+EiyJXMP)M+@a2-ajQ`SqKhsgZu)y(NbNpQbMv;Eo@0@E E1Jn66;s5{u literal 0 HcmV?d00001 diff --git a/silecs-codegen/src/xml/migration/migration_0_9_0to0_10_0/migrateDeployDeviceNumber.py b/silecs-codegen/src/xml/migration/migration_0_9_0to0_10_0/migrateDeployDeviceNumber.py new file mode 100644 index 0000000..6fc40a9 --- /dev/null +++ b/silecs-codegen/src/xml/migration/migration_0_9_0to0_10_0/migrateDeployDeviceNumber.py @@ -0,0 +1,58 @@ +#!/usr/bin/python +# Copyright 2016 CERN and GSI +# +# 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 3 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, see <http://www.gnu.org/licenses/>. + +import libxml2 + +class DeployDeviceNumberMigrator(object): + + def migrateDeviceNumbers(self, context): + modified = False + oldHeader = context.xpathEval('/SILECS-Deploy/Deploy-Classes/Class[name/text()="SilecsHeader"]') + if len(oldHeader) == 1: + deviceList = libxml2.newNode("device-list") + device = libxml2.newNode("Device") + device.newProp('label', "SilecsHeader") + deviceList.addChild(device) + classNameNode = oldHeader[0].xpathEval("name")[0] + classNameNode.addPrevSibling(deviceList) + print("Info: Device-number replaced by device-list for Class SilecsHeader") + modified = True + deviceNumber = oldHeader[0].xpathEval("device-number") + deviceNumber[0].unlinkNode() + + silecsClasses = context.xpathEval("/SILECS-Deploy/Deploy-Classes/Class") + for silecsClass in silecsClasses: + deviceNumber = silecsClass.xpathEval("device-number") + if len(deviceNumber) == 1 : # not possible to have more than one + deviceList = libxml2.newNode("device-list") + classNameNode = silecsClass.xpathEval("name")[0] + classNameNode.addPrevSibling(deviceList) + numberOfDevices = deviceNumber[0].getContent() + modified = True + print("Info: Device-number replaced by device-list for Class: " + classNameNode.getContent()) + for i in range(0, int(numberOfDevices)): + device = libxml2.newNode("Device") + device.newProp('label', "GenericDevice" + str(i)) + deviceList.addChild(device) + print("Info: Added device: '" + device.prop('label') + "' for Class: " + classNameNode.getContent()) + deviceNumber[0].unlinkNode() + + return modified + + def migrate(self, context): + modified = False + modified |= self.migrateDeviceNumbers(context) + return modified diff --git a/silecs-codegen/src/xml/migration/migration_0_9_0to0_10_0/migrateDeployDeviceNumber.pyc b/silecs-codegen/src/xml/migration/migration_0_9_0to0_10_0/migrateDeployDeviceNumber.pyc new file mode 100644 index 0000000000000000000000000000000000000000..3983bbc8081a2939b5ea3b1e5f4d14192d2ad008 GIT binary patch literal 2351 zcmd5;OK&4Z5UzF{JI)&du~-So1jL$ynZN}R@mO${WTnNsvXLSdqS1J!o%Cir<DKqo z9LYI_1GoKU95^Cz=guF1ud3}NQnV7{6wB4qU0q#|ufHk#_rF&b|7yKDh-vyM<M{w$ zKg5vWtLTL2873vtiUx|3Ir@d@lIX{0CEo5e`HcAopN_kS>8>87`T4GXX=2?u9rktc zy*Vl(mls!26wJPbShm;j54Xf_y-S|VQMcDDVLRqw8B&F`A@&a(cSIK@nkX_js_0VD z#T+?k=6H@|pO+|qMas>QDRa(jQKsp#EX#SC%#)d?1m6l>mPk#?WGbwMwSudpO7C!h z1#ybS1$HZBssu~6NousW?-nGNYx6~M52LF0P-D1M#y)+*OJcA<<7G8jpxwi=x~S2l zCdJGSb1_wk>x=pGRx#59uT5?i9v*?#BKbU%Whp_F^}YSECAY+BI_M=ffY?3!nJ$)I zkJbvg6`DvD^;@_ltAgt);|h%G$r{xev{}R#p*onQ=8<{v8!5=aqy#pt<BB`>Ym7nf z(c_2hUdt0I@Q+qIjjYu+kmpZXG}M99W7quX%dMVCb!_)_l;~pX5ElosEMZ85i>=gH z=PFoxZn}9))2OdglumT>u)&%f^P2rzrs|_?knc47$yO$`ZWLg86zinXKX2TK(HP`K zL(*&9bZS@NW@_dg*!Q9N4^`UF{%-<14O|q_p3Zb(VxPTz`^wulNrLQsPCJeJlHvX9 z^miJ~HP{MJ-$kj_u7>4!6uIMvFQXJM69Cki<2N%k{qZpUROXpJ>*R@^&7T(e2;3uz zlB9iX(!{O$#nVE+?3sRQvLgZehvHPbMeLns(4B}6ULI-J&NGKdl1dR}&~R`A4L_|b z#K8!WntYkEvN|0|4ly4dJIP^~CuU%DBBkVM;@KimJr0j&Eb&XhFJ{hlKm|#O1Ncqf z-o(TT_on2;8-=8<HI8BQcm8CsD{Qom>1mo6NCx{WW<i_}hj|tp=b$y18QA#v%w$=R zX5-*2FHY<Tgll=%tzlHyU^<Th_>s;6Tf_k_A{a`~HSl#c3%A41!)=#uho5YR+f%*1 z-L5|#ox8V?j6Vp2>rO7*u@A6Gs-o7^24qdGs})s;%tN=K-Yl)DD$RB`pkEi;P0`)M z`UACDlD5uw$I^z_cQH)cI$9sFQQY6rL7s4@=hnc8b>v5(%dc_wJq%4g-(^a7H+iVD z4ssVk<@aO?D!<W|i(ni#l>CMYKf{n)P8bR!!w_^mO|g_(yIZioF7EEprppCwKrHvp lN~yNxuZP=)bl$xGT*pq#?s6S+6JL1jzj}k~kv}1&e*xG6NMry2 literal 0 HcmV?d00001 diff --git a/silecs-codegen/src/xml/migration/migration_0_9_0to0_10_0/migrateDeployDomain.py b/silecs-codegen/src/xml/migration/migration_0_9_0to0_10_0/migrateDeployDomain.py new file mode 100644 index 0000000..83616f5 --- /dev/null +++ b/silecs-codegen/src/xml/migration/migration_0_9_0to0_10_0/migrateDeployDomain.py @@ -0,0 +1,34 @@ +#!/usr/bin/python +# Copyright 2016 CERN and GSI +# +# 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 3 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, see <http://www.gnu.org/licenses/>. + +import libxml2 + +class DeployDomainMigrator(object): + + def migrateDomains(self, context): + modified = False + controllers = context.xpathEval("/SILECS-Deploy/Deploy-Instances/Controller") + for controller in controllers: + if controller.hasProp('domain'): + controller.unsetProp('domain') + print("Info: Domain node in Controller %r removed" % controller.prop("host-name")) + modified = True + return modified + + def migrate(self, context): + modified = False + modified |= self.migrateDomains(context) + return modified diff --git a/silecs-codegen/src/xml/migration/migration_0_9_0to0_10_0/migrateDeployDomain.pyc b/silecs-codegen/src/xml/migration/migration_0_9_0to0_10_0/migrateDeployDomain.pyc new file mode 100644 index 0000000000000000000000000000000000000000..69cf44a3f250194b5f553539eceede5365966473 GIT binary patch literal 1419 zcmd5*&2G~`5T3Qulm=3u1r7*=FQ9;AHgE$WKqRF^f`A;Pib}|G>`h~8?;7u>O{L^Q zx$|ti2Pa+tX4X~<ZxG8fp7H#6=bO(zf45t|{2zNU)K>$aFH!V8R0-Y;4gvPja6mAa zFi2eZ4sZ(aY2Tsns6#dBAH0U<8k&7kWa^}^@+g(>(t|QGsyyq@FyR%7zKKd;XKV=6 zuxdtz3&E)4U^phVhC(0cp=fGj0G19c7^GOr;FQ7Ah50TlT<Cv(0m}v~8j#}A9Ez#? zz{q!NpW*SzZ$Q$Z_>J8+W{nzty#)+qZ{grX^wFVyfSQj6Z+ChlzZ!~H4}T!FiDWD^ z?<r|Ym1UwdO-xVh)V6XUC+ewJ!Qe@i2rrf1dAfJE^h%MdBa!G0teh%sd>Q4ULw)c} z0I#D=3q!$q5t-@EQIwf=N{#e~QWZ8blbB*X0;!<aWPB`V!cJj5EwYKNjPbN$Zp;Nt z$yJh0QjwU8=un^<Lz~ureg{3UN`FI($12a2<WrRkJ{B3*@$@*Al4o+xk5zf7izpVp zPBRf}KaWbyYdb~=4us^ojQKpzcy6hYVy`nR?1oRmu2J3aQ8(<?@5R4-dRUy8O*}?b zA}VzCb$p|@PyuVQ%WNH*><VkMEw;%lhg^)1SPtDrqvjCO2${=>Oh|?IL@U}padc=I z7!U)4HmVNQ2ZUQd3ke9M)q{rEQA2YFO-)oHOtzW*N$uXlkXROmcF$pmG?-=R+9?CV z_I#{WT6;jFY@=x6chlKu*_BvYXXzLj_1OM_YWzjS#%8bPAa)7QD%hW2rGbcKmz=-q Cf^Gi* literal 0 HcmV?d00001 diff --git a/silecs-codegen/src/xml/migration/migration_0_9_0to0_10_0/testMigration.py b/silecs-codegen/src/xml/migration/migration_0_9_0to0_10_0/testMigration.py new file mode 100644 index 0000000..f8abe0c --- /dev/null +++ b/silecs-codegen/src/xml/migration/migration_0_9_0to0_10_0/testMigration.py @@ -0,0 +1,91 @@ +#!/usr/bin/python +# Copyright 2016 CERN and GSI +# +# 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 3 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, see <http://www.gnu.org/licenses/>. + +from test.testBase import * + +import libxml2 +from migration.migration_0_9_0to0_10_0.migrateDeployDomain import * +from migration.migration_0_9_0to0_10_0.migrateDeployDeviceNumber import * + +import inspect #get caller name +SilecsDeployOld = '''<?xml version="1.0" encoding="UTF-8"?> +<SILECS-Deploy silecs-version="0.9.0" created="03/04/16" updated="03/04/16" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="/common/home/bel/schwinn/lnx/workspace-silecs/silecs-model/src/xml/DeploySchema.xsd"> + <Information> + <Owner user-login="schwinn"/> + <Editor user-login="schwinn"/> + </Information> + <Deploy-Unit name="Test123DU" version="0.1.0"> + <Siemens-PLC system="STEP-7" model="SIMATIC_S7-300" protocol="BLOCK_MODE" base-DB-number="0"/> + </Deploy-Unit> + <Deploy-Instances> + <Controller host-name="asl733" domain="ADE"/> + <Controller host-name="asl734" domain="SDFSDAFF"/> + </Deploy-Instances> + <Deploy-Classes> + <Class> + <device-number>1</device-number> + <name>SilecsHeader</name> + <version>1.0.0</version> + </Class> + <Class> + <device-number>5</device-number> + <name>Test123</name> + <version>0.1.0</version> + </Class> + <Class> + <device-list> + <Device label="MyDevice1"/> + <Device label="MyDevice2"/> + </device-list> + <name>Test345</name> + <version>0.1.0</version> + </Class> + </Deploy-Classes> +</SILECS-Deploy> +''' + +def testMigrateDeployDeviceNumber(deployDoc): + migrator = DeployDeviceNumberMigrator() + migrator.migrate(deployDoc) + deviceNumbers = deployDoc.xpathEval("/SILECS-Deploy/Deploy-Classes/Class/device-number") + assertEqual(len(deviceNumbers),0) + deviceLists = deployDoc.xpathEval("/SILECS-Deploy/Deploy-Classes/Class/device-list") + assertEqual(len(deviceLists),3) + newHeader = deployDoc.xpathEval('/SILECS-Deploy/Deploy-Classes/Class/device-list/Device[@label="SilecsHeader"]') + assertEqual(len(newHeader),1) + test123 = deployDoc.xpathEval('/SILECS-Deploy/Deploy-Classes/Class/name[text()="Test123"]') + assertEqual(len(test123),1) + + deviceListOnFirstPosition = test123[0].xpathEval('../*')[0] + assertTrue(deviceListOnFirstPosition.get_name() == 'device-list') + + genericDevices = test123[0].xpathEval('../device-list/Device') + assertEqual(len(genericDevices),5) + +def testMigrateDeployDomain(deployDoc): + migrator = DeployDomainMigrator() + migrator.migrate(deployDoc) + controllers = deployDoc.xpathEval("/SILECS-Deploy/Deploy-Instances/Controller") + for controller in controllers: + assertFalse(controller.hasProp('domain')) + +def runTests(): + deployDoc = libxml2.parseDoc(SilecsDeployOld) + testMigrateDeployDomain(deployDoc) + testMigrateDeployDeviceNumber(deployDoc) + # print deployDoc # for debugging diff --git a/silecs-codegen/src/xml/migration/migration_0_9_0to0_10_0/testMigration.pyc b/silecs-codegen/src/xml/migration/migration_0_9_0to0_10_0/testMigration.pyc new file mode 100644 index 0000000000000000000000000000000000000000..a52db80e075b9beaf1996d49001e4ec8ff4ad9e4 GIT binary patch literal 3670 zcmd5<-EZ4e6u(Z|bjdab3>f1>3YHLI!m-nAj1?ziOIlIUv{jO6sM8d=_N6g%?9BIO zNu~B_yz{s5uON7abI!G$q?@Xh7iQHr_v4&<e&^f$<Ik(5zl`4>yDWJM@cRS2;t32M z{AuhNV||?E*fWhCXz6ZF?ZSCJJ6~Z3E6mHYgH`6Ou-_OvC@^o8CTq+q(Bu-{)T^w) z{r*4jR5X}L9B%E3+A3rA{n;oezu>X(qp+dZs+L~np&NOAc+}7z^|y@g^!v?{-P_*T zZ1s#b9|zHKS@;2Wg^{sY)qBY3#@vzIYv@+pv~HWVZ}swI?48{zmEi%Yq1c!Szo8GM z9B-KBbULk0>(wYeGS@AuX8zpS>A6EbatuEd(g|IzD^B5Wgwd`u;$rN$T+!@At|LhU z(~U->C^U!Bh?|EzFoipu`eA4W;mn*y@iXEwlm=#^$SCrVGImYCWhy1r#nqYc^d<?m zx5Hnectmp44k}{rO+y}+CxXXD5FPno#6+TQE>LZHzKqT#v&~oTw-plOQRvHZ2pTu^ zJ{PjKUT;6r=T5V#=(Yu6J)e(wD2)A`R#_Yi$wv*n*WcVX?&@Vy6_(qb2mS5Vpm*1( zTj08J9LdOyf`<NZXRr0sptINB)XRsC;70qQ5l%*jJO;m}I@yVl2wGyE1nhR=Es+AU zTTv+EC<wqz!$?R&Y2t|BZoRITy=dg1)gFMr%wp&9+@ACF+FQN$gRQNUF@tpmL~6)Z z;0VDpWM!K+QlRKgaHz*$_%2U$Zq{sbd4pm>kpeO5((F+>{Ky@T$F@mZ%T!6CG{H|* z%Qn+xN@SbMI9>y*cm~#;^I#PftRz-mgQ#ey5GZyojHtM1sK6I;*@Sf3CNq`;2a>R% zcaGJ%mbxmn;5oGGXK6E?mqadTTfYr<S+f7dG|l2C3l!U2s(j6oi^cO2ym@$A@QS}- zkc_=#>{MeX8uMX<rN%V)@pD+!VR4#cGSB1+JIUb^%JR!xMv*59I93$2gqprUu}Tyx zDFvLt9fd`THKJHeDTpDZfDVykHxbJvVuZzMfyq^NQeZyZ0u86gekEYq$(*=ESFWX3 zk_7KE356cjt6Txip^d<}Y^Ag~Bvw?>y_`lqFfn0Xj1}GPquoX4;*0<a^ZLmTNklFt zt^O382G?%9;k6iIPb8no%GX&*)}M+MV6RrqTjDZIlB$82#fR!(VJku7Lkniqp5-Sn zQzcXZ-KCn_@sDB$I)}s-KB5JeMVQaVjvQ{jZ~}?Ku&l*$^Z5kUXrO?HvXt%j;|Z4- zvqxMG5PJm|bd5(1y&bu9t^|Ozt8lK+Dj0&KsGS|uh?qk@RYi}`N!6O<&5Rc*_rfhd z7IHrlJ~n9i4#9wy>AOl#QGp#sgMfr#7i!?f$caVT#o?=kAMr5j<4PM4YG$*6HMlph zWMmC$*1$3ma)*oxRMqjZ{2TzxH~FjnXaa%w3<jnZwX51S?fT-IyP<uQyRNwyOc)IK zw&10BeWMyN`vMC@`{_+~O6A}r&wTjGqtt|y*PegF9#ih2mv_Z27+;@zSqC)d?N{Ol zr|P#A3_SS(42h1^g_SL$xSNB6E{a%)t}Q1JoIE{r#C{x&E2v%<L#c}qNu+Mp>jeei zeEl}L`3Azxe4o0ROt23}0t;K};5AmzTw23`b|Hs;1ru;6lnqI~IfZ3Dt@~KzRR<tf zVKnS2gJTv4{vmv2u2aH|A$&Pz-!(W;6-oJHFYvmEvimL!^wmy=ew&Plj*ll{AM7X| z!(3o=F-V7!R-t&nB7#<~;_whYCA%Nv&K(%Cgsf(><<v~}ms}&i{|}s0^i>g~*oA*4 z#@v-%EVpD_W#&&|IX5oN{{L!(7PjGoeG>5IdoULm45i!^urQ2Y7IMY+i);S^N>SXo literal 0 HcmV?d00001 diff --git a/silecs-codegen/src/xml/migration/runTests.py b/silecs-codegen/src/xml/migration/runTests.py new file mode 100644 index 0000000..86c7e16 --- /dev/null +++ b/silecs-codegen/src/xml/migration/runTests.py @@ -0,0 +1,49 @@ +#!/usr/bin/python +# Copyright 2016 CERN and GSI +# +# 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 3 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, see <http://www.gnu.org/licenses/>. + +from test.testBase import * +import migration.migration_0_9_0to0_10_0.testMigration +import migration.migration0_10_0to1_0_0.testMigration + +SilecsDeployOld = '''<?xml version="1.0" encoding="UTF-8"?> +<SILECS-Deploy silecs-version="oldVersion" created="03/04/16" updated="03/04/16" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="oldSchemaLocation"> +</SILECS-Deploy> +''' + +# Test does not run in Jenkins, since "argparse" is not installed there + +#class BaseTestFake(MigrationBase): +# def __init__(self): +# super(BaseTestFake, self).__init__("oldVersion", "newVersion") + +#def runbaseTests(): +# baseClass = BaseTestFake() +# context = libxml2.parseDoc(SilecsDeployOld) +# baseClass.fixSilecsVersion(context) +# baseClass.fixXMLScheman(context,"newSchemaLocation") +# +# root = context.xpathEval("/*")[0] +# +# assertEqual( root.prop('silecs-version'),"newVersion" ) +# assertEqual( root.prop('noNamespaceSchemaLocation'),"newSchemaLocation" ) + +def runAllTests(): +# runbaseTests() + migration.migration_0_9_0to0_10_0.testMigration.runTests() + migration.migration0_10_0to1_0_0.testMigration.runTests() + allTestsOk() diff --git a/silecs-codegen/src/xml/migration/runTests.pyc b/silecs-codegen/src/xml/migration/runTests.pyc new file mode 100644 index 0000000000000000000000000000000000000000..488ae043b4ec4be2a173c460e964ff865a14024e GIT binary patch literal 999 zcmcgq&u`N(6n46H8(|YeNN|mEsz8Yo1_-LQ0|rP)T_-K&hjxiF$7-!6b`-m$yKsSj zfj^4_{|Z+Q@Zw}ygE(Ww&)<7_pZ(rv|M<CYe*XUL13~rZ!ulMhd<-Ur&p=CrW+m#N zrGd^nItqA8W3XKmchOgb&U<A}(C-10{f5yu0IAa4pUPjb43E}nVtt~yWP*=u-}P*Z zaw1~J=Og>w?2Yr(J{p_D;O*q~ap1h7St2ei$r4JW)6hf`zpu8iEt1nn(RgHghuC|B z{U^4y%HqF6rUe6z=5nx>Y-BH#$_5x0Md22QuE^*3q38Md<H;l-3z|j_<5ESOP`hGE zHsE3!rBr4Sp;gXAkVxq^pq_Tfh8A$Ehq2iRT*`3_Q$7HrKq&*U4q{vA3qnTecQ^f> z4ukrE7IWI)E?GCgq->t+0@S@tFZ9A^p{Ilw`W~$NWjdAWq{-feNWS7T2ugK#lUh@R z4|{mZgkMpT=)BWqA3StzWC$)MB25Ly3z1TMK@%*=qF|ikgs*WS@}*YGsjn}Ma*1mU zH%{l2W0?~S*Mgf~@Kt4QcByW{8Q{ODi*Ue|W&5aeU>q2g5?B4XWs@%>Nfm~KW<R$< zZC!MFqsf_mr|!RrEmhh)bqgqgex21*Jx$`X9f(~ErO|&;YZuNPrXpS?bbK4IECZ&o KXYB24-}wXU3KjAI literal 0 HcmV?d00001 diff --git a/silecs-codegen/src/xml/rabbitTemplate$py.class b/silecs-codegen/src/xml/rabbitTemplate$py.class new file mode 100644 index 0000000000000000000000000000000000000000..afe49a637829dc79e4d63c843aa6048c685db634 GIT binary patch literal 18417 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 F^uKF?&w~H} literal 0 HcmV?d00001 diff --git a/silecs-codegen/src/xml/rabbitTemplate.py b/silecs-codegen/src/xml/rabbitTemplate.py new file mode 100644 index 0000000..b02681c --- /dev/null +++ b/silecs-codegen/src/xml/rabbitTemplate.py @@ -0,0 +1,410 @@ +#!/usr/bin/python +# Copyright 2016 CERN and GSI +# +# 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 3 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, see <http://www.gnu.org/licenses/>. + +import time + +#========================================================================= +# Global definition +#========================================================================= + +#------------------------------------------------------------------------- +# Hash-Table + +whichRabbitFormat = { + 'uint8' : 'uint16_t', + 'int8' : 'int16_t', + 'uint16' : 'uint16_t', + 'int16' : 'int16_t', + 'uint32' : 'uint32_t', + 'int32' : 'int32_t', + 'float32' : 'float', + 'uint64' : '8', + 'int64' : '8', + 'string' : 'uint8_t', +# 'float64' : '8', not supported by microcontroller + 'date' : 'dt', + 'char' :'int16_t', + 'byte' :'uint16_t', + 'word' :'uint16_t', + 'dword' :'uint32_t', + 'int' :'int16_t', + 'dint' :'int32_t', + 'real' :'float', + 'dt' :'dt' } + +#========================================================================= +# Utils +#========================================================================= + +def toWordArray(strg): + wordArray = '' + for i in range(0, len(strg), 2): + lsb = ord(strg[i]) + try: hsb = ord(strg[i+1]) + except: hsb = 0 + wordArray += "0x%02x%02x," %(hsb,lsb) + return wordArray + +#========================================================================= +# C Source template (.c file) +#========================================================================= + +header = """ +/* +------------------------------------------------------------------- + * | Copyright CERN 2015 + * | SILECS - BE/CO-SRC + * | April 2015 + * +------------------------------------------------------------------- + * + * Release : SILECS_%s + * + * The following code has been automatically generated by SILECS. + * + * N.B: This file relies on the existence of explicit C data type such + * as int8_t, uint8_t, int16_t, etc.... + * If your compiler does not support them natively please implement + * them by including the data type definition provided on the SILECS + * web page before including this header file. + */ + +#define MODBUS_START_ADDRESS %s + +/*--------------------------------------------------------------------- + * DT + * data type definition and related utilities + *--------------------------------------------------------------------- + */ + +typedef struct +{ + uint8_t sc_100; // second cent + uint8_t sc; // second + uint8_t mn; // minute + uint8_t hh; // hour + uint8_t dd; // day + uint8_t mm; // month + uint8_t yy1; // year + uint8_t yy2; // year2 +} dt; + +#define _frombcd(a) (int)(((a>>4)*10)+(a&0x0F)) +#define _tobcd(a) (((unsigned char)((a)/10)<<4)+((a)%%10)) + +void SILECS_set_dt(int8_t sc_100 ,int8_t sc, int8_t mn,int8_t hh,int8_t dd,int8_t mm,int32_t yy, dt *date) +{ + date->sc_100 = sc_100; + date->sc = _tobcd(sc); + date->mn = _tobcd(mn); + date->hh = _tobcd(hh); + date->dd = _tobcd(dd); + date->mm = _tobcd(mm); + date->yy2 = _tobcd((int8_t)(yy/100)); + date->yy1 = _tobcd((int8_t)(yy%%100)); +} + +""" + +#========================================================================= +# DATA TYPE DEFINITION +#========================================================================= + +firstBlockUDT = """ +/*--------------------------------------------------------------------- + * %s / v%s + * BLOCK Type definition + *--------------------------------------------------------------------- + */ +""" + +blockUDT = """ +typedef struct +{ +%s +} _%s_%s; +""" + +regScalar = """ %s %s; +""" + +regArray = """ %s %s[%s]; +""" + +regArray2d = """ %s %s[%s][%s]; +""" + +stringArray = """ %s %s[%s][%s][%s]; +""" + +#========================================================================= +# INSTANTIATION +#========================================================================= + +allocationComment = """ +/*--------------------------------------------------------------------- + * MEMORY ALLOCATION + * PROTOCOL: %s + *--------------------------------------------------------------------- + */ +""" + +NBdeviceDefinition = """#define NB_%s_DEVICE %s +""" + +#======= DEVICE MODE ================= + +deviceModeBlockInstantiation = """ _%s_%s %s; +""" + +#deviceModeClass_deviceNumber = """ +# struct { +# _%s_%s %s; +# } %s_device[%s]; +#""" + +deviceModeClass_deviceNumber = """ + struct { +%s + } %s_device[NB_%s_DEVICE]; +""" + +deviceModeClass_deviceList = """ + struct { +%s + } %s; +""" + +deviceMode_dataInstantiation = """ +typedef struct { + %s +} _SILECS_DATA_SEGMENT; + +#define SILECS_DATA_SEGMENT_MODBUS_SIZE (sizeof(_SILECS_DATA_SEGMENT)/2) + +union silecsData { + _SILECS_DATA_SEGMENT data; + uint16_t array[SILECS_DATA_SEGMENT_MODBUS_SIZE]; +} silecsData; + +""" + +#======= BLOCK MODE ================= + +blockModeDeviceInstantiation_deviceNumber = """ _%s_%s device[NB_%s_DEVICE]; +""" + +blockModeDeviceInstantiation_deviceList = """ _%s_%s %s; +""" + +blockModeBlockInstantiation = """ + struct { +%s } %s_%s; +""" + +blockMode_dataInstantiation = """ +typedef struct { + %s +} _SILECS_DATA_SEGMENT; + +#define SILECS_DATA_SEGMENT_MODBUS_SIZE (sizeof(_SILECS_DATA_SEGMENT)/2) + +union modbus_data { + _SILECS_DATA_SEGMENT data; + uint16_t array[SILECS_DATA_SEGMENT_MODBUS_SIZE]; +} silecsData; + +""" + +#========================================================================= +# init +#========================================================================= + +globalAllocation = """ + SILECS_INSTANCE_DATA data; + uint16_t modbus_data = & data; +""" + +initFunctionDeviceMode = """ +/* Initialization function */ +int SILECS_init() +{ + /* Silecs version initialization */ + strcpy((unsigned char *)silecsData.data.SilecsHeader_device[0].hdrBlk._version, "%s"); + + /* Silecs checksum initialization */ + silecsData.data.SilecsHeader_device[0].hdrBlk._checksum = %s; + + /* Silecs user initialization */ + strcpy((unsigned char *)silecsData.data.SilecsHeader_device[0].hdrBlk._user, "%s"); + + /* Silecs date initialization */ + SILECS_set_dt(%s,%s,%s,%s,%s,%s,%s,&silecsData.data.SilecsHeader_device[0].hdrBlk._date); +} + +""" + +#initFunctionBlockMode = """ +initFunctionBlockMode = """ +/* Initialization function */ +int SILECS_init() +{ + /* Silecs version initialization */ + strcpy((unsigned char *)silecsData.data.SilecsHeader_hdrBlk.device[0]._version, "%s"); + + /* Silecs checksum initialization */ + silecsData.data.SilecsHeader_hdrBlk.device[0]._checksum = %s; + + /* Silecs user initialization */ + strcpy((unsigned char *)silecsData.data.SilecsHeader_hdrBlk.device[0]._user, "%s"); + + /* Silecs date initialization */ + SILECS_set_dt(%s,%s,%s,%s,%s,%s,%s,&silecsData.data.SilecsHeader_hdrBlk.device[0]._date); +} + +""" + +#========================================================================= +# Example generation +#========================================================================= + +instantiationExample = """/* + * Automatically generated Addressing example + *""" + +deviceModeDeviceListExample = """ + * This example shows how to address the register %s of block %s + * of device %s of the class %s + * + * silecsData.%s_%s.%s.%s = ....; + */""" + +deviceModeDeviceNumberExample = """ + * This example shows how to address the register %s of block %s + * of device 0 of the class %s + * + * silecsData.%s_device[0].%s.%s = ....; + */""" + +blockModeDeviceListExample = """ + * This example shows how to address the register %s of block %s + * of device %s of the class %s + * + * silecsData.%s_%s.%s.%s = ....; + */""" + +blockModeDeviceNumberExample = """ + * This example shows how to address the register %s of block %s + * of device 0 of the class %s + * + * silecsData.%s_%s.device[0].%s = ....; + */""" + +#========================================================================= +# C code generation Sub-function +#========================================================================= + +# HEADER file ------------------------------------------------------------ +def cHeader(baseAddress,silecsVersion): + return header %(silecsVersion, baseAddress) + +# REGISTER definition ---------------------------------------------------- +def cRegister(regName, regFormat, regDim, regDim2=1, strLen=1): + if strLen > 1: # if it's a string + if regDim2 > 1: # add another pair of brackets to hold the string length in case second dimension of array is set + return stringArray %(whichRabbitFormat[regFormat], regName, regDim, regDim2, strLen) + elif regDim > 1: # reuse the array2D syntax + return regArray2d %(whichRabbitFormat[regFormat], regName, regDim, strLen) + else: # regular string register + return regArray %(whichRabbitFormat[regFormat], regName, strLen) + else: + if regDim == 1 and regDim2 == 1: # scalar + return regScalar %(whichRabbitFormat[regFormat], regName) + elif regDim > 1 and regDim2 == 1: # array + return regArray %(whichRabbitFormat[regFormat], regName, regDim) + else: # dim1>=1 and for whatever dim2, use double array syntax + return regArray2d %(whichRabbitFormat[regFormat], regName, regDim, regDim2) + +# BLOCK type definition (UDT) -------------------------------------------- +def cBlockUDT(className, classVersion, blockName, regList, isFirst): + if isFirst: + return firstBlockUDT %(className, classVersion) + blockUDT %(regList, className, blockName) + else: + return blockUDT %(regList, className, blockName) + + +#============= DEVICE instantiation ============= + +# GLOBAL instantiation ---------------------------------------------- + +def cAllocationComment(plcProtocol): + return allocationComment %(plcProtocol) + +def cNBdeviceDefinition(className,deviceNumber): + return NBdeviceDefinition %(className,deviceNumber) + +# DEVICE MODE instantiation ---------------------------------------------- + +def cDeviceModeBlockInstantiation(className, blockName): + return deviceModeBlockInstantiation %(className, blockName, blockName) + +def cDeviceModeClass_deviceNumber(className, blockList): + return deviceModeClass_deviceNumber %(blockList, className, className) + +def cDeviceModeClass_deviceList(blockList, deviceList): + return deviceModeClass_deviceList %(blockList, deviceList) + +def cDeviceModeDataInstantiation(classList): + return deviceMode_dataInstantiation %(classList) + +# BLOCK MODE instantiation ---------------------------------------------- + +def cBlockModeDeviceInstantiation_deviceNumber(className, blockName): + return blockModeDeviceInstantiation_deviceNumber %(className, blockName, className) + +def cBlockModeDeviceInstantiation_deviceList(className, blockName, deviceName): + return blockModeDeviceInstantiation_deviceList %(className, blockName, deviceName) + +def cBlockModeBlockInstantiation(deviceList, className, blockName): + return blockModeBlockInstantiation %(deviceList, className, blockName) + +def cBlockModeDataInstantiation(classList): + return blockMode_dataInstantiation %(classList) + +# Init Function ---------------------------------------------- +def cInitDeviceMode(silecsVersion,ieChecks,ieUser): + dt = time.localtime(time.time()) + return initFunctionDeviceMode %("SILECS_"+silecsVersion,ieChecks,ieUser,dt[6],dt[5],dt[4],dt[3],dt[2],dt[1],dt[0]) + +def cInitBlockMode(silecsVersion,ieChecks,ieUser): + dt = time.localtime(time.time()) + return initFunctionBlockMode %("SILECS_"+silecsVersion,ieChecks,ieUser,dt[6],dt[5],dt[4],dt[3],dt[2],dt[1],dt[0]) + +# Example function ---------------------------------------------- +def cExample(plcProtocol,withDeviceList,className, blockName, registerName, deviceLabel =''): + + if plcProtocol == 'DEVICE_MODE': + if withDeviceList == True: + # device mode - device list + return instantiationExample + deviceModeDeviceListExample %(registerName, blockName, deviceLabel, className, className, deviceLabel, blockName, registerName) + else: + # device mode - device number + return instantiationExample + deviceModeDeviceNumberExample %(registerName, blockName, className, className, blockName, registerName) + else: + if withDeviceList == True: + # block mode - device list + return instantiationExample + blockModeDeviceListExample %(registerName, blockName, deviceLabel, className, className, blockName, deviceLabel, registerName) + else: + # block mode - device number + return instantiationExample + blockModeDeviceNumberExample %(registerName, blockName, className, className, blockName, registerName) diff --git a/silecs-codegen/src/xml/rabbitTemplate.pyc b/silecs-codegen/src/xml/rabbitTemplate.pyc new file mode 100644 index 0000000000000000000000000000000000000000..9675f7bf315d12e2adcdfa6a6a80e2ba72d6cec8 GIT binary patch literal 11292 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%0A*W-(d#U>K!Bb^K z_`_rgF~1%uft+qZb?eUNU>83e%i@hNd<6-DVTg<&(#El})hx%tijqpm(Ol)TJW9e! z6@*h_OO1{)3fU??HGA0rLtGrZw9U?U4<v_7ASEP{XLD$dACC12oBu`u@jyf!|1eB` zl@f>y#+CDwfB-lEnV>NfZUhjWH%1_h1fq{|$1!v?k;+a-^cv<~2=R4cK<f}%y=}~6 zh9}8a?MYEN0bIjfLqzhe&Y<vOcjwdS+=D-9@b4uD;Z7z8e=Dqt!ipje6RG5oAdVIA zE+$0zD(cUwu3arj^zgnPAmSBe&<Y<SU1qcdpj%Z5aiX${sF)QPq^txq6|K6{0>_A0 z^nfh5bqO<@;*3}ns91Kq0h$WOX6;h!85h`CPNRhqNAW$6XDm6EJeN3;IF~q`Y}*do zkJ!#_6kralKwc@bSXf`Ia2N{eMjvNj2D_S!Cd`781;h(x!wte{o*nbUg*B0|cxhCO zOodwZ%Ocey7$IIdUST3;86e<T0n2du=3jyEKBFJBa9iv=WZ|;vDRC&Fk`nu8_L+GR z<|qnAioKqOtr5Xi-<DH!0g-V8#f%eT!`-Uc9|wNq+kS0;ti6Vr?YZ4leZf2$Z?nHY zZCgo?KV^i)dE=cI+F@2%swIxmN33lFE;i~FCm0~J9M7=#62~gs%`N{kB-&)Hwbumv zr?|cD4di^Ap9cuAi<K;SVPtu@GVv{`!+Pm`bR8hOd_lGsB>K>wwCc++F54ztzz;B9 z;N=|O&tk>00U4e1dY1*wi};t5z+M`k_L0C4h!xeh4i5bd{T#X(J7(c_qZTHG`33Zm z{l;`0F!vl`>eByi67e@;+w4&!etyu2^;)|GHF~X`v4{h=*&qhYF;myYF<<U`sQa>u zWoDJ1eO7uOgU_M2STQTytg9aE`&j>=m;D3_LHy9m(7D|u61IGP_7O>ZChK;7@4lQ! z#0(g-xC0SL*RtSUet=Gar+OLrFwxDQBpqIWZG#bw^w^91`(FB>M=S%BgDjS|o$MtK zo86E14?QgJ;~q-C1Iq(sRQzC@(LGM#k6nDWte+1l1w8T=1Gax$GC0Ni8}bSVUev%n z37019i)Z*^iMKd#+rnEMoDG?5*kmInOPTDD$wp~xBZF&9mUqUY9Bbo{oy$i{mrv#{ zFGH6pa@kMGJqHv(blfJdWkha#DdAIPO=^7X=YZh-I7r*s|Fev*bcx4~awn%C(NVdt zxXwew7)yNE8K7eLKPP($#CC|pTQC$dp_Dk4u$fV=3|1YbhnVtZ^-%g0olB39M5lOI zm+0Fj*O7ebbMB2-;b_pZ=EIE0x=q!ex<y^$<BZL=#}8kT3wXl6BY}-`cmP-WHC)+c zA#i0JcSTfS`SKFd3%relGJYtS;KC@KHWx-*?c+|ShXJP;?0wP)ClKz!i4pR)(?$np z>+Pp_)-Ig79UG8nj`;(R|8`oGH=|_btOX4xItlLF?z8%$iAhH6G0c&zvxV|@(1P>H zdN<r0dRskMoE5$R_ea3KcNe&4ybxNtjb0He?wK1^%^G1Ux;9Z>7>GNd(Fx?T%r{9x z*|LQft_HZ6*{9es``@u?G2xU%03ta)bRo%Ub`mXS!SGqCbdi&HIN``~={hIU<uaG} z98+QjO0%5Y<z$W%w#?FfPL?=X=A_8UC!DMziH;-LtoaqI*16l3K4b9jIr)MUi<1f` zHYczeD)D)yG{ea)PVR7WkCS;$7CHHllaDxgz{$s)lsH-A<S{2tIH@9G>bsJk{hhc` zOn1BP>qgDF%f39s+NC4uAw(+ne3QFdGKbRhsUxXFsiF9L1o;SBQmI#vbNQ82I&~s- dGBt``@i#qu?A7$)^iX;P4}V+vaC$gB@;?RzK41U< literal 0 HcmV?d00001 diff --git a/silecs-codegen/src/xml/runTests.py b/silecs-codegen/src/xml/runTests.py new file mode 100644 index 0000000..bf970b4 --- /dev/null +++ b/silecs-codegen/src/xml/runTests.py @@ -0,0 +1,47 @@ +#!/usr/bin/python +# Copyright 2016 CERN and GSI +# +# 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 3 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, see <http://www.gnu.org/licenses/>. + +import sys + +from test.testBase import * + +import test.fesa.fillFESADeployUnitTest +import test.fesa.generateFesaDesignTest +import test.fesa.generateSourceCodeTest +import migration.runTests + +import test.general.iecommonTest +import test.general.genplcsrcTest +import test.general.genParamTest +import test.general.genDuWrapperTest + +def runTests(): + test.fesa.fillFESADeployUnitTest.runTests() + test.fesa.generateFesaDesignTest.runTests() + test.fesa.generateSourceCodeTest.runTests() + test.general.iecommonTest.runTests() + test.general.genParamTest.runTests() + test.general.genplcsrcTest.runTests() + test.general.genDuWrapperTest.runTests() + migration.runTests.runAllTests() + + print "################################################" + print "# Test suite finished - no failures detected ! #" + print "################################################" + +# ********************** module stand alone code ********************** +if __name__ == "__main__": + runTests() diff --git a/silecs-codegen/src/xml/s7template$py.class b/silecs-codegen/src/xml/s7template$py.class new file mode 100644 index 0000000000000000000000000000000000000000..81af5a7d8d4a8d34b94e06300c786ab8ff4c24f5 GIT binary patch literal 14472 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 MezyIkk+B`{Z?V}F8vp<R literal 0 HcmV?d00001 diff --git a/silecs-codegen/src/xml/s7template.py b/silecs-codegen/src/xml/s7template.py new file mode 100644 index 0000000..021a0d5 --- /dev/null +++ b/silecs-codegen/src/xml/s7template.py @@ -0,0 +1,252 @@ +#!/usr/bin/python +# Copyright 2016 CERN and GSI +# +# 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 3 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, see <http://www.gnu.org/licenses/>. + + +# Description: +# This module implement the methods to build each components of the sources. +# A component source consists of one 'parameterizable' text that can +# be specialized on call to append the string to be stored in the file. +# + +#========================================================================= +# Global definition +#========================================================================= + +#------------------------------------------------------------------------- +# Hash-Table + +whichSimaticFormat = { + 'uint8' : 'BYTE', + 'int8' : 'CHAR', + 'uint16' : 'WORD', + 'int16' : 'INT', + 'uint32' : 'DWORD', + 'int32' : 'DINT', + 'float32' : 'REAL', + 'string' : 'STRING', +# 'uint64' : '8', not supported with PLC +# 'int64' : '8', not supported with PLC +# 'float64' : '8', not supported with PLC + 'date' : 'DT', + 'char' :'CHAR', + 'byte' :'BYTE', + 'word' :'WORD', + 'dword' :'DWORD', + 'int' :'INT', + 'dint' :'DINT', + 'real' :'REAL', + 'dt' :'DT' } + + +#========================================================================= +# STL Source template (.scl file) +#========================================================================= + +firstBlockUDT = """//---------------------------------------------------------------------\r +// %s/ v%s\r +// BLOCK Type definition\r +//---------------------------------------------------------------------\r +""" + +blockUDT = """TYPE _%s_%s\r +AUTHOR: %s\r +FAMILY: SILECS\r +NAME: UDTB\r + STRUCT\r +%s + END_STRUCT;\r +END_TYPE\r +\r +""" + +regScalar = """ %s: %s%s;\r +""" + +regArray = """ %s: ARRAY[0..%d] OF %s%s;\r +""" + +regArray2d = """ %s: ARRAY[0..%d, 0..%d] OF %s%s;\r +""" + +regFixedStringLen = """ %s: STRING[16]%s;\r +""" + +firstBlock = """//---------------------------------------------------------------------\r +// %s/ v%s\r +// Block instance definition\r +//---------------------------------------------------------------------\r +""" + +DB_TIAP = """DATA_BLOCK %s_%s\r +{ S7_Optimized_Access := 'FALSE' }\r +AUTHOR: %s\r +FAMILY: SILECS\r +NAME: %s\r +STRUCT\r %s +END_STRUCT;\r +BEGIN\r +END_DATA_BLOCK\r +\r +""" + +DB_STEP7 = """// %s_%s ...........................................\r +DATA_BLOCK DB%s\r +{ S7_Optimized_Access := 'FALSE' }\r +AUTHOR: %s\r +FAMILY: SILECS\r +NAME: %s\r +STRUCT\r +%s +END_STRUCT;\r +BEGIN\r +END_DATA_BLOCK\r +\r +""" + +device = """ %s: _%s_%s; +""" + +#========================================================================= +# SYMBOLS Source template (.sdf file) +#========================================================================= + +diagSymbol = """"SILECS_HEADER",%s +""" + +UDTSymbol = """"_%s_%s","UDT %d","UDT %d","%s" +""" + +DBSymbol = """"%s_%s","DB %d","DB %d","%s" +""" + +#========================================================================= +# Sub-function +#========================================================================= + +# ------------------------------------------------------------------------ +# Utils +# ------------------------------------------------------------------------ +def toCharArray(strg): + charArray = '' + for c in strg: charArray += "'%c'," %c + return charArray + +def toByteArray(strg): + byteArray = '' + for c in strg: byteArray += "16#%02x," %(ord(c)) + return byteArray + +def toWordArray(strg): + wordArray = '' + for i in range(0, len(strg), 2): + lsb = ord(strg[i]) + try: hsb = ord(strg[i+1]) + except: hsb = 0 + wordArray += "16#%02x%02x," %(hsb,lsb) + return wordArray + +# ------------------------------------------------------------------------ +# STL code generation +# ------------------------------------------------------------------------ + +# REGISTER definition ---------------------------------------------------- +def stlRegister(regName, regFormat, regDim, regDim2, regVal, regLen=1): + if regLen > 1: # register is a string or an array of strings + strLen = whichSimaticFormat[regFormat]+'['+str(regLen)+']' + if regDim == 1 and regDim2 == 1: # scalar register + return regScalar %(regName, strLen, regVal) + elif regDim > 1 and regDim2 == 1: # array register + return regArray %(regName, regDim-1, strLen, regVal) + else: # dim1>=1 and for whatever dim2, use double array syntax + return regArray2d %(regName, regDim-1, regDim2-1, strLen, regVal) + else: + if regDim == 1 and regDim2 == 1: + return regScalar %(regName, whichSimaticFormat[regFormat], regVal) + elif regDim > 1 and regDim2 == 1: + return regArray %(regName, regDim-1, whichSimaticFormat[regFormat], regVal) + else: # dim1>=1 and for whatever dim2, use double array syntax + return regArray2d %(regName, regDim-1, regDim2-1, whichSimaticFormat[regFormat], regVal) + +#This method is used to add default value to the diagnostic registers +def stlRegisterValue(regName, owner, date, checksum, silecsversion): + if regName == '_version': return " := 'SILECS_%s'" %silecsversion + if regName == '_checksum' : return " := DW#16#%x" %checksum + if regName == '_user' : return " := '%s'" %owner + if regName == '_date' : return " := %s" %date + return '' #all other registers cannot have default assignment for the time being + +# BLOCK type definition (UDT) -------------------------------------------- +def stlBlockUDT(owner, className, classVersion, blockName, regList, isFirst): + if isFirst: + return firstBlockUDT %(className, classVersion) + blockUDT %(className, blockName, owner, regList) + else: + return blockUDT %(className, blockName, owner, regList) + +# BLOCK_MODE: data-block instance ---------------------------------------- +def stlDevice(devLabel, className, blockName): + return device %(devLabel, className, blockName) + +# DEVICE_MODE: data-block instance --------------------------------------- +def stlBlock(className, blockName): + return device %(blockName, className, blockName) + +def generateBlock(owner, className, classVersion, system, DBnumber, blockName, blockList, isFirst, protocol): + srcCore = "" + mode = '' + if protocol == 'BLOCK_MODE': + mode = 'BLK_MODE' + elif protocol == 'DEVICE_MODE': + mode = 'DEV_MODE' + else: + raise Exception( "Unknown PLC-protocol defined: " + protocol ) + + if (system == 'TIA-PORTAL'): + srcCore = DB_TIAP %(className, blockName, owner, mode, blockList) + elif (system == 'STEP-7'): + srcCore = DB_STEP7 %(className, blockName, DBnumber, owner, mode, blockList) + else: + raise Exception( "Unknown PLC-system defined: " + system ) + + if isFirst: + return firstBlock %(className, classVersion) + srcCore + else: + return srcCore + +# ------------------------------------------------------------------------ +# SYMBOLS code generation +# ------------------------------------------------------------------------ + +# HEADER file ------------------------------------------------------------ +def symHeader(baseAddress): + return DBSymbol %('SILECS', 'HEADER', baseAddress, baseAddress, "SILECS Diagnostic data-block") + +# UDT Type definition ---------------------------------------------------- +def symBlockUDT(className, classVersion, blockName, number, isFirst): + comment = '' + if isFirst: comment = "[%s/%s] UDT symbol: _<class-name>_<block-name>" %(className, classVersion) + return UDTSymbol %(className, blockName, number, number, comment) + +# BLOCK_MODE: data-block symbol ---------------------------- +def symBlockDB(className, classVersion, blockName, number, isFirst): + comment = '' + if isFirst: comment = "[%s/%s] DB symbol: <class-name>_<block-name>" %(className, classVersion) + return DBSymbol %(className, blockName, number, number, comment) + +# DEVICE_MODE : data-block symbol ---------------------------- +def symDeviceDB(className, classVersion, deviceLabel, number, isFirst): + comment = '' + if isFirst: comment = "[%s/%s] DB symbol: <class-name>_<device-label | device-id>" %(className, classVersion) + return DBSymbol %(className, deviceLabel, number, number, comment) diff --git a/silecs-codegen/src/xml/s7template.pyc b/silecs-codegen/src/xml/s7template.pyc new file mode 100644 index 0000000000000000000000000000000000000000..3cfa9954b20c5ef13d6722376b5d2097b90264c4 GIT binary patch literal 6909 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 F@}IuO(J=r3 literal 0 HcmV?d00001 diff --git a/silecs-codegen/src/xml/test/AllTypes.silecsdesign b/silecs-codegen/src/xml/test/AllTypes.silecsdesign new file mode 100644 index 0000000..a92fd2e --- /dev/null +++ b/silecs-codegen/src/xml/test/AllTypes.silecsdesign @@ -0,0 +1,77 @@ +<?xml version="1.0" encoding="UTF-8"?> +<SILECS-Design silecs-version="0.10.0" created="06/27/16" updated="06/27/16" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="/common/home/bel/schwinn/lnx/workspace-silecs-mars/silecs-model/src/xml/DesignSchema.xsd"> + <Information> + <Owner user-login="schwinn"/> + <Editor user-login="schwinn"/> + </Information> + <SILECS-Class name="AllTypes" version="0.1.0" domain="OPERATIONAL" > + <Block name="MyROBlock" mode="READ-ONLY" generateFesaProperty="true"> + <Register name="RO_int8" format="int8" synchro="MASTER" generateFesaValueItem="true" /> + <Register name="RO_uint8" format="uint8" synchro="MASTER" generateFesaValueItem="true" /> + <Register name="RO_int16" format="int16" synchro="MASTER" generateFesaValueItem="true" /> + <Register name="RO_uint16" format="uint16" synchro="MASTER" generateFesaValueItem="true" /> + <Register name="RO_int32" format="int32" synchro="MASTER" generateFesaValueItem="true" /> + <Register name="RO_uint32" format="uint32" synchro="MASTER" generateFesaValueItem="true" /> + <!--<Register name="RO_int64" format="int64" synchro="MASTER" generateFesaValueItem="true" /> not Supported for Beckhoff, Siemens and Schneider--> + <!--<Register name="RO_uint64" format="uint64" synchro="MASTER" generateFesaValueItem="true" /> not Supported for Beckhoff, Siemens and Schneider--> + <Register name="RO_float32" format="float32" synchro="MASTER" generateFesaValueItem="true" /> + <!--<Register name="RO_float64" format="float64" synchro="MASTER" generateFesaValueItem="true" /> not Supported for Rabbit, Beckhoff, Siemens and Schneider--> + <Register name="RO_string" format="string" synchro="MASTER" generateFesaValueItem="true" /> + <Register name="RO_date" format="date" synchro="MASTER" generateFesaValueItem="true" /> + <Register name="RO_char" format="char" synchro="MASTER" generateFesaValueItem="true" /> + <Register name="RO_byte" format="byte" synchro="MASTER" generateFesaValueItem="true" /> + <Register name="RO_word" format="word" synchro="MASTER" generateFesaValueItem="true" /> + <Register name="RO_dword" format="dword" synchro="MASTER" generateFesaValueItem="true" /> + <Register name="RO_int" format="int" synchro="MASTER" generateFesaValueItem="true" /> + <Register name="RO_dint" format="dint" synchro="MASTER" generateFesaValueItem="true" /> + <Register name="RO_real" format="real" synchro="MASTER" generateFesaValueItem="true" /> + <Register name="RO_dt" format="dt" synchro="MASTER" generateFesaValueItem="true" /> + </Block> + <Block name="MyRWBlock" generateFesaProperty="true" mode="READ-WRITE"> + <Register name="RW_int8" format="int8" synchro="MASTER" generateFesaValueItem="true" array-dim1="2" array-dim2="2" /> + <Register name="RW_uint8" format="uint8" synchro="MASTER" generateFesaValueItem="true" array-dim1="2" array-dim2="2"/> + <Register name="RW_int16" format="int16" synchro="MASTER" generateFesaValueItem="true" array-dim1="2" array-dim2="2"/> + <Register name="RW_uint16" format="uint16" synchro="MASTER" generateFesaValueItem="true" array-dim1="2" array-dim2="2"/> + <Register name="RW_int32" format="int32" synchro="MASTER" generateFesaValueItem="true" array-dim1="2" array-dim2="2"/> + <Register name="RW_uint32" format="uint32" synchro="MASTER" generateFesaValueItem="true" array-dim1="2" array-dim2="2"/> + <!-- <Register name="RW_int64" format="int64" synchro="MASTER" generateFesaValueItem="true" array-dim1="2" array-dim2="2"/> not Supported for Beckhoff, Siemens and Schneider--> + <!--<Register name="RW_uint64" format="uint64" synchro="MASTER" generateFesaValueItem="true" array-dim1="2" array-dim2="2"/> not Supported for Beckhoff, Siemens and Schneider--> + <Register name="RW_float32" format="float32" synchro="MASTER" generateFesaValueItem="true" array-dim1="2" array-dim2="2"/> + <!--<Register name="RW_float64" format="float64" synchro="MASTER" generateFesaValueItem="true" array-dim1="2" array-dim2="2"/> not Supported for Rabbit, Beckhoff, Siemens and Schneider--> + <Register name="RW_string" format="string" synchro="MASTER" generateFesaValueItem="true" array-dim1="2" array-dim2="2"/> + <Register name="RW_date" format="date" synchro="MASTER" generateFesaValueItem="true" array-dim1="2" array-dim2="2"/> + <Register name="RW_char" format="char" synchro="MASTER" generateFesaValueItem="true" array-dim1="2" array-dim2="2"/> + <Register name="RW_byte" format="byte" synchro="MASTER" generateFesaValueItem="true" array-dim1="2" array-dim2="2"/> + <Register name="RW_word" format="word" synchro="MASTER" generateFesaValueItem="true" array-dim1="2" array-dim2="2"/> + <Register name="RW_dword" format="dword" synchro="MASTER" generateFesaValueItem="true" array-dim1="2" array-dim2="2"/> + <Register name="RW_int" format="int" synchro="MASTER" generateFesaValueItem="true" array-dim1="2" array-dim2="2"/> + <Register name="RW_dint" format="dint" synchro="MASTER" generateFesaValueItem="true" array-dim1="2" array-dim2="2"/> + <Register name="RW_real" format="real" synchro="MASTER" generateFesaValueItem="true" array-dim1="2" array-dim2="2"/> + <Register name="RW_dt" format="dt" synchro="MASTER" generateFesaValueItem="true" array-dim1="2" array-dim2="2"/> + </Block> + <Block name="MyWOBlock" generateFesaProperty="true" mode="WRITE-ONLY"> + <Register name="WO_int8" format="int8" synchro="SLAVE" generateFesaValueItem="true" array-dim1="10"/> + <Register name="WO_uint8" format="uint8" synchro="SLAVE" generateFesaValueItem="true" array-dim1="10"/> + <Register name="WO_int16" format="int16" synchro="SLAVE" generateFesaValueItem="true" array-dim1="10"/> + <Register name="WO_uint16" format="uint16" synchro="SLAVE" generateFesaValueItem="true" array-dim1="10"/> + <Register name="WO_int32" format="int32" synchro="SLAVE" generateFesaValueItem="true" array-dim1="10"/> + <Register name="WO_uint32" format="uint32" synchro="SLAVE" generateFesaValueItem="true" array-dim1="10"/> + <!--<Register name="WO_int64" format="int64" synchro="SLAVE" generateFesaValueItem="true" array-dim1="10"/> not Supported for Beckhoff, Siemens and Schneider--> + <!--<Register name="WO_uint64" format="uint64" synchro="SLAVE" generateFesaValueItem="true" array-dim1="10"/> not Supported for Beckhoff, Siemens and Schneider--> + <Register name="WO_float32" format="float32" synchro="SLAVE" generateFesaValueItem="true" array-dim1="10"/> + <!--<Register name="WO_float64" format="float64" synchro="SLAVE" generateFesaValueItem="true" array-dim1="10"/> not Supported for Rabbit, Beckhoff, Siemens and Schneider--> + <Register name="WO_string" format="string" synchro="SLAVE" generateFesaValueItem="true" array-dim1="10"/> + <Register name="WO_date" format="date" synchro="SLAVE" generateFesaValueItem="true" array-dim1="10"/> + <Register name="WO_char" format="char" synchro="SLAVE" generateFesaValueItem="true" array-dim1="10"/> + <Register name="WO_byte" format="byte" synchro="SLAVE" generateFesaValueItem="true" array-dim1="10"/> + <Register name="WO_word" format="word" synchro="SLAVE" generateFesaValueItem="true" array-dim1="10"/> + <Register name="WO_dword" format="dword" synchro="SLAVE" generateFesaValueItem="true" array-dim1="10"/> + <Register name="WO_int" format="int" synchro="SLAVE" generateFesaValueItem="true" array-dim1="10"/> + <Register name="WO_dint" format="dint" synchro="SLAVE" generateFesaValueItem="true" array-dim1="10"/> + <Register name="WO_real" format="real" synchro="SLAVE" generateFesaValueItem="true" array-dim1="10"/> + <Register name="WO_dt" format="dt" synchro="SLAVE" generateFesaValueItem="true" array-dim1="10"/> + </Block> + </SILECS-Class> +</SILECS-Design> diff --git a/silecs-codegen/src/xml/test/AllTypesDU.silecsdeploy b/silecs-codegen/src/xml/test/AllTypesDU.silecsdeploy new file mode 100644 index 0000000..67fe6fc --- /dev/null +++ b/silecs-codegen/src/xml/test/AllTypesDU.silecsdeploy @@ -0,0 +1,103 @@ +<?xml version="1.0" encoding="UTF-8"?> +<SILECS-Deploy silecs-version="0.10.0" created="06/27/16" updated="06/27/16" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="/common/home/bel/schwinn/lnx/workspace-silecs-mars/silecs-model/src/xml/DeploySchema.xsd"> + <Information> + <Owner user-login="schwinn"/> + <Editor user-login="schwinn"/> + </Information> + <Deploy-Unit name="AllTypesDU" version="0.1.0"/> + <Controller host-name="Siemens_TiaDevice"> + <Siemens-PLC model="SIMATIC_S7-300" system="TIA-PORTAL" base-DB-number="0" protocol="DEVICE_MODE" /> + <SilecsDesign silecs-design-version="0.1.0" silecs-design-name="AllTypes"> + <Device device-name="testDevice1"/> + <Device device-name="testDevice2"/> + </SilecsDesign> + </Controller> + <Controller host-name="Siemens_TiaBlock"> + <Siemens-PLC model="SIMATIC_S7-300" system="TIA-PORTAL" base-DB-number="0" protocol="BLOCK_MODE" /> + <SilecsDesign silecs-design-version="0.1.0" silecs-design-name="AllTypes"> + <Device device-name="testDevice1"/> + <Device device-name="testDevice2"/> + </SilecsDesign> + </Controller> + <Controller host-name="Siemens_Step7Block"> + <Siemens-PLC model="SIMATIC_S7-300" system="STEP-7" base-DB-number="0" protocol="DEVICE_MODE" /> + <SilecsDesign silecs-design-version="0.1.0" silecs-design-name="AllTypes"> + <Device device-name="testDevice1"/> + <Device device-name="testDevice2"/> + </SilecsDesign> + </Controller> + <Controller host-name="Siemens_Step7Device"> + <Siemens-PLC model="SIMATIC_S7-300" system="STEP-7" base-DB-number="0" protocol="BLOCK_MODE" /> + <SilecsDesign silecs-design-version="0.1.0" silecs-design-name="AllTypes"> + <Device device-name="testDevice1"/> + <Device device-name="testDevice2"/> + </SilecsDesign> + </Controller> + <Controller host-name="Virtual_SiemensDevice"> + <Virtual-Controller model="SIMATIC_S7-VIRTUAL" + system="SNAP7 linux32" base-DB-number="0" protocol="DEVICE_MODE" /> + + <SilecsDesign silecs-design-version="0.1.0" silecs-design-name="AllTypes"> + <Device device-name="testDevice1"/> + <Device device-name="testDevice2"/> + </SilecsDesign> + </Controller> + <Controller host-name="Virtual_SiemensBlock"> + <Virtual-Controller model="SIMATIC_S7-VIRTUAL" + system="SNAP7 linux32" base-DB-number="0" protocol="BLOCK_MODE" /> + + <SilecsDesign silecs-design-version="0.1.0" silecs-design-name="AllTypes"> + <Device device-name="testDevice1"/> + <Device device-name="testDevice2"/> + </SilecsDesign> + </Controller> + <Controller host-name="Beckhoff_BC9020"> + <Beckhoff-PLC model="BC9020" system="TWINCat" protocol="BLOCK_MODE" base-address="0" /> + <SilecsDesign silecs-design-version="0.1.0" silecs-design-name="AllTypes"> + <Device device-name="testDevice1"/> + <Device device-name="testDevice2"/> + </SilecsDesign> + </Controller> + <Controller host-name="Beckhoff_CX9020"> + <Beckhoff-PLC model="CX9020" system="TWINCat" protocol="BLOCK_MODE" base-address="0" /> + <SilecsDesign silecs-design-version="0.1.0" silecs-design-name="AllTypes"> + <Device device-name="testDevice1"/> + <Device device-name="testDevice2"/> + </SilecsDesign> + </Controller> + <Controller host-name="Schneider_PremiumQuantum"> + <Schneider-PLC model="Premium" system="UNITY Pro" protocol="BLOCK_MODE" base-address="0" /> + <SilecsDesign silecs-design-version="0.1.0" silecs-design-name="AllTypes"> + <Device device-name="testDevice1"/> + <Device device-name="testDevice2"/> + </SilecsDesign> + </Controller> + <Controller host-name="Schneider_M340"> + <Schneider-PLC model="M340" system="UNITY Pro" + protocol="BLOCK_MODE" base-address="0" /> + <SilecsDesign silecs-design-version="0.1.0" silecs-design-name="AllTypes"> + <Device device-name="testDevice1"/> + <Device device-name="testDevice2"/> + </SilecsDesign> + </Controller> + <Controller host-name="Rabbit_DeviceMode"> + <Rabbit-uC model="Rabbit_RCM_4010" system="Standard-C" + protocol="DEVICE_MODE" base-address="0" /> + + <SilecsDesign silecs-design-version="0.1.0" silecs-design-name="AllTypes"> + <Device device-name="testDevice1"/> + <Device device-name="testDevice2"/> + </SilecsDesign> + </Controller> + <Controller host-name="Rabbit_BlockMode"> + <Rabbit-uC model="Rabbit_RCM_4010" system="Standard-C" + protocol="BLOCK_MODE" base-address="0" /> + + <SilecsDesign silecs-design-version="0.1.0" silecs-design-name="AllTypes"> + <Device device-name="testDevice1"/> + <Device device-name="testDevice2"/> + </SilecsDesign> + </Controller> +</SILECS-Deploy> diff --git a/silecs-codegen/src/xml/test/AllTypesFESA.silecsdesign b/silecs-codegen/src/xml/test/AllTypesFESA.silecsdesign new file mode 100644 index 0000000..01c9edf --- /dev/null +++ b/silecs-codegen/src/xml/test/AllTypesFESA.silecsdesign @@ -0,0 +1,77 @@ +<?xml version="1.0" encoding="UTF-8"?> +<SILECS-Design silecs-version="0.10.0" created="06/27/16" updated="06/27/16" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="/common/home/bel/schwinn/lnx/workspace-silecs-mars/silecs-model/src/xml/DesignSchema.xsd"> + <Information> + <Owner user-login="schwinn"/> + <Editor user-login="schwinn"/> + </Information> + <SILECS-Class name="AllTypesFESA" version="0.1.0" domain="OPERATIONAL" > + <Block name="MyROBlock" mode="READ-ONLY" generateFesaProperty="true"> + <Register name="RO_int8" format="int8" synchro="MASTER" generateFesaValueItem="true" /> + <Register name="RO_uint8" format="uint8" synchro="MASTER" generateFesaValueItem="true" /> + <Register name="RO_int16" format="int16" synchro="MASTER" generateFesaValueItem="true" /> + <Register name="RO_uint16" format="uint16" synchro="MASTER" generateFesaValueItem="true" /> + <Register name="RO_int32" format="int32" synchro="MASTER" generateFesaValueItem="true" /> + <Register name="RO_uint32" format="uint32" synchro="MASTER" generateFesaValueItem="true" /> + <!--<Register name="RO_int64" format="int64" synchro="MASTER" generateFesaValueItem="true" /> not Supported for Beckhoff, Siemens and Schneider--> + <!--<Register name="RO_uint64" format="uint64" synchro="MASTER" generateFesaValueItem="true" /> not Supported for Beckhoff, Siemens and Schneider--> + <Register name="RO_float32" format="float32" synchro="MASTER" generateFesaValueItem="true" /> + <!--<Register name="RO_float64" format="float64" synchro="MASTER" generateFesaValueItem="true" /> not Supported for Rabbit, Beckhoff, Siemens and Schneider--> + <Register name="RO_string" format="string" synchro="MASTER" generateFesaValueItem="true" /> + <Register name="RO_date" format="date" synchro="MASTER" generateFesaValueItem="true" /> + <Register name="RO_char" format="char" synchro="MASTER" generateFesaValueItem="true" /> + <Register name="RO_byte" format="byte" synchro="MASTER" generateFesaValueItem="true" /> + <Register name="RO_word" format="word" synchro="MASTER" generateFesaValueItem="true" /> + <Register name="RO_dword" format="dword" synchro="MASTER" generateFesaValueItem="true" /> + <Register name="RO_int" format="int" synchro="MASTER" generateFesaValueItem="true" /> + <Register name="RO_dint" format="dint" synchro="MASTER" generateFesaValueItem="true" /> + <Register name="RO_real" format="real" synchro="MASTER" generateFesaValueItem="true" /> + <Register name="RO_dt" format="dt" synchro="MASTER" generateFesaValueItem="true" /> + </Block> + <Block name="MyRWBlock" generateFesaProperty="true" mode="READ-WRITE"> + <Register name="RW_int8" format="int8" synchro="MASTER" generateFesaValueItem="true" array-dim1="2" array-dim2="2" /> + <Register name="RW_uint8" format="uint8" synchro="MASTER" generateFesaValueItem="true" array-dim1="2" array-dim2="2"/> + <Register name="RW_int16" format="int16" synchro="MASTER" generateFesaValueItem="true" array-dim1="2" array-dim2="2"/> + <Register name="RW_uint16" format="uint16" synchro="MASTER" generateFesaValueItem="true" array-dim1="2" array-dim2="2"/> + <Register name="RW_int32" format="int32" synchro="MASTER" generateFesaValueItem="true" array-dim1="2" array-dim2="2"/> + <Register name="RW_uint32" format="uint32" synchro="MASTER" generateFesaValueItem="true" array-dim1="2" array-dim2="2"/> + <!-- <Register name="RW_int64" format="int64" synchro="MASTER" generateFesaValueItem="true" array-dim1="2" array-dim2="2"/> not Supported for Beckhoff, Siemens and Schneider--> + <!--<Register name="RW_uint64" format="uint64" synchro="MASTER" generateFesaValueItem="true" array-dim1="2" array-dim2="2"/> not Supported for Beckhoff, Siemens and Schneider--> + <Register name="RW_float32" format="float32" synchro="MASTER" generateFesaValueItem="true" array-dim1="2" array-dim2="2"/> + <!--<Register name="RW_float64" format="float64" synchro="MASTER" generateFesaValueItem="true" array-dim1="2" array-dim2="2"/> not Supported for Rabbit, Beckhoff, Siemens and Schneider--> + <!-- <Register name="RW_string" format="string" synchro="MASTER" generateFesaValueItem="true" array-dim1="2" array-dim2="2"/> 2d string arrays not supported in FESA --> + <Register name="RW_date" format="date" synchro="MASTER" generateFesaValueItem="true" array-dim1="2" array-dim2="2"/> + <Register name="RW_char" format="char" synchro="MASTER" generateFesaValueItem="true" array-dim1="2" array-dim2="2"/> + <Register name="RW_byte" format="byte" synchro="MASTER" generateFesaValueItem="true" array-dim1="2" array-dim2="2"/> + <Register name="RW_word" format="word" synchro="MASTER" generateFesaValueItem="true" array-dim1="2" array-dim2="2"/> + <Register name="RW_dword" format="dword" synchro="MASTER" generateFesaValueItem="true" array-dim1="2" array-dim2="2"/> + <Register name="RW_int" format="int" synchro="MASTER" generateFesaValueItem="true" array-dim1="2" array-dim2="2"/> + <Register name="RW_dint" format="dint" synchro="MASTER" generateFesaValueItem="true" array-dim1="2" array-dim2="2"/> + <Register name="RW_real" format="real" synchro="MASTER" generateFesaValueItem="true" array-dim1="2" array-dim2="2"/> + <Register name="RW_dt" format="dt" synchro="MASTER" generateFesaValueItem="true" array-dim1="2" array-dim2="2"/> + </Block> + <Block name="MyWOBlock" generateFesaProperty="true" mode="WRITE-ONLY"> + <Register name="WO_int8" format="int8" synchro="SLAVE" generateFesaValueItem="true" array-dim1="10"/> + <Register name="WO_uint8" format="uint8" synchro="SLAVE" generateFesaValueItem="true" array-dim1="10"/> + <Register name="WO_int16" format="int16" synchro="SLAVE" generateFesaValueItem="true" array-dim1="10"/> + <Register name="WO_uint16" format="uint16" synchro="SLAVE" generateFesaValueItem="true" array-dim1="10"/> + <Register name="WO_int32" format="int32" synchro="SLAVE" generateFesaValueItem="true" array-dim1="10"/> + <Register name="WO_uint32" format="uint32" synchro="SLAVE" generateFesaValueItem="true" array-dim1="10"/> + <!--<Register name="WO_int64" format="int64" synchro="SLAVE" generateFesaValueItem="true" array-dim1="10"/> not Supported for Beckhoff, Siemens and Schneider--> + <!--<Register name="WO_uint64" format="uint64" synchro="SLAVE" generateFesaValueItem="true" array-dim1="10"/> not Supported for Beckhoff, Siemens and Schneider--> + <Register name="WO_float32" format="float32" synchro="SLAVE" generateFesaValueItem="true" array-dim1="10"/> + <!--<Register name="WO_float64" format="float64" synchro="SLAVE" generateFesaValueItem="true" array-dim1="10"/> not Supported for Rabbit, Beckhoff, Siemens and Schneider--> + <Register name="WO_string" format="string" synchro="SLAVE" generateFesaValueItem="true" array-dim1="10"/> + <Register name="WO_date" format="date" synchro="SLAVE" generateFesaValueItem="true" array-dim1="10"/> + <Register name="WO_char" format="char" synchro="SLAVE" generateFesaValueItem="true" array-dim1="10"/> + <Register name="WO_byte" format="byte" synchro="SLAVE" generateFesaValueItem="true" array-dim1="10"/> + <Register name="WO_word" format="word" synchro="SLAVE" generateFesaValueItem="true" array-dim1="10"/> + <Register name="WO_dword" format="dword" synchro="SLAVE" generateFesaValueItem="true" array-dim1="10"/> + <Register name="WO_int" format="int" synchro="SLAVE" generateFesaValueItem="true" array-dim1="10"/> + <Register name="WO_dint" format="dint" synchro="SLAVE" generateFesaValueItem="true" array-dim1="10"/> + <Register name="WO_real" format="real" synchro="SLAVE" generateFesaValueItem="true" array-dim1="10"/> + <Register name="WO_dt" format="dt" synchro="SLAVE" generateFesaValueItem="true" array-dim1="10"/> + </Block> + </SILECS-Class> +</SILECS-Design> diff --git a/silecs-codegen/src/xml/test/__init__.py b/silecs-codegen/src/xml/test/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/silecs-codegen/src/xml/test/__init__.pyc b/silecs-codegen/src/xml/test/__init__.pyc new file mode 100644 index 0000000000000000000000000000000000000000..27028e401eb7955eeda0c476ee5ea6317451d8b0 GIT binary patch literal 177 zcmcckiI?kGm`ivv0~9a<X$K%KW&si@3=F{<AQ3+eAi;n}6h{HY^po>*bMy1`GxBp& z^^;O_^ox@-$}{uw^mFnm^vm;$vWp86lT&qzGjmdti*<7oi;DH3?Bx8E)b!Lm{o<lz r{fgWi{gTw;68-r2%)HE!_;|g7$`THs@iw{nDWy57b|6O-12F>tuO=;W literal 0 HcmV?d00001 diff --git a/silecs-codegen/src/xml/test/fesa/DeploymentUnitTemplateFESA300.xml b/silecs-codegen/src/xml/test/fesa/DeploymentUnitTemplateFESA300.xml new file mode 100644 index 0000000..c36d558 --- /dev/null +++ b/silecs-codegen/src/xml/test/fesa/DeploymentUnitTemplateFESA300.xml @@ -0,0 +1,28 @@ +<?xml version="1.0" encoding="UTF-8"?> +<deploy-unit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation=""> + <information> + <deploy-unit-name>Empty Template</deploy-unit-name> + <deploy-unit-major-version>0</deploy-unit-major-version> + <deploy-unit-minor-version>1</deploy-unit-minor-version> + <deploy-unit-tiny-version>0</deploy-unit-tiny-version> + <state>development</state> + <description>Empty Template description</description> + <fesa-version>0.9.1</fesa-version> + <repository-path></repository-path> + <build-time></build-time> + </information> + <ownership> + <responsible name="Undefined"/> + <creator login="Undefined"/> + </ownership> + <class> + <class-name>class-name</class-name> + <class-major-version>0</class-major-version> + <class-minor-version>1</class-minor-version> + <class-tiny-version>0</class-tiny-version> + <device-instance>required</device-instance> + </class> + <executable> + <server extension="_S" /> + </executable> +</deploy-unit> diff --git a/silecs-codegen/src/xml/test/fesa/GSIClassTemplateFESA300.xml b/silecs-codegen/src/xml/test/fesa/GSIClassTemplateFESA300.xml new file mode 100644 index 0000000..f84b0ae --- /dev/null +++ b/silecs-codegen/src/xml/test/fesa/GSIClassTemplateFESA300.xml @@ -0,0 +1,657 @@ +<?xml version="1.0" encoding="UTF-8"?> +<equipment-model xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../design-gsi.xsd"> + <information> + <class-name>GSIClassTemplate</class-name> + <class-major-version>0</class-major-version> + <class-minor-version>1</class-minor-version> + <class-tiny-version>0</class-tiny-version> + <type>Final</type> + <state>development</state> + <description>An Empty design with GSI-specific standard properties</description> + <fesa-version>3.0.0</fesa-version> + <repository-path>undefined</repository-path> + </information> + <ownership> + <responsible name="CSCO"/> + <creator login="Undefined"/> + </ownership> + <interface> + <device-interface> + <setting> + <GSI-Init-Property multiplexed="false" name="Init" visibility="operational"> + <set-action partial-setting="true" transaction="true"> + <server-action-ref server-action-name-ref="InitSetAction"/> + </set-action> + </GSI-Init-Property> + <GSI-Reset-Property multiplexed="false" name="Reset" visibility="operational"> + <set-action partial-setting="true" transaction="true"> + <server-action-ref server-action-name-ref="ResetSetAction"/> + </set-action> + </GSI-Reset-Property> + <GSI-Setting-Property multiplexed="false" name="Setting" visibility="operational"> + <update-flag-item direction="OUT" name="updateFlags" optional="true"> + <builtin-type-scalar data-type-name-ref="NOTIFICATION_UPDATE"/> + </update-flag-item> + <cycle-name-item direction="OUT" name="cycleName" optional="true"> + <array type="char"> + <dim>32</dim> + </array> + </cycle-name-item> + <set-action partial-setting="true" transaction="true"> + <server-action-ref server-action-name-ref="SettingSetAction"/> + </set-action> + <get-action> + <server-action-ref server-action-name-ref="SettingGetAction"/> + </get-action> + </GSI-Setting-Property> + <GSI-Power-Property multiplexed="false" name="Power" visibility="operational"> + <update-flag-item direction="OUT" name="updateFlags" optional="true"> + <builtin-type-scalar data-type-name-ref="NOTIFICATION_UPDATE"/> + </update-flag-item> + <cycle-name-item direction="OUT" name="cycleName" optional="true"> + <array type="char"> + <dim>32</dim> + </array> + </cycle-name-item> + <set-action partial-setting="true" transaction="true"> + <server-action-ref server-action-name-ref="PowerSetAction"/> + </set-action> + <get-action> + <server-action-ref server-action-name-ref="PowerGetAction"/> + </get-action> + <power-item direction="INOUT" name="power"> + <custom-type-scalar data-type-name-ref="DEVICE_POWER"/> + + <data-field-ref field-name-ref="power"/> + </power-item> + </GSI-Power-Property> + </setting> + <acquisition> + <GSI-Status-Property multiplexed="false" name="Status" on-change="true" subscribable="true" visibility="operational"> + <acq-stamp-item direction="OUT" name="acqStamp"> + <scalar type="int64_t"/> + </acq-stamp-item> + <update-flag-item direction="OUT" name="updateFlags" optional="true"> + <builtin-type-scalar data-type-name-ref="NOTIFICATION_UPDATE"/> + </update-flag-item> + <cycle-name-item direction="OUT" name="cycleName" optional="true"> + <array type="char"> + <dim>32</dim> + </array> + </cycle-name-item> + <cycle-stamp-item direction="OUT" name="cycleStamp" optional="true"> + <scalar type="int64_t"/> + </cycle-stamp-item> + <get-action> + <server-action-ref server-action-name-ref="StatusGetAction"/> + </get-action> + <status-item direction="OUT" name="status"> + <custom-type-scalar data-type-name-ref="DEVICE_STATUS"/> + + <data-field-ref field-name-ref="status"/> + </status-item> + <detailed-status-item direction="OUT" name="detailedStatus"> + <array type="bool"> + <custom-constant-dim constant-name-ref="DETAILED_STATUS_SIZE"/> + </array> + <data-field-ref field-name-ref="detailedStatus"/> + </detailed-status-item> + <detailed-status-labels-item direction="OUT" name="detailedStatus_labels"> + <array2D type="char"> + <custom-constant-dim1 constant-name-ref="DETAILED_STATUS_SIZE"/> + <custom-constant-dim2 constant-name-ref="MAX_DETAILED_STATUS_LABEL_LENGTH"/> + </array2D> + <data-field-ref field-name-ref="detailedStatus_labels"/> + </detailed-status-labels-item> + <detailed-status-severity-item direction="OUT" name="detailedStatus_severity"> + <custom-type-array data-type-name-ref="DETAILED_STATUS_SEVERITY"> + <custom-constant-dim constant-name-ref="DETAILED_STATUS_SIZE"/> + </custom-type-array> + <data-field-ref field-name-ref="detailedStatus_severity"/> + </detailed-status-severity-item> + <powerState-item direction="OUT" name="powerState"> + <custom-type-scalar data-type-name-ref="DEVICE_POWER_STATE"/> + + <data-field-ref field-name-ref="powerState"/> + </powerState-item> + <control-item direction="OUT" name="control"> + <custom-type-scalar data-type-name-ref="DEVICE_CONTROL"/> + + <data-field-ref field-name-ref="control"/> + </control-item> + <interlock-item direction="OUT" name="interlock"> + <scalar type="bool"/> + <data-field-ref field-name-ref="interlock"/> + </interlock-item> + <opReady-item direction="OUT" name="opReady"> + <scalar type="bool"/> + <data-field-ref field-name-ref="opReady"/> + </opReady-item> + <modulesReady-item direction="OUT" name="modulesReady"> + <scalar type="bool"/> + <data-field-ref field-name-ref="modulesReady"/> + </modulesReady-item> + <error_collection-item direction="OUT"> + <error_codes direction="OUT" name="error_codes"> + <array type="int32_t"> + <custom-constant-dim constant-name-ref="MAX_NUMBER_OF_ERROR_MESSAGES"/> + </array> + </error_codes> + <error_messages direction="OUT" name="error_messages"> + <array2D type="char"> + <custom-constant-dim1 constant-name-ref="MAX_NUMBER_OF_ERROR_MESSAGES"/> + <custom-constant-dim2 constant-name-ref="MAX_ERROR_MESSAGE_LENGTH"/> + </array2D> + </error_messages> + <error_timestamps direction="OUT" name="error_timestamps"> + <array type="int64_t"> + <custom-constant-dim constant-name-ref="MAX_NUMBER_OF_ERROR_MESSAGES"/> + </array> + </error_timestamps> + <error_cycle_names direction="OUT" name="error_cycle_names"> + <array2D type="char"> + <custom-constant-dim1 constant-name-ref="MAX_NUMBER_OF_ERROR_MESSAGES"/> + <custom-constant-dim2 constant-name-ref="MAX_ERROR_MESSAGE_LENGTH"/> + </array2D> + </error_cycle_names> + <error_collection-field-ref field-name-ref="error_collection"/> + </error_collection-item> + </GSI-Status-Property> + <GSI-ModuleStatus-Property visibility="development" subscribable="true" name="ModuleStatus" multiplexed="false"> + <acq-stamp-item name="acqStamp" direction="OUT"> + <scalar type="int64_t" /> + </acq-stamp-item> + <update-flag-item optional="true" name="updateFlags" direction="OUT"> + <builtin-type-scalar data-type-name-ref="NOTIFICATION_UPDATE" /> + </update-flag-item> + <cycle-name-item optional="true" name="cycleName" direction="OUT"> + <array type="char"> + <dim>32</dim> + </array> + </cycle-name-item> + <cycle-stamp-item optional="true" name="cycleStamp" direction="OUT"> + <scalar type="int64_t" /> + </cycle-stamp-item> + <get-action> + <server-action-ref server-action-name-ref="ModuleStatusGetAction" /> + </get-action> + <module-status-item name="moduleStatus" direction="OUT"> + <custom-type-array data-type-name-ref="MODULE_STATUS"> + <custom-constant-dim constant-name-ref="MODULE_STATUS_SIZE" /> + + </custom-type-array> + + <data-field-ref field-name-ref="moduleStatus" /> + </module-status-item> + <module-status-labels-item name="moduleStatus_labels" direction="OUT"> + <array2D type="char"> + <custom-constant-dim1 constant-name-ref="MODULE_STATUS_SIZE" /> + <custom-constant-dim2 constant-name-ref="MAX_MODULE_STATUS_LABEL_LENGTH" /> + + </array2D> + + <data-field-ref field-name-ref="moduleStatus_labels" /> + </module-status-labels-item> + </GSI-ModuleStatus-Property> + <GSI-Acquisition-Property multiplexed="true" name="Acquisition" on-change="true" subscribable="true" visibility="operational"> + <acq-stamp-item direction="OUT" name="acqStamp"> + <scalar type="int64_t"/> + </acq-stamp-item> + <update-flag-item direction="OUT" name="updateFlags" optional="true"> + <builtin-type-scalar data-type-name-ref="NOTIFICATION_UPDATE"/> + </update-flag-item> + <cycle-name-item direction="OUT" name="cycleName" optional="true"> + <array type="char"> + <dim>32</dim> + </array> + </cycle-name-item> + <cycle-stamp-item direction="OUT" name="cycleStamp" optional="true"> + <scalar type="int64_t"/> + </cycle-stamp-item> + <get-action> + <server-action-ref server-action-name-ref="AcquisitionGetAction"/> + </get-action> + <acquisition-context-item direction="OUT"> + <acqStamp direction="OUT" name="acqStampGSI"> + <scalar type="int64_t"/> + </acqStamp> + <cycleStamp direction="OUT" name="cycleStampGSI"> + <scalar type="int64_t"/> + </cycleStamp> + <cycleName direction="OUT" name="cycleNameGSI"> + <array type="char"> + <custom-constant-dim constant-name-ref="MAX_CYCLE_NAME_LENGTH"/> + </array> + </cycleName> + <beamProcessID direction="OUT" name="beamProcessID"> + <scalar type="int32_t"/> + </beamProcessID> + <sequenceID direction="OUT" name="sequenceID"> + <scalar type="int32_t"/> + </sequenceID> + <acquisition-context-field-ref field-name-ref="acquisitionContext"/> + </acquisition-context-item> + </GSI-Acquisition-Property> + <GSI-Version-Property multiplexed="false" name="Version" on-change="false" subscribable="false" visibility="operational"> + <acq-stamp-item direction="OUT" name="acqStamp"> + <scalar type="int64_t"/> + </acq-stamp-item> + <update-flag-item direction="OUT" name="updateFlags" optional="true"> + <builtin-type-scalar data-type-name-ref="NOTIFICATION_UPDATE"/> + </update-flag-item> + <cycle-name-item direction="OUT" name="cycleName" optional="true"> + <array type="char"> + <dim>32</dim> + </array> + </cycle-name-item> + <cycle-stamp-item direction="OUT" name="cycleStamp" optional="true"> + <scalar type="int64_t"/> + </cycle-stamp-item> + <get-action> + <server-action-ref server-action-name-ref="VersionGetAction"/> + </get-action> + <version-item direction="OUT" name="classVersion"> + <array type="char"> + <custom-constant-dim constant-name-ref="MAX_VERSION_NAME_LENGTH"/> + </array> + </version-item> + <version-item direction="OUT" name="deployUnitVersion"> + <array type="char"> + <custom-constant-dim constant-name-ref="MAX_VERSION_NAME_LENGTH"/> + </array> + </version-item> + <version-item direction="OUT" name="fesaVersion"> + <array type="char"> + <custom-constant-dim constant-name-ref="MAX_VERSION_NAME_LENGTH"/> + </array> + </version-item> + </GSI-Version-Property> + </acquisition> + </device-interface> + <global-interface> + <setting> + <diagnostic-property multiplexed="false" name="DiagnosticSetting" visibility="expert"> + <description>Generic property which allows to diagnose any FESA classes</description> + <mode-item direction="INOUT" name="enableDiagMode"> + <scalar type="bool"/> + </mode-item> + <host-item direction="INOUT" name="hostName"> + <array type="char"> + <dim>32</dim> + </array> + </host-item> + <port-item direction="INOUT" name="portNumber"> + <scalar type="int32_t"/> + </port-item> + <config-item direction="IN" name="requestConfig"> + <scalar type="bool"/> + </config-item> + <state-item direction="IN" name="requestState"> + <scalar type="bool"/> + </state-item> + <fwk-topic-item direction="INOUT" name="fwkTopic"> + <builtin-type-scalar data-type-name-ref="DIAG_FWK_TOPIC"/> + </fwk-topic-item> + <custom-topic-item direction="INOUT" name="customTopic"> + <custom-type-scalar data-type-name-ref="DIAG_TOPIC"/> + </custom-topic-item> + <device-trace-item direction="INOUT" name="traceDevices"> + <array type="char"> + <dim>320</dim> + </array> + </device-trace-item> + <bypass-action-item direction="INOUT" name="bypassActions"> + <array type="char"> + <dim>320</dim> + </array> + </bypass-action-item> + </diagnostic-property> + </setting> + <acquisition> + <GSI-DeviceDescription-Property multiplexed="false" name="DeviceDescription" on-change="false" subscribable="false" visibility="operational"> + <timing-info-item direction="OUT" name="deviceNameTimingReceiver"> + <array type="char"> + <variable-dim/> + </array> + <data-field-ref field-name-ref="deviceNameTimingReceiver"/> + </timing-info-item> + <property-info-item direction="OUT" name="propertyNames"> + <array2D type="char"> + <variable-dim1/> + <variable-dim2/> + </array2D> + </property-info-item> + <device-info-item direction="OUT" name="deviceNames"> + <array2D type="char"> + <variable-dim1/> + <variable-dim2/> + </array2D> + </device-info-item> + <global-device-info-item direction="OUT" name="globalDeviceName"> + <array type="char"> + <variable-dim/> + </array> + </global-device-info-item> + <host-info-item direction="OUT" name="host"> + <array type="char"> + <variable-dim/> + </array> + </host-info-item> + </GSI-DeviceDescription-Property> + </acquisition> + </global-interface> + </interface> + <builtin-types> + <notification-update-enum name="NOTIFICATION_UPDATE"> + <IMMEDIATE access="RO" symbol="IMMEDIATE" value="1"/> + <SET access="RO" symbol="SET" value="2"/> + </notification-update-enum> + <diag-fwk-topic name="DIAG_FWK_TOPIC"> + <b0 name="SRV_GET_ACTION_PROFIING"/> + <b1 name="SRV_SET_ACTION_PROFILING"/> + <b2 name="RT_ACTION_PROFILING"/> + <b3 name="EVENT_PROFILING"/> + <b4 name="NOTIFICATION_PROFILING"/> + <b5 name="SRV_GET_ACTION_TRACKING"/> + <b6 name="SRV_SET_ACTION_TRACKING"/> + <b7 name="RT_ACTION_TRACKING"/> + <b8 name="EVENT_TRACKING"/> + <b9 name="NOTIFICATION_TRACKING"/> + <b10 name="PERSISTENCY_TRACKING"/> + <b11 name="TRANSACTION_TRACKING"/> + <b12 name="SUBSCRIPTION_TRACKING"/> + <b13 name="SIGNAL_HANDLER_TRACKING"/> + <b14 name="LOCAL_CONNECTION_TRACKING"/> + </diag-fwk-topic> + <fault-severity name="FaultSeverity"> + <description>Enumeration listing the available fault severities used by the fault fields</description> + <INFO access="RO" meaning="NONE" value="0" symbol="INFO" /> + <WARNING access="RO" meaning="WARNING" value="1" symbol="WARNING" /> + <ERROR access="RO" meaning="ERROR" value="2" symbol="ERROR" /> + <CRITICAL access="RO" meaning="ERROR" value="3" symbol="CRITICAL" /> + </fault-severity> + + </builtin-types> + <custom-types> + <diag-custom-topic name="DIAG_TOPIC"> + </diag-custom-topic> + <enum name="DEVICE_STATUS"> + <!--Possible (mutually exclusive) values to describe the device status--> + + <item access="RW" meaning="NONE" symbol="UNKNOWN" value="0"/> + <!--The device status is unknown--> + + <item access="RW" meaning="NONE" symbol="OK" value="1"/> + <!--The device is in fully operational state--> + + <item access="RW" meaning="NONE" symbol="WARNING" value="2"/> + <!--The device is not fully operational; A device in WARNING state can still be used operationally, --> + <!--but clients must be informed of a problem that might become worse. Details are explained in the errorMsg field.--> + + <item access="RW" meaning="NONE" symbol="ERROR" value="3"/> + <!--The device is in a fault state. Details are explained in the errorMsg field--> + </enum> + <enum name="DEVICE_POWER_STATE"> + <!--Possible (mutually exclusive) values to describe the power-state of the device.--> + + <item access="RW" meaning="NONE" symbol="UNKNOWN" value="0"/> + <!--The device mode is unknown--> + + <item access="RW" meaning="ON" symbol="ON" value="1"/> + <!--The device is in fully operational state--> + + <item access="RW" meaning="NONE" symbol="OFF" value="2"/> + <!--The device is turned off--> + + <item access="RW" meaning="NONE" symbol="STANDBY" value="3"/> + <!--The device is in a stand-by mode. This mode is a sort of “parking mode†in which the device can --> + <!--stay for hours or even days. It is defined by the following characteristics:--> + <!--It is safe, it does not wear out, it consumes little energy.--> + <!--Furthermore, it takes a short time to go from STANDBY to ON mode--> + + <item access="RW" meaning="NONE" symbol="POWER_DOWN" value="4"/> + <!--The device is shutting down. Note that some properties may not be accessible during this time.--> + <!--After shutdown the device will be in the mode OFF--> + + <item access="RW" meaning="NONE" symbol="POWER_UP" value="5"/> + <!--The device is starting up. Note that some properties may not be accessible during this time.--> + <!--After (re-)starting the device probably will be in the mode ON--> + + </enum> + <enum name="DEVICE_POWER"> + <!--An enumeration Type used to control the operational mode of the device.--> + <!--Its values are a subset of those in the DEVICE_POWER_STATE type--> + <item access="RW" meaning="ON" symbol="ON" value="1"/> + <!--The device is in fully operational state--> + + <item access="RW" meaning="OFF" symbol="OFF" value="2"/> + <!--The device is turned off--> + </enum> + <enum name="DEVICE_CONTROL"> + <!--Possible values to describe the control mode of a device--> + <!--Currently two control modes (LOCAL, REMOTE) are defined--> + + <item access="RW" meaning="NONE" symbol="REMOTE" value="0"/> + <!--The device can be controlled normally through the control system--> + + <item access="RW" meaning="NONE" symbol="LOCAL" value="1"/> + <!--The device can be controlled locally. But it can be accessed in read-only mode via the control system--> + </enum> + <enum name="TOL_CHECK_MODE"> + <!--This constant defines possible modes to check whether a control value is inside the tolerance values.--> + <!--Used to give information on how the tolerance fields are used to calculate the xxx_status information.--> + + <item access="RO" symbol="ABS" value="0"/> + <!--Use the absolute tolerance _tolAbs--> + + <item access="RO" symbol="REL" value="1"/> + <!--Use the relative tolerance _tolRel--> + </enum> + <bit-enum-32bits name="AQN_STATUS"> + <!--Possible values to describe the acquisition status of a field (in the _status suffix)--> + <!--If this suffix is missing, it means that no additional status information is provided for the corresponding field--> + <!--If all bits are 0, this means that the corresponding field is OK.--> + <!--Only the lower 16 bits are standardized, the upper 16 bits can be defined by the equipment specialist.--> + <!--The difference between the Status property and the _status suffix is described in the section on the Status property.--> + <b0 name="NOT_OK"/> + <!--Some problem occurred that is not represented by the other bits. This property is called--> + <!-- NOT_OK so that it is not mixed up with ERROR or WARNING in the Status property--> + <b1 name="BAD_QUALITY"/> + <!--The value was acquired with a degraded quality. This is typically used for measurements.--> + <b2 name="DIFFERENT_FROM_SETTING"/> + <!--Different from the requested control value (for discrete values)--><!--or out of tolerance (for continuous values).--> + <b3 name="OUT_OF_RANGE"/> + <!--The value is out of the normal range (e.g. a temperature is too high or too low).--> + <b4 name="BUSY"/> + <!--The property value is changing in response to receiving a new control value (e.g. moving to a--> + <!--new position, charging a capacitor, ...). If the value change does not reach the requested new--> + <!--value within the maximum timeout, the BUSY bit should remain=1 and the TIMEOUT bit must be turned on.--> + <b5 name="TIMEOUT"/> + <!--A timeout occurred, because the property did not reach the reqested new control value within the--> + <!--maximum allowable time. A timeout normally indicates a problem to be addressed by the--> + <!--equipment specialist. This is typically used for slow changing control values that are BUSY while they change.--> + <b6 name="bit6_is_reserved_for_later_usage"/> + <b7 name="bit7_is_reserved_for_later_usage"/> + <b8 name="bit8_is_reserved_for_later_usage"/> + <b9 name="bit9_is_reserved_for_later_usage"/> + <b10 name="bit10_is_reserved_for_later_usage"/> + <b11 name="bit11_is_reserved_for_later_usage"/> + <b12 name="bit12_is_reserved_for_later_usage"/> + <b13 name="bit13_is_reserved_for_later_usage"/> + <b14 name="bit14_is_reserved_for_later_usage"/> + <b15 name="bit15_is_reserved_for_later_usage"/> + <!--bit 6 to 15 are reserved ... dont use them!--> + + <b16 name="bit_16_and_higher_can_be_used_by_the_class_developer"/> + <!--into bit 16..32 you can put in anything you want--> + </bit-enum-32bits> + + <struct name="GSI_ERROR"> + <!--This struct-item describes the structure of an GSI-error--> + <struct-item name="error_string"> + <!--This string holds the error-message--> + <array type="char"> + <custom-constant-dim constant-name-ref="MAX_ERROR_MESSAGE_LENGTH"/> + </array> + </struct-item> + <struct-item name="error_code"> + <!--The error code according to the defined error-message--> + <scalar type="int32_t"/> + </struct-item> + <!--The timestamp when the error occured--> + <struct-item name="error_timestamp"> + <scalar type="int64_t"/> + </struct-item> + <!--The cycle for which the error occured--> + <struct-item name="error_cycle_name"> + <array type="char"> + <custom-constant-dim constant-name-ref="MAX_CYCLE_NAME_LENGTH"/> + </array> + </struct-item> + </struct> + <struct name="GSI_ACQ_CONTEXT"> + <!--This struct-item describes all AcquisitionContext items which are relevant for GSI--> + <struct-item name="acqStamp"> + <!--The acquisition stamp is used to indicate when a measurement was done --> + <scalar type="int64_t"/> + </struct-item> + <struct-item name="cycleStamp"> + <!--The cycle stamp is used to indicate when a specific cycle has started--> + <scalar type="int64_t"/> + </struct-item> + <struct-item name="cycleName"> + <!--The cycle name indicates the cycle which started at time of the cycleStamp --> + <array type="char"> + <custom-constant-dim constant-name-ref="MAX_CYCLE_NAME_LENGTH"/> + </array> + </struct-item> + <struct-item name="beamProcessID"> + <scalar type="int32_t"/> + </struct-item> + <struct-item name="sequenceID"> + <scalar type="int32_t"/> + </struct-item> + </struct> + <constant name="MAX_ERROR_MESSAGE_LENGTH" type="uint32_t" value="256"/> + <constant name="MAX_NUMBER_OF_ERROR_MESSAGES" type="uint32_t" value="16"/> + <constant name="MAX_CYCLE_NAME_LENGTH" type="uint32_t" value="256"/> + <constant name="MAX_VERSION_NAME_LENGTH" type="uint32_t" value="256"/> + <constant name="MAX_DETAILED_STATUS_LABEL_LENGTH" type="uint32_t" value="30"/> + <constant name="DETAILED_STATUS_SIZE" type="uint32_t" value="2"/> + <enum name="DETAILED_STATUS_SEVERITY"> + <item access="RO" symbol="INFO" value="0"/> + <item access="RO" symbol="WARNING_ON_FALSE" value="1"/> + <item access="RO" symbol="ERROR_ON_FALSE" value="2"/> + </enum> + <enum name="MODULE_STATUS"> + <!-- Mutually exclusive values to describe the status of a hardware / software module--> + <item access="RO" value="0" symbol="UNKNOWN" /> + <!--The status of the module is not known--> + <item access="RO" value="1" symbol="OK" /> + <!--The module is in fully operational state--> + <item access="RO" value="2" symbol="WARNING" /> + <!--The module is not fully operational; A module in WARNING state may still be used operationally, --> + <!--but clients must be informed of a problem that might become worse. --> + <item access="RO" value="3" symbol="ERROR" /> + <!--The module is in a fault state. The related device is not operational.--> + <item access="RO" value="4" symbol="NOT_AVAILABLE" /> + <!--The module is missing. The related device is not operational.--> + </enum> + <constant name="MAX_MODULE_STATUS_LABEL_LENGTH" type="uint32_t" value="30"/> + <constant name="MODULE_STATUS_SIZE" type="uint32_t" value="2"/> + </custom-types> + <data> + <device-data> + <configuration> + <GSI-detailed-status-labels-field name="detailedStatus_labels"> + <array2D type="char"> + <custom-constant-dim1 constant-name-ref="DETAILED_STATUS_SIZE"/> + <custom-constant-dim2 constant-name-ref="MAX_DETAILED_STATUS_LABEL_LENGTH"/> + </array2D> + <default>{myStatusLabel1,myStatusLabel2}</default> + </GSI-detailed-status-labels-field> + <GSI-detailed-status-severity-field name="detailedStatus_severity"> + <custom-type-array data-type-name-ref="DETAILED_STATUS_SEVERITY"> + <custom-constant-dim constant-name-ref="DETAILED_STATUS_SIZE"/> + </custom-type-array> + <default>{INFO,INFO}</default> + </GSI-detailed-status-severity-field> + <GSI-module-status-labels-field name="moduleStatus_labels"> + <array2D type="char"> + <custom-constant-dim1 constant-name-ref="MODULE_STATUS_SIZE" /> + + <custom-constant-dim2 constant-name-ref="MAX_MODULE_STATUS_LABEL_LENGTH" /> + </array2D> + <default>{myModule1,myModule2}</default> + </GSI-module-status-labels-field> + </configuration> + <setting> + <GSI-power-field multiplexed="false" name="power" persistent="false"> + <custom-type-scalar data-type-name-ref="DEVICE_POWER"/> + </GSI-power-field> + </setting> + <acquisition> + <GSI-control-field multiplexed="false" name="control"> + <custom-type-scalar data-type-name-ref="DEVICE_CONTROL"/> + </GSI-control-field> + <GSI-powerState-field multiplexed="false" name="powerState"> + <custom-type-scalar data-type-name-ref="DEVICE_POWER_STATE"/> + </GSI-powerState-field> + <GSI-status-field multiplexed="false" name="status"> + <custom-type-scalar data-type-name-ref="DEVICE_STATUS"/> + </GSI-status-field> + <GSI-interlock-field multiplexed="false" name="interlock"> + <scalar type="bool"/> + </GSI-interlock-field> + <GSI-opReady-field multiplexed="false" name="opReady"> + <scalar type="bool"/> + </GSI-opReady-field> + <GSI-modulesReady-field name="modulesReady" multiplexed="false"> + <scalar type="bool" /> + </GSI-modulesReady-field> + <GSI-detailed-status-field multiplexed="false" name="detailedStatus"> + <array type="bool"> + <custom-constant-dim constant-name-ref="DETAILED_STATUS_SIZE"/> + </array> + </GSI-detailed-status-field> + <GSI-module-status-field name="moduleStatus" multiplexed="false"> + <custom-type-array data-type-name-ref="MODULE_STATUS"> + <custom-constant-dim constant-name-ref="MODULE_STATUS_SIZE" /> + + </custom-type-array> + </GSI-module-status-field> + <GSI-acquisition-context-field multiplexed="true" name="acquisitionContext"> + <custom-type-scalar data-type-name-ref="GSI_ACQ_CONTEXT"/> + </GSI-acquisition-context-field> + <GSI-error_collection-field multiplexed="false" name="error_collection"> + <custom-type-array data-type-name-ref="GSI_ERROR"> + <custom-constant-dim constant-name-ref="MAX_NUMBER_OF_ERROR_MESSAGES"/> + </custom-type-array> + </GSI-error_collection-field> + </acquisition> + </device-data> + <global-data> + <configuration> + <!-- The name of the timing receiver --> + <GSI-timing-receiver-name-field name="deviceNameTimingReceiver"> + <array type="char"> + <!-- The number of the timing receiver --> + <variable-dim/> + </array> + </GSI-timing-receiver-name-field> + </configuration> + </global-data> + </data> + <actions> + <set-server-action implementation="default" name="InitSetAction"/> + <set-server-action implementation="default" name="ResetSetAction"/> + <set-server-action implementation="default" name="SettingSetAction"/> + <set-server-action implementation="default" name="PowerSetAction"/> + <get-server-action implementation="default" name="PowerGetAction"/> + <get-server-action implementation="default" name="SettingGetAction"/> + <get-server-action implementation="default" name="AcquisitionGetAction"/> + <get-server-action implementation="default" name="StatusGetAction"/> + <get-server-action implementation="default" name="VersionGetAction"/><get-server-action implementation="default" name="ModuleStatusGetAction"></get-server-action> + </actions> + +</equipment-model> \ No newline at end of file diff --git a/silecs-codegen/src/xml/test/fesa/__init__.py b/silecs-codegen/src/xml/test/fesa/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/silecs-codegen/src/xml/test/fesa/__init__.pyc b/silecs-codegen/src/xml/test/fesa/__init__.pyc new file mode 100644 index 0000000000000000000000000000000000000000..68e4dc6ffb146fbdf6125762cdd0dfaa2fe05df9 GIT binary patch literal 188 zcmZ9Gy$ZrW5QI;#5W)9I6E|QhVqt9~Xt|u5)g0bW$etv=puMl+6S#p?F3dN>G_#-Y zYWY4NE@Y;gsqa-XSJcLwim^Es3iAhH?SN7UDMFJ1!<9V<HNA@wd>o)p-9uVST#EBd xQU==zOqo*6ca9((!4N!TmJBx*iyN%40z?;GMqIbAywIg>NcGe6Zv017<_FmMF#7-i literal 0 HcmV?d00001 diff --git a/silecs-codegen/src/xml/test/fesa/emptyTemplateFESA300.xml b/silecs-codegen/src/xml/test/fesa/emptyTemplateFESA300.xml new file mode 100644 index 0000000..b6c3044 --- /dev/null +++ b/silecs-codegen/src/xml/test/fesa/emptyTemplateFESA300.xml @@ -0,0 +1,96 @@ +<?xml version="1.0" encoding="UTF-8"?> +<equipment-model xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../FESA_Metamodel-lab.xsd"> + <information> + <class-name>EmptyTemplate</class-name> + <class-major-version>0</class-major-version> + <class-minor-version>1</class-minor-version> + <class-tiny-version>0</class-tiny-version> + <type>Final</type> + <state>development</state> + <description>An Empty design</description> + <fesa-version>0.9.0</fesa-version> + <repository-path>undefined</repository-path> + </information> + <ownership> + <responsible name="Undefined" /> + <creator login="Undefined" /> + </ownership> + <interface> + <global-interface> + <setting> + <diagnostic-property multiplexed="false" name="DiagnosticSetting" visibility="expert"> + <description>Generic property which allows to diagnose any FESA classes</description> + <mode-item direction="INOUT" name="enableDiagMode"> + <scalar type="bool" /> + </mode-item> + <host-item direction="INOUT" name="hostName"> + <array type="char"> + <dim>32</dim> + </array> + </host-item> + <port-item direction="INOUT" name="portNumber"> + <scalar type="int32_t" /> + </port-item> + <config-item direction="IN" name="requestConfig"> + <scalar type="bool" /> + </config-item> + <state-item direction="IN" name="requestState"> + <scalar type="bool" /> + </state-item> + <fwk-topic-item direction="INOUT" name="fwkTopic"> + <builtin-type-scalar data-type-name-ref="DIAG_FWK_TOPIC" /> + </fwk-topic-item> + <custom-topic-item direction="INOUT" name="customTopic"> + <custom-type-scalar data-type-name-ref="DIAG_TOPIC" /> + </custom-topic-item> + <device-trace-item direction="INOUT" name="traceDevices"> + <array type="char"> + <dim>320</dim> + </array> + </device-trace-item> + <bypass-action-item direction="INOUT" name="bypassActions"> + <array type="char"> + <dim>320</dim> + </array> + </bypass-action-item> + </diagnostic-property> + </setting> + </global-interface> + </interface> + <builtin-types> + <notification-update-enum name="NOTIFICATION_UPDATE"> + <IMMEDIATE access="RO" symbol="IMMEDIATE" value="1" /> + <SET access="RO" symbol="SET" value="2" /> + </notification-update-enum> + <diag-fwk-topic name="DIAG_FWK_TOPIC"> + <b0 name="SRV_GET_ACTION_PROFIING" /> + <b1 name="SRV_SET_ACTION_PROFILING" /> + <b2 name="RT_ACTION_PROFILING" /> + <b3 name="EVENT_PROFILING" /> + <b4 name="NOTIFICATION_PROFILING" /> + <b5 name="SRV_GET_ACTION_TRACKING" /> + <b6 name="SRV_SET_ACTION_TRACKING" /> + <b7 name="RT_ACTION_TRACKING" /> + <b8 name="EVENT_TRACKING" /> + <b9 name="NOTIFICATION_TRACKING" /> + <b10 name="PERSISTENCY_TRACKING" /> + <b11 name="TRANSACTION_TRACKING" /> + <b12 name="SUBSCRIPTION_TRACKING" /> + <b13 name="SIGNAL_HANDLER_TRACKING" /> + <b14 name="LOCAL_CONNECTION_TRACKING" /> + </diag-fwk-topic> + <fault-severity name="FaultSeverity"> + <description>Enumeration listing the available fault severities used by the fault fields</description> + <INFO access="RO" symbol="INFO" value="0" meaning="NONE" /> + <WARNING access="RO" symbol="WARNING" value="1" meaning="WARNING" /> + <ERROR access="RO" symbol="ERROR" value="2" meaning="ERROR" /> + <CRITICAL access="RO" symbol="CRITICAL" value="3" meaning="ERROR" /> + </fault-severity> + </builtin-types> + <custom-types> + <diag-custom-topic name="DIAG_TOPIC"> + </diag-custom-topic> + </custom-types> + <data /> + <actions /> +</equipment-model> diff --git a/silecs-codegen/src/xml/test/fesa/fillFESADeployUnitTest.py b/silecs-codegen/src/xml/test/fesa/fillFESADeployUnitTest.py new file mode 100644 index 0000000..b78fa41 --- /dev/null +++ b/silecs-codegen/src/xml/test/fesa/fillFESADeployUnitTest.py @@ -0,0 +1,68 @@ +#!/usr/bin/python +# Copyright 2016 CERN and GSI +# +# 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 3 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, see <http://www.gnu.org/licenses/>. + +import sys +import libxml2 + +from test.testBase import * +import fesa.fesa_3_0_0.fillFESADeployUnit + +simpleSilecsDeploy = '''<?xml version="1.0" encoding="UTF-8"?> +<SILECS-Deploy silecs-version="0.10.0" created="04/05/16" updated="04/05/16" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation=""> + <Information> + <Owner user-login="MaxMustermann"/> + <Editor user-login="MaxMustermann"/> + </Information> + <Deploy-Unit name="MyTestDeploy" version="0.1.0"> + <Siemens-PLC system="STEP-7" model="SIMATIC_S7-300" protocol="BLOCK_MODE" base-DB-number="0"/> + </Deploy-Unit> + <Controller host-name="asl1234"> + <SilecsDesign silecs-design-version="0.1.0" silecs-design-name="MyTestClass1"> + <Device device-name="myDevice1" /> + </SilecsDesign> + <SilecsDesign silecs-design-version="0.1.0" silecs-design-name="MyTestClass2"> + <Device device-name="myDevice2" /> + </SilecsDesign> + </Controller> +</SILECS-Deploy>''' + +simpleSilecsDeployParsed = libxml2.parseDoc(simpleSilecsDeploy) +simpleFesaDeployParsed = libxml2.parseFile("test/fesa/DeploymentUnitTemplateFESA300.xml") + +def fillDU_3_0_0(generator): + generator.fillXML(simpleFesaDeployParsed,simpleSilecsDeployParsed,"MyTestDeploy", "some/schema.xsd", "1.2.3") + + # check that default class is removed + defaultClassTemplate = simpleFesaDeployParsed.xpathEval('/deploy-unit/class[class-name/text()="class-name"]') + assertEqual( len(defaultClassTemplate), 0 ) + + # test 2 classes available + classes = simpleFesaDeployParsed.xpathEval('/deploy-unit/class') + assertEqual( len(classes), 2 ) + + # test 2 classes available after overwrite + generator.fillXML(simpleFesaDeployParsed,simpleSilecsDeployParsed,"MyTestDeploy", "some/schema.xsd", "1.2.3") + classes = simpleFesaDeployParsed.xpathEval('/deploy-unit/class') + assertEqual( len(classes), 2 ) + +def runTests(): + generator = fesa.fesa_3_0_0.fillFESADeployUnit.FESADeployUnitGenerator3_0_0() + fillDU_3_0_0(generator) + # No need to test 3.1.0, it uses the same generator than 3.0.0 + allTestsOk() + diff --git a/silecs-codegen/src/xml/test/fesa/fillFESADeployUnitTest.pyc b/silecs-codegen/src/xml/test/fesa/fillFESADeployUnitTest.pyc new file mode 100644 index 0000000000000000000000000000000000000000..4804c5a96ddb0cda5730705483189fe57df3521f GIT binary patch literal 2413 zcmc&#-EQMV6dpTGyUljhrTmDMxUhUf0NInI3yUhJWt*g^qJK(Kfx22%u03t6j%R{r z(xlRsn{v+!@KU@AF97F^oiwG01qo@bczou}vFDrbeCOo1-=9?0{9nG0NO3K~^BcI; z0EQTT7P%zkWM*6B#4>)HT-u~xM3l(M0*PTP6K0WQk+3qkh0rB4eMI5~GhHTenfwf& ztB`on7>{v-UUdmJOa6fCplX4sarj*QR3aqUnxx#hVwp;$Xu5U3<~mG7GET%r(>?C* zcwf6)o0XuqyVq&;yfzzhdF`l#vq*Wf*J^&fhHpk03pI<IZtXd(eM#$Ixz1=9|J7A- z;DT+1+L)-M=?=6WZcsWNkNxqwFS85UsMYH9hyA@?G+=4yB|_;?M9j_KRLO>r2Vu(8 zFpO9pvnQian<KcJCMwt!=Q2x;Gxy-G!Qoi2%o!<`d0bv3aOC}PvOiLqL97rior~?n ziI)E&IG_*q3UZ>nW07b_094rLy3dr({q7y(KpikQw`(t9DHF;&+G{!L8i1uux7Y6+ zc`sZil`-Qm-Q9oL-))`tUU=&@pnaH0Eh7ml+k1zt?@sp*+a1?A3l;O)+nyMuXDox9 zOb-{(IdlbEEh%&+IR|nEQfV*894cOKtUsT@3wkE;ZKje7F;ziqX7|K^S|~J9tj=@L z;-OOY*+(%ikeN2SN+RaO=27gQUgzGr>&y}p(0LG3;{HcujsJqI@fKtOy<-;2h~BHC zP4xv<BglfDGZhwTf$VG4O`oMh4z;t>>Ai$B`%p0v7A{mR!8X!@Tm1^d8z^p5)Y`^! zk6|p4+cL4B&XZEn9BwS47l<yCHx~8^XcV{hEMgH|H}*8bHW5oE;%y)QhgYF_^{S5m z;DKI&alQc5DuS0Oqso-HKT)wNgRky4{B_j;i^itccq5>KMktwAW;D{EnoV@|v!;9J za$f@p@X@uueK)beT}9e7HpBCTbLcPnBd}EhJhL50KwcI{VWwEDKb|d3^@gplSX_q1 z$uQJ|&Q-|uW0(Oxmg&xqBbZ}`I1^QTY7D(#&~-v+Ci(-I#q2yBac#<Anq-5@9EPbX z#1J#66f7FaG?ju5kghYvk+N|j1m$8v$1=M#ZO|*~Ed}(nu%V4J*qW*=qM#liZK^ap zKk6z!ajrI{{o%FA6t1?9PuEXtr!@)))Kf%cJu9tR@0<IXwQ5Di2Lm!|wD>6)8ng(i zvr%}rgxr8<0R;;BvOs*`vWzTH$Om~o7QjUL>q=qd8*5DDL!9~(aNmdi?UY>uxQp2^ z-wHX$ma7gg&A(n3rT9*{MF81I7*JbaE7T*g)~t$M#R@UP!Jdy2<;fZ3tf8Oa0vyA~ zVH<k7cEN*$`8ecc`45TenlB=WxxnXDtP#l&b>5ay7ZYG)YCJp8;=3hq86vyyfptfk jvEG3y5pMwhek0B{5s^{kinU@_td$QJ?Nw{lUVi!~Dj<v! literal 0 HcmV?d00001 diff --git a/silecs-codegen/src/xml/test/fesa/generateFesaDesignTest.py b/silecs-codegen/src/xml/test/fesa/generateFesaDesignTest.py new file mode 100644 index 0000000..1118df7 --- /dev/null +++ b/silecs-codegen/src/xml/test/fesa/generateFesaDesignTest.py @@ -0,0 +1,115 @@ +#!/usr/bin/python +# Copyright 2016 CERN and GSI +# +# 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 3 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, see <http://www.gnu.org/licenses/>. + +import sys + +from test.testBase import * +import fesa.fesa_3_0_0.generateFesaDesign +import fesa.fesa_3_1_0.generateFesaDesign + +import libxml2 + +simpleSilecsDesign = '''<?xml version="1.0" encoding="UTF-8"?> +<SILECS-Design silecs-version="0.10.0" created="03/02/16" updated="03/02/16" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="/common/home/bel/schwinn/lnx/workspace-silecs/silecs-model/src/xml/DesignSchema.xsd"> + <Information> + <Owner user-login="schwinn"/> + <Editor user-login="schwinn"/> + </Information> + <SILECS-Class name="Test123" version="0.1.0" domain="OPERATIONAL"> + <Block name="Setting" mode="READ-WRITE" generateFesaProperty="true"> + <Register name="mySettingRegister" format="uint8" synchro="MASTER" generateFesaValueItem="true"/> + </Block> + <Block name="Acquisition" mode="READ-ONLY" generateFesaProperty="true"> + <Register name="myAcqRegister" format="uint8" synchro="MASTER" generateFesaValueItem="true"/> + </Block> + </SILECS-Class> +</SILECS-Design>''' +simpleSilecsDesignRoot = libxml2.parseDoc(simpleSilecsDesign) + +def testFillXML_EmptyTemplate_3_0_0(generator): + fesaRoot = libxml2.parseFile("test/fesa/emptyTemplateFESA300.xml") + generator.fillXML('3.0.0', 'MyClass', fesaRoot,simpleSilecsDesignRoot,logTopics={'errorlog': True}) + assertTrue( fesaRoot.xpathEval('/equipment-model/events') != None ) + assertTrue( fesaRoot.xpathEval('/equipment-model/scheduling-units') != None ) + #etree.tostring(fesaRoot) + +def testFillXML_GSITemplate_3_0_0(generator): + fesaRoot = libxml2.parseFile("test/fesa/GSIClassTemplateFESA300.xml") + generator.fillXML('3.0.0', 'MyClass', fesaRoot,simpleSilecsDesignRoot,logTopics={'errorlog': True}) + assertTrue( fesaRoot.xpathEval('/equipment-model/events') != None ) + assertTrue( fesaRoot.xpathEval('/equipment-model/scheduling-units') != None ) + + acquisition = fesaRoot.xpathEval('/equipment-model/interface/device-interface/acquisition')[0] + firstGSIAcqProp = acquisition.xpathEval('GSI-Acquisition-Property')[0] + assertTrue( acquisition.xpathEval('*')[0].prop('name') != firstGSIAcqProp.prop('name') ) # check if generated at right position + assertEqual( firstGSIAcqProp.prop('name'),"Acquisition" ) + valueItem = firstGSIAcqProp.xpathEval('value-item')[0] + assertTrue( valueItem != None ) + + setting = fesaRoot.xpathEval('/equipment-model/interface/device-interface/setting')[0] + firstGSISettingProp = setting.xpathEval('GSI-Setting-Property')[0] + assertTrue( acquisition.xpathEval('*')[0].prop('name') != firstGSISettingProp.prop('name') ) # check if generated at right position + #etree.tostring(fesaRoot) + +def testFillXML_EmptyTemplate_3_1_0(generator): + fesaRoot = libxml2.parseFile("test/fesa/emptyTemplateFESA300.xml") + generator.fillXML('3.1.0', 'MyClass', fesaRoot,simpleSilecsDesignRoot,logTopics={'errorlog': True}) + assertTrue( fesaRoot.xpathEval('/equipment-model/events') != None ) + assertTrue( fesaRoot.xpathEval('/equipment-model/scheduling-units') != None ) + #etree.tostring(fesaRoot) + +def testFillXML_GSITemplate_3_1_0(generator): + fesaRoot = libxml2.parseFile("test/fesa/GSIClassTemplateFESA300.xml") + generator.fillXML('3.1.0', 'MyClass', fesaRoot,simpleSilecsDesignRoot,logTopics={'errorlog': True}) + assertTrue( fesaRoot.xpathEval('/equipment-model/events') != None ) + assertTrue( fesaRoot.xpathEval('/equipment-model/scheduling-units') != None ) + + acquisition = fesaRoot.xpathEval('/equipment-model/interface/device-interface/acquisition')[0] + firstGSIAcqProp = acquisition.xpathEval('GSI-Acquisition-Property')[0] + + assertTrue( acquisition.xpathEval('*')[0].prop('name') != firstGSIAcqProp.prop('name') ) # check if generated at right position + assertEqual( firstGSIAcqProp.prop('name'),"Acquisition" ) + valueItems = firstGSIAcqProp.xpathEval('value-item') + assertTrue( valueItems != None ) + + setting = fesaRoot.xpathEval('/equipment-model/interface/device-interface/setting')[0] + firstGSISettingProp = setting.xpathEval('GSI-Setting-Property')[0] + assertTrue( acquisition.xpathEval('*')[0].prop('name') != firstGSISettingProp.prop('name') ) # check if generated at right position + #etree.tostring(fesaRoot) + +def testFillXML_AllTypes_3_1_0(generator): + fesaRoot = libxml2.parseFile("test/fesa/GSIClassTemplateFESA300.xml") + silecsRoot = libxml2.parseFile("test/AllTypesFESA.silecsdesign") + fesaRoot = generator.fillXML('3.1.0', 'MyClass', fesaRoot,silecsRoot,logTopics={'errorlog': True}) + fesaNewDocPath = "test/generated_temp/AllTypesFESA.design" + fesaCompareDocPath = "test/generated_correct/AllTypesFESA.design" + with open(fesaNewDocPath, 'w') as fd: + fesaRoot.saveTo(fd,format = True) + + print 'FESA design document saved successfully' + assertFileEqual( fesaNewDocPath, fesaCompareDocPath) + +def runTests(): + generator = fesa.fesa_3_0_0.generateFesaDesign.FESADesignGenerator3_0_0(); + testFillXML_EmptyTemplate_3_0_0(generator) + testFillXML_GSITemplate_3_0_0(generator) + generator = fesa.fesa_3_1_0.generateFesaDesign.FESADesignGenerator3_1_0(); + testFillXML_EmptyTemplate_3_1_0(generator) + testFillXML_GSITemplate_3_1_0(generator) + testFillXML_AllTypes_3_1_0(generator) + allTestsOk() diff --git a/silecs-codegen/src/xml/test/fesa/generateFesaDesignTest.pyc b/silecs-codegen/src/xml/test/fesa/generateFesaDesignTest.pyc new file mode 100644 index 0000000000000000000000000000000000000000..23d5186041cfed05c147cdf563884d1b54027d24 GIT binary patch literal 5931 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 L`J4FNnqT|@a3Rr6 literal 0 HcmV?d00001 diff --git a/silecs-codegen/src/xml/test/fesa/generateSourceCodeTest.py b/silecs-codegen/src/xml/test/fesa/generateSourceCodeTest.py new file mode 100644 index 0000000..edc60f8 --- /dev/null +++ b/silecs-codegen/src/xml/test/fesa/generateSourceCodeTest.py @@ -0,0 +1,48 @@ +#!/usr/bin/python +# Copyright 2016 CERN and GSI +# +# 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 3 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, see <http://www.gnu.org/licenses/>. + +import sys + +from test.testBase import * +import fesa.fesa_3_0_0.generateSourceCode +import fesa.fesa_3_1_0.generateSourceCode + +import libxml2 + +testFolder = "test" +generationFolder = testFolder + "/generated_temp" +comparisonFolder = testFolder + "/generated_correct" +generatedHeaderName = "AllTypes.h" +generatedCppName = "AllTypes.cpp" + +silecsDesignRoot = libxml2.parseFile("test/AllTypesFESA.silecsdesign") + + + +def testGenHSource(): + fesaDesignRoot = libxml2.parseFile(generationFolder + "/AllTypesFESA.design" ) + fesa.fesa_3_1_0.generateSourceCode.genHSource('AllTypes', silecsDesignRoot,fesaDesignRoot,generationFolder,logTopics={'errorlog': True}) + assertFileEqual( generationFolder + "/" + generatedHeaderName, comparisonFolder + "/" + generatedHeaderName) + +def testGenCppSource(): + fesaDesignRoot = libxml2.parseFile(generationFolder + "/AllTypesFESA.design" ) + fesa.fesa_3_1_0.generateSourceCode.genCppSource('AllTypes', silecsDesignRoot,fesaDesignRoot,generationFolder,logTopics={'errorlog': True}) + assertFileEqual( generationFolder + "/" + generatedCppName, comparisonFolder + "/" + generatedCppName) + +def runTests(): + testGenHSource() + testGenCppSource() + allTestsOk() diff --git a/silecs-codegen/src/xml/test/fesa/generateSourceCodeTest.pyc b/silecs-codegen/src/xml/test/fesa/generateSourceCodeTest.pyc new file mode 100644 index 0000000000000000000000000000000000000000..d6c7d920cdc956e5010282326b34c1e8d222f554 GIT binary patch literal 1921 zcmd5+O>Yx15FKy6nlx>J0_8*E0GEK&YypWALX^_dQ;?iUNRd#q-8IcB`^DN(TM16# z48M)P!XJP)-c8a1_cn=VC*xWB&6{Wc{I%A)-~I8yr}ERl^EHP44in%fXhJkBe1|52 z24&QtVP&3CJ?GbGSfijq!#b%t1y$M_Hmp~Jw?aXkhD{0@G;EQoQMgLM3e5x!+Y~hE z8}?eGpk<wP3RbPN!7%!rHXwz+@#%F0T*Kyxsj{oI(Hn5wW0k1fGb$Jv6=(X!#h9Pw zx$=!}A-o$!gR@NO?pX7}i@$!B=?4h#n(jP$u;1V9>M&Bi4wMd$6H6EaXkzSP=#Tsk z017e=<K040UlFQMSfvn^f((aDgT5e$j0%mB3PP&%VpbKxG;J6xnHC0kDczYv0-X0d zb?ng7H(@X0DiC3*WffSAC`yk9X%_n0PN_UkbA&8yt|b#-kQE-C#?dqTM&{*O9iU8e z4KpQ|VVWGIQJ`{5^(Uo003>2(^nCPmv}2g%Ir05;n)_-m4V2A7_^=4sB?}7QS_);F z8oT5mpDM%M^R&h;y#M~^sTY~ebL$3&$^(X;7Z>3CGzQvG&%qUvSTBJscjzEO*60|X zi}&I*amQ(_+#?ma+8>{UN#aJyse6*<6P<a!+AeTz$Kb;)eIF&E8dvAO3&LEh4<=!u zxn=1CXs4T<8HU4o?-ndPLPT>TNo<P8;_AsrI>06?Z1`l!8jKZ-WYm%sBUx#Z6((5- zauvq#83H|fSys>>*LaEvklfnyf>HspxRLTYW^CgmOXyNt#ey$ewWxss{oO2th|j$} z^LOFk%+C<Qv9b@xKJ0nrv|h(j$x4>DIhz^taP{zw^?tG}*?N~C(G}pyr-{Y04Zp0n zAsV7%Ibr<zOdIYe6Vzq%#?#6?M1&7Ox4a5=Mmt?dz}~;hvtWhtPcE*F|K+mAEJeIY zaqARnW2H#OBX6;>GPDX?Fe~q1;%e~uGEReOq+T&-eGjJXv_xC9owidKEqv>u?rc<> HwPx)P+fUEy literal 0 HcmV?d00001 diff --git a/silecs-codegen/src/xml/test/general/__init__.py b/silecs-codegen/src/xml/test/general/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/silecs-codegen/src/xml/test/general/__init__.pyc b/silecs-codegen/src/xml/test/general/__init__.pyc new file mode 100644 index 0000000000000000000000000000000000000000..dcd01aa4a2f45a49711959f9eb958f03364b5c75 GIT binary patch literal 185 zcmZ9GK?=e^3`Iw9A%gelrse`7E?m1Q=yI5*!476-%4DSVg6_SFCoqMs4E*=Q+a#aw zZu`ETZ)lcTX`eK*R&>TR)od=6!u&y6b$}^^6roRnpd|*ue)KT{#|g%iA2K+kT09d< t9b6Vzc1#`JDS~8#DKHe00xBpw25Wuv#oGPwDjPj>2&sEA9p`66V}4L0FoysD literal 0 HcmV?d00001 diff --git a/silecs-codegen/src/xml/test/general/genDuWrapperTest.py b/silecs-codegen/src/xml/test/general/genDuWrapperTest.py new file mode 100644 index 0000000..d0b43d0 --- /dev/null +++ b/silecs-codegen/src/xml/test/general/genDuWrapperTest.py @@ -0,0 +1,52 @@ +#!/usr/bin/python +# Copyright 2016 CERN and GSI +# +# 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 3 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, see <http://www.gnu.org/licenses/>. + +import sys +import libxml2 + +from test.testBase import * +from genduwrapper import * +import iecommon +import iefiles + +import libxml2 + +testFolder = "test" +generationFolder = testFolder + "/generated_temp/wrapper" +comparisonFolder = testFolder + "/generated_correct/wrapper" +deployFilePath = testFolder + "/AllTypesDU.silecsdeploy" +duControllerWrapperGenerated = generationFolder + "/Siemens_Step7Device.h" # just check one of them, codegen is identical for all +duControllerWrapperCorrect = comparisonFolder + "/Siemens_Step7Device.h" +duDesignWrapperGenerated = generationFolder + "/AllTypes.h" +duDesignWrapperCorrect = comparisonFolder + "/AllTypes.h" + +def fakeGetSilecsDesignFilePath(workspacePath,designName): + return testFolder + "/AllTypes.silecsdesign" + +def fakeGetDuDesignWrapperFile(workspacePath,deployName,designName): + return generationFolder + "/" + designName + ".h" + +def fakeGetDuWrapperFile(workspacePath, deployName, controllerName): + return generationFolder + "/" + controllerName + ".h" + +def CompareGeneratedFiles(): + assertFileEqual( duDesignWrapperGenerated, duDesignWrapperCorrect) + assertFileEqual( duControllerWrapperGenerated, duControllerWrapperCorrect) + +def runTests(): + genDuWrapperBase(deployFilePath,fakeGetDuWrapperFile,"fake",fakeGetSilecsDesignFilePath, fakeGetDuDesignWrapperFile,"AllTypesDU","0.1.0") + CompareGeneratedFiles() + allTestsOk() diff --git a/silecs-codegen/src/xml/test/general/genDuWrapperTest.pyc b/silecs-codegen/src/xml/test/general/genDuWrapperTest.pyc new file mode 100644 index 0000000000000000000000000000000000000000..aa0081a34ddd6b2da0764f53950b6a5fd34874e9 GIT binary patch literal 2277 zcmd5-O^?(@5N&(Dc4uc;2qBA-RZdYDA*~HuxS$9!1KcLavn!;zAmgrO%=jzr9+s83 zpykdl%OQUye<0K=f9wJ`E{kVee(vhByIxm4|NGx~_}=^YJW}<s&DV!~nt#}6{yS=| z)Uw5nS~@cBs<o>QF@sU3LOi#tmfa?<r<T12S8*M+>?`Uk-Bo+bfuJ6vEkS)o+lmHC z4;T#<ZB=MT#<qBDBx68hrMJ}wUf30-hXQt$-VtzB>5+hIN{<EnfGif1E1XgMKOggn z!_dOqwp~Cn*6cCxUr|P7Xi2}YlotL;85RYV=I76SQC^l5+17m%?ng;-cv_H|9eE~B zC^DLgBtJDj!MTVjrOdooSSs$%=uI4vw=z2y<GfYm@_lno8JjIORyJX8F@a}ZJ+66I z`z8~=%Brk}2;qF5<cX$Ig6x>bPV#bXiZG&Qp<P+b(uAman9_vrlo<1xkssx0nrHqh zPsx8tiEpCSNt|VVlD+lY=Nwd79;9Ju{2E8OCZ^CgW#qq26CVqyIZbe#ZJt+*9<swL zPVF!Jy5n$7PsuKXw3#gG31h7DH+CE3t(>UC7AJ0noU06Ka^AUWkL!?0!i>3WtuKMz zs-gvx>&=bxtR@GO1DKi*>=*b5P!yL(3aYIpWwxmZsc8c*x7hm)oCN(QuBIdyAjy`3 zKxz#=66KjK^CY42a%<y9UQ0{E1p;n2iEvRclmlr@`82<>;iBLQu&z3Dm4lm(;x@;P zR;&Z)`}w4YiMwn<W2m%X_VM4FFtKQ6{W<MV8&$Aq<}aMnN(}72xTY<6^@`79v8{UZ z)r30!yxcCO5pVF~rg>U~CHG>jf#Ad(u*0Aqlrui(8^t1gdkk8>S!OG)xfgXuoeh}& zo;u@D+n0;*kB7}gcd@(DdX1jVjtutYj(69)GeLdYx^G+I_%k$QQKgl-HbN0VN(00O z_<{x3*vOMZR%NLBU+YUI7>t#hOcryOu|Yp7XWtn(lk1F_I37GT7HKE(OP0@jBHYkW z4@OcSv6ppBZ%!&9wRmn!m10Y5Ovl)_06Hl>E*$a%-rLwT+81EM1Jr*2iUWKi0`Pi) sMBx-n2KY992mC!qbG=FE53I@j&SvC{+@Ujca2>gQMi+kWc1M2QPkdTDC;$Ke literal 0 HcmV?d00001 diff --git a/silecs-codegen/src/xml/test/general/genParamTest.py b/silecs-codegen/src/xml/test/general/genParamTest.py new file mode 100644 index 0000000..0d59b80 --- /dev/null +++ b/silecs-codegen/src/xml/test/general/genParamTest.py @@ -0,0 +1,75 @@ +#!/usr/bin/python +# Copyright 2016 CERN and GSI +# +# 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 3 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, see <http://www.gnu.org/licenses/>. + +import difflib +import sys +import libxml2 + +from test.testBase import * +from genparam import * +import iecommon +import iefiles + +import libxml2 + +testFolder = "test" +generationFolder = testFolder + "/generated_temp/client" +comparisonFolder = testFolder + "/generated_correct/client" + +def fakeGetSilecsDesignFilePath(workspacePath,designName): + return testFolder + "/AllTypes.silecsdesign" + +def fakeGetParameterFile(workspacePath,deployName,controllerName): + return generationFolder + "/" + controllerName + ".silecsparam" + +def fakeGetSilecsDeployFilePath(workspacePath,deployName): + return testFolder + "/AllTypesDU.silecsdeploy" + +def fakeGetParameterFileDirectory(workspacePath,deployName): + return generationFolder + +def CompareGeneratedFiles(hostName,fileExtension): + fileGeneratedPath = generationFolder + "/" + hostName + fileExtension + fileCorrectPath = comparisonFolder + "/" + hostName + fileExtension + print "comparing: " + fileGeneratedPath + " with: " + fileCorrectPath + assertParameterFileEqual( fileGeneratedPath, fileCorrectPath) + +def SiemensSourcesTest(): + CompareGeneratedFiles("Siemens_TiaDevice",".silecsparam") + CompareGeneratedFiles("Siemens_TiaBlock",".silecsparam") + CompareGeneratedFiles("Siemens_Step7Device",".silecsparam") + CompareGeneratedFiles("Siemens_Step7Block",".silecsparam") + +def BeckhoffSourcesTest(): + CompareGeneratedFiles("Beckhoff_BC9020",".silecsparam") + CompareGeneratedFiles("Beckhoff_CX9020",".silecsparam") + +def SchneiderSourcesTest(): + CompareGeneratedFiles("Schneider_M340",".silecsparam") + CompareGeneratedFiles("Schneider_PremiumQuantum",".silecsparam") + +def RabbitSourcesTest(): + CompareGeneratedFiles("Rabbit_BlockMode",".silecsparam") + CompareGeneratedFiles("Rabbit_DeviceMode",".silecsparam") + +def runTests(): + + genParamBase( fakeGetSilecsDesignFilePath, fakeGetParameterFile, fakeGetSilecsDeployFilePath, fakeGetParameterFileDirectory, "fake", "AllTypesDU", "fake", "DEV") + SiemensSourcesTest() + BeckhoffSourcesTest() + SchneiderSourcesTest() + RabbitSourcesTest() + allTestsOk() diff --git a/silecs-codegen/src/xml/test/general/genParamTest.pyc b/silecs-codegen/src/xml/test/general/genParamTest.pyc new file mode 100644 index 0000000000000000000000000000000000000000..1059aac19f8e8874af9d0446264a8a8380b9e6c0 GIT binary patch literal 3729 zcmd5;TW{k;6dpVGG-<cpg@6!HgaiSx^{OBNs})+BwB=>9#py06FOh3c8Y{j8&xAHo zd0NCPzYU3B!XJR|9NSGw!xM-!j>q4enX%7&b8f%=(X9Wn_v?4A$bNM^pW;@(qw(-J z#6*a}H8#Y+$mOOOn2b#^DTq^=4OC1K)|JGdl+P`TK{?0ix`G%~gscd!C|ZLmqY_X} zcxCZ3K3NxDg~5jKstg*!t1)N_ug+jocpD71gx6qjPk2oR+rryqup_)J2KQ+*{q{X< z%>NU=UfTfF)O@Uq1f|mIbpY#JMlx}<^oCl7Q_Br}8EN(A%^^2V66xw})HN}h-yL98 zMWdO)R=-Unz4YZ@2f^ulD%GCy1L-PHD*rr6bs_dii=#O3WWtMd6S9jqnW(Ab$`ePA zHO)#_^_)<)(G%RL5s>A^VHii&I1Z(CCId^k;|o8EtRT9yuHW-8{r1DqNtBggH})hp zZmGnzF2legMKUG=dY(9m6P`l2H=XOZ@TrkAk;hW^c^h5c#t|^-xQk&$dlrUUKub4u znHV~OjF>A^v|uzKh-UQoFf7#o&e)mKM^kcWS#~gf9Ay;IGMk!=m1z*qi50yGnHxts ziGx5U>m%v`^vH-}0;QG-vGhLVIYYVGTr;%7bl$*xD>t3)i)-Vd4KqJBt!9&9K5Tl& zov{tlGPjKnR_vUdutRe8LjgA>N$R0?1@KO6>}@Er>MXlH1%f!4e?(iLbAZ{?gLXs4 z$y+-D$jx4e)|DYzKbaJN5SCh3xuifrl-;5LDemKMGz)-VnZodh9C~lhE~8Z&XyEej z6F)kCysL<;-3wojAMdhHF?*VPC!3{m-_c}Jj#4twH!Sn;hnW-bCp6j6I98fHiUQFH zmV0=qWu)MOdOMRG=i!pW(^e+!r16nt>#@Vvph$<QL72({IvJt*1OptNg|UNc+i)S^ z-}PaAfo^(OI1b{SI(#;Hr$`5tcaZ1O4j&I4Opn>=`!WPs!&Bes${&4K-imE}G)vPC zg4mtt`*=ex>}xswJYB7K{x0X~ssGcO1<{QD&y297T0fp8*ed0UeJGVt-8AUBP4zpN z^3PN+>|K*#9Y}XFjz^>6LFday`;TtZd1F%Ndzy47=%Lfem0#kA?2Ln+_;=h;y6d~+ zNct!ohR;6zYy~ys?~6Gni46T&`0dPz^ej!W_L@!T!Lou&Bt7|$NTMicJ7;IU9<tv& zL&bC3f+(tGvr@04X?Mbg7Md-Q^K>OSHAt7U4$=(Lh%N|Jy2v+(R@5S;R1w-r;uSKM zE~k%5`lzOl8b6l2ka7<tK`yu!1qog)MECGzn`>CA;PR63z){jJL15F6O$p1UahvSX zrb5!D5MaNDhF|KSKt||L&nIgPXH{sE%pz8#3(R&R%y*4ScD2b`HKkk6AB_V4j2TdK z#WM6!L+^9-uBm3GhM3@-3Tn8p<&H1YlAYK2l2WYVVvbX{O=))}edMgGIJ7^+z?zwR l62{&vkYAC-D$=E4;4<q*ou3V}3{*F3h3qQV%C#b0e*tE<no$4% literal 0 HcmV?d00001 diff --git a/silecs-codegen/src/xml/test/general/genplcsrcTest.py b/silecs-codegen/src/xml/test/general/genplcsrcTest.py new file mode 100644 index 0000000..12e56fa --- /dev/null +++ b/silecs-codegen/src/xml/test/general/genplcsrcTest.py @@ -0,0 +1,77 @@ +#!/usr/bin/python +# Copyright 2016 CERN and GSI +# +# 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 3 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, see <http://www.gnu.org/licenses/>. + +import difflib +import sys +import libxml2 + +from test.testBase import * +import genplcsrc +import iecommon +import iefiles + +import libxml2 + +testFolder = "test" +generationFolder = testFolder + "/generated_temp" +comparisonFolder = testFolder + "/generated_correct" +generationFoldeController = generationFolder + "/controller" +comparisonFolderController = comparisonFolder + "/controller" +def generatePLCSources(): + deployDOM = libxml2.parseFile(testFolder + "/AllTypesDU.silecsdeploy") + controllerNodes = deployDOM.xpathEval("/SILECS-Deploy/Controller") + for controllerNode in controllerNodes: + paramsFile = generationFolder + "/client/" + controllerNode.prop("host-name") + ".silecsparam" + genplcsrc.generateControllerCode(controllerNode, paramsFile, generationFoldeController ,{'errorlog': True}) + deployDOM.freeDoc() + +def CompareGeneratedFiles(hostName,fileExtension): + fileGeneratedPath = generationFoldeController + "/" + hostName + fileExtension + fileCorrectPath = comparisonFolderController + "/" + hostName + fileExtension + print "comparing: " + fileGeneratedPath + " with: " + fileCorrectPath + assertPLCCodeEqual( fileGeneratedPath, fileCorrectPath) + +def SiemensSourcesTest(): + CompareGeneratedFiles("Siemens_TiaDevice",".scl") + CompareGeneratedFiles("Siemens_TiaDevice",".sdf") + CompareGeneratedFiles("Siemens_TiaBlock",".scl") + CompareGeneratedFiles("Siemens_TiaBlock",".sdf") + CompareGeneratedFiles("Siemens_Step7Device",".scl") + CompareGeneratedFiles("Siemens_Step7Device",".sdf") + CompareGeneratedFiles("Siemens_Step7Block",".scl") + CompareGeneratedFiles("Siemens_Step7Block",".sdf") + +def BeckhoffSourcesTest(): + CompareGeneratedFiles("Beckhoff_BC9020",".exp") + CompareGeneratedFiles("Beckhoff_CX9020",".exp") + +def SchneiderSourcesTest(): + CompareGeneratedFiles("Schneider_M340",".xsy") + CompareGeneratedFiles("Schneider_PremiumQuantum",".xsy") + +def RabbitSourcesTest(): + CompareGeneratedFiles("Rabbit_BlockMode",".h") + CompareGeneratedFiles("Rabbit_DeviceMode",".h") + +def runTests(): + + generatePLCSources() + + SiemensSourcesTest() + BeckhoffSourcesTest() + SchneiderSourcesTest() + RabbitSourcesTest() + allTestsOk() diff --git a/silecs-codegen/src/xml/test/general/genplcsrcTest.pyc b/silecs-codegen/src/xml/test/general/genplcsrcTest.pyc new file mode 100644 index 0000000000000000000000000000000000000000..70de350b2f54a5db12ed8df953535958c47da92e GIT binary patch literal 3323 zcmd5;ZEqVz5T3Igza?p!6fiFmq?JH!rTD6XK&_ynv6F(-xWNu8vV@|`-8w$`UfkPt zV@t`W@PTjqG{j%w55O~X=a;no22$$t?auDZ-OWDp%<TU4_j>jB#vd<S%6?V!-{aPQ zqVe#zXh_tX%NF&l*?f+AIgxWT%+pb3U7%iJX0bxOm6=?mUU4R;Pv)stB2^-<K($_3 zq!maNQf2arkgB9AskBO7iGG74Yvh$hSSPO{!VU7OB5aViD#A_j)<oDOZ(W2fUPrfn z18egC!LMDnAR2D&nF5PS8@&O+K2?!Q9HYErqr#Eix;p2^Nupe%S9#ivBa_5Ipb~+P z-&4lj#I2`j48CTO0Y(<pE-ktsI>%I=yd3e+qRBp;Th#jXF<s;cj(B;ho#)60XazQ@ zc>v@hPo_wIiJ&=$T&4luD!_bwSs?4>U3$Uqt<oitg(!6EC49ZDKSXOk34){PNa@zk z4ebZY)t(v!@l=1r%I=TP_L|+DmQ2~r`Fb?3!*&B-MaI?@3<j|_JCPGAy@pZts*#g8 zA^agyNfIYPd|GE<41YfGPbOjT0Dcm|POE)<-7viv>-{+JR3ggB$T5SxS59DVLYcwu z$5Cd&sE(3&B(~6w0#_%l`CwtI7JfHlPZ?g>Yp+>YNVJcVu@WcyiBhfDtqTR%(-fT6 z^8>?VSOmC@7i+`(xjH8c5*ReEuMPu}MxR0gL&7kQ>_HqV`$Pq{b_ZvE6xl&EvCraU zs7H>gcG9@)gh0v8WEbDV8f+}p28=dimQgd{K1JaOvyIWzFiEo&tHWo_Zahw0rEg<a zv&&@NvNo&|6|GOK+m@Td3@<p3Te!Lp0bFI4f=4wlvc_~oo-fY`Z9&1BkQ79H`U9w) za`G~l5s%;7mb|hhM*slO@uSm6+nQOiede3NqwP9>yCYor7*b}XXF*>I7cb4x8eGA` zIJ|o=$4-z2jETp*Y=f3&9fLkXus1O((%_HT%x0d>GWrlilen^7GtFe4yQZkU5C58i zkD9y4B+_@GkPIYi3)iOQVnTlNkOdf~A>&#C^s_;JK0q;9Xr!{t%urkw8VnZCpgu1& z7^E6+UQq<nuCGEMe0=0PE%nL=(KzT0?FO0P^(B*+>~@3L9hzG(n@x6&8hw*KF6_NB zFXmFAJIsznc&;b2GT*YS;+(VLmF8+i*7}v}%|Lw$qc;MT?f_SFhU?9)a)*Ps-#^}M zKD__neu}4>jD)mvW%CzSz8m;(OlOWQ0rU{l;ynZOA3)*i)pZAv^08YSAAI>$hRH-v z4exFX-C?3ae;ocab|Nzl-wklyTlR1Xo$vl9beMr1=j6mU$C5G!yh(9&Zww?;GhLcy ztb8|M;kul<wuH%(w_?Hvv?gmBXplyi$T;jS(xFoE2sMg39GAFTkxnWWKijSs(RO$f z>3qh`9d177hHHuJ-VP2($Z7q2c%6l&40n=oB%bU+mSYy>O1YAiUUg12Ikb3wzmL-u zRt~eN?r<;LpW)*GH@l8j9X`&;+00kzF+?8r6>omJvjT00cVwy6uW!JzHFuc5DRx|j u-v(gk9u(IN+qYrtjRW<Vd8NNVvu5GSRk=mKmMdD-?5dP2#Y(kO;Ok!`tSKG< literal 0 HcmV?d00001 diff --git a/silecs-codegen/src/xml/test/general/iecommonTest.py b/silecs-codegen/src/xml/test/general/iecommonTest.py new file mode 100644 index 0000000..842f277 --- /dev/null +++ b/silecs-codegen/src/xml/test/general/iecommonTest.py @@ -0,0 +1,51 @@ +#!/usr/bin/python +# Copyright 2016 CERN and GSI +# +# 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 3 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, see <http://www.gnu.org/licenses/>. + +import sys + +from test.testBase import * +from iecommon import * + +import libxml2 + +def testhasChildren(): + document = '''<?xml version="1.0"?> + <a> + <b> + <c/> + </b> + </a>''' + root = libxml2.parseDoc(document) + assertTrue(hasChildren(root)) + assertTrue(hasChildren(root.xpathEval('/a/b')[0])) + assertFalse(hasChildren(root.xpathEval('/a/b/c')[0])) + +def testGetFirstChild(): + document = '''<?xml version="1.0"?> + <a> + <b/> + <c/> + <d/> + </a>''' + root = libxml2.parseDoc(document) + a = root.xpathEval('/a')[0] + b = getFirstChild(a) + assertEqual( root.xpathEval('/a/b')[0], b ) + +def runTests(): + testhasChildren() + testGetFirstChild() + allTestsOk() diff --git a/silecs-codegen/src/xml/test/general/iecommonTest.pyc b/silecs-codegen/src/xml/test/general/iecommonTest.pyc new file mode 100644 index 0000000000000000000000000000000000000000..ee12f7681fe5eb2fe8033b5023d75a242e31a603 GIT binary patch literal 1664 zcmc&!O>fgc5S_J?l!lZRaiIsKs^VZFH4B_gizqDzq$0VMkb2wLOJiki2k)jIQhO>F z4i&$Rzrr7YH|w-SRVs0!PIh*_c0IH2t$+Sn>R$DKd`@Zlv@yTMupc2Z`~{7O4jVn7 zk)Q+iLJJxV@sJKf%0l{v#1>^Oue2#^d!@sB>_;8!m;c7I7YV42#S8!109p%U8^f{( z`4`AQzMylWOPGROKrW<n!6yFV#?JA|fL*9y^*Y#|CUdZLD~S5{Bkpt0UO~oNr-fNN z*0s&6^3D3I{>$~P&F<RmCsuQuNQwvZ{k%R-<@{hQ=d6mQ+O&KSQprJ%nJga~TQc?M z=N4d_e1L*qy9dz6s<!%lmAWnrWv#B=K|Rs#A<Ut&+r!*swJzNv?9;Jw!<}Pge6&g4 zRmSRw0r1;pRXQn<?zoD&s$7Jbys%%O$+Rkps+7a3&~l)SwCV69FH334Q+ZO=BRf{9 z-mtmRsof}0oSf=umFXj0N?WHA)k~+XlW^!-8JX*5-vc=N<1@F6S8>8j2T$R$+$426 zVp*(+XTo!b3k@+mcM>RbxdYbZ!3;|-8ZLR(T!e&nrx`a?IS=VFATdLg@7Vm`sB$+` z?qb88G|A?y@HAn_q-scVO&QPWgzr_t;e;vfmLQI_+s$k1JRN4x-}yRGCgSA@6Dwgx z`Fp9n9NZ83kGTq<|6#W3=Wx#8|3vf}{NX0<*yFzn1z(LzxX^%~05L2NBd6^}A!NeW zA$i2v{@xhF%(I_He;fYqoaeKzC#5gsC3JuFNi5(OF*x}4!FgsqpnN=i7VnhR{^nj^ kp$7h&{*o1}y63LqqRJ*lZ!)g72hj_<q8s#r#ol7?54=BZ0{{R3 literal 0 HcmV?d00001 diff --git a/silecs-codegen/src/xml/test/generated_correct/AllTypes.cpp b/silecs-codegen/src/xml/test/generated_correct/AllTypes.cpp new file mode 100644 index 0000000..08c4d7f --- /dev/null +++ b/silecs-codegen/src/xml/test/generated_correct/AllTypes.cpp @@ -0,0 +1,738 @@ +/* + * AllTypes.cpp + * + * Generated by SILECS framework tools + */ + +#include <AllTypes/Common/AllTypes.h> +#include <fesa-core/Synchronization/NoneContext.h> +#include <fesa-core/Synchronization/MultiplexingContext.h> + +namespace AllTypes +{ + //Global objects of the SILECS class + Silecs::Service* AbstractAllTypes::pService_ = NULL; + Silecs::Cluster* AbstractAllTypes::pCluster_ = NULL; + bool AbstractAllTypes::isInitialized_ = false; + + MyROBlock_Type AllTypes::MyROBlock("MyROBlock"); + MyRWBlock_Type AllTypes::MyRWBlock("MyRWBlock"); + MyWOBlock_Type AllTypes::MyWOBlock("MyWOBlock"); + + //------------------------------------------------------------------------------------------------------------- + // Constructor & Destructor methods + + AbstractAllTypes::AbstractAllTypes(std::string blockName): blockName_(blockName) {} + AbstractAllTypes::~AbstractAllTypes() {} + + MyROBlock_Type::MyROBlock_Type(std::string name): AbstractAllTypes(name) {} + MyROBlock_Type::~MyROBlock_Type() {} + + MyRWBlock_Type::MyRWBlock_Type(std::string name): AbstractAllTypes(name) {} + MyRWBlock_Type::~MyRWBlock_Type() {} + + MyWOBlock_Type::MyWOBlock_Type(std::string name): AbstractAllTypes(name) {} + MyWOBlock_Type::~MyWOBlock_Type() {} + + //--------------------------------------------------------------------------------------------------------- + // Set-up the SILECS components for the AbstractAllTypes class (service & cluster) + + void AbstractAllTypes::setup(const ServiceLocator* serviceLocator) + { + try + { + // Instantiate the singleton of the SILECS Service + pService_ = Silecs::Service::getInstance(); + + // Enable the SILECS diagnostic with user topics if any + pService_->setArguments(serviceLocator->getUsrCmdArgs()); + + // Instantiate the SILECS Cluster object for the given Class/Version + GlobalDevice* pGlobalDevice = serviceLocator->getGlobalDevice(); + pCluster_ = pService_->getCluster( "AllTypes", pGlobalDevice->plcClassVersion.get()); + isInitialized_ = true; + + // Connect each PLC of the Cluster that is referred from the FESA instance + std::vector<Device*> pDeviceCol = serviceLocator->getDeviceCollection(); + for(std::vector<Device*>::iterator pDeviceIter=pDeviceCol.begin(); pDeviceIter!= pDeviceCol.end(); pDeviceIter++) + { + Device* pDevice = *pDeviceIter; + + // Retrieve the PLC related to the current FESA device + // (from 'plcHostName' FESA field defined on that purpose). + Silecs::PLC* pPLC = pCluster_->getPLC(pDevice->plcHostName.get(),pDevice->parameterFile.get()); + + // Update the PLC Slave registers from related FESA fields just before synchronising done at connection time + setPLCSlaveRegisters(pPLC, serviceLocator); + + // Connect the PLC if not already connected + if (!pPLC->isEnabled()) + { pPLC->connect(/*synchroMode=*/Silecs::FULL_SYNCHRO, /*connectNow=*/true); + if (pPLC->isConnected()) + { // Update FESA fields from related PLC Master registers just after synchronising done at connection time + getPLCMasterRegisters(pPLC, serviceLocator); + } + } + } + } + catch (const Silecs::SilecsException& ex) + { + throw fesa::FesaException(__FILE__, __LINE__, ex.getMessage()); + } + } + + //--------------------------------------------------------------------------------------------------------- + // Release all the SILECS resources + void AbstractAllTypes::cleanup() + { + // Attention! This method is responsible to stop all the PLC connections + // and to remove all the SILECS resources (Clusters and related components: PLCs, Devices, Registers, ..) + // Calling method must ensure that no process is currently accessing these resources before cleaning. + // + Silecs::Service::deleteInstance(); + } + + //--------------------------------------------------------------------------------------------------------- + // Synchronise PLC SLAVE/MASTER registers and related FESA fields (automatically called by the setup method @connection time) + void AbstractAllTypes::setPLCSlaveRegisters(Silecs::PLC* pPLC, const ServiceLocator* serviceLocator) + { + fesa::NoneContext noneContext; + + AllTypes::MyWOBlock.setPLCDevices(pPLC, serviceLocator, false, &noneContext); + } + + void AbstractAllTypes::getPLCMasterRegisters(Silecs::PLC* pPLC, const ServiceLocator* serviceLocator) + { + fesa::NoneContext noneContext; //MASTER acquisition fields are not consistent, can be set with none-context + + AllTypes::MyROBlock.getPLCDevices(pPLC, serviceLocator, false, &noneContext); + AllTypes::MyRWBlock.getPLCDevices(pPLC, serviceLocator, false, &noneContext); + } + + //--------------------------------------------------------------------------------------------------------- + // General methods to synchronize the FESA fields and related PLC registers of the FESA server + // with or without PLC side access (send/recv) if requested. + // get_ : [receive block from PLC +] update FESA fields with related PLC registers + // set_ : update PLC registers with related FESA fields [+ send block to PLC] + + //--------------------------------------------------------------------------------------------------------- + + void AbstractAllTypes::getAllDevices(const ServiceLocator* serviceLocator, const bool recvNow, MultiplexingContext* pContext) + { + if (recvNow) theCluster()->recv(blockName_); + + std::vector<Device*> deviceCol = serviceLocator->getDeviceCollection(); + for(std::vector<Device*>::iterator pDeviceIter=deviceCol.begin(); pDeviceIter!= deviceCol.end(); pDeviceIter++) + { getOneDevice(*pDeviceIter, false, pContext); + } + } + + void AbstractAllTypes::getPLCDevices(Silecs::PLC* pPLC, const ServiceLocator* serviceLocator, const bool recvNow, MultiplexingContext* pContext) + { + if (recvNow) pPLC->recv(blockName_); + + std::vector<Device*> deviceCol = serviceLocator->getDeviceCollection(); + for(std::vector<Device*>::iterator pDeviceIter=deviceCol.begin(); pDeviceIter!= deviceCol.end(); pDeviceIter++) + { if ((*pDeviceIter)->plcHostName.get() == pPLC->getName()) + { getOneDevice(*pDeviceIter, false, pContext); + } + } + } + + void AbstractAllTypes::getSomeDevices(std::vector<Device*> deviceCol, const bool sendNow, MultiplexingContext* pContext) + { + for(std::vector<Device*>::iterator pDeviceIter=deviceCol.begin(); pDeviceIter!= deviceCol.end(); pDeviceIter++) + { getOneDevice(*pDeviceIter, sendNow, pContext); + } + } + + void AbstractAllTypes::getOneDevice(Device* pDevice, const bool recvNow, MultiplexingContext* pContext) {}; + + //--------------------------------------------------------------------------------------------------------- + + void AbstractAllTypes::setAllDevices(const ServiceLocator* serviceLocator, bool sendNow, MultiplexingContext* pContext) + { + std::vector<Device*> deviceCol = serviceLocator->getDeviceCollection(); + for(std::vector<Device*>::iterator pDeviceIter=deviceCol.begin(); pDeviceIter!= deviceCol.end(); pDeviceIter++) + { setOneDevice(*pDeviceIter, false, pContext); + } + + if (sendNow) theCluster()->send(blockName_); + } + + void AbstractAllTypes::setPLCDevices(Silecs::PLC* pPLC, const ServiceLocator* serviceLocator, bool sendNow, MultiplexingContext* pContext) + { + std::vector<Device*> deviceCol = serviceLocator->getDeviceCollection(); + for(std::vector<Device*>::iterator pDeviceIter=deviceCol.begin(); pDeviceIter!= deviceCol.end(); pDeviceIter++) + { if ((*pDeviceIter)->plcHostName.get() == pPLC->getName()) + { setOneDevice(*pDeviceIter, false, pContext); + } + } + + if (sendNow) pPLC->send(blockName_); + } + + void AbstractAllTypes::setSomeDevices(std::vector<Device*> deviceCol, bool sendNow, MultiplexingContext* pContext) + { + for(std::vector<Device*>::iterator pDeviceIter=deviceCol.begin(); pDeviceIter!= deviceCol.end(); pDeviceIter++) + { setOneDevice(*pDeviceIter, sendNow, pContext); + } + } + + void AbstractAllTypes::setOneDevice(Device* pDevice, const bool sendNow, MultiplexingContext* pContext) {}; + + //--------------------------------------------------------------------------------------------------------- + + void MyROBlock_Type::getOneDevice(Device* pDevice, const bool recvNow, MultiplexingContext* pContext) + { + if( !isInitialized_ ) + { + throw fesa::FesaException(__FILE__, __LINE__, "SILECS-Service not initialized yet - AllTypes::setup needs to be called before any plc-interaction can be done"); + } + Silecs::PLC* pPLC = pCluster_->getPLC(pDevice->plcHostName.get(),pDevice->parameterFile.get()); + Silecs::Device* pPLCDevice = pPLC->getDevice(pDevice->plcDeviceLabel.get()); + Silecs::Register* pRegister = NULL; + + if (recvNow) pPLCDevice -> recv(blockName_); + + pDevice->RO_int8.set( pPLCDevice->getRegister("RO_int8")->getValInt8(), pContext); + pDevice->RO_uint8.set( pPLCDevice->getRegister("RO_uint8")->getValUInt8(), pContext); + pDevice->RO_int16.set( pPLCDevice->getRegister("RO_int16")->getValInt16(), pContext); + pDevice->RO_uint16.set( pPLCDevice->getRegister("RO_uint16")->getValUInt16(), pContext); + pDevice->RO_int32.set( pPLCDevice->getRegister("RO_int32")->getValInt32(), pContext); + pDevice->RO_uint32.set( pPLCDevice->getRegister("RO_uint32")->getValUInt32(), pContext); + pDevice->RO_float32.set( pPLCDevice->getRegister("RO_float32")->getValFloat32(), pContext); + pRegister = pPLCDevice->getRegister("RO_string"); + pDevice->RO_string.set(pRegister->getValString().c_str(), pContext); + + pDevice->RO_date.set( pPLCDevice->getRegister("RO_date")->getValDate(), pContext); + pDevice->RO_char.set( pPLCDevice->getRegister("RO_char")->getValInt8(), pContext); + pDevice->RO_byte.set( pPLCDevice->getRegister("RO_byte")->getValUInt8(), pContext); + pDevice->RO_word.set( pPLCDevice->getRegister("RO_word")->getValUInt16(), pContext); + pDevice->RO_dword.set( pPLCDevice->getRegister("RO_dword")->getValUInt32(), pContext); + pDevice->RO_int.set( pPLCDevice->getRegister("RO_int")->getValInt16(), pContext); + pDevice->RO_dint.set( pPLCDevice->getRegister("RO_dint")->getValInt32(), pContext); + pDevice->RO_real.set( pPLCDevice->getRegister("RO_real")->getValFloat32(), pContext); + pDevice->RO_dt.set( pPLCDevice->getRegister("RO_dt")->getValDate(), pContext); + } + void MyRWBlock_Type::getOneDevice(Device* pDevice, const bool recvNow, MultiplexingContext* pContext) + { + if( !isInitialized_ ) + { + throw fesa::FesaException(__FILE__, __LINE__, "SILECS-Service not initialized yet - AllTypes::setup needs to be called before any plc-interaction can be done"); + } + Silecs::PLC* pPLC = pCluster_->getPLC(pDevice->plcHostName.get(),pDevice->parameterFile.get()); + Silecs::Device* pPLCDevice = pPLC->getDevice(pDevice->plcDeviceLabel.get()); + Silecs::Register* pRegister = NULL; + uint32_t dim1 = 1; + uint32_t dim2 = 1; + + if (recvNow) pPLCDevice -> recv(blockName_); + + pRegister = pPLCDevice->getRegister("RW_int8"); + dim1 = pRegister->getDimension1(); + dim2 = pRegister->getDimension2(); + pDevice->RW_int8.set(pRegister->getRefInt8Array2D(dim1, dim2), dim1, dim2, pContext); + + pRegister = pPLCDevice->getRegister("RW_uint8"); + dim1 = pRegister->getDimension1(); + dim2 = pRegister->getDimension2(); + int16_t* RW_uint8 = (int16_t*)calloc(dim1*dim2, sizeof(int16_t)); + pRegister->getValUInt8Array2D(RW_uint8, dim1, dim2); //use automatic conversion for JAVA non-supported type + pDevice->RW_uint8.set(RW_uint8, dim1, dim2, pContext); + free(RW_uint8); + + pRegister = pPLCDevice->getRegister("RW_int16"); + dim1 = pRegister->getDimension1(); + dim2 = pRegister->getDimension2(); + pDevice->RW_int16.set(pRegister->getRefInt16Array2D(dim1, dim2), dim1, dim2, pContext); + + pRegister = pPLCDevice->getRegister("RW_uint16"); + dim1 = pRegister->getDimension1(); + dim2 = pRegister->getDimension2(); + int32_t* RW_uint16 = (int32_t*)calloc(dim1*dim2, sizeof(int32_t)); + pRegister->getValUInt16Array2D(RW_uint16, dim1, dim2); //use automatic conversion for JAVA non-supported type + pDevice->RW_uint16.set(RW_uint16, dim1, dim2, pContext); + free(RW_uint16); + + pRegister = pPLCDevice->getRegister("RW_int32"); + dim1 = pRegister->getDimension1(); + dim2 = pRegister->getDimension2(); + pDevice->RW_int32.set(pRegister->getRefInt32Array2D(dim1, dim2), dim1, dim2, pContext); + + pRegister = pPLCDevice->getRegister("RW_uint32"); + dim1 = pRegister->getDimension1(); + dim2 = pRegister->getDimension2(); + int64_t* RW_uint32 = (int64_t*)calloc(dim1*dim2, sizeof(int64_t)); + pRegister->getValUInt32Array2D(RW_uint32, dim1, dim2); //use automatic conversion for JAVA non-supported type + pDevice->RW_uint32.set(RW_uint32, dim1, dim2, pContext); + free(RW_uint32); + + pRegister = pPLCDevice->getRegister("RW_float32"); + dim1 = pRegister->getDimension1(); + dim2 = pRegister->getDimension2(); + pDevice->RW_float32.set(pRegister->getRefFloat32Array2D(dim1, dim2), dim1, dim2, pContext); + + pRegister = pPLCDevice->getRegister("RW_date"); + dim1 = pRegister->getDimension1(); + dim2 = pRegister->getDimension2(); + pDevice->RW_date.set(pRegister->getRefDateArray2D(dim1, dim2), dim1, dim2, pContext); + + pRegister = pPLCDevice->getRegister("RW_char"); + dim1 = pRegister->getDimension1(); + dim2 = pRegister->getDimension2(); + pDevice->RW_char.set(pRegister->getRefInt8Array2D(dim1, dim2), dim1, dim2, pContext); + + pRegister = pPLCDevice->getRegister("RW_byte"); + dim1 = pRegister->getDimension1(); + dim2 = pRegister->getDimension2(); + int16_t* RW_byte = (int16_t*)calloc(dim1*dim2, sizeof(int16_t)); + pRegister->getValUInt8Array2D(RW_byte, dim1, dim2); //use automatic conversion for JAVA non-supported type + pDevice->RW_byte.set(RW_byte, dim1, dim2, pContext); + free(RW_byte); + + pRegister = pPLCDevice->getRegister("RW_word"); + dim1 = pRegister->getDimension1(); + dim2 = pRegister->getDimension2(); + int32_t* RW_word = (int32_t*)calloc(dim1*dim2, sizeof(int32_t)); + pRegister->getValUInt16Array2D(RW_word, dim1, dim2); //use automatic conversion for JAVA non-supported type + pDevice->RW_word.set(RW_word, dim1, dim2, pContext); + free(RW_word); + + pRegister = pPLCDevice->getRegister("RW_dword"); + dim1 = pRegister->getDimension1(); + dim2 = pRegister->getDimension2(); + int64_t* RW_dword = (int64_t*)calloc(dim1*dim2, sizeof(int64_t)); + pRegister->getValUInt32Array2D(RW_dword, dim1, dim2); //use automatic conversion for JAVA non-supported type + pDevice->RW_dword.set(RW_dword, dim1, dim2, pContext); + free(RW_dword); + + pRegister = pPLCDevice->getRegister("RW_int"); + dim1 = pRegister->getDimension1(); + dim2 = pRegister->getDimension2(); + pDevice->RW_int.set(pRegister->getRefInt16Array2D(dim1, dim2), dim1, dim2, pContext); + + pRegister = pPLCDevice->getRegister("RW_dint"); + dim1 = pRegister->getDimension1(); + dim2 = pRegister->getDimension2(); + pDevice->RW_dint.set(pRegister->getRefInt32Array2D(dim1, dim2), dim1, dim2, pContext); + + pRegister = pPLCDevice->getRegister("RW_real"); + dim1 = pRegister->getDimension1(); + dim2 = pRegister->getDimension2(); + pDevice->RW_real.set(pRegister->getRefFloat32Array2D(dim1, dim2), dim1, dim2, pContext); + + pRegister = pPLCDevice->getRegister("RW_dt"); + dim1 = pRegister->getDimension1(); + dim2 = pRegister->getDimension2(); + pDevice->RW_dt.set(pRegister->getRefDateArray2D(dim1, dim2), dim1, dim2, pContext); + + } + void MyRWBlock_Type::setOneDevice(Device* pDevice, const bool sendNow, MultiplexingContext* pContext) + { + if( !isInitialized_ ) + { + throw fesa::FesaException(__FILE__, __LINE__, "SILECS-Service not initialized yet - AllTypes::setup needs to be called before any plc-interaction can be done"); + } + Silecs::PLC* pPLC = pCluster_->getPLC(pDevice->plcHostName.get(),pDevice->parameterFile.get()); + Silecs::Device* pPLCDevice = pPLC->getDevice(pDevice->plcDeviceLabel.get()); + Silecs::Register* pRegister = NULL; + uint32_t dim1 = 1; + uint32_t fesaDim1; + uint32_t dim2 = 1; + uint32_t fesaDim2; + + + pRegister = pPLCDevice->getRegister("RW_int8"); + dim1 = pRegister->getDimension1(); + dim2 = pRegister->getDimension2(); + pRegister->setValInt8Array2D(pDevice->RW_int8.get(fesaDim1, fesaDim2, pContext), dim1, dim2); + + pRegister = pPLCDevice->getRegister("RW_uint8"); + dim1 = pRegister->getDimension1(); + dim2 = pRegister->getDimension2(); + pRegister->setValUInt8Array2D( pDevice->RW_uint8.get(fesaDim1, fesaDim2, pContext), dim1, dim2); //use automatic conversion for JAVA non-supported type + + pRegister = pPLCDevice->getRegister("RW_int16"); + dim1 = pRegister->getDimension1(); + dim2 = pRegister->getDimension2(); + pRegister->setValInt16Array2D(pDevice->RW_int16.get(fesaDim1, fesaDim2, pContext), dim1, dim2); + + pRegister = pPLCDevice->getRegister("RW_uint16"); + dim1 = pRegister->getDimension1(); + dim2 = pRegister->getDimension2(); + pRegister->setValUInt16Array2D( pDevice->RW_uint16.get(fesaDim1, fesaDim2, pContext), dim1, dim2); //use automatic conversion for JAVA non-supported type + + pRegister = pPLCDevice->getRegister("RW_int32"); + dim1 = pRegister->getDimension1(); + dim2 = pRegister->getDimension2(); + pRegister->setValInt32Array2D(pDevice->RW_int32.get(fesaDim1, fesaDim2, pContext), dim1, dim2); + + pRegister = pPLCDevice->getRegister("RW_uint32"); + dim1 = pRegister->getDimension1(); + dim2 = pRegister->getDimension2(); + pRegister->setValUInt32Array2D( pDevice->RW_uint32.get(fesaDim1, fesaDim2, pContext), dim1, dim2); //use automatic conversion for JAVA non-supported type + + pRegister = pPLCDevice->getRegister("RW_float32"); + dim1 = pRegister->getDimension1(); + dim2 = pRegister->getDimension2(); + pRegister->setValFloat32Array2D(pDevice->RW_float32.get(fesaDim1, fesaDim2, pContext), dim1, dim2); + + pRegister = pPLCDevice->getRegister("RW_date"); + dim1 = pRegister->getDimension1(); + dim2 = pRegister->getDimension2(); + pRegister->setValDateArray2D(pDevice->RW_date.get(fesaDim1, fesaDim2, pContext), dim1, dim2); + + pRegister = pPLCDevice->getRegister("RW_char"); + dim1 = pRegister->getDimension1(); + dim2 = pRegister->getDimension2(); + pRegister->setValInt8Array2D(pDevice->RW_char.get(fesaDim1, fesaDim2, pContext), dim1, dim2); + + pRegister = pPLCDevice->getRegister("RW_byte"); + dim1 = pRegister->getDimension1(); + dim2 = pRegister->getDimension2(); + pRegister->setValUInt8Array2D( pDevice->RW_byte.get(fesaDim1, fesaDim2, pContext), dim1, dim2); //use automatic conversion for JAVA non-supported type + + pRegister = pPLCDevice->getRegister("RW_word"); + dim1 = pRegister->getDimension1(); + dim2 = pRegister->getDimension2(); + pRegister->setValUInt16Array2D( pDevice->RW_word.get(fesaDim1, fesaDim2, pContext), dim1, dim2); //use automatic conversion for JAVA non-supported type + + pRegister = pPLCDevice->getRegister("RW_dword"); + dim1 = pRegister->getDimension1(); + dim2 = pRegister->getDimension2(); + pRegister->setValUInt32Array2D( pDevice->RW_dword.get(fesaDim1, fesaDim2, pContext), dim1, dim2); //use automatic conversion for JAVA non-supported type + + pRegister = pPLCDevice->getRegister("RW_int"); + dim1 = pRegister->getDimension1(); + dim2 = pRegister->getDimension2(); + pRegister->setValInt16Array2D(pDevice->RW_int.get(fesaDim1, fesaDim2, pContext), dim1, dim2); + + pRegister = pPLCDevice->getRegister("RW_dint"); + dim1 = pRegister->getDimension1(); + dim2 = pRegister->getDimension2(); + pRegister->setValInt32Array2D(pDevice->RW_dint.get(fesaDim1, fesaDim2, pContext), dim1, dim2); + + pRegister = pPLCDevice->getRegister("RW_real"); + dim1 = pRegister->getDimension1(); + dim2 = pRegister->getDimension2(); + pRegister->setValFloat32Array2D(pDevice->RW_real.get(fesaDim1, fesaDim2, pContext), dim1, dim2); + + pRegister = pPLCDevice->getRegister("RW_dt"); + dim1 = pRegister->getDimension1(); + dim2 = pRegister->getDimension2(); + pRegister->setValDateArray2D(pDevice->RW_dt.get(fesaDim1, fesaDim2, pContext), dim1, dim2); + + if (sendNow) pPLCDevice->send(blockName_); + + } + void MyRWBlock_Type::setOneDevice(Device* pDevice, MyRWBlockPropertyData& data, bool sendNow, MultiplexingContext* pContext) + { + if( !isInitialized_ ) + { + throw fesa::FesaException(__FILE__, __LINE__, "SILECS-Service not initialized yet - AllTypes::setup needs to be called before any plc-interaction can be done"); + } + Silecs::PLC* pPLC = pCluster_->getPLC(pDevice->plcHostName.get(),pDevice->parameterFile.get()); + Silecs::Device* pPLCDevice = pPLC->getDevice(pDevice->plcDeviceLabel.get()); + Silecs::Register* pRegister = NULL; + uint32_t dim1 = 1; + uint32_t fesaDim1; + uint32_t dim2 = 1; + uint32_t fesaDim2; + + + pRegister = pPLCDevice->getRegister("RW_int8"); + dim1 = pRegister->getDimension1(); + dim2 = pRegister->getDimension2(); + (data.isRW_int8Available()) ? pRegister->setValInt8Array2D(data.RW_int8.get(fesaDim1, fesaDim2), dim1, dim2) : + pRegister->setValInt8Array2D(pDevice->RW_int8.get(fesaDim1, fesaDim2, pContext), dim1, dim2); + + pRegister = pPLCDevice->getRegister("RW_uint8"); + dim1 = pRegister->getDimension1(); + dim2 = pRegister->getDimension2(); + (data.isRW_uint8Available()) ? pRegister->setValUInt8Array2D(data.RW_uint8.get(fesaDim1, fesaDim2), dim1, dim2) : + pRegister->setValUInt8Array2D(pDevice->RW_uint8.get(fesaDim1, fesaDim2, pContext), dim1, dim2); + + pRegister = pPLCDevice->getRegister("RW_int16"); + dim1 = pRegister->getDimension1(); + dim2 = pRegister->getDimension2(); + (data.isRW_int16Available()) ? pRegister->setValInt16Array2D(data.RW_int16.get(fesaDim1, fesaDim2), dim1, dim2) : + pRegister->setValInt16Array2D(pDevice->RW_int16.get(fesaDim1, fesaDim2, pContext), dim1, dim2); + + pRegister = pPLCDevice->getRegister("RW_uint16"); + dim1 = pRegister->getDimension1(); + dim2 = pRegister->getDimension2(); + (data.isRW_uint16Available()) ? pRegister->setValUInt16Array2D(data.RW_uint16.get(fesaDim1, fesaDim2), dim1, dim2) : + pRegister->setValUInt16Array2D(pDevice->RW_uint16.get(fesaDim1, fesaDim2, pContext), dim1, dim2); + + pRegister = pPLCDevice->getRegister("RW_int32"); + dim1 = pRegister->getDimension1(); + dim2 = pRegister->getDimension2(); + (data.isRW_int32Available()) ? pRegister->setValInt32Array2D(data.RW_int32.get(fesaDim1, fesaDim2), dim1, dim2) : + pRegister->setValInt32Array2D(pDevice->RW_int32.get(fesaDim1, fesaDim2, pContext), dim1, dim2); + + pRegister = pPLCDevice->getRegister("RW_uint32"); + dim1 = pRegister->getDimension1(); + dim2 = pRegister->getDimension2(); + (data.isRW_uint32Available()) ? pRegister->setValUInt32Array2D(data.RW_uint32.get(fesaDim1, fesaDim2), dim1, dim2) : + pRegister->setValUInt32Array2D(pDevice->RW_uint32.get(fesaDim1, fesaDim2, pContext), dim1, dim2); + + pRegister = pPLCDevice->getRegister("RW_float32"); + dim1 = pRegister->getDimension1(); + dim2 = pRegister->getDimension2(); + (data.isRW_float32Available()) ? pRegister->setValFloat32Array2D(data.RW_float32.get(fesaDim1, fesaDim2), dim1, dim2) : + pRegister->setValFloat32Array2D(pDevice->RW_float32.get(fesaDim1, fesaDim2, pContext), dim1, dim2); + + pRegister = pPLCDevice->getRegister("RW_date"); + dim1 = pRegister->getDimension1(); + dim2 = pRegister->getDimension2(); + (data.isRW_dateAvailable()) ? pRegister->setValDateArray2D(data.RW_date.get(fesaDim1, fesaDim2), dim1, dim2) : + pRegister->setValDateArray2D(pDevice->RW_date.get(fesaDim1, fesaDim2, pContext), dim1, dim2); + + pRegister = pPLCDevice->getRegister("RW_char"); + dim1 = pRegister->getDimension1(); + dim2 = pRegister->getDimension2(); + (data.isRW_charAvailable()) ? pRegister->setValInt8Array2D(data.RW_char.get(fesaDim1, fesaDim2), dim1, dim2) : + pRegister->setValInt8Array2D(pDevice->RW_char.get(fesaDim1, fesaDim2, pContext), dim1, dim2); + + pRegister = pPLCDevice->getRegister("RW_byte"); + dim1 = pRegister->getDimension1(); + dim2 = pRegister->getDimension2(); + (data.isRW_byteAvailable()) ? pRegister->setValUInt8Array2D(data.RW_byte.get(fesaDim1, fesaDim2), dim1, dim2) : + pRegister->setValUInt8Array2D(pDevice->RW_byte.get(fesaDim1, fesaDim2, pContext), dim1, dim2); + + pRegister = pPLCDevice->getRegister("RW_word"); + dim1 = pRegister->getDimension1(); + dim2 = pRegister->getDimension2(); + (data.isRW_wordAvailable()) ? pRegister->setValUInt16Array2D(data.RW_word.get(fesaDim1, fesaDim2), dim1, dim2) : + pRegister->setValUInt16Array2D(pDevice->RW_word.get(fesaDim1, fesaDim2, pContext), dim1, dim2); + + pRegister = pPLCDevice->getRegister("RW_dword"); + dim1 = pRegister->getDimension1(); + dim2 = pRegister->getDimension2(); + (data.isRW_dwordAvailable()) ? pRegister->setValUInt32Array2D(data.RW_dword.get(fesaDim1, fesaDim2), dim1, dim2) : + pRegister->setValUInt32Array2D(pDevice->RW_dword.get(fesaDim1, fesaDim2, pContext), dim1, dim2); + + pRegister = pPLCDevice->getRegister("RW_int"); + dim1 = pRegister->getDimension1(); + dim2 = pRegister->getDimension2(); + (data.isRW_intAvailable()) ? pRegister->setValInt16Array2D(data.RW_int.get(fesaDim1, fesaDim2), dim1, dim2) : + pRegister->setValInt16Array2D(pDevice->RW_int.get(fesaDim1, fesaDim2, pContext), dim1, dim2); + + pRegister = pPLCDevice->getRegister("RW_dint"); + dim1 = pRegister->getDimension1(); + dim2 = pRegister->getDimension2(); + (data.isRW_dintAvailable()) ? pRegister->setValInt32Array2D(data.RW_dint.get(fesaDim1, fesaDim2), dim1, dim2) : + pRegister->setValInt32Array2D(pDevice->RW_dint.get(fesaDim1, fesaDim2, pContext), dim1, dim2); + + pRegister = pPLCDevice->getRegister("RW_real"); + dim1 = pRegister->getDimension1(); + dim2 = pRegister->getDimension2(); + (data.isRW_realAvailable()) ? pRegister->setValFloat32Array2D(data.RW_real.get(fesaDim1, fesaDim2), dim1, dim2) : + pRegister->setValFloat32Array2D(pDevice->RW_real.get(fesaDim1, fesaDim2, pContext), dim1, dim2); + + pRegister = pPLCDevice->getRegister("RW_dt"); + dim1 = pRegister->getDimension1(); + dim2 = pRegister->getDimension2(); + (data.isRW_dtAvailable()) ? pRegister->setValDateArray2D(data.RW_dt.get(fesaDim1, fesaDim2), dim1, dim2) : + pRegister->setValDateArray2D(pDevice->RW_dt.get(fesaDim1, fesaDim2, pContext), dim1, dim2); + + if (sendNow) pPLCDevice->send(blockName_); + + } + + void MyWOBlock_Type::setOneDevice(Device* pDevice, const bool sendNow, MultiplexingContext* pContext) + { + if( !isInitialized_ ) + { + throw fesa::FesaException(__FILE__, __LINE__, "SILECS-Service not initialized yet - AllTypes::setup needs to be called before any plc-interaction can be done"); + } + Silecs::PLC* pPLC = pCluster_->getPLC(pDevice->plcHostName.get(),pDevice->parameterFile.get()); + Silecs::Device* pPLCDevice = pPLC->getDevice(pDevice->plcDeviceLabel.get()); + Silecs::Register* pRegister = NULL; + uint32_t dim1 = 1; + uint32_t fesaDim1; + + + pRegister = pPLCDevice->getRegister("WO_int8"); + dim1 = pRegister->getDimension1(); + pRegister->setValInt8Array(pDevice->WO_int8.get(fesaDim1, pContext), dim1); + + pRegister = pPLCDevice->getRegister("WO_uint8"); + dim1 = pRegister->getDimension1(); + pRegister->setValUInt8Array(pDevice->WO_uint8.get(fesaDim1, pContext), dim1); //use automatic conversion for JAVA non-supported type + + pRegister = pPLCDevice->getRegister("WO_int16"); + dim1 = pRegister->getDimension1(); + pRegister->setValInt16Array(pDevice->WO_int16.get(fesaDim1, pContext), dim1); + + pRegister = pPLCDevice->getRegister("WO_uint16"); + dim1 = pRegister->getDimension1(); + pRegister->setValUInt16Array(pDevice->WO_uint16.get(fesaDim1, pContext), dim1); //use automatic conversion for JAVA non-supported type + + pRegister = pPLCDevice->getRegister("WO_int32"); + dim1 = pRegister->getDimension1(); + pRegister->setValInt32Array(pDevice->WO_int32.get(fesaDim1, pContext), dim1); + + pRegister = pPLCDevice->getRegister("WO_uint32"); + dim1 = pRegister->getDimension1(); + pRegister->setValUInt32Array(pDevice->WO_uint32.get(fesaDim1, pContext), dim1); //use automatic conversion for JAVA non-supported type + + pRegister = pPLCDevice->getRegister("WO_float32"); + dim1 = pRegister->getDimension1(); + pRegister->setValFloat32Array(pDevice->WO_float32.get(fesaDim1, pContext), dim1); + + { + pRegister = pPLCDevice->getRegister("WO_string"); + dim1 = pRegister->getDimension1(); + std::string stdStringArray[dim1]; + const char** cStringArray = pDevice->WO_string.get(fesaDim1, pContext); + for (unsigned int i=0; i<dim1; i++) stdStringArray[i] = (const char*)cStringArray[i]; + pRegister->setValStringArray(stdStringArray, dim1); + } + + pRegister = pPLCDevice->getRegister("WO_date"); + dim1 = pRegister->getDimension1(); + pRegister->setValDateArray(pDevice->WO_date.get(fesaDim1, pContext), dim1); + + pRegister = pPLCDevice->getRegister("WO_char"); + dim1 = pRegister->getDimension1(); + pRegister->setValInt8Array(pDevice->WO_char.get(fesaDim1, pContext), dim1); + + pRegister = pPLCDevice->getRegister("WO_byte"); + dim1 = pRegister->getDimension1(); + pRegister->setValUInt8Array(pDevice->WO_byte.get(fesaDim1, pContext), dim1); //use automatic conversion for JAVA non-supported type + + pRegister = pPLCDevice->getRegister("WO_word"); + dim1 = pRegister->getDimension1(); + pRegister->setValUInt16Array(pDevice->WO_word.get(fesaDim1, pContext), dim1); //use automatic conversion for JAVA non-supported type + + pRegister = pPLCDevice->getRegister("WO_dword"); + dim1 = pRegister->getDimension1(); + pRegister->setValUInt32Array(pDevice->WO_dword.get(fesaDim1, pContext), dim1); //use automatic conversion for JAVA non-supported type + + pRegister = pPLCDevice->getRegister("WO_int"); + dim1 = pRegister->getDimension1(); + pRegister->setValInt16Array(pDevice->WO_int.get(fesaDim1, pContext), dim1); + + pRegister = pPLCDevice->getRegister("WO_dint"); + dim1 = pRegister->getDimension1(); + pRegister->setValInt32Array(pDevice->WO_dint.get(fesaDim1, pContext), dim1); + + pRegister = pPLCDevice->getRegister("WO_real"); + dim1 = pRegister->getDimension1(); + pRegister->setValFloat32Array(pDevice->WO_real.get(fesaDim1, pContext), dim1); + + pRegister = pPLCDevice->getRegister("WO_dt"); + dim1 = pRegister->getDimension1(); + pRegister->setValDateArray(pDevice->WO_dt.get(fesaDim1, pContext), dim1); + + if (sendNow) pPLCDevice->send(blockName_); + + } + void MyWOBlock_Type::setOneDevice(Device* pDevice, MyWOBlockPropertyData& data, bool sendNow, MultiplexingContext* pContext) + { + if( !isInitialized_ ) + { + throw fesa::FesaException(__FILE__, __LINE__, "SILECS-Service not initialized yet - AllTypes::setup needs to be called before any plc-interaction can be done"); + } + Silecs::PLC* pPLC = pCluster_->getPLC(pDevice->plcHostName.get(),pDevice->parameterFile.get()); + Silecs::Device* pPLCDevice = pPLC->getDevice(pDevice->plcDeviceLabel.get()); + Silecs::Register* pRegister = NULL; + uint32_t dim1 = 1; + uint32_t fesaDim1; + + + pRegister = pPLCDevice->getRegister("WO_int8"); + dim1 = pRegister->getDimension1(); + (data.isWO_int8Available()) ? pRegister->setValInt8Array( data.WO_int8.get(fesaDim1), dim1) : + pRegister->setValInt8Array( pDevice->WO_int8.get(fesaDim1, pContext), dim1); + + pRegister = pPLCDevice->getRegister("WO_uint8"); + dim1 = pRegister->getDimension1(); + (data.isWO_uint8Available()) ? pRegister->setValUInt8Array( data.WO_uint8.get(fesaDim1), dim1) : + pRegister->setValUInt8Array( pDevice->WO_uint8.get(fesaDim1, pContext), dim1); + + pRegister = pPLCDevice->getRegister("WO_int16"); + dim1 = pRegister->getDimension1(); + (data.isWO_int16Available()) ? pRegister->setValInt16Array( data.WO_int16.get(fesaDim1), dim1) : + pRegister->setValInt16Array( pDevice->WO_int16.get(fesaDim1, pContext), dim1); + + pRegister = pPLCDevice->getRegister("WO_uint16"); + dim1 = pRegister->getDimension1(); + (data.isWO_uint16Available()) ? pRegister->setValUInt16Array( data.WO_uint16.get(fesaDim1), dim1) : + pRegister->setValUInt16Array( pDevice->WO_uint16.get(fesaDim1, pContext), dim1); + + pRegister = pPLCDevice->getRegister("WO_int32"); + dim1 = pRegister->getDimension1(); + (data.isWO_int32Available()) ? pRegister->setValInt32Array( data.WO_int32.get(fesaDim1), dim1) : + pRegister->setValInt32Array( pDevice->WO_int32.get(fesaDim1, pContext), dim1); + + pRegister = pPLCDevice->getRegister("WO_uint32"); + dim1 = pRegister->getDimension1(); + (data.isWO_uint32Available()) ? pRegister->setValUInt32Array( data.WO_uint32.get(fesaDim1), dim1) : + pRegister->setValUInt32Array( pDevice->WO_uint32.get(fesaDim1, pContext), dim1); + + pRegister = pPLCDevice->getRegister("WO_float32"); + dim1 = pRegister->getDimension1(); + (data.isWO_float32Available()) ? pRegister->setValFloat32Array( data.WO_float32.get(fesaDim1), dim1) : + pRegister->setValFloat32Array( pDevice->WO_float32.get(fesaDim1, pContext), dim1); + + { + pRegister = pPLCDevice->getRegister("WO_string"); + dim1 = pRegister->getDimension1(); + std::string stdStringArray[dim1]; + const char** cStringArray = (data.isWO_stringAvailable() ? data.WO_string.get(fesaDim1) : pDevice->WO_string.get(fesaDim1, pContext)); + for (unsigned int i=0; i<dim1; i++) stdStringArray[i] = (const char*)cStringArray[i]; + pRegister->setValStringArray(stdStringArray, dim1); + } + + pRegister = pPLCDevice->getRegister("WO_date"); + dim1 = pRegister->getDimension1(); + (data.isWO_dateAvailable()) ? pRegister->setValDateArray( data.WO_date.get(fesaDim1), dim1) : + pRegister->setValDateArray( pDevice->WO_date.get(fesaDim1, pContext), dim1); + + pRegister = pPLCDevice->getRegister("WO_char"); + dim1 = pRegister->getDimension1(); + (data.isWO_charAvailable()) ? pRegister->setValInt8Array( data.WO_char.get(fesaDim1), dim1) : + pRegister->setValInt8Array( pDevice->WO_char.get(fesaDim1, pContext), dim1); + + pRegister = pPLCDevice->getRegister("WO_byte"); + dim1 = pRegister->getDimension1(); + (data.isWO_byteAvailable()) ? pRegister->setValUInt8Array( data.WO_byte.get(fesaDim1), dim1) : + pRegister->setValUInt8Array( pDevice->WO_byte.get(fesaDim1, pContext), dim1); + + pRegister = pPLCDevice->getRegister("WO_word"); + dim1 = pRegister->getDimension1(); + (data.isWO_wordAvailable()) ? pRegister->setValUInt16Array( data.WO_word.get(fesaDim1), dim1) : + pRegister->setValUInt16Array( pDevice->WO_word.get(fesaDim1, pContext), dim1); + + pRegister = pPLCDevice->getRegister("WO_dword"); + dim1 = pRegister->getDimension1(); + (data.isWO_dwordAvailable()) ? pRegister->setValUInt32Array( data.WO_dword.get(fesaDim1), dim1) : + pRegister->setValUInt32Array( pDevice->WO_dword.get(fesaDim1, pContext), dim1); + + pRegister = pPLCDevice->getRegister("WO_int"); + dim1 = pRegister->getDimension1(); + (data.isWO_intAvailable()) ? pRegister->setValInt16Array( data.WO_int.get(fesaDim1), dim1) : + pRegister->setValInt16Array( pDevice->WO_int.get(fesaDim1, pContext), dim1); + + pRegister = pPLCDevice->getRegister("WO_dint"); + dim1 = pRegister->getDimension1(); + (data.isWO_dintAvailable()) ? pRegister->setValInt32Array( data.WO_dint.get(fesaDim1), dim1) : + pRegister->setValInt32Array( pDevice->WO_dint.get(fesaDim1, pContext), dim1); + + pRegister = pPLCDevice->getRegister("WO_real"); + dim1 = pRegister->getDimension1(); + (data.isWO_realAvailable()) ? pRegister->setValFloat32Array( data.WO_real.get(fesaDim1), dim1) : + pRegister->setValFloat32Array( pDevice->WO_real.get(fesaDim1, pContext), dim1); + + pRegister = pPLCDevice->getRegister("WO_dt"); + dim1 = pRegister->getDimension1(); + (data.isWO_dtAvailable()) ? pRegister->setValDateArray( data.WO_dt.get(fesaDim1), dim1) : + pRegister->setValDateArray( pDevice->WO_dt.get(fesaDim1, pContext), dim1); + + if (sendNow) pPLCDevice->send(blockName_); + + } +} diff --git a/silecs-codegen/src/xml/test/generated_correct/AllTypes.h b/silecs-codegen/src/xml/test/generated_correct/AllTypes.h new file mode 100644 index 0000000..3edca8f --- /dev/null +++ b/silecs-codegen/src/xml/test/generated_correct/AllTypes.h @@ -0,0 +1,146 @@ +/* + * AllTypes.h + * + * Generated by SILECS framework tools + */ + +#ifndef AllTypes_AllTypes_H_ +#define AllTypes_AllTypes_H_ + +#include <SilecsService.h> +#include <fesa-core/Synchronization/MultiplexingContext.h> +#include <AllTypes/GeneratedCode/ServiceLocator.h> + #include <AllTypes/Server/SendMyRWBlock.h> + #include <AllTypes/Server/SendMyWOBlock.h> + +namespace AllTypes +{ + + /*--------------------------------------------------------------------------------------------------------- + * SETUP + *--------------------------------------------------------------------------------------------------------- + * Setup the SILECS service by calling the setup() method from the RTDeviceClass::specificInit() + * Stop and cleanup the SILECS service by calling the cleanup() method if needed (eg.: from ~RTDeviceClass()) + * + * In order to make use of the different blocks, defined in the silecsdesign, please make use of the static, block related variables of the class, defined on the bottom of this file ! + * -------------------------------------------------------------------------------------------------------- + */ + + /*--------------------------------------------------------------------------------------------------------- + * COMMUNICATION + *--------------------------------------------------------------------------------------------------------- + * General methods to synchronize the FESA fields and related PLC registers of the FESA server with or without + * PLC side synchronization (send/recv) if requested. Each action is done for one particular block. + * In case of BLOCK_MODE configuration (see SILECS doc.), the transaction is optimal with the following + * 'AllDevices' and 'PLCDevices' methods. + * Each method can be called in the appropriate server-action (set) and rt-action (get) + * + * getAllDevices : [receive all devices of all connected PLCs +] update FESA fields with related SILECS registers + * setAllDevices : update SILECS registers with related FESA fields [+ send block to all connected PLCs] + * getPLCDevices : [receive all devices of one PLC +] update FESA fields with related SILECS registers + * setPLCDevices : update SILECS registers with related FESA fields [+ send block to the PLC] + * getSomeDevices : [receive each device of the device-collection +] update FESA fields with related SILECS registers + * setSomeDevices : update SILECS registers with related FESA fields [+ send block to each device of the device-collection] + * getOneDevice : [receive block of one PLC device +] update FESA fields with related SILECS registers + * setOneDevice : update SILECS registers with related FESA fields [+ send block to the PLC device] + * + * -------------------------------------------------------------------------------------------------------- + */ + + class AbstractAllTypes + { + public: + static inline Silecs::Service* theService() { return pService_; } + static inline Silecs::Cluster* theCluster() { return pCluster_; } + inline std::string& getBlockName() { return blockName_; } + + static void setup(const ServiceLocator* serviceLocator); + static void cleanup(); + static void setPLCSlaveRegisters(Silecs::PLC* pPLC, const ServiceLocator* serviceLocator); + static void getPLCMasterRegisters(Silecs::PLC* pPLC, const ServiceLocator* serviceLocator); + + AbstractAllTypes(std::string blockName); + virtual ~AbstractAllTypes(); + + void getAllDevices(const ServiceLocator* serviceLocator, const bool recvNow, MultiplexingContext* pContext); + void getPLCDevices(Silecs::PLC* pPLC, const ServiceLocator* serviceLocator, const bool recvNow, MultiplexingContext* pContext); + void getSomeDevices(std::vector<Device*> deviceCol, const bool recvNow, MultiplexingContext* pContext); + virtual void getOneDevice(Device* pDevice, const bool recvNow, MultiplexingContext* pContext); + + void setAllDevices(const ServiceLocator* serviceLocator, const bool sendNow, MultiplexingContext* pContext); + void setPLCDevices(Silecs::PLC* pPLC, const ServiceLocator* serviceLocator, const bool sendNow, MultiplexingContext* pContext); + void setSomeDevices(std::vector<Device*> deviceCol, const bool sendNow, MultiplexingContext* pContext); + virtual void setOneDevice(Device* pDevice, const bool sendNow, MultiplexingContext* pContext); + + protected: + + static Silecs::Service* pService_; + static Silecs::Cluster* pCluster_; + static bool isInitialized_; + + // Name of the silecs-block which is addressed + std::string blockName_; + + // not copyable object + AbstractAllTypes(const AbstractAllTypes&); + AbstractAllTypes& operator=(const AbstractAllTypes&); + }; + + // ------------------------------------------------------------------------------------------------- + #define BLOCK_RO( name ) \ + class name##_Type : public AbstractAllTypes \ + { \ + public: \ + name##_Type(std::string name); \ + ~name##_Type(); \ + void getOneDevice(Device* pDevice, const bool transmitNow, MultiplexingContext* pContext); \ + } + + + #define BLOCK_WO( name ) \ + class name##_Type : public AbstractAllTypes \ + { \ + public: \ + name##_Type(std::string name); \ + ~name##_Type(); \ + void setOneDevice(Device* pDevice, const bool transmitNow, MultiplexingContext* pContext); \ + void setOneDevice(Device* pDevice, name##PropertyData& data, const bool transmitNow, MultiplexingContext* pContext); \ + } + + #define BLOCK_RW( name ) \ + class name##_Type : public AbstractAllTypes \ + { \ + public: \ + name##_Type(std::string name); \ + ~name##_Type(); \ + void getOneDevice(Device* pDevice, const bool transmitNow, MultiplexingContext* pContext); \ + void setOneDevice(Device* pDevice, const bool transmitNow, MultiplexingContext* pContext); \ + void setOneDevice(Device* pDevice, name##PropertyData& data, const bool transmitNow, MultiplexingContext* pContext); \ + } + + BLOCK_RO( MyROBlock ); + BLOCK_RW( MyRWBlock ); + BLOCK_WO( MyWOBlock ); + + /*--------------------------------------------------------------------------------------------------------- + * INTERFACE + *--------------------------------------------------------------------------------------------------------- + * This is the public interface used from the FESA code to access the PLC service. + */ + class AllTypes + { + public: + static inline Silecs::Service* theService() { return AbstractAllTypes::theService(); } + static inline Silecs::Cluster* theCluster() { return AbstractAllTypes::theCluster(); } + static void setup(const ServiceLocator* serviceLocator) { AbstractAllTypes::setup(serviceLocator); } + static void cleanup() { AbstractAllTypes::cleanup(); } + + static MyROBlock_Type MyROBlock; + static MyRWBlock_Type MyRWBlock; + static MyWOBlock_Type MyWOBlock; + + }; + } + + #endif /* AllTypes_AllTypes_H_ */ + \ No newline at end of file diff --git a/silecs-codegen/src/xml/test/generated_correct/AllTypesFESA.design b/silecs-codegen/src/xml/test/generated_correct/AllTypesFESA.design new file mode 100644 index 0000000..68ba063 --- /dev/null +++ b/silecs-codegen/src/xml/test/generated_correct/AllTypesFESA.design @@ -0,0 +1,657 @@ +<?xml version="1.0" encoding="UTF-8"?> +<equipment-model xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../design-gsi.xsd"> + <information> + <class-name>MyClass</class-name> + <class-major-version>0</class-major-version> + <class-minor-version>1</class-minor-version> + <class-tiny-version>0</class-tiny-version> + <type>Final</type> + <state>development</state> + <description>An Empty design with GSI-specific standard properties</description> + <fesa-version>3.1.0</fesa-version> + <repository-path>undefined</repository-path> + </information> + <ownership> + <responsible name="CSCO"/> + <creator login="schwinn"/> + </ownership> + <interface> + <device-interface> + <setting> + <GSI-Init-Property multiplexed="false" name="Init" visibility="operational"> + <set-action partial-setting="true" transaction="true"> + <server-action-ref server-action-name-ref="InitSetAction"/> + </set-action> + </GSI-Init-Property> + <GSI-Reset-Property multiplexed="false" name="Reset" visibility="operational"> + <set-action partial-setting="true" transaction="true"> + <server-action-ref server-action-name-ref="ResetSetAction"/> + </set-action> + </GSI-Reset-Property> + <GSI-Setting-Property multiplexed="false" name="Setting" visibility="operational"> + <update-flag-item direction="OUT" name="updateFlags" optional="true"> + <builtin-type-scalar data-type-name-ref="NOTIFICATION_UPDATE"/> + </update-flag-item> + <cycle-name-item direction="OUT" name="cycleName" optional="true"> + <array type="char"> + <dim>32</dim> + </array> + </cycle-name-item> + <set-action partial-setting="true" transaction="true"> + <server-action-ref server-action-name-ref="SettingSetAction"/> + </set-action> + <get-action> + <server-action-ref server-action-name-ref="SettingGetAction"/> + </get-action> + </GSI-Setting-Property> + <GSI-Setting-Property name="MyRWBlock" multiplexed="false" visibility="development"><value-item name="RW_dt" direction="INOUT"><array2D type="double"><dim1>2</dim1><dim2>2</dim2></array2D><data-field-ref field-name-ref="RW_dt"/></value-item><value-item name="RW_real" direction="INOUT"><array2D type="float"><dim1>2</dim1><dim2>2</dim2></array2D><data-field-ref field-name-ref="RW_real"/></value-item><value-item name="RW_dint" direction="INOUT"><array2D type="int32_t"><dim1>2</dim1><dim2>2</dim2></array2D><data-field-ref field-name-ref="RW_dint"/></value-item><value-item name="RW_int" direction="INOUT"><array2D type="int16_t"><dim1>2</dim1><dim2>2</dim2></array2D><data-field-ref field-name-ref="RW_int"/></value-item><value-item name="RW_dword" direction="INOUT"><array2D type="int64_t"><dim1>2</dim1><dim2>2</dim2></array2D><data-field-ref field-name-ref="RW_dword"/></value-item><value-item name="RW_word" direction="INOUT"><array2D type="int32_t"><dim1>2</dim1><dim2>2</dim2></array2D><data-field-ref field-name-ref="RW_word"/></value-item><value-item name="RW_byte" direction="INOUT"><array2D type="int16_t"><dim1>2</dim1><dim2>2</dim2></array2D><data-field-ref field-name-ref="RW_byte"/></value-item><value-item name="RW_char" direction="INOUT"><array2D type="int8_t"><dim1>2</dim1><dim2>2</dim2></array2D><data-field-ref field-name-ref="RW_char"/></value-item><value-item name="RW_date" direction="INOUT"><array2D type="double"><dim1>2</dim1><dim2>2</dim2></array2D><data-field-ref field-name-ref="RW_date"/></value-item><value-item name="RW_float32" direction="INOUT"><array2D type="float"><dim1>2</dim1><dim2>2</dim2></array2D><data-field-ref field-name-ref="RW_float32"/></value-item><value-item name="RW_uint32" direction="INOUT"><array2D type="int64_t"><dim1>2</dim1><dim2>2</dim2></array2D><data-field-ref field-name-ref="RW_uint32"/></value-item><value-item name="RW_int32" direction="INOUT"><array2D type="int32_t"><dim1>2</dim1><dim2>2</dim2></array2D><data-field-ref field-name-ref="RW_int32"/></value-item><value-item name="RW_uint16" direction="INOUT"><array2D type="int32_t"><dim1>2</dim1><dim2>2</dim2></array2D><data-field-ref field-name-ref="RW_uint16"/></value-item><value-item name="RW_int16" direction="INOUT"><array2D type="int16_t"><dim1>2</dim1><dim2>2</dim2></array2D><data-field-ref field-name-ref="RW_int16"/></value-item><value-item name="RW_uint8" direction="INOUT"><array2D type="int16_t"><dim1>2</dim1><dim2>2</dim2></array2D><data-field-ref field-name-ref="RW_uint8"/></value-item><value-item name="RW_int8" direction="INOUT"><array2D type="int8_t"><dim1>2</dim1><dim2>2</dim2></array2D><data-field-ref field-name-ref="RW_int8"/></value-item><update-flag-item direction="OUT" optional="true" name="updateFlags"><builtin-type-scalar data-type-name-ref="NOTIFICATION_UPDATE"/></update-flag-item><cycle-name-item direction="OUT" optional="true" name="cycleName"><array type="char"><dim>32</dim></array></cycle-name-item><set-action><server-action-ref server-action-name-ref="SendMyRWBlock"/></set-action><get-action><server-action-ref server-action-name-ref="RecvMyRWBlock"/></get-action></GSI-Setting-Property><GSI-Setting-Property name="MyWOBlock" multiplexed="false" visibility="development"><value-item name="WO_dt" direction="INOUT"><array type="double"><dim>10</dim></array><data-field-ref field-name-ref="WO_dt"/></value-item><value-item name="WO_real" direction="INOUT"><array type="float"><dim>10</dim></array><data-field-ref field-name-ref="WO_real"/></value-item><value-item name="WO_dint" direction="INOUT"><array type="int32_t"><dim>10</dim></array><data-field-ref field-name-ref="WO_dint"/></value-item><value-item name="WO_int" direction="INOUT"><array type="int16_t"><dim>10</dim></array><data-field-ref field-name-ref="WO_int"/></value-item><value-item name="WO_dword" direction="INOUT"><array type="int64_t"><dim>10</dim></array><data-field-ref field-name-ref="WO_dword"/></value-item><value-item name="WO_word" direction="INOUT"><array type="int32_t"><dim>10</dim></array><data-field-ref field-name-ref="WO_word"/></value-item><value-item name="WO_byte" direction="INOUT"><array type="int16_t"><dim>10</dim></array><data-field-ref field-name-ref="WO_byte"/></value-item><value-item name="WO_char" direction="INOUT"><array type="int8_t"><dim>10</dim></array><data-field-ref field-name-ref="WO_char"/></value-item><value-item name="WO_date" direction="INOUT"><array type="double"><dim>10</dim></array><data-field-ref field-name-ref="WO_date"/></value-item><value-item name="WO_string" direction="INOUT"><array2D type="char"><dim1>10</dim1><dim2>64</dim2></array2D><data-field-ref field-name-ref="WO_string"/></value-item><value-item name="WO_float32" direction="INOUT"><array type="float"><dim>10</dim></array><data-field-ref field-name-ref="WO_float32"/></value-item><value-item name="WO_uint32" direction="INOUT"><array type="int64_t"><dim>10</dim></array><data-field-ref field-name-ref="WO_uint32"/></value-item><value-item name="WO_int32" direction="INOUT"><array type="int32_t"><dim>10</dim></array><data-field-ref field-name-ref="WO_int32"/></value-item><value-item name="WO_uint16" direction="INOUT"><array type="int32_t"><dim>10</dim></array><data-field-ref field-name-ref="WO_uint16"/></value-item><value-item name="WO_int16" direction="INOUT"><array type="int16_t"><dim>10</dim></array><data-field-ref field-name-ref="WO_int16"/></value-item><value-item name="WO_uint8" direction="INOUT"><array type="int16_t"><dim>10</dim></array><data-field-ref field-name-ref="WO_uint8"/></value-item><value-item name="WO_int8" direction="INOUT"><array type="int8_t"><dim>10</dim></array><data-field-ref field-name-ref="WO_int8"/></value-item><update-flag-item direction="OUT" optional="true" name="updateFlags"><builtin-type-scalar data-type-name-ref="NOTIFICATION_UPDATE"/></update-flag-item><cycle-name-item direction="OUT" optional="true" name="cycleName"><array type="char"><dim>32</dim></array></cycle-name-item><set-action><server-action-ref server-action-name-ref="SendMyWOBlock"/></set-action><get-action><server-action-ref server-action-name-ref="GetMyWOBlock"/></get-action></GSI-Setting-Property><GSI-Power-Property multiplexed="false" name="Power" visibility="operational"> + <update-flag-item direction="OUT" name="updateFlags" optional="true"> + <builtin-type-scalar data-type-name-ref="NOTIFICATION_UPDATE"/> + </update-flag-item> + <cycle-name-item direction="OUT" name="cycleName" optional="true"> + <array type="char"> + <dim>32</dim> + </array> + </cycle-name-item> + <set-action partial-setting="true" transaction="true"> + <server-action-ref server-action-name-ref="PowerSetAction"/> + </set-action> + <get-action> + <server-action-ref server-action-name-ref="PowerGetAction"/> + </get-action> + <power-item direction="INOUT" name="power"> + <custom-type-scalar data-type-name-ref="DEVICE_POWER"/> + + <data-field-ref field-name-ref="power"/> + </power-item> + </GSI-Power-Property> + </setting> + <acquisition> + <GSI-Status-Property multiplexed="false" name="Status" on-change="true" subscribable="true" visibility="operational"> + <acq-stamp-item direction="OUT" name="acqStamp"> + <scalar type="int64_t"/> + </acq-stamp-item> + <update-flag-item direction="OUT" name="updateFlags" optional="true"> + <builtin-type-scalar data-type-name-ref="NOTIFICATION_UPDATE"/> + </update-flag-item> + <cycle-name-item direction="OUT" name="cycleName" optional="true"> + <array type="char"> + <dim>32</dim> + </array> + </cycle-name-item> + <cycle-stamp-item direction="OUT" name="cycleStamp" optional="true"> + <scalar type="int64_t"/> + </cycle-stamp-item> + <get-action> + <server-action-ref server-action-name-ref="StatusGetAction"/> + </get-action> + <status-item direction="OUT" name="status"> + <custom-type-scalar data-type-name-ref="DEVICE_STATUS"/> + + <data-field-ref field-name-ref="status"/> + </status-item> + <detailed-status-item direction="OUT" name="detailedStatus"> + <array type="bool"> + <custom-constant-dim constant-name-ref="DETAILED_STATUS_SIZE"/> + </array> + <data-field-ref field-name-ref="detailedStatus"/> + </detailed-status-item> + <detailed-status-labels-item direction="OUT" name="detailedStatus_labels"> + <array2D type="char"> + <custom-constant-dim1 constant-name-ref="DETAILED_STATUS_SIZE"/> + <custom-constant-dim2 constant-name-ref="MAX_DETAILED_STATUS_LABEL_LENGTH"/> + </array2D> + <data-field-ref field-name-ref="detailedStatus_labels"/> + </detailed-status-labels-item> + <detailed-status-severity-item direction="OUT" name="detailedStatus_severity"> + <custom-type-array data-type-name-ref="DETAILED_STATUS_SEVERITY"> + <custom-constant-dim constant-name-ref="DETAILED_STATUS_SIZE"/> + </custom-type-array> + <data-field-ref field-name-ref="detailedStatus_severity"/> + </detailed-status-severity-item> + <powerState-item direction="OUT" name="powerState"> + <custom-type-scalar data-type-name-ref="DEVICE_POWER_STATE"/> + + <data-field-ref field-name-ref="powerState"/> + </powerState-item> + <control-item direction="OUT" name="control"> + <custom-type-scalar data-type-name-ref="DEVICE_CONTROL"/> + + <data-field-ref field-name-ref="control"/> + </control-item> + <interlock-item direction="OUT" name="interlock"> + <scalar type="bool"/> + <data-field-ref field-name-ref="interlock"/> + </interlock-item> + <opReady-item direction="OUT" name="opReady"> + <scalar type="bool"/> + <data-field-ref field-name-ref="opReady"/> + </opReady-item> + <modulesReady-item direction="OUT" name="modulesReady"> + <scalar type="bool"/> + <data-field-ref field-name-ref="modulesReady"/> + </modulesReady-item> + <error_collection-item direction="OUT"> + <error_codes direction="OUT" name="error_codes"> + <array type="int32_t"> + <custom-constant-dim constant-name-ref="MAX_NUMBER_OF_ERROR_MESSAGES"/> + </array> + </error_codes> + <error_messages direction="OUT" name="error_messages"> + <array2D type="char"> + <custom-constant-dim1 constant-name-ref="MAX_NUMBER_OF_ERROR_MESSAGES"/> + <custom-constant-dim2 constant-name-ref="MAX_ERROR_MESSAGE_LENGTH"/> + </array2D> + </error_messages> + <error_timestamps direction="OUT" name="error_timestamps"> + <array type="int64_t"> + <custom-constant-dim constant-name-ref="MAX_NUMBER_OF_ERROR_MESSAGES"/> + </array> + </error_timestamps> + <error_cycle_names direction="OUT" name="error_cycle_names"> + <array2D type="char"> + <custom-constant-dim1 constant-name-ref="MAX_NUMBER_OF_ERROR_MESSAGES"/> + <custom-constant-dim2 constant-name-ref="MAX_ERROR_MESSAGE_LENGTH"/> + </array2D> + </error_cycle_names> + <error_collection-field-ref field-name-ref="error_collection"/> + </error_collection-item> + </GSI-Status-Property> + <GSI-ModuleStatus-Property visibility="development" subscribable="true" name="ModuleStatus" multiplexed="false"> + <acq-stamp-item name="acqStamp" direction="OUT"> + <scalar type="int64_t"/> + </acq-stamp-item> + <update-flag-item optional="true" name="updateFlags" direction="OUT"> + <builtin-type-scalar data-type-name-ref="NOTIFICATION_UPDATE"/> + </update-flag-item> + <cycle-name-item optional="true" name="cycleName" direction="OUT"> + <array type="char"> + <dim>32</dim> + </array> + </cycle-name-item> + <cycle-stamp-item optional="true" name="cycleStamp" direction="OUT"> + <scalar type="int64_t"/> + </cycle-stamp-item> + <get-action> + <server-action-ref server-action-name-ref="ModuleStatusGetAction"/> + </get-action> + <module-status-item name="moduleStatus" direction="OUT"> + <custom-type-array data-type-name-ref="MODULE_STATUS"> + <custom-constant-dim constant-name-ref="MODULE_STATUS_SIZE"/> + + </custom-type-array> + + <data-field-ref field-name-ref="moduleStatus"/> + </module-status-item> + <module-status-labels-item name="moduleStatus_labels" direction="OUT"> + <array2D type="char"> + <custom-constant-dim1 constant-name-ref="MODULE_STATUS_SIZE"/> + <custom-constant-dim2 constant-name-ref="MAX_MODULE_STATUS_LABEL_LENGTH"/> + + </array2D> + + <data-field-ref field-name-ref="moduleStatus_labels"/> + </module-status-labels-item> + </GSI-ModuleStatus-Property> + <GSI-Acquisition-Property multiplexed="true" name="Acquisition" on-change="true" subscribable="true" visibility="operational"> + <acq-stamp-item direction="OUT" name="acqStamp"> + <scalar type="int64_t"/> + </acq-stamp-item> + <update-flag-item direction="OUT" name="updateFlags" optional="true"> + <builtin-type-scalar data-type-name-ref="NOTIFICATION_UPDATE"/> + </update-flag-item> + <cycle-name-item direction="OUT" name="cycleName" optional="true"> + <array type="char"> + <dim>32</dim> + </array> + </cycle-name-item> + <cycle-stamp-item direction="OUT" name="cycleStamp" optional="true"> + <scalar type="int64_t"/> + </cycle-stamp-item> + <get-action> + <server-action-ref server-action-name-ref="AcquisitionGetAction"/> + </get-action> + <acquisition-context-item direction="OUT"> + <acqStamp direction="OUT" name="acqStampGSI"> + <scalar type="int64_t"/> + </acqStamp> + <cycleStamp direction="OUT" name="cycleStampGSI"> + <scalar type="int64_t"/> + </cycleStamp> + <cycleName direction="OUT" name="cycleNameGSI"> + <array type="char"> + <custom-constant-dim constant-name-ref="MAX_CYCLE_NAME_LENGTH"/> + </array> + </cycleName> + <beamProcessID direction="OUT" name="beamProcessID"> + <scalar type="int32_t"/> + </beamProcessID> + <sequenceID direction="OUT" name="sequenceID"> + <scalar type="int32_t"/> + </sequenceID> + <acquisition-context-field-ref field-name-ref="acquisitionContext"/> + </acquisition-context-item> + </GSI-Acquisition-Property> + <GSI-Acquisition-Property name="MyROBlock" subscribable="true" multiplexed="false" on-change="true" visibility="development"><value-item name="RO_dt" direction="OUT"><scalar type="double"/><data-field-ref field-name-ref="RO_dt"/></value-item><value-item name="RO_real" direction="OUT"><scalar type="float"/><data-field-ref field-name-ref="RO_real"/></value-item><value-item name="RO_dint" direction="OUT"><scalar type="int32_t"/><data-field-ref field-name-ref="RO_dint"/></value-item><value-item name="RO_int" direction="OUT"><scalar type="int16_t"/><data-field-ref field-name-ref="RO_int"/></value-item><value-item name="RO_dword" direction="OUT"><scalar type="int64_t"/><data-field-ref field-name-ref="RO_dword"/></value-item><value-item name="RO_word" direction="OUT"><scalar type="int32_t"/><data-field-ref field-name-ref="RO_word"/></value-item><value-item name="RO_byte" direction="OUT"><scalar type="int16_t"/><data-field-ref field-name-ref="RO_byte"/></value-item><value-item name="RO_char" direction="OUT"><scalar type="int8_t"/><data-field-ref field-name-ref="RO_char"/></value-item><value-item name="RO_date" direction="OUT"><scalar type="double"/><data-field-ref field-name-ref="RO_date"/></value-item><value-item name="RO_string" direction="OUT"><array type="char"><dim>64</dim></array><data-field-ref field-name-ref="RO_string"/></value-item><value-item name="RO_float32" direction="OUT"><scalar type="float"/><data-field-ref field-name-ref="RO_float32"/></value-item><value-item name="RO_uint32" direction="OUT"><scalar type="int64_t"/><data-field-ref field-name-ref="RO_uint32"/></value-item><value-item name="RO_int32" direction="OUT"><scalar type="int32_t"/><data-field-ref field-name-ref="RO_int32"/></value-item><value-item name="RO_uint16" direction="OUT"><scalar type="int32_t"/><data-field-ref field-name-ref="RO_uint16"/></value-item><value-item name="RO_int16" direction="OUT"><scalar type="int16_t"/><data-field-ref field-name-ref="RO_int16"/></value-item><value-item name="RO_uint8" direction="OUT"><scalar type="int16_t"/><data-field-ref field-name-ref="RO_uint8"/></value-item><value-item name="RO_int8" direction="OUT"><scalar type="int8_t"/><data-field-ref field-name-ref="RO_int8"/></value-item><acq-stamp-item direction="OUT" name="acqStamp"><scalar type="int64_t"/></acq-stamp-item><update-flag-item direction="OUT" optional="true" name="updateFlags"><builtin-type-scalar data-type-name-ref="NOTIFICATION_UPDATE"/></update-flag-item><cycle-name-item direction="OUT" optional="true" name="cycleName"><array type="char"><dim>32</dim></array></cycle-name-item><cycle-stamp-item direction="OUT" optional="true" name="cycleStamp"><scalar type="int64_t"/></cycle-stamp-item><get-action><server-action-ref server-action-name-ref="GetMyROBlock"/></get-action><acquisition-context-item direction="OUT"><processIndex direction="OUT" name="processIndex"><scalar type="int32_t"/></processIndex><sequenceIndex direction="OUT" name="sequenceIndex"><scalar type="int32_t"/></sequenceIndex><chainIndex direction="OUT" name="chainIndex"><scalar type="int32_t"/></chainIndex><eventNumber direction="OUT" name="eventNumber"><scalar type="int32_t"/></eventNumber><timingGroupID direction="OUT" name="timingGroupID"><scalar type="int32_t"/></timingGroupID><acquisitionStamp direction="OUT" name="acquisitionStamp"><scalar type="int64_t"/></acquisitionStamp><eventStamp direction="OUT" name="eventStamp"><scalar type="int64_t"/></eventStamp><processStartStamp direction="OUT" name="processStartStamp"><scalar type="int64_t"/></processStartStamp><sequenceStartStamp direction="OUT" name="sequenceStartStamp"><scalar type="int64_t"/></sequenceStartStamp><chainStartStamp direction="OUT" name="chainStartStamp"><scalar type="int64_t"/></chainStartStamp><acquisition-context-field-ref field-name-ref="acquisitionContext"/></acquisition-context-item></GSI-Acquisition-Property><GSI-Version-Property multiplexed="false" name="Version" on-change="false" subscribable="false" visibility="operational"> + <acq-stamp-item direction="OUT" name="acqStamp"> + <scalar type="int64_t"/> + </acq-stamp-item> + <update-flag-item direction="OUT" name="updateFlags" optional="true"> + <builtin-type-scalar data-type-name-ref="NOTIFICATION_UPDATE"/> + </update-flag-item> + <cycle-name-item direction="OUT" name="cycleName" optional="true"> + <array type="char"> + <dim>32</dim> + </array> + </cycle-name-item> + <cycle-stamp-item direction="OUT" name="cycleStamp" optional="true"> + <scalar type="int64_t"/> + </cycle-stamp-item> + <get-action> + <server-action-ref server-action-name-ref="VersionGetAction"/> + </get-action> + <version-item direction="OUT" name="classVersion"> + <array type="char"> + <custom-constant-dim constant-name-ref="MAX_VERSION_NAME_LENGTH"/> + </array> + </version-item> + <version-item direction="OUT" name="deployUnitVersion"> + <array type="char"> + <custom-constant-dim constant-name-ref="MAX_VERSION_NAME_LENGTH"/> + </array> + </version-item> + <version-item direction="OUT" name="fesaVersion"> + <array type="char"> + <custom-constant-dim constant-name-ref="MAX_VERSION_NAME_LENGTH"/> + </array> + </version-item> + </GSI-Version-Property> + </acquisition> + </device-interface> + <global-interface> + <setting> + <diagnostic-property multiplexed="false" name="DiagnosticSetting" visibility="expert"> + <description>Generic property which allows to diagnose any FESA classes</description> + <mode-item direction="INOUT" name="enableDiagMode"> + <scalar type="bool"/> + </mode-item> + <host-item direction="INOUT" name="hostName"> + <array type="char"> + <dim>32</dim> + </array> + </host-item> + <port-item direction="INOUT" name="portNumber"> + <scalar type="int32_t"/> + </port-item> + <config-item direction="IN" name="requestConfig"> + <scalar type="bool"/> + </config-item> + <state-item direction="IN" name="requestState"> + <scalar type="bool"/> + </state-item> + <fwk-topic-item direction="INOUT" name="fwkTopic"> + <builtin-type-scalar data-type-name-ref="DIAG_FWK_TOPIC"/> + </fwk-topic-item> + <custom-topic-item direction="INOUT" name="customTopic"> + <custom-type-scalar data-type-name-ref="DIAG_TOPIC"/> + </custom-topic-item> + <device-trace-item direction="INOUT" name="traceDevices"> + <array type="char"> + <dim>320</dim> + </array> + </device-trace-item> + <bypass-action-item direction="INOUT" name="bypassActions"> + <array type="char"> + <dim>320</dim> + </array> + </bypass-action-item> + </diagnostic-property> + </setting> + <acquisition> + <GSI-DeviceDescription-Property multiplexed="false" name="DeviceDescription" on-change="false" subscribable="false" visibility="operational"> + <timing-info-item direction="OUT" name="deviceNameTimingReceiver"> + <array type="char"> + <variable-dim/> + </array> + <data-field-ref field-name-ref="deviceNameTimingReceiver"/> + </timing-info-item> + <property-info-item direction="OUT" name="propertyNames"> + <array2D type="char"> + <variable-dim1/> + <variable-dim2/> + </array2D> + </property-info-item> + <device-info-item direction="OUT" name="deviceNames"> + <array2D type="char"> + <variable-dim1/> + <variable-dim2/> + </array2D> + </device-info-item> + <global-device-info-item direction="OUT" name="globalDeviceName"> + <array type="char"> + <variable-dim/> + </array> + </global-device-info-item> + <host-info-item direction="OUT" name="host"> + <array type="char"> + <variable-dim/> + </array> + </host-info-item> + </GSI-DeviceDescription-Property> + </acquisition> + </global-interface> + </interface> + <builtin-types> + <notification-update-enum name="NOTIFICATION_UPDATE"> + <IMMEDIATE access="RO" symbol="IMMEDIATE" value="1"/> + <SET access="RO" symbol="SET" value="2"/> + </notification-update-enum> + <diag-fwk-topic name="DIAG_FWK_TOPIC"> + <b0 name="SRV_GET_ACTION_PROFIING"/> + <b1 name="SRV_SET_ACTION_PROFILING"/> + <b2 name="RT_ACTION_PROFILING"/> + <b3 name="EVENT_PROFILING"/> + <b4 name="NOTIFICATION_PROFILING"/> + <b5 name="SRV_GET_ACTION_TRACKING"/> + <b6 name="SRV_SET_ACTION_TRACKING"/> + <b7 name="RT_ACTION_TRACKING"/> + <b8 name="EVENT_TRACKING"/> + <b9 name="NOTIFICATION_TRACKING"/> + <b10 name="PERSISTENCY_TRACKING"/> + <b11 name="TRANSACTION_TRACKING"/> + <b12 name="SUBSCRIPTION_TRACKING"/> + <b13 name="SIGNAL_HANDLER_TRACKING"/> + <b14 name="LOCAL_CONNECTION_TRACKING"/> + </diag-fwk-topic> + <fault-severity name="FaultSeverity"> + <description>Enumeration listing the available fault severities used by the fault fields</description> + <INFO access="RO" meaning="NONE" value="0" symbol="INFO"/> + <WARNING access="RO" meaning="WARNING" value="1" symbol="WARNING"/> + <ERROR access="RO" meaning="ERROR" value="2" symbol="ERROR"/> + <CRITICAL access="RO" meaning="ERROR" value="3" symbol="CRITICAL"/> + </fault-severity> + + </builtin-types> + <custom-types> + <diag-custom-topic name="DIAG_TOPIC"> + </diag-custom-topic> + <enum name="DEVICE_STATUS"> + <!--Possible (mutually exclusive) values to describe the device status--> + + <item access="RW" meaning="NONE" symbol="UNKNOWN" value="0"/> + <!--The device status is unknown--> + + <item access="RW" meaning="NONE" symbol="OK" value="1"/> + <!--The device is in fully operational state--> + + <item access="RW" meaning="NONE" symbol="WARNING" value="2"/> + <!--The device is not fully operational; A device in WARNING state can still be used operationally, --> + <!--but clients must be informed of a problem that might become worse. Details are explained in the errorMsg field.--> + + <item access="RW" meaning="NONE" symbol="ERROR" value="3"/> + <!--The device is in a fault state. Details are explained in the errorMsg field--> + </enum> + <enum name="DEVICE_POWER_STATE"> + <!--Possible (mutually exclusive) values to describe the power-state of the device.--> + + <item access="RW" meaning="NONE" symbol="UNKNOWN" value="0"/> + <!--The device mode is unknown--> + + <item access="RW" meaning="ON" symbol="ON" value="1"/> + <!--The device is in fully operational state--> + + <item access="RW" meaning="NONE" symbol="OFF" value="2"/> + <!--The device is turned off--> + + <item access="RW" meaning="NONE" symbol="STANDBY" value="3"/> + <!--The device is in a stand-by mode. This mode is a sort of “parking mode†in which the device can --> + <!--stay for hours or even days. It is defined by the following characteristics:--> + <!--It is safe, it does not wear out, it consumes little energy.--> + <!--Furthermore, it takes a short time to go from STANDBY to ON mode--> + + <item access="RW" meaning="NONE" symbol="POWER_DOWN" value="4"/> + <!--The device is shutting down. Note that some properties may not be accessible during this time.--> + <!--After shutdown the device will be in the mode OFF--> + + <item access="RW" meaning="NONE" symbol="POWER_UP" value="5"/> + <!--The device is starting up. Note that some properties may not be accessible during this time.--> + <!--After (re-)starting the device probably will be in the mode ON--> + + </enum> + <enum name="DEVICE_POWER"> + <!--An enumeration Type used to control the operational mode of the device.--> + <!--Its values are a subset of those in the DEVICE_POWER_STATE type--> + <item access="RW" meaning="ON" symbol="ON" value="1"/> + <!--The device is in fully operational state--> + + <item access="RW" meaning="OFF" symbol="OFF" value="2"/> + <!--The device is turned off--> + </enum> + <enum name="DEVICE_CONTROL"> + <!--Possible values to describe the control mode of a device--> + <!--Currently two control modes (LOCAL, REMOTE) are defined--> + + <item access="RW" meaning="NONE" symbol="REMOTE" value="0"/> + <!--The device can be controlled normally through the control system--> + + <item access="RW" meaning="NONE" symbol="LOCAL" value="1"/> + <!--The device can be controlled locally. But it can be accessed in read-only mode via the control system--> + </enum> + <enum name="TOL_CHECK_MODE"> + <!--This constant defines possible modes to check whether a control value is inside the tolerance values.--> + <!--Used to give information on how the tolerance fields are used to calculate the xxx_status information.--> + + <item access="RO" symbol="ABS" value="0"/> + <!--Use the absolute tolerance _tolAbs--> + + <item access="RO" symbol="REL" value="1"/> + <!--Use the relative tolerance _tolRel--> + </enum> + <bit-enum-32bits name="AQN_STATUS"> + <!--Possible values to describe the acquisition status of a field (in the _status suffix)--> + <!--If this suffix is missing, it means that no additional status information is provided for the corresponding field--> + <!--If all bits are 0, this means that the corresponding field is OK.--> + <!--Only the lower 16 bits are standardized, the upper 16 bits can be defined by the equipment specialist.--> + <!--The difference between the Status property and the _status suffix is described in the section on the Status property.--> + <b0 name="NOT_OK"/> + <!--Some problem occurred that is not represented by the other bits. This property is called--> + <!-- NOT_OK so that it is not mixed up with ERROR or WARNING in the Status property--> + <b1 name="BAD_QUALITY"/> + <!--The value was acquired with a degraded quality. This is typically used for measurements.--> + <b2 name="DIFFERENT_FROM_SETTING"/> + <!--Different from the requested control value (for discrete values)--><!--or out of tolerance (for continuous values).--> + <b3 name="OUT_OF_RANGE"/> + <!--The value is out of the normal range (e.g. a temperature is too high or too low).--> + <b4 name="BUSY"/> + <!--The property value is changing in response to receiving a new control value (e.g. moving to a--> + <!--new position, charging a capacitor, ...). If the value change does not reach the requested new--> + <!--value within the maximum timeout, the BUSY bit should remain=1 and the TIMEOUT bit must be turned on.--> + <b5 name="TIMEOUT"/> + <!--A timeout occurred, because the property did not reach the reqested new control value within the--> + <!--maximum allowable time. A timeout normally indicates a problem to be addressed by the--> + <!--equipment specialist. This is typically used for slow changing control values that are BUSY while they change.--> + <b6 name="bit6_is_reserved_for_later_usage"/> + <b7 name="bit7_is_reserved_for_later_usage"/> + <b8 name="bit8_is_reserved_for_later_usage"/> + <b9 name="bit9_is_reserved_for_later_usage"/> + <b10 name="bit10_is_reserved_for_later_usage"/> + <b11 name="bit11_is_reserved_for_later_usage"/> + <b12 name="bit12_is_reserved_for_later_usage"/> + <b13 name="bit13_is_reserved_for_later_usage"/> + <b14 name="bit14_is_reserved_for_later_usage"/> + <b15 name="bit15_is_reserved_for_later_usage"/> + <!--bit 6 to 15 are reserved ... dont use them!--> + + <b16 name="bit_16_and_higher_can_be_used_by_the_class_developer"/> + <!--into bit 16..32 you can put in anything you want--> + </bit-enum-32bits> + + <struct name="GSI_ERROR"> + <!--This struct-item describes the structure of an GSI-error--> + <struct-item name="error_string"> + <!--This string holds the error-message--> + <array type="char"> + <custom-constant-dim constant-name-ref="MAX_ERROR_MESSAGE_LENGTH"/> + </array> + </struct-item> + <struct-item name="error_code"> + <!--The error code according to the defined error-message--> + <scalar type="int32_t"/> + </struct-item> + <!--The timestamp when the error occured--> + <struct-item name="error_timestamp"> + <scalar type="int64_t"/> + </struct-item> + <!--The cycle for which the error occured--> + <struct-item name="error_cycle_name"> + <array type="char"> + <custom-constant-dim constant-name-ref="MAX_CYCLE_NAME_LENGTH"/> + </array> + </struct-item> + </struct> + <struct name="GSI_ACQ_CONTEXT"> + <!--This struct-item describes all AcquisitionContext items which are relevant for GSI--> + <struct-item name="acqStamp"> + <!--The acquisition stamp is used to indicate when a measurement was done --> + <scalar type="int64_t"/> + </struct-item> + <struct-item name="cycleStamp"> + <!--The cycle stamp is used to indicate when a specific cycle has started--> + <scalar type="int64_t"/> + </struct-item> + <struct-item name="cycleName"> + <!--The cycle name indicates the cycle which started at time of the cycleStamp --> + <array type="char"> + <custom-constant-dim constant-name-ref="MAX_CYCLE_NAME_LENGTH"/> + </array> + </struct-item> + <struct-item name="beamProcessID"> + <scalar type="int32_t"/> + </struct-item> + <struct-item name="sequenceID"> + <scalar type="int32_t"/> + </struct-item> + </struct> + <constant name="MAX_ERROR_MESSAGE_LENGTH" type="uint32_t" value="256"/> + <constant name="MAX_NUMBER_OF_ERROR_MESSAGES" type="uint32_t" value="16"/> + <constant name="MAX_CYCLE_NAME_LENGTH" type="uint32_t" value="256"/> + <constant name="MAX_VERSION_NAME_LENGTH" type="uint32_t" value="256"/> + <constant name="MAX_DETAILED_STATUS_LABEL_LENGTH" type="uint32_t" value="30"/> + <constant name="DETAILED_STATUS_SIZE" type="uint32_t" value="2"/> + <enum name="DETAILED_STATUS_SEVERITY"> + <item access="RO" symbol="INFO" value="0"/> + <item access="RO" symbol="WARNING_ON_FALSE" value="1"/> + <item access="RO" symbol="ERROR_ON_FALSE" value="2"/> + </enum> + <enum name="MODULE_STATUS"> + <!-- Mutually exclusive values to describe the status of a hardware / software module--> + <item access="RO" value="0" symbol="UNKNOWN"/> + <!--The status of the module is not known--> + <item access="RO" value="1" symbol="OK"/> + <!--The module is in fully operational state--> + <item access="RO" value="2" symbol="WARNING"/> + <!--The module is not fully operational; A module in WARNING state may still be used operationally, --> + <!--but clients must be informed of a problem that might become worse. --> + <item access="RO" value="3" symbol="ERROR"/> + <!--The module is in a fault state. The related device is not operational.--> + <item access="RO" value="4" symbol="NOT_AVAILABLE"/> + <!--The module is missing. The related device is not operational.--> + </enum> + <constant name="MAX_MODULE_STATUS_LABEL_LENGTH" type="uint32_t" value="30"/> + <constant name="MODULE_STATUS_SIZE" type="uint32_t" value="2"/> + </custom-types> + <data> + <device-data> + <configuration> + <field name="parameterFile"><description>ParameterFile of the PLC (*.silecsparam)</description><array type="char"><dim>512</dim></array><default>../../../generated/client/MyControllerName.silecsparam</default></field><field name="plcDeviceLabel"><description>Name of the related SILECS instance within the PLC mapping</description><array type="char"><dim>128</dim></array></field><field name="plcHostName"><description>Hostname of the PLC that contains the related SILECS class device</description><array type="char"><dim>128</dim></array></field><GSI-detailed-status-labels-field name="detailedStatus_labels"> + <array2D type="char"> + <custom-constant-dim1 constant-name-ref="DETAILED_STATUS_SIZE"/> + <custom-constant-dim2 constant-name-ref="MAX_DETAILED_STATUS_LABEL_LENGTH"/> + </array2D> + <default>{myStatusLabel1,myStatusLabel2}</default> + </GSI-detailed-status-labels-field> + <GSI-detailed-status-severity-field name="detailedStatus_severity"> + <custom-type-array data-type-name-ref="DETAILED_STATUS_SEVERITY"> + <custom-constant-dim constant-name-ref="DETAILED_STATUS_SIZE"/> + </custom-type-array> + <default>{INFO,INFO}</default> + </GSI-detailed-status-severity-field> + <GSI-module-status-labels-field name="moduleStatus_labels"> + <array2D type="char"> + <custom-constant-dim1 constant-name-ref="MODULE_STATUS_SIZE"/> + + <custom-constant-dim2 constant-name-ref="MAX_MODULE_STATUS_LABEL_LENGTH"/> + </array2D> + <default>{myModule1,myModule2}</default> + </GSI-module-status-labels-field> + </configuration> + <setting> + <field name="WO_dt" shared="true" multiplexed="false" persistent="true"><array type="double"><dim>10</dim></array></field><field name="WO_real" shared="true" multiplexed="false" persistent="true"><array type="float"><dim>10</dim></array></field><field name="WO_dint" shared="true" multiplexed="false" persistent="true"><array type="int32_t"><dim>10</dim></array></field><field name="WO_int" shared="true" multiplexed="false" persistent="true"><array type="int16_t"><dim>10</dim></array></field><field name="WO_dword" shared="true" multiplexed="false" persistent="true"><array type="int64_t"><dim>10</dim></array></field><field name="WO_word" shared="true" multiplexed="false" persistent="true"><array type="int32_t"><dim>10</dim></array></field><field name="WO_byte" shared="true" multiplexed="false" persistent="true"><array type="int16_t"><dim>10</dim></array></field><field name="WO_char" shared="true" multiplexed="false" persistent="true"><array type="int8_t"><dim>10</dim></array></field><field name="WO_date" shared="true" multiplexed="false" persistent="true"><array type="double"><dim>10</dim></array></field><field name="WO_string" shared="true" multiplexed="false" persistent="true"><array2D type="char"><dim1>10</dim1><dim2>64</dim2></array2D></field><field name="WO_float32" shared="true" multiplexed="false" persistent="true"><array type="float"><dim>10</dim></array></field><field name="WO_uint32" shared="true" multiplexed="false" persistent="true"><array type="int64_t"><dim>10</dim></array></field><field name="WO_int32" shared="true" multiplexed="false" persistent="true"><array type="int32_t"><dim>10</dim></array></field><field name="WO_uint16" shared="true" multiplexed="false" persistent="true"><array type="int32_t"><dim>10</dim></array></field><field name="WO_int16" shared="true" multiplexed="false" persistent="true"><array type="int16_t"><dim>10</dim></array></field><field name="WO_uint8" shared="true" multiplexed="false" persistent="true"><array type="int16_t"><dim>10</dim></array></field><field name="WO_int8" shared="true" multiplexed="false" persistent="true"><array type="int8_t"><dim>10</dim></array></field><field name="RW_dt" multiplexed="false" persistent="true"><array2D type="double"><dim1>2</dim1><dim2>2</dim2></array2D></field><field name="RW_real" multiplexed="false" persistent="true"><array2D type="float"><dim1>2</dim1><dim2>2</dim2></array2D></field><field name="RW_dint" multiplexed="false" persistent="true"><array2D type="int32_t"><dim1>2</dim1><dim2>2</dim2></array2D></field><field name="RW_int" multiplexed="false" persistent="true"><array2D type="int16_t"><dim1>2</dim1><dim2>2</dim2></array2D></field><field name="RW_dword" multiplexed="false" persistent="true"><array2D type="int64_t"><dim1>2</dim1><dim2>2</dim2></array2D></field><field name="RW_word" multiplexed="false" persistent="true"><array2D type="int32_t"><dim1>2</dim1><dim2>2</dim2></array2D></field><field name="RW_byte" multiplexed="false" persistent="true"><array2D type="int16_t"><dim1>2</dim1><dim2>2</dim2></array2D></field><field name="RW_char" multiplexed="false" persistent="true"><array2D type="int8_t"><dim1>2</dim1><dim2>2</dim2></array2D></field><field name="RW_date" multiplexed="false" persistent="true"><array2D type="double"><dim1>2</dim1><dim2>2</dim2></array2D></field><field name="RW_float32" multiplexed="false" persistent="true"><array2D type="float"><dim1>2</dim1><dim2>2</dim2></array2D></field><field name="RW_uint32" multiplexed="false" persistent="true"><array2D type="int64_t"><dim1>2</dim1><dim2>2</dim2></array2D></field><field name="RW_int32" multiplexed="false" persistent="true"><array2D type="int32_t"><dim1>2</dim1><dim2>2</dim2></array2D></field><field name="RW_uint16" multiplexed="false" persistent="true"><array2D type="int32_t"><dim1>2</dim1><dim2>2</dim2></array2D></field><field name="RW_int16" multiplexed="false" persistent="true"><array2D type="int16_t"><dim1>2</dim1><dim2>2</dim2></array2D></field><field name="RW_uint8" multiplexed="false" persistent="true"><array2D type="int16_t"><dim1>2</dim1><dim2>2</dim2></array2D></field><field name="RW_int8" multiplexed="false" persistent="true"><array2D type="int8_t"><dim1>2</dim1><dim2>2</dim2></array2D></field><GSI-power-field multiplexed="false" name="power" persistent="false"> + <custom-type-scalar data-type-name-ref="DEVICE_POWER"/> + </GSI-power-field> + </setting> + <acquisition> + <field name="RO_dt" multiplexed="false" persistent="false"><scalar type="double"/></field><field name="RO_real" multiplexed="false" persistent="false"><scalar type="float"/></field><field name="RO_dint" multiplexed="false" persistent="false"><scalar type="int32_t"/></field><field name="RO_int" multiplexed="false" persistent="false"><scalar type="int16_t"/></field><field name="RO_dword" multiplexed="false" persistent="false"><scalar type="int64_t"/></field><field name="RO_word" multiplexed="false" persistent="false"><scalar type="int32_t"/></field><field name="RO_byte" multiplexed="false" persistent="false"><scalar type="int16_t"/></field><field name="RO_char" multiplexed="false" persistent="false"><scalar type="int8_t"/></field><field name="RO_date" multiplexed="false" persistent="false"><scalar type="double"/></field><field name="RO_string" multiplexed="false" persistent="false"><array type="char"><dim>64</dim></array></field><field name="RO_float32" multiplexed="false" persistent="false"><scalar type="float"/></field><field name="RO_uint32" multiplexed="false" persistent="false"><scalar type="int64_t"/></field><field name="RO_int32" multiplexed="false" persistent="false"><scalar type="int32_t"/></field><field name="RO_uint16" multiplexed="false" persistent="false"><scalar type="int32_t"/></field><field name="RO_int16" multiplexed="false" persistent="false"><scalar type="int16_t"/></field><field name="RO_uint8" multiplexed="false" persistent="false"><scalar type="int16_t"/></field><field name="RO_int8" multiplexed="false" persistent="false"><scalar type="int8_t"/></field><GSI-control-field multiplexed="false" name="control"> + <custom-type-scalar data-type-name-ref="DEVICE_CONTROL"/> + </GSI-control-field> + <GSI-powerState-field multiplexed="false" name="powerState"> + <custom-type-scalar data-type-name-ref="DEVICE_POWER_STATE"/> + </GSI-powerState-field> + <GSI-status-field multiplexed="false" name="status"> + <custom-type-scalar data-type-name-ref="DEVICE_STATUS"/> + </GSI-status-field> + <GSI-interlock-field multiplexed="false" name="interlock"> + <scalar type="bool"/> + </GSI-interlock-field> + <GSI-opReady-field multiplexed="false" name="opReady"> + <scalar type="bool"/> + </GSI-opReady-field> + <GSI-modulesReady-field name="modulesReady" multiplexed="false"> + <scalar type="bool"/> + </GSI-modulesReady-field> + <GSI-detailed-status-field multiplexed="false" name="detailedStatus"> + <array type="bool"> + <custom-constant-dim constant-name-ref="DETAILED_STATUS_SIZE"/> + </array> + </GSI-detailed-status-field> + <GSI-module-status-field name="moduleStatus" multiplexed="false"> + <custom-type-array data-type-name-ref="MODULE_STATUS"> + <custom-constant-dim constant-name-ref="MODULE_STATUS_SIZE"/> + + </custom-type-array> + </GSI-module-status-field> + <GSI-acquisition-context-field multiplexed="true" name="acquisitionContext"> + <custom-type-scalar data-type-name-ref="GSI_ACQ_CONTEXT"/> + </GSI-acquisition-context-field> + <GSI-error_collection-field multiplexed="false" name="error_collection"> + <custom-type-array data-type-name-ref="GSI_ERROR"> + <custom-constant-dim constant-name-ref="MAX_NUMBER_OF_ERROR_MESSAGES"/> + </custom-type-array> + </GSI-error_collection-field> + </acquisition> + </device-data> + <global-data> + <configuration> + <!-- The name of the timing receiver --> + <field name="plcClassVersion"><description>Version of the SILECS class that needs to be deployed in the controller</description><array type="char"><dim>5</dim></array><default>0.1.0</default></field><GSI-timing-receiver-name-field name="deviceNameTimingReceiver"> + <array type="char"> + <!-- The number of the timing receiver --> + <variable-dim/> + </array> + </GSI-timing-receiver-name-field> + </configuration> + </global-data> + </data> + <actions> + <set-server-action implementation="default" name="InitSetAction"/> + <set-server-action implementation="default" name="ResetSetAction"/> + <set-server-action implementation="default" name="SettingSetAction"/> + <set-server-action implementation="default" name="PowerSetAction"/> + <get-server-action implementation="default" name="PowerGetAction"/> + <get-server-action implementation="default" name="SettingGetAction"/> + <get-server-action implementation="default" name="AcquisitionGetAction"/> + <get-server-action implementation="default" name="StatusGetAction"/> + <get-server-action implementation="default" name="VersionGetAction"/><get-server-action implementation="default" name="ModuleStatusGetAction"/> + <get-server-action name="GetMyROBlock" implementation="default"/><rt-action name="RecvMyROBlock"><notified-property property-name-ref="MyROBlock" automatic="true"/></rt-action><set-server-action name="SendMyRWBlock" implementation="custom"/><get-server-action name="RecvMyRWBlock" implementation="custom"/><set-server-action name="SendMyWOBlock" implementation="custom"/><get-server-action name="GetMyWOBlock" implementation="default"/></actions> + +<events><sources><timing-event-source name="Timing"/><timer-event-source name="Timer"/></sources><logical-events><logical-event name="RecvMyROBlockEvent" use="required" type="timer"/></logical-events></events><scheduling-units><scheduling-unit name="RecvMyROBlockUnit"><rt-action-ref rt-action-name-ref="RecvMyROBlock"/><logical-event-ref logical-event-name-ref="RecvMyROBlockEvent"/></scheduling-unit></scheduling-units></equipment-model> diff --git a/silecs-codegen/src/xml/test/generated_correct/client/Beckhoff_BC9020.silecsparam b/silecs-codegen/src/xml/test/generated_correct/client/Beckhoff_BC9020.silecsparam new file mode 100644 index 0000000..79e434e --- /dev/null +++ b/silecs-codegen/src/xml/test/generated_correct/client/Beckhoff_BC9020.silecsparam @@ -0,0 +1,80 @@ +<?xml version="1.0"?> +<SILECS-Param silecs-version="DEV"> + <Mapping-Info> + <Owner user-login="schwinn"/> + <Generation date="2016-07-14 16:03:39.957252"/> + <Deployment checksum="2843029646"/> + </Mapping-Info> + <SILECS-Mapping plc-name="Beckhoff_BC9020" plc-brand="BECKHOFF" plc-system="TWINCat" plc-model="BC9020" protocol="BLOCK_MODE" address="32768" domain="NotUsed" used-mem="TODO"> + <SILECS-Class name="SilecsHeader" version="1.0.0" address="32768" used-mem="MW16384..MW16407 / 24 words"> + <Block name="hdrBlk" mode="READ-ONLY" size="14" address="32768" mem-size="48"> + <Register name="_version" format="string" string-len="16" array-dim1="1" array-dim2="1" size="1" address="0" mem-size="17" synchro="MASTER"/> + <Register name="_checksum" format="uint32" array-dim1="1" array-dim2="1" size="4" address="18" mem-size="4" synchro="MASTER"/> + <Register name="_user" format="string" string-len="16" array-dim1="1" array-dim2="1" size="1" address="22" mem-size="17" synchro="MASTER"/> + <Register name="_date" format="dt" array-dim1="1" array-dim2="1" size="8" address="40" mem-size="8" synchro="MASTER"/> + </Block> + <Instance label="SilecsHeader" address="0"/> + </SILECS-Class> + <SILECS-Class name="AllTypes" version="0.1.0" address="32816" used-mem="MW16408..MW18167 / 1760 words"> + <Block name="MyROBlock" mode="READ-ONLY" size="53" address="32816" mem-size="122"> + <Register name="RO_int8" format="int8" array-dim1="1" array-dim2="1" size="1" address="0" mem-size="1" synchro="MASTER"/> + <Register name="RO_uint8" format="uint8" array-dim1="1" array-dim2="1" size="1" address="2" mem-size="1" synchro="MASTER"/> + <Register name="RO_int16" format="int16" array-dim1="1" array-dim2="1" size="2" address="4" mem-size="2" synchro="MASTER"/> + <Register name="RO_uint16" format="uint16" array-dim1="1" array-dim2="1" size="2" address="6" mem-size="2" synchro="MASTER"/> + <Register name="RO_int32" format="int32" array-dim1="1" array-dim2="1" size="4" address="8" mem-size="4" synchro="MASTER"/> + <Register name="RO_uint32" format="uint32" array-dim1="1" array-dim2="1" size="4" address="12" mem-size="4" synchro="MASTER"/> + <Register name="RO_float32" format="float32" array-dim1="1" array-dim2="1" size="4" address="16" mem-size="4" synchro="MASTER"/> + <Register name="RO_string" format="string" string-len="64" array-dim1="1" array-dim2="1" size="1" address="20" mem-size="65" synchro="MASTER"/> + <Register name="RO_date" format="date" array-dim1="1" array-dim2="1" size="8" address="86" mem-size="8" synchro="MASTER"/> + <Register name="RO_char" format="char" array-dim1="1" array-dim2="1" size="1" address="94" mem-size="1" synchro="MASTER"/> + <Register name="RO_byte" format="byte" array-dim1="1" array-dim2="1" size="1" address="96" mem-size="1" synchro="MASTER"/> + <Register name="RO_word" format="word" array-dim1="1" array-dim2="1" size="2" address="98" mem-size="2" synchro="MASTER"/> + <Register name="RO_dword" format="dword" array-dim1="1" array-dim2="1" size="4" address="100" mem-size="4" synchro="MASTER"/> + <Register name="RO_int" format="int" array-dim1="1" array-dim2="1" size="2" address="104" mem-size="2" synchro="MASTER"/> + <Register name="RO_dint" format="dint" array-dim1="1" array-dim2="1" size="4" address="106" mem-size="4" synchro="MASTER"/> + <Register name="RO_real" format="real" array-dim1="1" array-dim2="1" size="4" address="110" mem-size="4" synchro="MASTER"/> + <Register name="RO_dt" format="dt" array-dim1="1" array-dim2="1" size="8" address="114" mem-size="8" synchro="MASTER"/> + </Block> + <Block name="MyRWBlock" mode="READ-WRITE" size="212" address="33060" mem-size="468"> + <Register name="RW_int8" format="int8" array-dim1="2" array-dim2="2" size="1" address="0" mem-size="4" synchro="MASTER"/> + <Register name="RW_uint8" format="uint8" array-dim1="2" array-dim2="2" size="1" address="4" mem-size="4" synchro="MASTER"/> + <Register name="RW_int16" format="int16" array-dim1="2" array-dim2="2" size="2" address="8" mem-size="8" synchro="MASTER"/> + <Register name="RW_uint16" format="uint16" array-dim1="2" array-dim2="2" size="2" address="16" mem-size="8" synchro="MASTER"/> + <Register name="RW_int32" format="int32" array-dim1="2" array-dim2="2" size="4" address="24" mem-size="16" synchro="MASTER"/> + <Register name="RW_uint32" format="uint32" array-dim1="2" array-dim2="2" size="4" address="40" mem-size="16" synchro="MASTER"/> + <Register name="RW_float32" format="float32" array-dim1="2" array-dim2="2" size="4" address="56" mem-size="16" synchro="MASTER"/> + <Register name="RW_string" format="string" string-len="64" array-dim1="2" array-dim2="2" size="1" address="72" mem-size="260" synchro="MASTER"/> + <Register name="RW_date" format="date" array-dim1="2" array-dim2="2" size="8" address="332" mem-size="32" synchro="MASTER"/> + <Register name="RW_char" format="char" array-dim1="2" array-dim2="2" size="1" address="364" mem-size="4" synchro="MASTER"/> + <Register name="RW_byte" format="byte" array-dim1="2" array-dim2="2" size="1" address="368" mem-size="4" synchro="MASTER"/> + <Register name="RW_word" format="word" array-dim1="2" array-dim2="2" size="2" address="372" mem-size="8" synchro="MASTER"/> + <Register name="RW_dword" format="dword" array-dim1="2" array-dim2="2" size="4" address="380" mem-size="16" synchro="MASTER"/> + <Register name="RW_int" format="int" array-dim1="2" array-dim2="2" size="2" address="396" mem-size="8" synchro="MASTER"/> + <Register name="RW_dint" format="dint" array-dim1="2" array-dim2="2" size="4" address="404" mem-size="16" synchro="MASTER"/> + <Register name="RW_real" format="real" array-dim1="2" array-dim2="2" size="4" address="420" mem-size="16" synchro="MASTER"/> + <Register name="RW_dt" format="dt" array-dim1="2" array-dim2="2" size="8" address="436" mem-size="32" synchro="MASTER"/> + </Block> + <Block name="MyWOBlock" mode="WRITE-ONLY" size="530" address="33996" mem-size="1170"> + <Register name="WO_int8" format="int8" array-dim1="10" array-dim2="1" size="1" address="0" mem-size="10" synchro="SLAVE"/> + <Register name="WO_uint8" format="uint8" array-dim1="10" array-dim2="1" size="1" address="10" mem-size="10" synchro="SLAVE"/> + <Register name="WO_int16" format="int16" array-dim1="10" array-dim2="1" size="2" address="20" mem-size="20" synchro="SLAVE"/> + <Register name="WO_uint16" format="uint16" array-dim1="10" array-dim2="1" size="2" address="40" mem-size="20" synchro="SLAVE"/> + <Register name="WO_int32" format="int32" array-dim1="10" array-dim2="1" size="4" address="60" mem-size="40" synchro="SLAVE"/> + <Register name="WO_uint32" format="uint32" array-dim1="10" array-dim2="1" size="4" address="100" mem-size="40" synchro="SLAVE"/> + <Register name="WO_float32" format="float32" array-dim1="10" array-dim2="1" size="4" address="140" mem-size="40" synchro="SLAVE"/> + <Register name="WO_string" format="string" string-len="64" array-dim1="10" array-dim2="1" size="1" address="180" mem-size="650" synchro="SLAVE"/> + <Register name="WO_date" format="date" array-dim1="10" array-dim2="1" size="8" address="830" mem-size="80" synchro="SLAVE"/> + <Register name="WO_char" format="char" array-dim1="10" array-dim2="1" size="1" address="910" mem-size="10" synchro="SLAVE"/> + <Register name="WO_byte" format="byte" array-dim1="10" array-dim2="1" size="1" address="920" mem-size="10" synchro="SLAVE"/> + <Register name="WO_word" format="word" array-dim1="10" array-dim2="1" size="2" address="930" mem-size="20" synchro="SLAVE"/> + <Register name="WO_dword" format="dword" array-dim1="10" array-dim2="1" size="4" address="950" mem-size="40" synchro="SLAVE"/> + <Register name="WO_int" format="int" array-dim1="10" array-dim2="1" size="2" address="990" mem-size="20" synchro="SLAVE"/> + <Register name="WO_dint" format="dint" array-dim1="10" array-dim2="1" size="4" address="1010" mem-size="40" synchro="SLAVE"/> + <Register name="WO_real" format="real" array-dim1="10" array-dim2="1" size="4" address="1050" mem-size="40" synchro="SLAVE"/> + <Register name="WO_dt" format="dt" array-dim1="10" array-dim2="1" size="8" address="1090" mem-size="80" synchro="SLAVE"/> + </Block> + <Instance label="testDevice1" address="0"/> + <Instance label="testDevice2" address="1"/> + </SILECS-Class> + </SILECS-Mapping> +</SILECS-Param> diff --git a/silecs-codegen/src/xml/test/generated_correct/client/Beckhoff_CX9020.silecsparam b/silecs-codegen/src/xml/test/generated_correct/client/Beckhoff_CX9020.silecsparam new file mode 100644 index 0000000..90d7bc2 --- /dev/null +++ b/silecs-codegen/src/xml/test/generated_correct/client/Beckhoff_CX9020.silecsparam @@ -0,0 +1,80 @@ +<?xml version="1.0"?> +<SILECS-Param silecs-version="DEV"> + <Mapping-Info> + <Owner user-login="schwinn"/> + <Generation date="2016-07-14 16:03:58.791145"/> + <Deployment checksum="427563505"/> + </Mapping-Info> + <SILECS-Mapping plc-name="Beckhoff_CX9020" plc-brand="BECKHOFF" plc-system="TWINCat" plc-model="CX9020" protocol="BLOCK_MODE" address="24576" domain="NotUsed" used-mem="TODO"> + <SILECS-Class name="SilecsHeader" version="1.0.0" address="24576" used-mem="MW12288..MW12313 / 26 words"> + <Block name="hdrBlk" mode="READ-ONLY" size="14" address="24576" mem-size="52"> + <Register name="_version" format="string" string-len="16" array-dim1="1" array-dim2="1" size="1" address="0" mem-size="17" synchro="MASTER"/> + <Register name="_checksum" format="uint32" array-dim1="1" array-dim2="1" size="4" address="20" mem-size="4" synchro="MASTER"/> + <Register name="_user" format="string" string-len="16" array-dim1="1" array-dim2="1" size="1" address="24" mem-size="17" synchro="MASTER"/> + <Register name="_date" format="dt" array-dim1="1" array-dim2="1" size="8" address="44" mem-size="8" synchro="MASTER"/> + </Block> + <Instance label="SilecsHeader" address="0"/> + </SILECS-Class> + <SILECS-Class name="AllTypes" version="0.1.0" address="24628" used-mem="MW12314..MW14081 / 1768 words"> + <Block name="MyROBlock" mode="READ-ONLY" size="53" address="24628" mem-size="128"> + <Register name="RO_int8" format="int8" array-dim1="1" array-dim2="1" size="1" address="0" mem-size="1" synchro="MASTER"/> + <Register name="RO_uint8" format="uint8" array-dim1="1" array-dim2="1" size="1" address="2" mem-size="1" synchro="MASTER"/> + <Register name="RO_int16" format="int16" array-dim1="1" array-dim2="1" size="2" address="4" mem-size="2" synchro="MASTER"/> + <Register name="RO_uint16" format="uint16" array-dim1="1" array-dim2="1" size="2" address="6" mem-size="2" synchro="MASTER"/> + <Register name="RO_int32" format="int32" array-dim1="1" array-dim2="1" size="4" address="8" mem-size="4" synchro="MASTER"/> + <Register name="RO_uint32" format="uint32" array-dim1="1" array-dim2="1" size="4" address="12" mem-size="4" synchro="MASTER"/> + <Register name="RO_float32" format="float32" array-dim1="1" array-dim2="1" size="4" address="16" mem-size="4" synchro="MASTER"/> + <Register name="RO_string" format="string" string-len="64" array-dim1="1" array-dim2="1" size="1" address="20" mem-size="65" synchro="MASTER"/> + <Register name="RO_date" format="date" array-dim1="1" array-dim2="1" size="8" address="88" mem-size="8" synchro="MASTER"/> + <Register name="RO_char" format="char" array-dim1="1" array-dim2="1" size="1" address="96" mem-size="1" synchro="MASTER"/> + <Register name="RO_byte" format="byte" array-dim1="1" array-dim2="1" size="1" address="98" mem-size="1" synchro="MASTER"/> + <Register name="RO_word" format="word" array-dim1="1" array-dim2="1" size="2" address="100" mem-size="2" synchro="MASTER"/> + <Register name="RO_dword" format="dword" array-dim1="1" array-dim2="1" size="4" address="104" mem-size="4" synchro="MASTER"/> + <Register name="RO_int" format="int" array-dim1="1" array-dim2="1" size="2" address="108" mem-size="2" synchro="MASTER"/> + <Register name="RO_dint" format="dint" array-dim1="1" array-dim2="1" size="4" address="112" mem-size="4" synchro="MASTER"/> + <Register name="RO_real" format="real" array-dim1="1" array-dim2="1" size="4" address="116" mem-size="4" synchro="MASTER"/> + <Register name="RO_dt" format="dt" array-dim1="1" array-dim2="1" size="8" address="120" mem-size="8" synchro="MASTER"/> + </Block> + <Block name="MyRWBlock" mode="READ-WRITE" size="212" address="24884" mem-size="468"> + <Register name="RW_int8" format="int8" array-dim1="2" array-dim2="2" size="1" address="0" mem-size="4" synchro="MASTER"/> + <Register name="RW_uint8" format="uint8" array-dim1="2" array-dim2="2" size="1" address="4" mem-size="4" synchro="MASTER"/> + <Register name="RW_int16" format="int16" array-dim1="2" array-dim2="2" size="2" address="8" mem-size="8" synchro="MASTER"/> + <Register name="RW_uint16" format="uint16" array-dim1="2" array-dim2="2" size="2" address="16" mem-size="8" synchro="MASTER"/> + <Register name="RW_int32" format="int32" array-dim1="2" array-dim2="2" size="4" address="24" mem-size="16" synchro="MASTER"/> + <Register name="RW_uint32" format="uint32" array-dim1="2" array-dim2="2" size="4" address="40" mem-size="16" synchro="MASTER"/> + <Register name="RW_float32" format="float32" array-dim1="2" array-dim2="2" size="4" address="56" mem-size="16" synchro="MASTER"/> + <Register name="RW_string" format="string" string-len="64" array-dim1="2" array-dim2="2" size="1" address="72" mem-size="260" synchro="MASTER"/> + <Register name="RW_date" format="date" array-dim1="2" array-dim2="2" size="8" address="332" mem-size="32" synchro="MASTER"/> + <Register name="RW_char" format="char" array-dim1="2" array-dim2="2" size="1" address="364" mem-size="4" synchro="MASTER"/> + <Register name="RW_byte" format="byte" array-dim1="2" array-dim2="2" size="1" address="368" mem-size="4" synchro="MASTER"/> + <Register name="RW_word" format="word" array-dim1="2" array-dim2="2" size="2" address="372" mem-size="8" synchro="MASTER"/> + <Register name="RW_dword" format="dword" array-dim1="2" array-dim2="2" size="4" address="380" mem-size="16" synchro="MASTER"/> + <Register name="RW_int" format="int" array-dim1="2" array-dim2="2" size="2" address="396" mem-size="8" synchro="MASTER"/> + <Register name="RW_dint" format="dint" array-dim1="2" array-dim2="2" size="4" address="404" mem-size="16" synchro="MASTER"/> + <Register name="RW_real" format="real" array-dim1="2" array-dim2="2" size="4" address="420" mem-size="16" synchro="MASTER"/> + <Register name="RW_dt" format="dt" array-dim1="2" array-dim2="2" size="8" address="436" mem-size="32" synchro="MASTER"/> + </Block> + <Block name="MyWOBlock" mode="WRITE-ONLY" size="530" address="25820" mem-size="1172"> + <Register name="WO_int8" format="int8" array-dim1="10" array-dim2="1" size="1" address="0" mem-size="10" synchro="SLAVE"/> + <Register name="WO_uint8" format="uint8" array-dim1="10" array-dim2="1" size="1" address="10" mem-size="10" synchro="SLAVE"/> + <Register name="WO_int16" format="int16" array-dim1="10" array-dim2="1" size="2" address="20" mem-size="20" synchro="SLAVE"/> + <Register name="WO_uint16" format="uint16" array-dim1="10" array-dim2="1" size="2" address="40" mem-size="20" synchro="SLAVE"/> + <Register name="WO_int32" format="int32" array-dim1="10" array-dim2="1" size="4" address="60" mem-size="40" synchro="SLAVE"/> + <Register name="WO_uint32" format="uint32" array-dim1="10" array-dim2="1" size="4" address="100" mem-size="40" synchro="SLAVE"/> + <Register name="WO_float32" format="float32" array-dim1="10" array-dim2="1" size="4" address="140" mem-size="40" synchro="SLAVE"/> + <Register name="WO_string" format="string" string-len="64" array-dim1="10" array-dim2="1" size="1" address="180" mem-size="650" synchro="SLAVE"/> + <Register name="WO_date" format="date" array-dim1="10" array-dim2="1" size="8" address="832" mem-size="80" synchro="SLAVE"/> + <Register name="WO_char" format="char" array-dim1="10" array-dim2="1" size="1" address="912" mem-size="10" synchro="SLAVE"/> + <Register name="WO_byte" format="byte" array-dim1="10" array-dim2="1" size="1" address="922" mem-size="10" synchro="SLAVE"/> + <Register name="WO_word" format="word" array-dim1="10" array-dim2="1" size="2" address="932" mem-size="20" synchro="SLAVE"/> + <Register name="WO_dword" format="dword" array-dim1="10" array-dim2="1" size="4" address="952" mem-size="40" synchro="SLAVE"/> + <Register name="WO_int" format="int" array-dim1="10" array-dim2="1" size="2" address="992" mem-size="20" synchro="SLAVE"/> + <Register name="WO_dint" format="dint" array-dim1="10" array-dim2="1" size="4" address="1012" mem-size="40" synchro="SLAVE"/> + <Register name="WO_real" format="real" array-dim1="10" array-dim2="1" size="4" address="1052" mem-size="40" synchro="SLAVE"/> + <Register name="WO_dt" format="dt" array-dim1="10" array-dim2="1" size="8" address="1092" mem-size="80" synchro="SLAVE"/> + </Block> + <Instance label="testDevice1" address="0"/> + <Instance label="testDevice2" address="1"/> + </SILECS-Class> + </SILECS-Mapping> +</SILECS-Param> diff --git a/silecs-codegen/src/xml/test/generated_correct/client/Rabbit_BlockMode.silecsparam b/silecs-codegen/src/xml/test/generated_correct/client/Rabbit_BlockMode.silecsparam new file mode 100644 index 0000000..f213b46 --- /dev/null +++ b/silecs-codegen/src/xml/test/generated_correct/client/Rabbit_BlockMode.silecsparam @@ -0,0 +1,80 @@ +<?xml version="1.0"?> +<SILECS-Param silecs-version="DEV"> + <Mapping-Info> + <Owner user-login="schwinn"/> + <Generation date="2016-07-14 16:04:28.617415"/> + <Deployment checksum="3940683809"/> + </Mapping-Info> + <SILECS-Mapping plc-name="Rabbit_BlockMode" plc-brand="DIGI" plc-system="Standard-C" plc-model="Rabbit_RCM_4010" protocol="BLOCK_MODE" address="0" domain="NotUsed" used-mem="TODO"> + <SILECS-Class name="SilecsHeader" version="1.0.0" address="0" used-mem="MW0..MW21 / 22 words"> + <Block name="hdrBlk" mode="READ-ONLY" size="14" address="0" mem-size="44"> + <Register name="_version" format="string" string-len="16" array-dim1="1" array-dim2="1" size="1" address="0" mem-size="16" synchro="MASTER"/> + <Register name="_checksum" format="uint32" array-dim1="1" array-dim2="1" size="4" address="16" mem-size="4" synchro="MASTER"/> + <Register name="_user" format="string" string-len="16" array-dim1="1" array-dim2="1" size="1" address="20" mem-size="16" synchro="MASTER"/> + <Register name="_date" format="dt" array-dim1="1" array-dim2="1" size="8" address="36" mem-size="8" synchro="MASTER"/> + </Block> + <Instance label="SilecsHeader" address="0"/> + </SILECS-Class> + <SILECS-Class name="AllTypes" version="0.1.0" address="44" used-mem="MW22..MW1821 / 1800 words"> + <Block name="MyROBlock" mode="READ-ONLY" size="53" address="44" mem-size="120"> + <Register name="RO_int8" format="int8" array-dim1="1" array-dim2="1" size="1" address="0" mem-size="2" synchro="MASTER"/> + <Register name="RO_uint8" format="uint8" array-dim1="1" array-dim2="1" size="1" address="2" mem-size="2" synchro="MASTER"/> + <Register name="RO_int16" format="int16" array-dim1="1" array-dim2="1" size="2" address="4" mem-size="2" synchro="MASTER"/> + <Register name="RO_uint16" format="uint16" array-dim1="1" array-dim2="1" size="2" address="6" mem-size="2" synchro="MASTER"/> + <Register name="RO_int32" format="int32" array-dim1="1" array-dim2="1" size="4" address="8" mem-size="4" synchro="MASTER"/> + <Register name="RO_uint32" format="uint32" array-dim1="1" array-dim2="1" size="4" address="12" mem-size="4" synchro="MASTER"/> + <Register name="RO_float32" format="float32" array-dim1="1" array-dim2="1" size="4" address="16" mem-size="4" synchro="MASTER"/> + <Register name="RO_string" format="string" string-len="64" array-dim1="1" array-dim2="1" size="1" address="20" mem-size="64" synchro="MASTER"/> + <Register name="RO_date" format="date" array-dim1="1" array-dim2="1" size="8" address="84" mem-size="8" synchro="MASTER"/> + <Register name="RO_char" format="char" array-dim1="1" array-dim2="1" size="1" address="92" mem-size="2" synchro="MASTER"/> + <Register name="RO_byte" format="byte" array-dim1="1" array-dim2="1" size="1" address="94" mem-size="2" synchro="MASTER"/> + <Register name="RO_word" format="word" array-dim1="1" array-dim2="1" size="2" address="96" mem-size="2" synchro="MASTER"/> + <Register name="RO_dword" format="dword" array-dim1="1" array-dim2="1" size="4" address="98" mem-size="4" synchro="MASTER"/> + <Register name="RO_int" format="int" array-dim1="1" array-dim2="1" size="2" address="102" mem-size="2" synchro="MASTER"/> + <Register name="RO_dint" format="dint" array-dim1="1" array-dim2="1" size="4" address="104" mem-size="4" synchro="MASTER"/> + <Register name="RO_real" format="real" array-dim1="1" array-dim2="1" size="4" address="108" mem-size="4" synchro="MASTER"/> + <Register name="RO_dt" format="dt" array-dim1="1" array-dim2="1" size="8" address="112" mem-size="8" synchro="MASTER"/> + </Block> + <Block name="MyRWBlock" mode="READ-WRITE" size="212" address="284" mem-size="480"> + <Register name="RW_int8" format="int8" array-dim1="2" array-dim2="2" size="1" address="0" mem-size="8" synchro="MASTER"/> + <Register name="RW_uint8" format="uint8" array-dim1="2" array-dim2="2" size="1" address="8" mem-size="8" synchro="MASTER"/> + <Register name="RW_int16" format="int16" array-dim1="2" array-dim2="2" size="2" address="16" mem-size="8" synchro="MASTER"/> + <Register name="RW_uint16" format="uint16" array-dim1="2" array-dim2="2" size="2" address="24" mem-size="8" synchro="MASTER"/> + <Register name="RW_int32" format="int32" array-dim1="2" array-dim2="2" size="4" address="32" mem-size="16" synchro="MASTER"/> + <Register name="RW_uint32" format="uint32" array-dim1="2" array-dim2="2" size="4" address="48" mem-size="16" synchro="MASTER"/> + <Register name="RW_float32" format="float32" array-dim1="2" array-dim2="2" size="4" address="64" mem-size="16" synchro="MASTER"/> + <Register name="RW_string" format="string" string-len="64" array-dim1="2" array-dim2="2" size="1" address="80" mem-size="256" synchro="MASTER"/> + <Register name="RW_date" format="date" array-dim1="2" array-dim2="2" size="8" address="336" mem-size="32" synchro="MASTER"/> + <Register name="RW_char" format="char" array-dim1="2" array-dim2="2" size="1" address="368" mem-size="8" synchro="MASTER"/> + <Register name="RW_byte" format="byte" array-dim1="2" array-dim2="2" size="1" address="376" mem-size="8" synchro="MASTER"/> + <Register name="RW_word" format="word" array-dim1="2" array-dim2="2" size="2" address="384" mem-size="8" synchro="MASTER"/> + <Register name="RW_dword" format="dword" array-dim1="2" array-dim2="2" size="4" address="392" mem-size="16" synchro="MASTER"/> + <Register name="RW_int" format="int" array-dim1="2" array-dim2="2" size="2" address="408" mem-size="8" synchro="MASTER"/> + <Register name="RW_dint" format="dint" array-dim1="2" array-dim2="2" size="4" address="416" mem-size="16" synchro="MASTER"/> + <Register name="RW_real" format="real" array-dim1="2" array-dim2="2" size="4" address="432" mem-size="16" synchro="MASTER"/> + <Register name="RW_dt" format="dt" array-dim1="2" array-dim2="2" size="8" address="448" mem-size="32" synchro="MASTER"/> + </Block> + <Block name="MyWOBlock" mode="WRITE-ONLY" size="530" address="1244" mem-size="1200"> + <Register name="WO_int8" format="int8" array-dim1="10" array-dim2="1" size="1" address="0" mem-size="20" synchro="SLAVE"/> + <Register name="WO_uint8" format="uint8" array-dim1="10" array-dim2="1" size="1" address="20" mem-size="20" synchro="SLAVE"/> + <Register name="WO_int16" format="int16" array-dim1="10" array-dim2="1" size="2" address="40" mem-size="20" synchro="SLAVE"/> + <Register name="WO_uint16" format="uint16" array-dim1="10" array-dim2="1" size="2" address="60" mem-size="20" synchro="SLAVE"/> + <Register name="WO_int32" format="int32" array-dim1="10" array-dim2="1" size="4" address="80" mem-size="40" synchro="SLAVE"/> + <Register name="WO_uint32" format="uint32" array-dim1="10" array-dim2="1" size="4" address="120" mem-size="40" synchro="SLAVE"/> + <Register name="WO_float32" format="float32" array-dim1="10" array-dim2="1" size="4" address="160" mem-size="40" synchro="SLAVE"/> + <Register name="WO_string" format="string" string-len="64" array-dim1="10" array-dim2="1" size="1" address="200" mem-size="640" synchro="SLAVE"/> + <Register name="WO_date" format="date" array-dim1="10" array-dim2="1" size="8" address="840" mem-size="80" synchro="SLAVE"/> + <Register name="WO_char" format="char" array-dim1="10" array-dim2="1" size="1" address="920" mem-size="20" synchro="SLAVE"/> + <Register name="WO_byte" format="byte" array-dim1="10" array-dim2="1" size="1" address="940" mem-size="20" synchro="SLAVE"/> + <Register name="WO_word" format="word" array-dim1="10" array-dim2="1" size="2" address="960" mem-size="20" synchro="SLAVE"/> + <Register name="WO_dword" format="dword" array-dim1="10" array-dim2="1" size="4" address="980" mem-size="40" synchro="SLAVE"/> + <Register name="WO_int" format="int" array-dim1="10" array-dim2="1" size="2" address="1020" mem-size="20" synchro="SLAVE"/> + <Register name="WO_dint" format="dint" array-dim1="10" array-dim2="1" size="4" address="1040" mem-size="40" synchro="SLAVE"/> + <Register name="WO_real" format="real" array-dim1="10" array-dim2="1" size="4" address="1080" mem-size="40" synchro="SLAVE"/> + <Register name="WO_dt" format="dt" array-dim1="10" array-dim2="1" size="8" address="1120" mem-size="80" synchro="SLAVE"/> + </Block> + <Instance label="testDevice1" address="0"/> + <Instance label="testDevice2" address="1"/> + </SILECS-Class> + </SILECS-Mapping> +</SILECS-Param> diff --git a/silecs-codegen/src/xml/test/generated_correct/client/Rabbit_DeviceMode.silecsparam b/silecs-codegen/src/xml/test/generated_correct/client/Rabbit_DeviceMode.silecsparam new file mode 100644 index 0000000..73cbd93 --- /dev/null +++ b/silecs-codegen/src/xml/test/generated_correct/client/Rabbit_DeviceMode.silecsparam @@ -0,0 +1,80 @@ +<?xml version="1.0"?> +<SILECS-Param silecs-version="DEV"> + <Mapping-Info> + <Owner user-login="schwinn"/> + <Generation date="2016-07-14 16:04:38.516577"/> + <Deployment checksum="3940683809"/> + </Mapping-Info> + <SILECS-Mapping plc-name="Rabbit_DeviceMode" plc-brand="DIGI" plc-system="Standard-C" plc-model="Rabbit_RCM_4010" protocol="DEVICE_MODE" address="0" domain="NotUsed" used-mem="TODO"> + <SILECS-Class name="SilecsHeader" version="1.0.0" address="0" used-mem="MW0..MW21 / 22 words"> + <Block name="hdrBlk" mode="READ-ONLY" size="14" address="0" mem-size="44"> + <Register name="_version" format="string" string-len="16" array-dim1="1" array-dim2="1" size="1" address="0" mem-size="16" synchro="MASTER"/> + <Register name="_checksum" format="uint32" array-dim1="1" array-dim2="1" size="4" address="16" mem-size="4" synchro="MASTER"/> + <Register name="_user" format="string" string-len="16" array-dim1="1" array-dim2="1" size="1" address="20" mem-size="16" synchro="MASTER"/> + <Register name="_date" format="dt" array-dim1="1" array-dim2="1" size="8" address="36" mem-size="8" synchro="MASTER"/> + </Block> + <Instance label="SilecsHeader" address="0"/> + </SILECS-Class> + <SILECS-Class name="AllTypes" version="0.1.0" address="44" used-mem="MW22..MW1821 / 1800 words"> + <Block name="MyROBlock" mode="READ-ONLY" size="53" address="0" mem-size="120"> + <Register name="RO_int8" format="int8" array-dim1="1" array-dim2="1" size="1" address="0" mem-size="2" synchro="MASTER"/> + <Register name="RO_uint8" format="uint8" array-dim1="1" array-dim2="1" size="1" address="2" mem-size="2" synchro="MASTER"/> + <Register name="RO_int16" format="int16" array-dim1="1" array-dim2="1" size="2" address="4" mem-size="2" synchro="MASTER"/> + <Register name="RO_uint16" format="uint16" array-dim1="1" array-dim2="1" size="2" address="6" mem-size="2" synchro="MASTER"/> + <Register name="RO_int32" format="int32" array-dim1="1" array-dim2="1" size="4" address="8" mem-size="4" synchro="MASTER"/> + <Register name="RO_uint32" format="uint32" array-dim1="1" array-dim2="1" size="4" address="12" mem-size="4" synchro="MASTER"/> + <Register name="RO_float32" format="float32" array-dim1="1" array-dim2="1" size="4" address="16" mem-size="4" synchro="MASTER"/> + <Register name="RO_string" format="string" string-len="64" array-dim1="1" array-dim2="1" size="1" address="20" mem-size="64" synchro="MASTER"/> + <Register name="RO_date" format="date" array-dim1="1" array-dim2="1" size="8" address="84" mem-size="8" synchro="MASTER"/> + <Register name="RO_char" format="char" array-dim1="1" array-dim2="1" size="1" address="92" mem-size="2" synchro="MASTER"/> + <Register name="RO_byte" format="byte" array-dim1="1" array-dim2="1" size="1" address="94" mem-size="2" synchro="MASTER"/> + <Register name="RO_word" format="word" array-dim1="1" array-dim2="1" size="2" address="96" mem-size="2" synchro="MASTER"/> + <Register name="RO_dword" format="dword" array-dim1="1" array-dim2="1" size="4" address="98" mem-size="4" synchro="MASTER"/> + <Register name="RO_int" format="int" array-dim1="1" array-dim2="1" size="2" address="102" mem-size="2" synchro="MASTER"/> + <Register name="RO_dint" format="dint" array-dim1="1" array-dim2="1" size="4" address="104" mem-size="4" synchro="MASTER"/> + <Register name="RO_real" format="real" array-dim1="1" array-dim2="1" size="4" address="108" mem-size="4" synchro="MASTER"/> + <Register name="RO_dt" format="dt" array-dim1="1" array-dim2="1" size="8" address="112" mem-size="8" synchro="MASTER"/> + </Block> + <Block name="MyRWBlock" mode="READ-WRITE" size="212" address="120" mem-size="480"> + <Register name="RW_int8" format="int8" array-dim1="2" array-dim2="2" size="1" address="0" mem-size="8" synchro="MASTER"/> + <Register name="RW_uint8" format="uint8" array-dim1="2" array-dim2="2" size="1" address="8" mem-size="8" synchro="MASTER"/> + <Register name="RW_int16" format="int16" array-dim1="2" array-dim2="2" size="2" address="16" mem-size="8" synchro="MASTER"/> + <Register name="RW_uint16" format="uint16" array-dim1="2" array-dim2="2" size="2" address="24" mem-size="8" synchro="MASTER"/> + <Register name="RW_int32" format="int32" array-dim1="2" array-dim2="2" size="4" address="32" mem-size="16" synchro="MASTER"/> + <Register name="RW_uint32" format="uint32" array-dim1="2" array-dim2="2" size="4" address="48" mem-size="16" synchro="MASTER"/> + <Register name="RW_float32" format="float32" array-dim1="2" array-dim2="2" size="4" address="64" mem-size="16" synchro="MASTER"/> + <Register name="RW_string" format="string" string-len="64" array-dim1="2" array-dim2="2" size="1" address="80" mem-size="256" synchro="MASTER"/> + <Register name="RW_date" format="date" array-dim1="2" array-dim2="2" size="8" address="336" mem-size="32" synchro="MASTER"/> + <Register name="RW_char" format="char" array-dim1="2" array-dim2="2" size="1" address="368" mem-size="8" synchro="MASTER"/> + <Register name="RW_byte" format="byte" array-dim1="2" array-dim2="2" size="1" address="376" mem-size="8" synchro="MASTER"/> + <Register name="RW_word" format="word" array-dim1="2" array-dim2="2" size="2" address="384" mem-size="8" synchro="MASTER"/> + <Register name="RW_dword" format="dword" array-dim1="2" array-dim2="2" size="4" address="392" mem-size="16" synchro="MASTER"/> + <Register name="RW_int" format="int" array-dim1="2" array-dim2="2" size="2" address="408" mem-size="8" synchro="MASTER"/> + <Register name="RW_dint" format="dint" array-dim1="2" array-dim2="2" size="4" address="416" mem-size="16" synchro="MASTER"/> + <Register name="RW_real" format="real" array-dim1="2" array-dim2="2" size="4" address="432" mem-size="16" synchro="MASTER"/> + <Register name="RW_dt" format="dt" array-dim1="2" array-dim2="2" size="8" address="448" mem-size="32" synchro="MASTER"/> + </Block> + <Block name="MyWOBlock" mode="WRITE-ONLY" size="530" address="600" mem-size="1200"> + <Register name="WO_int8" format="int8" array-dim1="10" array-dim2="1" size="1" address="0" mem-size="20" synchro="SLAVE"/> + <Register name="WO_uint8" format="uint8" array-dim1="10" array-dim2="1" size="1" address="20" mem-size="20" synchro="SLAVE"/> + <Register name="WO_int16" format="int16" array-dim1="10" array-dim2="1" size="2" address="40" mem-size="20" synchro="SLAVE"/> + <Register name="WO_uint16" format="uint16" array-dim1="10" array-dim2="1" size="2" address="60" mem-size="20" synchro="SLAVE"/> + <Register name="WO_int32" format="int32" array-dim1="10" array-dim2="1" size="4" address="80" mem-size="40" synchro="SLAVE"/> + <Register name="WO_uint32" format="uint32" array-dim1="10" array-dim2="1" size="4" address="120" mem-size="40" synchro="SLAVE"/> + <Register name="WO_float32" format="float32" array-dim1="10" array-dim2="1" size="4" address="160" mem-size="40" synchro="SLAVE"/> + <Register name="WO_string" format="string" string-len="64" array-dim1="10" array-dim2="1" size="1" address="200" mem-size="640" synchro="SLAVE"/> + <Register name="WO_date" format="date" array-dim1="10" array-dim2="1" size="8" address="840" mem-size="80" synchro="SLAVE"/> + <Register name="WO_char" format="char" array-dim1="10" array-dim2="1" size="1" address="920" mem-size="20" synchro="SLAVE"/> + <Register name="WO_byte" format="byte" array-dim1="10" array-dim2="1" size="1" address="940" mem-size="20" synchro="SLAVE"/> + <Register name="WO_word" format="word" array-dim1="10" array-dim2="1" size="2" address="960" mem-size="20" synchro="SLAVE"/> + <Register name="WO_dword" format="dword" array-dim1="10" array-dim2="1" size="4" address="980" mem-size="40" synchro="SLAVE"/> + <Register name="WO_int" format="int" array-dim1="10" array-dim2="1" size="2" address="1020" mem-size="20" synchro="SLAVE"/> + <Register name="WO_dint" format="dint" array-dim1="10" array-dim2="1" size="4" address="1040" mem-size="40" synchro="SLAVE"/> + <Register name="WO_real" format="real" array-dim1="10" array-dim2="1" size="4" address="1080" mem-size="40" synchro="SLAVE"/> + <Register name="WO_dt" format="dt" array-dim1="10" array-dim2="1" size="8" address="1120" mem-size="80" synchro="SLAVE"/> + </Block> + <Instance label="testDevice1" address="44"/> + <Instance label="testDevice2" address="1844"/> + </SILECS-Class> + </SILECS-Mapping> +</SILECS-Param> diff --git a/silecs-codegen/src/xml/test/generated_correct/client/Schneider_M340.silecsparam b/silecs-codegen/src/xml/test/generated_correct/client/Schneider_M340.silecsparam new file mode 100644 index 0000000..1ea96e0 --- /dev/null +++ b/silecs-codegen/src/xml/test/generated_correct/client/Schneider_M340.silecsparam @@ -0,0 +1,80 @@ +<?xml version="1.0"?> +<SILECS-Param silecs-version="DEV"> + <Mapping-Info> + <Owner user-login="schwinn"/> + <Generation date="2016-07-14 16:04:09.437778"/> + <Deployment checksum="3940683809"/> + </Mapping-Info> + <SILECS-Mapping plc-name="Schneider_M340" plc-brand="SCHNEIDER" plc-system="UNITY Pro" plc-model="M340" protocol="BLOCK_MODE" address="0" domain="NotUsed" used-mem="TODO"> + <SILECS-Class name="SilecsHeader" version="1.0.0" address="0" used-mem="MW0..MW21 / 22 words"> + <Block name="hdrBlk" mode="READ-ONLY" size="14" address="0" mem-size="44"> + <Register name="_version" format="string" string-len="16" array-dim1="1" array-dim2="1" size="1" address="0" mem-size="16" synchro="MASTER"/> + <Register name="_checksum" format="uint32" array-dim1="1" array-dim2="1" size="4" address="16" mem-size="4" synchro="MASTER"/> + <Register name="_user" format="string" string-len="16" array-dim1="1" array-dim2="1" size="1" address="20" mem-size="16" synchro="MASTER"/> + <Register name="_date" format="dt" array-dim1="1" array-dim2="1" size="8" address="36" mem-size="8" synchro="MASTER"/> + </Block> + <Instance label="SilecsHeader" address="0"/> + </SILECS-Class> + <SILECS-Class name="AllTypes" version="0.1.0" address="44" used-mem="MW22..MW1801 / 1780 words"> + <Block name="MyROBlock" mode="READ-ONLY" size="53" address="44" mem-size="124"> + <Register name="RO_int8" format="int8" array-dim1="1" array-dim2="1" size="1" address="0" mem-size="2" synchro="MASTER"/> + <Register name="RO_uint8" format="uint8" array-dim1="1" array-dim2="1" size="1" address="2" mem-size="1" synchro="MASTER"/> + <Register name="RO_int16" format="int16" array-dim1="1" array-dim2="1" size="2" address="4" mem-size="2" synchro="MASTER"/> + <Register name="RO_uint16" format="uint16" array-dim1="1" array-dim2="1" size="2" address="6" mem-size="2" synchro="MASTER"/> + <Register name="RO_int32" format="int32" array-dim1="1" array-dim2="1" size="4" address="8" mem-size="4" synchro="MASTER"/> + <Register name="RO_uint32" format="uint32" array-dim1="1" array-dim2="1" size="4" address="12" mem-size="4" synchro="MASTER"/> + <Register name="RO_float32" format="float32" array-dim1="1" array-dim2="1" size="4" address="16" mem-size="4" synchro="MASTER"/> + <Register name="RO_string" format="string" string-len="64" array-dim1="1" array-dim2="1" size="1" address="20" mem-size="64" synchro="MASTER"/> + <Register name="RO_date" format="date" array-dim1="1" array-dim2="1" size="8" address="84" mem-size="8" synchro="MASTER"/> + <Register name="RO_char" format="char" array-dim1="1" array-dim2="1" size="1" address="92" mem-size="2" synchro="MASTER"/> + <Register name="RO_byte" format="byte" array-dim1="1" array-dim2="1" size="1" address="94" mem-size="1" synchro="MASTER"/> + <Register name="RO_word" format="word" array-dim1="1" array-dim2="1" size="2" address="96" mem-size="2" synchro="MASTER"/> + <Register name="RO_dword" format="dword" array-dim1="1" array-dim2="1" size="4" address="100" mem-size="4" synchro="MASTER"/> + <Register name="RO_int" format="int" array-dim1="1" array-dim2="1" size="2" address="104" mem-size="2" synchro="MASTER"/> + <Register name="RO_dint" format="dint" array-dim1="1" array-dim2="1" size="4" address="108" mem-size="4" synchro="MASTER"/> + <Register name="RO_real" format="real" array-dim1="1" array-dim2="1" size="4" address="112" mem-size="4" synchro="MASTER"/> + <Register name="RO_dt" format="dt" array-dim1="1" array-dim2="1" size="8" address="116" mem-size="8" synchro="MASTER"/> + </Block> + <Block name="MyRWBlock" mode="READ-WRITE" size="212" address="292" mem-size="472"> + <Register name="RW_int8" format="int8" array-dim1="2" array-dim2="2" size="1" address="0" mem-size="8" synchro="MASTER"/> + <Register name="RW_uint8" format="uint8" array-dim1="2" array-dim2="2" size="1" address="8" mem-size="4" synchro="MASTER"/> + <Register name="RW_int16" format="int16" array-dim1="2" array-dim2="2" size="2" address="12" mem-size="8" synchro="MASTER"/> + <Register name="RW_uint16" format="uint16" array-dim1="2" array-dim2="2" size="2" address="20" mem-size="8" synchro="MASTER"/> + <Register name="RW_int32" format="int32" array-dim1="2" array-dim2="2" size="4" address="28" mem-size="16" synchro="MASTER"/> + <Register name="RW_uint32" format="uint32" array-dim1="2" array-dim2="2" size="4" address="44" mem-size="16" synchro="MASTER"/> + <Register name="RW_float32" format="float32" array-dim1="2" array-dim2="2" size="4" address="60" mem-size="16" synchro="MASTER"/> + <Register name="RW_string" format="string" string-len="64" array-dim1="2" array-dim2="2" size="1" address="76" mem-size="256" synchro="MASTER"/> + <Register name="RW_date" format="date" array-dim1="2" array-dim2="2" size="8" address="332" mem-size="32" synchro="MASTER"/> + <Register name="RW_char" format="char" array-dim1="2" array-dim2="2" size="1" address="364" mem-size="8" synchro="MASTER"/> + <Register name="RW_byte" format="byte" array-dim1="2" array-dim2="2" size="1" address="372" mem-size="4" synchro="MASTER"/> + <Register name="RW_word" format="word" array-dim1="2" array-dim2="2" size="2" address="376" mem-size="8" synchro="MASTER"/> + <Register name="RW_dword" format="dword" array-dim1="2" array-dim2="2" size="4" address="384" mem-size="16" synchro="MASTER"/> + <Register name="RW_int" format="int" array-dim1="2" array-dim2="2" size="2" address="400" mem-size="8" synchro="MASTER"/> + <Register name="RW_dint" format="dint" array-dim1="2" array-dim2="2" size="4" address="408" mem-size="16" synchro="MASTER"/> + <Register name="RW_real" format="real" array-dim1="2" array-dim2="2" size="4" address="424" mem-size="16" synchro="MASTER"/> + <Register name="RW_dt" format="dt" array-dim1="2" array-dim2="2" size="8" address="440" mem-size="32" synchro="MASTER"/> + </Block> + <Block name="MyWOBlock" mode="WRITE-ONLY" size="530" address="1236" mem-size="1184"> + <Register name="WO_int8" format="int8" array-dim1="10" array-dim2="1" size="1" address="0" mem-size="20" synchro="SLAVE"/> + <Register name="WO_uint8" format="uint8" array-dim1="10" array-dim2="1" size="1" address="20" mem-size="10" synchro="SLAVE"/> + <Register name="WO_int16" format="int16" array-dim1="10" array-dim2="1" size="2" address="30" mem-size="20" synchro="SLAVE"/> + <Register name="WO_uint16" format="uint16" array-dim1="10" array-dim2="1" size="2" address="50" mem-size="20" synchro="SLAVE"/> + <Register name="WO_int32" format="int32" array-dim1="10" array-dim2="1" size="4" address="72" mem-size="40" synchro="SLAVE"/> + <Register name="WO_uint32" format="uint32" array-dim1="10" array-dim2="1" size="4" address="112" mem-size="40" synchro="SLAVE"/> + <Register name="WO_float32" format="float32" array-dim1="10" array-dim2="1" size="4" address="152" mem-size="40" synchro="SLAVE"/> + <Register name="WO_string" format="string" string-len="64" array-dim1="10" array-dim2="1" size="1" address="192" mem-size="640" synchro="SLAVE"/> + <Register name="WO_date" format="date" array-dim1="10" array-dim2="1" size="8" address="832" mem-size="80" synchro="SLAVE"/> + <Register name="WO_char" format="char" array-dim1="10" array-dim2="1" size="1" address="912" mem-size="20" synchro="SLAVE"/> + <Register name="WO_byte" format="byte" array-dim1="10" array-dim2="1" size="1" address="932" mem-size="10" synchro="SLAVE"/> + <Register name="WO_word" format="word" array-dim1="10" array-dim2="1" size="2" address="942" mem-size="20" synchro="SLAVE"/> + <Register name="WO_dword" format="dword" array-dim1="10" array-dim2="1" size="4" address="964" mem-size="40" synchro="SLAVE"/> + <Register name="WO_int" format="int" array-dim1="10" array-dim2="1" size="2" address="1004" mem-size="20" synchro="SLAVE"/> + <Register name="WO_dint" format="dint" array-dim1="10" array-dim2="1" size="4" address="1024" mem-size="40" synchro="SLAVE"/> + <Register name="WO_real" format="real" array-dim1="10" array-dim2="1" size="4" address="1064" mem-size="40" synchro="SLAVE"/> + <Register name="WO_dt" format="dt" array-dim1="10" array-dim2="1" size="8" address="1104" mem-size="80" synchro="SLAVE"/> + </Block> + <Instance label="testDevice1" address="0"/> + <Instance label="testDevice2" address="1"/> + </SILECS-Class> + </SILECS-Mapping> +</SILECS-Param> diff --git a/silecs-codegen/src/xml/test/generated_correct/client/Schneider_PremiumQuantum.silecsparam b/silecs-codegen/src/xml/test/generated_correct/client/Schneider_PremiumQuantum.silecsparam new file mode 100644 index 0000000..0e904f0 --- /dev/null +++ b/silecs-codegen/src/xml/test/generated_correct/client/Schneider_PremiumQuantum.silecsparam @@ -0,0 +1,80 @@ +<?xml version="1.0"?> +<SILECS-Param silecs-version="DEV"> + <Mapping-Info> + <Owner user-login="schwinn"/> + <Generation date="2016-07-14 16:04:19.735644"/> + <Deployment checksum="3940683809"/> + </Mapping-Info> + <SILECS-Mapping plc-name="Schneider_PremiumQuantum" plc-brand="SCHNEIDER" plc-system="UNITY Pro" plc-model="Premium" protocol="BLOCK_MODE" address="0" domain="NotUsed" used-mem="TODO"> + <SILECS-Class name="SilecsHeader" version="1.0.0" address="0" used-mem="MW0..MW21 / 22 words"> + <Block name="hdrBlk" mode="READ-ONLY" size="14" address="0" mem-size="44"> + <Register name="_version" format="string" string-len="16" array-dim1="1" array-dim2="1" size="1" address="0" mem-size="16" synchro="MASTER"/> + <Register name="_checksum" format="uint32" array-dim1="1" array-dim2="1" size="4" address="16" mem-size="4" synchro="MASTER"/> + <Register name="_user" format="string" string-len="16" array-dim1="1" array-dim2="1" size="1" address="20" mem-size="16" synchro="MASTER"/> + <Register name="_date" format="dt" array-dim1="1" array-dim2="1" size="8" address="36" mem-size="8" synchro="MASTER"/> + </Block> + <Instance label="SilecsHeader" address="0"/> + </SILECS-Class> + <SILECS-Class name="AllTypes" version="0.1.0" address="44" used-mem="MW22..MW1793 / 1772 words"> + <Block name="MyROBlock" mode="READ-ONLY" size="53" address="44" mem-size="120"> + <Register name="RO_int8" format="int8" array-dim1="1" array-dim2="1" size="1" address="0" mem-size="2" synchro="MASTER"/> + <Register name="RO_uint8" format="uint8" array-dim1="1" array-dim2="1" size="1" address="2" mem-size="1" synchro="MASTER"/> + <Register name="RO_int16" format="int16" array-dim1="1" array-dim2="1" size="2" address="4" mem-size="2" synchro="MASTER"/> + <Register name="RO_uint16" format="uint16" array-dim1="1" array-dim2="1" size="2" address="6" mem-size="2" synchro="MASTER"/> + <Register name="RO_int32" format="int32" array-dim1="1" array-dim2="1" size="4" address="8" mem-size="4" synchro="MASTER"/> + <Register name="RO_uint32" format="uint32" array-dim1="1" array-dim2="1" size="4" address="12" mem-size="4" synchro="MASTER"/> + <Register name="RO_float32" format="float32" array-dim1="1" array-dim2="1" size="4" address="16" mem-size="4" synchro="MASTER"/> + <Register name="RO_string" format="string" string-len="64" array-dim1="1" array-dim2="1" size="1" address="20" mem-size="64" synchro="MASTER"/> + <Register name="RO_date" format="date" array-dim1="1" array-dim2="1" size="8" address="84" mem-size="8" synchro="MASTER"/> + <Register name="RO_char" format="char" array-dim1="1" array-dim2="1" size="1" address="92" mem-size="2" synchro="MASTER"/> + <Register name="RO_byte" format="byte" array-dim1="1" array-dim2="1" size="1" address="94" mem-size="1" synchro="MASTER"/> + <Register name="RO_word" format="word" array-dim1="1" array-dim2="1" size="2" address="96" mem-size="2" synchro="MASTER"/> + <Register name="RO_dword" format="dword" array-dim1="1" array-dim2="1" size="4" address="98" mem-size="4" synchro="MASTER"/> + <Register name="RO_int" format="int" array-dim1="1" array-dim2="1" size="2" address="102" mem-size="2" synchro="MASTER"/> + <Register name="RO_dint" format="dint" array-dim1="1" array-dim2="1" size="4" address="104" mem-size="4" synchro="MASTER"/> + <Register name="RO_real" format="real" array-dim1="1" array-dim2="1" size="4" address="108" mem-size="4" synchro="MASTER"/> + <Register name="RO_dt" format="dt" array-dim1="1" array-dim2="1" size="8" address="112" mem-size="8" synchro="MASTER"/> + </Block> + <Block name="MyRWBlock" mode="READ-WRITE" size="212" address="284" mem-size="472"> + <Register name="RW_int8" format="int8" array-dim1="2" array-dim2="2" size="1" address="0" mem-size="8" synchro="MASTER"/> + <Register name="RW_uint8" format="uint8" array-dim1="2" array-dim2="2" size="1" address="8" mem-size="4" synchro="MASTER"/> + <Register name="RW_int16" format="int16" array-dim1="2" array-dim2="2" size="2" address="12" mem-size="8" synchro="MASTER"/> + <Register name="RW_uint16" format="uint16" array-dim1="2" array-dim2="2" size="2" address="20" mem-size="8" synchro="MASTER"/> + <Register name="RW_int32" format="int32" array-dim1="2" array-dim2="2" size="4" address="28" mem-size="16" synchro="MASTER"/> + <Register name="RW_uint32" format="uint32" array-dim1="2" array-dim2="2" size="4" address="44" mem-size="16" synchro="MASTER"/> + <Register name="RW_float32" format="float32" array-dim1="2" array-dim2="2" size="4" address="60" mem-size="16" synchro="MASTER"/> + <Register name="RW_string" format="string" string-len="64" array-dim1="2" array-dim2="2" size="1" address="76" mem-size="256" synchro="MASTER"/> + <Register name="RW_date" format="date" array-dim1="2" array-dim2="2" size="8" address="332" mem-size="32" synchro="MASTER"/> + <Register name="RW_char" format="char" array-dim1="2" array-dim2="2" size="1" address="364" mem-size="8" synchro="MASTER"/> + <Register name="RW_byte" format="byte" array-dim1="2" array-dim2="2" size="1" address="372" mem-size="4" synchro="MASTER"/> + <Register name="RW_word" format="word" array-dim1="2" array-dim2="2" size="2" address="376" mem-size="8" synchro="MASTER"/> + <Register name="RW_dword" format="dword" array-dim1="2" array-dim2="2" size="4" address="384" mem-size="16" synchro="MASTER"/> + <Register name="RW_int" format="int" array-dim1="2" array-dim2="2" size="2" address="400" mem-size="8" synchro="MASTER"/> + <Register name="RW_dint" format="dint" array-dim1="2" array-dim2="2" size="4" address="408" mem-size="16" synchro="MASTER"/> + <Register name="RW_real" format="real" array-dim1="2" array-dim2="2" size="4" address="424" mem-size="16" synchro="MASTER"/> + <Register name="RW_dt" format="dt" array-dim1="2" array-dim2="2" size="8" address="440" mem-size="32" synchro="MASTER"/> + </Block> + <Block name="MyWOBlock" mode="WRITE-ONLY" size="530" address="1228" mem-size="1180"> + <Register name="WO_int8" format="int8" array-dim1="10" array-dim2="1" size="1" address="0" mem-size="20" synchro="SLAVE"/> + <Register name="WO_uint8" format="uint8" array-dim1="10" array-dim2="1" size="1" address="20" mem-size="10" synchro="SLAVE"/> + <Register name="WO_int16" format="int16" array-dim1="10" array-dim2="1" size="2" address="30" mem-size="20" synchro="SLAVE"/> + <Register name="WO_uint16" format="uint16" array-dim1="10" array-dim2="1" size="2" address="50" mem-size="20" synchro="SLAVE"/> + <Register name="WO_int32" format="int32" array-dim1="10" array-dim2="1" size="4" address="70" mem-size="40" synchro="SLAVE"/> + <Register name="WO_uint32" format="uint32" array-dim1="10" array-dim2="1" size="4" address="110" mem-size="40" synchro="SLAVE"/> + <Register name="WO_float32" format="float32" array-dim1="10" array-dim2="1" size="4" address="150" mem-size="40" synchro="SLAVE"/> + <Register name="WO_string" format="string" string-len="64" array-dim1="10" array-dim2="1" size="1" address="190" mem-size="640" synchro="SLAVE"/> + <Register name="WO_date" format="date" array-dim1="10" array-dim2="1" size="8" address="830" mem-size="80" synchro="SLAVE"/> + <Register name="WO_char" format="char" array-dim1="10" array-dim2="1" size="1" address="910" mem-size="20" synchro="SLAVE"/> + <Register name="WO_byte" format="byte" array-dim1="10" array-dim2="1" size="1" address="930" mem-size="10" synchro="SLAVE"/> + <Register name="WO_word" format="word" array-dim1="10" array-dim2="1" size="2" address="940" mem-size="20" synchro="SLAVE"/> + <Register name="WO_dword" format="dword" array-dim1="10" array-dim2="1" size="4" address="960" mem-size="40" synchro="SLAVE"/> + <Register name="WO_int" format="int" array-dim1="10" array-dim2="1" size="2" address="1000" mem-size="20" synchro="SLAVE"/> + <Register name="WO_dint" format="dint" array-dim1="10" array-dim2="1" size="4" address="1020" mem-size="40" synchro="SLAVE"/> + <Register name="WO_real" format="real" array-dim1="10" array-dim2="1" size="4" address="1060" mem-size="40" synchro="SLAVE"/> + <Register name="WO_dt" format="dt" array-dim1="10" array-dim2="1" size="8" address="1100" mem-size="80" synchro="SLAVE"/> + </Block> + <Instance label="testDevice1" address="0"/> + <Instance label="testDevice2" address="1"/> + </SILECS-Class> + </SILECS-Mapping> +</SILECS-Param> diff --git a/silecs-codegen/src/xml/test/generated_correct/client/Siemens_Step7Block.silecsparam b/silecs-codegen/src/xml/test/generated_correct/client/Siemens_Step7Block.silecsparam new file mode 100644 index 0000000..8182e9e --- /dev/null +++ b/silecs-codegen/src/xml/test/generated_correct/client/Siemens_Step7Block.silecsparam @@ -0,0 +1,80 @@ +<?xml version="1.0"?> +<SILECS-Param silecs-version="DEV"> + <Mapping-Info> + <Owner user-login="schwinn"/> + <Generation date="2016-07-14 16:03:31.706052"/> + <Deployment checksum="3940683809"/> + </Mapping-Info> + <SILECS-Mapping plc-name="Siemens_Step7Block" plc-brand="SIEMENS" plc-system="STEP-7" plc-model="SIMATIC_S7-300" protocol="DEVICE_MODE" address="0" domain="NotUsed" used-mem="TODO"> + <SILECS-Class name="SilecsHeader" version="1.0.0" address="0" used-mem="DB0..DB0 / 48 bytes"> + <Block name="hdrBlk" mode="READ-ONLY" size="14" address="0" mem-size="48"> + <Register name="_version" format="string" string-len="16" array-dim1="1" array-dim2="1" size="1" address="0" mem-size="18" synchro="MASTER"/> + <Register name="_checksum" format="uint32" array-dim1="1" array-dim2="1" size="4" address="18" mem-size="4" synchro="MASTER"/> + <Register name="_user" format="string" string-len="16" array-dim1="1" array-dim2="1" size="1" address="22" mem-size="18" synchro="MASTER"/> + <Register name="_date" format="dt" array-dim1="1" array-dim2="1" size="8" address="40" mem-size="8" synchro="MASTER"/> + </Block> + <Instance label="SilecsHeader" address="0"/> + </SILECS-Class> + <SILECS-Class name="AllTypes" version="0.1.0" address="1" used-mem="DB1..DB2 / 3540 bytes"> + <Block name="MyROBlock" mode="READ-ONLY" size="53" address="0" mem-size="118"> + <Register name="RO_int8" format="int8" array-dim1="1" array-dim2="1" size="1" address="0" mem-size="1" synchro="MASTER"/> + <Register name="RO_uint8" format="uint8" array-dim1="1" array-dim2="1" size="1" address="1" mem-size="1" synchro="MASTER"/> + <Register name="RO_int16" format="int16" array-dim1="1" array-dim2="1" size="2" address="2" mem-size="2" synchro="MASTER"/> + <Register name="RO_uint16" format="uint16" array-dim1="1" array-dim2="1" size="2" address="4" mem-size="2" synchro="MASTER"/> + <Register name="RO_int32" format="int32" array-dim1="1" array-dim2="1" size="4" address="6" mem-size="4" synchro="MASTER"/> + <Register name="RO_uint32" format="uint32" array-dim1="1" array-dim2="1" size="4" address="10" mem-size="4" synchro="MASTER"/> + <Register name="RO_float32" format="float32" array-dim1="1" array-dim2="1" size="4" address="14" mem-size="4" synchro="MASTER"/> + <Register name="RO_string" format="string" string-len="64" array-dim1="1" array-dim2="1" size="1" address="18" mem-size="66" synchro="MASTER"/> + <Register name="RO_date" format="date" array-dim1="1" array-dim2="1" size="8" address="84" mem-size="8" synchro="MASTER"/> + <Register name="RO_char" format="char" array-dim1="1" array-dim2="1" size="1" address="92" mem-size="1" synchro="MASTER"/> + <Register name="RO_byte" format="byte" array-dim1="1" array-dim2="1" size="1" address="93" mem-size="1" synchro="MASTER"/> + <Register name="RO_word" format="word" array-dim1="1" array-dim2="1" size="2" address="94" mem-size="2" synchro="MASTER"/> + <Register name="RO_dword" format="dword" array-dim1="1" array-dim2="1" size="4" address="96" mem-size="4" synchro="MASTER"/> + <Register name="RO_int" format="int" array-dim1="1" array-dim2="1" size="2" address="100" mem-size="2" synchro="MASTER"/> + <Register name="RO_dint" format="dint" array-dim1="1" array-dim2="1" size="4" address="102" mem-size="4" synchro="MASTER"/> + <Register name="RO_real" format="real" array-dim1="1" array-dim2="1" size="4" address="106" mem-size="4" synchro="MASTER"/> + <Register name="RO_dt" format="dt" array-dim1="1" array-dim2="1" size="8" address="110" mem-size="8" synchro="MASTER"/> + </Block> + <Block name="MyRWBlock" mode="READ-WRITE" size="212" address="118" mem-size="472"> + <Register name="RW_int8" format="int8" array-dim1="2" array-dim2="2" size="1" address="0" mem-size="4" synchro="MASTER"/> + <Register name="RW_uint8" format="uint8" array-dim1="2" array-dim2="2" size="1" address="4" mem-size="4" synchro="MASTER"/> + <Register name="RW_int16" format="int16" array-dim1="2" array-dim2="2" size="2" address="8" mem-size="8" synchro="MASTER"/> + <Register name="RW_uint16" format="uint16" array-dim1="2" array-dim2="2" size="2" address="16" mem-size="8" synchro="MASTER"/> + <Register name="RW_int32" format="int32" array-dim1="2" array-dim2="2" size="4" address="24" mem-size="16" synchro="MASTER"/> + <Register name="RW_uint32" format="uint32" array-dim1="2" array-dim2="2" size="4" address="40" mem-size="16" synchro="MASTER"/> + <Register name="RW_float32" format="float32" array-dim1="2" array-dim2="2" size="4" address="56" mem-size="16" synchro="MASTER"/> + <Register name="RW_string" format="string" string-len="64" array-dim1="2" array-dim2="2" size="1" address="72" mem-size="264" synchro="MASTER"/> + <Register name="RW_date" format="date" array-dim1="2" array-dim2="2" size="8" address="336" mem-size="32" synchro="MASTER"/> + <Register name="RW_char" format="char" array-dim1="2" array-dim2="2" size="1" address="368" mem-size="4" synchro="MASTER"/> + <Register name="RW_byte" format="byte" array-dim1="2" array-dim2="2" size="1" address="372" mem-size="4" synchro="MASTER"/> + <Register name="RW_word" format="word" array-dim1="2" array-dim2="2" size="2" address="376" mem-size="8" synchro="MASTER"/> + <Register name="RW_dword" format="dword" array-dim1="2" array-dim2="2" size="4" address="384" mem-size="16" synchro="MASTER"/> + <Register name="RW_int" format="int" array-dim1="2" array-dim2="2" size="2" address="400" mem-size="8" synchro="MASTER"/> + <Register name="RW_dint" format="dint" array-dim1="2" array-dim2="2" size="4" address="408" mem-size="16" synchro="MASTER"/> + <Register name="RW_real" format="real" array-dim1="2" array-dim2="2" size="4" address="424" mem-size="16" synchro="MASTER"/> + <Register name="RW_dt" format="dt" array-dim1="2" array-dim2="2" size="8" address="440" mem-size="32" synchro="MASTER"/> + </Block> + <Block name="MyWOBlock" mode="WRITE-ONLY" size="530" address="590" mem-size="1180"> + <Register name="WO_int8" format="int8" array-dim1="10" array-dim2="1" size="1" address="0" mem-size="10" synchro="SLAVE"/> + <Register name="WO_uint8" format="uint8" array-dim1="10" array-dim2="1" size="1" address="10" mem-size="10" synchro="SLAVE"/> + <Register name="WO_int16" format="int16" array-dim1="10" array-dim2="1" size="2" address="20" mem-size="20" synchro="SLAVE"/> + <Register name="WO_uint16" format="uint16" array-dim1="10" array-dim2="1" size="2" address="40" mem-size="20" synchro="SLAVE"/> + <Register name="WO_int32" format="int32" array-dim1="10" array-dim2="1" size="4" address="60" mem-size="40" synchro="SLAVE"/> + <Register name="WO_uint32" format="uint32" array-dim1="10" array-dim2="1" size="4" address="100" mem-size="40" synchro="SLAVE"/> + <Register name="WO_float32" format="float32" array-dim1="10" array-dim2="1" size="4" address="140" mem-size="40" synchro="SLAVE"/> + <Register name="WO_string" format="string" string-len="64" array-dim1="10" array-dim2="1" size="1" address="180" mem-size="660" synchro="SLAVE"/> + <Register name="WO_date" format="date" array-dim1="10" array-dim2="1" size="8" address="840" mem-size="80" synchro="SLAVE"/> + <Register name="WO_char" format="char" array-dim1="10" array-dim2="1" size="1" address="920" mem-size="10" synchro="SLAVE"/> + <Register name="WO_byte" format="byte" array-dim1="10" array-dim2="1" size="1" address="930" mem-size="10" synchro="SLAVE"/> + <Register name="WO_word" format="word" array-dim1="10" array-dim2="1" size="2" address="940" mem-size="20" synchro="SLAVE"/> + <Register name="WO_dword" format="dword" array-dim1="10" array-dim2="1" size="4" address="960" mem-size="40" synchro="SLAVE"/> + <Register name="WO_int" format="int" array-dim1="10" array-dim2="1" size="2" address="1000" mem-size="20" synchro="SLAVE"/> + <Register name="WO_dint" format="dint" array-dim1="10" array-dim2="1" size="4" address="1020" mem-size="40" synchro="SLAVE"/> + <Register name="WO_real" format="real" array-dim1="10" array-dim2="1" size="4" address="1060" mem-size="40" synchro="SLAVE"/> + <Register name="WO_dt" format="dt" array-dim1="10" array-dim2="1" size="8" address="1100" mem-size="80" synchro="SLAVE"/> + </Block> + <Instance label="testDevice1" address="1"/> + <Instance label="testDevice2" address="2"/> + </SILECS-Class> + </SILECS-Mapping> +</SILECS-Param> diff --git a/silecs-codegen/src/xml/test/generated_correct/client/Siemens_Step7Device.silecsparam b/silecs-codegen/src/xml/test/generated_correct/client/Siemens_Step7Device.silecsparam new file mode 100644 index 0000000..46bf195 --- /dev/null +++ b/silecs-codegen/src/xml/test/generated_correct/client/Siemens_Step7Device.silecsparam @@ -0,0 +1,80 @@ +<?xml version="1.0"?> +<SILECS-Param silecs-version="DEV"> + <Mapping-Info> + <Owner user-login="schwinn"/> + <Generation date="2016-07-14 16:03:18.892092"/> + <Deployment checksum="3940683809"/> + </Mapping-Info> + <SILECS-Mapping plc-name="Siemens_Step7Device" plc-brand="SIEMENS" plc-system="STEP-7" plc-model="SIMATIC_S7-300" protocol="BLOCK_MODE" address="0" domain="NotUsed" used-mem="TODO"> + <SILECS-Class name="SilecsHeader" version="1.0.0" address="0" used-mem="DB0..DB0 / 48 bytes"> + <Block name="hdrBlk" mode="READ-ONLY" size="14" address="0" mem-size="48"> + <Register name="_version" format="string" string-len="16" array-dim1="1" array-dim2="1" size="1" address="0" mem-size="18" synchro="MASTER"/> + <Register name="_checksum" format="uint32" array-dim1="1" array-dim2="1" size="4" address="18" mem-size="4" synchro="MASTER"/> + <Register name="_user" format="string" string-len="16" array-dim1="1" array-dim2="1" size="1" address="22" mem-size="18" synchro="MASTER"/> + <Register name="_date" format="dt" array-dim1="1" array-dim2="1" size="8" address="40" mem-size="8" synchro="MASTER"/> + </Block> + <Instance label="SilecsHeader" address="0"/> + </SILECS-Class> + <SILECS-Class name="AllTypes" version="0.1.0" address="1" used-mem="DB1..DB3 / 3540 bytes"> + <Block name="MyROBlock" mode="READ-ONLY" size="53" address="1" mem-size="118"> + <Register name="RO_int8" format="int8" array-dim1="1" array-dim2="1" size="1" address="0" mem-size="1" synchro="MASTER"/> + <Register name="RO_uint8" format="uint8" array-dim1="1" array-dim2="1" size="1" address="1" mem-size="1" synchro="MASTER"/> + <Register name="RO_int16" format="int16" array-dim1="1" array-dim2="1" size="2" address="2" mem-size="2" synchro="MASTER"/> + <Register name="RO_uint16" format="uint16" array-dim1="1" array-dim2="1" size="2" address="4" mem-size="2" synchro="MASTER"/> + <Register name="RO_int32" format="int32" array-dim1="1" array-dim2="1" size="4" address="6" mem-size="4" synchro="MASTER"/> + <Register name="RO_uint32" format="uint32" array-dim1="1" array-dim2="1" size="4" address="10" mem-size="4" synchro="MASTER"/> + <Register name="RO_float32" format="float32" array-dim1="1" array-dim2="1" size="4" address="14" mem-size="4" synchro="MASTER"/> + <Register name="RO_string" format="string" string-len="64" array-dim1="1" array-dim2="1" size="1" address="18" mem-size="66" synchro="MASTER"/> + <Register name="RO_date" format="date" array-dim1="1" array-dim2="1" size="8" address="84" mem-size="8" synchro="MASTER"/> + <Register name="RO_char" format="char" array-dim1="1" array-dim2="1" size="1" address="92" mem-size="1" synchro="MASTER"/> + <Register name="RO_byte" format="byte" array-dim1="1" array-dim2="1" size="1" address="93" mem-size="1" synchro="MASTER"/> + <Register name="RO_word" format="word" array-dim1="1" array-dim2="1" size="2" address="94" mem-size="2" synchro="MASTER"/> + <Register name="RO_dword" format="dword" array-dim1="1" array-dim2="1" size="4" address="96" mem-size="4" synchro="MASTER"/> + <Register name="RO_int" format="int" array-dim1="1" array-dim2="1" size="2" address="100" mem-size="2" synchro="MASTER"/> + <Register name="RO_dint" format="dint" array-dim1="1" array-dim2="1" size="4" address="102" mem-size="4" synchro="MASTER"/> + <Register name="RO_real" format="real" array-dim1="1" array-dim2="1" size="4" address="106" mem-size="4" synchro="MASTER"/> + <Register name="RO_dt" format="dt" array-dim1="1" array-dim2="1" size="8" address="110" mem-size="8" synchro="MASTER"/> + </Block> + <Block name="MyRWBlock" mode="READ-WRITE" size="212" address="2" mem-size="472"> + <Register name="RW_int8" format="int8" array-dim1="2" array-dim2="2" size="1" address="0" mem-size="4" synchro="MASTER"/> + <Register name="RW_uint8" format="uint8" array-dim1="2" array-dim2="2" size="1" address="4" mem-size="4" synchro="MASTER"/> + <Register name="RW_int16" format="int16" array-dim1="2" array-dim2="2" size="2" address="8" mem-size="8" synchro="MASTER"/> + <Register name="RW_uint16" format="uint16" array-dim1="2" array-dim2="2" size="2" address="16" mem-size="8" synchro="MASTER"/> + <Register name="RW_int32" format="int32" array-dim1="2" array-dim2="2" size="4" address="24" mem-size="16" synchro="MASTER"/> + <Register name="RW_uint32" format="uint32" array-dim1="2" array-dim2="2" size="4" address="40" mem-size="16" synchro="MASTER"/> + <Register name="RW_float32" format="float32" array-dim1="2" array-dim2="2" size="4" address="56" mem-size="16" synchro="MASTER"/> + <Register name="RW_string" format="string" string-len="64" array-dim1="2" array-dim2="2" size="1" address="72" mem-size="264" synchro="MASTER"/> + <Register name="RW_date" format="date" array-dim1="2" array-dim2="2" size="8" address="336" mem-size="32" synchro="MASTER"/> + <Register name="RW_char" format="char" array-dim1="2" array-dim2="2" size="1" address="368" mem-size="4" synchro="MASTER"/> + <Register name="RW_byte" format="byte" array-dim1="2" array-dim2="2" size="1" address="372" mem-size="4" synchro="MASTER"/> + <Register name="RW_word" format="word" array-dim1="2" array-dim2="2" size="2" address="376" mem-size="8" synchro="MASTER"/> + <Register name="RW_dword" format="dword" array-dim1="2" array-dim2="2" size="4" address="384" mem-size="16" synchro="MASTER"/> + <Register name="RW_int" format="int" array-dim1="2" array-dim2="2" size="2" address="400" mem-size="8" synchro="MASTER"/> + <Register name="RW_dint" format="dint" array-dim1="2" array-dim2="2" size="4" address="408" mem-size="16" synchro="MASTER"/> + <Register name="RW_real" format="real" array-dim1="2" array-dim2="2" size="4" address="424" mem-size="16" synchro="MASTER"/> + <Register name="RW_dt" format="dt" array-dim1="2" array-dim2="2" size="8" address="440" mem-size="32" synchro="MASTER"/> + </Block> + <Block name="MyWOBlock" mode="WRITE-ONLY" size="530" address="3" mem-size="1180"> + <Register name="WO_int8" format="int8" array-dim1="10" array-dim2="1" size="1" address="0" mem-size="10" synchro="SLAVE"/> + <Register name="WO_uint8" format="uint8" array-dim1="10" array-dim2="1" size="1" address="10" mem-size="10" synchro="SLAVE"/> + <Register name="WO_int16" format="int16" array-dim1="10" array-dim2="1" size="2" address="20" mem-size="20" synchro="SLAVE"/> + <Register name="WO_uint16" format="uint16" array-dim1="10" array-dim2="1" size="2" address="40" mem-size="20" synchro="SLAVE"/> + <Register name="WO_int32" format="int32" array-dim1="10" array-dim2="1" size="4" address="60" mem-size="40" synchro="SLAVE"/> + <Register name="WO_uint32" format="uint32" array-dim1="10" array-dim2="1" size="4" address="100" mem-size="40" synchro="SLAVE"/> + <Register name="WO_float32" format="float32" array-dim1="10" array-dim2="1" size="4" address="140" mem-size="40" synchro="SLAVE"/> + <Register name="WO_string" format="string" string-len="64" array-dim1="10" array-dim2="1" size="1" address="180" mem-size="660" synchro="SLAVE"/> + <Register name="WO_date" format="date" array-dim1="10" array-dim2="1" size="8" address="840" mem-size="80" synchro="SLAVE"/> + <Register name="WO_char" format="char" array-dim1="10" array-dim2="1" size="1" address="920" mem-size="10" synchro="SLAVE"/> + <Register name="WO_byte" format="byte" array-dim1="10" array-dim2="1" size="1" address="930" mem-size="10" synchro="SLAVE"/> + <Register name="WO_word" format="word" array-dim1="10" array-dim2="1" size="2" address="940" mem-size="20" synchro="SLAVE"/> + <Register name="WO_dword" format="dword" array-dim1="10" array-dim2="1" size="4" address="960" mem-size="40" synchro="SLAVE"/> + <Register name="WO_int" format="int" array-dim1="10" array-dim2="1" size="2" address="1000" mem-size="20" synchro="SLAVE"/> + <Register name="WO_dint" format="dint" array-dim1="10" array-dim2="1" size="4" address="1020" mem-size="40" synchro="SLAVE"/> + <Register name="WO_real" format="real" array-dim1="10" array-dim2="1" size="4" address="1060" mem-size="40" synchro="SLAVE"/> + <Register name="WO_dt" format="dt" array-dim1="10" array-dim2="1" size="8" address="1100" mem-size="80" synchro="SLAVE"/> + </Block> + <Instance label="testDevice1" address="0"/> + <Instance label="testDevice2" address="1"/> + </SILECS-Class> + </SILECS-Mapping> +</SILECS-Param> diff --git a/silecs-codegen/src/xml/test/generated_correct/client/Siemens_TiaBlock.silecsparam b/silecs-codegen/src/xml/test/generated_correct/client/Siemens_TiaBlock.silecsparam new file mode 100644 index 0000000..7f4c984 --- /dev/null +++ b/silecs-codegen/src/xml/test/generated_correct/client/Siemens_TiaBlock.silecsparam @@ -0,0 +1,80 @@ +<?xml version="1.0"?> +<SILECS-Param silecs-version="DEV"> + <Mapping-Info> + <Owner user-login="schwinn"/> + <Generation date="2016-07-14 16:02:43.799998"/> + <Deployment checksum="3940683809"/> + </Mapping-Info> + <SILECS-Mapping plc-name="Siemens_TiaBlock" plc-brand="SIEMENS" plc-system="TIA-PORTAL" plc-model="SIMATIC_S7-300" protocol="BLOCK_MODE" address="0" domain="NotUsed" used-mem="TODO"> + <SILECS-Class name="SilecsHeader" version="1.0.0" address="0" used-mem="DB0..DB0 / 48 bytes"> + <Block name="hdrBlk" mode="READ-ONLY" size="14" address="0" mem-size="48"> + <Register name="_version" format="string" string-len="16" array-dim1="1" array-dim2="1" size="1" address="0" mem-size="18" synchro="MASTER"/> + <Register name="_checksum" format="uint32" array-dim1="1" array-dim2="1" size="4" address="18" mem-size="4" synchro="MASTER"/> + <Register name="_user" format="string" string-len="16" array-dim1="1" array-dim2="1" size="1" address="22" mem-size="18" synchro="MASTER"/> + <Register name="_date" format="dt" array-dim1="1" array-dim2="1" size="8" address="40" mem-size="8" synchro="MASTER"/> + </Block> + <Instance label="SilecsHeader" address="0"/> + </SILECS-Class> + <SILECS-Class name="AllTypes" version="0.1.0" address="1" used-mem="DB1..DB3 / 3540 bytes"> + <Block name="MyROBlock" mode="READ-ONLY" size="53" address="1" mem-size="118"> + <Register name="RO_int8" format="int8" array-dim1="1" array-dim2="1" size="1" address="0" mem-size="1" synchro="MASTER"/> + <Register name="RO_uint8" format="uint8" array-dim1="1" array-dim2="1" size="1" address="1" mem-size="1" synchro="MASTER"/> + <Register name="RO_int16" format="int16" array-dim1="1" array-dim2="1" size="2" address="2" mem-size="2" synchro="MASTER"/> + <Register name="RO_uint16" format="uint16" array-dim1="1" array-dim2="1" size="2" address="4" mem-size="2" synchro="MASTER"/> + <Register name="RO_int32" format="int32" array-dim1="1" array-dim2="1" size="4" address="6" mem-size="4" synchro="MASTER"/> + <Register name="RO_uint32" format="uint32" array-dim1="1" array-dim2="1" size="4" address="10" mem-size="4" synchro="MASTER"/> + <Register name="RO_float32" format="float32" array-dim1="1" array-dim2="1" size="4" address="14" mem-size="4" synchro="MASTER"/> + <Register name="RO_string" format="string" string-len="64" array-dim1="1" array-dim2="1" size="1" address="18" mem-size="66" synchro="MASTER"/> + <Register name="RO_date" format="date" array-dim1="1" array-dim2="1" size="8" address="84" mem-size="8" synchro="MASTER"/> + <Register name="RO_char" format="char" array-dim1="1" array-dim2="1" size="1" address="92" mem-size="1" synchro="MASTER"/> + <Register name="RO_byte" format="byte" array-dim1="1" array-dim2="1" size="1" address="93" mem-size="1" synchro="MASTER"/> + <Register name="RO_word" format="word" array-dim1="1" array-dim2="1" size="2" address="94" mem-size="2" synchro="MASTER"/> + <Register name="RO_dword" format="dword" array-dim1="1" array-dim2="1" size="4" address="96" mem-size="4" synchro="MASTER"/> + <Register name="RO_int" format="int" array-dim1="1" array-dim2="1" size="2" address="100" mem-size="2" synchro="MASTER"/> + <Register name="RO_dint" format="dint" array-dim1="1" array-dim2="1" size="4" address="102" mem-size="4" synchro="MASTER"/> + <Register name="RO_real" format="real" array-dim1="1" array-dim2="1" size="4" address="106" mem-size="4" synchro="MASTER"/> + <Register name="RO_dt" format="dt" array-dim1="1" array-dim2="1" size="8" address="110" mem-size="8" synchro="MASTER"/> + </Block> + <Block name="MyRWBlock" mode="READ-WRITE" size="212" address="2" mem-size="472"> + <Register name="RW_int8" format="int8" array-dim1="2" array-dim2="2" size="1" address="0" mem-size="4" synchro="MASTER"/> + <Register name="RW_uint8" format="uint8" array-dim1="2" array-dim2="2" size="1" address="4" mem-size="4" synchro="MASTER"/> + <Register name="RW_int16" format="int16" array-dim1="2" array-dim2="2" size="2" address="8" mem-size="8" synchro="MASTER"/> + <Register name="RW_uint16" format="uint16" array-dim1="2" array-dim2="2" size="2" address="16" mem-size="8" synchro="MASTER"/> + <Register name="RW_int32" format="int32" array-dim1="2" array-dim2="2" size="4" address="24" mem-size="16" synchro="MASTER"/> + <Register name="RW_uint32" format="uint32" array-dim1="2" array-dim2="2" size="4" address="40" mem-size="16" synchro="MASTER"/> + <Register name="RW_float32" format="float32" array-dim1="2" array-dim2="2" size="4" address="56" mem-size="16" synchro="MASTER"/> + <Register name="RW_string" format="string" string-len="64" array-dim1="2" array-dim2="2" size="1" address="72" mem-size="264" synchro="MASTER"/> + <Register name="RW_date" format="date" array-dim1="2" array-dim2="2" size="8" address="336" mem-size="32" synchro="MASTER"/> + <Register name="RW_char" format="char" array-dim1="2" array-dim2="2" size="1" address="368" mem-size="4" synchro="MASTER"/> + <Register name="RW_byte" format="byte" array-dim1="2" array-dim2="2" size="1" address="372" mem-size="4" synchro="MASTER"/> + <Register name="RW_word" format="word" array-dim1="2" array-dim2="2" size="2" address="376" mem-size="8" synchro="MASTER"/> + <Register name="RW_dword" format="dword" array-dim1="2" array-dim2="2" size="4" address="384" mem-size="16" synchro="MASTER"/> + <Register name="RW_int" format="int" array-dim1="2" array-dim2="2" size="2" address="400" mem-size="8" synchro="MASTER"/> + <Register name="RW_dint" format="dint" array-dim1="2" array-dim2="2" size="4" address="408" mem-size="16" synchro="MASTER"/> + <Register name="RW_real" format="real" array-dim1="2" array-dim2="2" size="4" address="424" mem-size="16" synchro="MASTER"/> + <Register name="RW_dt" format="dt" array-dim1="2" array-dim2="2" size="8" address="440" mem-size="32" synchro="MASTER"/> + </Block> + <Block name="MyWOBlock" mode="WRITE-ONLY" size="530" address="3" mem-size="1180"> + <Register name="WO_int8" format="int8" array-dim1="10" array-dim2="1" size="1" address="0" mem-size="10" synchro="SLAVE"/> + <Register name="WO_uint8" format="uint8" array-dim1="10" array-dim2="1" size="1" address="10" mem-size="10" synchro="SLAVE"/> + <Register name="WO_int16" format="int16" array-dim1="10" array-dim2="1" size="2" address="20" mem-size="20" synchro="SLAVE"/> + <Register name="WO_uint16" format="uint16" array-dim1="10" array-dim2="1" size="2" address="40" mem-size="20" synchro="SLAVE"/> + <Register name="WO_int32" format="int32" array-dim1="10" array-dim2="1" size="4" address="60" mem-size="40" synchro="SLAVE"/> + <Register name="WO_uint32" format="uint32" array-dim1="10" array-dim2="1" size="4" address="100" mem-size="40" synchro="SLAVE"/> + <Register name="WO_float32" format="float32" array-dim1="10" array-dim2="1" size="4" address="140" mem-size="40" synchro="SLAVE"/> + <Register name="WO_string" format="string" string-len="64" array-dim1="10" array-dim2="1" size="1" address="180" mem-size="660" synchro="SLAVE"/> + <Register name="WO_date" format="date" array-dim1="10" array-dim2="1" size="8" address="840" mem-size="80" synchro="SLAVE"/> + <Register name="WO_char" format="char" array-dim1="10" array-dim2="1" size="1" address="920" mem-size="10" synchro="SLAVE"/> + <Register name="WO_byte" format="byte" array-dim1="10" array-dim2="1" size="1" address="930" mem-size="10" synchro="SLAVE"/> + <Register name="WO_word" format="word" array-dim1="10" array-dim2="1" size="2" address="940" mem-size="20" synchro="SLAVE"/> + <Register name="WO_dword" format="dword" array-dim1="10" array-dim2="1" size="4" address="960" mem-size="40" synchro="SLAVE"/> + <Register name="WO_int" format="int" array-dim1="10" array-dim2="1" size="2" address="1000" mem-size="20" synchro="SLAVE"/> + <Register name="WO_dint" format="dint" array-dim1="10" array-dim2="1" size="4" address="1020" mem-size="40" synchro="SLAVE"/> + <Register name="WO_real" format="real" array-dim1="10" array-dim2="1" size="4" address="1060" mem-size="40" synchro="SLAVE"/> + <Register name="WO_dt" format="dt" array-dim1="10" array-dim2="1" size="8" address="1100" mem-size="80" synchro="SLAVE"/> + </Block> + <Instance label="testDevice1" address="0"/> + <Instance label="testDevice2" address="1"/> + </SILECS-Class> + </SILECS-Mapping> +</SILECS-Param> diff --git a/silecs-codegen/src/xml/test/generated_correct/client/Siemens_TiaDevice.silecsparam b/silecs-codegen/src/xml/test/generated_correct/client/Siemens_TiaDevice.silecsparam new file mode 100644 index 0000000..766dea9 --- /dev/null +++ b/silecs-codegen/src/xml/test/generated_correct/client/Siemens_TiaDevice.silecsparam @@ -0,0 +1,80 @@ +<?xml version="1.0"?> +<SILECS-Param silecs-version="DEV"> + <Mapping-Info> + <Owner user-login="schwinn"/> + <Generation date="2016-07-14 15:59:09.165849"/> + <Deployment checksum="3940683809"/> + </Mapping-Info> + <SILECS-Mapping plc-name="Siemens_TiaDevice" plc-brand="SIEMENS" plc-system="TIA-PORTAL" plc-model="SIMATIC_S7-300" protocol="DEVICE_MODE" address="0" domain="NotUsed" used-mem="TODO"> + <SILECS-Class name="SilecsHeader" version="1.0.0" address="0" used-mem="DB0..DB0 / 48 bytes"> + <Block name="hdrBlk" mode="READ-ONLY" size="14" address="0" mem-size="48"> + <Register name="_version" format="string" string-len="16" array-dim1="1" array-dim2="1" size="1" address="0" mem-size="18" synchro="MASTER"/> + <Register name="_checksum" format="uint32" array-dim1="1" array-dim2="1" size="4" address="18" mem-size="4" synchro="MASTER"/> + <Register name="_user" format="string" string-len="16" array-dim1="1" array-dim2="1" size="1" address="22" mem-size="18" synchro="MASTER"/> + <Register name="_date" format="dt" array-dim1="1" array-dim2="1" size="8" address="40" mem-size="8" synchro="MASTER"/> + </Block> + <Instance label="SilecsHeader" address="0"/> + </SILECS-Class> + <SILECS-Class name="AllTypes" version="0.1.0" address="1" used-mem="DB1..DB2 / 3540 bytes"> + <Block name="MyROBlock" mode="READ-ONLY" size="53" address="0" mem-size="118"> + <Register name="RO_int8" format="int8" array-dim1="1" array-dim2="1" size="1" address="0" mem-size="1" synchro="MASTER"/> + <Register name="RO_uint8" format="uint8" array-dim1="1" array-dim2="1" size="1" address="1" mem-size="1" synchro="MASTER"/> + <Register name="RO_int16" format="int16" array-dim1="1" array-dim2="1" size="2" address="2" mem-size="2" synchro="MASTER"/> + <Register name="RO_uint16" format="uint16" array-dim1="1" array-dim2="1" size="2" address="4" mem-size="2" synchro="MASTER"/> + <Register name="RO_int32" format="int32" array-dim1="1" array-dim2="1" size="4" address="6" mem-size="4" synchro="MASTER"/> + <Register name="RO_uint32" format="uint32" array-dim1="1" array-dim2="1" size="4" address="10" mem-size="4" synchro="MASTER"/> + <Register name="RO_float32" format="float32" array-dim1="1" array-dim2="1" size="4" address="14" mem-size="4" synchro="MASTER"/> + <Register name="RO_string" format="string" string-len="64" array-dim1="1" array-dim2="1" size="1" address="18" mem-size="66" synchro="MASTER"/> + <Register name="RO_date" format="date" array-dim1="1" array-dim2="1" size="8" address="84" mem-size="8" synchro="MASTER"/> + <Register name="RO_char" format="char" array-dim1="1" array-dim2="1" size="1" address="92" mem-size="1" synchro="MASTER"/> + <Register name="RO_byte" format="byte" array-dim1="1" array-dim2="1" size="1" address="93" mem-size="1" synchro="MASTER"/> + <Register name="RO_word" format="word" array-dim1="1" array-dim2="1" size="2" address="94" mem-size="2" synchro="MASTER"/> + <Register name="RO_dword" format="dword" array-dim1="1" array-dim2="1" size="4" address="96" mem-size="4" synchro="MASTER"/> + <Register name="RO_int" format="int" array-dim1="1" array-dim2="1" size="2" address="100" mem-size="2" synchro="MASTER"/> + <Register name="RO_dint" format="dint" array-dim1="1" array-dim2="1" size="4" address="102" mem-size="4" synchro="MASTER"/> + <Register name="RO_real" format="real" array-dim1="1" array-dim2="1" size="4" address="106" mem-size="4" synchro="MASTER"/> + <Register name="RO_dt" format="dt" array-dim1="1" array-dim2="1" size="8" address="110" mem-size="8" synchro="MASTER"/> + </Block> + <Block name="MyRWBlock" mode="READ-WRITE" size="212" address="118" mem-size="472"> + <Register name="RW_int8" format="int8" array-dim1="2" array-dim2="2" size="1" address="0" mem-size="4" synchro="MASTER"/> + <Register name="RW_uint8" format="uint8" array-dim1="2" array-dim2="2" size="1" address="4" mem-size="4" synchro="MASTER"/> + <Register name="RW_int16" format="int16" array-dim1="2" array-dim2="2" size="2" address="8" mem-size="8" synchro="MASTER"/> + <Register name="RW_uint16" format="uint16" array-dim1="2" array-dim2="2" size="2" address="16" mem-size="8" synchro="MASTER"/> + <Register name="RW_int32" format="int32" array-dim1="2" array-dim2="2" size="4" address="24" mem-size="16" synchro="MASTER"/> + <Register name="RW_uint32" format="uint32" array-dim1="2" array-dim2="2" size="4" address="40" mem-size="16" synchro="MASTER"/> + <Register name="RW_float32" format="float32" array-dim1="2" array-dim2="2" size="4" address="56" mem-size="16" synchro="MASTER"/> + <Register name="RW_string" format="string" string-len="64" array-dim1="2" array-dim2="2" size="1" address="72" mem-size="264" synchro="MASTER"/> + <Register name="RW_date" format="date" array-dim1="2" array-dim2="2" size="8" address="336" mem-size="32" synchro="MASTER"/> + <Register name="RW_char" format="char" array-dim1="2" array-dim2="2" size="1" address="368" mem-size="4" synchro="MASTER"/> + <Register name="RW_byte" format="byte" array-dim1="2" array-dim2="2" size="1" address="372" mem-size="4" synchro="MASTER"/> + <Register name="RW_word" format="word" array-dim1="2" array-dim2="2" size="2" address="376" mem-size="8" synchro="MASTER"/> + <Register name="RW_dword" format="dword" array-dim1="2" array-dim2="2" size="4" address="384" mem-size="16" synchro="MASTER"/> + <Register name="RW_int" format="int" array-dim1="2" array-dim2="2" size="2" address="400" mem-size="8" synchro="MASTER"/> + <Register name="RW_dint" format="dint" array-dim1="2" array-dim2="2" size="4" address="408" mem-size="16" synchro="MASTER"/> + <Register name="RW_real" format="real" array-dim1="2" array-dim2="2" size="4" address="424" mem-size="16" synchro="MASTER"/> + <Register name="RW_dt" format="dt" array-dim1="2" array-dim2="2" size="8" address="440" mem-size="32" synchro="MASTER"/> + </Block> + <Block name="MyWOBlock" mode="WRITE-ONLY" size="530" address="590" mem-size="1180"> + <Register name="WO_int8" format="int8" array-dim1="10" array-dim2="1" size="1" address="0" mem-size="10" synchro="SLAVE"/> + <Register name="WO_uint8" format="uint8" array-dim1="10" array-dim2="1" size="1" address="10" mem-size="10" synchro="SLAVE"/> + <Register name="WO_int16" format="int16" array-dim1="10" array-dim2="1" size="2" address="20" mem-size="20" synchro="SLAVE"/> + <Register name="WO_uint16" format="uint16" array-dim1="10" array-dim2="1" size="2" address="40" mem-size="20" synchro="SLAVE"/> + <Register name="WO_int32" format="int32" array-dim1="10" array-dim2="1" size="4" address="60" mem-size="40" synchro="SLAVE"/> + <Register name="WO_uint32" format="uint32" array-dim1="10" array-dim2="1" size="4" address="100" mem-size="40" synchro="SLAVE"/> + <Register name="WO_float32" format="float32" array-dim1="10" array-dim2="1" size="4" address="140" mem-size="40" synchro="SLAVE"/> + <Register name="WO_string" format="string" string-len="64" array-dim1="10" array-dim2="1" size="1" address="180" mem-size="660" synchro="SLAVE"/> + <Register name="WO_date" format="date" array-dim1="10" array-dim2="1" size="8" address="840" mem-size="80" synchro="SLAVE"/> + <Register name="WO_char" format="char" array-dim1="10" array-dim2="1" size="1" address="920" mem-size="10" synchro="SLAVE"/> + <Register name="WO_byte" format="byte" array-dim1="10" array-dim2="1" size="1" address="930" mem-size="10" synchro="SLAVE"/> + <Register name="WO_word" format="word" array-dim1="10" array-dim2="1" size="2" address="940" mem-size="20" synchro="SLAVE"/> + <Register name="WO_dword" format="dword" array-dim1="10" array-dim2="1" size="4" address="960" mem-size="40" synchro="SLAVE"/> + <Register name="WO_int" format="int" array-dim1="10" array-dim2="1" size="2" address="1000" mem-size="20" synchro="SLAVE"/> + <Register name="WO_dint" format="dint" array-dim1="10" array-dim2="1" size="4" address="1020" mem-size="40" synchro="SLAVE"/> + <Register name="WO_real" format="real" array-dim1="10" array-dim2="1" size="4" address="1060" mem-size="40" synchro="SLAVE"/> + <Register name="WO_dt" format="dt" array-dim1="10" array-dim2="1" size="8" address="1100" mem-size="80" synchro="SLAVE"/> + </Block> + <Instance label="testDevice1" address="1"/> + <Instance label="testDevice2" address="2"/> + </SILECS-Class> + </SILECS-Mapping> +</SILECS-Param> diff --git a/silecs-codegen/src/xml/test/generated_correct/controller/Beckhoff_BC9020.exp b/silecs-codegen/src/xml/test/generated_correct/controller/Beckhoff_BC9020.exp new file mode 100644 index 0000000..db9ec3d --- /dev/null +++ b/silecs-codegen/src/xml/test/generated_correct/controller/Beckhoff_BC9020.exp @@ -0,0 +1,328 @@ +(* +------------------------------------------------------------------- +* | C.E.R.N Geneva, Switzerland +* | SILECS - BE/CO-FE +* | April 2015 +* +------------------------------------------------------------------- +* +* Release : SILECS_DEV +*) +VAR_GLOBAL + (*SilecsHeader/SilecsHeader/hdrBlk *) + _version_a781_SilecsHeader AT %MW0: STRING(16):= DEV; + + (*SilecsHeader/SilecsHeader/hdrBlk *) + _checksum_a781_SilecsHeader AT %MW9: DWORD:= 2843029646; + + (*SilecsHeader/SilecsHeader/hdrBlk *) + _user_a781_SilecsHeader AT %MW11: STRING(16):= 'schwinn'; + + (*SilecsHeader/SilecsHeader/hdrBlk *) + _date_a781_SilecsHeader AT %MW20: DT:= DT#2016-7-14-16:7:52; + + (*AllTypes/testDevice1/MyROBlock *) + RO_int8_a583_testDevice1 AT %MW24: SINT; + + (*AllTypes/testDevice1/MyROBlock *) + RO_uint8_a583_testDevice1 AT %MW25: BYTE; + + (*AllTypes/testDevice1/MyROBlock *) + RO_int16_a583_testDevice1 AT %MW26: INT; + + (*AllTypes/testDevice1/MyROBlock *) + RO_uint16_a583_testDevice1 AT %MW27: WORD; + + (*AllTypes/testDevice1/MyROBlock *) + RO_int32_a583_testDevice1 AT %MW28: DINT; + + (*AllTypes/testDevice1/MyROBlock *) + RO_uint32_a583_testDevice1 AT %MW30: DWORD; + + (*AllTypes/testDevice1/MyROBlock *) + RO_float32_a583_testDevice1 AT %MW32: REAL; + + (*AllTypes/testDevice1/MyROBlock *) + RO_string_a583_testDevice1 AT %MW34: STRING(64); + + (*AllTypes/testDevice1/MyROBlock *) + RO_date_a583_testDevice1 AT %MW67: DT; + + (*AllTypes/testDevice1/MyROBlock *) + RO_char_a583_testDevice1 AT %MW71: SINT; + + (*AllTypes/testDevice1/MyROBlock *) + RO_byte_a583_testDevice1 AT %MW72: BYTE; + + (*AllTypes/testDevice1/MyROBlock *) + RO_word_a583_testDevice1 AT %MW73: WORD; + + (*AllTypes/testDevice1/MyROBlock *) + RO_dword_a583_testDevice1 AT %MW74: DWORD; + + (*AllTypes/testDevice1/MyROBlock *) + RO_int_a583_testDevice1 AT %MW76: INT; + + (*AllTypes/testDevice1/MyROBlock *) + RO_dint_a583_testDevice1 AT %MW77: DINT; + + (*AllTypes/testDevice1/MyROBlock *) + RO_real_a583_testDevice1 AT %MW79: REAL; + + (*AllTypes/testDevice1/MyROBlock *) + RO_dt_a583_testDevice1 AT %MW81: DT; + + (*AllTypes/testDevice2/MyROBlock *) + RO_int8_a583_testDevice2 AT %MW85: SINT; + + (*AllTypes/testDevice2/MyROBlock *) + RO_uint8_a583_testDevice2 AT %MW86: BYTE; + + (*AllTypes/testDevice2/MyROBlock *) + RO_int16_a583_testDevice2 AT %MW87: INT; + + (*AllTypes/testDevice2/MyROBlock *) + RO_uint16_a583_testDevice2 AT %MW88: WORD; + + (*AllTypes/testDevice2/MyROBlock *) + RO_int32_a583_testDevice2 AT %MW89: DINT; + + (*AllTypes/testDevice2/MyROBlock *) + RO_uint32_a583_testDevice2 AT %MW91: DWORD; + + (*AllTypes/testDevice2/MyROBlock *) + RO_float32_a583_testDevice2 AT %MW93: REAL; + + (*AllTypes/testDevice2/MyROBlock *) + RO_string_a583_testDevice2 AT %MW95: STRING(64); + + (*AllTypes/testDevice2/MyROBlock *) + RO_date_a583_testDevice2 AT %MW128: DT; + + (*AllTypes/testDevice2/MyROBlock *) + RO_char_a583_testDevice2 AT %MW132: SINT; + + (*AllTypes/testDevice2/MyROBlock *) + RO_byte_a583_testDevice2 AT %MW133: BYTE; + + (*AllTypes/testDevice2/MyROBlock *) + RO_word_a583_testDevice2 AT %MW134: WORD; + + (*AllTypes/testDevice2/MyROBlock *) + RO_dword_a583_testDevice2 AT %MW135: DWORD; + + (*AllTypes/testDevice2/MyROBlock *) + RO_int_a583_testDevice2 AT %MW137: INT; + + (*AllTypes/testDevice2/MyROBlock *) + RO_dint_a583_testDevice2 AT %MW138: DINT; + + (*AllTypes/testDevice2/MyROBlock *) + RO_real_a583_testDevice2 AT %MW140: REAL; + + (*AllTypes/testDevice2/MyROBlock *) + RO_dt_a583_testDevice2 AT %MW142: DT; + + (*AllTypes/testDevice1/MyRWBlock *) + RW_int8_a583_testDevice1 AT %MW146: ARRAY [0..1, 0..1] OF SINT; + + (*AllTypes/testDevice1/MyRWBlock *) + RW_uint8_a583_testDevice1 AT %MW148: ARRAY [0..1, 0..1] OF BYTE; + + (*AllTypes/testDevice1/MyRWBlock *) + RW_int16_a583_testDevice1 AT %MW150: ARRAY [0..1, 0..1] OF INT; + + (*AllTypes/testDevice1/MyRWBlock *) + RW_uint16_a583_testDevice1 AT %MW154: ARRAY [0..1, 0..1] OF WORD; + + (*AllTypes/testDevice1/MyRWBlock *) + RW_int32_a583_testDevice1 AT %MW158: ARRAY [0..1, 0..1] OF DINT; + + (*AllTypes/testDevice1/MyRWBlock *) + RW_uint32_a583_testDevice1 AT %MW166: ARRAY [0..1, 0..1] OF DWORD; + + (*AllTypes/testDevice1/MyRWBlock *) + RW_float32_a583_testDevice1 AT %MW174: ARRAY [0..1, 0..1] OF REAL; + + (*AllTypes/testDevice1/MyRWBlock *) + RW_string_a583_testDevice1 AT %MW182: ARRAY [0..1, 0..1] OF STRING(64); + + (*AllTypes/testDevice1/MyRWBlock *) + RW_date_a583_testDevice1 AT %MW312: ARRAY [0..1, 0..1] OF DT; + + (*AllTypes/testDevice1/MyRWBlock *) + RW_char_a583_testDevice1 AT %MW328: ARRAY [0..1, 0..1] OF SINT; + + (*AllTypes/testDevice1/MyRWBlock *) + RW_byte_a583_testDevice1 AT %MW330: ARRAY [0..1, 0..1] OF BYTE; + + (*AllTypes/testDevice1/MyRWBlock *) + RW_word_a583_testDevice1 AT %MW332: ARRAY [0..1, 0..1] OF WORD; + + (*AllTypes/testDevice1/MyRWBlock *) + RW_dword_a583_testDevice1 AT %MW336: ARRAY [0..1, 0..1] OF DWORD; + + (*AllTypes/testDevice1/MyRWBlock *) + RW_int_a583_testDevice1 AT %MW344: ARRAY [0..1, 0..1] OF INT; + + (*AllTypes/testDevice1/MyRWBlock *) + RW_dint_a583_testDevice1 AT %MW348: ARRAY [0..1, 0..1] OF DINT; + + (*AllTypes/testDevice1/MyRWBlock *) + RW_real_a583_testDevice1 AT %MW356: ARRAY [0..1, 0..1] OF REAL; + + (*AllTypes/testDevice1/MyRWBlock *) + RW_dt_a583_testDevice1 AT %MW364: ARRAY [0..1, 0..1] OF DT; + + (*AllTypes/testDevice2/MyRWBlock *) + RW_int8_a583_testDevice2 AT %MW380: ARRAY [0..1, 0..1] OF SINT; + + (*AllTypes/testDevice2/MyRWBlock *) + RW_uint8_a583_testDevice2 AT %MW382: ARRAY [0..1, 0..1] OF BYTE; + + (*AllTypes/testDevice2/MyRWBlock *) + RW_int16_a583_testDevice2 AT %MW384: ARRAY [0..1, 0..1] OF INT; + + (*AllTypes/testDevice2/MyRWBlock *) + RW_uint16_a583_testDevice2 AT %MW388: ARRAY [0..1, 0..1] OF WORD; + + (*AllTypes/testDevice2/MyRWBlock *) + RW_int32_a583_testDevice2 AT %MW392: ARRAY [0..1, 0..1] OF DINT; + + (*AllTypes/testDevice2/MyRWBlock *) + RW_uint32_a583_testDevice2 AT %MW400: ARRAY [0..1, 0..1] OF DWORD; + + (*AllTypes/testDevice2/MyRWBlock *) + RW_float32_a583_testDevice2 AT %MW408: ARRAY [0..1, 0..1] OF REAL; + + (*AllTypes/testDevice2/MyRWBlock *) + RW_string_a583_testDevice2 AT %MW416: ARRAY [0..1, 0..1] OF STRING(64); + + (*AllTypes/testDevice2/MyRWBlock *) + RW_date_a583_testDevice2 AT %MW546: ARRAY [0..1, 0..1] OF DT; + + (*AllTypes/testDevice2/MyRWBlock *) + RW_char_a583_testDevice2 AT %MW562: ARRAY [0..1, 0..1] OF SINT; + + (*AllTypes/testDevice2/MyRWBlock *) + RW_byte_a583_testDevice2 AT %MW564: ARRAY [0..1, 0..1] OF BYTE; + + (*AllTypes/testDevice2/MyRWBlock *) + RW_word_a583_testDevice2 AT %MW566: ARRAY [0..1, 0..1] OF WORD; + + (*AllTypes/testDevice2/MyRWBlock *) + RW_dword_a583_testDevice2 AT %MW570: ARRAY [0..1, 0..1] OF DWORD; + + (*AllTypes/testDevice2/MyRWBlock *) + RW_int_a583_testDevice2 AT %MW578: ARRAY [0..1, 0..1] OF INT; + + (*AllTypes/testDevice2/MyRWBlock *) + RW_dint_a583_testDevice2 AT %MW582: ARRAY [0..1, 0..1] OF DINT; + + (*AllTypes/testDevice2/MyRWBlock *) + RW_real_a583_testDevice2 AT %MW590: ARRAY [0..1, 0..1] OF REAL; + + (*AllTypes/testDevice2/MyRWBlock *) + RW_dt_a583_testDevice2 AT %MW598: ARRAY [0..1, 0..1] OF DT; + + (*AllTypes/testDevice1/MyWOBlock *) + WO_int8_a583_testDevice1 AT %MW614: ARRAY [0..9] OF SINT; + + (*AllTypes/testDevice1/MyWOBlock *) + WO_uint8_a583_testDevice1 AT %MW619: ARRAY [0..9] OF BYTE; + + (*AllTypes/testDevice1/MyWOBlock *) + WO_int16_a583_testDevice1 AT %MW624: ARRAY [0..9] OF INT; + + (*AllTypes/testDevice1/MyWOBlock *) + WO_uint16_a583_testDevice1 AT %MW634: ARRAY [0..9] OF WORD; + + (*AllTypes/testDevice1/MyWOBlock *) + WO_int32_a583_testDevice1 AT %MW644: ARRAY [0..9] OF DINT; + + (*AllTypes/testDevice1/MyWOBlock *) + WO_uint32_a583_testDevice1 AT %MW664: ARRAY [0..9] OF DWORD; + + (*AllTypes/testDevice1/MyWOBlock *) + WO_float32_a583_testDevice1 AT %MW684: ARRAY [0..9] OF REAL; + + (*AllTypes/testDevice1/MyWOBlock *) + WO_string_a583_testDevice1 AT %MW704: ARRAY [0..9] OF STRING(64); + + (*AllTypes/testDevice1/MyWOBlock *) + WO_date_a583_testDevice1 AT %MW1029: ARRAY [0..9] OF DT; + + (*AllTypes/testDevice1/MyWOBlock *) + WO_char_a583_testDevice1 AT %MW1069: ARRAY [0..9] OF SINT; + + (*AllTypes/testDevice1/MyWOBlock *) + WO_byte_a583_testDevice1 AT %MW1074: ARRAY [0..9] OF BYTE; + + (*AllTypes/testDevice1/MyWOBlock *) + WO_word_a583_testDevice1 AT %MW1079: ARRAY [0..9] OF WORD; + + (*AllTypes/testDevice1/MyWOBlock *) + WO_dword_a583_testDevice1 AT %MW1089: ARRAY [0..9] OF DWORD; + + (*AllTypes/testDevice1/MyWOBlock *) + WO_int_a583_testDevice1 AT %MW1109: ARRAY [0..9] OF INT; + + (*AllTypes/testDevice1/MyWOBlock *) + WO_dint_a583_testDevice1 AT %MW1119: ARRAY [0..9] OF DINT; + + (*AllTypes/testDevice1/MyWOBlock *) + WO_real_a583_testDevice1 AT %MW1139: ARRAY [0..9] OF REAL; + + (*AllTypes/testDevice1/MyWOBlock *) + WO_dt_a583_testDevice1 AT %MW1159: ARRAY [0..9] OF DT; + + (*AllTypes/testDevice2/MyWOBlock *) + WO_int8_a583_testDevice2 AT %MW1199: ARRAY [0..9] OF SINT; + + (*AllTypes/testDevice2/MyWOBlock *) + WO_uint8_a583_testDevice2 AT %MW1204: ARRAY [0..9] OF BYTE; + + (*AllTypes/testDevice2/MyWOBlock *) + WO_int16_a583_testDevice2 AT %MW1209: ARRAY [0..9] OF INT; + + (*AllTypes/testDevice2/MyWOBlock *) + WO_uint16_a583_testDevice2 AT %MW1219: ARRAY [0..9] OF WORD; + + (*AllTypes/testDevice2/MyWOBlock *) + WO_int32_a583_testDevice2 AT %MW1229: ARRAY [0..9] OF DINT; + + (*AllTypes/testDevice2/MyWOBlock *) + WO_uint32_a583_testDevice2 AT %MW1249: ARRAY [0..9] OF DWORD; + + (*AllTypes/testDevice2/MyWOBlock *) + WO_float32_a583_testDevice2 AT %MW1269: ARRAY [0..9] OF REAL; + + (*AllTypes/testDevice2/MyWOBlock *) + WO_string_a583_testDevice2 AT %MW1289: ARRAY [0..9] OF STRING(64); + + (*AllTypes/testDevice2/MyWOBlock *) + WO_date_a583_testDevice2 AT %MW1614: ARRAY [0..9] OF DT; + + (*AllTypes/testDevice2/MyWOBlock *) + WO_char_a583_testDevice2 AT %MW1654: ARRAY [0..9] OF SINT; + + (*AllTypes/testDevice2/MyWOBlock *) + WO_byte_a583_testDevice2 AT %MW1659: ARRAY [0..9] OF BYTE; + + (*AllTypes/testDevice2/MyWOBlock *) + WO_word_a583_testDevice2 AT %MW1664: ARRAY [0..9] OF WORD; + + (*AllTypes/testDevice2/MyWOBlock *) + WO_dword_a583_testDevice2 AT %MW1674: ARRAY [0..9] OF DWORD; + + (*AllTypes/testDevice2/MyWOBlock *) + WO_int_a583_testDevice2 AT %MW1694: ARRAY [0..9] OF INT; + + (*AllTypes/testDevice2/MyWOBlock *) + WO_dint_a583_testDevice2 AT %MW1704: ARRAY [0..9] OF DINT; + + (*AllTypes/testDevice2/MyWOBlock *) + WO_real_a583_testDevice2 AT %MW1724: ARRAY [0..9] OF REAL; + + (*AllTypes/testDevice2/MyWOBlock *) + WO_dt_a583_testDevice2 AT %MW1744: ARRAY [0..9] OF DT; + +END_VAR \ No newline at end of file diff --git a/silecs-codegen/src/xml/test/generated_correct/controller/Beckhoff_CX9020.exp b/silecs-codegen/src/xml/test/generated_correct/controller/Beckhoff_CX9020.exp new file mode 100644 index 0000000..c05bd13 --- /dev/null +++ b/silecs-codegen/src/xml/test/generated_correct/controller/Beckhoff_CX9020.exp @@ -0,0 +1,328 @@ +(* +------------------------------------------------------------------- +* | C.E.R.N Geneva, Switzerland +* | SILECS - BE/CO-FE +* | April 2015 +* +------------------------------------------------------------------- +* +* Release : SILECS_DEV +*) +VAR_GLOBAL + (*SilecsHeader/SilecsHeader/hdrBlk *) + _version_a781_SilecsHeader AT %MW0: STRING(16):= DEV; + + (*SilecsHeader/SilecsHeader/hdrBlk *) + _checksum_a781_SilecsHeader AT %MW20: DWORD:= 427563505; + + (*SilecsHeader/SilecsHeader/hdrBlk *) + _user_a781_SilecsHeader AT %MW24: STRING(16):= 'schwinn'; + + (*SilecsHeader/SilecsHeader/hdrBlk *) + _date_a781_SilecsHeader AT %MW44: DT:= DT#2016-7-14-16:8:13; + + (*AllTypes/testDevice1/MyROBlock *) + RO_int8_a583_testDevice1 AT %MW52: SINT; + + (*AllTypes/testDevice1/MyROBlock *) + RO_uint8_a583_testDevice1 AT %MW54: BYTE; + + (*AllTypes/testDevice1/MyROBlock *) + RO_int16_a583_testDevice1 AT %MW56: INT; + + (*AllTypes/testDevice1/MyROBlock *) + RO_uint16_a583_testDevice1 AT %MW58: WORD; + + (*AllTypes/testDevice1/MyROBlock *) + RO_int32_a583_testDevice1 AT %MW60: DINT; + + (*AllTypes/testDevice1/MyROBlock *) + RO_uint32_a583_testDevice1 AT %MW64: DWORD; + + (*AllTypes/testDevice1/MyROBlock *) + RO_float32_a583_testDevice1 AT %MW68: REAL; + + (*AllTypes/testDevice1/MyROBlock *) + RO_string_a583_testDevice1 AT %MW72: STRING(64); + + (*AllTypes/testDevice1/MyROBlock *) + RO_date_a583_testDevice1 AT %MW140: DT; + + (*AllTypes/testDevice1/MyROBlock *) + RO_char_a583_testDevice1 AT %MW148: SINT; + + (*AllTypes/testDevice1/MyROBlock *) + RO_byte_a583_testDevice1 AT %MW150: BYTE; + + (*AllTypes/testDevice1/MyROBlock *) + RO_word_a583_testDevice1 AT %MW152: WORD; + + (*AllTypes/testDevice1/MyROBlock *) + RO_dword_a583_testDevice1 AT %MW156: DWORD; + + (*AllTypes/testDevice1/MyROBlock *) + RO_int_a583_testDevice1 AT %MW160: INT; + + (*AllTypes/testDevice1/MyROBlock *) + RO_dint_a583_testDevice1 AT %MW164: DINT; + + (*AllTypes/testDevice1/MyROBlock *) + RO_real_a583_testDevice1 AT %MW168: REAL; + + (*AllTypes/testDevice1/MyROBlock *) + RO_dt_a583_testDevice1 AT %MW172: DT; + + (*AllTypes/testDevice2/MyROBlock *) + RO_int8_a583_testDevice2 AT %MW180: SINT; + + (*AllTypes/testDevice2/MyROBlock *) + RO_uint8_a583_testDevice2 AT %MW182: BYTE; + + (*AllTypes/testDevice2/MyROBlock *) + RO_int16_a583_testDevice2 AT %MW184: INT; + + (*AllTypes/testDevice2/MyROBlock *) + RO_uint16_a583_testDevice2 AT %MW186: WORD; + + (*AllTypes/testDevice2/MyROBlock *) + RO_int32_a583_testDevice2 AT %MW188: DINT; + + (*AllTypes/testDevice2/MyROBlock *) + RO_uint32_a583_testDevice2 AT %MW192: DWORD; + + (*AllTypes/testDevice2/MyROBlock *) + RO_float32_a583_testDevice2 AT %MW196: REAL; + + (*AllTypes/testDevice2/MyROBlock *) + RO_string_a583_testDevice2 AT %MW200: STRING(64); + + (*AllTypes/testDevice2/MyROBlock *) + RO_date_a583_testDevice2 AT %MW268: DT; + + (*AllTypes/testDevice2/MyROBlock *) + RO_char_a583_testDevice2 AT %MW276: SINT; + + (*AllTypes/testDevice2/MyROBlock *) + RO_byte_a583_testDevice2 AT %MW278: BYTE; + + (*AllTypes/testDevice2/MyROBlock *) + RO_word_a583_testDevice2 AT %MW280: WORD; + + (*AllTypes/testDevice2/MyROBlock *) + RO_dword_a583_testDevice2 AT %MW284: DWORD; + + (*AllTypes/testDevice2/MyROBlock *) + RO_int_a583_testDevice2 AT %MW288: INT; + + (*AllTypes/testDevice2/MyROBlock *) + RO_dint_a583_testDevice2 AT %MW292: DINT; + + (*AllTypes/testDevice2/MyROBlock *) + RO_real_a583_testDevice2 AT %MW296: REAL; + + (*AllTypes/testDevice2/MyROBlock *) + RO_dt_a583_testDevice2 AT %MW300: DT; + + (*AllTypes/testDevice1/MyRWBlock *) + RW_int8_a583_testDevice1 AT %MW308: ARRAY [0..1, 0..1] OF SINT; + + (*AllTypes/testDevice1/MyRWBlock *) + RW_uint8_a583_testDevice1 AT %MW312: ARRAY [0..1, 0..1] OF BYTE; + + (*AllTypes/testDevice1/MyRWBlock *) + RW_int16_a583_testDevice1 AT %MW316: ARRAY [0..1, 0..1] OF INT; + + (*AllTypes/testDevice1/MyRWBlock *) + RW_uint16_a583_testDevice1 AT %MW324: ARRAY [0..1, 0..1] OF WORD; + + (*AllTypes/testDevice1/MyRWBlock *) + RW_int32_a583_testDevice1 AT %MW332: ARRAY [0..1, 0..1] OF DINT; + + (*AllTypes/testDevice1/MyRWBlock *) + RW_uint32_a583_testDevice1 AT %MW348: ARRAY [0..1, 0..1] OF DWORD; + + (*AllTypes/testDevice1/MyRWBlock *) + RW_float32_a583_testDevice1 AT %MW364: ARRAY [0..1, 0..1] OF REAL; + + (*AllTypes/testDevice1/MyRWBlock *) + RW_string_a583_testDevice1 AT %MW380: ARRAY [0..1, 0..1] OF STRING(64); + + (*AllTypes/testDevice1/MyRWBlock *) + RW_date_a583_testDevice1 AT %MW640: ARRAY [0..1, 0..1] OF DT; + + (*AllTypes/testDevice1/MyRWBlock *) + RW_char_a583_testDevice1 AT %MW672: ARRAY [0..1, 0..1] OF SINT; + + (*AllTypes/testDevice1/MyRWBlock *) + RW_byte_a583_testDevice1 AT %MW676: ARRAY [0..1, 0..1] OF BYTE; + + (*AllTypes/testDevice1/MyRWBlock *) + RW_word_a583_testDevice1 AT %MW680: ARRAY [0..1, 0..1] OF WORD; + + (*AllTypes/testDevice1/MyRWBlock *) + RW_dword_a583_testDevice1 AT %MW688: ARRAY [0..1, 0..1] OF DWORD; + + (*AllTypes/testDevice1/MyRWBlock *) + RW_int_a583_testDevice1 AT %MW704: ARRAY [0..1, 0..1] OF INT; + + (*AllTypes/testDevice1/MyRWBlock *) + RW_dint_a583_testDevice1 AT %MW712: ARRAY [0..1, 0..1] OF DINT; + + (*AllTypes/testDevice1/MyRWBlock *) + RW_real_a583_testDevice1 AT %MW728: ARRAY [0..1, 0..1] OF REAL; + + (*AllTypes/testDevice1/MyRWBlock *) + RW_dt_a583_testDevice1 AT %MW744: ARRAY [0..1, 0..1] OF DT; + + (*AllTypes/testDevice2/MyRWBlock *) + RW_int8_a583_testDevice2 AT %MW776: ARRAY [0..1, 0..1] OF SINT; + + (*AllTypes/testDevice2/MyRWBlock *) + RW_uint8_a583_testDevice2 AT %MW780: ARRAY [0..1, 0..1] OF BYTE; + + (*AllTypes/testDevice2/MyRWBlock *) + RW_int16_a583_testDevice2 AT %MW784: ARRAY [0..1, 0..1] OF INT; + + (*AllTypes/testDevice2/MyRWBlock *) + RW_uint16_a583_testDevice2 AT %MW792: ARRAY [0..1, 0..1] OF WORD; + + (*AllTypes/testDevice2/MyRWBlock *) + RW_int32_a583_testDevice2 AT %MW800: ARRAY [0..1, 0..1] OF DINT; + + (*AllTypes/testDevice2/MyRWBlock *) + RW_uint32_a583_testDevice2 AT %MW816: ARRAY [0..1, 0..1] OF DWORD; + + (*AllTypes/testDevice2/MyRWBlock *) + RW_float32_a583_testDevice2 AT %MW832: ARRAY [0..1, 0..1] OF REAL; + + (*AllTypes/testDevice2/MyRWBlock *) + RW_string_a583_testDevice2 AT %MW848: ARRAY [0..1, 0..1] OF STRING(64); + + (*AllTypes/testDevice2/MyRWBlock *) + RW_date_a583_testDevice2 AT %MW1108: ARRAY [0..1, 0..1] OF DT; + + (*AllTypes/testDevice2/MyRWBlock *) + RW_char_a583_testDevice2 AT %MW1140: ARRAY [0..1, 0..1] OF SINT; + + (*AllTypes/testDevice2/MyRWBlock *) + RW_byte_a583_testDevice2 AT %MW1144: ARRAY [0..1, 0..1] OF BYTE; + + (*AllTypes/testDevice2/MyRWBlock *) + RW_word_a583_testDevice2 AT %MW1148: ARRAY [0..1, 0..1] OF WORD; + + (*AllTypes/testDevice2/MyRWBlock *) + RW_dword_a583_testDevice2 AT %MW1156: ARRAY [0..1, 0..1] OF DWORD; + + (*AllTypes/testDevice2/MyRWBlock *) + RW_int_a583_testDevice2 AT %MW1172: ARRAY [0..1, 0..1] OF INT; + + (*AllTypes/testDevice2/MyRWBlock *) + RW_dint_a583_testDevice2 AT %MW1180: ARRAY [0..1, 0..1] OF DINT; + + (*AllTypes/testDevice2/MyRWBlock *) + RW_real_a583_testDevice2 AT %MW1196: ARRAY [0..1, 0..1] OF REAL; + + (*AllTypes/testDevice2/MyRWBlock *) + RW_dt_a583_testDevice2 AT %MW1212: ARRAY [0..1, 0..1] OF DT; + + (*AllTypes/testDevice1/MyWOBlock *) + WO_int8_a583_testDevice1 AT %MW1244: ARRAY [0..9] OF SINT; + + (*AllTypes/testDevice1/MyWOBlock *) + WO_uint8_a583_testDevice1 AT %MW1254: ARRAY [0..9] OF BYTE; + + (*AllTypes/testDevice1/MyWOBlock *) + WO_int16_a583_testDevice1 AT %MW1264: ARRAY [0..9] OF INT; + + (*AllTypes/testDevice1/MyWOBlock *) + WO_uint16_a583_testDevice1 AT %MW1284: ARRAY [0..9] OF WORD; + + (*AllTypes/testDevice1/MyWOBlock *) + WO_int32_a583_testDevice1 AT %MW1304: ARRAY [0..9] OF DINT; + + (*AllTypes/testDevice1/MyWOBlock *) + WO_uint32_a583_testDevice1 AT %MW1344: ARRAY [0..9] OF DWORD; + + (*AllTypes/testDevice1/MyWOBlock *) + WO_float32_a583_testDevice1 AT %MW1384: ARRAY [0..9] OF REAL; + + (*AllTypes/testDevice1/MyWOBlock *) + WO_string_a583_testDevice1 AT %MW1424: ARRAY [0..9] OF STRING(64); + + (*AllTypes/testDevice1/MyWOBlock *) + WO_date_a583_testDevice1 AT %MW2076: ARRAY [0..9] OF DT; + + (*AllTypes/testDevice1/MyWOBlock *) + WO_char_a583_testDevice1 AT %MW2156: ARRAY [0..9] OF SINT; + + (*AllTypes/testDevice1/MyWOBlock *) + WO_byte_a583_testDevice1 AT %MW2166: ARRAY [0..9] OF BYTE; + + (*AllTypes/testDevice1/MyWOBlock *) + WO_word_a583_testDevice1 AT %MW2176: ARRAY [0..9] OF WORD; + + (*AllTypes/testDevice1/MyWOBlock *) + WO_dword_a583_testDevice1 AT %MW2196: ARRAY [0..9] OF DWORD; + + (*AllTypes/testDevice1/MyWOBlock *) + WO_int_a583_testDevice1 AT %MW2236: ARRAY [0..9] OF INT; + + (*AllTypes/testDevice1/MyWOBlock *) + WO_dint_a583_testDevice1 AT %MW2256: ARRAY [0..9] OF DINT; + + (*AllTypes/testDevice1/MyWOBlock *) + WO_real_a583_testDevice1 AT %MW2296: ARRAY [0..9] OF REAL; + + (*AllTypes/testDevice1/MyWOBlock *) + WO_dt_a583_testDevice1 AT %MW2336: ARRAY [0..9] OF DT; + + (*AllTypes/testDevice2/MyWOBlock *) + WO_int8_a583_testDevice2 AT %MW2416: ARRAY [0..9] OF SINT; + + (*AllTypes/testDevice2/MyWOBlock *) + WO_uint8_a583_testDevice2 AT %MW2426: ARRAY [0..9] OF BYTE; + + (*AllTypes/testDevice2/MyWOBlock *) + WO_int16_a583_testDevice2 AT %MW2436: ARRAY [0..9] OF INT; + + (*AllTypes/testDevice2/MyWOBlock *) + WO_uint16_a583_testDevice2 AT %MW2456: ARRAY [0..9] OF WORD; + + (*AllTypes/testDevice2/MyWOBlock *) + WO_int32_a583_testDevice2 AT %MW2476: ARRAY [0..9] OF DINT; + + (*AllTypes/testDevice2/MyWOBlock *) + WO_uint32_a583_testDevice2 AT %MW2516: ARRAY [0..9] OF DWORD; + + (*AllTypes/testDevice2/MyWOBlock *) + WO_float32_a583_testDevice2 AT %MW2556: ARRAY [0..9] OF REAL; + + (*AllTypes/testDevice2/MyWOBlock *) + WO_string_a583_testDevice2 AT %MW2596: ARRAY [0..9] OF STRING(64); + + (*AllTypes/testDevice2/MyWOBlock *) + WO_date_a583_testDevice2 AT %MW3248: ARRAY [0..9] OF DT; + + (*AllTypes/testDevice2/MyWOBlock *) + WO_char_a583_testDevice2 AT %MW3328: ARRAY [0..9] OF SINT; + + (*AllTypes/testDevice2/MyWOBlock *) + WO_byte_a583_testDevice2 AT %MW3338: ARRAY [0..9] OF BYTE; + + (*AllTypes/testDevice2/MyWOBlock *) + WO_word_a583_testDevice2 AT %MW3348: ARRAY [0..9] OF WORD; + + (*AllTypes/testDevice2/MyWOBlock *) + WO_dword_a583_testDevice2 AT %MW3368: ARRAY [0..9] OF DWORD; + + (*AllTypes/testDevice2/MyWOBlock *) + WO_int_a583_testDevice2 AT %MW3408: ARRAY [0..9] OF INT; + + (*AllTypes/testDevice2/MyWOBlock *) + WO_dint_a583_testDevice2 AT %MW3428: ARRAY [0..9] OF DINT; + + (*AllTypes/testDevice2/MyWOBlock *) + WO_real_a583_testDevice2 AT %MW3468: ARRAY [0..9] OF REAL; + + (*AllTypes/testDevice2/MyWOBlock *) + WO_dt_a583_testDevice2 AT %MW3508: ARRAY [0..9] OF DT; + +END_VAR \ No newline at end of file diff --git a/silecs-codegen/src/xml/test/generated_correct/controller/Rabbit_BlockMode.h b/silecs-codegen/src/xml/test/generated_correct/controller/Rabbit_BlockMode.h new file mode 100644 index 0000000..51ea994 --- /dev/null +++ b/silecs-codegen/src/xml/test/generated_correct/controller/Rabbit_BlockMode.h @@ -0,0 +1,202 @@ + +/* +------------------------------------------------------------------- + * | Copyright CERN 2015 + * | SILECS - BE/CO-SRC + * | April 2015 + * +------------------------------------------------------------------- + * + * Release : SILECS_DEV + * + * The following code has been automatically generated by SILECS. + * + * N.B: This file relies on the existence of explicit C data type such + * as int8_t, uint8_t, int16_t, etc.... + * If your compiler does not support them natively please implement + * them by including the data type definition provided on the SILECS + * web page before including this header file. + */ + +#define MODBUS_START_ADDRESS 0 + +/*--------------------------------------------------------------------- + * DT + * data type definition and related utilities + *--------------------------------------------------------------------- + */ + +typedef struct +{ + uint8_t sc_100; // second cent + uint8_t sc; // second + uint8_t mn; // minute + uint8_t hh; // hour + uint8_t dd; // day + uint8_t mm; // month + uint8_t yy1; // year + uint8_t yy2; // year2 +} dt; + +#define _frombcd(a) (int)(((a>>4)*10)+(a&0x0F)) +#define _tobcd(a) (((unsigned char)((a)/10)<<4)+((a)%10)) + +void SILECS_set_dt(int8_t sc_100 ,int8_t sc, int8_t mn,int8_t hh,int8_t dd,int8_t mm,int32_t yy, dt *date) +{ + date->sc_100 = sc_100; + date->sc = _tobcd(sc); + date->mn = _tobcd(mn); + date->hh = _tobcd(hh); + date->dd = _tobcd(dd); + date->mm = _tobcd(mm); + date->yy2 = _tobcd((int8_t)(yy/100)); + date->yy1 = _tobcd((int8_t)(yy%100)); +} + + +/*--------------------------------------------------------------------- + * SilecsHeader / v1.0.0 + * BLOCK Type definition + *--------------------------------------------------------------------- + */ + +typedef struct +{ + uint8_t _version[16]; + uint32_t _checksum; + uint8_t _user[16]; + dt _date; + +} _SilecsHeader_hdrBlk; + +/*--------------------------------------------------------------------- + * AllTypes / v0.1.0 + * BLOCK Type definition + *--------------------------------------------------------------------- + */ + +typedef struct +{ + int16_t RO_int8; + uint16_t RO_uint8; + int16_t RO_int16; + uint16_t RO_uint16; + int32_t RO_int32; + uint32_t RO_uint32; + float RO_float32; + uint8_t RO_string[64]; + dt RO_date; + int16_t RO_char; + uint16_t RO_byte; + uint16_t RO_word; + uint32_t RO_dword; + int16_t RO_int; + int32_t RO_dint; + float RO_real; + dt RO_dt; + +} _AllTypes_MyROBlock; + +typedef struct +{ + int16_t RW_int8[2][2]; + uint16_t RW_uint8[2][2]; + int16_t RW_int16[2][2]; + uint16_t RW_uint16[2][2]; + int32_t RW_int32[2][2]; + uint32_t RW_uint32[2][2]; + float RW_float32[2][2]; + uint8_t RW_string[2][2][64]; + dt RW_date[2][2]; + int16_t RW_char[2][2]; + uint16_t RW_byte[2][2]; + uint16_t RW_word[2][2]; + uint32_t RW_dword[2][2]; + int16_t RW_int[2][2]; + int32_t RW_dint[2][2]; + float RW_real[2][2]; + dt RW_dt[2][2]; + +} _AllTypes_MyRWBlock; + +typedef struct +{ + int16_t WO_int8[10]; + uint16_t WO_uint8[10]; + int16_t WO_int16[10]; + uint16_t WO_uint16[10]; + int32_t WO_int32[10]; + uint32_t WO_uint32[10]; + float WO_float32[10]; + uint8_t WO_string[10][64]; + dt WO_date[10]; + int16_t WO_char[10]; + uint16_t WO_byte[10]; + uint16_t WO_word[10]; + uint32_t WO_dword[10]; + int16_t WO_int[10]; + int32_t WO_dint[10]; + float WO_real[10]; + dt WO_dt[10]; + +} _AllTypes_MyWOBlock; + +/*--------------------------------------------------------------------- + * MEMORY ALLOCATION + * PROTOCOL: BLOCK_MODE + *--------------------------------------------------------------------- + */ + +typedef struct { + + struct { + _SilecsHeader_hdrBlk SilecsHeader; + } SilecsHeader_hdrBlk; + + struct { + _AllTypes_MyROBlock testDevice1; + _AllTypes_MyROBlock testDevice2; + } AllTypes_MyROBlock; + + struct { + _AllTypes_MyRWBlock testDevice1; + _AllTypes_MyRWBlock testDevice2; + } AllTypes_MyRWBlock; + + struct { + _AllTypes_MyWOBlock testDevice1; + _AllTypes_MyWOBlock testDevice2; + } AllTypes_MyWOBlock; + +} _SILECS_DATA_SEGMENT; + +#define SILECS_DATA_SEGMENT_MODBUS_SIZE (sizeof(_SILECS_DATA_SEGMENT)/2) + +union modbus_data { + _SILECS_DATA_SEGMENT data; + uint16_t array[SILECS_DATA_SEGMENT_MODBUS_SIZE]; +} silecsData; + + +/* Initialization function */ +int SILECS_init() +{ + /* Silecs version initialization */ + strcpy((unsigned char *)silecsData.data.SilecsHeader_hdrBlk.device[0]._version, "SILECS_DEV"); + + /* Silecs checksum initialization */ + silecsData.data.SilecsHeader_hdrBlk.device[0]._checksum = 3940683809; + + /* Silecs user initialization */ + strcpy((unsigned char *)silecsData.data.SilecsHeader_hdrBlk.device[0]._user, "schwinn"); + + /* Silecs date initialization */ + SILECS_set_dt(3,48,8,16,14,7,2016,&silecsData.data.SilecsHeader_hdrBlk.device[0]._date); +} + +/* + * Automatically generated Addressing example + * + * This example shows how to address the register WO_dt of block MyWOBlock + * of device testDevice2 of the class AllTypes + * + * silecsData.AllTypes_MyWOBlock.testDevice2.WO_dt = ....; + */ \ No newline at end of file diff --git a/silecs-codegen/src/xml/test/generated_correct/controller/Rabbit_DeviceMode.h b/silecs-codegen/src/xml/test/generated_correct/controller/Rabbit_DeviceMode.h new file mode 100644 index 0000000..d382f9d --- /dev/null +++ b/silecs-codegen/src/xml/test/generated_correct/controller/Rabbit_DeviceMode.h @@ -0,0 +1,195 @@ + +/* +------------------------------------------------------------------- + * | Copyright CERN 2015 + * | SILECS - BE/CO-SRC + * | April 2015 + * +------------------------------------------------------------------- + * + * Release : SILECS_DEV + * + * The following code has been automatically generated by SILECS. + * + * N.B: This file relies on the existence of explicit C data type such + * as int8_t, uint8_t, int16_t, etc.... + * If your compiler does not support them natively please implement + * them by including the data type definition provided on the SILECS + * web page before including this header file. + */ + +#define MODBUS_START_ADDRESS 0 + +/*--------------------------------------------------------------------- + * DT + * data type definition and related utilities + *--------------------------------------------------------------------- + */ + +typedef struct +{ + uint8_t sc_100; // second cent + uint8_t sc; // second + uint8_t mn; // minute + uint8_t hh; // hour + uint8_t dd; // day + uint8_t mm; // month + uint8_t yy1; // year + uint8_t yy2; // year2 +} dt; + +#define _frombcd(a) (int)(((a>>4)*10)+(a&0x0F)) +#define _tobcd(a) (((unsigned char)((a)/10)<<4)+((a)%10)) + +void SILECS_set_dt(int8_t sc_100 ,int8_t sc, int8_t mn,int8_t hh,int8_t dd,int8_t mm,int32_t yy, dt *date) +{ + date->sc_100 = sc_100; + date->sc = _tobcd(sc); + date->mn = _tobcd(mn); + date->hh = _tobcd(hh); + date->dd = _tobcd(dd); + date->mm = _tobcd(mm); + date->yy2 = _tobcd((int8_t)(yy/100)); + date->yy1 = _tobcd((int8_t)(yy%100)); +} + + +/*--------------------------------------------------------------------- + * SilecsHeader / v1.0.0 + * BLOCK Type definition + *--------------------------------------------------------------------- + */ + +typedef struct +{ + uint8_t _version[16]; + uint32_t _checksum; + uint8_t _user[16]; + dt _date; + +} _SilecsHeader_hdrBlk; + +/*--------------------------------------------------------------------- + * AllTypes / v0.1.0 + * BLOCK Type definition + *--------------------------------------------------------------------- + */ + +typedef struct +{ + int16_t RO_int8; + uint16_t RO_uint8; + int16_t RO_int16; + uint16_t RO_uint16; + int32_t RO_int32; + uint32_t RO_uint32; + float RO_float32; + uint8_t RO_string[64]; + dt RO_date; + int16_t RO_char; + uint16_t RO_byte; + uint16_t RO_word; + uint32_t RO_dword; + int16_t RO_int; + int32_t RO_dint; + float RO_real; + dt RO_dt; + +} _AllTypes_MyROBlock; + +typedef struct +{ + int16_t RW_int8[2][2]; + uint16_t RW_uint8[2][2]; + int16_t RW_int16[2][2]; + uint16_t RW_uint16[2][2]; + int32_t RW_int32[2][2]; + uint32_t RW_uint32[2][2]; + float RW_float32[2][2]; + uint8_t RW_string[2][2][64]; + dt RW_date[2][2]; + int16_t RW_char[2][2]; + uint16_t RW_byte[2][2]; + uint16_t RW_word[2][2]; + uint32_t RW_dword[2][2]; + int16_t RW_int[2][2]; + int32_t RW_dint[2][2]; + float RW_real[2][2]; + dt RW_dt[2][2]; + +} _AllTypes_MyRWBlock; + +typedef struct +{ + int16_t WO_int8[10]; + uint16_t WO_uint8[10]; + int16_t WO_int16[10]; + uint16_t WO_uint16[10]; + int32_t WO_int32[10]; + uint32_t WO_uint32[10]; + float WO_float32[10]; + uint8_t WO_string[10][64]; + dt WO_date[10]; + int16_t WO_char[10]; + uint16_t WO_byte[10]; + uint16_t WO_word[10]; + uint32_t WO_dword[10]; + int16_t WO_int[10]; + int32_t WO_dint[10]; + float WO_real[10]; + dt WO_dt[10]; + +} _AllTypes_MyWOBlock; + +/*--------------------------------------------------------------------- + * MEMORY ALLOCATION + * PROTOCOL: DEVICE_MODE + *--------------------------------------------------------------------- + */ + +typedef struct { + + struct { + _SilecsHeader_hdrBlk hdrBlk; + + } SilecsHeader_SilecsHeader; + + struct { + _AllTypes_MyROBlock MyROBlock; + _AllTypes_MyRWBlock MyRWBlock; + _AllTypes_MyWOBlock MyWOBlock; + + } AllTypes_testDevice1, AllTypes_testDevice2; + +} _SILECS_DATA_SEGMENT; + +#define SILECS_DATA_SEGMENT_MODBUS_SIZE (sizeof(_SILECS_DATA_SEGMENT)/2) + +union silecsData { + _SILECS_DATA_SEGMENT data; + uint16_t array[SILECS_DATA_SEGMENT_MODBUS_SIZE]; +} silecsData; + + +/* Initialization function */ +int SILECS_init() +{ + /* Silecs version initialization */ + strcpy((unsigned char *)silecsData.data.SilecsHeader_device[0].hdrBlk._version, "SILECS_DEV"); + + /* Silecs checksum initialization */ + silecsData.data.SilecsHeader_device[0].hdrBlk._checksum = 3940683809; + + /* Silecs user initialization */ + strcpy((unsigned char *)silecsData.data.SilecsHeader_device[0].hdrBlk._user, "schwinn"); + + /* Silecs date initialization */ + SILECS_set_dt(3,0,9,16,14,7,2016,&silecsData.data.SilecsHeader_device[0].hdrBlk._date); +} + +/* + * Automatically generated Addressing example + * + * This example shows how to address the register WO_dt of block MyWOBlock + * of device AllTypes_testDevice2 of the class AllTypes + * + * silecsData.AllTypes_AllTypes_testDevice2.MyWOBlock.WO_dt = ....; + */ \ No newline at end of file diff --git a/silecs-codegen/src/xml/test/generated_correct/controller/Schneider_M340.xsy b/silecs-codegen/src/xml/test/generated_correct/controller/Schneider_M340.xsy new file mode 100644 index 0000000..5806075 --- /dev/null +++ b/silecs-codegen/src/xml/test/generated_correct/controller/Schneider_M340.xsy @@ -0,0 +1,326 @@ +<VariablesExchangeFile> + <dataBlock> + <variables name="_version_a781_SilecsHeader" typeName="STRING[16]" topologicalAddress="%MW0"> + <variableInit value="DEV"/> + <comment>SilecsHeader/SilecsHeader/hdrBlk</comment> + </variables> + <variables name="_checksum_a781_SilecsHeader" typeName="DWORD" topologicalAddress="%MW8"> + <variableInit value="3940683809"/> + <comment>SilecsHeader/SilecsHeader/hdrBlk</comment> + </variables> + <variables name="_user_a781_SilecsHeader" typeName="STRING[16]" topologicalAddress="%MW10"> + <variableInit value="schwinn"/> + <comment>SilecsHeader/SilecsHeader/hdrBlk</comment> + </variables> + <variables name="_date_a781_SilecsHeader" typeName="DT" topologicalAddress="%MW18"> + <variableInit value="DT#2016-7-14-16:8:24"/> + <comment>SilecsHeader/SilecsHeader/hdrBlk</comment> + </variables> + <variables name="RO_int8_a583_testDevice1" typeName="WORD" topologicalAddress="%MW22"> + <comment>AllTypes/testDevice1/MyROBlock</comment> + </variables> + <variables name="RO_uint8_a583_testDevice1" typeName="BYTE" topologicalAddress="%MW23"> + <comment>AllTypes/testDevice1/MyROBlock</comment> + </variables> + <variables name="RO_int16_a583_testDevice1" typeName="INT" topologicalAddress="%MW24"> + <comment>AllTypes/testDevice1/MyROBlock</comment> + </variables> + <variables name="RO_uint16_a583_testDevice1" typeName="WORD" topologicalAddress="%MW25"> + <comment>AllTypes/testDevice1/MyROBlock</comment> + </variables> + <variables name="RO_int32_a583_testDevice1" typeName="DINT" topologicalAddress="%MW26"> + <comment>AllTypes/testDevice1/MyROBlock</comment> + </variables> + <variables name="RO_uint32_a583_testDevice1" typeName="DWORD" topologicalAddress="%MW28"> + <comment>AllTypes/testDevice1/MyROBlock</comment> + </variables> + <variables name="RO_float32_a583_testDevice1" typeName="REAL" topologicalAddress="%MW30"> + <comment>AllTypes/testDevice1/MyROBlock</comment> + </variables> + <variables name="RO_string_a583_testDevice1" typeName="STRING[64]" topologicalAddress="%MW32"> + <comment>AllTypes/testDevice1/MyROBlock</comment> + </variables> + <variables name="RO_date_a583_testDevice1" typeName="DT" topologicalAddress="%MW64"> + <comment>AllTypes/testDevice1/MyROBlock</comment> + </variables> + <variables name="RO_char_a583_testDevice1" typeName="WORD" topologicalAddress="%MW68"> + <comment>AllTypes/testDevice1/MyROBlock</comment> + </variables> + <variables name="RO_byte_a583_testDevice1" typeName="BYTE" topologicalAddress="%MW69"> + <comment>AllTypes/testDevice1/MyROBlock</comment> + </variables> + <variables name="RO_word_a583_testDevice1" typeName="WORD" topologicalAddress="%MW70"> + <comment>AllTypes/testDevice1/MyROBlock</comment> + </variables> + <variables name="RO_dword_a583_testDevice1" typeName="DWORD" topologicalAddress="%MW72"> + <comment>AllTypes/testDevice1/MyROBlock</comment> + </variables> + <variables name="RO_int_a583_testDevice1" typeName="INT" topologicalAddress="%MW74"> + <comment>AllTypes/testDevice1/MyROBlock</comment> + </variables> + <variables name="RO_dint_a583_testDevice1" typeName="DINT" topologicalAddress="%MW76"> + <comment>AllTypes/testDevice1/MyROBlock</comment> + </variables> + <variables name="RO_real_a583_testDevice1" typeName="REAL" topologicalAddress="%MW78"> + <comment>AllTypes/testDevice1/MyROBlock</comment> + </variables> + <variables name="RO_dt_a583_testDevice1" typeName="DT" topologicalAddress="%MW80"> + <comment>AllTypes/testDevice1/MyROBlock</comment> + </variables> + <variables name="RO_int8_a583_testDevice2" typeName="WORD" topologicalAddress="%MW84"> + <comment>AllTypes/testDevice2/MyROBlock</comment> + </variables> + <variables name="RO_uint8_a583_testDevice2" typeName="BYTE" topologicalAddress="%MW85"> + <comment>AllTypes/testDevice2/MyROBlock</comment> + </variables> + <variables name="RO_int16_a583_testDevice2" typeName="INT" topologicalAddress="%MW86"> + <comment>AllTypes/testDevice2/MyROBlock</comment> + </variables> + <variables name="RO_uint16_a583_testDevice2" typeName="WORD" topologicalAddress="%MW87"> + <comment>AllTypes/testDevice2/MyROBlock</comment> + </variables> + <variables name="RO_int32_a583_testDevice2" typeName="DINT" topologicalAddress="%MW88"> + <comment>AllTypes/testDevice2/MyROBlock</comment> + </variables> + <variables name="RO_uint32_a583_testDevice2" typeName="DWORD" topologicalAddress="%MW90"> + <comment>AllTypes/testDevice2/MyROBlock</comment> + </variables> + <variables name="RO_float32_a583_testDevice2" typeName="REAL" topologicalAddress="%MW92"> + <comment>AllTypes/testDevice2/MyROBlock</comment> + </variables> + <variables name="RO_string_a583_testDevice2" typeName="STRING[64]" topologicalAddress="%MW94"> + <comment>AllTypes/testDevice2/MyROBlock</comment> + </variables> + <variables name="RO_date_a583_testDevice2" typeName="DT" topologicalAddress="%MW126"> + <comment>AllTypes/testDevice2/MyROBlock</comment> + </variables> + <variables name="RO_char_a583_testDevice2" typeName="WORD" topologicalAddress="%MW130"> + <comment>AllTypes/testDevice2/MyROBlock</comment> + </variables> + <variables name="RO_byte_a583_testDevice2" typeName="BYTE" topologicalAddress="%MW131"> + <comment>AllTypes/testDevice2/MyROBlock</comment> + </variables> + <variables name="RO_word_a583_testDevice2" typeName="WORD" topologicalAddress="%MW132"> + <comment>AllTypes/testDevice2/MyROBlock</comment> + </variables> + <variables name="RO_dword_a583_testDevice2" typeName="DWORD" topologicalAddress="%MW134"> + <comment>AllTypes/testDevice2/MyROBlock</comment> + </variables> + <variables name="RO_int_a583_testDevice2" typeName="INT" topologicalAddress="%MW136"> + <comment>AllTypes/testDevice2/MyROBlock</comment> + </variables> + <variables name="RO_dint_a583_testDevice2" typeName="DINT" topologicalAddress="%MW138"> + <comment>AllTypes/testDevice2/MyROBlock</comment> + </variables> + <variables name="RO_real_a583_testDevice2" typeName="REAL" topologicalAddress="%MW140"> + <comment>AllTypes/testDevice2/MyROBlock</comment> + </variables> + <variables name="RO_dt_a583_testDevice2" typeName="DT" topologicalAddress="%MW142"> + <comment>AllTypes/testDevice2/MyROBlock</comment> + </variables> + <variables name="RW_int8_a583_testDevice1" typeName="ARRAY[0..1, 0..1] OF WORD" topologicalAddress="%MW146"> + <comment>AllTypes/testDevice1/MyRWBlock</comment> + </variables> + <variables name="RW_uint8_a583_testDevice1" typeName="ARRAY[0..1, 0..1] OF BYTE" topologicalAddress="%MW150"> + <comment>AllTypes/testDevice1/MyRWBlock</comment> + </variables> + <variables name="RW_int16_a583_testDevice1" typeName="ARRAY[0..1, 0..1] OF INT" topologicalAddress="%MW152"> + <comment>AllTypes/testDevice1/MyRWBlock</comment> + </variables> + <variables name="RW_uint16_a583_testDevice1" typeName="ARRAY[0..1, 0..1] OF WORD" topologicalAddress="%MW156"> + <comment>AllTypes/testDevice1/MyRWBlock</comment> + </variables> + <variables name="RW_int32_a583_testDevice1" typeName="ARRAY[0..1, 0..1] OF DINT" topologicalAddress="%MW160"> + <comment>AllTypes/testDevice1/MyRWBlock</comment> + </variables> + <variables name="RW_uint32_a583_testDevice1" typeName="ARRAY[0..1, 0..1] OF DWORD" topologicalAddress="%MW168"> + <comment>AllTypes/testDevice1/MyRWBlock</comment> + </variables> + <variables name="RW_float32_a583_testDevice1" typeName="ARRAY[0..1, 0..1] OF REAL" topologicalAddress="%MW176"> + <comment>AllTypes/testDevice1/MyRWBlock</comment> + </variables> + <variables name="RW_string_a583_testDevice1" typeName="ARRAY[0..1, 0..1] OF STRING[64]" topologicalAddress="%MW184"> + <comment>AllTypes/testDevice1/MyRWBlock</comment> + </variables> + <variables name="RW_date_a583_testDevice1" typeName="ARRAY[0..1, 0..1] OF DT" topologicalAddress="%MW312"> + <comment>AllTypes/testDevice1/MyRWBlock</comment> + </variables> + <variables name="RW_char_a583_testDevice1" typeName="ARRAY[0..1, 0..1] OF WORD" topologicalAddress="%MW328"> + <comment>AllTypes/testDevice1/MyRWBlock</comment> + </variables> + <variables name="RW_byte_a583_testDevice1" typeName="ARRAY[0..1, 0..1] OF BYTE" topologicalAddress="%MW332"> + <comment>AllTypes/testDevice1/MyRWBlock</comment> + </variables> + <variables name="RW_word_a583_testDevice1" typeName="ARRAY[0..1, 0..1] OF WORD" topologicalAddress="%MW334"> + <comment>AllTypes/testDevice1/MyRWBlock</comment> + </variables> + <variables name="RW_dword_a583_testDevice1" typeName="ARRAY[0..1, 0..1] OF DWORD" topologicalAddress="%MW338"> + <comment>AllTypes/testDevice1/MyRWBlock</comment> + </variables> + <variables name="RW_int_a583_testDevice1" typeName="ARRAY[0..1, 0..1] OF INT" topologicalAddress="%MW346"> + <comment>AllTypes/testDevice1/MyRWBlock</comment> + </variables> + <variables name="RW_dint_a583_testDevice1" typeName="ARRAY[0..1, 0..1] OF DINT" topologicalAddress="%MW350"> + <comment>AllTypes/testDevice1/MyRWBlock</comment> + </variables> + <variables name="RW_real_a583_testDevice1" typeName="ARRAY[0..1, 0..1] OF REAL" topologicalAddress="%MW358"> + <comment>AllTypes/testDevice1/MyRWBlock</comment> + </variables> + <variables name="RW_dt_a583_testDevice1" typeName="ARRAY[0..1, 0..1] OF DT" topologicalAddress="%MW366"> + <comment>AllTypes/testDevice1/MyRWBlock</comment> + </variables> + <variables name="RW_int8_a583_testDevice2" typeName="ARRAY[0..1, 0..1] OF WORD" topologicalAddress="%MW382"> + <comment>AllTypes/testDevice2/MyRWBlock</comment> + </variables> + <variables name="RW_uint8_a583_testDevice2" typeName="ARRAY[0..1, 0..1] OF BYTE" topologicalAddress="%MW386"> + <comment>AllTypes/testDevice2/MyRWBlock</comment> + </variables> + <variables name="RW_int16_a583_testDevice2" typeName="ARRAY[0..1, 0..1] OF INT" topologicalAddress="%MW388"> + <comment>AllTypes/testDevice2/MyRWBlock</comment> + </variables> + <variables name="RW_uint16_a583_testDevice2" typeName="ARRAY[0..1, 0..1] OF WORD" topologicalAddress="%MW392"> + <comment>AllTypes/testDevice2/MyRWBlock</comment> + </variables> + <variables name="RW_int32_a583_testDevice2" typeName="ARRAY[0..1, 0..1] OF DINT" topologicalAddress="%MW396"> + <comment>AllTypes/testDevice2/MyRWBlock</comment> + </variables> + <variables name="RW_uint32_a583_testDevice2" typeName="ARRAY[0..1, 0..1] OF DWORD" topologicalAddress="%MW404"> + <comment>AllTypes/testDevice2/MyRWBlock</comment> + </variables> + <variables name="RW_float32_a583_testDevice2" typeName="ARRAY[0..1, 0..1] OF REAL" topologicalAddress="%MW412"> + <comment>AllTypes/testDevice2/MyRWBlock</comment> + </variables> + <variables name="RW_string_a583_testDevice2" typeName="ARRAY[0..1, 0..1] OF STRING[64]" topologicalAddress="%MW420"> + <comment>AllTypes/testDevice2/MyRWBlock</comment> + </variables> + <variables name="RW_date_a583_testDevice2" typeName="ARRAY[0..1, 0..1] OF DT" topologicalAddress="%MW548"> + <comment>AllTypes/testDevice2/MyRWBlock</comment> + </variables> + <variables name="RW_char_a583_testDevice2" typeName="ARRAY[0..1, 0..1] OF WORD" topologicalAddress="%MW564"> + <comment>AllTypes/testDevice2/MyRWBlock</comment> + </variables> + <variables name="RW_byte_a583_testDevice2" typeName="ARRAY[0..1, 0..1] OF BYTE" topologicalAddress="%MW568"> + <comment>AllTypes/testDevice2/MyRWBlock</comment> + </variables> + <variables name="RW_word_a583_testDevice2" typeName="ARRAY[0..1, 0..1] OF WORD" topologicalAddress="%MW570"> + <comment>AllTypes/testDevice2/MyRWBlock</comment> + </variables> + <variables name="RW_dword_a583_testDevice2" typeName="ARRAY[0..1, 0..1] OF DWORD" topologicalAddress="%MW574"> + <comment>AllTypes/testDevice2/MyRWBlock</comment> + </variables> + <variables name="RW_int_a583_testDevice2" typeName="ARRAY[0..1, 0..1] OF INT" topologicalAddress="%MW582"> + <comment>AllTypes/testDevice2/MyRWBlock</comment> + </variables> + <variables name="RW_dint_a583_testDevice2" typeName="ARRAY[0..1, 0..1] OF DINT" topologicalAddress="%MW586"> + <comment>AllTypes/testDevice2/MyRWBlock</comment> + </variables> + <variables name="RW_real_a583_testDevice2" typeName="ARRAY[0..1, 0..1] OF REAL" topologicalAddress="%MW594"> + <comment>AllTypes/testDevice2/MyRWBlock</comment> + </variables> + <variables name="RW_dt_a583_testDevice2" typeName="ARRAY[0..1, 0..1] OF DT" topologicalAddress="%MW602"> + <comment>AllTypes/testDevice2/MyRWBlock</comment> + </variables> + <variables name="WO_int8_a583_testDevice1" typeName="ARRAY[0..9] OF WORD" topologicalAddress="%MW618"> + <comment>AllTypes/testDevice1/MyWOBlock</comment> + </variables> + <variables name="WO_uint8_a583_testDevice1" typeName="ARRAY[0..9] OF BYTE" topologicalAddress="%MW628"> + <comment>AllTypes/testDevice1/MyWOBlock</comment> + </variables> + <variables name="WO_int16_a583_testDevice1" typeName="ARRAY[0..9] OF INT" topologicalAddress="%MW633"> + <comment>AllTypes/testDevice1/MyWOBlock</comment> + </variables> + <variables name="WO_uint16_a583_testDevice1" typeName="ARRAY[0..9] OF WORD" topologicalAddress="%MW643"> + <comment>AllTypes/testDevice1/MyWOBlock</comment> + </variables> + <variables name="WO_int32_a583_testDevice1" typeName="ARRAY[0..9] OF DINT" topologicalAddress="%MW654"> + <comment>AllTypes/testDevice1/MyWOBlock</comment> + </variables> + <variables name="WO_uint32_a583_testDevice1" typeName="ARRAY[0..9] OF DWORD" topologicalAddress="%MW674"> + <comment>AllTypes/testDevice1/MyWOBlock</comment> + </variables> + <variables name="WO_float32_a583_testDevice1" typeName="ARRAY[0..9] OF REAL" topologicalAddress="%MW694"> + <comment>AllTypes/testDevice1/MyWOBlock</comment> + </variables> + <variables name="WO_string_a583_testDevice1" typeName="ARRAY[0..9] OF STRING[64]" topologicalAddress="%MW714"> + <comment>AllTypes/testDevice1/MyWOBlock</comment> + </variables> + <variables name="WO_date_a583_testDevice1" typeName="ARRAY[0..9] OF DT" topologicalAddress="%MW1034"> + <comment>AllTypes/testDevice1/MyWOBlock</comment> + </variables> + <variables name="WO_char_a583_testDevice1" typeName="ARRAY[0..9] OF WORD" topologicalAddress="%MW1074"> + <comment>AllTypes/testDevice1/MyWOBlock</comment> + </variables> + <variables name="WO_byte_a583_testDevice1" typeName="ARRAY[0..9] OF BYTE" topologicalAddress="%MW1084"> + <comment>AllTypes/testDevice1/MyWOBlock</comment> + </variables> + <variables name="WO_word_a583_testDevice1" typeName="ARRAY[0..9] OF WORD" topologicalAddress="%MW1089"> + <comment>AllTypes/testDevice1/MyWOBlock</comment> + </variables> + <variables name="WO_dword_a583_testDevice1" typeName="ARRAY[0..9] OF DWORD" topologicalAddress="%MW1100"> + <comment>AllTypes/testDevice1/MyWOBlock</comment> + </variables> + <variables name="WO_int_a583_testDevice1" typeName="ARRAY[0..9] OF INT" topologicalAddress="%MW1120"> + <comment>AllTypes/testDevice1/MyWOBlock</comment> + </variables> + <variables name="WO_dint_a583_testDevice1" typeName="ARRAY[0..9] OF DINT" topologicalAddress="%MW1130"> + <comment>AllTypes/testDevice1/MyWOBlock</comment> + </variables> + <variables name="WO_real_a583_testDevice1" typeName="ARRAY[0..9] OF REAL" topologicalAddress="%MW1150"> + <comment>AllTypes/testDevice1/MyWOBlock</comment> + </variables> + <variables name="WO_dt_a583_testDevice1" typeName="ARRAY[0..9] OF DT" topologicalAddress="%MW1170"> + <comment>AllTypes/testDevice1/MyWOBlock</comment> + </variables> + <variables name="WO_int8_a583_testDevice2" typeName="ARRAY[0..9] OF WORD" topologicalAddress="%MW1210"> + <comment>AllTypes/testDevice2/MyWOBlock</comment> + </variables> + <variables name="WO_uint8_a583_testDevice2" typeName="ARRAY[0..9] OF BYTE" topologicalAddress="%MW1220"> + <comment>AllTypes/testDevice2/MyWOBlock</comment> + </variables> + <variables name="WO_int16_a583_testDevice2" typeName="ARRAY[0..9] OF INT" topologicalAddress="%MW1225"> + <comment>AllTypes/testDevice2/MyWOBlock</comment> + </variables> + <variables name="WO_uint16_a583_testDevice2" typeName="ARRAY[0..9] OF WORD" topologicalAddress="%MW1235"> + <comment>AllTypes/testDevice2/MyWOBlock</comment> + </variables> + <variables name="WO_int32_a583_testDevice2" typeName="ARRAY[0..9] OF DINT" topologicalAddress="%MW1246"> + <comment>AllTypes/testDevice2/MyWOBlock</comment> + </variables> + <variables name="WO_uint32_a583_testDevice2" typeName="ARRAY[0..9] OF DWORD" topologicalAddress="%MW1266"> + <comment>AllTypes/testDevice2/MyWOBlock</comment> + </variables> + <variables name="WO_float32_a583_testDevice2" typeName="ARRAY[0..9] OF REAL" topologicalAddress="%MW1286"> + <comment>AllTypes/testDevice2/MyWOBlock</comment> + </variables> + <variables name="WO_string_a583_testDevice2" typeName="ARRAY[0..9] OF STRING[64]" topologicalAddress="%MW1306"> + <comment>AllTypes/testDevice2/MyWOBlock</comment> + </variables> + <variables name="WO_date_a583_testDevice2" typeName="ARRAY[0..9] OF DT" topologicalAddress="%MW1626"> + <comment>AllTypes/testDevice2/MyWOBlock</comment> + </variables> + <variables name="WO_char_a583_testDevice2" typeName="ARRAY[0..9] OF WORD" topologicalAddress="%MW1666"> + <comment>AllTypes/testDevice2/MyWOBlock</comment> + </variables> + <variables name="WO_byte_a583_testDevice2" typeName="ARRAY[0..9] OF BYTE" topologicalAddress="%MW1676"> + <comment>AllTypes/testDevice2/MyWOBlock</comment> + </variables> + <variables name="WO_word_a583_testDevice2" typeName="ARRAY[0..9] OF WORD" topologicalAddress="%MW1681"> + <comment>AllTypes/testDevice2/MyWOBlock</comment> + </variables> + <variables name="WO_dword_a583_testDevice2" typeName="ARRAY[0..9] OF DWORD" topologicalAddress="%MW1692"> + <comment>AllTypes/testDevice2/MyWOBlock</comment> + </variables> + <variables name="WO_int_a583_testDevice2" typeName="ARRAY[0..9] OF INT" topologicalAddress="%MW1712"> + <comment>AllTypes/testDevice2/MyWOBlock</comment> + </variables> + <variables name="WO_dint_a583_testDevice2" typeName="ARRAY[0..9] OF DINT" topologicalAddress="%MW1722"> + <comment>AllTypes/testDevice2/MyWOBlock</comment> + </variables> + <variables name="WO_real_a583_testDevice2" typeName="ARRAY[0..9] OF REAL" topologicalAddress="%MW1742"> + <comment>AllTypes/testDevice2/MyWOBlock</comment> + </variables> + <variables name="WO_dt_a583_testDevice2" typeName="ARRAY[0..9] OF DT" topologicalAddress="%MW1762"> + <comment>AllTypes/testDevice2/MyWOBlock</comment> + </variables> + </dataBlock> +</VariablesExchangeFile> \ No newline at end of file diff --git a/silecs-codegen/src/xml/test/generated_correct/controller/Schneider_PremiumQuantum.xsy b/silecs-codegen/src/xml/test/generated_correct/controller/Schneider_PremiumQuantum.xsy new file mode 100644 index 0000000..90041ed --- /dev/null +++ b/silecs-codegen/src/xml/test/generated_correct/controller/Schneider_PremiumQuantum.xsy @@ -0,0 +1,326 @@ +<VariablesExchangeFile> + <dataBlock> + <variables name="_version_a781_SilecsHeader" typeName="STRING[16]" topologicalAddress="%MW0"> + <variableInit value="DEV"/> + <comment>SilecsHeader/SilecsHeader/hdrBlk</comment> + </variables> + <variables name="_checksum_a781_SilecsHeader" typeName="DWORD" topologicalAddress="%MW8"> + <variableInit value="3940683809"/> + <comment>SilecsHeader/SilecsHeader/hdrBlk</comment> + </variables> + <variables name="_user_a781_SilecsHeader" typeName="STRING[16]" topologicalAddress="%MW10"> + <variableInit value="schwinn"/> + <comment>SilecsHeader/SilecsHeader/hdrBlk</comment> + </variables> + <variables name="_date_a781_SilecsHeader" typeName="DT" topologicalAddress="%MW18"> + <variableInit value="DT#2016-7-14-16:8:40"/> + <comment>SilecsHeader/SilecsHeader/hdrBlk</comment> + </variables> + <variables name="RO_int8_a583_testDevice1" typeName="WORD" topologicalAddress="%MW22"> + <comment>AllTypes/testDevice1/MyROBlock</comment> + </variables> + <variables name="RO_uint8_a583_testDevice1" typeName="BYTE" topologicalAddress="%MW23"> + <comment>AllTypes/testDevice1/MyROBlock</comment> + </variables> + <variables name="RO_int16_a583_testDevice1" typeName="INT" topologicalAddress="%MW24"> + <comment>AllTypes/testDevice1/MyROBlock</comment> + </variables> + <variables name="RO_uint16_a583_testDevice1" typeName="WORD" topologicalAddress="%MW25"> + <comment>AllTypes/testDevice1/MyROBlock</comment> + </variables> + <variables name="RO_int32_a583_testDevice1" typeName="DINT" topologicalAddress="%MW26"> + <comment>AllTypes/testDevice1/MyROBlock</comment> + </variables> + <variables name="RO_uint32_a583_testDevice1" typeName="DWORD" topologicalAddress="%MW28"> + <comment>AllTypes/testDevice1/MyROBlock</comment> + </variables> + <variables name="RO_float32_a583_testDevice1" typeName="REAL" topologicalAddress="%MW30"> + <comment>AllTypes/testDevice1/MyROBlock</comment> + </variables> + <variables name="RO_string_a583_testDevice1" typeName="STRING[64]" topologicalAddress="%MW32"> + <comment>AllTypes/testDevice1/MyROBlock</comment> + </variables> + <variables name="RO_date_a583_testDevice1" typeName="DT" topologicalAddress="%MW64"> + <comment>AllTypes/testDevice1/MyROBlock</comment> + </variables> + <variables name="RO_char_a583_testDevice1" typeName="WORD" topologicalAddress="%MW68"> + <comment>AllTypes/testDevice1/MyROBlock</comment> + </variables> + <variables name="RO_byte_a583_testDevice1" typeName="BYTE" topologicalAddress="%MW69"> + <comment>AllTypes/testDevice1/MyROBlock</comment> + </variables> + <variables name="RO_word_a583_testDevice1" typeName="WORD" topologicalAddress="%MW70"> + <comment>AllTypes/testDevice1/MyROBlock</comment> + </variables> + <variables name="RO_dword_a583_testDevice1" typeName="DWORD" topologicalAddress="%MW71"> + <comment>AllTypes/testDevice1/MyROBlock</comment> + </variables> + <variables name="RO_int_a583_testDevice1" typeName="INT" topologicalAddress="%MW73"> + <comment>AllTypes/testDevice1/MyROBlock</comment> + </variables> + <variables name="RO_dint_a583_testDevice1" typeName="DINT" topologicalAddress="%MW74"> + <comment>AllTypes/testDevice1/MyROBlock</comment> + </variables> + <variables name="RO_real_a583_testDevice1" typeName="REAL" topologicalAddress="%MW76"> + <comment>AllTypes/testDevice1/MyROBlock</comment> + </variables> + <variables name="RO_dt_a583_testDevice1" typeName="DT" topologicalAddress="%MW78"> + <comment>AllTypes/testDevice1/MyROBlock</comment> + </variables> + <variables name="RO_int8_a583_testDevice2" typeName="WORD" topologicalAddress="%MW82"> + <comment>AllTypes/testDevice2/MyROBlock</comment> + </variables> + <variables name="RO_uint8_a583_testDevice2" typeName="BYTE" topologicalAddress="%MW83"> + <comment>AllTypes/testDevice2/MyROBlock</comment> + </variables> + <variables name="RO_int16_a583_testDevice2" typeName="INT" topologicalAddress="%MW84"> + <comment>AllTypes/testDevice2/MyROBlock</comment> + </variables> + <variables name="RO_uint16_a583_testDevice2" typeName="WORD" topologicalAddress="%MW85"> + <comment>AllTypes/testDevice2/MyROBlock</comment> + </variables> + <variables name="RO_int32_a583_testDevice2" typeName="DINT" topologicalAddress="%MW86"> + <comment>AllTypes/testDevice2/MyROBlock</comment> + </variables> + <variables name="RO_uint32_a583_testDevice2" typeName="DWORD" topologicalAddress="%MW88"> + <comment>AllTypes/testDevice2/MyROBlock</comment> + </variables> + <variables name="RO_float32_a583_testDevice2" typeName="REAL" topologicalAddress="%MW90"> + <comment>AllTypes/testDevice2/MyROBlock</comment> + </variables> + <variables name="RO_string_a583_testDevice2" typeName="STRING[64]" topologicalAddress="%MW92"> + <comment>AllTypes/testDevice2/MyROBlock</comment> + </variables> + <variables name="RO_date_a583_testDevice2" typeName="DT" topologicalAddress="%MW124"> + <comment>AllTypes/testDevice2/MyROBlock</comment> + </variables> + <variables name="RO_char_a583_testDevice2" typeName="WORD" topologicalAddress="%MW128"> + <comment>AllTypes/testDevice2/MyROBlock</comment> + </variables> + <variables name="RO_byte_a583_testDevice2" typeName="BYTE" topologicalAddress="%MW129"> + <comment>AllTypes/testDevice2/MyROBlock</comment> + </variables> + <variables name="RO_word_a583_testDevice2" typeName="WORD" topologicalAddress="%MW130"> + <comment>AllTypes/testDevice2/MyROBlock</comment> + </variables> + <variables name="RO_dword_a583_testDevice2" typeName="DWORD" topologicalAddress="%MW131"> + <comment>AllTypes/testDevice2/MyROBlock</comment> + </variables> + <variables name="RO_int_a583_testDevice2" typeName="INT" topologicalAddress="%MW133"> + <comment>AllTypes/testDevice2/MyROBlock</comment> + </variables> + <variables name="RO_dint_a583_testDevice2" typeName="DINT" topologicalAddress="%MW134"> + <comment>AllTypes/testDevice2/MyROBlock</comment> + </variables> + <variables name="RO_real_a583_testDevice2" typeName="REAL" topologicalAddress="%MW136"> + <comment>AllTypes/testDevice2/MyROBlock</comment> + </variables> + <variables name="RO_dt_a583_testDevice2" typeName="DT" topologicalAddress="%MW138"> + <comment>AllTypes/testDevice2/MyROBlock</comment> + </variables> + <variables name="RW_int8_a583_testDevice1" typeName="ARRAY[0..1, 0..1] OF WORD" topologicalAddress="%MW142"> + <comment>AllTypes/testDevice1/MyRWBlock</comment> + </variables> + <variables name="RW_uint8_a583_testDevice1" typeName="ARRAY[0..1, 0..1] OF BYTE" topologicalAddress="%MW146"> + <comment>AllTypes/testDevice1/MyRWBlock</comment> + </variables> + <variables name="RW_int16_a583_testDevice1" typeName="ARRAY[0..1, 0..1] OF INT" topologicalAddress="%MW148"> + <comment>AllTypes/testDevice1/MyRWBlock</comment> + </variables> + <variables name="RW_uint16_a583_testDevice1" typeName="ARRAY[0..1, 0..1] OF WORD" topologicalAddress="%MW152"> + <comment>AllTypes/testDevice1/MyRWBlock</comment> + </variables> + <variables name="RW_int32_a583_testDevice1" typeName="ARRAY[0..1, 0..1] OF DINT" topologicalAddress="%MW156"> + <comment>AllTypes/testDevice1/MyRWBlock</comment> + </variables> + <variables name="RW_uint32_a583_testDevice1" typeName="ARRAY[0..1, 0..1] OF DWORD" topologicalAddress="%MW164"> + <comment>AllTypes/testDevice1/MyRWBlock</comment> + </variables> + <variables name="RW_float32_a583_testDevice1" typeName="ARRAY[0..1, 0..1] OF REAL" topologicalAddress="%MW172"> + <comment>AllTypes/testDevice1/MyRWBlock</comment> + </variables> + <variables name="RW_string_a583_testDevice1" typeName="ARRAY[0..1, 0..1] OF STRING[64]" topologicalAddress="%MW180"> + <comment>AllTypes/testDevice1/MyRWBlock</comment> + </variables> + <variables name="RW_date_a583_testDevice1" typeName="ARRAY[0..1, 0..1] OF DT" topologicalAddress="%MW308"> + <comment>AllTypes/testDevice1/MyRWBlock</comment> + </variables> + <variables name="RW_char_a583_testDevice1" typeName="ARRAY[0..1, 0..1] OF WORD" topologicalAddress="%MW324"> + <comment>AllTypes/testDevice1/MyRWBlock</comment> + </variables> + <variables name="RW_byte_a583_testDevice1" typeName="ARRAY[0..1, 0..1] OF BYTE" topologicalAddress="%MW328"> + <comment>AllTypes/testDevice1/MyRWBlock</comment> + </variables> + <variables name="RW_word_a583_testDevice1" typeName="ARRAY[0..1, 0..1] OF WORD" topologicalAddress="%MW330"> + <comment>AllTypes/testDevice1/MyRWBlock</comment> + </variables> + <variables name="RW_dword_a583_testDevice1" typeName="ARRAY[0..1, 0..1] OF DWORD" topologicalAddress="%MW334"> + <comment>AllTypes/testDevice1/MyRWBlock</comment> + </variables> + <variables name="RW_int_a583_testDevice1" typeName="ARRAY[0..1, 0..1] OF INT" topologicalAddress="%MW342"> + <comment>AllTypes/testDevice1/MyRWBlock</comment> + </variables> + <variables name="RW_dint_a583_testDevice1" typeName="ARRAY[0..1, 0..1] OF DINT" topologicalAddress="%MW346"> + <comment>AllTypes/testDevice1/MyRWBlock</comment> + </variables> + <variables name="RW_real_a583_testDevice1" typeName="ARRAY[0..1, 0..1] OF REAL" topologicalAddress="%MW354"> + <comment>AllTypes/testDevice1/MyRWBlock</comment> + </variables> + <variables name="RW_dt_a583_testDevice1" typeName="ARRAY[0..1, 0..1] OF DT" topologicalAddress="%MW362"> + <comment>AllTypes/testDevice1/MyRWBlock</comment> + </variables> + <variables name="RW_int8_a583_testDevice2" typeName="ARRAY[0..1, 0..1] OF WORD" topologicalAddress="%MW378"> + <comment>AllTypes/testDevice2/MyRWBlock</comment> + </variables> + <variables name="RW_uint8_a583_testDevice2" typeName="ARRAY[0..1, 0..1] OF BYTE" topologicalAddress="%MW382"> + <comment>AllTypes/testDevice2/MyRWBlock</comment> + </variables> + <variables name="RW_int16_a583_testDevice2" typeName="ARRAY[0..1, 0..1] OF INT" topologicalAddress="%MW384"> + <comment>AllTypes/testDevice2/MyRWBlock</comment> + </variables> + <variables name="RW_uint16_a583_testDevice2" typeName="ARRAY[0..1, 0..1] OF WORD" topologicalAddress="%MW388"> + <comment>AllTypes/testDevice2/MyRWBlock</comment> + </variables> + <variables name="RW_int32_a583_testDevice2" typeName="ARRAY[0..1, 0..1] OF DINT" topologicalAddress="%MW392"> + <comment>AllTypes/testDevice2/MyRWBlock</comment> + </variables> + <variables name="RW_uint32_a583_testDevice2" typeName="ARRAY[0..1, 0..1] OF DWORD" topologicalAddress="%MW400"> + <comment>AllTypes/testDevice2/MyRWBlock</comment> + </variables> + <variables name="RW_float32_a583_testDevice2" typeName="ARRAY[0..1, 0..1] OF REAL" topologicalAddress="%MW408"> + <comment>AllTypes/testDevice2/MyRWBlock</comment> + </variables> + <variables name="RW_string_a583_testDevice2" typeName="ARRAY[0..1, 0..1] OF STRING[64]" topologicalAddress="%MW416"> + <comment>AllTypes/testDevice2/MyRWBlock</comment> + </variables> + <variables name="RW_date_a583_testDevice2" typeName="ARRAY[0..1, 0..1] OF DT" topologicalAddress="%MW544"> + <comment>AllTypes/testDevice2/MyRWBlock</comment> + </variables> + <variables name="RW_char_a583_testDevice2" typeName="ARRAY[0..1, 0..1] OF WORD" topologicalAddress="%MW560"> + <comment>AllTypes/testDevice2/MyRWBlock</comment> + </variables> + <variables name="RW_byte_a583_testDevice2" typeName="ARRAY[0..1, 0..1] OF BYTE" topologicalAddress="%MW564"> + <comment>AllTypes/testDevice2/MyRWBlock</comment> + </variables> + <variables name="RW_word_a583_testDevice2" typeName="ARRAY[0..1, 0..1] OF WORD" topologicalAddress="%MW566"> + <comment>AllTypes/testDevice2/MyRWBlock</comment> + </variables> + <variables name="RW_dword_a583_testDevice2" typeName="ARRAY[0..1, 0..1] OF DWORD" topologicalAddress="%MW570"> + <comment>AllTypes/testDevice2/MyRWBlock</comment> + </variables> + <variables name="RW_int_a583_testDevice2" typeName="ARRAY[0..1, 0..1] OF INT" topologicalAddress="%MW578"> + <comment>AllTypes/testDevice2/MyRWBlock</comment> + </variables> + <variables name="RW_dint_a583_testDevice2" typeName="ARRAY[0..1, 0..1] OF DINT" topologicalAddress="%MW582"> + <comment>AllTypes/testDevice2/MyRWBlock</comment> + </variables> + <variables name="RW_real_a583_testDevice2" typeName="ARRAY[0..1, 0..1] OF REAL" topologicalAddress="%MW590"> + <comment>AllTypes/testDevice2/MyRWBlock</comment> + </variables> + <variables name="RW_dt_a583_testDevice2" typeName="ARRAY[0..1, 0..1] OF DT" topologicalAddress="%MW598"> + <comment>AllTypes/testDevice2/MyRWBlock</comment> + </variables> + <variables name="WO_int8_a583_testDevice1" typeName="ARRAY[0..9] OF WORD" topologicalAddress="%MW614"> + <comment>AllTypes/testDevice1/MyWOBlock</comment> + </variables> + <variables name="WO_uint8_a583_testDevice1" typeName="ARRAY[0..9] OF BYTE" topologicalAddress="%MW624"> + <comment>AllTypes/testDevice1/MyWOBlock</comment> + </variables> + <variables name="WO_int16_a583_testDevice1" typeName="ARRAY[0..9] OF INT" topologicalAddress="%MW629"> + <comment>AllTypes/testDevice1/MyWOBlock</comment> + </variables> + <variables name="WO_uint16_a583_testDevice1" typeName="ARRAY[0..9] OF WORD" topologicalAddress="%MW639"> + <comment>AllTypes/testDevice1/MyWOBlock</comment> + </variables> + <variables name="WO_int32_a583_testDevice1" typeName="ARRAY[0..9] OF DINT" topologicalAddress="%MW649"> + <comment>AllTypes/testDevice1/MyWOBlock</comment> + </variables> + <variables name="WO_uint32_a583_testDevice1" typeName="ARRAY[0..9] OF DWORD" topologicalAddress="%MW669"> + <comment>AllTypes/testDevice1/MyWOBlock</comment> + </variables> + <variables name="WO_float32_a583_testDevice1" typeName="ARRAY[0..9] OF REAL" topologicalAddress="%MW689"> + <comment>AllTypes/testDevice1/MyWOBlock</comment> + </variables> + <variables name="WO_string_a583_testDevice1" typeName="ARRAY[0..9] OF STRING[64]" topologicalAddress="%MW709"> + <comment>AllTypes/testDevice1/MyWOBlock</comment> + </variables> + <variables name="WO_date_a583_testDevice1" typeName="ARRAY[0..9] OF DT" topologicalAddress="%MW1029"> + <comment>AllTypes/testDevice1/MyWOBlock</comment> + </variables> + <variables name="WO_char_a583_testDevice1" typeName="ARRAY[0..9] OF WORD" topologicalAddress="%MW1069"> + <comment>AllTypes/testDevice1/MyWOBlock</comment> + </variables> + <variables name="WO_byte_a583_testDevice1" typeName="ARRAY[0..9] OF BYTE" topologicalAddress="%MW1079"> + <comment>AllTypes/testDevice1/MyWOBlock</comment> + </variables> + <variables name="WO_word_a583_testDevice1" typeName="ARRAY[0..9] OF WORD" topologicalAddress="%MW1084"> + <comment>AllTypes/testDevice1/MyWOBlock</comment> + </variables> + <variables name="WO_dword_a583_testDevice1" typeName="ARRAY[0..9] OF DWORD" topologicalAddress="%MW1094"> + <comment>AllTypes/testDevice1/MyWOBlock</comment> + </variables> + <variables name="WO_int_a583_testDevice1" typeName="ARRAY[0..9] OF INT" topologicalAddress="%MW1114"> + <comment>AllTypes/testDevice1/MyWOBlock</comment> + </variables> + <variables name="WO_dint_a583_testDevice1" typeName="ARRAY[0..9] OF DINT" topologicalAddress="%MW1124"> + <comment>AllTypes/testDevice1/MyWOBlock</comment> + </variables> + <variables name="WO_real_a583_testDevice1" typeName="ARRAY[0..9] OF REAL" topologicalAddress="%MW1144"> + <comment>AllTypes/testDevice1/MyWOBlock</comment> + </variables> + <variables name="WO_dt_a583_testDevice1" typeName="ARRAY[0..9] OF DT" topologicalAddress="%MW1164"> + <comment>AllTypes/testDevice1/MyWOBlock</comment> + </variables> + <variables name="WO_int8_a583_testDevice2" typeName="ARRAY[0..9] OF WORD" topologicalAddress="%MW1204"> + <comment>AllTypes/testDevice2/MyWOBlock</comment> + </variables> + <variables name="WO_uint8_a583_testDevice2" typeName="ARRAY[0..9] OF BYTE" topologicalAddress="%MW1214"> + <comment>AllTypes/testDevice2/MyWOBlock</comment> + </variables> + <variables name="WO_int16_a583_testDevice2" typeName="ARRAY[0..9] OF INT" topologicalAddress="%MW1219"> + <comment>AllTypes/testDevice2/MyWOBlock</comment> + </variables> + <variables name="WO_uint16_a583_testDevice2" typeName="ARRAY[0..9] OF WORD" topologicalAddress="%MW1229"> + <comment>AllTypes/testDevice2/MyWOBlock</comment> + </variables> + <variables name="WO_int32_a583_testDevice2" typeName="ARRAY[0..9] OF DINT" topologicalAddress="%MW1239"> + <comment>AllTypes/testDevice2/MyWOBlock</comment> + </variables> + <variables name="WO_uint32_a583_testDevice2" typeName="ARRAY[0..9] OF DWORD" topologicalAddress="%MW1259"> + <comment>AllTypes/testDevice2/MyWOBlock</comment> + </variables> + <variables name="WO_float32_a583_testDevice2" typeName="ARRAY[0..9] OF REAL" topologicalAddress="%MW1279"> + <comment>AllTypes/testDevice2/MyWOBlock</comment> + </variables> + <variables name="WO_string_a583_testDevice2" typeName="ARRAY[0..9] OF STRING[64]" topologicalAddress="%MW1299"> + <comment>AllTypes/testDevice2/MyWOBlock</comment> + </variables> + <variables name="WO_date_a583_testDevice2" typeName="ARRAY[0..9] OF DT" topologicalAddress="%MW1619"> + <comment>AllTypes/testDevice2/MyWOBlock</comment> + </variables> + <variables name="WO_char_a583_testDevice2" typeName="ARRAY[0..9] OF WORD" topologicalAddress="%MW1659"> + <comment>AllTypes/testDevice2/MyWOBlock</comment> + </variables> + <variables name="WO_byte_a583_testDevice2" typeName="ARRAY[0..9] OF BYTE" topologicalAddress="%MW1669"> + <comment>AllTypes/testDevice2/MyWOBlock</comment> + </variables> + <variables name="WO_word_a583_testDevice2" typeName="ARRAY[0..9] OF WORD" topologicalAddress="%MW1674"> + <comment>AllTypes/testDevice2/MyWOBlock</comment> + </variables> + <variables name="WO_dword_a583_testDevice2" typeName="ARRAY[0..9] OF DWORD" topologicalAddress="%MW1684"> + <comment>AllTypes/testDevice2/MyWOBlock</comment> + </variables> + <variables name="WO_int_a583_testDevice2" typeName="ARRAY[0..9] OF INT" topologicalAddress="%MW1704"> + <comment>AllTypes/testDevice2/MyWOBlock</comment> + </variables> + <variables name="WO_dint_a583_testDevice2" typeName="ARRAY[0..9] OF DINT" topologicalAddress="%MW1714"> + <comment>AllTypes/testDevice2/MyWOBlock</comment> + </variables> + <variables name="WO_real_a583_testDevice2" typeName="ARRAY[0..9] OF REAL" topologicalAddress="%MW1734"> + <comment>AllTypes/testDevice2/MyWOBlock</comment> + </variables> + <variables name="WO_dt_a583_testDevice2" typeName="ARRAY[0..9] OF DT" topologicalAddress="%MW1754"> + <comment>AllTypes/testDevice2/MyWOBlock</comment> + </variables> + </dataBlock> +</VariablesExchangeFile> \ No newline at end of file diff --git a/silecs-codegen/src/xml/test/generated_correct/controller/Siemens_Step7Block.scl b/silecs-codegen/src/xml/test/generated_correct/controller/Siemens_Step7Block.scl new file mode 100644 index 0000000..c5cd604 --- /dev/null +++ b/silecs-codegen/src/xml/test/generated_correct/controller/Siemens_Step7Block.scl @@ -0,0 +1,150 @@ +//--------------------------------------------------------------------- +// SilecsHeader/ v1.0.0 +// BLOCK Type definition +//--------------------------------------------------------------------- +TYPE _SilecsHeader_hdrBlk +AUTHOR: schwinn +FAMILY: SILECS +NAME: UDTB + STRUCT + _version: STRING[16] := 'SILECS_DEV'; + _checksum: DWORD := DW#16#eae21021; + _user: STRING[16] := 'schwinn'; + _date: DT := DT#2016-7-14-16:7:40; + + END_STRUCT; +END_TYPE + +//--------------------------------------------------------------------- +// SilecsHeader/ v1.0.0 +// Block instance definition +//--------------------------------------------------------------------- +// SilecsHeader_SilecsHeader ........................................... +DATA_BLOCK DB0 +{ S7_Optimized_Access := 'FALSE' } +AUTHOR: schwinn +FAMILY: SILECS +NAME: DEV_MODE +STRUCT + hdrBlk: _SilecsHeader_hdrBlk; + +END_STRUCT; +BEGIN +END_DATA_BLOCK + +//--------------------------------------------------------------------- +// AllTypes/ v0.1.0 +// BLOCK Type definition +//--------------------------------------------------------------------- +TYPE _AllTypes_MyROBlock +AUTHOR: schwinn +FAMILY: SILECS +NAME: UDTB + STRUCT + RO_int8: CHAR; + RO_uint8: BYTE; + RO_int16: INT; + RO_uint16: WORD; + RO_int32: DINT; + RO_uint32: DWORD; + RO_float32: REAL; + RO_string: STRING[64]; + RO_date: DT; + RO_char: CHAR; + RO_byte: BYTE; + RO_word: WORD; + RO_dword: DWORD; + RO_int: INT; + RO_dint: DINT; + RO_real: REAL; + RO_dt: DT; + + END_STRUCT; +END_TYPE + +TYPE _AllTypes_MyRWBlock +AUTHOR: schwinn +FAMILY: SILECS +NAME: UDTB + STRUCT + RW_int8: ARRAY[0..1, 0..1] OF CHAR; + RW_uint8: ARRAY[0..1, 0..1] OF BYTE; + RW_int16: ARRAY[0..1, 0..1] OF INT; + RW_uint16: ARRAY[0..1, 0..1] OF WORD; + RW_int32: ARRAY[0..1, 0..1] OF DINT; + RW_uint32: ARRAY[0..1, 0..1] OF DWORD; + RW_float32: ARRAY[0..1, 0..1] OF REAL; + RW_string: ARRAY[0..1, 0..1] OF STRING[64]; + RW_date: ARRAY[0..1, 0..1] OF DT; + RW_char: ARRAY[0..1, 0..1] OF CHAR; + RW_byte: ARRAY[0..1, 0..1] OF BYTE; + RW_word: ARRAY[0..1, 0..1] OF WORD; + RW_dword: ARRAY[0..1, 0..1] OF DWORD; + RW_int: ARRAY[0..1, 0..1] OF INT; + RW_dint: ARRAY[0..1, 0..1] OF DINT; + RW_real: ARRAY[0..1, 0..1] OF REAL; + RW_dt: ARRAY[0..1, 0..1] OF DT; + + END_STRUCT; +END_TYPE + +TYPE _AllTypes_MyWOBlock +AUTHOR: schwinn +FAMILY: SILECS +NAME: UDTB + STRUCT + WO_int8: ARRAY[0..9] OF CHAR; + WO_uint8: ARRAY[0..9] OF BYTE; + WO_int16: ARRAY[0..9] OF INT; + WO_uint16: ARRAY[0..9] OF WORD; + WO_int32: ARRAY[0..9] OF DINT; + WO_uint32: ARRAY[0..9] OF DWORD; + WO_float32: ARRAY[0..9] OF REAL; + WO_string: ARRAY[0..9] OF STRING[64]; + WO_date: ARRAY[0..9] OF DT; + WO_char: ARRAY[0..9] OF CHAR; + WO_byte: ARRAY[0..9] OF BYTE; + WO_word: ARRAY[0..9] OF WORD; + WO_dword: ARRAY[0..9] OF DWORD; + WO_int: ARRAY[0..9] OF INT; + WO_dint: ARRAY[0..9] OF DINT; + WO_real: ARRAY[0..9] OF REAL; + WO_dt: ARRAY[0..9] OF DT; + + END_STRUCT; +END_TYPE + +//--------------------------------------------------------------------- +// AllTypes/ v0.1.0 +// Block instance definition +//--------------------------------------------------------------------- +// AllTypes_testDevice1 ........................................... +DATA_BLOCK DB1 +{ S7_Optimized_Access := 'FALSE' } +AUTHOR: schwinn +FAMILY: SILECS +NAME: DEV_MODE +STRUCT + MyROBlock: _AllTypes_MyROBlock; + MyRWBlock: _AllTypes_MyRWBlock; + MyWOBlock: _AllTypes_MyWOBlock; + +END_STRUCT; +BEGIN +END_DATA_BLOCK + +// AllTypes_testDevice2 ........................................... +DATA_BLOCK DB2 +{ S7_Optimized_Access := 'FALSE' } +AUTHOR: schwinn +FAMILY: SILECS +NAME: DEV_MODE +STRUCT + MyROBlock: _AllTypes_MyROBlock; + MyRWBlock: _AllTypes_MyRWBlock; + MyWOBlock: _AllTypes_MyWOBlock; + +END_STRUCT; +BEGIN +END_DATA_BLOCK + diff --git a/silecs-codegen/src/xml/test/generated_correct/controller/Siemens_Step7Block.sdf b/silecs-codegen/src/xml/test/generated_correct/controller/Siemens_Step7Block.sdf new file mode 100644 index 0000000..e5d2ddb --- /dev/null +++ b/silecs-codegen/src/xml/test/generated_correct/controller/Siemens_Step7Block.sdf @@ -0,0 +1,7 @@ +"_SilecsHeader_hdrBlk","UDT 0","UDT 0","[SilecsHeader/1.0.0] UDT symbol: _<class-name>_<block-name>" +"SilecsHeader_SilecsHeader","DB 0","DB 0","[SilecsHeader/1.0.0] DB symbol: <class-name>_<device-label | device-id>" +"_AllTypes_MyROBlock","UDT 1","UDT 1","[AllTypes/0.1.0] UDT symbol: _<class-name>_<block-name>" +"_AllTypes_MyRWBlock","UDT 2","UDT 2","" +"_AllTypes_MyWOBlock","UDT 3","UDT 3","" +"AllTypes_testDevice1","DB 1","DB 1","[AllTypes/0.1.0] DB symbol: <class-name>_<device-label | device-id>" +"AllTypes_testDevice2","DB 2","DB 2","" diff --git a/silecs-codegen/src/xml/test/generated_correct/controller/Siemens_Step7Device.scl b/silecs-codegen/src/xml/test/generated_correct/controller/Siemens_Step7Device.scl new file mode 100644 index 0000000..32b0476 --- /dev/null +++ b/silecs-codegen/src/xml/test/generated_correct/controller/Siemens_Step7Device.scl @@ -0,0 +1,162 @@ +//--------------------------------------------------------------------- +// SilecsHeader/ v1.0.0 +// BLOCK Type definition +//--------------------------------------------------------------------- +TYPE _SilecsHeader_hdrBlk +AUTHOR: schwinn +FAMILY: SILECS +NAME: UDTB + STRUCT + _version: STRING[16] := 'SILECS_DEV'; + _checksum: DWORD := DW#16#eae21021; + _user: STRING[16] := 'schwinn'; + _date: DT := DT#2016-7-14-16:7:24; + + END_STRUCT; +END_TYPE + +//--------------------------------------------------------------------- +// SilecsHeader/ v1.0.0 +// Block instance definition +//--------------------------------------------------------------------- +// SilecsHeader_hdrBlk ........................................... +DATA_BLOCK DB0 +{ S7_Optimized_Access := 'FALSE' } +AUTHOR: schwinn +FAMILY: SILECS +NAME: BLK_MODE +STRUCT + SilecsHeader: _SilecsHeader_hdrBlk; + +END_STRUCT; +BEGIN +END_DATA_BLOCK + +//--------------------------------------------------------------------- +// AllTypes/ v0.1.0 +// BLOCK Type definition +//--------------------------------------------------------------------- +TYPE _AllTypes_MyROBlock +AUTHOR: schwinn +FAMILY: SILECS +NAME: UDTB + STRUCT + RO_int8: CHAR; + RO_uint8: BYTE; + RO_int16: INT; + RO_uint16: WORD; + RO_int32: DINT; + RO_uint32: DWORD; + RO_float32: REAL; + RO_string: STRING[64]; + RO_date: DT; + RO_char: CHAR; + RO_byte: BYTE; + RO_word: WORD; + RO_dword: DWORD; + RO_int: INT; + RO_dint: DINT; + RO_real: REAL; + RO_dt: DT; + + END_STRUCT; +END_TYPE + +TYPE _AllTypes_MyRWBlock +AUTHOR: schwinn +FAMILY: SILECS +NAME: UDTB + STRUCT + RW_int8: ARRAY[0..1, 0..1] OF CHAR; + RW_uint8: ARRAY[0..1, 0..1] OF BYTE; + RW_int16: ARRAY[0..1, 0..1] OF INT; + RW_uint16: ARRAY[0..1, 0..1] OF WORD; + RW_int32: ARRAY[0..1, 0..1] OF DINT; + RW_uint32: ARRAY[0..1, 0..1] OF DWORD; + RW_float32: ARRAY[0..1, 0..1] OF REAL; + RW_string: ARRAY[0..1, 0..1] OF STRING[64]; + RW_date: ARRAY[0..1, 0..1] OF DT; + RW_char: ARRAY[0..1, 0..1] OF CHAR; + RW_byte: ARRAY[0..1, 0..1] OF BYTE; + RW_word: ARRAY[0..1, 0..1] OF WORD; + RW_dword: ARRAY[0..1, 0..1] OF DWORD; + RW_int: ARRAY[0..1, 0..1] OF INT; + RW_dint: ARRAY[0..1, 0..1] OF DINT; + RW_real: ARRAY[0..1, 0..1] OF REAL; + RW_dt: ARRAY[0..1, 0..1] OF DT; + + END_STRUCT; +END_TYPE + +TYPE _AllTypes_MyWOBlock +AUTHOR: schwinn +FAMILY: SILECS +NAME: UDTB + STRUCT + WO_int8: ARRAY[0..9] OF CHAR; + WO_uint8: ARRAY[0..9] OF BYTE; + WO_int16: ARRAY[0..9] OF INT; + WO_uint16: ARRAY[0..9] OF WORD; + WO_int32: ARRAY[0..9] OF DINT; + WO_uint32: ARRAY[0..9] OF DWORD; + WO_float32: ARRAY[0..9] OF REAL; + WO_string: ARRAY[0..9] OF STRING[64]; + WO_date: ARRAY[0..9] OF DT; + WO_char: ARRAY[0..9] OF CHAR; + WO_byte: ARRAY[0..9] OF BYTE; + WO_word: ARRAY[0..9] OF WORD; + WO_dword: ARRAY[0..9] OF DWORD; + WO_int: ARRAY[0..9] OF INT; + WO_dint: ARRAY[0..9] OF DINT; + WO_real: ARRAY[0..9] OF REAL; + WO_dt: ARRAY[0..9] OF DT; + + END_STRUCT; +END_TYPE + +//--------------------------------------------------------------------- +// AllTypes/ v0.1.0 +// Block instance definition +//--------------------------------------------------------------------- +// AllTypes_MyROBlock ........................................... +DATA_BLOCK DB1 +{ S7_Optimized_Access := 'FALSE' } +AUTHOR: schwinn +FAMILY: SILECS +NAME: BLK_MODE +STRUCT + testDevice1: _AllTypes_MyROBlock; + testDevice2: _AllTypes_MyROBlock; + +END_STRUCT; +BEGIN +END_DATA_BLOCK + +// AllTypes_MyRWBlock ........................................... +DATA_BLOCK DB2 +{ S7_Optimized_Access := 'FALSE' } +AUTHOR: schwinn +FAMILY: SILECS +NAME: BLK_MODE +STRUCT + testDevice1: _AllTypes_MyRWBlock; + testDevice2: _AllTypes_MyRWBlock; + +END_STRUCT; +BEGIN +END_DATA_BLOCK + +// AllTypes_MyWOBlock ........................................... +DATA_BLOCK DB3 +{ S7_Optimized_Access := 'FALSE' } +AUTHOR: schwinn +FAMILY: SILECS +NAME: BLK_MODE +STRUCT + testDevice1: _AllTypes_MyWOBlock; + testDevice2: _AllTypes_MyWOBlock; + +END_STRUCT; +BEGIN +END_DATA_BLOCK + diff --git a/silecs-codegen/src/xml/test/generated_correct/controller/Siemens_Step7Device.sdf b/silecs-codegen/src/xml/test/generated_correct/controller/Siemens_Step7Device.sdf new file mode 100644 index 0000000..29a5f58 --- /dev/null +++ b/silecs-codegen/src/xml/test/generated_correct/controller/Siemens_Step7Device.sdf @@ -0,0 +1,8 @@ +"_SilecsHeader_hdrBlk","UDT 0","UDT 0","[SilecsHeader/1.0.0] UDT symbol: _<class-name>_<block-name>" +"SilecsHeader_hdrBlk","DB 0","DB 0","[SilecsHeader/1.0.0] DB symbol: <class-name>_<block-name>" +"_AllTypes_MyROBlock","UDT 1","UDT 1","[AllTypes/0.1.0] UDT symbol: _<class-name>_<block-name>" +"_AllTypes_MyRWBlock","UDT 2","UDT 2","" +"_AllTypes_MyWOBlock","UDT 3","UDT 3","" +"AllTypes_MyROBlock","DB 1","DB 1","[AllTypes/0.1.0] DB symbol: <class-name>_<block-name>" +"AllTypes_MyRWBlock","DB 2","DB 2","" +"AllTypes_MyWOBlock","DB 3","DB 3","" diff --git a/silecs-codegen/src/xml/test/generated_correct/controller/Siemens_TiaBlock.scl b/silecs-codegen/src/xml/test/generated_correct/controller/Siemens_TiaBlock.scl new file mode 100644 index 0000000..a12f7bd --- /dev/null +++ b/silecs-codegen/src/xml/test/generated_correct/controller/Siemens_TiaBlock.scl @@ -0,0 +1,158 @@ +//--------------------------------------------------------------------- +// SilecsHeader/ v1.0.0 +// BLOCK Type definition +//--------------------------------------------------------------------- +TYPE _SilecsHeader_hdrBlk +AUTHOR: schwinn +FAMILY: SILECS +NAME: UDTB + STRUCT + _version: STRING[16] := 'SILECS_DEV'; + _checksum: DWORD := DW#16#eae21021; + _user: STRING[16] := 'schwinn'; + _date: DT := DT#2016-7-14-16:7:12; + + END_STRUCT; +END_TYPE + +//--------------------------------------------------------------------- +// SilecsHeader/ v1.0.0 +// Block instance definition +//--------------------------------------------------------------------- +DATA_BLOCK SilecsHeader_hdrBlk +{ S7_Optimized_Access := 'FALSE' } +AUTHOR: schwinn +FAMILY: SILECS +NAME: BLK_MODE +STRUCT + SilecsHeader: _SilecsHeader_hdrBlk; + +END_STRUCT; +BEGIN +END_DATA_BLOCK + +//--------------------------------------------------------------------- +// AllTypes/ v0.1.0 +// BLOCK Type definition +//--------------------------------------------------------------------- +TYPE _AllTypes_MyROBlock +AUTHOR: schwinn +FAMILY: SILECS +NAME: UDTB + STRUCT + RO_int8: CHAR; + RO_uint8: BYTE; + RO_int16: INT; + RO_uint16: WORD; + RO_int32: DINT; + RO_uint32: DWORD; + RO_float32: REAL; + RO_string: STRING[64]; + RO_date: DT; + RO_char: CHAR; + RO_byte: BYTE; + RO_word: WORD; + RO_dword: DWORD; + RO_int: INT; + RO_dint: DINT; + RO_real: REAL; + RO_dt: DT; + + END_STRUCT; +END_TYPE + +TYPE _AllTypes_MyRWBlock +AUTHOR: schwinn +FAMILY: SILECS +NAME: UDTB + STRUCT + RW_int8: ARRAY[0..1, 0..1] OF CHAR; + RW_uint8: ARRAY[0..1, 0..1] OF BYTE; + RW_int16: ARRAY[0..1, 0..1] OF INT; + RW_uint16: ARRAY[0..1, 0..1] OF WORD; + RW_int32: ARRAY[0..1, 0..1] OF DINT; + RW_uint32: ARRAY[0..1, 0..1] OF DWORD; + RW_float32: ARRAY[0..1, 0..1] OF REAL; + RW_string: ARRAY[0..1, 0..1] OF STRING[64]; + RW_date: ARRAY[0..1, 0..1] OF DT; + RW_char: ARRAY[0..1, 0..1] OF CHAR; + RW_byte: ARRAY[0..1, 0..1] OF BYTE; + RW_word: ARRAY[0..1, 0..1] OF WORD; + RW_dword: ARRAY[0..1, 0..1] OF DWORD; + RW_int: ARRAY[0..1, 0..1] OF INT; + RW_dint: ARRAY[0..1, 0..1] OF DINT; + RW_real: ARRAY[0..1, 0..1] OF REAL; + RW_dt: ARRAY[0..1, 0..1] OF DT; + + END_STRUCT; +END_TYPE + +TYPE _AllTypes_MyWOBlock +AUTHOR: schwinn +FAMILY: SILECS +NAME: UDTB + STRUCT + WO_int8: ARRAY[0..9] OF CHAR; + WO_uint8: ARRAY[0..9] OF BYTE; + WO_int16: ARRAY[0..9] OF INT; + WO_uint16: ARRAY[0..9] OF WORD; + WO_int32: ARRAY[0..9] OF DINT; + WO_uint32: ARRAY[0..9] OF DWORD; + WO_float32: ARRAY[0..9] OF REAL; + WO_string: ARRAY[0..9] OF STRING[64]; + WO_date: ARRAY[0..9] OF DT; + WO_char: ARRAY[0..9] OF CHAR; + WO_byte: ARRAY[0..9] OF BYTE; + WO_word: ARRAY[0..9] OF WORD; + WO_dword: ARRAY[0..9] OF DWORD; + WO_int: ARRAY[0..9] OF INT; + WO_dint: ARRAY[0..9] OF DINT; + WO_real: ARRAY[0..9] OF REAL; + WO_dt: ARRAY[0..9] OF DT; + + END_STRUCT; +END_TYPE + +//--------------------------------------------------------------------- +// AllTypes/ v0.1.0 +// Block instance definition +//--------------------------------------------------------------------- +DATA_BLOCK AllTypes_MyROBlock +{ S7_Optimized_Access := 'FALSE' } +AUTHOR: schwinn +FAMILY: SILECS +NAME: BLK_MODE +STRUCT + testDevice1: _AllTypes_MyROBlock; + testDevice2: _AllTypes_MyROBlock; + +END_STRUCT; +BEGIN +END_DATA_BLOCK + +DATA_BLOCK AllTypes_MyRWBlock +{ S7_Optimized_Access := 'FALSE' } +AUTHOR: schwinn +FAMILY: SILECS +NAME: BLK_MODE +STRUCT + testDevice1: _AllTypes_MyRWBlock; + testDevice2: _AllTypes_MyRWBlock; + +END_STRUCT; +BEGIN +END_DATA_BLOCK + +DATA_BLOCK AllTypes_MyWOBlock +{ S7_Optimized_Access := 'FALSE' } +AUTHOR: schwinn +FAMILY: SILECS +NAME: BLK_MODE +STRUCT + testDevice1: _AllTypes_MyWOBlock; + testDevice2: _AllTypes_MyWOBlock; + +END_STRUCT; +BEGIN +END_DATA_BLOCK + diff --git a/silecs-codegen/src/xml/test/generated_correct/controller/Siemens_TiaBlock.sdf b/silecs-codegen/src/xml/test/generated_correct/controller/Siemens_TiaBlock.sdf new file mode 100644 index 0000000..29a5f58 --- /dev/null +++ b/silecs-codegen/src/xml/test/generated_correct/controller/Siemens_TiaBlock.sdf @@ -0,0 +1,8 @@ +"_SilecsHeader_hdrBlk","UDT 0","UDT 0","[SilecsHeader/1.0.0] UDT symbol: _<class-name>_<block-name>" +"SilecsHeader_hdrBlk","DB 0","DB 0","[SilecsHeader/1.0.0] DB symbol: <class-name>_<block-name>" +"_AllTypes_MyROBlock","UDT 1","UDT 1","[AllTypes/0.1.0] UDT symbol: _<class-name>_<block-name>" +"_AllTypes_MyRWBlock","UDT 2","UDT 2","" +"_AllTypes_MyWOBlock","UDT 3","UDT 3","" +"AllTypes_MyROBlock","DB 1","DB 1","[AllTypes/0.1.0] DB symbol: <class-name>_<block-name>" +"AllTypes_MyRWBlock","DB 2","DB 2","" +"AllTypes_MyWOBlock","DB 3","DB 3","" diff --git a/silecs-codegen/src/xml/test/generated_correct/controller/Siemens_TiaDevice.scl b/silecs-codegen/src/xml/test/generated_correct/controller/Siemens_TiaDevice.scl new file mode 100644 index 0000000..3f0ee9d --- /dev/null +++ b/silecs-codegen/src/xml/test/generated_correct/controller/Siemens_TiaDevice.scl @@ -0,0 +1,147 @@ +//--------------------------------------------------------------------- +// SilecsHeader/ v1.0.0 +// BLOCK Type definition +//--------------------------------------------------------------------- +TYPE _SilecsHeader_hdrBlk +AUTHOR: schwinn +FAMILY: SILECS +NAME: UDTB + STRUCT + _version: STRING[16] := 'SILECS_DEV'; + _checksum: DWORD := DW#16#eae21021; + _user: STRING[16] := 'schwinn'; + _date: DT := DT#2016-7-14-16:6:23; + + END_STRUCT; +END_TYPE + +//--------------------------------------------------------------------- +// SilecsHeader/ v1.0.0 +// Block instance definition +//--------------------------------------------------------------------- +DATA_BLOCK SilecsHeader_SilecsHeader +{ S7_Optimized_Access := 'FALSE' } +AUTHOR: schwinn +FAMILY: SILECS +NAME: DEV_MODE +STRUCT + hdrBlk: _SilecsHeader_hdrBlk; + +END_STRUCT; +BEGIN +END_DATA_BLOCK + +//--------------------------------------------------------------------- +// AllTypes/ v0.1.0 +// BLOCK Type definition +//--------------------------------------------------------------------- +TYPE _AllTypes_MyROBlock +AUTHOR: schwinn +FAMILY: SILECS +NAME: UDTB + STRUCT + RO_int8: CHAR; + RO_uint8: BYTE; + RO_int16: INT; + RO_uint16: WORD; + RO_int32: DINT; + RO_uint32: DWORD; + RO_float32: REAL; + RO_string: STRING[64]; + RO_date: DT; + RO_char: CHAR; + RO_byte: BYTE; + RO_word: WORD; + RO_dword: DWORD; + RO_int: INT; + RO_dint: DINT; + RO_real: REAL; + RO_dt: DT; + + END_STRUCT; +END_TYPE + +TYPE _AllTypes_MyRWBlock +AUTHOR: schwinn +FAMILY: SILECS +NAME: UDTB + STRUCT + RW_int8: ARRAY[0..1, 0..1] OF CHAR; + RW_uint8: ARRAY[0..1, 0..1] OF BYTE; + RW_int16: ARRAY[0..1, 0..1] OF INT; + RW_uint16: ARRAY[0..1, 0..1] OF WORD; + RW_int32: ARRAY[0..1, 0..1] OF DINT; + RW_uint32: ARRAY[0..1, 0..1] OF DWORD; + RW_float32: ARRAY[0..1, 0..1] OF REAL; + RW_string: ARRAY[0..1, 0..1] OF STRING[64]; + RW_date: ARRAY[0..1, 0..1] OF DT; + RW_char: ARRAY[0..1, 0..1] OF CHAR; + RW_byte: ARRAY[0..1, 0..1] OF BYTE; + RW_word: ARRAY[0..1, 0..1] OF WORD; + RW_dword: ARRAY[0..1, 0..1] OF DWORD; + RW_int: ARRAY[0..1, 0..1] OF INT; + RW_dint: ARRAY[0..1, 0..1] OF DINT; + RW_real: ARRAY[0..1, 0..1] OF REAL; + RW_dt: ARRAY[0..1, 0..1] OF DT; + + END_STRUCT; +END_TYPE + +TYPE _AllTypes_MyWOBlock +AUTHOR: schwinn +FAMILY: SILECS +NAME: UDTB + STRUCT + WO_int8: ARRAY[0..9] OF CHAR; + WO_uint8: ARRAY[0..9] OF BYTE; + WO_int16: ARRAY[0..9] OF INT; + WO_uint16: ARRAY[0..9] OF WORD; + WO_int32: ARRAY[0..9] OF DINT; + WO_uint32: ARRAY[0..9] OF DWORD; + WO_float32: ARRAY[0..9] OF REAL; + WO_string: ARRAY[0..9] OF STRING[64]; + WO_date: ARRAY[0..9] OF DT; + WO_char: ARRAY[0..9] OF CHAR; + WO_byte: ARRAY[0..9] OF BYTE; + WO_word: ARRAY[0..9] OF WORD; + WO_dword: ARRAY[0..9] OF DWORD; + WO_int: ARRAY[0..9] OF INT; + WO_dint: ARRAY[0..9] OF DINT; + WO_real: ARRAY[0..9] OF REAL; + WO_dt: ARRAY[0..9] OF DT; + + END_STRUCT; +END_TYPE + +//--------------------------------------------------------------------- +// AllTypes/ v0.1.0 +// Block instance definition +//--------------------------------------------------------------------- +DATA_BLOCK AllTypes_testDevice1 +{ S7_Optimized_Access := 'FALSE' } +AUTHOR: schwinn +FAMILY: SILECS +NAME: DEV_MODE +STRUCT + MyROBlock: _AllTypes_MyROBlock; + MyRWBlock: _AllTypes_MyRWBlock; + MyWOBlock: _AllTypes_MyWOBlock; + +END_STRUCT; +BEGIN +END_DATA_BLOCK + +DATA_BLOCK AllTypes_testDevice2 +{ S7_Optimized_Access := 'FALSE' } +AUTHOR: schwinn +FAMILY: SILECS +NAME: DEV_MODE +STRUCT + MyROBlock: _AllTypes_MyROBlock; + MyRWBlock: _AllTypes_MyRWBlock; + MyWOBlock: _AllTypes_MyWOBlock; + +END_STRUCT; +BEGIN +END_DATA_BLOCK + diff --git a/silecs-codegen/src/xml/test/generated_correct/controller/Siemens_TiaDevice.sdf b/silecs-codegen/src/xml/test/generated_correct/controller/Siemens_TiaDevice.sdf new file mode 100644 index 0000000..e5d2ddb --- /dev/null +++ b/silecs-codegen/src/xml/test/generated_correct/controller/Siemens_TiaDevice.sdf @@ -0,0 +1,7 @@ +"_SilecsHeader_hdrBlk","UDT 0","UDT 0","[SilecsHeader/1.0.0] UDT symbol: _<class-name>_<block-name>" +"SilecsHeader_SilecsHeader","DB 0","DB 0","[SilecsHeader/1.0.0] DB symbol: <class-name>_<device-label | device-id>" +"_AllTypes_MyROBlock","UDT 1","UDT 1","[AllTypes/0.1.0] UDT symbol: _<class-name>_<block-name>" +"_AllTypes_MyRWBlock","UDT 2","UDT 2","" +"_AllTypes_MyWOBlock","UDT 3","UDT 3","" +"AllTypes_testDevice1","DB 1","DB 1","[AllTypes/0.1.0] DB symbol: <class-name>_<device-label | device-id>" +"AllTypes_testDevice2","DB 2","DB 2","" diff --git a/silecs-codegen/src/xml/test/generated_correct/wrapper/AllTypes.h b/silecs-codegen/src/xml/test/generated_correct/wrapper/AllTypes.h new file mode 100644 index 0000000..5900b5b --- /dev/null +++ b/silecs-codegen/src/xml/test/generated_correct/wrapper/AllTypes.h @@ -0,0 +1,38 @@ +/* Copyright CERN 2015 + * + * WARNING: This code is automatically generated from your SILECS deploy unit document. + * You should never modify the content of this file as it would break consistency. + * Furthermore, any changes will be overwritten in the next code generation. + * Any modification shall be done using the SILECS development environment + * and regenerating this source code. + */ + +#ifndef ALLTYPES_H_ +#define ALLTYPES_H_ + +#include <silecs-communication/wrapper/Block.h> +#include <silecs-communication/wrapper/DeployUnit.h> +#include <silecs-communication/wrapper/Design.h> +#include <silecs-communication/wrapper/Device.h> + +namespace AllTypes +{ + + +class Design : public SilecsWrapper::Design +{ +public: + + Design(SilecsWrapper::DeployUnit *deployUnit) : + SilecsWrapper::Design("AllTypes", "0.1.0", deployUnit) + { + } + + ~Design() + { + } +}; + +} /* namespace AllTypes */ + +#endif /* ALLTYPES_H_ */ diff --git a/silecs-codegen/src/xml/test/generated_correct/wrapper/Beckhoff_BC9020.h b/silecs-codegen/src/xml/test/generated_correct/wrapper/Beckhoff_BC9020.h new file mode 100644 index 0000000..0434b10 --- /dev/null +++ b/silecs-codegen/src/xml/test/generated_correct/wrapper/Beckhoff_BC9020.h @@ -0,0 +1,153 @@ +/* Copyright CERN 2015 + * + * WARNING: This code is automatically generated from your SILECS deploy unit document. + * You should never modify the content of this file as it would break consistency. + * Furthermore, any changes will be overwritten in the next code generation. + * Any modification shall be done using the SILECS development environment + * and regenerating this source code. + */ + +#ifndef ALLTYPESDU_H_ +#define ALLTYPESDU_H_ + +#include <silecs-communication/interface/equipment/SilecsCluster.h> +#include <silecs-communication/wrapper/DeployUnit.h> +#include <silecs-communication/wrapper/Design.h> + +#include "AllTypes.h" + +namespace AllTypesDU +{ + +typedef SilecsWrapper::DeployConfig DeployConfig; +typedef SilecsWrapper::DesignConfig DesignConfig; + +class DeployUnit : public SilecsWrapper::DeployUnit +{ +public: + + /*! + * \brief Use this method to create/get the unique instance of the Deploy Unit. + * + * \param logTopics This parameter can be used to enable/disable log topics + * valid topics are ERROR[,INFO,DEBUG,SETUP,ALLOC,RECV,SEND,COMM,DATA,LOCK]. + * + * \param globalConfig This parameter can be used to pass different parameters to + * the library. I.e. enabling automatic connection. + */ + static DeployUnit* getInstance(const std::string& logTopics = "", + const SilecsWrapper::DeployConfig& globalConfig = SilecsWrapper::DeployConfig()) + { + if (_instance == NULL) + { + _instance = new DeployUnit(logTopics, globalConfig); + } + else + { + if (logTopics.empty() == false) + { + _instance->getService()->setLogTopics(logTopics); + } + } + return dynamic_cast<DeployUnit*>(_instance); + } + + /*! + * \brief Use this method to create/get the unique instance of the Deploy Unit. + * + * \param globalConfig This parameter can be used to pass different parameters to + * the library. I.e. enabling automatic connection. + */ + static DeployUnit* getInstance(const SilecsWrapper::DeployConfig& globalConfig) + { + return getInstance("", globalConfig); + } + + /*! + * \brief Return pointer to the deployed design AllTypes. + */ + AllTypes::Design* getAllTypes() + { + return _AllTypes; + } + +private: + + AllTypes::Design* _AllTypes; + + DeployUnit(const std::string& logTopics, const SilecsWrapper::DeployConfig& globalConfig) : + SilecsWrapper::DeployUnit("AllTypesDU", "0.1.0", logTopics, globalConfig) + { + // Construct Design AllTypes + _AllTypes = new AllTypes::Design((SilecsWrapper::DeployUnit*) this); + + } + + ~DeployUnit() + { + delete _AllTypes; + } +}; + + +class Controller : public SilecsWrapper::Controller +{ +public: + Controller(SilecsWrapper::Design *design, const std::string parameterFile) : + SilecsWrapper::Controller("Beckhoff_BC9020", "", design, parameterFile) + { + _deviceMap.insert(std::pair<std::string, SilecsWrapper::Device*>("testDevice1", new SilecsWrapper::Device("testDevice1", this))); + _deviceMap.insert(std::pair<std::string, SilecsWrapper::Device*>("testDevice2", new SilecsWrapper::Device("testDevice2", this))); + } + + ~Controller() + { + map<std::string, SilecsWrapper::Device*>::iterator it; + for (it = _deviceMap.begin(); it != _deviceMap.end(); it++) + { + delete it->second; + } + } + + /*! + * \brief Return pointer to the requested device. + * \param label Device label. + */ + SilecsWrapper::Device* getDevice(const std::string& label) + { + if (_deviceMap.find(label) != _deviceMap.end()) + { + return _deviceMap[label]; + } + throw Silecs::SilecsException(__FILE__, __LINE__, Silecs::PARAM_UNKNOWN_DEVICE_NAME, label); + } + + std::map<std::string, SilecsWrapper::Device*>& getDeviceMap() + { + return _deviceMap; + } + + /*! + * \brief Get pointer to device testDevice1. + */ + SilecsWrapper::Device* getTestDevice1() + { + return _deviceMap["testDevice1"]; + } + + /*! + * \brief Get pointer to device testDevice2. + */ + SilecsWrapper::Device* getTestDevice2() + { + return _deviceMap["testDevice2"]; + } + +private: + std::map<std::string, SilecsWrapper::Device*> _deviceMap; +}; + + +} /* namespace AllTypesDU */ + +#endif /* ALLTYPESDU_H_ */ diff --git a/silecs-codegen/src/xml/test/generated_correct/wrapper/Beckhoff_CX9020.h b/silecs-codegen/src/xml/test/generated_correct/wrapper/Beckhoff_CX9020.h new file mode 100644 index 0000000..7feef99 --- /dev/null +++ b/silecs-codegen/src/xml/test/generated_correct/wrapper/Beckhoff_CX9020.h @@ -0,0 +1,153 @@ +/* Copyright CERN 2015 + * + * WARNING: This code is automatically generated from your SILECS deploy unit document. + * You should never modify the content of this file as it would break consistency. + * Furthermore, any changes will be overwritten in the next code generation. + * Any modification shall be done using the SILECS development environment + * and regenerating this source code. + */ + +#ifndef ALLTYPESDU_H_ +#define ALLTYPESDU_H_ + +#include <silecs-communication/interface/equipment/SilecsCluster.h> +#include <silecs-communication/wrapper/DeployUnit.h> +#include <silecs-communication/wrapper/Design.h> + +#include "AllTypes.h" + +namespace AllTypesDU +{ + +typedef SilecsWrapper::DeployConfig DeployConfig; +typedef SilecsWrapper::DesignConfig DesignConfig; + +class DeployUnit : public SilecsWrapper::DeployUnit +{ +public: + + /*! + * \brief Use this method to create/get the unique instance of the Deploy Unit. + * + * \param logTopics This parameter can be used to enable/disable log topics + * valid topics are ERROR[,INFO,DEBUG,SETUP,ALLOC,RECV,SEND,COMM,DATA,LOCK]. + * + * \param globalConfig This parameter can be used to pass different parameters to + * the library. I.e. enabling automatic connection. + */ + static DeployUnit* getInstance(const std::string& logTopics = "", + const SilecsWrapper::DeployConfig& globalConfig = SilecsWrapper::DeployConfig()) + { + if (_instance == NULL) + { + _instance = new DeployUnit(logTopics, globalConfig); + } + else + { + if (logTopics.empty() == false) + { + _instance->getService()->setLogTopics(logTopics); + } + } + return dynamic_cast<DeployUnit*>(_instance); + } + + /*! + * \brief Use this method to create/get the unique instance of the Deploy Unit. + * + * \param globalConfig This parameter can be used to pass different parameters to + * the library. I.e. enabling automatic connection. + */ + static DeployUnit* getInstance(const SilecsWrapper::DeployConfig& globalConfig) + { + return getInstance("", globalConfig); + } + + /*! + * \brief Return pointer to the deployed design AllTypes. + */ + AllTypes::Design* getAllTypes() + { + return _AllTypes; + } + +private: + + AllTypes::Design* _AllTypes; + + DeployUnit(const std::string& logTopics, const SilecsWrapper::DeployConfig& globalConfig) : + SilecsWrapper::DeployUnit("AllTypesDU", "0.1.0", logTopics, globalConfig) + { + // Construct Design AllTypes + _AllTypes = new AllTypes::Design((SilecsWrapper::DeployUnit*) this); + + } + + ~DeployUnit() + { + delete _AllTypes; + } +}; + + +class Controller : public SilecsWrapper::Controller +{ +public: + Controller(SilecsWrapper::Design *design, const std::string parameterFile) : + SilecsWrapper::Controller("Beckhoff_CX9020", "", design, parameterFile) + { + _deviceMap.insert(std::pair<std::string, SilecsWrapper::Device*>("testDevice1", new SilecsWrapper::Device("testDevice1", this))); + _deviceMap.insert(std::pair<std::string, SilecsWrapper::Device*>("testDevice2", new SilecsWrapper::Device("testDevice2", this))); + } + + ~Controller() + { + map<std::string, SilecsWrapper::Device*>::iterator it; + for (it = _deviceMap.begin(); it != _deviceMap.end(); it++) + { + delete it->second; + } + } + + /*! + * \brief Return pointer to the requested device. + * \param label Device label. + */ + SilecsWrapper::Device* getDevice(const std::string& label) + { + if (_deviceMap.find(label) != _deviceMap.end()) + { + return _deviceMap[label]; + } + throw Silecs::SilecsException(__FILE__, __LINE__, Silecs::PARAM_UNKNOWN_DEVICE_NAME, label); + } + + std::map<std::string, SilecsWrapper::Device*>& getDeviceMap() + { + return _deviceMap; + } + + /*! + * \brief Get pointer to device testDevice1. + */ + SilecsWrapper::Device* getTestDevice1() + { + return _deviceMap["testDevice1"]; + } + + /*! + * \brief Get pointer to device testDevice2. + */ + SilecsWrapper::Device* getTestDevice2() + { + return _deviceMap["testDevice2"]; + } + +private: + std::map<std::string, SilecsWrapper::Device*> _deviceMap; +}; + + +} /* namespace AllTypesDU */ + +#endif /* ALLTYPESDU_H_ */ diff --git a/silecs-codegen/src/xml/test/generated_correct/wrapper/Makefile b/silecs-codegen/src/xml/test/generated_correct/wrapper/Makefile new file mode 100644 index 0000000..3f11b2c --- /dev/null +++ b/silecs-codegen/src/xml/test/generated_correct/wrapper/Makefile @@ -0,0 +1,59 @@ +## Help on how to modify Makefiles you can get e.g. here: http://www.ijon.de/comp/tutorials/makefile.html + +#CPU ?= i686 +CPU=x86_64 + +LIBS += -pthread + +SILECS_COMM_VERSION = 1.0.2 +SILECS_COMM_HOME ?= ../../../../../../silecs-communication-cpp/build +SNAP7_BASE = ../../../../../../snap7/snap7-full +LIBXML_PATH = /usr/include/libxml2/ + +COMPILER_FLAGS += -I$(SILECS_COMM_HOME)/include +COMPILER_FLAGS += -I$(LIBXML_PATH) + +LINKER_FLAGS += -L$(SILECS_COMM_HOME)/lib/$(CPU) +LINKER_FLAGS += -L$(SNAP7_BASE)/build/bin/$(CPU)-linux -lsnap7 +LINKER_FLAGS += -L/usr/lib64 -lxml2 +LINKER_FLAGS += -lsilecs-comm + + +#Optimisation flag ( 00 till 03 ) +COMPILER_FLAGS += -O2 + +# Warn all - always use this to make the compiler really picky (and thus more helpful) +COMPILER_FLAGS += -Wall + +#include debugging symbols - always use this or your debugger doesn't work! +COMPILER_FLAGS += -g + +# files to work with: +SOURCES = main.cpp +TARGET = Test + +# .o files have same name as .cpp files +OBJS = $(SOURCES:%.cpp=%.o) + +# Link command to compile + build binary: +link: $(OBJS) + g++ $(OBJS) $(LINKER_FLAGS) -o $(TARGET) $(LIBS) + +# Compilation command: +# Generic Way to create a .o file for each .cpp file (for many cpp files) $< is the "first dependency" +%.o: %.cpp + g++ $(INCLUDES) $(COMPILER_FLAGS) -c $< + +#support for "make all" +all: link + @echo "-- build of target: '$(TARGET)' finished --" + +#support for "make clean" +clean: + rm -f $(OBJS) $(TARGET) $(LIBRARY) + +#if you just type "make", the first command in the list of commands is executed + +# Simple Compilation command: +#compile: $(CPP) +# g++ $(INCLUDES) $(COMPILER_FLAGS) -c $(CPP) -o $(OBJS) \ No newline at end of file diff --git a/silecs-codegen/src/xml/test/generated_correct/wrapper/Rabbit_BlockMode.h b/silecs-codegen/src/xml/test/generated_correct/wrapper/Rabbit_BlockMode.h new file mode 100644 index 0000000..c562005 --- /dev/null +++ b/silecs-codegen/src/xml/test/generated_correct/wrapper/Rabbit_BlockMode.h @@ -0,0 +1,153 @@ +/* Copyright CERN 2015 + * + * WARNING: This code is automatically generated from your SILECS deploy unit document. + * You should never modify the content of this file as it would break consistency. + * Furthermore, any changes will be overwritten in the next code generation. + * Any modification shall be done using the SILECS development environment + * and regenerating this source code. + */ + +#ifndef ALLTYPESDU_H_ +#define ALLTYPESDU_H_ + +#include <silecs-communication/interface/equipment/SilecsCluster.h> +#include <silecs-communication/wrapper/DeployUnit.h> +#include <silecs-communication/wrapper/Design.h> + +#include "AllTypes.h" + +namespace AllTypesDU +{ + +typedef SilecsWrapper::DeployConfig DeployConfig; +typedef SilecsWrapper::DesignConfig DesignConfig; + +class DeployUnit : public SilecsWrapper::DeployUnit +{ +public: + + /*! + * \brief Use this method to create/get the unique instance of the Deploy Unit. + * + * \param logTopics This parameter can be used to enable/disable log topics + * valid topics are ERROR[,INFO,DEBUG,SETUP,ALLOC,RECV,SEND,COMM,DATA,LOCK]. + * + * \param globalConfig This parameter can be used to pass different parameters to + * the library. I.e. enabling automatic connection. + */ + static DeployUnit* getInstance(const std::string& logTopics = "", + const SilecsWrapper::DeployConfig& globalConfig = SilecsWrapper::DeployConfig()) + { + if (_instance == NULL) + { + _instance = new DeployUnit(logTopics, globalConfig); + } + else + { + if (logTopics.empty() == false) + { + _instance->getService()->setLogTopics(logTopics); + } + } + return dynamic_cast<DeployUnit*>(_instance); + } + + /*! + * \brief Use this method to create/get the unique instance of the Deploy Unit. + * + * \param globalConfig This parameter can be used to pass different parameters to + * the library. I.e. enabling automatic connection. + */ + static DeployUnit* getInstance(const SilecsWrapper::DeployConfig& globalConfig) + { + return getInstance("", globalConfig); + } + + /*! + * \brief Return pointer to the deployed design AllTypes. + */ + AllTypes::Design* getAllTypes() + { + return _AllTypes; + } + +private: + + AllTypes::Design* _AllTypes; + + DeployUnit(const std::string& logTopics, const SilecsWrapper::DeployConfig& globalConfig) : + SilecsWrapper::DeployUnit("AllTypesDU", "0.1.0", logTopics, globalConfig) + { + // Construct Design AllTypes + _AllTypes = new AllTypes::Design((SilecsWrapper::DeployUnit*) this); + + } + + ~DeployUnit() + { + delete _AllTypes; + } +}; + + +class Controller : public SilecsWrapper::Controller +{ +public: + Controller(SilecsWrapper::Design *design, const std::string parameterFile) : + SilecsWrapper::Controller("Rabbit_BlockMode", "", design, parameterFile) + { + _deviceMap.insert(std::pair<std::string, SilecsWrapper::Device*>("testDevice1", new SilecsWrapper::Device("testDevice1", this))); + _deviceMap.insert(std::pair<std::string, SilecsWrapper::Device*>("testDevice2", new SilecsWrapper::Device("testDevice2", this))); + } + + ~Controller() + { + map<std::string, SilecsWrapper::Device*>::iterator it; + for (it = _deviceMap.begin(); it != _deviceMap.end(); it++) + { + delete it->second; + } + } + + /*! + * \brief Return pointer to the requested device. + * \param label Device label. + */ + SilecsWrapper::Device* getDevice(const std::string& label) + { + if (_deviceMap.find(label) != _deviceMap.end()) + { + return _deviceMap[label]; + } + throw Silecs::SilecsException(__FILE__, __LINE__, Silecs::PARAM_UNKNOWN_DEVICE_NAME, label); + } + + std::map<std::string, SilecsWrapper::Device*>& getDeviceMap() + { + return _deviceMap; + } + + /*! + * \brief Get pointer to device testDevice1. + */ + SilecsWrapper::Device* getTestDevice1() + { + return _deviceMap["testDevice1"]; + } + + /*! + * \brief Get pointer to device testDevice2. + */ + SilecsWrapper::Device* getTestDevice2() + { + return _deviceMap["testDevice2"]; + } + +private: + std::map<std::string, SilecsWrapper::Device*> _deviceMap; +}; + + +} /* namespace AllTypesDU */ + +#endif /* ALLTYPESDU_H_ */ diff --git a/silecs-codegen/src/xml/test/generated_correct/wrapper/Rabbit_DeviceMode.h b/silecs-codegen/src/xml/test/generated_correct/wrapper/Rabbit_DeviceMode.h new file mode 100644 index 0000000..a90d775 --- /dev/null +++ b/silecs-codegen/src/xml/test/generated_correct/wrapper/Rabbit_DeviceMode.h @@ -0,0 +1,153 @@ +/* Copyright CERN 2015 + * + * WARNING: This code is automatically generated from your SILECS deploy unit document. + * You should never modify the content of this file as it would break consistency. + * Furthermore, any changes will be overwritten in the next code generation. + * Any modification shall be done using the SILECS development environment + * and regenerating this source code. + */ + +#ifndef ALLTYPESDU_H_ +#define ALLTYPESDU_H_ + +#include <silecs-communication/interface/equipment/SilecsCluster.h> +#include <silecs-communication/wrapper/DeployUnit.h> +#include <silecs-communication/wrapper/Design.h> + +#include "AllTypes.h" + +namespace AllTypesDU +{ + +typedef SilecsWrapper::DeployConfig DeployConfig; +typedef SilecsWrapper::DesignConfig DesignConfig; + +class DeployUnit : public SilecsWrapper::DeployUnit +{ +public: + + /*! + * \brief Use this method to create/get the unique instance of the Deploy Unit. + * + * \param logTopics This parameter can be used to enable/disable log topics + * valid topics are ERROR[,INFO,DEBUG,SETUP,ALLOC,RECV,SEND,COMM,DATA,LOCK]. + * + * \param globalConfig This parameter can be used to pass different parameters to + * the library. I.e. enabling automatic connection. + */ + static DeployUnit* getInstance(const std::string& logTopics = "", + const SilecsWrapper::DeployConfig& globalConfig = SilecsWrapper::DeployConfig()) + { + if (_instance == NULL) + { + _instance = new DeployUnit(logTopics, globalConfig); + } + else + { + if (logTopics.empty() == false) + { + _instance->getService()->setLogTopics(logTopics); + } + } + return dynamic_cast<DeployUnit*>(_instance); + } + + /*! + * \brief Use this method to create/get the unique instance of the Deploy Unit. + * + * \param globalConfig This parameter can be used to pass different parameters to + * the library. I.e. enabling automatic connection. + */ + static DeployUnit* getInstance(const SilecsWrapper::DeployConfig& globalConfig) + { + return getInstance("", globalConfig); + } + + /*! + * \brief Return pointer to the deployed design AllTypes. + */ + AllTypes::Design* getAllTypes() + { + return _AllTypes; + } + +private: + + AllTypes::Design* _AllTypes; + + DeployUnit(const std::string& logTopics, const SilecsWrapper::DeployConfig& globalConfig) : + SilecsWrapper::DeployUnit("AllTypesDU", "0.1.0", logTopics, globalConfig) + { + // Construct Design AllTypes + _AllTypes = new AllTypes::Design((SilecsWrapper::DeployUnit*) this); + + } + + ~DeployUnit() + { + delete _AllTypes; + } +}; + + +class Controller : public SilecsWrapper::Controller +{ +public: + Controller(SilecsWrapper::Design *design, const std::string parameterFile) : + SilecsWrapper::Controller("Rabbit_DeviceMode", "", design, parameterFile) + { + _deviceMap.insert(std::pair<std::string, SilecsWrapper::Device*>("testDevice1", new SilecsWrapper::Device("testDevice1", this))); + _deviceMap.insert(std::pair<std::string, SilecsWrapper::Device*>("testDevice2", new SilecsWrapper::Device("testDevice2", this))); + } + + ~Controller() + { + map<std::string, SilecsWrapper::Device*>::iterator it; + for (it = _deviceMap.begin(); it != _deviceMap.end(); it++) + { + delete it->second; + } + } + + /*! + * \brief Return pointer to the requested device. + * \param label Device label. + */ + SilecsWrapper::Device* getDevice(const std::string& label) + { + if (_deviceMap.find(label) != _deviceMap.end()) + { + return _deviceMap[label]; + } + throw Silecs::SilecsException(__FILE__, __LINE__, Silecs::PARAM_UNKNOWN_DEVICE_NAME, label); + } + + std::map<std::string, SilecsWrapper::Device*>& getDeviceMap() + { + return _deviceMap; + } + + /*! + * \brief Get pointer to device testDevice1. + */ + SilecsWrapper::Device* getTestDevice1() + { + return _deviceMap["testDevice1"]; + } + + /*! + * \brief Get pointer to device testDevice2. + */ + SilecsWrapper::Device* getTestDevice2() + { + return _deviceMap["testDevice2"]; + } + +private: + std::map<std::string, SilecsWrapper::Device*> _deviceMap; +}; + + +} /* namespace AllTypesDU */ + +#endif /* ALLTYPESDU_H_ */ diff --git a/silecs-codegen/src/xml/test/generated_correct/wrapper/Schneider_M340.h b/silecs-codegen/src/xml/test/generated_correct/wrapper/Schneider_M340.h new file mode 100644 index 0000000..d31fa17 --- /dev/null +++ b/silecs-codegen/src/xml/test/generated_correct/wrapper/Schneider_M340.h @@ -0,0 +1,153 @@ +/* Copyright CERN 2015 + * + * WARNING: This code is automatically generated from your SILECS deploy unit document. + * You should never modify the content of this file as it would break consistency. + * Furthermore, any changes will be overwritten in the next code generation. + * Any modification shall be done using the SILECS development environment + * and regenerating this source code. + */ + +#ifndef ALLTYPESDU_H_ +#define ALLTYPESDU_H_ + +#include <silecs-communication/interface/equipment/SilecsCluster.h> +#include <silecs-communication/wrapper/DeployUnit.h> +#include <silecs-communication/wrapper/Design.h> + +#include "AllTypes.h" + +namespace AllTypesDU +{ + +typedef SilecsWrapper::DeployConfig DeployConfig; +typedef SilecsWrapper::DesignConfig DesignConfig; + +class DeployUnit : public SilecsWrapper::DeployUnit +{ +public: + + /*! + * \brief Use this method to create/get the unique instance of the Deploy Unit. + * + * \param logTopics This parameter can be used to enable/disable log topics + * valid topics are ERROR[,INFO,DEBUG,SETUP,ALLOC,RECV,SEND,COMM,DATA,LOCK]. + * + * \param globalConfig This parameter can be used to pass different parameters to + * the library. I.e. enabling automatic connection. + */ + static DeployUnit* getInstance(const std::string& logTopics = "", + const SilecsWrapper::DeployConfig& globalConfig = SilecsWrapper::DeployConfig()) + { + if (_instance == NULL) + { + _instance = new DeployUnit(logTopics, globalConfig); + } + else + { + if (logTopics.empty() == false) + { + _instance->getService()->setLogTopics(logTopics); + } + } + return dynamic_cast<DeployUnit*>(_instance); + } + + /*! + * \brief Use this method to create/get the unique instance of the Deploy Unit. + * + * \param globalConfig This parameter can be used to pass different parameters to + * the library. I.e. enabling automatic connection. + */ + static DeployUnit* getInstance(const SilecsWrapper::DeployConfig& globalConfig) + { + return getInstance("", globalConfig); + } + + /*! + * \brief Return pointer to the deployed design AllTypes. + */ + AllTypes::Design* getAllTypes() + { + return _AllTypes; + } + +private: + + AllTypes::Design* _AllTypes; + + DeployUnit(const std::string& logTopics, const SilecsWrapper::DeployConfig& globalConfig) : + SilecsWrapper::DeployUnit("AllTypesDU", "0.1.0", logTopics, globalConfig) + { + // Construct Design AllTypes + _AllTypes = new AllTypes::Design((SilecsWrapper::DeployUnit*) this); + + } + + ~DeployUnit() + { + delete _AllTypes; + } +}; + + +class Controller : public SilecsWrapper::Controller +{ +public: + Controller(SilecsWrapper::Design *design, const std::string parameterFile) : + SilecsWrapper::Controller("Schneider_M340", "", design, parameterFile) + { + _deviceMap.insert(std::pair<std::string, SilecsWrapper::Device*>("testDevice1", new SilecsWrapper::Device("testDevice1", this))); + _deviceMap.insert(std::pair<std::string, SilecsWrapper::Device*>("testDevice2", new SilecsWrapper::Device("testDevice2", this))); + } + + ~Controller() + { + map<std::string, SilecsWrapper::Device*>::iterator it; + for (it = _deviceMap.begin(); it != _deviceMap.end(); it++) + { + delete it->second; + } + } + + /*! + * \brief Return pointer to the requested device. + * \param label Device label. + */ + SilecsWrapper::Device* getDevice(const std::string& label) + { + if (_deviceMap.find(label) != _deviceMap.end()) + { + return _deviceMap[label]; + } + throw Silecs::SilecsException(__FILE__, __LINE__, Silecs::PARAM_UNKNOWN_DEVICE_NAME, label); + } + + std::map<std::string, SilecsWrapper::Device*>& getDeviceMap() + { + return _deviceMap; + } + + /*! + * \brief Get pointer to device testDevice1. + */ + SilecsWrapper::Device* getTestDevice1() + { + return _deviceMap["testDevice1"]; + } + + /*! + * \brief Get pointer to device testDevice2. + */ + SilecsWrapper::Device* getTestDevice2() + { + return _deviceMap["testDevice2"]; + } + +private: + std::map<std::string, SilecsWrapper::Device*> _deviceMap; +}; + + +} /* namespace AllTypesDU */ + +#endif /* ALLTYPESDU_H_ */ diff --git a/silecs-codegen/src/xml/test/generated_correct/wrapper/Schneider_PremiumQuantum.h b/silecs-codegen/src/xml/test/generated_correct/wrapper/Schneider_PremiumQuantum.h new file mode 100644 index 0000000..58576f6 --- /dev/null +++ b/silecs-codegen/src/xml/test/generated_correct/wrapper/Schneider_PremiumQuantum.h @@ -0,0 +1,153 @@ +/* Copyright CERN 2015 + * + * WARNING: This code is automatically generated from your SILECS deploy unit document. + * You should never modify the content of this file as it would break consistency. + * Furthermore, any changes will be overwritten in the next code generation. + * Any modification shall be done using the SILECS development environment + * and regenerating this source code. + */ + +#ifndef ALLTYPESDU_H_ +#define ALLTYPESDU_H_ + +#include <silecs-communication/interface/equipment/SilecsCluster.h> +#include <silecs-communication/wrapper/DeployUnit.h> +#include <silecs-communication/wrapper/Design.h> + +#include "AllTypes.h" + +namespace AllTypesDU +{ + +typedef SilecsWrapper::DeployConfig DeployConfig; +typedef SilecsWrapper::DesignConfig DesignConfig; + +class DeployUnit : public SilecsWrapper::DeployUnit +{ +public: + + /*! + * \brief Use this method to create/get the unique instance of the Deploy Unit. + * + * \param logTopics This parameter can be used to enable/disable log topics + * valid topics are ERROR[,INFO,DEBUG,SETUP,ALLOC,RECV,SEND,COMM,DATA,LOCK]. + * + * \param globalConfig This parameter can be used to pass different parameters to + * the library. I.e. enabling automatic connection. + */ + static DeployUnit* getInstance(const std::string& logTopics = "", + const SilecsWrapper::DeployConfig& globalConfig = SilecsWrapper::DeployConfig()) + { + if (_instance == NULL) + { + _instance = new DeployUnit(logTopics, globalConfig); + } + else + { + if (logTopics.empty() == false) + { + _instance->getService()->setLogTopics(logTopics); + } + } + return dynamic_cast<DeployUnit*>(_instance); + } + + /*! + * \brief Use this method to create/get the unique instance of the Deploy Unit. + * + * \param globalConfig This parameter can be used to pass different parameters to + * the library. I.e. enabling automatic connection. + */ + static DeployUnit* getInstance(const SilecsWrapper::DeployConfig& globalConfig) + { + return getInstance("", globalConfig); + } + + /*! + * \brief Return pointer to the deployed design AllTypes. + */ + AllTypes::Design* getAllTypes() + { + return _AllTypes; + } + +private: + + AllTypes::Design* _AllTypes; + + DeployUnit(const std::string& logTopics, const SilecsWrapper::DeployConfig& globalConfig) : + SilecsWrapper::DeployUnit("AllTypesDU", "0.1.0", logTopics, globalConfig) + { + // Construct Design AllTypes + _AllTypes = new AllTypes::Design((SilecsWrapper::DeployUnit*) this); + + } + + ~DeployUnit() + { + delete _AllTypes; + } +}; + + +class Controller : public SilecsWrapper::Controller +{ +public: + Controller(SilecsWrapper::Design *design, const std::string parameterFile) : + SilecsWrapper::Controller("Schneider_PremiumQuantum", "", design, parameterFile) + { + _deviceMap.insert(std::pair<std::string, SilecsWrapper::Device*>("testDevice1", new SilecsWrapper::Device("testDevice1", this))); + _deviceMap.insert(std::pair<std::string, SilecsWrapper::Device*>("testDevice2", new SilecsWrapper::Device("testDevice2", this))); + } + + ~Controller() + { + map<std::string, SilecsWrapper::Device*>::iterator it; + for (it = _deviceMap.begin(); it != _deviceMap.end(); it++) + { + delete it->second; + } + } + + /*! + * \brief Return pointer to the requested device. + * \param label Device label. + */ + SilecsWrapper::Device* getDevice(const std::string& label) + { + if (_deviceMap.find(label) != _deviceMap.end()) + { + return _deviceMap[label]; + } + throw Silecs::SilecsException(__FILE__, __LINE__, Silecs::PARAM_UNKNOWN_DEVICE_NAME, label); + } + + std::map<std::string, SilecsWrapper::Device*>& getDeviceMap() + { + return _deviceMap; + } + + /*! + * \brief Get pointer to device testDevice1. + */ + SilecsWrapper::Device* getTestDevice1() + { + return _deviceMap["testDevice1"]; + } + + /*! + * \brief Get pointer to device testDevice2. + */ + SilecsWrapper::Device* getTestDevice2() + { + return _deviceMap["testDevice2"]; + } + +private: + std::map<std::string, SilecsWrapper::Device*> _deviceMap; +}; + + +} /* namespace AllTypesDU */ + +#endif /* ALLTYPESDU_H_ */ diff --git a/silecs-codegen/src/xml/test/generated_correct/wrapper/Siemens_Step7Block.h b/silecs-codegen/src/xml/test/generated_correct/wrapper/Siemens_Step7Block.h new file mode 100644 index 0000000..9e32650 --- /dev/null +++ b/silecs-codegen/src/xml/test/generated_correct/wrapper/Siemens_Step7Block.h @@ -0,0 +1,153 @@ +/* Copyright CERN 2015 + * + * WARNING: This code is automatically generated from your SILECS deploy unit document. + * You should never modify the content of this file as it would break consistency. + * Furthermore, any changes will be overwritten in the next code generation. + * Any modification shall be done using the SILECS development environment + * and regenerating this source code. + */ + +#ifndef ALLTYPESDU_H_ +#define ALLTYPESDU_H_ + +#include <silecs-communication/interface/equipment/SilecsCluster.h> +#include <silecs-communication/wrapper/DeployUnit.h> +#include <silecs-communication/wrapper/Design.h> + +#include "AllTypes.h" + +namespace AllTypesDU +{ + +typedef SilecsWrapper::DeployConfig DeployConfig; +typedef SilecsWrapper::DesignConfig DesignConfig; + +class DeployUnit : public SilecsWrapper::DeployUnit +{ +public: + + /*! + * \brief Use this method to create/get the unique instance of the Deploy Unit. + * + * \param logTopics This parameter can be used to enable/disable log topics + * valid topics are ERROR[,INFO,DEBUG,SETUP,ALLOC,RECV,SEND,COMM,DATA,LOCK]. + * + * \param globalConfig This parameter can be used to pass different parameters to + * the library. I.e. enabling automatic connection. + */ + static DeployUnit* getInstance(const std::string& logTopics = "", + const SilecsWrapper::DeployConfig& globalConfig = SilecsWrapper::DeployConfig()) + { + if (_instance == NULL) + { + _instance = new DeployUnit(logTopics, globalConfig); + } + else + { + if (logTopics.empty() == false) + { + _instance->getService()->setLogTopics(logTopics); + } + } + return dynamic_cast<DeployUnit*>(_instance); + } + + /*! + * \brief Use this method to create/get the unique instance of the Deploy Unit. + * + * \param globalConfig This parameter can be used to pass different parameters to + * the library. I.e. enabling automatic connection. + */ + static DeployUnit* getInstance(const SilecsWrapper::DeployConfig& globalConfig) + { + return getInstance("", globalConfig); + } + + /*! + * \brief Return pointer to the deployed design AllTypes. + */ + AllTypes::Design* getAllTypes() + { + return _AllTypes; + } + +private: + + AllTypes::Design* _AllTypes; + + DeployUnit(const std::string& logTopics, const SilecsWrapper::DeployConfig& globalConfig) : + SilecsWrapper::DeployUnit("AllTypesDU", "0.1.0", logTopics, globalConfig) + { + // Construct Design AllTypes + _AllTypes = new AllTypes::Design((SilecsWrapper::DeployUnit*) this); + + } + + ~DeployUnit() + { + delete _AllTypes; + } +}; + + +class Controller : public SilecsWrapper::Controller +{ +public: + Controller(SilecsWrapper::Design *design, const std::string parameterFile) : + SilecsWrapper::Controller("Siemens_Step7Block", "", design, parameterFile) + { + _deviceMap.insert(std::pair<std::string, SilecsWrapper::Device*>("testDevice1", new SilecsWrapper::Device("testDevice1", this))); + _deviceMap.insert(std::pair<std::string, SilecsWrapper::Device*>("testDevice2", new SilecsWrapper::Device("testDevice2", this))); + } + + ~Controller() + { + map<std::string, SilecsWrapper::Device*>::iterator it; + for (it = _deviceMap.begin(); it != _deviceMap.end(); it++) + { + delete it->second; + } + } + + /*! + * \brief Return pointer to the requested device. + * \param label Device label. + */ + SilecsWrapper::Device* getDevice(const std::string& label) + { + if (_deviceMap.find(label) != _deviceMap.end()) + { + return _deviceMap[label]; + } + throw Silecs::SilecsException(__FILE__, __LINE__, Silecs::PARAM_UNKNOWN_DEVICE_NAME, label); + } + + std::map<std::string, SilecsWrapper::Device*>& getDeviceMap() + { + return _deviceMap; + } + + /*! + * \brief Get pointer to device testDevice1. + */ + SilecsWrapper::Device* getTestDevice1() + { + return _deviceMap["testDevice1"]; + } + + /*! + * \brief Get pointer to device testDevice2. + */ + SilecsWrapper::Device* getTestDevice2() + { + return _deviceMap["testDevice2"]; + } + +private: + std::map<std::string, SilecsWrapper::Device*> _deviceMap; +}; + + +} /* namespace AllTypesDU */ + +#endif /* ALLTYPESDU_H_ */ diff --git a/silecs-codegen/src/xml/test/generated_correct/wrapper/Siemens_Step7Device.h b/silecs-codegen/src/xml/test/generated_correct/wrapper/Siemens_Step7Device.h new file mode 100644 index 0000000..be5bd8a --- /dev/null +++ b/silecs-codegen/src/xml/test/generated_correct/wrapper/Siemens_Step7Device.h @@ -0,0 +1,153 @@ +/* Copyright CERN 2015 + * + * WARNING: This code is automatically generated from your SILECS deploy unit document. + * You should never modify the content of this file as it would break consistency. + * Furthermore, any changes will be overwritten in the next code generation. + * Any modification shall be done using the SILECS development environment + * and regenerating this source code. + */ + +#ifndef ALLTYPESDU_H_ +#define ALLTYPESDU_H_ + +#include <silecs-communication/interface/equipment/SilecsCluster.h> +#include <silecs-communication/wrapper/DeployUnit.h> +#include <silecs-communication/wrapper/Design.h> + +#include "AllTypes.h" + +namespace AllTypesDU +{ + +typedef SilecsWrapper::DeployConfig DeployConfig; +typedef SilecsWrapper::DesignConfig DesignConfig; + +class DeployUnit : public SilecsWrapper::DeployUnit +{ +public: + + /*! + * \brief Use this method to create/get the unique instance of the Deploy Unit. + * + * \param logTopics This parameter can be used to enable/disable log topics + * valid topics are ERROR[,INFO,DEBUG,SETUP,ALLOC,RECV,SEND,COMM,DATA,LOCK]. + * + * \param globalConfig This parameter can be used to pass different parameters to + * the library. I.e. enabling automatic connection. + */ + static DeployUnit* getInstance(const std::string& logTopics = "", + const SilecsWrapper::DeployConfig& globalConfig = SilecsWrapper::DeployConfig()) + { + if (_instance == NULL) + { + _instance = new DeployUnit(logTopics, globalConfig); + } + else + { + if (logTopics.empty() == false) + { + _instance->getService()->setLogTopics(logTopics); + } + } + return dynamic_cast<DeployUnit*>(_instance); + } + + /*! + * \brief Use this method to create/get the unique instance of the Deploy Unit. + * + * \param globalConfig This parameter can be used to pass different parameters to + * the library. I.e. enabling automatic connection. + */ + static DeployUnit* getInstance(const SilecsWrapper::DeployConfig& globalConfig) + { + return getInstance("", globalConfig); + } + + /*! + * \brief Return pointer to the deployed design AllTypes. + */ + AllTypes::Design* getAllTypes() + { + return _AllTypes; + } + +private: + + AllTypes::Design* _AllTypes; + + DeployUnit(const std::string& logTopics, const SilecsWrapper::DeployConfig& globalConfig) : + SilecsWrapper::DeployUnit("AllTypesDU", "0.1.0", logTopics, globalConfig) + { + // Construct Design AllTypes + _AllTypes = new AllTypes::Design((SilecsWrapper::DeployUnit*) this); + + } + + ~DeployUnit() + { + delete _AllTypes; + } +}; + + +class Controller : public SilecsWrapper::Controller +{ +public: + Controller(SilecsWrapper::Design *design, const std::string parameterFile) : + SilecsWrapper::Controller("Siemens_Step7Device", "", design, parameterFile) + { + _deviceMap.insert(std::pair<std::string, SilecsWrapper::Device*>("testDevice1", new SilecsWrapper::Device("testDevice1", this))); + _deviceMap.insert(std::pair<std::string, SilecsWrapper::Device*>("testDevice2", new SilecsWrapper::Device("testDevice2", this))); + } + + ~Controller() + { + map<std::string, SilecsWrapper::Device*>::iterator it; + for (it = _deviceMap.begin(); it != _deviceMap.end(); it++) + { + delete it->second; + } + } + + /*! + * \brief Return pointer to the requested device. + * \param label Device label. + */ + SilecsWrapper::Device* getDevice(const std::string& label) + { + if (_deviceMap.find(label) != _deviceMap.end()) + { + return _deviceMap[label]; + } + throw Silecs::SilecsException(__FILE__, __LINE__, Silecs::PARAM_UNKNOWN_DEVICE_NAME, label); + } + + std::map<std::string, SilecsWrapper::Device*>& getDeviceMap() + { + return _deviceMap; + } + + /*! + * \brief Get pointer to device testDevice1. + */ + SilecsWrapper::Device* getTestDevice1() + { + return _deviceMap["testDevice1"]; + } + + /*! + * \brief Get pointer to device testDevice2. + */ + SilecsWrapper::Device* getTestDevice2() + { + return _deviceMap["testDevice2"]; + } + +private: + std::map<std::string, SilecsWrapper::Device*> _deviceMap; +}; + + +} /* namespace AllTypesDU */ + +#endif /* ALLTYPESDU_H_ */ diff --git a/silecs-codegen/src/xml/test/generated_correct/wrapper/Siemens_TiaBlock.h b/silecs-codegen/src/xml/test/generated_correct/wrapper/Siemens_TiaBlock.h new file mode 100644 index 0000000..63877a3 --- /dev/null +++ b/silecs-codegen/src/xml/test/generated_correct/wrapper/Siemens_TiaBlock.h @@ -0,0 +1,153 @@ +/* Copyright CERN 2015 + * + * WARNING: This code is automatically generated from your SILECS deploy unit document. + * You should never modify the content of this file as it would break consistency. + * Furthermore, any changes will be overwritten in the next code generation. + * Any modification shall be done using the SILECS development environment + * and regenerating this source code. + */ + +#ifndef ALLTYPESDU_H_ +#define ALLTYPESDU_H_ + +#include <silecs-communication/interface/equipment/SilecsCluster.h> +#include <silecs-communication/wrapper/DeployUnit.h> +#include <silecs-communication/wrapper/Design.h> + +#include "AllTypes.h" + +namespace AllTypesDU +{ + +typedef SilecsWrapper::DeployConfig DeployConfig; +typedef SilecsWrapper::DesignConfig DesignConfig; + +class DeployUnit : public SilecsWrapper::DeployUnit +{ +public: + + /*! + * \brief Use this method to create/get the unique instance of the Deploy Unit. + * + * \param logTopics This parameter can be used to enable/disable log topics + * valid topics are ERROR[,INFO,DEBUG,SETUP,ALLOC,RECV,SEND,COMM,DATA,LOCK]. + * + * \param globalConfig This parameter can be used to pass different parameters to + * the library. I.e. enabling automatic connection. + */ + static DeployUnit* getInstance(const std::string& logTopics = "", + const SilecsWrapper::DeployConfig& globalConfig = SilecsWrapper::DeployConfig()) + { + if (_instance == NULL) + { + _instance = new DeployUnit(logTopics, globalConfig); + } + else + { + if (logTopics.empty() == false) + { + _instance->getService()->setLogTopics(logTopics); + } + } + return dynamic_cast<DeployUnit*>(_instance); + } + + /*! + * \brief Use this method to create/get the unique instance of the Deploy Unit. + * + * \param globalConfig This parameter can be used to pass different parameters to + * the library. I.e. enabling automatic connection. + */ + static DeployUnit* getInstance(const SilecsWrapper::DeployConfig& globalConfig) + { + return getInstance("", globalConfig); + } + + /*! + * \brief Return pointer to the deployed design AllTypes. + */ + AllTypes::Design* getAllTypes() + { + return _AllTypes; + } + +private: + + AllTypes::Design* _AllTypes; + + DeployUnit(const std::string& logTopics, const SilecsWrapper::DeployConfig& globalConfig) : + SilecsWrapper::DeployUnit("AllTypesDU", "0.1.0", logTopics, globalConfig) + { + // Construct Design AllTypes + _AllTypes = new AllTypes::Design((SilecsWrapper::DeployUnit*) this); + + } + + ~DeployUnit() + { + delete _AllTypes; + } +}; + + +class Controller : public SilecsWrapper::Controller +{ +public: + Controller(SilecsWrapper::Design *design, const std::string parameterFile) : + SilecsWrapper::Controller("Siemens_TiaBlock", "", design, parameterFile) + { + _deviceMap.insert(std::pair<std::string, SilecsWrapper::Device*>("testDevice1", new SilecsWrapper::Device("testDevice1", this))); + _deviceMap.insert(std::pair<std::string, SilecsWrapper::Device*>("testDevice2", new SilecsWrapper::Device("testDevice2", this))); + } + + ~Controller() + { + map<std::string, SilecsWrapper::Device*>::iterator it; + for (it = _deviceMap.begin(); it != _deviceMap.end(); it++) + { + delete it->second; + } + } + + /*! + * \brief Return pointer to the requested device. + * \param label Device label. + */ + SilecsWrapper::Device* getDevice(const std::string& label) + { + if (_deviceMap.find(label) != _deviceMap.end()) + { + return _deviceMap[label]; + } + throw Silecs::SilecsException(__FILE__, __LINE__, Silecs::PARAM_UNKNOWN_DEVICE_NAME, label); + } + + std::map<std::string, SilecsWrapper::Device*>& getDeviceMap() + { + return _deviceMap; + } + + /*! + * \brief Get pointer to device testDevice1. + */ + SilecsWrapper::Device* getTestDevice1() + { + return _deviceMap["testDevice1"]; + } + + /*! + * \brief Get pointer to device testDevice2. + */ + SilecsWrapper::Device* getTestDevice2() + { + return _deviceMap["testDevice2"]; + } + +private: + std::map<std::string, SilecsWrapper::Device*> _deviceMap; +}; + + +} /* namespace AllTypesDU */ + +#endif /* ALLTYPESDU_H_ */ diff --git a/silecs-codegen/src/xml/test/generated_correct/wrapper/Siemens_TiaDevice.h b/silecs-codegen/src/xml/test/generated_correct/wrapper/Siemens_TiaDevice.h new file mode 100644 index 0000000..e6a3029 --- /dev/null +++ b/silecs-codegen/src/xml/test/generated_correct/wrapper/Siemens_TiaDevice.h @@ -0,0 +1,153 @@ +/* Copyright CERN 2015 + * + * WARNING: This code is automatically generated from your SILECS deploy unit document. + * You should never modify the content of this file as it would break consistency. + * Furthermore, any changes will be overwritten in the next code generation. + * Any modification shall be done using the SILECS development environment + * and regenerating this source code. + */ + +#ifndef ALLTYPESDU_H_ +#define ALLTYPESDU_H_ + +#include <silecs-communication/interface/equipment/SilecsCluster.h> +#include <silecs-communication/wrapper/DeployUnit.h> +#include <silecs-communication/wrapper/Design.h> + +#include "AllTypes.h" + +namespace AllTypesDU +{ + +typedef SilecsWrapper::DeployConfig DeployConfig; +typedef SilecsWrapper::DesignConfig DesignConfig; + +class DeployUnit : public SilecsWrapper::DeployUnit +{ +public: + + /*! + * \brief Use this method to create/get the unique instance of the Deploy Unit. + * + * \param logTopics This parameter can be used to enable/disable log topics + * valid topics are ERROR[,INFO,DEBUG,SETUP,ALLOC,RECV,SEND,COMM,DATA,LOCK]. + * + * \param globalConfig This parameter can be used to pass different parameters to + * the library. I.e. enabling automatic connection. + */ + static DeployUnit* getInstance(const std::string& logTopics = "", + const SilecsWrapper::DeployConfig& globalConfig = SilecsWrapper::DeployConfig()) + { + if (_instance == NULL) + { + _instance = new DeployUnit(logTopics, globalConfig); + } + else + { + if (logTopics.empty() == false) + { + _instance->getService()->setLogTopics(logTopics); + } + } + return dynamic_cast<DeployUnit*>(_instance); + } + + /*! + * \brief Use this method to create/get the unique instance of the Deploy Unit. + * + * \param globalConfig This parameter can be used to pass different parameters to + * the library. I.e. enabling automatic connection. + */ + static DeployUnit* getInstance(const SilecsWrapper::DeployConfig& globalConfig) + { + return getInstance("", globalConfig); + } + + /*! + * \brief Return pointer to the deployed design AllTypes. + */ + AllTypes::Design* getAllTypes() + { + return _AllTypes; + } + +private: + + AllTypes::Design* _AllTypes; + + DeployUnit(const std::string& logTopics, const SilecsWrapper::DeployConfig& globalConfig) : + SilecsWrapper::DeployUnit("AllTypesDU", "0.1.0", logTopics, globalConfig) + { + // Construct Design AllTypes + _AllTypes = new AllTypes::Design((SilecsWrapper::DeployUnit*) this); + + } + + ~DeployUnit() + { + delete _AllTypes; + } +}; + + +class Controller : public SilecsWrapper::Controller +{ +public: + Controller(SilecsWrapper::Design *design, const std::string parameterFile) : + SilecsWrapper::Controller("Siemens_TiaDevice", "", design, parameterFile) + { + _deviceMap.insert(std::pair<std::string, SilecsWrapper::Device*>("testDevice1", new SilecsWrapper::Device("testDevice1", this))); + _deviceMap.insert(std::pair<std::string, SilecsWrapper::Device*>("testDevice2", new SilecsWrapper::Device("testDevice2", this))); + } + + ~Controller() + { + map<std::string, SilecsWrapper::Device*>::iterator it; + for (it = _deviceMap.begin(); it != _deviceMap.end(); it++) + { + delete it->second; + } + } + + /*! + * \brief Return pointer to the requested device. + * \param label Device label. + */ + SilecsWrapper::Device* getDevice(const std::string& label) + { + if (_deviceMap.find(label) != _deviceMap.end()) + { + return _deviceMap[label]; + } + throw Silecs::SilecsException(__FILE__, __LINE__, Silecs::PARAM_UNKNOWN_DEVICE_NAME, label); + } + + std::map<std::string, SilecsWrapper::Device*>& getDeviceMap() + { + return _deviceMap; + } + + /*! + * \brief Get pointer to device testDevice1. + */ + SilecsWrapper::Device* getTestDevice1() + { + return _deviceMap["testDevice1"]; + } + + /*! + * \brief Get pointer to device testDevice2. + */ + SilecsWrapper::Device* getTestDevice2() + { + return _deviceMap["testDevice2"]; + } + +private: + std::map<std::string, SilecsWrapper::Device*> _deviceMap; +}; + + +} /* namespace AllTypesDU */ + +#endif /* ALLTYPESDU_H_ */ diff --git a/silecs-codegen/src/xml/test/generated_correct/wrapper/Test b/silecs-codegen/src/xml/test/generated_correct/wrapper/Test new file mode 100755 index 0000000000000000000000000000000000000000..e50a15463ea588b2eb28f158b3e9211f19d4d720 GIT binary patch literal 2479440 zcmce<dq9-M{y)BIBwd$G%S?-m3M&&-6f+A#a!D)_Ov?%oP)TmVVwhGKa&p@!x}EG! zoi3iPR#s+(C@NZ~BD>j5>FTVjX<24j@q4}AGtV**`{|tTAHS{Td0wx1&&+$?^PcN7 z&w71o`guKj^l&+!p02Z9L~%JuLg~LQ*XDv4!TgitN_0iy?-19?t^<K1gkuQ9k~&?R zOw!IZQbJv>Ubr5>`<{mAnWS&bb)ZHr=jv$4EA#94B$-=%9XL>jI#-t~TEZERy1JrG z?C1jFUFNEe(J*$TzB=)!9^+LF)A6c?>3GhyLw_C5DId$m??6+&fjyIeh?976jhDY2 zSFr`SjBma9ypIjgLcFGQx?XmyK$mlM;$4JzQa&C0w|^ZyhZPmh7&UTOQU1`P!jj6W zp;d{ahK?F}Mn&lv!$tonq(s|IxL}H;>DZ$W5cBSfFEwTOv8OGm8g}ZSX_u|{9#J>v z!adhb-SGvrUxP36I|$#}{u!=n&!DL4i9KDl(dj*V#`TOj)OFk2u4)SP>{Z><RewN_ z<VBvzA1ptr?`<_r(Fc7OJ^cKGCiIwg&k?<+7Bj78eAnaKg6{@=H{#3BoA|zk?|<-p z2VZ{P#dj0FAK?2Dz8~ZJ3BI4<y9M7b@%<X#Z}4?K-{R&wd;^Bqj%yI#9R}|-S6;ry z_Xm7`B*146zCYvp3%>jC{S{yP^Bcf^e1A9OAH2fAY=S-U?S*dyzP<512w#2<HrGSV z^)Ory$9Kq=zx8WMt2?J?=%~FD@=v_tw$Fa?zBum1MaQ?hf33SD>4(uretOQ0w{D*C z$nO8#Jn5y9l*iuxe(k00LpN+XY+&CXuAQ6o+eJl>T)p<HTQ={H`ElG)o<q~hpDg`x z^?3iBF-6rmy(4yPTzK%NEmwcAyypdV=LC;i-}3n@LkDHt9{KC4pT2r)_k%Sng75D- z{D+8xj+>CWYI4Opv6mDj?bx`Y?uWy(hb6w8x$9rAUiD@3+O%ihnEX=C_rr&M_e51= z|KF3Eu08LUSI+xx`h9a}O+W4Mk}s?7pLff`d(#(WO*!o0v6c7U@yZWx{BhxHOWN;v z@gFhs(&oJU&`WoFQ&K<Nap0?0mU#EPx%kUhcb;C*oc}?O*%6Q5_WJ{|A6#_mg4e#j zeL++4%9DP6X43qVbI!lK-;zU9j?Ta8{_=mG+ha)Thv}=%{OHq9u9`M*Us=QO2lC!n zr>)xk-#gtd7k#_y=L<M+cl=vNbk9ekyXa2-lEcIBVe&mMO!_O(FuP0tRQLs={N-~~ z82z_}N#`6i>h99_gpuEKSoiXGLZ9x^$>`lZUvp^p{0r#Zx=SZHj6U<j=;J!Ld;7S< zly_;Edigd?z5EeI{ww6$o&Fz(DepaD>~m_EdR!hxpJU)}-TA}UVf4%mW6vF7_&d<4 zcUP{j!|3V90MecOV`0)iD@;1UFn%>EO!_Zku<9<~H^bO}R2aTEO#07-vFDmF^>}xf z@?IOJT&u#!Zw=F*JQKzr?g``Pmxn3u3t{9RIHY@f9uvks8DaFlHH@B1!lbh&OgaO? z@Udai85O2~xH63W6T<lU&@lbdurT^WhtcQKF!C*7>UV1x`SoG=m0{93H;g`|VcHAl zCf&88Kp1;I9HxGIglX65VeENzm~wpu|Lm@RdpC^!2SNGn^nWr;|NKIjas22o=^P)X zyoZO;r!-7E`YDVZehyQQ>%-K`#4zo8Y#2Su!q|CK82fArqyO|U=?7rX?&>QwO#509 z#{RxA>8FPA!-vAyjqA(kzs#1f-V5WO(XexO`ac|||L+sVPwK+x<3fFPm;U=<>g9<r z^*$#|y$=b~pT7{M9{Ysh-wWfPBg53osbTEUH%$FzA)W5*a7h^XPr~p=gwf~SF!ehr zOn>-i82euvrrx)N$@lp%=~RZ1|2mAF?+GLSQW(GbAdH_}8paOSh0$|zm~@U0qbECC z{QsBFKf<JcWf*%#gy9Rr*x{`(^6#LZL6pCI&JWYB`-e%VcbI&4hiP|n!j!i;O#6xq z(~rFxM!q$S-!2HFXLA_7Buqcw7N*`uhne3dgpn@@<0tFF@Rx^4hx;qt`Bh{XJ3JZ2 zo>zpiXK|SR<fSnFP!guyeHTX0Az|#F8pi(Tgvs~eFm{Uwqt9z$?D>5deZGZ#5cHQ1 z%;}2$3+r;#h4J%K!{~o}nEBi9;rb=mr#pT6hROHWFy;L-jGa#nGf(S}jm{HXN4cU- zE|5|?WxosUeX#2=*QEz13-9>k^rN+W^@&<O*4U~EyvRptdCouh*^7uwe|K!>^e^qN z`LeG08hw_T^dTmnNZ9QN7dDB{?3_;QQ97NZ(=}gZ<i{MT<(pD8kLdF0ZRDGVc9y>r zJkzfpr+JuHKGE1er~YlHbe5lO$`yT@<{dkH&`+n+YVvjT-)!<N>tY85J(+&e8J*ML zjdY}5hG;(8=(F6|C#j46KN>z`aA)~Qlg{o_JL`F~v43k9eKr`rsf+xXCjB;(KHO41 z0rX2Jz;4l|UZxp-kg-FKv8QAI<!E5^lTE#~pQIT1sYZTw7x|&aul_MW%l9=E!+1>R z!1^RfVXR4~&FJqsNtZX#@Pmz=cN_gZhL6LwkLz&PzJEEI=l~z;m;T@xuhVh#k22|0 zcd_$rhF{ht-xa9$KG1XI#B(L#yG_3LNI!Ont061NF#2*C{Ehimb+N+&*m*ESVyASL zUm<oI;A$PyS<h7CZ>^>sMeF2UPZ+-~>!Rm1urvLwHKwzlyo+*CpSE)}PkZr`Z2Y02 zi~N1Y-<EZ;&()4!b@AtOjJ(UF<J8wY;}085J966NRFq5lnHp_Rs3)KQnEI+u?QDnd zjUA%9`17NtybY%RsWR#Ga>~`EUCcLpj?ojvk<X>3U!8VEl410v%-HRs^R+&X{)x~t z%JoCLGWF#|dJZ=%*I{n$=L=21nZ|AzUHX|P48Pmh)9HUU8$Fx4^oKEKKC?7C$;nc# zXPW*ksY^ecVf-Yci~meC`p0JJayf}jN51rvj4tK9#-v~0rQT_8mbb`^FHZa2E8{Zy zVbh;P8N-#M9+`ewmv(WHX?ICo`salhf1#=?GAGGVQLYEVZp^nVLbrF0_xzj_rd|#= ze$r&@Prdo^Md*I7VXU^pG)=o)c<xwHl3O+!j~ZRs*|UmEOR_7xx#iyMY*+UAbF(KG z%qpz#7L=zH<yKS_RJgKd7M2t;QdM!$aQ%2P`_fErSy5VErZ+x5Z+32ZwzoXD&|8s~ zmztT2KdG5B(z3F%;<B^ivr{Ke%p8@SnTWLi*GL%?Ge`Vy(Ikds=z_8-MFqJfm1P;Z z<rM|xB+^O>y&dSh!jk+HD4$xASDIf~GRu=&l3%0+C*>9umF6+Z<bu%c1*Q1~>9EX% z0&k|b91$3PUU@+QuOKtZOUrmGIh<EmB>c3DT<`1)3a(BmE%6pqc^NKL>fGF-)T*-b zf{Kd5(vlF(<Sv|XWkFttBq=L4;dtnlQdF3oT3%jSp2cK|#-BU2ywF=<?xA?T+(NUI zvb2(!r5&i!h8abu#$0b@g^pNQkylz$LIs#6GUk1jjy%4g!dqTCPluEj<eJQo!-eJf za2Oa!oXeY^ciL(6lu@oS?`#O>XXk105X>#fD<}$uURhdL0{^&RA{;7VMs7u69z2pJ zo>4h7yqArDOzK?5%Pbv}Jt@1e1oiAq%TG<6oLQPh&&j&@g7~=X?7XU~+!=*)<Ksu; zo?e~pomW->`I)7u;+A9J?!|>AC=ip&^p4CcC@)9b$g9fD&VvJFSC$l1mBA1N`4T>S zO!nj%aQXr!!c4Q_JK5z0GjfYquo)RBM`B2%1a`?rsR}aVvL|O!uM0B0iG`&VLXM<Y zj*suAAjKU8>6Bh!39MOMP~r`f4Km2O7%@g_OBT+AoeFY`yE7z<e?ev;j5H}5epH^D z=S?eOwuO_$fKb$`5F`?&LQ=;MX92QjRaIq|6_i($mgE){dgo=&jnk!#AE9-biDnTl ziIJsc1tqB&6WObb$WDWKE(B3br~0dsVjD}zF{Z5AZNe8=_fH+>9#K~5P0iCvI%$-m zBZCfIdbZS&=mx#1w0Vb%hAe`PP7<l0BNkVpK^3GH7Z-P<`IVM=yZGmD_-aLAcP?6T zwIqf1k&s8<MJEdzP0GHyFu$M#J_yBhL#P-H7X98F!Quv{Sf&4+X^hvG7og#mUaiYC z5@SM{_(;C)0obXtqnBX2?TPQ`wg=bw8-pg~LDBM57<9N)H>#X=(|L}{Eko_+(;rAo z%&ZulS6W<_TV9|kX`7agqtL7iXO&Ph3|VmM3Ww1tAeW97nP2dCEl83tt1K_bo?BS% zt;{X@OHpTZw9d}0<nOwzlz34R3U%Y<e`m84X=m&}{>He86$M@~XLt6^FUm0PB2^2& z%gin)E<=MYFDOITTUwqws{pktR+xeLKnc1*Z{BPeA=67Q6~n{NN@jUyXQQtyEqAQk z5n5X5%`TmpU7lMqtH9J^r%KU{!){Igh2^@pT7_{X7OEr{35((~a>Jp}v*i_(c{$F~ zF}(5rTZ;&F78Rp0To;tjMavdL#E;6(hRd>Vb;h3V`i;rdS$9uHT2GErF)xw{3w;Y? z4!phFDHVF-@ChKQH1duv>F<ol7+D=gz=Vba?cep7Flqigm=+^*UT%dKiTu3_nlXWc zD9RS{Aj$o|9Gfz|MHOjKwrgM9jY;ydvQsk?U{R;Ph#!H8Yd&VL<rQ>9X>_I+?dVHP zcOm(7Q+ay0=q5Lr-lk@b&PD<=(lSS8BWuofX&CfCqbe$Az@!)gw51#e_`k+K^a~t9 zX|9=^S=e5ipX)T(4sSI5h{>V?5M}S^n6qHFF?Jf9)}T$Y{y95v`j7v%{-s=r7+vya z7v#-JEw-Ap?x{mPZ)w8JqRNWdG6EqZv=ZH2%-}o_&Ldq9j5Lz<L#0Dj`tQAXe4I1j z88e_*$O{v^j=ZG(>wd1wbW59B`hx#rV&a%Qq;j5a|NpCNnrX&=H7|4W%q%UcNG&u@ z^goy<G@nHD(0CXcQH@u2xQA}4ojL~gRsT)LfQ4bPp6eHtmsXbKa|JLf4-<Hj@viJC zC0DZ<PA;gZESBYgSpzUQF0=x`q9b4CF(C$%sDi3&GvRP?5fKWiC@7kVmV%7X8&#H< zV=9b!)2wnY=J1w~w*s!3k0}F21ZUv^vEtl{IU%fb;RGr~i7HoPJ=>XaG;varn7LkW zc{WB`&dHz=M#7TPY%CpfWwhxeO1ewF68o=ta~^{UM{XWRE!WJv5^u*!X%<HHj#71N zgWRf+;vG76)m{oYqr5aXU%K<WqSA_j&e5>u5sfR*cNbU8VzuV!dagi03cRk0GWdsg zrmL`|0P7zwMpw-IF%!^4iMKS@g~@dVB4Rh8#Dz-Zs?u9pRC+a5*(gX^VZN3vW8~~? zZZ}{lH8Z!c$VD3#c?*jRvddj?M8tAc%&RCWo#o<s4C`Mr#KT8WQLvayUr-Y+t|BNm z177DUE-20`E@Ng?x)kQDm|f}3FTEQ26wb=c&u0vT&W5+om<MdMmpjg&Osry^DKvq( z3Y;V{7ns38u>dM!{VRpiDG6!PmHWzyqJjcZgoP@dnV&n)H6yRIY+gr6T{DeAjkXf6 zcn;;oTIHqQQj;BuRa`n3+0qrVDbJfq?p{zulo%IX8OBBQ22XJ=8VIH$1(LQ@I!(pl z1_rI-e3A8B?$vD<0(o<oyy%c!ke}<#h1`sa3cX?E;<zs3$pxb_v9imn7=sOi{6acE zM?x%b3?Dx_BRwS((&G!}7UmU9!lF)wN+()YMGE>3tineZXB3ndmgbx22{TGjGo$hg zyl{&6go?6k3}KMVm!-2L5kEp_J++)GhVuBh@daf?rSqnsNsr;Q%*z#d7j5FwO5mF3 zvUr_CMnKKZOro<LCYc$1N2Hg|8tpADE6l5qA>S%!Lgod@8KYqa?wc4pgsc$P!6z10 zBo`IVEpXy@F6n5iq=m(0McHL(9f_nC$?AXFr1aF(PFg|vL^SM@Nx5ZCvX1@Z5oVX9 zL*r4IvioC7{TFLOW9<19!L>vpO;%Tkt@VwM=b&DO?HkmctxLRB)X{|%X{ZgYQd+o} zSsf)z&^4OsOxularYytb(hI%bqJmU-T5d`Ag^G{M9Nm4$=uEU)xM1frM<xHIvK+zq z;S~kNa|_BR<z87@-o>nAPzQQL(JuR6ViuN|m`)wif8s~!4lS($6;Mu>?yOS$2;<Rz zRZXJDA-d&)osy1YgGI8%UHu>tZqSX}$B#a@aMu56&k<}-^SU=F)sgad;}gz2#?)O` z(_nWrZ?+WN(LW?Hvali(eKn>a<I!Drl8Nu?ASRa%r)C4>erp$#j*?c8H&;yHbV41m z;uEqkS4m0EvdifxHY!VYGSe=|%<ft>sUylOv2(?#rkz;#UaXBYe6%zi%pTBS(Ycir zlxJh)Dwl~v7p;d+Iv2&U`;$!Xh~nHbw8acZJG;GM#XqtL8_NjiemqcFZee*Ermva9 zv(aUAsgo|HNt{_(q8kIYD>G2q|HGE-(YxBROAj(?d;#Y(or?tWuWc|s{=!Oc_uaA# zACn96=5`)FI*dIA72DBH!2kE%>F{LC;R<J9wi)VBJJRiBR$aYa%4d%^(g?bE`WR;j z>e9RuOf#I2l9D|F6X6NzY3HV74?ko083``jLYLt{BhMINf~HM_*vK>D<F%xLV_YfI zrX`=7mK}e_2s<E@+z7l(hEGqtDRuz95qP8S0Q}e6U~;_Yf4t{^l%PESixgJJA>th# zTj6t%gdYfoF?-|7FwOEwG;?7H4$0uE^Pservw6xLB+`x!jO(P&*u;@?rR2dP>!iyt zT{`ALDgJkW>k#>?@2RnqudNmJW(gUlHKV3IfgMe>X3U)>);aXXm0B_EKpYxn*=aR0 z`kuKt7Sww7a`ou+Usv2Ylqj;3eAn;;|Ig6B#_yb(&fU?$IXA#qIe6yJa}&|{W}G|^ zPdX2E-Gb+%{4o4@c?PM&D+d(fMBgE<e_G+AAm_wy^QYtFQE%5HR``Wh`Z|6@r}(20 z*@>^i53s@ya9x2j1`N-@H+SFNKnJ^?NBZP^*AD?c$kk-<`_Ik66VOQ4I|h4)+>WC5 za(xogr>E;$qYt9Hbbbd)eoU|Y7?!W6>suq=WS%qgaqlaPU_SLR`uS>CeuH^_-j%P4 z*Ye^S3^bo=i+|T4ab0ZjUt4^=#Y551XNkq{2(d0#gT?=B@k=d!qs2Stm|(=vd!7tl zX366SMCh}^;@5{*m#fL*zp?lY7XPKiw_5yL7Qflz54P;qX7R^c^2*}*-ly}~ZSmha zB(D1`{(Fme4ezM0O%@+%@%t=3%Hr2pe6+=XV)3ySzsus|ES~RvIG;p||J5OJO|tk6 z7Vok64=g^z;?cB2pJ^8VVTg6PaxDHMi=S=rpILmF#s6sWRTlq+#aCPW9*bXW@w+X) z-r~1g{1S_AwfF{$f8XMlTKs=3ewoF;Y4Iy8KGWixEIw%Q8!Y}Oi*L1f=Y3-aZ?^ci zE%`Q!|IXr-#lL6qyDfgN#qYCt?b#-9M2DaA9cSkgY4ODliEEU_^L=jT)8FE+a!6dG zEq<-V$69=(m9KNYCIYfHA7{xgu+mAi_?;G?WbwaPyvO3#S$u}YJMVonc$&rEWy$AQ z{68&zw#7eS@nshOr^Q!Ue2c|bTl^0ezu4kGw)lFBZ@2g*7Qflz8!W!f;+I<dI~Kpp z;`!dZ^I2i>${}%WviKDizro@Uw9;v{_}47?%@+TL#kX1fAyzuhc~AP!r<S~P9*Vr% zl6Q?P5Gl^?Y&z27F~JCZqAXs|iFHtai^tKs&?nmBnYZ(awRp}6oKKv^2OJXDM2n}c z&L_#@ojD!DJQk0m*P%~_#bcru`b@KU9I+04axC6Clg7Z=7LVyv=u>9#m<WbGRTj^A zmh-8$c>A3BVvEQ0GxVvqcpR|{eU?}}j{Jo_4Hkb?h;_M^T0D-@g+9wHzJG{yxmH-b znHoxHlf@6P<TqISu@>KI@y=Ov25+|bL6&@*#UE$!%HpFfez(P+VDbAbez3*65<2|< zM2nBK_!x_iviOrMzQ4tvZ1K?+e~QJ&T70a<$65Rki%+!pQ!PHp;!m@9kHw#E@fj9B z)Z(XE{23OXWAVc*ezwKOS$vtr$6I`r#SgdmYKtFX@rx~fq{Y`;e1gR<vG`FI-(c~h zEq<xRCtCb6iyve0D=hv@i*K^{u@=9<;?J`9R*N5J@tZCFY>RKR_;V~?S$vYk@3#14 zi{EGQ=UTjLREPhkSbU_#kGJ?Ji%+%q{uY0p#YbEG1dETgc#p-$S$vwsCtCdZ7N2DC z6D{6j@#z+yVeykJewxK!VDUK?f1$<Cw)hN-FSGcIEWXO(CtG~A#b;UkVvC<*@%0ve zvBfX3_^B4(VDZx|eyPP@V)4r?{!)uyVe!)~zRBV*v-k}bf4RlCTKp9jzuDrmExyg- zb1Yt2e6Gdsw)hzqzt7_HEZ#M`!~gRwKGNc6T6~nn&$9Ub7C+nKqb<JB;$toTN{f%P z_#%r>wD=N>PqO$@i}zT3nZ;*Ve7VI>v-k>&&#`!~#m~0*N{cVE__-EeW${;Ae6___ zS^Q#)pJ(y)7JrS!FR}Rf7T;j;*IN8ii@(m|ms$Mv7Qe#ct1Z6C;ul){28+MJ;#)1g z#^N_y{345Qv-nzzR~G*di{EYWH(LBYi(hQ<uEY-i_gQ?T#ouJ{Q5NsF`2H4uv&BbS ze4WL|TKp{*A7}BmT706#*IRs&#ouP}9*e)-;xjD%4vU{=@poE$j>X??@v|*{iN%*$ z{5=+5W%2h~e6_{jXYq?I{(g(ExA+Gveu>3DXz>je|B%HmwfF{$UuN+STl@-(f5hUO zEdE~>zro^vv-nnvf7IePTl`}d-)8ZTTfDOPCoF!q#V@t^eHQ<3i+7p*>fYd<wD?Gi zf6C&cEdFVW?{D$XSbVg_KWp)^7XO^Z$65R`i%+!p=Pf?T;$N_MkHx=e@fjAs+~TKM z{7V*}WAQIr{A`PV)#A%6zDJLafGUe$*+ILiE&g?jUu^M>7GH1it1Nzr#Wz`egT>qX zBug!RwI%PV*%7H;JjCTv=N^hbhh5mq<*8X4+1#Emd~1xW{iKoj>pngScf>N%2in^4 zIq6hlmN?KVcrbBK;wHfZh<gz)6WoXR0OAJ02NOpS*9-1Rd?0bP;NP|Y(@g_qf`25A zB+e1Mo%kT)48dO!A55Gi_)}sO%oT_eyonfPbOoXXze#);ag^XS#D^2R1g|7^6Yu^L z#7Qp@M-jIPev<eI;#R?r5ceT&5_~W5k;Kac-%i|@xIyqu#Qlit1>Zn?6mhlSYlx2~ zE)!f%+@Cl{@Rh{J5N8OUK|FvsN${n_#}da0o=iNDI9l-e#Dj>V1fNTM9I;FAnZ(Bv z@BV}3A5I)i+$Q)`;uDBl1rH`3Oxz@R0P%^$%LMl!jv;Okd@%7z#Px!E5}!<5E%>)D zfKMSV6Z|7_EOCzD?ZiWfGX#G{d@6C0;7^H9BaRciiTHHlXu)q14<(KgyoUG;Vwd2R z#KVYp|1R}U97o(H_(|e;;#R?r5DzDA5_~W52;yaeZzmo}+#vWS;soM)!8Z_(BCZyE z4e@B=GQs7<iNraAuOuEroFRAy@tMR)f-fZ=OB^S7GVxi&(Spw>9!DG{_*~+%iCu!v zBtD0D_kO8=;w0iW!KV@@6SoQ;OnfeJli&fwDa6YJ_aPon+#vX1;#A^#!99u3Bd!+w z+vmU&h|2{3NbDib5xku^jW|Q_SH$NNCkg(Pcp`C};7!Eo#L<G^B%VYZC3p?-1;j4F zD~T^8-u;`@KXC?eo8TvjFCuOg{0Q-6;wHiO5@!-G6MQ>y7IA~%n~0|n*9*RZ_+sK} z!PgK^B`y<OPCSh`NAQ)zmk?(No<V#magyLmiKi3C37$-R8F94W^NBAfjuLz>@fE}_ z!DkX@6Yu_2>Yq4=xJ~e>#JR++f(H}NAZ`*ofH;qMnczOe`NR!^4<;@kt{2>scqVbR z;NLz2o<&?H_(x(6K!F^=+ldQ_GX#G{d?j&`;7^I?5XTALL|jB1E%;61V&W*lYlusT zU4mB<mlE&ZC-qNUM%*U&N#d)BTLnKtTu$61_+H`);$?zwC-xFI2)>E9lDJ;*4a9Sa zs|8;}d^K^I;Bw+B;vB(O63-*f5IlqU8sa3umlDq>juSkYcmZ*=;PZ*EC5{q&F7b85 zF2QFKUr)UI7pZ^ZYT`D*rxGtDZWTP3_y*!8!2^hEh?fcOL%fK%LGZ!EwZ!#;dlLVH zxLWXUp90@VTqgKO;>E-{g0~a<h%*F#MSK%+lHgB?{lsyCHxb`V94+`w;yU6e!E1<b zA$AE~Nqj5u?!8j~#P!5&f}bS5jks0tBgD58HwnI%_zvP_f^R3jlej_fO~iK**9*RZ z_@Bhpg0CUIo48DHIq?$W9Klx--$R@scn0yk#7TlLCBBb1PVi*n`-!6kpHKV%ag^Y5 zi610(2|knfA>!RXOZ^i!5Vr|FmH1)eR>6abA0ciMJb?IL#LEQtA%2v&LGZ!Ej}g}k z?n(SOakb#zJ^_A$xJ>Ym#7l{D1aBw)H*tpGuZW){P7?en@l(Wcf;SOAO&l%wP2y*W zqXe%ZewNrJcqQ?3#Jhiz`X^pS+$Q)*;^&E51wTUk0&$bzdx>8pUMBc<;^o8*f^Q;z ziMSpZSNX*6O!K{Wg~#`mr{<g88Chv9O;Pwo7*EUUXt}hs&Q5ZvVbJHN`g+dYJ^qMG z-j8v4YMZ=0+goMoUT=S<czoYxQm}g5Y&0-e<;2(8@RR(A#{R;yFu0j$_5NO-nqUvl zn9UV2Gu_9J$MeLRrXC(f4G_gyDK{)l0WGG=r6SL-8=#cdB}H+^IC%$YOKa39a6 z&3NN>uR=b|*V|`>P|z)Ml|nun+uJra+uGIFXReAqtHAYIPl>uCPI)o+SQ-0himQ?Q zD*kMSYD0VU)MdpCYm7s{syGCw%g{%YJEQSTa*0f&2NF>!CSYje1O_A_ApSEo6s#m0 zzjsv<O?b0O^Yq4xD3-zaR6_MK@lR{aV!*Ue!rRd+GRIRJr!gQ$C;S0eC*ftYknjkT z@Q}tFid8fIAx!v56F;^wmjR0za4-XIGXbYG&SXG60}f(9l?gbxaTWuXFd&iv*(Ttm z#$pCEFrYUB&NBfqjU^0N%76nIFw_K`*yv@zG6qC2psxuS+_-=ND;RJ91NNJ8oY1(C z0Zk0(#elC&Ky>2`4A{T`vD`)zaD3xp2DCCjs$`i7IIgjt0h<wkD!CV|W4R<+?pHKB z8hB9S-4tsJC0u6W4{Usp0V<U6R1<J)<D(4NtrJeR5?(eF2{)L82Q)rQF&BQiMO*%8 z6aSdT<qU{qfLQ)d^ng^Qf8(nRh+=?P{#z4pbmJ-p^k;xr{y!$*sK#{+h-QFT{zVhe zukkGg#4<oEf3FGX+xQ*>;us*7UuXi3Z2X7;i3||S&o%*l8b4z|5(C8Y7n*=08rvA) zVSreElnIDx{FVV32!Q3;|A#D316_{}2yHoTdh<%A=Na;;r*7bfaWJQ6;eKAcY3Lpz zJ-+cV__I~H*+%>T!L2Ll!X^R@iwL}U`*(`4g<hs3czi8t7vcxkNk0>8489&*+0lOl zpA9}8eA2=X2Ja8vYpX@SKrXy^U+9#Jv=^OA@a^DRE7|OfYSlUtFYZP2(0z7_cuq*Y z&w?9+Ex~nG{;vjK3BF|Ee+QokK4#&2f_K~6W$27}aWCS=LZ^&AqQi-X$ViueO<*yW z+vs!`L0b$4*AR82pFAb`4gS_va@LeLkXn1@Ytv}unjQVq>+)mV7z0o*{;{5#UHv@^ z+j*L^vahLw%CAwU{ik1^d|C44&68?(di(j*Zuja5QMFCif1d99PR0I+YS`qT5LK7a z?wcAF+~z*s<?&q>)8_FN#i-Zzp$zH1{FvS8fcubTqGYM{5oNl`e6Xn+WbVH#roYEu z6ce59&yR^s$6Xv0O6;o2J5=R?AE3(GPO4~o{I&d2|9@A0R`lPOpP7a)|Lp(Q^0V^) z*YfWUQ+}&HJpZryum%5*`WzNcpX4dhCBhv!tEft^D~icsPg$Do+of7yP*2@uF(vFI zo*mp1-n51M)#&ih?$dm0)dsTuxK%v&=kZ^x)QgPcYxej7la$B*bg$iPwzWImi+;yV z^|gs;NFU+O{c>uGyKy&@ekjN|E$Z&?b$%Jtptv#au@qMt+$@$dV<p{BJ-+WfzHMo~ zZ`8Tyz&-v2F&S1{ao6@oKM4WV_gLz6SxjOYN)+p9IUpwPam>5M1idkOKIESt>#1$` z9_aD+ZqJZja0qiBqo91{mma@2CN8aRK}@td7=1NUykY=TTo9A9f~`_A9kZ`;BAP%| ze3NOFGwVGtPZNyo@u#{Pr7!jEYR`xZ^g&x!6Qm65Xu|vVu*kdAa(2}y`qQ|sV8_6j z-&r*q+MSmDkf+WYGe@OEx!@fh-#V)DKK|8!;Hw=vLS>bQp5Ej8BDl4q(X9@?3u(kr z-ytx#IF$a#j`ZEPzJm^mc@!zNv%NjAiqN-}vG$=q30w%p0~7G4Bi)VGlrPic+YiTy z^0f3`hU)V8ukT`3*e7aw;Jy>+JV+ITjJkz@y(SC(A`D@rhjdzzPT)Me7C@TqWixv% z)XRQ$TyU78n6@<Ehv`1A^kT?wZ<_Bv-h$*tj*+Y4@JCHzUHV#RubP%<?-A^ieDJa~ zoo#BYr*2|ovis#f(|z0FQtE*K<ZDu5F-L~a4vb+x7s-Auiv3*wbhtw_N)p@bshbe# z8MDTFyT>1&=D#+YKJW2QfOhYB#<Y6e=WXze*|_KNWcS_c-M6n!j(sQ9-MBZkc5h|0 zXUH1QLhi&|@4j^^E&yx~?wiL0B>O%}Uj6;?fwLI^s~onS*Inu)REcV!KcR}3iu-I; z)u<Q8WMY49Gt~$Gcms?)J+Ny>NZ@blN4cVP)kr<PgqWdv`tEqEo(|EOCQnVi7=3tF zn(ue?7`{CmxljS#@#$zR?&LSvHj*1r3J!te;gbG}{^@YpwJex_KI}Coift!t%paA< zOHM(R#7t{<R=y7loAE9AisbC(kiQ-^-nZLn4{xRW{#0k9Dub&#JaU_3j(V+`r>-<M z6Rsp}-k+Tq9PEt8(4mWis(7(=Gx~<gFVi~OJzMPb%b|PnWq}z-^+ZqPbP24BpU_NL zE)POb47EeoQ7{<%HKYq~#6EubOiS;2c0hGi${E)qSls57y3ud)_OE%9jecrW?WXI$ zWrK99sn9I=i9cgs-TCc4&%WTdx;?bA32c`3kRQ{=MgjNxne72X`vNqIg*z6*wLJcD zTR!4avfaIi`w|{M7KK&H<(=q3pO}QcoE}!8STW<4LsIn~#KNG1ZBeK8WrPI~>zIkS zYfobD>K}I_gyWmoeI60Nab*VDYhw<6=TY6rejJ_dG&Y|cHlNvSK4ok^Rq6iMW2&jf z!nM?{S^G!QD{-oU6@VT;y>UBcwdk@quuMc+9F3wFGO2MlLfCJPWFtl!^?iahb-M3+ z*1-~}%`lHN`fVx+*EIC_?2vSKa5i#aVsT9DLX%B1<9s7|V^YJA3mW%}0=v}PjNtoH z_YSPzwv%ZZ$fH3r-siY_T6(dsN<$YF3q8_(CzX5{;|hEQ*Kl0dy@)$Rc6a**LRq^L z)jU`}@GPNkR~k(2Gf6LG(#UcM`Xm-F8~-LAug3^(R|`=*sK6)}i|96W0j|N%z|;qK z<8QDPf2i#!NwQsCK#PE1%0Ex>&p$(rComI^9`e~xf6=|q9!|yT=`!ptx_92swe#M) z4LY@Ua$e-}|Ij{f`;PYbOZzOxu0GAOzE4k=(@ysy&(7^M-AFY+in@;%i#3PZDf_cD z-(C;;U-WA1()OeI@Xdwvx~F5>P<iQfkH)m}3VWXSEmWzyGlttcjT4@tOKwvS(;N_P z0?EKX8F&C3gEg=Sfs=eH-S<Pf?<;9rTh$}f1+9S*q{GyciCym644KosF8OKl4|nZH zSddb@4dNm4HjwFcb7Ir$UXS4>7Bl{X*Op$=>9wSIfLx9Jp+`$fEbl!nDI6Q2Gwe1e z5#J>BEey6Q8l*awrt_`!w77IXl@y7NR)$ax*^|D3vEj94boMBOr2BqRi6A+k0`K+s ztNN=CktaJ1NR7u@fj!3<6d(f&XX?lKp9lIj;3|r#naGsMV#2pvXeRsR*R&_P9wf_= zf0}xi3^JNF$+v@32#=>OC7L%;9)C(4W=!ry+~`jCr^h5ss=G){@+Yg{iF*85_$xxH z7aUN#ao$9aKO^c@R4w|%O<s@3*9xtp(|zxF{8LpLMsMGHY0d!dzI%0&`}Xxou|K#Q zH`Z>fY)bd7_6&K?vk*(&_Uo@(ilq9-Z$vtkD;8~p-Mq)AkIhSTFZu>EEjq<OIIY$P zx=<&NzYJNu>+zq5teQN&)mBz(Fja_s)7`kKc9XmIPNp!V$uo`_xo??IIOaol?H8Pf z!nk_AOS|4DjJ9XU*smNwG2;|Y4O|Q|9VV`4*-;bwaczu&Ylyw!)Y=D*#$8t*K+`~1 zLLW%`ij{>4u<-#@PP-Zj()hri;sfuUr`3d%?E|&c6*+UxLm#MiG*B~;DU(Ityj*A| z`^A?aQTMV$h27w9+tdb-bc00d6Kks8dp*q@9jbO`zw`f}dSAzSpM!emMlgGb7&a79 z=zpvC%Cb<MUpHOq`*ozq`i=`#?Y~UbRx`w@+8KtFs&z<iJYk$=H>Ou6GN0nP56?J6 zu3ix7TT{Df-rZQQAP2Nxj&$*R)h$?sr2DgCqSI=&_YYLU1C4wX<=wstJV|%vb%^Jw zLxV%VhL~9<W|G952svj6^cHgXOLnh57aJAsTZb@F)bwuXk?#9gRiIJ>eMySHgc>${ zqyZwTf(;2CF^8jozamZ)R+ZcWM0dXNP<EvYV*0B&=t`3P=W_2O**7_gYbE$!5DP}S zp_6QId1p-jKLRNSZxx;y^<+lKy_&iIOy`8mPF#c4I!ScnOc{MT)>gPvtqfc%U6v+R zk$BWGfOZah4ln_m;<Uj}%%Z#v21o$YA-@@XC!-x;BK(X18trVx*@dA^@?+choy=sI z5k=5SoCzgpnn)E#b+jRZJDps-akfUeCW9ZSQQKCebs?CJIl_5JIfR05OAdizYog;F zZ6{Yx)lk46ncQtm?m94mW<;>+C~!ijRM&@8yTDFsm`Q67(@JGpgTRDjhuX6L<VGg) z-AmbHD7y$uhvLt5+_s`xwV{qclhuam&BhC3K8KhgmkC@4XBNpI=A5kg&jU|5REHD~ zu{cV(7x6ift=L7fEx$bG7b;f01&VQxvO|6pTB<F7sFB}C`3%bc#;rzX&tB#V84&6A zUMla~rAsmaH1$6R*Wkxm*<DU1oh$sGvQ@r3hNGj}^#v^jCS;y2EB?1biFB%(MW$-L zXChBB5l+fNvYo0X#mMfW>~)ll2NTLLXje@rg-$+tnn__NQ#gw$9Al>tSPSp!Nbl|X z`kHfG?z@_raqYpYr*7Pq)mRVlgxnwuTfpmq)e-vs1qoXl8R(($CP(%M4m)+@R#Ns` zegC*4`yucYPu<X$KxBIA1|7CWXP|e9x2l&YkA>wf%$FmlUrrr<bJD#>r}Y)nt<(4K zIO$$%(*44uJG4u>mv>1Q{dhwB%hbWQUp0J6pV&OTnQZe*hP}yVA8=T2h($3HMvdu( zS?eF%3Y^Ua(dFE2S`AaPbBk8P@ULQ#zC!nPbqNPTUOg<~SuxpUF_TMp82@OR@|#!~ z*0ZpR<Rnk6>w{qlLKrwO#*m9s&kKi1C7+Sfk+-M^K?M&(_s&hI3Uq7&R3Y!&+|uD} zL0zh$++Sb^WvFvPK^ba<9h9VELP1HYza12<4hjWDt3S{KFjv`b+ik!$^&RgH5qg*U z74oRo+1N5d&0=MPXQX1fD35>8qcAWBs5>{)cnNpM(y&|AW1q2VTGX|qWh+xHg4=q0 z-!XJ5ZHCZn3EifyW<SJ*7WVv`Jy-&vHuA_pc0O`Po|u77$@J~<#@77V<GK^md>`O} zv;V9ZWO*#IRO^r;HWUwSUzY|49P`D3ua@<Y)S&B!h$oHV<@WaWMNO5x9Up}xZU6oB z%LBfTd$?G#Oe~6)q1}1>=djwM)T1%IT%33FiLh$_kUBNTH`R>o>0a~%<uKLbvvv-o z4RTFbb_(>VMEUV_1FI#n>Z6Y^^^9XUdbUV)^~dPHxI^bZWaYQQaxa3r0nfkP!xcPQ zM%-pqFXq{$rlDU94h$a5byhm>`+M5gK#$5ubvY6igKbrlX)u4k6JJDy_!Abq5Q7nP zn|dAc%X(mr#8QbxoYfyTGu7bF>F5cgp)zf~73GWH#Nw`@R&@y{nSk{OsBKz_&KsNB zkLxhE342n9Vfv1+n<OkN#*N5NoXk|WsX{b8y*+U~v`zDE=D$_uTDg&;^am;UY`frh z!#<3ejat<O-=;Eo-%;><T@}>&5)=^yKNTfL!E2t^1#hO0!KZw!y40anuReU>g&58X zpf&bZgE3dceqA)ynNh)*bbmqYq}p%1m@RHo7h!vd*IH8*JH_7X(#Pzq{5ZWXFVfle zbGuoXInh{q_D8vRkIi_!4prMfL8T6)sHbjzBpZ9%;b{3igGaGO@1>$<_izLG2$&?O zw3Es+FzM{Z!g*2J>4D#1oa8C5Vg-$dYstQ!bZhisQ*j5@3K91$3l+>$cYRcRQ|;b8 zPkHK6v2&eD4}@x|(fCq!7i8Cisf(C!QZLtaD9xGbG<a@27enfgci<egpSc%tEt6XN zjr$hPnmoQw$FtUUsfRIhTGZsO{Y=<h>g)Z`5FOs}rt3?19BoI<q2>G$S<l7jJt`Qz zzsGk#j4J<t;%H-OzP49kX4lGFBq6xNI(5lgx*edOY*ve<uD7WSs21$YcCby2=lxN- z9e4*zjw+7asNkU*4JLA%mJ+Q-ye|>_{d&?s{)FjJh*OOFAjTHtuSD%!8>#pYg$8?> zHuWb1u^mnq!o$dVkMEbj2k-U3@Uw778CnAh_7u{o#<QN<MbLgd&X)N5)j!J|BGM4T z$3utoTsqjB45b?fLqvW55zLAb+|Vj*@3RxxN?KF}JS%vl<hxDPzfYO1>N-(wo2mv@ zW43_wM+^}C6YYmO{)h;YEl3_ZEnG|0Fe-8n>Zd8}s~7IrjrNJiUr?tSs_Tc$szfSu z5OT)iM)pH#?uY(>CeE;QGi)EsLCk+iY5FaH1_}7^d^F-pDWxeM<^=c0Fk2}jRqrju z+^X(-SBiO<DW;?cOTRACYzvQWVp(^o+c`oTUfl{(dA^VW_drH_T|L~3HnVi-aCfmR zkZhA{!iK?cvje1IZj(nN%KstrT&@LR>Q~@R?2sTxQ%BOD{0R%CC@pFuqt+#Cyhw*` zr(gOLDop58I`k<M`X3$oj0vqnC~bum(mM4iJVStL<y}8;j+!z)2KuoL8^zTPXc#=3 zurBcDpUg2L*%)-;T2_`Bz3Rs8c?A=j*T8T_=TV19d+O(Xn$9&YfpO{*-i3_13Leh( zcMgc+<4_pP`^X2NGCG?IhMkSD={oEMgz3{38??Y=3XFrm1TAn61aRu&NgX;8j@|wg za~pTx&+H;ZCH4Czo#|PKcZ`mA6*KiR)@Xggpl;~dpyWiuWgqg{B*qCoS+$R5c-iH1 zNDOY(nqu%wcx#Z9A~vMyah9fMLf}~~;MSVDIy9Z4H65fim2*s!jizG|?>ZfC8)lN~ zO?C`tI+`vA)k)JfZZX)JzDbABng*7$4}jGYk>+VS&HIpmKBdF@2u1|zjm&7s9I9om zr;HrfnWSZkjLay=1O`f>^C-hkUJcPQ9wU<gnYXme1j=B8)TJV{OpK8k37Mr@<}}J+ zW74I*gaM!re?EjdkATcgTE<NoIo$Jxmie6C2AScIDbX@}FwxWJeD2XQoDoqb9x@kd znU5)h4KU1qw9K7G29x82)3wZNl%Y4Pizs9Kau@`T&;pN806Mx<oE8wjJOcvzjup%J zAOOGYqeJPJv;Hl9IekxuU*@-JzZ{BqEjr#Mh^Ib(51EeEM{Mebez&|!ZU4wF#jfqo z;ZvRb@^mD4txhm1r0GAHYR{l(dKv^~Xn|jlJT#rHL#gQ-OGVQ!eiTjR7~RTuwWg;c z-bfwqUBpwv87t(M_jlFQ(^b>q9hwH%xwCGDAkFUvh}CM4fcCjhU>f+rEF*(Q#0f20 zW)@|{=U&n>DMscL$oyN&Or(tX+-+Lscq4N%Wc*rY7-huginR>)VX4nakSW$OM^Z+7 zE=|jPY-Bj6zfjBkg1M~rxs$XEw;PzwiI9oYGM`aKe6EL<xz)&EQjl<jmRUs^@wqQx zY*bVU6FC6_KOZB;d7J_$hfBS#1tw7-8UmkafjS7FCLh$H!%&lZ9+#Rt=LgoL`uT0T z$+$C~ASqLzgdWitmWml+v_5QBH}n@yQHS7=n$r!|P*>aCis96byA@)2^#v33_xlGk z^C!H^3&z$Pb#ASqLRQRi(DM%bgQ=?h9Vs354*O;47|)m(Q*?~ICdMGd$YqST83Th* zi#ifL2;vRY@!mG^1~FdES`QX}$yxE6US-9b3FjW9aRvPqYp9wX8S3_p6y1l1uxE=$ z;IIiE#E#8Sb1@+scNQeot*9YR&XV{{wq|3yx&l6q*{8U@@2f^uBc=i#Ob@~Kki;=0 z&>)C{#~^Ab8V={2?@<zlzL3eWcR3R^t=grO5m>aDxh5WkM(YXZcr5E(Z!$MN-S#Ox z<1Ca6WdX9SNzXVjk~gcP-hw3NBwOfGGUME(Hu1jGj5AI(k~1^TIJJzZW5&69gG9i5 z@G+^q0Mz1IVh9V387B>)79b9*^iHt^nJdZEtj&-KKz;JmG~X}!D1x@TdFGANN;w{1 z-x$VSLd(}Byovr(mT2TYXaVO(IC3fDW<xyuKiDq_`(mxXRUIJt?otCqnXT$4IBI%b zC3Y;vL*9RR|4F`|C;5Jo^=j}WkKc=GsGA=x{by}c6^;|7L<M`}FZSuaPV;@v0@Z$2 z`O%~?KY5Q#gOSmAkh6Lk>DM;R!+H>VCV0M~g0#xPlX$c)a2*}RKT?!TQtu&TRW)iv zT}|_&c9U3J8SqY|&eidSN1+VP%=AapCaf)19K~ifQ07}S;VFce!^;jzMu3}<lD|3} z0Zg-uFivG7M{x+kXq920sE(B(9(Sv=$ie?&U+BRHcwn(LN&5t$bwxDy%s0Z6C?ec6 zCF+G9L7Jw2{H8SD7se(ZFWTg(yBv=hmG|)UvBlBe0bF-{ZJZGnuZmW+I*mSj(tw30 zo>8!p{xFJ1sVQuyXy@Eh!c6l#LZ^VyYBZskB3hlM?{(SZ)WA?soQmSTZ1y0XvcNvf z^O<6q`i1RAA6H2Cwduu<JV}AeeaO|PY@fu_rMODisxGGOu~-pTdX=$JqW6$Iw&UQt zk$RuVIXe?P!&%=dnE>n4F=`>=>AvS~iMiF|3#x(iWjNB?;{J4e9D$N8r?-tFQ8<QE zInYz5&nF$}sVk56_})!LC!B=ZMMd;Vez}L<Zy3hJWPd?UN1X%h)tvR<{Hc+AY!@3m zon7DJb$UCw0d=j8{SV`y*HI@(Z^HfuGCvV?oTcJ9tBclxYEOwpfl*~4vo+V>)VsMp zY4K>Z@Cnh}39aU0fxEG{GVQu?vw>BOzR!{{?8a7T>~&=GG`@_oQ}w;ak(~g{-Poxh zGO-)`oQb4|lCA0#%6Hz4z2AtaLv&h;fK|J+vvFk-1|4<*Gu`V!Fx_`eBq!Z>DQ~4) zj}6rISk3QO{a`}biX{UV-LHDt3{1FR{XlzhyEb`BI?gTW)hXn0u!={Q&Vfz2E`F0@ zJiP=H#~h0W?<|ThV(xIhLY4r6$p&8{IW?z4vDZ--&dK5Ai_`0_j-~(n+-b{FX9YLL z{*sl|&e2v@-?4Ebt3M@+ZR#U~zn3B)t3AldUz`~1>+xS3tFA{}wt#mfc%5g=7nR%S z6;4ZP{x5WSzqzB>t8HB_HF=jCUCuXnM)$hx8Kree38#x5Mz~poF(k^DMgQKavLyS| zL_8D)-hxNmv1-5xOlqrc4ezrpaoK}{VLt?Ww9@!rmnODLeE_XkqaPsopSj^6%O3yP zYChYWZw-%8ZE`Q-lR%IET+}!&iR$b%2*is1R+%y2StPH%^=cF&VMl=&Lng<s5z_l? zRTGh6@aT|QX8{Ikk*fT`D*DI=IM}+DM!FY~#*}6?nL~Q+UE9MuSIXQdOCS_FZymQD zwyIySZNLGv4`(wiiih~5qia#mh$0Cen2>i6B5vBE?m!5J9Ni<cyZC%H5)lI-iFGs! z!_+#^vH?qjm@z$c{)Rgy(D``Lx!<(=MRjf%MSJI@*UiE{NoiDLG>ZXmeQ7PV-KNsC zwiAs`XLe}Y&X!P@Fy4ejcWC=9LV{?QvQIG_Dh29HswausI3`n<7aJTvceZzy;MBjZ zrZuqT`7MtN<H0ni0hN53;jhR6$iQA_qO;eD`y|}sd<=$h{u{`ix|C@m)RK}z5`k56 z^`*@A_)^MLDIbF9p?iLY$|ceR8*<4cI$SdJ=vxkJ^ZTpw;0zMbUyaqb5`g)k6M(&K z-u9)NV$)Ui1!5CDUB-A2y-1j?GCp>|ZrLg>5iA#OklMkT{Qem6X5XjkT10Q(;I8FQ zi^`TkBen;`hxV`<xOKjbgdb+QGv*;Cfc+l2v6{ga*4d|}|AGHqO<(Hp>DhpteEOVw zyZZD_GTr+0t!uPTpZL1?^qEoGr~9&{$rhjbL=;I#HX*EE<I}4U(#fYIS6M#&gR}+u z^bhdBWj%sD(Wn=$rIp05F>;Kn#JVB0S(T`+phNomwcJDf$1T1Om%4<DAfwhc(HeL+ z4n)%-vIt8fe-`v~HU-W=*t0qed&y>jcB~eVr8XD$_i6#ITd+X;1BF3!F105!)4FjB z_H}FuTxc@o8oo%!`w4S%)xubz&8pR$t`D(RX%Seac3P#iu&&wEoy{t)`H#~HK84tN zDS4IFMKtB&zK0gL9RkoavqRIROGMK@e-TY(v+A)`+B{sqzlW3gD9Dx6bP!{OHU&m^ z)pUB-&8k5inua#3xZuA|r+FNem0bwdhqYP71%I}d=}8&ctZL9Q&Sn)C{AX#I@36Gd z8wU%tjI&wA1^;nc=1t1T#=$f#<7`%8BAu}RASvUsl#z{tky=K2YPbm({9kC9+bM$@ zaj7UR<7`%O!M|F|%%u!lrrH5RqFl~q71#WaXqihXBO3=Bw2ZS^6%Co|wanR+k&S~# zDPuOPj)y?L7C4ClXaJbcX#uHiF32ZpfkPpH+Ah$c^vjk1l-fRPZ--yL@`kQ$F3Sh# zc%T0ZwLOfnLYq~EpgQ?wF*NJsm&4e|ZNJ3$l+YR}ro98PwWgmmN>N19V<GU87Ptli z(DXGON=>7*rj2?NRovt-qv-&|yHUrROigPUE995Qch$6+9ihF?Q42pdng%Kvh&nz7 zX^zop9!O=y=T2wB5rK=03`WF+0a|AJBao5Jsz@y})W{qSncsU$q2Hm5_}n*89O>|< z%$e6wklCVTUZ9NlT$7ghmK````az~i%lwlv;&b<Fnbk(7FJvCkGS^T>e6C8%JYZz7 zL`kU8GFMPWd@hSJJ%bCFQ6C7*(gLXz5QiI~1*TKr2nbBn0;f{|g>b1pS^(SNSv+Wv zFiZ;^2?12&Pp?b*c<R_M?M`vH6MvGOs)?_`@_3yMQ#fZ^s{Y|lj@9KI$WP&fx~jhB z<S2+nhg}J*%*;_@ISha&>~#t5!(engqo79TsB&t6xny%7i$<@R@4@q7sYicGqRcO^ z!=pA%k|-q4GcleZD&8T$(hNm(;lU;5r&wTcFAj4Te+3tR-g8vZp@@k^8fG+j5dNOW zKN$g=DzROWPVqH(B@1tBG?8FbKNe}S+=~dj!AkMt4L=^mjO2@fai|1;MeO)7bNg4$ z;_8KaG^s0CXlxb5Z^Ep><G(<u7hVR{-c&i3uRQ4&3|RYXu#IMRU2t9rGBTF#QX^nz zy(W)C@zkC4(G!^TO}OKv^ATp@!&+j$yLNs%LNQmtV@TO!*rvSj{@_u;BSJ(T3E98F z)O(j2Z&JC8wSx^hIh?_Vl(KHeQh87Orp7Z^SY*}0tgtob9pdpH31ca|!XvwK6Va5^ zuc#=_r-!VG-#8t!??5C7tkPJ=q189$^w<XQ{gRGN56tfOA!YRq91(L0?t%P)M&_x@ zj77rk+FQ{I(q&?Zuy*yO4x1)n6&#`b5vjMq<zQHO7`#ZI1NSY8X=AeY&_iKkccZID z#ntRP$bI9FEC?o2t-N9pe=<ezfKM>^CdRvs6=a=HZxi9Il;@kn$S!&DT6KtSoIG5W zy678s?Got`@KBM`NQ&nqP_3zGP3pN<onsqFmI3OGmr%iVTH#lZ2eWbs<z-^U9jb?) z#xCL@S+X>%Rw{(LS^|3p#-rH>c%GijKiD=74(tXD#3BH#bPg@zPgq;8Hwh1bnpCGv zC$C1XB*r66V(<;Ps)wMBbH;@8O)&=-Y~QOgY?PW3AH&RWn1_B7xEGy^l$!}K&i8VC z-5i-tm~<e@{R;d=A6G%S>zUKK<+|K$0Ix>l&&mh!r=#5eehTHrzLxBsZl+o&Wdmv{ zkd6%X(Usc(oeflX?MU$I!51NM3hrQlD^YS7p!rs9fL_o#RABh<kUuO815_h_^&r&h z@B?mT-7E|aZ{wXAbv?i;nS7u03I)@-@pq?0O~*cG4i~!e@*IyGjL(6h*d3E22X~?B zbnDGgpTP9kdxQPZW#p(g39&>GSf*Yhl)bky^&IcfCm~2H7&uM5%V=AV;82l}R)*Sw z^6NcLz&Q1;fml3XKay`hC92oRVN7>Ui2ow}3pz+O5rbCnFk^H2hX8e|R!Hj?r;gQ7 z(szrHQ9UCd=Pg8!y>N8fj!9~~Q6)*QViOER;ZVhRQ&62~^g?(0ojHpesa9Z&lqcZG zLp_W{1*p4uhZAjLvM9A!L*yK#7T7^as+dq#)k!KB_cSEET4gcdRAX9U&LyMkK{pc> z#|Us04~pru9d#_l4oLUUj>TGq-4^y?oqZX+dzU;l9j9bM8|-?wbKwrWVF+i8c<^Q% zkm-%yo@Z7jU<<cho%RA-0*><Nj&C3!7MQW|O)`Q>ABaXnr)#W6ZajN4f10x-_V_Xr z@lAR@k~~(%q17<F&Mb(x!&Teyh(jMMyE6taCrXQtl54`#J<&jqLJLz@J%=-9NNye9 z++nCHUFNh~*}#l?9;$LW=%3_TIY5f8k6W!%X;0|(ifq@ZSQZH*({AJ(7zE9O2NQk? zXxi&KcP;;sAN4)54A6*ZuPb32wAUkX;eK`|#~3uO<BYoax2f1as5#Og=U}MCOjx*G z@L-kCjue?JU?%;<iPx!8DsVrN56E0x?=|yRuuv8I{mic4NL<!qnqkh>xEDQ1ZRkq+ zbWQz>T=vql20tSU;MaOU8uOMT;jei9z}wBDQo<k;@~aeIjyyFYL^ozQ`Z{&cGFVC4 zc9i<#Iov1d?Su@)w`)+b(FzhM{x51dI}CUuUV3g<PdES~k?I~Z3_Oq0!3XJDmIK!7 zw@iP+nDcJ0Ual!-mm7;TJVsPQp*5zhi&03vA)Yu1PqgqZRDMiU@CrU&llL4s4H<iM zXd1Fref$hfRvAkJzkwzxUB*_`fPx15imka})q{G;YJnZM`qA{-2g8Y24jgfN02@M~ z{XYg%nil+yQLzum?Oc5{%IveI*UgHYl5T#w2iv+)!4qjFcE*pO_?@2|VZR@5a<ffi z!+$e2n7o+BRzi4}s?@^0((ocw%~~`(v%QX|kbm=3;WX%}pDHAa-M8|o!g`h|^i+X+ z@gD!xQ3~E{Wc%p?MgD#IZ_!1>2w#f9B>kD4(zoYLfB)3tCS={|sl`0006vuLcxv&I z)M%%t7Mq^dEoeJRp$ga=OQV<e=G4>KRI&3@i~F7e)!kEz<SEN~n7#74(n!Y*)BUre zf~Uv>J=V(?ND#^%l;+2x16x47dDB0>3001bGaQ?&{9sWND$RR@XY8E*UW}SJKMVy? z82Oa}I>J3jgQraA_4D|)r~3l>Sy#)S?d>l>fwhZ~AQPp3@qNcOIeIt69G}HJ6b}s4 z6r?FbceAk({6^KoBA7VBD^tvqoo88Cj0o$Wg^iNgRf~-#n6XQ$aR4fmGy0a4D6}$O z`}68UW9G9gJWjygAl{w)Q(m0Z55)FBi6}K2?&I;z#*X;>{@6EM>+Oq$1O|pR@>CFk z`qeQ1^r%U`Z-b*T+hD+O2}s2<12M5X$;e*J%0n@4m1I+~M?M{ABX`no*9M2N*=>E2 zRgU5I7nOzSkSaw7uS-<PvN^TxVe#<zA=GM;ufW1$!tCaHPu-1eC|k4t#s*%9*_&fr z9ygY&L_Vb2&P40Rod~S9=zF(>;Q`S*8V_@18#O+fvM=cSUXJV|z<ik02LvA`U1=gY z50h@7y!9{%c}_JVYNk%>9AI^+zCTUEpu_nl-7`Tj-J47#C*4!Kq>G0U>zAOA9z237 zfdS<a6rNlyT+f*;*=e0v_O)cswb+{V==t}nVGhNoTplumYzAZTesze=VClDC{rYc{ zDPzGo_p5C-6HVqrn}G}MSIstq(P+PV-e#)EJmfH4o^ru;9%@4|f_V8=9(2v6pr2=t zzf%o!@S_?>ve!kY|A(}rt*Rf5hN)dmbCe2@8}ood0+p+D3(%)u?UUn5kFI6E>DP_D zm$_W=n|LzgaheY&piIDY1S~Qq$7^qrFnv0Fk_c>56VYh()7spn`gAysQe#;qQw8UA z`1#mL4;_o2C#A;oKj`V44o~2H$La9%o?vlMLj0ZzdsBbELl?<xrJzQyE*@hU(L|in z;pT}9TlL|(Wa?L4vU{hq0PflYWW-O{Z0H(8a~+A|{>RWohW<j+s|-EG(Can5%+O~W zT2J*79yRnSpck)M0SmYm;YHayB$Bq;(IT=<^+U&|t#%rU$}{zcLu%!%ovhaPLCb0> zur6!-5Ojr()!H$tSXPUAJY=;9+Q;ATqZ`C(!*Jmgp%igfzz#UOj;$J)Pxk%wdlPa< zAWF4jAqaasxldc~vP&JmI7-`Zi3vzSK*%qClM*J}Xu?j>VJyG9c8d<HG+~G6Fszvo zwnm5Lny_7$NSfS(3;AJ&3433Mai7oK$q(24LQS_xd(#&E<T1;lH*~V-n)@w_{vhVs zre1{yI~IM0_Z@!N_-M$YFUknsZ_z@r=oi)6qJzkG?}z_*QY?A5=(kn%K>>6NJD)1m zCEQ{Hew}7n@(dle(1d-V!$6|ccpIPbye4e54%3$0t7~Vr342V3X-j^p!!9#nJ{_hl zi3dSU(__Mlbr^SC-L;SCu#qP0A{`bfVgJx!gG^Y04&#omyY@;Q7HPtc(P7+vcGq5@ z!}jde?)Ar1DLWsTxNC>&ur?F+r4GYRA;OIJy=}tQ=`id+BFuQ-8z$`EI*jcp<b6v` zSe*`I4;AvhB_`}D9mYvS$op<IVN-P25fWzif)jq$-j|A2ti5mgzqI#Jx0Q2QWubRu z#@}msUxm2VHZ>OGjpKbBpDgc7dL-n137iP|`yF__cwhE)+WQ{jSk=AvMJ^TZ+bsIw zc-qB|_Ze%on1J~R2(@F=R$nq<**Z*n(HfKop7MwZOVMH4`^=b8XTna=VcKhLYaR2G zw${;TdD>b-QAGBBtmT#2ovd}#J(jgnVO6&B!!UL@*6P9gj<(w8;gGd@(=Psgo39mX z#pA->?<$TvmbK*ff%It#Y=1A@!CeWSap(y(+TV27u0!Ft>TLqgb|Q(~kclE-Q)8K6 zya~8P-Tf(Mb#*W8BLi_A!fhV)<wX*SyHi={zC#;q69_Orm3^ir#0y@_G<oM)xQ@@v zR162xF*~u@fy0te#Mvg~WP6wTeX`b~o-us*WvDIc2xvheQkY<J={^J5LmD$%^&$Kd z#{l)_*aiY8`v%CXm%(tbeTRb#G!gP)kdwyjsKhglJ7eC37(=S%ns6ZwTB{7YFgHuU z>FT_qL09KdU{)qbbvkdxO}HD?>FhAhmAcxc&ZZ{+2&@*#U1}I$;BA1wbNs^xDa`vF zq{cmgGWg#|KOp0e=?z#(m+4&9Lps-Em}{b><>dO_Kas1mpX)NYZh-p*4#O-xAcwGF z&zH$$G0#!_b1wdHk)9Ke-;UU(Zn=oomh+EN;g4^&Dm<UZBBi$XTo|hDnMf~G*h>hs zxv~EkxD^W}rk3MW^%#UZRsEgxf%w%UaX41>5him?MWvpHAaj;I&Q$WX$kkNxZVY@} z@nch{S$$35<eC&X#^jo$-b4VabskOowlQrqOgkU1t*8a;b9n4lo3`#jt3t<jGVR>E zEYm)QDxkK-NIdWY);58iOc~5{GQR=@KI5NllHr{(|B);9d602WX57nU9HlevYciHP zozN-cKkl?V>2#CvPw>US7-Ss0nz?>USc5!*vq7MsZ%KX$cjMh7_9J(}6?8^VJ;2J0 z_y9V*dIp46a>Ki$&u+WJ%4`*sV(c54`hR{$X7Vmu6=3if{id3`b~$)edp{+c15W^; zC%Rys^h8fo>7HmCBH$4hcQjj(rL&vVT<@Ii!U|%WS_sYf_)1>ZyI?;PY*E!vFEsma zmtJwJIvO@+j9tWf$*cD;{&0?Ty`7nk-UicSip4q!b4TFk-xwFa7=Wcbr|arLJBJ5M z4lhw-M6J^~bexRqr185bwRx5%O5Y=Cx2U%!T1ua9lAK|ZJhMY-tkby?>R#(|D{(4* zR#(NpwR8D~?t~ugcgby=`heKXc=?dceh)et%dHKl2iccngYS*3;x~ysa57HzFROCc z$!?jbd!i`WhNwoGvSzPY8!a<w*|=omn`v^t4!L(6Ui?cw58Y?%WwI)?va0BmRll%V z?Uzn%t2z={VJ}ke0Lkvp!X20cV5jxDHk2(m4|}k$RMHJ`w$3{XPFXk?NS{HPhPstg zbt(#L4p#J|=&sQ;zuw9A(xUEy%jl;?>Qc5iJP}7n%#isAF(=cS)e_8b0&|!vlJEm~ zYSu-0#y-WhsJr$Wbh+vNe~CJy`1W_2zY_XPRi3dIW0>Q!W%c_#+@NyTjt9^`g1B%k zi($4Y)6j9@Kv>7oEIEN!m#`{`E~JS{VvLf*UUmKc*v{W0`(D<>mrP>CVfdnMcnl{Z zI1l#OCeshdI7S8Tg94Ob!hFx*XsEvO4g5i2Ig(zFsG+6ov-i?0yVP8ad%<J$W3nrG zf1G)5H6jSp$}rCy)ddp9EorT#8rNC)G$YK+)d>tcK?@5JMWSQEbHWm4-b^n)ica9~ zx6LcvOcE}1<7&v`b^55ldUXDJmFFMySp{Y0;Q4u8WVh!9-=qOL&I_W)*s9j1vHWxT zhc?;ttJ1MBi_{ESQ|SHdg*y^4U-3`KsoB@Vdw9*hp56+)*?&Uda+GP+Y(!Ag;Pz-u zFevg-k7K@tcQ6L5!a4!x$2x^wtl0a)!aN6n-H&GVIxX%82prCS+8^<Cc?{}lhdwe| zyB=g9Pv%Q^#tf6|>oItdhrWDY06ua*(}(|@VZv~Tj$!@iKh+46L4nS|0CmgVlwPh= z@C8=N@T~pd=sKu21ZEDY_Au*%szKjm-v=reqXmwLxYP1J2p&r>$slo(r{*_STV-V6 z2Ux^ZI92q0sLp^ypa*F<2st&7aohnuK$jskuoriz>fcdpJiVEM3#<Arh_P5hr8uw0 zxa69!RH0b^rpXX?x(UNb$0Dbqd8j&sg^J7ob>BaAktGEbIUq`k>&M*OwaCxXK30)S z*csSGzMRD1jw1g_?RA4-1}O4aO5lKu)>)lSI0*01=Y0q^WGdNsLA<<87-;?d{=7;` zKNT02{%%BKs+_gUVHLP+#a&db-`X-rBFG<cjl_}noe%I%<--@>*7gj{KXk8P4uY;z zhhyF0km`Zk*&T8=scuL0265EKbRzJ@CpiPcn`W9(_W|lT#Z=}Ua_|dpg4kiELpV-d zd8a5gRu|z;(GQ~xh8*arif|3cwBFxu1H+_)b}zaWhO2&UHYx+dl>FLc#3QI&?9bkX zi}c+X6g}=#{A_1)4#d=XI2pll^3&U-C!a@Y6yq&cndqkKrK?MDLY|ipDeL37#rw~E z4o9U{W5&g9;5jNuQawjz;aaxz&@MGj$=kg^1J;e6npM-NGB&~JeEx`^OIdOK&X5ZW z_ivuW^-g4q<Lls!glsE|IsV`}P;39yHm&_(RE#>&>WmOL%6K(_>JPPQ=I8YE9*Q$V zkvF*(*U)0|JB{VMIQE9hqGEM8id5Hc9g<b!CSZ6RiVgfohSnog?R|#@bwuwJl2MXg z>Y<kYhZDvZX=5(;n3`DtWWYn{j<eCIf+tJY(5$8ta2}qtXs46Ddr<*ZkH8<W-oqST zodIE^D~z?FM2yt~7x$u{X&8BGYMG3~LdaxOu-2i;0yvG2_Wc`vOqmt_DV#B6GDZk| z&7@E|8C1Tdhx;Se7NaTE<>0y6Y<b#oB7RIE8b55Po<gUnAN!@s3uCExVGRFP$WA`` zz;EGhM%=}Si%0B{X=B#87vVU%D@~pP{-R1Hu6r?dWHFeh#s>7Z(ejuase;#IGQ@aK z$ME0hQ@7m?qx%;L;M-cuCD?;wMbjwmkBDYI(2uWf@iF5s>Tt<`uWqH9SGQ8-)h+z` zqG*R#x8R;${7mw=uZvK?v9tPDV(`7$WQ-q#3&yj?j$(s#GUWSQFQFpvgbRJmxF->@ zQxsKpp0*#gSM%8|Kp|Ziww6LNdgb-HlvGU(bsa3Y@@S}?xQxswGFeh5gr@+e`<`Oc z30`hjy8H?Sn~0h%O%lJShG7Vm9s8}W?45TYA?M-1!E8Hdw)>DACuG0XYs`PQ$>XbG z@*cmw;21bE4lP939H|&%4~8^<IFlO*>(q{VT1uCTdkmig2ZsEK`GuKtwo<zv_cMnU z^&?!oW;cGUdaL{8CSOez!#-k|KO$vLjO!)_O2`7yCE_TMdL&<zipIhIn~doLhm*>? zgQ?*4(lfcHGG6Sd8`-KZqH3lUbDpQ--qO0F*eJ;sRsLOvKm!F%pg`Uol6hUkK_<av zl0Fi2nX)#S_`@0BnJ90Qkzt#fk3kU?u>NaZ0Y!9Tc#@9OqE2UTUzhL-##S0+k_nbP zfDhBbcbM2`m|$v0@$XTch&=+G8=>0->jJf?cXe=I6TJI2op-f~y-Wv>F^Rutg3C<s zZS)l!n36MJTW*m-3SRO7@A{Z7mc>v@*n`N(C(x&%c3&1mT^$k-INKIrQPjmD0f7^2 z0TxCjgaibhYztIVpl?V(U<4sn$ubU<QD6@(33ok2<}apm+d>kHYzR!3)wMnb$;YG@ z{)!+!h7y^F`p-|o>JT%x?b9!B|B~zQ4#|_cNG67r+|Pz(rHP-!43p-2T_pJuVkq~d zMSIzpy#4gQ-Qy%U9Vb6M?O&<85Eth>TLO1t=FAb7zY-&@kLMy<xOtDK;1eRvHA=4j zXWMY)ixqf^ICg#%4hiFDu@7YvKBf+~?8%8~N@OJ7%JJcl4Yr!Ls>?7iasih%_URa| z;40Sy)35|e_s>Cxdm4VH2ZPN5`dH1nNFF!Yg((AmG>cttyEj4|aVvs+yD;{E6sG+a zJwVQ4wMc=T<0t4n{10tL9(;39JzNYIj8H2Id$_9S#|h{CK`jJ};Kb>H>#uTt?Mpwk z^7x<Iz_{?<^qWJQCR^1p+gTrFIUfIOlD2QVdJrp_PzSk+?Fj|_n1w*(=ZMWF0Zx)Q zMnwTa>F@B{TO3=}%YnaSG1kuFGLwbZWRY%XA^ROpJ_~oql-qx!2j1#A?ZzZtR;ym_ zMe+*`{)ks+vUBYBV}bOM&fLkp$VEZZ@5wCa<n`1^PiJIKe+miHRqE*iekn_xgof_0 zYWa=Qjn!?{J<VhA2{Z4#lGRw3a4QdoqYv^k1Rb2LB7i6A;8GK@$OKanil2^P-FL8+ za(MJ|IxM}3wA%s=bxRg)hoGO*0s;qUs0E~akz~rLy1-x2O{d214EV);B5oJ^9QIbe zF;fq|IGC009|@l}n;fTc(8SNT<FL4T4RaC{?}aV8;7`MUWVCBhSHWB9D$+kT`WR)a zdYYXmT;*9}e~na<|3&WNCAY8h_zzGx8K0wG9>XfRLx<L|LdRpqG^EwDdS5ROW=S_> zVJie36Kgy)=yv>807~O{#sA0IcYs$_H18)sG!#uxBB2KiO+W*36+|?cAU7H`N)ZbZ zMam~A2nnKqfC<X=5&@09d@2?cP((xwE!3cb6s1WEh-8mJf*{2L`M>Y%o^n(C`2Bev za<|Ox&dfVITh5+6Sx1I)TPn@!i%L>f9<J&S&M8D|)-{5<Fn}4%Ey0d(HV_BL*MR*5 zoVYry^6;clW}$fHUHt$ca4x?N%7$6n@CW@Anbv0v20L!S*>Ha#1INlHVMDoey+4R> z)RZUz?X>zDiP`xkQ9nZBf!C$IP#6n>M9ih1-$e}`RY$w%v^buCOW^6)M3u3UMspuN z$-`S;_o)_QUi;Mzv<|#HxF5`@_KaZOg#8^}0?>?6IlPysE@L>xWF@Ez5vB8KA_FuT zISH)V=VJ<m{WzXJ!bu+ZsKiKr>-AdatD>I1j5_!3NAZe#K}`_yw-IG_$7&BKrF32w z_4G6l;N8!xHA8KXaN@KSN-TawpRTu2ntUWy);G^4P+x7HZN(qyyO#@05nUe?Yvfz4 zwIwB{m?>srBdcO>hka-jQPe${HlhYG!S2D*;n{-+qVL$L>UfqIa@9TBkbkBj=#}ei z_$-+CM!uPZF8K{}(1XR@ARf@!^LFckpO|dBgFlRHx4*InFF==ZQ`9US)g4s09RheY zfkgW;YA@PYt)+MWmx>cnoso^#|GAiAf41atPp~cC3W-?v0M!;#nr`~Cyab$P_v6%@ z3DIhRbj%`k;%O1TnUUhqRQ6+xWCiNu=g_>}k55ej8T#=du|V9E$++&o=r-x<A0IBb zoe&$I;b-lpvlVwhRa_?=odVUF-n9<Bi_<53o}ox(!fh0P#Lfl-Q$rB*ca~kx%(dN0 z*ZG4%v4~(6?ISsG+-sJ#wJV?jd8|xU(q<Ae`G`z;v41Oih&eXER>$n<jQ^zO42fRO zL7r~uj;R!{Nc}Qdw9)4$jp_DhsSVlQe?#E)P2Q<<mLf-6$pXrTqCaK>U8rj{BL#?1 zU0+fnJ&K}>zmkO3Ca)n^n&r^_Kf`Tx&FxKIZm|o!LWW|R?|sR_v@qWdTdTPogV1Oz z&HS6<PzqE%uxKoKA5euQuQEBM&y<$RWrn!lAzO2QnV0+OhWpdBaLv6cD$hH3>c>tw zr8Ki@`~1~br$58ZIo`=fUX|V&(N%<q8FRm_c?>F1+45S8>83K6&0WrhbibX1l4>3k z%&_C9%=0<iK*nTbLy~g_1|K9bGX6zzb9_zkA_uLv0dvq>SsmlMb$00vjo&{+4cTm- z*~HVC)K`Z~kccWp??8{#eN;GG4Li_%RH6$R4Vh5CM?(ShdFVcllgTlOwU08BQ)hKN zvPxJ%7GEmmKbQqohC`R$y&z)|E&EG%PT-HeyAyr<pd`{4;;nh?rg`3&&yvnsr0Px- zWgRgxM~bD&M%6}Whpq)<^jcLPLRy#_ih?gf#B8NxVrIQxT>)o~{w&sqkJ8DG?4p}U zT%rckdJ3|b$A7RDV-Okj?K<!#mwbS$Ko-n~N@ksy+TzX_$qX*xOn{SJCq+hU^e1=? zZ@N1UWgbe^LpnYhQCy48q!p~3`}Ta;fy4IVN5FYBBumYi6^0*dsg`-szo2_7;R(W2 zf123H3;(-7e?|oQB9f(1IiGm=gIVH_a+YYbk*Xm-X>=`fVi812oRcE13k4II5s(p6 zt!)Aq*i43HsYxwlf*!(`q=QiPr#WJGSI2H=Oz4A4q#junSmZajL^whhjDZ=t*-h2A z$S$t0RtuGgf$AufiiRk~cqPs*no(W7MdB)GG3W^V>lP%{)=U<%*vIXmK=LH9H*}1% zjwOqk{RvHq*%EtG$0U0`vx9cF#3p#MXES@aoh`BZJ=w1^yQiHku^T<vGnjp)oh`9A zPxe%1N7>mD3ug?=HE=#|tU7^CAy+DlRZ0gXW2E}Y&KRjSc{2QJrJdndi#!>LYPOw` zsNV8qbW+ppj7}=slaZjt*cl0Gm?xu^>ThSXQg?bX;#9Jo5vMwPGGbL5J0n)bF=%dp zh*p;%#=d$5#D>JtDx3+SqYziYDoZw>aMSLLNpga@YuJ#GOAP|->{v(jqciII#Xb1R z@$JFlN|j7x)%sF{;&0(#bGrV>^dXbMh<SOOmm2KSdHKlG@ABTP3GQU!b|6@*2|fY= z-sNqjbFuc0nZQPKx~9T%?Hf3sG>!67gI9F9iEQ*ZxOXo#NJUb}%j0+9y^xSsvX5s` ztmM#34N`Q4*EpQM$y&`#hrHCFttM!sIekj!lG7jV5>CHI?*XSZX?~lZ((2)*2LF5` z>N$zUmh!Wd^YZvAuD@D)u3wnPjYRLu<9?UZkV_3d)^&c23iPE0!~<{7%%IDGW_hW> zbDAcHG}Xz}cbbOd4{3O*!4OUJ7-=F&^O2_U8=B^zNzpWYNW&cym8EIo4Gk|fXrXC3 zlZMA7)c{QsW@xZS?u*nkjYtDT!c-Scvj<`F!%Gd0tQTE{lLop7!+0ig(ZP_0ml|x; zG{0cgx&$*p>}NsQkllN!!6%yL8`5B+9Husr#&fB`bWJdy1mH1DeX0q>E_tcJ7)|gB z2w;~pbS}~UrH`OpYqM*Y2ghr)d8t8nU2X`<se4$;xzyl~fo0HM0nS3uz6aJHVwb$s z;O_!aNn?l8Y93B`sX?J8h|ruKo*;sf(=M9R=QjzbJXNYX8BTer!2(@wFW6G^S<11? zPs(x{Q<l^Duw%oiRbVjYr3Me_I%lE+ZF6_A;s|S&q2Z+l-8D@nX~gEP)-;&82*$kB zprxj{n>1o`QJUsnL&HlAs%x6Aq!F7dhHz->T0_H24T|xU8&0GtX~gCVG|i=khVPSY z)HD&K5u2N(X-c3l+8i%6_*BzaScz(zo2Y5NGc?$w@lDq>8%ZNJcdw@T$k1S*^o`Us zpOXeGgsE#aO_rhI8LvAu%}bzx<y}UCD#e3vL*}qvVtK!AB%ZjOTs{0GQSe=jbo-^u z0K5rqH!rxk6>5}MGH=G}zH55#_^^VTsclSEZjP4Uz|EM%-W;dmSxe|O3Eyxr={lw| z*Cc!a1JvOE%vtRkbWzS=vARmPcY`r~l9!hvA17%<%AKe$upe9pc~@p4rlI=f{6IDQ zR>fHf&01BA$b+=NkD%C-5R5m~W4g~LwmE5dQz}0Z?>wcWe4g0O=}a!y<ePzQSr8`- zaRLIaU7c<TS;fiYC#K*Ia1gu&jpP1=Kuv!zMfn4DYT7N6Un$iR!bmAf_A3RILt@Tb zA((Xc<IsuWRbGs0IYtD0mDT@?fD~-nI6?A32sRn|;HeT>&#`S+G#rAtRISV~i_j9) zm!<p;e@#QAYFdd@whr#Lk)kvWwKVpd47k<e6kwaW5j!)9Q@4pwlaHifqyU3srQ(>+ z)2KD~;d7cC@<m6Itx+(gYCge7=SAwjqh#IjBz-*EnlTn!qXXikE(c%igv`#wisNSb z5tFE1MhaIO#|o)Jy%Nj^sA}eXH{lo)USI->C6GD&IJzE=n?r-K>XTNw$~eheC^Wd@ zUA6sGmx(s%IzPsD0FSZ9m@;7|Pt(Ngz%hJvkI5@U!#oN?24o8ewEAsRFtXVsYND98 zAhl|Wf>e*rTN<AzmFLD&ByKUjF%K%i@`{@v@*1!jMrfN*FrkH#?q&)W1^Ssi3gSc$ zve}I4T8_GnmzuI@YKBx)IqI|M=1$#|SW`2k4lpl-lTBXgIER`c^+h@AcfHgJ4mCrH zXW2sQ9_^*3el;fysk@km*_Nx5?p|stQ(cV|8qTedk(83yn2EuN6}Qo1W6t!n4R?06 zjN3?*2G_n^+<U(<G*z9VibgQ9&>&EtK7zw?HsDysTrh3O55mlG4k2pFQ<!=9_1afm zt-`V68<qXAq(xk>S;+LT5S87Yd1#c|cAAYXG=Gz#(uED*EKVNKeeQr)^Kw<&%a!c> zountXOQ(V>YZGct&1oKx`A3BQ(a-k4us-z?)xA*NW18i1R#}g-_sVA1KDZnVK79=b zn<VP$Wjg$vY~is{mMz8wgXYoUMr<S)T_gv-;Pf&vYSA|Cd2p#8*B$!GZqJ^Na|xo9 zn7dPLc=*KO27B8_Ez3Yn@FsVFFEDeEBRte`6PVGUAa4L#v$mlT65h$C(MxZKrIDZc zun!c>LqWBNA_SLA5=||XEY;y!UE{@gSI?#oWaWcI?WK;TyGbSJjo%?fj%Zo~(Ogi- zx@5fr;;8Hggn|94^a#}k*MwP$+QY}6CIT*Q02jeItUUMzOQ|PEV+T=of<`{3wQU4^ zfElt&bC=Gz(`5LOLHTYo^3Bll{f*ZE)IXAkHxMLkVSFdD@GQ#9$ts>pV2(ODf>q!g zCn7wh*&3YW$$Uef&f7H@`(5^Tcp}+6R*stqw>hP`hGF-VrhV{|^{Ls+!&eR{wIsa4 z1ovX-*^eT689L<Sw-RyR=36lE0k>$V*0?#*Tq4H{+wmnrSnINX$hLL^svBy>`ZWz1 z_Qo&Iscl7VsJo{8*pCRNoJL7&_*tIglzV;LCl8&lHbb#Dbg>^(Y$L?p@Bq4Qf`kEn ztUWBNcIa4ScO?$$0?=NZnZX_xh?WGe#{q&K=%g^LW(925;vE#^o{4InSo7$yOgM&_ zs+{{)L3tv9qnBg~IbrhayA*AxrlTnQT$6?)Bq&7;SsG8A)kWAPWQUN~7vkY8tn1kz zfUAoLuG^`OsMTDUzyVIv!Z9oXAjOKcXkmre8T^r?VVIL&95+G>D!T&-am-8-mrSKv zu$TP?xk4LXushl>PkhLTjT~#iF<#1vka~`J5!QITnLs0MXZYAG)%tEGAJ+;WbK`Xy zPI8u!^zz5Gq^sHRb*Rs3&)N`a$I5G1=VBpgebYi)(?Y&(A%ZPz8>tOxzNBG1mR}rH zrKGQ8ON)}~%q84QqNJajZtxA!wIyB3h%G5=(ULNx-eF#Z^%$6;q-_iz??_v|scXPT zPvHZdQqrJ#PK-R5cE+$|oE*--qCTqyYlEaoth|PG0_Ur(DAU3friB^0g;cgsEIl1Z z@gxmL@#Gg5DWN4bKY`87HJM9ZHIf#PE3~m6*gBGKWyF@0wP;BhQj3@uVGRZ|l(e<s zW2Cg@`(`!x7$|(;Sd^rp6O@tkb__v|q=QkP)qu5ui@RBQ4NKvrD65)jp_OSNUAM5E zt}on3nkH$v@j7pzw4~NuMb>a6&NLq_lg>HsKw{PVgf<3A1JDW$@)!y(3Okh?9TyRm zjRz|z4JBg0RyF_7<cy%_)TVS_KEgCpJ)A+N@ZyU>9(}{hlARkLW7wv9L(xbUy#?No zb*D+%!uY9dW7{yYfchjcH~unHFp=&&79|{aE-5V@*3C=3ICR`mfRsbWpACRsZBKp! ztA$E0fGO+O0CB%9z%FiTj@L$7yK93rJ=bL8YPV!-XD$ifGNFk>KgXqK>uL_O@r@ZX z`n}0$?cy*)A7_mNy*U3TyNmPxAz3^BOQm<o99OiQMAU6_BQmP}aHL>Oy;NWJ(@aMV ztAJG{uq`1V%Bm@&e89*eGzM+345<j_VRs0R^J%axZS^7#xXhzDEkOP38;O#J8p;^# z+ZYBMgZ&bCTPds!+MSIE4E8catq!Jz7B=#_g`sRAO<I6^leFCU1o?%#W!H>pM^@&V zOk5cc!@P=Sga&%Bfkp^HICUK(wxU>tb(yhNMpOf4M_7SNwWQ4rAJNj5uP7gUtfy5# zM`4nd8?W;WA31GV5Elr77a`zV2N>m&aRb+XDFFESiUYdM&nJx7{IDwP8CoM@BR@fA zM_7MeqWOt8{2Y_HjPC*R)5-8tC}|jm<k#?Xwhd>r1930{LlH7C5>qvG3@dF}Jsy#W zYMOXiVJ+$+q*#-rZ45_D`5QU~KmRfOTyFT;EN%MsU^`CDmfnRWg{0w{Ir%mGJR<zy z)@SfT0@-Rfs<KT_dz01Ms+rD+ts2&1fl5@*h#IL`*~cCg%)pngp|knS_-ZhzFd!j9 zefL_8nPE~IgV*aac!)15eg_m>S57e{7$@1?D_8>C2qmh9E^(JBF+)lmRlQ6J#z_{n zj3w@4a3^#N6*ae=plPG2DKW{E;4Q9!q;!_}P?tCX;Dbr>BFklbk)`pJe1Fb3KYCcs z@+x5&^`RIY4Iqju`gG(OL{z-kKyG|9gU3iVlH(i2yx9L}rKL++ZoJMjc<gO0_R)#@ zB7w1wKUfBw)gos$9;Il+!GpC}yD>wg+8I%W%#N^b!_FAf(xkS-s`Vg^2IH)<hv>F9 zgP*d5ebwM}sVg_WsSzQO^f|t-mqCO+Lv=d|l9p@s1&j#wTa!@lT1dZ<v1-^*HRp&f zWe-#nhag`0K=t5nn%oRjLzklAS}bDMjge`CFyb4IJPuU938uO6ml~eKWc=|BV9|G_ zDBP8#nSrV;m4SguC+5c2F$JSJ7K}g%XP}al2?KTWQg7%$b-~@9f$F7)KnI2PN7u6l zsyi5V2dWNiNjrBot~yAz9;hUtDHGg*s)|d`)>Rc|%RnX36EKjFfodzfl?+r{ZjgcM z3jA=||1ip#c4eS?-D^ZLP)&tSJOkAeI;vSE;ObenB?Fa2$1;kEy9`vc607&$RFhff z+|BF=tKcG9MQ(hY(QurYj&BsUmDL3T8$7I}fku9fIepiH1@T6fB#s+NcliqoK)+`J zztbI#F=D$XR$*=UOY^~q+QRGz>qg-N@XL6Ji5#cQy<}dNRfrDH7Y`D#4CD|o(x0QB zlp{P8Vg2x%H&5nd$x|StV`Y$ah9d;Re!joJ3K@y>=VZq>7SyuM^_<8wHN*dB$2T&W zGH*p(7Q!gm$$F?3Wya-!Mp?&LEXQ|S9+b6<wuL?5INnl^Z>co#=UlW58OX1`m_J>w z#82M)aCa)_0V-gw+3>><NgZOX^>}j_huzWl3L7O{EHYoshS>|AFc&Kynbxm{jY7@F zhOc?B@Su8M=I!Nn4)-Hl70G~&HINk1a~^hFXSIhd70zyCpu2`GHX)#G8N!1;QvmaW zYN*ITl?<pz&{(z^Ny;f>Kl##Ft`;-L7f(h?1zLL-1t;@`CMJn_HyI}98z!}<ahV*7 zC9=chOf;gIe3l_$QVM{{0T_NACfR}-2pa1inUR>yygP)+?D#Zfrv~4b$#^ORO=sf) zeljaNev*W-)6d9A6T$P7Y?(9Cs$wm@>x7jMjV_4Oj{tr$5LfvR(lBu7G6mmc;_ERp zF9%mLgCv<XiQqG&*0D?1u)c$dST9IwZoC*FaxwDwwta=_9y8T-Vs(DJuB*Cv>+57a z$pMum)EHgg{j3iwK1sz9)KhBN{bY&7$MdZ*#PlnmePEZo+7d@S@WCY6Rg)JdG38&Y zUiI;0olHcqUzHA4qjdQwHiOBLI2vk4okd@8^iJiO^Q^cVS{*<hc)*cUbq(3b!SWPc z6G!<}3&c|cIMvRs8q^1Dy39ESg=SoZx0*8IXsINoN&eZNGGuGwK=(*IxN7Rp%2J?? z=JAv9bQ8IT{HTh?I!`-CUBPPAk4%cYWQt1BQ7r|*SJyJ7B^hmp5cI!z5j)svwHHHo zc78?!90Hnz=1_?)MH5otEOoH}a|*+f>w&3;TnrJcVGnX}mI&wb-<OqH)RdJntY^nJ zWS<VgtzvYh8HS-4U$$aHG`IwbYqM-19wIw_s>zF!yky?q0LwHHvDsQenauC2XUE4y zuu7tg$YyZFNTS7&6gyVo*K%CSH4XYkeF@*iPlB5}rA5Zy22l5PU_Y56&Wbo_0WTh4 zqwM;4>qUVNhItC63VR-lxHVl8b2YCtJLvO`d9deqr7m8!F0Y-_L`I@I0vM?d;&oyP zK?9UQ&0>{JBni!_Tt=O-1rl2)DIDupW0@CW{bdr;`~}(Zks#qe)dUZfxsTqOlb|4G z#f168due~A>Xyaw%fpXXvl4n_q+73{s%}~TRIx8G%8jp2y#l3U)E%xGoeP0Bi&f{w z*E4yAIxpo@<Sk@ZO8^7({>)IT?xAVHw~-1{mj&#ndbjk}G|$xKC-6qIe-B;Mp1Qou za5HDk{5WONmdM)F<H)wo;kkm%p&G;jQF4)r)fLp%Ugid4x?dx6k+*$%F0v0~HX5<& zIavFONmSZ3=yJhn0t6iz9_ey}nXlhRhiTt{Mbm2a*?nlGE<wOciSLWf)d-B7PFJ7- zTDU7mfYNuWsQj8lx;M|P!!d(>`l%mY01z1e7-u?-kL!>L;wbQbHNB91kIYm?Y+Klj z5|+iS6tIz~h9i&8g7{AwJ2ET-XBNIlpsKrk(Fs2pm+%IB6utm1gz1s!)F_GBMXna$ zc#N(qO&yt_O()GZ9db6G3Lkv8W|tAp>8dQE9Tjzh^DKsy8#^kp@X=$~(OKBhAu)yA z_*i2r?}(tjXFq|hOobZRd|i__L+6Fl#)c!$u_I=vC;O2a+ft;09j$fksOoJVJ9+^; z(vI#SLuS|gHiqpfZA5VgV??Y<bwHklL0R-KDRHEZwfA14ro4$v)#fgc$vt_&nA2B_ zHKpN)T9^TPu_mag5cZ}zUu+xHFED=Fpdcx8U7Kq5H%EEYK%2T3l=_JYi5#<v<!l;n zAjr@om0y4qtGeNL5+uME>>fg#AdRGM&<>MnUKukqUOL@1ug1_WIp_G~m{)5?Z1Z9b z7B<zTT1He2WV;sjn6@xE+SKI>^y5$qW4f`hbjQMG$gBsObFfizn@%n<A)(Exn$R!d zWg;^-bI3Z?S0^&U#C-fxH9MKPi<vNaMpA>r<NGbZ3!mBX>xDL3(*|cnikT$GkJUrw zSh<o`^#o-4K3WVW`1m63qs4I1ek(3qMQ`VQv|ITKuga*M+C@&OW}p+|ye@4EOp*`z z{$hl#M|^>wZ|iCf@f}8Wi_G^m&uSw*hP<sSMS=Gcrr6pRVLxVy4A&BUT}L(Y)Qa>M zO(4-Hyab8V;Si?4piZm)-aHx6Ze@yoUznuVBg*&Z{GI2<$HJJRrW`yY&Fl7Lg;oWG zx;=@W01t?20$H%}3k{k;qFcQLGNa!PpI+RC$Vs$-E<Ot@2n>Z>M|94PpAAh$O$lHp z*{S*+B&jR#M^`P;20Ch#0q?3x9Rk_*JLV;LhXnf^0*P+&5)_hPnL{AaPrU?jh^RLm z0*U5$3DQY0&LNQKa7Hm^NM9vG>Yo051iN1yrQpzlBz9*a?l6GYv!B1=^&azlEj4FE zY`5M$18ek4fcR=F?Kc?l(3NmG`ZAKoaqi)J_Z)i%=Hv`TyCZOOZ;4vfi+z6FSlpWu zhyShcKLP)7r7IpyW4|ph3<qG~A%~4ruYeQ>j=7?Ajy%noN{=0wGXp=kZeXNzpE)u~ z56qdZ^XBWH#r!GAD#Q=}A*ghS!DA-K3+wfowZJ{qT_CGlQ;4IH338<3KbSDidPhs! zS>{MM*TDRTy6Ig^ke)|^fjQ|2s%gLT;o>kD7~Uh}FmN^f3Vugm;|_W}(vGe>rn&s^ zDJMUfCwEK8_wv-#J}l4KRsGu;@-3JH*NPpUntfQ0Jf_?%Udi{7$@#rEovGw3LJqB# zvp<Z9;dkQc<=0?O*LeI6)Cg->a1gJ=Id3kkNCbgeib~8>qX`$DRf<zm1G9D_Yeg*c z-$Z`<tvsnF(~%D>3>|oP7BuS}nz5jf$Dt0{QzX+P%v$v)&@R3bB{ri3wAjz6Zk=3K zL6fAdc}x-_(3jkG43)rB@ua%wIE*8)dsIF`{g-y+9*2)m&r3qcq50kKp><PBAticU zhA@5F{Zn!NOK4Z>Jsqa0sh4$_)~BA+;Ta4+rNdJh9)&RHv=8IgG%#+Yx=$#^`Bg6+ zNL07zKqu8r2NF~#9cZPl(t$YD0s;1+#`v}CidNCgMrtd_jczHoz&FA5+8G_PHkJm| zv8a_vk)`W1u~>k7yxRpS!)ldo%)|_fDe_gJEPma#v=ArY@QWL?gAsSPfhp?OQ4p8U znZ|TyTJS=D)+!hfmmhcG7xM!wQcE}U^xSIN;(x)Aedktc<u~UK1;6KgbAA_1T>j>K z`)y>L_KO(fvh2^9=vSxEDfrHoeA2TX%>rr)r@9~}B)_-6RTZhY1L}X=zCVu@p+tdN z&CbOaGmDk~4g~-0_Wf5#i<aznrg7;!xV#Em4>=Pe)g9-UyEd9%pghW#JKR^qkEXE^ zoCjnD`YrM5G<<6tG8iaZqr7t-Nf%%$ED5dfEmL7c*$T7m3hmpDLwTIXMRCPE-eRg; zz*fCHwzsRa&tl|EY(<x+PC;PVHR6ILr_@AL7DE>!4bKT8RT7+pysr_dIx%=DGvJik zAi^nO5}PA(&_-RPd2ZN(;im>i;D5{FMk&Fz@!YY1d6uZrXo0`4+^!e>J)!Y^p$Zz0 zERq~Tl}4H<-4}Qo)auV{=^Ao46sFdtmD4+{8<8vbe5euB7r3+9A_?bX^+`+KtMFYa zbKr&dtIZ;pvC3X_MQC^!8+N`j%}%UZ-OBzEm7A|^2zT}43}<T2!_oHbg=cY&^9P<x z#Wniq?oCYn>1+z0g2vg|NZ!3xpq@fa#cfjq#l$j2@I0Bh0o6i1=Bfc){YUk#xzm2f zYENc~I!p`4-bAE2f^<%bqz|kB&-`?NW+zhj9xbe9rzKU7htqP~;TAS7Y@EJDv+)~u zUcg2qzN()2qh>?djvXFkzv{~7vQ}gIR}3}=IBX2^ve8M{;N5=PU~2xr|NbV$DU`sp z+WnIDFFh$Bhb;G-6ivY|)#v$=_6=a1+UW~&wM7h{O4&iaY^8ic)<VBYabXIQD*Pq| z**)1SH8>dh{5!Qxi%PDiNLl$$wajXGfjiE>7&gp*Q7N6*jEPXwP&GL6uPmyj;=onP z%0t!s{I)|<<ZU^ay7FTU12M~(fTag5;ZOZZ@CY(FWorf&1nvES4*uX{c>4~6_Nd5= zYR5`(dYq0uYb9Q>Tc5cjHL%Lx`Y(Uh!DIgL&8%5_9^PnY?g7DhZ4`m2{zgf2GO@Q= zq7IO?;Go#lHiM#_i}B3YClHUrpolm2D--MszbjY|7_t^D35J>!>q-^}$)X_{W|e<p z;S^X~+~@x!R!(LsiiQsyx#GpDL3B`fi)S2K!;S$Sl2D${(UtXJ3&VV$jsS^EX#}uh zZMB#k<BqTMx5GzaI3ae}pEg&<4qt;N%Glwe9-<ueJ?v4X+{QAr!`sP}ZHLXsS*RUO zyctOq*kQLmyzc%R`M~ubj<>?x7LXqQl;deLI5`Y<r?;f${0H*#b5Xcyp$eyyRYxi{ zSgcUrkh))WVl&#sUBo_b54<CVQQTcdHlZ`e=in<<DS^}adNh8YSdOLh3*PYJ{w^b; zqq0APt<aa?)tAg;)O$8G0HvJqbHh2pdY1XPp9PzlnA37+Y9I*o1(~wJ8oU<<itZEG zo7(!Uf92U~xN<NH`(T3cKJ}&a^`uCD=|&nDnwnV1s~J#Lsd`m1Wt$e2r{F_b>H~B& zt0$(RW)58~UcEpU62yKm{OpI6G+1{rXRayBb%!mD^0(f`mT?K)T7UT3Q5UCnKA9SI z^U3zV^~9DJyd>5Vm`brH_hmQYwk~J3XLy?!?#4hblrD&SIxx-RLLY8*hk6p))`A9+ z><`?;4fvrli_o{$p2Kw+Y8_6grsfQVC%~Eez%GcDipN~@k%}h@skrneHF&waT?>~S zt=6H#_3ZplCcX@5uBLeiMu_V*;9J_H2Jp43@RL}XMdNlq9v3NA&AX!jt~<l*g}cSi zpgi9x-LJ-T48m78`1Se{B8b*Y)Mcnm%@kXQ=3WJjwNhq5{3H%XR{6>!tzw56U+g)A zSj9xSq9-c*8L^5|UJ&>A8TA-=fat^Jo*rWd=hVGO#g}G?K6*3IKM4$~!Y28~9VQys z=2Bl#-9R3wD}(xJ^&S&tg|!%rS~rA%{ehT-2K#G@7`#-2z0`o+#NT>{e`RS^fL-7Z zFCf@O0K14_AIgZmCFlBIz&tutop?1=Y}ufF%!~FJf4D(AN-k^Ip{6B^kb^z=o+7@P zX9QnND-FJ<iSGcUrUce$d~qWY+!%*jbr^o5XXmpXe6wLix8x-M0*(MM>qv6Z?U59M z?raX<g6`W0ad-|zm;GOTLG=ZIZXRf?&E?TGe&z)4Q);bWt@-&3Jq}-T%4Eek$&Jvd z^*V&7dQ<clSwpUK3ig04^oY*54xdBKxDam|!6U%PVbACtImpbp3n@vFsjUyD1RJ9R zodGcFGE|=uXc%w(7Z{`lZ$#hH@GZ09OU0<L@-M=-3WFZuQ-DtqK1?P7-*1FZ&7*a( zlNP47Mn5e`$tpUN5?+#VK}zs~lmPhYBE6IyQPo7<`jwY7aEHaxE_H@#33lPMLtgbh z2XukLZyJSxf`U7`NT-lB%8&NI>km%sq?)zjmH|E+AGllxFyy0Xn{`PEc)rq1r?FpI z_k+OpuIQ>0V^v>MM4fJmJ%F_|N!HXKcPdR97l$pcr8=pVY70u<HkFA>|6m`%F6!9t z<bGT$v=gqrLU~5iUudv+BCaN_0^g9?Mb+p=D)haAQoMx~?0RQoj3xN$_e<QbSgY=Z z$Y#GHO@alg6-pF0D{iSaC9-JOI9=jflu&IAO*PP{0dOOH0h(i9FBv82d|Jcug!k<B zqVaKffsCKIveLm>x8B`w8<>34H|t0uz8Zxg;68l~PbWXWHu#g;g_`hf-7As<58+X8 zO>|Cp^o2K&m7Wmer@%UYu(Qen1DKR&&!ZWvLvFB>+H@m`@bch|dQ`x-sf~~~lWVji z!&97GAGS~Zasu2(z)51xg0YpC%B!Aet@uK?$l`9rx2=d|-B(Zv98KY9SF34=VG>=s zDzkw~WOKoo*BWvy?z^RdjM3^7dK369G()}ojn3%I2`;9RveqQZ1a1Z_fnPHg9pI@r zJs)+TcA^GHwBoKJ+8>nPD_UnG+A#Qra-!9!K(tX{q>N~{QvgS_&k?gl8zkzESx%XP zz7h4cXqzaDD_Wdaw5!21rarjkX^kHn7q*qdP+{dG<8&ujmlPMSE`n`~k*7&&QZ(OC z?4-6zlb8s4Z>NCmc%#EQaR`GEl&Cp4F2~<n#k}#l{qdW?oc)nC+iT&@O5a1dRh&+j zxUNTB*t#AG;f^j7RBIH}n`Z-97f?tLu-B^9Ex0X)R*3vTB9GTnd7uH?q^cQ*JH5@# z!wY$^6$>vEp>Oq$zd>s$$9LjI^qKXjc7>m|bdI)!24EYornPD-RN*u**=YdT!(!D+ z7%ff~aGMy`RD7RR+tl8b2{2{fhphc!r}lSD?a+_Zp5d+ia;J7=4{N0cvi7>B_Gr}` zQR@rJFb99M<tI?1@J1Yq)V#)m8azl$T0Ok_ip9z<^)`%iN`3&>s=ka;l>B<I)fjB? zJ)zBL5(ss^-hM;}E$%@C?pD?50&~IAZfD*gmgGn0iqxf7Lmili6;a>EQ8#PJgMr(h zRQZ%)_lEHmsDu(=p0kiWJQy=2Rt$DuUH!zZv82MEUR2-M+@3}VI6ctZ<_}}VO*+Cy zk@^-~E82fxt@Rz!u$ziT4y*UjJs|7qsO%3#*4+5%@{3dJ^6P8)0?^n4Dms(7lB&9b zL;ZLX5)~ps*<-J>Wq+I{^^3H1J9uP21ufCImjeO&8TSH)UD;Qo5+nO!x`1Fz079d) z9=uG;-VCWZ{lnS4i&S$I4(wIuU@N%Z?fF)vdPy}B^H1#OQuOxuW(j4+dAX=x@5W6& zGJ}>Eyg#})#UE_LE{OZ7C*aE5YuwxMzXFNc2c~#C{wHFoT!t2@dkE6xHLSw9iW!?6 zDP8)<W`0iI8muAv4Y-5X1V_cH(6QzC_RZu^*Q!veJ}UMg>%q0bOh>6%Vjl8d*HGvj zIb%O!PJs$ACkOBd6Z&;IWdDeQs;jtBKqh(E`d8nv+TcQyk{kcLDJ47D7lYh+x-2OT zsdhZs8%Z)eT^=Y1>b>@>JP3AVwLtJ6c02QQ`543QJ6-*x^J!kxkCLZPSCToknh6cf zk%kC79Mg}B*sl7Bd2+N;qOUUQc?Up!)CmcE0c=c+n8c<!+9aar-`HPpzZ3g5*9T0( z`oJ1~4tr-aW?(dmTs>oO*10N~)q*|ZR|k8<ng8)P)6%2W>KVZv4Uytsoi#BwEb66v z{)X#ce--C9H-EKXW^`aT%-^|39CpuEx6jX-7#BX~!mNq$;f%}gEBULR>yZi{*EQvG zFw0Gh^@3;D_K2&cI^0O|@O8$yI^NZ$eN)GqlXiv<*S2XVA<i#E#vy@UavW<4$<hO| zr;|SP3z35iiAvUW^+a5C(&5gM2Oe6Pdi_XXy|0==cD<2h>b2@#1Kl3?N43p2D{Hvm zeRSfOC322XbS=Ty3BMG5FLso1)ggz^6HrF9+J8M97K|JHfOrinmNOSq`pZ)h-w>1B z+a%wjllz$Dt|s|9o!rSJw=l_9=;RhAIm#s0*U2#^`OL4n$r?JDJ(8RpkYss|gm0X& zJK!b}>74u3T2o}7PQD!HAz0*7ldLbV@U1e`uXt;kuZw(O^2V7WkLcu=O!7k}`5v7- z!6f%I$+zg_M@{lICiyy@+}9*GG09ix<Q^tDQj+s<>=4s$%&IBa6(;Y9MP0}(2>O%N z$cr&~n<Wnq$Z7I9z6(t9*SZK!W1zaNI`8-lt&q2L9-i<bZ;|Bb?=bEZ0({S=vvELb zmXCwS&acT<9y}cs%2$Xvo=j`&aXd?4YwX}z7((n}^KpjVp<`-ClE|<*fxZ&o|EVp0 z;-hHoCyGGders{7JRHvnD{hLjyZEV}hlk;~c`pygPH@I856`V}32q*q<#Rx_zjWEl zKd`SKw_n$aLydvI<>KppV4ZtStFbpfurIDxiFm$=n|qxnH)~xw3aOTM5+=y&&{zIe zF?Nc(50R*z{F`9lQ@}xd+C126q%*ENle;+JkOSjW-Qf}0;S#vr@L{Rr)$yGwl|prJ zQpOi`8$z7CBp#R2x=m=~(d_`?qC~ZXbGMy(1BM$oej48})AKb|g&B=;7?86!^#{fc z4+IfcQzZhyU!Vg7-$e-o@%Z7W`4Cc<(`Kwicj4uAYT2605Y=v_-))EbBIND^!($|> zVSnlV`VlD2WYjnHc^X`i>Pk-|vq$LRZMb|cd(0=Tx(QE*sRg_t6PEWbO<!x_3Um=? zVs^KfPl;+uks9)eLWzoD*gb%^mrd(|=5JWA+~;cLOJb3-n8KNr^(p_*?6bx-jLfW& zH7*X978a1qUg;3P4LJZXn`UhT_{-T40H=0fo&gZA--hMQa#<hI+Qa(WA|lS`fCU@C zdl;?=z;4WN0KA$pw+|&_ZEFDR4A}u-jf(}qffs22XMrAui9sIg^Hg5aYF2$^&{~Eq zB7XnXi`GxmG+NVXZ#G)T{$a#H>qTLpLbS$XKf*z44wVChMsrSJ&>F&Ug=qCePAFPk zm{Ja{>Xo9^7`&_P(xpsyyB3U_Nff)=PYINx60}yf^ss(RL@ZH@VYD_{a~ZA(trwZ$ zpf!at7p<4Cq7tOL1tAa6y04a?^<_<s)=AJ;j8<TMV2eL+T&|C>K12`nMBCjH7RKkb z&SmV0>gcKRaMlcJIP+<JHk?iWX2gMWjc`~Yob$K}wO2)Zs6D{>KKg?V=c^1?2<KDC z359bwQ_8_vtx`B|e-3b7Xc!moITY^217}S#UKyOnu}F7VZ)#Y#VAVF9dl{|>&Na+% z;9SI*3ui$)DnZ~}3V8r$P7Q(caCHr53rS7tS3%$NV0F{U@>mTBXsqgpPvJ5fjxzI4 z%IIJfdnKE%5UX&nzzKqBi8_PcU}JTJ;R><Zikwia@|jW&tB6Xmnl%+z-OEm6JIbYJ zLa-V@y;X+Q&A3|5!75WkEKyy_u35gcXSgD)VwvG!Rf91Xs|IbUEWs)oC<3bkk%HBA z_~A(RB<R`o%3)>qJkCC>>oLyho+r`O_=NS0sIRu;bwy-eb-y>(RAMW(FX!yVT0MYy zcI->Wx|y2WpR)Qq5E}2!xU_@J@3FYE!>bU+1uNT;+<q`<Ot`rYFW<f#BTksLW(cY5 z*doO2wlt%6{wG9=UBlQqo>+DZ;6f;Tlgrsw&N`B=W*yh&DbL<8APyj`i5L)<JOi9Z zOTQbB7a3rnKc4d7oTeUcqj64j#`19J$&BUqbAQ-&Cpm&niRuG$w@oyK;dtjT{R=Xd z%A_VywL_l8<6qWjCX*pmk7@iyi8X+KhTspz^P1+NAsD}(bR5a6knud4mTjO7yo@KP z<yUCNWhy2kc~zJ34=@*Z82^zX!VkU)bGI3v!LZBtE+9h7W8*3VdDbRk#Em+gmd>=* zO#6_3I2%dsJTNY^Msnw2@ln|;gs^vfe{k-fqTRw-=|RRV+z<cZaSP#OUb}?`D4G}H zvi@tFhxK}f^#kyScHi12VP_WERC-L2TFzt{w2RaNhTVR(8hbdVUoD0l=vRRV=~oA< z>3-D=sj0!y{kpe5RNOoz>a#T|Imr=WDWz-iWy5vw0&Bz6jesJU6p!yBjoOz|x+a(u zheHjcBk(+{SeZ#ny8S#*?n~yQALlI1P!)cx5(}-D4WPHswxE2m&<=luSm-u#4^QM; zD9&Tr7P^%CmbQf!x2Bx9{{;4K1N{-hF3>ZjsIkx>@+{sbVU1!k+D}xEGi@Bx?&lxe zy;GTmre}fiSi`sscTb$~FrJ_q8pd4<J;7%5G`Xsm@eYRZzo2BB@uLj8jPIm{*%rDL zd2+YBa}qR8Eoa&)P+1@F51(~(9tH!=8iyT}XS@db(bL*M?~|@?40PFXYS|gL(pyrM zGH!{1o^&}+!S1f3^08uCB`T5J8t30p!sQIK5tEI9)@Il>&}J>znmGQt&_4`RRS^U2 zh95fq$)Lx#TKd7->ZAn6|AxfFewZir?$rkn1LlZtQH(ldEODs4Kk0n;1ct>Oym7zL z3gsYg)D+uU-cIE4NX7U3WFUI8_!W9jILnWI_aKV%p5zmznBX|eUtGPk$9A!!7p*^> z?}QVu5pBq@i)gWnXo3nuo^^o0ZD2APQb%B0dX!(xjC}l|v&^jH-7ZUtbC*H5M@?_` zubl)zCeWym5Jy4wq5C;Au{brkxfTQ`B-Gd9Jd0dGhBovF@`^x%^ITxY2Dlf)<wy5u zbsaOz=pL=wGUkHZH6CqhkUKzHfLt|PK)x?bgZw7wWnzsdJe$G10W(cM0rTr2UDmlb zW3)8!3#poGBz{~kf{TY@q~tVQvi35jGoE?aULB7|$UcyF((JP(s=meL=Xm2L>b{a7 zecAMtnI+Vo(^oo*VA5Bj!A;(~_+xr`qXr&Trc&u}Pjz6hwoODb?9TCimZIng_&x*d zP=9B7og@~iJxtkxh_#S^__P=Ha6x7?_se$ws+lh!v3E)Q^;58g$Jm|4%3%vzk9uq& zL1kXfypTl}>(FlMzWN>kf+8sHyZ|G%E%acxye-73E1BWU^x_zEZJ~WLszN$^3upkg zaQfWkd?JyCA9nZ|phu?;bjPI?@!fDX0fv$0ER2cn1=PU<08+4)STDwO#y^-Y>Ckb6 z%47YoRUYf<6ExPz(#s9jAN)q`I9U6I@d~kSU(chebSf2Cw}KtpST|(2LaeJGClu>r zu($G9M{2A~R3%t%91pCgNZ&RK>cdAuunsh(G?idIGS(x&e?`y|H3W><Sl`QVMOfd& z3<v9ujJa5MkE1FC>+2vVu&#Mluzu(tjrIGWuN><#dmx_|l?QJ7I1QZGr?@~^`4RMH z4{+0k3l}(f2&rv+Y+aAsA5lX9ZUlOa4ctJ6D+DeDIibK^%an4R)Bx9_s1o4nKmxTv zI-&ut9oTmqc7od6gwl9{)6XDfQ}-*}GUSXrhec4_e*!DEfqRePihv6+!vSs_V=i#h z8dDVl++;`v;O_iefSdD|2Cf+N8n}?&3B(+qTIFzgxLQ7`;o3tJv*GIcD<e)nE0nff zxca#+>6;jjv}dRnz?Bc9x8YjIaD{Naj+{`qrZS~6xCZ@F30#Ao09=g>`w1LhpRz*W zYD)G);KKHg?NcMY0$ghZD1~pe;X1)^MR5JZ3<s_ajJa^_ZAeuJTw5U(;F|TP!1d1= z4cGOO3O9-igY7NG@}4p6P<g~M$7;l`5cgp`V^C2>2eB&~v3VCU&nQ^8jt8-u1=$jH zF}XLJj8zz}5HW>55sKJ$rj$dhy7r9Qey#+uFYunX8pf_+kAfS}7d;(p1hp4}*en;Z zzPOIu>0nbt&=S=XjM#{EW4I#3S~0^xtUhBdVr?2wWrA27GyueYKP`yef*+28&w>8D zJ>x3}%LBJ`j0Wy8aUTY_t>}{;;4*~^7dVe+y#Er9+&N-jSpUQBZQxQEt`NAZkP`|V z`%9(3)jC)SaDQb2xCPRkjAy(Q?0bM)RKF~69?$p|&cQgqZ4g0AR4%O825u_D6#+Mb z84hp{Fy;a`s-6Sf5J&~!I-L^WW}ei*Z2|rN@QkXkJX{w+SkC=c(Zp=ecsaa~2d;I} zwhNcXGkzBBk#-;T0?+s%jNXRpb%ra1YZ7uo;d+!QmG!e*3oC)^)(pT^)vzy~@gevV z4_p_L{g8g<@r*~KJOVT_0{jBowc*;ua7A$CGsA&v0b?#)tLst~($5w{D!>)^L*P1i zLc`TeQva7{yk>uS#O@uf5sMc0VLI4jKT}4>GuDY^^Dbf@&v^D?kHBpO*%I{!tldUT zF<c>H-y<g!v87BYhgdc38JFy<1hLmf0kJ#SHEhqwcS${n^`Z7c5c7D(>%9UD6G8EQ zESWZ&0WBG>2(gQq;UE^qn2T8L%cwFz>;hm3#C9AP#1imB&o~nF=j|CM>@5%6dyi@0 z?h^N5fLnZkqB_9cD_pq1c|2qCMIPWri+z=-F0gwWxT_eh5V#oRgaXI@QYmo9_f!I0 z;Ya}Ys&psg8UIAD^Z@r}Oj+POo-wPIM}P$)Xo-3fR%`?JD8m&2*M}Jna6K4vf$LYt z0j?*c0&tCg7vLU0rh)qk^c8tVdk3E<2CO64de_T+iH>^^>pJhOa_;W(fNmL~0eyx> zX#370bXgCe&k1)fpdQ~jx~4}T?@@E`oe!g1*nr;8aD{*-BPSHl4os=6Cr0hA1kfl* zpbDh789-ZseGj1DT}o-ZivW-BTu{R!zyT4oM12hFwgG*M;feswW`+ak7{**cpS^^t zke)amQUTDOB?9P&M>U{_LC@*GXHr?_+&d2%{I#n*Voe^^i2X?Gvk~*{W5nr#JEeIS zF^}(DS=}S>F{%cLEk=K^5u3|!g^0a?oKVCjF{K=05!!c7+*Ju;{T~5hF@}8^?Z)g4 zL98Cx4?)c1JHxyJTxA3}4fC}TD`vPN#I`cSL2M0UE@IoFsR}{tTSx`O-uO)r`{Rg4 ztRqs-+jn-`Ssu8-!!>XX#K9QfIergCb%1M9n_RfSd3<MNqzAZb1z_xG!0v6}PB2^{ zaJ!Hb3LN`OrNAxPQ3-JG4+C)bv6I+?-ZJz`PghH)5<`IV_|6^|dIT6Ff|jTo$g~;s zIxt)jaP^qs09TVS7r2H|RG9!*8;}CHgT(?|7yNM08wdJ|e5Yr<{lfP0aDDZ#hHJRE z4+Gc6pD3UM*GOsGh0Eg^@4mnz?Nl)?+<y+Ex8X`=xI(zDKu#!Ju}rC~pPk%R30x=t z1Gwf%UoxKYVzBRl>+_4t!sYRduSR$TC=fwQ)O6Uc4ObS!6~Xl|GaR_?W6Xu?k&7I- z9)whY>*`+xu4$HrYXj)ZdPcKrjmLdq))jd8?2Xr#_;LOCcN3pJbDvX4S27m*eE7i! z>@iX(ejmuaPYDhmjJ;0@J&2HLp(<Mp!)CZQe$4EfOXdf7;4Cdl>=nlJWAQ}prAp#8 z2<h^8w!LGx(DTF#V&CW(gOeU56+>eXvbjdI!AO+w#A`BcKQ(`Ql=}qz1%yF=X(saV zTa&+r?{LcT;TW3_{Ve@ui67UITgM8uiFIX6XB>V4a!C0-2$kRY==($YzB6u!?mG$M z4@}>gxr5f`^qr2iXb5iK@r+T8s(MT>RSX9E|LBKy--%?n!oG79<{sL2_AsSf-?8`q zw^q`3z8;Le^BAq(c6D2~hxDDyn#}XgDrP~)_Wpkrj{rdt6#M^R#O^yi7_O-AT*(Zl z@5C|Y_MP@Ms4{VNE$Ef7|9@EeP8xn>{~z@KGDg|6MX~Zcps8nz5=|Ko#LJ^Qc8gY! z{nYP9>LU(M{azge1*M4tG0x@lZ6ONkO=fKc$rGMJS3zCEJqmi5s>Cd$1I7d!;T8<L zPyK$7qUNMQ4dhwhAVr?&2t(==EX`WRw0HPtHvY&X+-L1axOid6cjzH)maoyI?5WdV zKQiK&<y+OsjF_c7!aazZ464tBd6@oEuqaUz(6Ei_V-ha+2=^W)n@6~}G3+8bAd;;K zqP-y%5N-a8Ao|oHjp%aF{|lnMJ?B{x)pwgJ0jqc*z?wxnw5_=sr1p#iACZp`u(rE$ zKVOP-$o6T0Wul)FH3fac2I~oiU9h%EQ3F<g<mn?;i<nI7Q7KF#FxGqg^9lYy#;h~p zQ6X^oz%}=EewD6fyvVI^Hy*f-UWlj%uAOW|KcLug&cpTvhVAcRu{K<*BwP-zIZQTi z{g+`EuK5?RHG%5`$N;#;{48*7I;i1_LMooVg>39se*UPz_n~+Vpn4Kvs9hceUMHjj znbRG;w|ekOQ>V!Y@RHLV(z({Tg6}))5&R;tuoATmHgDtg4Z|*8A?J_gA+PNDBlef` zJAd@_17Q3*!?;ZC-`L_|JVD)H7<W&1tall2?q$5UAX}mudKixmWjy5k(H}7HvgeNq znYJ1Y{O|Ke>(jNdO`xIJzG2^HMjYQTIRa6Sv3={Z{_sB@oxdh#QlcI}^R}_|k#IR< zyMf8Z*g7!m8e38|wkF2b339{Osvi(zd$3R&+k2qL`J=Q7&L4He`J?eTf3yP9RCfLd zPc#1Y?9qhpDzVPD1_0zf;xUYMF52V)IZfS7&O@wov8$=Xzdf27AsQ`F*P@Ht*4c(( z*E&Pa9z`Lq?AfEgVQ%Ml_UO?4VEj$mmF))4q6d21;5$_{<F0k)xr{&imxu910#1o~ z3XR*0k7C$mT)QIU2K$o9?`er&vqo`)H!*D$)Be}lqc&iip0H4QkMV@vz`Msd4^=_b zW1KwbU_9Z*KRulPLm4sJu7PRT#<^I+<&5)PCL7~?iDB0`KMZFrVw`V43>fF|ePWzz z_iE#eKq}52rRlRr89aMbWS>214G7@y<?Iox&~xqxudU<VEc0p>_CMB#n&6G1I5^1q zcsomNrSaHEUcE5{$?fDXWI*HLL!*ynXFU2iB6=%P3t`YUlCv3hk^EVT8YHJ7&!XqC z)-YL+9LuzgOq<U?wDyY69C>FWeectt)-+;7^NHy24dmPLI8mZznT^y(rFpF02yy1L zM~Ie2h!SYl2K8qNmjiVJlMSf(47;FiDLrR{x(*Tn)K~ThsK<6|P!l9ozT1LN52yoS zAi^_Ie?aNeM)oR2pBx&W;jUx!v7(2O;yIA?I~E{%C8M(sFz(bLhf|WD@YEqG9gw2y zkm%RroH``_G2>1hk%XhxQ+5f7zBtKCQJoa0p0+6@I$?^JLN-$ipS39@I^;Po1z+2; zzMW=MNc4{BUWzKDSUA%oi=@1V6we&IbuP+y;`JDJWRbPx_?JC(NXo-V(Pbq1`>ReJ z5<kGWT?bZ$J>Ce7U(2|ZM`r$8rY?jRB5aq_>%Z7{%BEa^6y3Hg5OdzM>(T`#Fz(b* zgE}aD-&2PiHTxbZx(*?@_amnc$-b3wrw)O5@yDJzB;`Y-=sF~N^<1Y8iC@mRQ->JA z47dYbLZXd6_fm)vJcoDnHHAd$F7i@{5oDvEYYK_hUgD(?BY0|=O(D^m`CbaKfU&DQ zvPjBcr07~DdSVUAc;Y`Z?#Ln#rxkeWkdzycqRUA1yKkI2B))`kyAD9zW<zMa0pn60 znV(?Pvcqp9Y?spz*TTv=H07_&cH3eT&tmCj_?P(OjJr=I;&8yUR$z3jzo17y*avPy z?U5$G@T;}dAv|Hs&d*4vGYyW5&%8P6vvG0Di5M;f`r)5*eAyp&C!`fO(f28Y(SZeH zKHd(mm9+}jD&VAMwIdjIFb9hIOpiF*ifgkLT=9~iW}pg|rx&lKp8B`e205+uvs-)N zoV3>Ed|PX#Tk980ip5$d^Mb5#{_x^je4GDGNQ4+(QGJ0rz(K?&WQjLWB=p5dr_ho! zO^H^2{&fylT_r_-eF>=ZUWZ=w9V2{I^}z3*VIf*t#P_c-jM!t_28LaqzxPka=Wpd8 zg7YtwC+PcUoA&wFGc{{XoH<V#oET}<!$;mdw^2?$GL|d^Bkn*ET%Cr24EF*>+{#!m zY<6VEy{PppV{*xFPk+vc=;d(~6jPda&+1<vhBJsexeo`$0@dOy*^;Y#iy=I3w!)ni zYgH#q!sL`T%eFxzH8?P>CoY`ofiv|o=C&(tk{nRD6%#iOnVU>@ah$@GXEM~$%`t{< zIQqN|w{N7WdIYi{NemD5^<#Z^{Y!lTQ(yZE>+7e!A@c=EV$itZllS$GOIN*6O78ni zSAGU@tq(JB{?}A@r_5Q9(3%O8*HEkGNVdLnGjNV_;Lgp(f1l%f_g(v8_1S9){RG}i z?W8`}=3oCuD!%J(YCOl+5j3hU3ec>sLc*mtL&Z5=+cJGRB*2YgqnURl^1^jqEb@Rc zE<$)z6WmFHb|CnzyA&?Pdbj;<m8Ns?g@c$6eqd`|UtWP1n@<T#>OGh#%e6(h6}sFG zlvDLt>RNf{8FvS~k0gKVpK!y@Hr!)S9F-jbU#Va8$D8{+q+4IaLZo=V<`nms`ySI3 zK9ACx(=`wgq6nw>(zdU+CdkyBeyDTF>EBz0(^$=EO-gx&odBHTMnqq{F4vQsj%2Cp zY)<Q!<@8?o{SZz^iboJmt%d9psIwL7+>$I>3n#N2<pd90>NmsC;7dZj1)Am;tnrp` z#8D@pKG5*P)2ycjXr^nLZ%9Kgs5WUDzoBUkn#VNFJkoFkRdX~AUOtn0aPz$HHcc~= zG#nw-vzi7QTtag>Xc9C{CTTc&sezhi55nZ98EEQgn!8EEF;Ly8X)rJfO;gaEOcL3< zl7^#?YM^N_w-K5+&}`K-O-Vy*R;K}oZI^I`zOOVvBniMH-hb5uf_7sNysZgJur!8U zF4nn3`=Tv^cHd>LUDm**WRw8k?(;pO%dJ2;^)yRen@5X)U8W)_#4hpFG8FBnVaIau zlx>%I@!og2u5b)WYfjsGIK}0TzDP~bUvqk~%jv+)!s*VX!l{@^`f1H6zTfTp=_b*m zkDTs=1g>3HDa+|<!pPhIc=rW+&`x%LUYl9G-^w%?*F&Atbe-0IFe^4UkrhW+cNiLc zw#WB~rrAguvAKISO*=zV7c{qPn$JliHg~P2!J}Hi_%hJ6*EBDYMr`g<P4kPfgBZ|U zs%f4ejo4fX6aao!8k#zwIoVD0(4RD7bKhwiOjo5XTp;D!u4%fFMr`gQ(o`uPPuOuQ zyf04^v?75R+%uZsUJ}#>!P}Z3iUbfMObyZm*O7qZ^3$5&6jr@3xE?yUAq?)#?*+!L zO9-QS`y@1<wWbp;?8+mgFs#vBD7y|X1DCgXplXNSp`rSj<KPWIj%T@ZM)Z@@!MG`l zca}VRoKz8KHlnJ)eqQgDhI_ygF-l&_kN)}t)$m)@Uv;cfM>J~>g8Tqj!<R=Rmq&vW zuE%rI(0G0#ra*X${!-QScg!nz=|zcJ#8Q6J$o(mkXJO<K1H#A>Gnvf>Z$XQ=?=Dc& zA51}ub@1sTT;l~JQ(xOMP=fJ{@ZJ?(=54;Mkixeyc@L^wQ-^z4CLcKiEvI6^j{8Va z1#i2@vbZ$ZD-KgPekUw4rSrDYH3Ru6o%5rf-XWUIjV}@V!Y4}P*H^74=1NPcaeU#S zkZD*^*GJDcb0>TU35hBXV)BL|mg1W{4NzO&_w3zz<M?gmnL=%(rlF9RXsxnrE>Qu7 zTbh-1q=oBRP!!t(ni2IdvaPvDv~bo4h@0eIELFq8sz1!a`|4C=CsCwt<_100+5(Ey zsLxc-aK))i)U!{6!(cDo=W!cE<Nc`v>&)=yRI5^2m=v|VV>Q(T!dh3MvZSa*9jg^z zpA@yCW3qbU1XAls>Q^0;i(4cGJ7%ke<f<AI5i7pr)?mjqY7z;Lp%IBKfL^SFh@D7^ zx~E!p@dd||qN1y<QJ=sTtZ!|q``F}C#3<NE{2HpK76Yz@@!3d84lXsfJz)-;j6{+p z2j|9T$nX2{oY@55jOQz@lh+N0$LLmCpy&_Kv0l6t{Tp@@58je-b0&g+f&t__VRC99 zM?MFo3Ux-h$@m>uCCjBPYMsv6jbnPOVTa_%baJlFS!r^XNe;i}pkB~93+~coW+BIt z2T!=_>L^&H!1LwT_xdfcv^&8^a5T`tr)7|=t~`Z%-4et!=jxQS5^ZTLMN6ZP%{xZy zwWW1D?6I_g$F!xj!R_((9!?X6-3zVkJE~Zps>(dSzR*e%jsqD)OIN`dGp|xrk0RO} zR<`w9c2{2;{O}>+FqGrg7?wvR>Pj?fzG?)l)O4x<14e<+Fl7Q$Ca+=lG}}DR-L?8U zWBt~`<Rj~aqDbBLH(Ui&GDG6~RO;6{{*I0(2M5LnhsCL0CYhYGn~s+FLaktMc@o+O z=FPGEAvTwpKC5dfP}_BOoXI{7G4yKTH%N_gx2NcG`;cKw;s>46$>gk|y5R*hp9Lx# zHR|u&XqHy1_x|vvs26oqcXaZhCOZTY9mOadqId#UYvHy%u^L8HFJx1<jTV-cW}T^- zc{w9B5COX%`pIq)7C7x3NiHY9AUXMkEP^M3Y^Ektks!jZe=0A*L)9sP!^ORDKTle> zfJzPg33c)|@0ovL2bNdgomR6&d%m5$wNk!;Svrie0_!;#Cd+&VlP+D`Wmx>E`Q1v_ zBzGAYH~PZ%zjY536&I70QNl`8_GB?~UoFGV6R6LyGt#ir2ki6<VW*1APCd;|iecwE zvV&3CTqK8k{91vH;^AbdvBS`(<rqSNbTmg>j#PtwgSLWQuUrpX2dd0apA%vj&)3EH zHPmVYagH-6k*s(IBQUua3_#zaO~#*QeDWF^wqAzmJDcr+%iX9>@CQ=CLhl6xN(QTp z#*{xbZ~$1an??Kyn6uV^Q16s-7J;>xUgGz}qDw`Ht1$1K4qoJpS-dl~y6}&&kv@cD zcU}$5YK#v#cEIC9nj9hPC8`J-wtdKMhRdHdh*qnZVa^&vtA&iY`vPk%)+8JJdF*S! znBY2bBZt;%HxiH3UhTi(-BBO~Ev}!^@%CHQ4m-se=F4fT@#mr1N^`Zf<Mh91s|nU; zY6sDV`hep;)#=L+ZS5xKunAXN=Uk7ws?ejY-+!fyCF*O~iLI@93|FMBTxK}hdWJDq zTdyeAB-)w=JwjXkp(Z%pMQgOSPJ#Y>wB<a{$5=o4$Rt|v$<K8EPtAFVv!fz)<YZ|n z?z+38=ScqTKJ<9h{TKD+!X48j5?~^z`~}I?V(Y+Ejz{%dsgxL(uR#~n|BXFi1lX_I zLJ7FaP;60VZ$S}&iv=tvIRrdO%fM1DH+~}cfg5VVWgm*(0c+#bwLrZB@z7PsuetLc zH{Ls63P=fT(AVvmk7xyWFCWoUO(9A$cJ@$PGI!-t@%$(1vtbG9%%|ccZ_TL|&skwy zYE<{L?SJF+GCDbMCb@MXLJf=WOYK~kSwFQ4xE#ZI{|i`K!QbH%bPd%Z0T)-|>6!v6 zGb$yBI~nK?UnS!gcZ*t-5h3x#gbyEGy<O|)V-zi23t!s#%&52gLE#qP?Ns5gEDV;~ z?pCV@DKymZy4`hE8dEq~g)XK-7aq4E`(>#)L(*-82^2mxq?R6LnTWG1VK4tOl`lx* z;wwz1^!3PomEuQG?8?=!FMef<j=sb*p-;zzUT)D-bAI8h9@%()2;hs+(ab!3&MW9= z&a8eMIjCS(Z(1h5VjsIXE{Tu;{%uC&@@e^8jG5o-UM~xl$w!8Amn0a`Q3S*%(_lvf zn1s!~8=-G!zwksp+LsS6;L7Sik92zML=dW9p>}e=6i?5Xm>{KdCDR{Rr{;cwfsUU! zz;MVs`Ka1awOS0IMD3=waNma!dIO@i(53|ocMwR;(%c-<M_9afkG$S5tu2j@lV9I6 zm^Z3^hNCMCN705Op#ewr!4bKUbX-=8@0CA04<|#C8q(d|63S4QP=;8CHH}b%J4RG} z%}{H@P=9F*AM%r5-}{MRr~n2`6}`4xmpjJs0n7^x7z%u>8Pe(4{RT&a^5F`x32F4Q zkWN92LGGLTfTkjITU`f?TFtacthca&Cx6USPm(mk3P@UR{C$SMLgB#|MgCeE{{F-R z5tiF*_!AoNXU*39>2&&oqiQXb>*24C-MGFFFM^HYvj|w|p)TuQEEesEvVc4oI)g0) zDnYjCK$x!?%7N9Xmy5K*h8l+E8-|1i4D~Y%>GW|JxR0vgp!G16Mf-9Umcd4aA=Y7i z%Ms8ts`_b$h8TwKF&cVDGj!$#Fce`J+JWcxEH}e2Bs5^C;3KUeoj$G;8QKk64@1W} z@VN~AOm8I&u@0-VVTch`z`O`+yD*X)f45<1l4fWp#tD@HzeJO|*)TNHFeEf!=o-V2 zP9K*@hHeRE=z&m%?sOPp9oFo#T0@MeYcxaM4MY75L+P5K{awM(&*I05)R%b9Mh&GI zhJ*$Teej{ykffuVZNmwKK$4$5ZYRvo;{v{+yB9@CMXbQ8Z@6JZ%_e<>^%cTgh~r8P zJes+Zvj~{eU52+rY2SA%dFx?#t7mvikUY33{(`sahBuv#E7+l|Mxgbe*U@20`d@Rh zAn36UYurCtS&XRan!Q+79*p>T3H>&nvqWWIAt^C4mm-DFTB5Rr2Fi+K4%P+1(TOT= zj;<?OrzHo6#bZ?#=MUo2@}(w^Be^`IQDKKDwqDSy>3bRRJ$StyC@1|)8<917cW3}P z_nDl*$l*L(w}Iz5I@@oudoWus*seby1-qJ@cE~Xcwq`n~jmf!Ga%2r3sdMU^oIelh z#<Y-_?;nyXFErUdAsgS|<ve9mA#;o{NA?4N4t7)zZab0YF%8W=ecwwmOmkKg#S+X= zlaZz|V$0SJtZ<ko5pHz=oSX9iML|+4#B7kJNKVWV=4g=gO<(Y)Hb}z~Rg4TF_)w|L zUH93`=7y4t`Hlu>;6dWSN!rQX4Efeyr;#}f4H;zS2o%0mCTD}_4qpM+lVUYZXD>6^ z^N_89nYCZEIM-z4BEtX^&^d3IoF`3<n*9QGovv}J$-Woa=Bu1(QjqM9+y~v86_Cs- z1|Y$sc+DLZ-;kCgomCXi3>Aqqt$4O+-Otq(6win{0`PHm2T$BIqI<*`@Ko&w23Qdd z;V^5RyoPfV&m@iC<H7gdx=r2Qtq-36>BrREog7Nc0!1l-L+a6AvCoCu%Ra+LT{%@P zzO8#U_FsGT%eWX@a`+@jkqSWK;*QvntKtu0{u(%lM1R#Z6*v{VDK@L{%dGX0ftzC0 zP5VT_H}QcJSh^aviKmlzc<Jw~Mtvg7T7H}<2r_<QO4g`H$v5Vl(x1@OJ|hSC!*`TC zqF^TWzh!yPDkIBXT9&kox{1$qtdf|0Dx)WE+e6nWQVYS}c?k8$UJ>dMSt1mu`+>MC z)Vq#Qi$LZGRnG`@2N6P3)hiP!co&u|XR;1{ne}aC;I3GH8`8OLGVOR&ZG4Pp(|cSk z9mmFHd<Az^9lQq4`gLQ4iCjGX4bSX6T2EAO?<V`+yQ(~w^zw3P=OFaLJ!G~-jfZ!! zH-<+t?4BDdWTyvi=%5LzH}b6QNHI?{n3l-2Z<)r6$E+{$r}MCeWv`#SO?o&wcRab@ zBUUqBFMYduxsOwYKWXmW3#vT#^cLW#hQs|S$_eh5(^Sp-R|^=fXzBYJGn}PwkTG}Z z`{pjzBun3!5C==&2N!Wb@-6vNFMa<8Jq|?o13qCPms5qHcS6vs{VvfvQ3-nSKFTi! zW^Nkm`auYKh2*6&^a?h6<)@}7Kdstq>n~uq67*h1URm^>X4?6qH@G9XZ)~`aqwP(6 z-@|>JYG$~v5WVVN?mHRo!^p8g?+;jYh3M^OhJ)Tl#$5FFVW-BR_X8>edhah3^v-^v z(d#OyN&SFN8T9m>ntY1m^ue*o;>&OSFHuaUuXX$22wHI(toZ(`p@+-ZdytS$Jv@%5 zOHLn5SM_%?FC#vU+g-KMC-Sz5`;}XJ!Z&$POc2|{{jYS92E`)`yC}XPMWqj>sm;i< zc%WELvkOCNDbqM6TXgakH!#r$-Mcj(C0PRa{;&i1zF+)<vAz}XH4fj2>Otz#wmvzo zxdWBKwews~3XV=Wy>Bcfg!LtQ`0g0W_s@{q@g1?`G33l?f~v-}&@-pFRWmNLR{Q+q z&N%LrEw5o<pYah2fW@)zm-Z0gEpZXXeVjvga|DP}?{3!uhygaB;&-_MOhsFc0AGpO zl&Fbx<Hi6-GhC7TxQ7{z0j4tM8esozRE4;YJ0TGa@bU#>fa5>c2DlXTDZyH6IK&2O zJ?$^e5B9?7+Y85sH;+1O9LiWd^5OYn1y(s!<-JLRbZv0}RgwsmY)yblo|ArOj<OfO z<55YPdY<e7(?rJ>*SRXm#5p-fCGS&tz;rk)+qT7YhFx3Ck)mRYi7FX+Ru)pMN1059 zR07i;XBt1dU_FRGA-3q;^ID&LZ<T&R<3u02+RJx>+Ww>FJC1ydEv{!P+7_36=i&Q^ z0D$w)uxy*}*$lgUhrG};4S8i>=o!nj6)+h0g&tbrFf2f5q1^4}9j_1JNhQbkdWLaq z^XyYk!dZAuJU1fao@4BM?r7M)z{|GJuzeQxY+K;(5-xY*`6niu6VKl>>{{Rct!z!K z??=c0>-*p{vA%PkYU{fJsb#HCEbmuidG_J;3N6q0!!ED?n?Jk_3rlr@_zvR_hrI2v z!E{yQ2aRQg{_uC4<#cQ?PLx-o6fD}tau35UmLdKyA9-c{;asMjk3W359r(UYT!!(7 zpS|VbJ5k+9<yPhoJA3&aN(s?-=+AAw<3srl@rRM*v5Y_b14i|){*ZGoTB73*x3z@; zInu$6KRgOQ;qiwvw`c(>^oL{DdldhX*b(l(0~5A24rI6@e|QTs9DjH{W3EN^+)P!7 zMcxD{VUd^46N?-^S6k#<(02>g%BDXY9H@0us6+gvj6<y0AAW+3-wOTVsy0x`lj1v! zKivI>M<r?MDY93YKO9uxQAsY92TbpSW!sphG3?r6h(GLzyt4i<j%nxP4{MO`Rnkw4 zKfK(_cY<2CN%LKyKb*JD!}lHmphVH1+kC&uu*-LdKOB#|vi@)=(<=6dm<Blhu=f?( zA67Svi$8oA&cfplFCya=`@>UfJ#05OZ2ty(wk`00gv<HEZ<%cT;c|vu>)W)Et%>!m zfef&|mp&2eJNmJ<zAKSh&ice5T4fxfzHZ%_8YU{=OQA-0Bgecr3=2J51H1@v76!b* zuX&6vK~?|W1D;F>J&UqqYdl(LBHF_9PnfU`-fo6n@OBaah{(p(3gnf2Eo%<bR)Na; zfPc6$^DN4UD!mBbC(do9@k<du!ATazvrk?P!LO%i)O~};vmm?1%lRP6i0;yk+?p9x zQwf*DuLhG1e&=919{i#<IQUfqvcPZKY{BnJ{BSq-QIzFkY;bZQ&H$Fkxf5niay`BW zuPHB9g4bIufma`K1O~4~@F$MnOi*`|3pfesY-RCET<yVYglGrv|4|Gxfp5cbC3r<4 zuPk1F!*b3KuR|>~UayHWFnIm-atK~;eMb#eh}SbP3TLSOQZ$YCztOsl*JBbchu1w! zHhA5}u-o4T;4y*eZ@nQJ@M`{%;Pupp8n5M`uLQ3OX1Zp+@!iaSn{VuE4)|V{E@kE$ zr_nPV_|nzuWD4+AINzAO(xZg=qO1}%79GHbZ#cs)d?E9VG~|_?Z(Pr`^O<k7Am96F zFfw^ZSG&>6ccMD@jpjSSne%$qU*F_=_&y_Q$Ni@;Vw>-U47+@X%r{;|UfKCZHq-uX z{Z($hF(@7aG%^Cj(N{c`>rp(Oh8qDYoNq*W1-RA-Pzp=7t?vZG70ow(Vumx{*ua=; zfqM&}H0|-XLLyk;toOwN|CyyN@Oq>UhRaXpgkx&0D*r$8jq9d|x{?7J!W`e7mqR5r z#9f&A#xQst#}?Dn#p^Yu6|TQd;%TSTA>*k$IM5@oY#Y-;hFwfU<{N8}S9ZQJpK0ea z-*~+l_`Z|Y4_lP=*B38%_)buLsaD$smR)~!_3}NO5`yoJ9==<J@*OhYs6`&J64KxG z(!<yp7}a^qHx4y5{!co%?f>8`JoAmW){!0e{tM6g>lr@(wC{oVQtSr)4^7(^_?U#t z`#&bz{*PhT`Ub3JYck*H4Y}z5-qZf?UE}{iU(Wi@Z@#g1TBy<8D7wP1y*Ccvy(E3j zfOl#}2zalND;vDB<JTlU<FvK#nP{s-Jq{DLjcypjuF-|eH*QB>+3~9j)6Q$Y5f8?> ze%>XW!r*ruc=zD9ca4Len4M?7v5pTMZO%`M=1bHv7_p7t=MpZ5-|I{^_&v|Ci{F1& zJNV^74B$8D9l>w;e>HyRK+o|jd1~l%qugwxZm<%xu4)3biljRkwEXZUj*Cc8#pIzf zw6^AXWDYkne*^os(OSlEC1|~iys~KJFzvk18q-*#)yD8Hv%_i6hoE(p=&!=rMy!|f z9)fC#iXyjWc34%y<<L3;!?w{XWY|UP_mvJ>hfx@4ef74W6^$Rx4$~yH0<<chYYYhd z+gxK*BY<}WI|=+`I)}Vqjt9JSb>%7zUWIdwn6EwHC5x&`R4qro5*5a<3tq@v;}AMY z*}2AMrk&4RBd;O&9wlzT>}~u2Z{iqTq8dY0!ssfTYxKwaPfkahMhW5Hd!udJ====3 ze22_6+LFgIdmFJ#`#;S!{%imNKBv`iokPW6;uRoHeVMNXsBo_F=2sp8z7wk{Q7^)d zZQFa6;fm%Ok21rVYos&g+TUX<s0#7+gCP;@@7g!T{${+P?Qb*a?cKKj-@T3Rp9ys& z1E_&Sxc$TRp^~@7S(v#->2n@T)6{!p513Xs*9a`~sAMsf2TUiyvTaN=7<MrYnQQbz zUfH=uGSkjyu5l&#J}mvjIKUoWz7y21%QfE>?rm)O(!+O{;d?zS+va;I!!F+;bB%Y9 zS9Y#3jcNaTZ(}UpKjB!_&M+?C?|C>2&sf!-j8{C@sPAPvMeL?T)h4UP`$b5&ocB8l zlefL!L55xHJF%3liS;QIhV^~@npoc@_@Vc^6RG8_uj08zALk7wXTj`Oso9~HccVSw z7#<4*<Hchb1gA{(SYCo^wakN{9PoaZ+YEZQK5C%{!5c(nCF%l4&Jy((Y}$h$4pN|~ z+2GiRJnKi!7WKvjH$A>(8g?(ktU3IHdk$oS0|@O`-)3nUyxSb}>S`z-6qjM99jl)W zfpV}Y*E5izQp5l4Xu$D?Pf=3zoSVtBf$};DmxJ<hCYxzTU4~sKTP<;*Y(yUyj5+#> zK-mL7gz{O?<Axc20tfGpb#t%e@|y=m`h=<jUZR@*bS2<@b{W7MBCf%Jw;mqG8442A zFfwD$KLos&UE%Ls;1PbZD5*rHpikJ{uPeiD_X`29De}sKcM;Pn0q^YO^57kd(cpa` zPQrk90VMGB!;kZ*P8YmaUH)JA+{6D$Q9Is$gDKnKO^|Ro@CGy4fOikWE_lPfcEC%A zFaWRp%L3kWFKO_;1-$_eQ%CpvMc(rQiE7`ZN&q`o2Y@Y-9%TTlJ0%3LJTedhSU*?b zcjtQq-YkkKQLn=CZNR26TnS(!kyjS5`<PY<VAmNLyuIy4uusSN2aN?ompINoa4jCd z&Mc-1UBK>f`9FZ08lB!2ZTQ~_^R)rnAmMU=eaU14*vAaJfaQI~*2Hms24Mi$q+9`P z*NYmkdXk!i6FAX0!EHXnT&{<;n^*~8Jud}d5k}ku&Q%7(3we52b&4ATn5Tyw`_v<F z6R|Dq|H9gBz;-iS31BObR~E22OsfR2H=Zir!=ArH1C}IyzyS6>+=&OU9-=}QFi#Il z@bW)EfW`OE$+K~f4J2F+uxd;;fSrN0djPAx$N}ser~ufe7X+|Y_@R3oiq!wz!^Tgj z1h6-21F+t-E!d|3_9Z-z2e5u*AOtW^54#aN>W+mzDvBvl*H8kHrbJ!Aa3z3UjJ&dd z{RPvh46vQ!%LBGIS_Afi_yGgh33NpdU@w136}o_Vdf3Fd9{xWSRhOtS;K2s$VF{N5 ztQV6FU_BUidsx4PY)yJtPY4LW8qXBK9-pBB`wH~*g*X}I>0y1l2i8^efG=IG92W}R z0DBUAAPUgECjH4wg8xFdbf8O9Z;=&1CzD_q&8E7}B^wh42f8mrMI~w+?B0fM1j8<L zugSxEbKs#D@~r7dv7TfyXXWZfrpX})elk=}LhxCOOhs-qGQ2F*o{!u%q72(;IJWs+ z<CP&n?fOE?;7*A7exsR=<bUFkp+pp4qP~JL+cL~y*p(q<LOdOLWhcbrm{xv5JQ_!E zybt?^T&%6Gp<!J7`ULnBkJZJIanFQUUIWpy!0KMMI~lga$f|J@f54iH>y@**y-YS% zw}oNX>JEO+*2L;|pdwh^?B~Vm!tp~l(M?isO$)5Tp_^JWQv$VqG-q#k^rkpUPIydd zP>Rd%YTyrCf4Y4FwX%~qt)8gFF#Q(+)G+ZI#xNg%`|%iNwFMef*D#-SK`ox`0kytp zu|yq&ncJXlXV?WbWObH@yt1pa51CeOb*2sT<*{0ZXUZC8b}h(oJ-dZ%m~X-TI5Ob8 zCpB*S#rj}BZ@eo*ORo%lDJ|y7jXg445-I}@P`LB_Q?M#+gs>CoTyg3k(>S}gI9yt9 zONKs)^HWW2jMJsJ8y9#C9nNEnFV6pe<b8L1RK*&05F!zfgc6Mui5L;27?21Ek%S@} z2pFX*ASf0D6qSG=ia?06u8Um7axK`fqktlM5h+q)7f}>J2~}nZu&79plJ9xmnX_lk zCad`AU*C6sS9Z?Kd*;05nP=XaQ$iJl0_9n-NjzVJ@$OeFcfTPp3ac@=oCC(2q+AA! zd8{^I?834O#=i4-H34IH*a<M!eNe!dAJAZ22zlIs$P3h-n&Yp%N^V2wCvi%un}?0~ zH^xd!6mV!gl~dkI?S*k(6n135Qn5$yQ58h+E};)Ivu(P|6TwMT(}`g8O6`W1Ew{`P z_u=^mVA?@p9?LEYJ;{D+v_;QssjQ2UiliDF?A);;)MxJazKj(U*0W%N71kwh(b4YA z_M#ismvF;7Lhs*7K=Aj!foCVIGo@T6tP@ym!g>qKZdfP1$*W0N$G{kbwaWt%)@S@W ztUp2i@2%8!=En$L{Amc@hcd)W@XiL?Si^4xmGK16$|GN$V;TRwI4P{2#rSZ7_Xx`| zf_Ep{qJuY#buoh1+t^?S@3I6PyrTpT@F)|+AaIQpywbUJryD#gk5mX`BzR{U{fhx* zCwSjTxlHhuu-XJ~KFe<KR=mNhN$?iI7zFSB=@Psx_v_%LqPE;TGInNi{upochR{@Q z&vmPe=#|RwG84eiJFV#Dsfx5cR%WvM1<U%g1ax7w6~n-Z-g=hZ=y@`e|Di29GkJ-1 zF*1{v?$9<o9z6jRoC+J-8yh4sej20HLSRRF)Ip$309Izw$hM)cL^`bMTQ=12+Th7d zeh2QOGn1{XD?c;AQ`DFx^kncwyawJ>g2n;f_OTw|-S;}$tjWO2Oh!L%xqh}lCaiA6 zr5)g1E#)%6>&$8cyf!Sm!1KMvs|oNjVKabN{XPNSO@$hGuRz`x(3wf%d)2PU_E($b zrY1X`)T9nmlhdM8lk!sL;cCWhF@X72B?R?Gp$-GgB8=WhQ1jFXYU=@}m6=@eoaLR# z;>ED?VTe1x?7*@MOiyN#ini#?q#EmDWG2T(Ya8y52IlUHu;B$6K!zGC+BT%CmtWO3 zxGA%hnFOD;Y*-?(39D&<xnsk4mR%b>naLouMQ0{H)|H=`WI<C-VZX~rF)Y{*q+zk( zkyoIs1x70~*@i49!h$u7sy_hO4j8|Xav3l#VzmL|>nyuq{NQC?O~5!GdIOA83IvQB zr)n_Pk=ovQiSO0!l<luQ%}q^0Zfa65IyLd`W+mO~MPElJBS}96kyFGCMy60o4%jDx zKK#9Vs^?IOWF*#F`<rJhcbvi)Bd7cnSau?}lw~(^o{Z!Lv_(&9Ggud6QX6%Pw!xm% zZm*!j*~nNRliK~ad%}5vIM|)ku68q$TDJb3B<x{Tg*uy6&k10<oK?>*R-15cV%ZJn zo;mb_gmWu8LO9=^BH^rxAFg_ONNwl58$ExUt=t{|t4GC%+FfyoS}WlN6SYS`FILnp zeknR?U{NQ%uK%<ZwOsKI{{BtGq_9e0IY!j>VBkbYZ3F9KL~X;!vQhh>w1N!6+k_R& zAp9ESVhzH4@uM3xD~}xfl%@ZJv=pf8109^G`J`NC5VmBsiQ0KAyHUIN#Yohe!gxgO z*u4_9zW8C(9)<kh%Ojr|5hHjXo~RI~#u9AKkoyj!(+b`MD&rY)RvtO@Nz3?$#7SY* zAMkgETo0CG1n)w$MF+1g>tY12s<FWyawm@K;JqWnV1id07FfZ1?*+Qk4W5-pKKEZs z|F6XDVf8qm>;x|$<ubv`XSE65aF*TRO?aMHlOcC2j6v`^PLkj~agPq(2FRD2M_TW9 zW~n{HV+5=kELN*zM48cc9;nC)*vC}B6EKS-=fU{Ml(AVHgTMa^<U0X-lI0iyn}oLL zfQ?{XjDY!!4R*kK9@7Ck#aJL5ISkZd1?*IDp&KxZBg2nd`k!s|{~7Rg0=7}gWdgR6 z)h1x?vFrxy<7XoQ`w+$;U^DKPfbE*719raDo)kx3d{d05^*f5FRp$V4hS_LPkrlO? z&qYVg;>aTya*?Pt7Vm`Ben8%d+76auMD1g=MMrHR>taN0;f-ZE^6@`()N+Lk%rJWs z<I##*p7_y?n#GarZ2gDRQgCECbv83wnv}~#?Q~X~s8wLujatpw>_vuIWyBLv+i;ge zttEcQk+(zs?{VaW8)5|Szef<fD+o3xcyHhA30_|+;~8=mM|ODB3f@R@68`=%;O_+Q ze3oMbuPWN2gLeopiWR(F*Ov|6MtskZS>{7R3?_K{F*dE>J@O3Q=?2f@$h&7*`oAG= z$Nm>|aDsP}l*<G!kJTo4U08O5*Y{~&O@h~*Jb?YL2@<^g@j7@5Azv;>#$IcGFw7gh zAq*DR+M5m`dXLEPGE15R7^RV+m!}@5Hi(|P**e`#PbNKLS^uVZDXhj~7&y_pnPoS6 zp0##Qv_-GA+p#XjTDzUG;fd%a&6%{}D`Lk%V7hHXy87lRZG*d{vDVs)@uB?)eT2mK zVYL8wc5HZwW!DDJTHBAd=(YA(){)h{uR!uHz*@S_thKK_sDXEeQCztGPSA@5ygF3e zTHaV|?TWVAt&G}#0K^XP_DQ)6@V;lY0p4dUyTJSLzr30N?`zlq;Jq+TfOmAP23~uq zHEZof)oR>`#daTevAx4tY@fx&c0%-GyWIC8hpW_UV?Z<OcZBsYL4~m9@n-N<;2;Z{ z$EdFdn$~K2`%EjWHN}r%wGlvf!ulo4Zdg65?YGeuz1p75x)`hN8AG)V)1#qz_W{_@ z+Srgz8y*D*MQlh{ZH)~sG_BQk1KWmPPck}Tb%td_6|W7R)%HH%DtfiOk#*&-w%7fp z;dsA{cf*4UL(YO@;0dZAJQ#f+AparD-7gA|!is$Ez;TF_%fQjcY6Hg(EW2>*`8cm8 zaO?y-0moYT0>@EfG#uwbp7#L~7u7xmP^{g>U2ZFPxy_qWQFj77x#V-#c=6Yfa7zU> zF8>v=8!yyha>*aA^Th6MD(IQmtXy)~49g)8i{rxTYD^Fg{(7<O;?J|*ZiTk!iS2CG z#mGvI4c0c;xnu>X&xvgjaRZZtU(SRDRzMd&hBj+rvvSE7gO>j5BotxwB#`U`bcU46 z1oTc;n}CjF*$wF3kMe2~(A!}Q0@~>g3FuR|>ws>8JnwBkVBOg+ceTA|P>h&W`voyu zC1c9T|3NR-c>9<-cw%N{lJmf?k*Q#__y+ku280u{Cs~dWvq@-+j@by-#faGmV}l*D zp8IvoPB9ip%!YwnteBlDUUZWYE0YWdEd9?m`u_|BJ2BfR<uWl_$!Zg`_gHpg_VFW; zn0*Li5VIM#Nz8VQ)-gLDwSO;@yl`NQ;9ZW7xU0$>D$YDUe26D_RcA#9&&ni!#he}q z-Z|o=unGbEPVjzWIY#hSpe;IhZ?Y~%@SeH4?0}nzFN1Tybro7L1MX$8ixs>aai<$R zE0b(x>whgR1=%;D&Sn`<U&>{IcPgt*@csa9tl(9Bn7zn=i$houysvMS;9Y<pE(1p3 z+;THX4?|A6Dn`I&??u4+5ob=o-UAU?qwQ)c;2CWeLuUJ}fZZmJ3Cn!w1gsgYi4m|Q zv_%K(7@!j?U>gUN4OsCW9k5x#2_|5_V^~@Nd*VNIp&KxZA*Ub_jsR}HxEk+2LI)>c zqoiCWV0~F_0+z$FJKC<E$*W1gE++*9l2dPyfK3>s1NJ}2M>AyXtbcWXZ{UV7PR#mu zmLPD?$Y?UD)d>vBNZ|6+^Hju>TESSLTRvbj{eH{v_ryW?{tHm=1a1t=Zs0swe}A+^ zXZ@X77bENMY;1TuI<-27HvB-?IN-a)wjo{p^pLi}O|7h~f7N}K4Zn%o!|DS-*|A|B z%dQQctp5?TMQ8o@vabBB-@d~(a<|4@s!?1RehS#c!dw~^x6&*t>p$IAyMs}?5>+)M zaTr)GXBT`cs}1JXv+QE-=OC{pnA?PofVsIN1atBDAxU(VTK5i{_u-%at2=DX`o;ie zZU{lGB&=b8c>~DD0%pPt9aMKYYUTXlX;x6r7B7a?&w#lT)Qv2=LG|SPOVJjc^S{oz z7&-rweY6c_?yyZ)upx`X!U5*<AfJd0>8cAo?yzDVj4S)upQg4ASJPTd0}U-3&hXmc z$@%{Ps-koLpIKLa&cAt=2IC_#+6@67z<{&B`1pfVq1>E*a)IUUc>*K6|A@;uU>qss zG6dL%)dq|{mR&Gj72wqbjJ;qdz}R58fN}gy8jSBlUUGiiVe>xx^QU*%V!yTa+La7r ztS^);`5Cdy7a}olt*!58#d4?`PlXXn_pP=6k*G9L4w-5>Xofg4toi}n4j#L+?Bekm zIaMB#%u_AU7J39Vp-Do07!Rrr>j=2e2>x>i{_%VjD)NQ0O4NIaj1@9I)}8fjy|dKv z2ejVqTWcTiDq8PXrdWD^Cm{)|*+8_T_rol^dhe9ELG(^n<Ion`gqje(rGniK<l*W% z){zE7cnKmdv>5*cdZcz~7aCg)+Xr3ReUvy2AB>T$k;pfBvUkFSBQjLXduvyNH6p_( zRUP+h6WsUKK6FjkG1)SqmN8)yaPDC9E0)W9Z*379BJZue$|Dz_|C^3$YJ9#0n}E-I zZxDQLxL)Hk1-1T9{Od4D55Px3Kjj}$N}SgNOaG$Z=A6_Qc~bIXaAW!oI7AUe@M#`n znga@oI3!Q)p>ocoEiWt2bsh4}y_Q2xVf4W(p90xVOqa6k#?-@&FQ6@&8)vYt3^%%8 z%Zq%WZ2WfUoo@7oBQ~r5^tSX)SFMfS?nM2Tt9M;n@9qpa^sZ^?eX3V)&qTc&BOrRB z{*HCtiCSYZaT;r#?YWQe=Z~1p-zfv!aN`D$g~g2%@25I0H_ms}z8+5^M3Tct1T|qb z5SMoFce#|yaAR9m8*XgIvWvaU`*=0s##XQy*sC~9us7&BjlHKK@Bf6zD-U(fgOKGt z^J2ah@=VV^<HGq{5y#=e8-@!%xx$L$P&JAQ#^S=>_gD^@DvrbV?=id`{9Veji$4z+ zHbh%A7glH8$#CJ}Ezo<ukcHvG8n)h9YGI+)yId}O3j1-9Kz=GA2&;#IW=HS)Sa$XH zaN!8FMRQ?4*8NQ`%%BN-WtbQ)>;;yH4E<E~%QS65xm>tmqGdv5W5QR!wS&c#ESJZH zud^Y-g-`Ry#p9a=xTePA3$O`z95Yn#`1ufx$7-nkXIxmVM+`1ZD~3aUB#Im^%)H!k zNS@k4<zjJR5pu>zOb^m^;FP66wiDC0S$1RU;ljtz7R`lIS$8sAIBGNWPBVH77Z&!i z^v3(2M(=XDFwxfgQls~&mfn8=<(A$aF5HZ^XfFJeb$`u;i+<8vI8p|<;lj^B78Vzd zo=P{C%Y_3bSnj@GP!m>{Q&qEQ=`7_kT-c1&h6__!cCpuT3a=(y*a-Fmdxr)K_VVz< zMaxXc|06E^kMGa8aL$j2;~?P;!-XH_T5%kzhEl;;T-a^A<&bgWxUjku!`s1ME0$gS zdARTlv_*5_DXcpgF5I&Tde0HEFkBdK>z$=uovigPmkS@d)6#pXgdnW$1DYMZ?_$~2 z+rx#|pe>pUyR+_Za$ysiuvLbM;lfT}35yGN-m6V0mkU21XPI!6#$xEN1g;${zQ=NT zTsWHz5iXp`BNva)PhwAk$H!n3@OaZe!Q=9)H6G(o`_H&A?y?wMn6eQLSxXc-T-dU^ z<&Zq}EtQMKg&&Ny9I~6PgG1g1vYnW|%(5F(4;MawwrDOK$GVf@!l6Gv?-ZlAaN&d; zOYd}5&*)t)7gn_OZe{fT1ITvt-p8`5w}%VYp)HyVm$L4!x$yN3nhS@>05@E?9Asf} z;jnw?#&WqZH{WviL_tkhb*8F@3)@J!3>T)d+HhfQmR;<fcQ>yl*sBBI1A8R{1bbcZ zLoS>K`G3TPg`NM53!nHNam*9mFkHBxn-#~Qst*;6#f9z1SPmH>jti?+7~W1C8?o%h z(ZhvR&=$>w2Z5-Q;=(Q8LGLGoEDRSO!4QiONtSwgqSm`yE-bji()(=*L0H{|Ydd=1 z%Cf7shYPQyj!|pmOIi0fxv)M>STDoGaN)(a390IbyR-@Aa^dpZEfc~t7DN9%;M&3B z8!VT{g%7hK!iCd#<l^zs3G7Mm_yBAI9tZXlJTC03@pu68|BMR{WX0gZYWP09T16B& zTzFnrE2eqsV=5Pm3+LTtIb<_k2Zy{2WIHi^l4Uoh9xj}OwrDOK!Mc;-!am<Z?`lSG z;lf+GSbC?cB%^n^TzF`-rFSEv_dX!o(R&-quHGIlT!Xe~E_|DHf6axnztLRSTL!q{ z!i69UiwpaYryI-V!Yo_u(SjO$|C6d3E^I30GF(`j)rJcbSaz{@)}6eXV6QrS59}59 z7VNdf54mtW<o^*DPPp{XxbVSsh+`Mw4a0>mb+Y0(RQaf2EH1q8Rx6Izh~vVl5r(%D z$2u&#arAKE37{vM3wN{bWb(pqzlPoq3RxH~+?#Fbouy`u(|VW7g?HX!>HV^VAgpf1 zwH>{$W7*Z)!-bbo$0#mr#k#-Ag*9lxCo)V77hYhSkgC2It4%1E3m1;EOxR9iG4$U6 zt{p5s%W`>Kcpn=gTsWRbE*|~)>`CxA2{r+bmtP@xd^JzwQ9=HnaiMA-gA3!<!XfVy zMGhC91=@_vZ+U77m5arNFOIYvvW~8UL!Jb(otVyG*^Q}(3-3T%G#6gOx|88T-&fE( z&gd;%cx^{ZZ~VOrqj$MnSTe%WyN=O&8<6ej{T<7$-X1PojJ9Yle3^BB&4mwtskyM5 z3~<ARuYxQrF6=ReZY-AzTia?66V!xNQ>tpXuz{4zaA5+g4Hq5*_$}<6eh056*gFNj z2ll?{CD?0*A9CR+ocoWs@RoLe#)Xr=Kpfi&Zx}B8Z>AN;p{fHFjKziL-fYG3N^x9R z)uDxAZCF)j*^Q%z3x5TAqPcK0>rRFXKmHtgPZqK;T)4G^rFWK^cDvTQTrM0r+|v6= z2|-w0hif}}_hZ@B+rx#IP{$}PY{a_1$%XMW;X@fFh6~TOO-NNMZqp`|%Z0DrWSQ_i zjm6M^7Pxk>_z278ap7HTh;ZR39=Tk2&uI1}c)SBP0gs(?1&>en(0Ke2^8btrf4n#b z7aqXJYt>w$$l=1%L7NsA&Zly*xbX2CEr+b3>)?<XK(-UpsVuuO^>E>hXp82;D_M6k zT-bqnACPfko@eWOiKRFGI`XYr?{c}Y_y$Yw>PGMHfNV$aPg!>L_Hf}_Xp82;Ct3H` zTzKCnnhV<-#gll`=V_3I#f2TIc==q|*jBs0peC#uP*uZ)wWM5z3y%Tt+Ol10Kg%xm zD%`@W3HA=+WMHo-N3fTQA9CSP)czwbyteh9abZ6G=8kG6ykWR7*w%{UP?b&vV{ze` z*IRMCOdJRPi&z_0r?BkC(Zhv51NG5dxQ=xv!-Y$Vpm)BIh2g^WZ7jXB)c8?a?{c|t z$S_Oq84?2A|Hic){B>v9)!V~`EvRD@7uI3j-{it0Yhc0x8Qz8qYuYB@`==wd3FUI( z)7M!hd`4q2^dAAP9W36@a(P^MD;pwQIFv^&9&aDPo&=9K!Y1IcO*g^g%*!+$*FyfE zapBsQF}P5zhC`kc-Z1x(D}XjFE}TQ<VsT;MTFW7e={h)MDv<5ObR5fWOg&t9HQJ)N z@G{n&3>T(TZzbczaA8h{r8nMxzFF&CE*E|?)YAJDqxYvkwxjn_mR-F)T=)XoqPcJe z>;9Sx?^>m~@Is@waN$glg~f#zQStJ*u%4}U4?#^>)uO6~3oA>x3>WSP;2kd9!Lp0J z-*4j81be%2GO+hS7r|a_{E!R#p!OeeVc!e?j0=aaL>yCvHw+g}xyXv+P?a`Z$1yMR zm)5LjYN`&g;&_QT4*VCfHmnW;*;X7qT(}W!(OkHObtl7x^FM;#!-Xsi7k<*p(mP9y zqGK^`%H_h|*I0T_rG*$b-Knd|XD{{Y?cu_P)G>++tF!KJa^c<;FySQ`-i8ZLwM|G> zuidCkD3=Ro4z^5KCMXK4`+;i*ixXKcj|;D3Lxc<a@W{pE4L8skg2$_26Y$uyli+b$ zw#MTs$p14gT-7WF7yh^$4w)sqVYu-3bStKL>Io_riwo}^WI5z5x(+cN2V^@j9l^58 zDIPBDg|=ueyo7Zp!-Z+o`$rikh6^)oz0=i}>$TqHa$(UxOYei?e%${CvK_tOX4%!- z!-bEbEt(6bvhJ_B@YZFT3(qx*3l~lUSy)_nJ{2#Y3zKZMI~uhsQ&q!-M}h2e9)8`y zYO_Y(z_N?I&~?0;U~e-z0`}&06znD7hg|4G?LXqeoD2Sp3kNMl9BT`27%m*!!ouHB zl`>4nv0N@Jy~>JX3vnFy4`_DcxSM4+jvg-j5^d33xR`Y(!-aD`gx-UMEDRTZ*xb@P zOAV!CV{u_OTkmnS5aZ@jOYc@*y**rb26c?$!c$oHH@R@@5}5E`8Qz8q{{Txw(x6oJ z%(dEta=CCCUSx<oLh_EF2;aX1t{p6nX1P2r?8k-(7y5YQ;_<4XbcW!u7i<C^8)OO| z$9K?pd>``vj0@jCKL!`B#S@@vy6}eK!cbGoA$jUSDi@0j$Mm-x@&a9ln2rFl9V}kM zvWrCz7j{BhG#9pD-N|ra3iVzq<HT@bOIz=B_3aR?cez~nK|f3H-Qs@S{|2%hy<cY8 z)!V~`51=iY3&*kUuetEL#hMGxG>Qusjt5y-Tv(Tim(PWjY_%^kY99rf9sGr*TqZBv zz-q&VpR?>@@2A1MnqY4oYykFNyhN~ftewVQ2h{!}F3ddd&$uuTS)NJ|-Y{Hva}x`H zLshkFbR5g&!r%H>acn4#3#;8gvlGY7EW2^^aN$R2i{`?&Sa&j9_{96rJ5R{MaN&Z+ zmfl&a4;>qe3)|azkD!GZH?1ta8+rBiaA6hd7{!GL0jR&rh3nsg2|*d&h70$BB`hxd z&me6=xm-BDx8?d*1V#A!r%=Pe;xLxW<HGK2h;U&C9=UkzIgri}Ja&Sez+<hpg2z#9 zG#=+d{-1H-+=el@aMdC><Zj^&!-YRJvK*49CR4dsTzJ!!mO~z+>k!jxfNTegSF-G4 z(Zhuoqb-^X8?x?XxUd@aUM1tiaN&8j-s$S&tF_+ca^buyEWJ02`*Hsp$aeI8l4VzK z4;M~CTQnDrVBKGHVZV1Z7gjZj3m1+8Sy)_{NX5(N!ozu%+UFa!!$7lxzwJ^k!-b!- z+Hm1=mR;<9J%Cpe?5%+fz~18-g1!B%HTKd`dlFn|y_=WqKhW3bU*Fs3Kk6&kGgLKB zje$MiLc}mmIKyD?+B6ULDqW>xn8o#R5}sLKjQhsUyBj5!Th6E>PQ&+)fn+C!-?8k* z@JV@Q-F%pPG1@{iQ4^ZTYV4I~sh3$djdeHipV9cIOS@s_%iJ$D&_)QG;=>k^hyDxR zff4P6H4G4+KG!lLU3H{~F@Rhk;^7O&h(@*%eQ7QRP<_jY8eStjK>QsjiU#6V)<pra zGhRH|?|tb1i?=lpr^@IyH}STEBrG7_*PrURH}UWskfZkKUY74?3xx3fOI+Fk;?+_v z1H{g(Hb88{vI|6CKVD6Mm<gK!#OfCb5N~Rwf%ppKL4wPDfiZb_)8u1#N?thmZI0(7 z+~yUB!kYLRLZ|}%alXdkh2?PdAAC8v+&>7tU;!d}v(Sfu<)`OZ5zSM#P*sN#1(w)5 zbzIY@r{$UgabZ~X0LUF!c4XOw<qYBvb_)d0MVp2o(WmPYSvQ`D9LRr$;U5>4C+cY< z{333_at~h7P;+Gb7+A*JMx?7(`)VUxSYq$pG2)?I%ZQ~C89e_AkUK`)#j<OJ=iR(( z(54~yI(vj+sj55c%6~Vn6Ex-fCx>L57$^<^XIM}?+K1q9p@`d5j;cF)SgO`Cs%`?T z9VmV!<uXuwpVbD6b6Iww_+f8eO`!NT^ad0Q(glh?UZ|m154Ge(0MQ1a^WupEL4Jz0 z<olV~f5MH`>c#+Jvw4W$4#LN|kJl9p6iHO_l%kRz5L(>$Rd>rNC&YPSwFZ!O;<uP( zH+~*&oQ<|<ZhU}svAEF>LphSlaN|vQy-77NMx^uJ*yOV<BhuBm#t0XL7B^P0jc8|# zs9+iKJK${@;o-&~&=$>&t6BHg+_>OP4agg1m>WPAfh{aRj<}K#aRF&@WA7Zx_frK* z*#D%eX7lD!DVG7{`K&g8tjn?s$YxjYY68e}U_Su)YjXi)5BzZRCII<=lN-mT#DL|a zc+pPv6zVYC_!bz*g5?!d)dNe58{7IU*W4s7466$<?j2a3%d!hg4>wjuTQoQR25iOT z#%*WD;KsFYz=-Jt6vmdoGK66mF(O?(n5T_!VQF#Wm~NI4FGyst{)Zxt5!bNn8sXu_ zPE=SR=yGEV)|JnVji4#Hag&S_1H}$d)`DX3<xtjwqQ#9LUuLO#h(;m1SO!=-P<%(q zWuW*ps|^%qvg|_f`CjZrp!gW{1{7~<Do|X0frernYX2Q>+@Bl+gh{U>ejgJ)4mUOd z14ZJOr#`2W9uQjG_)b^LDci((Vf8v7?Zj_3%WnKU+&C3&(cE||>tb=^Eyjp4+}Pta z7*Wv}At1c|EX#;=RoNKfg3#i|eO)Xg>Kh|=0@98VKd|f?;o-&)(H6~(ud(j0x$)6g zH6XjoFgJjF18iXdvR6++q+D)nW2=3mKq;(RP*uZ?4W(QLkX2c209lH$U;#2Imsb-& z#v>2_<adn)kQd^I+&CKN{+rx*RjnAXobU=F+ES>)aO1;ZAPbfmRMi7ZiyP~8wj$a? zT!{Ohv{md5tI9095%q9m32+q6jo-5_R^GS<=`pA5GI`^|mtn*x0?OgWFV3)xNLRP@ z&_=khw79W<C(DTYBr;*u3yL^KbYj^x!o!V?sBjcF)?{7z+*k#gk{g%FI5AL6g|ZeD zS9XW878EURoSSW_x`{@C8(##h9Vk97<uXv5%xVM0e3o5qEX-jq0>!(aH=x*~kw9_I zc^Zm4Aph@h<F`pMKzLvd;y0J@ak%kxFpvep`Bc&aLW>(8&$67dMx2M|zW`|`ep6X? z<LBYV8_^ccjaRZR7B^mDj3~p67t)AbGFr?8?W=7Wfxmz4(?+-;w779yN6Ux`#)wY< zX~&2US$2)^aO3l6i{{24>;9S>C%mWu*}^EE#Dw=Du!RN4R#e;qq?I?;wbkw}P{RBF zRMl|fsZuTj$T0Bl0CGFaE+7wF#;XY+LpT|LTzswovKD^GjlEI(Z*pU1^%$@m`~o7H zEYxARaU2-Pg5_D=bVRcvTRj#x#$9Sf^g?lASRDe$orspO>_*hXjbEWHnj1f0T`X>V z{qz{z_{8%tB9DM_xN$)Z%ZPN<hyKRca$#w4WBW|Yh!Hdwgwx70qLJ4K4>wk!!cp9K z5IBp$jr*R{P<&AayWz%4P}YLtD_yCAJ55{MIJ1ML>M{Wlo`1mQ94Jndav3OI&uYVs z16X#UcykwCO`v!UYylK6JV&57Jyk>TW61wI-1vUg7$Ds6EaEp)sKbEpmqaUmd1@Aw zjKz%;+gna~U7QzIcL3532ybNB1)+x<yQ3|d8!u*EEN;v&MwH>kS~TJ_87+nzo7qOB ztFJn1BU}(#+_>lx%ZQy4ldyUdkamoCo@Lhv4>uN~Et(r|XWd_O<KWpEkTs3s!i{6V z78W4SpyC!FEp9ArXQ|!7sC^LNb^y6s%4Gog4XX_xi&%C6xgncZ6F`0e8vw}JXA2+? z)z^S*gW7+S8_&TX<tcZ+F&i;fM+hiq%Dx&5WO3ths_KEI#f>}KTCS-jE)1(p0J#&< zuUK{?>fy$B&=$>&&$2ESH_pJvj?2v(?|vFav^GY_a^}%$mJ#^=uQ9@frNxa6Y$JMg zVr20BU(1LpUL!o*xDS|$=EjYzD?e{s_mqa>{W91MH!2J_3yOg(s!%RB=C`r@{i1*f z-~Yws94HQvav3Q4SZ$!#fn^tpJv;Jh0>w_S6Hu&GPoOxeu7=`V$p1Us`1GkUK)3{S zrSgS33^%T?V#O~{ji-_x5L$WTkc%y+%n;|{`DaWV4hXxm?1Iq4jV;g?&5d<f7mFLu zGDei)#zX&w5%UNiXM#?$jYwDTT&j(5L1=N~lNpu~pGZu?>OX+AV?-g#t`Qz?ycuoL z+}M|Of6a~A(3%UGgEB%4Ap3(YEI|H|3B@fyTHLt3wWW4VqxMFC+X3X4QZ56?_gHNJ z`3B1_AeVID)dY|WU;_X-^(+D8rW6gxx~Tm(xiP*{3|OA`1S0wq0p)PxrC=b78@Ezb z4=gQi{P-fvHHXB7*#82^oru1}vKvtkH$INGXl^WET`X?Aqhbth9QrtnNHInTH%_Q* z8G-LV7$aO*THILCHlmd=;tzn_F=8Lft`Qz?T!*%3Zd}T`^0{%*V;YJhWw0A4evaX0 zL2-0@f}>n+9MH=0_x%DQeE){(nI%kTDVKp_GgccYrn2lpvE?Pann1A;oDV1-IzynC zhaWCsW<vho;l|0hTUhP{{oJF7-vFTw!;Sxox8j$l22n{52rX{x+|qK&9pb#Ox&&k0 ziC+tr-S~O9u_oH0x$y*$6q6f|$7v(VaO0*~Fyaxy$Kl2U7<7@5l&&6cr;TtyXmR7D zbjyf0B_{a$7f{48;%1gzBRt&LlL~)^TXvyEksE^TSohc5cpkJSH*S;>VgT75id%r( z+!l&kfV8-==t4{FgESC%#ZrLV0p#0KE(6G?SZx6L5X&wgpKHTj1dxxy1_1KL+5*UB zwKO10A^&f3W9Y<*@?m)zzL}|35Ks;`HUtAjBATaGQ&kTvEpD9K!g9?faUu4<0CFdy zkF)GX)WeMv(H6~(H?b}jH}*TBjVQC<*yUjuaZJXKS<VbT#WEsY#Tg@9SX$h;tGQ*w z8ODgs0J&qtI+k4{JlwblZPDEL0_)1>#wY)yp?JAbR+cdH!5J15dtXd&l*^4BY*j}J zi17D+sGi}*^QBw{ib<?CP^`qV3&rFNUQM7_1<nT)H`Nd*w#E;+F(2~(4mVzZECvXt z;UOB;L8!xU<1=6&3xruz(gQ+^8_#cM#jl?@4}bp~W8H~gO_tsGdARW)pdZbR+gKMX zZ`^uR8&QTEmpud{?j(F1Zro6M!ZjjYO>C`=a6xEs<8@6fBmN^X39GB1h+{-gmR%z} z+}M%|M{#3)*8Md%o(8SSjZ0;O7;bC;#VtU7bP*0MKw8}R#s!wz8)+c8@dbd}0pw#+ zE(6GWS#1D0hGiF!(^|0?0ptYO06=z66hOXMT?2AE<o``>{NhLqSnkD>hUz5(%HhUS z!9W%)U!$rXSX$gTvx()JW#U5Ye*xr9L?^QBM%2TNL(mq@jXhWwiyJRF5`!BX(}*oH zehfEeAGeH1S36p2BV1To-1u2z%ZNWDGGX-*K<*f^h-KFZ4>vxEwrFm=k9Fm9<D>^Q z6fZK$3OCLIXIM~dLuD-}TKkQuwyKvKRnMe)h8wF&xeOE!0Qn9S70WIZk6g&B2^9C? zWI%CQHGyIZe#ngjQ2Xz2qwi1*5DpI@eyKtoh8w3Gwc?kj($eW6`%jKp+*tK|D}I-V z^YH#(#A3Yv0(e{T^Kj!vv_*5{8rH?)#?=R7aN~;)z=(ky0}eMX`NJ|IT@9h9VT21p ziyJR%WEnA*=7MB0skksmShZx?1)+x<lc{hNH&$TXUvuMLBpT$#7i5?lZmbB!EkM59 zg6g=FwZ)AOooA`NRG@_C-vDk0katPB3?PTG+HhlkmR&#&Z_cX;AP2(+0J23D0p$Is zX+Rc1{@>)r1qWil^6Tk{s9&hVz;gFtE24QSNL4+sw74-p&2r6);zI0y0pw0Zhp_BM z)WeOP(H6~(7qTuEH=cbU1~*ot5vyeU7;ZezHUiIoH`7MAu(Y^w-no_$n<X-M{u>~7 zjChh|*9Z?cPC{EWH;!Ok`P_INUacS$&os&kH;xBqSWv7>Wi2RL+*rw0^&+F{QNY@P zVpz&$ptyn628y4v>_YLU3wSkw;yUOJD85)(pm^+54aE+q{dc&r*{?A`n0p`MS4pVD zfbfQc9uOuprH5j0WB42^erJpG@b@nOX(xUgS$5;+;l`zCi{{4HSr>~NU;8BnH{M?e zBRX;nINbQ$@0Jnisxv(uiyJSnjkt>Df*a4F;)WZOS$2)^aN`l6DViI1vhJ_B@oU&g zK;9?A+;HPA3^WUn4>X}V<#OYgRLl1-2$b;r8!qht@){|Z0c1B;8$h;a*#%^7V_r=F znGKr($eQs2$dN!lC+jyL|8H{Rqv05^e767*y+x?Q!1BxAtcd2R+o`GtmKHY-XkfYK zesLl8zW{P4qMccGBkJMC^U)T~jkQ=8iyKb~$Kb~OQ(?rbGJXs<o@N`7uI8SvjVPBJ zA357H;v<PnSUmucJ4Q@m*)_t$jn|<qnj3quu6%C144M*(M`fHCC=LQ=SWql&ghLC8 z7B{N;ma1nORf_>@2a4ZFxeOGSu-ZUzKFcl?SDeSI2^1GWZ$R<>Qv`}zDrhLCqW0vu z5ih_b_yU!Eh0Dh_@C8qQgZ2h9`rpH!%)9Zkcn+T2SDR>K!K#Fn*?n^S$NJ*cncsX< z_QX}>Q|`OeyZE>o|Ih)7S5h#L<O^J>4t7aOjZd70KG4^awA<LvYJB9tIly(A;t#5* zuf#8#@pn1YEOB#2YgF^_UBU9Kw9->_7hB{v<9wcVGtrA~_e<TvG=fkakgG2=m9x@L zm=o9HSGB<zW`Q*~O=`N*m%)W;(yu?X7&j_--5mca^<^C^a)TwpVRatHofEmUSUx)v zxdDucQAZsIwDB@sVx(dZE9ymrn;KzWSFL4RJBrHT3Le%di8I2fYVEnGI0JEhHcsMv zxU`{APFtB(<f7tQ=5Hkx1sc25Kn@^(v3f*=cBvjbp0bJo8#p+7(8`(R#&It`O=jYF z2~Uh2$K&|M0afOe5yxS7BO;aMni9v)C2$#|P|Y~*rT>Cu;y8q7JugE&Dvr$<m_Up; zj>Z|@INk#n#famnXIXK4G!1f?!v+IpP8_dbIYt~aq|J(B8Y^PNF@bGv9FG8Po;W5n zL<Qsc{fUNgzCcDgemHg9hVu*_B#zG!08Shqk<nhPJ`<r`s({CK9B0n#>kBqd!}djQ zU$A~Yeq}@#lq4|x`5YweO2&pcb_Wi|=;hEo>I~gL{L$moCAqcy#QCb8a&T3p{Ht?= zbJ8YDWJf0~jjI$VdOnCH2lY+G9D<NfxmU-whG@8tVg3$bE<yGvnB@7P3#F4K(wVB! z5GMvYXZeB?!4J13sBu6^;qt_3Z^@>+3lBY{Guq$^YAU){KQ+J~M{Fw{&y}&QHl;ck z@OMc|P<NkmqBJ*vQlRQ$Jc<R-Q6Y}wMQ0-Zb)YxSR*xbC5`SDc^aSKes_?KE4iTBs zk06s+I2rY7Ao|Bq$v8OYd~r_3<YPKs%Zcqk{0bbR@sFeYaXfdGObg;NU%^U*Aguag zIl|u%rUJO_DMM`=30c1kmS<sNNis7u`cCam<q5@V1FyqMwShHO(6jsa3W|~t$$~wp zYAbw0C(eP|{EImabVtFA!ysPO8HiW2&yKin6uNsBXXx=GzRQBCj_+`n-16OBXINwB zD!7<-oP*KlOti@?yHismbPNlqd|h!;@*eR{Mpyh0I)xnT1*=kpf*dRc?@a<8X96ke zrTSh#VE+&{Y52f*jcC#BaGd%af)PLvY3fthXc;vUsyIgBK7wV`OUV`>rb(E?Di_GL z0Fg-`djZiM{X2j-Lt8ca4{g;vvRfd2J`Mqh(2>6YL>CSNIC4W>8kaHKaO5ZAUjf7n zGQJClACT|Rr$xMu0HTOBQ&!Pun$3NId$U5NAorP4x*tP!rXJ}sy~iIr45bQ|17DSW z@V9ElKm<l+`3m>uH=;7V<F!)1!67BJF+zde)ha{Ac3Ab~mBApaA2>L4HmXS@>c4n@ z44MrLEx~EoeRG4O6P&0P>}d<1OtY>Vh<{lhrTF~a5^{0TMI4SWC^gr=Pc>lxQxGck z6@$Vx35GDWxad?w>~v_!(QzdetR-jp{3El}!vJ_mO`?t+sRA5^7RXSTnAGy1+77R} z6w@c|LUAD6zVR+#={&Tm$#o-G;^>%C&jX}}K$-)jS{@(`!eQjQBkctqVO5dpwAQq8 zh+#~O%;O2@So1&K0RG31@IOw0{&dJ{A%$Y~6RQeVwPkR#2d@OfXSPZJ!+%hP8Wikl ztOimtki6;;yUHvi=7Jg3A){7M6U_q|?MHy4gPEtYz8xJG9~vt|s!!V4kZ-7)!&qB? za2h?ItYxk+GW8)-QOkTonFPxGf{}%Onj4vVklA^&T;@H>RHn=qTIMt(Qx`HtTIMOr zAf9pRH7&CfWvW{TGOuZwdnp4v#;HOrv%<)n1(|@B8AchPJWgG!Wu7rIDUcbZWx7!Y zV<JvvQs$JByLq8AA&{p9T2KHfSe&Y-1qM>!3<$K=0?8DB5pn7$yow$!p#Vl^Mv4~T zeniVn>L=Y=4-si~kfF%D>2PT&;MW@HK_DAr>Rl|c3pSsCQ+!P}`htVj$6;#DPw~lI zjk$|sd?i_c6Isc2&ZysFgdqCO7vdz&@0FmCJ-^SQxHZ2!vpbVvFhPQ<2+$QS&p*u< zn3$jr0_hl(m8oJNIqP@+I5Sr+l6RT6)ErJ!AnUf6IbmsY^hH&g&=fsk?W4K1IOZVM z9*HtFZz6N+F4dIBQ&v#}SZ!En${qzj<JtkaX!5E9_O)TzT*)N$#EF5BDmsMKLd-zW z;eC8?fjYbdYm5#fr~^nLlK+;Baq?01DsnzCcs;@zvHox!vHmozK_`y}uJte1!?`f) z5`E<>%$1wESKbdtM6A!`rC@zi1_Gxw=kb(Pw3gQ6FTC}^rv{Gq#tip_#3cTc-^BD+ z6Y_^32otGB)l*(g&A&pJX=y6ab`F&grhf;s6&&#WIPHKrjG*K;>Sn4@Q_~rEaUrNP zv>hkw^IpQCFL+OqYM7!4P^Sm8(xRr+htRP)8^);#XBZlEl0S9lnI0xgK~D}7Ho}Eu zp@1A~wYsvpW<nw8mS;f>o;bn)^)0Ew@?Mr5Cd^hRaH*0uu>K42MMfk1kp6B&xO{<o z64YJ+>OBd*!qWVPY6t^Y)RpWLXB?03pQB4U{%xLvb06UGlvQ-HVNKij?`z+m_ba?z zupARmWz~)m4a8r<sz96x#~vP)3CF{Pw1gwAwuEB_Sd@57re-=E8=<llj`J{hLVbyO zIqwV{F2g;fIQ1*s<MV&?Ke9o~<v#!SzTn`b-`?=~`^xz546Qg{y@Y12nC4M&WI%Xa z9={n|@)54lxT^ZJwiPb6s*jUB;kp@4cESY^S>bxI8vIxv4#((GQxRl_s5{^k;!<Be zZo-<j1Xz{OaMocj8(vDTFV4ys_lu6#B1kMni;RGq5dd5Bw|ELPXOaTV8&UIjVZ2JR zHJ7xnx>xggICM0}aI!QHRkbw#m<B@6nQ&QXH{?PeitsKq2{q81%ZkvK_y?K~gUXn5 zm+aS?ACuq%V0Zy$IU+~J-=id4j+d)Nai*0}{FX6L{1~vW`q#2tE=gx!m|`WJ2XW{q zjuC7ro=(NjG%imxihobYAXlIfpRw$WkW}>}E+x6b8&DW}S2B8cq2A=(u=+2~-~d>_ zswu08a4TIHgS`SPU1&z(K=Pwu_LkX?&Io2)4jJ_@l;Nb-02S4)1FVCY-B@1*7DuHE zzg;WM>1fvJ!q31CWbAa|TP;(YGLkNQq-E@MVUd>MK88*gW^0+##NmC?m@Yh_WqzcL zqziXx89QCLOUo>$jHC<ww9E<#WS=yq3xl-G9Lh+#&`QhL=|ZNKnNAr=7phanN*B)2 z0;4G)>B3$(4FZvLAzlmgqX3MEQ=e;rNV*UjDz3|f0MdoGbSu+^iu)Lf%oLq2!~^+J z>B3@e7Bq>KF3cjExaq=6U<RxJx;0)oGtez%WuRNVl{iXWIkWUjpZ{>diROv-kAj81 zU~&P{U;ja@1yX&(s=e(C)~->yttcynE`ryV-Buwk)CZDo)kaojd#e6mRSQqm#kZrX zuBWOSs}ej_16lPuJn43SH><XJs@`GMSGtPfg<jvVYKf<6H>+OrRGnbeW1gzB@%NcS z1)i!7th&up)tgm=Jyj!F)!kF|0IS+~s%En)%~SO@t7>?verDAP-~(n8(=ezO$R$+b zsY+wj22WKRR^gM&)`{&{^|q&~1FP`vjU|=MDm?jMRo%*}37)DKS#_hQYBQ^Pd#X+a zfrqj@Roz*|k?k5ZidA(yRen}g)>T{`!0dUfI)E}xG*!!3wbfI#j#cDuS86}2KJZk< zV=fN8>ZxkWsz*IlU05|$SCN;X#NDVWxdVNh<7at%oqJr&<12B@r4i(NAXO^q<Q_l6 z<5oBZw%NXc#|?1|Q+fO&k82inO9A)uxERMAaG_^0O)#my9NP#?>YwFy0@vwg({34A zz)I?8X7_J-FuR}RGfX7M;{t&pDM(&2cjL@J^0-jLxPqg|@#C@*XRSg0g4OfIm3)P3 z5~nS}wQ~cblLDjb<p%Fe%?;j!Id7L*UIQxOw-0oKYPV7~<TG7s;MRd`LDZFLAtP^y zZfM2^+2cD!H{8$l56-BC2Av414K+EFWE{to&XyxdY>{)`LJ=){;ZU{|OUpqP=ir=3 zF8#~tRH|4N(|#zomB-FXf(zm7YqEzhr$%3M(3iW_fIAqYlez?Ms@Ekj8h**V0e(^A zahWb!fu8I!m@)Mlt-v+Xg4-2E>LT6pKC&Dhb`ed-z(++YLEF>Z*wchfy1UJZ(p`OH zPoh34l_z}zf5=XWzevx<p|7iflNmeszOl0>16EE6+*uDZKQ|21bMa5AufiH%Fn;r3 zXi{N~x=UYuF#yl}pswhNn`JGR|Id)&2Wa~3b#99UdMBw1s!}It9!#Ey9G~g*(PgZX zUB%tpVJVSg>~Zk2INn7wAa^;FjWbc=erYEjR78nqrk3=PAJq)Cz}wEBfj697z!bVt z8a8uNv5~8MrEAp2(|NIsDo_d%i#Z0=%T-u629DXK?!v`NYO!A&`~>4@)$i=q|1*nM zi!!^^N3^?OmCxidC12<@l<ZmuN2ba+3B-T9i$liQ&uXk5#97>VrU^Oz_3CctSlz)= z4PDLcD|M|@NU<M_$)*j!TLX1+N>`7qT~bHKu-L@#O*Bx+uIBd(C_7Vjz=k+GV2fct z_GJU{?L@UTsX*yysJlD~a+R@JhNhQyiq^9Kg*`C%rCVbL;4RwDEjMh*V8E$K1XNLH zynJ3-TGUzdiNCn0bG;Vy>b|4+Xj5~@H-_fwVFC_)JiuStH$^In)e#s+o&SShnz1sw zZ;t<q>^|B4Z>d^>cvSBW-p8;SZwBJyVrZEFExY=6;3BC;sa*fCB%>AawW~T+DOQQc zWmiyj^(Y#WQ8F=AZIOY5{ZIKVR(VEIWrmK4JmTKdzq(v~ztbAZZe}1pZ%6rF9RPLy zRNpfNa>Z)MF|F^Tf7p&~=jfYm^lfbPeGYokv2COE?S~MzhiX0jYcSsZ>*-P%_6dFc zU$`iEZhKjM+25-`P*?w6|Hyj&eYyUTu&!8jImp{=6H{~j2US}T3G3#=t^ED@h@&ny zNgvP{N>x)(V0ROYb-x(({rJ_c&Avu<6qjS`!CE4mM)^SU9n>z6c@bS4%y=3yYP1Yv zy+jE0#rO_p&SL#8P)^hmVXbby2hDnkuu{uh0Y2a=gFA`~w9K`XktM>jTE<=?JfdZ~ zQbu+ZCu$jci7-~nG@*<v5&CNxdx_9r%bZRbSt4AdWmd?Ptd|Jww9GHqgwRWbL@i@4 z5$b4}^_1asuS(z(dx>zOkN9N?1(5XNeuNf?ED^S8ffp$t<oKEvh%6D-Xn_YHfF(je zw{nTFWh+CG`RO6qQQVe*FnM<rE8~>dON84=%<d9lDn<qG8Tx-mC<ctKzzk$alF%yg zb{d4S--dcZEQ5!7&iexjp=GYL6sfw>vVk;-eJ&76^BT~C+03=n#>!@XA#CkzrnfIp zKOZ(tZXY)m_Qj7!dGSmJ<h1mq0*HN;Pn52ySYe=^>yzK(t^@XDacOtT_u<TbTX-qi z&fzqbu3rC;N@CvP?Sphog{R>h_1pWb<qYdD=DgRDrhqd0L$k=d*PRE>yq8|mOLy3s z%H!0e++g!`sFA&dvCA2T*)jR8Tj`{5PB4FUoO+1Ypr?w}OhyRZA0~`W2S@Xuga;k7 zOIKwV9IG;RDNgSyOTvr`XdH%XFX;d|NwK<II@qP&<2iMugIy&b%5SlH0hJuyi>Vpr zNuPg%A<VwqPWs)U^^$ns*LzEs`wEU%xbydd!&N3>zb&(;Kq=$kE%3@!aI%SQuXq%L z8NZ>LIZQ`sDN<)vI#G%~gUJ_jzu*Z-WOEq6iNV?*sY{ped<Ow|p1{d%kP<YXTTH8P zUyUhT)2>P5EC1?CykI$QYWY7Z*iymw^={v3AF=AAUlRu`M<_>b#>Px=SQ0KW18Ts+ zUlXs2!+-G=;O1WwYg9^8ubhf2;*kX06~faczM?Kk2^`bECMKcrNd#4`ry&6*L6Y^X zR_X-#GozF4Qr*BF01ft`8q>|ejC5ml4%;-=FNNV~`K_P!$AxIIZpWnxe2P_DL_#j4 zs<Q^SHGRR(Nix+&d1E$=qc<+a#+%RIH3=R`_)Cvm^;5(nkBzcCLQgy+cE<3;Obku+ z8BMS~v6+){Fr%IBN)42d8&90gfMbgeZ4!UBX-~ASC@sSJaM^iiu{?2xkU+6&LHp@) zRf#oTPxMF61tT$Z^#VpV!wdHKI2&}7L54u4B_WP+Ebs=P6jE7G(?rcd9Lu6Bwk$WQ zO&|%5+hU*Gzn1Yvf(r?&V*pJ;WV^Q9+j6h0_(HFvr|!XO+jE1Nqp;o5wdFxypj}P? z1ERn3weP1A3;9T*&!3A232If~W}q*Ca$@1DsGeV;%k*Eq*#h{VwmQ4uMAfkuVjRUY zpuvnvFspm8-gb35y{#8c>%@6QYGWLBC8wc-?9$b~z#u>lDyDSx@9{O+;9GIHVotkN ziBoSxf`?tCK>Wf@4ddRa;PW@e!zCKKut(hocnftiDxU~k>EzL@#?YT`M!qbIvP;+G z6ci;;#l%8<@vt=12mkom4@yfJJG<qkl2y#3{m12Y#P7XZZURL&E*X_OY&-1Omj^on zckhf--$Hvl33g?$bA>ML)IHt12l97fG&xTdr~`rrS_3!ZmItgZ&YHejRRe-ba3k4- z<hYDf-o+9?Rfp=OE4#ESx%;84cPl{k##z&qVJ#1D#6Jx`xS8nejX1&`s={sw`I*`; z!7(W+5i#-wh=)Mt#2=A}%s7SaFH$#_9yd6=n?tq=DU;qTX$=?GVAt%db3%R&Rwc;7 zcd1o~k}uFYZ5b1Ymdn+g<HsG&-lf{G6Wn6LT^*KcOLr5KR4I%l1-Fr5g9^@9M7<vS zWMG9aX45wVLoYyCOplqnOFY@uQ-nz%xsq6zxth8KGuA*xRiJfdLv~^=Mr1H^5$h+w zNMu`|V*+9`@84dho1aCq&bIn$nOBVrv#rirrhqasxwh0Ye3Y2|@c!+2TIMFoNVavl zmca}qGTe}@tYvyoMzXCC^n^Ygj7%NKgnEd&7g9#Dt<_qFD;Qpj8?v8inOc;Q4cX_l z40nSl!~3^$wag)`;&rxlkCs_$WOxfVsAV=$MiQ>8w9H&1!@Ib*YMEt}feLXdL(5Dz zGRcs+T+6%&8KhmcDR4^32!!V54U9?VIXdkc31}tu2QkF2_?|e*{1nYMCbo!MQ@O&} z8h0hi-QA_Fc#+z04^o`hcz#i5`W%CxSY@*si#mPW8M{56+rsOxhZ8%Ao6B+MCUGBv zZ!n&7{J+ckA_)K+J>1Ov+!yN0Ynuff=AC^<F)jk}L!dcuOZv;hj!6~<ac_(vOr`!V zwNU7s<f}MdsXXn28*oNf^n+PBWhu4BslH$yZdWhQ^7%Ut=gDf?AIC8ikhO%>Sv;*f zg@l!N%yl$|Gm>|F2ZaLNan&nv)gHK54zAj#Dh@#D<hnXCVWGr<{1eQ@5{N!ZF+9PI zFYGs?m-sfYV{+TL{A<_1+fz@7Z5K&Yl1IsP<Q861el~`#Xs*5%rrM=$z&1N#e)kP} zqU(oqBfC#y%(CiQx*DT<7>}o{;xz|4&&}lquzeP|u%sFdPQf7Y6|7FkZMSo57*9b3 z+G8EYJC^b4P0$EMk|k{IS$P`m2+cx+W{H`4U!&#TNW#_xDCz0nQ@UF1Baiuub1R;! zwzC+h*eP*ohsJ6V*eZK^CG5LY%=YiiZ9iPy@flo%3|t-)VOIYu%=`ZO3g9x+Z(G`O z`VsVk!F3@vTZqNxG+aDAhDJyhhlfpYw;rcIh12I(uuuQ;u=n(RWJx)_wdZtm{lR6f zAB^gN{?Q%$2Gn@2FBYVh>7hqd4<jQzEGV~!ZTJeg*9WIX_0S~J!|13UM1{e)rQ_}3 z<3nCAsAG;1Ej%6cmGf^Xqrmj2^IwgezmKy}Bna94bNq)Q+r8L0Vz%V(!|4ulUdwf= zlpPfu#wn}EVgPN<^_MCjIxh4hsU}ddYs($ET>t1@#Xy#l5#}rXn7=8ZmxYi*a^j)f zCR=m;+f)Z=fISBGRF{LS{iw8*F{5&WH&oCQEx-t=`>YEiYe9~LTInZ@e$*jg75hN! z<U3rW<aBetGfcGcK<#Ad9C>Ji%eC)tNH_}KF;S<hRTN0c^&e7;*;a78G`~tt!LicB z!tR_<k@RS+o1I|nPG&rT9W(s78cg5o^y*C3A?oUb=;<<Fpq9_S2G{TfMkuUg7Wgpo zo2<@B?7BxWo-IG|`FCpxH5~Cke?GTA>Q)o|(Ai@b>TxUM0#DZX+D}Z%ugj60sBT41 z8qR4Pt_7VF5(eTP?XN!n33M?q^!fs>xxrk8UxNl02lu}F+@Uq|FZKD8@bpS%TiL(b zlc4SgBEgmWDHO<D@C|-~8Fi#}RYE8P{LTaxQYLrAe6lOQQp<xS@!)a{@3(m3&6U!! zIwi*WDw0FNo4E5Af1F*Jc>u{_=mrX6D?xUkaK&VO#Yy^#9rYFGN-M5-C$C6*)dDA* z`4&~2cbG@=@l&kAPt{B7;2=_WxHK<SFN4=qN{ds&QUL=*KyFyCdzC0J4m~gU3qzoS zT8g^K9n!cF5IlX^NW5*(36nX@Hur5OVHB1$^9A~#^8n_|CTo2wR7H7H;o4D5HZsQO zTdyzUXK`1+K(%DR0<C<72c^?XAh!52Vmg@7P0I$@>G#Cryf-jsokayOmhz#0v1%q- zhSk+@4I6ar8LS2Ra{W%;8p?qH<B_1g0&v#EkKNWVj=60DpRMPFJV2m=`K@42k{Wq{ zTE+kP6$0Wfwx{4)dIqk9--<H-t_4{m2e}U7tJli>n^4aDJHY3!rQ&~!OutX^Ea+#Z z-y2?n!jdomOUXCzvXSYxs-AsoS4F(^<ogVvPiaoRLwQiJDzcI_?|XcM33v<r$cWEP zliZN;PMW+#4&o9E`?DE%Jf>IOZMegM!!RSFS4Rtlgfm)8OOaa77CdrMEb&>wKc&bx zHAA!VlWg$($Xcn(M~ZOf@2CkZG&Qr*Hk-5N<5yh`@nz|R7L=2k;c$)*FLy|%c)8<Q z!JRx5{)@u83y)*KSu53Kh6Z5pA(wF;Z0^AFIp)#LgwPsZNk3{vbyR(6*6#&KMKxA5 zjL1Lc%Jb@KFM<<#o|Q02YBn)ki6NnFSQ{6b%vSvU*Do2VjN15tda4il6(J@XzChOm zU(;!6xK|a&VUSojfF+0p^x}Sv+~30UFLac4cxUlqMlFyUV|zVY;P9V#qWf^p2RKos zNHCm7jp*=~=|MRBIgy@~_M<tAx~dSmia1<q4*kN;7wRW|;P97Rhfm&RIXscw!r|Wo z49;5^pRru_Eeu{+&676mZK;^ein4EE%%t#CwzYF?Q)75&zfCiBKPt|Er?2=zJpKCT z+S9usC`7eOHDE9?v0^6MrJlo6+K8-wr33T))7d#=pyK8Tqp21MW~7-csD6GCEmKx) zfmE)4i=H`f7k7Dfza0NT-VEd<#SxW2x+^@GIBgLYLwFiYb)s_$m*cTIcRbByDjLkV zhqnfy(zD_}xlKEZMUbGh6sbZv#ETTTF0~{!(fs2egtr}GjymeZ-IN4X#CRdRx&|*x znX{JTS5<*{B)n3S0?#qL(ka6GksIFUcUs|1XSeXdVc^LbPkUH)$J1Esp_}o<i>oiB zSw~nZmaxJdPhDMk8E(&@Ih4mrW26f3gv3y7)P)lH&xLFaB#-<|qP*%;9py?G4kCno z&4N#mtsMIGE%59ulsfcvZg4_r*WgVRIwKb;^)E>~K!*$~Elol|FhRHhsf#;B@M|^r zl>w>#D=n6QRAe!jaST%t$J+rJ60_2d8`nN3zZpFSA|S7d=n^3-9gvIZVFYBpNX<$+ zX3m<4Uo`>Zk$_0e{rh+=GdvNHFWi76?XUv!Y?$hW)lC?&PCy2->;_~9ucQf%7grsm zSqDTanzF(T$U;}1CaG#@4lQFP0wOhk06z!_-d2qZP2xYZ*&0aR_=yDMBK&Z8jp2zD z>H>f7r%3QY^Se;|pUX6=D7&<8LgDi9H3QS6u}hOJrFdcwtR?<`P%rE5xmt(gUb<0- zBVRC^aZ48+jvM4~R@zayP~`2kC08LFXGy4*nD?GIK3<`J5st|sJuB@GbJkG&s@>=+ z5)P?3yhn%QHi{t}%z>dgc8%1OZB{sv*e$}b0fW_{zt34NOMkqwnlEiS7E;0SUk?58 zx~hO}LVt3Y&qJI33QABx`n&RDiNhO3Iu0ceH1wB>kT4S(fC$2R83cj&b!#Ax`F@RW z*g*`4VY8%RO{FA0qCpn367%dnSc3HZ5S6$i<o~TCovBSAPvx}xc3d^&pG`C2?;qgr z+$P&(_n_EU@W&~>#BS?bexkPOknQfyJ@0Lj*;AVbc0()V;c(~J`9i4K{j;4d<@NHs z0k0)FsULfOzQ8yv$tPy1UpUN2sH^gC;u^Rkw**s>^Q-eQE|6&D_yUv<;)N5{iHUB2 zubu?)81g}?5{Q3A`v_L^OqGfb^)@YfLC&NSc?BnXYDh;0#&BapEyDS^fsq4x7Vb@) z#;2*cEW<N6_ax;6FT*^6)z~ubtf-&%9;acrR>A6qaq<=n()N@bf2Fh>ULx0jJygQ> zcw<P%skb1G5MB<win0>WFFf^gQC2lw8j9yT4*3c`f(rOQ&Vd`TwfPvHIHskkIRUI1 z3rok=E5Qayk=hz!4!KLU!lOWn<3%1AQ-6>&U{or6hj$bL=?p?waR~c>vgo1)vi8@o z(3N+D<?qqq#WWbUMtvZs$BzPP&^cTe7@Oj2KQ=YL5oWvmI=W~7sr+p$?0Q*3ex?1T zSy;MsO-U-LiDA!m<i&}Yed9xTa87hjQBVE%L}|~!E$MV=A)aS}e}|>?EZmVejZa0% ziWmNE+%q^9Tj6)7B~(Z(<h|!*S@hdDj!>{%Aimxz$IZ@;93E+a2zTgG&9C^HVL%-d zOSZL@Uw=iPABz$HAUh~$vGYK374&R^0uC}k@%aZJC|C)&LBWj-1f>F=E#vA2US2o0 zE8ba0K=Kr|#9a)usqI1*L|F(P4LvG}-svylLEXhdsMsv+2yP2zevKcMfmjNffd};? zA8QDVO^4gto{ZbmlS<CX_2WsQQgt~{$+y7nMsNh;X;0v8MhY&@rTLjS=oz>^4MEtE zSokQDeec4YBh$%q<bF>i)mc*+=1xjb4-y_6ltqb!%z=3+tp0!Hw2BgD(6zW7o>Q<U zK`p?*$JPWrBk>Dne1aw(K2AzNGV5eJTco3meHdw~2Y8Nik)BfW)7q*Z=vMHVu5q)S zwKz-FgSfCcUw)993wE&sogC%*w=Rx+duO$J=SR)vSUjy%ozN|ZPZb1;Y|iotjL&k| zoL5%cq)oHARD8{fvdJusQSY)%*jx@@=Aq5z@9sne*?ihZ!sb7%;Bdp=XB5=PD{<*6 zkHEPKWK5r(OD`~+sg#yDjSsQ%?gzFmRTbLHhLwra&X9VHMLrf^0S5(b;}WMGrh5y< zC!n~O#o)9^qVlmE=W@&Gh6M7I?0VxDuS@W{AUf_~rScwIV|hkZ56GPoljIr8p?y&n zsSxTPLeY%HtW;LvSdYb`EIkejKEjyHGGh@Ohuv&k0<%nStdX!Qg%vgaYmIk%KT_Y} zDVfRl#Kn!pV+Z+Z*jn1<E7FSVuBWBF59OWma#L2Xk$7ryEJ5>?>I~w)2vTdhVv)~U zRS{LW0X)1%dqpp~OaoBj8m8menaY!qxfnl-bKynx7{UeO8rx2@e$fs>EIIK?hy^mv zq7(SSBlqT$k1oTJp^HFr5N*l_g30yIO{24OU`s+yd+Z11gUb)*SIqUd$SHu|6FAwz z(}ZCNQ7AbF7lZ}*vj27viwym0xs10s+@vY#L~|Oe186Emz<kmRH(TJz+U*k(AG|^~ z&x@7X26Y1+($qYGe5rZ`3IXO=8o|F@7V*uU$MEPzSH`?pok>R2$$`(=H_`Vhoi|0Z zrmvStd&-`VC0&ot6|?2JKH@kT9-5q47u!?VUDyTpbGR>~D2DcY`OPT39K(H(jMiCc zOHJEzx@{d?ud>h<$<)}OdTpoUk!Mp1nHpa8qU$lKsqZ&fnc9sE5Y%V^qHz-EhAdl& zFo%jsoY{3nG=~%`jfUzMaB@isZiJfG%RfV7=pO#FlwyJ8kC)2WJqJIG+O_B*YZ?-U zw@oi`h<9$_T-8|oAO9b^NbchJce*!nYGV-dMoy*LzCfk4$PknbrF-E3ZcnZZy+K0* z@hx~oAOH!Cb3bQV8ZYDX*G^M2fl^$62@zh*E@HjvApXS}i#f76yF5VOkS})eg2*Uv z>u9Om(0dMgmh|H>UVtp1^|;;2i(wpn3+QM72I95d&YdX7fG)`x?}k9=L%IBM^b&d) ziX5DlmWm&IRRr(liI0=uB^B7iiDO9`4>0g%^+MPuNbqD)cInTIcSbK%lLLpa1wi^x zK!P`v<TqncPn=bY#-pdnQnxTIh275<&toAVm9x^8m=kZquiA><BJh%$@D}!geGrNP zUie-DuS<B1|IUI}Wp)dAeZ}~g?+C7BxtxUnuk?zvnS}r=9%Dt>se{*5cd<?HgYa-9 z5ACVru3}Vh>d09l@O$9{4Zm#=G=LV@)?@&Y?_djem&)Kta!0%=OSMqVVOm|zDOQb0 z=Tla3EbG+(-#)>9C?NOLVq8V<MB|wE!}!seKvqKOmX%D%CVJZOJdl0da{0=c{10-y z-TF{B_>XlRt-6a$T~n*B0sUMkZ>;B6S3CbBn>GVO38)^p64OEhU*V?w8f2_boVGn% z+2)=!-)Z<p8gSKnlR`gXvA}&C-l36K6<g!+{sa{Vw9z%I+2e0An8K>6anW`j7p%f) zEXIrUh3Jh(xb-GIzJ(rTPnpiaa~Rwe_alE@j6cFmVAs!)8D(b%Hn5@f!3hl@FdPDC ztDxH&<7aUm#8qR2$QP`%pBKQLJ@-!I<a?9i@>5DKh7Q=|QV+_S2MH2+9uKRuADJ+A zhxdNwUV0FL?#h9L`<#ehRjqeu9h-~^O-{fY-}nlCKJ07qTjc(SY9Kz?Fc6Ok${*cE z(+OXbqv+6Au>G(&&%aR}kx|*DK42map&uIi{QG@=Om)7%<q5u}P?Y~`;A@)bLz=MS zNJU?huYB!__`Lr2>eZj1NxK!8^m$fd=dXPgzP_WfuiY=c#LHHo)5a@xoDPny%-tV2 z#rMAM5IweAGcH~&`Vl<@JNypsi58)*7|D41g6mAV*KQ18z*BtfK24m4_a?y2yeZrb z{PwA@$!_0@KPu)n*^=Y`j!*gc+O18T%8dZ*0{WWlH&x^M=LS2h=T%tkKY|4sC^fgq zVVVECAlYAsSmai~6XBfar8%sgL0!w`B{eX=$H(QAewpLPFUC|t&%%TE?hci(yI_aa z?6&2>Ucvm#xZEbc&`BkUIe`ur`$|8_@powLLr(20{N!FdhXg<Ufb05JY{QL*-ndLS zr^&vY6(=y-dnc&NjS8_ZSuzpX%QD<s;nT^zATEGfgQQ+P%p=|q{{i8^Jwb9GZs_q1 z*+5?^FZ<b8pBnW;d{zw#=o8d8T;^E!(+6)pUfLsA=~%A+TzvEa(Z-_+xW#2{IY^Y? zblF?A9)lzS`Pz3&%5RSGln=(qgOigaQ^eJRo$zqe9jNJ?kP|ptwdZC1gX2mj!LSq9 z!dr^)#^nI`x1lAsDeU3BM85L802MGQXGLkn?!iij+4-qCfit9Uh~Ys{xOSVWB8KpR zMCPb8PaTqF8Dz|}0#g86*tW-O8z{kj<0U3;6E$v6`~ci?%@1B#v8z&O2D)^1M{@YM zf8?>ywvIoL<Z}YmYx_J5GWZ0pDO|_=lPhs}2KO<Oa+pmZxyG&ma0z)HG}cRXEWH!B z;!erI&A<IQ_!v!2lRY^rj#Vnj#j8x{urvC_vwbMgK`f`3MLs%1buEcF?`&g5jjR>h z3|v+ti>IiX=jZDfpJSDI?>uf4q;l25LSxgLvt<xqbzhJm7W_<MeEzOTbNY}rx}t(_ zR&!7dL4TBKtoou9Y9twiEOA$=&TIo;4+A6T2HMDeQqG5l9ujk9=vMM2c3tbMu=bA1 zx$RVL;$;fJ<~f4_c7Pr^F646jcn<I9{XHw3$UlqD%kcvj+I2bp$R<bNqFg^<_bXQX z2*H`Y0M;td77xf2;*PXW49i9YkO^}U&~E+M@6o-$7OE6%+21pGedVN*^WhtArgQ~J z=>u5HMKvy`{hWi_co=EuVE5Q>bNM)Epeg2WB<ieHy{2Oc)9&}N`wXYYs{<Rc5w&7x zrCfh|yxft{vqCu6Kapb%Plud59&i2Li^mh__5T4pHn{)a#p74^Ie1)+k{6HfunpMy z2F&;W4IY;kM&t4N4JU&~2U|`u*49_V#~87Y=q4Kx_|<z0*n08>TI9Ano;dAs&fNY| zUlSxDyAG@Nm~yx~3o0TtVFe;v5Np6XnBZ@T<FcLE*iqa`SUi$_2Qz-vJ8$V($i{N? zhDL4ZE36>deqI2N7hvJNi!;W5F(^vL`miaP6ekZb<YDGqe3kAh8GT?AF9$#Bw)Gf2 znD_Y@45vv|@;mq4Ql$>B+U2yvJc8!LLfo1{Vta6G8z|PP6ME~Wdn?k4Rik3_acy6K z%df)H#Ay#gKsCU0Ax}nYWk}=bU`jW1a68%)r;S9v+~~Ul7uGWDBzXE#A4F~z5g$Za z;(4J%@^*ysiHdlp2$MaZFq5Z0R`TT~f0#b3pzel5$$2=WFGlkKFIzw}Nhagf#P8_1 zu-d)}#(U`o8UFEkk<~-!93*M_sg&(BpU>A^ijyH#^p-1CgtjQD6iNj%k8q!bk8KP9 zE8%!6_f~Rs`3q^oqc0uw@m@!^nLb`m*;HL#;m9W87|(k&UyBO90Mi(oa57_?*LnAI zcD7!C!8MbOi29ao!OY|A_hVfSIsLwmWA=O4^y`c2_lc-}f&SnS5Ieu;8UNy&5nuR% z%uS2baL7m2B?Eaf{5^)o6d-Sq^+;FL&csS2CG-gLIVmMBS||5lLTv__8ab2+QqrT) z*=RuCe^gC$;_=qE<og`|_uK~l(!9sVM`GlqLwU`Exjo`K*VPirG+IXxoZv1<T@+>4 z0HaA&=K(evP^>5-ht!?bIRqtj0N(IrAo&tY=M=6|@5La*vY02VRCn+|*00=yP{VkL z?{c!-pJgN!Si|D`ClNU)l8FO&MD?YYuyU{_KbVpE81_$ke}J6<#<{Kfiql;nxh;(e zWFDdCgBf=~MrD9i^mCWNjFxB15Ff$%H{l@Mc^bpE77%Wr+xnqRKdAhm7PyiEc-1qb zsuswE0G?95Rkz})_T-gs@M@W9$TM3W6qVF+ab2IZW;pMs`f|}^UbHRGYO`3>4mRKR zAx>-(`L0Cbw0LX=dOk(fR?I>!QBtfmZHf*b(j9(|v$dw%U?NNrO)r4J9a`WW2td<S zx|N!qr8RvS=`S?J&89eYhS9VM&g-Pl3*bC8gJ)ghXgVNT(}8?c!v1L13>p8TX-Mu& z!)uMvXSkkN-;v7ldpi;j+)kP)nO~o@^C7cV%bZIYzUZ%N@Z#|yJT@i(YXq4$wM=Eo za6(agp*Unfhaz(xWFFEoCD={T&(MFOWzvjH8e~RknXf2=r@`^PLoE|$WX^?5FD>&9 zWe|}#HATzFvz@T3A!J%<na3$3TW*83%=?fhV$Oj~EiE&VGT4v7^B-DfmXS$?%>KIK zpCObXEL1XO3@#f$V7(T&i~`UR-`D+G1SHyg17V34Xbu5H`#asrXg7ULaJd5yN;tS| zyjBkezLgNr=N-qUlX{M4wOLF=fbAYYl?Ru%Kr>IYp97A$3W(s6uP|im4j1BVt!Z~l zQ@+2@NDDj#0chIH)pW|MqUnuVQ-R5(ue7For{QoN@zEG+dJq=4xXg;ybS1-R<MJS& zWHgO@cke9p`MU1&d@3uLdxjmmAJXAF5CJVyl`?|430kJP!3y7jxJAo^vDc+B*H_Cp zZ^`l<h|9IiH<S^~wbU{@4Gxka(^AX4M;XD~=~`xmk-?q7j9OZT`*<32Avg&-KVxKS zLFT|&;;VZpBbZxF8S^2Xnh@Ba1#YB(0B(*Jkhf%UGdW|47U)R<0bGF=khf&9U7hiq z7HACtgz*O5%C}?}zbs+=43C0f+j+?s@VulEk?-y;_@4(@QQzI`0p#mYZRd0{2$92^ z9V@e@w^{i><&`t}i=D#yKfZ)cbk1@*_UKBnsxP9Yctv0)=2`A_Vz$M<^3@%bQ&!G= z;MD2(0ZGrJ2FyG*1ARDt9LH*%E*D4}GLMh+@r#b^+xj>_*_U<sPDl1J95X|>4;9Qj zHk*?)2#eJ?%6l`9&y0w=TKDx1j#V#RepcF`!=<L*w@|@;PneUOe$S5T*OPgC!a$g3 zj!ovVk8rAGc0{-0fSJb;b`r@vK0~d}*XB7{#PH7}SwwE|&IIo4<oG}Do9kcAY$G=~ z66;cI!v*5|yH{k^y5$p-MTFIQ6d%A|fdA)ZgxhrF2f_F_A{onNXKN!tU2u>pbxwsk z_MVdLPOMbv)SejxJ3m*nFIMffi!xWf=Sc-t0gwP=^Ere`=02h&nDH!R)CHfR1>B4e zkY+T(-V5UY5bIxnl@8@H6{xM-CZbJ`fGJuak_yCWf$JcE5im@*l5*dFkyp!n#7YI; z{ZwC+sld8qx#%UlXmg$wNd+pS%0szjQi0}TmPNTt1*Yi^e_7;c`aMjvQ-Pbbzy=6F z)BovKYFb@unyfXIRG_NSl&L@)ecpVWrwVvhBo(*^RUS>tqyhzBG5}>$fgQEQ`s=Bz za6IDy`m$4j)mp|!8KLD<wTzt#yr5;8QATKa8x)U91*U14B+76ds+MXQI~BNA%N%$Y zGD6EwY8g8f=&WTnP)2BZoR+auf%CP@63R#_aHW>9Q-K66^BiS_mRo2UI~CYjOZ+p9 zGQ!MNC}X7ppK5`T6cA<(VQe|kW-72i3tR~SMEf({%4nxPFSzWDhgh9dp#H}imrMmF z>+>4oJoPBgilhSb7Dh$8Oe*jwaBQNjQ&gq`7wZmxz}Z^Uj+UlO1?p;n<q&|T=eU}V zdrmZ6Z>0ibinOLo1@_hyA3cHdR0%9_ad|_ure#ur5<tnp<ybR?GZlDN_nAv&1#=Ix zV{a-jS<9qTMlg4)ma$WT>$FU5$_VDVYZ*Hg=%Qr~zXKV;Tq7-Grvi<%%#V~2%$=fT z>{K8@%PgmiU~V&<6qO2uYKX7qP)0Dfm@-x>@P!r#P(T3pUo8+x1r}(5J18K48?OZ- zslcOJ;3^0pj92ScrULV3OBgS~lOIS07OaNny{W)=Z+n0hl?r45`8rgR3S5E6l{dHZ z1ABU&2kBOV5;C<{<jKLzJ-C881Z1JSfmg#s7uuzd56dyqfbaG37RqwGK=yM-_5&Pq zYTtwkPQe$M3pi8oQ<V2k?Wv9q_v*e9aID7Y@&TvcVW!`TXk@>=qx$U})i1x_>+UMN zOV4`e_L?{$GPlR`Y|QQT>4nJL9tMP>=Jp3yVQ!bFH*@?4aDM_H$Sv5Dhn<I1RiCe) z=$-tP|0CS_2@3AzV^6Lz4&(T-RNgDl4;10?13YYrM_@Xtm5|okcYfU3`dZ#K#bb2` z_|y@^Kf>+i6zq?)g3lraIya_tV;~m<iTN6@%5w`aL4QU!FtM?kkSTw_W?B(0OC@?y zv2+aEhMCx?+XW+7dpT>fP}`QZU!&GM4=^e%OKn?DA-s*3<5&MnLqCf%*qMGD;FI^P z#{mwnfFzu^oJcm011yxXd9Ng%`)B5%uBX^=tEi(MV%fd7KS0f1hKgPo3Aa3rcm*=n zJf-jLpNc?mTVs-3X=QG^-x3RJGu;YwP0fCQ_f2+9PvSOXk}9czt;+_y9OQe+dALO_ z`=h(mmu&pGWGh0P=WLDOttV{u;QpI@WGWZmnbW(mI!%MO<Hu7O4IXZ|w1Z>hxjsB! z^M6Qt7q}{m?R|WsV0fvG7fw``XjqUQgLIdqBq-=cvCMm^X=!Asr3R^a!+>(T-DPEF zce_|tcCwCnEki}ItCy_oCYlwqL&MUPGUfj~YrXH@FVH#P^ZWeye00Av^US<!)~q$N zX3e}a!lRjq_~bXv6dwmc^v}@U(~2p+3T`-Q%t!ysII~OuVb@QxZM~t;qV1@;?fRL< z01Y=O&WvZ!a{Y|tbG%d!=bza)lGPId)|veY>K7lXA00oZ;bC+*e!gJW;*ag|B)OdC zV*LW1uYfV#$zjXd>xzB3$h({ItGD324#&?Wn)V*jw3B;O0U>Lzg#umz0G(XErgBvM z@Cm*xt-vv=mI)ix@$*AddFd>^v<GvAti5bR)v}@LS$jRCT6L_wC0bzT5T!v>(H{Tl z_?e-A^Oe$%G*!lbrL=)kD%ReG7NxZIvNhjtaGROOm@8!My-!b?(?wO!+Ix%|_&3(x zi6&C}mr;OPdu$KrxzpPFQZWmNk&!n}F-~i5wPNlhMn>M_AROg59Y0GHGmsb=d3Pzs zY3<#um@A2qk$0tHoYvkD#hg!!jJ)#|<Fxit6>|ojMjd&_DaL8-ov)bhiII^vT`^8; z?<C9u2+ww6WbkcGjKkXdRsnAiAcOBIb}5#dkJjE+1uO;ta`~O6vbC>xT;wuc245}w z@=dA?wDum+eB+SMyuw@|YwuV32c4}w36#}xr@R6=u4nCewZIEPlwR+kl-Axq70^H_ z?Hs0b{t}^di+BuFOp4!AN@?xYL<^6;23h7bY7myoSL#w)&)Pc;QL^RIY3;qGWj=@k zROVh{!L_ZuM-(%a7?HUG#W=0KJjDzpMr3ZJVo+7It6pI+R54c*BQn=jF-~i*t70x9 zMr5v)Vm4dj9UVXCE2aT4V(lFTlR&f6@pB5tyF#9RdJPznxsQo)SbOCP_=ErvxYrdB zvi7zrU^M|Ea0?U=vi4q4z*7J~;3jG+t-Z~Qr5P{Pb2_$e1m|m8dvVC(5Ue`Z-atsc z!`d5*mRmGL$8YYMfQP~Kcoz_^?_&c|S$tj(Zy-P3+`FFnvS32=O2ik+@EI*#M;OlM z0|}-B<V<%Rq}VSYCKAPCwLWwXi1pP0KPccyTJS#TIC{p~$MQK`9mhaKj2SO(k?~mH znHh)G{?fcwFnnm$&@1r)61nUTZ^($4{=Oe^xIT{sIB9U(8WOVb@d0vTxs93g@TGAm z=R;C#mSoKK9l=hx{L;$HN$Lk{IX>fT&XZ<;W1J{;14Kh>G@5l|uS?h!tRA)*Sf4ra zkk+kwCshnwz%(((&=t&8DQi9K01K*Zx(=}*rj%)cv^0dxI(<%(G?>pTG@NZ?mufhL z*oFFhp^cq|FwN(Vh#(C`RwkPU>PsCOrdSY@u4UbTu<4@DS&{}C5)jT9*59|&TG`4N z+}~Fk+7*Uv%#hs^TO!;=heU(0Sy?plUHkn0ZJl8uzPW*wv_AZUk#iRInS^$bu0jU$ z#u_44OD@`t7t(I*AGRAGe#2ommY|_%H_oR{SQm57;&b>0#7o(g(hgEW%qS!WuSTS9 zCSAsNW;4rq_AccMkr+Hm;<0U5w$=J$+dP7X^n0d1tk&c@WDp;yw+NpJ`~@t&bxO=~ zuRY;jdn6;!u@n4fyN{StPtm}P+Ovq6T}34`rb20pPzKH^K2h2rZ!GM)O)k97bXd>z z+zRvl+q3{Z-&}!C1roLjdgWgGJ0F(|Up!x1DNB$d>&<1x&lKc+;~j7YrlYL=Ekl53 z65+)&<1*Z9_oA2_-ydezvo2S03BPo>hKbw?EWe=-0x!Y~Of)nc>OAiWg>14QVng`0 zn;_MlJB6(x)VA>CFl)O>XTmK?fca)M(W~W_6SgQ%a@}xixJBQ8-O-}Iyu-@i`!Vz+ z_DtY4KG)wE%(t2cB~9B>B4#t9{>I?R1mDaw*%&OrfeeNx5Ao*ae<Ok$gOjDjJidpt zxjz69!oWrPB~P%S%FUJN7#Y5wVeI=w@hK&?!HlDt|Nm&pQ_0|CF-6;<Dc?atYHLa% zsI8|d{|xi>w$~hdUBX5Hy*EJtZA}@-=l`rJosnEuQ`#`gf7O)V9~4cw7C)R*JctbS zG$p>CrtDq{Hu|Gh1VmF-q~}pnZe&q)H6>yV8=%5G24^`m#aynMazEt8(v+FP7tbmy zWg=26O=0^oZy~fSq$&3xU~5W@LsPs@{U4fgyc3#fKT3x<3|sQ|n({uyxxS{f18t`I z_PUz#)>}l^(Ui<^i$1o((W0eqvocj?A(YY9lmb5g2Td6#X%0;p#EAc(DOWKqtSN~M zIyL30RfwRbG?Etcj9#eC{TzUnrc7MIhAKDB(3enCMl$?2nxb=M*}8$-**37tL6?P{ zGH>Fsv2iah!5GVJ;&N&feI{H3kv*T-NWlY2%@mv{CrvCnY?|^&I?mTKeLttvn4~9B z;!<#mTW8HpGPGBiYwRqtL1`Zjx#QPhn&TvCKn`@Iz2ZzqDq`Wx7}t!p@+ApMs%(Ot z!TkD%!qiO0pmLMIs{66ba*_wN^Z?P;-U;sU?*aZ;4uIgP9=M^7b-)Q%!lDtu>1fN) zR@Hfj=d-gKmrhPZMKPy8_Q3^q0oX1YmF{OGm19M`yXav`2!xEC8a)TCSsRQj@rXCO zIii5fTUX*2YyKToUxre8EK%d|@(=V6@_7SHB{LSfrQbT-z$aWWhb>TAzPS*i4Pxxz zISjV6*0<WCW)#Wu$dY-btOnYR-h-;==sn=-1I(eWW+~Oe9~;3+`O~(rHaH#+7;^@K zWqS{%|HXQxZDssDpw}^r?F9U2O<sv)oly)_j6I9x=8<&8EFwl`6rB{~C95!7;ObC2 z#pDqqGm0jPv1hSd@QGB+aAIUe@e@=P^w_gldI5eqCFFJ|MrIUS6!Wb#&)@{k_;)BK zo*0=?JgXRc7R#+0uPP>z7@1Mrs~CG0%dHy=6l36&)JerqVysy#_ify%fSm-OuGs&f z0P(JH)5bsrtN{R%igPuUv)GCA*&1mc>{GMXEN*{O8-*J=Zv9hg`5^L{gX{&avTt|0 z08x&~hP%js`dYKtgY19RXQ68r7o)(7w7{$orGA!b&9}Mbqlp4KDy5S&m6UFIKqy@c zr<hIY`~Ol(xeesoKZMdqQY!sb$PcvpnL3nSQ<u`K>QWky0w2@@HzK$4^dR_RQ`!cA zDGGQ20Pu9HrjpV)r8HG36+cj{MJYWB8Jh22<TC;03i*Nh)TMMW%~|J0ivWbxo^P+V zq?+D_U#g|{ok*;#`gLK!VLuR;i*_oe1u^0WicyTMLG&T4RLlu@_*8=qgK(5%YY_bf z4=UzsVnl;>D8|+xuJ%k&%qC()gI-dMtwG%Q(O)qy5F;8?pcq?&xbY)JG4~TA8Z=Td z>nttf#*Y??xq}$dpstFsH7FLCs*}Q>Yl#6*adss!mIiV1zgGbs0z`w3y&(Y6pq2n^ zR6uJ0(AuACDqH)qVv);fzlG)U(v>Qg=r}zKG~Z!(rp<HA74iekKvXRadYP4Sw)S)E z9xV+DIS|sdz!#BQDa}?|LJoxX3RnODDD9xBbRZNI38jDhD$7Opy^g{y2Lf4wNo1ee z6xDGcG!Id8h+{}QbRs(cO-DA)Jr^;%bN&nYsx$X2wjidIX@Rs!2%B~Ke1oKM{;Of( z4|kC))$q;4F4X7#Hg*=mod1qQ1Zh|;3E?^TNaAbH!JoGvCSA+&A#A8GpeJ9_IR9n2 z9JYO5ZWt%+a(Fs+SD1z58ita)tOF)LMp#e8YeDvib7MM&L2E|9Rf5lJZRfyINGqtg z+*2d-$p|nXUo2ov;G|g>z_9I)dgwkdl2b^xkNcR>bZLc%QR8?v2YZ=D{s5DogZ=cE zWUz1BUI+WzU!w^o_tD(6g4BA>vr?{;6xl|asVOs{v}{ZdQsiTvGIJSIP-@OA4zsxj z0zquH1}!tk^!HW!f|<VWap#OV3{l4nbDO&;MY^NK3D3!IXok5QZ!j;jco-3jkmkcN zg!|1hem8}fI+MzGiT>oKx~B5|FEf7~Q~4dTMwgfFc*bEWKk*7HP-SkW<Xg*2L-_n3 zOyyKbbC}ABwZZls_A-lX#<WxgOT;NK073cY8Q!vH%Mqlh{LMVJp{EOeI5WyaJ~5R~ znhZait=t?$6dOH-;d!N$idvIOeCZ|rm;YUc;#piCi}OeID-ao4k*<5;LD3(KsVhUv zFv(zRcX<K7xccd0m525a0!xO@7v6h5Z>K3uB}HV&r70dO<yYam$lXui0!xiv?vSBV z5K~)*hC5{_`u~!loACy7i%6_fhDP!Ov-&bLooFBSYKJD!;+W|9(%;C?i(whM1n!&A zQF%k80$AUrdRsEooX`J3hJJ^DS6<|hp&uk7w4PZ@hITN`DMM=+5tgAHFCa)6dVH?P z(9t<6L&@xWba&S2`E0gw^9-Wc=tmg-TN%=|O8fBfd52d~J^gcs+v;TQc+uA24x+i? zt2k9RJ%{4K&mW|%)vKl&ykCw6v#-5eY&-t`B)aJc2luJ;rWAGJD_Lg9Ewmua{T1-6 zgt-4DNTLQm_bM1+asN?1hq*tR^D(sjG8R5f(v<rWk;@4C(66Y<D=aWyZu%mPn>H+$ zpu}BCe8|yp9AueZ&kM7I6{OK0+YD_0b-s1BHpOye@INhcF#pPgJd~E{e<^_{^JF4C z3%^jo`2Zv9=2^H-!*@}J@6O09Uv6}k@6Kk{Y%bbev{YD7q1S=5gt|~|UU`;+?b+Ez zRc<LHS5Nu66R$-=fGa)dwdXQH6mEzn<XH*1NXX>(DP^Xcrrc<y<VcF-X^Rw2=EQ?| z)AK4&IfR3RYZ;zbN@)pqN*L8bCsAP|gB*4<pC&5gDF>%fvP0x&3>7G(xFo|@>Mlwm zE8usWOBmW~fc$zM!Zv@i2(&P6GU70ta5C$|8Wp3)2yC$=p~A}vUo+exR0Np2ma%}< zQfNr1?hOmopvN6Tb)Ph7mFbIa$`-0?_*`G8NRVkKX)06_(VP+Wg^D#Yze7EOx8h0h z5_b@BP-E*f3@>57JPX)8A|0_CW{O0$#199EK`5P!ngd*RApcHsA)R@spFHZ50jNB= zbQ>85{g}%)GzrF{z+k+^=-GtXQ+<??%rY)P898$A)=G)s_h2ZejaAN7S`LrZ3+^NP zK*ubroQI{{cN5}S&VFcdP5|3bKo29(^{^aUU#mFyH3=58oJCeSGp%x7v&xBKIZLFR z377?}l%p)*F=9CnS$h8p%ZaQ^=jAku6YjN2ki|#T$i)%{O9^A+Spp-#LYC0qD&ba^ zfJGw|yVVRwAh?6{z{Ov}Uw_o$8KRr*<wsmAP{!4Qv6S(C(TECjKHd5O&k%lQ0DWpI zVkD<+?2<msQxl~rzd{=EQ4c|DH04Jt<x5GClbxQ{l#i^G_asHs@jgv?%Sw4sQbdKv zBPFD$@4(by&;KGSMMYiCFuX6|L0D1c_CRbR-mBiTd5766+P(f#JeyX?u6CPF+v?eE zN3eO=`~o5<i0s0(*Eg~!rJmguc>&O|LmUb!{pzPrGk+bs?JnW6d^h;^qYec<_>4;R zt7t=8L7(AsSV2cv9k~oC^CV3bP9i2VBCMdDEHHZ|GZ<;X$MI%Mp&6G>d<$!go@1_m zitpcAnTJ06!s()%_e@jeTmvM!dvXr4vkI}m1n*(L-Wp#ctNi5kLwjgP-uF2+Qia)1 zM>kgHWg~W(*$MU6j(j;^ZTG$3Q^L@syAa7-dl;Tq$~My`#g2UVK+(yXPry*$mXs3g z_Bw~AxOo>5IJ|0c$q25e>elh&LwMi|rbEbty96-*#z9aAFvVsp9)G|iC)0Q|c!cEe z@h~3oMn3KeKkf|!_TkYg;afafC6t5#rD4F1FyLc6vRr@f!G+Zg^4znc3#%h>JIb7> z_xNUx8)HDCtiV>8?!STu{+YvhfElBGL7W4B6)KtG+fKjoLa1L>@d>d1GO!<wF*d)Q zE5AuF8?Ol7gaW<(7T%^Y1>ZxRM}kD@Mo|vt9GSk~OcG}4j2fVCH04L}I)(w&rhAC` zWW|_^Fo2-_isDqm-IP#{H&URsCz4xLvivf06lC(8@-nlXokYNM>Ss;(lC366{)Q&p zVHLOu37LB2+oPItgO&0UQuwNL>s8|*I_iiesSs1Mk`|M=W*K9i(V$vIB+%Rp<+T6| z4rCBrqL@uA)}&LrA$P;&)fjFN85~)ghb3qtvLhL3Xd?5kD$<3+bpca`-So6Fj4|fO zW5Te<&sB!)r%Is~%uT*LD-84;3Tp6uBrC%nla9vop_TA55|m-HLX}|otoLf@lvYdL zxST<(gG#mdo?rs~>=wyp<Z~RcFj^`76rrzv0a4H$iWs9s#P&WB60sy?Q4uS<TSUx- zpZu6$4nz#^K@q{ta_UD&(2g+$Z*)mDMbJvBl!zF8uepaW1%#cE@{RKiJI1`TSon4U zKY0M3UVc*f#@r0&iZpm$HyV5Z$;!7;pcR7lh?Q_B5|nS5nh;?XI0Olnpk1aZM`1Ov z=x)}ll=d>LV%t(fQpxaMw4y}Nq$lm7L1j1zG}UNT1xPT+pxq)YHu%VCtttcNLnH?` zQ>^@C;Hn7G)weA<JBr?da@P9@DrR@5ry$$x7$3rLf!a>7NH0K}QM#CiRY@0V^YHvM z25&~Pa_K545Asd461+%IE?q>e;xSLG=LjrW={m^ue6nl6(u2FKsU`y^8Z}rIQP}|d zb#ZM9>SV73Z*{D0MeUgk;jy<6qw8+5ghZgrZj6V}BFeYzNo<wbi!!<L1%1SEN!t<2 z?%QCooGLmZn7Oppnh{4LlY9x87<GH-MGeg-kE0l0ui>UtA0Xth8BF&_{V6{(RACkA zduf1td=IZ<xhdR5@>D=+No}iSN!GH`y&T8T0Ovd+4Uow1EWqI!z61@Rl2T^gmj>}f z{-h0Xz)GemK=?8whgO}AK;o6#hxk-$)#;U5GH8}+P?x1xn7Ka$kl-{1F`CLjR0|T6 zqxVr~=9Q9D*0R+6`)e&rMIaa0bH`m|Pg;j5_z8H%0b_2HrqWNC4jx2tfwYl~FGqzO zPW4W}@6hBdB&$<>qhf5QI+vwhRZJ2wvMlwuVr-{6m!<rQIhz=9s^6^`wax}7a9L`S zVt$3gS)J<FDTc!<eUe<3x=t~l69ZYrUK7RGPIWFzr6^`SF&H{r<}Ah7PIWFzwNT76 z#Bk6zhbXmCLEEX$WvOEagf;VsLFeo;?-S!#mikfw;|TzbIA2Zy;#B9d)J6qd2LN2v z1)55y`sb6_8fni4!%p=*iz#e_6Syq(X}P@lQsgsznJcs`wVFQeq_4e!k)ONZ_x+n? zslF7_y30}zXo35YTPZ#Mm{dh5<+9Y>3fKk!DE&fHNofbAG~PjJqD3i}rLr{NGstI_ zF;{3=>W;dU)?1cZ2A!`(X*>!%xnHV2I7De*2c>NQ_*wzol+uo2O6N@!p1xp&r?M<H z=TYS;m!)3Qd@V`o3Dh9GEOmg+XD3hVElZt%0R7#v)G#fx3<c=2)H5u&_Oeu0#k@|8 zEKAK$jIBXjmWox(L&S&%4N;7(L0pzP`JFK4Zem1(QWRrr5SOL)DrOil=(k<wY{l3b z#AT^9is?p-XiyML0?oDtaarm~#k3(tG-#V*Yz^YF)J(-RBt|sodBxZo#AT`Bim8CV zUo~hpF^*-aGzEN0fN0Q21&Ca7St>yR?*IU~yhc+gmyg~dt$pC9um&x9SX&!ox#t+F z0|hHaJ`>Gcp=GHSh^p1vFN0CFmZhShakgBBmZe_R0=tJOeH)`bsuEh3dQbruE2WDy zmCI7W+lA6wgi=$v2!+>PmO3!67DaWIrS64<D>bq#<p*(cV;q)U?Ah;d@ZX;O?xLCc zGHR@|U)$$-9U&P0;^o&<g}wUbsPGGRG2(Rg`!lY8ASzi<izNljY}5?sb9<i&dz=X{ zy8`4lj7$VV?x~x|O<lEEU4((pzMSRIg8;)2c%2ey`8=QFb9nYU+Ol#<k13Qioy|(b zR7QknzqZelFE>Mx7W@h|SG>gaBtGQxe3xvwZXs#d8hjH0G)x>D#_yRjUMInCAp=j1 z=4hXd?^cGJxy1XUj@~8!*jl0M_Tae#N>6GnYNgLb8poUWz5r)&Z!ad>(~*A%UO=u+ zN0v=IzsPx7>kgLV)AG!j1>~qY8nHPU*30bS#>c{X%2{8q;)dW$CjAx$-%EqAzoQ9f zh+)n5T{&RbEFf=mTO_XhV9n7A?H}Tc-c5)B_t=Ca%@jy`!efO<%VYH&r4{(!Db7)9 z)*_qBnJwGOCXv9NCzTIACW269HXy5e&FX|7`D)}Pv)pS|CR8BoUh{OqPxv+Y5LgJ> ztq@CEQujkx)RDmc00}u(!XzfhOtY6H;9PJi)~dlKG+1_E6!^AM6V#u0u2qZ6Sqs>` z;x%iBKv3M%{-{m4WMu5gTlr&oJI2sDl+JkMgK8ZfeL$?k6n>WhA`hb8)*8~w!cNcU zzmdCTri>g>`WGT4WPyLR01APP<`rfqo@{2A>8#4UQfjg7;=*1mnedTWW;oL^k6i?c z7vN}u1$_p{Mcw=0f9INTB7OIcb!jj4y7rpzg%-qgWLh9C3Skqk&%dG=n&!b64L7&3 zE)D;IbaR|645a;NV}C%H>(a+98glB;P)dAl8dB|YS7=#nNyF3ne72;4hJ`FwJUg<7 z?yjz0Ub*m$B}?0BpZ_nnQ2#i#9q*iW`Fo}Fa_Su^CAi{qv-`e}Sdf20SIYDZ7RF1Q z{k^<AyzeZzSP##IGrc&a`dL8zgVGEC?Cvgl1kbqGVqGizZs?Bx+*w<&_1}vYbNPCu zSLVx252oBNcZ+Vv$>OlpaZe|x;MJn}t?q3RzE_m*UjH!OU6w`hg2YsrBMkd+>R(xw z9B?KwI-#riT;pSC{X-_IOl!P?vQPv*t&&^HxR+2ryu=3v^9~z~*SIo6CO%{EY^HBT z4!J-YeojWrU<4Gggh(t^Z`@Bn)Sg=)28dq8Xt|3Wr>pZBSG5S#KiS~S(HOJdr}-r@ z;2DMQIW~}JQ*b{MRx8>n$@Bxk=s7aj%^_|XO9VzU$36jFGOfE|hab`kByF)!Ner>( zi4uL=WGkbBVn<`NHHWU&j03EUV=N4@W{hNfT3lZ&eU~K0zTb%2yWhNmyxiEpITdd+ zFE`E6x8O@j8;YHSHPB=BwYpyr`72?Fp$B8}hnQ9iz1xW<nTqC<d8Z!wMJIY$2+b$+ zKs|K66TK>g=99UBX+oG(5p?%K3<)g>0r_N->lJ&Ev)Dx;G@ncZreSJeaSp{EMeiD7 z#~5IOpIEKRfZ2^?|EToBQ{COg@Q*==W_uw$Q8(YrUN!c~G3{LLqDLw4(#5{o0GPZP zd;uL@n;0~|a-G+TF$MQAfI$nTvs+D<(b3b?T0yvZ{^^=cR7R$Ckt%y)t+Xtpv8R`o zWAVWli&O^8fMQWUn%6E_UUHD+E{e3E?0l818!fV=I}XmPP1dWT51!YNjg)-&faBH7 zpd%qF#Q;vE^+#O?R)8b(NArinjqt)<<d@1+$UD9MNnZ0kM;r_n_tbgimHNt;tyd1i zD|NW}CoPshh?Z-R0A~lu>Rimn3NwU8S$mQD3gczK7I3oJG?V_N$|OiZ+V<uo89%R- zT?=~~>7KDDf5$N#>OXUUE6-ilD;;d**HF?Wj)1RTjMHPFC6z?tNLkKp+mM18Buc*v z-fyn?ngMKkmdy-ib|I<!iPmIC6u1H11DVQGhjZ_BSd)(x5m#kKfil~gyk4F|TN31U zQoQbJM$6YU6{ZuP<19$D>2V)RLBCpVy0G5<*eGcd&rLU}N%$=A;hNmluue_hlnzh6 zaNck7zCsD%n*3YJ4%Y;E?V3D2!%>ruq{da|Q8cMtlLzFvUQH%5+N#MoK8I_PKQC01 zJ3upP(hXIBal3ew)?_d6;hHRmvejynA1NJno4mHKR!xFZcDN>giIhs4?3wPUNrY9C z52$;Vh5w#B*Q?3PjJ9g>B%i}IdA%T1lVzY8HJO4cpe7%V)S5J@Rg-Tb>eS={XH5=# zS*s>(>eS@-a806}HMvUKuFBL<m93f_ljnLh`IgaEO?L4)T$6)yLpAvVbwo{GK^0IF zmsOK=#G*~)&;%K~*-IDg$!mp!$dkEd?#t!zow#@NR$hHF0Np2N+B_v#tV`V4Ih<c? zT?gHR;Sh(~@YgaR_HWM`09=*n58rOV#_^CpWR3c41ZjwEh97s)za-Al1C0>F-ZBC( zN<Q}m8R+bxuPbElr!i*#ECxJJ!@s~jW+(Y(5AFy*L@f<?9<!2HAzA(C?1Z6sX2)E} z52ou@aqAhh{nD$zjNpyb8YD|#J##tx%Qqx~hjOd&U>0s5pEY6;yR!fzkh%;3j`}-4 z*KoLNpDTlmcFyJ;t<QopM8p3}d9e%;hTo@z2RyrLH2Hv)%r`N4nI@Nhroqita)FgR zPm_(cX!e36d!}23J&K^Rg0zu2ug|fW!x;0l26bM*`j{~gb<HBd>ouqVseO+SK!V8( z+ACzF%3OpP_I_7NN2W{+4&?j&QLo(~f^uj$e<&g+O7S`5)sm<j9>5~bTaO|vmXBe? z`HTR|CnG?XkKD_5U`r<}(VPPrBzieIb8ymT^b#sP7_E8A%uo>|&v>gHrdi1>pNtm$ z40uND(co|^ne;F@PIJ$-7TZ!K+2gSay9~k5jI7UW@L2A_NaGW{^g8WgMIs=*R*NwB z8=5Z!keVLQ7}QmQyBV~lm$U?*<}w<R88B}n8G~pEp1Gc~)n3cC&P+kORG8$?fWgf? zJnd$z3#;$2PO<+LIkRwVaTjY1pu*&`EU5Mzkf@&uZ2)(1pWG?D5Z!~uVFNBMxc5hO z9oEjZopVdf@~mUgwq^{)9j1E!bH@CS<!c?;?o<HsiubsE6GgS6mLn^Ai~U1u2?1wO zkecK%;CHB{aW%kpbJrd=q}5+Yi?@MJ+cD-}=w;FDYcYhdp`M#Vbhz0^YfIV51xQx2 zW+>|$@U-T)6UcWP60DoVM&eN$$?j9~X4+~arrxa#+O0zQ3T|YlXOV4MLskm6HYz;T z!2Lijc$ig$8|X%fkVmbMTE`w7QmgX#Hcqm$&AE^?YqwTex)iB$M`)_NfD*rPnpF7+ zKTrYbD`#t!HFuerh(W><GQJdQznXTA^ogSO)Rd6YGMBlX9S7JyPsH33zQGcSi*BpT zi&%}EzhzZK(H?j4auVy0+AmdzJ=a;2yn9Kb>dY@@%`O&dY3T&$0tK(;9-%$QqW$PB zrCsyjdtUP1UR^v*qee987@us86C2FtDxdW-^BNjiq!r8~xqnu}gUgjhie6}?F|-fw zcd<6-9WDTS3g+U@vSM)t_@kO=oq7$nTW1BfM8F!*wk7Mo->G%dH7R!Os8a{6(-KRR zT3dC}PPfc_i}nfCDJfK^HhjV?G3=B%goX>=XNwYFx0^8qh{^F!!|;95e0URvZ~ugN z)^d|PkHs$d3iCFexA%(1J@;apmz$F($vfHNwbe90ssv2+C_dq(ETB>Xd^*S{`UCim zy$Dbk^1xMwOBn_)K~R{NgEQt^JEd>{f!BXmvR=i4vMyCp;IF7MK4gXXd;K^$iMRS- zUQmuMWI?Y1=r{Bd@jCk>>2K%?a|04KYmjsl?+mnCL#KEB=ujPlBc5eW!^*p%kNkZx zk22xu!H<QY7mM!&-)*5`hTxr8<e<<nV4i~(<=_fLR`G7osn$>tm|ZZNGBHi;qNo${ z`q<0sP|=^|9BpRL<`&A}qcP?JrQ_RbrK6dX4rU38xohP&=YkG48}`Rlne-Fb@O>H` zC27EpMt{^j`u;bsuf+v-(LVO3D5C(YQaYoIwrF6CdHinS#j_R-^Jl0Gim(yD`&l%z zSpxA5`dAzY_zbsY;euA$fY)Ft2L${sZ;tI$n}9qlr@+^X52y6yen_(&W6sx?=U6Xq z%9ms9M)B;BF6Jvgf^yoCra5B#g<QZYGz|)?BknmjE9FRzKW*&*nCNKmWze|bFVqd( z2ZcEH@$r-sxMMBP5`$*K;nOuBzW6Odm8Vx6A!&;fE+?Es$gk%(Om&kE(n5RQnP9HX zhtvm(r113}P>OZCBWJvvGhQ(fs$#D|+<XtagDR5*m9OkliHkb0|DDg_o#~zO5aiDE z)1=z(8OjPlSeLMuP~|7#K`t<mI;q81GokmV&VX)zY`)}cklpkwmH%r(a(^y{J{I-* z6lv?@Cs^e&^Yk>l(UyDR+d`B?;7SUn!_*&8RFXFZ3~eE=i0yY>9T^*KwNNtjMw|I1 z8G5jqgBa6U-@D9uZ-Vo^1O!{L2B?#uFUQM+XQRaTm)#E!-OJ#7M$NX2!qW}h#j)(o zwY7>WN$bf4qXw9MHy{U(&;^Ni32m_}uB}6&%Tfau8x^Ku#)lkG-c8^hJ0<y7NR}OA z3MMn)x#qaCY6{yAlBBuIOv-eIJx3rK<m5mk>$u6{D7be(vcoZE1cNrKSxE2(NHE_f zftwicNBvufjy>GJ4(*wetcLF{+$m|||Ap6EhVKDJv}FWJJBk2n#}oP(<`Ag0YiZSv zG3JH4q;?lsYX*-(lvz8?U1kQMfl#~YR_*evWWI^D?V`!U%QQH|N+xAYj@9Jd7VEA= zvT{Pl?yct9sWxwfm>wEb5hn?zA^QO_LnL?{%tlZFQr+)01{IXxXAIgSB*`$F5fc=D zA21U0CSt(i6*=T>tPekQmE(JIFdMT~Jcg#CdD3Uof>YM*lWy9YC*F3aurAW7-EeBH z-LT9O^qx{NV!({0<g2{)MDG$BI-eNI_;Qm<;a(lVq2+!=i3PY=JFl0O((-<_gdtBx zHL>^Tw4}18f;|3yGD#?#b4;6I)7=irm_Zkuzz?zQK7fE*{b+SWUQ}UqLoE4$q8bBF zs-u6MCb5_QDBNqIH1(@PQx2^+lH*<jZG4rTI_ODLdM>f(=>&Sni850}0Rf;lNKoFf z76=4`=m((CFd{g#&);X85!iEWc@f;jad0UFcj7;uDv4dVvQ`tdh?H47!u)fwa#NER zWhP7|)f1Ajj)NOc(dE7^Y_Bo{H33&ZSqa)6RVGyuM&KspZ}M;tSGg%*j?mt*^O<a& zp}?0L3}$S{5kVJHuqNf{4VALU@<O`)AgADb>|xUeKUcCj2C%N$B(Xpq><GTVFKPnA zz>-!VRS!veZ3-)piBszFSpah4-m-Y}BNa-HAWROv4_OI*M1jFet|2BKM11foMDM}S zOG;S^UJ`G;B(e5OvTDBss0oRtfG=q*1y+u#oXFzS)Jcc^IxPP3Q1Q1~#e>6AhY!Fq zM;(5eT&oU1O-MFvSv+>ei2oAxGckzJno1wi79A?h)a||CN3w3ruH)#%LFyN0w{sPA zbLB^yTL<D+-G*F~@>(0xl5VcGA#F1B6ng)am)ex}WM4LmCkhzz#a-l%Zb%z|`59Ik zPr*lSu0^%5c(jOpFOs<-?J7<F0m-_Z<}$_D+iAEVElx2zh!Nwzkz(xaG~AH(=LUJr zN@6hlVYUDs;av&VySO3kTg5CQMz+&zQVeH#q=y^QHYp~L7>qkE^Q2<FwFH72(v~S^ zI5Ft@asGp1)>)WDVCE^NJ24nVv7cEn(i7ob+>myQV&aKG&*n0nh;eL4>#cyZ2mp=P z|Dyode}faaA?-2+`~o*Ow$oIB?a0pUG?{(a8fnW9hPTsX+^LPi4QXlXg<IQ^&#Y&z z(1x@@^q41o{a-eut*3s~-H>(yb;tW=BezmIR%sDRxgqU)1&mWlv%-`<*;^>R)IsUv zlax|!NL#J>x|343Qc6}~sk(7pO6zS%bJwLb9tGxVfydxaS4!7|FW{O`+6I7Z1$+$v zc>0v4lBY+rgwj_J2v1?hWB>R>rIZ`e&eMEvBcHjIxkBe8%%$(%$<xKCLai-IqVLMn z&_yXcCt>?qVQVglg}IOQ92OkbAfA)(iemZ_BOB5T*awWQLEMm5q?k^`hz6A^#?~M# zH+pgv(}Eb$pk<1&HHaJ1dMV}vT==R%vlL@%5I3Z?SIpPMhz1Q;jIBZ3kk(i+n}`t& z>Y^C15KXJ+B>ucc>iz;TqCqi=u{DSr(#jNbKQW>~htVLm2JxJPl?s?dfN0Q13Xs<3 zhO|c&Fc<)|_8XeY)^3m~tzEG{tU)z*Xlu7XzFRb30`i$@%oW;@_7+zKoUL7NL)tXR zv8_R&4QX*&;5W#vl(tn`t|mV)RC!LnBmCF`04Qy!soan@yq8dVyHILwB$2f@q|L2O zQJoEGL5P%6bBLD2pCE40B8;=US*&kb^!#DC&p~ef=2<}-8EXdvY2#Ql4?TF1r3BJ) z5H^qNb5}{jCXfd-Jlw`k({MVm6ZE;GjU9n7H==Yy1UJJxYGqP&!Tk=z*WQRyU_ne9 zEo(f&rlmd)mNd}N&?<K<B3SOftxR^ghag<ea`g<PrnW7Tce{|4HW=$Hj)R6LF_%B~ ziwtnVpZ2&kgeMso^VxXvLx;ef|CW|ZWPCp~k1e1a|K8KIR!Gxkzf1ulpt2iV0jF-1 zW^bmc6wsUb(m>iY*mw2;GdEc;<$yR-^L>VV<_l0C-pRWRQMClL-a*4(K)7rHy_>b* z==o1AZ~<~Fr3Eb2al=%M0;VXXw`eLUU7IeH{&70oajw2i*~8)Vz}v!}Y*N~hxk4T1 zKk8CC0-Z&zj<aK!(oo0A;WwaVp2nhwcARVvN5{$G_fEweBt|;UHx*-doII(hpJKKV zBORw-F?PqvLHM7Fd6gLHIB!#o-EnfjZK9X}F=Bf3QjFbkUJT4(_)XBDQ;3m{vyEcx zj+4XaF2xKXMmo+@U?l2gcbptD-%?B}G175<sTjNC<S6){VlE^`I?jI+W0@Wt1@Bfs zBmvTKKB54TOAdE8DxebUN$8I9G?lIW!8Ov_S7AC~%jNc4wY52<C278m$Y-u$u29G6 z<<gY1<D67?n7oF4o742*_*cG4*ftfpl~R){RS`-#_?0T)2Bq{vO(msml+yK>U4l{> zUt3$0azI?7`BF&fV&)3T<ryxcI4PBHeVs?)EQTCgl-9ao%ByAmhyqmRy0PHe2Ms4F z<^y6x=FU}&^Pu6Tig|+=k-1|a9OdA%`OpA*<V|7B!^DWp?NrQ<)*#CPbf;qSi4mE5 zT``+249C#76mtVHB6ANYMjZF(95{?VqL?&dMCQg4<2Y#e9t9*2AOhD@0ip5lMg=q_ zKm@L>0z%{8H469*t2iA0G*!mG?jmp({mEuDH;x78t?`ddim~J_F8qX>tM2#*A#{#^ zP&yg^e(l!Ig?ma#Y+0XX{ISP9j*g!p)eb{x7xEPx2cKeTfwVk?%|rS;M$#|_&DC&$ zjlE05<B1)s&x393AcS=cddMDwj^3hUkPDd57?fy&kPZm*KoaCnYng^0Om(oDVy;65 z_TJRzes72{>}7lzSY+!uRXJ7DN|2_ke^~*dLDbpy3U~zouztR#QiHy`nr};^x7614 zuW#0uQZ-Mml$XxsO9wJn=xdT3L^+zoT~yCV8YtD`JiWY9goLX6sup-<h|<4MMN~zE zggU!W0T(Kz`!$t9(pf2;EtDD$iIg)Cw{DP@4gB+KE<F85At{BpIfUeM5Vr^w|B;#4 z>@P7rkoF0}W~n}}mozl{d<}nPW2b9)GqDr(`3)O85@DJ@?;?U`N-Oe-?ilNg=I+GT zHh&^4h>6#-f-JX{K7VeP8)=pMgH>*qI_3T_u1>lBC|@c`pf^a2KYWldUR^+O6sxjc z<Dn5S5aFo#s5#DzgiiDzj};x<2&t`ej%4x}<nu>mcMYTP`E6ZP6QFAQfvQJyUk%RI z^!mQA{Zj*EYZmSgfh(=b6tp~3<Co{3WvRT}d=ZCb7Ob`5%*|5ccVlm8E`js#1QPy5 z5^yFmKC1<1S-lC<y}pKpb4R-J<IMKANGEQP>k#AJ{3k9KfAe$PeU6>~GpF;cVeID| z1%R*Dcu0_3v%wu_e9zVx^&YMTGv(fUYfnIk?s<pzN&mc3&Xw^s!^Iv|W@`%&&qtf~ z7%+uCJfVH(Ik<tkCuEe+EeL@8FGC#UahuJrVr5)hE}hBJ{ju*eMo-_oU1EAoFPJ$6 zOF8Xl@bfOq$z6h^99*V?!@LHFYYbPg4MjR`|LyP2I$SVwvMa}(dB99~8?~iZX;VBK z9QTHp^GDMyiYT*kIG;T2SuQ3I&)h`L$Ogq**xFd*w^9n30)IH)N@Oohj<S-+NwViG zD>wu}X~{CvS5r>y*L>Y1Mc$CCDZf}LZ6!s%XaC1YdG`S;<t#~&lP>-mAt|3(DM#3n zek_oZqyv)1TDeA`1z@(}neF=PjR@ja<Wjo-SpoA7`j6mC!VW9uMfNEEUeSfqAw#Xz z6ZxFT3H`J5Lr$9qkxZ&QU(*U}rTx3WA+FI#s_YAy94=4@>Toky2#sBSC0f=u9>Rfj z-`JfVgm?|T55nr}H3mLj%9q2#TgemY>2vJ}Ym5%<*3eyh)z_&}e=C_uF?A&K9+VQ2 zOiwe1WF{g2S)9~`6j7llnbR1mC7JC>@!v{jIjr3OCYkRdy{=^Lev^$^OEL>a+LGCV zUS@o#%5u@T4Ji^TnLEhKfag9dB`D1vmdsZ*xx`BTP$g!P72JrRC7G)<<z_48c}Wq; zT%sw1t&|5OMI>|94f5{ZR>~wv5y`woQ&O#zK`g?S%-)hl$;^emIV5u!gS8~{0(6$O zC9^SN>Plu5OP7@cO6IG#IVCfAqciQtT!&=diKM!cxq)zhY*V&%NHRU0DF^?PWIpnT zO6Gka6C+>RR4g8atedW;DV5wGn|B38Db2&T;4WTZ%oJgY&afvz7m>F&<4M15-Ef9I zLes85np!tI6cCzW_ff!k0KmF=O;c&z)THojX|1Zm*3DnTK@LnR&altZe7|Cu#N;to z$hz6Ym6Nb7@i%uk=ZQY6brYIlfApf%g6nBY=|v7o>74$T0v-YYl)A!{4pB;%oD@pM zH963tlr!u(n(sDJ`XSgBp2>8nOKH6s_J>rQI<861usdj(7m!$)I<Y-41F@a^oMAUp zObu3Sbhgu9G0quw@CB*#A!1~<lcX5u4ErO+lo2DdohZdPXV@zg^Expy+c^jZfF9=z zdx2seB1UFA?<od4hlbWWobOc3-NZy9-aMfg=M4Kg#S9~+Au;)ian7(iDyADT4T!m( z7{?5|xdPe|fL<Hlb0{D*!>)c_IMWyav~~+krCi>2xya>S$05k$hN@iBS})UlUtvMU zd^-#;4b8A~xklrZ%SoWDmOtfN$duLE;fot*Yk`Z9TPeMtrCOdJn&r1BU>X3RbiAgL z()T(Er9+ic5t9u=lu}yjT{Pcyr1T2r3eB)v*QK=H4Eu^OrL|_*KP?lkH6*d()%gmn zfgD^Pp>0eTb(vx+u-2tA_l{zmGwfFt^ARy3a}O)VIm7lV=1pQm<|Zk|Im4c$m`8~b znaftpW|z{#8TNIGnMRDrTzkbhXV}S#89|K5Tm&(W8FniL^dvw8?f^IqKxl?t{hV+n zi2yJI=N~8_G{gQ@0Wkoe8K2iwPM%J5lxEy`OlH{CgV2JtXV?L*0fq&u&J6njh^}Mu zv=qvV*+ewXl*P?|F*OGkVZI$m`+#L|E;XF+K-yafn;d<9M$#~s>aOAUY-~pjFDEu$ zpC7idF$i-mwG0uQOI2H$?77rYNL-z{)Q=X#>}49}a|oLq`n+D!K*KtOS?&%*u-rKC z%Q;6|TBlshS>_$)7r8Kr639t^?5GadA<-upk75o*=V3lGIz~QE<tqM$L9ku$du@NQ zVP4pays%+<kny_SAIZjP$^9FET|a>Ea?^thKsbZpd8K?Mzwc3d&pOzbmpXnT)4F+w zmy)J#*Co2|KL~N)Hm!#kV{K=ET;|}#<_W$P2mUg?0O{uFkecwmEs0rj9l3>#zewh{ zJ{O_54TD&w?%TSzH_Q}!-`1-GNM)6oLix46#<-Qw^*;ueT@}<9IWAB?2A4RG<khb? z+{OGB$Mn3G#cmCr;A>%zfWz4FHSRLq@%0iiU=o*(CU_oE0DPT<AK%^hbhMurO<`?T z;VkN1lz=^-iJ|7`Fi@JqTevmGZ0sjZa@S{4IkWP5mMdE@rjSno&plSkBS^6}H9sKi z@r<`prb`|%6enrQC@bYA$s>p84bqe$R!XL%NS;)tpp{2l3#LK@<S?LX5ugZkXFcsx zWHLtb)+gTgqF<%RjaBi5XCm_27M^L4msWft|9aa$bb1eX_%FOA_$R85O>-Cy=^HxA z_$7@0UfPp$UGoK`j{uG~UlEW`z-DIrj`8&U#2}tz-iRbI(y@i=>cM1Q=<Bf2{aF+F z5{W~@hJNw}+3DxabV$rJY1%5&V{lkvI`cVvKS-jb3at?x#MU*O>&Ta%O;qSi%M8Su z^K*dcf+xtpPl+NVJ@CWH(OjU>vBi6RhI1(Ut2ge4i7`K2FAe|uZdMED8TP|zO?z;Z zUC|a&9q?3G2@8-=Tp~N7Ew5I<^SPCFr>3!Yb{8#>e1j9P?Zk6vmon?0&<*`^t{2G6 z_U&6Qj7cX{&PU~Rv|}#^Z$=0YE6l}^KKsL^bNL+pa48XQ750>y3t2;d>@Sx}z5C#Y z^?rboi#@@<T~clJv4py;SIH#X2Nd<<CCmzMLmtk&iygv(IG@Yw>kZsxc?eMAA0mzw zCg2sO9gymknK{ysBE`K>Q)^@PHnRvyg$rGf@qVfo&(p(ZqegP*IED$FeTLv=(B1F& zcA=$Dv^jvPb5jgH3Y{5a+6`natIXA+hKOj+h;T0`KBcy7ce<=zLSD``y7a6y+jxe; zihE<El4)hE9V8hT(~x|IXkU(qn#bAVY0-?Ii7MGv9cLRyH0?MR=X8+0Q30XZ##ajX z1^^7Q-8GfA(!=ffwzS_IvyBHK1biuH8?S4=e<Po1#9X1-MgbQBlfDjb*{HXk*GQ^W zXSOj)3%nyl=_>Nmv7VQ%fa{ggM>Lg`RwM|ec}l6wHh!Rtfl|&kVl-b8DILjNA*=2L z7XqD>)|+jN<lyi(vyJzb2+O}i0Xo}Yd(@e2Jgb<^#E9ir4)y`#oNdfh%yMF6wy{w$ z&e_H&#rTL3%kOc;IA<GID`pZgV)@;z80T!GwPLO(Ml8SU6yuz2xD?|dMl8P$igC_1 z4n8JzKaUu({LWI0bGETbF{gU~BgWq$G>9#iZO|w$D&PkKFkHIK76pW68w(Wh5de_O zmo$~F{YN`#?YB>aXTc}3wYAy*-=O)PLO#R(Ej-&uL{zQTt~cAb6LMT{w&B(S2Zkt( zb5P3J#&J{}iju07{@GV5N=mO&O1mhf>^V)2MJZ<++cjTvQd-JfA-UYog+QlV)|+jV zLfmY*%m@D{>)a4CUCZ2t0#xQEu;ALWjT;p6DlsB+eH7!IZFEyifEbavixuOXZCt3B zDa44()u3{CmvgpJ^QiD<2r(ja-zbJ-Gil~*<Dg<vi4mDws~G2OV~b)gBt~TJQDPjk zjh7V=Nq`94R0V`)8w(UriS;NIxa$=Vnr+;vfIR>};5ut6XB+e5Mc|$|F0+jVeZcwJ zvyJPx#uaX^I<t-QpdF6c#${+Z+CPE2hKt#YeV`o9@6IGD>W4Nc%2)0@3kbJx4m4h0 zBz_xudHT;jCG8f#KLKeufw9qY><@;{@X0^DhI@T2&Dp&y?_iaAfw{cI;Qr5OGwFAm zDjJ`Y_*#EojBNwqD{boaXXA~nnqvG?^m4lnH2cRhV1Kfs*1Ydi$33JxHMg4W>yJ83 z)?v@i_CAv_znFq1Uz|`SP4DT6<_!<yt1kjjzTM~(L&N?6K;})bn%{dcz(|bRC=FkA zeQ)lG#u7@b)MlGm3)u`_1knlp4%t8?Pb?+aJVU8Pjke*#rr;qY29M)Ej?X-2eY6)9 z0Y&mD3Cb^#_joSDw9|BEGb3)5#4Xk|<T;J|(nyoW&y0uf)il2l=7N4-war|{S2AGY z?U%D0mL2-mhXE78<fvdzA!u>J5yTO=OnyDjKMTmedMgo&ByO>$fr#lA5gO0?&~dX$ zYX=d_+1NtFQ}QH6iI!b?ul*J?muXSK66g!raM+@tKq*-C6e#E@6wFGPOn@Zd^?%^X zw4A^=M$R0-cgHy2ofLX^8$MyrJ`5sE)m$j<Y{Ucy$@{FBQ)mOw(4BF<ax>=F8XUBG zcU+GD*5sTHw<dbaG81Bu6FY=)Ypwkd&xh>Ie?{g;;%>Qk?>d-K{BvigmfjO(&ds3I zS9mv9M4H#3SJ|6?h@>1t5Kzdq0q&B<b-3g3>z|GFrmSSI?~lr);97R1#e4G3_4-r1 zzAL=`DbZe>mF$}uofmnurZ<-6;6X0j9Fv{8Bmc`B-xjYQQ->Vvx*p?A`ZEXfhygk9 z{wI42zd!1Y*d;IX28t3YL9D2eH;|c-4oyx7w&$DtgR#yN@RU4FnLTMXOAn9_3Qpu> zggpE9?Z5;)zpM3f{!&axUP3lALu&UMKh>Lzd-<pZI7NP&c?%LNr|bo><}4*XhZvkE z&weymg8%R>7gy2pGx!ZK6<~il<O|REJi&~+U7vCBfO~PN8OywGey_*oo0X8BH?lGd z!Mw=ry(ULUNmE?;gHZ|&!#9tiApEkN)+ncD2LmjoHH&Gb#pGeo<JS0S#+}2mVz>92 z5`k&7zG8s+1=3d8nl<}@a#y%5#+y1ZA<kXA3(MpoT#Om~D~Xd?obmD*Uyg{7?LsZh z3YOA>GAF?&7z~-^ein=uya*y-jkBL}tWROp7zbcsF#n57mURA%AU=@x1H$GyecmN$ zaJ=-;@KGCkxrX-<d$B&3+Srx|(@FCgBIu;)AZw=Kh4f=tcu(zx^f(J*zGPY;&4sY} zNS_be<!(fn<({(2?N_JVr|Oi8HE<lVgk^Md@EVlr+cyGdefe-3MIrBp9GMW~qf|l@ zw=mg1J6fa^bLE9k6J9QYY_eD?&0>rLxVRCMaGrByIx!l|?TyOn9N!zjhZ=?3(lONO z_0+)&Al0eHUF@804l1RFRG3W=ZJloJP1EV-KhQqbJe+O_PB-7fWI5!#IV_c^Fsq?F z_H=UvpTpD5_1#I7_zC_cWXH}ukE5MuUz|=i;~0za4C4>#V$HKHo`6#oW-W-3>28&| z1icKRKu5|E(}OR%TIyb5uAus&?tSGQt#^|j)eX<o;Ile(f#v47K8HShO|IFNjb-+1 za?$s*H))4=b9F;+>XxZn9AoQHHkS1reYWpo&V)asxj?GgDpk~$MNki+YFid|9Ie2h zpK>Il0PAy@*2AE8RpMxU@yrE~L}HecSbs+lS!Kp5VK}n~9t}JfR%86na^++6haU-t zfF$B05$iE7qh@=yzrQQnpB0Vs;2l)IRoSPnzx(&*bOR{?09U>nF$b8Hmvtppp6v|A zvHC-#pbXz(ZxXHnt!{|!d+K_-`f@{fhQ)#YzE8O2;xC&6@#41eV#`7f%^A|(T-q7k zQH3c$7lbIZ68W*Tr}ASq+3_mbF<97v^9_(fb}S)VEOrb=1<+=lSY)zR#_Ml|TMDuu zGuYD+=1Y8-FEPRwt2Jvg=9S9pQSYD44-pn?Sr*F4_D3cNhhS+bhvJ1pp<oO-)Jg>; z12?YQEZR2pO|U55?zP|*8iLPb|5n}N%)J;hp>E)WyZB{Poi;ZeJO@iu<8q)ss&Thm z?a;W@goYeE{ZbqncW*cHtitq!uG$)RC7;6@*C&+_(YWs9us`<fe~8BA#;V4>47}H` zI<m`k2L7r1uwLLp&}=X$k(!Z=J7yh1_7N%`I$^>V2kBSv)p<Owqxa87BX#!rhZ%3T zq3C2@M?K7VkORk<oVbT(WS^y<n`d{Mn2?zNq0N&|-dCP<g<>gBu0>8dy=ZuB=vj*= zS0y`mk_+CEC!H`1+B|8;=P*w?cMb6*QEDIiM=RmUK>Sc<9|4{tUJ!@!V7CtU7pdb5 zXIq(Du_*0NAAoP6^HS$F#$kfZgM}amU-acA;W~)?8I?ocpU%3zi`IdCEcz<DJl;ff zupR7%%6LUQSr^fR2=No>!IkGp1LOP$5TsddtDEH#X88o~tNe(}gSFyWv`LwF%F6w3 zIAdgh_WHJ)`yNEy!hY71SCJRuXKjW;Ho(Gxv`OcFpp%2GZjqxZ^Cg7T_RN38=lXuu z)rbzlt8e*PmrD-YACEF?%-dH=0|dq8=8v7(Qn<gjg>t`D4{|^3Y8}F_@PF3{+J5x7 z!`0Zx->J1q$27z&V>Mv?r4w6j-eHaXXMcziv0G~lQ!tegdvG&$$29O_cUZDcum&e| zt=R<y@kc#PG|elW3PIvc5aL&v38g7unrvDaoRC~;!PwiG?SRPetFagk82ihoBtUw@ zGP4yNP@2C)wA`yW90T=#sMj;hDrBHuJIE>4%Q{A*+<c97d{nKf`TtARHWOXDYUkKh zTh6q<ty(2}aaN*M)ml2MW>|X^9Ap0a#8EZ$gXjdM$wIzjk2FT?oEW~&+BO)KEY-05 z#P|-_;V0hR6%~at-g*W3;rW9f`eDX9RFqfz#1}x-IitihdYc*V!FQ?!BE4AuKmdEA z;;{w-v&rc&rXAaDLSlXePwVLKJ6zd}3Lk-*W}_?0PCcAog>7tIv8aXlId%bJ<XPPk zZw~ZI=aF|PpC3q$;V&;_z?>XsX7HAR2Z6#FiZH&A6_c^9W)@?jz&qN*Gvm$q44)&9 zZa#+W;6l;UD)SWiO@H-NM%eCYuGGk_Ip!5HE#RSU0BNU(dJ9$z9s6NUvFr24j&oBq z(%MU#d!7Zx+$>_G9_mr^Se>*bjQ<J+*`7dpsQYQ!eMnQs%sK^xJk(by;C2Aun0ZoD z>0hflhZ2_7UmP>)^*QWeb<{)MSo3A@rQ?_@<e@$XQ4WXA-|UAOC)J`Dmg~L)esQv~ zKx$Eqr97qd90#S`5A&=7$^ihSN5KG8l$2&Er8{N8dZT!#ds>vzLw%>_TZ?>V19OEu zfkj+4O!_+PORwjl-oQ>$6sEk^7bh2JnG;B?xE|Ram}xur!~8W@Ds&w&;-OAcjMGE? zm0~&*Bi_RE6yx+zZ&b{=#E7@>cT^7Va(bwjD&`bcJJnmbTQN=#^}UKICq}%5Zz#s; zp}t8mTZs{Gp-(aET&&CB1b%VSLou%q1NREPe^d+{mV$`~rnO@H#K8IBG8x1;_QOOd zU@8F-1jH*K<e@fmgnKstfYxrHsch|G%|tHG{w?gG9^6^wk{;@{nlB0Y%*S2u($IdG zHCzLBw)P~tMV#Mpd<==RT3h9kOPiClzyrvwl-|Qq9s6MhDxeGiP&!;wN$DF+h0=%M zb+NxVdF=|N6q9vNg64Y;`Aj?J3d!Zfx|G)QP`3+HT5CVd7qf+HgGj8%+y`I{WW~83 zX02kbB1U9xxni6i>L(O)0Wl(T^AzLsP|s9M4OR?Q=0+*T>7gE_m_x*f%%v)3vn4C^ zQ1?(w88ISrv5I-d!n6b?UNNr|BQp0Z7>P!hMWKW@!V{^0M+gvs+ogbzhuX{%&deY{ z1nx}*T+I?-N_ak2z!(6~j1OxnJ=8xnmS#L&B_3*%j25izq5h65hhf30<Ds4g(N&>3 z#L;d(6r6L;-|@<g_u-g0Yg82v0jxc9u2r*a|D<^O0b?qM(KlT<-MI3|u1=V9hHQrq zJF@WnXbyQff6zL`M84cSngZ^$LZsR*$01!x0^`h&3}V>KPMwsP{~}HwwjB@D7r~Lx za?%Y41icuTw`0iSxv&_}YkAhs`zNzREr<pS{twUk9IY5V>vw~t|IM@h?+#W~s*IPp zFmhW}X}RAb5u>m_wk2QtUp(vmY~Hg%=V*m=b^_13H_#{EI;qUEYq~-($T9e8iV`lD zKwd%|d^TNZUZOSLO^9JEZlPNR;p88m**Wqr2b*G~!$n+)#30V!*7ldP<gP3^-g*uE zlSK*9Rv?`LmP#1RjiQ93Rv;!=Mhsj<$n6<lO!s4rIeIw^9DkPt+o4(gHZbT^Fmu7E zosA!LXs!?mnUw$$`O`de6wHL{0jG~);{-}&Nnen|P2}?9;2+Q(ONPEg2a7Gqs5+)P zN~alpIX8ZTCv>TvK_hwn?@A50_oc9GjJX5aVZGpF@M~0nz<j*G>t8K=@^)J-yve%& zgy+E*VsoI8w@^754c{Z`n(p<_O7NN<7|wNPG=ebnSIX<mee!P10qCH~XTY~IVILXB z4?Vg~NY1;IN0VG2NBmcrK>{yQgfA-^J;!<8!d{6n*j<fs6LT;ThHajV2~*g&2{xGx zR3y0itIR4s*=OjmY0R^X0j;!^AK^1RQF7`R+t(BzCisRl9GGvWAV_=E>(7KBbsH1y zF20P$A4EnPJ%IDwS!lLZUu;~o)@dHU47CI70BZ-sd@>hE1Up+&CL#t}ADA6&njy37 z*eB^VXo{en2^KBx9~FFF!gLlh-0X+p!rIPCK<ZYrlX$Ggl7(I<XZqU_;&tZ+^!#|T z;61csamfs<V`as>9Z`uL8(DEFd$QqRf<25QF25|=LrXiycOdVaoNi+W<eksn=1U47 zCOiYYf$8yPhL(ZX=D?xv`(8|L^9dL)gqVjg+UU6^LR0~R4TZ0$xd|{RuIb5U9-r+7 zVLi>+6h4$}G42dBr1D(mg^-eAoHblz9)~O-+7Xvv3K@5y1(o)Y<8LO4V3nJ_D3}?- zDFc~;Lw3-<wyTIcuWH{w{Ly+2uUM~(#?XgeFDi=DVRkQAw8LjY-m*UN0H6=)lPJHO zM3rHqAme=4E*W*I0s6Pl!rk2Tl#*kwdjnbNI4F3GqO!oItl@}@5j}-XZGIAl<9svf zasZz=<zGtjqt>7>_C+NiI^_f!)Oq^|Bkdbe^cj5^<ItDwz^}ZG>!a&XI*;Dp8uTL$ z#g;V$jo|q%qTy@{42T2C>FhH|0k214K^w%>xcU-w?2uo^WOEMByIRJWu`F}|pHYpi zrqezIrPcjWF0#OJb&C==5Kgzu*xJ;A2ENb?MY{)=!ID6yL;>tA)raN{G$%4+;-lO} zb4e=TauLp@@c!5Vbf9fun3}Cg;26EK7_ZsV0Z$_BRRmvUN?>uqUnrls7Rj&Y0_GYe z`emKJ42|syOT`#@yM1TE;)K&yMiOW`Acr`^$P<Z41%s&VEH}q@a6=a|nckaiX3GWY zy}=B1tGOP<vT_`M>Am6e*?bP)$b&U%>5f+MO}~=E)*bK?aextFS5F5E%=em7rls1| zGw(3i90RW07M&k&N)r&lllC5sVB>fWyC~RIrX!63eW|c^WGCQMd#w+r`X-`nBEc6H z&Zab75d$gu14W>~E9A%W9$+O0ebc6Ru)sW)$W}toT-uILo=;xa28omW)<<36pmiKw z+9mDbL0Cc|l$_@x$o@BxT5yyM1`)gD7lRUhy?%7NMF};0gr24|Ao7NQq@1x*WPCng z1>y-~eVHdY*n;nq0SpEntWq+jmk<fp=`0SNKbzPf=)}^ZH04l8Snw!#Axor$XCek8 z@(RZ7rL3YjFEis+p2PWI$8RE4gAw8H%rU&wP#kJZ*Dv{fO$`X?Zq7isD%&AMdHIzA zyD3PyDMw6D=9w(m>>?m4*aff4@n0<N;p`6VtIz?ka{S{nh1z~jx1Tpx>k_c67$<~R zjJ>Iu2{BkRKGcqlOzq~XaXw`nRf4YDjMH+xo4=3r23jFrZ?Ed_m(FraHnJw?_%>q| zStgnP!z!{jbthJllgem2pg*cO>J4<q?%#KXei|j|7n2A$4M9kE*}7Y048C08Xpa@& zt>%5o5(DNPl`4l|r|d<V4E@QbJ)iAyNJP4r_;%9RW(J<Il^A0ttCBh#<9<2TPb!nC zC;og0((JB=GkL3VW<$HkY1BB{bZ2Im^Mlbg7;QL=I7b`KA~FW&1a6BSlH>c4i;Q^9 z=$J|zFTt%7znEr_qvDe37^r*2RAM~o73cL;dVSyV-NoPJ@5@R3F%MH89o;Dp0OR|z z!!Y|{E*`MVeld=@gI~tP;n021G$QyMWLm!YmEHZ4*4<7kWSTXz!Fl)~>v9}s4avTP zicq*M25-)<f&<^*O>76AHCMw10pvDT8u2KxF)0ZCgakft{$VXr9jojFryNwN!Wga@ zqQ0<NVhnce%HULH+A8Z%U-L2xMs+`tLNbPC`%YvG$qC#M!{YYp`m8SeVT}XF*0q7H zM6O@dmV{(stm_rc4aQ}rdpsJpV-9$TDr8GFe$W3H+=9f0j@pB5U19Ene$w2_PW?8& z%DhB@hfYSD*F<me#NuXy8F>BYVDK?7?q*LqMfYRjp=xPK-`8d$(SghhVFQ##!@n%? z*uZd>oCc1ibbD(?8*l1%sM)MG#CQK)^b=WvO;L5(LzM0N!rDWmZg&xtKGEK8ePZ&i z*87wE1FGdiQ+y<i`Uj907>1Z$(cYw=v;7xg-$k`I=}WUu>N3g|d<bvJ@%O-Hk981V zSN410J^$L|B>jmmsT+EE%~Hg!sb}S+njCj;Bc^z{fe#p~KKM-4<Rn#RV`M9=sO}$8 zk=H2O-zb|#4<tf1A$?EtSiWB7_pViDkA%bWvJ=hIFA#Y+$9FNlo@FaxjhSo;ZG@Nk zD%Kft{JBUzmDAx8ZyAh6_G5i$jqo>yzu4^3kUMR7<a^&hs{{O?l@<35g4MuN9kCf@ zHZGna1&9|pVgtSlUStf*_MNmZHxC`uoQNeeaQChlcM%S<faQs~2o&uoE3*9}kt^^P z6OpLk157XM6%9p12T3xP10XBclo{yA2rQ~$ACB+4oTSs<&8H(PFF+XZnGn1E=A`tk zptj}{5EqA6%{?H?BODLDmP8r7P<XZv8>uUxq{03iRro%yFEYXGrQZ4@6IdtHp3moM zn{JX8#nvBh(&v0L+H{*YV%yYna#DXsoBp11q(5eH_|^kGCRSeAxi5u|$dWF%g`t6E zX%!5VZ9AA{VFN_og`BYXzBKP%Xjc@SFxcFa6SMIm0$<4&@@KI2YWm_k<eUILgQhU} zzCyJ)gmytJtRj5V9*yxzoc>fe6OFp`PyGu{f9*q}%*)V<?9D%6gzA6=fasiv-yttC zmHkm$b`Q6;Mh47Yz-aclJD@U^&8h#J*l*w~kQ~`Kf)>QvtITkeW<DcZ$+@qA(F?Z= zxm6=1diGa1vaTMI3N+4%eE1ZhTd7;};MbapR^7=}^jpAnOsyJbtciF(9RgvlC(-gL zd3Ir0eBO=LR-gqSHe2r&Of=wLO=Y?a@aR#@IiwfE3>SCMkPlrz8mr7JkS5bk2qr4g zMiFz0fk40L4ELHdvatD!8Gb&ZYI-F?moQowN1YZe!Y2@bpZ&&<Z6Q2SBVNQ6P?x2q z=C|^W#l$aa38OiJ`!gFvZ-uRh&0K|l{v#hBi9~e;c5CpgMlfhv;6J^<AcNZuGJJbe z_MjL1eG`p|K{$b8-r;yir`ZYmeOorcRKaxx1)oM|__n8%nDvO2a~a-08ws#STC?-P zpBc^0&-Y8F?|ZtlqN-1~b(vFO7wuC#`?g6A(-pA7)2`Vq%{k}c>BE}Bu6MhOo1v7- zM(!f|!gB%(6AJLVo_#|~Nse#lU&p+!`}Vz;j&P3e(<iV##dE7&$aC^EZ6f+`_&0yI zcdQZ3@qTu|+qmd(0V3DO<G*9eaR)?TW&~>6f9w&j?|YP!1D6HM$Z=<GHf_<ESg3CW zxw{gLVy48Mt|@cfiL8~A;Utlga@;Q-nA!x2dYDglclLr%R-eSg;dcXhCCu@agDOTb z#^i%%s3->aMC_h`m###(Y9^tn{ZC5~XxVS_nwV4Pg6DC-!rEXX=r<zPUXhfN^(-!B z4@VLX#B4Nxu;Yq1MENSPiBMYO*z51Z26ma*s6%0Ojc+TO&RrBh6g*S&rlR=^Kdmt} zNae^g-9H(9Sx!RhjCCwtT$|uR0lIf&M%KKc98t%hDSbh?s}8H%zH)Spk-24&2@PDi zcrX4puRtAYO7j0<Jg9{q%lDJ>+=bP5<~1p-o{|>@EvsylvFQ{rD18sdcC1Ke`i|NX z4wL8vN8<cuFg@0xtFOsRtBg{g!K0KT(Ao;0FruG;dDhj8CjGuL+HK{`v4lCAju4In zKSh4*{UT?)?lpa)d|L_+xN*G5ggs3HkqyvuATqK}Br1g1hV^2j5!;|%Y%|10__o0E zo>0=H@OyV4vjNTi826fUeY+6Wgos^%0pkj*Z*X6`1&OWPYwl{~UNibEZLD}uTw}^m z4_>oa;xmOmTG;{}6Mg#%4_Tq#+?Rb4XdQ>2&wg{?bao@?GJa$E3m$q$jQY(z{6qZP zEQ^|`vJ7SDEio%I`%wJ$UT5JT+D7P>w)<W3k<$|=|JZyW5~lwAK~etRk&a-bzjw4F z*wEj*nIqW1-#ezJ#1RqU@7=1<j0?xK1W7R?wl1QrWLlz6*?@rpvQKNIurzw>pbTHN zSbJk~F^#|^7v5I)+CA>ICo<MknBV7r+z&edzw+RvFe75Pq@eB0^AJ?@)=hGYzgdTK zsA}>Xh(R`H1TD1jcmWEu3jTj6^=Z6kb9Ea~Ill0~pIZlk%6W$uk%;1&{EIkr;5)sv zrO!jNjzJzpM1z<GgRLjg#Xf=ruMe9YKx$Wu<N<bNCIbfT%YzFUa^PkC#uForfxvXF zTg9>E*h<B_Yf9Epo3hYn<oNb&A~X||rRh(w&v_6bVbjSoa-LEqiX7wH&Ki%GQE?vF zUR;9Vbj<WfUv*^@<42iNAo>;7NEj7u0*JOvSu~f9e6tbBmI5mvPlbomRnY6}&;P0^ z)G8?8-)PF;s36p8Sfl@@Ky945gS!SS-3e=pYRX5{6#2xuurz(de^QQ($RAdU?G0UF zIUWSbuA>M}HL0fvP@`thvv@}dP^H?sF$hj}Do5~k2r$jRXlZ}UJ&r98?!fFa_#6`o z568hRi)FE9CV;^jdE(d@uxWf>)@-+zOj5pqcut38aPQFoE|6fxusGpPiCLI12F(a* z>`39rfq(KW^aibI{v{JCVi-?}!O`dNv;<QC&zM)U1HzH9X&nBa+al9fy`F-H8etUZ z9q4jJZl=He4lMsJz!n5a+MbzkeN3M~$15{XQpEhh2?KI7eJ=?OxxT1p0QF-`s@ajd zc}H}vFRKB%d+RY0rDx8cm@xDSnthl(qOUsnN2bpt?E;O7*mSg%guy=EOq(kH*h`gh zx&G*yExu24HwU9P{}df)c22GjmU&5o%+%jz9m+x#QBqEZd+o<CL$b&2%4Aou5T5Pg zl1zVO!t_o#{)Gvv$R1d`;6jiu?aJ4un*z*7ic97+&CTql<ma8WkqTJZ9#~8!KuKmq zr8fc=TxJ9qnVIx+M#Ps{#Wn8Y?VOchYY7StPeR2R?c0?Zm=mGx1;gWsA%mpNsQA)c z!a}rB0xJ%W5#9aisBfSsfgMMn8Eg%)%gKkrl7?IZqyFC{1!Q7s;)Br-IqA;g5~Xp2 zLAKz$ziKz+fw~Rp|ECL!<7h|jlt(LOGz?_1{nB$`6tR5w+D|q>_FQPjFPgM-Wd!=v zNXun7S`p8Y;9hrgDb_vEQ*|bTmytL!En^+?lgF4ji2o>P&cpN%Y;Ka<P2Xa3`8H5o z26SNj>A7cT`a<L;eO`QIPAoU^d&hnvuB2lxWkq1J(>)=gG9&45R`Cz+;&aeWY@z6s zJ^xuoy1`dB>wB~lxnHZDa2|qtSP5-~vE|+g-@sW#H%^pkOoyn;-#xClX8Kg=fz8wG zF7RDaD9JQ|4GRNzBVwfY%vgtpgOQ3oOO5=IaZjAAfla#9``M3}PI*u6@wOd|?dguB zvDMk19mqbpE2nMInWe(6MrDz4s1U6qOmwlO?Fgj?G|{64UC)ei<rYqlY><C;;q+Fn zIcLF`${-#?-!_;=QOO{s+wkaFdsqN(#D<$I_5wr}?!ZZJ7;@84pDVlF8$COP752Bl z0DxNO7S1|9vT0ttIZko*M+IeNHwLyHqFpuV&G0EoLliM$>mdA3iqf_Lf{oObSK_9l zt%l|o^1X#fzP^$s+Q^pVPTDhwGXwZs78PJ7{DCr*gb6V2MEQUf$8)?3wqGDB`$_5t zbe;{4|KPLr24b&5tQn0-M{$X7t9w2d$~K|LbYT{i)q=LWd;UC@<B#oxSNMB2gPcvQ z+2Ox8I^_djPm&Mg@>6faD=;lWZRbQb%}>uQ>mAw9<sEy}>u=(na3aoEzPYB6cWjNX z^*O$;#E>jJ*u(qTPu|9Pf5!M1aO6z=$er_*?@2yZo?BCrT0QI4vYy=M$vfTt`Uh-g z@`znH9#|*TZ!1z+zhtf7?N4a^lC>W~B@;2J8z!;11OuyrFgAD8;3B#CKIZhtjywxB z>f5aNgE=!JHnT=0zP`;;KByd8w?@6ZV|TDp4Up>!?}QH^5KtZ8taC6a#Aw4O+-Y}3 zStNA^O>+feyCSlcw_%gQ8LeD1E~soFm3rB#6zHftt1P1xrJCaq)P!dg^2?62ZH>^B z?&3{ILO=N68bTmnjmn^5Fi<#uF+Vp)s~4Bh$>@uE3>os9!-l#GqHf-VKm^%jI;Wue z!^}%ZN6a5#DV(!05KrH3P5{e_$#kJR@Sf<3#(T$}Dl6t(OOhtkV7<+LDR$|DwP~IB zx^$Jr=Aglp#)vFNumboi{HUg~Q=ngsZ&b8z6ePu4vsrmJ#N~~E)mjqgO$A$fLJ`Uu z@Gbd2$d*&;r#Kom85mrgm1Wp__~#v7hl2UR6h5I^nXn82FMe4AG0U^?mf~;dIzaPB zua8IkvE}ZfLZ%nuLWs7wM;+H<ozK}V>&ibqvjF~8-jD(>%rE9i)C4{6R316TCH@si z^ZJ{5JD?-xW9rd4QQoAZaQ;TQK76v9x8?(cyu}~Ph)nqaBw#ANP|D0ciDS|9RX9=v zX?t>fXEHJEYkUr;fv&t5OxQ;?#&g$5+?NF&P%_*?xQG_u$CjgeWwq@Y9R|T6GM&_! z<tB~?Dn3x?i3!bM_j2A3js#6}G>;|r)7vQ?(ULpm1g6t~#sF%9&~-J^u~i=2_f=zj z-IR_b@c%uQmN6LLZw>K%{zS&fGwRL|reK7GF#%??QQ~vP9u4%0n7=#wvmepZw644z zmUe!UcpT6unZ6QA9Q88>8iH@O&RpAg;_-Nc6Cug&e`b$8?rn&&d_QL<(cLk2k2&fV zM&)Co`$J`$*)7cF(Za2~Mj3@4V<7`KMn>R+jgpMi!?PX%qev7+ItQ;ZhJmNF7Ub|4 z&hF7;(H*l7P|QKxMGr#E&>i&0if=B2;ZwxBTz+@AzR~W$RHnglU?kjWaB3J((!clv zcM(0D*@dZ)s_eoUwp1-cB>yN?q=kQ#!@U9B4?*c_mSDP}^`%vE{LK>BAvF^UbfZXi z!;I)nB2~1jkUhI$V@MPvDPl8Mkd*Bzh_b#4NT$DY_So&-2~a8U9b&+49#1h@#V0a- zoik)w<DTCTT?ht~akBR8@-_sNgI-g2(R`#7c6GVu&&5Mla!qg_+Pv`IX0ACXY^qoq zF(Q@6misqQTd>h2@b*$XP)x%~>@cW%F*RlU;?{#nDu<9HdGXnmSXWKKrol{qc64wO zp}uNw!-!0OdSq?}J|S`!@t#+|D`P`CN`|EUi9z0<SsL$kzqrd?=s_ZJ4c*0;5SM|$ z$o*hTJYqna679=CCqs!wUKdxQws;#hXE&2ucrS*f3)s~(26YiBds0sLyLUA|G!pM* z@5+DFAXjQ$LbF*PmSsrx;Cm>;I~H>V@T-d~2S<A+?BRIcocwwg$r!ycjw7gx2EH;M z4C7m*#*n5OF8Pi{x&AH*Gulbh_?sYm1k8aZH9eUXk1njkU5L)6a)5=9mhyFp_8s;8 zy1BX$2TIsE72d|Pco5+q%KX$b?*3<d(hlCn3%9Tt{P&UdsoUK-M}2Sev8*Ax)XJ8= z&Xw+(?byW>mznyhd*K48n!h3F8x8u{H0RPV0he23p)DXlSe>W4(cdga4Ao5E&P<AI z5FVz&>PCo9$nQ`vyMZgeeZlO8uKYH+_{J%h^AMP=F3e<RqbWD<L~veBqlkOptu}vP z`O!NT8{DHRYv4-thZ)(}T|9!*fiNR;5QMryk@ule4lT}duf?^3C7>?T_ow(ncbXxf zDKoV?|EbEI8N<*8=n|L?7hHexeWW{8{y+BK1w4u(>;G?ZfrxApFKE_fbx_oxBqT^Q zAh-!hB*6fY1kH+?gk(ZSl1ZGIK=6u!EEuA!qN1`ci|C8Dl~q?!QKKS3S6x)p=qj=+ zY6D&n710fu|L0V7_w<B-?)$v&|Nndb&o9q2`A&D8sycP*oH|vfs(a>r-olJl7KS-8 zt*_*;3Fq$6ltML?W?_``mqa;%B75W9PC;AY^A}@;U9qC1g_j}G{4=W<5SsWlvHJ5x z=ERv_q^O2J|2Gz4$1vNUZt$;~x&64f;zcHkEf%%tuN0=HmPyyiE_CLbY6hf3i6i1f z17+g%OOlv#oj}}$k?<sh^=$WGX1rgjC5H0l42ZEAJlhv%F5NCva|SRs+WHIJy@Yqk zv6vi-wk&$@`EI2*)q4tClgBL@bc!183*Y)z;UQ(al3N#w`7+;{__sysYvCbFcPR~8 zqBQ8Oq~iA%Et9Xs4C_3c+}yWtQT>o|=BBOjr%;1Dxbi7;=5eiKQq3xDLccPX#pvK< zT&NR64!tE#&ftvw&b&S^7FNGiJZg6!Zjre&TL%9^rc;HZ-Uzb&@=9T!VuVf?6z=>Z z535P1z@C9d4ka`tE5nkV3q&L4t#5IugT%p@gUDN&7JW*lLCTBGgB#o19Z@@P%#fJo z0kte)Vx*svo@l3#RDR>waReMYSiydu@&`=5I{FbNpvT`eNB0x2(}(n<N$2cB!7sPv z&fC_VJ8wNJ>=VpmNWZRqEkeRMWK}|w&s&C}lf->WCTkheNgO!dO3a<tC0Y3)bv7^F zM_SC^nptKJoB{!&ZTv`fAF^`PRW@4!pNgYnHgG7fm&3GlWoq@JPOavaWwxuA-@dNG z*Z8%!t#%|cUHs;O+73qh&>?e2GnZTmE43YYsP)cMDUBtMSpHMO;HVu*^Zz1W#)iX8 zJ8!&4NL5%NFQy|ePR0-kQ~PKWnTQlum*{A5Tad|bwmFxCd6&n9)f0|F`Eabhq4;g) z=N<+wC$L5XZ`h(5SfQ?@f$_S5bc#N^DuTb%Q1v8TH<gMdu*d3Cc6;ta;G#MS(w_P7 zO5(uFDQf3Ew46s$-!5FVn}Cl*)>yHBW`3xq6cAkxQ41&N<-7zV0Q$1S<V3O952yYI zwrS?R{!lUZ0?~Y01#@*&xbrM(Ou?HC($+d3=CD>Ck{LTkN<GF2+jp3CG@Bwh#5cBv zG<7}iHBsAC*=>^NrF-G>44cbsRNRxx(g>HIDZb**(OeF4xO@TW_vCU*xXb49Eh*K_ z<v5k5xO|p0^9A%Uic3q0B=SoCViQV@%=i09>(nBnRq|ag`OwW@)IR@Og6iqoMKfb) ztjyh)AcM>wktf;B66v_MvA^Wn%-7%JRT|s)BlY!(Hti67{R^Q@(cgdgLCS$Pfoo1_ zrzMcc0jghDTAB2N4j-AOC}{Mf@DuHFUzN1Bu~|}XyZ$~{rBUu0uBF@zZb-RvtxR^g zOL~;+oQ1R|k*Pe6AoE|QNNj($wj`K4E}=GwRNy#@TPwMlmoSll%KR>di@7Zs#zbaJ zysM(Aq`0*%H8h~OwI!RY9Igs6lYZ|HHue}fN%Q|MR*CB06$<lgank(f<XYAvZR>_4 zQ>$z?tH;yw*^ZdjE*8NL6B7wi({}SrmQ?l~^A&#FfWhTG&Nj;a=+ktkOi85}xxO6b zCHWI8dATH`_AG2W%nH&tOK+83xQNgghxYF7mJ`!Q4$<dQrB<FN=e-ilQPevXq~z_1 zYVNGLHOI$Gp*%BIxJ|N_B9{VVBF7~beN8J1TLbKOPpIQGcesQ?zT#)*&DH#1q_kW- zDEo{_*F7jAfRjxL_|ZM)k*dfb8Cird_7pN<mZaiVjzoint>@L5Up<c;TH~AELy=ks z-q$H$$m`y6LX{k@QR3W1#6w9<4#1dw`e@0?UGv%>l;k#FuO)Sjj8Aforo%iN8*thy zwA+)c_Nt86?2~5F-VL1i*ggW!B7L7U|6A3Dr9+Mr+0zz7VV1l}&-_M8Z;k)p-NA-) zd~%mGMApizBjvmKWmlK#JjpnbnBK`0_!RHvlb)3Gly81RKb(x0vHNP@J~Gf(NGNyF z+vc;<p)os?imKn<d4!DE56O+=3+MePY8%S5nIg1m-lS=dEUMnjNezoz^9s4kL35RX zA6Z=dZz`bQtKZZw`R8{$l$f&~pdsS!c9KEaM#j0E=W9(Zl3kVgL$*p^QE0Nrjd>P* zF@MNh3DtAKXgy!`rd*_Me;4CHG~3@9jQw~Ml!a_ijsD8K;!>?ADpaCY>;z?8=HW5N zJR?eg*=gH2E-Zb+rTLe=s(afPD)E^syG2x%=6j_#_;nd8ZGn~Mk<Kq7O<RTLS6fA! zn3-6GIzyLYUdc6r(k3CTl`b*IqBz?>7v5nZ!A$2;Da!DFO71+=nE(kdA`s_O*jiXp z*xJOs!n)$toYdT~yld$zMB*_QHR)zQOi?P#mvr4KtJGAiV~?`ppRkTMo>kT{1+iis zt#7-mV_I=5?}*BwM3(OA42p?L^WF6C(L!SZEV5`oztqW>4s!(lMT<rEDd8y^JnKhG zENEretW#GQ#zP-<Q|?R26G!<uK6o6iaQmUs%ZMxdO44=TOIu|8`$76d4h6krUPczQ z;BLj|zz;S%?8b#kWjujih7WXV1tqED0CMJWxY(j~(|lIA*N31V#gydzjcUk}96Xa` zlRYnn-x{B-tGd)(Rh~>FGW21C&0SJ7mu9V&%6AL2RL+;O)tUYb;XFWb7@4M&qG{Pv zpLT~Av1Y7CnOfsyEQPQ_w2s6x=srS8*Q^&0<DU8U^gt;xfZ&1970UzF)kqP_1L0>} z9w>_$pg0{|4i72pC`x)*RE)_t-m3)t5;w+Gs*F^&W2!3@=Y%BuZ&{9Mht)CheyxA< zJdEv_WKfE-yceF-gK5MutyI29yDBsDI}u-&d7T#8@iLOMW&PW_JVIUa^pR>}hxwKo z`m)Aa$>08{t<@u1_=L!tLrA({X$J1=CG*Gcr5m|$d8$vjCy$4zZr5c)VBUj)Z|}6m zaJg;XtV|wNUCMM)9D1t6Op+sB3p+$~+LtLWr2LrMhi&86-o=M4rCjC1TCEB!A6BBO z&{ir3Klk@x^p1JT)5=UAcvG3_wl^HT&q<m;S_<sdk!6deArR${p4_b@edv5G>9t~2 z+L2v}l%pNl%jk)nar@g`XxFtzI=XG?kR<62DOW}`epPrLqRLi%5kDB#9M`2rJj->- zck{G8(!KniI2VrVs#5BtT-VWG&@n@m>$18p_j~DLE-dHOhp{HgdF_&Jk9J;Cx;U@5 zB`IcS#Cb`A`JCK!Ij_HeD}qqYtB*9hb>J;Zyjfpv(#|Vgxlbl`!3lD9Z9S$?O_K6J z_gbd#<0ZP6d4>`9R6itP;;F+}+pSaHjNhiw<7g2_4U6V&NH+hdypB#a({;yuaxImk z$H(oJ(Ud3lJIrm;M{QY0T%=RtRf?K>{P>+p*<$6{iIkik6o<6EpA4i{{pKDvpOlAr z?S1)jj+%Ng#uT=mi*va&p}4gO<Iio$d^s}r8fLZV16ri?_AO~DC2m59c$Z};O;PKx zAv-z!&-q1OULg9<7_{FMES29LIzOc_mbq9p2Yb~SV_wje(7XXjzV~;f(T6Lrre*cE zHj595Ov^42ONIftYwr9?Y4g}?v}ksSVrgxD7%Ay-z;Quh+`E|->2ZJ;LR*DwQTH(K z6W(KrrXP&dzUNmWJ_h0AzoA^q_jGqk3GpXujw@exZ1BLo2W>GQRc=8$By-#@@t_<M z?J&=P<!IkCM;H??WELpK;@7D<27dRNt17QLH|zKx^*ZkoRfYJVe`&G2F;|P_Em0Hg z>XwNi@e9UQ%9EtHywhfMQ2!!JhPhGnk+u)oig%K=#cQY`W1ozm45-hkf#WOlHVj_* zC-FaS|HO{33a___3|r&Bmqw^{3WuQMhw8TQ=H*MVw13Ezdh>F%94uCk#7JmPX5p8M zXJB@kq??pwF>a_PDI<8vlHg~;*5T3uT={2af_ytdOq%dm5!xz^*{-<$$Q&it_6sXs z)W7Y;+nT9~qyJ?L1wFXGT{v{OpZTil35)w*AB6j7#N=S++%LhltUIsP9WqW0Hj4Xx zZtlyzwz;1m-)!z%Syu`7r&`=!F4qU*{#JC=&As`IP`Ad<a+*NcH-7cs+)cPZ8f15X z95(+<_knc4kD`P$;RXg}nh<X_;c77nZEE?VL?UzPfZwCqx&wYE-|QxA?5mqlhgn8g zCmQmdOHItfHLIrzJ4)KZ>b_TORvXZjhlO#)YDE;Ar52l?eXiKNR^C2<d3Ek~*!%-R zci7y4I%zhy$~T+M!4{j(i<vkQCNMB|{B{BZ>e+kZ8QErzj5Mqx6>noN5r*5cPJqU| z_iIv!NDk-5$}w=!HuhI?|5yZu8wyIAyt-tGPU}b7)0l{1?t@hbrU-%jSnd^?;7gNO z>p#qobgH~~VWd>rHueu+MqUw-X;nIme3Nv(4dgTLlU&ZLOK#?t>q-7zUR`pZn3Xbe z*Q-kmUEr1E)|{5QIF(nIe0-*AW{u`FE5hmZFDp)u)0}dQh2NXorNtw!E_qbv8zY>C zX+h)_5r_2TbiY@ZgvEq3r%|sisnlie`V3~->(~9UGy2sfxteCP&@gJTx|hnMU#@+u zrdcaA3>JoYv8E}M;fx+S5&jKLvs`G<T*Dl#Y2<+?p~3ZMeK=alX0FhnT!wj+rZFrU zo@UB=PSex~O}x<TMo94U0pFz@`LW!)HBF(=;MooHbxpI@qLEjZ%-1x-ga+?unD=WM z_p3{)G)=P5FwZf}1w!L`b;;S9;QLP@P<rXr1WGUER}|7T!4?S6%ker@^m2KJ>g|g@ zkLcy?U+UhLSC@2+Qj+*H`OL#4m-Fh9Gr1L|m;1fC<S^xc#rarzDX%VhL>K6FIDPsn z)fC04yj=S>O;D^k{ew;wPIqrmoPM-3^6HYWzR;Y?t4n-3-w^VdGbESu>XNVJA%LOp zM_#G3->XYzp#8R9Hd}qn9%<IEbeWwLpmi=$3XXntNmsU#&^n<}I=2JyL6c^cb2Q~_ z(KIWBM(NxJO>>Av!y($Nc1<&1Xq3*a)HI)1x-t-&m71nbXq3)frD>kGXyjcS^EFMe z&?ud|K-2ueqB#N@ucpZm8l`im3ytg5B}JOxXdzGvH&7EeuP#Z`1l`*ppb>`oEnPtg zqeb;u#Ah9*2|j@Ug?mS*%BxFGeMxm={tor(lC;l}{Jizqgr1)g%O{#Uoh+{I>hbE5 zbts|ks*lB0yoO;e!QcE^O4Yue7<Oy?FCy35M^VQT?Oo-RPHTLsXi{sV93W)Bg-0Ly zh1hra%B<TYUh^w6feh+d;*RwY^2CdJaoG{Pt61ue|BKwUJl#AUH5Y$q-fquDHtw{& zxol{(#;+A-<oSAJa~!g%pG`wGvl3KDHlLtE{i}>$kX80OSj%^aXFm5093AiQA|NQ! zIlm;U0aTr5hl(c*?-QlOiBOWJTE-1cB}<~1=tkTr0%T_ciQ|u&KbE!->#vbKZDTLu z+AP=Ki&PqM_CkH_vuU&S^|?YjOn)D1(+=WVV)Dh@keK``E0Z0Q??RD!#QJ}4k(gU0 zjr|#}&CU9|SEa$jdakA15I3aU^;Rak+*Liw{pm<c_ml%fTHZmSe=^q3%Hzz}w7NWb zp<Y0KE&AIU|H2E1v~}RWpBFH$KRn@uq(#a=t@wYBFiWyIZM7@RGFOc0%pEcxvcfE{ ze5@u%UCoq^#y`DXgcOOZT&^@G>yw~PUM|Tx7)1P^v|i#WD~Vn8jH}$hJ!cszEN<U| z;R_Qgno=Mmty(OyP*kA~mV}e;lgP%wb^};bBB;54llpk?_+VqM?5YPDm&DHIPSb*` zmTPwuM1-Ig5+k;2L8vImqY`6fGHbQ;5fhg5WOnur+KKY3ppXjZziTnCGCuMNOT=yl zx`T#7HiVFTni609QLuX8P)O=0x(lL0A??Dmj^Ypa09i(bLQelw#1{#L?2(Rf$MHXr z8@-1@UeUBYLLraIT~{b%{l_8=6$<GuZEqcTJ#F9|?#IvRP{;`~(#jr}ydAZ;)nmo+ zB_!aE<1?<zcjEY-?GIuL(uXQAVivtZ572QPzttVLUE16lzlkcS@DK%-#y_c&<OCkW z5=SBQct;e@tiMOJh688M&V|OD{Fx{Rm*ziNw9>yVR{y@KWTuBg^A_oBe)y(I3E6zy zN@LjWFz1k_wOqm{PV{h{*o}%Fs))YFe1IEH=uq0NNX<)7p6zNIU05}zap}@@0xf8I z&Ar02E4)9ox9Gms_M0|Jz48BkMrr#Tp9t*MauHbQBHjm?pqj11@+{QO#q1=o{_Yml z_Muk$-a*4eXteIm&+OJk#YDESGiAj@B>&&JlsNyyQMJV5CrCX07t(cTgv8^2kluig z#D7WSbUc1XhvM^yXI1AF!>+ZtcHo$Z#N+>nG0Cu?f*t7+)7L?Y6JS{uXT8PaGZnM( zt5qEX|GCapl{+4vuZosf$U9mbw_hr3cbFa9C_565{}%&+9r1Wa1_fGn%HOSs$3M^p z<sntX<25x%d}ZE)UH2OC5I>=wzPDd`#!p#@YS{7kPEIvVR1a$tlead5wSkqCi2e|y zCnoQX$D{HRk5^}lnG30S{9)Y7w#f?#;peD<@rMnX`Pt`*ddb8omN8;}yHd=g`Dz!X zHU3g1uYvbJt;D7s%0}C~=n1tI7uirwHv6xnI1);jYic9gp?rwGW6qI)cw1JDrE8bS z$bm!Adt4pnDQa}fTH2sxe~u*E4kb}KS#2mw*@cVr*4Y#>+*W%-SyIg3aBKhFvoL16 zU7yO-Y@1&wLzW<<8XUjIwV2-v`!2UaY?2W25A?D`=!G&R%nN<Qvz+vj)Es}~Q<i5@ zD^9fGB#xj+<o+C&XW7b(SxG~AmQGPg5gvEV-~K~M<bitK<Z`hRZGFEM&9gm=&~Crq z@+|7&F)p-IvA2f566K*>HNLcEUFxU!PGxoR&p+vMD(ymN#n<J#`PLTQ4U*A`uTN8U ztK#cVyp2TNTf_hQNIJ&Z8opb)#_dvWk{i)3Maq`w`fN=baVe5uR>@tLOS$wz5rc9m z?<qGh@C@XPOIbogWNUa68B{l9u19{{c$lA!6tRD0Yp3{|y}Vvah2966YbAU9pU8gw z;S4r1Gukie-b9zl6ZER9bkw~g*&M2T|GFWPYOa+~IIr8WH1xi$GFWn0yTkO0q}#Io zP@p^VMwOz5(fLZeS#>jYN;4@=ze=Io`L#gRajJ&7n8-wlkPjADP$Us@jyklS=Zc4) zyMl-P)efk{!#jT>G_Tcl_6soH8o%`kOI?+BMQ*dFXt^y{V%Fyx4CX5lbsegFBa<=i zn)gdIo3*)5x8*)j1g)<Af6^>vpF${|hl!exFdtF&$r{os;*Z?YOH|84{8D*~uguT? zq5G7)=Emn0yI;dD?)?-6Dvr0Ghgd>xwWlgk^DD(EP?6j;2N0gOqUL?z)A10JxKl;V z6<LyEF@Axr>bb|&P$wb7xR4Vy_vk%g`4P-xR24F5cu>n?ht;otkZ#rvX*ykulpeIC zG>;VRLp;*9yD)jZr|U6q67#1UKE-n{Vo!G&TIB5MwyME^Urk^fR31d!!$D%^kNy?j zt;Jny{C9HID!*1JG4ubDcG)4@9x?Or;_?{%{_(CzFRQ?6(5uP_l?wmflAj9MZovk0 zEOfJcvtywHd9kZB<*$nCkIZ<vc4DGEV&)#oc1N92%}<0whx;?4xZf^U2jG5@_!PMR zwdVeTOSEbxM!1*pO))Ie_c+`i<>vnUU7GvvQDfNw7%$fc;(q!E(cGJhgt|3;#A9|7 zBoG~vE2jfaayOwz%zT5WAWgX79n}FzRuj&l8q2zp-A%X%#nv5AD&Oo5SjsC|r2|Gv z6CBoi#>}?}RcrigVaJLjw8p>usLiUx%r6(ldx@DJXR-Mx{s2Asy`|o(#BTK<;6vz+ zq#wsVG@D{64x3*P-4!<5#7JChwvEl>sDLYGK0tYyfz67yv8M~eypRqWGw?oHiD*d7 z+<&4Bo@0-e`#azSN94rJFVtzVr0G!6%bLK6nHOq;9c+*jDtbVtO2p5QO54UxRd2b~ zaj1Ro=}IMLevHod0{P5l$>qe%Z<M`ucf>C~9{${~Rc@AXLQNB0G4of4s8-A&x90RX z7pD?4e^?V#YEJt^I6dzX#p%1Qn0cwisl?2$*7>r@XZ{VbMPifj+=}9KznJ;o#Dp}b zQ8Dvjy3EhtfLRqYm;NB`D8s3A%gNOH3r(|0Xb!=@nUge4y+v~pG&@dEjebmM7}*T- z6iwrfnZK%OmI;lDU-s2BL#%QnW`3Whxk6}E{PJH20Djyt^Hxn$DKzwmVLq#A+%fY; zO_MJ)aYA#4rdi8(X_v&zOEgWY(8LPOEKTE%nWt%*0Ybwp%`m43jVoq;xF-09^8mWH zGc|z|GymauC7JgjKrfHbsiK#4YgBI!{2~%F_r9z3Qex&Cb-w$_XMWg8rB2NJ3~ojB z_I@$*57DV8y_A^wRl2|`a%)b1C#AYx_g$?C3L$_~pH3A{pM6+ydYg{!D>Zrg9nC4T zgsd!`&m)|kCb^uL`4_TN?zW))V&<nsIE{MUH+vLfw3{hF>)iW@20b{}(iP4IW^L3o zYlTMX+~b<Y9W%dQ(<~PnrE@oF8h6Zmv8I_TG)m|En&uNrS0rZc*EBUkqjYY9rg`3? zk(hajrYRH}rE@1~8h6Y*Q_~C+8l`hFLgR{=57Y!l2tkY}+&_^t1WwHS2al4>k8G;z zZfw^CPR#s6P4G_$=*E>gRbuAfKcu>`OUKNA*h~*b$ILG#i>teO#LO3>x>~7J%=~tY zcZs}p;LC*Pw<h%2WxpcD!$CA2nd+DHL}*B2xFoxlkTbQ*%Vgx%0PEJV3`T>f-=p7X z!pyecH%W)d!%~VShg<``NlNBFL@9coo)EKVw-B*>>ldLTuawS>gm8&u9JE_9^1Qi} zju!Qmc1d{pCA5?4FJD7bpVZ&q=R1T6+warYKdNhJZ`arV652NX{dJr6O0Ff0{2@0a zjGSdvV26<}68h+)=*QbU<m$5eb8Tkn?|bZWPqfO7CsE3s+N0d~9_8`|yrM<#>L(j{ z<CHv}8QE4h`=BVq7Fc%@ZOweMb+U(e1P9G$mlVb}<`jPab?f9IJX`Vo*Ya<62Cqih zDX*wwdOGjraPiO$ynSW&p9xo_p3^$!)57oH&_9{QgRY}^3h{-)q_f{B3a>Z+f*uu% zXKBqFQrzdIq=)l7@_Ss5Gch^q0a@YAY${%Kd7aFjII1=YokkV6k;1fO&-$38`DdzI zr6u-cpNY46d58J%XN1;S0Z5F9o90`eN~rxKv*T8Uaz1>m{dK+hSNRI{8cj{&z&p7k z(Pr+pbJxuNz08*`PcSDg;R|;+DcTL@<dY<?1QQLIF=O76Ns+7zmcA<A9<vBL%rY^W zwyfL5#8@aczbTizVpWyXVP@&%%dF({tYpnnhk2AvzPVE8K7(XE*Gk)@ioMoKIF^Kb zeMaaAoigZDoh44CsCoPke^+_VxAN?GL$jiV)nVTMmP-DOmHam=d5OhoE6L6}=0)=z zUh8CCny<)r!d_U8mXLYF+Yle_Twbj&HGvXrgF~P$FLo11<IQ4+KwXY?69~uVsSbg< z93+>VOI17w&t`w_Nar7~9FMgu{7wXV&3e&v_gYG<;_qS=wn@A#J8L}e+tVZpTPK&a zUX5AgWf#T<F^TV6FUKT`+x#(n7qbXr78{Be?JE4fQ|*fFJW&mS{50D?iL4e6-Gd46 zj=8dUnBy7ARU&2{ki-@y_W91Xg;!-gv07~5@+S7$de}lIDL-iocW=|$Ez%KN==hjx z#PRga3dI&4w7;%5?~|`lws6QY?znAX*bSB~<hDiILf#3I*Rh2?L`1bMEPOfI77CS0 zWwrfUtENxsW5gDQ>SVu_Ji$tq{uk5fuakdwk-j{YWNizBUsH-Z%St$$1j`os>6GMD zon`OqlA>(ki&s^ibF4gDND;Ht!s;;Z(nfTemHeEQEP5rZTurje7G7bW$+m@O<$IJZ zT#E&|Y$2#GUA9o=5VTXiImJz<0HIP?wo*0;T-NIRxr5SuUe&p<84}=O3kP+_Hu3 za<dm(uwH2=kHsa-yLu2mOwh=Y&x-QqQ+WmD&Lep-5Wk#9X!a$><uNas*COv+hVvo0 zNe}agLGGxR0w3%=8sE`6p2vQ^<Rs@tK9e)3|C?3fIJM!usLjpgex&v2{pfqp?pA|% z-Xa-W8T(DSV~zb^D5BDGQP#P9x8B;c#eDRiO0Ug-EK!INny=blUou~ouVm3ZxFwfx zQR*$+vJ_m2?VMIi!7H!V3NF%?UzMBgk<4t;=)r!V?7zyT`Ck%8M{P7=hdD#(N!EkM zXf;`=lq{lEg*v&-O7>aFnx_tPs7}830-bvT$(A1f<`t!_ORba)m7?_cM4gg;qRw-a zN>K-a57jA6R-UfEX$=>di3+d7G_=m*?O!zeVXD@p`ESBejtWcD%;)H0t-|VZjlR?> ztVDO0L!d5ibQ4JP%qtxNb?KK&TSJ8<^Fr>3hK7{o>Ap3`bF(#XP+{!M9G<M5UDkSz zM@C*X1!+AeG8GAC@V=p;i#m#1^U9MR?oN7mchbW@wvEipy?$gy+n7<|=W`Z@#u}}` zA)~$yycd4q%u-L%Jc+yV-j*Hn_Vx=EP%r~9fe93%oJo<TwC7~-t}A{Yfyv^R><ows z=Z4pZ`OUr9nHgk|;X0S8%ZJ<NQyQCW8S=)7MtCge-J4MJGQnXZH>r1BnC7cIv5|u% zG3%r?p<}P^%fqpWJ4efpD;_34u9%@tT$nFB%p=gkjQRE>d^=_lKh@kCoBNEc5Y&4u zRlMaR*eLGv1^l=exej}7N1V2A<2}*pcNmKFubRpmp6xS~(Vne!JW_77q^zfXTFOxq zJ|*RMk#dQW@-AeHtPwO4zCM&?<SrbU9WCV%Fk?%3ViC_o^Xf?vsKm`}fo=$wlo!Wd zp3z!5gnn4GDe2+ob4P6mytnA(MQ<X?5<24*J&>G34|II9%6fKvJkmzhnMiJLM>L{6 z^Z%w~EaDxbe!g<x_9Y~Vgoh#Fr0cHbYUc#q*Nj&ia@*qi6+XX}-@BJzx+4Z#_7EaJ z?jQuAH8M)X4PjYf>^z;OM0H6yzgbH=gl&p{M_wlRd~Vy3M?)Q_o>WheUM!3ycAp#W z$UpP)AxYQfaejxNb<ICB=n3-5lJHKGQE=o6dnR1n!~4Haiai=0a3*}u2YS2{a}@9Y z@;|snK+m))6z~6M`|Eo10r?u`{STG#((V1z7g&R1-gSC#+@wn0U>5vJ@;cssuk7y1 zrFp$X@fjR7VTU>4Wi^Q1I8YBjGduKvB<d;y(y2PR$x1G^lGj+t19bADshT>CWbMgM zcu5u8VkI0&f;DO$qEim{=qx{OaJ>Il>s6kKR-Ub-2&Y<D9p;LSDmlwae%?x!kxMwe zhGdubfAvLs==7NF@;%D?&u18RdH-g8>GJ;74uMF*EOQe`<IQmnfx0}+O&}bbgB=2O zdAMBKW2^9N8r+f2Pf<R=^8PzTp!<7&p3sbA?)y!M*B<?t5E{z=nC4-uo@-lAuYLY? z-iWYAt;b`<jQh2op7gq`pkw)k;?}-}NgE3n^_5p{{m+yUI$H4{|6`gDt8MLDt6nnD z_r=z}NgEgSRrUN7jl8r?rt+MKlQ4rhy+f;OvN-nPypUCSa#m>PmKsLRU;CIZw#%dN z&73Is$h>_akF4+Q8;Z&NLXnw|)Ac#?zX;{;JO;pVhWhJ-KZweZ<F6vs)>sv{;ClaP zh8^HIc4sn<fFA<*$o!7zt;8U#_=Y+m$MZtVF>}2mvi*q-yt|%3;WpR3_ZT(g-p*d` zo&1MLUPUJ&Fh91>39fjti}%lQhbLTx>uK9>u<zVv-?@T2lzyG7^chx-zjWQ}rSx%j zSx)I0_8oq7MAvt$edn9^WSohgb*Ig6EYTgs+lNBi8o%m*DZ3AtlIk$%ly;*o?ePQV z$#<s^sTuq6(^2~oSI8jHI`ES_V6=7Yy;1{bv7s^l^*kxoe#91D1Vr8^<o*S;(T@A3 zL;R{vyPGr}h8v{`oc)Nkn&5f}2*dqKr%E)nNh;+X5w5szgH@^QM_jM-O_xePd4Wou z{fOb*a)sx5Im7>njFA$HvCm4&&ySAL1^&|E^hPPwiu=lb#BrLy(41bXQ-#wFw<}IR z)p6fLadpa`L_D$|@fCMyNas^<dZy%Z;=cEAD~i+o_9M=Wa2mBAv0RtAm;&^Eg!D&` z{fH|yO_R{5{fK8ZO+BNd@Fx2a7igL?p;58nJ2Xw9MI&eU$7q^tp;58nS(?VZAMr~~ zGe~GuY<P;MF|2Y<pqzgb5l0S&(5TpOx~6gOM|`AdwsB}d$A<fB8uxxgyQbMFG%7ay zDT5bnckf61LDM`aG%Tlhe}~Yx_9L#<1UCx-JR0VoG=Z}p;nM_{L4aP))2Y(iowupp z9->ditHR%YRvUxtM`Y`K6Ub*ylw8h!#Jh4JW9a*llkxlQM@&Tfqx4etBfg~X5L+LI z)9;^CO;Mc68UD94ft>e%)Aw|$aGI_;y;lXYwVIr2aVq-}_vn1><TLM<T#jD0_2hKF z{fN8KV~f+M{fP5*nIQ_$IyXTIj^2;R)->fpqjc^hP2=8=I7ZWq5gMg)F`CA`AJIi- z1mh7JrE^<o9Cf+(BerOoIH6HG_mrl2o-P*~ko^dCIH+x`$!Q3!bGK@mKUg$JK=UVE z&Z|PBbS@w?uKkGXG{K`npmgF~P2lWD_%y*CLZB2bLlZdr5fe4RH4xB^hwD_?kC<_b zQn*8Tl@*VZ`qm-&=>3RpIYtmstRDLjdr?B&Rcb%t5PD904e!|bcjlYsQ<BQ-XzewV zyx9L+`<Q}SEw#qqwUqL8Y+{etbL+rjVabY3e5`Ki*n~{QoY=(CZ{X$d^uL*_P+}7q z_ScupH2E4e`)->rUeOhYUUQi^L*mdc&EX5Qo1`j=>EKm|Y6hZ16PK;CLlXlYkDh(M z`V6h(@d&X==CEHpEtiql+e12ew<sIQuUpA7<CN<gbn>AS^yR}O>)H1`PpV>nEYb<L zl3+#HT6N0OBX!CZDn&&mF4ZaTSb3&fb&15JuH&i86`5#QYfrC}%_{jGHN8Gjj3E+e zK1yG@rq^)}K|AG}--$BWC8+uI$NG*Xe{-{3GC5RnWMOIhHl_UQ^ug1=lFTAiM<F;a zR-XBV{M4yTv*qQYbEOSzlSIWP7PYHIYH@6J4o78Uwy&T-ey;Q@`8}<do<M%QdPWLh zLCnu$m6)^A)UWk@WmfK!7isYeK)mk{U6-S8S;C(D2&V*XQsp8CUN{K)Sz-94+=cl= zSXSGm<(P7V;x&JTt&_}eR!L#IkZ^Hq4NgC5ned);GFtkzv{45)3P-(^bZv>uo%UZT z*pY?rA}3foRV(6Ke&5qdPP(agE0Jb9R`T_0$~w$nUa3&5q`&=jz1dH`(o51OtY}%l z&bWp<mX)mGu6g}z%S!$@OIu01qTOKrX@HdYnYNMhp2RXZZ?oeOZ6TV7{g0=VDu2ZQ zDr)$*wQ?DW?X~LUO;+-QR<dTN!>rfI+t1dy+ep?HGVgI!Y^RkFBEedp`gBU*FrDQB zm7*+UvQBx-%9CT&rIZBL<aZpbgElXk6aR`$uv+=d%#&}nZcD4oerS!h4t2Q~OLGX6 z#6Hz`Y~_E~O&~2ZUvdc4<>PW0r8KL!BTBPQ24l(*9?cuM>9Ud_;hmW|VktVVx1WU& zj@@~2QEMEkPLE;;C8oT!bfI(~+AXg!YT-LZ^CiC)RG2h=6WVU(^4>#EK&ux#77r!d z_U<?L^H21BuF9$PJ!~4nj_j{|A^|&eI&d@kEXr!f$#^|3?;e-GZ(gjGzx1TzB%~)j zQ$M7$cu~!et?b_Z{R)CIZ6|IN;JztuJKR;wYvcD8F1m2YCKj35#X~>IU9^vr-TX!r zzaRImdFEdb48NE(DDxjl$K{akN31)amsN$2{D3F%`>^X9*iqPep=?pt%iF(d<ZO36 z@5N<(m@4PFd4J>jY@0v*%DU&^-Pm4;nh?>mf9@`RFMJj9LouOWKE2W7HIk0Yhks5V zg*UMzm4xQ6Rs8*B3RAn=S8ETN@S<vJumAc;4BqvZ*XZ|qt3%!zBi|RSb}pv+YrM5S zKes3QjmfpO##H}If8%Vw(Ol#YWvl<0rz<#ZgmHF#V^s*uuL^n9z0*hPdthlO;PcNg zCRPPQ-hfeBUp32XOlmBh<FBp@G#X`7a`Os|{G#0PM!}RRlcyN@1>>fUH%bf2rj{7F z#l@5Jj41_q=W%0FzL7V1;zT2#S9==VKgY;O&rHuSa_j5M<}`VO`BR;*Myb!+;PnS9 zN<-eJGxEK&eAQkf<PC=O*G$*<5k_s*Om9h5psL|)U%fXy$iM1flU!ReT63mXeQUZW zPhsUr`q~!Zq|A&63z-@D-lqD-IaB?<P=QU+JC<1GCC|)J1Z(Ow+SFU^`mFRNR=UlP zaj)iQNl$*VZFWx2_Xd44{0HD8$I8E=LD!pesYbi}N-I61XZg|XMSVhn#`=11phrC` z?EHRR?$#!a8KbrQ)>!G2GEXa2LO(xH)zst-z_s*Ofsxi!UtQ>}Z!$`YiVN~eJ>Hfk zrKg^%z>H?PHxwN0F@k~W;kwV#sv8>`n*F}&s*tbIKiua>-D<0<y~C>;1K#1fic)Vt z%1*CtYBCzMLI#yW`WyXTtDdyHdLM<`wNCK{8=C{w-k>Mot@l<1Z8DElmZv)46|HXy zG(r?K&hrL>)IV0SU)(sum|hk1RaXR+6^tGoY@W_nqo%o`VUD5xCY`Q%JHsllz?k6; z<<`^$C~e%F!p2}|QdNUDb*RTv$M-Zp7qokrr>LX~BEIGoPc1DgnBqyTfx(b>D7S`7 z8FtojbF9*&3@6vHsN$lT^aiAzKSQ+MOPhU7(iN6`^Xi+$%9VT_wzPnRt?BiR)iWy^ z8f&~pjp}6m{l8IBNpYU4gxZ?Y&M-p0s<fuYK&YzTKm$T^JoJVUn(gzW3`Q_i<*%s< z)TC7#^;Oen`Mk4@psxWfsjl#b(ne%t1fA>P8EL0wWVkO!Mqg$^?oQ6k;<_o|ZSXZW z7?(Cz`9omCX(Ka?>D8k$Mr0V(EeZnF4HY9ZGBXVMLK!49HZ)aLhbjWTMx&|4R}ly) zfajXV*+HYJy2Ae27^?FIDuT^T(!z>r|120#!<!MTuJe0+H4LlMz11`88X2VnRnw>Y zLWbXG6#1K)L!QQfXL55$zS&me@rf$aaRG15V9^t8Z=N)d?i10r(VmlyQeB~^mLet< zrD>|5<gW1rtESiE87!9|(hfCNH>z>CD8GUswI2Nm1)9AE9W{Ei)&R@VU>vEU48tg@ zw5|#+xR})Fv0M+yRN3sWN%!Q2Lf(d^kSEmWVeF<#U$D+imY$yOF?11;vW+~kM?8)v zs0w#wh$La|Y5OO`tEV(n6>1KS?th5k$_Rtg%IYY$X7p%pi?_Nt<h{tF+|_7LO|!T+ z1}C`<^P_)0DI#yyPL=G{-X_UT*Hn9bvqZS~k*XSxa+utm;S<XWiZG1fvkaGPnl<4# zF)ldG$4RT4+T*&iHr9IF`Oq^>Xy?qU^7|V@o}f46shPt#!%$jZKgWZXd25tMlmWMt zR4oh7l(MuY)HfgoN7*7i!zu%{I!GDxyfEraH*~u%ZKju%x{21fhqI89{kZ1f97BK2 z!+03$$Y+GAf-_y0KVvMRo9bbCxNb#yol#bYQcIOC735A;z4Z7TkJqoX9gYjsH)C>> z*Kc?tDyPiJ;hm-{^+RgaGlL8V70$Oj>lPJZ`~hE3biE4ahq60qKEFo^o1r}5sU=a2 z@#Ls<c-1#uB18wJ2~5$_jp5C~01mLazPZLbe0n2pV|cKkiov5P6d11cUcRQ+;Rc&p zJcGx2G7y5-Q$Dd+j4t4tj)wm%-)hT}oF!F(AVYthQP2_!FtT|pw~bJ1eKVQ^$}M|p z1C0$xa=1=RBNG!X%Yo0*t}{Au_(Wy}SXf$-zqWDs<k@~kyJjj%t8bj)^B;_Mycb$k zt5G8!I;zg-V)dj=9GP*p>JKq97>6T<A0%VBZ`Bhd`I&zNeAS*16VIRHCv7q5x$sn_ zfIe>!VMQ}#NyTciQPbE^MH`t1rA-gu#MHOo90r00nQy2u*O)jtf85m4w6eSsqjXYk z$r<Wf-lX#sN>=f=^@dCqWPXC|YSJ1gKqe9gt=?uWuf8f6oR%Z>W6{KmhO6;Hz7+Yz zw=%cJuTq7c#}r~T^pP^*i0dEj(X$=Hu;)9cK_OGdvQs=tMVT9^0b4Y4jAx7t{q=NP znqv%UnQ574dCnR=x{+C8Rj4tLb`~=ldWlhE+H7B_&Qs<Y>(NY%9$io`J~D)2US!v- z@qej4$8LJoXty`>G;4yJTP*`ufl(SXrq4kyYnZAUHM1K7H3kDty-|%AjGB<q%zYMG z{Fj9mzyeEvHC3&(-crc5R?nZKi9Kg*Q!K}#W>fZsd+bd!E}CXsB<@;Ql2-5a&j{6F z!#Hr6VyJJ8YL3BIaUk}>5&w*Xt_lRI=A_m58ZskaM;K^eTF`eH)?+OMBc&S=HX`~n zOdJD~HdR}MR$WrIjU#lrE>nGHQiMa}tNr)-Bm2V7@!7`bZ9YHn*~#ZukMeuhe15?v z%=HQ2X?*^d^yU9J{miz-?pnvqou8h2ew9!8GnofsY&Bdl%lVJIL!O;YX<1=a&?EB$ zcVTi*)~Z$b!l;DEcrnT;g*W^{-pu5sdZwB^x>>YlK|<lAPsE+IxRv@pm?fyZif^lw zh)$|`gZNBmhzcr)EpueCgW2Bt`ZQ5n#iS5govu>VB-bP379L-GOpj6!vH0X#*4B+I z1!i~x&GlYSO(QE&DI8m<uJcs+=P0jj7krT7`rC6e-2hdkW}cCgzCc8wbeo3APmRYr ztE#@4A=uMWQUwj`Z}A}Xe!3wUoe}S6H7DKB(Fj<s@kIQs2iIK1+Qh30fsLTdbNwMt zs;!Pp#K@t14qZyBu3hC5|LbY+F}V?89Jul6kuk;Mq7MD2^2`o2B3M<FGrXvp;84`j z<0h-BmIZ#A)Jfmi?Da-zjcI=0WqQ(MWkG?hP>EXr?kXCp{LREHLd^lMTG{_}2J!81 z^V3D^X~WMVwWk&ynK_6W2Ih$VG4GKHu@ajP$K2>=aS*WlM-<s?mIPktgnU0TEAr<E zM|w9`iB?Ugg0hsrCS;MS*E}xmVAdS+vGk<2+(1CWffeH<6j(8(ptR_MqDkW`CQUA@ zkg(zT1^HETJla>;_NZpvcK#wiaUm94&ODVlrNoA)&5ACi>xDrNvy51vw*_T{6MGdr zUB(+bK4ah1YwDhN?WQ^RgI;O2&(B;p(8!`ntggWus%xzAq`LHOsC0t9R`#o^6c!Ga zUu*Voyd)t}thZ+&HZxIO=&B?#0%=!n(<^(kOo-uv5f%^O)N-KG%3vdnRdz#@w7AN1 zzUWHY<Q}?IYDYFa%vXb+%+m>Kupq-EWm4y{CbMW|x<>{{ZL`*07XFRR^);U9^rfFc z%<K2aK&CWVrt(A)eYHOPjP5X*g{bwnw}#a<1cU;qiq51HBsQUj`JxiLQqd-R*-nG^ zALtdm45&IRs^V-idH%_aQ`Pd)T6#!KUa=D?Njlmg33v&3s>uERRE!3aoxWBB*mN%< zsIG5h=CAuqS{YR=8EkH?LM8A13*g8|VChF{(Ce=mjv37wN?%6Ggr}-d#O|ye2G1Nd z6LZyOS7Ftv<eiU4NK<{o5J2z9*rS%?_(58rh8;EC50WA-QH2t1vv6@_8E}NF;nt{L zqhj<*lN^6)TeGNBwTb{sb6hJ|%c*nIc2SB6k!6EkqUw>WhiIoT2CC6BO6DHDO46=J zJb(@Zj3z$o=$RS^k)p+oRljJa5<{RzzcXGmGzR8~s3dAO2W`oV=s}O%gbA>Z>ME?u z6Kq5`sVqRm!5<>_<WVtkXZ*!cTJG6LY}JPqUPd?QuFUsU&F~XnU@a`;ILkqzXXKPn zrIXDHT}HGIW+I)UMtxy+(s{Ud*15F78wfOt1Dxu2g8q?PY8wiHHP<s07)C@&?H-IC zt+Bv~q)jtUtYOmMc3pRP1)oRxY~b@ApU?S(`5eBWJA5LaY(D4kxtPzTeCG4HjnDmj zp5e2J&&PcB@Hymn-QhuehVvQ6XDXjMK9}>kfzO}#JjSPk&-;A7;A1T84j;kiBtFG_ zM)9fO6X0_#pPTrs<nsuh7x=u%$6l{E>&L7f4J;rYHOt2gMihB0exv4!iA+$cW_Zh( zqKuWk@KxKlN*M<wP&d{`80CsmtkxS)WR}RSTlp&DFgB<}YTYYso~{ECW3?t;K@3o` zm#Te{vBniw*n1s>NryS^Fx1$DR`?h}2^yq(#`|W88K|f!L!6|c_AC{3Kjs${=l<4X zGz6`%k&&t+eGI=v6AS2My$8fnuDQuE7RSj(v{03d<}lqMKtwE4J9RNJH4FwJXd>Pg zSy!CKCXKV?$+<D-#3tj!TI0m}`WpT<^8uUb4B4QSzk>(YstHciR47NO!fQUySrT2F z#c+&9kFJ<lK_F*_x5DR#wUGP1zEe@v+|pYW1Vt*uW{3xQ1H)^)e5q&LRUtDbL=rTK zq^p{BT+egTNuJ}apscPzJOLgKgZDSr*AG7aXV=E&u(VC@GFidHP#{>5&SH*0jEW*6 zUIO|Rp0j9kFM?`RG487R;r18Bsm%7$&hiBjiZi~X4(%;}R4a$eRgi#&mk?A%RZUfs zY&}U#)9)F>;3$QPbEl}mP8HJTRFB^?6t~X8hWTV&fwQjBLDd>xjb72n8mLMyw0=%# z#SZeZHY(AvP}ycYS;p1o02}FQHX<W4gCF~)+CS3`Ee-W)*7_}|xS~Cc;xjZmvr%1{ zWT^Gx0m73MflUd$w2Io9Zb<l8wzNI6lOgjVDTFx@^I0YW#v}ycX=)^%1RX2Tlbf1@ zbrsXAs%NGSW%EZ30J5}{5G|_e@q5+$s8Nb=^%IxOFTG6D7<UGXec0pGC`S&CbxE>e z1^c495~UJ_CIlFzV`IvOdGbVC+0mBiSYv?bUo=Uo+U6>v5t7WVsDz~K%b`|WFzO~T zLW_l2jlLRXILts*_AwO|GyKgJ)h#VpYK30{PW2T|qL7~=jw={CMWSJB25GY%qf)F} z*37Xnpzji}^qe(J=jtUkNmB1Y%bpF7aNWD$4m1>uIk>oO>!DRlb;js!cLz`Z(}r5r z)p@I$D%3zz;RuAj6YJ}FdyLvGJj;pFYQLps1!~rur&vSQGKa5_rL+?;{trc=OX?}v z1F@whS`~_8Rdo<Tt1VvLhE$~s2j$e(K*Un778SGICDN&?@vx*C`BR<j40crfKhs^& z))lG0xBjzwNR-{Spx!$m+CqCZVwP&DWvAHE`M)M08|Ib?l$~Tt*OH@}OpGZ*{p^j8 zX&0p;`5IqsZAIwk?0}r&7#HJj*(pC^KR=`UnE&DN54P#j)5;>M)w|C8|7ZOApOEi# zLSLMc_`ecXPCwd1hzC%P!E!bBRMMG4I5#-d<W+VP@YZ?*YL+OOZS%6}6p5b0Ml{;x zHZ3RLn{Pabw>#i;z-@~%AL`kj|4sW~K6M_$cS$Hv>b;b?NA&Q|2;)e~7Lst|xE*Vb zEhBoQm|jY8jZ^<ewN6$8Y6kIBmKA9o<JQlg>Gc#vWY9Z^KkX?YTP+Ww&(^eEHO1~I zJ6n{aP&?%RFDv!`(tfG4+r+XW%7l8#&sj=1rwJ-JkKzjjqlW@pZvW|_gH!&~GY9s1 zC^I9n<?CJ%P0CWENM`2rDpn(ULDoz9h%;2WdzoLM?Tk=uFZ8EtIb@y@WFpRaI%3%s zK8{pWG!;1<jc^OKpg@;m@nh%Da^;r+)m@bgUq%o5gVpDjfK?m$dz}Bx%wRI?I#RrU zy8DRr0e5m|>(j(m$X9LPTG3xUdA1KEHE?28*0gf!&05P6C*fENkxsSmEnBQ)u{av+ z;mnns2UF44lXIIxM9d`o35mqqPxjQ-SIw{^!8*_^Y3@KWkrx)zDhMU=>(PGa)b;_J zrq=A%(PsCN=ZWL;oPe)tu-aQuG3H@*RC%=L#EIt<HI<Vm>Hr3@GS9@u8V=Wa3aqHB zgsgkZ<u2co8rcU|YT*2fXqTJ5z;H8@KTb{%3`0ym`wX|cq3WDdkG6W$&EDFeE6Xb( zY*8y)nEHGr_2-pL-S3_p+>eB@9a3Gm)yJ|olFBI^I=nt@#84|7$;O17z#Golx0%BU zKFZc$y5@=lG+acL5h);Zs3+L0_CITz>w7EY0Qso+XXJ}W$>}l0rFBvpwp5Ebe8iDD z!cJbdfK;D4{h6g0i4<7i-d|9AA%@y+vQIP`B}AMFWD)3%9OOm(T1STw`>kh-)(Co1 ziPSRR6|1QonyyZcIomSq05x%XgxJ{}b~n7~o}$pnK{;?d9V6syst)I>Q=?TJ_>gUC zHW=9zbnRJNHR`=Dp-Cg&)1d1&CUNYcR|X|026H~y7*R)4<&@?WubjyH?<uVcsYS%6 zEVQ)e8D-6+A-gz)PYBed8=h2yc^VrvRy#!f_7^w1^i}>KX9px%x_~nTnhd4Xs;ENf z(_}ke_86U>P$QWpa&Ir%Qj-lXof?rTC&2CGDoLb>$aY`kyliQRL#J-x;;`6>bOtF8 z2gG#5k|Ok`kbV@&!vR#qmbLdao8ed;eWqe(@Wrd!4c2i}_V*(XfOx8#+1~euP!enJ z%i_yW8YEg0B?b4%XvL;9E1FeK$3$2c8e+N;6Re-3dd)ehE?qaZiL)i5*;1GUwwi;+ z*}ecC$5nEghx3fGNiT%<<~qlr^dUC;oP^;ETD9ZIM;mgqVj^1w>ZpZ$kpczfb^TF) zj{S;XwYG)bPTWpEgJd}a<W7@<?DW&=P53V`{EfyOZ_v<t?k+bl%)@C@G!0*)hO^Pu zlLy>j`$eBdSIJzdQ|+2opG#HW?L&d;VtR8et2Wz5MG95HTvrQi{xUQ5gAR%>S0kMC z43)EIveUk7`p8P0;+5GzH8X?822o#qAX=SFnJ$Ms;O}QR=blF`RpHv|f2#ChvYA`T zYDGyxGt%QS*CjViz(acaq~rNhipmPoCQmB<tudt_H{bP5rD&Z|=W>)9xxOiFvU^r< z^vI(cQGd2Pvn*l#FU|KOljW${zQnKoyHodro)>mcg)jQ=bgzCu#+qoVlSHluvUH;3 zg55H;<>@^47A5Wfwf6phD_@@XQ5*WsZgEk8bz|C;v-9K}K>9_V+Gf9YXZq}#O;A)Y zJVL{wC~|NzH8@ls^%<_uJQ=RSdJN}!lG2kP;@8BBI)2|x7VTtY3qZ!y;jVKq;#xQl z?P;u5E~v(xTXW%dQ_};DGkKh(2dDZ-qHN<uT5U;%EptSN>k&>kbiu~98Yw-EYzA{6 ze6}$SVQL9Fw4BJ`OpA3g#6_TnGfv(*N1&9avQCm%yB&zam7}4N88XlO;Hzr9!Rmmo zi7St4Z!NVp@bForerc|2D%XTFX67M}bMzpRM;ld8&pKJ<N^Yw11%#{NXBWuhE!IY; z%+6$Hg8W%prK@wd#x%$-@;KuzhY#e?@2qNhfZ<f{rA<TagIgA*oI+NT-cN$6p!{(* zy_{@=m|kW&qt7bN@-^~!f|89Q7DYUOYy!?nDtY+As@p{?GqC_uT)oL@&)*J0*~~d< zwIRA6Ev!h3<m6k8nhDFgRv+J1&$U>U3)xIBk4|!!hx0z}nUuAfu?L~w=BRHAU(7kd zS|0kEIDYS$G_|<c$jTUDgsPj2{&-$l@@l;qtyPvDvUc-DSNyWHkZ1V3KbzV<&Zj%a zXy#|e0#)+tre7Tts8GjLM>`K6D&2678l@X22K(<vTV3TpIiwDstIX`f%cDHgIW`a> zm1;+`A!l!y6GvgSz_AOZZ=$HKLs~yOpE?j_*EOA!1r<R#z0M+0pFy@8YYkkzP&gc0 zBs#w#lm^^|D%b$`b1b=fmVUs*lWIMxIGoeQ;*VJ6%frDK1Q%*zVNYgi<Uk0;>JyP9 z{fya-da4>did3jvU*xj)`fc^<l}^nlEH;@nI-FYH7~XqtUnF0o6@)b+=jsegBo@CB zdAJ`6h^BGMbdzXRlxcP}vAe)XTqK&tRbYe!<FfsK<{A5Or)IHE`sr4>Q;?qI+UcW6 z)-}2&zpnC6w-e>`mc`mnsmOnz2a!^(Deg~I66xMZ)`ROzuXK(y+^YSPl+&$ge6NI& z-W)3N7@IcIosug;<W`Vq8izL_VbpAvLtrwYjwW*#g+Dtmp{u+ebZU^+|7?9w`V`IS z{`w^8PN@ah94F@0&>+uisW0j+3&Wff)Z_Bh^X$FVmsQ4NDtWnOQ>=6QmKr+zoF<W` zIXzNc`kzsH#(s$|{T-1}><fkJy#+jiROOFQI^~}+&NriHqAP!9rm`RXOaZ+0`Bm(h z7yimHE@8pEcXn4ed5~eGT-g<#3oZoP<@&0wuqoGI>aV%Jx+`1)t_Bm1<Gnc7Ku;Oj z*LH<Bf`#B#ux?&gI9u|8<zOe+LcW&y(18ipb%l*%4Wk_NfNOt8xnRmd=)l$B8gTwi zUEwC`Sqv@&Zw6O@&w*>fo!}<$=$pI3d%-*~*<%<@U^ch_EC-i^E#M=d3GQCn6;9!_ zR_!g+3$6g?g0F(SPR@Ab)~@g_aP@7}cf4WLETdiEEYLW?FuuH<x2A%7z;bZ;9pncu zUQT{+$4cq}D_7CJA%?N#UhY%xG5>`eDd%Fa96WM0?IS$}TnG*VSAc`TUEoA8;Y7oj z1A4%FK>3lcH^54;8(at`-`5ph4IU3}1V@4<cn6qzl3|>5KlOl*fElTVG2j96gCig8 z3NHg+c?dazhdxYwLuuDz$Pc`g_wg(Q-v?KN?YwtrFF1}DY89SBKk_cJweZ;_NcoR} zCb$VqIGOhG2D)tU6>u(C#~UBlf}esWxSAK%byCis!Cm0vV8W^V0wU-EH-JmP-Qa3a z-m=;bP5@1C7HAAJjFq5=Gp%dE9Po9p65IyP1^0j}zyw~C+zuWCZUu*dyez~x3-o{` zU=BDPtOP^gTyO!n3H%&P&44dn-B}67bs#@*(niw3S9vdSLZ)H-$a{%%z#Dk?`$Di2 zTnpy#0|mwi?t{!7jUT}laQd6*JNP<if;;$8kJQt!Cw}q69Lby5-s3upc7F&x`1wb) z2Rv#k{SD@TyTD7pl+z7kDVPJc3!Z@;{*!d@DKICS_Wz4=z^lNm;NoqRKMFhkl=gzl zOxiJ;`nN*|#_fQAFa_KMUa%ATGvW8Eu5cZ=6*R`6zk6sG81p^)2EGoi1|R9B-m!*p z_%Xcp7hL=6ec^@lw{h&ga66a`X49YJz;f_@FqMA&Qm(-f$3YKH0#}18Koi^zrluK2 zzGq*!4!j>+1|B<@bZ`V{(9ikc3i|JAFqwY32`opxgOBGvxEeIUi}~S?4CH;xkbU7w zFylnh!B4<S<XOv)<g5U%NZl9S1zvE<zVKX;FSr`K=~T)`o^OI{z)i#Ug*PG357KyD z8**El4nN52tl_i=yf~BggMktI!h4ZZ(@4_KLa)ITa6Xs;E(8m~#b70P6W9XY3N8Wf z09S)6!FKR|uoHX)+yy=bCj18d1U=vfU^ci7ECEfh4m>i8_JBFyGO!+O2bY1J;Cj%= z!Jfesa5tC@uF2jPZUSEimw=yxYrt-B6PU~|rSAf}z{*_1=sOzz!DMhFcnr7|90KkI z-#n9ckK-4C$I>qFCeX;EeP9YW={N8V{+L64a6m5Y%18geCh!z+A(#zzf@g!fz%sC~ zfbkrx1Vi9ja4xtBTnu{7roCV`xC&edJ_4=)+rhoyn_$U!!}u3i2VS2~d%?rUQxCYM zko$$`FE|(M1~-8NiqJFg7%;nt_JSo~I#>tpm;k@vUT_!K_ndv<oC(MYEC-JPo4|MY zE$!9d!b!*t99e=~&M}N#=TaWHvJ}3-NmJ=Ru>bk+4X!Ik?#1*IxCz_>n&9;p(C&%I z=|buO_g+Llf~zXfn@No8pa)zJHi2(~3&E|R3GN1SCS&)!;Bg5!09*|o1sWyzA20<x z9jpWM!MWfRa1(eTXo9t1&bjmpSPotbt_Bx_?clATXNqCm3uc3lgG;~{z}4XE;9l?@ zFu9cWfpy@Q;9Rg9+yoA&qCW5#FuRO?087AhunycYopi7Z%$W*(HT;0<YN!vKUW?v= zeSOq(9`c(>ez3TK`{2dkR<H@oJ|F!8OTZ=IYH%gk4n78^lp|L#1KbQQ1V070f_uR1 z-{QCY)C;D7CU^>%bAe%u2A6@w;4bh&uyC4T_`ynWF1Qw40&W6VfT<Uv&tML?9$W@) z2G@Ywz=Vqo<6F=J#x<fZU^2J_90ZzRI%r(XI02S}C14X+33h@3a2GfqEUCaBfpy?2 za1;1AXo4HT!b<!jSP7coM({^4wF<p$qF!(ixC<NxmQQE=1lNL-Ku<OGf^)$p&;+jq zjT-6&E5TJ@3-}ng72E*s1v|lVFZF`F$;8+Tc7h3)QXiNCmeisjU>%qNZUV=FCRhd* z&R{$NE5Q)h0;UI%CzuUx1n&(Y*E+_3Fb7<D8TEnw%h3lg`)c?BGp?mPpJ9xdM|;3x za0PfV*bZL8YjpR5mw_plU>9IESbiPlfprU@11J5C>zU~760X5cFuC3^9{fFgk42Bc zRL0rMZbrUf_ARuJarX7wpa%=@Ko9e<pXJC4EdL|*<Rh0q!4J50CG9Doo_lC7xbeRz z7o2q;@;V!NJwX3}Pd!Av;~AgUP+uYX{1@~My#G=9r-*X@N_pUbCn#?M^lPyL#-sA5 z;Y-G+XOJJ`(2D1%pK+$_dFW-ld6E2#FD?9xKsk8QM)(HJm&wmKvixt<15S7iI>wCw ze@7l*`zHDqtb7YT87IuQ$p<cd7ycLz&g13%%fSBsARqSsI6peF0xbK8YwZ2~e<ByL z>uvM{`01y}4LiPKJLQ7AchY~@?ZPj~2X^m*4qW;T^<lUD_t4+qioKMFy&m;%_y-@{ zhrWQv8{Odq>~w8Rcen*ikM9nf;QD^u;d1PAbpP(~MsU*rp4r0=&ra$NuLeIjtUH{7 zy-hi?JG>D5@+iu|zWl%J4$lSq58`<`?CSbsDHl9xaCdksc<%|_;T-I0+)0!JzK}{j z?CRoEyTeW3mNcII124;<zH01pM0a=@cxx8*VLwM@cZZjNkBsgPCu1)o#!^4{`fn%) z`<OJ2`oSIf)Q=rpGQK;Uik{yA8tCQpBFY7aozoqzL_f>Hh2XIhyTk3^HgGSPF}XXO z(LnpbLNFh!1XqGfz{kKfVB)#m;a%W>((bUwk6wd?;45GYxUr0Og8AnmS8(ia;inOM zn}&SBabOd8Hn<R+0ImQ_z_s8%FGe0<Vg-DGgDNS%iT(iRf&-?*H@FHkE=7Mp4_H>+ z9WDXmYTy@q4BP}(dXZZIoIyW;4}*2!2jCJgp^kQeBYm_Bd<0AhqQ{p|9{9>k^Z_hu zpq>zN1}njJe)<V~9b5|zxs>*ThX-hHGyVWvNWN`g3D>6wxdvOnwcz8R3GM|`W+C?w z?F6p?TflYTYOo75W}{EDC<nX)?BxDta4y%|!DV2|Y}x_lgQ+dNr50QPUJq`ZgS~=t zub@9$=;te$kAsEavtT87{T#{xH(!C=<o-3Z_bS?TE%k!W@+|8LaLXd(1a54jT<Uur z+zM_1_kv%5$<+HLm;-i$<zV6s^gDPsxDY%FTnnB8ZUWB&P4HaMfZt0%54Zr#0at*P z;C)~VxEovpc7Y~1<wo*dW*C13v%z=3axiWQ?FP>Smw}7Hwcv=Gu%FA}>t@;qjsu&( zyKX_hz&F9IVEQuTh1>?*!F|vJc7h|oz2MnkGV&@1Gp@!TgN5K4uoC<LTnHxIiTuEk z;70HYa4)z3OrFbp7)%A%fH~j`U?q6Ra@q;bUkN|pLU1p*7)-tfJp)t0rC<*D7+48D z1-5|g;1X~HxEg#FYzN;2JHc*n7kJ9u$m3e%1ZIHOf`#Cp!6tAIxB^UAMSk!eFnJ#J z-%q{ZtzbF09Bcwtf(yab;0o{|a4q;AxCxAZfPMor!Q}adaS@mbUJsUlZ-RTlZD7iE zwCf?-1>XE;+5ukm82w6m7q|v&=S9|?-2WUj7GMvLlMl=XGr%UW99#}Ifg7Hr9pJ8Y z)c-r?sn4J{;G19z_$jyq+zYM&-*^`JgYD~~Unp@3=)shi;1|pX>%b;(3Ah|w4R(T^ z;Gm7PZxQ3rE0hoZncsYE2QSz}dDmm#Zz6B77_0+df0uf}V>+o990nS#%s<|vJ>YpC zArG+RW9k9Rz;>`4>;&h7#$xmdOaVUtGr)vx$N?M)Hi5OD&_Cej?eq({7u*HDu!DSU z=-E#C7d-EC_yRp&&_3{(uhC<08JKVbe&Ac=0M7poI|E+_H-cODVaGS(@4BfMYyw-r zAHwhrn(^UqC)f?{0)Npr98Oqb7^6TB=moRE--DIlGhhq216%=if$g9<fc#+JUy%Rz zhA|NIfVp5c=m$%{xnL7GASoPP3uc3xz#7m5mw?GPG5&(7pb3_M$0U;vOa~W&IpAur z3~UE$!L48mXxxlF9Y($2`Xl(sCGg^-C?6~w1mDzC4yG(cUSI~e1}p?W0Gq&sUsDe_ z5?lj525to(KMwj^7+*c%a2>d9Fy(<y9Zx&JSHWH2<Ega&R_u6aI9v{vq{A;b72FG6 z118^wU4p6LdteC|Kb&&G5#SOqA6x_80d57)%Yg4?jQ3y(xHU5zUIxaUMmqQ-=(!!e zABlYLq@Ab3514TV_m?C0Z1RB@j-q_f53T{re?xvSIS0BwAP2A<%qW0w@UC-^Gko_g z=04>g54M13fy=-pU?;d4Ot`}^swYwpxCCqgH-O8)_DR$O4w+0l;A`}`v=>aCf?TL) zGMIc9{R*anzXfx^0cG?D_$9az%$Z7mf|=(*|3~x%%m6ooh2V(uDHpsFoC{7Xrybx- zupPVx>;xzMmU_WXFlB{dd<bTMUxS6<9<UNjynuFq&rG9!u<j!0|3v%<%m8CAMlRsl z;9T$)a0U1g*bY8fLA$}5E2$5>yNdR$#LlNvE;zUvdhknd7x)&x+?8`T`s<^gz;19g z_|hem1HL|!`d6_YtA`Ferh)c?mEdY{G1v~S1v|lQpm7g!_LC1B1LlCwhA1Dr_;UEU zmwEIRv;!OjE(14$8^QO%l>b7XuS723(5v7ZJaRtyDSrsKm2$Gdz2L223;9-qCRltO zd_ms=wu7s{PH+=wtY#bmQ^3>(@CBAErd;r*n<y7N>t_1-KJJ4VU>8^kCN4$Z;N##L z@S<Cw2Mh0n{(kfbOa*TM3&BUgN^mDQ7d(17?F93{HDDvy3Em0r0ylyw4`6S9M84pT zmDm+H<!;i!wf8d4Jjgh8Kl%v{dw_O=P2fgwDYz9}3+@H|55mtw$Pvr|Zw1T2`@tsg zS#Tk^30w{S3)~2P3z}fUL&)pT^beQ<ri0mF4p<IO0b9U&a2dD&TnnxMJHe;Gz2Igr z<zeQFU^dwKDD4A32N!~eKLI^xJ_(;|@JnDhxbP|D2Fl+c4Mv~KN{Xi#eOi+H#g<>3 zW5oVyK)(d}O^G3-%cruoD_j7^t-n3r$W2V17c)N5b5Z}q<lMxBf<vRqQN{FC#n`2w zV^%qJlrw<u_TMnR%;zKJr%+$qX3C$qIBs6wi3{S}Vv7<pZitDg@1K~EOC|gXFOTur zI;|@_Fdq6Yo1aOEIk8v8YL0Rbm3A@I8>ut8!oLJH&!ve8@|`~^r;CrIPXyyS?ufL@ z8)?@V(mvp`q_QjA02<>GliOkn6H^w)<|cX;#GRd(IxoH`F=s~q#8htNCZ<3z&S6*8 zGl+JzlYgP)pS&P$UOc?E#Vn4EDR3Gl_2fgBTJ_(rXFmDM$$zkVq}>k+KR-cN4Bcia zkAA^rsdnEOGcGaZhS+h5p0>DgiK&a@^Aj@`^vzAop4V@DVoA)z{)ySSi5a<xsZc-} zC5Vv}Q6IxtLV5G}9``QthGKC{eqzdk*n&jQyttVB{)s8*R)JP2sa5Ich2%5nr%7@n zKhblcBQ<Q5TkA>BApLwWZWrZFT+nx3zl#%>^tmzShS;{a#qlwBk!8GSkZM14mA<a< zG%3&4<r-Ua<R)_lK7(SJn?cvg_qa)S?$2-W{`{6fTSmTJ<a_@R^3~~lmh1{0*&!)Q zb`uiYV`4kvdX=7-mio)*|AWF0dXy#Yj9sqyX~Pa}T}1Np=#v$FVo&dbI_A05G0!e% zkX0V`uI=>B^vuD={&qSb*cI+)(Fz>NM|89+u>XB&^G@zdUl`{kCSQn^34J}EaF6>U z|M`55pnOG-{1=El&5J!J(KA)`KSPSj{~&Zn+jLgBl7Bs)Q|<c)$S>{uoKFUH13{xu z#;jt;{v~|?`hC(t(ua{g=pgA*Y-HTL^ONBS(w3yOO?W+aL09-pFm5svTg5B-J};KR zv)*Yd$x4q!jxQju-%xMdaGU-dq0dj8+b4EtpTv}WHR5Xh6gj>Le?c%#CfLfJ7=ji+ zk3C_YF(v(#7ErSul!UK1^d~XY6&}rZmkly}&5LVPTtO>o{Ed_k^eNDvDmNl+I6KjU z$&10#VY!FWuCp!Xtb9Xg#{lwu%5_`^6ZQyys;=>goBG7O<KoZCcOm(nBHtd#_jGUh zGGewRdh*<?O1qYlZ^wLo=SlLdvGb|%Mb$UQl|g9ML*EVkUxof=O@D)oacwdlEsn#U z7RVSkukZN8oS3DF8To3AcZN2yDVrF8e2nI<@H#1HrY@&V%CUTevdi&w#_DJvA^AlQ zmtxmfkpFPGfjHfII)+;^Zu&`|4Zm?G+vO{}r=J(l&)7X9aBO*>{VEVU{Fd_XoyA_c zlyCisZpyfMEBBe|8F5EauBv-{;@sGnJMEs7{{I}hBWHJoUy%B{SRh8mZN`{+apM!0 z^o@O}PgF-L{ioi$TDroE`;u=T`IPP`TQ5qijGf)rRvzk*dSu-EkuyBaQqKdror`5` zu=M%d#HQGDqpLBB$+wt%*>k(XSHWkTEJ)$+#+ZU=U!}&|eC?~+`^5e>CNZ0?rEA>I z%9^JzuUI~>D@?J@pU80x_vNfmoO4&xmvKMDeZcvX_SAEukTW-Rau=T3gr~)#TUMWm zflf$Fr4yZbgVeK%d_yTuWau7G*KvPrkNeV(o4J3keLo`O{l?QS=%(6quJQCp`p0MA zKR|xb(=pKbp^NBgi8D?}`h}!d9whw=(x)6CUG!Y!m`{2w-{VTPp0&lCEizMjuIwlu zQ=GJ)nj2!zOUZu;`4>z66LkI?B>#T)EQK_v-e+KlvS%sh1IqccUCz!MRp0%m<tY89 zy=yp&C1u7vs>`wFJNu1CBEK@|*F!Jg<8FqY!Tx+p!cty{^me<vs}EkD)VT`!&Csjy zt-@}{e>T2}9*<<;7{?hhmg<%sN9G&_*4PtsmE9)=%GId$Gl5u5zAMQV7rw!=|03<r zGGd|}pzvD;y_{8hLFm7N9-FyAY^F`-oIS_mKlM5uOTEh}=dx?N!WT$69d^CS@6z#? zyL^@&cV2~l74#>oaYxr{^%Ht0<J+3p*u$a+9+68Na#@O=+#>mIv-2tctNM3B;*!|d zYxmDLhJ3s6JGqkYMmryJvBtUaiS4nmCq?H|{ZGDsa~5$2`WbhX-7af9Es0$o?`l~w z{H=oi@z$>J3aKYW_rEm{Wel?B@R4zGlFTteeR>}kMJLDfCwA1P^;!FhIZUey50&|v z)ORHF-BU>aG>-Z{((Q7u8PJu*@saw@O<WTb`$Syt^+|a(l-K_IuJAQ7u3v8Rk3GBB zAd&JWByNq1oyNG%t^LMz8DAcwyxli<g*Wg$ZlNyE^3#l!3&h_mKN@pS^q35}@=x+J z)T!Teg~!VcHBQpkGB@+gawI=a=0T*1Oyp0-^AP#6$(N+==zns5G50s#7VS6W{wnT2 z&V5}%gnk|O@8v$~>ih})X71nGgI@Y;75%kocUL%*?{QDiA8^VtM=hmCa&N!@ViTm- z@%=yXPx<6ar@mp5&o$q_ko)6$+#do-i2LW+_YdG-q#etlyTGP%`KQOY@3-$CApbD( zFGUWQ(VjfM$Gz3&?jz>gO_9kn=|aCA`Wv8^u_x|f=p*wQWxwwEqR8`G=vP87-{WqC z-ZegpejN#)cac6t(l58mi;M>`xmrz_T^C?9q9)EnTk@BYe+~K1mHgv-$)9uZ{7cFI zf?fX+z2rYg{UVRe<ljtwuhjq1VoM$_{(l?cxmaj^L97wI4$1eoG<~o0-gA2dM+z{K zsA!3{ljVu%73Cd4dG?>k`Z4aG!u`m+BYGXTne@wUvDSGAbzV#)&LjE1CB5k&=|^Ii za>iP%6MM-&lJpBnkJKMM?<pgF(m~Qgq~{zYeJSZ94wC*D=|c{ZzM1r+4wC*Y=?Mo( zKQftl_tFEmZzSoTA0T}g@*P0=%fGhPx$j<Y*`4yY`>k_D&&NRjXUbE0_5}2ixiNO< z%#C}U=gBy+9)4y}pVAX-a1vv!jAtUpb(H%)-{Tr}xr<{W`YTJYjXl<llJ8aWU5tFj zil40RHD7F6v^!Sy#lc6-tzF>>l5bk?`LfC9UZ_faW5_p)@l35(N_)>&AG3eH5c$?I zKT4PS&gnhhpdR(f*!Cd#9$_7Fv-oAJK5L!ZV_r2Oac)d(b6hVoW9jE_DX04`+ROL2 zz0|M9VryQNaaEMxlX{07M%>_!+P}ngYJT18YX$+=`kLOs0iys>^Kq%So^rA&XQI@* zqG!F*!7ySuT&Z_C^yfi8Q|RaZRJ{{=tylVK8|7SP^Di6A%0K)+?0pG*R7LWC_v=?P zlVrkWxHKBT2!a6-0*ay{;DxBDc%!1?&8oYi>wyX++~GbYL9PfW;gDO1Tt+~MAQ}NR zAVNe$RFH@VN#_5pe(xnSZ)O6nyZisGALjE(rl-2Qy1Tl%y1Kf%TJw|E3wagM!DV0J ze2EYgZ#m^BN6vSZE1#DC$hRB$&R~5<S^4ZWBgkUwC!MN%q>K$NfqF$8)2R>xV#TzQ zz&!{D)fIVRTeVDU<?{{GDG%kf_@N{)0%7yV!8(tvZ^O2e!FGj;{&_JrOy6dcJmc}B z+!ugnAme%O1bF@t9Zy%_Sq?mUy)wbU^T*aJOouGsX^6A_xm=&8EIhUx(EVn-T``X_ z-Sd%tA=1~><H|}OJdbJn%5@MPzq@BGyZs5U3mmrVecr!TZ{7dEbH`NJ7fkN|@Oo(d z6k4uF9aL@&wKLi=7WosiO9G`ZT$sH>>QOPyp&X}qz(g@>J~m6-L(bl1v22$`z_)2u zNnjfD<1paUb0aFC)L6qFamgsRYc0?LcXk>h93&GU`)@1Pxj0>Kq`T@Q(q$vvH7AiS zAL%-sAYCHLEk?S|NXNXvI$N626<Y9BaaUp9(EX2z|7G-lUqqYIp*z-9w%tMZKg5J_ zx0~v~i#&edUxoa&m`+;<>2VZhe}b*2e6OUtD#kJ^(lSNk>jr%3nBR6YKdubH=UTVf zdoSHpZZv${z8v6t{>_rW25#Rh3!ly37!T#^p615f@b+=PrPhI+8G2z;goFCGYn6I8 zm5bhvi0X!PJCQC1^=A1Kw$==$K|AA{NF?C?$_Ad1sP6>`TRiuKy_&N1cErC3eXt$J zYnhBW$X+`?SuwOZR?pKpwQ<%P_`2h_`7WeXg&fzik@bQuA=XPPUlH>0-LwZe-?+&6 zZgJ&f9!o_1PDlO9INwvqr{_t`8*KM)Zv0SAG{iIAIwSpfloQYV!|74Ku=&{@w+lS# zCmA+uF$RHWEbw%jQxf3)J@al0PcR==tiNr(!A?;+c8Vf!V!0e({yqe}3vdUoJJ+wZ zgBNl+Y#pxgLb!O;6;amVsleA38?wKGPvW?qjVye@_Lh!Sx*NZ`=*oQD3;71kD+$a; z*i5wY1<UCUyngRgWvVj9hY4!#m&M4Rfqp6E{6_}__X`*KNpQb#c|}OS5#_Dq^oNih z{SsWBEss%Nc3623oucO%=->Gz0S-GKu1DL`u^s@tJ-2^ONIg2Ssi~!`s0ok1#lW)w z_3qC|f_bT)VJ%Ui`*3~70&kNA*bg#+_oYhetGb!)3MV3eBL3aGICvdUvCiUtD+c~~ zs7Dg>!F&t9ZJ)QtQFrBo-fAgima4(^N<sa{{|q{Cd%tn&rETFAdJT+T(l{QvYsq=> z$8_Aes3gGlXY(WE*EA@%d;Jh>_u}%hkiO`hlEBvpn~#U^Nrmmb6O^|NZYo&gz7Y9` ztSAX==KNPV{HgUm<WDnsDp(xaOw0ZS`kjTlr~9~`=UMq|eG2)4?U&HAPg9dUmCU~^ z7kU8SKR~zROt&w?@nK#X!1grWpIW0>6?N}WT@lCQHwSngUt1Em5A8C4vG4@j<@8=Y z@RaXIAFid^oe@baSaPNW_+Bh53Cv_YV^D@37s2>&CL;K30QR?)>S<IiXLyWcorU$y zEx3z;u=8Q~V!$88olSCp_-1%M;I{#e<$d{w;YEOV1{}kn{KN1Pz%PmbPe_8k69In; z;58zo?+ADq`o)dE8{h{4_m!7w+y4OnJOVre@J$im*?_Nz0M7;dEx@%M!Y+f`RRDN4 z;BLAd0z4}M9<v_gAmHx$Cj$OF;5_Dn?Ru$p`e1l6l5_@qs*}EAOor_{^+GzXpF4jB z;L9C&CHWU4T`tlE_di%r<O9z1I2U1oy=Q$U=}t>AO$CVQxDfHHSYBP?ti!af;LQ8# zP1ib`@g~;?pZr=9IFs?BUTIMLoId6Fj)-qvNqi5)ry^eWlg=M%FG@#z!zl4w?{4+5 zZbtkegv~{kJ{oGr=zgnf`DocckT0W4X<(H^zGWf#?0wp&RgMf5T+BZS4KR10yjX;t z55rRcAK-#>{YvV=ZhX@pFQ+%~wR7R)a>fGQ!UgAYn2yPS&kb*nUdLUHP2@?g_He!| z<eT)Hoo`<V9irxIi+lyhxAErEz&Hc+s~WQY)_StmFRteEH7^+MnS<NW?QGcFe-9m> zjF;)?!5!BZ7_V)&vDfv%ct=WgPei<nfp-Y-!c0~E;dZ72Z$H52FntC({H^CHyT7}u z*CNm-7x|7IxAQGJxqRG?V&q$XTWMfCx8uvo=<{O4cJzkOXi^$ZpU!CCG2HQek@21} z)Yh}Ke&C|dy%F&i0B=!AIDN8#x6a+Af%#0I+bz7do>@*GH~(-yCZ7Y@0etc0)VAb! zTfir|;M@;>l;0h9lK*Hq8Nhdk3m=!C4fqW%IMcru%9)Kj&zk;rdm``=_%ky7OMuq| z-e5lB@)8<iOoJbS;apx3%G+|E-7hcw@qXzEyo-U?4_wZN%S#7*whPX5?27vByuUOs zkNay%<o<H=Gvg}&z8=6A=M;i(h93g_4i}uu$wfJ5J^07VY1;^RfzPdPbOk)t1!wvt zbG>@l{bjf3kMvg#@UDp<PkICI^oQ+!`QnfFi-`&IMVCD3i25=e{{i@H9*4Cvg4dy1 zf7SXX*6^%vLRbwnBCJEX-HE98$KbO;jORfMkG*bkjpwJr#xwU%H{?G(0R5Z!V40Oa zbpCr<t#rvXE_W>QnU9uQ=ajy2$_<kvPpg^IExt9sBsRuAqX^eOQvrY21?PG)9dCQA zG_aWKxzDMm)-THC%M@2VnJ?3UuOaZc<x3Xei7q&o(-Y-Pf86F*yInRt%FD@$P|hLX z`y6zP1rF!K<(o~QJGtOoP65hU1$ZvE=ev;hpx^i$M0X}#$oh`+`BBaS_!iJ~NE)X3 z#w}+f(IEr%h?U`V$Oc@v;9O2GlvC2vro-7zIid4iBsvrW-zv~G7C4*_)4_ip>g|Ga zIfW=^I^dcPjhu2SY)sMUkbrU;8l{1SOuxIGe7b(+^mEgJ%j=AMQ&p*Dx8Z%|F#A+@ z<!%?}OGmy0vg^6p$#>#<<|5xjk6q8BPQDY@lj&H)XV<gQ@RP1*3g|o_#;)h>PQDY@ zvj_6U#@Y28>g21uo-D_*kgp&3WHQU2)mFaXb-0#e9m?exCQG*&+?qd9n!;A&FAZ65 zv79LZ{x$GD(Vy}EV&RV<*C8Sw3zKimcj>@;4DAY@Z@E9arr_=n;98%%a70A<W=0r) z8OZlQyiMOnoO~yyZyxgPuVT|T)5%vkeYu_`$k)A^UC*r{`L1x}gu9+hw^X#d%G0)d z=3OUkPdj<}oZAdCzIwQPE&x2k1?PHZqrC2ax8>4tr=FTF<#N+K9=U&#&&QYqzIcS4 z55wC6-rfage)FUJoPU%CUT1!=+f@m_y%de#vVi|E=o-AfXS($S{)6zzF@W)3I5HaD zz;BO7<hNqreG7Q2I*q|M(<cvj>-@9ST3`Ls!t0(_-2KRO=-3?gB;bn;!pHD#fOm7j zx&A3A|K8{Aet#)y{iDvyi-ETa@K$q`mk+qd1?P4#9T&V{_j`G}PTcQ_*l<{1HN4+b z0nc^8xf~Pam%vAgUZ2|SIvM(<1K*3l=cZp4;5}V%-Tx@3eQ%q7ua1n?|552z47_K# z>d*b<Zvi>yf^)kHQQp{>ZTgkB>%{cy27Dhwp19l93-CM_oX1T^)N9WxrGY8T*LJ%q z88^M7jhh1Ce-ikE`J3B!2=IqpaHeN2%Juav4GiRRr$nVE#?uoK$5Y3apeOM9fy?=D zdEEf7;es<gQ&5k3@QtJQWj0vlx%nj0Iy49Pwm`0XokH-<<>Udr$_3|kjYT;<;A=;p z)88DmT~YZY5tV%sc&oX}O9lL47o6K=q8>}((?{!l<?T8#pQIymL*R4E*DSyjU2ra^ zC(1G4D@fDNZr91s?+`M7j``cok7g_Azb-hJQ^0fuT<d*Xoqp2oDc9fJ`mdJ%$XsQR zE&tUhJw7Yp<LL4q_4*y{uMtFlJ^q2e^AKD9Ut-~ptZzh-|G>K#c!S3Ww>J;}asXez z`szy--r#+>X!f-d<V%L!c!Tqm-_r=y8%DeI6sA)u>M<JfI-AGc7Y>~&&Ud)hmuZp4 zJJX{#@cdAtG?31C8jZH)A@JDy^|qZZ;`rru=OTZLnx%oYy4_ZOo1buI!CL3cM*Y$A zu-;beV-+J`r=j+GevVUanEn#g{?hwGJ_8ZjzX_<%Siqli!MUA1TI1Z}u+qSD+|I30 z%R@WwiYTWJ0dI5Q4eoa?&%6ldm|bu#uK?veH^Oe;(WvD`ZC^Lw-2=MT050dl<@Eym za~GV;>xlYgjk4QUdrY)>Eo%Gnfp;wMy4zO-c!mqk<t;{e)5qBDyCiCPQQOzH4eA`B z9e!^2IJ+JHjEXmEJH`TUSwd(#bpHcy8GM~-d*7m{c%#<$5b!Pq-r)XVyt%;J7QWLo zU;P*rZ`AsBycm2Lp}q+y?=JXa)Ac=XY_$H2THh?-JvTyqdjjvo*X{Z~5*2UM`W6H4 z-qXVAo5%E-YS(v0RJ>8^+xZgMgMrsg-$ayG4BvB_zF$Vg8@0aKz}q!KeR~0K4fwLt z^gUzTAEs{!@cLc#O#nY6fGIpKIP*yn%DV_Y^K?5dk6K>TcJu_2HIUQp@tF?zau=M- z>x%ka_NLvw2cwo3wLc1h<Z0jy?hkHXG2oB8;9OoF%Ih)5Zr{MD<wb2@=SwjUy4u0z z^#DB41?TcoxgK-v_RWb}UexyG0&fA<pKf{<0G{uHb9veLH*&t+zO7Nqi`u@F%V4Vj zUbmjx5%A|-a4s(a^%(!Q-M*ty%Zu8+EZ|K6UU&a32E3sQ&gG?}yxc{0`)ZGmHXfq3 z&wn}OHuMoUJ(B_7>4JAgdBrGi-ICHkCeO#0SmlN3c@_5YhjHY=ZCENlSH*mifpYqw z9Cv%O0e{g2XZ@)c=&&0;C|~9BZwYTN^e4W*g!Xnt(IFQsLdrGUfzGb>aeWd2Pj<n% z-G@-_{&(zlKlA6?osM$yp+CCYodr0rzk}i2?w+8Bk!!bm=)d0X65xLx_}%@Ta0TRs z3(oB>Lb<W4>~_!j^X=}9a_U5AUuV?ovNd-5zWCSMR|x!@T<cwKM-K4cyUuRMX%qA~ z`7?amu|4*QP>#Ewn2w|K>~?gp$_ZYloGgE41AlUacJu=Nh3oBhy!7YW;qL%G#QMkG z4yNON_-fVTY|g*lj-J5(3h)Q>8}~<Bw9m8IZpXeq-;M&5!|Q2xJD83ae`vSkw25Kz z@nriW6@zdm*2V62m?-zIt#&)Ev+(~JzJf;+(Ff%Ow}a)<V!&T?!C5Y(qx|Q#+3kDq zUvFQ+m5_(7_Hnr>fG4})+<zt9ub<fMPW$ui9*c7FVfS~pI|uOfE;zTlH~vlf)NXg? zzus>DRgj0kAKb6p?qtB9cEP#b#VB_=d=TsTZ{?qFcLvI-<0^;C&j!4j3(oE4M^9J5 z_pu(ApZx3XHm`<W8XK<HBm%zJ1?P4j;(mayW!>(hf4<%6DCZ88<L>V)z;AZJx!pZM zkG;F>cE`Q;FOTCA;5UKa-QNk<fTyuP7Yt8DxkV_q81Q!_@||auYuiceeV%seO_!aA z`>zM^J%|2_LD>1QzLtve9|inxjL+w^L)&eDul#<~RHbeU+n`TG{#@W4@5ljtuCC&I zGM8J3_>18KyEzw%dmemiAO*o3l>0RD>3j3@(0|Bl`y9F!UQ<Hu&2zg8k-iD^_ss~K z*MzjY^7Fqae--j=Qph*d$`^btR-eDucObMM5}frm)f839{deHI2zHuZ4d7c4j<0?B zeR})ceIHYOR>`^h#lW|x4)~twzszZuwr|>YuP%?_Tw%G{i<L&Eduk_)i@LU5Sks+v zTv{KF?~3?r#A|-m@fGJCnVu=vqTdj&%YF6a%gq7a$4`%5Za(7gLVUDxvr%qm#OI?9 zW=E&o3OnWXd{tmUP=k?<$9p02?Loe(Os8|h>0Z%~Hr;Xf`e5Ya()xZ;3hFuaj8f}7 z`ge}p(tHnovhTZAavr@W@{cYo4Q$~0Y_Rg%c3M3Sapl3I-VPmzO!sW$Yp~nSXUnY< z<<sp)zU`>*Ds-}$7~X!(cNKSeP<)Ka@<k>9<4d^?!!g+&Pc0^C`DNcrLHmc9u6rr^ z2FKLM!$S8@Z{S-4d<DR57CZHW9d<bT)`^Vo%_#Vifg|C1*aASO6oi9hL&!O1re`tA z-H3GSxgSP^@KZ%UEDG<36cFLIJ;(<fW~P%5^&P-I1ldnlJ7Y=cu^PQU+XMNEkncJ! z&z2{_^7jV5ERq^pUINM}LVJGwDpdY5yae!rE;zS2ALSGRelORrE9$4^BgTpLQw9%3 zb>P#*zF*7Zz2gm77wrumcNKEDE#ebVP6_bc#q~bTYOn3b2kkAtZ`NJ44-@lRUUx(O zTKh@^Wt>03sgHf%qn%oSD@$ycM~$wC<Nhl^eTs@I?>}zmV&FZ1bl7<irq{u%+sUq4 zjD8MU#B+M4W2di61Erk)8)x3I)A#X&T;$?*C!ij6_Ll~FbG^&;lZyGx*0*sR;-RpH zbN;T#-}Rf)z;7(?qvzkF)ZQ?AKi79G^2Z;v>E?IZ7nyF%5B@Ib_wPzW&ebzK8SqVj zn+Q7}hPMTLX#{vzz^6yR(-ZKKfRDm_=zO@p(gBb8vGV=`ONt&hVqXpE;+dWUEx9*> z{Y6H;cgAjdj2|P5Aw8Z-P;Nf(E#k`PvnTMm<Mz=uD)bH{_sb#F<C?>zflIg^4Z`L3 z6_(xQX;mMb=`y=;{uGqk@kpumqiNO-$zL%Z_<r%D$c~*xa2RTbeJ6N-Oho?0H({Ry z`77qRit)z%o&o&B5&t^EW`VVy%z&>$$d_wbz8Gm08(CbRT%<2S`uUvx?eO(2<T2Zk znj4@6Dp+0}B-is9)3N7IcK%oXc>cC%Pa*Q>aQW9c>tEED{k`Iz6v`h!`h1qrU)KOb z$Rda}E_);YHAiheuY>$rUPb0}=C|UTF)n{D4WJwCwA!a4d~rTsKH@oD;w?g4j&w}Z zAe<rd0QW~nr0a-u=h^AfjK|9LA*OF4%Im^-m|wng>^WWBy!N#6LJS1=H}Y~lvVp(t zu~O|f%c=)_9$B)u+-FuQ(xs!E(MYGq2Rrr#k%H$3_FDK`m3o+HKp^|(Kj+IuzDIw- z{J{0gik$CfS3YhR(@_LUE&nvnhvzdY@lVqgSyR!j-%;*hF1MqVe}sWC7&e}@eyn|7 zcHsM|;025^++i<ggmQZ(*DC{fQ+|Wp8DTTV!fV@|^!U<p_bPa(eKCyOS}x=xe?R2k z#`$+yc562s*Sh9s=7Y|+qOX6CJ}#5d=qiZ6mF4+t;0@(dFO0P1^BA|IE7GTylm>p_ zdTb1_pKCqQ9+&Nmt>NR6`DQHg??wJsIR6_~d3-0Tk1~2W6L>1e-3FTBEguXcTMkyt zQTE<>^Osyj@R%qD{+Y;k1>?BgY0vc*Z+3aiX$)i4^Jns{*ylm|%Q$^YCq2{&=H&?K zyCVI12Y*#3eRTZkNWarb|J_)dzR}Y!M*4$J`VA*eUxf4}NZ*d@&-;VA{~)KL)IR}q z^_SV{U#&bn_g6=xUxD#-5#wKErB5^9Ng8@hCtIR)MqE#%D@HvU^SGISbQtHs_qtu{ zKy<iNu`=>R$o**EfpbNu=Q9XfG6T**Y+cm2Jy=>mr$Lfbr0<M+*5vf|hvA(8zZURj z41>R}dr@bG_W-;*;98DCzCB{YdjtM!&9X3kV=UnN0k6t<><{C~0ep7^cpl)N0uFMN ze>i<1;0Y+Vb~)6le=*=QBjEAh34dJ?;K_iG2Ruk^(d}vrc)tknu7EEBJ>7KZ3HWVD zf10a4>44uH0iFf;4K6s#nZ<x#3wT||qy1Oh03Kl%Vm_@O6d=Am;yEqzsO8_HBEA^$ zmqp3XbW6Akb_T=;+iOw*F9O{f1CHgeFrOc7^S{=AVJ~<J(hHSACD@&pEy%3?2fmA4 z__%Jp0bc<=u7R*s&k8+;>yd?cKk{MN>2|^?gOBUMbnFE9g9w`?qwIRXtCBS*b}AR6 zK^5Wh4gue@$X6d>i*D?h+WPSL^WP0S72=yRNRMr_BTa?)wcvWCB3*B!<LM80nj6<w z@iG3+fG-8Sl?AVMogTT}bs2ixB0eASd``+5vyij)TnAYm><f{-_ohV|vW#8(iO2=M z2DQrqUob$+0F6(tc`Iaq?c=tc@lGTO!1Xq}q29p5v}L+j^|tP~a=i;dw@rw@o9C^G zBZJGr931TX-7f2C)h3GBN%Lnfl()TZ^zxXF2NAE!yY$bM$Mw$wzGG*US^iVbih{4= zzWdd1E4(fm?b`z1A>d0mUK;SQ{4E}#=@G17X#Kxqm8Y@zaI15AJoLH;WIi)g4sbtY z0NxJpXyYLV@hu|c%LBYwCHaaF|2XPPD8u<MAC~}r2jE(cqu<#|$2^da{<#hC%?O+4 zS?#m+AMjRWe+Qh;1ipjFcP-mHt2+5GhU~cnUJgvvT!k3exPRIrUkT*pK@<5#So!RA zor{+p`<kiNn~}KL(lZKRxEQa>wBKNBKGSu84=b#F;DQK4+tz+DW>J1F%FjpoNnCGl zW&Cli<u4lZ>2t8tf@NH4sD;mu@@skVMiaLu6rZa-dc43Nf~kIuV)tc!>jr%LW6J^u zxqg>e^$WJ2XnnR*mBU_@uUu-H=C`8zaNZdFp8{OL_xMWyPj$gr4kmQRddh)oIjGlC zA?qIIpSDQX*-01VpR+6A-5q$8{9Kn*l-~pCU|tudAMMg<^?ZW0*fY*_f>>+b&gl-h zi}b<s64xUS@FxMUj<EA#cwu*}YXGm~0P)S^tk{M}8fVN8`KZ@j$hQ+=vya1%k?e_A zGCy1gUomqcbA!c?i70O`@ag@AZopSTld$~;uJ_pcA+zw-CD^C@!|)uy2StGA0p1I6 zut)hvw;%BCuJpS7fOiHwiBqF4X~sR}^C0I-c)*Hx%Zn7iFGfB$yd&V}Mu2w%yjBEw zFThQ}J>|8v`ZojcpX!D4X*S><qz~p_=F?ojPj}!IG!5g^BBVRZNf*SYC4jeZ;8F5( znT4QNYoybB`ta~d`IPC~^+D)uNFR;An2zlbKN)Gw2EbRLze7fa&8OF4rHW@8B8VHT zdbxhRfo~Y_Y5qDe?1cPPjQU;ED7+v2J<!ew@MOS~Bf#4NULyj$E8rpmyeHt_<IUFK zeq?@22V5e3FgzLXEWm3z@F@Mm`SXyju9GgPe+vO`>cFGq=Q49aj}}O$`}Y}#ev#!6 zr$2=B$IdUa{FvY9q=(&teLqL=W1fh5bZlN``7!78=x_U61oWq1KR|4unHJ`?2SsYR zmGcnp(|~@F_^Kn)Fdg#{zg2>-yiPgL32lGrm?v!ijoOs5ScV-(v-HY*;OUGvb-x5o zGtt2V`Dgph*Y-F}erX<N&37VTvE*I?>bnnkG+#=GPPSdnwa=Q2vN9gVJ{#z&`5;Pv zaepsHx*{i?-QNt)2mDtTobeU`?g#x(gxCKF&KWrAY`mS3zYy(62E2&^J*ryt2;Q%% z*#ENUbEr9`P=LeDRG=&HrJz1#Eo^-Dz2JWpAGa?L_1@X4EXd!YvnIQzd>zJmL^jI( z9O;%LZ1%R=5qu9{>#d#8rLViS2unVvJc@N{>u|lbBj7gx9*HlR=833ZJH&s+<?=mk z-M4yerT6wWl-JVYo6bo8Ez*CFiN-v`Nng%4Q-b|_>Gq@i*=<kUzlV@6$4M8&H|As5 zKXkzvZzA9Y4!jb6?1*$bopd%{Zg&F8I|Mk>-n`Ihhwhsja4IvzK*oH*bo>?RI~Yh` z+v=ZSyN+HX2A>ze&QGmM_-rhff0>Ps%dePc^t$bj;OmI`6#?I#c4dJZxPG@=_`>9v zmJ8Y^Xfxc`f%y<7SBM}Kt#xkA|Df0Y_GN)NJf5C#>Q%88cCB5ZACnpg{W#KiN=3bT z17G{A$^!W;_jXwLLie??#Rh2??0A{y>5|8>4!yc8a1O$j9`s<j9>nb}0Nz5x_hUZX z>9p4+Pp@J*2sVya_fZ5%sQDk|)VjVbz->1hhUgElo4{qCWj5hjXgNRj3Cu@GA8kDK z1ioa%x8?TkMZJQ@6Sjbx$ch2Q<!2#%^Be5(wBJb|c|38u^O63CTgn2zbN{4S`bpUO z7K=HrS`U}8A@7Qn+u>Orck79B4!4KvvAqD#aKU-JWdQy>;9O^`O_A3fi;=FklP+i+ z=L0^{1!ufPfM+}KO2)DOZ;&HSx}b4fi2le0`~s$TlDq%ZIYH#s`j{W(t-7Nu@HZ3b z&vw$=@~%&;y4$SiALhe!lv~oREO55n?lj~6az5nxGabb}Wr0ojG9R@1BX~aouLtUV zqI9I2?xcGvdb%8>>v*q?@1^MJ3XpEUlWt(-bUgk_kZus(me>3;G9(?Wy=*Vo6Qhc- z?uY0D`L!HinV5=pcY3hQ+Mn2I<qMvV^tzT0Lp%~bA9Y0jUdTTP`KPix%CYhf=lx(? zPpQy%uC1~lMn$}5$#`;sXU{_zpWMIm9Xu7|9P^^BH)(gA%_8YdDZtbDDb_X0v_Eu~ zwZSq7+o%5wCO}ti|C7)IkiNPP<^IzuH~4&5m>fJ@PkrI7eE*C4qX6|-{-mX!TH{F1 zIgmBRgAt9i$isZ-e;V~czG!l%2=zUTc)ef84^dZ)CB7Q^oO>K3pdQygZOfgnLelfP zH)I}Xd69wgeb1EzY9Z`=7@iHd2k@#65Z?^X1-$fGTV4dofdas*BR%(tWAET`bO`Ws z9C$_D!`6!le}|phNoV8b{3(E6>cFGqXF7I8y7ovHjgBd(M=IjAUOXm@E+OX+b^C$u z@JnTu|3TpAk8VHU#{hTJr2z2n0S|6Jr#}R^>>Uc{`kMd1`~-Nk`WB+TKEw~@@iEs` z-*)QK;PW?JPFLWYI;1S@K6g*RJHH%SKBrFyyt@m|^v(jjmjjPNZ_b~Gbk95Kg8Hiv z@C*kYCBJSzHoit8-37p9y$ji+T>ditWW-NLeDJ;v=W7f2>wwqbe83<4P9Nv%X5)3| z>jgO1D^fnjI~MV;M2SyDJk#-M#J`QOIcS*H>oTyf>)2Ugz%~ZC971+Q+HB-Ih<uY+ zUOsN+3zIhxRONnON1Cep3H-D&-V)$V>0{%)_uqq;dABR*@MJ%GoZJk&6@3`dZkFE* z`&NU(`Kt)<&Mr9fR|(+V9e4%qFnN&tEbNp{x*+~)3;6R6JW76UM<UAUjdZUfY(D6; z!<NZ7X9i0ra`Wz;wLa{O^!Z3{a6fejr)QYn{*h9jN7=AQ1<owsdj;e1LLR@DTlj4K zLC?=u;icpTP>(Tlq8^rMobwfMzM*B-yPLO!<bzVr_u?bJyXgmA+GdmmKIQga6VhIN zu5Nu$dzs(UpM!lA=_8E?re8PUD?q%Km*MNd5P8Y<&OrL%qsy%QizOlTj=F!*8Ts;% zufdqIz=tO4{V3#|UN7l&No2b{-Yc6OWgjAe>-|s2!3m*uHm+YUz_%|h`@`>S<sjd! zz{fOk<~1%S5AeraaOUqqz+ZOYQTUVdo6if;*GU(|--&>abKp_(bN_Wjx=Bb^(SH@^ zy*2-%9vO(ou?3uea`-{(!_e;jS-xG%iwCApXQW?<^eZ|2){y?|?C@Qd>pT+YOGm!e z6U(f3M{+~*X+CG;T!<2eJRR|ui+lr+&*1Sf(aIP6zN6M7^}3erb9*AJ@+>?|$9Atl zk7qm&RgR~Nl9AL%eV(o}@FY&M$6ZScPw@JyvvnS?oly|37c(6)kpE-k--WOl>VMA} zw@<sK2TT8Z5$7TnmIcm0K5IU^wR|4reojIB^eFLdxvUp3A0qxH4(Dgs^AhBobC#r% z^I*&;9g%+l@^hb<6P^6v6FYzK`)i!07t-e;{RmD!&`NLHBTo9g8XhO+OG3mgs(jyH zw;$=MAzdrvsn{pC_V>9yoe|#<@xO6=<+6hrX-6cJzUF_>c_;An02*`i&|o@hJ~r@v znk}iz*V~<uHXZp)$dy_=Z`l4tgY8EZc1pdE$~t?c?~W7z-=-yH*17tjRy~6Cg^GE| z#@EG|ALUrR9@ojBPaTYpK0H3|bJ|tWzaWZw+%*p|Uvxvh?%?O0Opo5kr)7~o1KA0x zPF~P-qSxOUNbk$E&PAAi3rintZq(x~7wH!xeHX6Ry;i;KbtuM5@I9n9(mmp|{CgRE zm=!GlD$cQR{S$lRd<Ek5{ME>*Pr3aiWd7oD)EViYo?aGM#_e6})CcFxLeD05;b$$t z5Ex*Nb<L8W8OVPC`8RX^EGz$s_V1a0@{q6hjIuyi6Zs0Qd?Wb1+_3YQ_CEY!LtPMM z{$qRzpi7@wWq~I>z-Rl94dx%$`u4^uYhu;ao=Bs@TJPk%g7F9bz8tunPXYpYfL{nW z%yi`+h8F^!?1J++Ee5<g;ET}TJWhjc26(Gr0A0&Ay=$v{WT^fS(qT4CE`<B3Efl)m z7$18Xpz+`waqwP?#?ui7^`&8ZI*G{A8~M*#T7HfQ>j$Gfjtq6;gIvjo&q90`#2;b& zn&-97$ZwPEad@8b<RM+%Wo3aOb~^3%-sq!MN~S{*;?ogdhvQ*u<kt{6Ux^LBm*K#l zhO@U%8#kBdOY8&x2FQ0E$MboX4pzNV0sk5B-3+($O_j#Sjt<LUF1K4BA?7SEv;2qg zxgwOy@Lqt=09>#00q5IeT%QcUrvd&U!WLep-8zky<8u&y!#mO2nUDD8h<Ecr5#VnC z&Sg6v4wv*nc@fel^o9NixJ|Emtj#b#r`T}z>ut$*thpkO4H%qA4S`M`$!3k**1aX* z`+h}PV0Jk^$b?{gSC+5EuB|ea)GL+X<M!kO-!-|R_EzSjBEVAtpTGrI@DbKI#z2RU zIGw*A`UUAal&8~Y>M)n~s#2$e)w|pesYtg9>2Bn7&=<kC;0*o&S%<%_i2ok(ofx3` z1CO=`#rHyd?RU%cyNq`HPA8t*F&6RLoOlR0<I^fWmZLd<k68tNVtQ4y1NBoRorWNa zKipr1NdL@goO39ruh!*pwj_9u-H~O|_$9LF(fF7?DQW2THD!VO7^2I^dsk@+I{<8S z1OVff%k7GEFCd-fW5@;jER!zxn)0_$uI95N*H+mhjd9T?P2ggD*}!)U_`X*7q4DXn zC>47+&`k$;?7hd4hI$=V`HKK^9Zu4^0^=(NzM*+#fy3o=LG|ssauqs)#&=zn1ya2a zz6(bOMEG!jbxa3s)|Uk?W&o7zXVICd2zCSf2EaEk9Q6*?VXt%Ul*|mBQ90jO<lBXO zd>?`HW#EB#=zv=H;Wg(%xAKZ)+&}rqH*Z5(U?##=|LC*dY(XC3FfgYpM!J-ZCr+2x zAAVAi?#gm}dOX~q-ww9A+iE}3_5L#44%ZFv1<0Sm`R#QT)2kQYc`i8DD+BPI4qWqB zl>HB+D|FHYt=IAaKkUGx<mdj+LHmo5t}oBaPau=#DLpnS&U0#>vd6}r8tQ>4^D^Tr z0ltP?%K}pv-xnu=@1q*3PZWGipRoflx9$$Lw=oTS0QE(H--EDO4~cXe^_<AI?TW|e z5YOqyB7L(@vCqiqOYoy2y|zPSIfEAQEVujv(ceg4v5u|K<2XJA@wHHXq<AjRM3s6w z<;^&8dA)(}*C^#NzOKNxd{<c@n{huLf{)h^6N9R++nbK`D}Zk{r@u8My>9PoK^YkT zVx(`ey(}<`(_i7Fhb%}_I{i3T`XZ!%6X~@c+tf)PS&!v@>^2BG4C>Eih44S%3tVu` z|A6N?@F@Jtco!qxMkie`{{vp=z@y~vjQlyE`yQlg<Uza7M>|f$|KL|&6n<rVCBV0Q zUs>P^#y2GdpUZA!kEaDSR8katOsmdl$6Mdpe9KIA0=~@~jPZ9cI$vf1Ume8jaj@Cx zH$845j)Md!l4C2ucL?|fAbvLLYR(PE=jO9S)UOQbHJ`oaq>s*Loss_8?`%Hn@1&2; zXL+b^^CM*;e#v;e76P6OcpHS7hO8Gif6CHhn2$;je;MM>=6K95d|!q0C1B~(sgiuD zh<_0AZocje_&;56=Ib7S4|U*C_>$|BfpjCBbU}Qb4fqTP9wk5XVLI9~8|i97PcUnP zZkn%Mx<c^zk*TIS80DZo<0}BZCyUDhag47{I6jxIfI|?b+7|_1D)9BpfFF%tg6*D| zb8H{2`s@)K=(>jL109jC8`^&t@;$`$*psf?74{w`^71*1!%AJPB3S6SJxs^ve=iH1 zZvs!Dg(rADT4B$ybt$yR8)bdVe9{)CxjV`%dzHYI_%!1cM~&5d)D7{yqr`K6^AW76 zh)+h?`7nGe;5jaM3gA6JzvX~0Mc8~2_1C;$-+O6i%nlOQS}!RCp34HE^C;sl2K?d( za6e4mts}sb0dL`g>-GcQ4Dd+vA;)(^e7#EIdn3L^lz6UZ7UE4;xeQ+nxNyO_ynMh* zK%Z#!IfVEhDv9^QkhrIk_!Pu{jQF}J%aSLzhxB)6#OGHM-xKlcD~ZoQ{F+MQa}d9x zlK6bYFOCw={F9CL&qchRzc0h$s6v*6?WZw46G!6wycw|eJ&`sIDwdDijt`HgV&LnB z_;Yw%E(g9y^Qe|L_PmGjq$;^L(Gm4;;SB_~8o;+99G@Pa!Fnn7C+9|yH_RvekuTmX z<nz_!8Gf&CB-RrQ=eA9a2?S6~`G?0~D*h${j_F5;n=)vC=e{cK(!3*#;cA#^+@agf z`MYs^Y{0T>aM=C?0@8nmI!`nt>;vF0fTKZmS|iYjj!N|~0%-=}5u`B&f~X73WBP-9 z>t$8IE~F7&(S-)aiifFRtQaZjc#L>c(r+<hwWPcl@vWqFF`}PAOJhW)L5pL=VuKdO zhz|{#86)-^lpP}i22GC<6BUh*5pOFR8zVL;8XY6{DH<6gepB>?Ps}jsGoQ#cX@^gI zY|>1hC^0G9C&m#?_lbE#<9%WS(O93@Lp0haej^&-6Qezp?h|u7)XyjKJapVEc6sPG zuQ=+VHC|EdMGGtvv=sFbzQ+1pGbQdWaV_;0x8nCB)K`jsS`l}3!FRW6vrO@cMCgE| z>81!s$}*Wk15Iur!ZXkwQ!FuPwJEk5w8G?e=9%Ibg9;S47U6-4;r&dYS;GHNjan&j z51`m|DQ*JbDZ-(ZSFM=wvMB=XX>N6KAAM0>JVSZaMVX`()x;o!mQ)in4VqU?tTbp= zHIZ-7?^Q*qL0`p*(Taw|iEKqj;=~S<Hu*(A4=t@CGCXvsig?RItK-FL4;_pbA9-k7 zyy)wt#eOl~OLP5Vj+X}e#a7>Ya;0Bvh~>;n<LL7^u`v#nSzX<#TAM^lSEBKwM+`Ar z(i^6DN76V`?2z=O66r?VN+qVDa!R~uT!S<LBOaQtqFtZ^c+U?cwdpL8Vj;V}4!vcF z1~kSH7tya$+(5gec!2O4z;iT9ioudFAf`$VuLNI7v0ZYCBa#zm7@QBZ2Z{yEuPC5e z%|@VGe0Om(em{vnd;*#0$iz;xOp1PzX*@yF>r%~-^p;fb$}>30tL1#2*;v+#yB5Z6 z+9bs|^t2RjNqSqVrIOy2>Z9QF+@RA?Mm=gInmA>hDXTYy)$nF|K>dUMi6+2AS22*d z*UxyUpA^F+jg{gx=BhU&<**qcka>l?xJN697L>Tm5PKwjBgM~>N~G$`qf(6nw;4*e zSZy*0DL+TA8{!*oz10e?(<S)TA>mH(2xx)dt$47vrb|U{e5cEVNm9&}wT1XjQnnJm zO6sG)Rrh^sh~EqjPgV>^#vQT-a&)BY#6#3mq)8egxwn6oVuV5P=sXw0+YtK<nxaIm zqW6^8qv#uOfk{J6G25j1rpPzx6H^>E=@(OsCCVhRoM<(PLZW>nN{P}vBGW_DJz|@O zhIz#-FU|9c_q~+w7011_%qI$bEDnD45gw_{ilG@XVoeNfh!I6G^j(Y?6iXvwMNTX& ziWMKl(vDbhB$j@S6(izke4JPlM<sD$o}ZTZ#U4L>;}-{+11(y&NrKj$F6l!<OqaC8 z5W6LPEyYnuze|NdKEO~I<dX~qex7ZpjRvROWmI)Y%_Qn}Hqc#2H$sx!grN%Q@#M#* zI4EhQA&SwjhRvmK7!3K)NI>j&1}%dW(UN1jx^I{%2AC{G7MKj*Y!cEGv54S$qC3w- zurW2qeQ4`<1N?4AtwaY*1|0AH9n6x5_xY%*;Ev?9A#s@};8ny|tAdPYQw!Cet`>J9 zT*1oV*E3~8O~6`Qo+jle8Jo$BWu>v}UX7z0BP&laEL>5CdI|WxmR=U!=n2sS-wQa; za@ppn6hoN0NR!f<hxTP{UJx0wJ3<)h(+sf)qSat=_lY6CHt3KcjvG~U`m-+siu-7c z6#ro9{UV3fGukb(&0s@Jwb8!+KgQ4>#!^A7_#u{ljujbkG$u}b&7v3ty5MYTBCe$4 z24)QSI)td$Zh&)B-!w2O#3THbK?e-+lR@yzG*}@MvSk)Y`MInQJ?r^PG3Rd9vJ?^( zVa(Ux7(7#hOFv)&t1k@NYv7JZ6U4r&Xsco=j_~h_4wxdxq(!D!Ytm*@eS|sMRAnZo zTtf7YN30`y-6QgeMtH=JM8`-B@-Sqfhhw*SY9r-O9{S8H26$<eS4{QNEU#Fm!ykJY z{+*Z8WccWiPrUA<Z9cKcM=N|{lMa8a;eBGbKEq;IuXra$Yt%t<{7!jObNa#*m(vzZ z&5{-x;+UjTDTW#}&QOz>qj*e1M(u$#Q#@G@(33U7(^N~qKT~bSI&$owH6V2Xpnsi2 zI$PXa{dFlGqo>6{8IRB+W;muZ##{rVu`|c{&Y%XOIS$wX9y<O)$EGiVk|9d0{HFmu zj~T`l1g}<=YC(5vidJ1Ex>k>jvjJT!uD9~K=Uaag;O9{b(T?+CUQCK>3L_rj`O+7t zj}*f(mrFcQOw%N8BLq#20nCdH;s#>$W3&!2#HW%9CCj-ZQfacPkw#E*;O6v`kv<Qz zt-)F$O!?4Y`WtG9L8A<n9U=WTXz9NymVc9>>zQJqN$;3yl}YcLYNr{FA48p$kbaP? zk_x2QE9qOQe&8ue4XVJ;gb!9c^jJ6`<!;#u<hX_<#skz#{EY*X<=HGXs1Jsagib6D z>F^i>{IwQ5qr?ve{cMOdC|XKE-O5sGg`!Ci*^0hXth}a~YN!dFNWIBC^NvYBngU~F zuPMIJ;X&wIv6Sd*66=X}lGvuhzYtQ7^U%*8*3i~_M1hBPd(?gp9rmc<UOM0v%e}PP zD?aqn4zDWo(tfWh@zPg5@rI9bd}4)<@_gz8AARIgzx#m9(QBOc*Ns0{w1zsyzt2GY zxwYDf8|>dqpTzj{M4O=a^J;YvH(9@{osRfM)o&43;QK-R0f&Y)seT(Y1U$BcKYRk2 zx5^th&9%)~b|X*<9#LYVL2DIjX=9bxYY=n|47V~vS!A4|Xr@vN6fIM@A5NbrwM$Wv zQopFsKCdg|8`DMVq0^ohLl}3(WE9BMan02|r#;PTUTEA2<~fY9E2=*$o<}Y;t1iz^ z_2?HV?yZh#<a0@1NzvcZu+Y8};L2Pq<y3hd^(EPc+NrBKa4U6Fvn1rPdQZ}FLmigD zu0|X5n&H*TT+I6h?KZqS4BBVJlo_07lA?X4TB>Lc3|5K`D%Ibl4AVQ_q{(K?auZU` zyTPPS%@{0;kbWuE$@7TqRP6w<%8&3Q4^8uU!Ab~^;)Ty^-ZlkZQRKxGYZ30%mtTDW zeRg0}J>Bqou0x_*5*`zMnSM)UY9`coNy7~>&>)1@8tq|JRS8*2ELQhpf7PU69&yBc z={SjE;_xgF&GU$jo^u5jTnU4{VuBY3t&T#a^Dt%ah{I`}Q5aRGm?n9YFN9`oifz#H zO&)DOVsJ^?q9CYO%VkPzQ2gV7;)uZ}Cwj}|43>&?$YewV2m=$ieeKTbZY%tO%r^4; z3#gr51N4y%R!B?5*eb6Sykx?eiLZ<^Rwy}w=f$n6$#1HhlQ?fPR<4+*A3c4PgltD> zro0OKx>^~WW1P`X$<LS{Ca5N0>T)JTEo!u<YsKA|5niPcQY_}IfcjYrYEY-G=wuHr z{(VlJ%f<EhjTD(p<(ctV@n6{VVfA7Pw%Xs7@!O=>#M$@Av$(qqEKsf)iGJer0oj~& zsfT&t)0?2*43_sC!0N`}ux2QcXIu!!KPqX4!UFp|o#*@x$a5n-DZ1Sy#QTz_8sakv zdCamIt0}Ch5Pr>I_ySvBYI_f|Jjqih)Z|eH`tBY`aV@{a9IWaMvB~IwgXt>iZ6#K# zOK?Whq(P?0(vzj01D?eyiw7$x`8t-1lC1>mr9yA-mn<8&K|HB4@p!_!?4mwA7vXe+ z#FPozoFmWdNH0M5><$6l%buYy2`!N#zal&5KdmJc<m=iDxBDzhTJvKv3;C<)m=w3u zr&8Q^&nn3R9>E_aLkAn@=;AYEd-_(1PDxLQS0)<>?Nx;9LZeN34cuwcajfBqhLe~{ zG?&EtMEN9&h`u9{=Aj`TG2KINdc;}}ZS;se9{R>3e)CWtuNdv6*Sx&CUg#BhUfK+s zgqMoE;+U68y<&uqEg7?YG~XxI`e>t1?C?RU)op)FK9EdLLD_#mTt-)dv7QqBv0lOY zOVWE%Op!EGid+rZCuxx(zQ@dMFj?`=7&II}uuOyuhG0=*o}wj6yr*cBQd<>mSL$2U zlnb)8CcRF+iB>!PrO~T7P@Q;x{ql;Gp!NTnCT%SZi(~0{tQZ$ZS#e?+&v<A_o!a>B zgw@;gunO3VTxd5st`;wwE~Sp*Q36*zLoZ@v0)kH<vqZ|D<yH7~LqZQoOpH=cYCee# zlKPVPQu4C*xHgbXFz6SEOoKj9;v+~>B@P2(V0hAC%!xefiQS5DbRxr~F{W5y(ppm- z(7M8SqRGViGz1l$KQ>+r@YI~_5lcK>5FX}DUgQ;<y%!*y?mK@8tH(DYoE4J*gWLO1 zkK@HxF_aT4evXNs0ApP&hu6o}0Q_j|h5h2i+BiDs7u(}#g<lNv(+Izq?5AwMdect} z{OWx_<@?okKkf3XQa>SmPP}fu#V~<P=-4+lWa*d$+fSjS4O)OtP^@DgG{kZk#CXw5 z1qPga(;h?pY*2}z1}GY))O1D5m4f+i1+E4twjO=Y^0=HGLF2+0SrEf!%4?Dy69ZTu zT`s9iik&bvN%0e`j*{6NYWp%>;1+{+8DhH*V|@)c3OS&}I>odv#FVOy6NfSXm{ed2 zOrsl2u||i#H3{$xqK`@B5G~Tm*@q;4Ao|=RhI(j~9^r3$*oubmCmx0$^H8pr?Prs{ zVgbw*Ua`|lL;d1sFZ~!NM)_z<oS5cIo*M@<MsjAH7!gBhu+PQNC$VBJj2T$n#n8_& zA}yAN#HtaoG(J|%i=`#8YIQ8Fk5#*4sW?`BA4|t#)%Z99h7ECy^FSQqPxo_Kv;6cu z40e9n;ul}}>40Ahj;EjF#msox9xqnJ(+BZloeuw?;iIZh|EgkM7200~Z?Dj2Rqz5T zhs!j4T2&fXO{}U)N2-cXt5Q)_u}g=CS7Z3w)o5yUv85XItuDT<M#a^{_d5Jqb%rmj zPHC;gy6RL=U3^$Q5#i$MG@ynE=<v)Mw7iCRy9UE|)}Vtm#J(C=BfR!BT96=ipGKn+ z#LuTudV(m`;WrZ)z9xZjew09a6T}xfoL-Zb)fLlf(!{!AMNRspj@VQ)d3zmES~EGX zj#yrca_Wc=Yf(vUaj+KU*A^3M)9bZGPHkFLTP?3mt81$rwP|;4b)Yu=SX&LOLzC;M z@pWiQ9ksd+0mI=sjB`|7#=oF0m-R_qT79}WT$iSvF49k@F{g`+(>c8SbcPq4&Nb|l zNJkSzULtKy6kjFMfkZLnOq!i4W}ZpM&J^p<qz}&&yUwJdGsT#*>JLm6o6n-mB=Ox@ z^wU|QUlI*Y63dfle@pRNJ=$7Nyj73ht|#8BN1N)21NCT1eerue>RVrosZW#Yi=6sY zdbU_mpT;y0dG)Dp1MyXTI)F49GP^-F#J<;nHk>UEH=wk$#gwyY=GkJ+*$gQ>I{~p{ zl4(-1n48Qc9y*7nG!!N0P+CJVrXfvgD3&**iH*eOhE&o}eA<w{Zz%Tb@Tf)%pV#R0 z2`$CuMzpJu*xrZ`9(*n>X)NA2mj*T#AD>H~oh!aMmwq@`9X*$RKUa-zOmiBm?8da9 zvD)1DG^F3xnBHh2N*fcNgMYnALqH0e(4h0gp(b>^i73|L$>%)*_?Q%WBSpNP!li6W zp|ob=`xMG=Dke3hX-&oarnI!FTG^D=HB~#B(&47++otqWQ}tT2T1daR8I?2>+nUkN zX5!~&j3M)U{=eva`sRGG`F#5PeDR462hQ&S_|fKctc4hP0e#v+<X`aUdo4t63l9I- zLc?2f-kg@SsHOO@CDW}>Dxn{zrE)K?OQpT3q9m0$VR9?VZY5T=qW4>gFI&-m@J4GI z*jh|$O|x5zm95Jy6_|alyP8IOVYI?>4{Lxa1mTrBn#2gz1}`#vrRpO*$fOZ^L5y&@ z*#+TGO#0juyY<>}n!T}6VQb*^ca^<ZPh(EmZ;H1~T5gK<CVgls?52EXsza{zbSrs2 z+m>3>W+^&g{g3^K=UD9<D%D6y6C|F^ARM$?CTW#a+d^#v_sctLAa5($B1L<eA)zxq zYfYsJn#y>|O2iVWp!$6v73`~nl<31N9+9JU6s)T^8p@g{uyOLep^6Qdw$$*D<sasQ z|5iEo$lKZO*#s7USY*aaaX&qZ9f_9}R+fXM%3{4s&BIzwD(GE!>jEpfEr!T4Xoex) zHh7KqE;fA(g{f$lp^6Op&QN6)1_{<5{u^avNSP*i<$ft`mr!!%@V?5+VyL9iQd!#| zFj`?-14_#_sj$^BT=6nupCRU9o5>LG8MMhz*wWf=D44B(HWa4S!HU<Vn@v_Fr<vkM zMaOKLzZz-M1a0@gGa<`NT4kzjA#8?r>pJlQs3pM}Mmy%Tp7ac_IR{BKjCVzt(-!g8 z3~i9=JLs}{lj1W&WE(Wc5bqeY#!wh7`Mi!}%0jCMz@VhqBnf>22K6r#f%gw9C|;^W zTV%$Vu+gX~*hn<hJMKE6FIcf@Ot}&RV4M`)=@IcP^;TA`GI`;m=3-MuDwvp{x?$yj zy#Q?fP1jpb%M6uk(0hjZ)SyBG2TY*-z;qg9ywLsqA1~unf1g}`-!Jc|hW>5_1{0U? z7T+US7Wbw!SPdl>?kZctBC4Qku9FHjPMFYtfj)2W#^!88EH&s|L#=~8@2It3^JWBw zMo@?AHNt<ZoKyXNs^3q^_vrFnkB>SS@vRAt=Q>b!xOS5xX{l6eB)0t(q&qZ}5^Rs* zj01Lv3}MaY*cgND5QF_kL;Yq@no>E6R^kMN;u8?sO3T|90j2Z~xXLtfEJV#RX`ZRp znwN#HZBeIwdONZ?lp;*fFh1~B(ks+o;#LmqWoo8YxK`j)ja0DF^<%pz?Z9TWLD=TQ zigy(Z%6fwSk}c}$s6nNMdPC7-SXLDcH|-Vg5k<c$RjMf6RAWubG}Tm-W|?Y*2^(R> za@*3cST3I2%nbVAm6XAH<8X;Vx!TsW&Cz*&H0T)5ftbD31cieL6$J${ACmW;yaoUx zCGK)*H2|tfM5WPEu(VZ04GB>ixvYCmTGkhEQPAaZ><TtCXdJU}lEo0#+>X7%t%d@r z_iJ6~C)~UXDGKyMSv<#|haSUume(Y<x1Z1(Yq+FG8B$G?P{Gs^2^$+!XrzR_uEY?( z>)qRM?WT}5F?B%mTfYcp@rj(Kv_^`HBa{W}-J23mY|%=oVD5x#6&R+lKc!jd4TFy+ ztiYy>q1N-c2D@F~8&qt-ky*$@c8Z4o9vXH#*)_#x?k<e@GQDM85NX6)tZ~qwBZf*3 z?Jhlz@8-2!Bf{24DxZb8mmXsCrFxYHNcEb;63t$cZRDc%;}9R89-wW8n1W+^_CWx( z#-I(3ii0CYKNzZSa8a5s{);?#ihh4?4FC7&H&V($dfj;umX+d4-lh0EJr4^m4a2^t zgtW3(&+8->fePoYa4H%{5A<{b!*Td@f`crU;drD{OBCTeC2YE{o8pk7qsrQK!U0$s zYpQIMw@md}DzzzOp%=*1_4<P|4>bRgSl$}+wY}71Lk*Um+YH)iC<x47cv#R-^)D|# z*{*SFy#8;<yT7L1a%#N(5rffxThIGz^4xz{SN?0#@YJ|HHEww?;nW)U&#!S$jio;} zmSEfFwcq))QHr*NlfIAQbkfVX%%leMtsV6SPQys`4j)ufSYYDFEEbr!u`(Gqzzng_ zpmz+l%Aoh1O%rV8;DF@uNH%m{H>c41QnVr5UE#YZFXE`KvX&Fm`SuLo&RHYX*AnIn zJ{J;kGp@j(FARml-rpGN_powK*$7Y8MtJi54tr&P#WxDSbS?{7yCyiN^QktZV%Ow| zfelnOR5b}U5kjW@$M!UqD{O*`_Z7`Bg*J`y^_yX)(g*$29FrFE4k4{E)h8j#N2g9F zzkd9$>|LIs)5-1qoTAeyI{iD(44mSpQ~Y#_pZ@!2bxw`DQ{(Q`xcl#qJH0;UTZ3)r zV~P7TaLMow+{?lBsNqtLkyx3j`4V@L`HtI%QsG82JZj<KsJ;w<tJ?a!f^~UY?c@~! zAM(Tvz(Mf*q0}-(>rIiTXsRiGQ1mla4JHjS)d-Wun`)*>b4|5S-v-SOQOfN-omwa? zl`qCzLDQwaC)7`$)Eutwv%V#1u~e%hma6Itt`|1JM=LQvA6?KZQL(|mno)gX(C3E2 z(S_gi%|u*Mn29?xrdXu-2(G@9D1K7(n^I+p`kQJT-`iKXOEBA1D<jqG6unN-i!B|e z`0LboJSD$Q$@^3DWBFavQ~JayeS&??oYKGkZ|JMIFV+Y*x5RvdMkw2_n01KvxPi0B zYFx$9Kipe8{VG0#d_&SxaJKO>LU60F&Jf#dcTE3lx5K0RS&DW8{6By9`S0>k_9=Hi z+>qh$+)gQGu){jO0FA@LaH_Le-#z<YDx4nfYp5(^j2e&2;6y)q#20X}<`Kg@G}iV? zpyqjKiAQaM&p(g)!b5vKs-L$8($8dXAkNWj^y@8r8@>^3CO90Jhz{0nP@co(F`SBq zN0d<pLl+p&BEcM$0PhzCsyo6f%!H3j@wM3u;pr5=io`NvB%cv`yns)Q3+mPr;x_tD ziU(<}_FsTob+~4O<IoHAy{Zo+eI(TmNxP*w5`4SxPv++v{t58McYFO8*_|J}?`zi) zAR`b5WYuJRUph&CCUM}_@;w&aApq{|-OA2kl9Hz?adQ&x%Hg`uF>GnVr3Fq?<6I+L z@k#nY@?pj_ENwBA*wGPgttow^kq-@G^ATH+IIa(`T);3-X&)f=v<O=Lhs!{lzcOy& zD+kZeT<z%r$JB8o6XA7yJyT#0^>c&$-K;X$YY$wE%+O)IHWtU=Yf_2v+8@|kis1GG zUculS?5OsY0p~PBNi5Z#3pSaw&GBN8P7I$#l;vTcoqaTi?j`owi7<Q~0lwTrb8&m# zL!-RnkcW<X#1JosXTmq7S9}29U_SA!m*D%e)XP3TGkqLh=41HhKFWt@G9N975kq1q zD@Kfq;V@hv0DcUP0%OJaSlSvZ-ioESW5q@tE{bLNj5r!pU966yqw!)}9BqylyW`%M z3**I{c>ZxHo+CC^;Y43np+nWg4^=3yn)tQKTM`~PXI0}LxCxJlzSTL=EZa|Jm9xPq zSKR`icyCG`1OcfbH{OEFCkq*ZzP?nZUV>B|l6r{V;87gbpKI98En%F%Ga2Kw!^igw zc>4R@NP_2xIVxzpY8>@t-6j#PuuXT5p{DYj*6`%vTmUV1^R-d38$p@mxP7sO0qW~Z zp-V)k1e9XcwbcbRaLMBuxJkW(?!)y+{8$JVlKM8}G08_{hZ=ALMiUGLV~=$og!5|N z2EMELjxc+Z<dXvM4TW>*dh82ayZAz~Bg%lZ@6hU#=e7^Ke%ejOR7JD2cP&jyKl`$| zE(r$#EYj9)h2NJZ-7B8CLWpHD3F30UO=HNO)_ixbUDEw<@qqviCg62Zu=yd$H!mPN zLF-`#-1KtnSM0CU5s2LGXXTS;HHVX~TatR=;%rrfc0%~-u`xyOYUA?fY6Aj*FQXzB zF2VYn;$uahDe(>buqp+YV0}!!41`#?E?PrkC_L7Zm`XH@l=d~DKGBZA_OqW4tMGp> zy{g^>#CP_Wdn7z8StJYbh=$TGxZoP?4Re7MWBG!B$l~iq?5;<^H`6)r2|S)%$>0hk z%o%TTkbQ1dhaW-(4=D=%d2nqBsPSMEJ5vS5m<wC>WL(yd%Ul1G9o9tp(ds$&4WwiK zjXY9u7e2^46sqNJc$;S6Tkz%6@PqdtoKnJhQ!@Z?F&h46SK<P^_K<}C#VpiWv?B~Z zNxHt(YW9cDlr1lTkFX>51X8VLU%;lyOLj?I@UbQpUywt;x|b3hz}`%ELIfjFB<s9w zh>f<(rD`2;?Y;{=0B1kXX+KD)aZ(Gux!obYo4B<p0{W7)HF;vvu^eD_{-a~7h;L2{ z7+<06y{TvcdtZSID)_0>?W)@t-?!7fe2f20+b<xyLer7{+BmGyG2t%ps2(e*q3>Ke zU$n4dedkaLjs@wIA@JZd!Qn>KOk7~6FArDh&+Sk7=t5VVF3!XaC)E4&dUxRc*vrv* z@A1t)+u7R@soke@yMlZ-2K!;GUX#udx6obo)pg6!RB!@c4XP^|StHF?pDqA@=>n^- zlegl2O%}7yQsXD^2}+3wtYf*MgXO#n%<MQpH3ApKY_4n2o_z-4oYiE*@@C94@>@#G z(7uG=OIxEo?M%3TXo9k@OP9EY@ijZtLTS-dT8!rfQqGo1$kh^##YOuhTseH6*J!wp zh(SLKCUwIW*59%}M|Kzh-^63tJDk#2%2b|qcmTHtd-df%Ai%YJ;98`T4w3j)Q2~kL z@GneaqIL=VzDfC}_}rwgOts&n?@iT@XfUZUM3YF(CwiaMDxwXfz99mJ0K9yA#0(GI z7ncj^K;~g7zm?~p)2>Ov#m!gXL4qBV!}k#G?1OCJTl6q)bsm%IIJ=9qy?<&KX6#5A zx9o7C3dhgV6yN-OM`1GlOeMYM5!inyBlZ^b5wX9!sU*HL=_gb4AsR>u-h#%EnnSdZ zR4&nbq@Z~hllq?MH&SCg1Pr;J25_<GNtzZTUWbG27<Ll`$L4V22$zk&d#SI_asj5a zLZh@oqc-|zt4|gA=y#tw>Z1~$g6Cskm>+XyMZ*J`*UOIV+qoSa?B0^}igsE)PU49x z>~Fkh$Sp?fPIg#4R322KSiyPUa0311mlXRgi7B3TUwOo@9^?lX@+Xk_vV5-o8Q*(F z=Oi54g2fheg#3ONJ}q#hFOq*`?Eyh)FCOemb+@5*Xg^PVFbOI#3Hw68hS_e4SF9uY zfc>RChcLXp4)cmd-ir`BAlOqS>X0qvWO*)XbrY|A{>B$}C$T?Lf!!tC(1k$8rF`@# z+|}boBOHBZ8E1XqwY_pq=BXAwATEQ;Nr*ByTq`n@rh3IBqCs8(cG{`k($0ZvHm!ON z_s}?x(w-94QV+fBQ5!t8#iRDYX}m|lMeT8q%JdR2tn(5|*};BRG~=;wNTP-!)f!ai zwnW5bsGzux<>hVcFYI2P2VUgRbS*@&Xww7mud_N1ra%pg0&o%j5L}E*{A;z9<z_`= zPvjRHI)>ZNcBOu@;YY0t?_hRe2kYRKc}n0SI&L~|$Hpc6#A&~d6Abv#wSB+m>Z`~Y zaJX)L#E3`wEF5Rl6FD5tDp~^(ZhQ4Z#Tz#R?l$b#@2VPD0Ne{_KH`y@C<=2sf^*ox zA3M<ft1+kJ5j2oFR>}<7ju+-#B0mFwr7!Lwg50~L8fd^lHg>4t)pU>122=%Y5nikR zL!;jZpK$6-_=lTr(f|?#CVQFI-s9BICY6|K6wyRd(}~{Hb5{YW4~e#uI!26VutzIR z<#zD@qjdw{oKXj|trfhYhz`(}9$}BB&w@!{?a-W(%+G;b%Pw<nBdl`oO~yMGm@N>* z1$RI<g>lr$uKO(Aw7;SZt<pfT`AmCQm~YZjQ+%l1^`+@o1U@6$Ljs<YF-gz$(6=6Y zYI(~`Z+pcSFMaA2KY959knuj6tX(9p^@-g+`r0S@#qexAGlu5Ihz&8cB}RN5Lx=Ea zN!Tj_aJI)%pJhO>K3L9Q_IPKP>`j?AnUBf)&xVHbAnv1zCvL$3`L*zCWU_4t|A*l! ztKxgs`HIb^csoJgy0_dx!sivP!76Q9Q7aX#Q)-8z-AZXMxO^M}7^a)SEcE}Oyj$h< z_0iC)Sv9zmr|D-21~ll0^RzosocPDR@~u)8Nm%@BEfJ=}axHPYaW|d;Qcu8p)O>ea z;6Hh;WUc0UIM9M4reW;k7VB2aZl~3BwG|E%v}>rJq_RwHuvASqY(?aA){@~2V-k*d zFf|2eiZG6t>{Vimeu`wf4hNt#n*v5FykhdY$zga@hO_S7tcVJzqX-Yye1@euTzk&e z;qQ2nev}5v5;jo<^#uFAzMdaz=)kVCZe_RRe`hzdGr|nFI2`j0n>pckSAiX1Fu}5V zwxKo~c(*-Godu!uc92~Vj5kW6<q%7f`WRxL>?nBO1Rm0%Z>Pb7vN1xUZQ9e7?K*v# zc>%m;z-uksLDOxYYY)u`kMZC+l9e9X=Mn2YorHjLGb~2T^|GJ+72XkYvrkyg^#{ao z#2Yd29lSG!EoXaTZd>kH&c2C7UG#9M0*~RA2GpFzL4(U-6Y0q=I$z*-TKdWk>zy}S zaE}^b^pj;Z(fKPhq5pBwVCk)sB)iwYlHX9cojveALp!AXy2}a)v$tBWk4Ej)Ug~ih z2G5L)U?<@AtX^P1W@uOF0%N|fbGdzudHP;2yMx6GDu>Pb2xk$^fc>5RjxY@S?|KAu zSA@UU|9|$hS>P3GybQrA16)w9w6YY_gs)Z?R!F$ZuQ?8jI|IIJ(V1?$i2L^tc?OWB z&><7|eO8&GXG<vMaMFecU!ab^qrKA%RqQ1jZgZ?%J#gn{=Mf6afQRAtsl%vmn3RKu zm9!hfbh;LH+)t_91do{SX@&41Pcl3sLg7aEOYb#r`@~z?*1OHe{u9|}cB9i-)o#QS z)J=2;++qI>FYdfxUq6DaKZ{SK1$i?0Kbr@{@11DBtuO}8hGa_^2Jqww!XL6M+imcY z6YmbdppKQ*0?Z+*kHm>IJTQPCmZjZVm-dI-bAC@?n^$~A1U`WKT0GcwjQYr5Jz|iT zf4u4Ch)rHj1dF=G5UjAC1;6KP_vwHYE9!K02gr&?=|@caw{MaB_!WW!jjM(D0#1?O znB7Rm2F7f~;dSa}Jch^1c#&-;Z?c#4;y2TJv*r@E*LGpgdUqthV)^if?HH?UNOCx= z#-Y3+20ORFdkeTNgfP7N0zO|GW3{j4pJaQW=#<c1JP&Kj``B@b7az+6xIOP<+<@?Q zBLSw8zN!<#pQr@5@5ZejgtwS=O7PB*Nkzo#zojJdcxOs|M6`nxGzY|v^_+*4>pTfq z9e(Gz8sQb*gpV-hyeSAz;sxp!A0yl2qxWLO_r8{Ry(~9|!$aYv7Y>(WX_}uOA?o87 zt77TPII%hQ@2ld(&NvSL7RT^OeonK>-wx>q#3y9Mi^cKP5H5(vYg1FJB;b**EmiPr z_kyZt?W`)cu`~_R;jcUwZ%MVFzX^6Q|1iQZ0%FRY05|&1#0#%6fPjb_wA&ci6t!Jj zyv1Hz;0GL23p({LB634o^1tyqRrF2f#*Xo}vW7sF(H$6UWsGQswBN757Nvf_Vz^QL zJ-G9<bJt@1<a}z41H3{!!A{3=Y&HEFwz;%{__zh%P~Qd;56f)|cEfFQ9aL4tKYmbk z5ux3DvdV<8<&qXkd4J-!`E(usowzC(wleDM(~5NN|A9xyqI5IQS)uC(Kij<9Bw1GU zK<1V5vdie8#0w3JSaE_kR52a~Ua7S4$UeRNF^_STX26!0Zw!=pR1cagUUK7qj<mqs z2waU|_q`ml;zq=Dr^m%hY`_~RX`f_c-g3#$W8s*#g%H+UnA7wIoSMlqP7tm?_8#78 z?RgErZz#N!fWW)<_Jl9B&h20~mjwEs?ojk*6ifPl{%pwK<Rh$$vDVX1n-;Bg_t!ER zuAV0vNd>0B7290+BsB154C@T=u0I!!0c}_KN~>Y&px&N@IliB%Cg>yfGx^OvwN<aM zi_2GLXzE6J7k4at;&O=@dUtS!<TDQgV%SUtTl)`^pANB%RoEUwc)9lf4`l)8M6e!v zL-8Y+P#IoV9LB3jfa4I{`z9X}$68Py`4^K+4#U_EIK&F@kEZII2+zvUOuPx`p?+Rg zWS|^Q^3pV~Sm~|4%PY2f={+A_L8yi&LMLOIhBE1+?|dTQV+>PcXjY6^8lzd;H4gO~ zb>~nAy?@2~q=C%(@(i}ewS>DWz1NM0N7M^Yp<vH;^hqGmZ{yX)V_dviy#!lgfK^XK zxDj=N-2@LW!y=-Ae2}LV-HwH!5D&rR#%175O76o;BDovJj(qtDwCi&xi-lL<98y?! zEwGgeAJp#z*C%+7G1LGF!Q%`-U3Mk!C?V<j)J;ES_~+iysV{4v&*yIFRRu4I><1k0 zUCs=C4Kt8=lk8Nb8Fp>xX8pF{<9OetA8(k##Dwc5%e7m?HL?cImszVvtrIJ~hEzDG zR_;Ln=hPgEp%2dFzB`-O1}*rE!Tp9d!{g@~do$KffJZl5v2*Vp2Kwn`euMKpJHa{a z`9&Q463opAV4<F2*ox`v;A8fWXKlOwMJ6W@tu{YscWrgp_}KULD{Sn;@hr{0QN$d0 z_&@mm2db2YSD^4zAMd*#=Vy9&2AgU$gmC+m-E514#vKS_w-ZJ|_<;*x?a5BQVN$9v z6aHW}9fQ|(h+j{`4%7y(z)1^OLw+L4@ru448pN*>-iOya@P-E<ST-ZgSNgTJIo8e; z+F2y!F4<q!%JIYY!jm-2HE=Ou$+vMTc|0DyQc39^fonn7q(n7xiJ$WvL1GtH9*}P) z{l-ruLP=8Ci<;(a8sae2E>hcxz9faMO<-8$NkJ(^p85m5ykCg$L?3<PJP@?RN2~Gd zF`gB{VJIIzwEUZo_XYbpPaz__GKS$3V^7-~E9S(}t~fs2v_6hsc|o{1j*jD*U_WEV z6F95<Vh2Bj<A|F;=5i@#O1AF(y~*BKYzIS-!((YXJXofMx>|0`mx%aLCE;o7*=7}l z3r(8nQPYTKlUhr(k-Q%heMT|Z1}!FU8b6K{v)D6$v*G=tMLxB~d+9Kr%JFe{n@{6Q zi%rUoRcm7zUukUHU4FbxQ|%Le=p+T<*Zc|d{o*};Ji?!FeGl+I2vQt1(XW^#pHq(; zfxen8<yc++L9$6<EVB^a7RZ-3PBzq9{m#HaBTph?shNaVE1|J|;!&RyeMPE-D9z*5 zrzT@&duYDLyUIiFdt!d{+=294z1O_vQ*Zk=bLRBeq&H&K2eDNU{w22Ualcp@SM9?% zu{SOi;Y@$C&3^HvKOW)3T+spS6*j20Li9>TeZk{CysfII1%yw#3f?*OnOb(!30t~# zd>{(Ab_z_8aA^E@sPfl~$N7h|=~jo!ybdon=tE2C{Dy<|(l83C!wbt!ywP-X(lgc@ z4dwa%D$<O3I9v0;1J@6TmATkBHq-~Q9ge4A)<AfR(HroORnk$#Pc<TpGmF@_KW<V# zQj-bi6TEm~d<n&TK-l^Beo3^SVn%v~OC+6*=e&Gsq4&}wUNzds;pM((0G}6=v^7TI zIUj_l#kNiJi?3s={lX8orXc)oTmrcHo49y{f93sz;Vuq_n%)3Bfsft;AFXYPy}R{^ zl{l(~M<jld?G`)EmCKA*08clQ-oWF4CQb1uNVxf=HWF<muig}i!Hayy$vXt+DLpYO zJx?S3BJVY&UNz1)Uh<Eaq=FcQqmc+_#<radevPemBvuTFOGS8fTr)f`l;)2|cnnu` zwyU;_>(@KQzkl|<>L^P^jMD4-Ntl9Q%h?UXy=?j}cDHa66h~`~ns|l|(;r@b`O?@e z@!q^;KP}ep(?ObXA|hniL7e%B{XAml7w%<yFCV`-D4SyQa)v=Tf|z5}Jc9QW;n$q8 z?v}Xg`T@?m;00@w5MiBDv|hu)9wst>W8-Ug1DN8rX8lY)X!DhVc&Uj^XJ~BL&RQqe zNW9rGQSlFJHyZDIA(38bh;b%dYP0OSAzQ+mIos)e^@`zU(;Z&ke_86q$&H%hyy8a; zNu1L#cgxQ_Y}&>Tyn>2|`CgrfUqKZ|yqtL`+k}D9U$w=Z`sv#z+vwka6@eCzcXt83 z?`R5okJ9v>r0EUsS|IUznB*#<_ayUHAqMJq3P-c*!G~eK!wYq6t0}V$Htj6*INA;L zIJgS*%dumouWzpg`aTMeJn~&`Jg<TX>vXGi=6jflZGcmsQxrHwfxkEf0`{lg{q1y1 z2lThTTTZmTeV<w1d+xbH$G5&1W=eb>YHxiHy21KBcDwamy}R|DW`D2iZ~gvonDxDK zg7y8|tpCT}d%#y&WbflM_oiGR<c3awNFa!WP?FGNh(M^)dncq^NFXFJg<=V)fY=a~ z#g5q4j@Uc0E|zsy)`Hm4wW6ymyVwi<pEGmjEw>R}-S1z2h7b3=XU;Qc&di*t@4WA; z>88gu?evkRT@Gn_(-)eq|3TBwn&hi=w{+HY@?uTb)oa@75=|8dKPF#>H<ZHZ`my~Q ze}wtBng5>ogtxT(JLY>b|1I;=nE!_Pi<tkK`TLl^lKFkiU%|ZRZLR+j=F^zJocZa@ zU&j0y%x_`-M&>VN{z>KsGXE{}1DHSdA3DAM%nxV2AM+<M-<SDonD4{<UzyKl{!8Yw zm_Oznt>2V$Rp)@Zd~VGUMbA53)65(lzT-wWejDS@*sF10yyC`h+u_DP$M|mX+Al{o z*3{_Vbf?A}{$}QtG58shrtMfbPsiKC{(Vz{PWNck=rQ^;?{V8##rn$!YX5zPslh)N zgx|sVzGF51Z%j*uYu=={<9IID$K2@|xuJ(xUvqAk?=dy$cl(n&{*W$OZ#lQyyO@4Z zq0`@O!i(JY7=3GYyUTmi^O`sI?qGfmr(^6i^5<A?!h`8TjyLB_oqh$=L(ARvn0O|g zzKk1v6#S55b^g1q(E9S2wp*$BIOcPhnski);su@Gg{;TOP5BIAxd}J8FWCMmtk?LR zNzd>mo}q_0oz@(05!0ucn)v;hH}Q<URT1npxXiA)Jm#&{`G19}$<L19{4jpsc^ZEV z_xA?>To8T}<L}z6@!v2t_#H30{WJAAZO=D<)c8amKMr22`Q2A*dfR?Y>tE9Jp1qoW z{Gz6*Out~<FxJ<W>8{r_&Xj{GuQhwQe!FQqjNH&&Y~L5Vbo^m|(scNptnUs@E&HC< z{232wy6;|1H{7kMv9I=F%}-z&$-YVZqT9ES?e=}B^{r=W{L4_wz6O?`iDziAeWpH> zUUS#yCbp;RzqCEgdE7Vn%pm+O#`ofR!4{?lKPd>GnXc<;*w<SB45p^OCb7Jf!%q#8 zSFt>a!#6TD{&0xXGdQEy$dg{z`HdvcWcdzG$HX_(geUO4=N+adzYE`Rm*?B8r*9`6 zzLw`n2EXG?H-1ugT|Vneba-|^(~_BPoUx~h@xvK+i0KFO-FTD#9q;S#O&rhYG4kh* zB0t3P9YOI;ev&?Lr)$z#xJ-xdWNQ4<q;IIvo6ERyN5QYj(B<{eDO&%cQ#GAb>9)h@ z-^TcrjO%im#;vS#<4t*p13KK~!{{;c)Ch8e+to|k_rf2vo)4J5eSzjrK2Os_>om>T zrfG8yuUf15w>N8gAM>v<oyOrwOij9mzRl_H<aEFKiRqup>HXOBMQ@$|%q`mf;Y@?` zA9uEvx4cTz;QU8Q{}Imjr4jO<%IV+2`EDE`edCXYHZ=XCmH!Y<zXPW`<7ZC)X!&2r z>2Klum;TJ@oANT$_?>AVRop&|9|p@evE0;CuzUy0O*sb3pJTbnXR!RxQRGP<X@4{8 z4#^6FY5$<`1s)w>a1(Kln*I#GFo-`bh#!#T#&=X7Di<O_2a9dfhNvrb<Q-REU8n8* z{KyZLBv|Mff?pwG)vpjMj~Sw_;+X#`M)QrC|F?R|R){9d<Fu*z!;w+fpO?7<eRR9! zY>Fft1f@Uyh5{ktH7nG!p}5|ZKSYI?@Eyl%-lsx^c$)={m^bNTov-q<DM#b6Y*oC` zbBOsR1GSu^|36E*U9bJ%|Jefgjb(f#_s_xE+QaRCKhuLuk1$P~K14-1hG{RRc}yoT zUBI-0X+6`8Ot&)K&U7c!JxupAJ;?M3)5IB^KGR-I^O#Oxx`1f~(|V>GnQmpeo#{@d zdzkKLdXVW6rin8-eWtyb<}sbXbOF-}ru9rWGTq8_JJX#^_b}bh^dQqCOcQ5u`b>K< z&0{)&=>nz|OzW9$WV)5<cBVU-?qRy0=|QGPm?qBV^qKZzn#Xhk(*;Z`nAS7h$aE{y z?M!zv-NST0(}PTpFio7p=`-!cG>_>7rVE%>Fs*00k?B^Z+nMfUx`*k0rU#iGVVXFX z(`VX?X&%!FOcyY%U|P>~Bh#%+w=><zbPv=0Ob;?W!ZdLnr_Zz((>$gVm@Z&i!L**~ zMy6YtZfCla=^m#0nI2?%glXb@PM>Knrg=;!FkQg3f@wX|jZC*P-Oh9;(>+Z0Gd;-k z2-Cy`oIcZDO!JsdV7h>51=D(_8<}opx}E7xrhAy~XL^w75vGZ}AAAhcUQF|tPGGu# zX$8}IrW=`VWxAc|PNsX9?q_<C=@F)h3pxKx1^>-r`^>(v2{-eq1-!qDd5-!Um7kxJ z+HKT?>FKF`d-d%#AT>KPD?77KR-e>vQvxNaqYG<wc+af<>7wD_taR}SlGd{~JqJrI z9HNYQpQm6+OEo`2g<?j@yqSSkG2fP_w42H`KAG`5m><u)Sf=HdFu#rYGnvn<(DDh) zuVH>BPch%F((<`1A99lB&t?8O=3is`IoKleaD}hg-X?_3?`@|HQL;HLH6(76=8xB` z7{)vv?^J*5nZK9$U;@R^e`u0q{kazoQIOACYh>n4nlII?xRiOL{|)9lu>7kadG5_R zzDfT-%x`7<rdzc9H0Bd;)%@ek2a{7#t{xoH_OQLrF+Pb4`0co%D#|F1XztkfnIFh^ zaPVlW`dh-h$=?gioB3#KpVnvcJBN9b-{s6tVSP_CKbiS<jdXk?FK1q_L$Cr0Dz6t< zUd!>#ohCdXtN!Njou}r^mosnb|3>BwKG;7VV)+Fee@qi?-&xE*$GoYp^$A-32+M~x z)qE?d17;;^-r$@1HGeweH!|Ov+r#zEw0ytRfHPWXz9-{%FyDyf54F_tAuRuf`6JAK z)k@2oFg~V@=HFoX+sv<Heo<R3@5uJ7Z>RZ|9RKq6n#XbBuzxrl1^?^jjbZ=0G)3cc z=WF=hlQqu^VG-<4!SxqhU+;1Jot*x)r)qtMUs$jCKd}8@tkL``=Bv)s{1)cp)@%M` z=GSb{{2fx;n|Y3#fBRg`oA}E&YTm>@v`O=Ll0*G%y~xdv+pKvL|D7$GH}U6Prg^*= zP5m8nh34;J{)H<wZ}hL(>X!H2=9a&6jpna1`MX~8>rDP{)VxXW>6<if(mVAQ&2MFV zyW2I7Hxj77ZFgw?cB%OZcWU0~OS)V0M&Isx-1zGI-1xo^xbX)b)I1((SAQEG(fnD= zCq1TlJX)as9@(XNlYaf<nm6fZ?{?$&KcRV(zf+&qyvd*EubMaYb?LL3U(V?#KIfKS z|AJfI?j^T;$IEVc*Vo+gN8WJDv)^*dpZ<qip7)+xzV`#S{KSvk^0)u#md`lomVa`{ zEiXFkmVfoRTVC;%TORYRTYmEQn!kd}tF;)W>S;CeTRfUK^6Xf*{H}Pnd_rTld{2T~ zzQpgAf85M1U*FO#k89(WUz_ZfckbYp?>xpW&+Futzn12f&*|!xf6>h?U!LKXH}B<^ zUzDl&Ozqwxxc_~e<xfcsI44`<4bRam(gRl>@f@B+)$^rkeKp?f)LB5j(D+%)48Cu! z#`o6IgW)1q>7RIq!J88kof9-PcsvePaH@)bt}l-5+c1gq&s&(m<3;dz8m#|;xjMd? zZv>Ao!RgOa>5pA$(odMD<KN3u`QZ6L@Ob@rfyNIER?NIE&ud;b`oCj*RRsJa9;&a_ z{&+4Ab0TCd&p*wH3k<vJ&zxW|^Eq?!!0^HIzgB!Af!#-#6AT95mF0#vCm6UmggJp> z_~7~pp5K|19A^GyPFfh=oSZOxr24vu^Sg@eGwTx$7G^$q5z9NUV0#eWoX{}Ki|1KB zhVkaaiII2V6DZSJelqjL%)iNeC+3eZZ{}}3R%!n*_SG}rkMZ{~e*;&@oKrOZb(Z%( zRr7tBU&8!c_zC?zS?`vA!@QAe6dvhe{WDJ2`2EbA6FR2+%}E_IpEf6cjNF|3F><5d zQ0?!RpXy`(UBf4TdPL|yG=4Z<lA{5)ovZC@5&^H<>*fxP82`Y<8viL**dMRbyjed5 zug|({)$+%U!9g?^yhrrhZ1f*s{1Lvh6Wsp<MHkw>*AH6pZ`bK<Iz}Ud+e@&%Nd9lq z8K>;aUEG-Szw&Qd|CY`g5xl+$?jMaFLv{JTi?<Q!0#D)-AxF$DCIe)u@hwxD7(AZ@ zN%I5&nY|JeZ{3?=@O{71_U7^}ui*YEczs$Go3Au6Tm<(oCe@4hB6xjh<apFK?4P#p zKZlKdYdF0x`A%4{J;C)CDZL9gwcz>;9?y+Yc&BREzj3e|@2kBq!PIvfT^<usG(6b8 zC;Mu7DQgS1H`tzD{WQKk<4+9Y7cp<f(+8M0>;I$W|2xK;@;JA@PS5m@4=``~!-LF! z&GsA^pz$Tlj~l4@)?8jiIhx<g@<`>&Vxj$a`rf8oo&%59@o$YW2shRE*>4#9dnago z2d^7vIE}A($KXZ2#-AS*|JcU{ziFh#&rL8I-BjyOJYw*lOwo9}$Uf}fsR;GpdjN@? z-wiV~{%)R6m=ic=yf-ItOn+}q^zd?Cn3FxG|9_58?pz->bs=>6qn4ZWYb$j6-?q{b ze(Cged42f4N#C5bxs3bcV6zXX{R|4FJw{P3#L)8cX{)LNHN&Up<O~l~l~=BsUQt$? zlT&XqVx$8{sG73H6$(KY;%P{0YD;o*3Z@hl)K&)qxr!?)tSKulsHv?kt5}>{Tv}M& zBUOddC18bRwKXa@kHZVg%PWfuYb&dDXsQXXDl9`#WkpS`j{h_0omy5ND6W}VU078W zsHO}pFDnjoHwhL@4M1F*Ra2`o^1m~{%5!<3rsiiVMN6k$zN#Ajm$^#KgL8~8D66Om zRM!@WkFh#1ZWroKeNVEb(VX&u6~DV3wYneCo+9|Y<s!dLw+mDk)&#_elihBWUs+LG zU0GgE9YDR!i0<gp!<Lik@Tj8@b20li{u}I}ivzV|&{Y*y0JmWEQB`eU<5p!G;<hU3 z%*Z%9j_7ig5X%b7DyV}O_u%-EzL#`7hOZ{r64&|4$(b6cri|p|tSGB39aB+NS39)0 z7+sDyJ`!kRU9F8uUmr#lGCno1Y<Zx1QekazsTdj+Grp{%vRcfJjwxIM%t^qg{;CpP zHH{7#KWQuxZ-z^2MQK@a>Co!MH6jr=L_$iZ3PV?|5<e17TwEF`UaG|D8^Xk{3Fx?W z;e?AY0*zQ%R#RIeo(LybmQ7t%QCwPGNyD?)aQ3gWx68@NFR!bq4OIW{hgV0^zlk2s zl^-5bb>H^!IlntcgC~`ynOlDOn{^H|-&%HlnC_{b2LZ7WYgbby*1%v%4~3JOs1q*? z6BYg5xXQ)TDyzzhYsAgr5G9yj*9NR%@=xI~&T(`!c0WQa)ZJ^{vOop;&|^1;K|lr9 zvDkNA7&(eZjnkNrh7;GQ(QG`8LIvVT6a<ZB1)@2|*f2&~BVvK*8V*rbGqtp?7E7ez zl`AR=)VO^PZYJw98k_GIqL*WM;Ot<)UsSd@Cx?byET#e_2&lk{rL3|-6hwxj#6sYg zg~FBIN#pXz7gnjUNsYeC3afsm^+=CYQ%XpqJFoqI%@fa@9Lh*uD*ol<EGnxg5jWwq zkI5ugnJU!$^1_;$8G-5=s;GU@Kobg=1w_nw;nj?;tf^Ii>~MhM%BodkDyCIp#wO-C z8op&nO#mi-w=s<F>Oe8RtG4OaI+mzvV2Apjt>LZO|E+m4*6Vt5(Fwip?|pzO0ecID z7Tsv@?#_(+fO>S6VyP*$U)iQuPR=lF!!7;4n5}cdzme&fl^fSg{n?9u?_C?T^=rmY z9$SBdy{nm>r)~MYf92|JSpTXEPK>_v*V>eR?_vL|yF#XG2<~Bv%PT7a1r?Pg0rBQ# zzxzf5@3DoH=5L~_4e<@Eio|1=hgtMs5v{<Y=@sFnLrY4ku{S<!m9_5j;#7qxHfvc` z&sSm__TWRLNX0}Swu&{1jd&^|98%dc4x7V5IJO<El&S;EDwhX_SJFnmS_hu)*jTVo zND*VFXn9MRG>ob7w}lbvh&p-fN4$_iyAkvR#`WLeh3I8c6jfpYnv+u!s4Xlj&&jD# zTMz}sm30+#+t|s9dzavi!s=#gP7dF09jf*z0Ce%<H3t%QtM&3Q+_y1h6|>aVWaRq3 zE$vhE3L_ndyUFGGv`1f4w@l0mgHYv6(a&%Qrxn&L%?)camiK{`f#SN_fcOLvez7%? z_TArJGgNycM=H4FoVW3d>K6T^yE^cqAT{FHO4k3YTX)%;c>foRFK6n%krkLbORi<u ztyRBZ`*o!In`p$2{5W?w+ML8?xEx#0IJLvW0{8z_wbfQHI-)#4+w`->k26PX?1_GZ zV(GordYzCcu5l-<I%0L4MO`_2grC%_*qb^*2ZL;@fB7WcS-zvro#n`-HnbK8u8J^5 z{m9aG#d9a_S!oZwc2%P9wHc8Pj4G60UAL=8TjQAj!+m2;_&3toTDfucv-hmBri<th z3b>~*vn$(wdZe;Pmj()}3iLwGYHcB#1IsJRO6Z0QT+r4kR-9(LscUW-GS_?*$dIn$ zXPkq)=di@gRn=^Ccp>JFN%gj!F6qP-6@hAz8%aDRP#&OzOr>D}ld3CgD~l`3$J63> za}<C&OR_5rfMS-5Pr^v1uEOz+Wuh$}u`m^9%pO)<h<i!H!$|b%L{x<ljhSTT^jC(F zss+u{VFZ&3s|%OajKpF>K|TXS)!~16E@<wWplmtspFIMhE0Mv2f6|B|@OeIW;i>aI zu3GCA6{6~GUU<m3e6FH%BFS~-J`hQ)tMLPfU77ufC#|NO5tLVJg}wRAAPLshf!dkX zWwim-eOO~qjd(s78VNWQU*dAPrP4ViP*@VIvOX9ImEmv)Lve8OjCCRD;AUxQa47Ps zCk^5|e2~Xwm_GGjPo_k(4P4*_1$7l=ICNcBSYCE=prnA7_XUNH!^a_=)lc%m(0Pry z{r-zio=hTEfBrwn7)@Zr&~qA4zD0%q<tcTOy`N1{P&xhAdR19;I?t5Fuj`CH&b(P? zTYg^_|18_)&H~jFeaF%Kt2eTr{I3>uyr#SSLc6!Lr-eB=_O-Zd^RLx~d2Y<}*x#2J zKk2Cj>tI5N&;DzR?K^5_T3j8#MBDarQH?LCy2fG*(+=^7tAfOJRV7d`wYIRfu0}i> zETv;o`IE*}EUFYggqKZM!l7G()KWxxxQZ2@8A+Z`v-l^1rDZj2a-c-WtGO-wm$To_ z+uY4vO*DSd*+9r*?w3z8*kKCmR*LpFg~@o)e>)clpSk~9ZMY1q!y9vgU0TmP)t#H& zcbd*J{M^z+)m;<jFd+e|UhKJuTTaufJMhf00tKz=waSp92vOjCB#f%0>i(b{t-vFK zLu>F1gm}aunpTR|U1IGmx>oww5vaja86|b)0TKT|kUBc|sMQS*7E#00qSGCsqoic+ z1!X=Mlu#WWqAV<#T3)z3FeR`UxAAb|QydINsi#NWpfTth#Egf7)Ro|1Few~gNSbVo z$30>Lk76oTI+Lo)DzVU7C9ZQsQ@tgGI=Tf(c(lQq>1LtPe6Ay!*&zth{9Z7mtY$<- zVNp4{w4|MOqAGStSxvE?`-x=^*-^4uujS%nM--*59>3z!CxQ}Dq3=6FkD{Knr#xxv zIZBM`x(e~s(>7cgV>0%Szt{qMs-tdxT8m+E;@@nLiXB*q$7hRcv71y_L_0!{y%GeV ztp4fipg>9!H#_wi^L@SOt}eaT?51O-`1EEzE>Rj-DZX*sF*e?&EaHW2ms{<d#%_5T zcKOxW=J`j3WQntmipdstM#78>R4lG76|YB<kF2a-R#+=y9rw3graGUj>KztTT3F+J zFm84vkn6#?GsB|FYNp_Ehl<*=<pFVf1jLNW^1@o|ZHbp70H)$*c44)Uw}&fyJVbye z2+9LPtE&rFiHr!C;gxl0X&N&<0*1OE-i8q6+u1ANWY&}1KjSv(#lNurhoIk#I<DFu zQB_%7s`g?(hy<B7UdeOr;36>dte?68SPw;^wy0e|?W<~o@8Pg0^sx?q9a=M0JyI_| zj0DySEnJHo;gW_@HBhU~)Dt2>lyqq%=`=KW%w?BViA%ylFtW@jEYB@bewQcSjRG2p z5w5m>U(w;taK>sysz#<q0pu<sEqUUaC>WJcpKS5k(J-RLU6D<}1fQ&37X_jbUxr1X zD_%ZT6^?3+*~4>jbZv1eo;K}~T8A!laRuI*3ocKryF0oOeX?1Dcqc3}D5Z$$6x`FG zbi}Pk#fg-ABdbE8pzJRQiwH6mg`&!%rnIuUHmFom?u(oRRZUiZQz|EiMFu4mIiWAZ zM%V7>NJ!-4L9Ni{&Hf)Q2Ny(%pcRW}qCuuosfgGIj+(6UqRCNks<^~?Q4l(<r@|tF zN)nZ(bE~S(a%J_jgqZ$dWNRtU15Ksf6%Ck=<7Nive<+;BAe*9CbY9r_cJ*qD#4FKY zmOY}&!{Mx9CkQHwswh}h7UI@u2uf6Z5CxIToro^^>_;M7Mg=dHMFFU^ZVC$sDrr|g z7S8MYKN{JN>B`Ma&0ZW98I+!*Hw%|q(#{5@Cgw%K>9N*WHTAK`8XZW{Y}e6nVp~`U zM&&7iMVy>9aK`*8oH~u=fzwzxCkm9tPlMYL1*b4p;y*+|IujQsJRaFfD`~Mh63RJK zcrXfx(-iMU!Kj%+(?3VHhi3t%G_H>V)upjW&nyl{0XlVxKD&>SxKb->BEhIMIL+Im zU^q?j^3gCtJ`vd<>Tvq^HHC3$!;r%NWCV?{U27DJB0=Eft~9@I5Kz=U6*)<zPy96! z0x6PF_I#=6=?J>qNbzb|9Q8z_Tr)VUgD<05oSDz%iITrWNQaBbw&+h`kwGctMoK65 znFggJHXIcv-iid#)n;3~{I3zxbOFVukzgnSRVQNj-y$nwzvN-unf*L*Q<QjA-S$NA zNHnBt=$ZEHQEUlo$#qd;IV=(HM#I^5h_pT7tO#-jYr5qul^%NKusy5-3>xfrcF{EX zdjpaRlW9(9ec0$B35ge?;KFFn6A90Sv&*Si^p6Hnr70Fhg1|@Ju7!r1Cw51HyBw<B z^AW6rUb`N%hl`3RKxF`DUM2r%6tJDV_&y5EPF&=^5Wz<HfHT$QQE)0%u`LQhm-91` z5RP)T+*D6Xd%YOJJVc>3V=V~QMg!9P)QnxPL;>ou4l?1my$vxzERF`V3=n?|3kz+u zE+cTKL@jYu{b#)t!5(h4R*`Is2DB`K`yB`i46?}{Rj6iM78UPnh(+R#XfVqj@pTlK z+lV~T=jEfMEapc;P@>}eNC<~lx|T}+juOG?lA~UUU>p=%*+ubR5e3JsUvKwN!RLvO zqrk1?MfX=5khmy|gi@{Fnd)^>kd&%;HVQzM^OunTC=NAAH7#`GYvD`}a>oecnmwsX zem$HP9vbWp5aqu-EHWs)FvE{?3it1@IzmztgWrf?6$-(zJcLyjHw-EEM#7;A-5Phk z86j;qQmoj2G@N)SEJW{Pa5Y-1!)|YdQ>U@2-tBe8x+qX<eTcGoCkjrt7_*^#!rKi? zT$~#PXeBLPj)F4z<~7-fe;g%cdyahV(V(Vf{164G^UaCRd#7QEi<^!HRBFXHQD7$D zs_9w7mKv%`-;Hbrjox<6KM@6~a~4K@=l2?<UQ|TExvW=4zYzuPvU$+^k&}1Wtdwqv zg0+>315secQg;#0_#m<oRK&KI-5mv~&2?)|`mjNo#k?puW3wuQXQBXImL7K?a?09L zrEhH%n5|Dd7X@bQ)6*+={_{SHY=vXFMgw>>q-&`8Dhg8PESx3NKW>mE;+kkU+Ya$* z6r8(6R5{Q6XXNBj&h{$tfha&bc@$WyPa<n{7K2K@IttiMUhIqlvlADMKRrs)m{?eT zpeI}_qeOA7L0*ambk6v)4<5ycU=uEg62Ue>ydDi^86dL%b(G|3a^;--ZHp2CRbZ_+ zzK?>ll1Kf|Idl{Q+{xb`1#TrTy#J1@)Jj}T42#keHRJnc^6+33Y|zZ5^?$-8uGL!8 z2jsja3Ql{zN&ML;NN3_A`EUc07J(=zlW(3p{5=X(rEHHWJwA(^wt}*1ads4-&NnCi zZWN$1anbwph9oUci2^hE4l}iQKT0%eaQ4h)*cXxQ&^ZgE{>mtk9O}h^C^(n(WwbFh z<;%#XxNN>73eaJ*QrhUNhA0)&qri-%R==tgKNckhm4WSL9lnlif;QK!d3hAPL$i21 z3eMQ9OzrVaWCL85o*f0KEmiv7jRLdviQeBvPS)5LZoY6?lz5bXd&K@C8qyv$(Q!@v z?kKi|Ss>?$+oQyCSR%fThO_Mu`QIPK3Ts<HmGkXU;I49Ld?d17J9!jCNfe;2U|k_9 z`JGX~cJiX}4-H9NOp5|D-e9$ZVzpJYGfEUHerw=vFYJ?`u5)m-r)UkH$bVfFpw54g z34f0g!8Sp(mklvM1fsx98MtOHe~%KuSpYpek<)kPe|;1j*S~Y(^mY`umAvTTZ9w8; zc~}(oQS^ry)ak%~#zfFW$9?N!!wKt6eT&bIB5xmOJ*gl44IVi;<}75-JW(ERryBA6 z@=J|ukg-P{D2D%8rxYhAgafHBFaRb*VmL9TVEX*6Q`3nJhpuZl^v+07bxPQo{<jTA z_V-7~REW-^NJ#4lrd5z<CPh%HY#g?Vo@=5{GKo>mZJ-XCjuXf@{u`*ld#tM~m+3%# z$i`~;Wi%J5Zqcx)bwKyYE<lXuTiP*fA23&9Nt<xulDcJ8R{e@=lOthFaS8hKNjlk1 zUxeK-T!_nZ?Cv+evZ4gptHh_P=+P4KQFvKVH6FGo#={n(+wox|Qy&DETpV6nhle$a zmx>F+OO@=y@G|-ejW$rE<%Uh!fv5|QuvJi5)Zo8I(ARFi94f>E18t?_@rIa{IXP@> z<3S-3W$3!l@Ol+fd=@Iv0!sE~4<$SCj#!a9TZm@{+sgGB$q_4y165oRr8uVlWi$lZ zcs>p;Ev~FyB|7FsQAI#{aBkF5K;!W;zrw`<Q5g+~@3WMfWI4h}Gzpc!IU}Q3QC_)N zd>##;x-?NaD(GPOPkh<JOVDEuo`w`|QC(Si$;i6$a+BrlW1^tzgW`+5KMH-!iBWV1 ztM-li5#UA>egrsW(vJX>v+nnjv(guucU1~87Y=L66JN1V!_+i9Y!eXwf<!&;R#f<l zJPpx$PEgADI7KxM{@0L4O@&Y;ZpPl9=q|N$e;z%rLr-uqp}6odB>o_WXMPX>QyKM1 zkZF}X{M-_ZK>LM?;em2I!m@usP;@O6!xpmr{LEoUh5W=9V<<iL!;U|XTK(9jd2892 zqR=eqkEBq?!iAC*2m+zlT;+Nf03p`>jL+nJ6>LB~k{4SR1(~HnmoE+qCFt>`L4h^3 zl~wG;IcQ)muYm|3i75~hf(12r=Mc+^f@QVlsgnY+JXnT!<&}%a;1L<L9lS|}8o0PA zhFUm%1APVpE*fha5i;$mtsGam0xw~j<?Nr-bjdL{sx>Zrd4o`IGzfLf_^4*Fe=KYe z>e>dO-fIx5D>`50aM4~;<LnZDQVaZbyhP>wiNCtu$9}a3J!1Wz>A$)RRMpj#78Dg? zM!jf8)E2TdP=S{xi7_*yp{mQ4%`C<1rlwZWklq5_f$5Jzx`N_@z_O~^RXSX){-=`u z^dA>ToX}vr>Z?}a*CVcZIZo6K5aRpZwt>^|`UkvWnLbyEM?uSq@G(TZ;sPO)0(bzs zM6AyYi&e8?pu~Wzu<~Ubol^gMA|>A1A1~G}lj8gDg?ZI;QDI2|y=f1}X7J8uyrr%{ z&qMTDil*>Aj#yypz0i1(pR%|F^;d(BP1e`AL&W3;L@Ei?;4_`8#MNQ2*akx%ANIx5 zn|}yrPe46uUceh1w8kx{EiJ1NF9K~G0q@PktLAFdXF;uN@l9BLCVyqis>%zhtalRF zJ0bLnLPxGOP7J}e8Ncr^Oko8nvz`N|7kY+OxBkbdbJ+&xDA2DZs}_&`7%f3YIrY#k z-Y+>r*>3b7^$kTXBSYRt(ZE-zx+ih3V4Ln|thp1gqZe6SgjTaIYNR0VaaDI1SNsIZ ze#zPz;MjJwZGjuxjF^Q@L@ot)Cu15%bpW50ttrF9>+W92ymB~vteU_{bpd>amwGLH zE-y^$WS?M1Qg0OvaTD{dQF=`)8yW5$rD&NISZD{ox-@rDVR=me!jb^5E?^FB83sgS z>{B^19rO+ryL6(a8qr!5u;b0BiA}hY3+rktsR+ZA1$8Y(Eczh=8>e1Vf?ig46X7C? zMK;>hSV*52E+R^$tfs0GFR-}C)({~*S6dbz+W4cV=!$Bm*}}2mZ1wXf1nXMl0Kuhz zH<47K5DMx23SqL+9i?Yh=5yzZx9x}#TvMy#t~ZQAtJcHE|J64L_3mCSR5JiQ(v-cF z-oUD+d@Bm8OLA2M#QH$fJn=BL*P|^+-1vwsMEnu^<VsJ2n!kEkk@C%g@<4^?(aabz zL%sZ5&2Y4-5mQtuOfMid8x0Ll9xvNn94OFVKMLbB-Mi<BORz`&BQwRHp`ztMb^CC+ zGEG3www%3(t7V1cyMghnms?py^O`Y(i>85!{%ZpqC6Sx{<4VHrug#0Z?aidf<~w4A zmcsSMgrk;%L(PvU14k??aYqTH50KWB*oL}Z$e5pN^^ep|v7KffZAY>?vv31vh{a~W z&B?KqiWl;2Ypf1hZO)D?tFEc#v}hx37Ct{;Dso3zrbS)5;PW97S2m*X=TLH6kdjK= z5>smnm9pl<^9=!g1&}FRM;R33t>6{Yt3=Z1uwr_zu=rDW8K&)Aay3@bVL?<~xnj(s z5w!RfE60Xain~mhk=3gEZX#xUSPXW}mgQr>ETeap)z(#4h;<Xf0_j!@n;~wT85R=G zQ1MMcSgchvYCVm++E~(FeyUI0f{m;m`DUHRuZ>f$m&N+Byj;}@^2Lmp93AR-IoT=E zk(hnbx0%Ib4TF6Y9air!aW?L6YKI7$8wZk#Vy(I<H~g<YF=?_8vqF;@9>9C+Rw0)9 zwzQKISN$mTQ%6IiI)`E=iZ^tX6(c=WJf9ye5}kzzj?^=>1hn1smQ9*;yS_8NAUYaW zsn;EycT|}9g!8>eMVb$#?>{PXRC#3)K3AnmU&N0Hsaa>fP!ukBs&&87as(&5-e$ze zhC}y8hdPuV4~GhJL|ck!4~7->p>@?FuZyP^xw%6laoGwX=9PqrN;lY5=dSAG+^7(% zE~28eb>_2YZ$-u0ri(__-4I8?TGr{xs>4Pceb2j<b&n(jiwdAfA{P)nb^W!ygc~P} z{x9CXt&;tXd?1DM!k<TRe5>+#+(!G|E6QqX)SaWy`LjChNKRlTKfhhC&>vjyQ}(+< z{Qiw-z2iWiEp4?V;uvX-ERi9YEVu`%vCAT=<8g|{>8Wbs+;ejyu^nem9>?Jx)km3K zuAg}R<Xy+j_wmDc?x*h}(N|#bFioMTb=;SBW9Y@t3L<bL*7OE$2>Mm*Cl*AM!~P2K zP(*RPQ=53Jfw-=YGe=GZIXO;F&3+ntY4-E_!A7ERr4SEI<6<o;{6)?b{ln=0FRRUi zTd%76e<3^5ows%;44pK<=^2=pPo=OC)zy{N<|NyN(PFHyd}-J$+fkGfr((;U4m%Eg zg+=k({#Q7TXhp!`)H^;4@QLGiR9K+nD*%=AqL`@N`ESu6%A=oh9Ht6Mus$e69Q;w} zevY$PL7H-Mf&#=H(ZE#Tlyh~8lA6N`)f#daHx@VI*w8d<8R7iuOHPjcj_@-hBDh}h z9`U79?DBNhc3BObm7Z2PB~Z*u&I40_o=$Dr&(z8uh91+aIW5PDCguC0xx?w50N3X# zCPn~J;j<rK8x^8m`12?jhxd+j9Jg?q<f`gRB7jON^Hp~}#nDRLN+wcwy)lAVZO7}9 z`7{Cq+cflcdGVp6<vLT)2Li;kj`r#lmsBbPE_JjQr<gWlX!C-We~&c)6Yppoc2uXc zizSZZb52M_-Lj%UHH8$2`Use^nxW-*$9RFbC?bGf?~MZ~_`{+D1JS#GZ!EGf-oB0F z;SSfs*>G&1AT_!WnZv>e)kYLa<E@PwD+cbOnYffxp-QS{N)z$;AR*GTZEZNFhcB$4 z7tvo@SsF%E&$4|{WR%D~YI|$nj3%PPRYJVDCiM76l+z+lpKja4tM>?>DgQJwa#3A{ zc7@n8xnDWz&i&7L1H~LOow3f&3h%07M-(+;Gh)SAHYR#@-*+Hw1+KdQZ=Y`~!^%v( zR2<2fOOdhBmg|Q(48*~SNex0>;XtX)XQRqy#I6QlK6GG=p-!7eU0~a6%gvQY*<_0y znaIg;FyhV&ZIEqVPL6#|ZY%aHzx~hQCSn2nHt`HQQuLZhHBR;mP02<<zv&UUl+~9N z^XqUjcbVn5HKHaINK1}j*ad4t^r^SsJDzWQ<mixX4(~Q~uc&CcK16@Lmh^Q<qL=9| zAk{SYs14U{3!(cJKjMC$X|(sB{mag;cb#Jwj%~WyVzp{gq&pgN$Z1GAE2jg)JrB0h z(O$S(blH=Kf1gAn&7=zxL@e&&o#}Y?K6-83<Us0Ak0^uD3dPG1sft=wSf#%v>1+i* z=>#(0hYY%jX&z8B=acQbx~6Sd2z(NWb(G@)qo2ttOQ)T%%D4JNS8*lw)l);(W&dZ{ zr`yQ1y}76i-%I`It6$colfJfH+Tk7J3XAX=<J|B<?UNhA3r$7l)6GCVkPrDLG!5tH zfn&Z6l?PT<;m!O;S&iuYT_^@;^jw&U--lwB1_D*VUwo>@8Cc_Yjy#*hL>!KAhPcDe z_;AQ%qyPV>?uQ|qEEAK>5z(LZOLnSc|EvB%f3ch_oQOxqo%+=E&uXpl6XP7#?VE5t zNr=<@#6Bc6QQae$ac-44ZCdbaxdG;^q>$W&oLvb)s2-7F|AX&-{v6g?L(c!}!x$c& z(f4C^InFRgpR!EAaT8}9G-xUq;zbRL<!)Fb@QMYMaI~kie&PPb%#r>_$^7s8F;RzO z$6U(lj4FMnU7zsoky=|_7vP%2In5G0SyEVBjEP_YZfoF#KxK77ZQ)`}jtUBNRO<kz z-9d{dEd4Var%FRQl@NysL8xgM{FlopAbR3NvePj`Vl-T*<BVW3UIX!SXw`$N@U?QQ zQ>uSqZwkrx{~}S{cHNKW$rR&TzYmQ$s?z`exV&L^`F&{QW9S89W=9#aCei1;@Eyro z>jSvr(l9vsBCpt<8mfT4$16VX6e_^|?&W28a<fO5$g-=#$Z!wQ^t0;o$Su0s@gr`C zoZ8I>ndMfPtksBpS)o8Slr})Hhl&l5>3f@s7@rVzULnQ=M&anK^M2;!7z!P+5{Gp+ zt4sAQ;FocUW<d8C3Mwiqio_eSLR2p*o<#5OxjK%bOku8VJaf=YH@d_nCSWQDkSXUW zQ)a)>RJ20uZ?N|`CNRFFNZ*E;q%0dh%(^f72?yBsQ)`uNh@tL_G=eoMzOwr`!zt58 z7|z)9s0nb|bDFZJ;+>{qGKywB>{(V+uuOgEn4Xiut^E7lVSMZEV^?SiJy6vM#@dn9 zvF9QLDccK*O6X+45tu-kW0nf!0cF5rA2$^fTL^I%%4}I>Nl{%*0X(K)Sy@E^y=|bf zu2xKkeJrZMcUtMWGL^>VcDOe9Svx@4)vS>fv7EjIT_HZRL%4Fq1C1?^(%L@J;>lo9 z(ahpihRAfW2LC-G@kmo~7Sg1*9FWm9c>53t?J$Ue$Z!oZK{^Ynsw-<N#m&y3!jh6| z@j5)gIGK(tmY^Jpu#3aW#Mj_0JtdX31u7!h&;b?U5r2qF6n9k$k>$9LX5B#17ow%( zCN}o)a2s~HZX@II(w>|g^EK@^9QVi=rnYU|sDVZHPDpS<S2<+RV2Q13(X-f&9mW*8 zci}cqO#9I>PI1QwW5u7`2ujhBQ)7e`Bo6#Yd}fI&m&O9S81}gV?kwlzgqA|LfJ<YL z#f-NNw*6z&@<g!>{_%z5HmtFyUSEh;9lirqQ!zG#^N;i0{y{J+Mca#xbNE1TLgzVT zR$=J7KWs_|cS#4ELRI4q6Zt<n#u9f7%Sg*2vBQlB%BeBJ%Di~_N8&rWtKV2)8}Ni1 z;Lfu04|kAg<Mxjri@DTngULTGM0ey7AHJU`u7-d7+wrOtz|D}2Ra4E1!m1k4%W*U; zR9-G_iYi|uoNtl}jb9>$PP84I4mqr{Ezo<m`WA?|)^Xr#>VOEKj~$0qT#3;F5HI7a z3y3QmXH{Gfy^E|tw>gf5xIo$@4Z7cPTw`2WZEbmA1l}cASYg{nB}i}os~J75a)L;7 z9GEx?e!{fM(PH6jyJUuyEsm~yrlXlh11rsA9PNJEin5CQq0?-mRlS#s*x<2aF^!~n z6Nc_3H7CY6P~r1bA1+v&?}!&v>-8>PJnuk;*jgVHBEI-h=#=?(3A<87E?vAB?m&ji z5F&&N7UwwPg{hYMkT9{w5yR={^)@38HvrSl(P@XI0&_#c#85{Jm(#my{L)A$M-<`3 zffuvi5w2Wva>9iQ9JH~bxynB$$Hj_Q9l#(L$jJ!`5W^SRT0?T3lM@mo?r=n~OC3jM ztZqk?<A9CHpdCzuAx#3g%eu-jI=Ji)!cnJu=WRlG=>jj)ENLl3%#^`GT!B6>_;1H? zI>ht&S|M8eAs3w27mF@kcpC3U$cqzHNc=v$h%yE{E26Xb3{%P2mVL4yh;7+7A0)1) zUx<!bv90niYJ$L4=VvH#!R?A{dP0#4-&N$I<_QG3xVIvkXDafCT1B>8q{t;Z6uI<i zMK0T?$mK^Ax#HNS6#dH4id<Ev$kvM#x%w7GwmqxJHUCuPS|29jv8}GpROF9S6uD`Y zBDY+j$ZZcOvi&7R?)YAj9m&X3Y^yu_DRS3jMebgv$USE(a_?B&7msaqU$G+huT|uM z8x(o)NktwytjNQD%>H9rJvvB{$L1@tYqcVOx<--5|E$QL-&17wcZxi5Omm9&<Pb%k zDpKU>wTk@ZDn*{TPm#awQ{-=7D)MX_EQMlQ?HLFX-zrWnP&8hip{P$@59*tDk`U6j z%tOE1@F16rZ9QOX8^mip@b$Jt27L+AXl)uqHv!eSIULCs=aJqf{Q(m)!P5?PA1A*= zfr+M)#Bp9JF9bHRFc|<pN&FWRI7v2xSV}EO?1BZ9L~ygGr{bbnzsdM*z84`e-s#UG zev6N~K-yww2ZH$)eMq1tBk}7w1mA2ka52<3&x6axw9T!7qqo>t1!0R8li;^41bjNC zMgK}z+hX;2q}{^bN{G}Jy{8DVOSHIYITl{BMag;)Pm3Km7r!Q^#q!l4z7`3nt~E(5 z?&}Yd+F}!`c@1J5Hx?98_QM5t$QGGs0MCdPN#NFcTKv5a31dX_O;<~pQ*|4evjq^@ z;$QH1Pm9`7WX|6glR1S;$(+Y}k~vM5aKuiRP(Chwl_I`*2IV^$1uI)rFQVvQ52fh$ zqQF!tS1zGc9u+Zw%@|JL%c!VZtV<zq<9-^}ve9t}EC8t0`l1*i+qUzxrjto+J9#D( z+$&qpgNL>4?70&~1GcFoT-y|n9EnJYgHZrdw2|+@_O{1(qz<sEEjD?=1R!FQC*~_M zNj3Q7StW`qT%$<Im5K!J2Ju~wAKB;!6tCQg1lr1r%29*mn^7v~3_xJw)hG?=zX88O zwCp$&%$L9=%k;JIl0xq|kdF}{=_m0A1wI$WE83mh4S*Xxit+VX28gd~J$_@`Em}4Z zHnv-Qks?bygNQ3{r^vEwMJi5Iq_RknlQt?+d#fVL|E$QWw-q`0dqqy^m_u4l8>&cs zi6U#N6*+yqB4=Ey$eDjuWbJ#3tp84tvyM5QqCa!LGU?d>R{gQ<o?D~H^T#XMi?bBj zdzT_FRVlKMUPc_-?&UoozM1VPlVdP)%4XAR=(i9KDt&KI8)&)v1pHnThxU378hEDn zR_ST7bvQ~&Cftodz<Zl)hr~s~0l0(rc6m`RXiPY67MSfaAA)X8<-?u9?T~UZv?Ruj zKvXnu6?m_dRaT&XE)@B{CEe}i2vmmm5jhw&?3L$O7&QEcpbZUQ>9IV>_xaff^*vRM z-)1)z(XR(3Bz+Q-5$T&Zoqqp-Mk$*;S4!8r$bo!M)Y5ND^Z~MieCKo|{Ltb>V17V? ze!5aWB1KY{6xXDY^6n1t2w&HOe?$k_8U>Zq>oanqJ|rV|LYx#2T(Y-E`Qum$rz?by zoC95tH&WrHCR`~LjjmV^B^M&_80D!+_sg46pyZ4)amP~p`juls%SUHIdpoWDW}`)P z{44UCGU7@6o^l=F(z83+BRZV11#aH)U<Uf%<3GahLx><{$H!4zjdCBwuMS8ZN{G>o z0hXduK?%$l@eMgstIw&+k8O2?di>Z{KTwAs8*?1hZ){ArERbebu0W(_=c0d<&Fap; zZ*045+AZ(aj<{1h;$zwacWDoNT)X9;$q_rt!lD|{?v^2=gvg){o&4BOR}htyEf?)} z>=+{iDV5udNXwf|R(?BwEJSG%)!DSC>X)7(Sc_u(&<G*YHm!pwPl?_k(FvBQ%WF#^ z8mmN(U^t)e%3<(9PyD~oV7)Q%uOlU|FaCKVGH$Dq#g3gT#IZ54c#{K7caW0k^zB5H z_`nfJwrj^h6%=&bxod@ZCDkwg(HQL|uQW!aCP`&i!kwAu!CR@3&zErRv0z#&CMlr> zrckME6w@}LB|I{<tzuFW4rhZ&R!p~qQOAL4r<lxy>$`zzub6=eZ^G=<4vN_&5_)w7 zcZ}km76~_X0@qP-&xwS4F>0o!D()4L@D}=m)Xwr%`0U#vVecAnUF2Kf4v2)FnBb;% zRkj}z38$j|Q@bnfGm&uC1aLiMt7IX*5(&qnDWqmfiDFnI6JAD7lbR)4gF8beoQ9qy zHCw(9ooC8~|Frjr)c*2wa2sU8xuoR;nF=kNWWo@P<f)@&dJ`col?iz3g-9KvxNR~4 zuaFR_Co1kHnJ}HWv5MOv6Xp>&PIW^M$b|RrLJAX<ox5bhqj2HWN%C8yw_6I&!+EH) zp;TSnUPoTrb{3RcdOjScv+yBUq+c?|T*sszJe{ry;!79sc72^By8GG{ZonYAP*R)> zU)r=)ozWD5>k*SSvk0_j7xbEGvq{|Z{x-OrPg0S-8J?6jUAaU0i71)01^Eb%5xuCv z)BoNm5=_G3bT<I%IR$#tmJEO(lOkpLZlX&9qK8R=><pO!M$&9qdw+_=4F{3-p+|+k zN#XQ^sN|3-a&#i3G2U3rLnQt9)ek8*xF!ho#>5uQB>4QZ0RLPoquIBgq#BtbFCt+R zFGZH)C|vz;a#IkHN$3=r)f~7n9)+VxyNYkjor}&eZITw!R9*{7Q#PXRfE8)0w3KG} zZs|*u)dSi(n)qwO`pC235@`o@c#6EEJGk?egUGK4buE<&b!&cNQ8csyNs*mb1GiM; zXvLt5CJ3A&mkkGOvGOoEm|*k+CHWwkTGJuaV%iq1snXJ<uAIq|>J+(vO7RPAEUigg zMZA0lgx_f)tyGi{k^G|(K1Y`eEnT#&O1UYzeIo%mQ$uK3qie@VH>E<_!mGT5Ry%&W z(&d*T=TMy#>8RaFsQgIPF0sh$C(4=bpxU`Z<7kl-jKh#hc2;Txt)GJI^ec5K@+GqM zVGX18m2Im*9L@k@iAK=UOCvb?)>9z7UkhnL<`TYt9E4T6GSu2a{U|@?>OU7*?;uY{ z_ndaAY8bSP)0R@6AuGYim9|YeFs<!u^B~)M3}lZg87=r+vV3aeo0Lvk1-f)LL8qVg zHC36UrJ*BUikvV4vguwW++jtus@G3psD=ALG9SiI-`ZtjV3+l@woD(`SBNfWkv$^a zhnCl616{|YFG9cE<!rk4rT=pxuFs+Cg!Hj(aeXdbC#8R}6xZj`b<6ac3S6I0*KO0! zLtoQnBVBh$ABAaOmka1RHGMn^zRN|l0njadHA=C|#pKhOaL|d==sM_9r?sxi9!je_ zb&OZ25}~!PT_UPM0x)JQ0N0UvNvmSJSPY;gY)`vbX`uCTu!a;ljVkL(o%E-KP!+DO zR0(peQ`L5mr=$Y>y((y0Z`;Ws54dS3(ss!n2v<K^*as{o05NHZpXDPvQe-(HpOP~O zNk2|xOiT>A@)Vgf7nnAx)0MP}cNnfzrpQxB%L|f<Q_=$8)?zx#tEip4EGH0x*8ahW z4l)@tfwVuV{Lrp|BM}ON89T`(H|Xw*HVjn5NBG_<gb&l<w1c2kt2WOuhhQF^HcDrJ zHWxy5KT!z8IE|ovhfqWla_mVOL0b|Up&BEnGLQP6nYu00ZiTXghJrh(vst4Bw12^Z zelm%2^rj!bWUZu44Q)KB#cJ?0jMZsgc`Aqk&~}HNJJC<pz>Cv9tj4dB(>{nx!CgHe zPn36pC;;t{I20tyAJPCAB#(e70L`Oq4cc*2<n=i~{Y9Pvq59DX?M_KC$0$eYOuqXM zsb<DB|F$v41@h4R(hf*JHIOI6Ao{0yAc;S?4Qq4{t#jl5Mg5!S>~dTlqINYv#!tre z7b}YZjKL0zpRoQv;s<l^z)2$ho3)6imO*JGCW#T3<I%q(m!peO;$dzvUPFkojrYjz zn7*qfTuOikD8Bkpb(}2sqf3sDlW%nuf<ok4gF<bMsfDbuJarN7(j%U{#mMxCt*lIz zU!W6+Pn5TzPuoeT=Lkhtu5_->0;;)uxecSf2#Zps(OPy}&ZrKgM(HBs{4b!8Vb=;O z%69T?cnO8bfrQ$PAIR2I*`~@TF^_zcWYb8-mVSkd#CMVRA)YF-IulPv9w-Bqi$r`k zxgA5aihPWmdLp9qkh@WlDnuj2ARi?>$afnwWYVQqdS>G~ONC^y^cj*;w48Kugp~X& z-<t?JKDV<EY)s!4D2%~!OlJ%U!{iZ25<4P9ny}%rO=}b8KNb=QMiY39%(4W$BJU?p zL~kB5E@rV1)W^yxgvcayeo6*SO93WU&J}_N23cbRk~QGd@g5N~ZBAd-aG8~cpE^1J z%P<fQdq!8F7Cej2Lq2RHRKHFzBs2>y6;pKbLiVVat%N9cf5=L27>U?l2gO!a<jI<G zK-64*8W6fT)R;kqO>Jk8ns#UT_QRM#z6=<iNtapbvVU(X<~BXgM{pAg7ILtB6rO!- zK+Z>4A_=H?RoG&=+zQj1oF~Zt%m8?q)IhV@k>#WP(m}q<@S91O-Dacy7Iqy#+pOtl zt;UKohw?AdTO;RPkEd&2dihdZ52fp*^!b>lb{$36ZPWc|mR(2Fb!z&V6n6|=cS~<h zaZjY{%=A)<JC?2orcZ$4uH)!>mq;G~uIqSWo)+n^o(X0GmCAD>{Y_#f67#%BFU7*Q z>tteH5b6Iw)9E^um={I*iKvyX(}~$D(ogLIW+pK&iS$1rV_g>zvrnWKjsa6Z%*!IZ zgtQeA^9s@-Z6(CKD$+-iwnfCeCel}uwo+nV7wOlMwn}2&5b5(tTNN>H(m3x!?RPzm zG9hV)TJ@%CAs~iGiB)jdH8EI*$}Au4W_upSKz3X@^<bX;h<M!jG$woIR^W1@x*Uy; zr`sk1sHNLT#8peTc;V@YPA0uq20}a+qS1FxB~&K0{Vd-!_)7m1@#AaLx44H8Lv!IM zafy<yr5u)semSnWBot;CPap@<S8^79^X2M65Vey1VFG2sD<4DxiKP@zuryiTx!g$K zAZZOrwI}DxmwQ1$irl?ah*b#p%5R(s#$arVOOprZAzSb>FE)Q2>Ib95;*OJD;4NC( z-<GzQC71xmWyn7wvtBugBr0K;wFgXGwmfB=Zk1lS(u${>H+2fw2RwWda5?hgOww>o z5M}}(x~B5wJ&OSxCO6j^g?|YHM#3MU(&A2(y-|%+@Lu_ejpH=0#MlrwRd%Q*vA;di zpmNn~LrRj&!XOhjPnM!oy)rv2B!+4%Ab&s%ubgf{l+EOO(6XZfkd<<VN@%48p@Q_& zkAa*j&qM#_l~-7hUId{Z1HtYJe90?!S`cM3{TRqvc_|pL{D%dh{F?Inz8P%UAa}3V z!?Ra<J3y$cr5`AH2E$OsOVS6Uy|M?S>_rwvp#eM%rIPWKY!^?!krq%4m#xx~$QAOR z{e)PpJguqxI2J(*eX_#FjZlFZcS*Uy3e-K~U@f^tUSkVrCl-Au>B)FN?sf|t8DPlc z@{>pqR~mbyKgG(TDkzmtb@z!?y(D`EL7dVz<Rn|F;!>^aG@8nfDBE91xzxgN_ns`z zLGi^Mk*A)GeIMjao^L_)CNU%8Jf));afgjiF3gB#o=?wW#Pc>n`ChWzOa^rKOowIU zYVx3kz^p|H`+0_Awn0uNo1h(Yk1`T#pAr!_*mED2aVlmv66$u%!qJ`|5KF}zVaLQ2 zaFj>HP4+z6T8Qm5G#1%0Svbej8$!B0C|5gUKJ^4*7JHIS%qyKSm9X6N1&UY2e9#$l zI`s>+9*HguLj~3VP9e=U<4*S6RKUW+P9e=3;#PY;!UROcOzLPA!YH}qEh#eAcn+Tm zm3>H{dsM5Qg@(jk?s;SdAd}q?6mfh4v|sBfsATOGPVG+&gfqiCFkZ;>f})O+e;bXc zk9tO<+mJU{Qs{hW2?V=6y|A)X6UxVJoyqd?7zkhV+)|2ZDF!n6o+Z@nmJ#oHp1~Fw z&Cz6Bsw-b&q{Me!;=cCG?9VEWBY+xcv<eMK@Lu6(4WolJB+HDMu%f+p+9-C+B{o7e zWJYxH#!q6zc{YNbTj}WOedTmUY_}2Y+=Wn|F+y%brK=|NoQ>dA6k>+lyqpo=xe<<j zBUvhJclrJ*#-??$%Ejs!Q2GRmEAd{8(ou<yaKjjpku0wr#E5bm;dGokj)kI&ypJwM z9h_rBRNnfj6<WsOiHWS^RvW-sqeV;H4(}GYhqB{kH^P-Q!e)5o0CfHed&I^%v!+!3 z&AS%9qhP6>T_r&7Oo_hXou18zQ8vPvwY8hjj$>lJ8-}b^+7LD3*|=n>aJ^$LgF~wX zx7b((<E$#!h?u@(8TM2dm@B^&A){1|G5I|l6v3HkrMx0$2ilFYp<SAlX=MX@qk^rA zxo!@_Mh3w`vb7~96YW}coy%;jDgt)jWNIYaW4=Ytqf*{%!<07qL76Mq&X@yntnEG< zM%oyWahBY%kP&aX5qgr5EawhJdhf@4Y#L=FOr4z_no5+5Tw%YB31qQtCq%-!%AI0m zY?a5M&rvz53Kz>+_$ryMv7OO9st8v`ihx`y?BLi5wTyi>9M)M4D#FCr0od14%D=WF zsA^C@&iod}X5}-sI~pgKjg1Yle0l8Q1sq{UqzK0Hb7QYChMW}+8)Eq#v44TvD$5@T z7r~zSaoIc=`z_`?D#AzMA}I6OomJWFjy-k&M`+hIOn$ALn>_4^J;~J6*l-bOE}-YD z`SJ(qoUim;9;;LE%G2x^DzEmBY7hBx`Wc9Ev***}OpH6i#jq=3v|No&IODQ&dznSg zONgKyl2qzRShA!|po|wix$sI<FP2$IfX6dchL#~1&A$PY5$`#F1#le+rw4p0R20Iq zF=#>K;tq`F-HcpI6NDc==@oG^;%-A{MmEaXPN5Goh`9N2Yhenl<>hjxkaoN>{^2P` z>rn<?YYFYuh{_gHA#B{LxV=~gDC}QsEV;4^c2?Y7W<GSthS>$EwPk$e`R;hu)~1_P zG^zxtXprb=O7w=feHjePvtiCe36{~=dr~RGme?>WQDdM|`KP#!%^7=P7%Zop(b4<F zX$*V7hB*yfgf(8=TXEk>hP`FOoCXpsBhz~$yj~Sv6D(BN6G9ABD!+|8G@P;7VX!bz z!4l)?hPF~U+lDy}990MdJH(faWY`)T<}{FC87Fv8=*zI%Y*>haO69=#G%U?k$}fh& z!axNZ8^7Na^fxxlX<&S77&tqA<_Ol-3G;p~8mEB-%b4c9_H>4gw_za$DwWIQpG;$H zZ5S*JR4NyGyBi<8!iG5wycZow+~)Ylm$SCVZJ5(Qf@LiA7A7+6pbZN#P^r8#elgru zm0&CQcd$FaK&5hx_bd$k3YKfboCc<$vBW(e{~uH_9W<21HjJ8)aeUe!k9#-12|QG7 zkgv00ln<mwh>XqNuIPgl;!Yc3DKcwBg}u)E{zArn7zwMAciNC~ulFA0NTtvS2|F@w zY}oBRshko0Y=mtC6)27{DI4~BUl`3;*5t<Nq(vr`V3w}}>N2U6vV8jY54axW)4wDf zq{7EsfZ(=q=X?K*p!C<#hsA9q1tL8r0oNDMwJ*H_TRU-^=uA(N7(*)B#%=bl=!M<b z3lUAo6Q?6$MjyS!cH(<z&=~{i7=@H4E?)~~IANt6tM@H#zqeFxTgZNLU<x$fzZAWS zT4-fpk1X*l0%O1V#bU@F?zn_yqiop#dHsCI9;?Q9FAFG~_S+=(q2EtK_@7t9L*xo) z_yRC-Pn|mh;hU{+U1I%YhlvpGdubkTkngYnFrov7jJVg<H)7d7OQyy?GXVBNcaqWB z(*kW<S@IoVwm)bTj7Cd|dw&-)B$JUxZL}7Sl2zlN;!(K^(;Yb=NZL<+56y9h8)0rh z1FD>A0pJ~zW+7&kCmp_~gbuyz6TPS!saShYz=an+aXy$#s`LJItT)v=YkY6i`AiI) z-g)%GN8uR@sCTvs9y%A7^KU^EU;1-haJ_)8lhOm(xGtdUww@6LpEDI&`l%ba-lB1< zg&>*y0Y84aGNQ6!Na0lywFBNyR}j5`j?Y`wVIjxrM<Nxgtro4gYY@lMF^~&7B$?%# z4P+)=cKRv_=YtaVgC7^uqviE`y<!8dTkM~S1X`SWycg$jUr9jT#CSZ$AY`-bsjwk+ z+aeswZ2Z}^bUki59jMmVA0oVozsq$L{(L5`yQ}aCtvchLez&X0zni3v#DJHOK9@iu z_eJE(*E8=1l#6Gz7YCDuQRAQZ4ixn)q)@y*Y2t1;d(R@x$%!*7!4+%HGja3D;7T+X zGqG7JxPaz-6E8<g>bXdBNfYUaYR|=*OPz$*QHY*pnmfUFE4)t*`*b`It>rC9R(M-~ z2RnNvD~?VXCv^qe!D5FOgY7JLkcp5UMtkp>C27kYY@<7n3Hf)FK<krMK`>Xgx<LuV z__7kZ6+<V$d)CSWKqT%W71%~pVW&xn>6i}lKS_p+(1Hz8wznm!m*Xf~WS%XcD0+hS zG3wE1y-pSeK@^T53n-&^%Tp|fbtjGX1AFd#9Eu1pX?NObT0gm*a<}i;*>E#dq<nw? z&#V0OlaneSdwb;=?u=fwWIA8{<T8kQe)J>;N7a*k69h<>EvU#7<hl)bH6?N*TT|v# zp-h%PkkQTMJ7{Riwkf)p`l0mYaNyWZRhLucmFPcv4wNzFs8~5wo{m=A^LY910I~V9 zXffD4`81q>io`2dQ$nhArpbHIz4RO^>k;IYj@&ClG)QC;Hp>@4b!OfRV3zM;{AN-u z;RYRKgM5FZ0J_Xlm($5Pd_8ZKrG11Lb}pupJs(zwL*RIHyuIg6sSbpCWqY+N+w)KI z-z&+2RNxaSlJr;LSIm&`sGfgDwsV3cGnM2oQckc0==wTPt^7?cMbYLXx=dU}y2z}T zVc{TOE!a%D%u<)rDNo&cz99eA4|dY1*7JR3neYxvr~>zalK8yC?q3A%LzRal@30N% z-g_QUvbNq~pQnNQNQ(Z{akkz`&G};)2acM~<VvvrwAhW*pg*zLCaGXQwb;$nqz_tb z0k!FWS?obHzn+I=Gp)J3oV5`AVfhr6ptunNlM=}vByJS^hsyX%ITXd<m6f(+mZYwr zr^n-!7g(YG<DgI<m|(dV@;hufRkTYU1Nk$yoJv~ElDClRIEX&5MBLO^tq(GZg4SlL zWMQjng-tvcAU5hhNSrS>tcTV_&tEY$)3=rKEC?d!kA^ha^BNYKURh*G{MnQx<>KvS ztrwUMo*|HW<@z8@2LPexdh}>LJ9;_~C(JED81f-ts&awp>}iLx^~yaqhQ$8Q!Ha3~ z1N0L;yL<MuAPnb|M7sFkb;M-(zQu3mz3{y(AC1txNCj2vY|)DhqW`lY>kOJnvO&I{ zbh#RrS^9DUlFRbZfpX7ZFj45$j{-cU=u3J%JR8_7UjfBv443I3*TLy}?NIYhdgMc& zJESK<Ae)QDOt1YJG<aQU$>^aG$mWymbz<b*Bvbuz2YD8$yN%+@XRP4<n_!FVoxW}W z?6~$+Of7oT;p92zq~bD@LNV6KIjiEpW-;rT^9MAt-r3B?%-IRez56ihoAW5KeVI*~ zv#tx+e$1xM`CDtS{h1vy=Y5oE?*W>PNtpN`{Hgaq&3Y!Du@2lI7S8zu^PJu}95X>= z?n5pH`RFKrW(sW1L`93aS-#6*^t=tIrPO=6O@+F)sSnYq?esIUao+i1y2Pn~6Ci$s zj&J+Y^FPM*E-L0El>bc#%kt5|XLY-pmaA&EMWNS#QK3x+a%c<DHM7-pXw0F<X=K(( z{l8cA-AO<+X^tN}93&r~jM(pgiYbd4QxZui9gj>v^$Y}M(vu^D)a4)_&DgShH1Emq zWfy-^A_P5WlYUnloc1jtW5xXHz%r2?pz9csk(9mkp8(O*02)+I#lfIubnPS1ijM($ z!vd{Tj}vH3tLWM%+WoKwNqpcr08p0iAbuB667+bFI%A>_n&9B&G{EBYAv1dD$A1M% z2ZzrFG)H(FeH4(M0@Ci6B6BIcgFZD!j|G|Vp%mUpALXOxgiLtt*$6-Ep)=)@9vre0 zSFKY2P)<aFdKx0TnU@|&lJs<uKC_@oDMj9jHkLiWqvq7~%#lf;;CO_$@KUi#dI-r+ zg`|Fvi@i%BoTm?L)1yf$lI{*t<OKj`FV<&H>47DEG|%pDQ{)J&hq4QFbb6L47|~Q7 zglA@d?UD3|lb<pfoU1-E<_#&bPt_&XR4%~1xa@i<=_x3`I)UFoCc^gY8`P;wdMZjA zNdp>sfi#jmKzWk%sFW?!$KyK4VvKm%k5C6B=^?6MK#IJp7Jz4U4b$^g3W2hj(iY)M zboS|iD}5Y*j`NuU`U7S**~L2h^t6jcs6&Q0#ZBd&>{ZXL&@(XVkrn;iN{Z}vB81)b zsXlr#MyJ_9E<^X7{en8|M^DNG8{0vSssP|+b=Hrbp$P@FqVl+1ojawcYit0@DnQzI zsN;qoyJZVUAhUh;%IUOzEL({4!-<{xp@93f%RtdKdwLa0FHRz$e_CPxcV!|1<37ds zKcJm&^$f^F%(AL-F|hMH5Of{b`L9qDLthdem^Mj;r0qk9h#k~+eI7{8G4Fzn&FT0V zk>lIOQebXMU-VY7gPRWl*XfEPOrTrdkI1ouTTw{t;A6)ql08+C6Xq*2Zm}Y>Pf}#j zDIkD$*3jM>nyaB>G<1fB7At6{LTm-(`F}t<zKbw1ke+AJiRCq;eH_uLH!^%er(`m6 zNZZ3?%aG*uFjB<*;dC6;X&IM20u!_3xSgn!{PuBehIqvA{c(F{V&PEac^+jpvc>*u z@dh1QQH^SI0GD#L$n`-{%;=8yLhbzJ1!8n()qwj+dhyBVuGeF{RNdzW$P)=f8wFjl zI2_$$eImGRc6gpV_bkNen^1^w#-cN$O6)~HR1K<E?<P8pD)Nefov8SWRmF7j`I8aL zb8Z*(>TM4K>HCsu*;6+h0m(m5!0WRR;KSWtA;(t~;_{4C3YgY`epg{clRh=w^PPu+ zlD;DJjMCQu4k&$B48m_off$^)6a`jNkR=AEtXEgrVsQ6s)Kwobc)%m-s;?M4{AG33 zPYj;?A9dAV3|^2!)!F||*dhnDz6Q+1JT#m^t<`E4?YckNEpuAE2+@fo8k0Paa)rTY zQY&yNxiCx*Mg&2OEZ?iR$Ru6;DUXOur-j2to`rdmj!Y00xiu~__fzCg$z}3dkk6*C zLMNBkvOiKr(KVrja@(i@bR49r0x<nfqVN+JEJ9GAuzImLv4}1)?Z_ll|JEcP>!&hW zL^&Coq%*l%^zWcVsZ?kx|6@C85tMdTqHHQfE$X919?`#>5~*U<q7ho;75#fD(F`hQ zEt;uCF`|E8B`R$?#E8nYC|2Z9E0yC?a=IYra%8hXzBGU`Y3(`4*NZN(h7|qj&15m- zvt}Wn-LXlSmc+~V07<|4R3XM^oq%8<sb5zGR0@8!=yWYIJfZPUFwH(_2km;Rqvg}P zum^H2LfguC1W#<&29>&){3|hWA$|c*-3`d%lt1IQ^!zbGOv?Ix0VE#Ca%&J%PV(mr z6{4&k+WDk5RGY#(SW+UBn#q3xkVs<M0#ISiWeivy=2z%`ax46QQj1k)T9ZnEAu3Xy zoD0JzwM@svRyrfW%_uWjzLCIX(q-;8^p-emyJi?|4DeywrKIXAgg6e{uC>Da*Fgd> zAGY0U39Kywec1N<bRkHse2fs=>B@g0MKy<Qzif|Js!{OUHsBHs(1&fCk7NyT2-ODp zX~1+JwjGQWyX<BoC`|=JLi(`nR+IxRx8!g_DNC%ww)eM0_@bcL$_jJXwoe)moI2^I z@_Pr~l;t}QTqa!(QUQZhK$dSTvNOncGYRQ3OI_w308Sn|vkMGqLcxyHx35$3BygO* z{mcsUcPHBiTc>ZqX)u@f36dU=K6a_pq56?!q<RlD4D!)Nb|zis{!!QT67-{1O;0Cf zXCcH<(-l^j|9nX7n%-auf@-<~nn|s^nGl!KmH!lqYHGS1;Z+p;j14$l19VMaf?;22 zIAo;}rlwDy1{KW_Pn+zg819<B3=IhygzQBqWr<bOkDyJ+NkOrd6{e=A6a(SVO?CH~ zs_Es3mPwa`RKOq~1!Vd9A+15ai%CeAS?V(Ppswl95!{4=9X0&~!V*c~sOkMyn65he zoV5aSSwlHJ=RU|MM<6x2%<{!xSvdV0q?YN;m+zuwsNG8M6OshNgJZT`(XGsux8(>y zVmTaf6F;IW+&WRh`7*w#5cHJ0EF|H-SV;GQy@m3Ol|qp7$a-6tFCRqD<6R`rK3i9s zM_y^`Z7);SLb^o0izT2(K5R);ZHat&4SGXwrF?3RiM-#2sCL(0R$_GYo+b~X*?QET zy|&qC*fJmDtuoNoXrS*)GlaYhiO};V-oMCcg+dgfU-rm63u2_t%0`%1&{n%g&LgSL zdcG{C)Ss74AklG8cE(lGm*m%&6zRB^I^&LlAA4VwucJ(L-20qymGn*d2BuOvE`7q< zN|#<W=KY5}3sXFDY>%WnbX;5cQc2&JuXNWf$s?0SIpQwEFyj40UXP(p$L&Q@UDNqe zNe{`x>rC8n&bY^;U3fo}W2Op0<?oSYkovhGJ7K=${YqY%Dg@p2^T_oMA-#CS`<=Yb zYf`<AgtT-<AuFNqtN=&4JaQKaDc=y%TS~k!o)cP|m~T2_DxuHwR*H%FjU%SAHo^0D zv9Y$zXj`qaHpw$P!&uwbA*6Mhx1|SLqk>HI$jKyRYn8CAXZ9>pH5HDS>Yhpm&#hBT z%yS(vl`z%Q;&c=9CP&OqFvNM6cpIZ!uZhE@d<jB!RVoTq9)9Ka`Ep+Xh||2EtuSB@ znhJx-Ol7M9myx;)yf-Eq@Ub?S_0iV6cbnIHvMyw=9B)IYN_2Z_FI!__;N9*04@MEM zEVnV_NvNwE79;#6@8_^U=ixFpM0dmLo-l*o_uk)Fh#OUgpCqtqTFRyL4}*KJh33z_ zC!u1r=EG4mD{yQ~Pt5kT=2ZA?c+E}aCh|;t#Ddnd+zdEyvPVv{0`)sS)cDHc=^j~O zi|LdNUJh~rX$yGd*_MPmWqq>QJI(7o4Zw-$CvUYNeia$V;#MQ_GS4aSVcKAlPZPp) zvvjiAdy;1l`Y9>_`Mwn$9kddz^n3}Ip&UyODu`q1lg-}Mo{`wTQ87D`P&arMp6R)> z8^_GGW9pO5-g7*0X9{sUshw@dWZ_27>A6DOO~U2Qm~^t)dy!{&CysfsGo})5@w86m zm^+*?A6kNZUhes$pI0u=I)!v5+Pl@$wHLe%#V9{^3TX!Cz1CBW!d1d}be>!Y`V^FR zN=z*<@>mk60`OB!p!~k{AnMsM{n2b6q`Zu>5vqkG%ckUjH^kgn$AwrHg2){K#C<Wf z^^DkLBdAVvYfP4}bOG$&F{SAYyFVOklsY2m9UPk)18ZKgAyk1l(?tg;y<=lvT@UGD zTT1C5H%dA?w)_|_h*smR{Ho@}@dL5#CL#VnTT0sf&Lpa11L&6ITpOaYqS9e4t79J@ z3`o5Vp>x%K`hlTz;@i8|vjiLK@)8RI8|l!O_ng>6=+>1}K4=NeIS_@oB=)-u_RQA_ zp}Pl_i)6V4eWmxhSPA8-!oLqe+(iCzz_Vx`r_vFvlxv=KD8wh8oY|bpP(rv;$)=h= z<mua(brgr_P>9bwSH-iAbs;*o919(7Vp?OW^cc!m-WZ}oA^OMcMi2Z1A^sAi;~4pL zBj~s*wj7O7FX?s9fO(#t;w8ZUaQ_4GGU;-Vx*X)A>)gLWWu|}T{TR5*TDC*=tf64x zZPo_sTe(Ey<72|VMGiu1NPH9^DVFN6tEHS}1v>gbj&h4U$(H^Z5iyUa`%V6DA4liA zhcsOj1W1-NVf1&CU!WnV3F94v*sD_2J()jS9+S+a{WmK*cXR&Z<p(GUazXi#9aHyY z{^7E5Hph&Eb8}``I9~QE;FxJ7G-=Y)9sU_|O+W6ehS)K6H|H;qoy)nin(vHBJ(<5$ zHuZ7Llbtb@@Fe+xiFt`LCUtZEtL4X7r>NSz$0?+4&VRi;WfeR2^G+dkbN-v<OBhF# z*B^8W=~)T?L-Ixx@oQ9~Ns~<>=w_uJbnrhXSEKk8AS*23RXL-(5O0%)DFjd@Wf~@( z8}}cU*Px(PXIX2j;LcJZ+IxInu8J#cgz91xO!puD{+_>MD3=eqA>51kM|kM*DwWUI zZG@v2^H1~Kg0?G<*ivUNMkA|#k%wMzAv>UV*AC$)&*a|8f0AbfdVkr^l2Y0jiTx*g zaxuSBBk>dx8h3dC=J?O>Ty_@TlLQBpl};h`TK<bX-4i(L7g}mf@hQYLo_(-DIq}_A zbc3LN&40V+2Y7+X`AZ=P>b3ljc$%XYRqy#_NGb~PS5HSXt|ueM?rNl7%m0$6+aT6) zJRwx$H+Cq*Tb=_o{~u@X9bZ+^{EwfxC&|4)NOCD5L6Fb`B$5E3NHK^Mr36%(AcWo_ z)Bu9PLNOp66hsB=*bqdqAtLsMqG0bJb{?@jJ{G?3_w4SyH-XRZk6&J|oHIM~p4r*i zdiIoSJ-zY_8yvNge+fK+la6a8XV_3gygv)`fR1b1%GpSfG)7-c&e1E_dHEd85)j{Z zp;w@jV@MuzmC-K5(X3tQIE5rzzl~_5#9uTJU8>34)8fVV;DdNxlS$BtznG9vN9ona z_u>nrK0rxC^6FZ7mr3UcPXmz5=8w;|eTx9WKLtnq`<^*+LkBtjFPbAC^gDZw8)#iO zxuQAlj__h~oNRM^JtDNZPF6=nzK#gYn&JZ4-x?(xCB}U6@(J+4Yt4oc@;B!WfJ5_Y zV6gva$9dp)loMDN_;*XA{&0v=!9zmI+aZ!4VVWgBwq@o3{m>UUaz{>v63|Aq^5k4x znftq1j<kDkb7N(dxI}sEGYoSV61_fR7*mAGo@tDFVd!K}L}u=I<;e+LT=_4YMhjKt zw<7>3tL*hVAXDXEA~L7UCx`rZd!tS2$XXTI8;_HFfW%HLpB(bvzZK)MnMk!bMu^5m ztGS_$faZ{Fr;K*WXwC5s6}}BZ+r$WQ6;5l>Cboq65-HvVu8EnnW|e#oM9irV&h0|n z^l!~=qa1(H8{kyp^L3syxdh7}|Jo~&ONMv;QDiT<W2Stf=P#uxVqA%6Pw)~PM!?*! zWiOW893M5vNkrJa)N>8ugd77;5mu_BF&xPOKj%GIYt3;f<bS>bwUDSyr;+G0gB|6H zN^s{V;fJ)6C}!JH-Y+5xB22R-V9~$HhNwVmz&5HsziMf&%=I%UNo&=dZB+lP$0fb) z_`X49BTF|8M`UJI&%2fI?;@5lXlttqNfLy4;7cM9#!1sM(oNGzk<$o|syB%spswwz zhKz<#)q6&SPF)*T9SJtD4QC1w>RR$0An|yVwygRxdy;EfF;YaBc5_2F1Div#oif@f zqd#9X3H7@*P=r2p;qft^*YEa#J`WP8EVsoWd4E7YV1@*UH`Op73W)p~;U>?43`Jp| z?e}Eh`bJ3906IJvdJ9x9T{~^ReS!O`*q1uaixo14{SE})Xp6^JiSJ3F$<YM3-z$O9 z5Z;G8WlBWoBE%T>dowT*R#d$-g0KPZ_g<higsT2PMCjDHdg=FJpmPW7_nSnh-^rQz zTC!&J@6*7fbeqA+s11v_oMrzqa2SJt=28X4C~KoCIQ@<Xt_4D!Y(<2Y(d9CXHogly z*~;1&P|n7=^7W4auisCBt1EjRV=gwjs9k2-P9NaQ4P6USj$!cFpKl+rjxQe?tz$mz z;KkJOGt7&CGIjiZgqwT?WYIdl0&8J?=k+%t#;9JTjwfM{QJ<!$G9*T5>-a|8J1Zi- zIfW+2NF84a;f=5;{USnFNw$uk#Zp?;r$!LbIzEE2NYz(IgihVo@!>12-@AxVzg_fg z9VgVc8N3^{QMQg(i_PWtGi=y8-U5L-nTCRzGP+!B9Sc@Y>goAJ#P|`Z;}53bDJ#aw zMi+HVg?6DrFmo8*+|VSFhRb8!6T^V7wi4X1-T@5j?LBYWHQ@A>VI^qH^ALbaBs`hW zA8yJzu5B{>$)XzaDxgUONpcB}n75T*C?}!<eg;38w=caSna~E%al$+$2)@y^O9wpc z-3$C#wd>)*BdlB`GlEF2O&{{)9JF~^*dG&(UbbBn0YFwr{}vxc?^NZ&s4Pt?mOysn zZ@BbUnaP$hp(pJ^i-FA{nH$=UjHWFGnIkpt1w9-=szd@2n6V7UUem$JL<BTi@;b9A zW+amr;s`&QqRUF71sCDBkjVZ40ChikS&Y2nFQctI2(A-7#%#K#VHwIyq&^PDwm02m z*T<I&Bg`19GvwoQp)f#JBR4#As5!fJVBMMUJ5ZG-&3#-Hb0QMCA)?!bt^=K8NZv=C zMp;gv#`b*A`vqhr5}r&Jy$3AMfR&`~B~ywjCqGbAjzk5#H|))nWs8w-9a)K#7!~JI zyU>5Z%%KF&$ie=!c{pSwh56$Fr|>^33k~335D0r<8ggvH78D9hxIP()rb&fZ;shqF zuYp9fYDlC7ItriLPpT@Tpp~T6Yyw0qs^zg!VAp&ZV{+|$SS=x{CPaLvWNHf}>iq9q ze0`6cTOt<FWDg}m)<Ec(JQ)$#f=oA=HuvS-h$y)sY<RPEiy<jzKm$B-2L>v|_@q+v z5FE?b0s)AFd`{>Uv|koIH&l|(<I3hdW<Zw1%-bp1E=0Qc78Jwp2GQJJqkWGAo^Rl8 zRx!Un;}@2d6!Vh}{_Jv0F0K6yj!8o14Ie(&^LOY*c@9_I#oXQXA9f%T$cVd=#oWF1 zUnwgo=8YKtb1>(trC&vFyA*RU_hp22mxL%F_k<)M;pK1zn8PJrG4GA|^}sY15(9dN zrT9CnTKzW80txuR?`IX)NQGob8OhvrSefYa6kajE`sB}dViFP~&fzzrivOkYO%9{R zlbQ5#_#LideoV^W=fr9Pfg0g897m>?!_SfwckTkv`wm0`4)RWPG4DV7f0vQOcu@QZ zFn)NXjSUGX@=j@S5f-?9GbbSd2|vtT%v-E}fs?3CtjP{k9PPwLv6#0P{CSRPYO;7> zXE0YfCJAK0Cnbt`Yt`qczO{wvH^03cZsrvyu{<w12?<Gl9Y=gA7m^&_doAYE75+(w zQM)k?UiAs;tjSM&9?MS}<#`Jh79+PNCrQHsA79K3r6X}Q-w!B$AOsx0C0(*83AZn@ z`Nipy#S2O5BVD;6h4E|D{>%uhlWHie6JZM$=3#YHIiFY<{TH3ZUjg)jMKXMNk(aQG z*+RfCSNjh}%=C<!>8ZID^ZjD~001$4?;8Cbg#`TC!Z9ZxQKqSlU|B9^TRQD9+LrLK zW?o{)U*y*vZH<yBqsvS3Vm?dY_jDL-VrYj&_&ysuta(_nn0LMXLI*PSR?O!?{6&tb z)nPPe>H{Ffzfyj?lWUd6R97)?hx_}TSep)dXA$p;>rhe5TcQ3@08FQi3+P?QV%}Tz ze~PgG7Q^NZazA;DEo+Rqh1MKzBl``?0K9ATGxhjBzTe#mv|-2k$va*CSSMD)G2-h) zenF+z9>a?EZvad~rhza_)CBi4P!o4MBU%&5Oq%iOdXaXRW@=CH57K}>X{!yVnDe6l zwbLUZB_r{?RG_BLhB=%vi#enF{LZ+x9THM<cOi~_(m|K}=Q%uI)#qH0UJj@5oZ9&~ zaNSVMFVXmIon|-cc*T4V-tS$Gc>{F(k&a0MeVUVCyAWT+EdDA1@|9rgAa>4^mK=$% z^RELJ?}y^3hhlzZ(ticX#d1k4d>Szz{4(TXDTpRe<5MX>+k|a?{L24F6%N5+eDR9> z#qwS>v0w@M8$NMVD(B^^&glf`)Eh_G-V2~pse(!TI|+%z3XLK0a<~<shhjc2<97yA zLr4O}<C8JPd>F@{<Rq?tOvP6Y>4bU6s+bRc_=_Cq;X;igpQG~ccg&dnF`oTH$C|kD zl-o&)&noyYIJ`B&8~6UlV46;lVrQ=GwqOUxTYpKIX*Ty*B52gXJUq-F2I=MSLH?MM z@>vtVo72=>jOl4Y?t-PV9)qAi-Sisk+61~b5@G}WubqLp0p(xoY>}{&{kuy+dpX=) z%Hh68F?WRg#~qRckt4kL%bo@eawN#-REhgWs+7ZRqGIll`5!sW4JNd_jVUcAl<Vws za9b^oTx|_lbF7HtNW!Ku&+~88#8P><H4Ltd<Bk<26R}*0)2%F9)`qwi@q0PjB+wMN zIb6)0Q-6VzkZ^^#2DB~25|CaFw@gjYxs}>3v<BQ9Zk!f#3)6oLNo{F55<s&Eo0w$c zYw$Q;s~fTyF+OoP%`9fvxmLKFoIKD!?GWl{45GLS16OUL&Bz9hH=O(?j%f;4%#BUI zlVfT%dd1we^v5`+s_S*^f`!^Xo;4vW=6xuCzJpnV+;{XhJ7!F~c%MvDySe&OOm66Y zaE9@BHT1R+39oo-9P~eQ`Xr>JOHKY*jQ%)G&h6k7^AgAZ)q!->L!kc$M$SIyV>gp1 z{_ux?4mv%8JQlzBaT-i4K$$@YaJ3RhaOpUTzcQl_kLM6p%pV5v2Sd16p2swc-vwd9 z%b}CY<WEexBG-UZ@=qbIB6RUya?Nl@dc{4de|JPb;XnnGsC*5^pyw;xA2Fsa1>gS$ zBWFC6if2&sV<go-62?FLwuteMzbjJAi?)C_*`hQ8F%94b`2wJnN%?RY8!+}PTN*>5 zRKABy|B88q73k)y=oC}N3h{+jdve6eByg8YE{@XQD<0Jh{yy()=sdDmw3uH7$;PO1 z**FyXSdf#&Qn`YO<2KR00}|h8f*o>(m+);+7e%HAtq?vdRAh5rHaTD2mMvR~uzexC zQhB%#Uf|-|TM2b^`$;~R_jg$aRuqQuk!4_*nB-Htjd<QF{PXuJzPTPHnBsF(SO?Y` zSelPf(B}a13K(l86=Tpg>qS0vAiQ-dL)jDp+;ahy0V*#*qp%J;ZIGUX^jhKEaKBaF zO68gI!xXCA4gp_+FBSd{(s!WNODU)g!nMTXR^?@Tj+;;_8^LeqQ)4TrWuTY=XDH|0 zA!aaLE>iDiL$D8^jnXX!f-%kW$4RM-0rOY2#yZJDzbKWyphknj7PWBwHp#|(rak*} zWWC%6!E)J+qYSu78l4R`Np6;|1gsbSjO}tcU(qzYQ8=gFVvChSZ>IUB@)ww!<LJXl zQ12>r98|@4&)Xzi0yvdIsN^0mm1>Y?Ls}|9P~$*t6t+!=<3?FR<qD-z0_Lp>oDJ$I zs8zBb!gX>Z(v`7XSSOo7^#rw9?g6z<9>sA6(rbmw6=(7!O@1FNoyJ^0hhPIBrE(b5 z)1X#K25NDg{Dd@DMN}^=#BcQ2==FsZ9pQIXp9n!hkb&+Q14*>dgxP^o=?_5%h2)+M zaxN;dJp>#w@MrRJ1{N`|<H3<=j-|r9c0}@Wkd*Ryy%ovp42a8%KmUino8)GcG0hst zbB4YRmde8rWQEw6p9WPb+i~oRwEfeo@>}Gi0yK_{5&6o^8*9$8<vX~$NrqvBs%vFC zQI1g3DmjVs7QM%C`t;2*5eU?UcY|<@T5a>c&z@yVtLe;|W7INay+Kjyt#qqB2kIKc z+v=PdGk03qKM_mw)e^_dnic39N7lVonuFdWgUyIK2T}~o{D^2^6LfU=CQ;_PYi1TO z{A`E6&tXWI#YDof=RxD$T!3^F;1)@!3Sqtt&x4UL{dWdhwEk?4^xq_O@j@#rgiDD{ zO67X+-hoTEY3mworIYMA;SXsE6Q+fQDk9U3a$Ag*{jdT|sq6x?6Xd0GFQ^+pZ4zGO zy6pI*R>F6;%Qo;zFhJq-4nSMwTu?o2Zbbl9E_g^Y%mhEN5)HNll?w{B(-q`)3wDL9 z-0ya|0{oKYQh<{`JLUFmXiND}z+)%&yj{jZ7MPu)T<;e7w+iC5(@NWp%U8Z^$(&U_ zUT;_o*Bh0Zns^O>Hzr<RSm_CSMl43nbn#k2r%k+^mCs=%60ZYVJjSbXqKnr%)=&lp zpK|dU0Fa5-`xaCPQ00P8HABX0H4r9VdqCNEW!u8JLY_5V<w0k}>vzU0-<o>Ro@L9R z+2!MPp_Q$UN4%0vygr0CwtZRYBzs0I)*<AkeWg^6#LHPZ2`iC!b%WfruQi}-`?7}m zCY%wk4*|06%YwE7RJkAtK9>sPRV~TIs~srUzAV@k@~rXNUJi6dyuOHM`?9FE<MUx2 zj4jLNl#kaN7IO%`Rjgv-H4NU^_GP6f>>06mUft)2zn)Ip_GRTM7<D7@dR2?Z_EkOE z#p@jl>`P$T{x}RE+rBJlH9(aMI>BcXubY7|?dus(u6^0Uxk8>bUfJb9XT*y?;UW1J z^>QR$dyC7*>q;xz58o<QH1YZp-k5kzx6--xj98pf_ZhD=_I?vDX9e$xN8{B8a?`#x zfimrDq&1XJVA*(m36P1`cnewtQ00QD@Y%$xR@lX>GbkIcXDrwi@~rVH4=NY075W6a zHzgldF~{1oY^gTC%zAe$a<%K-7j%{SFc_<3C*0)X6&Jj(DVx96b(?S-E#I2D$esac zIhTd_0>Y~RL;Sd}mTu)IVak6UtFpit&pQZtsr(n>%9xFA({*8Q3moJOE|M43AXkN5 z04vp1;yh4hg?NU-B+M>cA#PDH7m53o;zIE&P;{vfv~#I1CNsYTO0&qU#`VQSP@9CC zpANJWptzZ(k_ZWZu*A%bPMT7YdvT_1@wK+KI_EiQ5u|8WKh2}_oc9uNL15ZV2T-Qn zG_d8}PjK0Gvlt-LZXC$NL{PclZZ*hp=~*?%dGBjbw%x3-7F}(hwcV5lm1#E{b&Bs` z?c^X+9V*y0Dx@-y`d7?5sDXU6Bwd-1h*_Cn(|W=z+#0jHA-n^7gRt3cwPx#2%~vzB zrP2b1<y^=H!TKFihzzg2ip$=X;B5o%PT}Uk-BxplJ<G&jAup9_kk!Hk^iA?;;hCu9 zuBhUD5KL0Y?6W}pMOYf&0Kt=htd|l{_`6fM;jznRwm*{T1#k`SLRKM-nQjKWJSw>* zGQAUmL4dGgxFhnGHSuA@RH<AF{yo5~mmZ+DNqNj>83aE5?iB9dd}dXDawev}tloSF z*=sPfNx1jyP^%Hh<bkEq54?D6I?xeX`JdHJbX735RA}J>V2lNa*dJqIo?5`2J?u&Z znxf9M+WFjIOtqtuS)Do7^3^VfEkm#oSSr;a+pW29iP_3ZPa>D3My4Abfz))PE>@b8 zsO_&E3@q1f<gb}_yXi)MsVOcW`&n=y!DYMAMKu{cE+2<j&?tMZT<{<GV}{_XfihFp z9iVJinrVTq7-#KD<w3S970qS9O;>US<+>}<m0o5(p0`48&@Zw%9WBaNu57uy1ltaB zcOk;ti1d$u-zB>L-gq$5*Pg>-)yK8aQ&xAMJxlX1HQ3pZ{RgO<^pdeWD&Yk*`iU^# zyB2fYs*C;~tcm@J$Ts(ns~Hn6{O<$COq>q!n?<5HSqke9Q@_xZnK+%?!{SPd%mJ`{ zZ5rf4gTHBD2EfL)#Q6k%SE>vDBZ}kNKjmCkd3hGs(VnsX*L*n+UILV<ylJ3p<-KBo zE~ICzyz-zj;~+fz7F}o1w0s!Fwh=s(W~CBBT-R%k|3LbQQl~&Qs>3oJ1ofoV*iVg1 zOXYp=u7$Kz-URh2DEvilotQrJx%IdG^n8`emWLKmg?*-X22HbPov<hmYc}>7N;j&M zJ<3V>>-4TieFmxNQGZz7B1lmu%VEBJk2<fetCu9}##VyM_NZcjOpi*lpbUGiT+jtZ zO^<p6C{rm%K-o&ku|QYIvsOxZ&{=wvE9fCp6mwnh7xTfNnP~EDR<GH!Y*}?JJ>o=j zNj(;m(@{4o^^#Fl7zZi68&WggmRRXZXJcyHYiNU`WuQK7aJ+S>eAsZ~Z3jp>nH7Q8 z6Zvk|$;?b-F3(Gx)rrrjRZe7cpl2qs@~Fr}_JTq<k(Gx;CbDV`&X~w9wV4%0G7Xt< zAk$HRn~AJEDl(D11PCjU6WKItVt&MwnaG+oj80_bF_DSPOhMbN>Z8ttoq`Hr!UWYJ zw#EeY21xl=+;uqO|0Mj6&Os&qG_?7uWR@(3PEysRLO`{b74z*2|8s}eI}3XE3GZK! zYwy<ZS+PLMb+HSYlFKkRNg<yQEBR*t$@=-g-yp}JcE~!v<0|qX+!DN%t>b6No`<WY z@+YW9jY!48?6siGIJ;qv(KrN0W%S7FiQqVU7Z7Hgb%<>iiT=7CCQL(*YmD5?IP2so zxX6f%v!ft4<Ln+#W}F>ko$O1X9cTYl9LL$VnXXGuv$$e=u3V6+?s1%*0hH;|H-WNU z`gRL+QK;OnRQFl-HX)c>Ekl}eX;U6ocBnORS!7GQ2u{lAs}|D&<5IPmi;F|7h{ojs z^^fz<8o+E^oP2+5T#~a~Ty6wq;_}D*d??{B9F5Bn#p(Q$?cyS~m=z*%IZxfw`3ERF z|A4Y_DX_pRoPv$Z>hoM&S~h1~%H!7Q7S#8U>EBj)3WLp5TihIYDWi8Up^2BlPtIXE zIP^P25fJX0WC*0DIXP)@G;Cj~`wZJXfZ4D)`A$Z|?bn@x+%%`Ixh`z=ZK+NYXq(eY zNX?er%b?5*k!^8#E(!%>)Om(2(1LhgzBC49!{)-}+N*0$Jz5gX=JY+NZBia*!gfb1 z4H^zx^*U~hEpJ8@#_jo~w83k+mw+>IbBID9T-@5_xp+9~R!Af9xF2E@k0z~MJen5g zYtEk&XyY*hQWK8{K$&>7vbc`+T)AMjI>mS#S3KiUsSS*oZOmIO@GYlcn^9I<7mv3< zZIkji6OX0s)GHje%Ci`ZN@wRQBc&?iae6sz90s2skt>x~K;@jzvhyan!{!5<{3|YK zeg^X}#HDf!6hCE#n^O?3lfRKZj`TXIfJV8d1F2L{FM--D^+B!Gn>4w$I<`W~zcudg z4K&6ZH4QtG;_aCcO7WJ>EuhSe8mD#$YP?ay+cWPej<;;uccRC<QR8r4HB^GTQF8~x zrNSFEpMhE>{P7iYqbBYGQoK>q9#rg&n(0WJ8#Py0j|*w?`(R7;m^W(f0mR&>`2^G| zS*>Pyqh^$bc&*;h$g}GEss3$noT~GN#wLJbZ)m(lC2UX>MoV#$I>&GWWFnY@J9CQe z86$S4BR6*V)t{Rr_iPY%v!&sMp8LB^UPPtUvi`Zq`M1RV0Uy`PAqX*c@R=&lViN4x zUl&)Wl!bp4!Y^pi><R6$ZEK%B1J_+~+!KoH0-R|C_gZ;Ibu@ytaqnv*WFt5q7<0F7 zmQrjEJ3*O7;MDp;%{7AW6vsx;_afH_9BvVCkw#Dov1tSkgTmGpgr*U^hqP$~e}al_ z1ebJmjlh}woF=~ywpEYW2o?ci8o`sGR!K@Kjj<8rcSCtm;KD+D8rc>&A5z>wyHnL! zsdE4_mFgg`T4<zFL)~4ao&j-{x)~7sZPW(m3=}ahclT^SkFt$zCDQtLlkh1w*U?wH zidzv^D(MiUU2I@?%Ek$}{;^^Qm(e*ZSo|H3Jq09gB7@>D)MBjb2XcT_aEdZ|92C|| z5oEYqjN|tJm&y=O|MY~~R^bx;>sk4l?N$^)MjyG6kcYs(w->29K=Bp$QrQG*Wglk7 z2h6J3%+l>Ssm4L|ZXjgO6~Lew?i*V1=P;gB!>lfjLA+M`mXq>_YBAg=Xx{w`an05j z7R-vPrL|CKFlKA-Xg_+yE8FKUWmepicy4Y!lu#-H?Uays8F5@$bOU9kgx4(Yusv5U zSf=@MN?4?LP6>B`vQxre7ML<GpY}aBMZS1BjdO~e(4SL6d7PON>JCsP9L$>Qu37oY zI0QFk)XytvgKMs?z?sE^Lp)-Uh)jmU`WIs7WgxUoWSl%DO`~TbbLAixnU;fHWSrxD z3AB+}0I7-0W1viAYT5$Ua|JEfuK6-Dd}YZj9;#mf56ooQ&jN=!1v^=`9zrl9!*45Y zlkzwdnKfAd>z@hCYFpez@KQ#FR?`Fnvj;E}7>C#r4NSXLgfTGNu7oWU7$@H!8<-o1 z5y>VqZ@3GL^V>_02Ic^yCNO`4GJzRu%Qw}Pv*0Psmw{=GyiH(+fU<#k)B>M%3N|nc zMi9)v)EUXZl*gIC9ED8(%wqIvTihIYDWme&&;%Ewe*tECnL`u-;TBb2BNG!gCtVs1 zTaiYWVS8gVax!6a@|}!^TZ}%&0ZYTi=KxGkYi2vd$(XQx52*=TLrf1QZ0#(rvprWX z_(k(&*oFgT!gf6<8@3-U(DfwO)9%9TXu{S5<=!UcaVBiuL=74aW-&V3mN%m&<JNaA zZE!K#05}sjhbROh5;sUqJe+hZq>*^sIf-W2j7Cp(@fc#={+vMDzaE6t#N!)KCLR+k zZiYQqE(oYoj7Qxm#B=272Fk{xvu!@E|G0RJn@TX7QN?MDM|qry#{tO9pIMAvJu_dE zDd#XAD>l*w7o*34GmFvJi&%CpMjf^<u#v^+G?dybM*GjuH5i0uG0Nu|%wqJ8nWVTF z{Qy+#VziyDjziGGVzh8Qjd2~)W)>-~K4vP##pr{e%sRxWd9|YJkZ%;nbx7~o^q7lL zhsyyjvJTk;u~~=w2h=JlgwU)*Qs<E3Vzf7?*mcNtNSnpzSnKg>n*2Vve;ti+9r6Sq zW*zb~C_Id$X1NZTUCa=h#b`&Xev<0n27gs`E=KPMD0VUW1(nQV)RiKmHgw!#bkbb6 zZgFB~I<jtgTOqlH(KtjPZr##m9$nKvvlwk){c}dK7`=Xdxy5M6Vv_6`i_8arF^kbt zv}hKi&)By0qCErmuHv{DO`Q*%S&Z(qaz18*#psxgw8ciy3mCH)U7{45!vRpH5jeF) zP;-mXzZJ(uF!Czb2pn!F!{@F@wm@te!E>Ni$>$K7M(_>NrV((jH?|QBMcOn1XOdgv zXap~8pfNUrwSbsL@H(hfk`I7cj9$8sQ8tUwH*JB7sD3<{s|B7|i07IBGK*0MdB;K{ zm0I&^w-`MG;wtq4K=5Z4qt3uq=H(Wn<4ejmwyj9(pIMBqvYD>4XFPaq7NboU8Q4}` zjE=M7Loh9)p3qWoA^HYTW+6KL8sN9;LiAD#PN_ri4*<t5LMLL#F^kZ?*Qp8@p`Xvl z2aR>SstmcA5H3Q01;i{uS6@$xi_rHLb3o-HG{t6A-JX+bTznHzT!h}T1m?^zU)PEk z!MIz5J`1r~ggWUVNHNSWR}1|MajR%4ESRaFxwYVBD8?+c1}|e?oC=PDGE?KSdHGO6 zIWhpWQ$fZJ#BmXN1t>EWthKn!_FTE3vX+@s!Ft7WDtH2voeJDa;#H?$R}>$X(m1Dr zg}BbyCgpKvD#%+wr}(#3+Dt&vY`BXuP(vd=(X2azKNz@8*ddJ~_5+c8Q>jb^?;S`t z3STpG`YCnMjSFyRYcQBSv5ej*sWIY0ig#lxBLmEX5cAKh_KK|sTLF;~zi(nGxZ3N8 z6{lIYIK*`piMna5FxJh>fZ4in^3P!@GEHBm>oe93S8AqiYR}JylIQW)bY0!Vt#)<O z36!auW)|1do+}sJr}?sO<|>|bb1NuYH=kPI4^F|>&Av6RZbo39-zMd8rf$+PFX*2M z%*Yw}n(7NLWkm8Vk-z|E0^<-<EfR&!-%J<-^AW9?M(gCOSzfoEo2R2P1M?av6PVuC z??W+xsixx`8*Lv@CNM)RZj>u$!2!*efmx<_2IfIfHZW_h$_MRvZZF!cU*5!!U>fao z^tNqM9%lm6<YrZNEvAPpu2-LdX|TlwrZ-@wCp$zw5GZhejU9usg_cZE`dTYR24i~i z_mG>O%ob*XvTJ_6X1||6+mnm59WW?6K$)OCZE*+fxpKi#&6h#>TJa1@1q8|l#kCT* z6Yhf2RMps%-vG5u%HvE>7NgwyXYQCSEY8=|a(l+F#cN=A$Lu~(8}yD@d6c_r_LUmD zQ@6a`hUcfw(x?q;iB}r6Z$%~s=ETPxZ1mF+SiXVrfu2fpjbAnGSw=H2v;H1M*aqD% zc4Bu$A)^dr2_atbnjprHI-u=a95n+>n726Y7CBykM~mb5zQLjK`Bd=YCz-Qs*|VK< z^2z$xIh01Jz$Nf~@xYq=du8-&FBIh4bnn5~eX<C8p$dE(FZVX0c{eLmkuU%IYd*i) zbjp7x7`r(QAgjC;I5S#p17+HtLlgmlw)Zwnn+|yz5Zm_riN?xSgRvLvx4X9Y04US; zhFaiB0&Uy-O>t~{&9}O?H`d~&+H>WC%hWZty$L{>3yPJXY}?yzfe$+cJ5s%@V79%$ zHnzR;IMenzK&F3N^<M4+HYgbl8I&*7Ki<zR1kAL~Z!F?>dzPt*iel@07AVs?%cETD z45JEpPq#1ZZ-$<`r_1MrT;7j3%M-_${2?0!J#%}tJSuW~^>#JANpG(nwI&uJ8<}Ws zt$qZ#c}56(m(1Qh7i4ayF1O)xVd9-^mgzLqOqt3fT$$S6VFSo}NGom5pEH0J|J>?Y zRWU$jsCS5)ED|lNnZh`#{Xko0RCDr-M%wyJ%NlW~Ygs!%nU?jm^}LWk+p_*t99ve) zyIjk9(c<284W-~g&6h1}3Q(qHtp#OU*8eQf^*}eOy{=%ktc1JSvdZJi-j=*mK0^f- z+0xFo=TL<VG?r5N7P5R;!4l$0keODz8f6KEDruFy3I2LHh~p;V-C>8>4@{Nmr4j~j z4ouu8ohM<rV=auZ=PKs}N;RjR5I)PCHp){Vn_2luS^-900P{=8S4l==diEC5SKPy~ zfbXm2TX<i{QufL>YO*;5YXK>hhM-;r1>^A`+gS7>gD#b1Fweaga{g`5*VL+6j4Mtk zR4O+EHUqG2QeL`VmP2NqLvpej)<VKdc%f!uAq+#+Tz{Maaj&lIRR}LC&w#k=kB^+6 zm=fhx3|DpU;;&wb?2x^~k-FQY?w9xHc^==37Lf;}dcOIE+MEs@v0jkwIF_8p@i`7n zx_KWIJK#Me>ziZV^m96lLE1xltET(fwBlPid?m;qQ2C+=ey^rKx9NxFAkvjoZIV-~ z2(`Br=5;jL<h)fKn{%&SiAk^Pi#T2ds7Rfkn!%U$-{SaWP#FiX<58i*GdLQ?L-Gv- z75ogF-A?%^-t#VP`#hp?tCo8a{^mX+KQ0El-Ruba^y$+jb^7%Lv*TYi@ylZAYJN3Z z@THxePjSk-qyySsLXzw(#sHV481rkoz3Vu}Zu$BmwAHqscgE(uX6e<Lb3Hg04XlUB z^gJp>?D*ZCS{-9&+9eT&G4sJRxR6Mt-C}->ly^7HkB5R~ev$O5s~jt^Th?Rn&mKKv ziDSj>mT(4GV|E}+MlrNo%ny{NwRWtO-7+Qw)VSOTD&tYHKQ+4JLfn&T0VjOP>2Lww zx0C5;Nce5hUGVI@yJ7|Q7Z$g`i3Avj#-q{?Wx&rYc5M>Fv%j@iJ1>S;iEjQVf3}U` ztw-qatBd?_Zp7YjI{LG|uo&U}gc`%|FRrYHXBtetbxhS~R=|TE<VYP;>D^JOmSHNq zS8Z3}yT#P_CB0pZ=jU9IkIipcQ-m8s73DB;j>m|D{_~iO9y7{It1NB%J6>Rq_!vIY zQe^Ky$BTPR#*dlnrB#((Xvao3v`4N*4ryt^+bM>ZvPTZ1<EGUTJ~L-{8IQ@dQM0_X zI<mT#<K^#>@u-Qk`f}hJ$6NHcj6-#&HIk{A&y21okIQZ}rnIKAG2)CDcwFX{fO($O z9~(i&Jub;;;%T|kqGN;^dR(4B)Y4k%uPIuaczbqTGMH`TrA85C#^cfy9Ve~5G?EAt zZhnEbk=9AZFLcbEd!!|LXIf{e+rjZJd0eUzcae;Z6gy68)|(36rSgD}W#;^QSOK-r zE7JzZJXGEiFi-(|WH!o>Hdww(b39bQ-{^K}!(<)Wi^0Y1(Wjl#Mo8~-9M7xSzAj+X zWhOKD2=*S65k*B_+AO)FqUU{MG5~MZ7%#0@o*m_QfyZRRR4=VW_T@NM2$eJ&m2|D} zI{`*DrDo1J*k2<b(0+T2&X38c*)zPfo1`Q9LU%B<1&x_H+DqFkH4#k13+$Crbb{tN zK6;`34Mf>1=7$+up_f}8aOT$;Pau+(7q?gTq1QEUxetxX@<My%8S+{!UJ&77E?kV3 z);zBj;$d+ad&T@><5#Fc%gf&@$Iv^Qw|Q!j<HaTJ7W><cvm6g2j`;z{*Di7_cw&CV zu{xq`ttIY~85j-2aS46L+m8og7_5ud6b>cSN9AtUvC?+hKbE?|bGIF;zZ>p2Zk%3& zLX;V&S0nyrkaxpAKh3hb4THUC(bapcrTNIrFe5|$O=x>%OfAMxUDnj8L71$qDb6AI zD|y0N{59LjFpcofxp*sPvodyjW7;uxpA=qJT-N<lObAb*+hL%r(+U0c;`A5Ms;!b? zyq@3~yM>&~vpWWz8Gol`%|(MVmP;IJAli#z#XDBp2nutDvBmeF4GJ}BST*}O7UmAa znuYn;pb{KQ;I&}|9cyq8$HEL_6#s~KtO|~`0##`gD>~MWNL(s8)}LrQ29@}fm|qM# z&=kK8b^)u?l)C?wFJWRbAY1DG{bxtq@{Fne{p(M1s0eFNB!UsvLs@5_9vyH7YZnF< zlcQ&yNJ|{%Sdq}z!&GPH7_Ux~?szDmdPmgiAWS8ghOR+#8IV>31-VigPs&fV@Uri1 zk7H=4PmV87N>k*Mb$ip27#1H>&e}R*X$<Sei}4Uh?t7?Je$9rz`_<-7Trqo%(3wIq z8k1q%%9VK1?67yn-^pBjXS6ETcoN!zC<X$-pRuqA#05W^iBl+egeOV3O=a;thrsMp zBluP<3gX4Z#ZQ<z3$S=pujkhl@e-GGBiY~$V3wk6__)@SAeSjwYZu5H6i~Awu*;SE z)e&%4DECtw6K|YCwINeMu2k}uFF|e~86WcF4<d1=@^@p?Eb%^)38CL`gr9f8Pro7{ zl@HTkaPG)BFC}SSmLL$%{)8Rp`LBcRg$6$j`YNi1yb9Fq07OOgfu(+13(rD%eh&;3 z$*aeLRNxo~40^$<6U1Ac(!5y!W;(}<my(0=5cECY;aVea1IbYJyFqunA9PCSfDcTk zt)SCF!JXjbqhh^Up_xZPcP<5;5qfbs=q}8zLFmfYKzF6h%+SD_L0|G1=$z1wpF#Ke z0Cd~XPlrMG{TlRs?4+ziVn`4!zU+nmLfBG<GVwlKdIO0onK*%8?0XQ2iFEtFC>5j7 z9<&x8zq#?-^$4GayV6X&AJ)k0jb@Y>Zb?jHxYgf)SI)+WT_-nb3Rsf7wHU{gcVRm& z*nc@#;cpuN6yAsSEMC&sZ*WSi(q(5==vTS1P*1D&>uL4-dRp_lp4O(JsU}ugm#3%o zm+EQ5G(By+QBODBucw=z*VCrA^|bj<J>9~msuHVg>7u7wi}ZBcje5HME<J61Sx?)J z>uI~6N`*U{>FMs?db)R(o_1{1(*wKp^w1$aJ^YKFb|%%J-Xl%*w5yw*c8}E4qgU%` zPktI9kMSj_#43-^)6?F~dV1n1Jw16sPfx{R&6-%{ne+7Y?4^3zKTA)~ZPe3&y?T27 z13ex5kDgwriiVk3<;6Tby);lyFVEA{D{J-i>iv3p?KM5U{)3+0NW_GnSmn)ZoT^kw zkjwNOlwv)HWE0LwL$QLC#Hwu$)&{m}TdBiSyV^Kay}mv~d*g5&S_M%L#pAPT)xWNc z`j*rHGKfzQv`){fAr!~s=ft-Go7NMml1@o_=Oi3!N*H4NMx_eU*xu28yyTZJ1CgAE zsYjA4b;Hr;>&?~L_Je*(C$!AC>K#Ud6JCj>xP+_rMYj)ojlmDMo(6ZqCA|R*^Y@@K z!p$#buL$!eo)$@X^b(u`;hmT}7sZ9=l;9K!C#K+(5`L^TP8s3VXx59M(YPnhQ27*# z(w!2{31XAL3#TA;eIWc+OA0ZrtiByT`C7e*U&9D*1Vq9=qo)MIv%1rrx5m+(5tHc7 zv)Oc~(nPCR_a>I(=2xls$+akUI31Cb@Qkrk|FbjI_uzs>bJ;SHxjge9f(Kkg@Fvv1 zgcqY~0^y2z26j$`#$fUd?^;VR=1KLMf!awhUA=CgJwxwH?V({L>jmzH9+EYLxaze7 z(gsRtADs^_K0p06e6N0PKnx>NFNvvregGmdwcraq_0?XSIw;Vd%n|46Y4rJe8q*J_ zq&pE&sd^gWm4}f*9a%dW<Mib9h)QM$Fw<5qz%hLzj`-#FIs=h70bGVOK_%B1;rGJn zBQS)Av`tqL{2Q@#=Vt<NPe2n%EirmYQlqPJOiUYF3A27;+PEA&P2!KlCZ<i^tEVY% z>1pb5Jx%*ZPt%)pB4k!KJ<S=Wr+NHQ+{Co`H|y!DC-t=OV?AAcT2G5AUqHw;b@g;@ zM?GCPOi$OB=xNDKdRqE~o?h**`Mt4^LuuNf5A^i*5tSW2rKfj$<x}=vMLiv9rl+Ih zaY|y}mZVXeaZDb2jK>Ch$!WF;$8(bZhvV81dPymIZBFoh2~_WoB^Wy7ZsZz#K=hZP zQ%|5d1Rs>q=zgKp#)FV}Nd5*avxYoX52>9Z7s5)~Gtd?EUuEtQ84+Qo|B0GQ-$mQ? zq$|o0d|FQ3gE>;JieS*QpM*8^Y_$_<K}qLSz>mu(6+Ho2vQ!40{00^(l2r3eaFQPS zjK^LlC_S);^x@T{-~5-y4R?~WcO8!BymUK`<Iy`}iaUPD|F7ca!b;j9=*AY8??xM@ zDeeojUEdY=6RdH3u}Y|#4j<FA*KWfxc?3cs$<00@=X}_dq^U2F_A%{B@+(@-=P}Dm z(g$mJy!#IvtMcBsq*cUxFYDezcuVS`;D_LZ@Q{{!6)3MRFNLdLDjaJX%4NtXecjI+ zA^DS-Y3M7GPMOz8`%n7ga^HEL$1Wnqg6TV6W9jk_4Bbtv@b`#R%cwS%)FLp>Tge=I zQpR5AWlHS;dT#T8cH2?plLCMHS`6?XgmgezME<lEI6TI=ps{>;4F>rqpST*fwopb& z4^T`3BEC`uReU0%NNot)z765V5C?oY5)oRf`%2Mxj~+)b<QK|_N}r0s!^<#=(?g%% z<$0=H6%Ew5q?Vg-AF-D1BYwr6B>utlfOpQdOEJDQ;SORY-9c;sEs>_3n}N~eFNVo$ zhA$#|=XM>A;U8Z-WS2>-kjd3h@|I%A6RZ5jIW)1#znnr7tDNQxn!FtIkR;E(mVmUa zru*+U9e$tb@XuDv2Rv<mGd&&XrKjh|<CG;MM$YuocI0>W@RNA3!0{rT6hxyZ%<<B8 z?z|Y^B17+%Kb^?PlSdw7z8M@Jl3&%%vxc1~TTqnR**X_wp&;pX=HoCH7QO7%iy`Wy zqV5#+iHOeoa1um4RTRVan*CLPA-(MkpqtleHyokxa>n8)wYnsP7J-}FVl4cU3awag zE%m2<D_khsAW3@z9C5sh<jDvx{V-cjOZ}<e3Kz?}5rG{;8VG;tw?ePDah}J8g#1Rt zr!<%T991o#VA>Guw2+;Og9W@~0Q>>i3YTBe%3A0^fI5`k4F=NZ!y@|EwT*xp_C{Bj z7#2k^PlX{P{(@44k@E{ZkIg~mM>3)|X1)sJ?}9<uQchdFXeBdy0Wov)LLhAJw9U(y zr=gI?ZrfU~Xj&^HA#@G=Y90E3LXrtewwTO_XAEqQ?o^#@Pg=?|jnEawNG0&nC}5<O zH%=NvcxDOKMt|ftV~QA{8>tgQT+Ou(bq73;WJ2gtkb$`Pk?3a$q2c6{)0Rv9jNqU; z$>@^<YhX4QI)g32@7V|RU}bkkRRphG0CXsHr~&9<q*Fp;(AR^*NvHW;3BRHttTYh* zGG=gOuM&Lf4l;Qghjda-G~q(za6d&qP(%tM{wij$s8*rX3c{4ps$)dOyV_YTqk&Rz z7EA~=12T_fv;ShDQa5n{vTqkxH)-k$+>e4R+~^Tx5PpMG(fNI*;Z6vo)$YXa(9fmx zQw}`g1?}-&*zo(P0E+81IQbSHvVghpTQ@^3JRTQ`f$-ih5SZ}5m$<Y$f`L0ey!r=t z5blP#E*O6KCIl$_^4(|_;Y*QO#c+>jG5&-fMmJ6j`(NRTEBw{Fm~O%we!|!iUjI5* zmALEfg~Nsa!8$&i@DP^f;iI^!t`>gjG#W&B^gcZ77ryW*ESAEZUqPV5bvV6*lQE0d z4FCKZR$bwGTQDSs-?|r_JpA!?407QQo<_$G&xUUq;f-G+CgDMtrR#;)eTPXfy!m&8 zJNzQ@Z5VE_3$snQ4zwDF_aDN@9d7kLM$&LS<k&R)7rbp2zVUI4SmFDB#UK;D<5tf* zFZ@^~@tS){4G}^~ISy!CT>763)+bPq@V8J1gdYMlF5Kfq2BqOgEb95E=+Mx6bUojF zCDyzWZoC4gK=_uYeXi$oM#Nz~?<GBp!b@^xE;ict?bQWK-JS2i_3Z7aD?bdM>sLE8 z1~Hs-8*qLS0$I1sGnc~Utz(gO#i5)Un)d1sx{9H{0pCwvq5QXVKsQx>hwAm<Wad*< zfv?oGTXiIwJWr6<aXF^r_ZuWj8f2-R#>aULQUpejcm(<ls_O+(D0O>7BvLhzl3KL` z5;ZiDmda01Hb~P%M(U{+NTh2bGqpR$odz{Ek&}97CKBgpqHXFYXyOfOX=1;ZdR`-> z&ehb*Uh2Jdk*cGqLtg5hen@3#>U}TuvtdZplVarmxtIFxBBUC~LZnW3soBGkYNWoO z^imh(BGpt=zj~=l`yiDikD*xq^-|kUL@GzxBDF|TkJdygS9&9Lt)woz0I3#o9c*4F zslS{P@EWw1bx19f)aA5tfjkG~YDvw<4A-EC97XD8N$t+m#hThGsePEbL{s-lYJaAB zYHFvX4rQvBE@t;i>aktOp^y5xUs9hzB{b+On~)!FocT|6!T{fy{XF>5B6NyI9<O9V zT`&bU^57`wn=rK+Ixh6nHKgfKDCAx1=oEZVZyEYzp-`h!sPX0V&=|PCaY0<;fj8lt z-vCop<G~c?KVAdmmE3~zLhCOC-Cr9+=n_a951R{goabK!1C1w6Mk0^WOzBn|jNwA> zgqtL0uFjNqF(NnqCZPP2<nw@`jEyZ*dL%&_=l8-%xS5hpN>vRmQ?6VJ#BWBQ`z+}k z%AIg6g_V4IAl!XP9~>j(7mylX98e+mWK_wyHDn2deT|SiHAYDF&TwldI$z^?M#>GG zveNfhq!Y#^?&}zDE|jGRS>vA!KT{rViqssfWI06?r}*^0;c7aQ2mvb~Q|grfH_70* zA!I^O4xA}dE&^<vwi0Pe7!NSg38y?`>0}>3HX2J4BbJnk&6cJ!Wf(*EyK$CVPG#ac zX8?qM8zDEMR0yTy9^hYL;=-LN<Et8Xp*zwIkn0SDyH=)3oOE>tq*Z-w4cyF1CuQQ7 zDOa#gMjF+I6l#0XDrFLdt*;S#n6>k;!Eq0)JPr$X`Z>)YxII?R&vZ4HDeuwOrwokS zXHj1r;#4yrCK?2H)(pa`-*y#*j~gNP+sX)!HHNUrR0en9%wCc<UakJdat#L8#y4xz z=l-1Wk)_4e$msSsa)ig=PMHS5%HBN}vS(DroxC!#F6^VL)h4(1%Gj)gA*J!3tSsT4 zUyNR+^ugM(aerThcSRH<6`M{T;(tF*c{_3FGHZ(0Hfaer4MS~PVWMA3e=z8v&m}D* z9TyslQ8noX(xK4z1)xhwCx&`LDQP+Bl+f>3uP3b_T`e?oD(D+Yr-fEvG)Y=Xx>l(B zAkeEwXM}nq<VkC%fX)n+V8x!aj;%QdO|yXAt(J*5H!-z%h-6a^Y`17cxTzV9h;~H) zF764y9W*c8?u>@T0jk0G#_QAqH$ux>$dt=jSzAojUlQ>%jHN535wzW%)z?_A%E0j- z4Kz1WquHShV-SJH`=u`UdN9IFB(cdKS3i+eKtD2NGLbJyPa=7UMaIR&Vbso)^M?Ra zL)39@&&D{eCNt$KT6sqpPT|gN)QTG>Z|w%eQNa;=sAoYmmh^T&Jg4R1c5h53<iU-7 zY?7nQz{Q<l?egHiTLk`vhR?0xXe3PFGbMi(5Zz4yxNCf-?H5J>(aRvX>2xNd5*v13 zgWz7XL1;I${taCM#6Z)Fxecv;a1wZAAOwqyfE&|R&_GgHqEC`>WR(hctBvzCiwpaO zm}?vRvH&Lqa34EbI;{U^q7^s(W(JNb=LUBf1G};zPm)J)QUJHUV+>@-Y3yk?ZYTfZ zqyS#eM=iMc-FZGxuSgMudN2snoKoV>MRUUJ(;k>FM6cSp4-mz;CeUdR5GRB;oaCvq zAlhCK2TA5n8_;Ea?saDV{2RjH-!K{EN%pIT62uZN^Y^(U0sNCDh)ur*2kZ}wneJu& z?|SIz_DWhUD{<n<v%JiIH)DuVahtN@4Dm4FWCo;ZTij!XIk}R62WegpTE`jkDF)-r z1o^Cyz5bo&P^c~bIBjM{Spapa$n8$1VKi=J$nO{gGLz&1RON1>ULcB8nS5@?k~6c4 z9K{H!sPE5;(rBbg<{XO((~R2s8%0Qe2@!%{#SCRl`TQz;ngJZiCh7?sAX~!NX2^?J z1-?Vs#gu70GvvQ0NM-|h40;-}iB8WbUnFCujrB4!<sl55s@zEU9(ZP!91K{FLE@U4 z8Mh8?gM~bj0SOGol%AlR1S@@(QW^>l4&nLTCT)20CA72z*H-6qAmrvP==P*Tp~)EV zn{+0f61oygnkL;zr-hPHk4<`z&Inyc-HS<QhN@8a64E)L@zm`}x^1Wrj!k-z-tUFl zAl0Nd6S$4|!F5RVVG}&$g+5`TfQh%g(0E+uH0j60J6`CEE=XL)#9=RVNg)#bnRwR= zEogwmKqlVvLU*Gon+#*(h!+}xm3EWiOdRz>qiJm<6S!UZ39XH0;sY<#tq_T^Onm5t z=F-}DCO+~)+i7hY6CZn_D`~BWiBHhOB-9Pbg)D^dzLj=AvpLyS1Q$I`7BvN15<<Mk z<=3f(OThCkL8tWBpr)H;pw_)SRyg(w;t-)La0pdv)w=~=3gzQ}@kv5jq<a!NV|*1M z%JY+6fESW9dMS=Qqy&R`e06C()$BL<atE?ZyOesKm8Q!hXt#9Jmlr9$l2V=W06BUd z4Aho`sHsul`|@?Hfr~Mq#n+dghI-yLl_(8l#F+1hsWZN@G(e3TX+~69Pex<a6W>hk zMqzz9pAyX&dA^B08Q(&#>Sa2&FC!y*W|xdh1l#~PH66I~WgV7XzAP_?LGbNXa1VKO z9Do<f`q|Fl?z4cA@o^}{Un0#h2{G`#9Esv=o?9>=#9t=0W>EYm#Aa<kso9!?TLpj& zmGOwGFSY8P4HCy18zZOD%ze2a0#TpYeo(lbsIvIEGC(sL8G$g6={z{d0$G6>(U-*$ z$WlUhaF9ikSb-2;g&TKS+opzXM%T;DVEOV|1fnI<Lidn=!tiC899&|?WM6(HOugj+ z`MiqqXT2vOIPFU+E+uU%ieOxD79uKHFG<ZHfjJSNcd=A&f=q6a@AL4sg0{38@?AVw zg&`Rf#a*JztX(2AB22TJ*wRRL$nvN__uZ{vuRK&%5K{mPIUq;=FG!g@-jqM1xJcEP zfxIU*>PMoW5WVYcGx}K0k4iO0taW3chJ4Fn|1Q!$f=L?-v0$DkMfl?Xl?6B8<zfU$ ziX#xc(clmXf$`lfVp9~MwP|gH13xach^L|mZF?EAo(?n(^hfh#Q<L{22xOqbyud}6 zV%W&!Hww*&(i02b(O!JVz++gut7a7pmbPD8VUNIR%qptcoI<0SAzt@@7vC@NOe%im z0t1=!ifUTn6@lgu^2WbRh}C@Q1!#^6q&v+ev6?EJ9QYlcs^%TBn*BL0%nAq=v7D%7 zf2@#8jQIJ1dxu-$C$U0qzsHvZzQr;|HUAeC_L7O8iI=q~aB2Ze)^6wmV49mo*g)bp z2c9klq<vWkLL9_OE`EDp_%v&M5D_L&z2pU~jIz)=Fki@=a;m-L^&U`tCeQ=JhOCN6 zVUzDj#2*Ztmtt2D4@7Nd$bmQr4+nOP$I=8nS>B8YO~18>uLG|NKCME;$%t)(=!u6^ zz4$)^16x}Y;YQBqSU{qGOR}}lf&equum`}!W&`2HIsWC{ZNt1giqMX15e@ucUyGO% zMcBrzHnRQqud#@mqX^r$N5FhmSJ{e6*DmyA6k&5w!~j`8$0ClGMQC|Up)y3VP371; zi>-`?VM`Sm7*I6A;z#@I5FO35d0Ci6WTne?OxTJT5JhxDbj<D3Uh**F9>3OqW*q8Z zRurOTYoN>WtWyO^*2ab?z!r@w)%czMMl=u2<+-wmGDRac%a=A7{1tm5ij6Irnta{A z9&JZq6*J3307X;8$9{hdSc=GvB4Uen{c7~%xVXPBM9~IEAv)tlaT%hx=5d?Qpw--> zC{|&%s0!;E*Q%$5J#rRUnetL0YrI_S%KJ$<h1f!?@u_h;(Qnj;I80tKjoB>otgDOT z?zqCja>~KZDAvZf9Q11)ItNCv8UovV)7eQLiu(&AkLG-J6sFdAK+F}kFOE;NsI{$8 z7}FM!wN!Q%TEt6b5oVE*AwxPMzhiOVb+`GQiozoKxw%KNf5nZ-wb&+@24bV43ap+o zai><+ZPFMEOD)kAXVZ!ezGl-Xz8;20Rao+WDWH^!?HJ!@mc>4PHmv$(<Esh<@olh~ zp~k<8Drhz6!8S3)j)>3gVzJelMamn+p5ghN_)}Q@tMUB*OTl@*JpLBv$n>*e&+z== z_*bwrQRCasrVw5E+1NZ0|5q)maQJKr>OK$7rGxPe+gOFTth1CiQgWy8X8d$lQ+a1o zh^|+A$Z0gQtSy1f@g@gf#zi%v%`IB$9@76>Xxtb05rY#;?aQXKX+$fbx0GNI&f2v6 zJa^IaEEG(GWD_upunggqf7anZ2ee9^;lHO@orBF1I^vDjOa6z2QdTf<BWLpp*^!vg z9|YkIPOiNYPV}%31vDbUEqlIs(f8s9Bs?(D3cJJ#Ls&t?Uzu<{T;Y9iDU20zn<MLs zz$o+{b#O&QXl_hI9W+}a@$(Yitzfacqu5Aygr_tazcgW&TMvC0g+&8sU|IhS{N3JK z6NJ)+MkC0aVXX(P-IZ_ztx6rtjKX3wB`m9=KYhG~T^@x+GS%vFCZ9{FQ^jJhIt$jq zvg-IREVQugQCO^lW2?i#&l3K|nnoRbB?^mmkg%*A{~ok@h5Z(Vo#CLG{43$)MHXAD zc_cIuEF4r=Qt&rtvP%>e>tOd0aIjWzGy<wQPmIE19V9I40{?<m7Pc`8i)88|s3zM6 z>*LZ~O+IrLEF4r=&)}yn&|gPku?_}P;o#ulz^>L>rJP7{V;v+c>vDfP7G;`gn<(rI z2i4@9;ETAbQ0%a?VBw&eEcBbYHn=zni*;}h29o&o!2@%wwFjcGSO*Eqn&gj2vat7~ zurnM~laB<)q1mc~r_X|ggKBb-zZ6ry!Wy9ypQV%3?*j+l4*r5F)@R0gM`5uYn7g9! zUj-{+Nir6lOQuC(EC=!<B5S?h2xE{UZiylyhTJ@@*gO1Vg%<nv|Aj3xPpj4*|521k zb2t^%Vvw8<2mR@jEus!wvt^F@px8#n-*^3YFe<9Gv*Jvv_3{|OgwP<E%VU%h^x?dO zPzmVP_DErC<@cEfc3S+6{)1qJKElKhzmf*<b%;dJt4N1JQ@P2snh%zxcztLnEq=W} z0$r&3RZ#P!fG@&kwKQ971$+rMt1Tan5-H$ov{@GsE7I5OTRgZ2!xy(Lq=B@p4a<*D z!l=ScB&psKwx<(}8wH0)LH1M~jP@$ajmjFzomWEk?2IBHFD9S+ZFtT_j-e~WKVO0f z%7|G0FpSReFD)Mc{?!q_iC6=vRRH0U_lDZ%%r-{=aH3X6$Ua<x$>3*}bbmyqbDx_4 z&x6ZZ^#WDVx7Cy5fJNJbLBVM(kK&K*M}fqLf^pgidr46*n0Q9^W4R-B%Sju^Kd>Bs zs=_quM#l&M&ye;V1kIvA6SOt;F~+WK6BSsE46D91;-gIzBaz2CZ*dSaZYaA`7Ywg{ ziH~Q0E@Tty_a%<mBgn<`L;Vh-g0e@Nl=L$%Fq>4M-}?EGjW(&ce&GzH#+X#7pLt{1 zq*D5smz7N_<I)k6CwtiwOzMK9`%yvC{m0(WPL&?W*7IxsjmacCT~mA{KBW<owIWIT zo^v0%2<a)b(d=BwLF+`a>cglpnUaTRrR;0ZQ?{tUyKKT}K6=O36|!f^5+Krs(F7j7 zQ{F<kJ;F;LO-C*<f@LC4L?zlYtqOkEGb*5pSyU`TjGfgx<a9ZR;w)rXbvUzI(px)c z(pU%V1Kh*P-gf{g;^q7Z!noEz=HOyF`$)sVc;^8XDFX<YrsZiMeWyb9`P_?b2P%%p zobnWivcG*11G@IGo67+*q$)$6D2tcjVLg;a9tFZEUoNNVbQSq>i1n?%2~!@TFJID< zhBaO5a)4|>pU-Y9aTxA=86elxK(f93XAF})WaKy`JITvv1PlqPlTp;@)R#xmC9*rq z)o87FnA=#@=tV>5<q?|@@)6{`%b=SO8jNEeYbhZ_*IS1sl0h;-$$@Mfq3ru50eeK< zmoG#fPw8E3G(5hGk-bm!Nm^g(nOb;G{xg>z?1P;&DoJ`Gj@}?ai^_f;#eTn>WUxwJ z5&0n^KzFUhT6tY2A++q4l2(JZ=oUY1&^lBF$vlz?N)BY1GPB>28_$QI9Er1!sb`+w zJrUzy_HmVj{O*sV(PV$4Wk~V6Ga%U~RF>v<=f-39w{jb7Wcao13;(=D%C2MI^><18 zn!ig{%7E&R;*$2|ewQ2`g7oKz)V|XHu(4cE1{FelN?xkP$elvT(%2sGjH3L)82=%i z5e8o>V<*Q-t`H6d*@1vB*%5B~3ovNz>{_`GdGDy46<tOi2l@D@oRRjfkR3Fg0MYdk zk?m^MYzVU3BQnhvzG^S56j%jq)PFf~4_USZR+9p+6`OwK%f}H2l)LnRG(GSk1}0xT zl*1G>{Sb?!O}w7W;=o%gkdLbNr9nB&lSsqPofy%w>jdgyc14#dhhZB6rl<oj^#U~! zTVEzeF%+k-qn-M4JOE77z?)TxvA$4b!iQGJL_%m2j(L~Cp@a};l?pV$Y8~QLphNs0 z0@;4TC~F;hjbv?*35M(jwS*9#%J*Nv<aS;j8UA>TCFec$2e1jDf2e`+12+H{&j)+w zSkS`vlgy)0e0>SBA!(3(s*g?ar6nWd8%~g2N!dqC2;XEfn@NpjDa}1VeHkBNx4k9- z>E=!9BTD}E1$Z33IlT3TmS%v=As2I<3^i}=+hky<d1>D!<A$2|^=&dV)V!*1lPN<N zH-M=;o6Hz$UeLG6{GsOEe3Ohz>}OufH_1Rh^G3cE4mB_1Tg^l-Zx%|?I>gr>@-BzZ zc~fw>G9lC!P7hm#Rds_$gO{OsrZsqy4~K@XZGp!spCXC7(HB7cG@lX;g}QtPdOyRQ zg7|j>55r>^)%zP*e9Ti<2;^RXgmUk5+^Pst^=@cAIov6e-05w9((_k80a1M?4xZGJ z1N}TN_t=kEJ?fm2Mxn&K*#XnPf|bYDoLVc{I>e{X6GD6pyHlves2@fn3oN@ryJ}#4 zGMdhM!)J_{;<Xq<I?n5q(qhv00P&Ry1DecmSkM&GA%cp(189B(G*{orFqY<#4taG? zFG3c_14{r(2(7@ekXi6uG=06mykmeT#1Qiq3Fc`SzM+=hj-_oZZK{C3Mju(?8*8rh zbs&2^EeYRXbL`G!-$eI>Z?qY9rp&ql>{EfG<ntA`XwKRt&4I=6M(Fz_Ey6xuofEzX zXKs{hh%)7VTpzV)6VOE<-;Q$`3`g5(QPpQmg|Ew{(*-^7Nu)^-4)xVpzC@==W-Q2* zRRFdaXP%7Xt99l9qUd0oDP3y=G2E#0t-JDw8uC*%5Pt@QFXN@NkmXBtp~QVGUW*0h zX{Z`9>|7{ZEyDNp((%tgC!wRZxJv`g_xFsGoXsGsPuX4#D_`o1%FIJNjb#+-y2aDo z02aRPS00clyJi9KhN)h@38)Cf=28qUEhd`c^VLAJo5hEYT!1!US<_;aDL&s9G6;PX z3Qw6b?&-e1`NOw}^rav3=1*hEy9C19*bJp&K4c6k3Nr;mcZ+wF-ORDmSx{G)?pQvw zII0gM^*Sq{I>YgxJ{&i`3;@>0(E3h&ChGdKvXNa;)|T(e&z<q8^n^nE=3!E^JgnmK zYQ6wq^2_t!XJrASb^TGTzmj{wto&mL-{7j5R5AcEuhNvF$zI!f3!vY;ZM`uU;*E$A zv*&tk>wgDm^S1Si!0{5>rDb%%>HKpSBAIx8os~SbPrIF`4z=H;tYeiAk!p6!NPN<? zT0fXe>{y+g#EuQW(o>5c^>o1>dg>*rG`NzU##YA((0T^i+(0`R=*0#)z(7YSwAlz; zx^_z5gnW|LV#y@_8yLVkg*hI2&6=aY7u4NNC-T#7)KmH%=1_UVHJ;bGTICkFF1s+j z@;+2bmvbuD$PaiIeOmd=f%s8^k^b9=S+}a)He-FvtEuia`ht`auf_I!jAA|N6u|%C zbB238>ap`-vCmKb_h@t{=1Ltp>p`AI5HD;Sz3Y2DvX-Ff$@x)!D_Oo2I;|2%fN!xF z$XJOLcwjZ?h@R;+>ps%=+SX<G$7sdWO-fFOmcJZR*7<46fK2*>wd~Kn2#oYiWPCIT zj3nHx^yIRsBS2o8LB{2^c$|mDfh6gdo03)_P?9vV4Ue_Z043>`b~uh5?sZIxhrO}G zbG?qWGn8uKb!^&Rsg_>HHhfEZ?C@4z$BU*bmFIQrw?e7bUdLhY!V9l$F^<wMwLN_A z$4`{BOVu|y1S0w^=U1NsQ2|94r+2FZ4kn_$)sd>*0gjo8h!AKbgl2-sqph|qBb0ai zU&@29Ml#BTs4{=%C2ua3mm<EQPF2}vL-R1kb*jeq958k9vlh~!hEATxA=L^HuPwjG zC6^5IP`GjC<0vGt<j5nc?M{k&CNoCkS(2V9rjR9G+s9Ot!JujRd)74~7=2nrEf_^3 zYH36Puk8U9X;_V@s}Z3YysV-DjI$99G@>}K?VBnZe@{d-!HD9$9QIP_RXb;2KF;03 zdA#Cm9XbGHUi$z_@J0~rx_9mmVAO4h$-H_{-UB3b`vQC`KKC%#Kw=y;>x#dT9s+$@ zX~7pG@d9ES4APMo5bL3DrCknA%nOL^BfRu0AOW~XJ=nWg`bPwjYiIKUVm9V5nw2?3 zj3JfYgR1TY#IOE?frjjxqJTaIU|v8R`>nO`Oe7E8S1J1f;(7aF;<G4%c`6JUnHLbh ze#l<&{T0b5@&e+pJ<zTV6;t4J)mAUu3y9C{03t@pmV6iiPY88^S{}*P%4n^Ogirvv zv<?+gNHRgm79RkI*APDfyE@r1uOY5w_7udthIoI3m;MDv#QPVF_IM5Pg^0k$yN&QQ z_l!yS7y(U~7tfLFB&1r0zQHk%WQ)_Lrt9{Isp-V-$hi|ZF*V&V!b`shl4wm|5D}EC z=}X^1yQ7gpA__>Qx1g%4={Hwmh9&!&D4?wYn3^8>thI1YB#*Py^tV2)5?+ZSm}l9V zegOsfo3T9>$tY6ONjt$0Ld6s~UA5H<SJRFE1tLbux;qx+F&k=mBwH(^wK5VyKWK<A zp^#)kh-8b;fJ03`0J=KaF*Usayfg}8YI;M2XR0px!l?pntYMsAD`*|si(?*1e9Z?L z4g4O5oM0E(d?{u+ZsP@C5DL6NhCI@U&&SFox8QTI5X)c8YAY$v3a^ymH{-{t!599N zQ`+5D$eVh>5t98deia)<ki4j{hdhC4DL7URykjaYAeT{U?ADXo*F!o{W*+8~yE7sZ zjW-@&+y+i?nzVYxDQ}2EwBOZ}X_z{K3uWL&T6i=nW{ttZ#w#JdO-`P27LG<CY-NDF zi1{P<iriFLywe?M<+ljLN#Br%-@rrS$&^;bsBeqjLq;+8w`DGdFQc1FsVSY6z9)TN zbh-txy4|tx41OR3e{{N2Vs%yeiEMqu=`N4eT@w%8FJxd6zGHw=1mwP0U6me_g9lAd z3dl>bx>FiM_XqhN>l~wdELK;gCuIgY0ONyC(e#WdZ+k$4zshGf;k)Um>VRZGnr;JG z7mJDDf90uH@SCnJDC`&`<mY38f6G)1uO`<kDC9LIf~-O>F!_kfw3tH18$y0-CKwmk z8fgUUV>DG53cUM`(|jaGQ@u?L)Vj-g`(}(#y-f)Wde?dTeT-0Fnywbu^}XlOMSRK& z>pkbK3ey5FWAHFdq9KLW+jmmoZLPqrPn_n3F`6pO2;8;FX%3Ik{NWsEPV_(f8XwXP zaocAFgr+U2adXgS-$Ra!0eGQ5`$-3WA_}I*>T9|MPe=fGm7k5aWGsIi1zQN80uFBV zd*G8>tR7$DFgn=GS-qx5){|7Mnu7=Z5x)>qKZ>Ce>guj>5WnX?{khAjZ&`>LNc9Gv z1t0T={}=D3YJnFLtfPuHDRZ#k<{T-0^Y1+1EbsXLu&m(txOeV%mXH3QmTSmrw#<Tn z{17pSFSRJMUqCALiG)GF)S~mN755KF!>ITXjD}ELMQdXMk{^-SLD@W}8ob;;@to&9 z4zP@jK+;t?L()s2JSC9zDW2`bP$VTpxM7x$sRpM9Rzk>Hlr0f;4A3f^8<@YslvtjK zYMRGXgC&7#zgx{CQB5nnE->R>t9dG_nW4|H21^60KENlXnP*CY3kUM#1Fpf9ffs+m zSG6h3rqFrI$5exB1EUUE%}Zi6Rk$(m@oB3$E>@Gzbp|&FZh6lx>#vU$@&VW2ZGo=0 z+Ev=NSRq$%!R>)Nj$7frsL(vp61+6-4-E72F$FqGr?VzdmOrpG4&D&AA8U&pEX%)9 zg!YgOsmum=SDb&F4Pr*$hz*PA&=rWs;^sVW5#6H*wr|rLGvxgSfc+=#q3<kg>e*nu z^m(^n$M{tb!kZOQ2&*0s=<sQ{V9)rUP%*M2DrG(>jY<c{|8SoT#OqOnb|<SpCjPOH zq5pGKO6%#dS<HyP4j)^PD*Ymb)uL!V)=Eiy?yIoE4~*HE@=>649^fb+-wnPSn8pti z^@%{>BOlEPmd2lW!G@tIB6K(P6>(F1ZldV;AZv**!-JM0LpELr8+XL-e%+Sy(K8VD zvb~%L<lzENJI#?Za#6$&fhVx;VX5T5XV_@Lnm-wMXqWZ0CYp>bsr5q<zXtyImbKA= zh_aqGgpC?;%digF$y|n=VPhi^t>Z>KjpwF_SX9nNBYC+35WC`k-|nt=O<%)0&n)qt zN2n7*4?r)EWNRf`he)@08YXip4&--zCRD45%iTp}dwz0_6y!Bgri>`^DsGgM%ybq& z;!QHV+eMNub4>I3CLIH<$_~klO6Nln>v-OXsrXl`HTXm=EnQp=kRe<!R>bS)FWUv< zSR$5du4W{w*g~oz4q9W^Mbyz~ILuXSFMa>Cf!-R`G$UEXi=^IitNBb+(+Yb_2h8YN z%^yZJ%}7>pfIRZ89jyL{YFgoN>5h)5!(6q?W4z@^R&l(P9JHFb6q*2Lhzh4mB}_xA z$qnjAIXTQ#yj{NEXKQm(tdPT8#XIE<T&(?#n98zPA&0q&_sJT}BPzTrR(K!|!YAds z-JZ9G5q*h5b;xupeXPCWA(`}{1)Ml5-~-vW9v{%Bg$n(h*REsoS>cMOqz6VY9W0v> zVe+s;p(4%+ytlzt#idb%4lxQd<448Tf!V(yo1(H1R5nMkid_R)KiG1vjUr-3v5J=m zn%@ciJyEG<!GnF0vEtakqPqb(9EGrD+R>@v^uSL?A^jmDW!{*HE6xva2U%z03Ikja zAbf}WMb`$JV4y#O4kL|Xg&egit_=*m!xsJjarWNvSrpy-@Sfc}$xR3(Ktc#Llu!c+ z2|<cL=)I|cjov#5f>Dto0xBX!2`F}KSU^QZDIzFh<3RyM6gw7ds66&Z-s?IuyL%__ z{r&Og^U3baIoCOJrq6wLXSN5KF%@7&zQp_7dym?tI4KbK3z*|t;uG#4XpdUM%g;h^ z)JojpPF`tKdGf4O6!E6J{FF`Q;8{92Y9$_V*ZCtbodzW>Rm3Omf%~kERFs-&z=5S0 zwGw}EbGF)XttAm9a?5coG0r=FiyhZ4E~TTYRKeVf!|hZm`~}M+Y~rIlN2X<T0b~kH zkXIat1wzXxN3)jEyU1iPPme~dn_1&xxU*(ql&sr`enB`Tcy>+QIzpFk6>|BDT4{CV z>wuP_;Ck{3&eN%z_2culUwXh-sjEUQr0N&YT7Mx15iyF45G>+hIPuX&z!fl<7ncM~ znHHljiSeNHqpAg<#CTA~2egbO;DjEOg#p8siGNtvW1r*wB`Ud}h*b<_%%-UCLFte6 z&qR{<hJdRLz<5ypiipwhZIDJrHz+9SD;snaD#}96n4G~h6&Co)7TsgpX9J?tlE8y9 z{YyyqEG4a0_#TwS{{j)Co8`9$oi;u?9byFx!f&Zp65^xHU~S9jaxxjjqd)}n_5%SA z%8v-AksRYe*#%k^GGaU^?+3Ju(+E1D2StHl`zr>wW%Msx3mD8RYbvzGWib_6>rx~z z5R{k-Z57ZmhJX`R=mi0zRE2(d0uOSiWEK&l7|Q5MQNKcqzJ{-#<l903&y5DaROoq_ z3RJ_3K^o_%&|?Ro;-e5jiINqXi=jXVoIiquf(jjnX;rF1#AG-_rPT_*LMPJY7Q<x~ z9o7mhgjfNCEtSwRN<w_}j27`wG8v4IGMIP3ROm|xr;!{}p|^rog^ZXAeI%e|yoz8< zg(@(tP@ZUs_aAUAU=WA0A)z71aG^`=iLs$ejEoqU*w{C*?;dO^e>swWh9OJ>>Mt8A z%`hS`U1>t*3zlhJVm~K}!^R^$LT2C+8-#I&h3Lw-P;cN8yJrJAHv}9lZ~VfxF0tv* zY=j>PA=<qHmsrkE)bLu!CLS8BOKeTl*Kjg~u$2K~U1FzS@Lf~Up+U|q_ifqpgYU(t zPp-*&;1b)q&zJ2IE2|E(BeD)7knx?2ij}o4v7^8EvI}BmtxN1%j7vuL?pRst5{tXt zbOl#-#L8NiShqc<C%JMgR@S=2cAfTR|A>{fF0q}D`?8gX#pKtz#GX2aw-`{>uH=K8 zVGGi_#J<B1BraK884$y?F0tD;`>9SPv!qL`?bCjuH<4+bOx7hfD#+`@F_P9L)_0RH z`AUqWb&17cL^0NW7Q?hIvA>S^*8UsAv@Wry{^vWkstpgVwJx!FyZx$ZMW(gZy2K8n zJsM})pcqN(61xN4$W-bTF_P9LcIX{EZNrZry!8d9>47mWF>UsNOY8((SO)x72o7Ch z7HnN&tMS{?fPV_X7GhmuHQqASgY%t71c|eHO^*y*VlCdLfh|Lf?QYg3HV{7oOiH6m zLd-y_3);XX_Q7(;nWh<DNw9V;ZBpi9!PX^qIaXFi^UnW=X6q6=j^&`yeDeR)9J<8L z1PWtZVl_tw#h@-Rokl~KSgVlz3P!^im)L~?#}3MYON?)vyuqRK$^ep~!e${3mssv` zyAWSZgg?w$m)O?dObN*5KpX?Kb%~Y#-Q-x_3MB)V*bk3b$!|l+z$JDR12oG@;zz}# zsa~&}+>KcA&L*=inf|0;U1E=XkM2cgVXUNjy;i$z(7jZ0Xso0%*Sc?GmQ~5CV<oLi zY~C)rCM}L-T9;U}Vmo(ljb&PwSOu)c{y}BPJ0UZ0iKSsCke|rVY-F$|P=3}W_SGMb zvw(T2FgieJ4+&giEjQRg<d;CL4vVlZv5gN{#HAsEC7WSk)+KiNb_-j0E|_&UwToNN zlPK>AA#D7iOKk6luytq1Wje@>b%|BNl%@soNr;H~F_|znt`^*x;*JS&LhTu`Nn8<^ z_X!|bAw;vH=>#sZKMn!XBZQp8B{m-p5*ZmlU?YDz!X?I?(M(XT519VXEkzW^{f1w& zOivyp!VC|Zi@+r|^mUuh*Umy%msnp6<eJL2XQg6YVxv(|no3zTh?1$O!|RlL38qBV z(Ub_&daNCaIPETd)avMemJW4zrAM0GhL1-vFEh{5VO?SuuE7_XiC9xgN8l2xiSjV7 zfS8d1>pZi>dk^DueDo#A6)@ORgDs;B=dFfHxWp#F4`W?oB%kFH<7;D8rU4Y|664E2 zhG<-3ItB(Vv9=+1HUzOuH!iWX*YF`gYP!4>AaIG*^%smqMBJdM1}?E)7`wH!*9PKf zG}a|nbjB9+GofVQ5<Bd-sDq(o;1WCdnU(w@l+0A;K3rmbKCpvTA{-937%X$Re7(*N zRt?DXtyQnr1gVR`N{6{Fv69N1DZlKnk|Sd!txN3mZd;qz#WJl+?96`Ku<wjzT9?@C ze_H0YSf+J}?YYZwZf1!dBU5YCbSvK_)@OwU{C!Tq2a<UQd}h>8eS)7~zhhdL*cr?U zI#{+R!lYrxIO`HC_}o_F*bu==HA7+G66=Uck?TuB>?j78SkX;3pAUwJm{ANau^#aM z$^MY5N$?W7#M(a($X6kREi-h9)xfYXX96zMo)1UP)$UzC+nKofM86Qgv@WrCw>ZwX z=xx$EmdQ~IF0qGTleXW>$c(7~GxEVDcKlY`6z2uvegRvT*!LgXoZoX6!n(w6d(fux z@>!`^msoH7_|S3fi?ej7!|RB9HP$0)X&lO=q@{}Z#Qpg>YiR=_wCM+yW~oao{}nr~ z^(>{MzF3#ob$8owEmj`GRa^xQT0By@W%OzY7nmTg@k+qx26D@2F_{eJ(OI^jZkv-+ z;Q4BeW?Xl9StxNPmO($O`vhO!ih2_Ze??>qBPrg*t>_JPpJJqnH}Rtrh-|G4kxXym zQFPq8&oXilU!9WTuMq860l6VqDo$pJ3_%FP+Q=ut>%QYl%WD?Py9?`)x_w*Xr<}_5 zisgOyGI)cF(OZ=_IpAgRh;S&*fmq#<Z@{6z?8&MSK!FTifU5QsP~%r)0#P+j1Ss(8 zzY5;eOf)$bio723vSj~C@Mb>&1LdoLZj@%pW-KP_UbE<DFg-|`y!y;Wc#c$e(SD2r zl39v5MR-nj-P>^dRY{JKogzsX+v{%d<kEm`m%&q|8-7aHy|3{a{(`tFU}x~<JEyOF z_7J!aR7Qnyj>C_j5TT`EVar(H8w+8Cf$cjNY?{1!A7GoFxF1^;+fiFg22JUsVV#0# z0b4*TdeNf^cVth)ttcJKlMnUm_<Z@MCL#|>?Wrgtas@l^l(tEvZ9p`y4Zx2z2k0kn ze*?~iZom#9AWx<0Nlo~g5}tnSdHep}tXN*zA>chX?KEEgBl^}rF=|+OJA0#1{}<-U zmVjqo!mcOZTnyn?C;o1Q-wFT_R^D6L%dPMa0nZoaw!DPHkss_-R31@daYknZ@$nsQ z%S$-g^-&9mWulwXBy9Wuw17c;dqA%wwBlQUDbX(c<VN(WGvY*haI3Eqo!lRnp6pxE zeCgBAbE5raAwX61%}6*Bm3E=r6VP<X$>38OXS#gb8l@oH0;X+U(^X95V8AdBqR$h4 zI3+q-jQWg4i=f46wXTdBcfoY<jB(tbd~V}v0#t=ay5p>I=LfVH<EmQY4A>fm@?jCQ z;v*y!$75lNEGs`nw&k!mR#H2W_#U61qKRv@WIP2H3;tr<TSobkaVx%wmz%KQeNfW) zT>?j<y_%rv7WG8pnNIHA$gngYJA*s7r1|I4Vg`UjJAy-^24bJgmooPq;}MZGFsl$@ zUr()X5Z}n`{T5-l`hW|Dv;nr@6KEU4LqVeb?sDU=fTQs%jOG3AadkU^n=W@_JnQ$E zE7Pf-0C8p-;*+k(O#w9{2|UcU>`wh&bQjmRM^imaL`9X$)c(|Om-}c%Ja8!oRj<S{ z*=hRiao=u*J-5Vv7U+grWxno?0kZ?>;?4BUF})&FyG_3X?j&eY@yq}LarUWxM_fJv zQt?g!(--GTtlu%W<N4O^F+`}{89O-Ene(vvee6!oun8;)by&nj%=_o=A=I9x^2k{_ zDq%qB_m#T{2sQGJvvdrjj+5?-Ev%03OX;XDU;f}a{eE<>LjkhP#g;B=l!>;~jjK2z z9;^aG;B^R3ieVj}oE6sbPso=OQ^yxVrV0Ti>Udf}%{T>KSjU&5S?c*@Hxu!<$^~^i zxvkwz{zxp-*6}SJ&=auol2-%WVI5xpW?j(b>wxK3l2+pZ_od-hJc2Z>!9gAKH3}84 zA25A!TgQinTDyA?p>~(5<M_HZfk~l`l6AaNY%0so(qZd(1Aeh-9-ll*hpl6|!0I?y zN=Hz~A7JcfnTsu5)G@QxGWr{c1+2dKsGuAR43*a_YFEI>QoC~!$m`LTX3fA-ZX*IX z$Zs!Sp<CAgfT%aS@-rZH-U<%3@XqGfNTucTXz7eK?uYw%evIEBl~#W24XoRw3&%bn zr;C1BLslcTDyl2vMW$6x8l#CzxA|KgN6FkFrPZK&k(?`K3}$&5G~h*C>q)Z}xNZFJ zdsw)lhsudiTezkgAO{YExApVYc1?xTAl?Syg$~f9i>v{X_Yw%ZGM=!6Ect0W2&3lw zhHJr<fr&)J#O*6Vp0?t+ohApD0!%S^o9)S!A!i&UO%~?JU089+8evI$a(jTWb4XuF zIRO3N%!CWeta^3?keHI_E7{D&&yNCZU|*aYHvJ4>e?N;#r}<cZqMS{UW8ZGV(_ngX z@J({6hMc*w`B}Wxx@s}Xh!u!E&oXg2uzUBt?>KFfN$CN&SqS!(WmuZZTeY9`Z5cz} ztGHmT*ZwQ;4)(ss=Pd|$)8s#BS#tQPcYL1FXEsB!@pVK)-Guv9(bv%}*e>IvEVq`? z-3S+$AQ#w0H`IbnpMrRGpD~`p0QR@gMOCzqoWDwPioOBIt2ozjuDN#j@EK0r)5sS7 zin#dm@<3NL49L9U!>@7@HtFl21zZ;v@l8apj}Kx1Y4P2=BEH?|jVsA1;`_VaJP@x_ zO-ZgkL@46K>)q{R84v|D|3)4_#3|sUT)<hkh%YRAF9jM-i@u&*bW0M*hkXqUzz%+> zs)*mq^8P5nxtgvf-BRNe)hiEn`c*cU3`h*Spe@)%{0x`Z(#NRs3`Vi#gDI4yipzYq zsz5=FbTY@2=oECMj^Bawuo=&krh=ULJW$pv;%O+}N}t65Y#+_~TEu3$*XJ-G3uONa zEbcx191RL-B*Xi`aSHflP?K2su8{lOmtz1Lxs9iY@BMrK_#6hn;hSbf+)d(DE3yVM zAQ_psItAQJQoxM?Mcn%1b@4H(H>R+PxL?E@?XwvuQI_0YQgk~FSn6XKD1qTdhoV1d z%6&dY^*BWnDEORDR6(a`WE8|VeIf(M&Q9uRN)C^?)YfY_MSM}%`^zVq*1AxRSH@A+ zKaN9Iy{cEE8!VE!$Y<kIj3DRl;}RduLgacq^r5H%n?pau7s~=vZH=b<G~8mjVIIR& z131sEDB^eHJnpKu!1hK+f$a%IQUw=7s*rF9@N073BcVX=7=hlZxrhg@dED_H)46ZZ zPsZ}YvY+}4Z7VT#vqXPaM7wzIHCB{?5=GD7Aw>_=gZk<|#*7_BJOR#YUXmCeJr9I} zO<2GbZN<eK=<^vsEf8PC&op{-5z-D}KBI`>DEmc4r-;Ypd;EYRn({0jk<TOWF{a%H zQUSk%8n3}3etOY+)+ic>Z!YSW7K>g0z<Uo=Eer-YZj9#VQ2)yUEg-C@H)VfCXo2j_ zfW{n`5vPD(Wh~;a9Ix)RRs{nb<wiQu3mYP=wni^(iXetiKnv)IE8uUkr6Rv%<MSY6 z**?5MK<I{KNX)QAXNmq^L!n;*u9~QYp24UY&Tybj>kFY|qQ|ehnyuN?hios^%x?gB z1Py(Rd<LANRm}BUh^tBlWU+Lv3ZW_bb=U&xD&oO@-d8@#)+E11>6Jx8T_D>!U>Nxz zY9jwmM&wvjf3av5i@5#DD*#dx(LShID>ICvzh)KH+Y_K(KFEwFMchK?P4bC4NEpdk zY++8(W8~lH^L3z!X{bfqLF8@n+1f`@r!%;bNavj*?jG@81^{HtMiEz^sTXlOigz?1 z|09OXJw@K1=TJA#s^iWZul#j3qh?Gf;x-_!ZYd)7*?6r=5xL{Y>syN0pU6?Ah<t_G zn_H52gMJ7WU!e8w@EJN(#TE#6A$a^6sMdrU7{hKE<&j@S{G6!wDL^Rdk@$|N4UR(a z1gK5{73igipRn+%&1W0vg&;m&!9KS@`iBve>@+g|fuvLPCKj(=e-${0aSA7^lfFQX zgpq4*l;Qa3XWUJ)2TLT#Y@j`}RYn_H*)k@g4K1lm5jeIlu|pMcqmg$zh^9{eu(SG` z=YzZ(WX(DQW(m^##H$D+t3^2H;td3yf*%1jol_NZ^NK_l#1@)S{hr5Ggm96Q5QHZ? z3GaJE8x=)#7<o;7X$I`l=Ww2a=-euxr>KZ~j=X*#8to}|LBn_9<vL%1--waS&2gk^ zaZPd(Zi!Q8h)wl%cDZ%F5Ca%Sxrefdn<c$HKF9Bj)9_`^e;jm1{R(FhH|BZo`yktp zxzE+}7TR)%>5LQD8O@|sW�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%0A>TJiJop!aT4}P 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≻X<DwvjP+c7n{Evi(8Ueyi<9Y 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Ƿ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∾8)2pwPh)n}n$ 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%0AM$bH)~PVqZP!_tr4v@ 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%0DpamL+wg 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 z�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�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 K7h37F@c#fiyMgKe literal 0 HcmV?d00001 diff --git a/silecs-codegen/src/xml/test/generated_correct/wrapper/Virtual_SiemensBlock.h b/silecs-codegen/src/xml/test/generated_correct/wrapper/Virtual_SiemensBlock.h new file mode 100644 index 0000000..1681d8b --- /dev/null +++ b/silecs-codegen/src/xml/test/generated_correct/wrapper/Virtual_SiemensBlock.h @@ -0,0 +1,153 @@ +/* Copyright CERN 2015 + * + * WARNING: This code is automatically generated from your SILECS deploy unit document. + * You should never modify the content of this file as it would break consistency. + * Furthermore, any changes will be overwritten in the next code generation. + * Any modification shall be done using the SILECS development environment + * and regenerating this source code. + */ + +#ifndef ALLTYPESDU_H_ +#define ALLTYPESDU_H_ + +#include <silecs-communication/interface/equipment/SilecsCluster.h> +#include <silecs-communication/wrapper/DeployUnit.h> +#include <silecs-communication/wrapper/Design.h> + +#include "AllTypes.h" + +namespace AllTypesDU +{ + +typedef SilecsWrapper::DeployConfig DeployConfig; +typedef SilecsWrapper::DesignConfig DesignConfig; + +class DeployUnit : public SilecsWrapper::DeployUnit +{ +public: + + /*! + * \brief Use this method to create/get the unique instance of the Deploy Unit. + * + * \param logTopics This parameter can be used to enable/disable log topics + * valid topics are ERROR[,INFO,DEBUG,SETUP,ALLOC,RECV,SEND,COMM,DATA,LOCK]. + * + * \param globalConfig This parameter can be used to pass different parameters to + * the library. I.e. enabling automatic connection. + */ + static DeployUnit* getInstance(const std::string& logTopics = "", + const SilecsWrapper::DeployConfig& globalConfig = SilecsWrapper::DeployConfig()) + { + if (_instance == NULL) + { + _instance = new DeployUnit(logTopics, globalConfig); + } + else + { + if (logTopics.empty() == false) + { + _instance->getService()->setLogTopics(logTopics); + } + } + return dynamic_cast<DeployUnit*>(_instance); + } + + /*! + * \brief Use this method to create/get the unique instance of the Deploy Unit. + * + * \param globalConfig This parameter can be used to pass different parameters to + * the library. I.e. enabling automatic connection. + */ + static DeployUnit* getInstance(const SilecsWrapper::DeployConfig& globalConfig) + { + return getInstance("", globalConfig); + } + + /*! + * \brief Return pointer to the deployed design AllTypes. + */ + AllTypes::Design* getAllTypes() + { + return _AllTypes; + } + +private: + + AllTypes::Design* _AllTypes; + + DeployUnit(const std::string& logTopics, const SilecsWrapper::DeployConfig& globalConfig) : + SilecsWrapper::DeployUnit("AllTypesDU", "0.1.0", logTopics, globalConfig) + { + // Construct Design AllTypes + _AllTypes = new AllTypes::Design((SilecsWrapper::DeployUnit*) this); + + } + + ~DeployUnit() + { + delete _AllTypes; + } +}; + + +class Controller : public SilecsWrapper::Controller +{ +public: + Controller(SilecsWrapper::Design *design, const std::string parameterFile) : + SilecsWrapper::Controller("Virtual_SiemensBlock", "", design, parameterFile) + { + _deviceMap.insert(std::pair<std::string, SilecsWrapper::Device*>("testDevice1", new SilecsWrapper::Device("testDevice1", this))); + _deviceMap.insert(std::pair<std::string, SilecsWrapper::Device*>("testDevice2", new SilecsWrapper::Device("testDevice2", this))); + } + + ~Controller() + { + map<std::string, SilecsWrapper::Device*>::iterator it; + for (it = _deviceMap.begin(); it != _deviceMap.end(); it++) + { + delete it->second; + } + } + + /*! + * \brief Return pointer to the requested device. + * \param label Device label. + */ + SilecsWrapper::Device* getDevice(const std::string& label) + { + if (_deviceMap.find(label) != _deviceMap.end()) + { + return _deviceMap[label]; + } + throw Silecs::SilecsException(__FILE__, __LINE__, Silecs::PARAM_UNKNOWN_DEVICE_NAME, label); + } + + std::map<std::string, SilecsWrapper::Device*>& getDeviceMap() + { + return _deviceMap; + } + + /*! + * \brief Get pointer to device testDevice1. + */ + SilecsWrapper::Device* getTestDevice1() + { + return _deviceMap["testDevice1"]; + } + + /*! + * \brief Get pointer to device testDevice2. + */ + SilecsWrapper::Device* getTestDevice2() + { + return _deviceMap["testDevice2"]; + } + +private: + std::map<std::string, SilecsWrapper::Device*> _deviceMap; +}; + + +} /* namespace AllTypesDU */ + +#endif /* ALLTYPESDU_H_ */ diff --git a/silecs-codegen/src/xml/test/generated_correct/wrapper/Virtual_SiemensDevice.h b/silecs-codegen/src/xml/test/generated_correct/wrapper/Virtual_SiemensDevice.h new file mode 100644 index 0000000..8b1ef27 --- /dev/null +++ b/silecs-codegen/src/xml/test/generated_correct/wrapper/Virtual_SiemensDevice.h @@ -0,0 +1,153 @@ +/* Copyright CERN 2015 + * + * WARNING: This code is automatically generated from your SILECS deploy unit document. + * You should never modify the content of this file as it would break consistency. + * Furthermore, any changes will be overwritten in the next code generation. + * Any modification shall be done using the SILECS development environment + * and regenerating this source code. + */ + +#ifndef ALLTYPESDU_H_ +#define ALLTYPESDU_H_ + +#include <silecs-communication/interface/equipment/SilecsCluster.h> +#include <silecs-communication/wrapper/DeployUnit.h> +#include <silecs-communication/wrapper/Design.h> + +#include "AllTypes.h" + +namespace AllTypesDU +{ + +typedef SilecsWrapper::DeployConfig DeployConfig; +typedef SilecsWrapper::DesignConfig DesignConfig; + +class DeployUnit : public SilecsWrapper::DeployUnit +{ +public: + + /*! + * \brief Use this method to create/get the unique instance of the Deploy Unit. + * + * \param logTopics This parameter can be used to enable/disable log topics + * valid topics are ERROR[,INFO,DEBUG,SETUP,ALLOC,RECV,SEND,COMM,DATA,LOCK]. + * + * \param globalConfig This parameter can be used to pass different parameters to + * the library. I.e. enabling automatic connection. + */ + static DeployUnit* getInstance(const std::string& logTopics = "", + const SilecsWrapper::DeployConfig& globalConfig = SilecsWrapper::DeployConfig()) + { + if (_instance == NULL) + { + _instance = new DeployUnit(logTopics, globalConfig); + } + else + { + if (logTopics.empty() == false) + { + _instance->getService()->setLogTopics(logTopics); + } + } + return dynamic_cast<DeployUnit*>(_instance); + } + + /*! + * \brief Use this method to create/get the unique instance of the Deploy Unit. + * + * \param globalConfig This parameter can be used to pass different parameters to + * the library. I.e. enabling automatic connection. + */ + static DeployUnit* getInstance(const SilecsWrapper::DeployConfig& globalConfig) + { + return getInstance("", globalConfig); + } + + /*! + * \brief Return pointer to the deployed design AllTypes. + */ + AllTypes::Design* getAllTypes() + { + return _AllTypes; + } + +private: + + AllTypes::Design* _AllTypes; + + DeployUnit(const std::string& logTopics, const SilecsWrapper::DeployConfig& globalConfig) : + SilecsWrapper::DeployUnit("AllTypesDU", "0.1.0", logTopics, globalConfig) + { + // Construct Design AllTypes + _AllTypes = new AllTypes::Design((SilecsWrapper::DeployUnit*) this); + + } + + ~DeployUnit() + { + delete _AllTypes; + } +}; + + +class Controller : public SilecsWrapper::Controller +{ +public: + Controller(SilecsWrapper::Design *design, const std::string parameterFile) : + SilecsWrapper::Controller("Virtual_SiemensDevice", "", design, parameterFile) + { + _deviceMap.insert(std::pair<std::string, SilecsWrapper::Device*>("testDevice1", new SilecsWrapper::Device("testDevice1", this))); + _deviceMap.insert(std::pair<std::string, SilecsWrapper::Device*>("testDevice2", new SilecsWrapper::Device("testDevice2", this))); + } + + ~Controller() + { + map<std::string, SilecsWrapper::Device*>::iterator it; + for (it = _deviceMap.begin(); it != _deviceMap.end(); it++) + { + delete it->second; + } + } + + /*! + * \brief Return pointer to the requested device. + * \param label Device label. + */ + SilecsWrapper::Device* getDevice(const std::string& label) + { + if (_deviceMap.find(label) != _deviceMap.end()) + { + return _deviceMap[label]; + } + throw Silecs::SilecsException(__FILE__, __LINE__, Silecs::PARAM_UNKNOWN_DEVICE_NAME, label); + } + + std::map<std::string, SilecsWrapper::Device*>& getDeviceMap() + { + return _deviceMap; + } + + /*! + * \brief Get pointer to device testDevice1. + */ + SilecsWrapper::Device* getTestDevice1() + { + return _deviceMap["testDevice1"]; + } + + /*! + * \brief Get pointer to device testDevice2. + */ + SilecsWrapper::Device* getTestDevice2() + { + return _deviceMap["testDevice2"]; + } + +private: + std::map<std::string, SilecsWrapper::Device*> _deviceMap; +}; + + +} /* namespace AllTypesDU */ + +#endif /* ALLTYPESDU_H_ */ diff --git a/silecs-codegen/src/xml/test/generated_correct/wrapper/main.cpp b/silecs-codegen/src/xml/test/generated_correct/wrapper/main.cpp new file mode 100644 index 0000000..a43e59a --- /dev/null +++ b/silecs-codegen/src/xml/test/generated_correct/wrapper/main.cpp @@ -0,0 +1,14 @@ +#include "AllTypes.h" +#include "Siemens_Step7Device.h" + +int main() +{ + std::string logTopic = "ERROR"; + AllTypesDU::DeployUnit* du = AllTypesDU::DeployUnit::getInstance(logTopic); + std::cout << du->getName() << std::endl; + AllTypes::Design* allTypesDesign = du->getAllTypes(); + AllTypesDU::Controller controller(allTypesDesign,"fakeParamFile.silecsparam"); + controller.connect(); + + return 0; +} diff --git a/silecs-codegen/src/xml/test/generated_correct/wrapper/main.o b/silecs-codegen/src/xml/test/generated_correct/wrapper/main.o new file mode 100644 index 0000000000000000000000000000000000000000..9c2bf1ee5a3c6a701d0b411a5ea5eb24d9b64df3 GIT binary patch literal 353312 zcmeEv349dA@_+Zv?q(p64ImH@BtXDGOtK3Y5)6>YwSjQo3Wksa0wIYx2*`b@n;1n- zQ63`Vjd)+6h=L+M^?Bd-3C4#!?>qmh>YihFCc4iDJb$16n-9!%SADCxy1M$9o|(<E zA=yJ6oHOm<YydNI8kMov^Bj66gHjo62AfXUGa%m+{-a!H_#ZFRUFG#Gc};?AicEXq z+DE2)$!n^-_LJ9idF?N+1LZYSUI)qRV0j%XuYP&WlGhRPIufqqAB7X!i<R-O`oenz zb9?Z#4^PA-n!j#BT(S)<$)N4U`s(0BgW-G2Q0x0HSm#*=jEvCb6HJUC#XSwi?<wwK z!1hL(4U0E1nwlABnix&YjP53eYG!mZF(S;2I1|HdW^^?%TxLcW6T@j{bT%;*Gb7f- zz~<9E*U7{P^4u8)<M%w*(SQXvNe2@nNb%_g<M$M|H(+~%Jm1d52=aW4i4o-awkAf9 z=i8VVL7s1IVgz~qG!rAp^Q}ybAkVinF@ikb!o&!2P_)5l)IqBbde1+whdN@9H~n=T zUV%1c{uMvtr83LEs$TU62FJnaJ<-y&kg0!f4?5Cs6^Lm}z#lk7^7T)6I>A6uzpwt` z`aOk7o=&T=AXdM-epmgiru?@0t@T$oX4c(}l~Vs~{onUsx3ik&S-r5Kp`j7Mx9Shq zAF6-CRQ^Nt57ggh%HL9dQ~eF5{FeI7jacVd9sRoniTXc&^wQrN8Va@gAH4{3hW^Zn znUA1fGAB%Y1hh4b--|gIDr2(i^5Z;fsUEfG_*Z=y<6qH$ysFb=qg8$6Uv)6%{OOs~ zGN&IHx#pjhtpi7ndmbAWy=MQix3dGEie`ARc35=Xn1;aQ==#q*otQr`E$)4Ppg8Ub z6_g#wk2{_X*&m?DR4P)~L&n$?-o+@qc3NDFzqU9oHoG=IE<PJlUN9&%)RgCRQw|21 zBI4oy_xk_!+JlA?2*>dd5eu^GisNSB++3O+_)?4ub<^TX^g$x<u1*ge$_gBmLx-0p zVSnwUBZ3e(;IC!=+KeOq+Fi<V4DdDo^sN2`63dsQGSBK)A?3M$$RN+Y<A!Q6j`*Rx zF=)X&GAs+iEZ)Gp=?@(92R_RRd@M^|3}B<Lc-F+gI0*pBofemx1vQHIA9BV)k<6b~ zUl~XJ)L*+O-oK`y((SK}Xc%LRf@w$mfdf?^_-iZUyjgXN<6>onG>wbnW;{rmu+X$0 zszyK;Sm4_)du8ETzvi~uA#5LwrGYOS#(0mmguX6SJz=;|x>ydOLh+jYmFcUVYS4Q2 zwf?%wxVa=+zuq5sLaSW;LxzoDvef-f{d-2Id#wH+fCd>MeW|X$kD=dl#d9z~VHw4Q zI{GMP1Mg{4M@NI<M~A`5(0dpiAP?SxcZ+HjsYIO~)q;=X6W!4;OFG&xC8}TKIgwed z7*pa{WaI!qFy>6-ii&g&beGC783Rdon#3~}K~xt~)mA`FZ^l@YRvZ&3)D)AEks#>m z1=B%f2bR?;wK*o6H5WQuNMNja5+B%%jBp9bC>KEcfHn^%7>gEwKFzR%77kfdOQ)uv zY-|+|^bVlzG>2|NYfK6g7;9scI<Q%<NYvHVTry)ZdN%TsjHs+u2x+I&T#|-$YcIV9 zHDK)YAP8zkNC%w?t`($?Itk<i=?sIU7ul(gaE~xzAk{inqY0}zL+enhVM$#`2Q`+- z#I8vaq7@ZqCNS1bwzbMw_kMcwo@q21s*cyQ<l`RFg-|1GxSk#e7se7=aq=<54a%I= zR%S7iXh<-Y#CcXLq$YQUc1;FRZ+B{7A1Xpu_KJa6?VZH5co4Pi16HV_2$Vis_nFpA zNKI+QhqW?5eS<*4*{P%$9i_D;V`<T{=zgu3CePS8-NBA@N07$;hDM=ofI$GiW3UV~ zD45OAD?%XvD+zN5BH~<wAiBmNU4t-Di>AT4Dud405FHIcmq%eYlt|_}qH~7nKol3| z`*oUdqgE6&k>-eA)at{HHWa})LN`Wh0LHSNK|wGQ1_TvrILaKj9iYia2Wvyp7$8yj zX0^fskTg~=!f2{-y1_7@X!RW*1VlPx6AU2KR?sHujp;&%Od<%mNvro{gCra@#ZaSR zrgnz7I4`6Ia7%H1YoJflhEm3+8#Tg?azSeu_&G)yTDP1byE2)TOFfZ>)R{q!10{Jd z@{*Sr%ZHMr!x$?t$`Z{}7-ApD&JtrHW3$aX;h7?XBw}!mZloN_=9&p2%!-9?a7adX z&eLOts!<}i*wM6hD%JfT*^$P8G943{4J4uGLW8KeyxbrmPS{)#OvFa7#A@KUgcC=V z!KWcnNX^G#20@HfCqa<MQg|<LksyjKgrx4*i)4nz_(jIxDWn!h!s=y-(MF6dJ)6d| zWvC8kODtwN2ZXM11;<j+D?-OgEgvcJs~|5&K9Cl))h3#ttl_c*GVEfl1j=24IV_!W zmx8Pk)u)+|3qa1-ss(S!Gn!(X)qoyfD+jCrYDEf`K$ih#m<dxyW#MFuxXUqzwE^vz zzk)}?DuS`Krc#l9rO77Duj3t|WL$AfiJVFSvK|nk><v^lV;c#B)&T|vfK5R%jBPga zp~qcCayV3MF(V;=HR)#T8d-az##@C9NdFB|PzR{-wjjOemum$Idd>DA&B(hBYK;0A z+aYQI8m=cVAa|!(7sb{Mpi7Ge^u&!|lhMM4WjCS6WYnNlH)CGL4a(hO=0pBgQ(koX z+lYb#s8}ZL;+<H>Rv3e~17}z(Tp8`A6zac2(7;=Fk{re>brc$Z0eY7W8Ops|BfE4o zWA|u8lM2v$uSV9eq7&X1N)`kD{Ya+R(luk_K461}_Ipqxn~DVTLpEgCBH9y57MAQq zGC5f<5=Qa6cELIruCS<uW`>0@o__DZZ5!5VBks^DDi{H4YCN@iX%w6l6}PCEv!XJe zbz$E?#&ue6A5dJU^}#(`@F`=Re6H4m)<JDut?Lr#a>ea*S^ETCuKb8D>srDP<!Ze? znJyb9(`92NT{f+w%jP@ja@A9G+43q~uKtZK*K~t+b+z8=r_0}}=(24cU9P>AF591_ z%XRg1*`dOHfUEURFI{dNN0*xy(&g4`=(6iUy6k?1E_eJ&mpj{eQ0}g?>2mj2y4*95 zF82oLa^Hw(gxsG;mj_nU<-r^1^3aoX+4D7B_Ig?%@{u&UJUX2&`<Kz>vFqsa_yM{c z_?RvSf1%40XS77QCo|}BXeM2rT1}V3f1}IO_tWL?uhQk2@9FYvTj(;b*3YHFC8D*P zUqIIgzLKsg-w9V(GQ$qP`Rr=bcUxPKYm@pGtYBSj(!PfaZf7!nGeiUQIFNF~BpjIn zFvg)lpzYoKdvF+QPI2Z|IKL9GQMv5^;6aXOJ%Xc&&ADJi#erI+KrJC5&R{vjm@@HM zkO%wVpfi`23J^tQ+tgX0Uf^TWD<IGXlFkk~JLwE}bZ|t|IhM}*1#~%%bTG3C@N$7( zF5t@rez_1>u1QFdJB8%aLeFZcV7XH>r)<~1W6p9z@Txa7L7`fdW3G(}{0R1Fs)7}a zu+y-1JO@Cyrei#&J=`M05!2Z*7F$N)BHP7r7XTnDnlGlKgAWCvsQ&O+hqJcSXfbCv zxFG1w=4v-;6d+vfMh~LP80zrtrsPvDcR5}1x6-BH9=M1w6S1@p3cy_xXu)DU*Yt(5 zqOP3-XU`3AhMQkJ@$UiGj&Ln<!8MG14g`*;s0ISp!hpisBd5hp4$1^YbNj-1sbFLK zS?lOB*O7*~;`Vfz*NZMC!|75wlP(utPM6Bt=raERT^7Dimy3R-%c4&3Fw50`NhV#E z=F??)IbBv<OqZ2A=(6enT~>cgmy3U)%Oz)=gW^v=Kqfs~00z6-KfjzVFPuZXm!{C= z<-6(fN*P^Vy^=1kJqH(aCC&Xu(1q`=gCUvvt5>;=J0iCY1}BOBs_f$Jp>Rf>SGk?9 zO9G7|vzreBM!X0G<xbAWf|e-v5D=B!Te*+(GM(r-9~60hM%|}VJ1Gx~3$M{JM#m>T zdIbG`C9GUCMWj1WS*P!rRS5PqK!F}i(TQ~=o;$J$MRy07usmzdk|!nvqm#bDAnJ`g z3@0hmGTA}#I0EUI(sVuEgy^$1Iw_Q+<CQ=>gNlrPfG!w}JnGK5aQ0AOYTDZi?YC%J zSSKifbp#hPw&;3*a~j|}tlR`)PP``2;*9M90S=2HIGW%bEeWxhY~pVUU`|hJ*%?EA z0{6IDe~UxDtMzXy>C%7$zRP(gwy(<>?}LjuazxtIe!B?Edqg1a6M^`sh`{|K0v{J) zc>n{k3(uWd!P?)7MkL^Xj&bb46tMD(=Ck&9A`6xB?HWt)&82rmQ1e6@mkuGURUVvh zhG2p<fLI?QYoN}GBdHO@GLe}grZmL?9)p#OQ(VLXM&S@9Ky=Uor<>DNR8pxecRC}d zQ|b^XwtJ_v63m^6r`KaW`~&Dp)J0;WIoTyLt!d^HohP;pWugVAEoEXvCWbPxBGZmC z@gmcnGG386oieE+(}6PkWvORS?kSn;M7if>E|zky%Ul=!2E^?9G8f0+gWM6B>rS>G zm${yl`$p!@;;q{;_JhoMIR`f^7XwDDkGFx`N}21$KLMSqWG;n&3%N^WZXk~ZEo)`Y z&wD^OxJu@-D7RhahEwilnHxd5J7q4LhM@;#ZWP(MU*^W}pP{^iT&zwzXJT{3V>88c zVOUxZOm|@_kj-hQq$5N%rK4F-wLOZon!!;fLG3yLvx@+Cmb2^RnQ%=+Lf5It7Rl+z z723N_q;MdOT`w2}bSF!~4v+tnM*&QMfTW<Ke%*CWUtoAq$fw?nNd$_~s_ROg02z*} zWfA?7{+Wa5?;ssdAc_GgxlY9eA;a<Hp%W_CaFIY&oD}U6{;g1kt8Wi-1yV926%^*# zNT-u5ZX6K2h?cl42jOthPVzzKjuA{;$_plH>ZOS;6kJ^4+i;Hv>u}*O4C_t9Y1d<d zE{m_D0O3C%Y6p5{5IDtyS#S;Bfk@n3fx|ln;hGSzgw3J|<NXnaCr~m7E?$$SO+r(t zu8C6SVo|l!_nj~n?@6pK{zWkHPKB77(0Rfyc<Ul;CFMb`TO}ZPTO(R0h}%k`D8aiO z52l3wq)9V{XisEP98v3H7ApIN5lnXo9Nr{_;-schfx!Ex5Ia4jPQvyI7~WqQwgw^Q z2n61G34~ev0l~x@GApx8GzQ&U(23$$Hh(QtT}<#@ucD5Dw{gN!th2`3P63Sfc7}Nx z?-AnR4WE^_mUQA>pjGFO*kl}U4NY>=9}^W~-l+@f&FeuLw8H&x@$Q9FpUQbGHSS`( zx1@0;?h>>|rZ2^`7|r4Wm=>d1Tn(n1^#B};tHpG*NMDBO(?q%s(=j4_Ii@>^^c9$n z73p=jxQG|&^%&D$EkHX6uj9QgRZsKQHRKVz_cc619Z~~akLo$z6&r2|0<0$uc)uK~ zK{{`%DEgm>pa!QDc~G`GHmz*+U&+yUzikw!)nPwB3+Qwb%-*;TQB+tyVH2PovdBYx z5+d<rMmh;8F>Ptk<#-owGMrRO#ETr=$?*o?&=NFQzQ#u(0`L7p5wbpyQGIY%z*Gp* zG*d4X!xwHCP{-Hk=L$ORAPCje=gpGCL<Mkjp%LBL0)hJujUdJd1a3(P1a(GpDU(HC z#@!0CL!Szk3kL3ANXFS>w0{R{ht_i3)DXs_T6s6vRUsGwaJ$2(9g_+^(-q)8h*d$9 zp#XPCObW#PX4f<Wfa_>Og9u#NyodQBVA4q-L^ws8gX9BFD`Q-L8<?OFIKn;HL7uch zq;!Q<1CKbi9q!R-{Sfgbj&CA)9Q##YGBn~ltT1=Ny`KlMo*VJ5zY8z8kVX82EV>Qq zifrU)?BYrm@te**H<&Fv5#gW$s0+_Vz=J4HCu(DfauW(Ee6@y>trgLfcqqbe)p%mY zCM%@|(Iop2^*o|5Wi1Eytl`a0M19vds*Qo_fNDq=8s~WtoUGZ^o=`~PsfaoVCyf_N zymyc{0eNOi<A_Hdt<vO#a4Ih-Eo2e#hOoFPj5y1n2qa5WvEVdy7ijQeQV}<PKBD*} z_i5y!75#c(Aaoq$Q{Ms7Iq6;CUWhyUv}(&(f70zdm;VNws7^rP8f`Fd+eV{#x&cRH zWO1L)kay&w=Qy(g#Bhw|;}GFRbsj86b}i><1mMKLD-1w86JP=YNW&Jr3=a-+p4Y%Y z8L-X^5XJWz2pZQBrWG_3(-cv!=>=)hvysPt43Q=)1_*al5JI?v<_vT;_MJ3ZcKg(K z!I(5P0SxzI(nraZWOQ@e#5y2HBAIdF-fjhaI?$q!p}Du)EIwbSiA~OdRCu>}TmZGr z4xftqrD^IGID0WkcPuly_r+~inrplF!}`ngIhYpndiP9Bi@Ch}Fiea2ySpFLV$SZK zg=sNocOQ;vuh2OH)2Skzjp_ZefRUJaN@hl(SDu%d(U^HbX2xRXMVT3onU`c{B4%Ee znaP-WMP@F*%&Rh!gPGT4W+rA{mzjLbydg7%n0ZrXW@F|pnJLB0+cHyz8JHTxyx4sS zR)XUWHI1fpBfv7K0lF`D!fhz`skoa>gXNh$a0C;{I-HY5@^U>HzZL;>>oyc*>DDbm zpn4=F0EGm4#v;m#ecz`}08+|uIH_&><edetMPSIeqd2BHKbLYXIig^NfjPO?K8S2| zx26kLLg5cV0a3G2j!CW<6$STg<W?Y8M6!g4NoXO^75<Y&L03{A4+Sf*`5UVKOcOW7 z;EG*5cLH%0J_b2dux3^-;$W{-_yS!{bZ;CK<UXLgpVV+&2xb&OL`%s^oNH2e*aoZ> zJe+Xoc!hsq;LK%?mt}fRhceJ};@%L8)XbVDA-x)h6iCQK9YQu^>}gsSNXP;mf^PQU zNrNnwkZW{E5<>8#L6%F%J{>|f<4J?8mXHs02-Y{qf0q&jqf+5Y2Vj!5raC9QB9)v4 zTp2|=hS0LKghLWIR0p!bL~>t4mt_=b@-fd0m6sT}Ap}UcoAXO`q8Jgy@R@Kczs_Lb zPOO}X5+39SgBhj@NZH5v7mY!J%6N`@I_gy<M^QcL>629T3Qr7yn7MEBF$R}pvDHNx zvfAHqK3B)c;azl9_iyBbTI{BEIz(&|ON1MT0!D~C3<QO+M8I2t8sY^5L9r(hJqdxK z#*gU;xoUBrO-u|j9(jh|<%jZul6>awZ%D=?Q}k=e^c#{x3`tq$SYqymGoNWlO6GaQ z#K(htnMG23VnmW#Et18C<U<z8N@CLV|Eh&~k-_}h!dzxBqhY^X4y(gNgf1s0?~M#G zqU!C;1jK!{fQ$`>XfEDiXfLs7|BedbmxYK*#g7QZH|ShV=Rso7g7R@gr}Xbj#Kffy z|5#^=ek&0l69U(0+#MTKFE*6tRx<aGhKe&0KogBnApp%33_H@`578jYIGqp_x^oN! zb!3T%GZ2><2y<{J8i?Hn!W7&IVi=)Po;MJtQW7Q^o$QxjglXIm7A5pFuw6Ure$fX8 z&HMR=Swn(h5|JSEky*tC!V);^ND;3wAXGQ8uuk}z!9hB1GXSQlx$iXWcr6%Vt(wAh zZNC{<OVyq+RK|7*@_<(Pw++NF17WF}*!JM1283oj11EzZneKe4mYWPL!OT@1V!#gB zz^wJ1ZPfSc5CKc2OAO`hyXuuD8_dzT#()hCfmy1B&*ET(jpOP(14}M2g|B<Jp>l%( zBW-xne2$O5rMCMG7;4i3?h>jlmG@3CLM$?*w?8q;YZ4b+Q!3Q#@}CXtz{apvzi%`A zUS=m{aejAt)Ib5SwJ`zB5B&}7vvycZGmJI_el!HA8R%rLZ?1vu*-iJ2fwfpZ-w>G8 zn1E(^t%1G74r{Ue4nyEUI{{<mC!6*mL*S^L0GV$N=Yxho`|dXN)oZTR;W<NKgq?t~ zUKK0#gslz?TWnf|FEJ#juEvS_gOs?%ByoqGgwY6o3bceRSOhvl;je&z2uM^Z7Gc6U z31Uhd1W?Z55v`oh$cMTiayCzhARBlm#EA(XYoIwH+l>XH89ZIrq%kKM%&8XUbYkMY zJf9!RO!$BbB?EWpOyh2Zs-=~(kQ5R2uz|%;4uV}`z>XU*!-3K@KNuyqjn`d69z@q@ zh2CIj8(_df3r%RMpbXhI$AIaD1{wI6q4G)_tSmX9lcDlK17<PsJww}j2Fzlh*U%Q( zL$9vAfj=86d)Z($*F;6=b)IU#EC%8$CDJv^4VcBifrf#*44A!vsfNmzY_OVv_+pAI z`6mNrF>tB@>)ca!jm5wThJhmun7x7X4V9HPSgna?7%HzZU={;67}_2;U={=C8rqH- zFna^<GE}xs(Ce&YH3OF$D$@;^#lROx8@_1B^9-0V!pNceBZA=_IA3GHupU}@8>l=& z++`qiMdo|NgzF9LXN_USuxRSf3HKRNO`u>oB4Wig8x9(Xvkin{17XE(b;8RA)^x8R zN;RCxyn{f!Pb~p;Ui6Yr73YnRPE*AhnQ27Nx&p{C?mFcFkRWbhtL$=AAk$Z1TI_kc z*Wx=p(JTv9#JD#o)k&}$dnJf5J{%<ydW$VKkx9kZD7fSdMl9zeXgYD<j%eJr;9?Q( zegFw{qm_^dZn^})a=+QVSLY2gc;fMj`%&ca9HirZ8<+dg?gK=xw$Kj|eS=OHBc(Lr zRb=99#qZPsnh|g6yjOJ|&3!==U>6$Y$&z0HX2gR)Nuxg@Bicb7h0%g3Z-gHq5AnVs zTxlZRtdNQDVUkv7869O*I5ACnMGaXJHY2(<c@!iRh>1GLc(Kh>@U`ApWy;88+2+c$ zdr=jsQ>Gf^>9>N22nFQ=OpEPrB?r?n0)F0j&?1agW@0^&#~a|}!IZ`-Le?9|Y7cl1 zrZiR=vPkM|WRaA3DOIUP7D)*Ss0F?x=~Jfy(u>K?h&Zd+yO7Uzo&^u0;1wuH!-E<) z=qz8}Wh2LA4`TBD=2+x5ZTig)uqPIhtZ7Rl9qEa?UZY3$B>E`CG>iWm#&={aWqO>C zAeN3xAT@Eo4ZWoQ63@lqWi(<EbCC)^03&iUMUIPHp2#^wE??xtGo8c&ky8b)P~@UT zZkEW!j>#=9W{E{2H&Dg$#7=i&8-6Pk%M^Gf12(jyoc5M+Vu#>t7k($2DBnR&^l{vB zhb&Y9uK)1DSFWVxeBSy7Vz7}#`P!qH#7cey5K;S4h1^C=T*A3eqj{c0L&RP};-#FQ zZg6On6MKP)oA>~Ofg)mo_IWZ0OUU&+Hv~dBGvpq=NQVSHNfW;wgLuAGM+nnI+$PdE z@CGy_e-HsLP<<rteXKtXRB!0KAmO7r;HMCPn3fWoQ3uBe<!!KX<dm^QOcYO1$+mHV zayEFM4+flYtB2ZBY^W!u5=7xLdydSCMSkJ{%A!jYz6=W@?@SPCGbL7PCGXLRK+KC5 zpIQLT>AeqRed=B~d$E<^0Uhwt)Mt=@NgpLAVsNO5xAED%;j>fpLE>I|IYbM*eVkqh zRk(PRk@%RjAQtdZD8xM_aAuP@L{#DdsCK^)&Sc^o=6saSkni>;K10fIh~rTUQ5Tx^ z8d#X7RzlW`NgpLAVx8g>U*un&t=ahrS;iD$^{2#9W$rVoL$u5tAzqBk9p(5FOR=(J zea_vG)4NW6aQ2Jf>_3CE$AYt824|1+7DBW1+}F}`6Z?SYFdn#kP>}e&<dhnmDMU(i zI23+`PW7A#3dIW(lCJ>&4uemN33Mlud?)aqHuz?i8(5#}EZNnhm<l`&juvK8v6`)s z(7!M=V?)?7dZUOf9xDydA)0VIDLhl>czR)#D0-!vI!MgLA(##T)bw<cm|H_I7(*IH z%;^e$&cGns^DX3=>`r3yU*WQz$P(^_sKbm;{Ta^Q`ylpwD$dYJr~;dHDoa9x@c&fc zb%CoFd1-1QCYM3dCz3en_*8tMoQzI78wn!0cPe0gY7R;?g%Mjkh)ueaR<`)bhj{N0 zzX;KI?<U~nh2Mb)9)2{U@!rA=$B#qA6D_H37s~Ueb#lsDu!Sf0SkqV9k(`VZ#d)BJ zC3}$ya~&61pUgT$wwKI0MYgxhsv_G*W}`*+Y?+M}*%X=05ZS&W>ufff%1sqnF^?vv zNv44IlakGt_f@Dxnu^<p-i~0iHywn}_o-Kd(bG^*?7eVv3yYfAJ^0pk4<hZwq)b1I zuWyT`Q0#tmb2Rw>W}x|0eDRqcSL6HFwAw=Ib&w%yB)oG^)K;v!xAjEO*bhIa;l2w~ zex>V2V*nA^5>D`O5cOUkEf{Iii9#kfeKG;6CjrTeUyh_vGEK!5n@`1cPlDPj4{gWq zY^V~w^3hl}y}V!^>s5ehCrgO#H5WnnHGlvWqdO#M9;Q_URU`3j9khTxClHzzVp<hn z{Pg<NaRfj<^%$Hlz#{PT9(u<_ylB#qD%Hy^UNXavemvKJcjVh~z1oUb0r4v!5q=Wi zLA*7Gp9KZcJBwHO@H?R(`qvJ8r<~)5Lq_4$E5!+G!gA<qh+Zue{2+<r*G1x;1@e+C zxUYlO)cDO&PywwJbSuY?kUZ!lI%&0-CSKUaPm@SU3<px<Eb-1Mey}87%`?VZiO3P+ z_$^Z?LOk&7^`nF1Cr%!$WN58=3lA?A9+Lt~ImfS{JoE;>=+eDzptmmZt0-Y4PH1uz z==C7hiQ}hI22Z>mCxsuz0f^&ARG|P_iDyL%<M&mB(0nsTR3AUM60ZY<zW>-OPgEbj zb`c1A$xy0or_gsR_zetwvLe1)k<6artv>uRMwBUyeUV=F!!Kn*jg^4c=v_bjhNcm~ z?eyL$eqCb#G+*6GuN!_I%$ou3VZC4G6Z^~WaQj4cM$*~s6Tr1CFeyGjNa>oJ@)3^$ zBJG6rZ7-JZ%sH>Dn5B045E$K4yZjy0ICHBOu+*+&h|={{pfFcj%*6xX((jCqAnWSa z=^MP96XQZ+ddEHk;nKfl2IQ#l{--?v!mj?Uk>cv#EsHL_#?xisbh>2EqRZ3^=~B1| zE&%N!pveN7E}&TgI!QqD2ukG)@H9X<q9Qa&4QPS;IKqg5o!g<288Kg@Eg9`j2O~w@ zGfyKIoZC+937$@u!SB*#$V^f+wAH&i7@G+aY*^bPkmSo)x(bS%{!aIS+UfIin7<2k zV6kTRcSkG@pO*qZ3PIXNfgd+7;2S7|E|$%HSkM4nVqq}DMohvJHUo{{@uDuNozeYy z)G(b*_3amP43K6*y9S*g$RkT~wO5Y>A)Ir54(lH^7aW$K<753hUQDT8tbfnzDAk+w z@B1*N`mp|kU!&C7tpC`rD3!wcU(gSmGvytyg{QT-4l*=xrnRBFSr|A{&~DzZ^-I8_ zjhw7@)7k+=PDWWB(KBK)LI_Cs)HfjEMO`UaM-YyN;{HGwAtc-e65e-F_@5Xu16pCs z(nK`iv=k^AX2?h^D7`IBpxMBs27u*vG}4D(Pza=g-11p$_)JW~vcrq0ls3p7;Xxl2 zqMi}aqLRy4N(W-aqSL7UBRUHfDD6V5Ug$-^>Md9fmJ&}aa;sns5iEtJBoS*8`dP3h z3zn0m^dZ*l<{28RNU&V2ANEq7-LYRB)SM4(k*0P9kQeVg)6^tP!aXEQc^e)HIY;`Y z0HHnPSxf}ScMHfzBYgvb3`iW;$w9LrKUD<hsHXcMBZeArJ`J&a2T;Y@Vl*k7g%ep+ z)C@Rl@L7Okd^VoP_<p?r()hx0dPN4L#(4T=GFC*qwipUb=?_dmw&3*{(8Z9gZ2^pF z$(@iDG!LOgzZ}yFMJSSD5s*PbqW_H%cAAAC%&;;(btvGxm`vXe9R^;uU4E{%F#s>y z&P7#!1BzC@b1+}6(>&J$$9UOxo6ZQ@A`mazqFVkaB6efSb0vxj)5XTj#YleN0Bkk^ zCIFU^1~*WJK^~kiZC<vGHxMX6Fs-1Os0VMi_+UhlCBZM-7KTWZ6~c?o3Y6xubkvRh z`w*hZr(Om*FDBE7kVXWbIs&Sbrrv@~O!_F9egts5+vGSfBofKmmJhsr`xX|D49(y0 z_U$)1&C?TY7r}vV-$G7+rN8BSxpTRoicglI)O$fgnu;6QUQDLnC|Y{XU`-jc^h8v4 z2~f0>p`}Z7nx_spMoV9+Gi+KK)$&^qaTTUKi%`_u(q%|~+5oID0jQ-(!*RWg##*{1 z$O)4@DA7nuCn1U~32x~zA<|?;a7&XrNH@0KH`LPeLClNEG$N#_Nbsp=gSBbudSqhK zN6GYKqNTqDawL*XE&T-0qL88a8(R8ZohF*jc+Z-E($}CIzjIGh`4A`#lRni6bNa-e zpfs;Ch<^k<1DYAektaAZm_uxqDN{L8k<AB#Y}8Rq$ww#3bYkLH?mQQnUz(Y@#Khp? zOAV&jT~G>%iA~_(TMfNp=Rlc5TnFE)bA(5waH&c7T?0b>PHI>pHT-I@u`nhzY%^(y z9jaB!gHfhI4ih97#$^W|phGn7v&6-%b_bt^Tv2tY{soilMHbmtOtM#5WZy8!-fxk8 z$0Yl*MfL;Y3a@@;k^O|YSVsqs9u{iz7be*x<cgM-H9BsR&9=yXLtON~gBJle$dNw~ z6QBAy_{E{jUreQ5k4(IE)|@OhSA@a)k%|7+m`(?znW*bKp^_>wh2&46lFf)ItZnNL zQ5#K6VQrsK=4r%46CHdkGR@YC=Px28N<t;YUYL-q4V8=~wL<ddP{}z8*7G_yZq>a4 zOwlgn3UQ*am(8@q1a@TUU@Vtx^_am|n84i(uo<$QAn0U;k2E0YSkWV8cN5Q06<%y$ z%-!u3Q%PHbAz~P&XTq`$pAh&as_>HtrmjUHB~E7Ww<gVB|B+^w6J04Z$HL;+UbDDc zS4KPd*@zL{KoZ9~_ynCOe&d7YSILIoAS^N1Kf!3I{WwU0g9mhu9F*k<E8a7}H7mbO zhj>U>BIZ$i;06<a3K2oW?1jX{_~4)D;@SYcfS6cg?iis<iZ`1T@j5U`c0#78sbsD) zB-0H^X;2L@Z%4IL4N1wooS63@bG}7#ogum2BDu+sywf5nUOuM9>a!N+Hj*3!{^p-s zm^%z+M7Hh(@w8VNM=`;>A%h&?p}PlJmjH1e!nzDI5Y$5?;s!#H6N~H-_Zx_{1_Ike z^hT-ZUk2;}JD9Xryc)<~F(6pBe5Xqp;es^dUmIL3M~jB3#3e7a9;w%tx|7siAmmdG zE^7CfizpY6^9=}9h02jy;1?3nilqhw->dfENi+0iY7@R$hiEp|kSzK0A)RS{4@B8a z2rQ4kg$OY`P%We@uO|f6^H+Ps5h|Wa=>)x0w!B%#7lfcvG7(`d<+!0E&tAtjhK@D% zI@(gBKZ<p^$zDeaA)Y|Q;Se2X(A=rqO|_+tAx8#S=ZPg=vmv<9`xfN9m`tN&nu_W4 zzk^DzXYvE%<$a`QIg*(o?o#LQdAViGvx%p{xD@pWfH<2gXxDN+MJJlZKq+!7ztG?w z071Eq_xub=_8e+j7XlE?<`Ex<(t`00M7&I;N~ZX{idyU$U0eo@=N$3`HP%r>QjBCC z@udz)y2t31k<5{XWLIPcl__4Sr(rI`kdy}HkR%Or(=C$Xt!$FK$Rc^6A-UNic`Y%i zHSe`BcM_8V`vnX07K3@r!rVj5H_@ZfV>Ks;ZbctDc%C-^K3l*W1b81cj6(o<%G@zM z;;|?VmX(GI(_ra2-RLsc7zk_{F%*jN!;?ZV{!lPPYwRJ!B`3UPAWWl}XM&Lb&EQfI zc#`9fr%*sTjMIIAk*RUToXXGExmwxc^BS6o$00K)Tvn3KP7r{+)WQ@KA4TDny4oQ3 zT}R>+#P{gpL5SN4K{bEH9`P_CsFd&ROZmG|N;{~rO*6h?=r{)v)cJ$#c+b!=-CoC6 zgrIS4nY|8|g2MrgYuAP7(0>n+N;d9b7iQpS<_7<!sfR(vE0TEj5g|>*(JW2<6q%Sz zc>$U{+BJAGY!URp@?3s=5l^PG5Tc5$5!YyrKW`L;NbT<0HJ)ecG;)9k!{7MXHUb;= z)nkdcp#vrUWR!?6`q`Jb5w+u{kg3FbbegHeV(NRGKch2csT$*Bogq4s*adLqaiQK* zTLd<+6buYix!N~L8l=2+YZB0f3zQpqcX%2ag<LLQ5>jsEJVPgnCBN8~QFfz7+>ztc z5YU&TB=2tIQN<Qmc=sdkTtsis70W3?c?5arI)0zd6HmOP;wN<B7j%Fo{EROAmCg$i zei;EYvbKWag~c8}B;`)5^12Q%Ga<OpB%j(Jpk7R-5h0BTDLCFigI@<s8Da?08XSu= zLhNEJ7m=LF78=h*p6u}41S~9R6kO9(-1JYuZ6mL;{8^wx;`?=sQz^>I=}<~6>-QQI z&wT~+-l6M<yys*9BARhAQTaZm;KA{cM*=en5ppk8tRQ?x420y;pbdt20qcDQw58y< zq$=-UHU-|hLnD>$oZcCfv2%>iMBT{NW9KW*7wbf^B_Pq?@{I<AT0pk%kEj|8=XW7s z9jTMNUy(;UzRwywQAc>k1(|<C_~*K2ZAqyT^K78=W`GbzipY@SV#Fcw9y&r3Z)=E; z(3wHvod`jZH4hPFw&!|C%GaZmt_H%)1rMWHKJ_ZVdNG+sgft>d#1Bo>v43-vohLWv z#$M~7_w*d%esk<?4*mufhycz?sF1O{;ZNLsqf<TefhVgnb`K59^u=V0sUWwQ<b)H( z?jt7Z=Sddk<HWoK@gtBaN|cg^iFpf@$>-@zvxmk$XNcG62+b-n;gI+)of#zlCW({X z&mn^B_QYoxHG9`6;JBf~jQG$nvL#f*M#rayjy{N>ItG>UxuIiHhz`+}#vUUC`kYJe zLhEAH(&z;~pSluQUO~X~MEv>)+jzn>qmA)x2WD#HN3bje1hw(&I@NO?@HB6VHl{CD zzePj=$py7By-m^b{7|N7<1)l2BU6+Z)W&t7k&o4xL5(EZn8ZtTgl3g!V-jDhGlRrM z8<X94BZBM>^1f(eD&S>9hqaBVl<(|yh&Co2F;G!a$DmR~8<UQHh%ng^)W+y@F1-tF zi~?!u3?O>Zy*_m=CIuDGouP#oKkag$wxFaqv(gnn8N)AFmH~gAU^<N5m|&ddYrY=W zHnEB}%Rdd!C<JlOGC0e5o6q1!3`PwwJoxyMmC<m(XK^f(M*v;O%B6!CRe2>K87_o) zypHg6%mAVUEI|O>whh(+8gC8qNO*?96OT1{oz4@*qEFD0G<6MNy_oc=J2Dt6y#$h8 z-u`At=fGpmNK9xR$i5IL@wx||!D6cMS*T|ToHaYTLy{5s3jmP$o=Z*q{yIMbs6nhD z$ihN+S2zjXOx&UIQ3^j-Cz`aD3(rpCYoRoF=a5R))`8T}j#j8rHnC5g0~w!+=rnZ| zq`e}E&rwT}=XJE*k-^wkkc`9x<64tH0;DK1&x2gq<c{|IRfB=ghFJyK<mkjNha49o znn`Ku4?y%H2i}nb{iO@x6dTn-$zkkk_)kIb8ziLLqk3QjsSb+5sGd<XV2L9$38z6O z#vvy1s8&1=q@pMUgo6+(n<c6}Bw5D{(7Fs!?Powr<8?wF>f+bv8f3^u#c?!@@6j2u zBBEKMk`?~4&hm5v9juCKALWH4O8^2iim-{e;w3n&UoUWg6ZrFC)D>0tsmn4bG?Vch z3p_6to<_+u71Pz%v;&PpfwcgH7$)HT2Hef6#^0Y&W&pv&sm7mdP^v<RxU^O_YD7%% zg*iD3m~ty^lzVa2U5&fD${iXA6HpNDN>=0Ut#UY+Q;iQ|l=p#n5o!8{<Gwtr##Nre zbEQ$3-~@nmo*OdEiz`4cuCl7}*@)5wh(bd%2R&h_{v1}VN?%O_CcqB-{j6&I)hy-w zAP!ZX-lt&I_^VIKMH(9u+{E_cZ$wr9hRU~S7*g)REc4>;a8=`vNh$j@HmLwd<+5(G zkjT925tKOyK(A{cOn`y-=(QT3KP$fkaZDCe-vt<@#Z2iNOn@LhDXqre?p6{s4kmzu zKg?Z?k64w_8i!=eD$`LgUt<fwYJ9w)EYygiC95ZA0`YQ<hzTeH-;}7vN2|)s8V3`= z!7ayXd|<B}(m0slo@d|;zmy9cFFt#%#<we!;~Iwanhab7VAkUpzK^9u<uSH+2@#HC z8Z_YRi$1j-WR~Lh0oA*pYbf|z(#w$DJQ06!S|;h0E}u#;{55K&Lgx)IBnBW%6w*8c zv7q!f=q$=*fL^?u=j4<z_uW`5Fz}bFmD_bSBMdbosI+SQzF2u208}H<_g2u~QE<aw zTlhp{U?M2g@Q*B1XJITgXc&qm__1cZ#dZx=I_FEJm<W=^JJ)J_mp~bzVJO5P4$GMH z0_?EjZPIFd>aEPsK%(8M3qf32t`Vs@gk%LOX4T&y|5}YtO=@bcYJ427?AO>7I?y}I z7(5lHp`sceg(|NBKy+HCgPuZG<Fi%em`?tM3o<?+S3Cu>t|oO$q&j?zti%NY*b4fY zdiZ^OWthgGz&6{7Pr8&sjZKP8>{a5HtYZN-v=RUqxr`hkh|m(ap8+j#qo#yf!h=~c zKCPBYij;$>fZnvFz^TT0QTbSt!vws92#2FR&4yl_GOKY$S57OGRmX$?@lov{O?W=) z3`jCBPT}5;8F0dNLpA;qjgqQK4xIs#tQx<AS4M^q10bW!)QFgXo{N)Unu?!dR)6FM z{^dZXLG1KBGC7l-zGpp9;rmcH)2SMNWl}i|*)<#(41Qk{e;G0;11(;H42Vt8jX!>+ z{HhDMFD1GVkeS67Lw|#xII7`E86<;$4M6EKOVbN~2f&nR*5pj!FfVQv(5V{Vmr*i- zNKK0gs2;u<Q;jd<D04NA);~&^a{?MCUb3pj7eAEc8i-;920M)Z+ccu7f6T`ILCxZv zjeI#t;kydT6B=GB!3X!s+dveZAX?5`iK#%2m@VzagqUW1pEQFsw828=`=kXVnHOK= zH`Ns1HBp9Yl2nRNUCNQV_!4Rq<wDVGq-prFgEAA?0{VlTfpG&$S*hv5gq-YOz68?D zi<@O$-1n%)9U<ib4T%Xv<}%m#hanBgnUH*pgmB-8guJ*-RE;}i%3GS`#u?Z$)%X~b z_kv{`HJ4V2`An&CB9)>6)*P2PaU{XeSjdz*%E;<n?!;{j<jjHPij%goWL>+#y@-;n z>Ba<v0&dY(<IbtFSmR(qtHcUO%Sv1fN#?~ZQ{i;nN=;L*1gaM|POEVXQ@J0qWIBxm zAX&y-c}Rp`gNO4<+K`12;~fo0g^`3<fvn`Xo9vmaG-wDi)P$&RiH<vMjx0zz4j(uv zJv5@ITs3ZNDg!hkH6yFWT}!1vBa%4X$BG$Gc~rQp8lOWc7ilo55ceIGt2Lr2E?!5X zXk8zD6ysBG1Ih*XcQy7vLj1Xn>g`UDe^Zmkgc#6T7SkVx@!}tfsm5Cz1^<8tRhmXU zaP&_=@Z#_5z-}g@@K+j?)8|t26v7{1rN8r0{S+3E4pfrG1TG!(82ptPdU@Q7uxk9n zAj(u=ilGMnE(m6r7p=XNx(VkifI?karNz4`$*S>p8k8G#dH3T@Oql~sZqt=fq`>cg z1Hn5RgsRI?@@>eHeV7pT!QU1U_Tk?Zsm7Z&2P-yvz!U%h{sDkO55DzG5UAnx8m}7f zupC1*Ei}ahX+eDG!MDx@YAyG{nNMWZc?n?e0Zj+ZBXW5DC<4iHRB?Y2fs=*kgYHkw zna?PL9kQIck4Dg<Nc5n~IKC?sdho4V%NVPpR=8sZSb>1cK^(gMT!ohRk^n1;U;+#i za}|`v;|da7OJ`-Cf};W+SAwRCm~x>)OA#Qf<85$sG9AGDTM4?dr)1RdSeX(^*YmzI zzmDVFU_O)z{>3~LzE(17_y(EUz-u72k>gq-^l%o{@J*6l!?){*bsT3X^8o|+V6v`C zGB)v{p^#a;h8IX;4L?s$jnRRdIj-MA4`n{zz;6LYEx!lOe9~s#-3~UFU&V(YU<3CO zx*wrY-6oE6n)y&ll^XuDZo_ds^{Gs4;kX1aAHGj(_-Q&WLZ&uxj7{_5Zr-GZFO$R? zUL{jnE7i&TdVaM`UCnQT)Ovoe%&+6PTrnT+`iPoRY`^y<qlUjEQ<~aiy2v^{V}@B6 zK0)~;;yV(bBN?0dh!6-0xT_pBe4-BV*+I^LMm)!0*p&5Y#7qeG8h*md+RU%g>j>7$ z1A1=_ze6%M@P{E)!*>J&>8|`5>U4C{Wbw+keh%ht;TLEllw_(=!n0d>6>u6FuHtjx zisAuoKSuSr5R1k!3XhGpC`V@lftu{c%!^2qHfC<Ip!ihNh{~$*M?@W4K!yfVOa$F` z;jd6t<Ii>|`!ozD#A3qz$pJ{ix48hKO@Kz-^g}s33Zg%o!zXUxXrlRO)}w~6mb7j5 z(e*v=4JwQXgI>8UM2q`-2(P;(v4-C)Q(HLR<eCrn=hyP<fVK<<D9PH+&j<lEAHACj zjF<Ep-djU#<U_QiNp177*Yfj#zO0syhKo`aeeHFYfZ4$df#;}-7J`lXE57pg{1w?V z41eWSoML~yO9lRS{57TOcm3rF!(Z#c<)<{hqQK@F{@?M}rSpH!Urk$v;jaT^zBb~Y zg8n!FZ2oWg>%r>Z^;gp{{Pi`Ne+vCo0ydvye_cjzpqmCkO7g9zUDVim_X&NKDrQJr zyuuCd-*xgfj@xLV2LO7*1XaU7(3qPz?yH#(<r!F&IrJ6h50bsjeqFenKS>I4RftCo ztr9WS=nAohR)_+Oi$syag`zk%aolz^AIdVAk}4%}1D^w_EgUyL&4;t1hBuQK>)hxX zY{b?&yE*UJLNxva&U-hK!jm{IZL&=9G<EA;LpY}zpP)K2Ad+Zhf(g^g1U9XUD&f(X z+zr7eumO%?7kcomk&DqmXGq@lG$*fw9r*RUx1{alxOotI@HyWAzlN7e-e!L9j8F`0 z0}O#C-X|HGd6f-BSq@9%fMjgo%S37?#|@9rgU=ZVrh&P7p;rrd5YW>b3f-wQHgen% z2|f6n8a__aH*i0stm~1h`4oZJ$#MTC^x!2=ku{%7-WHB~&*sB3xrUF`X&W2SQp3a5 z08jREpxJvun^CjldxNHChepQc3_bYP^Wh0f4R0-Z)@~Hl{SUfP8YrlxZlqjUdhNft zeB5bSKB9%qNB;}#IY~os8M)_=yV7MGAJB&$eCq_*{<(qr0`HD#JY@dNsWQKlcMZN5 zA{0;lker<;d7CY_j0kf-0YR_b#xb_tvgqf&@0X%?{&3-c7Qyt<;XhjV*U-Wr?K9T? zjWynGD)%IggD@8y)w>Sb1fiZ#!&T|m8vd(3nSCu&TR1*-F&}(f4S!w7J!f!@M<<Q- zncd5S`%Gxh!anmK^r%`;f5LmzAhP+SG)lNVs?mw&ik0Y3ZKBy?nT~jg!EJ23O<jRH z!W}KeWHtiIy_zPo#wM~yNb4z{$W-ADIRkCxr)DBM0aFmG9)few9<bk-gJ?*MYK26Z zq}OVwmsR7}7s~q@o}Mhw(<k`;0;%$84ZbVph+bu0(2y!V1K$vn$*viI5AaV=Eac!@ zBmRcb@ulR|@E`S*6V&2iGtTDET#ZtHIL>YW6({Nj_}>|4+mLzxMwf>DU%7;?p{*9I zw{>X~ywzgomqlyB^2;u=@6^vfNo3v$_se?Pf<m9sv7PS?S@`k%doD)DJf$!CLig*; z_au$(*L_6hpL(|ykntzmZP3v|@8fv>flJVD;oZxfvSmya8FdQ$@o319#q%3#(H}4A zgVbS}+Qji8x%u#X12;5ZN@5NFM5eUo6Tis(dfr3^<$B&mrmp5)A+^r>kmhgBmjYP6 z@t{U~JX6E9M>h5kYP82Q#v_|k^`NFVSsdPjn$QOt@GxT*i8uN{12!mTn7vL9cZ^l~ z345@EWo+Y5hO{wKm1~^egN+;b^T^!B@tvyBLs{?aRD%uow8m^?PiVb!7~%9iA)6pr z=X{-l&<Fyp>1((a4u7>ENF|HI3j#}nej2fp#OKTqem!B0y2<hc?T??HZRYrvTj&Ar zy43J?CdN*_sVEc#_d@yJ%P<UXl{|Qetf6-Dv0Bn3$Ma`_zy@9hJa}5Hi=D4ww{u*g zn-8A<Y8`@i>todQdTNVI?d14^S?Cef_8?g|S>xI4IkYuaUF+=jyxdgwsh=V*rE*Wf zln}ab;CWwOj_&@$wP-BCPQ7P#P`M}DGd7FSJauhYj!C-$VW-|Pd#T)$?-<KsG%w>y ztnq)i7%e03o_e=^MdhAsx7jU5^Tw=0zx~A)qYg6a6!^ok7|pwE6Z+%7w-}wV0n0bm zA=>KWue%uCzaA|PZyjQ@82yIC|JsYu)zBz^v>4q*4fn^3(U%GL`-{;63PK|Y{`!m2 zCpLy31U8FNA60nH46%IrzpxnHZdr`-yoab3HVe`1mW3$K`vSoK-Xb*b{HxH(e`XPy zwHYP<lSODPX_zQm=s$ap<KNl#Yfg1O1yey^ZTT;k@I3b&Dmqirw{ZMY%zSt@*YFZa z+r;rRGxGsILs!G6>g+b5?0aA<Bi2N;S?%S1w*{N+50}Ab671Bs%`H^!$!;4v$9S#@ z%P|>OBka^W=5Z?bzu}m;t!BsA-cC*=-<^7=yhi1oY^OBx#H^r%9HTuk+h}=10lRMS zTM9cZTi%G_c^gTScBjD_f#p9O3Jcu`CT;m25lmZu!z;bEusmal4lmkX839{lo!}vl z{EDN!12f_)jvK{?cdAo-Z-9ju2j6<%4($Vho9L;&>c;QI9am=D%=4?58i8Na;URvK zOl^W+<KZFEP4VM@<;wS$T05oMeEYUPjJ+4=$<(Qjz42t)$&S74mS?$Y^AD~?r)W=m z8;Q=6W`z28qEkH6y&B}SXS(+93C$Aa|2vOYw^-g2vc4lEw%qmig8uk%YB)X4=CP#O z^vCVysA}{%QUbwFePrEE<(}}!3VtlPlfNe$5W1p%s7+$8L*E?Lc-#3NEh#~&8VMbK z1Ah+a8~8yuZ{hfK*nG6Su!gsgv~4_du9+v&El+pUP)Q>+<|e*ZOG-Fm_!E*SqN9fY zL+00U{9es`L_f$sBbCXLQNz1wkWJjBC8Y?UYq-Zu+(@6PnKfcsRcrWF5@vnWyMfmN zuaWnV4#5XCC;a{cZMv1l+0HlMU%ld7=57?Z+lYtXMRU$~@zxoP;jryZ@6Xund>EXU zCE@t&yq<}_+u>ll`G#c1nkc9mkKKHGP@eF8G<+oRcLnix^9O_SckqLdk0i0Vnpjg1 zdm#ws{YPuYI$?nwhv0b;KshHulXH-;2j(P=kZurm^Ur``n0qJHcw8zX=(|t89F7Hd z338f2ZfIy&M(W3b7vL|8wbRv)8(^UBCOLN$UBn;IC831gh!KQ)h?zh|-b}6*6-gM3 z81c7t!_gxYlbUhO&>EpQaVDw}e>_wp<ryT0MA1VkfpSU`J=zc?Rg&l_fgnXo(kw$) z?7dW##4dD^e{R&9K9DiVIG-3vH-L2tH#0sbhWsmw5?pUX`@)9yPaE1X8`_sPwBtmR ze}hppCpj=R#b{1ybTh%!;KB#y7SHew%wX(3(i_v1F0LC<8NZ+B7v!-R@dImu=8(8( z6V7=*pIxwk#k4ZfREZNmfFxw2C9Q)A7kfW1&8uWF;%DOoE<@tP55)=E@&`yLrn^a& zaY^iHCORZB$xL)gqR&iJC9#j02w%@)c*OKI6JsUu95YcfbAX9>r!+m&L>n%J#c%J5 z>Nt6ODrFqsrNHQP(M@^-h~L@07zoe+QrlG0CTLm%TwtO(B`()QlYg7%LSBIdyaoF1 z=ecENET)n`pNRs1R$0Jes!cS<{k*7z#Vj+CRA{6sXrz@UTC}LZmHZ9Vf6mRQKd-8s z#cU?fFd$F_6_n(&n5#`R$Agqf_M!vi-$3M&<}=YWTrU&NDRDFwNm*6W`j~JqyJ0T* zY!fY3(x9K{<z`44Oe7l3*-Z41Wa?F-3_0Q?Q@;`<&60kGBx@$dycYB~L)Z=)7$r${ zBTkS^omLE<vP+V7K?!4=HV^x2X(C*{e5t6;IMO7D;SBj^RU4%$oI~JP_7FKzXcRn{ zM(_y3MDaVz<A-6@_reeaBPi89s~u8I^N*PzoG~F0A!0gHgneexGAqhuCCRzNEGS#j zOp<elndG+Wim;O83}Y5-VnsEzk|M37W_!8#i(y!8@mIq{ttU=593g8xaiT$DLe)tl zNh4y65`$bX<`^;gPlDwPV^cD)-%~SBBB|*_5TS4u+%q!P6)6grq-(9D?H1A)8W`}` zZ1C@X-QEiBuUT<ZEa~T{<~Yt^l)`_WTvbt?TwF9Wc~)Lt@`BWqoRmI^<pue(b1M^z zi%O~%B=<?`lhijkDarU(RFYR*m0ysYmyjU2Gm9!K*a^{8u%PmUC}L)VMY^J>xFD}0 zF|TyqysDC-yxhv7(vrlyva;lvRYk@5$y%-KV8E;_C@;*-gG!f{7o0TZ1s7HomCY+C zsXS>VR8<xg7ga7i!TPJqVWKQ354Yu{tHXtxn^J2fBlhwOX2Op#Q1Aum)sQDHHtl+c zp<OSpw6vlU!lb0IDA=sznZzkrkXKNKu@_{sVA_z9^9w3-i;C?y@aIL7;qO-FG{S3y zOd`o;<ppKsrFjJv6$Sa&_3glw3(E>}D$8@BbN`MN<+&xZ3hcy*@jHS=(4}%KOUr); zQdU`>1D*s2lob3P&Sa^bC8gx=Tw5nr%*!pW%z=V5GuZf|0_cJjIpZq}%K8p2m|v7v zkc6)QvdrS*3E+|nk*laI2ImwY5601wg6f>y;^I;mR!Yl(1UJkGD9bIv8~|qKRutvs zR8*E1mCO>9yxF<s(!GK(52~320}_^11VL0@kUNjTT5)hu?yM5X7v%xY$-qDy$i@}S zDyje%0?nn-vP)4nten7#c}029(IE?_=(UItX2D<Q0ETWA6ehB0e{n$$4s?~0WU`~8 zGC#kd5RfX|)`|?8msgE7p_Guvq^M|Nb-qvxCFFnyq_aQ*TZ}|N56nJ7q!?T{tJJ`O z6lg#mxR=mnWjUs{7P@HwfFx{MfTp5SNWw%1dbMOa4)B$UMJ068PSy%cWzjse2+-!H z1Gk8JNRVuDSe%ws&W1M0M+?w9K$!)UL~u%ORdFRy;Fer?KBv009IFn5poXu^%R{$| z793wtE`tjiRk}W}I2XF4^u2JCFoQg%`4H4jAX9(`t&NdZSXGjTqY6-<0O3_3Sy5G3 zShOH%HUw64_&clG@I!<sXuhiQa+q;U3IOPV2rS7jDlf>Z)I$`=(Lk=qfsqdW{y50w z&MXH133_gRF<4h#UW5?|q!y^5vS3zuZgEatPGv3xCQw^~KT1o%S_}-4pI=&(Z_bzG z>N(I+Rt&K?yR<mJpd6e660nk4SWuBuQc8h9q|-ntbOxw8@L^3=QCL)xD-3G`p;KCt zS6a4Ew-u^ZP=dLfB8X*>XbTd6D9F#rFDNdc9tBibiczFh7gf%Nuq>KYf;A=qSd42U z3gzLx4hn&xl5(IQb6UEhtf&Oqc5Y6^!V>7ep!sy+14@HGu)WKLDCWwAqoA7T7!6cZ zIxn}R2!3-3e&!psLCZo{9t1;Ud1-Mm4FZrKTu@eAx^QAi5yqnI>e?tP;-aK#UO_pG zLt<118je$%g=Nq(nuU7X$*G;_&>ocqFzdh_a87PHjV@3hFm*f)YZGa0QAE*8cW+HV zyEv3r7++QOiQ`OIdO97<#5jYus&crHteDA1-Q3Z&ZQsluPN(wa!a^l_n^KmpM5jAl z%K3#(MY+SRwp4xRDb?!7PPcN?qP5C<j!I{Qa`}>#kpHZ?x<}bwF=fEhe+TRvO1e_B zcr9qE2d<)A<yg7Qfs0_LYA&)lcQ#S_#X6fRgQqyv^Dr|UGwMpmplGG3+S1{Vc19|# z)t1U^$1U*lp|MD6?rf$s15$-!tpgM)1!_xY(|jQIboe;H7di^LvcPdR2UYVNMI1P- z9n-k8xza5O(omV^na*b8!RP~g8xS5@S_tWH`EX@;C1f94x)z~ox-w%5&>!ZN*^qyE z>9+o$yJ#1X9_Q*FAbq%WiZY|n894z+-w5eQ<#CdZb9CW$;-kI-xq(TbC=;wuI;BG@ z7fX2uEQwUECrhqykR_4IO{8m}oh40`v1rMgL6$UC@=@1iLcXbTE6JzZ+R{|X`U<cg zhA5bZ3N~m8c94RD%vOV{4E`#4@+!5nT6Io;kh<J4MY*d*x-(k&S1Gj44~su`wovYI zuf5jUQh8v>aHaJwXsb6Dt#opw|HqIVB#Kg3D#O=8_WGqyL7*IUBLBNZQzot64%wI4 z$B?~s8OG47ES=Knkp4wUg7l?Ogd6U>LBkX!Wr{L<IOw@?=@cmUHTTD>z>>c&RMUYr zZKbjhJ^vJ2sm$00G7s~W*`Q$MvX4R856U*+y}3v&><`#%%sj@P(t)dixNYgjKuuAH z_jjl^{VBG8l_Lu1=Gd0qFWJ)14n%M@18mrN(G)2BZPygg{OJPhVOt~i0R82Q_CWeQ zJ{;25Ern1R4&CT`s1<m}y(<UM4GTWjt<z$Y>@t`CDg2#hMLEa{p`H&f8{Qc*mpLmT z^TVQ7A+33K7o>ktrbut1Gxktgjdip|)1%BfyTYHERel1?qLfRPqJ2N|O0+LZ*+-EQ z4;?~xFZP)|!e3?`-MAy6HHbdr{0a)%vnYK&Wd6w=XL5*xXMpt7(n_^TneRyEO593i z+EYqgy2Ibv=}@w^0k`kRn8HZt>lntBsp!3~;Eq>83$*HL;NAg^1#C5GwK93768Dud z(*cGzS3K&g{T-2wRcd9Um3sA$EA^+H4dID#EWK^^(|e3po%1!+>Jjd^0DQAjM7WZ& zRvErWoT2Gn=W9X1^-G2yhs+Bw9&_a`8gbupOsRs*PRhLFNFM>29ZRsO?p~(Gs@o@> z2dXb|sJnpj;}YzOmq7o8w&cps(3URcLUpauLLIJ@u2foJ?A@wv1L~{Q=}wPw1q6(u zl&n>5cVQGXEQIk;QP#NEDxY68Tv_K@i|Q7xgvntZ^1pJV(>#G`m?w6@JTZJW2>i&_ zDmAXcocYQf3ovZ{!PMc6$gBmKl>?Nwmx`*d4RQllegTuCl)IKWdh*|`8sc0^8C7j9 zSn#U@l6obOa<VHi94i5B39T4fiC@7uw{nX^ow5cDxy+q33$n)-svpbjYY@YCR?}E4 zI@#LQ&|2Rw#pqU)RZegoR~n#qH&@PAV@Eh$j-=K=iB$`s&NCd{un#m<&3y&uFf~@| zJf!Z2r7F7eo@GxR26&2^qzC_M$iEEm{<rm4nxmBL>5^VJ;vt|L<13Pd_F!CW{}uhA zfJrM4gKd9jINHv2q{D2f_h3y<CvfH4rBI3HFq?Y;7^)BL39sBxoUD!*J7L*0-XHkc zzv_!<{~=h)G3Kvb7VlrvQ0ey9Ml_63{ek!Vs}4q=f0THT2@H-?j|d>7{DDK10YXCq zZ+5zpz`Db2Vg~$gP`dG$6i5trea)3ZNUU<WE_JZ=unfa{hb5>44v>42dw|y0bwval z<GQ3ND|D@F%GPq%&rRUv9M_Lc*rVKaun9ZLU5__mD;=);o3Lvfu6vuXdmXO3o3Ljc zt{a=MPaUqEO<04&wWA5UN^xy!!tPRB8=A1E71z2Z>?6gswh8-DalNIo>z%GQRQ9mb z^_t3Fbh_Y=#{c4U?Nr%DmurX0cDr1gRCdVa+Mu%cU9NR1`_bjPSY_+nuGK2L&FxyL zvV(5d&k^h$x9i6U_O;u!KZ1P|0W}aV=*>Dq+As30&x$;cWw{o!iIAV=S^+<QEEwmF zf$OyBo1E+=4yhyDwZq98xNEBuJ#>i^YY6G<p*~J_pTqU2ll{Zt+T+A}9(1zr9j=!Z ztSzK3QINjU32N@c6PVHFtjL*A>}t-&0-@9u;0*uXDR4INL`a<Ly1fO<alO@oRk#ke zV83zKo@jQd!*yRYyV2p=9nJPSTsK9tXB@7dJnUD8>w`$PPI1*lvYm?SUy<xJr|aov zY^B?Ee-yjS?fN2$-RgEd+MGS=c75KQJ@0nC(44J^aNXOCZHjQ+-i+NA;R-Zk|4<L` zz0KI6rYL-Wr0dN{_EaPo^JoiUT3QF!YK8Tf{VxZ*nY(UqvWK{9qm#YHUGFJuwIgz` z!mb136n2Zl510m6T*H#Z^$y&vm<}1o6tGD42d2fno*l@KI|6~89Vm`F?uXO+S%Fuw z1C?<<K<Goff0q?_rm`S&AH*el6d!<z5Dy&k2cGb+Iuu*kB0KOY(XwhO?1#kr>qe-V zp8J2x4t(wp9259egW|bAaKvBRA<kc09H(a2=Ep^6Ln<b_wlXdjdQ$uWf88+EpZ0j= zI)AM%t9D7OzjhJ`3<K+4@TWcR_Y8f?pLY1`8#6tdpY*JIEHnPOA)bBT4O#PDRjj|q z<Ng&t;UgZ;6_eot8L)J@=d!_&$qc-j`Pi{eM+YE7_DX-?OR`H==77AuM_0J3D}np& zf_&Kcfg4jTGqD8r8DJkQpN%eIqYDe!#FDusrPU>@DyyV2mC*^4z7$Nu88f|mVFu1a zi%WCyIvAf`A}6H}a^OrHxQcr?HZm7CmDu>=-1!A;ROxuQYn@$Q$|j7<95jRt&dMCd zhKw6GdK?=(<lKqF*!Uq6CXQj5+1aB9v2jBNO#;HG!EDgzkt5mQ%n6wc=p&dn$(Q8S zch3e-)RVXoV%ckhTg-||v0>#irF*f$+_?o~a?5k)4Tb%$B(Y6jhI#O{-9h807&|rp ziqTSn|8RWOq{19$Gbd+G%AA-vAuI69M9}>;1aJ%laOL3ay2Wvx%tx@;%zY3A4TYXg zgK<Ewh{+CoCQ7MY1o1XE+P~_{n5?v4t2*KE9;g?*HUF%732cZte|qM$%;}jIWab=r z5S97Y?5}JyIB@*9=doeYYxXbudv@SAlBj>Ic35=Xn1;aQ==#qPNr$k^UsoDGUY}BO zQtP{TI;|$Yzjjf`1S1`Az@JuM^+6VN6mJ$(C6>tNPY2sGr%`V<SpI;BWxZYj5z|1g zudn}6S|TpwpIYd1a(=5@aKyi&0eMv}tnPt5nD(!Eu`*`W(+yC`$<b?GT=t2-t}@Oe zs`*Ckm>=qfHw64Y)PEwzljm^=d7Z|S{J8gVP=W6IEsiJ0vjdA^P+9TCrKq$P9<HM9 z2G8n^lvn(#793%fBm8y6aT)%=yIK#GNa=}VdIzpu3@~UcX|ZQbHyEKL*tZ|&=@!1j zRDpe1l8~>R7B>ZlpBXs(%*NrT42Pcu*|iVHEeDi;#X+?0fQXNb2fRY8ZbDo(Y4Ha> z%L*JMVm8<r?FY_C;$+JKB@4#5z#IO+huMK+S{rCQkS5WrL(VuT#Wb9vGA}9{EsHsz z%K#@9Iin;;j9b}(55(vSVJd8t<?C{XXzb5|AwC}L$PRSF5|4iPTSJ2ux*q(XiLH7H zTNcCDbHyXT#nv4`Dv$2QY~af*IcDmrWsyepM76R54Z<^qh*snJw?N6-`r~k}e;!U+ z<7y&EzZp-r;c1iJd5#uBXGO#5(8mk=n2pkXfy*-c;C<T^yw3*(FO+a%`={ofKi^Mr zJj)7v=ZE<VMl~GLeunOYe-1OdZdcs<U~zWc&ba6CDqG)Qw;>MwB|}mUZ2;a6L}dP^ zF|`&L890(1_*Zt|Lzt;`|3Pm+0U9u=kEMO-Su;k({`D}GCy2j#*1QTUV<f&0aGi*6 zrf1j9jnA%oIPOklK*7J_Rm7zK&>%nLgpr2^#bX+1xVC_bG-L<nro#UWils+mfk-Ln zcm6{N0d*NF474y37)$PKh}tp?_GsW_2fh~~upoi_cmCQ1F+}jgpaH1CaWT5BV_=^Y z?fZokKODCmuH-!uK(%B1b@vikQ|qsTp$F9B%4v$!J2-C2$iNq9kKbQ6C>9gZ{@Oua zm?1o?mx9jh+U&TDk#%E_jI7N(Qr}g~KPzxNUcT75=J3K1{@O9o^yUhVw|;-%d9XS* zJMf&pcJh%dSp5WE$kG--p3RSCc-B3c5&tjGzQbz{SMARZJm&B5f`7%2&|8)*y%|)+ z_zr`fss~pe2ESEy%04GA)wB9z2Rc}GR<Z|dL7V)wWl+>V{Ix@&sQv!HW2T}Whox5h z)1G}Vu6fb3W&>*IvESbx3-VmP2(xLgc-G)T6P-Io_v<x85&qPP4>%Dfg969yGzg(d zK+FaguLWOVOZ=?0fadSUV*t8FPz)@Nn;~NW8b=I9xG2S#2#NtfnPXrL+6pD(n$Zt2 zyIiwC#=v46o9`vErWV^iHM=f94*Ul3COaCGm5NOtFPpw{88&;Y-t2L5-EnH#{RwRM zxzO(SLVdImLKyV#wR=^W-sVfsr}lmrG-7*u^`^aEHtllcXiYm)5~*o5;$9@KIEcfT zX+7oXl)?P{L3sIMHSqYF7Z+|WT#F?@+u=;-`%bh)?S#14tW}@K9Ib)~l=x`Gdjb`| z8tXcc^VdO#gK^CynL&~x0H;lXl|?xHWqKYvm*&47s1#cIIM|ULc#VoYdKwZbUi6L) zF|r*X!Xz1Ju$c6c!9+EN(#3IN?8&S>7gvOtfpO9G>q%ezo55=9?+wmt@n3%h(Y4Ui zB2<<xhPwLYLM0625ZU!Grhi5$0@WX+A<IPAsX0Idhj|S!>=)sKZ?p;?JsT(n{&k=S zIn5~rz6FNvv@d^_PSg6v(Q)8LsDfbxI!o-ANJrHFQ!Ay?Yqls?7Vt0KqR~Jx)(AsE zv!1JemP$A}&$Q5~>}yuH7EOaj{z_N36evdzfPkruj&=^x`lN2!D6_6)sq1T9S4W`e z*hDjS6O7JS?sqzNHBb!0?=X_jL(|(iN^_<@#T;D<!A!_{SaV{_zkT#3jbxx^m_pvO z`W`UAY}nWzgkj(7h7AOYRteAQ6zHjDd^3svLC62}y|h9bWw34KlpFZcsEKBO{cFP5 zFSSB~8+;S015e@XNCA9wHBfZ-932+aG|%cvf|_QvY?@=blJZ8IW{|{wsbhUW(F?3M zH;rCeP>d!>4gb_Nv@>fsdJv+^(Dy8$!Z=3xyxJQtgD3jD#>3?yVF;fD$f#7!oRq-@ z74Sg*1lti(U*qBWpDbsTueW&5W3qTV4y?x4J*?U|n;7aY&c<6w;h_GUludC~MH9jx zSs`Psr0G^tI4G;sI4fzIl@t!jDs@2^Br9Z+l{6-l6q@JE#%K%4DrFNP7LrxUVh(3E zMq5Z$MHUNf>JciXu(DWsec8-V*!(bwW+_acV0AVXupxySVbgbPNTE^==CwG&j%Jnf z*~nRGp>j4R*^ok|6n3Fq(=4$PLnS%;bKUL_BluLCbgIj9G5AY;{tlu3bg{*DWGie* ztc`Rij5Evd77B5(ur!5f7d-9?Eg&@iXCvm%#hFD)f%;l{R;Z094rEi?u#`K%%uuUB z^9~51(8B@o^GC;@UWbG#{_iUaV{H4=Muw%^GLD@@Da%Z(uq#JfVmYj-%w~xh4k<JM z6b64%E-d1o1T|@}s1Ma-<8T|&iIVzX8-#ii^EM8*A%#lXKx{}>ssFV>s829&<2oBs zsH6?VhGdocUmJw_1oJkovmu2_+CXebR;mBBL8wnKZ#&;xTou+VX|oezGvC`xoR-^a zoA$IJg;vMGDxyPafA%&$Ji{$0Yw;F{t-~!StD-;GCKkmu#fMQ=D8#|Sxwp2M9ID2q zQNyrLVHMVU5?EW=5p9s6M*Owaah4NmunoxyvFT>vkU|yx6_%_gxPfdU%w~AAA%*(J z37b{xRV%eB)k;;^`2U0$T8P3H+eN!=7qCH|e0A}b8xe>kJK|z1(P~||^|E!#Nmdum z_N1*{wj-9+SexeiPb6*Bg;{18k~Uq-s=P|I#6~E{Mo)O8P(^=@;p@-V*k<xRsiaWv zab~lmvmx26-@+kTi#u_(JGHvQsjbaQ)N14jQsiV;?p<c-W&aM<YFap}2b)eBst7)3 zwr*0{60MSdh266g)Izo^-*Cb|)GM6XJi4?jylqx9HYBU=KdC4z-8OcI<ACryXRV4& z{DxE9NmB$<lXW75rEZwSu<Wv_vxO9@=r22Eo?zeDgto;uVa0JcQZ@r)7`p#L%f@h5 z;MQoeSvK0PUu`REqt1H20P5_BC-~0d&wC(T$v^Lw|KJ|Prg?0fZg;a8hNNxSTSi@# zUHSYHw;J2QvSP6r>qCvRU87na<J&yhw;@?|hw*scQWh+;o?mKH6$>yd3oKG6Qa$Lp z-FBTAHr47fo8d4VQm7)^C7~_RDtYSHiMEFQe?qkSKin1mDRYq3#EZgw5U;TCk>Q5j zpI>1?f8B2#T22-<)N3cJ9DBVsrSG;Kt4<0vv~=5<?0@5$;igm8mrq$iM%_f}locF) zK~@vPAFaYip8Rpm0WU^{)+IC#qr~wgHp{A<P+%C3$Ns{)?yw!>!lqiC5zZiGGrEN; z`cHx~+yJtcX(MR`{pFS$;rr@jApZ|I$ZBHvqfz)so8Sq5>1B%ywL8pl>wUX%%Vz)S zPm)5dg3;~Nmw2b`xOGyfq4nkL|FL%-08&-g|9`L)EB1(e!G?gag{6r|TVSP#EZB9J z-JM-Vwy`rb3!+3+6h%#<(U@RKqKO)7#F#`hMH6c@u_YQzqA_X`Vl>gj=>MF1&Y8LM zo%djHS@h?BpDu6aGv}S#+qvbP^vMuDRd{L4e=;;%hQNZJ%opmc<1kKgz89WyTTL>@ zfAnQ@Mv@`<CbT~42#EgfN+V!o_`Tz6oPw<7A&b3e&HvM9qjw`<=;Q5z=<sJGo(hkW zEiZ{tLW?#_kcG@?b`4tda$(5ssgNf_5Gm`O?`8qE-jFT2Gf)wJ4_hi3X0H#~`V@jt zdw7ltr}%6{F$hWX{3k;<tcE~*l6<x--+~poV>LVwp`wMk60R_khWInYosgbZxJG=o zpn!A@(sS{_kPMwKazX(pUnH*xgcPy-r#^{W)T*E&I&?pug#<QCER2ObicW@zgrNMV zPAmYS2$i;FOACS_Q(E-!`mkm!ABH@Pj#B;%$=jj%F+3}Wiheq-gnA_uZbqo1o-eqp zhr5L_R8UsSYhMa@D%Ag>5WN)c@$g)L&wldeB;3_d4~KgtR5agzA??#Ae-hP)`wXSR zDk_u-sdT&32@xS1*duVh!n}Rm1#~S6_XfHb7RWFbl9j{6!dS?o=!=jbh9G<@G()sI zgNA30aJBzOebnBFi+X+wSGv^qFUA-SV<_|4X}%-2!-RC(3$KyeDT$Fq8T%8@)r3sn zd}0*huaN8%Vq5576ymRtdHs;C97Sx1VEbvv1W@~xZjOeK82L=(ppdMGUJY5K7QLb^ z`j-$jp9z#7+%38!Eo2egX9DF1JESL`H(^8d==*u&w4TA`kDlFQc>eOnE%-x7g%zni zL^cFPJ|6i4Mj0KhlV`I-nUL~D)yA596VcYCA>Il>o8za>fNKm;q}>@hSNJ)g`H9@Q z`oiL5t4+Lpx(-=z?f&WdCe(HFn%)2J&P;B4)mV6~y&<%HX(w%`Qz4IsAgVnJ_NJw; z-P@^dbDVCcQz4Ispw01+#ev=F*}Fnpq5o6VLSy%kVO(Lz6xcnq-Ux;Egxw2Yl3-8R zJ@iTY(e9ys`2QJN#Mu2a7#HR>yMLbB8>&~<hc+&s18V7K_y5nrdUt4h@j0NDo^~&+ z$q11$1$HmIF0v==9@-X!LVLpQ1qyYpr?dzQy%(NxTTK%E`8jVzR)@ACpE?b(%~CT^ zu(vP~H|N={E87{+!qO^4>YmVs@^e5jtRYQcVF(o!UWw*ES?Dg8f}YG5>TD=6PIA5% zo^o4FGRJ@P<#XOpE(>iaKcf`WhT62xs87Rv7UKVVLu>obC`JEwZXL_U$X2VMK3#{h z0hUjnu5UtJ&-Y^C8^Q{gEVSbgI-(AR=x<uMxyc0p;q^?&Ld|f&&7mQEv(0&Yb7V0l z{%@?=3u%fv6Cx)m+qq6M^zj@A=u790IE|5zycdEn`r21a3tdHvu7<8&4u$w+xPL<* zCDD-OtD&NWxe~50l7`d|1-nzgvjqjDb4OhMfxlrJB*Iuhn<he*Ip!fu^)5l@j=20I zGBK96PDu|fMWJvr{1f$jNOjbn+M~lVXsG`~VPT0D9!PvPw7Cz3_~d3JO}JMI3R|d9 zC`A7iBorP9R25cHp-kah(K>g;VcdD&LwZjk$a}zj3{C6sw2czo!qr5SGa-G9DABFq zqbRov^=8!bTiEYmyWhfCe!lpuY-s<#F}f~zlC<Ed$ASf^w1&8j30kmyB&5;^uMakd z7VP@wC=HjzfRohv{8@zX?RTMqd8_=xHEvxR63UQFKz<6L1?Q}S1;gDzKZfjh`_y*K z<@+t~s8I^khOmtD|D#}dT;xY$-e7Wz>^<8eO1ALMwy=GYcjRXminxMlcySAPykNm_ z*YlI@a}*c~^7lh0EjxtfM`d1X5z_R9AXF4ObrcHopDc9lr=TbEg*q3FV4UQ94^5;` z7v}hnzI>h+jcm?vVT&IB*y*s#W}z0ah`1><{xSb{3G&Wrq-uXnezhMW7=pr|4X2-B zuaJlD%a4Ng)BGTJws96GpKiUr)m*pW+I_1zT)0E#HM@VF+qjVN5Eb*)`Gr43Fa#C+ zY`CDsxZT_1LVKPq%y%TUHb0^^hgvx89@3jH44DGEw<oiA_W3Cm3y;8dN?MB9y`Abh z;&Jnu-9O*;Vcv_IsX#9aE#@KAqR8$cFY|7XI(qj0P_Kkg^Mc(At4KnmOo81C&tmq3 z-9s0HhC+M7?ga{U+7m3oLhpsA+*XrBe}10pmcoaw`LXiJ$G3R~SyUc!VoJV9-U)Un z!qr;7%{rty2^U0lAuD`BI&_60)J^Bj^+Og?QGa5TuRG7iK&Fi`A@8WmlM691Y+dc- z(J6TzEga^1wsXLbabn*KuXF7QyN9-pq0pYNdm%3->k=Gq;&u-ycT}uHr@Zr?H63>6 z`XIDVQ!q76cK>uWnlJ3WIli%H>>l?17yHfb?a|+!XG5moNnOD&atnDp1X&>M9wO55 zj#70uHLMOS5SriZ9?~WjhD?FoKaC2bpjxFp9xJp9Z;@d4P>+Q|d&2G^m01WfX}gDZ zP^#@$yNBdg`^oMhitH!5Zx^)EfAn659)0uj;dVia{tN%D2mR6-<UbR|%{{w!4Myg< z7sgE9?qM=v%;fF9LpCf2Zs=mv?uGToOxo@pp|gM_>oAcwy7SI2zV5x1{%H(?v5k$h zmb4~P6K0PbIU&*7*s^4Hb22@0<kIYyV4^3-QmJG^vy<Qt!K3tRDqS~nWNc<lEZvq! zjB?*<;;Ce9ER}9cHaCo_of~f(SnN1|B(ZohopN}z@_1uoOKm*e(k8UncxyaKsHHiT zmgl#C-s)syqBeDWTfDV3(Z&H<n5<3oHwR<Y3Hmu*no3JRww?zvVQx&MQd=k%Gdi>J z>ylw>hN^fpWsYgFWOFLfmW~B)wq~<kes&r%Kl|&(GUeJuo!O2{-DZ@hh<u;PBA?G} zmuQQp5<w-s_06yA#<w)5+gchMxdK?4{Sx#)D+og4$yIn<Q3NN`+55h#Y)v_GWJ4ld zMO9V2ndDA8XOpUKUzV#X>ycbv?Yul%F8fSy&~-u36i+sD1s_y&^XvLjBCYARx@3KQ zEFFxeZ>i)N3Htczc0mw}O{|()8NBU2E{w+-lc{tp9d8H*Y##)RlFjrbxPm@5)lksV z{M65P3j#0a1yAh}1kEk!xos_r=+{^HTVhcxQ|AOj_Y8vUx3AN;#@d$Vg~4`vvFqeQ zc^N&ohx^vzyjX0XhYq1%9@r@e(oMktg019AB3>73p*W^rCOWx>TzD+QvFVm3YJwKE zwABR-1pJmGxO^Z<%uKY#h$e!c=(pgCL5!sxi#4~@CFJ*429t-Wd1_1q&zA*3vMxBM zoCK?yS{sA$Ln)4G)6|HPZ>Gzaws>=jzWtKE$uG{8>xc0($HYj}Jo@!!{n`|7o0n({ zDz}wiT~h2iocx<?j<+p|)h}qSO($ELgT0Ay5e<GvA7ZiEmZnx}O6!|R)$AiFJzJB_ ztT|XQnta%tPBgT|8)LOD9j_-;)6&uy3tq{5+UF=vvKV_j7{Z_9!Bo1%Q&LOM<Iimk z!3w=!ulFD7{dv8=qxT)h1i`|VWL+%SgFZF4G$&$n6OGis2IcgfqB@nJP^9V`;|;0c z$AqNVQ0}cyHUv|~Vvf0IoS$PVD97gJsIO1(f8U{!-H>z(dK|;Wpfz}ldeq#`1*gu^ z5C5SLCKgMkscN7OM=+gcZJgX~^da*zr+)ARkp;QQ@EaD&^bvxJ<Gp7nPgBXsD87YW zS{b8k)Ye2Pk)f;TMdJDNQZkZyMR_$@^Rg97a48vLrQ;P8#rUJEiO%@8wt*C}E~Abd zNuRig2EWb!siig1+{A%8;^w@^Qi;U8I*KX2-ljk4ByQur+dr>S2K6tB@|<gjoNqzU z8#>`s1aq!wIp2cdD)>%yUd}Z==UWgQFP_ZMlQW;>!^QCZCGbD|-1)UL20CM)GX^?i zpfd(KW1uqzI%A+S20CM)GX^?ipfd(KW1uqzI%A+S20CM)GX^?ipfd(KW1uqzI%A+S z20CM)GX^?ipfd(KW1uqzI%A+S20CM)GX^?ipfd(KW1uqzK5+~*wlp^syMJgEZ$PUy z-73{l#h+*wP0-qsN~V(w6EU}0Cw9{G>hw@q%3R^rFP9F9RmW)AZWFC6jyEJymAp<{ zwgkD2K5o%>%c9y;z|W>i%SpVprFBV+mw%@!XVlJ^Qd?ab3uxuLEsA%N=1RP}a^{rk z7_%wW>2g|^TUDK!F}<`rXO;a>S<zZqogTtVoJpjzI$lNJcwKJQl<HJ<S*)_Ma!7r$ zxvp|%^-!m;Iz8MLzK&SHdwFVUEq5iYt!<6hmCCJ5Zsl?tBDV_Kuhf=qS<on+N)6$K z;H71}MI{w$OvL9U>M9p<fEIBWY2i1e$AV^#zeHUzrwNB;L@d_OydYM)cyZ~lyw$u_ zGioUWt&J3Pa>T{2TL<o9CY4-V*_2&pT-(w}Ymi;Sl$K;yi&wPL&Z#tohU1N*okJe0 zPqxwe;+A@j(o|Ehlvg>|H!euc-Dut@9<Az!=PYh^D~3x;$a_u6=48`?rpg(dP}ybt z&QI-3v5H!X&^C%r31F$WX`rgMau_)lOSteP1KA>!rtBB1jn~diDBwLq3!0Pj7ZBjw z+fEM+m2F6r(<t3+rN6DsuBsju<G3A0`D<FNjrPOEX_EnMOG`Agv@Ho5+FBOSD*FcZ z$Pill9~(kR6sww=EUT=nSQu|yK)ElI5yiKeD5os#W#`BO!2Y5nu`Os-)fF);6htbA zQK~g2>eH1oNIv6+w`0LYRpy5+>v)CRQWF(}<UJ~8xaghzld`yPqB<i}v7LNs;Pwe} ze3h119Wr5dX-RfDeCZG>jk6M|v{VzNl%MJnwMkx9-`e6zWGu0mvQ~3LA{M7|60fWC z*645jeSDmIY7z~!6UT*{>ey^<iZ7tz-_%qaxDwqMrvlBTprxK=sfyIvxjCWrCYMf% z&~$BmtTb4fvx%jia;K|}ax&wHY-VKF+go5tOB-7jCE8*&EekSrZ)P)JV*Ub311BK) zy`81AES}C(?=DakZre)L)S8mqP^B~zPA{Myc9kgAp<Kgr^&X>Iooje1L%c7iKAC8w z>;gr)JjXruMv7vxwXvMiuXIE@K_7W5RJ<*jUJ^^vw<@U;%9`VqQ<MJF)iK&=s)^e{ zC9<^CRXdq9qV{-8B>j-K1SR=G-K!<-nDrA}fV{{r&)J?sO*i!vta|0GG=5_qUHehZ zMrF5+x&V|7hUc~NoEhSct#jj*0X5ah=GwMIQ=&N?uW3v;S!xx_#mgN0kj_dq1%iE^ z^?2D3s;m|?CE94Km~2bt?P!UHL|au;WkrljpUXdmH28H1ZRn&+F^uvXZNjSIf*hyT zj`}cuv!bP!dIz+7NB8Z-$oEv(+iGG9$w&1|B-^C4-{Ts6@_qX|QWdUtQs1Vxa<0tu z+RCY5NaRvi&T`9^ZL3_>>sMgZ$H~u{+{jLh&E$S8r5W{x(#d!u?T@5ZM!L<GlVO7w z<tExe)|861EJz1UEejL=o~?9K><rolCnd3if;XJJn@P$l%16i8CNJkT=Q!mWE6BQq zEH$@fk=v0-PuIp<<F!<Wacx-N*b+}mb?7?1buA01WJv(pS+VE#+^0bIzqHKX4OlvY z2NMe@V&my#E%gGLX+OT@RU5px(ldfQT^nnTH&MrnPAqVn;;NdDp~T?e*PXr~rNNOx zlNnpoa?jiiDx`pQRPHM)<tiYNj!oySq|~#OBMu}io2pT0T$QRE!s$fvnP;UlV}-@_ z__lukCNrXd{(L$2<rli$r)|w~8v0C&H7#)a5$oM>szb|yYv0?F4Rg~?)K-%>oSQms z9ZLIJX#nSvUD7;NIuv_gGytk?qM;cLhUwpvrc0|ov@Vg3CmV;`2HPRL%T|)G!>TQp zarD3huaCvvub?{0svXxetV`4^a6^)IclCy(7R6hs;T=IvP)(;B<b$!bwbUT9O@Ljd zu~@ohf$ObSr?|i7qKazO4yxiRsH>G;Lh;RwKYM^{FS2R`+&Kx{s7v=kCxZH>v}`bT z<(>M7`Y3(vF#mb|9M=t`*mJ#A;(k*i8K$6qN3wEwELN9npd(T$^)LdrTR)Ja3}gsE zS)8`PH*Ip@pBde|vX`=Qz&V{pAY@KZuESy;no)vMEH9z`^>wjD$@E-0#icIU;^aCi zkzF(G_hETliycUAr7NYC<|?0kDVyLEbT)t+Ce<!zqg+wDgnZvr!@0#7Pb%7+*+_!C zC`mh@snM?If0F!<6YH?-k?oHbRNuF{hR%)lO4R$MW!ZX)s#i`P_dDCRcvQ&7Exr$t z6e`O`TW)Wqz#cet$;cK%5tldqs$E!P)!r6xgvMVBnir%JbrcR79k;YdPPFl_S|^9P zLPUGo%_>B7^z`ajg=_w$>Zwi*qX9#rZDE4GFO87}p`|u9my(&RYB4w%f-8cI8NwR{ zMB4BwYwe(nNz-Q+j~_6gc*vk3gN7BCm6Vp1l$Vwl_nS#Z!O8Ko@WV?>50hlDeu@}b zxufE|Y{sM{TUyCC*$SaFZv>Swer{yEG{U8E+XCt!%^<TVwGV6?72^==$Bve7R4Jo2 zS*)-#rjDnSO}DfrYp2rL9~s+Bv8!{JioIA27G{EE<vC`Dq1gfRQtO@ssYR*Uc(a%` zHWt*pvYxg4ZY1!P!<*uZ$*_Hf8+TD{K-LsGb;|c>*0hrC1;^Ye2<f@Wlo>n8#@jH9 zL(ie2j^WU@OsBd7TaMwBPOiVQQ7fM38D|pa)TLmv!Pd*)aXKS}jQq~d&|!6%b>d~1 z<Qc9rBf8-{cIK`hW$tONbIRV$4yfFzEdeDNpTMOZcDA9my6Fir=B1j0`3txzh>`KV zhLeLD0^cm|+QrJCs=1YW`R-@vgbv~937MFn7_yOD_Ar+iwP!rA$a;&uwKO}!A&vLa zT$uQKMExrbBsJ~a{cvU>*ZR-_Ei_3&W0sl}6(l+khR=Wz4|Y(;$aOGkX`q&H5zW^7 z&^A*&VN)eTsgGWh%*-qd(c<Hb9@!IPT+Fs}%;y^!yuu$gUE;<%ty8Ig>$-T<jyqpd zcZKG4*z8D!k_nGxvyFKyM%_TBP|N9T(r~KZrp9X$jofPG*T0-YTX~u%QwK7kOvPrw zI*KBRI5Nkxfk<XcO6f-#@jJ6nthFA`BZ8A|sADp>g+s#z;QCs!p*pqM=-7z;Ddp@> z@x`v8ptQw&&ISj|=R781M`+%JKP(iR7#*cV$L`p1G5#2vL&+y7aTp8oOtP}Hlul|& zxq?a)WEMHzj8%#(2|WMis!Ypn!x~yzI5Le}f!wlYp3IcQMmi?keVm{M9y#NPvrabf zpR57S+AF2$jiq?%F;&KgCyhG1WN`^xr8*hc-m)cgFftWN8I~rhDA_sYb2}c~e<F)2 zXTAh?jk%>vC7Q^(I4yp9OB+Q8J;NO+H`P_?<%Q@j5!o@R609B~acNVgG*Qg;9xKeo z=|*yQ6K1H!x}+<oT(45GSyC5YLT7eaL8QuUBWYVucfs|oU4yH6v}5w3*Q|4moT>d? zE$yn2AVrM>*?DC;qC-8S1;d#(sePh0yOAwrcF<?GeY7c1_Dy(oT3V5*E2ZVu!9X_m zH0kJ3>S=9;*`UICOlH}+0?l;VG~`xQl$K--kXBvTZ)Cco*-n0-pv;xR%tduLl}j}a z#F}Z$kylon%?0LsxtmVyYDtWSMAVO|i=~q^@T_l(*XjVB^>m!=!|b+{a;etl%-L*i zpiJkIQF=&$>#!c*Pzv?D1oft(`WC*4IH#W$Z=^=EQcuRyDrZJKT{}0%qYF8R%%wr5 zd~Dek!J>{2+^eC=ae*H7C+U?t$6iqF!8T)Oe1maMsW<uWMo`mTw>4@in{C@#d|any zY0kWv%a&49%6MglGhp#T1nRT4w9)z;Dgv?WF^oDeqc9a%Dm=qdW{~D)FU8@_ZU<<_ z#7&y`9*Ar>w0~Eh9TR4K{Rtai*I#d;{K>;!SzE$pN->eO<M3fQM$_e$ROv8hf02Q& zj3=o)uo-4rjCxmOkBrkKAJ3D}h==S_si6NNG9cH^b$!?^&~7E>bN^S?JcU=yvdF3= z#+LV3Gx>@#I~l>aKjzG)Zq77NlVLz39GNc7M*l|I=~}Ex*&0YI61efIr_L;_1>kzJ zEm247&iJ@VDQ)fS>y(yLnaP_yp{6x#0Z&0?ITNFPMhV2wPEB(Ir6pAx?wC>TjkMAV zD_4oQQqukf6`n(~+JWo$G_5qF9*_(`8X8+_c>aVNsm$QonG*HXQTAUdP9uJv9}1e; z9uD(e*b^K<DMi!eG-jY%wlgRxq@BjHWL*U(s9PP8+c}OLwaKJ+*fbZnSA0Tvo!8yS z3D7W|OK|Oa{s3oaW1^YtcU;&wSJfvMQ@*ke0Zq5k$)_~7N>NveMkNVdVv*umcOIK_ z?<5YBh%Q+d(UOgXOtfeFB7q#>>dqw(bjU(>BzBSXaVC(o=$I~}O}vbAU1|w7HJ!9b zu}N$osZvfC>zt(G^<?YxJ6prl5bh0>+n-JSX>&KwNVm9EpK@lbiw_)=mbsEu>sC5& z!@HnfGN|OT4r=Pn#O^hh0j;NULtk>(St(0PvIdT-rm0P^oCrouyvUV0d%7+}vu6kS zzEn-zyv|W723lFSk)aL^W2rUZS-{)^`iacP+0iSvFJwA*D}ULNMVZjK(C$ga%#tpx z)1)n;++3GTQMHwzabuf0=C9sysWwbcBQB@Gv`dAK>uTq$q@d+EY_sH|FB6QiC?eZ& z**YEWOpf!0j@k7ZZj_~STili8aTYBxB^y&ZSh&d9ifv6{M$s1TV>?rvESuqqeIvQH zpk}$LiKd=1t8FQNZ|<_YA=x<yH~z>@WKb_#YVa-KM`~E8iP80)RLkiB-UPWjD7Ck< zCTDtvv>=`OObxWq)ph8r-CHrlKRM=_Oh0a^oGsp8I|j8h7w-(C)OBliCYDU=PNUXp z${u{gG#}`0u}2X(Kh@G!xUsR(H#T-$F*9>BB`&ScD<i*WC$O4oDI4=bIjwj`NbihV z{Hogg-a%yrPvth#1RX^@wT%2w&Vr57a$B)M^9n7Ex=h>kOWh_1UW=2EMChRMK^9Z# zCF_C|4s=J&pl4Tv^H4n#Ag|`=NZ0e1*^wu*6Vb8&)SJJjd`+?MpN3zT&?QbTNvJw= zJsxMy)*>Z6o@~#YUT2`GXMMslHp*Ai!UcK{0XJlRIm^VzmaPI^64O+ai)S~F7ZPgc zP2WuBs_Q0RT}W$eXz87^OF5eq2RwhcLw0?d)9TQ?%DoWnHFGX)=a9|1WL(N^$q6la z=aR|`w6e1<ItSPst4+mP+Y+?ogvQTQmC>-l<yWm9T{PFW&<hw+WWuKCW3vO<<Z>qa zw}8KGhXT1kdq8RvZIs2RhL<6OX1I>494p-X5Df`!{dNas+RUb$rg(~G4XCe6D@SeZ zlpE~G9HG3tf)j$m+}?)MjT2L~G&D;m>v^V~s(u<_Qx#0c{#3%XYMlFXSG%yGr74gl zU(|zVzhtczXf&#=9B!3JC5?_;JMFd-@kIZ|MlFrB>wso7czt$mr#f=f+mxgy+yI^Y zoU;spv%Ff}+4L=utM6BEaZ6=h_Yh?oab4`9!wxpmQ@prl5JhAZpSv$fEYvfmxRo(9 zgs0Yx=AO3DL{oMt1l8GXYSi+K5<^q-lC6tqF$<WTVpWu<s`a%Jv<kj;t}D>e=4Z^B zG)Sj?ZAmKl^o|)BeCLkoIV5E|Wu|q(a2om3ip;hpm4UO>#AJP@OS;@OOQn^SvSx{! z8#Bk*n#F9(95nJIF;`AnA-l@lWl(;f2d@Vp6A+u)**E3lo6OWSTPL!Upk$uqp*U6T zyk?YjNc^}LjBKHIdJQbj**lqigPFwe<{NRT8%9~512<%JuylNO<!4T5+lY-YncI2H z+pZ|3*uD6M{g^Gmo78E$FSuFs%&@W!j?yOGQYX7PX+0nLzhbm}b0sss&zLcjkcTM9 zGBf2F*l6hFN?q22p~h@kt)T1Vva%Zq4Ao58C7rrjEjK1M>JZgr+_>e872M8Eosr^s zmek_<Hdo)!e2s{=vkk{hMQnhkA`(x>bA977ztlNHp=@xI&mIr!k2?SBLME=kNV{5$ zoVAUs5BhV9$7AEj$Qk42cd2_%4>bpE>D(>3Z3&vvCLx=~gk|!%D<MCX1@lxtQm;mq zI8kcRy3>xeDMs%-5ZA5o3Y*@L$&Jifdd^+W7MThf-7GzQucb;(t2Rnve;Gwso9VVg z>mH75fx-4WWXw>I-5{^occu|pC`3VF-}3ZnX5~8NGiTd(wsV(3Gd6Y}bIOiDst9=C z!5Mf{p>y>C?ds+pfvrxbqC!im-MUrX=*6DusL@}xmDbLKmOFptoNk<>@Z_x99G112 zke_+K8U>sd-*L1xyFnV4;7kM!(*RO|myLREs%%g#ZE;ldbl@-M<Jj}pY`H3TbIm%` zj@$NX@*>r5u8obixuIf*#i@4UX7C*6c<C8-m|OYl-+2@tGL+10Q<GQrxy;+ndR~l9 zwCBSX)3en{yGui*r%_r_?K-Wq)5%8K8<(KQILDOb+Mik;p^CkfbDvktBWncLgu2?? z?I=m<zLLTorA9H<I5$Q4G~GgZRu_71u|C#Teod;r1~<F)f9p3=>V?nUYd~FH=&e7Z z70R@$*R4_JRiVj7UhA1%dL$pE0_~syIQ4y8^T2aH-1iCXAn{%ondqVFj@ON5&LDBe zlDML8<`Et_s_EBu7C<FCBzMcYw_80^w^Ffht!a~GgqycXLi>4H6IUUnpZ7!az<^`g zZ(;K$vhwP|!a4=nxveR@l{~vs%&n53M#^6$kyBx9q$4kDa^0we=iL27@OG@&M6K*n zaSO<@gL6tMnmcfw;QdOrSBX~jxH+f#cq8>=S#$0ZqU@r*(o$LvQKhe$Wn)-s<`i7B zm%F33k~U&wCxj@w`Tc@ce!-|)sU=I+t7BF`T*~B+yj-I35*J=u%rPKk%WcMW79FzG zlCPX4-}>VeRhb+wr@6$qgHi9+(~%Cg{DiEt;lNP_$!z1XZ4NXP$aK`i3zSKCF2OsP zXj6I6_1Y?{c^PX?YX$j_*1wcwjnlN=n*75P4z!q?8a#@Eutiw;J=;Py^Pu%gq9xZL zrZJL<b!R5`mm!f!g(B7+Z=_RH8xNhogNP<zYJ-KDO*=e^&g)U!T<z(cO*BUgO)a2T z0k=^)yU4GpT10s&XL<S}KEG)Zo!G=nQz~;OzQ(q-#g|m`_WGQNFOS!xDi_PSOHOUd zEf}MP|FQ`{81+^t{{?*d4qI2~CArKyu4g^mx|<ZQORL<ZFvoqy$l|iP%iUJ!>3|T9 z!)$rmXgRhycV4cNUEz_f%W0>J>_o`vv=8@s#4hyh>;smT=B-I`2RBLFrZRSuoJA)U z?%W>sct<8cW*3RBZOaUz?PRn*N2&+3F_gt!lsnw`i}yIxw`P`u&`gS}qSVCa7madS zeO0-5aS&@xET)V;(_Riup=<YiNM?UR=$bV;bjoc+b@oEnPHDVn!mj6Jadm?SBd}=o z#!8?&-7I(Ab&mbe87VU-LijO~UyFUhrr57zs4b>CjL&wVz2tUkn+rsy&%v!nis}}s z$C}yB;O#rfeG4>Ld3c&}>vx;&FoX{3EAqk=+3XRqC)(A|Hk0U@41UDToboJ)n&2`6 z`0^HR?J3jbOqOR(HyEC#caHOJBG-<{syMEbb)v3Ai+bJ(4&+*PEVz+gS(9&GrF_L} zz2pE2D(5+G-*)@u`|C)Dx)8JtkQy?YkJ;!(dX?A7rIt1)Ji3_vqd~LV(nXycYLYlw zb8GvoF&)k@E2H?8R@C<6B+09E{9dAgwj*ZFYozB>>8$;e^waE8&gRryqp+Rkn4Kb_ z6KuGpC39n@666XklOKlZ2&j@%InnHDa~L~p^0+H+?=N*@$y7)sm%5yEI-&D0Pg?2u z8`OQOm2%D20@shqT9iX8$AUWhZqqtVBDTmv%?|7iWHzr*L`|A{%($^rW3eh)0z~}~ zK7@cbEm5%CSwM0^WcGLt?$5aLSWOd6RxHhKv1OMfY`neEop6K6;6rn1gXgw1B?i+B z*kH2yEJ`*v4{mH;Ja|z{+dQ{`{P2|9ta~`Ea!L)>&$U$1HYAz{(}dvQ#Z8Ta(^UNo zCP4L6nhuSqZJ}crYSV)k(X<~O%gGU<OM&SVCwD8IS;<)=r%&T8-paG)XAavOIWq5T z!7W{+xjrWgv0GiuQxVqB=yzDKB$3KYBWEk7(5V}?c)Rs%6ik0~8)XZ#31!-rDc$Uj zvo(4PPGu;@V@O$0+HsD$b4F#`dh~Ypg*3-ANLw0<_ToA^46}n5YVnpm*Y6TzOo-i; zjN355wDBy-)pjx4X|`ZnLm88b*J2qCL^d;gs)Iz~G&;=3Rp(w-g~4rzk-4Dy7RJQX zof9+87U(GF9NEJQQ+S|XP8DWlK*v;6(}dsxI!V<np@8<-n`5_H73KqZ_HdM&3oLf# z-F9~XBB$buN1H*{4j?c~$fwdlb;}p{Fym%EE?{n=(N)XbnQ+@O%eYElBSOgHRXJp3 zb9)38*#YX(Ofpddwb2GC>YGiZHYHQB4j8~KgdA?<CX=OmmHpif@VrbMR);!kj;nCp zsm)}z*qDVcw8}OWuFQBnq~Sc}#kr8|7<$6ULT?kBCt2Zkj8u}(`2-0%8C92oP?od9 zwCHd;J-LF-zBxzz7F6=&=sK>g<$Mjb4bz#CiPVC|wAp?dxi^wb)$#dGG#KDhA}B)q zMRwdX>!|5SncF9Grk*MtYTtG{(_*8Xy>oOXu@66-I|kXr-bk-smMmvhh}iOoA?`dt zmxvwL55!Y(ZN*+Y?Jyhfw~?Konzjg8%Xs*a*^j#L!j)z>{NohocAc%TO&PgSpY#}c z?!}OaHvh;xvES1wPdh+N<^o7KV>HT+L9JTevYlNwdFq*Uv^(RhpfsC7r+m;<G0mU2 ziN<2Lim=X|6-f;w4|=?Vr8)2Uy)|eq>BREP@w76q&SuomD#i5ztH?t%G^9g0YUsS` zbenV`ZJh0fNS1epX$8~KMzyWEGCiWG=!6{4gpo0wM+Fw>6pt5We+41eX1mtfa?hvQ zsPl<fRM@mmRWqVBp8V<nNzcsix_oZJ9pF-(=ELr3VY=Ig;^(oj){OIwE+~=d1!_TD zjh5REkKoa$JA#^aH<Zx1)A@gy*}bjT_i?eKYqec$cu8#=wzXyobn{Fqv-fPmY<VPO zVE5XB$RegwiL{WO`W4OYs6wjx+gTUe8g^Qjo^0V`zS(0rBi7Q~U4&HU*_KtZ?WE~w z1UFw&NEOk99rcYgd$s;zOX@>p?2axoy6$rB+B#ZVC${sP<{!?5;r+C3Rc$~g=_g$O z#d<HBsuTU?&vuYn${oTcNvVxmp$W+k`OSySu<%q9+4byXW;y9B+=MxFL9-e#MU$)S zXt$x8!EzQDx02Kyy-(*rx}%O=tI&ZxBHoqEXB=`mvw5<-jC!a%hboq$4s_YK7IK&K z6K|TAqbb>^xl?_$mA1oUrkg*MV+Y(4^|@qqq-B};gXhmmea^NXf8_+{J+Hh%^G_j1 z(?CIe_R3*a?aknc59)HbW650U$QokHWz9b|eYBmO#%h_S#M-?r+iL=wM@TI~IaObA zqdx5zkK_&(!YedccS=RZ9skGP$+dq(FOJyM!iY^Icp=mFx$6UHBehgjGzHV<&SlPK zsEyR>jd;uk_ko(-Ic55K4eD~Z<857|l35H+)j!X7Wa>pe)Qu~d%&sLKxI#`FA!|6P z8gdgsQH%V_%5oO@Wv1=vA=+y1P7xHvSRZ7M=$pw~na0Zr?ldCKvEEPs-TD|lQcl(a zxW<+1^hSEAPK~$fldTrPM4rh>d;9tl^SLI?7-aoE6%<^*-%ba*>aG+@`rPI`YqOAL zDe5sgWzcyrY@aPhK#r1T&)f7{bxR|iAT@DjbxSqB7l$^TWM8J@z9yT*o>!e3kvV3B z_q1}Nx_qAdqO8)AY*rt^86+L&1ZT<i_joe<&uFQ?o_(MR?4N<in|9?4MB6Swt+jW? za#J7&!%*Ned;fR{$m=xuI14|!iofNJSUEAn58HdWymK8WXVW{c#Dvyi#=Fn&I!KCo zGN_XMz@5M4cB9Fu3{*txldiI&w6u8lS|YAdsP-XaQ{#drmoE#d)Z`5+nG-BCgQB5w zt{=U{B~yOA^VB?J0xty6JTgRwh;Hwg%a;DILe7#fgNNqYPu|s0!+Gv#Ytyg&@s0wc zY|j0EKBdNgZ5S2O_HLvUyABu8#G>q}NUk%P-Q>mwU0RUD<%N!>q7=(}L6$pzgAZiO zES;7qY(9FCUfD)Zw9(>fuENYX;g;BCn;Om&TcXy<?p<)|vUVf4*oY3(&DQc}`5HA! zo&My#*-R{Mkucb4bF>_dHYUdEd956^cU!EY+ETL>YQ4xcazz;+?A;@r2b@ht-sM5l znoU9WHBeMbxKo+jPA%%%R%x3gDddi0(vnLHEqGaCW5ybJBpLR3QNqw6JQ(6di*<6V zXY2JMo=bPst*gjZIH6_$G2V-*Ei>V;_2*jLa3Zq`l@15yI+NZ|m87}xi1Bn-^t;gL z`y+YV7@aXMi@tTMYPNY)`<Xjz(-p{^wTZgifNW4wk~1}MIo0N_AD2DmNE2+hoiHQi z+f(O{jKVz4Mk}_&OsDfQtH@>dRpynoi#e>Cj_FU<CQ8fvGiY7!rLZMzwlcXg(8Fe} z4@ntG&WdndN=bKbE{Vr^9A}$tRk8-iT19@ThfI{|YeK1>=R&2Y8hs)+cts2!7)UGK zY;{StPX2V(wCP!jZb!Dx#&P^*2dkwe*{%GPewj&5S_CDLzlC>^=qwS%zJDZ$Wa^yN z>~2Y+<S1A7xPsx{QtM`@GmY7BtHD$@b0&hzC!4*RygH_tU-DVTB0~KaT_kO-=nx)T zu%modlRIF-B9AHxTI==c%@YUm)`Q%B#ivk(I)j}1C$r;)`iUH|?H}TVY-+Y0K&}kZ zsx<eu7)i!Vb>Uvvxv+&QOYuh7Oc>R8O|%@4*R^p`$;p-O04KM?E^qm6YDtQ==I~gM z8c&%|SP;^Q*m~ysfyFK(ZlM(tQu9(V;91E=9_`w$fexE|c1Ku>>BOyS*ZDw--pslf zO`@DF3t2m+Tcl`x&HkD0%7DzL!!>(Qko-gV_4rOcSwi13nt8%4Vc_v__I(CiFX#(E z_#g|JILh{yW{?p;Yli4N$IX+g*V<*-wf9z%vdpBd?Q7T)h0fnY;i^|V?~=}C@y9S; zOOw)#BTjrMt!*F+jI2b-)Zn_`Dzn&`R_ry=t1##v?YV4?4Cag$Q48AWbpw<@dQ@Y_ zEw;!%FN*6QT^CH}!N>+*IvrSQ(2S*b%i5Fu84fb3yM%C?wA9&l&c@lnadxJgtYo5A zAy$`ap*Q+A*Xf%oGi6NbV_x*+jzn~3#Zi3rvGfHyDtB-^NT-9#B+eJm(%TvQ7K&tw z%whUQJ!(~QcJ1e`=;oapEWy&W04Z}KO=gf2EY29k$;A#zUECmK>s@kMIVlW0c57&& zH>|nSCv%LW-l{O(WS%`vNP|2qd*bR?G8WR}d|HM~FZuHh-gFft*RNK{(fG_h%~%Ym z>QB;$#8uaM(^jQr{(-hE%2P9*NyW9}pJId#m6WB<BDFK_s4gzp?JP*VtUwPFr}oHd z){b3{E;SIJZk#)aDD}>)rcm-4Tn;N83B?1}Sep0#Y-~b~?E0CRH5USE!PF8>eKDCn z*)r8n&Kx(r4O6<s?KVME?}&{f8ZXw~Z`q2O%q5wrB;9&j;0eQ28nSDn$^zR7$tU*O zt6ri8_HHwa46Qb@LcvxD^5H*pQkHwMCwKMPYDz19lXR#l9hk!;WEIe-JzT;CzMr;# z)W(rJ@Ng%uQ96+Ih<B(^8&a33FXoa)opBm%rsEB{->BHhIUuomI$xc>k=3qavuDoE z0B$ogHEwo63%B;%sQPbu58E%!ZNBRdd!~vCdB>g$1aHBq<q1h!j!OqYjN-m!EKN&L zX@x%>13^ahwg&o3#A)3^gX{xw-?+E#y~8Wh#qu`(y9qgZRi$nGpI#l~1Nr=SR&oVr zTZQ=`cRjF7k1-?bXvhYaj@V5Q)MvIRSI6wcd-B`dMBKePlYN={wtx=J1~3cIas3#Y z*Qkk6N+;|2rNTS`<-g8{HvBZYVThJ)wz}%cgfcqeQkJPs-SCpX+X=9NJCm4+_cB|W zjHg+*i8=2kPFJ`N9WBny9AoT1!QO)9+TJXvy$mMEq#(`qPpq0s<=piZGfTO+)|6EH z<P#;biHWD0`Lq%@wM$m*x}+Qp;4B@Vc%F@PFAN&8yR-eaexqw8ywmjD@fG||EBCI6 zka;dTR--}2204AvQkbaE?;e(VQ%}@8qz(r4!ki(!<NDdzV|ZzcfgK@0O`~^isyDc! z(YhTKYKGCwAXs05LleH6%+I7T<yPV72~Ztvp~<Xr-^f%b4U}jd0l)u4PHv%1{O$-& z-p$TgI-=ttub8T&vvPO|pgg2A$nEVomzHFYkkP?MiaNG*76qM!L2I|TwJb0L%MwoA zxd5;9$vwHHbVSIO|H>MwXL#nE*HrMKE$sAIdwBzotlT+1Za5~zU&mKNWwxIUVqy*O zCe>ic3|XhS_NbyB^+w*n>vxOMSle-9Q8w^tzu$EcBG28fNzqI;&v0`NmqCb5X=nNv zTez>yC%&5<motgk_CH0delThL_>sl^=>64)74Y)vz+L;wE$DK_jHxq&E{k{WS;VAh zpB;K`v${(V97JFEkFQGl>&73(_S$)Q*GavKPu;H9&SQIRQ@MQ*^kz;M>2Yd$I5nbW zXX3^DBV9YlE$B!0v-ERsa>wbNc1gG8J*KVbzN)CISIMPayEbmuYn!p#JNIu^**&`Z zewf~COwrOJ@x|Ef*$)@0++KWl{;ck`4SnP=yv>ZRY4n#9jzl&b!|AujS%|JC{%2gT zomX|8+^hE`MPqvvujn?hSHI=mt9p%T*sfPU0%LpiCV_Fzn=XvoP+0hK{y1hux8>c* zkE^;~Qq;B51%~wxRGCkrf9@vq7nA-=HX$>aWbROztLQU_@v^StdiB1vXk4%2Ro%w* z>UT-^3B5{I^cdS~`0}2Udd=uMZM$B>$Mz~2+p8Z*kYpy%CG_}&uB;>omeZe$SNipm zt`mCoUQtxpt9W_0t`oNF)tl0yQnHH6D<%5ObbfF`ui{fAse^&^^-KEO@pPAbv7*QF zo~QL%-Q}{bmlmz+c1icHUnlWNl<k6I`a4VIPo~eAyjf?tA_&-zZ>Y@0^f}azQ*-?| zgXH#gc{m7O+BW-)#?$0XJW;G@JRRL@UDu*Vx`oCR7m;8L{k5vj3JV*>)ha4WmcJ;5 zms8xY=~6Vb3uUqKUKShAI)Xu|B~A3sU%JyG3wNJupV|_Q@j<k2I2{afwuV79sT6%o z)GVM;PE8GMYz_uF89~YB`j#BfNNX1qu$DnonMN(XoxrDB3~H#Qb)#+*0Szzt#dxCL z9v*Hj6}_gJ`)u-1#+R(W<C>1mI(TnTTMNe+$7$)HQVj;JVx$%An+Q?~$3sq#BBLx{ zw8KKrQzaWeN@inz&W@TxQVcpVl(f9gBTTTwl7GT%e=+MPIn)k(o4ZohypSKixk=## zt8mfrWtCyQBF@g0v|>>_rnx6}(yXe;5>rXClF3M{dZS`ojI*-GZI&#SId(QzU)A(5 z8P98BKj*4IFJ)sk%(<vk*l3JwOeHxVngc=|kCgO6ym56>Thb^)qf)-NE~t@rfJ*#k zAY0xnUkIeF@bsd|TxLil*zz`r&uHPztAl9wU}6w;;tr?5290b)e_}3MFX)xT8>^Hn zxFdQ}Uiwa8KFBRj&3`-_(N2ujhelcE*PLRVeR_PwMhglzUG2HL^az4oLKKWqX8p?3 z=sWkZTpRD*`$RlHHRSmb-gBmBM8xwa==0pi<cr-uj{fX9yGK1ghh+KkpPx(L?K!)T ziEy7~`SQa*ioV-(cApdReA+#o`}~n1&qw)xnLh9Pe}2gGOC#LBFy#58LY|Lue|5<7 z3pV5Vt3#f@WHX*$6Y~5qoALb3A<tKD#`AZCJilr)o?jdC{H2@m{JN0mPv4B^9}Rh) z)70{<-J{a~>5%6y-;C#92zkC`GoD``^8A&X@%$Sh&wn}O`C?)`WTRq~b8XOXuhAIA zzjpS&(C2;V&*IYm=}{eQJ*|~1*I#?k-!>}LTknU^o!!^ri_#!?VY|%7oDb;MK>C$+ z;`8hE`QbVqH6_LNLGPt>2NCy+J%5NB9AzIu*$ENP_xOT5bMLL$XZaI8@7GDb<kjDj zf#rog<q3|zz3C6*Z+3`I*7Lx_{BIE4xtrYWUvz&4{eW@Gvc<Pcj9UD$`)t!e_v?wV z&K}}j`XpEDb8=_fj(=hPiPMi^?w{~Iaet0J%<k_`f9O8fsq8*DAFNgPZ46H$?n1Y2 zBpT-bF)xbz4sy%<i~j#Q{en7Kc&+-sM4x2;_n|-Z|Idkqxj#eQXB(D(q5BWfk74e= zq3*BKhuQrD=?~pMj`Xt=Wh!U4xi875GH~C%+WmC;z@H_x?CBs_^IQ3B?%6N+JwXqL z`TyoSM5EOc?0>E+?0Mr0)qTu=cc}Z$UT2Qe9pi6)g!}8%{mJ?)yWfxg(EYDQxc{`e z&o)8-LifKE;r=#vO86J+!|Z;4`a}1B8sUEN@8m&ehf^JVL-!wyaDQ2d`&QSo9*h5J zRPabeUin|A?k{Iy??U${)AM2J|Gv6^vp&n=A4Go`{>2gQ&v;oLbap`1!8de272*Dx zyCnYS=(Fs83H_n_*GIU&M%`yyqkp0MUyE=*xLe$RL2j=9&t(+d|8Io*!FqA^WZ!Z6 zjPCy{!u=P%FAn?pZwNh)?jJ;AVd+0-y*SKvQU5~s51{A6(tpN%;{G~)nB#va{h|BE zM7Y0Uy*$V^R{uixkB)GE=e6Sg)jj2Dc7Hhiq5EG__q#$mKmDdWXXQk`<;VYJ5$@mo zptwI-A7uAO(jU72K!p1n)ct+TVZCGc{~Ymr@mumhF+7jo{}AE-4I%#L@gMqsH%ffY zKNx>w3Ut30Js*~ThOf(yKkjRx`@<sKpQG+?D*ehL++P;r{@4)rkBe}BnYs_%x4iOu zM#S@L3XH!65&nNP#QzgQ{Qs>8_tzB|f7eI2zw<-+={GUN{U;*aU$5?OD*t~F@w`py z6_cC(RqTJE&+kU~|AY|#SCKsCzXNIBF)aTVzby`7dByMh+q@<CYmK^JqMYlGDfEZ# zPmXZEMBU$1|EW!%2j_z-eg31HbAREm`d3qg|DRU>-%%+~u>ZL&NB^G};r^sA%X4qj z@BW4EpB>@;vYzswm49}B2K}M?S4FsAeyzAPg7Sxdq5D@vxPNts`!hq_zcs@B#&3vA z8+^y<GrIrn2>0($_h;w>9R67$?yrk*|CBZI;Oc(49zgdWh;TpHmVTgX#tHH~yMG-0 zVf;U-?pr<=X_}LNR9u>|+KAlEeY?LH@%*S0r9tODr+?XVcK?Gu@5}J#)Af1e_MGv5 z>+{fk2wL@d9fp{ACj188q30osxu0gl=?A)=R>d5D+!w_7WAlvEwDiHdicggX*Y@xr zeMJBBcl0|y@xqxx`}N{)K@g+Asq}~LbN4LF{a~d${}Z+2keIvBedBm%xo*KfK1R;p zi<~7Y|Cgd*&wS|Qtrp1rxhTNeQGPFSmYQ5y{#N8HC}Dj6eCXthBY2+(eqaPYIFEC* zcJ<<c*T3+^Hl{9_(OovZ4^zG~3(;jU!gVt1Db{}Sh3;1=tE|V$rOETW0L!n|d}Z=y z5oh^1`n=t*rSDF^%Dc5K#BQWNmS0DAzD)m5=(E$W;W7P>5oh`Jbm!{?xdnfqyVI}o zrk{T<aux>_^lnAY65s*-SmZ|NVSHddBvRx?wD~_3WnwM&x1u~Njr?8|@W?FxDsm&H zFg`pV5-D;cjQpR9f>HU<$#aiB|0)W&r=5Ql1!MCek)mLH1fLMWCr0qe5uAHo`B#za z5ruKI+K5b%>w$#H&&Y>FiUMx2^RFV;l7?|^;qtGdOm5BnttdDt7wESlSJUVJR1}<; z4~Y~}$q2iOsAPm)Mf612RTSD1v3@OF@K90Stb+&?1zMTp$!`P1<hd2ezls8AJXEA8 z*gjvFNKt0CGxz7BV8>jb---fl+~C)uU?(8*wJ2}&W?Uyp;HjcuS0E;jqeA1m=gG4f z!0K%O#}DXBUuRJlTB$$oMOh(Ceh~3KLAJaXtNgSG`Bvg#`g!eVUuOvy1v{voo1Ok_ zy<z&<J{jhpmm~DN=lFrDmD&aR&eu7VmBaL$AHlDP;J=RGuSf8|MsT*<h52WDDq3Ou zzzALv!6!%X*%5qh1aBkW*K6;r$FtJ${t~(Luhp2}iO}<S1b@rv$+nMXuTD~@wy)Pd zE?1W>BHky+whP6|ZzdiVZ!bjf{}K<=zYkSaeZBUV`!{@zAl@g)wj;%kQa>j`KJ7SL zY~?aL@K1<``SY(4d>`ufgvlR8ypPvjTmR>@2>E3Z{IUrCR0QuvRdZjjzrkY)zWO@O z7FxM3*84cev;7UT$DTzzEL?X-@TVg9#}WERP*brh^)v6F-}&Nov3!jt9_DUs1YZ@w zuZrNWMeu(_@Q)*SKWfs#{8<&j;}Lu%@jhPv&Fo>fI6hV)h5ohtv(EAH8E!4j^AY;r zb@CH4@}_4uYI^$wlQZ1hEh8Qlu31i=EmU%u%=`%XtDL;mIzeV6b`SAlQ{vzG1#5$9 zTWRYLymXDvQJPBI!IHF1SWZ&aok3H}%4iu{Grfll4xXi5a<O!6eXN96y_s-n1-x9y zq)Kz7hT<W#CRUasHmrI{Go8iQGK*IIRl9c;nOwOqHzM8Anyj5l`*7{&Awg_*GwtoE zqis&91)Esc$BV7$h~~wMWArwk6u)nV4ylhV<Z#WxwV2scW67z!#eDukT(@SIMRHd3 zWuKo=8nK+vd52xjUn!dJqQCZ=e#J-3kq%o5P21fvyEx^gUzr_2*<HukH?W`7yhyec zr^c7^?kV0yL??NU$nNiv?U8g032mFLi8u18yfys7&M>tlv6;O8DptEV&aVPbHuJmN zYk8YeUE>T+Q~seXp>K<D-)LWIMu?Zk+l#S=R8g)cKk-v=5DExMlsaYEw}@49cxcl! z1<Adxo06hBWs#qkD7-#;V>v^Ax0g!s#%_07EAMx<J*zJJ*=c&52zG#j?}d)q{k!P} z@Oi<@E@jn%kyo^`5*)UiBu_TeYiW4-ZbVLSv6;KBwzMRxFT5yvziUy9SelzDkm0|F zRRp$Z-V{gF0iR^CKF2HuHCwCTS=Jj7EiIu9c6yMcWXO=cpy{bC4YRm*P4RmCO)SBe zpQAlTF%_#@LhHKeK$_Y(zfx<XVWG_dTt(2iGxYz=DRc%v?w-zwi091%*+*yaW8Puk z5f8at7NO<R%O;!neG{7*!UCIBp6g?+)+NrZaV@8&bp)lE><N+Ia*7EZ^|9$<l9LrZ z_o@EEjOF>ly_hv51Z9%-NDrNRE%hgzbheRPH;e)>-Od){qZ{SzE)<TTbcQW0)lbBm zbd!8lEm1gHu5u=^ayc(XrK@JeW|hzzy@tkSOsOu9xkGNNTgqvhGoSxX6>&>NJ-sJ& zu2#C3J+o0jyTDyPM+9kadgg2aI(}+e%pFNUUZa!uxcU|!yS9bi6~nDcD$U&0YuxlK zj@Kj?mX^_x@2MocIgZ}k>W<ha4fQRY3pct=#T6xNIP|GdOj~1eLuQG`F5$kJY?wnm z0zc=e_Ul%sAWuT;KldYdp|bJ8hYm+XMxOt<P*&2}zjG;5a0F9dpiw%rI*f6aEgHgR zF6%Gz?>yJ@;m30Enp?i8TkPgw+!y+X?fiT(_w^j$sPH-ZnQsT_XVxF5Khr-*IqNZ7 z4x@69vwriRjRaXw4gHy(ah^QuVSRi}l3T`~HoiDkIqI?TsQJfcbmoAbV*TErchsZN zofmH@PY*w1^B#*mJ%0S0=gD)p`snuyJkIe`qTesqJNoBZPoDKydaUs{>#_L#j&js< zk0;N1`sw%kJ<fW@==XJcM?F7N&hZ@6&wP7aKQrfNY@X*=%9;7`^IPSXUKS7QJ<k4_ zqu<}uJNoBc<)+6h5p3t=i#h9=%U|d!>LPd4v!im;bA*TmyLz1Uv?|{>LeC+dJje4m zl^@`7)?@jmB0|qmo;>TZ5%mO*vz}%2$Jg`-JtuhbtcUlK@O7%kS<i)z20=rF9$qiY zm&FgSKj(|r;qqniyjs2n%Odow^yJw;r>gvA9%uhtt(@1{@`dSjqbJXLYMfLMusxYC z^UoUhEeP(4(DOr2p7kVE{vnUEe{NR(ScIP6c=D`=_k8g6lE+!k9gYUUpCa`9&68(6 zi&Xxf9%nskmH#I~&&Qs;UruekG{+CeX))RR_}ZSo(8aen{aO9IhjL5zr7T3(-X3TF ztYb*mL7tu(`fhp#dGZ{t^I4d#a*wl~M;#4<BO~-o^5j{M*&C;Nob^1dda5JzoZ!j( z@e}hne_T!WS-$E#J%0Q&d-Cj`FFWZV;Pu6PSw39vz6HVAo}L<F7C#qw@~p?|{YyN~ z;d(>$d?iB98c&|}tWo)IdYtuaQ2xCLJ@<R^tmj)Q|6`A{p7)hM8lmSIPoDMMs`Af! zob?2nUtf*T^Oh&idhSv^8$8Z>woyI*iO|!H<{kL5{A}fDTaUAzomJ0n%2{0v{aJeL z=gG5wenfwK_4PRGv3aP05qgGt@~r1!RzlYi9%ntp>YvI8J-i;8FALWr@->*{an{pM z^_&)=hv$R%GChyW*PzMctfxfvq$Bh!@#OvTwanujr^Q;n&iC}hiCa8htDI+U+1;J# zkFOgd_`RN<T9Pw8JP*Z}=~?f-1;Mis{PhSu?|FPG=`j7g9+)rFzs`N5`J)IvRXN8& zE&Z9E29TeldYU8n`4M`a2Kf@z^LzyVTZEp2G<`Tfd_{Het<2;6=y1&s)0J~P)U%*o z$9tUR*DF6uImZL{$t@nP1^q9m{5>A`{qvZo-*@-d9%pygsh*xa<O8~Ukn+6ndfeAD zU3p%3J<jrT)ZMd`qr2CF{>dtTkH>Su>*=poS-$<+<Ls`bd(WOCgzgSd&f#VGej*l3 z@VM{p$;vUjbslFuR!*-{j_&e&A756_ta0Ch;0aH@hM47tmpp!+$6xdKe2;JN_;QcG zubkceBK_IbWgGd#{yd-l%-sr)ukiSh9>2ijQ<Yn|to}dIllQ}Qy2qD!dd^Ue@qD2t zf1xLTjVFIPaf|;4Jo$N^{4*Y(>+zR7-stf^Dd%wc`K=qx1M<c3b`kwqyzS@ll^*B$ zO}<#(ulGtk?$@isBlwZZ**|{%Ji(K1px?|t36J~XTH<j(9=_u7CQr|G%F*2)dh))z zk9*t?uNG66|Fw!DSF*Mg*3YZ^u2MtJF8m{1#_t&8zGhZ(8c)s=ewf^xJlkaMI8?yl z9`C82`DQB?OwSD~<;SB`#&~N&zy#o{)t|>A*LK0iL#AhtW>6b17(aiZDCo}_gf8Q} zj)yNh=gWBi6NOI!`SAw}pACFKh46ad$$f;Uft&o5z>n1M-U9q9$BQ28SDQbJW(&U; z<X_kLc?kG}hlu<mz)N+>@RPu&=>i>Ir^J`JJK!Ms{u1!@!-T&E{F#e{{{#5#3xxk0 z_^Z{z{|9^z&45Kk^1JzGMq0l6{cX<YV>ILJ1oGp)Ao6<v|DVREovCK}-#Sy|dEFFW z#&@|yzV`<{Ul;n60{@pb4#R=(rv>pS;E#_G{S$$IP4oG5;BTnA#{sY0QS_V&JgJ4X z4)~%SM1CId)}g|!e{S(GT;=_KILAM)v*Bw6=$WYUmjLfSMdYsl-n~)y)xdwQ6~Nbl z?^Po5HvvDXS@><hyX#WK`+?8DP~>&{VJ6*|X}SIx$lrLn$Ug>rUZwC~0souU<1YdK z`EZf9@q)$k`bomy26=aI2L1F7@c(JKejoS~T28xk6Md$Ce=T3z1K(+?$n6gNs}~4A z5cu+4g_i?2J(Gc7qv?J*@VhntUj@8a_1^$|pZVf0uixX#!u3n;q|o&s@c-$O=U)Q< zk=9qg0={1PTfj$XyYN2nAF6*o0)G8+@z2ZM<!=7`vF58k0zbY+<o*JDoK7J89rzx- zME*VC-L)P3FYuw`MZUXsAk05^tNa&$?>AQD4+MUemX{LXhn^zxqk+$F6<!^|+kh|K zUgVbmuh#nW65tI7iTn+~AHPia&A>OPVf1$3&(@2)KW^gstwQUKAAtN$agkpKe5Cd( zehz$(^F{t~;0JIgk*;TeKd0s51>jxJ5cyYtPtx>$4S185-!58DTe@rZ3HAp*RNLzc z;DfcDo(6mtPae``?TqQ4e2MTh$XmHP6L?Xn$X^NkY%P!90p7T$$lH2NbNAPpE)RhG ziHC^%&w<Z8NBHBwM-CGHJn)qj!e0jdy5_4lfS;!w=l6iG<Us>n2W}&G^Z#FYV-sD6 z0iSxT@WH@s0;UQ0TStq$jr&ahylKL(2l;as3;#Co{f`lT8}K2T-yQ{i<i#TYN8q!y z9{3;dy(WshjR(!2eYM<ezpeakeC?(3eOKUJmI&Vq_|DpIECzm}8W#rv7cDfu0Q?u) zU!4fNe5E{54g91&!sh@#fCp7{H32{WP~m3)kLy6{0^pUWi~N^>U#9u<df=xVCi1rf zf26<g2Y`Q|TeyA!{NR2f&+B{nvUHh#pnSLUzl<-}{`NmX{;%5JbzwoeOn%l1`MwkI zBWi{32mBq4&jG+^&lLF)z^`f+J_-2veTB~k{`YahYk|KwQaG<S=8JFKUQ`a?Z?t~| z_?RxjR{@`-{952PFMA8{*(!e@@Kcok40v4Y$!CH8Wq0w<AAldM;r%P{lQmsF0KQ?R z=;^NQHvi1=FjMQ9U4SpSK;-uWezEd_zz^2)egyCXwB4Ty{Jb%u|9Ift_Yz(Ud>5^M zT7dsh<Ka@^)3m*~68N2~MF01IAENE)Bfx*tOXObzUbU0(UOIlV_#AVx@ZEv$sqU5n zpQ`*s;HT~;dKLnod!g_z0bj52d>8PKj~4k~0>41>;S0bw3>10W8fW3U;ful#-BIqw z|2;{*9}WD+TCNuX|FZU%z65-h_Wy4MK6|q0e+u~HYB%^R@P2*Of0}OQ&z_eEF9Uv) zrq?XsKb<1-X98cQ@p&Ea34=ub2f%kdSNQY5x9KnZW8i-(6TXk;FZ2J6qlFIxeqyok zYT);3xo81?thQ4Z1OJQ0^CQ6jp>~F6fe+FA`Fr3`=(y=E;P+RHKmQH<E-mjxYDcl~ zo}>Mcoq%^wiJpCccRN7%p};5Uc&8lrL(4?|DBzE3IiCi6xt5Cr@C(O?o)y5iJ4X1o zf&W3v#iPKl)bxE1_->k?chPZ`#m~RnME_vmx2gOQz&}#?6M>&wDSBeSC&z@J3w%e7 z{~LjiJ6hy_2E0Q1C$9r9(Q)oaz~9w+*z5`x-o@H)9Ji~uWBkp8e6IukEzQp>fDc$H z^4|b{&Edk=0<YHk>c_y()$;WM@Fm(#{T}$3OGW<&z^_*O(#ODGUncT<X*sj-{!{y( z#lW{O5&4n8hqVeH3;f}Oh0g*0NA1rq1%AG^6JG=#*L?de;G?zNJqz6IGp_)DyIK76 zCh%YO6TSiXb@jrx*Zz^k&$s&v?+^UcVZtW>U!v(a1^C1xME-Q(+pQ8lANafK&lSKQ zsT28Cz;8QU_^rU#YW;IJ@ZGfE`wZ|OX}Ne2_yDa}-v@5-`7!Xsnc|=Q_mI2A=QSFi z2Lqp_?b=A-JI$Bp#{y4XEc`g&hs_gyD)9cQe<|>9X?uAQ@ZG129-F5!|3BAN_&p%s zTkD;-fgh&jCD8tb=`p?+@W1JJsvP*uW5nGNz$-Movw)lYNx;w6dUyfwM5*XM6Zn3b z&#wjkuQHLp9(Y@o@E-yHaDnij0KZ)G^NYauTPE_q2R`Fy;r|8xX1VY#I_|M}?zLR_ z6yS$06CR7;i-A9_{mE|tzhWEF^IhPFbQgXf@Q<~A{t57FibVb?;D6Ts@Na=1q4n3F zfft=Gdj1Lg(8Gj(4E%`};qK*C^wHu?vwzULxBPDWqhsa!!N8j?5?%)UhCafN0)C>_ z=Tm`C*8cN}z~3Drdg_7SH(YoM_(NlaF9ZI(wnwXgcUvj)*8s24`2RNWS(<O}0Y2&w z(en`S4f_2_;Jv4b{L8>^({l6y@SSQzetWHtEnU`YzvT<SFFIP}`vCuIoA80azo-4} zNx-LQy*3kgcdb{`z{|D$IuH2oW{JD2fv?bb_zLj-wSBw}__f*(yb1WD8m<R`oBYGT zKhSpS72u^>AHD|sD6P*w1b*XS30KkHa<_E(aE^T68@Tzq5AYFMPKN{ki;hQ*0=~D# z|4iT`wS7Mk_^27;pEH2(yGZ!Cz`JO@dL!^RwcYs+@L!!FdL9FQx#q)XfKSnU`#0db zYI%PTc%}Mt7tN;@&kt3LyS;&bQ`2_{@Mkn19s&G`nWE=-;6F|YKMnXf>Yp=!oBX-J zOSN2I2i)Xu0$#bTxVsLx$v*=8Y7r0q2>dW@FWv+`U+oy(HNRMVKBoPm9e`i1<!cb| zb!Uph6~L=|3ZD#o_yFO@0Dp0~@RNZz>Nuq}g0GC=H%9QENASNz@Ll#3e_8yPe+EbJ znZWn$A<s7fe?sFe4ZQj?k-rSM$$tg-UQ<N=PT(fL7WlWdUVRq$(OOPl0=}=7iw(d{ z{@=j6YX@TY{d42(-)i@;bx9VVwr+0{$e*!To}Uif`YUz7O@1Emv$fxIF7STZZ@&=u zES3K{aFhQg@M$`peE|3#yNdrG20mBowHJWfc<}eYzh5hQ-UDv^>JNe6I!xqu)po<; zdAg?KUcej96Zs0@CO-=Jj%SN}HSqlh2|o$=lC<zv;IAGbd=c=&wZCyG@C&Aj{Fi~x z*LwKdzz@*=?d`xPXuAIt_@BFp{>Om-wNd!%z)k+Iz<<|8<a-s%-QxeG5%PU7aI@<j z4Sd^^MgCae-L<?o0yp^-@ZV_rcqwp`|1$6sE(qLp2k>3h-TQ#|+(+b}0dDdy0)JlX zy^nyKe0Lo;SiBu^j_5xaxXBL$euKvIB;Y1L9r%w&iT-BbS7^Jl0Qf)WiTowN%^q?E z@EJRa{B6KZ{vO~DYJPqZxXG^veuCCBbm*45EZ$7MC-6r!KlcT0@`nL`O#5S1z^j&v zdozHat9Hxzz)gNJ@Q<2B&(*+9{u{vG)Ar>Tz)k*X;H?@z?*TXY4}t$i>w$d_%#BZz zKM?qxr-|HT;3j_z@KdyYYXQEu`g0-hA8UR772qa+9q>Nd?^+Ao<R1k7xQ=Ik5B&Zy z60X;QuhDv7`-5`h$K-bf{%pC(jRkJ<lY!q_Eb?u@O@0aRQQE$I9k|JV6ZncHqW>x2 zCjT7p<JErkU*IO+^<dFw<?j2M{|5p$`EuZ0YUTM8fSY^__yg*ni-4Q_YTygi-#-9u z@(%%T*8ap>z)k)g;75!U|L?2z4~qwrKM?rEnqJd@->dm*7Vsy!i~e(fuh({J1@N8w zi~OCyFVuG7KH#sFi2U=w%^v;=@P~>;zDU~#3-6;dg>MJ^m9vER0sc-m;r)Q$sQsML z!2iBn<ST*iqWzqcfuD7*$kzb>kCw;9z-@lv9N<rk5j{5nH~H@Z-;pDPuE&6z{4>D! z+DGKy0dDdi03Uah$nT|gCX4@NTCR(MAFBP*F~CiJ67cV7``8HF<Ws<>>?Z!X61d4< z1AK(0;}3v;Rqfgj0q@mS^uG$+<lg}PBQ1|Rsy)f#$K-bhe(_|{KLohR9|3%qBSijW z;I#?iHNdw$TKIXuP5vU_?++FE+ku<>y}(!QCGx)kZt}kazTNI3{~_>kdkQb=FL#T# zcQk$u1a9*Ef%m;Yo<9b-$sY%NrPiklft&o<z>}jz|8>CM(0cMF;Ja!4^Hbm^{}}KZ z?XPYCZu0*I{tYd6dk)BrH<RBV_?NZ6G#dDu$IA1zo^Ct(%3aUvjuxH(d7E!-1U^Xp zcL8vdzZCc)ji0-LoBR)echP+Q7vLtp0r<lj-t7lUI4oQyzbo+nsGWHjaFZVmeAQIZ z`wie9Y5x8$@Oe9k{C&WGqxJ9$z)x2_uK_<t%f&muzpzsD2Z!f|*X({hfOl&Wxm|#N zSNkD*0-x7K<PQh_QG@Vu;AiUiq6+w3agjd;_!Zi}iUYqz%V`7fgEW6G0ls#y=syQ| z@+9G30sf};AHD|sk8?!+F5qX35xy4qgWC#!0r;P_Uj04r+ch0O0&eNuP1{e)w+Cx~ zV;|t9I=|2t_>(o_pAo=ss1kk@@B_7fI2-tkQ$+q0;KQ_heFOM6dyD*cf$w^x@b3dZ zCMNu0;NQ~z-;=<9%as#dF9F{{)A4oS({z0IHt@&4D0;eRezABq`JTXMX@6i};Kdr= zzQFs}iT+{0P5wyWPmU7#81P=||0dv<?=12QfxmLH@Uws)tnKxAz>nHd<Szq0b6??K z2L7wlg<lVR?-PaJ2E6w?;r9bSO8dh<1O9-Hd!GTmMEhxP0smOj^<ThuQ+K=RIK$HS zVl9um0$<T6{wxMQdW`Tvz`v;aM*&}?>3%fuZ?=h^df*526W$2?9&MM;06t9nOBVs} zqI#|d-lFyMw}IDd`hFjH{~qF>b-*89D*QR%wtxA}2yXk0EdEV?zf#eMd`twd1%A2a zhqHm({L6CS4~uib*MT3T<A|Gpm!B#R`~dhLG#%FgFP|pzzXje;`K!P`(0=2Gz^xxp zRF)e*$6PAkdjtQPmiGgIZ_s+RKX8lxiNJra`F|SlRjuOgY~W96y>|-mzFI%j0l!+y z%RJzHHQ$^I{9$dsE(E?!h4|++;2)nS{GY&WUu}`rH<sTlpKJ$woaXZxz;AC8{l^1u z)^fKBxb^F<1wK&wIky0RL*wl};8WBN`7_}6Yrn|sd={>!wV(C}ke{dR`#*sHP3`=y z(@#M(Jy-RS@b0ATt?^MSh3^mi>TQG{4t%!uZ;u3Cul3{v;3KvFc|7nH7mEJVfKSl) zpAX#X)ypIJoe}(T;MRV;0o?Q#X@0c$$>b~Gf6?}-FYt;>BwU99-&g1R#sL3dipWm_ zUa#p@2i(pJm<N2j;iBh4;4f=G*7mnqxNe;!^0$Kg&($t;H}G%jc>HPL?`uEmdEo!q zUGz`T_SxKBIYam{zz1r5SP%R)&Cllnw{=Kg2fk>s=)V{E6Mcn04}6|}{{wKF*RlN; z=Km`7XQ1WS`0sW6wiEFElH%_Ez)P12KOFeFdf}sh@2&N-)gR{WvzqQFf&6Y-56=ZY z_+rt&5covR&o=;nOY7fTfLp)tUf|2LeS8S`2jj$DJ72;4|832OgEbt+SI-vt3gEM} ze>)%e56%?%Gl1I*OTGg9KZlC^H-MY`1Hkvtbo?oBlYbfbIV(hew-Iu;aP517eBT#% z?QX({0H3RTD)1)db-<@wCVFlIzGSBGp8<bg>*qfJKSuir9|KqQK_9h`TDaD#p7FpZ zYd)+8{;sB18u%X%5Px0>y#EoxZvuXl@}B{()pqlB;D28tdOiYv|6an2RiB0H1?@*2 z3H-XzB7YL_e`)@21OC3&pH~8ZQTrkH058?=PXphedfozltNQ=nz?W&e{1I@=2ixj6 z)xx{K*0(zW|GVbz{ed5%?aRTyPd!QE=S<)~*ZS>`z!x4S@_z$9TkDZ`fnTfjgS{%x z{69eR>)vXgFusSzTOZ(0XnWBQ_~R+@&tTwPwVfLZ{3j=i{E@&9)%ctY+{Uxb!2cW* zJ!#+xZ8ui}xAlUnfnTtb=(z!S<tpJf1MjEy*vEk%to@T$fG^xz^!y2U{1D-P2Y$T9 z!+XF#o+R>tmM2TEznmhx2k@_I`P~Kh-rBzJ3H*`$M9+S}$7_B*5crOoe+~nFt@6RZ z7i&FI0erZYw<Cbxr}^0S7g~6C(R8^T<c<Fj`0_7ExE=;RT>beLaMSYvaMSZK@Golr zt>01Nj`{Oh?I$b-Zu+l`;I~KcUqtXfMevU!_?R)d{<Qs;Q-SYxp2#JE*G?Cn27cnc z!p{J1_OxZdYqXxZ7<ltOqUUnpM{7FX2>j$7ME(}wKiXdS_kd5<cIPqRM{B+MB5(`W zUn6*rv4OiR-G8g)ZU^A&)t`NV@2m0I5BOg-pPvZa_H#8w@D;#qpVu1TH*0vl1-zg3 z&mRJA@{a&NUF(fM0JnW!ZvelqO5$sqak=qk`@DJqZ%&F_f8e$rwFLNF9d}FwzTYy@ zGZpxodkCM4yj*xQ@HY+;{tMuTE))K81pgOs+vm0OczMq9kDa?U9=N6Z@e#ZgxTX6_ z;FgZ7f!nz}-vw^+cLM*%MDh3Iz%AXM0sgYqo9_U(bblZCG1~v%eL`;hSi0{G{MTAP zlmNGM9}4_zEq614+y1^2fS=tU{<s_Xq059n62aF4w{+jTGB;di_dX1{+IdQVzoq?y ziNNns`DwtLcNF((f!n&B(}6#Gw#Y97{x7ZHE&x792RvT~e&<D^=bONf)$;Wt;HPN) z{8Qk+IZgDe2flcO@IM3pnbrdz1HUOQ@;x;FTDg0CFX4TGzoYH@VZfIpM1Bl#lb;0q zq@^N%8t{7ce*$>3+Q-iVZt}~4_nag8uK~V7%iZ<Bf7eUo*8(^B2Z3Lw{p#m{|Fpa4 zc^UZA+Wx)^+~ofYe6Pbr&#v0fwRBmn?ebp0_g1@P32>7i27JxMqJKK@4>iBd2EOO< zB0mrKk=ie9176Zs<Sztn=fqwH{Lvzj|0ZygH@l<7!%LbU9tL?kSN0dcSM4eKe-GT` zUk6@yfXIIc+~TK5$A9LZ?dOX8UcfDWih*CR={pp-%{w0n{7Z91e>HHEKM8n)j)Pi( z+q|>cJI((~juZW>BILgW{K^#~{~h2l?f={f-0H{Yf%iOJ^t=MRQtR7p+CMUX+PRb4 z1HW0vt%m}){fvWv*PbKp9s~ScwLcsO{O)5!z8Uy$=Luf``~<asUJKmhZT*FXYXg6v z>rs&Z$wk7S0)F+b!rudK@*e`fO8cFCkCx}m-R;hj@53VaaS^-~_`}-YxEQ$2gIoc8 z(Rt$TZNR_!Md9}VFP$R%m%wcw+^>NDQ`@6I12_4<0l#ai=-*!5*^a()mD;wO@P5F5 z-Cy`<;I<F068JS2iu}pIO}+;B^EzH#4BYm?odf($t#7{!+~mIo{PsTLpSytDzODO# z-?g*IKLy<O**yn*nc8pP25$Y;e*zy<E&8|Bbg=lhb=^Ayzv?iNKNPr~S3U@MH?7~Q zfM0)+=$QfhPiF|92i)qfHsJ3r7x^oI-+qYjuL8evfbjc)+dh$Xz$?3n{PVy~{uSUW zE)n_nfSde>!2hA`-JaV1Tl|~+{=nbR^co4=<i`SkLG2-@0yp_O-~+Y3vUwr%kL^Re z0OWfN)p!PO>)6)-AKhEz9{_Ih4+EbzNaSAze*3Y){{;LxwfBAu{QX9e@1f%@3s-uM z@IJszz8~<(r;7Y|;O}dGJ{ouvJ49CkxXCvHf3By<UjTf`p~5c(zVck*w*WW!JAe;g zCi0H~xARG#0q$N}LXYgG?Xbn$nQ9*^27dT1qCW-P+M^}F2dX{dOTcYBcrEb9wOro` z+}fA5z|U8^_mjX){x`r6(DZr-_%iM1@1)}oi-+;G65fM>Tl+E)_|a;|9tYgytAKyE zRrJSzTl-QEeBw4De-?0)Uk<!wzQ}(SxV1-XfUi}1$oGL;d-NmVztZvMv%sxAdI|Up zt<N_Aw|&R|2ELE>XL@UWVCk~9hlFbc@Rb9F&jN1y7EcB~T<epCz)k*a;Ct(M>N@1w zZ@dZkYOSXp0B-g3!@ytFe*VkAP5w{7*J^zg%#?6j{8;<m6Zp`bMQ(rKR{tLi{GzTR zKMc6_Cr1NcrTyMnz>nAQ-pRnLSBd`lz^%Pl4E*vPME*+PCVvg^=R`cX7r3=AKLlQ( z?a1@Mt-W{!_!P~D9{@M`K-+UmmvQ~YL;C=?_M$KF38O^*NZ=+v0eEk<o5g@zdr=Sk zYufId3*6){1U`7G_~%C8_P(O`fuFvs$akA1cZ-J+Dz^*pDJw<p;0Qh*_`XMq{OQ2W z-G#u--Q~c|-K!$_y}-@gCxM%u*MZx65PHtejfY3HzqC8>recxn7s1B?zu-)fpA5WA z%j0Rl2dbU34)_W6qUQ|Yf6?*#GT;+hME)zlP5x`Z-_vq(AMk&jB6@xV{8r5m&jL63 z7lF@E`FDZay5j!;KTz}k9y*S({Aufo_W^#$eDUYWz%9Qu0Jr>>25$M}!U+Bl@QV)@ zci#eT>$2Vfe%gT|zoXh0EnFtQJMh;|7Wr|&Eq~4cZs&&AMewB&{3_s<Z?6M>`B3rC z-M}s1-Vb~?9cMiS-16abz`wD(=zkly$^R4hNR{uU{UeJ{%ZGaaKXI_=9{}9s%YffI zNaUvhw|qMb_+tl)d<$^Pw+n&4q~-KJ;Cr4fdVUW4Cps?vZ3O=pa7)MkA@3*pcRNw; z7H^i0wy(wbZ*~*85|Foa8HW4_k)MWK>#JG7m#KUUa7&kkz>n8*aS3pfzY_TFDt|k0 z>)+lB{4%viJq_H>v3VZ2oj3Om@XODXc=!PLt102TYkXKd_tE-)AK<&I{7~T6s{SK^ zpFK?Up8))E9T&uazqX^uUklvw;dg*rK725OzXaU!;j6%}+*aKEH*m{`9|6B}w8opJ zr^TD)!+n5%tmE8L;3hvD_)k^78o1@FlYl>=<Iq;%Ccg;yP1?>~0o?N8SAoA8m+;;L z-16ZA!0$dt<evj>`S4}nH*^vC_kmkJ{22ImVj{n{_6scjEg$v){*;Dy6mZLj<AK+- ziT*{v|5YRWJm9vD=tAJO{^wi3Yt{ev05?64NANd+pEFYYv#pNvEFP}Zaq>>Uf1>Sv zf8ZyaDSAqPAE@>9MBvTp|Ea+3y>T_bSL*!2T;M;{@#@XMhh8fF`95%q&nJQZP}A$z zz<cQY*581e{JX#pOlo{;{b%v{eZj#_z@Jom`oX}>pA&$`i$&2K;AadJJ`ecGI|%=F z1b;AszW}`AV$rj^rkjQ9KiV%m0QkOXksk>Be6<gZ0RD&GB0mYZt-DJAf3-p6=K&wQ zkMMJW|7nQu3xJ<fEc`m)!?YdwA#n50bHL3$`8(iytG%(u9C63u?Rk|O1-xNTkvlGe z&x_#8BKS8W_=6Grtq6X&*5BrT^XH@pek|~xYPqNfZhBgQoBT@PCVxu=e=>r<5y9U9 zZtnKfdK$yqCxRal!7G8A{*!=PxLP9k7bE!BBly|~{<{eNI&kynKY$O=a@tk<3l=}S zRt4@l4EVV_2_FLdgY$&X0B-Up12_2w;1$}QT?O3q+yLD4tOaiI|Emc8Ti_Ny?*TVG zJJw0~EPjmd3EcFQ0yp{NBKW)resKi<GH`SEJHXA|4<h*9IzNx$Dv#ht0ylSO0ylS0 z0dDe1;8S({dlhigb35>!I^KQ?xXHf={8u`zd>6RMe+2wT8eiM0eaqsfxmohTAmFBF zd;~W;ndve4n?U|Y`-%QLfj_MLH^6825&1s=k1O9++f{S7|9FxA0`Lo3g%1O6{ya8< zFO1+9NANYkt^7U!+}!<h1n)Cf{A=Md`4PakSuS!-z)k+D2>z=G{(1!Ot?i-t=f@+& z-EqLp-BTj?^%49R5&T);R=(Z>ZtlJZ+~l`AJv=@Sh~PsacvS>H5xAvGD{%AY`4RkQ z5&S9O-_d^Ko4`%~A@jn+I}Lb$)iVe9oW11vdBFG5dSoH+%d}lt1>E#s1ANsA(f@Pc z=Kr@N_`iT#`u1oPeO>6bjeK<f_5xn1zx7qV9evlT+5J-Haqfbfe?|c}cc*&#S(jb2 zfbXC`ECfBK|6Je}KbHZ&NW=d%;H#D20{o(*#Nj8EbNp;?o}~M8z<aX*U9W>4^XK0^ z&he(*8G7-pd(55Z!2Fx?HP{9CZ<Y52K1|*1=kaot<=Y^SbGm$KrTjR;<LvI0s^@6n zzfe9)Ie+DNC>1rqDV{vLJ4Shv$65c!s%H`Kimvj&*&b&-+Ux`uc%1djQ~Ar4n}3cF zHNjUsdDgQ=`FA|ddhSs@_W*xW`A<RrB-Qgca5Z}bzXLrZisXUUfnTWn9nfR(`5#Z7 z{r|MOyS?@=tla%r_3WYC;=%On=gG64K;yr^$2lI}RXsz159}rmj|N_+{AlIo?teu* zm<hZ{-JK8I<d*<9`5S=`Q2pOk&hfzEDpCDwJ<j2}M*aCP@Lwx`9QbzK#ewIPTe!^K zS3G%kcaFOIrpMXc!&T3_z#Ej?dEThMM~k>`;aaWwck?*wzfSe+2mE>E2YQ_SxlZ*Q z?s3+$V-Im}7;syMFbQ~@${(v7{ePk-&+cwecTe~DVB%j^J!#-SRDOoXSx>Q+$1i%E z_54xgS1ULFe3gFV>uOJ)^~_K`w|JcO^ytabL2!43o(F(`O~ix8LC+}F^Bl;Ve_jD@ zdj1Z2+EmYn5%S%%Vzhj+OvAN@#|M)izoU8%P;T*K?j8z!jfQJD=y^)@j01Vob2M<% zb28|8SM|&V`J2_<R^UHVelF-4sGXF{fzMEWqsO_uyQNwb-R$YtD04sD0elZFM?VFw z**SRJ)6e<p4psJR;2V^0@bv60UUC1v4_v#A!4C69$m;nEHC$g%&i-IMT8#z!1K(L5 z4+eprU#Xsvp8P&4%eQgBr|ECUfu6m$l^^DSys8i8dh#4UCEC8EJ<j=aq3Su`<9@&K zGT_#4yal-RuYL)<Y<KbJQ_4BsI7x~%eV+%uO8Gy5_f`I1Pd|rij)tqJ&L>!UJ)_~; zMY*{<LG|nfe2Vfxpl2IaNY@CEH~)<F<k>&#)IZZb&hb22^_&3wBIP!JW&Sk%r+f0O zzgRQe*&b*8�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 literal 0 HcmV?d00001 diff --git a/silecs-codegen/src/xml/test/generated_temp/AllTypes.cpp b/silecs-codegen/src/xml/test/generated_temp/AllTypes.cpp new file mode 100644 index 0000000..08c4d7f --- /dev/null +++ b/silecs-codegen/src/xml/test/generated_temp/AllTypes.cpp @@ -0,0 +1,738 @@ +/* + * AllTypes.cpp + * + * Generated by SILECS framework tools + */ + +#include <AllTypes/Common/AllTypes.h> +#include <fesa-core/Synchronization/NoneContext.h> +#include <fesa-core/Synchronization/MultiplexingContext.h> + +namespace AllTypes +{ + //Global objects of the SILECS class + Silecs::Service* AbstractAllTypes::pService_ = NULL; + Silecs::Cluster* AbstractAllTypes::pCluster_ = NULL; + bool AbstractAllTypes::isInitialized_ = false; + + MyROBlock_Type AllTypes::MyROBlock("MyROBlock"); + MyRWBlock_Type AllTypes::MyRWBlock("MyRWBlock"); + MyWOBlock_Type AllTypes::MyWOBlock("MyWOBlock"); + + //------------------------------------------------------------------------------------------------------------- + // Constructor & Destructor methods + + AbstractAllTypes::AbstractAllTypes(std::string blockName): blockName_(blockName) {} + AbstractAllTypes::~AbstractAllTypes() {} + + MyROBlock_Type::MyROBlock_Type(std::string name): AbstractAllTypes(name) {} + MyROBlock_Type::~MyROBlock_Type() {} + + MyRWBlock_Type::MyRWBlock_Type(std::string name): AbstractAllTypes(name) {} + MyRWBlock_Type::~MyRWBlock_Type() {} + + MyWOBlock_Type::MyWOBlock_Type(std::string name): AbstractAllTypes(name) {} + MyWOBlock_Type::~MyWOBlock_Type() {} + + //--------------------------------------------------------------------------------------------------------- + // Set-up the SILECS components for the AbstractAllTypes class (service & cluster) + + void AbstractAllTypes::setup(const ServiceLocator* serviceLocator) + { + try + { + // Instantiate the singleton of the SILECS Service + pService_ = Silecs::Service::getInstance(); + + // Enable the SILECS diagnostic with user topics if any + pService_->setArguments(serviceLocator->getUsrCmdArgs()); + + // Instantiate the SILECS Cluster object for the given Class/Version + GlobalDevice* pGlobalDevice = serviceLocator->getGlobalDevice(); + pCluster_ = pService_->getCluster( "AllTypes", pGlobalDevice->plcClassVersion.get()); + isInitialized_ = true; + + // Connect each PLC of the Cluster that is referred from the FESA instance + std::vector<Device*> pDeviceCol = serviceLocator->getDeviceCollection(); + for(std::vector<Device*>::iterator pDeviceIter=pDeviceCol.begin(); pDeviceIter!= pDeviceCol.end(); pDeviceIter++) + { + Device* pDevice = *pDeviceIter; + + // Retrieve the PLC related to the current FESA device + // (from 'plcHostName' FESA field defined on that purpose). + Silecs::PLC* pPLC = pCluster_->getPLC(pDevice->plcHostName.get(),pDevice->parameterFile.get()); + + // Update the PLC Slave registers from related FESA fields just before synchronising done at connection time + setPLCSlaveRegisters(pPLC, serviceLocator); + + // Connect the PLC if not already connected + if (!pPLC->isEnabled()) + { pPLC->connect(/*synchroMode=*/Silecs::FULL_SYNCHRO, /*connectNow=*/true); + if (pPLC->isConnected()) + { // Update FESA fields from related PLC Master registers just after synchronising done at connection time + getPLCMasterRegisters(pPLC, serviceLocator); + } + } + } + } + catch (const Silecs::SilecsException& ex) + { + throw fesa::FesaException(__FILE__, __LINE__, ex.getMessage()); + } + } + + //--------------------------------------------------------------------------------------------------------- + // Release all the SILECS resources + void AbstractAllTypes::cleanup() + { + // Attention! This method is responsible to stop all the PLC connections + // and to remove all the SILECS resources (Clusters and related components: PLCs, Devices, Registers, ..) + // Calling method must ensure that no process is currently accessing these resources before cleaning. + // + Silecs::Service::deleteInstance(); + } + + //--------------------------------------------------------------------------------------------------------- + // Synchronise PLC SLAVE/MASTER registers and related FESA fields (automatically called by the setup method @connection time) + void AbstractAllTypes::setPLCSlaveRegisters(Silecs::PLC* pPLC, const ServiceLocator* serviceLocator) + { + fesa::NoneContext noneContext; + + AllTypes::MyWOBlock.setPLCDevices(pPLC, serviceLocator, false, &noneContext); + } + + void AbstractAllTypes::getPLCMasterRegisters(Silecs::PLC* pPLC, const ServiceLocator* serviceLocator) + { + fesa::NoneContext noneContext; //MASTER acquisition fields are not consistent, can be set with none-context + + AllTypes::MyROBlock.getPLCDevices(pPLC, serviceLocator, false, &noneContext); + AllTypes::MyRWBlock.getPLCDevices(pPLC, serviceLocator, false, &noneContext); + } + + //--------------------------------------------------------------------------------------------------------- + // General methods to synchronize the FESA fields and related PLC registers of the FESA server + // with or without PLC side access (send/recv) if requested. + // get_ : [receive block from PLC +] update FESA fields with related PLC registers + // set_ : update PLC registers with related FESA fields [+ send block to PLC] + + //--------------------------------------------------------------------------------------------------------- + + void AbstractAllTypes::getAllDevices(const ServiceLocator* serviceLocator, const bool recvNow, MultiplexingContext* pContext) + { + if (recvNow) theCluster()->recv(blockName_); + + std::vector<Device*> deviceCol = serviceLocator->getDeviceCollection(); + for(std::vector<Device*>::iterator pDeviceIter=deviceCol.begin(); pDeviceIter!= deviceCol.end(); pDeviceIter++) + { getOneDevice(*pDeviceIter, false, pContext); + } + } + + void AbstractAllTypes::getPLCDevices(Silecs::PLC* pPLC, const ServiceLocator* serviceLocator, const bool recvNow, MultiplexingContext* pContext) + { + if (recvNow) pPLC->recv(blockName_); + + std::vector<Device*> deviceCol = serviceLocator->getDeviceCollection(); + for(std::vector<Device*>::iterator pDeviceIter=deviceCol.begin(); pDeviceIter!= deviceCol.end(); pDeviceIter++) + { if ((*pDeviceIter)->plcHostName.get() == pPLC->getName()) + { getOneDevice(*pDeviceIter, false, pContext); + } + } + } + + void AbstractAllTypes::getSomeDevices(std::vector<Device*> deviceCol, const bool sendNow, MultiplexingContext* pContext) + { + for(std::vector<Device*>::iterator pDeviceIter=deviceCol.begin(); pDeviceIter!= deviceCol.end(); pDeviceIter++) + { getOneDevice(*pDeviceIter, sendNow, pContext); + } + } + + void AbstractAllTypes::getOneDevice(Device* pDevice, const bool recvNow, MultiplexingContext* pContext) {}; + + //--------------------------------------------------------------------------------------------------------- + + void AbstractAllTypes::setAllDevices(const ServiceLocator* serviceLocator, bool sendNow, MultiplexingContext* pContext) + { + std::vector<Device*> deviceCol = serviceLocator->getDeviceCollection(); + for(std::vector<Device*>::iterator pDeviceIter=deviceCol.begin(); pDeviceIter!= deviceCol.end(); pDeviceIter++) + { setOneDevice(*pDeviceIter, false, pContext); + } + + if (sendNow) theCluster()->send(blockName_); + } + + void AbstractAllTypes::setPLCDevices(Silecs::PLC* pPLC, const ServiceLocator* serviceLocator, bool sendNow, MultiplexingContext* pContext) + { + std::vector<Device*> deviceCol = serviceLocator->getDeviceCollection(); + for(std::vector<Device*>::iterator pDeviceIter=deviceCol.begin(); pDeviceIter!= deviceCol.end(); pDeviceIter++) + { if ((*pDeviceIter)->plcHostName.get() == pPLC->getName()) + { setOneDevice(*pDeviceIter, false, pContext); + } + } + + if (sendNow) pPLC->send(blockName_); + } + + void AbstractAllTypes::setSomeDevices(std::vector<Device*> deviceCol, bool sendNow, MultiplexingContext* pContext) + { + for(std::vector<Device*>::iterator pDeviceIter=deviceCol.begin(); pDeviceIter!= deviceCol.end(); pDeviceIter++) + { setOneDevice(*pDeviceIter, sendNow, pContext); + } + } + + void AbstractAllTypes::setOneDevice(Device* pDevice, const bool sendNow, MultiplexingContext* pContext) {}; + + //--------------------------------------------------------------------------------------------------------- + + void MyROBlock_Type::getOneDevice(Device* pDevice, const bool recvNow, MultiplexingContext* pContext) + { + if( !isInitialized_ ) + { + throw fesa::FesaException(__FILE__, __LINE__, "SILECS-Service not initialized yet - AllTypes::setup needs to be called before any plc-interaction can be done"); + } + Silecs::PLC* pPLC = pCluster_->getPLC(pDevice->plcHostName.get(),pDevice->parameterFile.get()); + Silecs::Device* pPLCDevice = pPLC->getDevice(pDevice->plcDeviceLabel.get()); + Silecs::Register* pRegister = NULL; + + if (recvNow) pPLCDevice -> recv(blockName_); + + pDevice->RO_int8.set( pPLCDevice->getRegister("RO_int8")->getValInt8(), pContext); + pDevice->RO_uint8.set( pPLCDevice->getRegister("RO_uint8")->getValUInt8(), pContext); + pDevice->RO_int16.set( pPLCDevice->getRegister("RO_int16")->getValInt16(), pContext); + pDevice->RO_uint16.set( pPLCDevice->getRegister("RO_uint16")->getValUInt16(), pContext); + pDevice->RO_int32.set( pPLCDevice->getRegister("RO_int32")->getValInt32(), pContext); + pDevice->RO_uint32.set( pPLCDevice->getRegister("RO_uint32")->getValUInt32(), pContext); + pDevice->RO_float32.set( pPLCDevice->getRegister("RO_float32")->getValFloat32(), pContext); + pRegister = pPLCDevice->getRegister("RO_string"); + pDevice->RO_string.set(pRegister->getValString().c_str(), pContext); + + pDevice->RO_date.set( pPLCDevice->getRegister("RO_date")->getValDate(), pContext); + pDevice->RO_char.set( pPLCDevice->getRegister("RO_char")->getValInt8(), pContext); + pDevice->RO_byte.set( pPLCDevice->getRegister("RO_byte")->getValUInt8(), pContext); + pDevice->RO_word.set( pPLCDevice->getRegister("RO_word")->getValUInt16(), pContext); + pDevice->RO_dword.set( pPLCDevice->getRegister("RO_dword")->getValUInt32(), pContext); + pDevice->RO_int.set( pPLCDevice->getRegister("RO_int")->getValInt16(), pContext); + pDevice->RO_dint.set( pPLCDevice->getRegister("RO_dint")->getValInt32(), pContext); + pDevice->RO_real.set( pPLCDevice->getRegister("RO_real")->getValFloat32(), pContext); + pDevice->RO_dt.set( pPLCDevice->getRegister("RO_dt")->getValDate(), pContext); + } + void MyRWBlock_Type::getOneDevice(Device* pDevice, const bool recvNow, MultiplexingContext* pContext) + { + if( !isInitialized_ ) + { + throw fesa::FesaException(__FILE__, __LINE__, "SILECS-Service not initialized yet - AllTypes::setup needs to be called before any plc-interaction can be done"); + } + Silecs::PLC* pPLC = pCluster_->getPLC(pDevice->plcHostName.get(),pDevice->parameterFile.get()); + Silecs::Device* pPLCDevice = pPLC->getDevice(pDevice->plcDeviceLabel.get()); + Silecs::Register* pRegister = NULL; + uint32_t dim1 = 1; + uint32_t dim2 = 1; + + if (recvNow) pPLCDevice -> recv(blockName_); + + pRegister = pPLCDevice->getRegister("RW_int8"); + dim1 = pRegister->getDimension1(); + dim2 = pRegister->getDimension2(); + pDevice->RW_int8.set(pRegister->getRefInt8Array2D(dim1, dim2), dim1, dim2, pContext); + + pRegister = pPLCDevice->getRegister("RW_uint8"); + dim1 = pRegister->getDimension1(); + dim2 = pRegister->getDimension2(); + int16_t* RW_uint8 = (int16_t*)calloc(dim1*dim2, sizeof(int16_t)); + pRegister->getValUInt8Array2D(RW_uint8, dim1, dim2); //use automatic conversion for JAVA non-supported type + pDevice->RW_uint8.set(RW_uint8, dim1, dim2, pContext); + free(RW_uint8); + + pRegister = pPLCDevice->getRegister("RW_int16"); + dim1 = pRegister->getDimension1(); + dim2 = pRegister->getDimension2(); + pDevice->RW_int16.set(pRegister->getRefInt16Array2D(dim1, dim2), dim1, dim2, pContext); + + pRegister = pPLCDevice->getRegister("RW_uint16"); + dim1 = pRegister->getDimension1(); + dim2 = pRegister->getDimension2(); + int32_t* RW_uint16 = (int32_t*)calloc(dim1*dim2, sizeof(int32_t)); + pRegister->getValUInt16Array2D(RW_uint16, dim1, dim2); //use automatic conversion for JAVA non-supported type + pDevice->RW_uint16.set(RW_uint16, dim1, dim2, pContext); + free(RW_uint16); + + pRegister = pPLCDevice->getRegister("RW_int32"); + dim1 = pRegister->getDimension1(); + dim2 = pRegister->getDimension2(); + pDevice->RW_int32.set(pRegister->getRefInt32Array2D(dim1, dim2), dim1, dim2, pContext); + + pRegister = pPLCDevice->getRegister("RW_uint32"); + dim1 = pRegister->getDimension1(); + dim2 = pRegister->getDimension2(); + int64_t* RW_uint32 = (int64_t*)calloc(dim1*dim2, sizeof(int64_t)); + pRegister->getValUInt32Array2D(RW_uint32, dim1, dim2); //use automatic conversion for JAVA non-supported type + pDevice->RW_uint32.set(RW_uint32, dim1, dim2, pContext); + free(RW_uint32); + + pRegister = pPLCDevice->getRegister("RW_float32"); + dim1 = pRegister->getDimension1(); + dim2 = pRegister->getDimension2(); + pDevice->RW_float32.set(pRegister->getRefFloat32Array2D(dim1, dim2), dim1, dim2, pContext); + + pRegister = pPLCDevice->getRegister("RW_date"); + dim1 = pRegister->getDimension1(); + dim2 = pRegister->getDimension2(); + pDevice->RW_date.set(pRegister->getRefDateArray2D(dim1, dim2), dim1, dim2, pContext); + + pRegister = pPLCDevice->getRegister("RW_char"); + dim1 = pRegister->getDimension1(); + dim2 = pRegister->getDimension2(); + pDevice->RW_char.set(pRegister->getRefInt8Array2D(dim1, dim2), dim1, dim2, pContext); + + pRegister = pPLCDevice->getRegister("RW_byte"); + dim1 = pRegister->getDimension1(); + dim2 = pRegister->getDimension2(); + int16_t* RW_byte = (int16_t*)calloc(dim1*dim2, sizeof(int16_t)); + pRegister->getValUInt8Array2D(RW_byte, dim1, dim2); //use automatic conversion for JAVA non-supported type + pDevice->RW_byte.set(RW_byte, dim1, dim2, pContext); + free(RW_byte); + + pRegister = pPLCDevice->getRegister("RW_word"); + dim1 = pRegister->getDimension1(); + dim2 = pRegister->getDimension2(); + int32_t* RW_word = (int32_t*)calloc(dim1*dim2, sizeof(int32_t)); + pRegister->getValUInt16Array2D(RW_word, dim1, dim2); //use automatic conversion for JAVA non-supported type + pDevice->RW_word.set(RW_word, dim1, dim2, pContext); + free(RW_word); + + pRegister = pPLCDevice->getRegister("RW_dword"); + dim1 = pRegister->getDimension1(); + dim2 = pRegister->getDimension2(); + int64_t* RW_dword = (int64_t*)calloc(dim1*dim2, sizeof(int64_t)); + pRegister->getValUInt32Array2D(RW_dword, dim1, dim2); //use automatic conversion for JAVA non-supported type + pDevice->RW_dword.set(RW_dword, dim1, dim2, pContext); + free(RW_dword); + + pRegister = pPLCDevice->getRegister("RW_int"); + dim1 = pRegister->getDimension1(); + dim2 = pRegister->getDimension2(); + pDevice->RW_int.set(pRegister->getRefInt16Array2D(dim1, dim2), dim1, dim2, pContext); + + pRegister = pPLCDevice->getRegister("RW_dint"); + dim1 = pRegister->getDimension1(); + dim2 = pRegister->getDimension2(); + pDevice->RW_dint.set(pRegister->getRefInt32Array2D(dim1, dim2), dim1, dim2, pContext); + + pRegister = pPLCDevice->getRegister("RW_real"); + dim1 = pRegister->getDimension1(); + dim2 = pRegister->getDimension2(); + pDevice->RW_real.set(pRegister->getRefFloat32Array2D(dim1, dim2), dim1, dim2, pContext); + + pRegister = pPLCDevice->getRegister("RW_dt"); + dim1 = pRegister->getDimension1(); + dim2 = pRegister->getDimension2(); + pDevice->RW_dt.set(pRegister->getRefDateArray2D(dim1, dim2), dim1, dim2, pContext); + + } + void MyRWBlock_Type::setOneDevice(Device* pDevice, const bool sendNow, MultiplexingContext* pContext) + { + if( !isInitialized_ ) + { + throw fesa::FesaException(__FILE__, __LINE__, "SILECS-Service not initialized yet - AllTypes::setup needs to be called before any plc-interaction can be done"); + } + Silecs::PLC* pPLC = pCluster_->getPLC(pDevice->plcHostName.get(),pDevice->parameterFile.get()); + Silecs::Device* pPLCDevice = pPLC->getDevice(pDevice->plcDeviceLabel.get()); + Silecs::Register* pRegister = NULL; + uint32_t dim1 = 1; + uint32_t fesaDim1; + uint32_t dim2 = 1; + uint32_t fesaDim2; + + + pRegister = pPLCDevice->getRegister("RW_int8"); + dim1 = pRegister->getDimension1(); + dim2 = pRegister->getDimension2(); + pRegister->setValInt8Array2D(pDevice->RW_int8.get(fesaDim1, fesaDim2, pContext), dim1, dim2); + + pRegister = pPLCDevice->getRegister("RW_uint8"); + dim1 = pRegister->getDimension1(); + dim2 = pRegister->getDimension2(); + pRegister->setValUInt8Array2D( pDevice->RW_uint8.get(fesaDim1, fesaDim2, pContext), dim1, dim2); //use automatic conversion for JAVA non-supported type + + pRegister = pPLCDevice->getRegister("RW_int16"); + dim1 = pRegister->getDimension1(); + dim2 = pRegister->getDimension2(); + pRegister->setValInt16Array2D(pDevice->RW_int16.get(fesaDim1, fesaDim2, pContext), dim1, dim2); + + pRegister = pPLCDevice->getRegister("RW_uint16"); + dim1 = pRegister->getDimension1(); + dim2 = pRegister->getDimension2(); + pRegister->setValUInt16Array2D( pDevice->RW_uint16.get(fesaDim1, fesaDim2, pContext), dim1, dim2); //use automatic conversion for JAVA non-supported type + + pRegister = pPLCDevice->getRegister("RW_int32"); + dim1 = pRegister->getDimension1(); + dim2 = pRegister->getDimension2(); + pRegister->setValInt32Array2D(pDevice->RW_int32.get(fesaDim1, fesaDim2, pContext), dim1, dim2); + + pRegister = pPLCDevice->getRegister("RW_uint32"); + dim1 = pRegister->getDimension1(); + dim2 = pRegister->getDimension2(); + pRegister->setValUInt32Array2D( pDevice->RW_uint32.get(fesaDim1, fesaDim2, pContext), dim1, dim2); //use automatic conversion for JAVA non-supported type + + pRegister = pPLCDevice->getRegister("RW_float32"); + dim1 = pRegister->getDimension1(); + dim2 = pRegister->getDimension2(); + pRegister->setValFloat32Array2D(pDevice->RW_float32.get(fesaDim1, fesaDim2, pContext), dim1, dim2); + + pRegister = pPLCDevice->getRegister("RW_date"); + dim1 = pRegister->getDimension1(); + dim2 = pRegister->getDimension2(); + pRegister->setValDateArray2D(pDevice->RW_date.get(fesaDim1, fesaDim2, pContext), dim1, dim2); + + pRegister = pPLCDevice->getRegister("RW_char"); + dim1 = pRegister->getDimension1(); + dim2 = pRegister->getDimension2(); + pRegister->setValInt8Array2D(pDevice->RW_char.get(fesaDim1, fesaDim2, pContext), dim1, dim2); + + pRegister = pPLCDevice->getRegister("RW_byte"); + dim1 = pRegister->getDimension1(); + dim2 = pRegister->getDimension2(); + pRegister->setValUInt8Array2D( pDevice->RW_byte.get(fesaDim1, fesaDim2, pContext), dim1, dim2); //use automatic conversion for JAVA non-supported type + + pRegister = pPLCDevice->getRegister("RW_word"); + dim1 = pRegister->getDimension1(); + dim2 = pRegister->getDimension2(); + pRegister->setValUInt16Array2D( pDevice->RW_word.get(fesaDim1, fesaDim2, pContext), dim1, dim2); //use automatic conversion for JAVA non-supported type + + pRegister = pPLCDevice->getRegister("RW_dword"); + dim1 = pRegister->getDimension1(); + dim2 = pRegister->getDimension2(); + pRegister->setValUInt32Array2D( pDevice->RW_dword.get(fesaDim1, fesaDim2, pContext), dim1, dim2); //use automatic conversion for JAVA non-supported type + + pRegister = pPLCDevice->getRegister("RW_int"); + dim1 = pRegister->getDimension1(); + dim2 = pRegister->getDimension2(); + pRegister->setValInt16Array2D(pDevice->RW_int.get(fesaDim1, fesaDim2, pContext), dim1, dim2); + + pRegister = pPLCDevice->getRegister("RW_dint"); + dim1 = pRegister->getDimension1(); + dim2 = pRegister->getDimension2(); + pRegister->setValInt32Array2D(pDevice->RW_dint.get(fesaDim1, fesaDim2, pContext), dim1, dim2); + + pRegister = pPLCDevice->getRegister("RW_real"); + dim1 = pRegister->getDimension1(); + dim2 = pRegister->getDimension2(); + pRegister->setValFloat32Array2D(pDevice->RW_real.get(fesaDim1, fesaDim2, pContext), dim1, dim2); + + pRegister = pPLCDevice->getRegister("RW_dt"); + dim1 = pRegister->getDimension1(); + dim2 = pRegister->getDimension2(); + pRegister->setValDateArray2D(pDevice->RW_dt.get(fesaDim1, fesaDim2, pContext), dim1, dim2); + + if (sendNow) pPLCDevice->send(blockName_); + + } + void MyRWBlock_Type::setOneDevice(Device* pDevice, MyRWBlockPropertyData& data, bool sendNow, MultiplexingContext* pContext) + { + if( !isInitialized_ ) + { + throw fesa::FesaException(__FILE__, __LINE__, "SILECS-Service not initialized yet - AllTypes::setup needs to be called before any plc-interaction can be done"); + } + Silecs::PLC* pPLC = pCluster_->getPLC(pDevice->plcHostName.get(),pDevice->parameterFile.get()); + Silecs::Device* pPLCDevice = pPLC->getDevice(pDevice->plcDeviceLabel.get()); + Silecs::Register* pRegister = NULL; + uint32_t dim1 = 1; + uint32_t fesaDim1; + uint32_t dim2 = 1; + uint32_t fesaDim2; + + + pRegister = pPLCDevice->getRegister("RW_int8"); + dim1 = pRegister->getDimension1(); + dim2 = pRegister->getDimension2(); + (data.isRW_int8Available()) ? pRegister->setValInt8Array2D(data.RW_int8.get(fesaDim1, fesaDim2), dim1, dim2) : + pRegister->setValInt8Array2D(pDevice->RW_int8.get(fesaDim1, fesaDim2, pContext), dim1, dim2); + + pRegister = pPLCDevice->getRegister("RW_uint8"); + dim1 = pRegister->getDimension1(); + dim2 = pRegister->getDimension2(); + (data.isRW_uint8Available()) ? pRegister->setValUInt8Array2D(data.RW_uint8.get(fesaDim1, fesaDim2), dim1, dim2) : + pRegister->setValUInt8Array2D(pDevice->RW_uint8.get(fesaDim1, fesaDim2, pContext), dim1, dim2); + + pRegister = pPLCDevice->getRegister("RW_int16"); + dim1 = pRegister->getDimension1(); + dim2 = pRegister->getDimension2(); + (data.isRW_int16Available()) ? pRegister->setValInt16Array2D(data.RW_int16.get(fesaDim1, fesaDim2), dim1, dim2) : + pRegister->setValInt16Array2D(pDevice->RW_int16.get(fesaDim1, fesaDim2, pContext), dim1, dim2); + + pRegister = pPLCDevice->getRegister("RW_uint16"); + dim1 = pRegister->getDimension1(); + dim2 = pRegister->getDimension2(); + (data.isRW_uint16Available()) ? pRegister->setValUInt16Array2D(data.RW_uint16.get(fesaDim1, fesaDim2), dim1, dim2) : + pRegister->setValUInt16Array2D(pDevice->RW_uint16.get(fesaDim1, fesaDim2, pContext), dim1, dim2); + + pRegister = pPLCDevice->getRegister("RW_int32"); + dim1 = pRegister->getDimension1(); + dim2 = pRegister->getDimension2(); + (data.isRW_int32Available()) ? pRegister->setValInt32Array2D(data.RW_int32.get(fesaDim1, fesaDim2), dim1, dim2) : + pRegister->setValInt32Array2D(pDevice->RW_int32.get(fesaDim1, fesaDim2, pContext), dim1, dim2); + + pRegister = pPLCDevice->getRegister("RW_uint32"); + dim1 = pRegister->getDimension1(); + dim2 = pRegister->getDimension2(); + (data.isRW_uint32Available()) ? pRegister->setValUInt32Array2D(data.RW_uint32.get(fesaDim1, fesaDim2), dim1, dim2) : + pRegister->setValUInt32Array2D(pDevice->RW_uint32.get(fesaDim1, fesaDim2, pContext), dim1, dim2); + + pRegister = pPLCDevice->getRegister("RW_float32"); + dim1 = pRegister->getDimension1(); + dim2 = pRegister->getDimension2(); + (data.isRW_float32Available()) ? pRegister->setValFloat32Array2D(data.RW_float32.get(fesaDim1, fesaDim2), dim1, dim2) : + pRegister->setValFloat32Array2D(pDevice->RW_float32.get(fesaDim1, fesaDim2, pContext), dim1, dim2); + + pRegister = pPLCDevice->getRegister("RW_date"); + dim1 = pRegister->getDimension1(); + dim2 = pRegister->getDimension2(); + (data.isRW_dateAvailable()) ? pRegister->setValDateArray2D(data.RW_date.get(fesaDim1, fesaDim2), dim1, dim2) : + pRegister->setValDateArray2D(pDevice->RW_date.get(fesaDim1, fesaDim2, pContext), dim1, dim2); + + pRegister = pPLCDevice->getRegister("RW_char"); + dim1 = pRegister->getDimension1(); + dim2 = pRegister->getDimension2(); + (data.isRW_charAvailable()) ? pRegister->setValInt8Array2D(data.RW_char.get(fesaDim1, fesaDim2), dim1, dim2) : + pRegister->setValInt8Array2D(pDevice->RW_char.get(fesaDim1, fesaDim2, pContext), dim1, dim2); + + pRegister = pPLCDevice->getRegister("RW_byte"); + dim1 = pRegister->getDimension1(); + dim2 = pRegister->getDimension2(); + (data.isRW_byteAvailable()) ? pRegister->setValUInt8Array2D(data.RW_byte.get(fesaDim1, fesaDim2), dim1, dim2) : + pRegister->setValUInt8Array2D(pDevice->RW_byte.get(fesaDim1, fesaDim2, pContext), dim1, dim2); + + pRegister = pPLCDevice->getRegister("RW_word"); + dim1 = pRegister->getDimension1(); + dim2 = pRegister->getDimension2(); + (data.isRW_wordAvailable()) ? pRegister->setValUInt16Array2D(data.RW_word.get(fesaDim1, fesaDim2), dim1, dim2) : + pRegister->setValUInt16Array2D(pDevice->RW_word.get(fesaDim1, fesaDim2, pContext), dim1, dim2); + + pRegister = pPLCDevice->getRegister("RW_dword"); + dim1 = pRegister->getDimension1(); + dim2 = pRegister->getDimension2(); + (data.isRW_dwordAvailable()) ? pRegister->setValUInt32Array2D(data.RW_dword.get(fesaDim1, fesaDim2), dim1, dim2) : + pRegister->setValUInt32Array2D(pDevice->RW_dword.get(fesaDim1, fesaDim2, pContext), dim1, dim2); + + pRegister = pPLCDevice->getRegister("RW_int"); + dim1 = pRegister->getDimension1(); + dim2 = pRegister->getDimension2(); + (data.isRW_intAvailable()) ? pRegister->setValInt16Array2D(data.RW_int.get(fesaDim1, fesaDim2), dim1, dim2) : + pRegister->setValInt16Array2D(pDevice->RW_int.get(fesaDim1, fesaDim2, pContext), dim1, dim2); + + pRegister = pPLCDevice->getRegister("RW_dint"); + dim1 = pRegister->getDimension1(); + dim2 = pRegister->getDimension2(); + (data.isRW_dintAvailable()) ? pRegister->setValInt32Array2D(data.RW_dint.get(fesaDim1, fesaDim2), dim1, dim2) : + pRegister->setValInt32Array2D(pDevice->RW_dint.get(fesaDim1, fesaDim2, pContext), dim1, dim2); + + pRegister = pPLCDevice->getRegister("RW_real"); + dim1 = pRegister->getDimension1(); + dim2 = pRegister->getDimension2(); + (data.isRW_realAvailable()) ? pRegister->setValFloat32Array2D(data.RW_real.get(fesaDim1, fesaDim2), dim1, dim2) : + pRegister->setValFloat32Array2D(pDevice->RW_real.get(fesaDim1, fesaDim2, pContext), dim1, dim2); + + pRegister = pPLCDevice->getRegister("RW_dt"); + dim1 = pRegister->getDimension1(); + dim2 = pRegister->getDimension2(); + (data.isRW_dtAvailable()) ? pRegister->setValDateArray2D(data.RW_dt.get(fesaDim1, fesaDim2), dim1, dim2) : + pRegister->setValDateArray2D(pDevice->RW_dt.get(fesaDim1, fesaDim2, pContext), dim1, dim2); + + if (sendNow) pPLCDevice->send(blockName_); + + } + + void MyWOBlock_Type::setOneDevice(Device* pDevice, const bool sendNow, MultiplexingContext* pContext) + { + if( !isInitialized_ ) + { + throw fesa::FesaException(__FILE__, __LINE__, "SILECS-Service not initialized yet - AllTypes::setup needs to be called before any plc-interaction can be done"); + } + Silecs::PLC* pPLC = pCluster_->getPLC(pDevice->plcHostName.get(),pDevice->parameterFile.get()); + Silecs::Device* pPLCDevice = pPLC->getDevice(pDevice->plcDeviceLabel.get()); + Silecs::Register* pRegister = NULL; + uint32_t dim1 = 1; + uint32_t fesaDim1; + + + pRegister = pPLCDevice->getRegister("WO_int8"); + dim1 = pRegister->getDimension1(); + pRegister->setValInt8Array(pDevice->WO_int8.get(fesaDim1, pContext), dim1); + + pRegister = pPLCDevice->getRegister("WO_uint8"); + dim1 = pRegister->getDimension1(); + pRegister->setValUInt8Array(pDevice->WO_uint8.get(fesaDim1, pContext), dim1); //use automatic conversion for JAVA non-supported type + + pRegister = pPLCDevice->getRegister("WO_int16"); + dim1 = pRegister->getDimension1(); + pRegister->setValInt16Array(pDevice->WO_int16.get(fesaDim1, pContext), dim1); + + pRegister = pPLCDevice->getRegister("WO_uint16"); + dim1 = pRegister->getDimension1(); + pRegister->setValUInt16Array(pDevice->WO_uint16.get(fesaDim1, pContext), dim1); //use automatic conversion for JAVA non-supported type + + pRegister = pPLCDevice->getRegister("WO_int32"); + dim1 = pRegister->getDimension1(); + pRegister->setValInt32Array(pDevice->WO_int32.get(fesaDim1, pContext), dim1); + + pRegister = pPLCDevice->getRegister("WO_uint32"); + dim1 = pRegister->getDimension1(); + pRegister->setValUInt32Array(pDevice->WO_uint32.get(fesaDim1, pContext), dim1); //use automatic conversion for JAVA non-supported type + + pRegister = pPLCDevice->getRegister("WO_float32"); + dim1 = pRegister->getDimension1(); + pRegister->setValFloat32Array(pDevice->WO_float32.get(fesaDim1, pContext), dim1); + + { + pRegister = pPLCDevice->getRegister("WO_string"); + dim1 = pRegister->getDimension1(); + std::string stdStringArray[dim1]; + const char** cStringArray = pDevice->WO_string.get(fesaDim1, pContext); + for (unsigned int i=0; i<dim1; i++) stdStringArray[i] = (const char*)cStringArray[i]; + pRegister->setValStringArray(stdStringArray, dim1); + } + + pRegister = pPLCDevice->getRegister("WO_date"); + dim1 = pRegister->getDimension1(); + pRegister->setValDateArray(pDevice->WO_date.get(fesaDim1, pContext), dim1); + + pRegister = pPLCDevice->getRegister("WO_char"); + dim1 = pRegister->getDimension1(); + pRegister->setValInt8Array(pDevice->WO_char.get(fesaDim1, pContext), dim1); + + pRegister = pPLCDevice->getRegister("WO_byte"); + dim1 = pRegister->getDimension1(); + pRegister->setValUInt8Array(pDevice->WO_byte.get(fesaDim1, pContext), dim1); //use automatic conversion for JAVA non-supported type + + pRegister = pPLCDevice->getRegister("WO_word"); + dim1 = pRegister->getDimension1(); + pRegister->setValUInt16Array(pDevice->WO_word.get(fesaDim1, pContext), dim1); //use automatic conversion for JAVA non-supported type + + pRegister = pPLCDevice->getRegister("WO_dword"); + dim1 = pRegister->getDimension1(); + pRegister->setValUInt32Array(pDevice->WO_dword.get(fesaDim1, pContext), dim1); //use automatic conversion for JAVA non-supported type + + pRegister = pPLCDevice->getRegister("WO_int"); + dim1 = pRegister->getDimension1(); + pRegister->setValInt16Array(pDevice->WO_int.get(fesaDim1, pContext), dim1); + + pRegister = pPLCDevice->getRegister("WO_dint"); + dim1 = pRegister->getDimension1(); + pRegister->setValInt32Array(pDevice->WO_dint.get(fesaDim1, pContext), dim1); + + pRegister = pPLCDevice->getRegister("WO_real"); + dim1 = pRegister->getDimension1(); + pRegister->setValFloat32Array(pDevice->WO_real.get(fesaDim1, pContext), dim1); + + pRegister = pPLCDevice->getRegister("WO_dt"); + dim1 = pRegister->getDimension1(); + pRegister->setValDateArray(pDevice->WO_dt.get(fesaDim1, pContext), dim1); + + if (sendNow) pPLCDevice->send(blockName_); + + } + void MyWOBlock_Type::setOneDevice(Device* pDevice, MyWOBlockPropertyData& data, bool sendNow, MultiplexingContext* pContext) + { + if( !isInitialized_ ) + { + throw fesa::FesaException(__FILE__, __LINE__, "SILECS-Service not initialized yet - AllTypes::setup needs to be called before any plc-interaction can be done"); + } + Silecs::PLC* pPLC = pCluster_->getPLC(pDevice->plcHostName.get(),pDevice->parameterFile.get()); + Silecs::Device* pPLCDevice = pPLC->getDevice(pDevice->plcDeviceLabel.get()); + Silecs::Register* pRegister = NULL; + uint32_t dim1 = 1; + uint32_t fesaDim1; + + + pRegister = pPLCDevice->getRegister("WO_int8"); + dim1 = pRegister->getDimension1(); + (data.isWO_int8Available()) ? pRegister->setValInt8Array( data.WO_int8.get(fesaDim1), dim1) : + pRegister->setValInt8Array( pDevice->WO_int8.get(fesaDim1, pContext), dim1); + + pRegister = pPLCDevice->getRegister("WO_uint8"); + dim1 = pRegister->getDimension1(); + (data.isWO_uint8Available()) ? pRegister->setValUInt8Array( data.WO_uint8.get(fesaDim1), dim1) : + pRegister->setValUInt8Array( pDevice->WO_uint8.get(fesaDim1, pContext), dim1); + + pRegister = pPLCDevice->getRegister("WO_int16"); + dim1 = pRegister->getDimension1(); + (data.isWO_int16Available()) ? pRegister->setValInt16Array( data.WO_int16.get(fesaDim1), dim1) : + pRegister->setValInt16Array( pDevice->WO_int16.get(fesaDim1, pContext), dim1); + + pRegister = pPLCDevice->getRegister("WO_uint16"); + dim1 = pRegister->getDimension1(); + (data.isWO_uint16Available()) ? pRegister->setValUInt16Array( data.WO_uint16.get(fesaDim1), dim1) : + pRegister->setValUInt16Array( pDevice->WO_uint16.get(fesaDim1, pContext), dim1); + + pRegister = pPLCDevice->getRegister("WO_int32"); + dim1 = pRegister->getDimension1(); + (data.isWO_int32Available()) ? pRegister->setValInt32Array( data.WO_int32.get(fesaDim1), dim1) : + pRegister->setValInt32Array( pDevice->WO_int32.get(fesaDim1, pContext), dim1); + + pRegister = pPLCDevice->getRegister("WO_uint32"); + dim1 = pRegister->getDimension1(); + (data.isWO_uint32Available()) ? pRegister->setValUInt32Array( data.WO_uint32.get(fesaDim1), dim1) : + pRegister->setValUInt32Array( pDevice->WO_uint32.get(fesaDim1, pContext), dim1); + + pRegister = pPLCDevice->getRegister("WO_float32"); + dim1 = pRegister->getDimension1(); + (data.isWO_float32Available()) ? pRegister->setValFloat32Array( data.WO_float32.get(fesaDim1), dim1) : + pRegister->setValFloat32Array( pDevice->WO_float32.get(fesaDim1, pContext), dim1); + + { + pRegister = pPLCDevice->getRegister("WO_string"); + dim1 = pRegister->getDimension1(); + std::string stdStringArray[dim1]; + const char** cStringArray = (data.isWO_stringAvailable() ? data.WO_string.get(fesaDim1) : pDevice->WO_string.get(fesaDim1, pContext)); + for (unsigned int i=0; i<dim1; i++) stdStringArray[i] = (const char*)cStringArray[i]; + pRegister->setValStringArray(stdStringArray, dim1); + } + + pRegister = pPLCDevice->getRegister("WO_date"); + dim1 = pRegister->getDimension1(); + (data.isWO_dateAvailable()) ? pRegister->setValDateArray( data.WO_date.get(fesaDim1), dim1) : + pRegister->setValDateArray( pDevice->WO_date.get(fesaDim1, pContext), dim1); + + pRegister = pPLCDevice->getRegister("WO_char"); + dim1 = pRegister->getDimension1(); + (data.isWO_charAvailable()) ? pRegister->setValInt8Array( data.WO_char.get(fesaDim1), dim1) : + pRegister->setValInt8Array( pDevice->WO_char.get(fesaDim1, pContext), dim1); + + pRegister = pPLCDevice->getRegister("WO_byte"); + dim1 = pRegister->getDimension1(); + (data.isWO_byteAvailable()) ? pRegister->setValUInt8Array( data.WO_byte.get(fesaDim1), dim1) : + pRegister->setValUInt8Array( pDevice->WO_byte.get(fesaDim1, pContext), dim1); + + pRegister = pPLCDevice->getRegister("WO_word"); + dim1 = pRegister->getDimension1(); + (data.isWO_wordAvailable()) ? pRegister->setValUInt16Array( data.WO_word.get(fesaDim1), dim1) : + pRegister->setValUInt16Array( pDevice->WO_word.get(fesaDim1, pContext), dim1); + + pRegister = pPLCDevice->getRegister("WO_dword"); + dim1 = pRegister->getDimension1(); + (data.isWO_dwordAvailable()) ? pRegister->setValUInt32Array( data.WO_dword.get(fesaDim1), dim1) : + pRegister->setValUInt32Array( pDevice->WO_dword.get(fesaDim1, pContext), dim1); + + pRegister = pPLCDevice->getRegister("WO_int"); + dim1 = pRegister->getDimension1(); + (data.isWO_intAvailable()) ? pRegister->setValInt16Array( data.WO_int.get(fesaDim1), dim1) : + pRegister->setValInt16Array( pDevice->WO_int.get(fesaDim1, pContext), dim1); + + pRegister = pPLCDevice->getRegister("WO_dint"); + dim1 = pRegister->getDimension1(); + (data.isWO_dintAvailable()) ? pRegister->setValInt32Array( data.WO_dint.get(fesaDim1), dim1) : + pRegister->setValInt32Array( pDevice->WO_dint.get(fesaDim1, pContext), dim1); + + pRegister = pPLCDevice->getRegister("WO_real"); + dim1 = pRegister->getDimension1(); + (data.isWO_realAvailable()) ? pRegister->setValFloat32Array( data.WO_real.get(fesaDim1), dim1) : + pRegister->setValFloat32Array( pDevice->WO_real.get(fesaDim1, pContext), dim1); + + pRegister = pPLCDevice->getRegister("WO_dt"); + dim1 = pRegister->getDimension1(); + (data.isWO_dtAvailable()) ? pRegister->setValDateArray( data.WO_dt.get(fesaDim1), dim1) : + pRegister->setValDateArray( pDevice->WO_dt.get(fesaDim1, pContext), dim1); + + if (sendNow) pPLCDevice->send(blockName_); + + } +} diff --git a/silecs-codegen/src/xml/test/generated_temp/AllTypes.h b/silecs-codegen/src/xml/test/generated_temp/AllTypes.h new file mode 100644 index 0000000..3edca8f --- /dev/null +++ b/silecs-codegen/src/xml/test/generated_temp/AllTypes.h @@ -0,0 +1,146 @@ +/* + * AllTypes.h + * + * Generated by SILECS framework tools + */ + +#ifndef AllTypes_AllTypes_H_ +#define AllTypes_AllTypes_H_ + +#include <SilecsService.h> +#include <fesa-core/Synchronization/MultiplexingContext.h> +#include <AllTypes/GeneratedCode/ServiceLocator.h> + #include <AllTypes/Server/SendMyRWBlock.h> + #include <AllTypes/Server/SendMyWOBlock.h> + +namespace AllTypes +{ + + /*--------------------------------------------------------------------------------------------------------- + * SETUP + *--------------------------------------------------------------------------------------------------------- + * Setup the SILECS service by calling the setup() method from the RTDeviceClass::specificInit() + * Stop and cleanup the SILECS service by calling the cleanup() method if needed (eg.: from ~RTDeviceClass()) + * + * In order to make use of the different blocks, defined in the silecsdesign, please make use of the static, block related variables of the class, defined on the bottom of this file ! + * -------------------------------------------------------------------------------------------------------- + */ + + /*--------------------------------------------------------------------------------------------------------- + * COMMUNICATION + *--------------------------------------------------------------------------------------------------------- + * General methods to synchronize the FESA fields and related PLC registers of the FESA server with or without + * PLC side synchronization (send/recv) if requested. Each action is done for one particular block. + * In case of BLOCK_MODE configuration (see SILECS doc.), the transaction is optimal with the following + * 'AllDevices' and 'PLCDevices' methods. + * Each method can be called in the appropriate server-action (set) and rt-action (get) + * + * getAllDevices : [receive all devices of all connected PLCs +] update FESA fields with related SILECS registers + * setAllDevices : update SILECS registers with related FESA fields [+ send block to all connected PLCs] + * getPLCDevices : [receive all devices of one PLC +] update FESA fields with related SILECS registers + * setPLCDevices : update SILECS registers with related FESA fields [+ send block to the PLC] + * getSomeDevices : [receive each device of the device-collection +] update FESA fields with related SILECS registers + * setSomeDevices : update SILECS registers with related FESA fields [+ send block to each device of the device-collection] + * getOneDevice : [receive block of one PLC device +] update FESA fields with related SILECS registers + * setOneDevice : update SILECS registers with related FESA fields [+ send block to the PLC device] + * + * -------------------------------------------------------------------------------------------------------- + */ + + class AbstractAllTypes + { + public: + static inline Silecs::Service* theService() { return pService_; } + static inline Silecs::Cluster* theCluster() { return pCluster_; } + inline std::string& getBlockName() { return blockName_; } + + static void setup(const ServiceLocator* serviceLocator); + static void cleanup(); + static void setPLCSlaveRegisters(Silecs::PLC* pPLC, const ServiceLocator* serviceLocator); + static void getPLCMasterRegisters(Silecs::PLC* pPLC, const ServiceLocator* serviceLocator); + + AbstractAllTypes(std::string blockName); + virtual ~AbstractAllTypes(); + + void getAllDevices(const ServiceLocator* serviceLocator, const bool recvNow, MultiplexingContext* pContext); + void getPLCDevices(Silecs::PLC* pPLC, const ServiceLocator* serviceLocator, const bool recvNow, MultiplexingContext* pContext); + void getSomeDevices(std::vector<Device*> deviceCol, const bool recvNow, MultiplexingContext* pContext); + virtual void getOneDevice(Device* pDevice, const bool recvNow, MultiplexingContext* pContext); + + void setAllDevices(const ServiceLocator* serviceLocator, const bool sendNow, MultiplexingContext* pContext); + void setPLCDevices(Silecs::PLC* pPLC, const ServiceLocator* serviceLocator, const bool sendNow, MultiplexingContext* pContext); + void setSomeDevices(std::vector<Device*> deviceCol, const bool sendNow, MultiplexingContext* pContext); + virtual void setOneDevice(Device* pDevice, const bool sendNow, MultiplexingContext* pContext); + + protected: + + static Silecs::Service* pService_; + static Silecs::Cluster* pCluster_; + static bool isInitialized_; + + // Name of the silecs-block which is addressed + std::string blockName_; + + // not copyable object + AbstractAllTypes(const AbstractAllTypes&); + AbstractAllTypes& operator=(const AbstractAllTypes&); + }; + + // ------------------------------------------------------------------------------------------------- + #define BLOCK_RO( name ) \ + class name##_Type : public AbstractAllTypes \ + { \ + public: \ + name##_Type(std::string name); \ + ~name##_Type(); \ + void getOneDevice(Device* pDevice, const bool transmitNow, MultiplexingContext* pContext); \ + } + + + #define BLOCK_WO( name ) \ + class name##_Type : public AbstractAllTypes \ + { \ + public: \ + name##_Type(std::string name); \ + ~name##_Type(); \ + void setOneDevice(Device* pDevice, const bool transmitNow, MultiplexingContext* pContext); \ + void setOneDevice(Device* pDevice, name##PropertyData& data, const bool transmitNow, MultiplexingContext* pContext); \ + } + + #define BLOCK_RW( name ) \ + class name##_Type : public AbstractAllTypes \ + { \ + public: \ + name##_Type(std::string name); \ + ~name##_Type(); \ + void getOneDevice(Device* pDevice, const bool transmitNow, MultiplexingContext* pContext); \ + void setOneDevice(Device* pDevice, const bool transmitNow, MultiplexingContext* pContext); \ + void setOneDevice(Device* pDevice, name##PropertyData& data, const bool transmitNow, MultiplexingContext* pContext); \ + } + + BLOCK_RO( MyROBlock ); + BLOCK_RW( MyRWBlock ); + BLOCK_WO( MyWOBlock ); + + /*--------------------------------------------------------------------------------------------------------- + * INTERFACE + *--------------------------------------------------------------------------------------------------------- + * This is the public interface used from the FESA code to access the PLC service. + */ + class AllTypes + { + public: + static inline Silecs::Service* theService() { return AbstractAllTypes::theService(); } + static inline Silecs::Cluster* theCluster() { return AbstractAllTypes::theCluster(); } + static void setup(const ServiceLocator* serviceLocator) { AbstractAllTypes::setup(serviceLocator); } + static void cleanup() { AbstractAllTypes::cleanup(); } + + static MyROBlock_Type MyROBlock; + static MyRWBlock_Type MyRWBlock; + static MyWOBlock_Type MyWOBlock; + + }; + } + + #endif /* AllTypes_AllTypes_H_ */ + \ No newline at end of file diff --git a/silecs-codegen/src/xml/test/generated_temp/AllTypesFESA.design b/silecs-codegen/src/xml/test/generated_temp/AllTypesFESA.design new file mode 100644 index 0000000..68ba063 --- /dev/null +++ b/silecs-codegen/src/xml/test/generated_temp/AllTypesFESA.design @@ -0,0 +1,657 @@ +<?xml version="1.0" encoding="UTF-8"?> +<equipment-model xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../design-gsi.xsd"> + <information> + <class-name>MyClass</class-name> + <class-major-version>0</class-major-version> + <class-minor-version>1</class-minor-version> + <class-tiny-version>0</class-tiny-version> + <type>Final</type> + <state>development</state> + <description>An Empty design with GSI-specific standard properties</description> + <fesa-version>3.1.0</fesa-version> + <repository-path>undefined</repository-path> + </information> + <ownership> + <responsible name="CSCO"/> + <creator login="schwinn"/> + </ownership> + <interface> + <device-interface> + <setting> + <GSI-Init-Property multiplexed="false" name="Init" visibility="operational"> + <set-action partial-setting="true" transaction="true"> + <server-action-ref server-action-name-ref="InitSetAction"/> + </set-action> + </GSI-Init-Property> + <GSI-Reset-Property multiplexed="false" name="Reset" visibility="operational"> + <set-action partial-setting="true" transaction="true"> + <server-action-ref server-action-name-ref="ResetSetAction"/> + </set-action> + </GSI-Reset-Property> + <GSI-Setting-Property multiplexed="false" name="Setting" visibility="operational"> + <update-flag-item direction="OUT" name="updateFlags" optional="true"> + <builtin-type-scalar data-type-name-ref="NOTIFICATION_UPDATE"/> + </update-flag-item> + <cycle-name-item direction="OUT" name="cycleName" optional="true"> + <array type="char"> + <dim>32</dim> + </array> + </cycle-name-item> + <set-action partial-setting="true" transaction="true"> + <server-action-ref server-action-name-ref="SettingSetAction"/> + </set-action> + <get-action> + <server-action-ref server-action-name-ref="SettingGetAction"/> + </get-action> + </GSI-Setting-Property> + <GSI-Setting-Property name="MyRWBlock" multiplexed="false" visibility="development"><value-item name="RW_dt" direction="INOUT"><array2D type="double"><dim1>2</dim1><dim2>2</dim2></array2D><data-field-ref field-name-ref="RW_dt"/></value-item><value-item name="RW_real" direction="INOUT"><array2D type="float"><dim1>2</dim1><dim2>2</dim2></array2D><data-field-ref field-name-ref="RW_real"/></value-item><value-item name="RW_dint" direction="INOUT"><array2D type="int32_t"><dim1>2</dim1><dim2>2</dim2></array2D><data-field-ref field-name-ref="RW_dint"/></value-item><value-item name="RW_int" direction="INOUT"><array2D type="int16_t"><dim1>2</dim1><dim2>2</dim2></array2D><data-field-ref field-name-ref="RW_int"/></value-item><value-item name="RW_dword" direction="INOUT"><array2D type="int64_t"><dim1>2</dim1><dim2>2</dim2></array2D><data-field-ref field-name-ref="RW_dword"/></value-item><value-item name="RW_word" direction="INOUT"><array2D type="int32_t"><dim1>2</dim1><dim2>2</dim2></array2D><data-field-ref field-name-ref="RW_word"/></value-item><value-item name="RW_byte" direction="INOUT"><array2D type="int16_t"><dim1>2</dim1><dim2>2</dim2></array2D><data-field-ref field-name-ref="RW_byte"/></value-item><value-item name="RW_char" direction="INOUT"><array2D type="int8_t"><dim1>2</dim1><dim2>2</dim2></array2D><data-field-ref field-name-ref="RW_char"/></value-item><value-item name="RW_date" direction="INOUT"><array2D type="double"><dim1>2</dim1><dim2>2</dim2></array2D><data-field-ref field-name-ref="RW_date"/></value-item><value-item name="RW_float32" direction="INOUT"><array2D type="float"><dim1>2</dim1><dim2>2</dim2></array2D><data-field-ref field-name-ref="RW_float32"/></value-item><value-item name="RW_uint32" direction="INOUT"><array2D type="int64_t"><dim1>2</dim1><dim2>2</dim2></array2D><data-field-ref field-name-ref="RW_uint32"/></value-item><value-item name="RW_int32" direction="INOUT"><array2D type="int32_t"><dim1>2</dim1><dim2>2</dim2></array2D><data-field-ref field-name-ref="RW_int32"/></value-item><value-item name="RW_uint16" direction="INOUT"><array2D type="int32_t"><dim1>2</dim1><dim2>2</dim2></array2D><data-field-ref field-name-ref="RW_uint16"/></value-item><value-item name="RW_int16" direction="INOUT"><array2D type="int16_t"><dim1>2</dim1><dim2>2</dim2></array2D><data-field-ref field-name-ref="RW_int16"/></value-item><value-item name="RW_uint8" direction="INOUT"><array2D type="int16_t"><dim1>2</dim1><dim2>2</dim2></array2D><data-field-ref field-name-ref="RW_uint8"/></value-item><value-item name="RW_int8" direction="INOUT"><array2D type="int8_t"><dim1>2</dim1><dim2>2</dim2></array2D><data-field-ref field-name-ref="RW_int8"/></value-item><update-flag-item direction="OUT" optional="true" name="updateFlags"><builtin-type-scalar data-type-name-ref="NOTIFICATION_UPDATE"/></update-flag-item><cycle-name-item direction="OUT" optional="true" name="cycleName"><array type="char"><dim>32</dim></array></cycle-name-item><set-action><server-action-ref server-action-name-ref="SendMyRWBlock"/></set-action><get-action><server-action-ref server-action-name-ref="RecvMyRWBlock"/></get-action></GSI-Setting-Property><GSI-Setting-Property name="MyWOBlock" multiplexed="false" visibility="development"><value-item name="WO_dt" direction="INOUT"><array type="double"><dim>10</dim></array><data-field-ref field-name-ref="WO_dt"/></value-item><value-item name="WO_real" direction="INOUT"><array type="float"><dim>10</dim></array><data-field-ref field-name-ref="WO_real"/></value-item><value-item name="WO_dint" direction="INOUT"><array type="int32_t"><dim>10</dim></array><data-field-ref field-name-ref="WO_dint"/></value-item><value-item name="WO_int" direction="INOUT"><array type="int16_t"><dim>10</dim></array><data-field-ref field-name-ref="WO_int"/></value-item><value-item name="WO_dword" direction="INOUT"><array type="int64_t"><dim>10</dim></array><data-field-ref field-name-ref="WO_dword"/></value-item><value-item name="WO_word" direction="INOUT"><array type="int32_t"><dim>10</dim></array><data-field-ref field-name-ref="WO_word"/></value-item><value-item name="WO_byte" direction="INOUT"><array type="int16_t"><dim>10</dim></array><data-field-ref field-name-ref="WO_byte"/></value-item><value-item name="WO_char" direction="INOUT"><array type="int8_t"><dim>10</dim></array><data-field-ref field-name-ref="WO_char"/></value-item><value-item name="WO_date" direction="INOUT"><array type="double"><dim>10</dim></array><data-field-ref field-name-ref="WO_date"/></value-item><value-item name="WO_string" direction="INOUT"><array2D type="char"><dim1>10</dim1><dim2>64</dim2></array2D><data-field-ref field-name-ref="WO_string"/></value-item><value-item name="WO_float32" direction="INOUT"><array type="float"><dim>10</dim></array><data-field-ref field-name-ref="WO_float32"/></value-item><value-item name="WO_uint32" direction="INOUT"><array type="int64_t"><dim>10</dim></array><data-field-ref field-name-ref="WO_uint32"/></value-item><value-item name="WO_int32" direction="INOUT"><array type="int32_t"><dim>10</dim></array><data-field-ref field-name-ref="WO_int32"/></value-item><value-item name="WO_uint16" direction="INOUT"><array type="int32_t"><dim>10</dim></array><data-field-ref field-name-ref="WO_uint16"/></value-item><value-item name="WO_int16" direction="INOUT"><array type="int16_t"><dim>10</dim></array><data-field-ref field-name-ref="WO_int16"/></value-item><value-item name="WO_uint8" direction="INOUT"><array type="int16_t"><dim>10</dim></array><data-field-ref field-name-ref="WO_uint8"/></value-item><value-item name="WO_int8" direction="INOUT"><array type="int8_t"><dim>10</dim></array><data-field-ref field-name-ref="WO_int8"/></value-item><update-flag-item direction="OUT" optional="true" name="updateFlags"><builtin-type-scalar data-type-name-ref="NOTIFICATION_UPDATE"/></update-flag-item><cycle-name-item direction="OUT" optional="true" name="cycleName"><array type="char"><dim>32</dim></array></cycle-name-item><set-action><server-action-ref server-action-name-ref="SendMyWOBlock"/></set-action><get-action><server-action-ref server-action-name-ref="GetMyWOBlock"/></get-action></GSI-Setting-Property><GSI-Power-Property multiplexed="false" name="Power" visibility="operational"> + <update-flag-item direction="OUT" name="updateFlags" optional="true"> + <builtin-type-scalar data-type-name-ref="NOTIFICATION_UPDATE"/> + </update-flag-item> + <cycle-name-item direction="OUT" name="cycleName" optional="true"> + <array type="char"> + <dim>32</dim> + </array> + </cycle-name-item> + <set-action partial-setting="true" transaction="true"> + <server-action-ref server-action-name-ref="PowerSetAction"/> + </set-action> + <get-action> + <server-action-ref server-action-name-ref="PowerGetAction"/> + </get-action> + <power-item direction="INOUT" name="power"> + <custom-type-scalar data-type-name-ref="DEVICE_POWER"/> + + <data-field-ref field-name-ref="power"/> + </power-item> + </GSI-Power-Property> + </setting> + <acquisition> + <GSI-Status-Property multiplexed="false" name="Status" on-change="true" subscribable="true" visibility="operational"> + <acq-stamp-item direction="OUT" name="acqStamp"> + <scalar type="int64_t"/> + </acq-stamp-item> + <update-flag-item direction="OUT" name="updateFlags" optional="true"> + <builtin-type-scalar data-type-name-ref="NOTIFICATION_UPDATE"/> + </update-flag-item> + <cycle-name-item direction="OUT" name="cycleName" optional="true"> + <array type="char"> + <dim>32</dim> + </array> + </cycle-name-item> + <cycle-stamp-item direction="OUT" name="cycleStamp" optional="true"> + <scalar type="int64_t"/> + </cycle-stamp-item> + <get-action> + <server-action-ref server-action-name-ref="StatusGetAction"/> + </get-action> + <status-item direction="OUT" name="status"> + <custom-type-scalar data-type-name-ref="DEVICE_STATUS"/> + + <data-field-ref field-name-ref="status"/> + </status-item> + <detailed-status-item direction="OUT" name="detailedStatus"> + <array type="bool"> + <custom-constant-dim constant-name-ref="DETAILED_STATUS_SIZE"/> + </array> + <data-field-ref field-name-ref="detailedStatus"/> + </detailed-status-item> + <detailed-status-labels-item direction="OUT" name="detailedStatus_labels"> + <array2D type="char"> + <custom-constant-dim1 constant-name-ref="DETAILED_STATUS_SIZE"/> + <custom-constant-dim2 constant-name-ref="MAX_DETAILED_STATUS_LABEL_LENGTH"/> + </array2D> + <data-field-ref field-name-ref="detailedStatus_labels"/> + </detailed-status-labels-item> + <detailed-status-severity-item direction="OUT" name="detailedStatus_severity"> + <custom-type-array data-type-name-ref="DETAILED_STATUS_SEVERITY"> + <custom-constant-dim constant-name-ref="DETAILED_STATUS_SIZE"/> + </custom-type-array> + <data-field-ref field-name-ref="detailedStatus_severity"/> + </detailed-status-severity-item> + <powerState-item direction="OUT" name="powerState"> + <custom-type-scalar data-type-name-ref="DEVICE_POWER_STATE"/> + + <data-field-ref field-name-ref="powerState"/> + </powerState-item> + <control-item direction="OUT" name="control"> + <custom-type-scalar data-type-name-ref="DEVICE_CONTROL"/> + + <data-field-ref field-name-ref="control"/> + </control-item> + <interlock-item direction="OUT" name="interlock"> + <scalar type="bool"/> + <data-field-ref field-name-ref="interlock"/> + </interlock-item> + <opReady-item direction="OUT" name="opReady"> + <scalar type="bool"/> + <data-field-ref field-name-ref="opReady"/> + </opReady-item> + <modulesReady-item direction="OUT" name="modulesReady"> + <scalar type="bool"/> + <data-field-ref field-name-ref="modulesReady"/> + </modulesReady-item> + <error_collection-item direction="OUT"> + <error_codes direction="OUT" name="error_codes"> + <array type="int32_t"> + <custom-constant-dim constant-name-ref="MAX_NUMBER_OF_ERROR_MESSAGES"/> + </array> + </error_codes> + <error_messages direction="OUT" name="error_messages"> + <array2D type="char"> + <custom-constant-dim1 constant-name-ref="MAX_NUMBER_OF_ERROR_MESSAGES"/> + <custom-constant-dim2 constant-name-ref="MAX_ERROR_MESSAGE_LENGTH"/> + </array2D> + </error_messages> + <error_timestamps direction="OUT" name="error_timestamps"> + <array type="int64_t"> + <custom-constant-dim constant-name-ref="MAX_NUMBER_OF_ERROR_MESSAGES"/> + </array> + </error_timestamps> + <error_cycle_names direction="OUT" name="error_cycle_names"> + <array2D type="char"> + <custom-constant-dim1 constant-name-ref="MAX_NUMBER_OF_ERROR_MESSAGES"/> + <custom-constant-dim2 constant-name-ref="MAX_ERROR_MESSAGE_LENGTH"/> + </array2D> + </error_cycle_names> + <error_collection-field-ref field-name-ref="error_collection"/> + </error_collection-item> + </GSI-Status-Property> + <GSI-ModuleStatus-Property visibility="development" subscribable="true" name="ModuleStatus" multiplexed="false"> + <acq-stamp-item name="acqStamp" direction="OUT"> + <scalar type="int64_t"/> + </acq-stamp-item> + <update-flag-item optional="true" name="updateFlags" direction="OUT"> + <builtin-type-scalar data-type-name-ref="NOTIFICATION_UPDATE"/> + </update-flag-item> + <cycle-name-item optional="true" name="cycleName" direction="OUT"> + <array type="char"> + <dim>32</dim> + </array> + </cycle-name-item> + <cycle-stamp-item optional="true" name="cycleStamp" direction="OUT"> + <scalar type="int64_t"/> + </cycle-stamp-item> + <get-action> + <server-action-ref server-action-name-ref="ModuleStatusGetAction"/> + </get-action> + <module-status-item name="moduleStatus" direction="OUT"> + <custom-type-array data-type-name-ref="MODULE_STATUS"> + <custom-constant-dim constant-name-ref="MODULE_STATUS_SIZE"/> + + </custom-type-array> + + <data-field-ref field-name-ref="moduleStatus"/> + </module-status-item> + <module-status-labels-item name="moduleStatus_labels" direction="OUT"> + <array2D type="char"> + <custom-constant-dim1 constant-name-ref="MODULE_STATUS_SIZE"/> + <custom-constant-dim2 constant-name-ref="MAX_MODULE_STATUS_LABEL_LENGTH"/> + + </array2D> + + <data-field-ref field-name-ref="moduleStatus_labels"/> + </module-status-labels-item> + </GSI-ModuleStatus-Property> + <GSI-Acquisition-Property multiplexed="true" name="Acquisition" on-change="true" subscribable="true" visibility="operational"> + <acq-stamp-item direction="OUT" name="acqStamp"> + <scalar type="int64_t"/> + </acq-stamp-item> + <update-flag-item direction="OUT" name="updateFlags" optional="true"> + <builtin-type-scalar data-type-name-ref="NOTIFICATION_UPDATE"/> + </update-flag-item> + <cycle-name-item direction="OUT" name="cycleName" optional="true"> + <array type="char"> + <dim>32</dim> + </array> + </cycle-name-item> + <cycle-stamp-item direction="OUT" name="cycleStamp" optional="true"> + <scalar type="int64_t"/> + </cycle-stamp-item> + <get-action> + <server-action-ref server-action-name-ref="AcquisitionGetAction"/> + </get-action> + <acquisition-context-item direction="OUT"> + <acqStamp direction="OUT" name="acqStampGSI"> + <scalar type="int64_t"/> + </acqStamp> + <cycleStamp direction="OUT" name="cycleStampGSI"> + <scalar type="int64_t"/> + </cycleStamp> + <cycleName direction="OUT" name="cycleNameGSI"> + <array type="char"> + <custom-constant-dim constant-name-ref="MAX_CYCLE_NAME_LENGTH"/> + </array> + </cycleName> + <beamProcessID direction="OUT" name="beamProcessID"> + <scalar type="int32_t"/> + </beamProcessID> + <sequenceID direction="OUT" name="sequenceID"> + <scalar type="int32_t"/> + </sequenceID> + <acquisition-context-field-ref field-name-ref="acquisitionContext"/> + </acquisition-context-item> + </GSI-Acquisition-Property> + <GSI-Acquisition-Property name="MyROBlock" subscribable="true" multiplexed="false" on-change="true" visibility="development"><value-item name="RO_dt" direction="OUT"><scalar type="double"/><data-field-ref field-name-ref="RO_dt"/></value-item><value-item name="RO_real" direction="OUT"><scalar type="float"/><data-field-ref field-name-ref="RO_real"/></value-item><value-item name="RO_dint" direction="OUT"><scalar type="int32_t"/><data-field-ref field-name-ref="RO_dint"/></value-item><value-item name="RO_int" direction="OUT"><scalar type="int16_t"/><data-field-ref field-name-ref="RO_int"/></value-item><value-item name="RO_dword" direction="OUT"><scalar type="int64_t"/><data-field-ref field-name-ref="RO_dword"/></value-item><value-item name="RO_word" direction="OUT"><scalar type="int32_t"/><data-field-ref field-name-ref="RO_word"/></value-item><value-item name="RO_byte" direction="OUT"><scalar type="int16_t"/><data-field-ref field-name-ref="RO_byte"/></value-item><value-item name="RO_char" direction="OUT"><scalar type="int8_t"/><data-field-ref field-name-ref="RO_char"/></value-item><value-item name="RO_date" direction="OUT"><scalar type="double"/><data-field-ref field-name-ref="RO_date"/></value-item><value-item name="RO_string" direction="OUT"><array type="char"><dim>64</dim></array><data-field-ref field-name-ref="RO_string"/></value-item><value-item name="RO_float32" direction="OUT"><scalar type="float"/><data-field-ref field-name-ref="RO_float32"/></value-item><value-item name="RO_uint32" direction="OUT"><scalar type="int64_t"/><data-field-ref field-name-ref="RO_uint32"/></value-item><value-item name="RO_int32" direction="OUT"><scalar type="int32_t"/><data-field-ref field-name-ref="RO_int32"/></value-item><value-item name="RO_uint16" direction="OUT"><scalar type="int32_t"/><data-field-ref field-name-ref="RO_uint16"/></value-item><value-item name="RO_int16" direction="OUT"><scalar type="int16_t"/><data-field-ref field-name-ref="RO_int16"/></value-item><value-item name="RO_uint8" direction="OUT"><scalar type="int16_t"/><data-field-ref field-name-ref="RO_uint8"/></value-item><value-item name="RO_int8" direction="OUT"><scalar type="int8_t"/><data-field-ref field-name-ref="RO_int8"/></value-item><acq-stamp-item direction="OUT" name="acqStamp"><scalar type="int64_t"/></acq-stamp-item><update-flag-item direction="OUT" optional="true" name="updateFlags"><builtin-type-scalar data-type-name-ref="NOTIFICATION_UPDATE"/></update-flag-item><cycle-name-item direction="OUT" optional="true" name="cycleName"><array type="char"><dim>32</dim></array></cycle-name-item><cycle-stamp-item direction="OUT" optional="true" name="cycleStamp"><scalar type="int64_t"/></cycle-stamp-item><get-action><server-action-ref server-action-name-ref="GetMyROBlock"/></get-action><acquisition-context-item direction="OUT"><processIndex direction="OUT" name="processIndex"><scalar type="int32_t"/></processIndex><sequenceIndex direction="OUT" name="sequenceIndex"><scalar type="int32_t"/></sequenceIndex><chainIndex direction="OUT" name="chainIndex"><scalar type="int32_t"/></chainIndex><eventNumber direction="OUT" name="eventNumber"><scalar type="int32_t"/></eventNumber><timingGroupID direction="OUT" name="timingGroupID"><scalar type="int32_t"/></timingGroupID><acquisitionStamp direction="OUT" name="acquisitionStamp"><scalar type="int64_t"/></acquisitionStamp><eventStamp direction="OUT" name="eventStamp"><scalar type="int64_t"/></eventStamp><processStartStamp direction="OUT" name="processStartStamp"><scalar type="int64_t"/></processStartStamp><sequenceStartStamp direction="OUT" name="sequenceStartStamp"><scalar type="int64_t"/></sequenceStartStamp><chainStartStamp direction="OUT" name="chainStartStamp"><scalar type="int64_t"/></chainStartStamp><acquisition-context-field-ref field-name-ref="acquisitionContext"/></acquisition-context-item></GSI-Acquisition-Property><GSI-Version-Property multiplexed="false" name="Version" on-change="false" subscribable="false" visibility="operational"> + <acq-stamp-item direction="OUT" name="acqStamp"> + <scalar type="int64_t"/> + </acq-stamp-item> + <update-flag-item direction="OUT" name="updateFlags" optional="true"> + <builtin-type-scalar data-type-name-ref="NOTIFICATION_UPDATE"/> + </update-flag-item> + <cycle-name-item direction="OUT" name="cycleName" optional="true"> + <array type="char"> + <dim>32</dim> + </array> + </cycle-name-item> + <cycle-stamp-item direction="OUT" name="cycleStamp" optional="true"> + <scalar type="int64_t"/> + </cycle-stamp-item> + <get-action> + <server-action-ref server-action-name-ref="VersionGetAction"/> + </get-action> + <version-item direction="OUT" name="classVersion"> + <array type="char"> + <custom-constant-dim constant-name-ref="MAX_VERSION_NAME_LENGTH"/> + </array> + </version-item> + <version-item direction="OUT" name="deployUnitVersion"> + <array type="char"> + <custom-constant-dim constant-name-ref="MAX_VERSION_NAME_LENGTH"/> + </array> + </version-item> + <version-item direction="OUT" name="fesaVersion"> + <array type="char"> + <custom-constant-dim constant-name-ref="MAX_VERSION_NAME_LENGTH"/> + </array> + </version-item> + </GSI-Version-Property> + </acquisition> + </device-interface> + <global-interface> + <setting> + <diagnostic-property multiplexed="false" name="DiagnosticSetting" visibility="expert"> + <description>Generic property which allows to diagnose any FESA classes</description> + <mode-item direction="INOUT" name="enableDiagMode"> + <scalar type="bool"/> + </mode-item> + <host-item direction="INOUT" name="hostName"> + <array type="char"> + <dim>32</dim> + </array> + </host-item> + <port-item direction="INOUT" name="portNumber"> + <scalar type="int32_t"/> + </port-item> + <config-item direction="IN" name="requestConfig"> + <scalar type="bool"/> + </config-item> + <state-item direction="IN" name="requestState"> + <scalar type="bool"/> + </state-item> + <fwk-topic-item direction="INOUT" name="fwkTopic"> + <builtin-type-scalar data-type-name-ref="DIAG_FWK_TOPIC"/> + </fwk-topic-item> + <custom-topic-item direction="INOUT" name="customTopic"> + <custom-type-scalar data-type-name-ref="DIAG_TOPIC"/> + </custom-topic-item> + <device-trace-item direction="INOUT" name="traceDevices"> + <array type="char"> + <dim>320</dim> + </array> + </device-trace-item> + <bypass-action-item direction="INOUT" name="bypassActions"> + <array type="char"> + <dim>320</dim> + </array> + </bypass-action-item> + </diagnostic-property> + </setting> + <acquisition> + <GSI-DeviceDescription-Property multiplexed="false" name="DeviceDescription" on-change="false" subscribable="false" visibility="operational"> + <timing-info-item direction="OUT" name="deviceNameTimingReceiver"> + <array type="char"> + <variable-dim/> + </array> + <data-field-ref field-name-ref="deviceNameTimingReceiver"/> + </timing-info-item> + <property-info-item direction="OUT" name="propertyNames"> + <array2D type="char"> + <variable-dim1/> + <variable-dim2/> + </array2D> + </property-info-item> + <device-info-item direction="OUT" name="deviceNames"> + <array2D type="char"> + <variable-dim1/> + <variable-dim2/> + </array2D> + </device-info-item> + <global-device-info-item direction="OUT" name="globalDeviceName"> + <array type="char"> + <variable-dim/> + </array> + </global-device-info-item> + <host-info-item direction="OUT" name="host"> + <array type="char"> + <variable-dim/> + </array> + </host-info-item> + </GSI-DeviceDescription-Property> + </acquisition> + </global-interface> + </interface> + <builtin-types> + <notification-update-enum name="NOTIFICATION_UPDATE"> + <IMMEDIATE access="RO" symbol="IMMEDIATE" value="1"/> + <SET access="RO" symbol="SET" value="2"/> + </notification-update-enum> + <diag-fwk-topic name="DIAG_FWK_TOPIC"> + <b0 name="SRV_GET_ACTION_PROFIING"/> + <b1 name="SRV_SET_ACTION_PROFILING"/> + <b2 name="RT_ACTION_PROFILING"/> + <b3 name="EVENT_PROFILING"/> + <b4 name="NOTIFICATION_PROFILING"/> + <b5 name="SRV_GET_ACTION_TRACKING"/> + <b6 name="SRV_SET_ACTION_TRACKING"/> + <b7 name="RT_ACTION_TRACKING"/> + <b8 name="EVENT_TRACKING"/> + <b9 name="NOTIFICATION_TRACKING"/> + <b10 name="PERSISTENCY_TRACKING"/> + <b11 name="TRANSACTION_TRACKING"/> + <b12 name="SUBSCRIPTION_TRACKING"/> + <b13 name="SIGNAL_HANDLER_TRACKING"/> + <b14 name="LOCAL_CONNECTION_TRACKING"/> + </diag-fwk-topic> + <fault-severity name="FaultSeverity"> + <description>Enumeration listing the available fault severities used by the fault fields</description> + <INFO access="RO" meaning="NONE" value="0" symbol="INFO"/> + <WARNING access="RO" meaning="WARNING" value="1" symbol="WARNING"/> + <ERROR access="RO" meaning="ERROR" value="2" symbol="ERROR"/> + <CRITICAL access="RO" meaning="ERROR" value="3" symbol="CRITICAL"/> + </fault-severity> + + </builtin-types> + <custom-types> + <diag-custom-topic name="DIAG_TOPIC"> + </diag-custom-topic> + <enum name="DEVICE_STATUS"> + <!--Possible (mutually exclusive) values to describe the device status--> + + <item access="RW" meaning="NONE" symbol="UNKNOWN" value="0"/> + <!--The device status is unknown--> + + <item access="RW" meaning="NONE" symbol="OK" value="1"/> + <!--The device is in fully operational state--> + + <item access="RW" meaning="NONE" symbol="WARNING" value="2"/> + <!--The device is not fully operational; A device in WARNING state can still be used operationally, --> + <!--but clients must be informed of a problem that might become worse. Details are explained in the errorMsg field.--> + + <item access="RW" meaning="NONE" symbol="ERROR" value="3"/> + <!--The device is in a fault state. Details are explained in the errorMsg field--> + </enum> + <enum name="DEVICE_POWER_STATE"> + <!--Possible (mutually exclusive) values to describe the power-state of the device.--> + + <item access="RW" meaning="NONE" symbol="UNKNOWN" value="0"/> + <!--The device mode is unknown--> + + <item access="RW" meaning="ON" symbol="ON" value="1"/> + <!--The device is in fully operational state--> + + <item access="RW" meaning="NONE" symbol="OFF" value="2"/> + <!--The device is turned off--> + + <item access="RW" meaning="NONE" symbol="STANDBY" value="3"/> + <!--The device is in a stand-by mode. This mode is a sort of “parking mode†in which the device can --> + <!--stay for hours or even days. It is defined by the following characteristics:--> + <!--It is safe, it does not wear out, it consumes little energy.--> + <!--Furthermore, it takes a short time to go from STANDBY to ON mode--> + + <item access="RW" meaning="NONE" symbol="POWER_DOWN" value="4"/> + <!--The device is shutting down. Note that some properties may not be accessible during this time.--> + <!--After shutdown the device will be in the mode OFF--> + + <item access="RW" meaning="NONE" symbol="POWER_UP" value="5"/> + <!--The device is starting up. Note that some properties may not be accessible during this time.--> + <!--After (re-)starting the device probably will be in the mode ON--> + + </enum> + <enum name="DEVICE_POWER"> + <!--An enumeration Type used to control the operational mode of the device.--> + <!--Its values are a subset of those in the DEVICE_POWER_STATE type--> + <item access="RW" meaning="ON" symbol="ON" value="1"/> + <!--The device is in fully operational state--> + + <item access="RW" meaning="OFF" symbol="OFF" value="2"/> + <!--The device is turned off--> + </enum> + <enum name="DEVICE_CONTROL"> + <!--Possible values to describe the control mode of a device--> + <!--Currently two control modes (LOCAL, REMOTE) are defined--> + + <item access="RW" meaning="NONE" symbol="REMOTE" value="0"/> + <!--The device can be controlled normally through the control system--> + + <item access="RW" meaning="NONE" symbol="LOCAL" value="1"/> + <!--The device can be controlled locally. But it can be accessed in read-only mode via the control system--> + </enum> + <enum name="TOL_CHECK_MODE"> + <!--This constant defines possible modes to check whether a control value is inside the tolerance values.--> + <!--Used to give information on how the tolerance fields are used to calculate the xxx_status information.--> + + <item access="RO" symbol="ABS" value="0"/> + <!--Use the absolute tolerance _tolAbs--> + + <item access="RO" symbol="REL" value="1"/> + <!--Use the relative tolerance _tolRel--> + </enum> + <bit-enum-32bits name="AQN_STATUS"> + <!--Possible values to describe the acquisition status of a field (in the _status suffix)--> + <!--If this suffix is missing, it means that no additional status information is provided for the corresponding field--> + <!--If all bits are 0, this means that the corresponding field is OK.--> + <!--Only the lower 16 bits are standardized, the upper 16 bits can be defined by the equipment specialist.--> + <!--The difference between the Status property and the _status suffix is described in the section on the Status property.--> + <b0 name="NOT_OK"/> + <!--Some problem occurred that is not represented by the other bits. This property is called--> + <!-- NOT_OK so that it is not mixed up with ERROR or WARNING in the Status property--> + <b1 name="BAD_QUALITY"/> + <!--The value was acquired with a degraded quality. This is typically used for measurements.--> + <b2 name="DIFFERENT_FROM_SETTING"/> + <!--Different from the requested control value (for discrete values)--><!--or out of tolerance (for continuous values).--> + <b3 name="OUT_OF_RANGE"/> + <!--The value is out of the normal range (e.g. a temperature is too high or too low).--> + <b4 name="BUSY"/> + <!--The property value is changing in response to receiving a new control value (e.g. moving to a--> + <!--new position, charging a capacitor, ...). If the value change does not reach the requested new--> + <!--value within the maximum timeout, the BUSY bit should remain=1 and the TIMEOUT bit must be turned on.--> + <b5 name="TIMEOUT"/> + <!--A timeout occurred, because the property did not reach the reqested new control value within the--> + <!--maximum allowable time. A timeout normally indicates a problem to be addressed by the--> + <!--equipment specialist. This is typically used for slow changing control values that are BUSY while they change.--> + <b6 name="bit6_is_reserved_for_later_usage"/> + <b7 name="bit7_is_reserved_for_later_usage"/> + <b8 name="bit8_is_reserved_for_later_usage"/> + <b9 name="bit9_is_reserved_for_later_usage"/> + <b10 name="bit10_is_reserved_for_later_usage"/> + <b11 name="bit11_is_reserved_for_later_usage"/> + <b12 name="bit12_is_reserved_for_later_usage"/> + <b13 name="bit13_is_reserved_for_later_usage"/> + <b14 name="bit14_is_reserved_for_later_usage"/> + <b15 name="bit15_is_reserved_for_later_usage"/> + <!--bit 6 to 15 are reserved ... dont use them!--> + + <b16 name="bit_16_and_higher_can_be_used_by_the_class_developer"/> + <!--into bit 16..32 you can put in anything you want--> + </bit-enum-32bits> + + <struct name="GSI_ERROR"> + <!--This struct-item describes the structure of an GSI-error--> + <struct-item name="error_string"> + <!--This string holds the error-message--> + <array type="char"> + <custom-constant-dim constant-name-ref="MAX_ERROR_MESSAGE_LENGTH"/> + </array> + </struct-item> + <struct-item name="error_code"> + <!--The error code according to the defined error-message--> + <scalar type="int32_t"/> + </struct-item> + <!--The timestamp when the error occured--> + <struct-item name="error_timestamp"> + <scalar type="int64_t"/> + </struct-item> + <!--The cycle for which the error occured--> + <struct-item name="error_cycle_name"> + <array type="char"> + <custom-constant-dim constant-name-ref="MAX_CYCLE_NAME_LENGTH"/> + </array> + </struct-item> + </struct> + <struct name="GSI_ACQ_CONTEXT"> + <!--This struct-item describes all AcquisitionContext items which are relevant for GSI--> + <struct-item name="acqStamp"> + <!--The acquisition stamp is used to indicate when a measurement was done --> + <scalar type="int64_t"/> + </struct-item> + <struct-item name="cycleStamp"> + <!--The cycle stamp is used to indicate when a specific cycle has started--> + <scalar type="int64_t"/> + </struct-item> + <struct-item name="cycleName"> + <!--The cycle name indicates the cycle which started at time of the cycleStamp --> + <array type="char"> + <custom-constant-dim constant-name-ref="MAX_CYCLE_NAME_LENGTH"/> + </array> + </struct-item> + <struct-item name="beamProcessID"> + <scalar type="int32_t"/> + </struct-item> + <struct-item name="sequenceID"> + <scalar type="int32_t"/> + </struct-item> + </struct> + <constant name="MAX_ERROR_MESSAGE_LENGTH" type="uint32_t" value="256"/> + <constant name="MAX_NUMBER_OF_ERROR_MESSAGES" type="uint32_t" value="16"/> + <constant name="MAX_CYCLE_NAME_LENGTH" type="uint32_t" value="256"/> + <constant name="MAX_VERSION_NAME_LENGTH" type="uint32_t" value="256"/> + <constant name="MAX_DETAILED_STATUS_LABEL_LENGTH" type="uint32_t" value="30"/> + <constant name="DETAILED_STATUS_SIZE" type="uint32_t" value="2"/> + <enum name="DETAILED_STATUS_SEVERITY"> + <item access="RO" symbol="INFO" value="0"/> + <item access="RO" symbol="WARNING_ON_FALSE" value="1"/> + <item access="RO" symbol="ERROR_ON_FALSE" value="2"/> + </enum> + <enum name="MODULE_STATUS"> + <!-- Mutually exclusive values to describe the status of a hardware / software module--> + <item access="RO" value="0" symbol="UNKNOWN"/> + <!--The status of the module is not known--> + <item access="RO" value="1" symbol="OK"/> + <!--The module is in fully operational state--> + <item access="RO" value="2" symbol="WARNING"/> + <!--The module is not fully operational; A module in WARNING state may still be used operationally, --> + <!--but clients must be informed of a problem that might become worse. --> + <item access="RO" value="3" symbol="ERROR"/> + <!--The module is in a fault state. The related device is not operational.--> + <item access="RO" value="4" symbol="NOT_AVAILABLE"/> + <!--The module is missing. The related device is not operational.--> + </enum> + <constant name="MAX_MODULE_STATUS_LABEL_LENGTH" type="uint32_t" value="30"/> + <constant name="MODULE_STATUS_SIZE" type="uint32_t" value="2"/> + </custom-types> + <data> + <device-data> + <configuration> + <field name="parameterFile"><description>ParameterFile of the PLC (*.silecsparam)</description><array type="char"><dim>512</dim></array><default>../../../generated/client/MyControllerName.silecsparam</default></field><field name="plcDeviceLabel"><description>Name of the related SILECS instance within the PLC mapping</description><array type="char"><dim>128</dim></array></field><field name="plcHostName"><description>Hostname of the PLC that contains the related SILECS class device</description><array type="char"><dim>128</dim></array></field><GSI-detailed-status-labels-field name="detailedStatus_labels"> + <array2D type="char"> + <custom-constant-dim1 constant-name-ref="DETAILED_STATUS_SIZE"/> + <custom-constant-dim2 constant-name-ref="MAX_DETAILED_STATUS_LABEL_LENGTH"/> + </array2D> + <default>{myStatusLabel1,myStatusLabel2}</default> + </GSI-detailed-status-labels-field> + <GSI-detailed-status-severity-field name="detailedStatus_severity"> + <custom-type-array data-type-name-ref="DETAILED_STATUS_SEVERITY"> + <custom-constant-dim constant-name-ref="DETAILED_STATUS_SIZE"/> + </custom-type-array> + <default>{INFO,INFO}</default> + </GSI-detailed-status-severity-field> + <GSI-module-status-labels-field name="moduleStatus_labels"> + <array2D type="char"> + <custom-constant-dim1 constant-name-ref="MODULE_STATUS_SIZE"/> + + <custom-constant-dim2 constant-name-ref="MAX_MODULE_STATUS_LABEL_LENGTH"/> + </array2D> + <default>{myModule1,myModule2}</default> + </GSI-module-status-labels-field> + </configuration> + <setting> + <field name="WO_dt" shared="true" multiplexed="false" persistent="true"><array type="double"><dim>10</dim></array></field><field name="WO_real" shared="true" multiplexed="false" persistent="true"><array type="float"><dim>10</dim></array></field><field name="WO_dint" shared="true" multiplexed="false" persistent="true"><array type="int32_t"><dim>10</dim></array></field><field name="WO_int" shared="true" multiplexed="false" persistent="true"><array type="int16_t"><dim>10</dim></array></field><field name="WO_dword" shared="true" multiplexed="false" persistent="true"><array type="int64_t"><dim>10</dim></array></field><field name="WO_word" shared="true" multiplexed="false" persistent="true"><array type="int32_t"><dim>10</dim></array></field><field name="WO_byte" shared="true" multiplexed="false" persistent="true"><array type="int16_t"><dim>10</dim></array></field><field name="WO_char" shared="true" multiplexed="false" persistent="true"><array type="int8_t"><dim>10</dim></array></field><field name="WO_date" shared="true" multiplexed="false" persistent="true"><array type="double"><dim>10</dim></array></field><field name="WO_string" shared="true" multiplexed="false" persistent="true"><array2D type="char"><dim1>10</dim1><dim2>64</dim2></array2D></field><field name="WO_float32" shared="true" multiplexed="false" persistent="true"><array type="float"><dim>10</dim></array></field><field name="WO_uint32" shared="true" multiplexed="false" persistent="true"><array type="int64_t"><dim>10</dim></array></field><field name="WO_int32" shared="true" multiplexed="false" persistent="true"><array type="int32_t"><dim>10</dim></array></field><field name="WO_uint16" shared="true" multiplexed="false" persistent="true"><array type="int32_t"><dim>10</dim></array></field><field name="WO_int16" shared="true" multiplexed="false" persistent="true"><array type="int16_t"><dim>10</dim></array></field><field name="WO_uint8" shared="true" multiplexed="false" persistent="true"><array type="int16_t"><dim>10</dim></array></field><field name="WO_int8" shared="true" multiplexed="false" persistent="true"><array type="int8_t"><dim>10</dim></array></field><field name="RW_dt" multiplexed="false" persistent="true"><array2D type="double"><dim1>2</dim1><dim2>2</dim2></array2D></field><field name="RW_real" multiplexed="false" persistent="true"><array2D type="float"><dim1>2</dim1><dim2>2</dim2></array2D></field><field name="RW_dint" multiplexed="false" persistent="true"><array2D type="int32_t"><dim1>2</dim1><dim2>2</dim2></array2D></field><field name="RW_int" multiplexed="false" persistent="true"><array2D type="int16_t"><dim1>2</dim1><dim2>2</dim2></array2D></field><field name="RW_dword" multiplexed="false" persistent="true"><array2D type="int64_t"><dim1>2</dim1><dim2>2</dim2></array2D></field><field name="RW_word" multiplexed="false" persistent="true"><array2D type="int32_t"><dim1>2</dim1><dim2>2</dim2></array2D></field><field name="RW_byte" multiplexed="false" persistent="true"><array2D type="int16_t"><dim1>2</dim1><dim2>2</dim2></array2D></field><field name="RW_char" multiplexed="false" persistent="true"><array2D type="int8_t"><dim1>2</dim1><dim2>2</dim2></array2D></field><field name="RW_date" multiplexed="false" persistent="true"><array2D type="double"><dim1>2</dim1><dim2>2</dim2></array2D></field><field name="RW_float32" multiplexed="false" persistent="true"><array2D type="float"><dim1>2</dim1><dim2>2</dim2></array2D></field><field name="RW_uint32" multiplexed="false" persistent="true"><array2D type="int64_t"><dim1>2</dim1><dim2>2</dim2></array2D></field><field name="RW_int32" multiplexed="false" persistent="true"><array2D type="int32_t"><dim1>2</dim1><dim2>2</dim2></array2D></field><field name="RW_uint16" multiplexed="false" persistent="true"><array2D type="int32_t"><dim1>2</dim1><dim2>2</dim2></array2D></field><field name="RW_int16" multiplexed="false" persistent="true"><array2D type="int16_t"><dim1>2</dim1><dim2>2</dim2></array2D></field><field name="RW_uint8" multiplexed="false" persistent="true"><array2D type="int16_t"><dim1>2</dim1><dim2>2</dim2></array2D></field><field name="RW_int8" multiplexed="false" persistent="true"><array2D type="int8_t"><dim1>2</dim1><dim2>2</dim2></array2D></field><GSI-power-field multiplexed="false" name="power" persistent="false"> + <custom-type-scalar data-type-name-ref="DEVICE_POWER"/> + </GSI-power-field> + </setting> + <acquisition> + <field name="RO_dt" multiplexed="false" persistent="false"><scalar type="double"/></field><field name="RO_real" multiplexed="false" persistent="false"><scalar type="float"/></field><field name="RO_dint" multiplexed="false" persistent="false"><scalar type="int32_t"/></field><field name="RO_int" multiplexed="false" persistent="false"><scalar type="int16_t"/></field><field name="RO_dword" multiplexed="false" persistent="false"><scalar type="int64_t"/></field><field name="RO_word" multiplexed="false" persistent="false"><scalar type="int32_t"/></field><field name="RO_byte" multiplexed="false" persistent="false"><scalar type="int16_t"/></field><field name="RO_char" multiplexed="false" persistent="false"><scalar type="int8_t"/></field><field name="RO_date" multiplexed="false" persistent="false"><scalar type="double"/></field><field name="RO_string" multiplexed="false" persistent="false"><array type="char"><dim>64</dim></array></field><field name="RO_float32" multiplexed="false" persistent="false"><scalar type="float"/></field><field name="RO_uint32" multiplexed="false" persistent="false"><scalar type="int64_t"/></field><field name="RO_int32" multiplexed="false" persistent="false"><scalar type="int32_t"/></field><field name="RO_uint16" multiplexed="false" persistent="false"><scalar type="int32_t"/></field><field name="RO_int16" multiplexed="false" persistent="false"><scalar type="int16_t"/></field><field name="RO_uint8" multiplexed="false" persistent="false"><scalar type="int16_t"/></field><field name="RO_int8" multiplexed="false" persistent="false"><scalar type="int8_t"/></field><GSI-control-field multiplexed="false" name="control"> + <custom-type-scalar data-type-name-ref="DEVICE_CONTROL"/> + </GSI-control-field> + <GSI-powerState-field multiplexed="false" name="powerState"> + <custom-type-scalar data-type-name-ref="DEVICE_POWER_STATE"/> + </GSI-powerState-field> + <GSI-status-field multiplexed="false" name="status"> + <custom-type-scalar data-type-name-ref="DEVICE_STATUS"/> + </GSI-status-field> + <GSI-interlock-field multiplexed="false" name="interlock"> + <scalar type="bool"/> + </GSI-interlock-field> + <GSI-opReady-field multiplexed="false" name="opReady"> + <scalar type="bool"/> + </GSI-opReady-field> + <GSI-modulesReady-field name="modulesReady" multiplexed="false"> + <scalar type="bool"/> + </GSI-modulesReady-field> + <GSI-detailed-status-field multiplexed="false" name="detailedStatus"> + <array type="bool"> + <custom-constant-dim constant-name-ref="DETAILED_STATUS_SIZE"/> + </array> + </GSI-detailed-status-field> + <GSI-module-status-field name="moduleStatus" multiplexed="false"> + <custom-type-array data-type-name-ref="MODULE_STATUS"> + <custom-constant-dim constant-name-ref="MODULE_STATUS_SIZE"/> + + </custom-type-array> + </GSI-module-status-field> + <GSI-acquisition-context-field multiplexed="true" name="acquisitionContext"> + <custom-type-scalar data-type-name-ref="GSI_ACQ_CONTEXT"/> + </GSI-acquisition-context-field> + <GSI-error_collection-field multiplexed="false" name="error_collection"> + <custom-type-array data-type-name-ref="GSI_ERROR"> + <custom-constant-dim constant-name-ref="MAX_NUMBER_OF_ERROR_MESSAGES"/> + </custom-type-array> + </GSI-error_collection-field> + </acquisition> + </device-data> + <global-data> + <configuration> + <!-- The name of the timing receiver --> + <field name="plcClassVersion"><description>Version of the SILECS class that needs to be deployed in the controller</description><array type="char"><dim>5</dim></array><default>0.1.0</default></field><GSI-timing-receiver-name-field name="deviceNameTimingReceiver"> + <array type="char"> + <!-- The number of the timing receiver --> + <variable-dim/> + </array> + </GSI-timing-receiver-name-field> + </configuration> + </global-data> + </data> + <actions> + <set-server-action implementation="default" name="InitSetAction"/> + <set-server-action implementation="default" name="ResetSetAction"/> + <set-server-action implementation="default" name="SettingSetAction"/> + <set-server-action implementation="default" name="PowerSetAction"/> + <get-server-action implementation="default" name="PowerGetAction"/> + <get-server-action implementation="default" name="SettingGetAction"/> + <get-server-action implementation="default" name="AcquisitionGetAction"/> + <get-server-action implementation="default" name="StatusGetAction"/> + <get-server-action implementation="default" name="VersionGetAction"/><get-server-action implementation="default" name="ModuleStatusGetAction"/> + <get-server-action name="GetMyROBlock" implementation="default"/><rt-action name="RecvMyROBlock"><notified-property property-name-ref="MyROBlock" automatic="true"/></rt-action><set-server-action name="SendMyRWBlock" implementation="custom"/><get-server-action name="RecvMyRWBlock" implementation="custom"/><set-server-action name="SendMyWOBlock" implementation="custom"/><get-server-action name="GetMyWOBlock" implementation="default"/></actions> + +<events><sources><timing-event-source name="Timing"/><timer-event-source name="Timer"/></sources><logical-events><logical-event name="RecvMyROBlockEvent" use="required" type="timer"/></logical-events></events><scheduling-units><scheduling-unit name="RecvMyROBlockUnit"><rt-action-ref rt-action-name-ref="RecvMyROBlock"/><logical-event-ref logical-event-name-ref="RecvMyROBlockEvent"/></scheduling-unit></scheduling-units></equipment-model> diff --git a/silecs-codegen/src/xml/test/generated_temp/client/Beckhoff_BC9020.silecsparam b/silecs-codegen/src/xml/test/generated_temp/client/Beckhoff_BC9020.silecsparam new file mode 100644 index 0000000..2d941be --- /dev/null +++ b/silecs-codegen/src/xml/test/generated_temp/client/Beckhoff_BC9020.silecsparam @@ -0,0 +1,80 @@ +<?xml version="1.0"?> +<SILECS-Param silecs-version="DEV"> + <Mapping-Info> + <Owner user-login="schwinn"/> + <Generation date="2016-07-26 15:37:54.682340"/> + <Deployment checksum="2843029646"/> + </Mapping-Info> + <SILECS-Mapping plc-name="Beckhoff_BC9020" plc-brand="BECKHOFF" plc-system="TWINCat" plc-model="BC9020" protocol="BLOCK_MODE" address="32768" domain="NotUsed" used-mem="TODO"> + <SILECS-Class name="SilecsHeader" version="1.0.0" address="32768" used-mem="MW16384..MW16407 / 24 words"> + <Block name="hdrBlk" mode="READ-ONLY" size="14" address="32768" mem-size="48"> + <Register name="_version" format="string" string-len="16" array-dim1="1" array-dim2="1" size="1" address="0" mem-size="17" synchro="MASTER"/> + <Register name="_checksum" format="uint32" array-dim1="1" array-dim2="1" size="4" address="18" mem-size="4" synchro="MASTER"/> + <Register name="_user" format="string" string-len="16" array-dim1="1" array-dim2="1" size="1" address="22" mem-size="17" synchro="MASTER"/> + <Register name="_date" format="dt" array-dim1="1" array-dim2="1" size="8" address="40" mem-size="8" synchro="MASTER"/> + </Block> + <Instance label="SilecsHeader" address="0"/> + </SILECS-Class> + <SILECS-Class name="AllTypes" version="0.1.0" address="32816" used-mem="MW16408..MW18167 / 1760 words"> + <Block name="MyROBlock" mode="READ-ONLY" size="53" address="32816" mem-size="122"> + <Register name="RO_int8" format="int8" array-dim1="1" array-dim2="1" size="1" address="0" mem-size="1" synchro="MASTER"/> + <Register name="RO_uint8" format="uint8" array-dim1="1" array-dim2="1" size="1" address="2" mem-size="1" synchro="MASTER"/> + <Register name="RO_int16" format="int16" array-dim1="1" array-dim2="1" size="2" address="4" mem-size="2" synchro="MASTER"/> + <Register name="RO_uint16" format="uint16" array-dim1="1" array-dim2="1" size="2" address="6" mem-size="2" synchro="MASTER"/> + <Register name="RO_int32" format="int32" array-dim1="1" array-dim2="1" size="4" address="8" mem-size="4" synchro="MASTER"/> + <Register name="RO_uint32" format="uint32" array-dim1="1" array-dim2="1" size="4" address="12" mem-size="4" synchro="MASTER"/> + <Register name="RO_float32" format="float32" array-dim1="1" array-dim2="1" size="4" address="16" mem-size="4" synchro="MASTER"/> + <Register name="RO_string" format="string" string-len="64" array-dim1="1" array-dim2="1" size="1" address="20" mem-size="65" synchro="MASTER"/> + <Register name="RO_date" format="date" array-dim1="1" array-dim2="1" size="8" address="86" mem-size="8" synchro="MASTER"/> + <Register name="RO_char" format="char" array-dim1="1" array-dim2="1" size="1" address="94" mem-size="1" synchro="MASTER"/> + <Register name="RO_byte" format="byte" array-dim1="1" array-dim2="1" size="1" address="96" mem-size="1" synchro="MASTER"/> + <Register name="RO_word" format="word" array-dim1="1" array-dim2="1" size="2" address="98" mem-size="2" synchro="MASTER"/> + <Register name="RO_dword" format="dword" array-dim1="1" array-dim2="1" size="4" address="100" mem-size="4" synchro="MASTER"/> + <Register name="RO_int" format="int" array-dim1="1" array-dim2="1" size="2" address="104" mem-size="2" synchro="MASTER"/> + <Register name="RO_dint" format="dint" array-dim1="1" array-dim2="1" size="4" address="106" mem-size="4" synchro="MASTER"/> + <Register name="RO_real" format="real" array-dim1="1" array-dim2="1" size="4" address="110" mem-size="4" synchro="MASTER"/> + <Register name="RO_dt" format="dt" array-dim1="1" array-dim2="1" size="8" address="114" mem-size="8" synchro="MASTER"/> + </Block> + <Block name="MyRWBlock" mode="READ-WRITE" size="212" address="33060" mem-size="468"> + <Register name="RW_int8" format="int8" array-dim1="2" array-dim2="2" size="1" address="0" mem-size="4" synchro="MASTER"/> + <Register name="RW_uint8" format="uint8" array-dim1="2" array-dim2="2" size="1" address="4" mem-size="4" synchro="MASTER"/> + <Register name="RW_int16" format="int16" array-dim1="2" array-dim2="2" size="2" address="8" mem-size="8" synchro="MASTER"/> + <Register name="RW_uint16" format="uint16" array-dim1="2" array-dim2="2" size="2" address="16" mem-size="8" synchro="MASTER"/> + <Register name="RW_int32" format="int32" array-dim1="2" array-dim2="2" size="4" address="24" mem-size="16" synchro="MASTER"/> + <Register name="RW_uint32" format="uint32" array-dim1="2" array-dim2="2" size="4" address="40" mem-size="16" synchro="MASTER"/> + <Register name="RW_float32" format="float32" array-dim1="2" array-dim2="2" size="4" address="56" mem-size="16" synchro="MASTER"/> + <Register name="RW_string" format="string" string-len="64" array-dim1="2" array-dim2="2" size="1" address="72" mem-size="260" synchro="MASTER"/> + <Register name="RW_date" format="date" array-dim1="2" array-dim2="2" size="8" address="332" mem-size="32" synchro="MASTER"/> + <Register name="RW_char" format="char" array-dim1="2" array-dim2="2" size="1" address="364" mem-size="4" synchro="MASTER"/> + <Register name="RW_byte" format="byte" array-dim1="2" array-dim2="2" size="1" address="368" mem-size="4" synchro="MASTER"/> + <Register name="RW_word" format="word" array-dim1="2" array-dim2="2" size="2" address="372" mem-size="8" synchro="MASTER"/> + <Register name="RW_dword" format="dword" array-dim1="2" array-dim2="2" size="4" address="380" mem-size="16" synchro="MASTER"/> + <Register name="RW_int" format="int" array-dim1="2" array-dim2="2" size="2" address="396" mem-size="8" synchro="MASTER"/> + <Register name="RW_dint" format="dint" array-dim1="2" array-dim2="2" size="4" address="404" mem-size="16" synchro="MASTER"/> + <Register name="RW_real" format="real" array-dim1="2" array-dim2="2" size="4" address="420" mem-size="16" synchro="MASTER"/> + <Register name="RW_dt" format="dt" array-dim1="2" array-dim2="2" size="8" address="436" mem-size="32" synchro="MASTER"/> + </Block> + <Block name="MyWOBlock" mode="WRITE-ONLY" size="530" address="33996" mem-size="1170"> + <Register name="WO_int8" format="int8" array-dim1="10" array-dim2="1" size="1" address="0" mem-size="10" synchro="SLAVE"/> + <Register name="WO_uint8" format="uint8" array-dim1="10" array-dim2="1" size="1" address="10" mem-size="10" synchro="SLAVE"/> + <Register name="WO_int16" format="int16" array-dim1="10" array-dim2="1" size="2" address="20" mem-size="20" synchro="SLAVE"/> + <Register name="WO_uint16" format="uint16" array-dim1="10" array-dim2="1" size="2" address="40" mem-size="20" synchro="SLAVE"/> + <Register name="WO_int32" format="int32" array-dim1="10" array-dim2="1" size="4" address="60" mem-size="40" synchro="SLAVE"/> + <Register name="WO_uint32" format="uint32" array-dim1="10" array-dim2="1" size="4" address="100" mem-size="40" synchro="SLAVE"/> + <Register name="WO_float32" format="float32" array-dim1="10" array-dim2="1" size="4" address="140" mem-size="40" synchro="SLAVE"/> + <Register name="WO_string" format="string" string-len="64" array-dim1="10" array-dim2="1" size="1" address="180" mem-size="650" synchro="SLAVE"/> + <Register name="WO_date" format="date" array-dim1="10" array-dim2="1" size="8" address="830" mem-size="80" synchro="SLAVE"/> + <Register name="WO_char" format="char" array-dim1="10" array-dim2="1" size="1" address="910" mem-size="10" synchro="SLAVE"/> + <Register name="WO_byte" format="byte" array-dim1="10" array-dim2="1" size="1" address="920" mem-size="10" synchro="SLAVE"/> + <Register name="WO_word" format="word" array-dim1="10" array-dim2="1" size="2" address="930" mem-size="20" synchro="SLAVE"/> + <Register name="WO_dword" format="dword" array-dim1="10" array-dim2="1" size="4" address="950" mem-size="40" synchro="SLAVE"/> + <Register name="WO_int" format="int" array-dim1="10" array-dim2="1" size="2" address="990" mem-size="20" synchro="SLAVE"/> + <Register name="WO_dint" format="dint" array-dim1="10" array-dim2="1" size="4" address="1010" mem-size="40" synchro="SLAVE"/> + <Register name="WO_real" format="real" array-dim1="10" array-dim2="1" size="4" address="1050" mem-size="40" synchro="SLAVE"/> + <Register name="WO_dt" format="dt" array-dim1="10" array-dim2="1" size="8" address="1090" mem-size="80" synchro="SLAVE"/> + </Block> + <Instance label="testDevice1" address="0"/> + <Instance label="testDevice2" address="1"/> + </SILECS-Class> + </SILECS-Mapping> +</SILECS-Param> diff --git a/silecs-codegen/src/xml/test/generated_temp/client/Beckhoff_CX9020.silecsparam b/silecs-codegen/src/xml/test/generated_temp/client/Beckhoff_CX9020.silecsparam new file mode 100644 index 0000000..8bfb82c --- /dev/null +++ b/silecs-codegen/src/xml/test/generated_temp/client/Beckhoff_CX9020.silecsparam @@ -0,0 +1,80 @@ +<?xml version="1.0"?> +<SILECS-Param silecs-version="DEV"> + <Mapping-Info> + <Owner user-login="schwinn"/> + <Generation date="2016-07-26 15:37:54.700573"/> + <Deployment checksum="427563505"/> + </Mapping-Info> + <SILECS-Mapping plc-name="Beckhoff_CX9020" plc-brand="BECKHOFF" plc-system="TWINCat" plc-model="CX9020" protocol="BLOCK_MODE" address="24576" domain="NotUsed" used-mem="TODO"> + <SILECS-Class name="SilecsHeader" version="1.0.0" address="24576" used-mem="MW12288..MW12313 / 26 words"> + <Block name="hdrBlk" mode="READ-ONLY" size="14" address="24576" mem-size="52"> + <Register name="_version" format="string" string-len="16" array-dim1="1" array-dim2="1" size="1" address="0" mem-size="17" synchro="MASTER"/> + <Register name="_checksum" format="uint32" array-dim1="1" array-dim2="1" size="4" address="20" mem-size="4" synchro="MASTER"/> + <Register name="_user" format="string" string-len="16" array-dim1="1" array-dim2="1" size="1" address="24" mem-size="17" synchro="MASTER"/> + <Register name="_date" format="dt" array-dim1="1" array-dim2="1" size="8" address="44" mem-size="8" synchro="MASTER"/> + </Block> + <Instance label="SilecsHeader" address="0"/> + </SILECS-Class> + <SILECS-Class name="AllTypes" version="0.1.0" address="24628" used-mem="MW12314..MW14081 / 1768 words"> + <Block name="MyROBlock" mode="READ-ONLY" size="53" address="24628" mem-size="128"> + <Register name="RO_int8" format="int8" array-dim1="1" array-dim2="1" size="1" address="0" mem-size="1" synchro="MASTER"/> + <Register name="RO_uint8" format="uint8" array-dim1="1" array-dim2="1" size="1" address="2" mem-size="1" synchro="MASTER"/> + <Register name="RO_int16" format="int16" array-dim1="1" array-dim2="1" size="2" address="4" mem-size="2" synchro="MASTER"/> + <Register name="RO_uint16" format="uint16" array-dim1="1" array-dim2="1" size="2" address="6" mem-size="2" synchro="MASTER"/> + <Register name="RO_int32" format="int32" array-dim1="1" array-dim2="1" size="4" address="8" mem-size="4" synchro="MASTER"/> + <Register name="RO_uint32" format="uint32" array-dim1="1" array-dim2="1" size="4" address="12" mem-size="4" synchro="MASTER"/> + <Register name="RO_float32" format="float32" array-dim1="1" array-dim2="1" size="4" address="16" mem-size="4" synchro="MASTER"/> + <Register name="RO_string" format="string" string-len="64" array-dim1="1" array-dim2="1" size="1" address="20" mem-size="65" synchro="MASTER"/> + <Register name="RO_date" format="date" array-dim1="1" array-dim2="1" size="8" address="88" mem-size="8" synchro="MASTER"/> + <Register name="RO_char" format="char" array-dim1="1" array-dim2="1" size="1" address="96" mem-size="1" synchro="MASTER"/> + <Register name="RO_byte" format="byte" array-dim1="1" array-dim2="1" size="1" address="98" mem-size="1" synchro="MASTER"/> + <Register name="RO_word" format="word" array-dim1="1" array-dim2="1" size="2" address="100" mem-size="2" synchro="MASTER"/> + <Register name="RO_dword" format="dword" array-dim1="1" array-dim2="1" size="4" address="104" mem-size="4" synchro="MASTER"/> + <Register name="RO_int" format="int" array-dim1="1" array-dim2="1" size="2" address="108" mem-size="2" synchro="MASTER"/> + <Register name="RO_dint" format="dint" array-dim1="1" array-dim2="1" size="4" address="112" mem-size="4" synchro="MASTER"/> + <Register name="RO_real" format="real" array-dim1="1" array-dim2="1" size="4" address="116" mem-size="4" synchro="MASTER"/> + <Register name="RO_dt" format="dt" array-dim1="1" array-dim2="1" size="8" address="120" mem-size="8" synchro="MASTER"/> + </Block> + <Block name="MyRWBlock" mode="READ-WRITE" size="212" address="24884" mem-size="468"> + <Register name="RW_int8" format="int8" array-dim1="2" array-dim2="2" size="1" address="0" mem-size="4" synchro="MASTER"/> + <Register name="RW_uint8" format="uint8" array-dim1="2" array-dim2="2" size="1" address="4" mem-size="4" synchro="MASTER"/> + <Register name="RW_int16" format="int16" array-dim1="2" array-dim2="2" size="2" address="8" mem-size="8" synchro="MASTER"/> + <Register name="RW_uint16" format="uint16" array-dim1="2" array-dim2="2" size="2" address="16" mem-size="8" synchro="MASTER"/> + <Register name="RW_int32" format="int32" array-dim1="2" array-dim2="2" size="4" address="24" mem-size="16" synchro="MASTER"/> + <Register name="RW_uint32" format="uint32" array-dim1="2" array-dim2="2" size="4" address="40" mem-size="16" synchro="MASTER"/> + <Register name="RW_float32" format="float32" array-dim1="2" array-dim2="2" size="4" address="56" mem-size="16" synchro="MASTER"/> + <Register name="RW_string" format="string" string-len="64" array-dim1="2" array-dim2="2" size="1" address="72" mem-size="260" synchro="MASTER"/> + <Register name="RW_date" format="date" array-dim1="2" array-dim2="2" size="8" address="332" mem-size="32" synchro="MASTER"/> + <Register name="RW_char" format="char" array-dim1="2" array-dim2="2" size="1" address="364" mem-size="4" synchro="MASTER"/> + <Register name="RW_byte" format="byte" array-dim1="2" array-dim2="2" size="1" address="368" mem-size="4" synchro="MASTER"/> + <Register name="RW_word" format="word" array-dim1="2" array-dim2="2" size="2" address="372" mem-size="8" synchro="MASTER"/> + <Register name="RW_dword" format="dword" array-dim1="2" array-dim2="2" size="4" address="380" mem-size="16" synchro="MASTER"/> + <Register name="RW_int" format="int" array-dim1="2" array-dim2="2" size="2" address="396" mem-size="8" synchro="MASTER"/> + <Register name="RW_dint" format="dint" array-dim1="2" array-dim2="2" size="4" address="404" mem-size="16" synchro="MASTER"/> + <Register name="RW_real" format="real" array-dim1="2" array-dim2="2" size="4" address="420" mem-size="16" synchro="MASTER"/> + <Register name="RW_dt" format="dt" array-dim1="2" array-dim2="2" size="8" address="436" mem-size="32" synchro="MASTER"/> + </Block> + <Block name="MyWOBlock" mode="WRITE-ONLY" size="530" address="25820" mem-size="1172"> + <Register name="WO_int8" format="int8" array-dim1="10" array-dim2="1" size="1" address="0" mem-size="10" synchro="SLAVE"/> + <Register name="WO_uint8" format="uint8" array-dim1="10" array-dim2="1" size="1" address="10" mem-size="10" synchro="SLAVE"/> + <Register name="WO_int16" format="int16" array-dim1="10" array-dim2="1" size="2" address="20" mem-size="20" synchro="SLAVE"/> + <Register name="WO_uint16" format="uint16" array-dim1="10" array-dim2="1" size="2" address="40" mem-size="20" synchro="SLAVE"/> + <Register name="WO_int32" format="int32" array-dim1="10" array-dim2="1" size="4" address="60" mem-size="40" synchro="SLAVE"/> + <Register name="WO_uint32" format="uint32" array-dim1="10" array-dim2="1" size="4" address="100" mem-size="40" synchro="SLAVE"/> + <Register name="WO_float32" format="float32" array-dim1="10" array-dim2="1" size="4" address="140" mem-size="40" synchro="SLAVE"/> + <Register name="WO_string" format="string" string-len="64" array-dim1="10" array-dim2="1" size="1" address="180" mem-size="650" synchro="SLAVE"/> + <Register name="WO_date" format="date" array-dim1="10" array-dim2="1" size="8" address="832" mem-size="80" synchro="SLAVE"/> + <Register name="WO_char" format="char" array-dim1="10" array-dim2="1" size="1" address="912" mem-size="10" synchro="SLAVE"/> + <Register name="WO_byte" format="byte" array-dim1="10" array-dim2="1" size="1" address="922" mem-size="10" synchro="SLAVE"/> + <Register name="WO_word" format="word" array-dim1="10" array-dim2="1" size="2" address="932" mem-size="20" synchro="SLAVE"/> + <Register name="WO_dword" format="dword" array-dim1="10" array-dim2="1" size="4" address="952" mem-size="40" synchro="SLAVE"/> + <Register name="WO_int" format="int" array-dim1="10" array-dim2="1" size="2" address="992" mem-size="20" synchro="SLAVE"/> + <Register name="WO_dint" format="dint" array-dim1="10" array-dim2="1" size="4" address="1012" mem-size="40" synchro="SLAVE"/> + <Register name="WO_real" format="real" array-dim1="10" array-dim2="1" size="4" address="1052" mem-size="40" synchro="SLAVE"/> + <Register name="WO_dt" format="dt" array-dim1="10" array-dim2="1" size="8" address="1092" mem-size="80" synchro="SLAVE"/> + </Block> + <Instance label="testDevice1" address="0"/> + <Instance label="testDevice2" address="1"/> + </SILECS-Class> + </SILECS-Mapping> +</SILECS-Param> diff --git a/silecs-codegen/src/xml/test/generated_temp/client/Rabbit_BlockMode.silecsparam b/silecs-codegen/src/xml/test/generated_temp/client/Rabbit_BlockMode.silecsparam new file mode 100644 index 0000000..fb5bbdc --- /dev/null +++ b/silecs-codegen/src/xml/test/generated_temp/client/Rabbit_BlockMode.silecsparam @@ -0,0 +1,80 @@ +<?xml version="1.0"?> +<SILECS-Param silecs-version="DEV"> + <Mapping-Info> + <Owner user-login="schwinn"/> + <Generation date="2016-07-26 15:37:54.786452"/> + <Deployment checksum="3940683809"/> + </Mapping-Info> + <SILECS-Mapping plc-name="Rabbit_BlockMode" plc-brand="DIGI" plc-system="Standard-C" plc-model="Rabbit_RCM_4010" protocol="BLOCK_MODE" address="0" domain="NotUsed" used-mem="TODO"> + <SILECS-Class name="SilecsHeader" version="1.0.0" address="0" used-mem="MW0..MW21 / 22 words"> + <Block name="hdrBlk" mode="READ-ONLY" size="14" address="0" mem-size="44"> + <Register name="_version" format="string" string-len="16" array-dim1="1" array-dim2="1" size="1" address="0" mem-size="16" synchro="MASTER"/> + <Register name="_checksum" format="uint32" array-dim1="1" array-dim2="1" size="4" address="16" mem-size="4" synchro="MASTER"/> + <Register name="_user" format="string" string-len="16" array-dim1="1" array-dim2="1" size="1" address="20" mem-size="16" synchro="MASTER"/> + <Register name="_date" format="dt" array-dim1="1" array-dim2="1" size="8" address="36" mem-size="8" synchro="MASTER"/> + </Block> + <Instance label="SilecsHeader" address="0"/> + </SILECS-Class> + <SILECS-Class name="AllTypes" version="0.1.0" address="44" used-mem="MW22..MW1821 / 1800 words"> + <Block name="MyROBlock" mode="READ-ONLY" size="53" address="44" mem-size="120"> + <Register name="RO_int8" format="int8" array-dim1="1" array-dim2="1" size="1" address="0" mem-size="2" synchro="MASTER"/> + <Register name="RO_uint8" format="uint8" array-dim1="1" array-dim2="1" size="1" address="2" mem-size="2" synchro="MASTER"/> + <Register name="RO_int16" format="int16" array-dim1="1" array-dim2="1" size="2" address="4" mem-size="2" synchro="MASTER"/> + <Register name="RO_uint16" format="uint16" array-dim1="1" array-dim2="1" size="2" address="6" mem-size="2" synchro="MASTER"/> + <Register name="RO_int32" format="int32" array-dim1="1" array-dim2="1" size="4" address="8" mem-size="4" synchro="MASTER"/> + <Register name="RO_uint32" format="uint32" array-dim1="1" array-dim2="1" size="4" address="12" mem-size="4" synchro="MASTER"/> + <Register name="RO_float32" format="float32" array-dim1="1" array-dim2="1" size="4" address="16" mem-size="4" synchro="MASTER"/> + <Register name="RO_string" format="string" string-len="64" array-dim1="1" array-dim2="1" size="1" address="20" mem-size="64" synchro="MASTER"/> + <Register name="RO_date" format="date" array-dim1="1" array-dim2="1" size="8" address="84" mem-size="8" synchro="MASTER"/> + <Register name="RO_char" format="char" array-dim1="1" array-dim2="1" size="1" address="92" mem-size="2" synchro="MASTER"/> + <Register name="RO_byte" format="byte" array-dim1="1" array-dim2="1" size="1" address="94" mem-size="2" synchro="MASTER"/> + <Register name="RO_word" format="word" array-dim1="1" array-dim2="1" size="2" address="96" mem-size="2" synchro="MASTER"/> + <Register name="RO_dword" format="dword" array-dim1="1" array-dim2="1" size="4" address="98" mem-size="4" synchro="MASTER"/> + <Register name="RO_int" format="int" array-dim1="1" array-dim2="1" size="2" address="102" mem-size="2" synchro="MASTER"/> + <Register name="RO_dint" format="dint" array-dim1="1" array-dim2="1" size="4" address="104" mem-size="4" synchro="MASTER"/> + <Register name="RO_real" format="real" array-dim1="1" array-dim2="1" size="4" address="108" mem-size="4" synchro="MASTER"/> + <Register name="RO_dt" format="dt" array-dim1="1" array-dim2="1" size="8" address="112" mem-size="8" synchro="MASTER"/> + </Block> + <Block name="MyRWBlock" mode="READ-WRITE" size="212" address="284" mem-size="480"> + <Register name="RW_int8" format="int8" array-dim1="2" array-dim2="2" size="1" address="0" mem-size="8" synchro="MASTER"/> + <Register name="RW_uint8" format="uint8" array-dim1="2" array-dim2="2" size="1" address="8" mem-size="8" synchro="MASTER"/> + <Register name="RW_int16" format="int16" array-dim1="2" array-dim2="2" size="2" address="16" mem-size="8" synchro="MASTER"/> + <Register name="RW_uint16" format="uint16" array-dim1="2" array-dim2="2" size="2" address="24" mem-size="8" synchro="MASTER"/> + <Register name="RW_int32" format="int32" array-dim1="2" array-dim2="2" size="4" address="32" mem-size="16" synchro="MASTER"/> + <Register name="RW_uint32" format="uint32" array-dim1="2" array-dim2="2" size="4" address="48" mem-size="16" synchro="MASTER"/> + <Register name="RW_float32" format="float32" array-dim1="2" array-dim2="2" size="4" address="64" mem-size="16" synchro="MASTER"/> + <Register name="RW_string" format="string" string-len="64" array-dim1="2" array-dim2="2" size="1" address="80" mem-size="256" synchro="MASTER"/> + <Register name="RW_date" format="date" array-dim1="2" array-dim2="2" size="8" address="336" mem-size="32" synchro="MASTER"/> + <Register name="RW_char" format="char" array-dim1="2" array-dim2="2" size="1" address="368" mem-size="8" synchro="MASTER"/> + <Register name="RW_byte" format="byte" array-dim1="2" array-dim2="2" size="1" address="376" mem-size="8" synchro="MASTER"/> + <Register name="RW_word" format="word" array-dim1="2" array-dim2="2" size="2" address="384" mem-size="8" synchro="MASTER"/> + <Register name="RW_dword" format="dword" array-dim1="2" array-dim2="2" size="4" address="392" mem-size="16" synchro="MASTER"/> + <Register name="RW_int" format="int" array-dim1="2" array-dim2="2" size="2" address="408" mem-size="8" synchro="MASTER"/> + <Register name="RW_dint" format="dint" array-dim1="2" array-dim2="2" size="4" address="416" mem-size="16" synchro="MASTER"/> + <Register name="RW_real" format="real" array-dim1="2" array-dim2="2" size="4" address="432" mem-size="16" synchro="MASTER"/> + <Register name="RW_dt" format="dt" array-dim1="2" array-dim2="2" size="8" address="448" mem-size="32" synchro="MASTER"/> + </Block> + <Block name="MyWOBlock" mode="WRITE-ONLY" size="530" address="1244" mem-size="1200"> + <Register name="WO_int8" format="int8" array-dim1="10" array-dim2="1" size="1" address="0" mem-size="20" synchro="SLAVE"/> + <Register name="WO_uint8" format="uint8" array-dim1="10" array-dim2="1" size="1" address="20" mem-size="20" synchro="SLAVE"/> + <Register name="WO_int16" format="int16" array-dim1="10" array-dim2="1" size="2" address="40" mem-size="20" synchro="SLAVE"/> + <Register name="WO_uint16" format="uint16" array-dim1="10" array-dim2="1" size="2" address="60" mem-size="20" synchro="SLAVE"/> + <Register name="WO_int32" format="int32" array-dim1="10" array-dim2="1" size="4" address="80" mem-size="40" synchro="SLAVE"/> + <Register name="WO_uint32" format="uint32" array-dim1="10" array-dim2="1" size="4" address="120" mem-size="40" synchro="SLAVE"/> + <Register name="WO_float32" format="float32" array-dim1="10" array-dim2="1" size="4" address="160" mem-size="40" synchro="SLAVE"/> + <Register name="WO_string" format="string" string-len="64" array-dim1="10" array-dim2="1" size="1" address="200" mem-size="640" synchro="SLAVE"/> + <Register name="WO_date" format="date" array-dim1="10" array-dim2="1" size="8" address="840" mem-size="80" synchro="SLAVE"/> + <Register name="WO_char" format="char" array-dim1="10" array-dim2="1" size="1" address="920" mem-size="20" synchro="SLAVE"/> + <Register name="WO_byte" format="byte" array-dim1="10" array-dim2="1" size="1" address="940" mem-size="20" synchro="SLAVE"/> + <Register name="WO_word" format="word" array-dim1="10" array-dim2="1" size="2" address="960" mem-size="20" synchro="SLAVE"/> + <Register name="WO_dword" format="dword" array-dim1="10" array-dim2="1" size="4" address="980" mem-size="40" synchro="SLAVE"/> + <Register name="WO_int" format="int" array-dim1="10" array-dim2="1" size="2" address="1020" mem-size="20" synchro="SLAVE"/> + <Register name="WO_dint" format="dint" array-dim1="10" array-dim2="1" size="4" address="1040" mem-size="40" synchro="SLAVE"/> + <Register name="WO_real" format="real" array-dim1="10" array-dim2="1" size="4" address="1080" mem-size="40" synchro="SLAVE"/> + <Register name="WO_dt" format="dt" array-dim1="10" array-dim2="1" size="8" address="1120" mem-size="80" synchro="SLAVE"/> + </Block> + <Instance label="testDevice1" address="0"/> + <Instance label="testDevice2" address="1"/> + </SILECS-Class> + </SILECS-Mapping> +</SILECS-Param> diff --git a/silecs-codegen/src/xml/test/generated_temp/client/Rabbit_DeviceMode.silecsparam b/silecs-codegen/src/xml/test/generated_temp/client/Rabbit_DeviceMode.silecsparam new file mode 100644 index 0000000..0020f58 --- /dev/null +++ b/silecs-codegen/src/xml/test/generated_temp/client/Rabbit_DeviceMode.silecsparam @@ -0,0 +1,80 @@ +<?xml version="1.0"?> +<SILECS-Param silecs-version="DEV"> + <Mapping-Info> + <Owner user-login="schwinn"/> + <Generation date="2016-07-26 15:37:54.769333"/> + <Deployment checksum="3940683809"/> + </Mapping-Info> + <SILECS-Mapping plc-name="Rabbit_DeviceMode" plc-brand="DIGI" plc-system="Standard-C" plc-model="Rabbit_RCM_4010" protocol="DEVICE_MODE" address="0" domain="NotUsed" used-mem="TODO"> + <SILECS-Class name="SilecsHeader" version="1.0.0" address="0" used-mem="MW0..MW21 / 22 words"> + <Block name="hdrBlk" mode="READ-ONLY" size="14" address="0" mem-size="44"> + <Register name="_version" format="string" string-len="16" array-dim1="1" array-dim2="1" size="1" address="0" mem-size="16" synchro="MASTER"/> + <Register name="_checksum" format="uint32" array-dim1="1" array-dim2="1" size="4" address="16" mem-size="4" synchro="MASTER"/> + <Register name="_user" format="string" string-len="16" array-dim1="1" array-dim2="1" size="1" address="20" mem-size="16" synchro="MASTER"/> + <Register name="_date" format="dt" array-dim1="1" array-dim2="1" size="8" address="36" mem-size="8" synchro="MASTER"/> + </Block> + <Instance label="SilecsHeader" address="0"/> + </SILECS-Class> + <SILECS-Class name="AllTypes" version="0.1.0" address="44" used-mem="MW22..MW1821 / 1800 words"> + <Block name="MyROBlock" mode="READ-ONLY" size="53" address="0" mem-size="120"> + <Register name="RO_int8" format="int8" array-dim1="1" array-dim2="1" size="1" address="0" mem-size="2" synchro="MASTER"/> + <Register name="RO_uint8" format="uint8" array-dim1="1" array-dim2="1" size="1" address="2" mem-size="2" synchro="MASTER"/> + <Register name="RO_int16" format="int16" array-dim1="1" array-dim2="1" size="2" address="4" mem-size="2" synchro="MASTER"/> + <Register name="RO_uint16" format="uint16" array-dim1="1" array-dim2="1" size="2" address="6" mem-size="2" synchro="MASTER"/> + <Register name="RO_int32" format="int32" array-dim1="1" array-dim2="1" size="4" address="8" mem-size="4" synchro="MASTER"/> + <Register name="RO_uint32" format="uint32" array-dim1="1" array-dim2="1" size="4" address="12" mem-size="4" synchro="MASTER"/> + <Register name="RO_float32" format="float32" array-dim1="1" array-dim2="1" size="4" address="16" mem-size="4" synchro="MASTER"/> + <Register name="RO_string" format="string" string-len="64" array-dim1="1" array-dim2="1" size="1" address="20" mem-size="64" synchro="MASTER"/> + <Register name="RO_date" format="date" array-dim1="1" array-dim2="1" size="8" address="84" mem-size="8" synchro="MASTER"/> + <Register name="RO_char" format="char" array-dim1="1" array-dim2="1" size="1" address="92" mem-size="2" synchro="MASTER"/> + <Register name="RO_byte" format="byte" array-dim1="1" array-dim2="1" size="1" address="94" mem-size="2" synchro="MASTER"/> + <Register name="RO_word" format="word" array-dim1="1" array-dim2="1" size="2" address="96" mem-size="2" synchro="MASTER"/> + <Register name="RO_dword" format="dword" array-dim1="1" array-dim2="1" size="4" address="98" mem-size="4" synchro="MASTER"/> + <Register name="RO_int" format="int" array-dim1="1" array-dim2="1" size="2" address="102" mem-size="2" synchro="MASTER"/> + <Register name="RO_dint" format="dint" array-dim1="1" array-dim2="1" size="4" address="104" mem-size="4" synchro="MASTER"/> + <Register name="RO_real" format="real" array-dim1="1" array-dim2="1" size="4" address="108" mem-size="4" synchro="MASTER"/> + <Register name="RO_dt" format="dt" array-dim1="1" array-dim2="1" size="8" address="112" mem-size="8" synchro="MASTER"/> + </Block> + <Block name="MyRWBlock" mode="READ-WRITE" size="212" address="120" mem-size="480"> + <Register name="RW_int8" format="int8" array-dim1="2" array-dim2="2" size="1" address="0" mem-size="8" synchro="MASTER"/> + <Register name="RW_uint8" format="uint8" array-dim1="2" array-dim2="2" size="1" address="8" mem-size="8" synchro="MASTER"/> + <Register name="RW_int16" format="int16" array-dim1="2" array-dim2="2" size="2" address="16" mem-size="8" synchro="MASTER"/> + <Register name="RW_uint16" format="uint16" array-dim1="2" array-dim2="2" size="2" address="24" mem-size="8" synchro="MASTER"/> + <Register name="RW_int32" format="int32" array-dim1="2" array-dim2="2" size="4" address="32" mem-size="16" synchro="MASTER"/> + <Register name="RW_uint32" format="uint32" array-dim1="2" array-dim2="2" size="4" address="48" mem-size="16" synchro="MASTER"/> + <Register name="RW_float32" format="float32" array-dim1="2" array-dim2="2" size="4" address="64" mem-size="16" synchro="MASTER"/> + <Register name="RW_string" format="string" string-len="64" array-dim1="2" array-dim2="2" size="1" address="80" mem-size="256" synchro="MASTER"/> + <Register name="RW_date" format="date" array-dim1="2" array-dim2="2" size="8" address="336" mem-size="32" synchro="MASTER"/> + <Register name="RW_char" format="char" array-dim1="2" array-dim2="2" size="1" address="368" mem-size="8" synchro="MASTER"/> + <Register name="RW_byte" format="byte" array-dim1="2" array-dim2="2" size="1" address="376" mem-size="8" synchro="MASTER"/> + <Register name="RW_word" format="word" array-dim1="2" array-dim2="2" size="2" address="384" mem-size="8" synchro="MASTER"/> + <Register name="RW_dword" format="dword" array-dim1="2" array-dim2="2" size="4" address="392" mem-size="16" synchro="MASTER"/> + <Register name="RW_int" format="int" array-dim1="2" array-dim2="2" size="2" address="408" mem-size="8" synchro="MASTER"/> + <Register name="RW_dint" format="dint" array-dim1="2" array-dim2="2" size="4" address="416" mem-size="16" synchro="MASTER"/> + <Register name="RW_real" format="real" array-dim1="2" array-dim2="2" size="4" address="432" mem-size="16" synchro="MASTER"/> + <Register name="RW_dt" format="dt" array-dim1="2" array-dim2="2" size="8" address="448" mem-size="32" synchro="MASTER"/> + </Block> + <Block name="MyWOBlock" mode="WRITE-ONLY" size="530" address="600" mem-size="1200"> + <Register name="WO_int8" format="int8" array-dim1="10" array-dim2="1" size="1" address="0" mem-size="20" synchro="SLAVE"/> + <Register name="WO_uint8" format="uint8" array-dim1="10" array-dim2="1" size="1" address="20" mem-size="20" synchro="SLAVE"/> + <Register name="WO_int16" format="int16" array-dim1="10" array-dim2="1" size="2" address="40" mem-size="20" synchro="SLAVE"/> + <Register name="WO_uint16" format="uint16" array-dim1="10" array-dim2="1" size="2" address="60" mem-size="20" synchro="SLAVE"/> + <Register name="WO_int32" format="int32" array-dim1="10" array-dim2="1" size="4" address="80" mem-size="40" synchro="SLAVE"/> + <Register name="WO_uint32" format="uint32" array-dim1="10" array-dim2="1" size="4" address="120" mem-size="40" synchro="SLAVE"/> + <Register name="WO_float32" format="float32" array-dim1="10" array-dim2="1" size="4" address="160" mem-size="40" synchro="SLAVE"/> + <Register name="WO_string" format="string" string-len="64" array-dim1="10" array-dim2="1" size="1" address="200" mem-size="640" synchro="SLAVE"/> + <Register name="WO_date" format="date" array-dim1="10" array-dim2="1" size="8" address="840" mem-size="80" synchro="SLAVE"/> + <Register name="WO_char" format="char" array-dim1="10" array-dim2="1" size="1" address="920" mem-size="20" synchro="SLAVE"/> + <Register name="WO_byte" format="byte" array-dim1="10" array-dim2="1" size="1" address="940" mem-size="20" synchro="SLAVE"/> + <Register name="WO_word" format="word" array-dim1="10" array-dim2="1" size="2" address="960" mem-size="20" synchro="SLAVE"/> + <Register name="WO_dword" format="dword" array-dim1="10" array-dim2="1" size="4" address="980" mem-size="40" synchro="SLAVE"/> + <Register name="WO_int" format="int" array-dim1="10" array-dim2="1" size="2" address="1020" mem-size="20" synchro="SLAVE"/> + <Register name="WO_dint" format="dint" array-dim1="10" array-dim2="1" size="4" address="1040" mem-size="40" synchro="SLAVE"/> + <Register name="WO_real" format="real" array-dim1="10" array-dim2="1" size="4" address="1080" mem-size="40" synchro="SLAVE"/> + <Register name="WO_dt" format="dt" array-dim1="10" array-dim2="1" size="8" address="1120" mem-size="80" synchro="SLAVE"/> + </Block> + <Instance label="testDevice1" address="44"/> + <Instance label="testDevice2" address="1844"/> + </SILECS-Class> + </SILECS-Mapping> +</SILECS-Param> diff --git a/silecs-codegen/src/xml/test/generated_temp/client/Schneider_M340.silecsparam b/silecs-codegen/src/xml/test/generated_temp/client/Schneider_M340.silecsparam new file mode 100644 index 0000000..eb92428 --- /dev/null +++ b/silecs-codegen/src/xml/test/generated_temp/client/Schneider_M340.silecsparam @@ -0,0 +1,80 @@ +<?xml version="1.0"?> +<SILECS-Param silecs-version="DEV"> + <Mapping-Info> + <Owner user-login="schwinn"/> + <Generation date="2016-07-26 15:37:54.747831"/> + <Deployment checksum="3940683809"/> + </Mapping-Info> + <SILECS-Mapping plc-name="Schneider_M340" plc-brand="SCHNEIDER" plc-system="UNITY Pro" plc-model="M340" protocol="BLOCK_MODE" address="0" domain="NotUsed" used-mem="TODO"> + <SILECS-Class name="SilecsHeader" version="1.0.0" address="0" used-mem="MW0..MW21 / 22 words"> + <Block name="hdrBlk" mode="READ-ONLY" size="14" address="0" mem-size="44"> + <Register name="_version" format="string" string-len="16" array-dim1="1" array-dim2="1" size="1" address="0" mem-size="16" synchro="MASTER"/> + <Register name="_checksum" format="uint32" array-dim1="1" array-dim2="1" size="4" address="16" mem-size="4" synchro="MASTER"/> + <Register name="_user" format="string" string-len="16" array-dim1="1" array-dim2="1" size="1" address="20" mem-size="16" synchro="MASTER"/> + <Register name="_date" format="dt" array-dim1="1" array-dim2="1" size="8" address="36" mem-size="8" synchro="MASTER"/> + </Block> + <Instance label="SilecsHeader" address="0"/> + </SILECS-Class> + <SILECS-Class name="AllTypes" version="0.1.0" address="44" used-mem="MW22..MW1801 / 1780 words"> + <Block name="MyROBlock" mode="READ-ONLY" size="53" address="44" mem-size="124"> + <Register name="RO_int8" format="int8" array-dim1="1" array-dim2="1" size="1" address="0" mem-size="2" synchro="MASTER"/> + <Register name="RO_uint8" format="uint8" array-dim1="1" array-dim2="1" size="1" address="2" mem-size="1" synchro="MASTER"/> + <Register name="RO_int16" format="int16" array-dim1="1" array-dim2="1" size="2" address="4" mem-size="2" synchro="MASTER"/> + <Register name="RO_uint16" format="uint16" array-dim1="1" array-dim2="1" size="2" address="6" mem-size="2" synchro="MASTER"/> + <Register name="RO_int32" format="int32" array-dim1="1" array-dim2="1" size="4" address="8" mem-size="4" synchro="MASTER"/> + <Register name="RO_uint32" format="uint32" array-dim1="1" array-dim2="1" size="4" address="12" mem-size="4" synchro="MASTER"/> + <Register name="RO_float32" format="float32" array-dim1="1" array-dim2="1" size="4" address="16" mem-size="4" synchro="MASTER"/> + <Register name="RO_string" format="string" string-len="64" array-dim1="1" array-dim2="1" size="1" address="20" mem-size="64" synchro="MASTER"/> + <Register name="RO_date" format="date" array-dim1="1" array-dim2="1" size="8" address="84" mem-size="8" synchro="MASTER"/> + <Register name="RO_char" format="char" array-dim1="1" array-dim2="1" size="1" address="92" mem-size="2" synchro="MASTER"/> + <Register name="RO_byte" format="byte" array-dim1="1" array-dim2="1" size="1" address="94" mem-size="1" synchro="MASTER"/> + <Register name="RO_word" format="word" array-dim1="1" array-dim2="1" size="2" address="96" mem-size="2" synchro="MASTER"/> + <Register name="RO_dword" format="dword" array-dim1="1" array-dim2="1" size="4" address="100" mem-size="4" synchro="MASTER"/> + <Register name="RO_int" format="int" array-dim1="1" array-dim2="1" size="2" address="104" mem-size="2" synchro="MASTER"/> + <Register name="RO_dint" format="dint" array-dim1="1" array-dim2="1" size="4" address="108" mem-size="4" synchro="MASTER"/> + <Register name="RO_real" format="real" array-dim1="1" array-dim2="1" size="4" address="112" mem-size="4" synchro="MASTER"/> + <Register name="RO_dt" format="dt" array-dim1="1" array-dim2="1" size="8" address="116" mem-size="8" synchro="MASTER"/> + </Block> + <Block name="MyRWBlock" mode="READ-WRITE" size="212" address="292" mem-size="472"> + <Register name="RW_int8" format="int8" array-dim1="2" array-dim2="2" size="1" address="0" mem-size="8" synchro="MASTER"/> + <Register name="RW_uint8" format="uint8" array-dim1="2" array-dim2="2" size="1" address="8" mem-size="4" synchro="MASTER"/> + <Register name="RW_int16" format="int16" array-dim1="2" array-dim2="2" size="2" address="12" mem-size="8" synchro="MASTER"/> + <Register name="RW_uint16" format="uint16" array-dim1="2" array-dim2="2" size="2" address="20" mem-size="8" synchro="MASTER"/> + <Register name="RW_int32" format="int32" array-dim1="2" array-dim2="2" size="4" address="28" mem-size="16" synchro="MASTER"/> + <Register name="RW_uint32" format="uint32" array-dim1="2" array-dim2="2" size="4" address="44" mem-size="16" synchro="MASTER"/> + <Register name="RW_float32" format="float32" array-dim1="2" array-dim2="2" size="4" address="60" mem-size="16" synchro="MASTER"/> + <Register name="RW_string" format="string" string-len="64" array-dim1="2" array-dim2="2" size="1" address="76" mem-size="256" synchro="MASTER"/> + <Register name="RW_date" format="date" array-dim1="2" array-dim2="2" size="8" address="332" mem-size="32" synchro="MASTER"/> + <Register name="RW_char" format="char" array-dim1="2" array-dim2="2" size="1" address="364" mem-size="8" synchro="MASTER"/> + <Register name="RW_byte" format="byte" array-dim1="2" array-dim2="2" size="1" address="372" mem-size="4" synchro="MASTER"/> + <Register name="RW_word" format="word" array-dim1="2" array-dim2="2" size="2" address="376" mem-size="8" synchro="MASTER"/> + <Register name="RW_dword" format="dword" array-dim1="2" array-dim2="2" size="4" address="384" mem-size="16" synchro="MASTER"/> + <Register name="RW_int" format="int" array-dim1="2" array-dim2="2" size="2" address="400" mem-size="8" synchro="MASTER"/> + <Register name="RW_dint" format="dint" array-dim1="2" array-dim2="2" size="4" address="408" mem-size="16" synchro="MASTER"/> + <Register name="RW_real" format="real" array-dim1="2" array-dim2="2" size="4" address="424" mem-size="16" synchro="MASTER"/> + <Register name="RW_dt" format="dt" array-dim1="2" array-dim2="2" size="8" address="440" mem-size="32" synchro="MASTER"/> + </Block> + <Block name="MyWOBlock" mode="WRITE-ONLY" size="530" address="1236" mem-size="1184"> + <Register name="WO_int8" format="int8" array-dim1="10" array-dim2="1" size="1" address="0" mem-size="20" synchro="SLAVE"/> + <Register name="WO_uint8" format="uint8" array-dim1="10" array-dim2="1" size="1" address="20" mem-size="10" synchro="SLAVE"/> + <Register name="WO_int16" format="int16" array-dim1="10" array-dim2="1" size="2" address="30" mem-size="20" synchro="SLAVE"/> + <Register name="WO_uint16" format="uint16" array-dim1="10" array-dim2="1" size="2" address="50" mem-size="20" synchro="SLAVE"/> + <Register name="WO_int32" format="int32" array-dim1="10" array-dim2="1" size="4" address="72" mem-size="40" synchro="SLAVE"/> + <Register name="WO_uint32" format="uint32" array-dim1="10" array-dim2="1" size="4" address="112" mem-size="40" synchro="SLAVE"/> + <Register name="WO_float32" format="float32" array-dim1="10" array-dim2="1" size="4" address="152" mem-size="40" synchro="SLAVE"/> + <Register name="WO_string" format="string" string-len="64" array-dim1="10" array-dim2="1" size="1" address="192" mem-size="640" synchro="SLAVE"/> + <Register name="WO_date" format="date" array-dim1="10" array-dim2="1" size="8" address="832" mem-size="80" synchro="SLAVE"/> + <Register name="WO_char" format="char" array-dim1="10" array-dim2="1" size="1" address="912" mem-size="20" synchro="SLAVE"/> + <Register name="WO_byte" format="byte" array-dim1="10" array-dim2="1" size="1" address="932" mem-size="10" synchro="SLAVE"/> + <Register name="WO_word" format="word" array-dim1="10" array-dim2="1" size="2" address="942" mem-size="20" synchro="SLAVE"/> + <Register name="WO_dword" format="dword" array-dim1="10" array-dim2="1" size="4" address="964" mem-size="40" synchro="SLAVE"/> + <Register name="WO_int" format="int" array-dim1="10" array-dim2="1" size="2" address="1004" mem-size="20" synchro="SLAVE"/> + <Register name="WO_dint" format="dint" array-dim1="10" array-dim2="1" size="4" address="1024" mem-size="40" synchro="SLAVE"/> + <Register name="WO_real" format="real" array-dim1="10" array-dim2="1" size="4" address="1064" mem-size="40" synchro="SLAVE"/> + <Register name="WO_dt" format="dt" array-dim1="10" array-dim2="1" size="8" address="1104" mem-size="80" synchro="SLAVE"/> + </Block> + <Instance label="testDevice1" address="0"/> + <Instance label="testDevice2" address="1"/> + </SILECS-Class> + </SILECS-Mapping> +</SILECS-Param> diff --git a/silecs-codegen/src/xml/test/generated_temp/client/Schneider_PremiumQuantum.silecsparam b/silecs-codegen/src/xml/test/generated_temp/client/Schneider_PremiumQuantum.silecsparam new file mode 100644 index 0000000..6daa7f4 --- /dev/null +++ b/silecs-codegen/src/xml/test/generated_temp/client/Schneider_PremiumQuantum.silecsparam @@ -0,0 +1,80 @@ +<?xml version="1.0"?> +<SILECS-Param silecs-version="DEV"> + <Mapping-Info> + <Owner user-login="schwinn"/> + <Generation date="2016-07-26 15:37:54.727642"/> + <Deployment checksum="3940683809"/> + </Mapping-Info> + <SILECS-Mapping plc-name="Schneider_PremiumQuantum" plc-brand="SCHNEIDER" plc-system="UNITY Pro" plc-model="Premium" protocol="BLOCK_MODE" address="0" domain="NotUsed" used-mem="TODO"> + <SILECS-Class name="SilecsHeader" version="1.0.0" address="0" used-mem="MW0..MW21 / 22 words"> + <Block name="hdrBlk" mode="READ-ONLY" size="14" address="0" mem-size="44"> + <Register name="_version" format="string" string-len="16" array-dim1="1" array-dim2="1" size="1" address="0" mem-size="16" synchro="MASTER"/> + <Register name="_checksum" format="uint32" array-dim1="1" array-dim2="1" size="4" address="16" mem-size="4" synchro="MASTER"/> + <Register name="_user" format="string" string-len="16" array-dim1="1" array-dim2="1" size="1" address="20" mem-size="16" synchro="MASTER"/> + <Register name="_date" format="dt" array-dim1="1" array-dim2="1" size="8" address="36" mem-size="8" synchro="MASTER"/> + </Block> + <Instance label="SilecsHeader" address="0"/> + </SILECS-Class> + <SILECS-Class name="AllTypes" version="0.1.0" address="44" used-mem="MW22..MW1793 / 1772 words"> + <Block name="MyROBlock" mode="READ-ONLY" size="53" address="44" mem-size="120"> + <Register name="RO_int8" format="int8" array-dim1="1" array-dim2="1" size="1" address="0" mem-size="2" synchro="MASTER"/> + <Register name="RO_uint8" format="uint8" array-dim1="1" array-dim2="1" size="1" address="2" mem-size="1" synchro="MASTER"/> + <Register name="RO_int16" format="int16" array-dim1="1" array-dim2="1" size="2" address="4" mem-size="2" synchro="MASTER"/> + <Register name="RO_uint16" format="uint16" array-dim1="1" array-dim2="1" size="2" address="6" mem-size="2" synchro="MASTER"/> + <Register name="RO_int32" format="int32" array-dim1="1" array-dim2="1" size="4" address="8" mem-size="4" synchro="MASTER"/> + <Register name="RO_uint32" format="uint32" array-dim1="1" array-dim2="1" size="4" address="12" mem-size="4" synchro="MASTER"/> + <Register name="RO_float32" format="float32" array-dim1="1" array-dim2="1" size="4" address="16" mem-size="4" synchro="MASTER"/> + <Register name="RO_string" format="string" string-len="64" array-dim1="1" array-dim2="1" size="1" address="20" mem-size="64" synchro="MASTER"/> + <Register name="RO_date" format="date" array-dim1="1" array-dim2="1" size="8" address="84" mem-size="8" synchro="MASTER"/> + <Register name="RO_char" format="char" array-dim1="1" array-dim2="1" size="1" address="92" mem-size="2" synchro="MASTER"/> + <Register name="RO_byte" format="byte" array-dim1="1" array-dim2="1" size="1" address="94" mem-size="1" synchro="MASTER"/> + <Register name="RO_word" format="word" array-dim1="1" array-dim2="1" size="2" address="96" mem-size="2" synchro="MASTER"/> + <Register name="RO_dword" format="dword" array-dim1="1" array-dim2="1" size="4" address="98" mem-size="4" synchro="MASTER"/> + <Register name="RO_int" format="int" array-dim1="1" array-dim2="1" size="2" address="102" mem-size="2" synchro="MASTER"/> + <Register name="RO_dint" format="dint" array-dim1="1" array-dim2="1" size="4" address="104" mem-size="4" synchro="MASTER"/> + <Register name="RO_real" format="real" array-dim1="1" array-dim2="1" size="4" address="108" mem-size="4" synchro="MASTER"/> + <Register name="RO_dt" format="dt" array-dim1="1" array-dim2="1" size="8" address="112" mem-size="8" synchro="MASTER"/> + </Block> + <Block name="MyRWBlock" mode="READ-WRITE" size="212" address="284" mem-size="472"> + <Register name="RW_int8" format="int8" array-dim1="2" array-dim2="2" size="1" address="0" mem-size="8" synchro="MASTER"/> + <Register name="RW_uint8" format="uint8" array-dim1="2" array-dim2="2" size="1" address="8" mem-size="4" synchro="MASTER"/> + <Register name="RW_int16" format="int16" array-dim1="2" array-dim2="2" size="2" address="12" mem-size="8" synchro="MASTER"/> + <Register name="RW_uint16" format="uint16" array-dim1="2" array-dim2="2" size="2" address="20" mem-size="8" synchro="MASTER"/> + <Register name="RW_int32" format="int32" array-dim1="2" array-dim2="2" size="4" address="28" mem-size="16" synchro="MASTER"/> + <Register name="RW_uint32" format="uint32" array-dim1="2" array-dim2="2" size="4" address="44" mem-size="16" synchro="MASTER"/> + <Register name="RW_float32" format="float32" array-dim1="2" array-dim2="2" size="4" address="60" mem-size="16" synchro="MASTER"/> + <Register name="RW_string" format="string" string-len="64" array-dim1="2" array-dim2="2" size="1" address="76" mem-size="256" synchro="MASTER"/> + <Register name="RW_date" format="date" array-dim1="2" array-dim2="2" size="8" address="332" mem-size="32" synchro="MASTER"/> + <Register name="RW_char" format="char" array-dim1="2" array-dim2="2" size="1" address="364" mem-size="8" synchro="MASTER"/> + <Register name="RW_byte" format="byte" array-dim1="2" array-dim2="2" size="1" address="372" mem-size="4" synchro="MASTER"/> + <Register name="RW_word" format="word" array-dim1="2" array-dim2="2" size="2" address="376" mem-size="8" synchro="MASTER"/> + <Register name="RW_dword" format="dword" array-dim1="2" array-dim2="2" size="4" address="384" mem-size="16" synchro="MASTER"/> + <Register name="RW_int" format="int" array-dim1="2" array-dim2="2" size="2" address="400" mem-size="8" synchro="MASTER"/> + <Register name="RW_dint" format="dint" array-dim1="2" array-dim2="2" size="4" address="408" mem-size="16" synchro="MASTER"/> + <Register name="RW_real" format="real" array-dim1="2" array-dim2="2" size="4" address="424" mem-size="16" synchro="MASTER"/> + <Register name="RW_dt" format="dt" array-dim1="2" array-dim2="2" size="8" address="440" mem-size="32" synchro="MASTER"/> + </Block> + <Block name="MyWOBlock" mode="WRITE-ONLY" size="530" address="1228" mem-size="1180"> + <Register name="WO_int8" format="int8" array-dim1="10" array-dim2="1" size="1" address="0" mem-size="20" synchro="SLAVE"/> + <Register name="WO_uint8" format="uint8" array-dim1="10" array-dim2="1" size="1" address="20" mem-size="10" synchro="SLAVE"/> + <Register name="WO_int16" format="int16" array-dim1="10" array-dim2="1" size="2" address="30" mem-size="20" synchro="SLAVE"/> + <Register name="WO_uint16" format="uint16" array-dim1="10" array-dim2="1" size="2" address="50" mem-size="20" synchro="SLAVE"/> + <Register name="WO_int32" format="int32" array-dim1="10" array-dim2="1" size="4" address="70" mem-size="40" synchro="SLAVE"/> + <Register name="WO_uint32" format="uint32" array-dim1="10" array-dim2="1" size="4" address="110" mem-size="40" synchro="SLAVE"/> + <Register name="WO_float32" format="float32" array-dim1="10" array-dim2="1" size="4" address="150" mem-size="40" synchro="SLAVE"/> + <Register name="WO_string" format="string" string-len="64" array-dim1="10" array-dim2="1" size="1" address="190" mem-size="640" synchro="SLAVE"/> + <Register name="WO_date" format="date" array-dim1="10" array-dim2="1" size="8" address="830" mem-size="80" synchro="SLAVE"/> + <Register name="WO_char" format="char" array-dim1="10" array-dim2="1" size="1" address="910" mem-size="20" synchro="SLAVE"/> + <Register name="WO_byte" format="byte" array-dim1="10" array-dim2="1" size="1" address="930" mem-size="10" synchro="SLAVE"/> + <Register name="WO_word" format="word" array-dim1="10" array-dim2="1" size="2" address="940" mem-size="20" synchro="SLAVE"/> + <Register name="WO_dword" format="dword" array-dim1="10" array-dim2="1" size="4" address="960" mem-size="40" synchro="SLAVE"/> + <Register name="WO_int" format="int" array-dim1="10" array-dim2="1" size="2" address="1000" mem-size="20" synchro="SLAVE"/> + <Register name="WO_dint" format="dint" array-dim1="10" array-dim2="1" size="4" address="1020" mem-size="40" synchro="SLAVE"/> + <Register name="WO_real" format="real" array-dim1="10" array-dim2="1" size="4" address="1060" mem-size="40" synchro="SLAVE"/> + <Register name="WO_dt" format="dt" array-dim1="10" array-dim2="1" size="8" address="1100" mem-size="80" synchro="SLAVE"/> + </Block> + <Instance label="testDevice1" address="0"/> + <Instance label="testDevice2" address="1"/> + </SILECS-Class> + </SILECS-Mapping> +</SILECS-Param> diff --git a/silecs-codegen/src/xml/test/generated_temp/client/Siemens_Step7Block.silecsparam b/silecs-codegen/src/xml/test/generated_temp/client/Siemens_Step7Block.silecsparam new file mode 100644 index 0000000..de28157 --- /dev/null +++ b/silecs-codegen/src/xml/test/generated_temp/client/Siemens_Step7Block.silecsparam @@ -0,0 +1,80 @@ +<?xml version="1.0"?> +<SILECS-Param silecs-version="DEV"> + <Mapping-Info> + <Owner user-login="schwinn"/> + <Generation date="2016-07-26 15:37:54.623827"/> + <Deployment checksum="3940683809"/> + </Mapping-Info> + <SILECS-Mapping plc-name="Siemens_Step7Block" plc-brand="SIEMENS" plc-system="STEP-7" plc-model="SIMATIC_S7-300" protocol="DEVICE_MODE" address="0" domain="NotUsed" used-mem="TODO"> + <SILECS-Class name="SilecsHeader" version="1.0.0" address="0" used-mem="DB0..DB0 / 48 bytes"> + <Block name="hdrBlk" mode="READ-ONLY" size="14" address="0" mem-size="48"> + <Register name="_version" format="string" string-len="16" array-dim1="1" array-dim2="1" size="1" address="0" mem-size="18" synchro="MASTER"/> + <Register name="_checksum" format="uint32" array-dim1="1" array-dim2="1" size="4" address="18" mem-size="4" synchro="MASTER"/> + <Register name="_user" format="string" string-len="16" array-dim1="1" array-dim2="1" size="1" address="22" mem-size="18" synchro="MASTER"/> + <Register name="_date" format="dt" array-dim1="1" array-dim2="1" size="8" address="40" mem-size="8" synchro="MASTER"/> + </Block> + <Instance label="SilecsHeader" address="0"/> + </SILECS-Class> + <SILECS-Class name="AllTypes" version="0.1.0" address="1" used-mem="DB1..DB2 / 3540 bytes"> + <Block name="MyROBlock" mode="READ-ONLY" size="53" address="0" mem-size="118"> + <Register name="RO_int8" format="int8" array-dim1="1" array-dim2="1" size="1" address="0" mem-size="1" synchro="MASTER"/> + <Register name="RO_uint8" format="uint8" array-dim1="1" array-dim2="1" size="1" address="1" mem-size="1" synchro="MASTER"/> + <Register name="RO_int16" format="int16" array-dim1="1" array-dim2="1" size="2" address="2" mem-size="2" synchro="MASTER"/> + <Register name="RO_uint16" format="uint16" array-dim1="1" array-dim2="1" size="2" address="4" mem-size="2" synchro="MASTER"/> + <Register name="RO_int32" format="int32" array-dim1="1" array-dim2="1" size="4" address="6" mem-size="4" synchro="MASTER"/> + <Register name="RO_uint32" format="uint32" array-dim1="1" array-dim2="1" size="4" address="10" mem-size="4" synchro="MASTER"/> + <Register name="RO_float32" format="float32" array-dim1="1" array-dim2="1" size="4" address="14" mem-size="4" synchro="MASTER"/> + <Register name="RO_string" format="string" string-len="64" array-dim1="1" array-dim2="1" size="1" address="18" mem-size="66" synchro="MASTER"/> + <Register name="RO_date" format="date" array-dim1="1" array-dim2="1" size="8" address="84" mem-size="8" synchro="MASTER"/> + <Register name="RO_char" format="char" array-dim1="1" array-dim2="1" size="1" address="92" mem-size="1" synchro="MASTER"/> + <Register name="RO_byte" format="byte" array-dim1="1" array-dim2="1" size="1" address="93" mem-size="1" synchro="MASTER"/> + <Register name="RO_word" format="word" array-dim1="1" array-dim2="1" size="2" address="94" mem-size="2" synchro="MASTER"/> + <Register name="RO_dword" format="dword" array-dim1="1" array-dim2="1" size="4" address="96" mem-size="4" synchro="MASTER"/> + <Register name="RO_int" format="int" array-dim1="1" array-dim2="1" size="2" address="100" mem-size="2" synchro="MASTER"/> + <Register name="RO_dint" format="dint" array-dim1="1" array-dim2="1" size="4" address="102" mem-size="4" synchro="MASTER"/> + <Register name="RO_real" format="real" array-dim1="1" array-dim2="1" size="4" address="106" mem-size="4" synchro="MASTER"/> + <Register name="RO_dt" format="dt" array-dim1="1" array-dim2="1" size="8" address="110" mem-size="8" synchro="MASTER"/> + </Block> + <Block name="MyRWBlock" mode="READ-WRITE" size="212" address="118" mem-size="472"> + <Register name="RW_int8" format="int8" array-dim1="2" array-dim2="2" size="1" address="0" mem-size="4" synchro="MASTER"/> + <Register name="RW_uint8" format="uint8" array-dim1="2" array-dim2="2" size="1" address="4" mem-size="4" synchro="MASTER"/> + <Register name="RW_int16" format="int16" array-dim1="2" array-dim2="2" size="2" address="8" mem-size="8" synchro="MASTER"/> + <Register name="RW_uint16" format="uint16" array-dim1="2" array-dim2="2" size="2" address="16" mem-size="8" synchro="MASTER"/> + <Register name="RW_int32" format="int32" array-dim1="2" array-dim2="2" size="4" address="24" mem-size="16" synchro="MASTER"/> + <Register name="RW_uint32" format="uint32" array-dim1="2" array-dim2="2" size="4" address="40" mem-size="16" synchro="MASTER"/> + <Register name="RW_float32" format="float32" array-dim1="2" array-dim2="2" size="4" address="56" mem-size="16" synchro="MASTER"/> + <Register name="RW_string" format="string" string-len="64" array-dim1="2" array-dim2="2" size="1" address="72" mem-size="264" synchro="MASTER"/> + <Register name="RW_date" format="date" array-dim1="2" array-dim2="2" size="8" address="336" mem-size="32" synchro="MASTER"/> + <Register name="RW_char" format="char" array-dim1="2" array-dim2="2" size="1" address="368" mem-size="4" synchro="MASTER"/> + <Register name="RW_byte" format="byte" array-dim1="2" array-dim2="2" size="1" address="372" mem-size="4" synchro="MASTER"/> + <Register name="RW_word" format="word" array-dim1="2" array-dim2="2" size="2" address="376" mem-size="8" synchro="MASTER"/> + <Register name="RW_dword" format="dword" array-dim1="2" array-dim2="2" size="4" address="384" mem-size="16" synchro="MASTER"/> + <Register name="RW_int" format="int" array-dim1="2" array-dim2="2" size="2" address="400" mem-size="8" synchro="MASTER"/> + <Register name="RW_dint" format="dint" array-dim1="2" array-dim2="2" size="4" address="408" mem-size="16" synchro="MASTER"/> + <Register name="RW_real" format="real" array-dim1="2" array-dim2="2" size="4" address="424" mem-size="16" synchro="MASTER"/> + <Register name="RW_dt" format="dt" array-dim1="2" array-dim2="2" size="8" address="440" mem-size="32" synchro="MASTER"/> + </Block> + <Block name="MyWOBlock" mode="WRITE-ONLY" size="530" address="590" mem-size="1180"> + <Register name="WO_int8" format="int8" array-dim1="10" array-dim2="1" size="1" address="0" mem-size="10" synchro="SLAVE"/> + <Register name="WO_uint8" format="uint8" array-dim1="10" array-dim2="1" size="1" address="10" mem-size="10" synchro="SLAVE"/> + <Register name="WO_int16" format="int16" array-dim1="10" array-dim2="1" size="2" address="20" mem-size="20" synchro="SLAVE"/> + <Register name="WO_uint16" format="uint16" array-dim1="10" array-dim2="1" size="2" address="40" mem-size="20" synchro="SLAVE"/> + <Register name="WO_int32" format="int32" array-dim1="10" array-dim2="1" size="4" address="60" mem-size="40" synchro="SLAVE"/> + <Register name="WO_uint32" format="uint32" array-dim1="10" array-dim2="1" size="4" address="100" mem-size="40" synchro="SLAVE"/> + <Register name="WO_float32" format="float32" array-dim1="10" array-dim2="1" size="4" address="140" mem-size="40" synchro="SLAVE"/> + <Register name="WO_string" format="string" string-len="64" array-dim1="10" array-dim2="1" size="1" address="180" mem-size="660" synchro="SLAVE"/> + <Register name="WO_date" format="date" array-dim1="10" array-dim2="1" size="8" address="840" mem-size="80" synchro="SLAVE"/> + <Register name="WO_char" format="char" array-dim1="10" array-dim2="1" size="1" address="920" mem-size="10" synchro="SLAVE"/> + <Register name="WO_byte" format="byte" array-dim1="10" array-dim2="1" size="1" address="930" mem-size="10" synchro="SLAVE"/> + <Register name="WO_word" format="word" array-dim1="10" array-dim2="1" size="2" address="940" mem-size="20" synchro="SLAVE"/> + <Register name="WO_dword" format="dword" array-dim1="10" array-dim2="1" size="4" address="960" mem-size="40" synchro="SLAVE"/> + <Register name="WO_int" format="int" array-dim1="10" array-dim2="1" size="2" address="1000" mem-size="20" synchro="SLAVE"/> + <Register name="WO_dint" format="dint" array-dim1="10" array-dim2="1" size="4" address="1020" mem-size="40" synchro="SLAVE"/> + <Register name="WO_real" format="real" array-dim1="10" array-dim2="1" size="4" address="1060" mem-size="40" synchro="SLAVE"/> + <Register name="WO_dt" format="dt" array-dim1="10" array-dim2="1" size="8" address="1100" mem-size="80" synchro="SLAVE"/> + </Block> + <Instance label="testDevice1" address="1"/> + <Instance label="testDevice2" address="2"/> + </SILECS-Class> + </SILECS-Mapping> +</SILECS-Param> diff --git a/silecs-codegen/src/xml/test/generated_temp/client/Siemens_Step7Device.silecsparam b/silecs-codegen/src/xml/test/generated_temp/client/Siemens_Step7Device.silecsparam new file mode 100644 index 0000000..4dd52a1 --- /dev/null +++ b/silecs-codegen/src/xml/test/generated_temp/client/Siemens_Step7Device.silecsparam @@ -0,0 +1,80 @@ +<?xml version="1.0"?> +<SILECS-Param silecs-version="DEV"> + <Mapping-Info> + <Owner user-login="schwinn"/> + <Generation date="2016-07-26 15:37:54.639689"/> + <Deployment checksum="3940683809"/> + </Mapping-Info> + <SILECS-Mapping plc-name="Siemens_Step7Device" plc-brand="SIEMENS" plc-system="STEP-7" plc-model="SIMATIC_S7-300" protocol="BLOCK_MODE" address="0" domain="NotUsed" used-mem="TODO"> + <SILECS-Class name="SilecsHeader" version="1.0.0" address="0" used-mem="DB0..DB0 / 48 bytes"> + <Block name="hdrBlk" mode="READ-ONLY" size="14" address="0" mem-size="48"> + <Register name="_version" format="string" string-len="16" array-dim1="1" array-dim2="1" size="1" address="0" mem-size="18" synchro="MASTER"/> + <Register name="_checksum" format="uint32" array-dim1="1" array-dim2="1" size="4" address="18" mem-size="4" synchro="MASTER"/> + <Register name="_user" format="string" string-len="16" array-dim1="1" array-dim2="1" size="1" address="22" mem-size="18" synchro="MASTER"/> + <Register name="_date" format="dt" array-dim1="1" array-dim2="1" size="8" address="40" mem-size="8" synchro="MASTER"/> + </Block> + <Instance label="SilecsHeader" address="0"/> + </SILECS-Class> + <SILECS-Class name="AllTypes" version="0.1.0" address="1" used-mem="DB1..DB3 / 3540 bytes"> + <Block name="MyROBlock" mode="READ-ONLY" size="53" address="1" mem-size="118"> + <Register name="RO_int8" format="int8" array-dim1="1" array-dim2="1" size="1" address="0" mem-size="1" synchro="MASTER"/> + <Register name="RO_uint8" format="uint8" array-dim1="1" array-dim2="1" size="1" address="1" mem-size="1" synchro="MASTER"/> + <Register name="RO_int16" format="int16" array-dim1="1" array-dim2="1" size="2" address="2" mem-size="2" synchro="MASTER"/> + <Register name="RO_uint16" format="uint16" array-dim1="1" array-dim2="1" size="2" address="4" mem-size="2" synchro="MASTER"/> + <Register name="RO_int32" format="int32" array-dim1="1" array-dim2="1" size="4" address="6" mem-size="4" synchro="MASTER"/> + <Register name="RO_uint32" format="uint32" array-dim1="1" array-dim2="1" size="4" address="10" mem-size="4" synchro="MASTER"/> + <Register name="RO_float32" format="float32" array-dim1="1" array-dim2="1" size="4" address="14" mem-size="4" synchro="MASTER"/> + <Register name="RO_string" format="string" string-len="64" array-dim1="1" array-dim2="1" size="1" address="18" mem-size="66" synchro="MASTER"/> + <Register name="RO_date" format="date" array-dim1="1" array-dim2="1" size="8" address="84" mem-size="8" synchro="MASTER"/> + <Register name="RO_char" format="char" array-dim1="1" array-dim2="1" size="1" address="92" mem-size="1" synchro="MASTER"/> + <Register name="RO_byte" format="byte" array-dim1="1" array-dim2="1" size="1" address="93" mem-size="1" synchro="MASTER"/> + <Register name="RO_word" format="word" array-dim1="1" array-dim2="1" size="2" address="94" mem-size="2" synchro="MASTER"/> + <Register name="RO_dword" format="dword" array-dim1="1" array-dim2="1" size="4" address="96" mem-size="4" synchro="MASTER"/> + <Register name="RO_int" format="int" array-dim1="1" array-dim2="1" size="2" address="100" mem-size="2" synchro="MASTER"/> + <Register name="RO_dint" format="dint" array-dim1="1" array-dim2="1" size="4" address="102" mem-size="4" synchro="MASTER"/> + <Register name="RO_real" format="real" array-dim1="1" array-dim2="1" size="4" address="106" mem-size="4" synchro="MASTER"/> + <Register name="RO_dt" format="dt" array-dim1="1" array-dim2="1" size="8" address="110" mem-size="8" synchro="MASTER"/> + </Block> + <Block name="MyRWBlock" mode="READ-WRITE" size="212" address="2" mem-size="472"> + <Register name="RW_int8" format="int8" array-dim1="2" array-dim2="2" size="1" address="0" mem-size="4" synchro="MASTER"/> + <Register name="RW_uint8" format="uint8" array-dim1="2" array-dim2="2" size="1" address="4" mem-size="4" synchro="MASTER"/> + <Register name="RW_int16" format="int16" array-dim1="2" array-dim2="2" size="2" address="8" mem-size="8" synchro="MASTER"/> + <Register name="RW_uint16" format="uint16" array-dim1="2" array-dim2="2" size="2" address="16" mem-size="8" synchro="MASTER"/> + <Register name="RW_int32" format="int32" array-dim1="2" array-dim2="2" size="4" address="24" mem-size="16" synchro="MASTER"/> + <Register name="RW_uint32" format="uint32" array-dim1="2" array-dim2="2" size="4" address="40" mem-size="16" synchro="MASTER"/> + <Register name="RW_float32" format="float32" array-dim1="2" array-dim2="2" size="4" address="56" mem-size="16" synchro="MASTER"/> + <Register name="RW_string" format="string" string-len="64" array-dim1="2" array-dim2="2" size="1" address="72" mem-size="264" synchro="MASTER"/> + <Register name="RW_date" format="date" array-dim1="2" array-dim2="2" size="8" address="336" mem-size="32" synchro="MASTER"/> + <Register name="RW_char" format="char" array-dim1="2" array-dim2="2" size="1" address="368" mem-size="4" synchro="MASTER"/> + <Register name="RW_byte" format="byte" array-dim1="2" array-dim2="2" size="1" address="372" mem-size="4" synchro="MASTER"/> + <Register name="RW_word" format="word" array-dim1="2" array-dim2="2" size="2" address="376" mem-size="8" synchro="MASTER"/> + <Register name="RW_dword" format="dword" array-dim1="2" array-dim2="2" size="4" address="384" mem-size="16" synchro="MASTER"/> + <Register name="RW_int" format="int" array-dim1="2" array-dim2="2" size="2" address="400" mem-size="8" synchro="MASTER"/> + <Register name="RW_dint" format="dint" array-dim1="2" array-dim2="2" size="4" address="408" mem-size="16" synchro="MASTER"/> + <Register name="RW_real" format="real" array-dim1="2" array-dim2="2" size="4" address="424" mem-size="16" synchro="MASTER"/> + <Register name="RW_dt" format="dt" array-dim1="2" array-dim2="2" size="8" address="440" mem-size="32" synchro="MASTER"/> + </Block> + <Block name="MyWOBlock" mode="WRITE-ONLY" size="530" address="3" mem-size="1180"> + <Register name="WO_int8" format="int8" array-dim1="10" array-dim2="1" size="1" address="0" mem-size="10" synchro="SLAVE"/> + <Register name="WO_uint8" format="uint8" array-dim1="10" array-dim2="1" size="1" address="10" mem-size="10" synchro="SLAVE"/> + <Register name="WO_int16" format="int16" array-dim1="10" array-dim2="1" size="2" address="20" mem-size="20" synchro="SLAVE"/> + <Register name="WO_uint16" format="uint16" array-dim1="10" array-dim2="1" size="2" address="40" mem-size="20" synchro="SLAVE"/> + <Register name="WO_int32" format="int32" array-dim1="10" array-dim2="1" size="4" address="60" mem-size="40" synchro="SLAVE"/> + <Register name="WO_uint32" format="uint32" array-dim1="10" array-dim2="1" size="4" address="100" mem-size="40" synchro="SLAVE"/> + <Register name="WO_float32" format="float32" array-dim1="10" array-dim2="1" size="4" address="140" mem-size="40" synchro="SLAVE"/> + <Register name="WO_string" format="string" string-len="64" array-dim1="10" array-dim2="1" size="1" address="180" mem-size="660" synchro="SLAVE"/> + <Register name="WO_date" format="date" array-dim1="10" array-dim2="1" size="8" address="840" mem-size="80" synchro="SLAVE"/> + <Register name="WO_char" format="char" array-dim1="10" array-dim2="1" size="1" address="920" mem-size="10" synchro="SLAVE"/> + <Register name="WO_byte" format="byte" array-dim1="10" array-dim2="1" size="1" address="930" mem-size="10" synchro="SLAVE"/> + <Register name="WO_word" format="word" array-dim1="10" array-dim2="1" size="2" address="940" mem-size="20" synchro="SLAVE"/> + <Register name="WO_dword" format="dword" array-dim1="10" array-dim2="1" size="4" address="960" mem-size="40" synchro="SLAVE"/> + <Register name="WO_int" format="int" array-dim1="10" array-dim2="1" size="2" address="1000" mem-size="20" synchro="SLAVE"/> + <Register name="WO_dint" format="dint" array-dim1="10" array-dim2="1" size="4" address="1020" mem-size="40" synchro="SLAVE"/> + <Register name="WO_real" format="real" array-dim1="10" array-dim2="1" size="4" address="1060" mem-size="40" synchro="SLAVE"/> + <Register name="WO_dt" format="dt" array-dim1="10" array-dim2="1" size="8" address="1100" mem-size="80" synchro="SLAVE"/> + </Block> + <Instance label="testDevice1" address="0"/> + <Instance label="testDevice2" address="1"/> + </SILECS-Class> + </SILECS-Mapping> +</SILECS-Param> diff --git a/silecs-codegen/src/xml/test/generated_temp/client/Siemens_TiaBlock.silecsparam b/silecs-codegen/src/xml/test/generated_temp/client/Siemens_TiaBlock.silecsparam new file mode 100644 index 0000000..2b261f3 --- /dev/null +++ b/silecs-codegen/src/xml/test/generated_temp/client/Siemens_TiaBlock.silecsparam @@ -0,0 +1,80 @@ +<?xml version="1.0"?> +<SILECS-Param silecs-version="DEV"> + <Mapping-Info> + <Owner user-login="schwinn"/> + <Generation date="2016-07-26 15:37:54.606556"/> + <Deployment checksum="3940683809"/> + </Mapping-Info> + <SILECS-Mapping plc-name="Siemens_TiaBlock" plc-brand="SIEMENS" plc-system="TIA-PORTAL" plc-model="SIMATIC_S7-300" protocol="BLOCK_MODE" address="0" domain="NotUsed" used-mem="TODO"> + <SILECS-Class name="SilecsHeader" version="1.0.0" address="0" used-mem="DB0..DB0 / 48 bytes"> + <Block name="hdrBlk" mode="READ-ONLY" size="14" address="0" mem-size="48"> + <Register name="_version" format="string" string-len="16" array-dim1="1" array-dim2="1" size="1" address="0" mem-size="18" synchro="MASTER"/> + <Register name="_checksum" format="uint32" array-dim1="1" array-dim2="1" size="4" address="18" mem-size="4" synchro="MASTER"/> + <Register name="_user" format="string" string-len="16" array-dim1="1" array-dim2="1" size="1" address="22" mem-size="18" synchro="MASTER"/> + <Register name="_date" format="dt" array-dim1="1" array-dim2="1" size="8" address="40" mem-size="8" synchro="MASTER"/> + </Block> + <Instance label="SilecsHeader" address="0"/> + </SILECS-Class> + <SILECS-Class name="AllTypes" version="0.1.0" address="1" used-mem="DB1..DB3 / 3540 bytes"> + <Block name="MyROBlock" mode="READ-ONLY" size="53" address="1" mem-size="118"> + <Register name="RO_int8" format="int8" array-dim1="1" array-dim2="1" size="1" address="0" mem-size="1" synchro="MASTER"/> + <Register name="RO_uint8" format="uint8" array-dim1="1" array-dim2="1" size="1" address="1" mem-size="1" synchro="MASTER"/> + <Register name="RO_int16" format="int16" array-dim1="1" array-dim2="1" size="2" address="2" mem-size="2" synchro="MASTER"/> + <Register name="RO_uint16" format="uint16" array-dim1="1" array-dim2="1" size="2" address="4" mem-size="2" synchro="MASTER"/> + <Register name="RO_int32" format="int32" array-dim1="1" array-dim2="1" size="4" address="6" mem-size="4" synchro="MASTER"/> + <Register name="RO_uint32" format="uint32" array-dim1="1" array-dim2="1" size="4" address="10" mem-size="4" synchro="MASTER"/> + <Register name="RO_float32" format="float32" array-dim1="1" array-dim2="1" size="4" address="14" mem-size="4" synchro="MASTER"/> + <Register name="RO_string" format="string" string-len="64" array-dim1="1" array-dim2="1" size="1" address="18" mem-size="66" synchro="MASTER"/> + <Register name="RO_date" format="date" array-dim1="1" array-dim2="1" size="8" address="84" mem-size="8" synchro="MASTER"/> + <Register name="RO_char" format="char" array-dim1="1" array-dim2="1" size="1" address="92" mem-size="1" synchro="MASTER"/> + <Register name="RO_byte" format="byte" array-dim1="1" array-dim2="1" size="1" address="93" mem-size="1" synchro="MASTER"/> + <Register name="RO_word" format="word" array-dim1="1" array-dim2="1" size="2" address="94" mem-size="2" synchro="MASTER"/> + <Register name="RO_dword" format="dword" array-dim1="1" array-dim2="1" size="4" address="96" mem-size="4" synchro="MASTER"/> + <Register name="RO_int" format="int" array-dim1="1" array-dim2="1" size="2" address="100" mem-size="2" synchro="MASTER"/> + <Register name="RO_dint" format="dint" array-dim1="1" array-dim2="1" size="4" address="102" mem-size="4" synchro="MASTER"/> + <Register name="RO_real" format="real" array-dim1="1" array-dim2="1" size="4" address="106" mem-size="4" synchro="MASTER"/> + <Register name="RO_dt" format="dt" array-dim1="1" array-dim2="1" size="8" address="110" mem-size="8" synchro="MASTER"/> + </Block> + <Block name="MyRWBlock" mode="READ-WRITE" size="212" address="2" mem-size="472"> + <Register name="RW_int8" format="int8" array-dim1="2" array-dim2="2" size="1" address="0" mem-size="4" synchro="MASTER"/> + <Register name="RW_uint8" format="uint8" array-dim1="2" array-dim2="2" size="1" address="4" mem-size="4" synchro="MASTER"/> + <Register name="RW_int16" format="int16" array-dim1="2" array-dim2="2" size="2" address="8" mem-size="8" synchro="MASTER"/> + <Register name="RW_uint16" format="uint16" array-dim1="2" array-dim2="2" size="2" address="16" mem-size="8" synchro="MASTER"/> + <Register name="RW_int32" format="int32" array-dim1="2" array-dim2="2" size="4" address="24" mem-size="16" synchro="MASTER"/> + <Register name="RW_uint32" format="uint32" array-dim1="2" array-dim2="2" size="4" address="40" mem-size="16" synchro="MASTER"/> + <Register name="RW_float32" format="float32" array-dim1="2" array-dim2="2" size="4" address="56" mem-size="16" synchro="MASTER"/> + <Register name="RW_string" format="string" string-len="64" array-dim1="2" array-dim2="2" size="1" address="72" mem-size="264" synchro="MASTER"/> + <Register name="RW_date" format="date" array-dim1="2" array-dim2="2" size="8" address="336" mem-size="32" synchro="MASTER"/> + <Register name="RW_char" format="char" array-dim1="2" array-dim2="2" size="1" address="368" mem-size="4" synchro="MASTER"/> + <Register name="RW_byte" format="byte" array-dim1="2" array-dim2="2" size="1" address="372" mem-size="4" synchro="MASTER"/> + <Register name="RW_word" format="word" array-dim1="2" array-dim2="2" size="2" address="376" mem-size="8" synchro="MASTER"/> + <Register name="RW_dword" format="dword" array-dim1="2" array-dim2="2" size="4" address="384" mem-size="16" synchro="MASTER"/> + <Register name="RW_int" format="int" array-dim1="2" array-dim2="2" size="2" address="400" mem-size="8" synchro="MASTER"/> + <Register name="RW_dint" format="dint" array-dim1="2" array-dim2="2" size="4" address="408" mem-size="16" synchro="MASTER"/> + <Register name="RW_real" format="real" array-dim1="2" array-dim2="2" size="4" address="424" mem-size="16" synchro="MASTER"/> + <Register name="RW_dt" format="dt" array-dim1="2" array-dim2="2" size="8" address="440" mem-size="32" synchro="MASTER"/> + </Block> + <Block name="MyWOBlock" mode="WRITE-ONLY" size="530" address="3" mem-size="1180"> + <Register name="WO_int8" format="int8" array-dim1="10" array-dim2="1" size="1" address="0" mem-size="10" synchro="SLAVE"/> + <Register name="WO_uint8" format="uint8" array-dim1="10" array-dim2="1" size="1" address="10" mem-size="10" synchro="SLAVE"/> + <Register name="WO_int16" format="int16" array-dim1="10" array-dim2="1" size="2" address="20" mem-size="20" synchro="SLAVE"/> + <Register name="WO_uint16" format="uint16" array-dim1="10" array-dim2="1" size="2" address="40" mem-size="20" synchro="SLAVE"/> + <Register name="WO_int32" format="int32" array-dim1="10" array-dim2="1" size="4" address="60" mem-size="40" synchro="SLAVE"/> + <Register name="WO_uint32" format="uint32" array-dim1="10" array-dim2="1" size="4" address="100" mem-size="40" synchro="SLAVE"/> + <Register name="WO_float32" format="float32" array-dim1="10" array-dim2="1" size="4" address="140" mem-size="40" synchro="SLAVE"/> + <Register name="WO_string" format="string" string-len="64" array-dim1="10" array-dim2="1" size="1" address="180" mem-size="660" synchro="SLAVE"/> + <Register name="WO_date" format="date" array-dim1="10" array-dim2="1" size="8" address="840" mem-size="80" synchro="SLAVE"/> + <Register name="WO_char" format="char" array-dim1="10" array-dim2="1" size="1" address="920" mem-size="10" synchro="SLAVE"/> + <Register name="WO_byte" format="byte" array-dim1="10" array-dim2="1" size="1" address="930" mem-size="10" synchro="SLAVE"/> + <Register name="WO_word" format="word" array-dim1="10" array-dim2="1" size="2" address="940" mem-size="20" synchro="SLAVE"/> + <Register name="WO_dword" format="dword" array-dim1="10" array-dim2="1" size="4" address="960" mem-size="40" synchro="SLAVE"/> + <Register name="WO_int" format="int" array-dim1="10" array-dim2="1" size="2" address="1000" mem-size="20" synchro="SLAVE"/> + <Register name="WO_dint" format="dint" array-dim1="10" array-dim2="1" size="4" address="1020" mem-size="40" synchro="SLAVE"/> + <Register name="WO_real" format="real" array-dim1="10" array-dim2="1" size="4" address="1060" mem-size="40" synchro="SLAVE"/> + <Register name="WO_dt" format="dt" array-dim1="10" array-dim2="1" size="8" address="1100" mem-size="80" synchro="SLAVE"/> + </Block> + <Instance label="testDevice1" address="0"/> + <Instance label="testDevice2" address="1"/> + </SILECS-Class> + </SILECS-Mapping> +</SILECS-Param> diff --git a/silecs-codegen/src/xml/test/generated_temp/client/Siemens_TiaDevice.silecsparam b/silecs-codegen/src/xml/test/generated_temp/client/Siemens_TiaDevice.silecsparam new file mode 100644 index 0000000..270a0f1 --- /dev/null +++ b/silecs-codegen/src/xml/test/generated_temp/client/Siemens_TiaDevice.silecsparam @@ -0,0 +1,80 @@ +<?xml version="1.0"?> +<SILECS-Param silecs-version="DEV"> + <Mapping-Info> + <Owner user-login="schwinn"/> + <Generation date="2016-07-26 15:37:54.588418"/> + <Deployment checksum="3940683809"/> + </Mapping-Info> + <SILECS-Mapping plc-name="Siemens_TiaDevice" plc-brand="SIEMENS" plc-system="TIA-PORTAL" plc-model="SIMATIC_S7-300" protocol="DEVICE_MODE" address="0" domain="NotUsed" used-mem="TODO"> + <SILECS-Class name="SilecsHeader" version="1.0.0" address="0" used-mem="DB0..DB0 / 48 bytes"> + <Block name="hdrBlk" mode="READ-ONLY" size="14" address="0" mem-size="48"> + <Register name="_version" format="string" string-len="16" array-dim1="1" array-dim2="1" size="1" address="0" mem-size="18" synchro="MASTER"/> + <Register name="_checksum" format="uint32" array-dim1="1" array-dim2="1" size="4" address="18" mem-size="4" synchro="MASTER"/> + <Register name="_user" format="string" string-len="16" array-dim1="1" array-dim2="1" size="1" address="22" mem-size="18" synchro="MASTER"/> + <Register name="_date" format="dt" array-dim1="1" array-dim2="1" size="8" address="40" mem-size="8" synchro="MASTER"/> + </Block> + <Instance label="SilecsHeader" address="0"/> + </SILECS-Class> + <SILECS-Class name="AllTypes" version="0.1.0" address="1" used-mem="DB1..DB2 / 3540 bytes"> + <Block name="MyROBlock" mode="READ-ONLY" size="53" address="0" mem-size="118"> + <Register name="RO_int8" format="int8" array-dim1="1" array-dim2="1" size="1" address="0" mem-size="1" synchro="MASTER"/> + <Register name="RO_uint8" format="uint8" array-dim1="1" array-dim2="1" size="1" address="1" mem-size="1" synchro="MASTER"/> + <Register name="RO_int16" format="int16" array-dim1="1" array-dim2="1" size="2" address="2" mem-size="2" synchro="MASTER"/> + <Register name="RO_uint16" format="uint16" array-dim1="1" array-dim2="1" size="2" address="4" mem-size="2" synchro="MASTER"/> + <Register name="RO_int32" format="int32" array-dim1="1" array-dim2="1" size="4" address="6" mem-size="4" synchro="MASTER"/> + <Register name="RO_uint32" format="uint32" array-dim1="1" array-dim2="1" size="4" address="10" mem-size="4" synchro="MASTER"/> + <Register name="RO_float32" format="float32" array-dim1="1" array-dim2="1" size="4" address="14" mem-size="4" synchro="MASTER"/> + <Register name="RO_string" format="string" string-len="64" array-dim1="1" array-dim2="1" size="1" address="18" mem-size="66" synchro="MASTER"/> + <Register name="RO_date" format="date" array-dim1="1" array-dim2="1" size="8" address="84" mem-size="8" synchro="MASTER"/> + <Register name="RO_char" format="char" array-dim1="1" array-dim2="1" size="1" address="92" mem-size="1" synchro="MASTER"/> + <Register name="RO_byte" format="byte" array-dim1="1" array-dim2="1" size="1" address="93" mem-size="1" synchro="MASTER"/> + <Register name="RO_word" format="word" array-dim1="1" array-dim2="1" size="2" address="94" mem-size="2" synchro="MASTER"/> + <Register name="RO_dword" format="dword" array-dim1="1" array-dim2="1" size="4" address="96" mem-size="4" synchro="MASTER"/> + <Register name="RO_int" format="int" array-dim1="1" array-dim2="1" size="2" address="100" mem-size="2" synchro="MASTER"/> + <Register name="RO_dint" format="dint" array-dim1="1" array-dim2="1" size="4" address="102" mem-size="4" synchro="MASTER"/> + <Register name="RO_real" format="real" array-dim1="1" array-dim2="1" size="4" address="106" mem-size="4" synchro="MASTER"/> + <Register name="RO_dt" format="dt" array-dim1="1" array-dim2="1" size="8" address="110" mem-size="8" synchro="MASTER"/> + </Block> + <Block name="MyRWBlock" mode="READ-WRITE" size="212" address="118" mem-size="472"> + <Register name="RW_int8" format="int8" array-dim1="2" array-dim2="2" size="1" address="0" mem-size="4" synchro="MASTER"/> + <Register name="RW_uint8" format="uint8" array-dim1="2" array-dim2="2" size="1" address="4" mem-size="4" synchro="MASTER"/> + <Register name="RW_int16" format="int16" array-dim1="2" array-dim2="2" size="2" address="8" mem-size="8" synchro="MASTER"/> + <Register name="RW_uint16" format="uint16" array-dim1="2" array-dim2="2" size="2" address="16" mem-size="8" synchro="MASTER"/> + <Register name="RW_int32" format="int32" array-dim1="2" array-dim2="2" size="4" address="24" mem-size="16" synchro="MASTER"/> + <Register name="RW_uint32" format="uint32" array-dim1="2" array-dim2="2" size="4" address="40" mem-size="16" synchro="MASTER"/> + <Register name="RW_float32" format="float32" array-dim1="2" array-dim2="2" size="4" address="56" mem-size="16" synchro="MASTER"/> + <Register name="RW_string" format="string" string-len="64" array-dim1="2" array-dim2="2" size="1" address="72" mem-size="264" synchro="MASTER"/> + <Register name="RW_date" format="date" array-dim1="2" array-dim2="2" size="8" address="336" mem-size="32" synchro="MASTER"/> + <Register name="RW_char" format="char" array-dim1="2" array-dim2="2" size="1" address="368" mem-size="4" synchro="MASTER"/> + <Register name="RW_byte" format="byte" array-dim1="2" array-dim2="2" size="1" address="372" mem-size="4" synchro="MASTER"/> + <Register name="RW_word" format="word" array-dim1="2" array-dim2="2" size="2" address="376" mem-size="8" synchro="MASTER"/> + <Register name="RW_dword" format="dword" array-dim1="2" array-dim2="2" size="4" address="384" mem-size="16" synchro="MASTER"/> + <Register name="RW_int" format="int" array-dim1="2" array-dim2="2" size="2" address="400" mem-size="8" synchro="MASTER"/> + <Register name="RW_dint" format="dint" array-dim1="2" array-dim2="2" size="4" address="408" mem-size="16" synchro="MASTER"/> + <Register name="RW_real" format="real" array-dim1="2" array-dim2="2" size="4" address="424" mem-size="16" synchro="MASTER"/> + <Register name="RW_dt" format="dt" array-dim1="2" array-dim2="2" size="8" address="440" mem-size="32" synchro="MASTER"/> + </Block> + <Block name="MyWOBlock" mode="WRITE-ONLY" size="530" address="590" mem-size="1180"> + <Register name="WO_int8" format="int8" array-dim1="10" array-dim2="1" size="1" address="0" mem-size="10" synchro="SLAVE"/> + <Register name="WO_uint8" format="uint8" array-dim1="10" array-dim2="1" size="1" address="10" mem-size="10" synchro="SLAVE"/> + <Register name="WO_int16" format="int16" array-dim1="10" array-dim2="1" size="2" address="20" mem-size="20" synchro="SLAVE"/> + <Register name="WO_uint16" format="uint16" array-dim1="10" array-dim2="1" size="2" address="40" mem-size="20" synchro="SLAVE"/> + <Register name="WO_int32" format="int32" array-dim1="10" array-dim2="1" size="4" address="60" mem-size="40" synchro="SLAVE"/> + <Register name="WO_uint32" format="uint32" array-dim1="10" array-dim2="1" size="4" address="100" mem-size="40" synchro="SLAVE"/> + <Register name="WO_float32" format="float32" array-dim1="10" array-dim2="1" size="4" address="140" mem-size="40" synchro="SLAVE"/> + <Register name="WO_string" format="string" string-len="64" array-dim1="10" array-dim2="1" size="1" address="180" mem-size="660" synchro="SLAVE"/> + <Register name="WO_date" format="date" array-dim1="10" array-dim2="1" size="8" address="840" mem-size="80" synchro="SLAVE"/> + <Register name="WO_char" format="char" array-dim1="10" array-dim2="1" size="1" address="920" mem-size="10" synchro="SLAVE"/> + <Register name="WO_byte" format="byte" array-dim1="10" array-dim2="1" size="1" address="930" mem-size="10" synchro="SLAVE"/> + <Register name="WO_word" format="word" array-dim1="10" array-dim2="1" size="2" address="940" mem-size="20" synchro="SLAVE"/> + <Register name="WO_dword" format="dword" array-dim1="10" array-dim2="1" size="4" address="960" mem-size="40" synchro="SLAVE"/> + <Register name="WO_int" format="int" array-dim1="10" array-dim2="1" size="2" address="1000" mem-size="20" synchro="SLAVE"/> + <Register name="WO_dint" format="dint" array-dim1="10" array-dim2="1" size="4" address="1020" mem-size="40" synchro="SLAVE"/> + <Register name="WO_real" format="real" array-dim1="10" array-dim2="1" size="4" address="1060" mem-size="40" synchro="SLAVE"/> + <Register name="WO_dt" format="dt" array-dim1="10" array-dim2="1" size="8" address="1100" mem-size="80" synchro="SLAVE"/> + </Block> + <Instance label="testDevice1" address="1"/> + <Instance label="testDevice2" address="2"/> + </SILECS-Class> + </SILECS-Mapping> +</SILECS-Param> diff --git a/silecs-codegen/src/xml/test/generated_temp/client/Virtual_SiemensBlock.silecsparam b/silecs-codegen/src/xml/test/generated_temp/client/Virtual_SiemensBlock.silecsparam new file mode 100644 index 0000000..27fc184 --- /dev/null +++ b/silecs-codegen/src/xml/test/generated_temp/client/Virtual_SiemensBlock.silecsparam @@ -0,0 +1,80 @@ +<?xml version="1.0"?> +<SILECS-Param silecs-version="DEV"> + <Mapping-Info> + <Owner user-login="schwinn"/> + <Generation date="2016-07-26 15:37:54.665042"/> + <Deployment checksum="3940683809"/> + </Mapping-Info> + <SILECS-Mapping plc-name="Virtual_SiemensBlock" plc-brand="SIEMENS" plc-system="SNAP7 linux32" plc-model="SIMATIC_S7-VIRTUAL" protocol="BLOCK_MODE" address="0" domain="NotUsed" used-mem="TODO"> + <SILECS-Class name="SilecsHeader" version="1.0.0" address="0" used-mem="DB0..DB0 / 48 bytes"> + <Block name="hdrBlk" mode="READ-ONLY" size="14" address="0" mem-size="48"> + <Register name="_version" format="string" string-len="16" array-dim1="1" array-dim2="1" size="1" address="0" mem-size="18" synchro="MASTER"/> + <Register name="_checksum" format="uint32" array-dim1="1" array-dim2="1" size="4" address="18" mem-size="4" synchro="MASTER"/> + <Register name="_user" format="string" string-len="16" array-dim1="1" array-dim2="1" size="1" address="22" mem-size="18" synchro="MASTER"/> + <Register name="_date" format="dt" array-dim1="1" array-dim2="1" size="8" address="40" mem-size="8" synchro="MASTER"/> + </Block> + <Instance label="SilecsHeader" address="0"/> + </SILECS-Class> + <SILECS-Class name="AllTypes" version="0.1.0" address="1" used-mem="DB1..DB3 / 3540 bytes"> + <Block name="MyROBlock" mode="READ-ONLY" size="53" address="1" mem-size="118"> + <Register name="RO_int8" format="int8" array-dim1="1" array-dim2="1" size="1" address="0" mem-size="1" synchro="MASTER"/> + <Register name="RO_uint8" format="uint8" array-dim1="1" array-dim2="1" size="1" address="1" mem-size="1" synchro="MASTER"/> + <Register name="RO_int16" format="int16" array-dim1="1" array-dim2="1" size="2" address="2" mem-size="2" synchro="MASTER"/> + <Register name="RO_uint16" format="uint16" array-dim1="1" array-dim2="1" size="2" address="4" mem-size="2" synchro="MASTER"/> + <Register name="RO_int32" format="int32" array-dim1="1" array-dim2="1" size="4" address="6" mem-size="4" synchro="MASTER"/> + <Register name="RO_uint32" format="uint32" array-dim1="1" array-dim2="1" size="4" address="10" mem-size="4" synchro="MASTER"/> + <Register name="RO_float32" format="float32" array-dim1="1" array-dim2="1" size="4" address="14" mem-size="4" synchro="MASTER"/> + <Register name="RO_string" format="string" string-len="64" array-dim1="1" array-dim2="1" size="1" address="18" mem-size="66" synchro="MASTER"/> + <Register name="RO_date" format="date" array-dim1="1" array-dim2="1" size="8" address="84" mem-size="8" synchro="MASTER"/> + <Register name="RO_char" format="char" array-dim1="1" array-dim2="1" size="1" address="92" mem-size="1" synchro="MASTER"/> + <Register name="RO_byte" format="byte" array-dim1="1" array-dim2="1" size="1" address="93" mem-size="1" synchro="MASTER"/> + <Register name="RO_word" format="word" array-dim1="1" array-dim2="1" size="2" address="94" mem-size="2" synchro="MASTER"/> + <Register name="RO_dword" format="dword" array-dim1="1" array-dim2="1" size="4" address="96" mem-size="4" synchro="MASTER"/> + <Register name="RO_int" format="int" array-dim1="1" array-dim2="1" size="2" address="100" mem-size="2" synchro="MASTER"/> + <Register name="RO_dint" format="dint" array-dim1="1" array-dim2="1" size="4" address="102" mem-size="4" synchro="MASTER"/> + <Register name="RO_real" format="real" array-dim1="1" array-dim2="1" size="4" address="106" mem-size="4" synchro="MASTER"/> + <Register name="RO_dt" format="dt" array-dim1="1" array-dim2="1" size="8" address="110" mem-size="8" synchro="MASTER"/> + </Block> + <Block name="MyRWBlock" mode="READ-WRITE" size="212" address="2" mem-size="472"> + <Register name="RW_int8" format="int8" array-dim1="2" array-dim2="2" size="1" address="0" mem-size="4" synchro="MASTER"/> + <Register name="RW_uint8" format="uint8" array-dim1="2" array-dim2="2" size="1" address="4" mem-size="4" synchro="MASTER"/> + <Register name="RW_int16" format="int16" array-dim1="2" array-dim2="2" size="2" address="8" mem-size="8" synchro="MASTER"/> + <Register name="RW_uint16" format="uint16" array-dim1="2" array-dim2="2" size="2" address="16" mem-size="8" synchro="MASTER"/> + <Register name="RW_int32" format="int32" array-dim1="2" array-dim2="2" size="4" address="24" mem-size="16" synchro="MASTER"/> + <Register name="RW_uint32" format="uint32" array-dim1="2" array-dim2="2" size="4" address="40" mem-size="16" synchro="MASTER"/> + <Register name="RW_float32" format="float32" array-dim1="2" array-dim2="2" size="4" address="56" mem-size="16" synchro="MASTER"/> + <Register name="RW_string" format="string" string-len="64" array-dim1="2" array-dim2="2" size="1" address="72" mem-size="264" synchro="MASTER"/> + <Register name="RW_date" format="date" array-dim1="2" array-dim2="2" size="8" address="336" mem-size="32" synchro="MASTER"/> + <Register name="RW_char" format="char" array-dim1="2" array-dim2="2" size="1" address="368" mem-size="4" synchro="MASTER"/> + <Register name="RW_byte" format="byte" array-dim1="2" array-dim2="2" size="1" address="372" mem-size="4" synchro="MASTER"/> + <Register name="RW_word" format="word" array-dim1="2" array-dim2="2" size="2" address="376" mem-size="8" synchro="MASTER"/> + <Register name="RW_dword" format="dword" array-dim1="2" array-dim2="2" size="4" address="384" mem-size="16" synchro="MASTER"/> + <Register name="RW_int" format="int" array-dim1="2" array-dim2="2" size="2" address="400" mem-size="8" synchro="MASTER"/> + <Register name="RW_dint" format="dint" array-dim1="2" array-dim2="2" size="4" address="408" mem-size="16" synchro="MASTER"/> + <Register name="RW_real" format="real" array-dim1="2" array-dim2="2" size="4" address="424" mem-size="16" synchro="MASTER"/> + <Register name="RW_dt" format="dt" array-dim1="2" array-dim2="2" size="8" address="440" mem-size="32" synchro="MASTER"/> + </Block> + <Block name="MyWOBlock" mode="WRITE-ONLY" size="530" address="3" mem-size="1180"> + <Register name="WO_int8" format="int8" array-dim1="10" array-dim2="1" size="1" address="0" mem-size="10" synchro="SLAVE"/> + <Register name="WO_uint8" format="uint8" array-dim1="10" array-dim2="1" size="1" address="10" mem-size="10" synchro="SLAVE"/> + <Register name="WO_int16" format="int16" array-dim1="10" array-dim2="1" size="2" address="20" mem-size="20" synchro="SLAVE"/> + <Register name="WO_uint16" format="uint16" array-dim1="10" array-dim2="1" size="2" address="40" mem-size="20" synchro="SLAVE"/> + <Register name="WO_int32" format="int32" array-dim1="10" array-dim2="1" size="4" address="60" mem-size="40" synchro="SLAVE"/> + <Register name="WO_uint32" format="uint32" array-dim1="10" array-dim2="1" size="4" address="100" mem-size="40" synchro="SLAVE"/> + <Register name="WO_float32" format="float32" array-dim1="10" array-dim2="1" size="4" address="140" mem-size="40" synchro="SLAVE"/> + <Register name="WO_string" format="string" string-len="64" array-dim1="10" array-dim2="1" size="1" address="180" mem-size="660" synchro="SLAVE"/> + <Register name="WO_date" format="date" array-dim1="10" array-dim2="1" size="8" address="840" mem-size="80" synchro="SLAVE"/> + <Register name="WO_char" format="char" array-dim1="10" array-dim2="1" size="1" address="920" mem-size="10" synchro="SLAVE"/> + <Register name="WO_byte" format="byte" array-dim1="10" array-dim2="1" size="1" address="930" mem-size="10" synchro="SLAVE"/> + <Register name="WO_word" format="word" array-dim1="10" array-dim2="1" size="2" address="940" mem-size="20" synchro="SLAVE"/> + <Register name="WO_dword" format="dword" array-dim1="10" array-dim2="1" size="4" address="960" mem-size="40" synchro="SLAVE"/> + <Register name="WO_int" format="int" array-dim1="10" array-dim2="1" size="2" address="1000" mem-size="20" synchro="SLAVE"/> + <Register name="WO_dint" format="dint" array-dim1="10" array-dim2="1" size="4" address="1020" mem-size="40" synchro="SLAVE"/> + <Register name="WO_real" format="real" array-dim1="10" array-dim2="1" size="4" address="1060" mem-size="40" synchro="SLAVE"/> + <Register name="WO_dt" format="dt" array-dim1="10" array-dim2="1" size="8" address="1100" mem-size="80" synchro="SLAVE"/> + </Block> + <Instance label="testDevice1" address="0"/> + <Instance label="testDevice2" address="1"/> + </SILECS-Class> + </SILECS-Mapping> +</SILECS-Param> diff --git a/silecs-codegen/src/xml/test/generated_temp/client/Virtual_SiemensDevice.silecsparam b/silecs-codegen/src/xml/test/generated_temp/client/Virtual_SiemensDevice.silecsparam new file mode 100644 index 0000000..dcde87d --- /dev/null +++ b/silecs-codegen/src/xml/test/generated_temp/client/Virtual_SiemensDevice.silecsparam @@ -0,0 +1,80 @@ +<?xml version="1.0"?> +<SILECS-Param silecs-version="DEV"> + <Mapping-Info> + <Owner user-login="schwinn"/> + <Generation date="2016-07-26 15:37:54.650596"/> + <Deployment checksum="3940683809"/> + </Mapping-Info> + <SILECS-Mapping plc-name="Virtual_SiemensDevice" plc-brand="SIEMENS" plc-system="SNAP7 linux32" plc-model="SIMATIC_S7-VIRTUAL" protocol="DEVICE_MODE" address="0" domain="NotUsed" used-mem="TODO"> + <SILECS-Class name="SilecsHeader" version="1.0.0" address="0" used-mem="DB0..DB0 / 48 bytes"> + <Block name="hdrBlk" mode="READ-ONLY" size="14" address="0" mem-size="48"> + <Register name="_version" format="string" string-len="16" array-dim1="1" array-dim2="1" size="1" address="0" mem-size="18" synchro="MASTER"/> + <Register name="_checksum" format="uint32" array-dim1="1" array-dim2="1" size="4" address="18" mem-size="4" synchro="MASTER"/> + <Register name="_user" format="string" string-len="16" array-dim1="1" array-dim2="1" size="1" address="22" mem-size="18" synchro="MASTER"/> + <Register name="_date" format="dt" array-dim1="1" array-dim2="1" size="8" address="40" mem-size="8" synchro="MASTER"/> + </Block> + <Instance label="SilecsHeader" address="0"/> + </SILECS-Class> + <SILECS-Class name="AllTypes" version="0.1.0" address="1" used-mem="DB1..DB2 / 3540 bytes"> + <Block name="MyROBlock" mode="READ-ONLY" size="53" address="0" mem-size="118"> + <Register name="RO_int8" format="int8" array-dim1="1" array-dim2="1" size="1" address="0" mem-size="1" synchro="MASTER"/> + <Register name="RO_uint8" format="uint8" array-dim1="1" array-dim2="1" size="1" address="1" mem-size="1" synchro="MASTER"/> + <Register name="RO_int16" format="int16" array-dim1="1" array-dim2="1" size="2" address="2" mem-size="2" synchro="MASTER"/> + <Register name="RO_uint16" format="uint16" array-dim1="1" array-dim2="1" size="2" address="4" mem-size="2" synchro="MASTER"/> + <Register name="RO_int32" format="int32" array-dim1="1" array-dim2="1" size="4" address="6" mem-size="4" synchro="MASTER"/> + <Register name="RO_uint32" format="uint32" array-dim1="1" array-dim2="1" size="4" address="10" mem-size="4" synchro="MASTER"/> + <Register name="RO_float32" format="float32" array-dim1="1" array-dim2="1" size="4" address="14" mem-size="4" synchro="MASTER"/> + <Register name="RO_string" format="string" string-len="64" array-dim1="1" array-dim2="1" size="1" address="18" mem-size="66" synchro="MASTER"/> + <Register name="RO_date" format="date" array-dim1="1" array-dim2="1" size="8" address="84" mem-size="8" synchro="MASTER"/> + <Register name="RO_char" format="char" array-dim1="1" array-dim2="1" size="1" address="92" mem-size="1" synchro="MASTER"/> + <Register name="RO_byte" format="byte" array-dim1="1" array-dim2="1" size="1" address="93" mem-size="1" synchro="MASTER"/> + <Register name="RO_word" format="word" array-dim1="1" array-dim2="1" size="2" address="94" mem-size="2" synchro="MASTER"/> + <Register name="RO_dword" format="dword" array-dim1="1" array-dim2="1" size="4" address="96" mem-size="4" synchro="MASTER"/> + <Register name="RO_int" format="int" array-dim1="1" array-dim2="1" size="2" address="100" mem-size="2" synchro="MASTER"/> + <Register name="RO_dint" format="dint" array-dim1="1" array-dim2="1" size="4" address="102" mem-size="4" synchro="MASTER"/> + <Register name="RO_real" format="real" array-dim1="1" array-dim2="1" size="4" address="106" mem-size="4" synchro="MASTER"/> + <Register name="RO_dt" format="dt" array-dim1="1" array-dim2="1" size="8" address="110" mem-size="8" synchro="MASTER"/> + </Block> + <Block name="MyRWBlock" mode="READ-WRITE" size="212" address="118" mem-size="472"> + <Register name="RW_int8" format="int8" array-dim1="2" array-dim2="2" size="1" address="0" mem-size="4" synchro="MASTER"/> + <Register name="RW_uint8" format="uint8" array-dim1="2" array-dim2="2" size="1" address="4" mem-size="4" synchro="MASTER"/> + <Register name="RW_int16" format="int16" array-dim1="2" array-dim2="2" size="2" address="8" mem-size="8" synchro="MASTER"/> + <Register name="RW_uint16" format="uint16" array-dim1="2" array-dim2="2" size="2" address="16" mem-size="8" synchro="MASTER"/> + <Register name="RW_int32" format="int32" array-dim1="2" array-dim2="2" size="4" address="24" mem-size="16" synchro="MASTER"/> + <Register name="RW_uint32" format="uint32" array-dim1="2" array-dim2="2" size="4" address="40" mem-size="16" synchro="MASTER"/> + <Register name="RW_float32" format="float32" array-dim1="2" array-dim2="2" size="4" address="56" mem-size="16" synchro="MASTER"/> + <Register name="RW_string" format="string" string-len="64" array-dim1="2" array-dim2="2" size="1" address="72" mem-size="264" synchro="MASTER"/> + <Register name="RW_date" format="date" array-dim1="2" array-dim2="2" size="8" address="336" mem-size="32" synchro="MASTER"/> + <Register name="RW_char" format="char" array-dim1="2" array-dim2="2" size="1" address="368" mem-size="4" synchro="MASTER"/> + <Register name="RW_byte" format="byte" array-dim1="2" array-dim2="2" size="1" address="372" mem-size="4" synchro="MASTER"/> + <Register name="RW_word" format="word" array-dim1="2" array-dim2="2" size="2" address="376" mem-size="8" synchro="MASTER"/> + <Register name="RW_dword" format="dword" array-dim1="2" array-dim2="2" size="4" address="384" mem-size="16" synchro="MASTER"/> + <Register name="RW_int" format="int" array-dim1="2" array-dim2="2" size="2" address="400" mem-size="8" synchro="MASTER"/> + <Register name="RW_dint" format="dint" array-dim1="2" array-dim2="2" size="4" address="408" mem-size="16" synchro="MASTER"/> + <Register name="RW_real" format="real" array-dim1="2" array-dim2="2" size="4" address="424" mem-size="16" synchro="MASTER"/> + <Register name="RW_dt" format="dt" array-dim1="2" array-dim2="2" size="8" address="440" mem-size="32" synchro="MASTER"/> + </Block> + <Block name="MyWOBlock" mode="WRITE-ONLY" size="530" address="590" mem-size="1180"> + <Register name="WO_int8" format="int8" array-dim1="10" array-dim2="1" size="1" address="0" mem-size="10" synchro="SLAVE"/> + <Register name="WO_uint8" format="uint8" array-dim1="10" array-dim2="1" size="1" address="10" mem-size="10" synchro="SLAVE"/> + <Register name="WO_int16" format="int16" array-dim1="10" array-dim2="1" size="2" address="20" mem-size="20" synchro="SLAVE"/> + <Register name="WO_uint16" format="uint16" array-dim1="10" array-dim2="1" size="2" address="40" mem-size="20" synchro="SLAVE"/> + <Register name="WO_int32" format="int32" array-dim1="10" array-dim2="1" size="4" address="60" mem-size="40" synchro="SLAVE"/> + <Register name="WO_uint32" format="uint32" array-dim1="10" array-dim2="1" size="4" address="100" mem-size="40" synchro="SLAVE"/> + <Register name="WO_float32" format="float32" array-dim1="10" array-dim2="1" size="4" address="140" mem-size="40" synchro="SLAVE"/> + <Register name="WO_string" format="string" string-len="64" array-dim1="10" array-dim2="1" size="1" address="180" mem-size="660" synchro="SLAVE"/> + <Register name="WO_date" format="date" array-dim1="10" array-dim2="1" size="8" address="840" mem-size="80" synchro="SLAVE"/> + <Register name="WO_char" format="char" array-dim1="10" array-dim2="1" size="1" address="920" mem-size="10" synchro="SLAVE"/> + <Register name="WO_byte" format="byte" array-dim1="10" array-dim2="1" size="1" address="930" mem-size="10" synchro="SLAVE"/> + <Register name="WO_word" format="word" array-dim1="10" array-dim2="1" size="2" address="940" mem-size="20" synchro="SLAVE"/> + <Register name="WO_dword" format="dword" array-dim1="10" array-dim2="1" size="4" address="960" mem-size="40" synchro="SLAVE"/> + <Register name="WO_int" format="int" array-dim1="10" array-dim2="1" size="2" address="1000" mem-size="20" synchro="SLAVE"/> + <Register name="WO_dint" format="dint" array-dim1="10" array-dim2="1" size="4" address="1020" mem-size="40" synchro="SLAVE"/> + <Register name="WO_real" format="real" array-dim1="10" array-dim2="1" size="4" address="1060" mem-size="40" synchro="SLAVE"/> + <Register name="WO_dt" format="dt" array-dim1="10" array-dim2="1" size="8" address="1100" mem-size="80" synchro="SLAVE"/> + </Block> + <Instance label="testDevice1" address="1"/> + <Instance label="testDevice2" address="2"/> + </SILECS-Class> + </SILECS-Mapping> +</SILECS-Param> diff --git a/silecs-codegen/src/xml/test/generated_temp/controller/Beckhoff_BC9020.exp b/silecs-codegen/src/xml/test/generated_temp/controller/Beckhoff_BC9020.exp new file mode 100644 index 0000000..e0e9f23 --- /dev/null +++ b/silecs-codegen/src/xml/test/generated_temp/controller/Beckhoff_BC9020.exp @@ -0,0 +1,328 @@ +(* +------------------------------------------------------------------- +* | C.E.R.N Geneva, Switzerland +* | SILECS - BE/CO-FE +* | April 2015 +* +------------------------------------------------------------------- +* +* Release : SILECS_DEV +*) +VAR_GLOBAL + (*SilecsHeader/SilecsHeader/hdrBlk *) + _version_a781_SilecsHeader AT %MW0: STRING(16):= DEV; + + (*SilecsHeader/SilecsHeader/hdrBlk *) + _checksum_a781_SilecsHeader AT %MW9: DWORD:= 2843029646; + + (*SilecsHeader/SilecsHeader/hdrBlk *) + _user_a781_SilecsHeader AT %MW11: STRING(16):= 'schwinn'; + + (*SilecsHeader/SilecsHeader/hdrBlk *) + _date_a781_SilecsHeader AT %MW20: DT:= DT#2016-7-26-15:37:54; + + (*AllTypes/testDevice1/MyROBlock *) + RO_int8_a583_testDevice1 AT %MW24: SINT; + + (*AllTypes/testDevice1/MyROBlock *) + RO_uint8_a583_testDevice1 AT %MW25: BYTE; + + (*AllTypes/testDevice1/MyROBlock *) + RO_int16_a583_testDevice1 AT %MW26: INT; + + (*AllTypes/testDevice1/MyROBlock *) + RO_uint16_a583_testDevice1 AT %MW27: WORD; + + (*AllTypes/testDevice1/MyROBlock *) + RO_int32_a583_testDevice1 AT %MW28: DINT; + + (*AllTypes/testDevice1/MyROBlock *) + RO_uint32_a583_testDevice1 AT %MW30: DWORD; + + (*AllTypes/testDevice1/MyROBlock *) + RO_float32_a583_testDevice1 AT %MW32: REAL; + + (*AllTypes/testDevice1/MyROBlock *) + RO_string_a583_testDevice1 AT %MW34: STRING(64); + + (*AllTypes/testDevice1/MyROBlock *) + RO_date_a583_testDevice1 AT %MW67: DT; + + (*AllTypes/testDevice1/MyROBlock *) + RO_char_a583_testDevice1 AT %MW71: SINT; + + (*AllTypes/testDevice1/MyROBlock *) + RO_byte_a583_testDevice1 AT %MW72: BYTE; + + (*AllTypes/testDevice1/MyROBlock *) + RO_word_a583_testDevice1 AT %MW73: WORD; + + (*AllTypes/testDevice1/MyROBlock *) + RO_dword_a583_testDevice1 AT %MW74: DWORD; + + (*AllTypes/testDevice1/MyROBlock *) + RO_int_a583_testDevice1 AT %MW76: INT; + + (*AllTypes/testDevice1/MyROBlock *) + RO_dint_a583_testDevice1 AT %MW77: DINT; + + (*AllTypes/testDevice1/MyROBlock *) + RO_real_a583_testDevice1 AT %MW79: REAL; + + (*AllTypes/testDevice1/MyROBlock *) + RO_dt_a583_testDevice1 AT %MW81: DT; + + (*AllTypes/testDevice2/MyROBlock *) + RO_int8_a583_testDevice2 AT %MW85: SINT; + + (*AllTypes/testDevice2/MyROBlock *) + RO_uint8_a583_testDevice2 AT %MW86: BYTE; + + (*AllTypes/testDevice2/MyROBlock *) + RO_int16_a583_testDevice2 AT %MW87: INT; + + (*AllTypes/testDevice2/MyROBlock *) + RO_uint16_a583_testDevice2 AT %MW88: WORD; + + (*AllTypes/testDevice2/MyROBlock *) + RO_int32_a583_testDevice2 AT %MW89: DINT; + + (*AllTypes/testDevice2/MyROBlock *) + RO_uint32_a583_testDevice2 AT %MW91: DWORD; + + (*AllTypes/testDevice2/MyROBlock *) + RO_float32_a583_testDevice2 AT %MW93: REAL; + + (*AllTypes/testDevice2/MyROBlock *) + RO_string_a583_testDevice2 AT %MW95: STRING(64); + + (*AllTypes/testDevice2/MyROBlock *) + RO_date_a583_testDevice2 AT %MW128: DT; + + (*AllTypes/testDevice2/MyROBlock *) + RO_char_a583_testDevice2 AT %MW132: SINT; + + (*AllTypes/testDevice2/MyROBlock *) + RO_byte_a583_testDevice2 AT %MW133: BYTE; + + (*AllTypes/testDevice2/MyROBlock *) + RO_word_a583_testDevice2 AT %MW134: WORD; + + (*AllTypes/testDevice2/MyROBlock *) + RO_dword_a583_testDevice2 AT %MW135: DWORD; + + (*AllTypes/testDevice2/MyROBlock *) + RO_int_a583_testDevice2 AT %MW137: INT; + + (*AllTypes/testDevice2/MyROBlock *) + RO_dint_a583_testDevice2 AT %MW138: DINT; + + (*AllTypes/testDevice2/MyROBlock *) + RO_real_a583_testDevice2 AT %MW140: REAL; + + (*AllTypes/testDevice2/MyROBlock *) + RO_dt_a583_testDevice2 AT %MW142: DT; + + (*AllTypes/testDevice1/MyRWBlock *) + RW_int8_a583_testDevice1 AT %MW146: ARRAY [0..1, 0..1] OF SINT; + + (*AllTypes/testDevice1/MyRWBlock *) + RW_uint8_a583_testDevice1 AT %MW148: ARRAY [0..1, 0..1] OF BYTE; + + (*AllTypes/testDevice1/MyRWBlock *) + RW_int16_a583_testDevice1 AT %MW150: ARRAY [0..1, 0..1] OF INT; + + (*AllTypes/testDevice1/MyRWBlock *) + RW_uint16_a583_testDevice1 AT %MW154: ARRAY [0..1, 0..1] OF WORD; + + (*AllTypes/testDevice1/MyRWBlock *) + RW_int32_a583_testDevice1 AT %MW158: ARRAY [0..1, 0..1] OF DINT; + + (*AllTypes/testDevice1/MyRWBlock *) + RW_uint32_a583_testDevice1 AT %MW166: ARRAY [0..1, 0..1] OF DWORD; + + (*AllTypes/testDevice1/MyRWBlock *) + RW_float32_a583_testDevice1 AT %MW174: ARRAY [0..1, 0..1] OF REAL; + + (*AllTypes/testDevice1/MyRWBlock *) + RW_string_a583_testDevice1 AT %MW182: ARRAY [0..1, 0..1] OF STRING(64); + + (*AllTypes/testDevice1/MyRWBlock *) + RW_date_a583_testDevice1 AT %MW312: ARRAY [0..1, 0..1] OF DT; + + (*AllTypes/testDevice1/MyRWBlock *) + RW_char_a583_testDevice1 AT %MW328: ARRAY [0..1, 0..1] OF SINT; + + (*AllTypes/testDevice1/MyRWBlock *) + RW_byte_a583_testDevice1 AT %MW330: ARRAY [0..1, 0..1] OF BYTE; + + (*AllTypes/testDevice1/MyRWBlock *) + RW_word_a583_testDevice1 AT %MW332: ARRAY [0..1, 0..1] OF WORD; + + (*AllTypes/testDevice1/MyRWBlock *) + RW_dword_a583_testDevice1 AT %MW336: ARRAY [0..1, 0..1] OF DWORD; + + (*AllTypes/testDevice1/MyRWBlock *) + RW_int_a583_testDevice1 AT %MW344: ARRAY [0..1, 0..1] OF INT; + + (*AllTypes/testDevice1/MyRWBlock *) + RW_dint_a583_testDevice1 AT %MW348: ARRAY [0..1, 0..1] OF DINT; + + (*AllTypes/testDevice1/MyRWBlock *) + RW_real_a583_testDevice1 AT %MW356: ARRAY [0..1, 0..1] OF REAL; + + (*AllTypes/testDevice1/MyRWBlock *) + RW_dt_a583_testDevice1 AT %MW364: ARRAY [0..1, 0..1] OF DT; + + (*AllTypes/testDevice2/MyRWBlock *) + RW_int8_a583_testDevice2 AT %MW380: ARRAY [0..1, 0..1] OF SINT; + + (*AllTypes/testDevice2/MyRWBlock *) + RW_uint8_a583_testDevice2 AT %MW382: ARRAY [0..1, 0..1] OF BYTE; + + (*AllTypes/testDevice2/MyRWBlock *) + RW_int16_a583_testDevice2 AT %MW384: ARRAY [0..1, 0..1] OF INT; + + (*AllTypes/testDevice2/MyRWBlock *) + RW_uint16_a583_testDevice2 AT %MW388: ARRAY [0..1, 0..1] OF WORD; + + (*AllTypes/testDevice2/MyRWBlock *) + RW_int32_a583_testDevice2 AT %MW392: ARRAY [0..1, 0..1] OF DINT; + + (*AllTypes/testDevice2/MyRWBlock *) + RW_uint32_a583_testDevice2 AT %MW400: ARRAY [0..1, 0..1] OF DWORD; + + (*AllTypes/testDevice2/MyRWBlock *) + RW_float32_a583_testDevice2 AT %MW408: ARRAY [0..1, 0..1] OF REAL; + + (*AllTypes/testDevice2/MyRWBlock *) + RW_string_a583_testDevice2 AT %MW416: ARRAY [0..1, 0..1] OF STRING(64); + + (*AllTypes/testDevice2/MyRWBlock *) + RW_date_a583_testDevice2 AT %MW546: ARRAY [0..1, 0..1] OF DT; + + (*AllTypes/testDevice2/MyRWBlock *) + RW_char_a583_testDevice2 AT %MW562: ARRAY [0..1, 0..1] OF SINT; + + (*AllTypes/testDevice2/MyRWBlock *) + RW_byte_a583_testDevice2 AT %MW564: ARRAY [0..1, 0..1] OF BYTE; + + (*AllTypes/testDevice2/MyRWBlock *) + RW_word_a583_testDevice2 AT %MW566: ARRAY [0..1, 0..1] OF WORD; + + (*AllTypes/testDevice2/MyRWBlock *) + RW_dword_a583_testDevice2 AT %MW570: ARRAY [0..1, 0..1] OF DWORD; + + (*AllTypes/testDevice2/MyRWBlock *) + RW_int_a583_testDevice2 AT %MW578: ARRAY [0..1, 0..1] OF INT; + + (*AllTypes/testDevice2/MyRWBlock *) + RW_dint_a583_testDevice2 AT %MW582: ARRAY [0..1, 0..1] OF DINT; + + (*AllTypes/testDevice2/MyRWBlock *) + RW_real_a583_testDevice2 AT %MW590: ARRAY [0..1, 0..1] OF REAL; + + (*AllTypes/testDevice2/MyRWBlock *) + RW_dt_a583_testDevice2 AT %MW598: ARRAY [0..1, 0..1] OF DT; + + (*AllTypes/testDevice1/MyWOBlock *) + WO_int8_a583_testDevice1 AT %MW614: ARRAY [0..9] OF SINT; + + (*AllTypes/testDevice1/MyWOBlock *) + WO_uint8_a583_testDevice1 AT %MW619: ARRAY [0..9] OF BYTE; + + (*AllTypes/testDevice1/MyWOBlock *) + WO_int16_a583_testDevice1 AT %MW624: ARRAY [0..9] OF INT; + + (*AllTypes/testDevice1/MyWOBlock *) + WO_uint16_a583_testDevice1 AT %MW634: ARRAY [0..9] OF WORD; + + (*AllTypes/testDevice1/MyWOBlock *) + WO_int32_a583_testDevice1 AT %MW644: ARRAY [0..9] OF DINT; + + (*AllTypes/testDevice1/MyWOBlock *) + WO_uint32_a583_testDevice1 AT %MW664: ARRAY [0..9] OF DWORD; + + (*AllTypes/testDevice1/MyWOBlock *) + WO_float32_a583_testDevice1 AT %MW684: ARRAY [0..9] OF REAL; + + (*AllTypes/testDevice1/MyWOBlock *) + WO_string_a583_testDevice1 AT %MW704: ARRAY [0..9] OF STRING(64); + + (*AllTypes/testDevice1/MyWOBlock *) + WO_date_a583_testDevice1 AT %MW1029: ARRAY [0..9] OF DT; + + (*AllTypes/testDevice1/MyWOBlock *) + WO_char_a583_testDevice1 AT %MW1069: ARRAY [0..9] OF SINT; + + (*AllTypes/testDevice1/MyWOBlock *) + WO_byte_a583_testDevice1 AT %MW1074: ARRAY [0..9] OF BYTE; + + (*AllTypes/testDevice1/MyWOBlock *) + WO_word_a583_testDevice1 AT %MW1079: ARRAY [0..9] OF WORD; + + (*AllTypes/testDevice1/MyWOBlock *) + WO_dword_a583_testDevice1 AT %MW1089: ARRAY [0..9] OF DWORD; + + (*AllTypes/testDevice1/MyWOBlock *) + WO_int_a583_testDevice1 AT %MW1109: ARRAY [0..9] OF INT; + + (*AllTypes/testDevice1/MyWOBlock *) + WO_dint_a583_testDevice1 AT %MW1119: ARRAY [0..9] OF DINT; + + (*AllTypes/testDevice1/MyWOBlock *) + WO_real_a583_testDevice1 AT %MW1139: ARRAY [0..9] OF REAL; + + (*AllTypes/testDevice1/MyWOBlock *) + WO_dt_a583_testDevice1 AT %MW1159: ARRAY [0..9] OF DT; + + (*AllTypes/testDevice2/MyWOBlock *) + WO_int8_a583_testDevice2 AT %MW1199: ARRAY [0..9] OF SINT; + + (*AllTypes/testDevice2/MyWOBlock *) + WO_uint8_a583_testDevice2 AT %MW1204: ARRAY [0..9] OF BYTE; + + (*AllTypes/testDevice2/MyWOBlock *) + WO_int16_a583_testDevice2 AT %MW1209: ARRAY [0..9] OF INT; + + (*AllTypes/testDevice2/MyWOBlock *) + WO_uint16_a583_testDevice2 AT %MW1219: ARRAY [0..9] OF WORD; + + (*AllTypes/testDevice2/MyWOBlock *) + WO_int32_a583_testDevice2 AT %MW1229: ARRAY [0..9] OF DINT; + + (*AllTypes/testDevice2/MyWOBlock *) + WO_uint32_a583_testDevice2 AT %MW1249: ARRAY [0..9] OF DWORD; + + (*AllTypes/testDevice2/MyWOBlock *) + WO_float32_a583_testDevice2 AT %MW1269: ARRAY [0..9] OF REAL; + + (*AllTypes/testDevice2/MyWOBlock *) + WO_string_a583_testDevice2 AT %MW1289: ARRAY [0..9] OF STRING(64); + + (*AllTypes/testDevice2/MyWOBlock *) + WO_date_a583_testDevice2 AT %MW1614: ARRAY [0..9] OF DT; + + (*AllTypes/testDevice2/MyWOBlock *) + WO_char_a583_testDevice2 AT %MW1654: ARRAY [0..9] OF SINT; + + (*AllTypes/testDevice2/MyWOBlock *) + WO_byte_a583_testDevice2 AT %MW1659: ARRAY [0..9] OF BYTE; + + (*AllTypes/testDevice2/MyWOBlock *) + WO_word_a583_testDevice2 AT %MW1664: ARRAY [0..9] OF WORD; + + (*AllTypes/testDevice2/MyWOBlock *) + WO_dword_a583_testDevice2 AT %MW1674: ARRAY [0..9] OF DWORD; + + (*AllTypes/testDevice2/MyWOBlock *) + WO_int_a583_testDevice2 AT %MW1694: ARRAY [0..9] OF INT; + + (*AllTypes/testDevice2/MyWOBlock *) + WO_dint_a583_testDevice2 AT %MW1704: ARRAY [0..9] OF DINT; + + (*AllTypes/testDevice2/MyWOBlock *) + WO_real_a583_testDevice2 AT %MW1724: ARRAY [0..9] OF REAL; + + (*AllTypes/testDevice2/MyWOBlock *) + WO_dt_a583_testDevice2 AT %MW1744: ARRAY [0..9] OF DT; + +END_VAR \ No newline at end of file diff --git a/silecs-codegen/src/xml/test/generated_temp/controller/Beckhoff_CX9020.exp b/silecs-codegen/src/xml/test/generated_temp/controller/Beckhoff_CX9020.exp new file mode 100644 index 0000000..6dcf462 --- /dev/null +++ b/silecs-codegen/src/xml/test/generated_temp/controller/Beckhoff_CX9020.exp @@ -0,0 +1,328 @@ +(* +------------------------------------------------------------------- +* | C.E.R.N Geneva, Switzerland +* | SILECS - BE/CO-FE +* | April 2015 +* +------------------------------------------------------------------- +* +* Release : SILECS_DEV +*) +VAR_GLOBAL + (*SilecsHeader/SilecsHeader/hdrBlk *) + _version_a781_SilecsHeader AT %MW0: STRING(16):= DEV; + + (*SilecsHeader/SilecsHeader/hdrBlk *) + _checksum_a781_SilecsHeader AT %MW20: DWORD:= 427563505; + + (*SilecsHeader/SilecsHeader/hdrBlk *) + _user_a781_SilecsHeader AT %MW24: STRING(16):= 'schwinn'; + + (*SilecsHeader/SilecsHeader/hdrBlk *) + _date_a781_SilecsHeader AT %MW44: DT:= DT#2016-7-26-15:37:54; + + (*AllTypes/testDevice1/MyROBlock *) + RO_int8_a583_testDevice1 AT %MW52: SINT; + + (*AllTypes/testDevice1/MyROBlock *) + RO_uint8_a583_testDevice1 AT %MW54: BYTE; + + (*AllTypes/testDevice1/MyROBlock *) + RO_int16_a583_testDevice1 AT %MW56: INT; + + (*AllTypes/testDevice1/MyROBlock *) + RO_uint16_a583_testDevice1 AT %MW58: WORD; + + (*AllTypes/testDevice1/MyROBlock *) + RO_int32_a583_testDevice1 AT %MW60: DINT; + + (*AllTypes/testDevice1/MyROBlock *) + RO_uint32_a583_testDevice1 AT %MW64: DWORD; + + (*AllTypes/testDevice1/MyROBlock *) + RO_float32_a583_testDevice1 AT %MW68: REAL; + + (*AllTypes/testDevice1/MyROBlock *) + RO_string_a583_testDevice1 AT %MW72: STRING(64); + + (*AllTypes/testDevice1/MyROBlock *) + RO_date_a583_testDevice1 AT %MW140: DT; + + (*AllTypes/testDevice1/MyROBlock *) + RO_char_a583_testDevice1 AT %MW148: SINT; + + (*AllTypes/testDevice1/MyROBlock *) + RO_byte_a583_testDevice1 AT %MW150: BYTE; + + (*AllTypes/testDevice1/MyROBlock *) + RO_word_a583_testDevice1 AT %MW152: WORD; + + (*AllTypes/testDevice1/MyROBlock *) + RO_dword_a583_testDevice1 AT %MW156: DWORD; + + (*AllTypes/testDevice1/MyROBlock *) + RO_int_a583_testDevice1 AT %MW160: INT; + + (*AllTypes/testDevice1/MyROBlock *) + RO_dint_a583_testDevice1 AT %MW164: DINT; + + (*AllTypes/testDevice1/MyROBlock *) + RO_real_a583_testDevice1 AT %MW168: REAL; + + (*AllTypes/testDevice1/MyROBlock *) + RO_dt_a583_testDevice1 AT %MW172: DT; + + (*AllTypes/testDevice2/MyROBlock *) + RO_int8_a583_testDevice2 AT %MW180: SINT; + + (*AllTypes/testDevice2/MyROBlock *) + RO_uint8_a583_testDevice2 AT %MW182: BYTE; + + (*AllTypes/testDevice2/MyROBlock *) + RO_int16_a583_testDevice2 AT %MW184: INT; + + (*AllTypes/testDevice2/MyROBlock *) + RO_uint16_a583_testDevice2 AT %MW186: WORD; + + (*AllTypes/testDevice2/MyROBlock *) + RO_int32_a583_testDevice2 AT %MW188: DINT; + + (*AllTypes/testDevice2/MyROBlock *) + RO_uint32_a583_testDevice2 AT %MW192: DWORD; + + (*AllTypes/testDevice2/MyROBlock *) + RO_float32_a583_testDevice2 AT %MW196: REAL; + + (*AllTypes/testDevice2/MyROBlock *) + RO_string_a583_testDevice2 AT %MW200: STRING(64); + + (*AllTypes/testDevice2/MyROBlock *) + RO_date_a583_testDevice2 AT %MW268: DT; + + (*AllTypes/testDevice2/MyROBlock *) + RO_char_a583_testDevice2 AT %MW276: SINT; + + (*AllTypes/testDevice2/MyROBlock *) + RO_byte_a583_testDevice2 AT %MW278: BYTE; + + (*AllTypes/testDevice2/MyROBlock *) + RO_word_a583_testDevice2 AT %MW280: WORD; + + (*AllTypes/testDevice2/MyROBlock *) + RO_dword_a583_testDevice2 AT %MW284: DWORD; + + (*AllTypes/testDevice2/MyROBlock *) + RO_int_a583_testDevice2 AT %MW288: INT; + + (*AllTypes/testDevice2/MyROBlock *) + RO_dint_a583_testDevice2 AT %MW292: DINT; + + (*AllTypes/testDevice2/MyROBlock *) + RO_real_a583_testDevice2 AT %MW296: REAL; + + (*AllTypes/testDevice2/MyROBlock *) + RO_dt_a583_testDevice2 AT %MW300: DT; + + (*AllTypes/testDevice1/MyRWBlock *) + RW_int8_a583_testDevice1 AT %MW308: ARRAY [0..1, 0..1] OF SINT; + + (*AllTypes/testDevice1/MyRWBlock *) + RW_uint8_a583_testDevice1 AT %MW312: ARRAY [0..1, 0..1] OF BYTE; + + (*AllTypes/testDevice1/MyRWBlock *) + RW_int16_a583_testDevice1 AT %MW316: ARRAY [0..1, 0..1] OF INT; + + (*AllTypes/testDevice1/MyRWBlock *) + RW_uint16_a583_testDevice1 AT %MW324: ARRAY [0..1, 0..1] OF WORD; + + (*AllTypes/testDevice1/MyRWBlock *) + RW_int32_a583_testDevice1 AT %MW332: ARRAY [0..1, 0..1] OF DINT; + + (*AllTypes/testDevice1/MyRWBlock *) + RW_uint32_a583_testDevice1 AT %MW348: ARRAY [0..1, 0..1] OF DWORD; + + (*AllTypes/testDevice1/MyRWBlock *) + RW_float32_a583_testDevice1 AT %MW364: ARRAY [0..1, 0..1] OF REAL; + + (*AllTypes/testDevice1/MyRWBlock *) + RW_string_a583_testDevice1 AT %MW380: ARRAY [0..1, 0..1] OF STRING(64); + + (*AllTypes/testDevice1/MyRWBlock *) + RW_date_a583_testDevice1 AT %MW640: ARRAY [0..1, 0..1] OF DT; + + (*AllTypes/testDevice1/MyRWBlock *) + RW_char_a583_testDevice1 AT %MW672: ARRAY [0..1, 0..1] OF SINT; + + (*AllTypes/testDevice1/MyRWBlock *) + RW_byte_a583_testDevice1 AT %MW676: ARRAY [0..1, 0..1] OF BYTE; + + (*AllTypes/testDevice1/MyRWBlock *) + RW_word_a583_testDevice1 AT %MW680: ARRAY [0..1, 0..1] OF WORD; + + (*AllTypes/testDevice1/MyRWBlock *) + RW_dword_a583_testDevice1 AT %MW688: ARRAY [0..1, 0..1] OF DWORD; + + (*AllTypes/testDevice1/MyRWBlock *) + RW_int_a583_testDevice1 AT %MW704: ARRAY [0..1, 0..1] OF INT; + + (*AllTypes/testDevice1/MyRWBlock *) + RW_dint_a583_testDevice1 AT %MW712: ARRAY [0..1, 0..1] OF DINT; + + (*AllTypes/testDevice1/MyRWBlock *) + RW_real_a583_testDevice1 AT %MW728: ARRAY [0..1, 0..1] OF REAL; + + (*AllTypes/testDevice1/MyRWBlock *) + RW_dt_a583_testDevice1 AT %MW744: ARRAY [0..1, 0..1] OF DT; + + (*AllTypes/testDevice2/MyRWBlock *) + RW_int8_a583_testDevice2 AT %MW776: ARRAY [0..1, 0..1] OF SINT; + + (*AllTypes/testDevice2/MyRWBlock *) + RW_uint8_a583_testDevice2 AT %MW780: ARRAY [0..1, 0..1] OF BYTE; + + (*AllTypes/testDevice2/MyRWBlock *) + RW_int16_a583_testDevice2 AT %MW784: ARRAY [0..1, 0..1] OF INT; + + (*AllTypes/testDevice2/MyRWBlock *) + RW_uint16_a583_testDevice2 AT %MW792: ARRAY [0..1, 0..1] OF WORD; + + (*AllTypes/testDevice2/MyRWBlock *) + RW_int32_a583_testDevice2 AT %MW800: ARRAY [0..1, 0..1] OF DINT; + + (*AllTypes/testDevice2/MyRWBlock *) + RW_uint32_a583_testDevice2 AT %MW816: ARRAY [0..1, 0..1] OF DWORD; + + (*AllTypes/testDevice2/MyRWBlock *) + RW_float32_a583_testDevice2 AT %MW832: ARRAY [0..1, 0..1] OF REAL; + + (*AllTypes/testDevice2/MyRWBlock *) + RW_string_a583_testDevice2 AT %MW848: ARRAY [0..1, 0..1] OF STRING(64); + + (*AllTypes/testDevice2/MyRWBlock *) + RW_date_a583_testDevice2 AT %MW1108: ARRAY [0..1, 0..1] OF DT; + + (*AllTypes/testDevice2/MyRWBlock *) + RW_char_a583_testDevice2 AT %MW1140: ARRAY [0..1, 0..1] OF SINT; + + (*AllTypes/testDevice2/MyRWBlock *) + RW_byte_a583_testDevice2 AT %MW1144: ARRAY [0..1, 0..1] OF BYTE; + + (*AllTypes/testDevice2/MyRWBlock *) + RW_word_a583_testDevice2 AT %MW1148: ARRAY [0..1, 0..1] OF WORD; + + (*AllTypes/testDevice2/MyRWBlock *) + RW_dword_a583_testDevice2 AT %MW1156: ARRAY [0..1, 0..1] OF DWORD; + + (*AllTypes/testDevice2/MyRWBlock *) + RW_int_a583_testDevice2 AT %MW1172: ARRAY [0..1, 0..1] OF INT; + + (*AllTypes/testDevice2/MyRWBlock *) + RW_dint_a583_testDevice2 AT %MW1180: ARRAY [0..1, 0..1] OF DINT; + + (*AllTypes/testDevice2/MyRWBlock *) + RW_real_a583_testDevice2 AT %MW1196: ARRAY [0..1, 0..1] OF REAL; + + (*AllTypes/testDevice2/MyRWBlock *) + RW_dt_a583_testDevice2 AT %MW1212: ARRAY [0..1, 0..1] OF DT; + + (*AllTypes/testDevice1/MyWOBlock *) + WO_int8_a583_testDevice1 AT %MW1244: ARRAY [0..9] OF SINT; + + (*AllTypes/testDevice1/MyWOBlock *) + WO_uint8_a583_testDevice1 AT %MW1254: ARRAY [0..9] OF BYTE; + + (*AllTypes/testDevice1/MyWOBlock *) + WO_int16_a583_testDevice1 AT %MW1264: ARRAY [0..9] OF INT; + + (*AllTypes/testDevice1/MyWOBlock *) + WO_uint16_a583_testDevice1 AT %MW1284: ARRAY [0..9] OF WORD; + + (*AllTypes/testDevice1/MyWOBlock *) + WO_int32_a583_testDevice1 AT %MW1304: ARRAY [0..9] OF DINT; + + (*AllTypes/testDevice1/MyWOBlock *) + WO_uint32_a583_testDevice1 AT %MW1344: ARRAY [0..9] OF DWORD; + + (*AllTypes/testDevice1/MyWOBlock *) + WO_float32_a583_testDevice1 AT %MW1384: ARRAY [0..9] OF REAL; + + (*AllTypes/testDevice1/MyWOBlock *) + WO_string_a583_testDevice1 AT %MW1424: ARRAY [0..9] OF STRING(64); + + (*AllTypes/testDevice1/MyWOBlock *) + WO_date_a583_testDevice1 AT %MW2076: ARRAY [0..9] OF DT; + + (*AllTypes/testDevice1/MyWOBlock *) + WO_char_a583_testDevice1 AT %MW2156: ARRAY [0..9] OF SINT; + + (*AllTypes/testDevice1/MyWOBlock *) + WO_byte_a583_testDevice1 AT %MW2166: ARRAY [0..9] OF BYTE; + + (*AllTypes/testDevice1/MyWOBlock *) + WO_word_a583_testDevice1 AT %MW2176: ARRAY [0..9] OF WORD; + + (*AllTypes/testDevice1/MyWOBlock *) + WO_dword_a583_testDevice1 AT %MW2196: ARRAY [0..9] OF DWORD; + + (*AllTypes/testDevice1/MyWOBlock *) + WO_int_a583_testDevice1 AT %MW2236: ARRAY [0..9] OF INT; + + (*AllTypes/testDevice1/MyWOBlock *) + WO_dint_a583_testDevice1 AT %MW2256: ARRAY [0..9] OF DINT; + + (*AllTypes/testDevice1/MyWOBlock *) + WO_real_a583_testDevice1 AT %MW2296: ARRAY [0..9] OF REAL; + + (*AllTypes/testDevice1/MyWOBlock *) + WO_dt_a583_testDevice1 AT %MW2336: ARRAY [0..9] OF DT; + + (*AllTypes/testDevice2/MyWOBlock *) + WO_int8_a583_testDevice2 AT %MW2416: ARRAY [0..9] OF SINT; + + (*AllTypes/testDevice2/MyWOBlock *) + WO_uint8_a583_testDevice2 AT %MW2426: ARRAY [0..9] OF BYTE; + + (*AllTypes/testDevice2/MyWOBlock *) + WO_int16_a583_testDevice2 AT %MW2436: ARRAY [0..9] OF INT; + + (*AllTypes/testDevice2/MyWOBlock *) + WO_uint16_a583_testDevice2 AT %MW2456: ARRAY [0..9] OF WORD; + + (*AllTypes/testDevice2/MyWOBlock *) + WO_int32_a583_testDevice2 AT %MW2476: ARRAY [0..9] OF DINT; + + (*AllTypes/testDevice2/MyWOBlock *) + WO_uint32_a583_testDevice2 AT %MW2516: ARRAY [0..9] OF DWORD; + + (*AllTypes/testDevice2/MyWOBlock *) + WO_float32_a583_testDevice2 AT %MW2556: ARRAY [0..9] OF REAL; + + (*AllTypes/testDevice2/MyWOBlock *) + WO_string_a583_testDevice2 AT %MW2596: ARRAY [0..9] OF STRING(64); + + (*AllTypes/testDevice2/MyWOBlock *) + WO_date_a583_testDevice2 AT %MW3248: ARRAY [0..9] OF DT; + + (*AllTypes/testDevice2/MyWOBlock *) + WO_char_a583_testDevice2 AT %MW3328: ARRAY [0..9] OF SINT; + + (*AllTypes/testDevice2/MyWOBlock *) + WO_byte_a583_testDevice2 AT %MW3338: ARRAY [0..9] OF BYTE; + + (*AllTypes/testDevice2/MyWOBlock *) + WO_word_a583_testDevice2 AT %MW3348: ARRAY [0..9] OF WORD; + + (*AllTypes/testDevice2/MyWOBlock *) + WO_dword_a583_testDevice2 AT %MW3368: ARRAY [0..9] OF DWORD; + + (*AllTypes/testDevice2/MyWOBlock *) + WO_int_a583_testDevice2 AT %MW3408: ARRAY [0..9] OF INT; + + (*AllTypes/testDevice2/MyWOBlock *) + WO_dint_a583_testDevice2 AT %MW3428: ARRAY [0..9] OF DINT; + + (*AllTypes/testDevice2/MyWOBlock *) + WO_real_a583_testDevice2 AT %MW3468: ARRAY [0..9] OF REAL; + + (*AllTypes/testDevice2/MyWOBlock *) + WO_dt_a583_testDevice2 AT %MW3508: ARRAY [0..9] OF DT; + +END_VAR \ No newline at end of file diff --git a/silecs-codegen/src/xml/test/generated_temp/controller/Rabbit_BlockMode.h b/silecs-codegen/src/xml/test/generated_temp/controller/Rabbit_BlockMode.h new file mode 100644 index 0000000..f45622a --- /dev/null +++ b/silecs-codegen/src/xml/test/generated_temp/controller/Rabbit_BlockMode.h @@ -0,0 +1,202 @@ + +/* +------------------------------------------------------------------- + * | Copyright CERN 2015 + * | SILECS - BE/CO-SRC + * | April 2015 + * +------------------------------------------------------------------- + * + * Release : SILECS_DEV + * + * The following code has been automatically generated by SILECS. + * + * N.B: This file relies on the existence of explicit C data type such + * as int8_t, uint8_t, int16_t, etc.... + * If your compiler does not support them natively please implement + * them by including the data type definition provided on the SILECS + * web page before including this header file. + */ + +#define MODBUS_START_ADDRESS 0 + +/*--------------------------------------------------------------------- + * DT + * data type definition and related utilities + *--------------------------------------------------------------------- + */ + +typedef struct +{ + uint8_t sc_100; // second cent + uint8_t sc; // second + uint8_t mn; // minute + uint8_t hh; // hour + uint8_t dd; // day + uint8_t mm; // month + uint8_t yy1; // year + uint8_t yy2; // year2 +} dt; + +#define _frombcd(a) (int)(((a>>4)*10)+(a&0x0F)) +#define _tobcd(a) (((unsigned char)((a)/10)<<4)+((a)%10)) + +void SILECS_set_dt(int8_t sc_100 ,int8_t sc, int8_t mn,int8_t hh,int8_t dd,int8_t mm,int32_t yy, dt *date) +{ + date->sc_100 = sc_100; + date->sc = _tobcd(sc); + date->mn = _tobcd(mn); + date->hh = _tobcd(hh); + date->dd = _tobcd(dd); + date->mm = _tobcd(mm); + date->yy2 = _tobcd((int8_t)(yy/100)); + date->yy1 = _tobcd((int8_t)(yy%100)); +} + + +/*--------------------------------------------------------------------- + * SilecsHeader / v1.0.0 + * BLOCK Type definition + *--------------------------------------------------------------------- + */ + +typedef struct +{ + uint8_t _version[16]; + uint32_t _checksum; + uint8_t _user[16]; + dt _date; + +} _SilecsHeader_hdrBlk; + +/*--------------------------------------------------------------------- + * AllTypes / v0.1.0 + * BLOCK Type definition + *--------------------------------------------------------------------- + */ + +typedef struct +{ + int16_t RO_int8; + uint16_t RO_uint8; + int16_t RO_int16; + uint16_t RO_uint16; + int32_t RO_int32; + uint32_t RO_uint32; + float RO_float32; + uint8_t RO_string[64]; + dt RO_date; + int16_t RO_char; + uint16_t RO_byte; + uint16_t RO_word; + uint32_t RO_dword; + int16_t RO_int; + int32_t RO_dint; + float RO_real; + dt RO_dt; + +} _AllTypes_MyROBlock; + +typedef struct +{ + int16_t RW_int8[2][2]; + uint16_t RW_uint8[2][2]; + int16_t RW_int16[2][2]; + uint16_t RW_uint16[2][2]; + int32_t RW_int32[2][2]; + uint32_t RW_uint32[2][2]; + float RW_float32[2][2]; + uint8_t RW_string[2][2][64]; + dt RW_date[2][2]; + int16_t RW_char[2][2]; + uint16_t RW_byte[2][2]; + uint16_t RW_word[2][2]; + uint32_t RW_dword[2][2]; + int16_t RW_int[2][2]; + int32_t RW_dint[2][2]; + float RW_real[2][2]; + dt RW_dt[2][2]; + +} _AllTypes_MyRWBlock; + +typedef struct +{ + int16_t WO_int8[10]; + uint16_t WO_uint8[10]; + int16_t WO_int16[10]; + uint16_t WO_uint16[10]; + int32_t WO_int32[10]; + uint32_t WO_uint32[10]; + float WO_float32[10]; + uint8_t WO_string[10][64]; + dt WO_date[10]; + int16_t WO_char[10]; + uint16_t WO_byte[10]; + uint16_t WO_word[10]; + uint32_t WO_dword[10]; + int16_t WO_int[10]; + int32_t WO_dint[10]; + float WO_real[10]; + dt WO_dt[10]; + +} _AllTypes_MyWOBlock; + +/*--------------------------------------------------------------------- + * MEMORY ALLOCATION + * PROTOCOL: BLOCK_MODE + *--------------------------------------------------------------------- + */ + +typedef struct { + + struct { + _SilecsHeader_hdrBlk SilecsHeader; + } SilecsHeader_hdrBlk; + + struct { + _AllTypes_MyROBlock testDevice1; + _AllTypes_MyROBlock testDevice2; + } AllTypes_MyROBlock; + + struct { + _AllTypes_MyRWBlock testDevice1; + _AllTypes_MyRWBlock testDevice2; + } AllTypes_MyRWBlock; + + struct { + _AllTypes_MyWOBlock testDevice1; + _AllTypes_MyWOBlock testDevice2; + } AllTypes_MyWOBlock; + +} _SILECS_DATA_SEGMENT; + +#define SILECS_DATA_SEGMENT_MODBUS_SIZE (sizeof(_SILECS_DATA_SEGMENT)/2) + +union modbus_data { + _SILECS_DATA_SEGMENT data; + uint16_t array[SILECS_DATA_SEGMENT_MODBUS_SIZE]; +} silecsData; + + +/* Initialization function */ +int SILECS_init() +{ + /* Silecs version initialization */ + strcpy((unsigned char *)silecsData.data.SilecsHeader_hdrBlk.device[0]._version, "SILECS_DEV"); + + /* Silecs checksum initialization */ + silecsData.data.SilecsHeader_hdrBlk.device[0]._checksum = 3940683809; + + /* Silecs user initialization */ + strcpy((unsigned char *)silecsData.data.SilecsHeader_hdrBlk.device[0]._user, "schwinn"); + + /* Silecs date initialization */ + SILECS_set_dt(1,54,37,15,26,7,2016,&silecsData.data.SilecsHeader_hdrBlk.device[0]._date); +} + +/* + * Automatically generated Addressing example + * + * This example shows how to address the register WO_dt of block MyWOBlock + * of device testDevice2 of the class AllTypes + * + * silecsData.AllTypes_MyWOBlock.testDevice2.WO_dt = ....; + */ \ No newline at end of file diff --git a/silecs-codegen/src/xml/test/generated_temp/controller/Rabbit_DeviceMode.h b/silecs-codegen/src/xml/test/generated_temp/controller/Rabbit_DeviceMode.h new file mode 100644 index 0000000..01e46be --- /dev/null +++ b/silecs-codegen/src/xml/test/generated_temp/controller/Rabbit_DeviceMode.h @@ -0,0 +1,195 @@ + +/* +------------------------------------------------------------------- + * | Copyright CERN 2015 + * | SILECS - BE/CO-SRC + * | April 2015 + * +------------------------------------------------------------------- + * + * Release : SILECS_DEV + * + * The following code has been automatically generated by SILECS. + * + * N.B: This file relies on the existence of explicit C data type such + * as int8_t, uint8_t, int16_t, etc.... + * If your compiler does not support them natively please implement + * them by including the data type definition provided on the SILECS + * web page before including this header file. + */ + +#define MODBUS_START_ADDRESS 0 + +/*--------------------------------------------------------------------- + * DT + * data type definition and related utilities + *--------------------------------------------------------------------- + */ + +typedef struct +{ + uint8_t sc_100; // second cent + uint8_t sc; // second + uint8_t mn; // minute + uint8_t hh; // hour + uint8_t dd; // day + uint8_t mm; // month + uint8_t yy1; // year + uint8_t yy2; // year2 +} dt; + +#define _frombcd(a) (int)(((a>>4)*10)+(a&0x0F)) +#define _tobcd(a) (((unsigned char)((a)/10)<<4)+((a)%10)) + +void SILECS_set_dt(int8_t sc_100 ,int8_t sc, int8_t mn,int8_t hh,int8_t dd,int8_t mm,int32_t yy, dt *date) +{ + date->sc_100 = sc_100; + date->sc = _tobcd(sc); + date->mn = _tobcd(mn); + date->hh = _tobcd(hh); + date->dd = _tobcd(dd); + date->mm = _tobcd(mm); + date->yy2 = _tobcd((int8_t)(yy/100)); + date->yy1 = _tobcd((int8_t)(yy%100)); +} + + +/*--------------------------------------------------------------------- + * SilecsHeader / v1.0.0 + * BLOCK Type definition + *--------------------------------------------------------------------- + */ + +typedef struct +{ + uint8_t _version[16]; + uint32_t _checksum; + uint8_t _user[16]; + dt _date; + +} _SilecsHeader_hdrBlk; + +/*--------------------------------------------------------------------- + * AllTypes / v0.1.0 + * BLOCK Type definition + *--------------------------------------------------------------------- + */ + +typedef struct +{ + int16_t RO_int8; + uint16_t RO_uint8; + int16_t RO_int16; + uint16_t RO_uint16; + int32_t RO_int32; + uint32_t RO_uint32; + float RO_float32; + uint8_t RO_string[64]; + dt RO_date; + int16_t RO_char; + uint16_t RO_byte; + uint16_t RO_word; + uint32_t RO_dword; + int16_t RO_int; + int32_t RO_dint; + float RO_real; + dt RO_dt; + +} _AllTypes_MyROBlock; + +typedef struct +{ + int16_t RW_int8[2][2]; + uint16_t RW_uint8[2][2]; + int16_t RW_int16[2][2]; + uint16_t RW_uint16[2][2]; + int32_t RW_int32[2][2]; + uint32_t RW_uint32[2][2]; + float RW_float32[2][2]; + uint8_t RW_string[2][2][64]; + dt RW_date[2][2]; + int16_t RW_char[2][2]; + uint16_t RW_byte[2][2]; + uint16_t RW_word[2][2]; + uint32_t RW_dword[2][2]; + int16_t RW_int[2][2]; + int32_t RW_dint[2][2]; + float RW_real[2][2]; + dt RW_dt[2][2]; + +} _AllTypes_MyRWBlock; + +typedef struct +{ + int16_t WO_int8[10]; + uint16_t WO_uint8[10]; + int16_t WO_int16[10]; + uint16_t WO_uint16[10]; + int32_t WO_int32[10]; + uint32_t WO_uint32[10]; + float WO_float32[10]; + uint8_t WO_string[10][64]; + dt WO_date[10]; + int16_t WO_char[10]; + uint16_t WO_byte[10]; + uint16_t WO_word[10]; + uint32_t WO_dword[10]; + int16_t WO_int[10]; + int32_t WO_dint[10]; + float WO_real[10]; + dt WO_dt[10]; + +} _AllTypes_MyWOBlock; + +/*--------------------------------------------------------------------- + * MEMORY ALLOCATION + * PROTOCOL: DEVICE_MODE + *--------------------------------------------------------------------- + */ + +typedef struct { + + struct { + _SilecsHeader_hdrBlk hdrBlk; + + } SilecsHeader_SilecsHeader; + + struct { + _AllTypes_MyROBlock MyROBlock; + _AllTypes_MyRWBlock MyRWBlock; + _AllTypes_MyWOBlock MyWOBlock; + + } AllTypes_testDevice1, AllTypes_testDevice2; + +} _SILECS_DATA_SEGMENT; + +#define SILECS_DATA_SEGMENT_MODBUS_SIZE (sizeof(_SILECS_DATA_SEGMENT)/2) + +union silecsData { + _SILECS_DATA_SEGMENT data; + uint16_t array[SILECS_DATA_SEGMENT_MODBUS_SIZE]; +} silecsData; + + +/* Initialization function */ +int SILECS_init() +{ + /* Silecs version initialization */ + strcpy((unsigned char *)silecsData.data.SilecsHeader_device[0].hdrBlk._version, "SILECS_DEV"); + + /* Silecs checksum initialization */ + silecsData.data.SilecsHeader_device[0].hdrBlk._checksum = 3940683809; + + /* Silecs user initialization */ + strcpy((unsigned char *)silecsData.data.SilecsHeader_device[0].hdrBlk._user, "schwinn"); + + /* Silecs date initialization */ + SILECS_set_dt(1,54,37,15,26,7,2016,&silecsData.data.SilecsHeader_device[0].hdrBlk._date); +} + +/* + * Automatically generated Addressing example + * + * This example shows how to address the register WO_dt of block MyWOBlock + * of device AllTypes_testDevice2 of the class AllTypes + * + * silecsData.AllTypes_AllTypes_testDevice2.MyWOBlock.WO_dt = ....; + */ \ No newline at end of file diff --git a/silecs-codegen/src/xml/test/generated_temp/controller/Schneider_M340.xsy b/silecs-codegen/src/xml/test/generated_temp/controller/Schneider_M340.xsy new file mode 100644 index 0000000..8bfb3e8 --- /dev/null +++ b/silecs-codegen/src/xml/test/generated_temp/controller/Schneider_M340.xsy @@ -0,0 +1,326 @@ +<VariablesExchangeFile> + <dataBlock> + <variables name="_version_a781_SilecsHeader" typeName="STRING[16]" topologicalAddress="%MW0"> + <variableInit value="DEV"/> + <comment>SilecsHeader/SilecsHeader/hdrBlk</comment> + </variables> + <variables name="_checksum_a781_SilecsHeader" typeName="DWORD" topologicalAddress="%MW8"> + <variableInit value="3940683809"/> + <comment>SilecsHeader/SilecsHeader/hdrBlk</comment> + </variables> + <variables name="_user_a781_SilecsHeader" typeName="STRING[16]" topologicalAddress="%MW10"> + <variableInit value="schwinn"/> + <comment>SilecsHeader/SilecsHeader/hdrBlk</comment> + </variables> + <variables name="_date_a781_SilecsHeader" typeName="DT" topologicalAddress="%MW18"> + <variableInit value="DT#2016-7-26-15:37:54"/> + <comment>SilecsHeader/SilecsHeader/hdrBlk</comment> + </variables> + <variables name="RO_int8_a583_testDevice1" typeName="WORD" topologicalAddress="%MW22"> + <comment>AllTypes/testDevice1/MyROBlock</comment> + </variables> + <variables name="RO_uint8_a583_testDevice1" typeName="BYTE" topologicalAddress="%MW23"> + <comment>AllTypes/testDevice1/MyROBlock</comment> + </variables> + <variables name="RO_int16_a583_testDevice1" typeName="INT" topologicalAddress="%MW24"> + <comment>AllTypes/testDevice1/MyROBlock</comment> + </variables> + <variables name="RO_uint16_a583_testDevice1" typeName="WORD" topologicalAddress="%MW25"> + <comment>AllTypes/testDevice1/MyROBlock</comment> + </variables> + <variables name="RO_int32_a583_testDevice1" typeName="DINT" topologicalAddress="%MW26"> + <comment>AllTypes/testDevice1/MyROBlock</comment> + </variables> + <variables name="RO_uint32_a583_testDevice1" typeName="DWORD" topologicalAddress="%MW28"> + <comment>AllTypes/testDevice1/MyROBlock</comment> + </variables> + <variables name="RO_float32_a583_testDevice1" typeName="REAL" topologicalAddress="%MW30"> + <comment>AllTypes/testDevice1/MyROBlock</comment> + </variables> + <variables name="RO_string_a583_testDevice1" typeName="STRING[64]" topologicalAddress="%MW32"> + <comment>AllTypes/testDevice1/MyROBlock</comment> + </variables> + <variables name="RO_date_a583_testDevice1" typeName="DT" topologicalAddress="%MW64"> + <comment>AllTypes/testDevice1/MyROBlock</comment> + </variables> + <variables name="RO_char_a583_testDevice1" typeName="WORD" topologicalAddress="%MW68"> + <comment>AllTypes/testDevice1/MyROBlock</comment> + </variables> + <variables name="RO_byte_a583_testDevice1" typeName="BYTE" topologicalAddress="%MW69"> + <comment>AllTypes/testDevice1/MyROBlock</comment> + </variables> + <variables name="RO_word_a583_testDevice1" typeName="WORD" topologicalAddress="%MW70"> + <comment>AllTypes/testDevice1/MyROBlock</comment> + </variables> + <variables name="RO_dword_a583_testDevice1" typeName="DWORD" topologicalAddress="%MW72"> + <comment>AllTypes/testDevice1/MyROBlock</comment> + </variables> + <variables name="RO_int_a583_testDevice1" typeName="INT" topologicalAddress="%MW74"> + <comment>AllTypes/testDevice1/MyROBlock</comment> + </variables> + <variables name="RO_dint_a583_testDevice1" typeName="DINT" topologicalAddress="%MW76"> + <comment>AllTypes/testDevice1/MyROBlock</comment> + </variables> + <variables name="RO_real_a583_testDevice1" typeName="REAL" topologicalAddress="%MW78"> + <comment>AllTypes/testDevice1/MyROBlock</comment> + </variables> + <variables name="RO_dt_a583_testDevice1" typeName="DT" topologicalAddress="%MW80"> + <comment>AllTypes/testDevice1/MyROBlock</comment> + </variables> + <variables name="RO_int8_a583_testDevice2" typeName="WORD" topologicalAddress="%MW84"> + <comment>AllTypes/testDevice2/MyROBlock</comment> + </variables> + <variables name="RO_uint8_a583_testDevice2" typeName="BYTE" topologicalAddress="%MW85"> + <comment>AllTypes/testDevice2/MyROBlock</comment> + </variables> + <variables name="RO_int16_a583_testDevice2" typeName="INT" topologicalAddress="%MW86"> + <comment>AllTypes/testDevice2/MyROBlock</comment> + </variables> + <variables name="RO_uint16_a583_testDevice2" typeName="WORD" topologicalAddress="%MW87"> + <comment>AllTypes/testDevice2/MyROBlock</comment> + </variables> + <variables name="RO_int32_a583_testDevice2" typeName="DINT" topologicalAddress="%MW88"> + <comment>AllTypes/testDevice2/MyROBlock</comment> + </variables> + <variables name="RO_uint32_a583_testDevice2" typeName="DWORD" topologicalAddress="%MW90"> + <comment>AllTypes/testDevice2/MyROBlock</comment> + </variables> + <variables name="RO_float32_a583_testDevice2" typeName="REAL" topologicalAddress="%MW92"> + <comment>AllTypes/testDevice2/MyROBlock</comment> + </variables> + <variables name="RO_string_a583_testDevice2" typeName="STRING[64]" topologicalAddress="%MW94"> + <comment>AllTypes/testDevice2/MyROBlock</comment> + </variables> + <variables name="RO_date_a583_testDevice2" typeName="DT" topologicalAddress="%MW126"> + <comment>AllTypes/testDevice2/MyROBlock</comment> + </variables> + <variables name="RO_char_a583_testDevice2" typeName="WORD" topologicalAddress="%MW130"> + <comment>AllTypes/testDevice2/MyROBlock</comment> + </variables> + <variables name="RO_byte_a583_testDevice2" typeName="BYTE" topologicalAddress="%MW131"> + <comment>AllTypes/testDevice2/MyROBlock</comment> + </variables> + <variables name="RO_word_a583_testDevice2" typeName="WORD" topologicalAddress="%MW132"> + <comment>AllTypes/testDevice2/MyROBlock</comment> + </variables> + <variables name="RO_dword_a583_testDevice2" typeName="DWORD" topologicalAddress="%MW134"> + <comment>AllTypes/testDevice2/MyROBlock</comment> + </variables> + <variables name="RO_int_a583_testDevice2" typeName="INT" topologicalAddress="%MW136"> + <comment>AllTypes/testDevice2/MyROBlock</comment> + </variables> + <variables name="RO_dint_a583_testDevice2" typeName="DINT" topologicalAddress="%MW138"> + <comment>AllTypes/testDevice2/MyROBlock</comment> + </variables> + <variables name="RO_real_a583_testDevice2" typeName="REAL" topologicalAddress="%MW140"> + <comment>AllTypes/testDevice2/MyROBlock</comment> + </variables> + <variables name="RO_dt_a583_testDevice2" typeName="DT" topologicalAddress="%MW142"> + <comment>AllTypes/testDevice2/MyROBlock</comment> + </variables> + <variables name="RW_int8_a583_testDevice1" typeName="ARRAY[0..1, 0..1] OF WORD" topologicalAddress="%MW146"> + <comment>AllTypes/testDevice1/MyRWBlock</comment> + </variables> + <variables name="RW_uint8_a583_testDevice1" typeName="ARRAY[0..1, 0..1] OF BYTE" topologicalAddress="%MW150"> + <comment>AllTypes/testDevice1/MyRWBlock</comment> + </variables> + <variables name="RW_int16_a583_testDevice1" typeName="ARRAY[0..1, 0..1] OF INT" topologicalAddress="%MW152"> + <comment>AllTypes/testDevice1/MyRWBlock</comment> + </variables> + <variables name="RW_uint16_a583_testDevice1" typeName="ARRAY[0..1, 0..1] OF WORD" topologicalAddress="%MW156"> + <comment>AllTypes/testDevice1/MyRWBlock</comment> + </variables> + <variables name="RW_int32_a583_testDevice1" typeName="ARRAY[0..1, 0..1] OF DINT" topologicalAddress="%MW160"> + <comment>AllTypes/testDevice1/MyRWBlock</comment> + </variables> + <variables name="RW_uint32_a583_testDevice1" typeName="ARRAY[0..1, 0..1] OF DWORD" topologicalAddress="%MW168"> + <comment>AllTypes/testDevice1/MyRWBlock</comment> + </variables> + <variables name="RW_float32_a583_testDevice1" typeName="ARRAY[0..1, 0..1] OF REAL" topologicalAddress="%MW176"> + <comment>AllTypes/testDevice1/MyRWBlock</comment> + </variables> + <variables name="RW_string_a583_testDevice1" typeName="ARRAY[0..1, 0..1] OF STRING[64]" topologicalAddress="%MW184"> + <comment>AllTypes/testDevice1/MyRWBlock</comment> + </variables> + <variables name="RW_date_a583_testDevice1" typeName="ARRAY[0..1, 0..1] OF DT" topologicalAddress="%MW312"> + <comment>AllTypes/testDevice1/MyRWBlock</comment> + </variables> + <variables name="RW_char_a583_testDevice1" typeName="ARRAY[0..1, 0..1] OF WORD" topologicalAddress="%MW328"> + <comment>AllTypes/testDevice1/MyRWBlock</comment> + </variables> + <variables name="RW_byte_a583_testDevice1" typeName="ARRAY[0..1, 0..1] OF BYTE" topologicalAddress="%MW332"> + <comment>AllTypes/testDevice1/MyRWBlock</comment> + </variables> + <variables name="RW_word_a583_testDevice1" typeName="ARRAY[0..1, 0..1] OF WORD" topologicalAddress="%MW334"> + <comment>AllTypes/testDevice1/MyRWBlock</comment> + </variables> + <variables name="RW_dword_a583_testDevice1" typeName="ARRAY[0..1, 0..1] OF DWORD" topologicalAddress="%MW338"> + <comment>AllTypes/testDevice1/MyRWBlock</comment> + </variables> + <variables name="RW_int_a583_testDevice1" typeName="ARRAY[0..1, 0..1] OF INT" topologicalAddress="%MW346"> + <comment>AllTypes/testDevice1/MyRWBlock</comment> + </variables> + <variables name="RW_dint_a583_testDevice1" typeName="ARRAY[0..1, 0..1] OF DINT" topologicalAddress="%MW350"> + <comment>AllTypes/testDevice1/MyRWBlock</comment> + </variables> + <variables name="RW_real_a583_testDevice1" typeName="ARRAY[0..1, 0..1] OF REAL" topologicalAddress="%MW358"> + <comment>AllTypes/testDevice1/MyRWBlock</comment> + </variables> + <variables name="RW_dt_a583_testDevice1" typeName="ARRAY[0..1, 0..1] OF DT" topologicalAddress="%MW366"> + <comment>AllTypes/testDevice1/MyRWBlock</comment> + </variables> + <variables name="RW_int8_a583_testDevice2" typeName="ARRAY[0..1, 0..1] OF WORD" topologicalAddress="%MW382"> + <comment>AllTypes/testDevice2/MyRWBlock</comment> + </variables> + <variables name="RW_uint8_a583_testDevice2" typeName="ARRAY[0..1, 0..1] OF BYTE" topologicalAddress="%MW386"> + <comment>AllTypes/testDevice2/MyRWBlock</comment> + </variables> + <variables name="RW_int16_a583_testDevice2" typeName="ARRAY[0..1, 0..1] OF INT" topologicalAddress="%MW388"> + <comment>AllTypes/testDevice2/MyRWBlock</comment> + </variables> + <variables name="RW_uint16_a583_testDevice2" typeName="ARRAY[0..1, 0..1] OF WORD" topologicalAddress="%MW392"> + <comment>AllTypes/testDevice2/MyRWBlock</comment> + </variables> + <variables name="RW_int32_a583_testDevice2" typeName="ARRAY[0..1, 0..1] OF DINT" topologicalAddress="%MW396"> + <comment>AllTypes/testDevice2/MyRWBlock</comment> + </variables> + <variables name="RW_uint32_a583_testDevice2" typeName="ARRAY[0..1, 0..1] OF DWORD" topologicalAddress="%MW404"> + <comment>AllTypes/testDevice2/MyRWBlock</comment> + </variables> + <variables name="RW_float32_a583_testDevice2" typeName="ARRAY[0..1, 0..1] OF REAL" topologicalAddress="%MW412"> + <comment>AllTypes/testDevice2/MyRWBlock</comment> + </variables> + <variables name="RW_string_a583_testDevice2" typeName="ARRAY[0..1, 0..1] OF STRING[64]" topologicalAddress="%MW420"> + <comment>AllTypes/testDevice2/MyRWBlock</comment> + </variables> + <variables name="RW_date_a583_testDevice2" typeName="ARRAY[0..1, 0..1] OF DT" topologicalAddress="%MW548"> + <comment>AllTypes/testDevice2/MyRWBlock</comment> + </variables> + <variables name="RW_char_a583_testDevice2" typeName="ARRAY[0..1, 0..1] OF WORD" topologicalAddress="%MW564"> + <comment>AllTypes/testDevice2/MyRWBlock</comment> + </variables> + <variables name="RW_byte_a583_testDevice2" typeName="ARRAY[0..1, 0..1] OF BYTE" topologicalAddress="%MW568"> + <comment>AllTypes/testDevice2/MyRWBlock</comment> + </variables> + <variables name="RW_word_a583_testDevice2" typeName="ARRAY[0..1, 0..1] OF WORD" topologicalAddress="%MW570"> + <comment>AllTypes/testDevice2/MyRWBlock</comment> + </variables> + <variables name="RW_dword_a583_testDevice2" typeName="ARRAY[0..1, 0..1] OF DWORD" topologicalAddress="%MW574"> + <comment>AllTypes/testDevice2/MyRWBlock</comment> + </variables> + <variables name="RW_int_a583_testDevice2" typeName="ARRAY[0..1, 0..1] OF INT" topologicalAddress="%MW582"> + <comment>AllTypes/testDevice2/MyRWBlock</comment> + </variables> + <variables name="RW_dint_a583_testDevice2" typeName="ARRAY[0..1, 0..1] OF DINT" topologicalAddress="%MW586"> + <comment>AllTypes/testDevice2/MyRWBlock</comment> + </variables> + <variables name="RW_real_a583_testDevice2" typeName="ARRAY[0..1, 0..1] OF REAL" topologicalAddress="%MW594"> + <comment>AllTypes/testDevice2/MyRWBlock</comment> + </variables> + <variables name="RW_dt_a583_testDevice2" typeName="ARRAY[0..1, 0..1] OF DT" topologicalAddress="%MW602"> + <comment>AllTypes/testDevice2/MyRWBlock</comment> + </variables> + <variables name="WO_int8_a583_testDevice1" typeName="ARRAY[0..9] OF WORD" topologicalAddress="%MW618"> + <comment>AllTypes/testDevice1/MyWOBlock</comment> + </variables> + <variables name="WO_uint8_a583_testDevice1" typeName="ARRAY[0..9] OF BYTE" topologicalAddress="%MW628"> + <comment>AllTypes/testDevice1/MyWOBlock</comment> + </variables> + <variables name="WO_int16_a583_testDevice1" typeName="ARRAY[0..9] OF INT" topologicalAddress="%MW633"> + <comment>AllTypes/testDevice1/MyWOBlock</comment> + </variables> + <variables name="WO_uint16_a583_testDevice1" typeName="ARRAY[0..9] OF WORD" topologicalAddress="%MW643"> + <comment>AllTypes/testDevice1/MyWOBlock</comment> + </variables> + <variables name="WO_int32_a583_testDevice1" typeName="ARRAY[0..9] OF DINT" topologicalAddress="%MW654"> + <comment>AllTypes/testDevice1/MyWOBlock</comment> + </variables> + <variables name="WO_uint32_a583_testDevice1" typeName="ARRAY[0..9] OF DWORD" topologicalAddress="%MW674"> + <comment>AllTypes/testDevice1/MyWOBlock</comment> + </variables> + <variables name="WO_float32_a583_testDevice1" typeName="ARRAY[0..9] OF REAL" topologicalAddress="%MW694"> + <comment>AllTypes/testDevice1/MyWOBlock</comment> + </variables> + <variables name="WO_string_a583_testDevice1" typeName="ARRAY[0..9] OF STRING[64]" topologicalAddress="%MW714"> + <comment>AllTypes/testDevice1/MyWOBlock</comment> + </variables> + <variables name="WO_date_a583_testDevice1" typeName="ARRAY[0..9] OF DT" topologicalAddress="%MW1034"> + <comment>AllTypes/testDevice1/MyWOBlock</comment> + </variables> + <variables name="WO_char_a583_testDevice1" typeName="ARRAY[0..9] OF WORD" topologicalAddress="%MW1074"> + <comment>AllTypes/testDevice1/MyWOBlock</comment> + </variables> + <variables name="WO_byte_a583_testDevice1" typeName="ARRAY[0..9] OF BYTE" topologicalAddress="%MW1084"> + <comment>AllTypes/testDevice1/MyWOBlock</comment> + </variables> + <variables name="WO_word_a583_testDevice1" typeName="ARRAY[0..9] OF WORD" topologicalAddress="%MW1089"> + <comment>AllTypes/testDevice1/MyWOBlock</comment> + </variables> + <variables name="WO_dword_a583_testDevice1" typeName="ARRAY[0..9] OF DWORD" topologicalAddress="%MW1100"> + <comment>AllTypes/testDevice1/MyWOBlock</comment> + </variables> + <variables name="WO_int_a583_testDevice1" typeName="ARRAY[0..9] OF INT" topologicalAddress="%MW1120"> + <comment>AllTypes/testDevice1/MyWOBlock</comment> + </variables> + <variables name="WO_dint_a583_testDevice1" typeName="ARRAY[0..9] OF DINT" topologicalAddress="%MW1130"> + <comment>AllTypes/testDevice1/MyWOBlock</comment> + </variables> + <variables name="WO_real_a583_testDevice1" typeName="ARRAY[0..9] OF REAL" topologicalAddress="%MW1150"> + <comment>AllTypes/testDevice1/MyWOBlock</comment> + </variables> + <variables name="WO_dt_a583_testDevice1" typeName="ARRAY[0..9] OF DT" topologicalAddress="%MW1170"> + <comment>AllTypes/testDevice1/MyWOBlock</comment> + </variables> + <variables name="WO_int8_a583_testDevice2" typeName="ARRAY[0..9] OF WORD" topologicalAddress="%MW1210"> + <comment>AllTypes/testDevice2/MyWOBlock</comment> + </variables> + <variables name="WO_uint8_a583_testDevice2" typeName="ARRAY[0..9] OF BYTE" topologicalAddress="%MW1220"> + <comment>AllTypes/testDevice2/MyWOBlock</comment> + </variables> + <variables name="WO_int16_a583_testDevice2" typeName="ARRAY[0..9] OF INT" topologicalAddress="%MW1225"> + <comment>AllTypes/testDevice2/MyWOBlock</comment> + </variables> + <variables name="WO_uint16_a583_testDevice2" typeName="ARRAY[0..9] OF WORD" topologicalAddress="%MW1235"> + <comment>AllTypes/testDevice2/MyWOBlock</comment> + </variables> + <variables name="WO_int32_a583_testDevice2" typeName="ARRAY[0..9] OF DINT" topologicalAddress="%MW1246"> + <comment>AllTypes/testDevice2/MyWOBlock</comment> + </variables> + <variables name="WO_uint32_a583_testDevice2" typeName="ARRAY[0..9] OF DWORD" topologicalAddress="%MW1266"> + <comment>AllTypes/testDevice2/MyWOBlock</comment> + </variables> + <variables name="WO_float32_a583_testDevice2" typeName="ARRAY[0..9] OF REAL" topologicalAddress="%MW1286"> + <comment>AllTypes/testDevice2/MyWOBlock</comment> + </variables> + <variables name="WO_string_a583_testDevice2" typeName="ARRAY[0..9] OF STRING[64]" topologicalAddress="%MW1306"> + <comment>AllTypes/testDevice2/MyWOBlock</comment> + </variables> + <variables name="WO_date_a583_testDevice2" typeName="ARRAY[0..9] OF DT" topologicalAddress="%MW1626"> + <comment>AllTypes/testDevice2/MyWOBlock</comment> + </variables> + <variables name="WO_char_a583_testDevice2" typeName="ARRAY[0..9] OF WORD" topologicalAddress="%MW1666"> + <comment>AllTypes/testDevice2/MyWOBlock</comment> + </variables> + <variables name="WO_byte_a583_testDevice2" typeName="ARRAY[0..9] OF BYTE" topologicalAddress="%MW1676"> + <comment>AllTypes/testDevice2/MyWOBlock</comment> + </variables> + <variables name="WO_word_a583_testDevice2" typeName="ARRAY[0..9] OF WORD" topologicalAddress="%MW1681"> + <comment>AllTypes/testDevice2/MyWOBlock</comment> + </variables> + <variables name="WO_dword_a583_testDevice2" typeName="ARRAY[0..9] OF DWORD" topologicalAddress="%MW1692"> + <comment>AllTypes/testDevice2/MyWOBlock</comment> + </variables> + <variables name="WO_int_a583_testDevice2" typeName="ARRAY[0..9] OF INT" topologicalAddress="%MW1712"> + <comment>AllTypes/testDevice2/MyWOBlock</comment> + </variables> + <variables name="WO_dint_a583_testDevice2" typeName="ARRAY[0..9] OF DINT" topologicalAddress="%MW1722"> + <comment>AllTypes/testDevice2/MyWOBlock</comment> + </variables> + <variables name="WO_real_a583_testDevice2" typeName="ARRAY[0..9] OF REAL" topologicalAddress="%MW1742"> + <comment>AllTypes/testDevice2/MyWOBlock</comment> + </variables> + <variables name="WO_dt_a583_testDevice2" typeName="ARRAY[0..9] OF DT" topologicalAddress="%MW1762"> + <comment>AllTypes/testDevice2/MyWOBlock</comment> + </variables> + </dataBlock> +</VariablesExchangeFile> \ No newline at end of file diff --git a/silecs-codegen/src/xml/test/generated_temp/controller/Schneider_PremiumQuantum.xsy b/silecs-codegen/src/xml/test/generated_temp/controller/Schneider_PremiumQuantum.xsy new file mode 100644 index 0000000..fa28512 --- /dev/null +++ b/silecs-codegen/src/xml/test/generated_temp/controller/Schneider_PremiumQuantum.xsy @@ -0,0 +1,326 @@ +<VariablesExchangeFile> + <dataBlock> + <variables name="_version_a781_SilecsHeader" typeName="STRING[16]" topologicalAddress="%MW0"> + <variableInit value="DEV"/> + <comment>SilecsHeader/SilecsHeader/hdrBlk</comment> + </variables> + <variables name="_checksum_a781_SilecsHeader" typeName="DWORD" topologicalAddress="%MW8"> + <variableInit value="3940683809"/> + <comment>SilecsHeader/SilecsHeader/hdrBlk</comment> + </variables> + <variables name="_user_a781_SilecsHeader" typeName="STRING[16]" topologicalAddress="%MW10"> + <variableInit value="schwinn"/> + <comment>SilecsHeader/SilecsHeader/hdrBlk</comment> + </variables> + <variables name="_date_a781_SilecsHeader" typeName="DT" topologicalAddress="%MW18"> + <variableInit value="DT#2016-7-26-15:37:54"/> + <comment>SilecsHeader/SilecsHeader/hdrBlk</comment> + </variables> + <variables name="RO_int8_a583_testDevice1" typeName="WORD" topologicalAddress="%MW22"> + <comment>AllTypes/testDevice1/MyROBlock</comment> + </variables> + <variables name="RO_uint8_a583_testDevice1" typeName="BYTE" topologicalAddress="%MW23"> + <comment>AllTypes/testDevice1/MyROBlock</comment> + </variables> + <variables name="RO_int16_a583_testDevice1" typeName="INT" topologicalAddress="%MW24"> + <comment>AllTypes/testDevice1/MyROBlock</comment> + </variables> + <variables name="RO_uint16_a583_testDevice1" typeName="WORD" topologicalAddress="%MW25"> + <comment>AllTypes/testDevice1/MyROBlock</comment> + </variables> + <variables name="RO_int32_a583_testDevice1" typeName="DINT" topologicalAddress="%MW26"> + <comment>AllTypes/testDevice1/MyROBlock</comment> + </variables> + <variables name="RO_uint32_a583_testDevice1" typeName="DWORD" topologicalAddress="%MW28"> + <comment>AllTypes/testDevice1/MyROBlock</comment> + </variables> + <variables name="RO_float32_a583_testDevice1" typeName="REAL" topologicalAddress="%MW30"> + <comment>AllTypes/testDevice1/MyROBlock</comment> + </variables> + <variables name="RO_string_a583_testDevice1" typeName="STRING[64]" topologicalAddress="%MW32"> + <comment>AllTypes/testDevice1/MyROBlock</comment> + </variables> + <variables name="RO_date_a583_testDevice1" typeName="DT" topologicalAddress="%MW64"> + <comment>AllTypes/testDevice1/MyROBlock</comment> + </variables> + <variables name="RO_char_a583_testDevice1" typeName="WORD" topologicalAddress="%MW68"> + <comment>AllTypes/testDevice1/MyROBlock</comment> + </variables> + <variables name="RO_byte_a583_testDevice1" typeName="BYTE" topologicalAddress="%MW69"> + <comment>AllTypes/testDevice1/MyROBlock</comment> + </variables> + <variables name="RO_word_a583_testDevice1" typeName="WORD" topologicalAddress="%MW70"> + <comment>AllTypes/testDevice1/MyROBlock</comment> + </variables> + <variables name="RO_dword_a583_testDevice1" typeName="DWORD" topologicalAddress="%MW71"> + <comment>AllTypes/testDevice1/MyROBlock</comment> + </variables> + <variables name="RO_int_a583_testDevice1" typeName="INT" topologicalAddress="%MW73"> + <comment>AllTypes/testDevice1/MyROBlock</comment> + </variables> + <variables name="RO_dint_a583_testDevice1" typeName="DINT" topologicalAddress="%MW74"> + <comment>AllTypes/testDevice1/MyROBlock</comment> + </variables> + <variables name="RO_real_a583_testDevice1" typeName="REAL" topologicalAddress="%MW76"> + <comment>AllTypes/testDevice1/MyROBlock</comment> + </variables> + <variables name="RO_dt_a583_testDevice1" typeName="DT" topologicalAddress="%MW78"> + <comment>AllTypes/testDevice1/MyROBlock</comment> + </variables> + <variables name="RO_int8_a583_testDevice2" typeName="WORD" topologicalAddress="%MW82"> + <comment>AllTypes/testDevice2/MyROBlock</comment> + </variables> + <variables name="RO_uint8_a583_testDevice2" typeName="BYTE" topologicalAddress="%MW83"> + <comment>AllTypes/testDevice2/MyROBlock</comment> + </variables> + <variables name="RO_int16_a583_testDevice2" typeName="INT" topologicalAddress="%MW84"> + <comment>AllTypes/testDevice2/MyROBlock</comment> + </variables> + <variables name="RO_uint16_a583_testDevice2" typeName="WORD" topologicalAddress="%MW85"> + <comment>AllTypes/testDevice2/MyROBlock</comment> + </variables> + <variables name="RO_int32_a583_testDevice2" typeName="DINT" topologicalAddress="%MW86"> + <comment>AllTypes/testDevice2/MyROBlock</comment> + </variables> + <variables name="RO_uint32_a583_testDevice2" typeName="DWORD" topologicalAddress="%MW88"> + <comment>AllTypes/testDevice2/MyROBlock</comment> + </variables> + <variables name="RO_float32_a583_testDevice2" typeName="REAL" topologicalAddress="%MW90"> + <comment>AllTypes/testDevice2/MyROBlock</comment> + </variables> + <variables name="RO_string_a583_testDevice2" typeName="STRING[64]" topologicalAddress="%MW92"> + <comment>AllTypes/testDevice2/MyROBlock</comment> + </variables> + <variables name="RO_date_a583_testDevice2" typeName="DT" topologicalAddress="%MW124"> + <comment>AllTypes/testDevice2/MyROBlock</comment> + </variables> + <variables name="RO_char_a583_testDevice2" typeName="WORD" topologicalAddress="%MW128"> + <comment>AllTypes/testDevice2/MyROBlock</comment> + </variables> + <variables name="RO_byte_a583_testDevice2" typeName="BYTE" topologicalAddress="%MW129"> + <comment>AllTypes/testDevice2/MyROBlock</comment> + </variables> + <variables name="RO_word_a583_testDevice2" typeName="WORD" topologicalAddress="%MW130"> + <comment>AllTypes/testDevice2/MyROBlock</comment> + </variables> + <variables name="RO_dword_a583_testDevice2" typeName="DWORD" topologicalAddress="%MW131"> + <comment>AllTypes/testDevice2/MyROBlock</comment> + </variables> + <variables name="RO_int_a583_testDevice2" typeName="INT" topologicalAddress="%MW133"> + <comment>AllTypes/testDevice2/MyROBlock</comment> + </variables> + <variables name="RO_dint_a583_testDevice2" typeName="DINT" topologicalAddress="%MW134"> + <comment>AllTypes/testDevice2/MyROBlock</comment> + </variables> + <variables name="RO_real_a583_testDevice2" typeName="REAL" topologicalAddress="%MW136"> + <comment>AllTypes/testDevice2/MyROBlock</comment> + </variables> + <variables name="RO_dt_a583_testDevice2" typeName="DT" topologicalAddress="%MW138"> + <comment>AllTypes/testDevice2/MyROBlock</comment> + </variables> + <variables name="RW_int8_a583_testDevice1" typeName="ARRAY[0..1, 0..1] OF WORD" topologicalAddress="%MW142"> + <comment>AllTypes/testDevice1/MyRWBlock</comment> + </variables> + <variables name="RW_uint8_a583_testDevice1" typeName="ARRAY[0..1, 0..1] OF BYTE" topologicalAddress="%MW146"> + <comment>AllTypes/testDevice1/MyRWBlock</comment> + </variables> + <variables name="RW_int16_a583_testDevice1" typeName="ARRAY[0..1, 0..1] OF INT" topologicalAddress="%MW148"> + <comment>AllTypes/testDevice1/MyRWBlock</comment> + </variables> + <variables name="RW_uint16_a583_testDevice1" typeName="ARRAY[0..1, 0..1] OF WORD" topologicalAddress="%MW152"> + <comment>AllTypes/testDevice1/MyRWBlock</comment> + </variables> + <variables name="RW_int32_a583_testDevice1" typeName="ARRAY[0..1, 0..1] OF DINT" topologicalAddress="%MW156"> + <comment>AllTypes/testDevice1/MyRWBlock</comment> + </variables> + <variables name="RW_uint32_a583_testDevice1" typeName="ARRAY[0..1, 0..1] OF DWORD" topologicalAddress="%MW164"> + <comment>AllTypes/testDevice1/MyRWBlock</comment> + </variables> + <variables name="RW_float32_a583_testDevice1" typeName="ARRAY[0..1, 0..1] OF REAL" topologicalAddress="%MW172"> + <comment>AllTypes/testDevice1/MyRWBlock</comment> + </variables> + <variables name="RW_string_a583_testDevice1" typeName="ARRAY[0..1, 0..1] OF STRING[64]" topologicalAddress="%MW180"> + <comment>AllTypes/testDevice1/MyRWBlock</comment> + </variables> + <variables name="RW_date_a583_testDevice1" typeName="ARRAY[0..1, 0..1] OF DT" topologicalAddress="%MW308"> + <comment>AllTypes/testDevice1/MyRWBlock</comment> + </variables> + <variables name="RW_char_a583_testDevice1" typeName="ARRAY[0..1, 0..1] OF WORD" topologicalAddress="%MW324"> + <comment>AllTypes/testDevice1/MyRWBlock</comment> + </variables> + <variables name="RW_byte_a583_testDevice1" typeName="ARRAY[0..1, 0..1] OF BYTE" topologicalAddress="%MW328"> + <comment>AllTypes/testDevice1/MyRWBlock</comment> + </variables> + <variables name="RW_word_a583_testDevice1" typeName="ARRAY[0..1, 0..1] OF WORD" topologicalAddress="%MW330"> + <comment>AllTypes/testDevice1/MyRWBlock</comment> + </variables> + <variables name="RW_dword_a583_testDevice1" typeName="ARRAY[0..1, 0..1] OF DWORD" topologicalAddress="%MW334"> + <comment>AllTypes/testDevice1/MyRWBlock</comment> + </variables> + <variables name="RW_int_a583_testDevice1" typeName="ARRAY[0..1, 0..1] OF INT" topologicalAddress="%MW342"> + <comment>AllTypes/testDevice1/MyRWBlock</comment> + </variables> + <variables name="RW_dint_a583_testDevice1" typeName="ARRAY[0..1, 0..1] OF DINT" topologicalAddress="%MW346"> + <comment>AllTypes/testDevice1/MyRWBlock</comment> + </variables> + <variables name="RW_real_a583_testDevice1" typeName="ARRAY[0..1, 0..1] OF REAL" topologicalAddress="%MW354"> + <comment>AllTypes/testDevice1/MyRWBlock</comment> + </variables> + <variables name="RW_dt_a583_testDevice1" typeName="ARRAY[0..1, 0..1] OF DT" topologicalAddress="%MW362"> + <comment>AllTypes/testDevice1/MyRWBlock</comment> + </variables> + <variables name="RW_int8_a583_testDevice2" typeName="ARRAY[0..1, 0..1] OF WORD" topologicalAddress="%MW378"> + <comment>AllTypes/testDevice2/MyRWBlock</comment> + </variables> + <variables name="RW_uint8_a583_testDevice2" typeName="ARRAY[0..1, 0..1] OF BYTE" topologicalAddress="%MW382"> + <comment>AllTypes/testDevice2/MyRWBlock</comment> + </variables> + <variables name="RW_int16_a583_testDevice2" typeName="ARRAY[0..1, 0..1] OF INT" topologicalAddress="%MW384"> + <comment>AllTypes/testDevice2/MyRWBlock</comment> + </variables> + <variables name="RW_uint16_a583_testDevice2" typeName="ARRAY[0..1, 0..1] OF WORD" topologicalAddress="%MW388"> + <comment>AllTypes/testDevice2/MyRWBlock</comment> + </variables> + <variables name="RW_int32_a583_testDevice2" typeName="ARRAY[0..1, 0..1] OF DINT" topologicalAddress="%MW392"> + <comment>AllTypes/testDevice2/MyRWBlock</comment> + </variables> + <variables name="RW_uint32_a583_testDevice2" typeName="ARRAY[0..1, 0..1] OF DWORD" topologicalAddress="%MW400"> + <comment>AllTypes/testDevice2/MyRWBlock</comment> + </variables> + <variables name="RW_float32_a583_testDevice2" typeName="ARRAY[0..1, 0..1] OF REAL" topologicalAddress="%MW408"> + <comment>AllTypes/testDevice2/MyRWBlock</comment> + </variables> + <variables name="RW_string_a583_testDevice2" typeName="ARRAY[0..1, 0..1] OF STRING[64]" topologicalAddress="%MW416"> + <comment>AllTypes/testDevice2/MyRWBlock</comment> + </variables> + <variables name="RW_date_a583_testDevice2" typeName="ARRAY[0..1, 0..1] OF DT" topologicalAddress="%MW544"> + <comment>AllTypes/testDevice2/MyRWBlock</comment> + </variables> + <variables name="RW_char_a583_testDevice2" typeName="ARRAY[0..1, 0..1] OF WORD" topologicalAddress="%MW560"> + <comment>AllTypes/testDevice2/MyRWBlock</comment> + </variables> + <variables name="RW_byte_a583_testDevice2" typeName="ARRAY[0..1, 0..1] OF BYTE" topologicalAddress="%MW564"> + <comment>AllTypes/testDevice2/MyRWBlock</comment> + </variables> + <variables name="RW_word_a583_testDevice2" typeName="ARRAY[0..1, 0..1] OF WORD" topologicalAddress="%MW566"> + <comment>AllTypes/testDevice2/MyRWBlock</comment> + </variables> + <variables name="RW_dword_a583_testDevice2" typeName="ARRAY[0..1, 0..1] OF DWORD" topologicalAddress="%MW570"> + <comment>AllTypes/testDevice2/MyRWBlock</comment> + </variables> + <variables name="RW_int_a583_testDevice2" typeName="ARRAY[0..1, 0..1] OF INT" topologicalAddress="%MW578"> + <comment>AllTypes/testDevice2/MyRWBlock</comment> + </variables> + <variables name="RW_dint_a583_testDevice2" typeName="ARRAY[0..1, 0..1] OF DINT" topologicalAddress="%MW582"> + <comment>AllTypes/testDevice2/MyRWBlock</comment> + </variables> + <variables name="RW_real_a583_testDevice2" typeName="ARRAY[0..1, 0..1] OF REAL" topologicalAddress="%MW590"> + <comment>AllTypes/testDevice2/MyRWBlock</comment> + </variables> + <variables name="RW_dt_a583_testDevice2" typeName="ARRAY[0..1, 0..1] OF DT" topologicalAddress="%MW598"> + <comment>AllTypes/testDevice2/MyRWBlock</comment> + </variables> + <variables name="WO_int8_a583_testDevice1" typeName="ARRAY[0..9] OF WORD" topologicalAddress="%MW614"> + <comment>AllTypes/testDevice1/MyWOBlock</comment> + </variables> + <variables name="WO_uint8_a583_testDevice1" typeName="ARRAY[0..9] OF BYTE" topologicalAddress="%MW624"> + <comment>AllTypes/testDevice1/MyWOBlock</comment> + </variables> + <variables name="WO_int16_a583_testDevice1" typeName="ARRAY[0..9] OF INT" topologicalAddress="%MW629"> + <comment>AllTypes/testDevice1/MyWOBlock</comment> + </variables> + <variables name="WO_uint16_a583_testDevice1" typeName="ARRAY[0..9] OF WORD" topologicalAddress="%MW639"> + <comment>AllTypes/testDevice1/MyWOBlock</comment> + </variables> + <variables name="WO_int32_a583_testDevice1" typeName="ARRAY[0..9] OF DINT" topologicalAddress="%MW649"> + <comment>AllTypes/testDevice1/MyWOBlock</comment> + </variables> + <variables name="WO_uint32_a583_testDevice1" typeName="ARRAY[0..9] OF DWORD" topologicalAddress="%MW669"> + <comment>AllTypes/testDevice1/MyWOBlock</comment> + </variables> + <variables name="WO_float32_a583_testDevice1" typeName="ARRAY[0..9] OF REAL" topologicalAddress="%MW689"> + <comment>AllTypes/testDevice1/MyWOBlock</comment> + </variables> + <variables name="WO_string_a583_testDevice1" typeName="ARRAY[0..9] OF STRING[64]" topologicalAddress="%MW709"> + <comment>AllTypes/testDevice1/MyWOBlock</comment> + </variables> + <variables name="WO_date_a583_testDevice1" typeName="ARRAY[0..9] OF DT" topologicalAddress="%MW1029"> + <comment>AllTypes/testDevice1/MyWOBlock</comment> + </variables> + <variables name="WO_char_a583_testDevice1" typeName="ARRAY[0..9] OF WORD" topologicalAddress="%MW1069"> + <comment>AllTypes/testDevice1/MyWOBlock</comment> + </variables> + <variables name="WO_byte_a583_testDevice1" typeName="ARRAY[0..9] OF BYTE" topologicalAddress="%MW1079"> + <comment>AllTypes/testDevice1/MyWOBlock</comment> + </variables> + <variables name="WO_word_a583_testDevice1" typeName="ARRAY[0..9] OF WORD" topologicalAddress="%MW1084"> + <comment>AllTypes/testDevice1/MyWOBlock</comment> + </variables> + <variables name="WO_dword_a583_testDevice1" typeName="ARRAY[0..9] OF DWORD" topologicalAddress="%MW1094"> + <comment>AllTypes/testDevice1/MyWOBlock</comment> + </variables> + <variables name="WO_int_a583_testDevice1" typeName="ARRAY[0..9] OF INT" topologicalAddress="%MW1114"> + <comment>AllTypes/testDevice1/MyWOBlock</comment> + </variables> + <variables name="WO_dint_a583_testDevice1" typeName="ARRAY[0..9] OF DINT" topologicalAddress="%MW1124"> + <comment>AllTypes/testDevice1/MyWOBlock</comment> + </variables> + <variables name="WO_real_a583_testDevice1" typeName="ARRAY[0..9] OF REAL" topologicalAddress="%MW1144"> + <comment>AllTypes/testDevice1/MyWOBlock</comment> + </variables> + <variables name="WO_dt_a583_testDevice1" typeName="ARRAY[0..9] OF DT" topologicalAddress="%MW1164"> + <comment>AllTypes/testDevice1/MyWOBlock</comment> + </variables> + <variables name="WO_int8_a583_testDevice2" typeName="ARRAY[0..9] OF WORD" topologicalAddress="%MW1204"> + <comment>AllTypes/testDevice2/MyWOBlock</comment> + </variables> + <variables name="WO_uint8_a583_testDevice2" typeName="ARRAY[0..9] OF BYTE" topologicalAddress="%MW1214"> + <comment>AllTypes/testDevice2/MyWOBlock</comment> + </variables> + <variables name="WO_int16_a583_testDevice2" typeName="ARRAY[0..9] OF INT" topologicalAddress="%MW1219"> + <comment>AllTypes/testDevice2/MyWOBlock</comment> + </variables> + <variables name="WO_uint16_a583_testDevice2" typeName="ARRAY[0..9] OF WORD" topologicalAddress="%MW1229"> + <comment>AllTypes/testDevice2/MyWOBlock</comment> + </variables> + <variables name="WO_int32_a583_testDevice2" typeName="ARRAY[0..9] OF DINT" topologicalAddress="%MW1239"> + <comment>AllTypes/testDevice2/MyWOBlock</comment> + </variables> + <variables name="WO_uint32_a583_testDevice2" typeName="ARRAY[0..9] OF DWORD" topologicalAddress="%MW1259"> + <comment>AllTypes/testDevice2/MyWOBlock</comment> + </variables> + <variables name="WO_float32_a583_testDevice2" typeName="ARRAY[0..9] OF REAL" topologicalAddress="%MW1279"> + <comment>AllTypes/testDevice2/MyWOBlock</comment> + </variables> + <variables name="WO_string_a583_testDevice2" typeName="ARRAY[0..9] OF STRING[64]" topologicalAddress="%MW1299"> + <comment>AllTypes/testDevice2/MyWOBlock</comment> + </variables> + <variables name="WO_date_a583_testDevice2" typeName="ARRAY[0..9] OF DT" topologicalAddress="%MW1619"> + <comment>AllTypes/testDevice2/MyWOBlock</comment> + </variables> + <variables name="WO_char_a583_testDevice2" typeName="ARRAY[0..9] OF WORD" topologicalAddress="%MW1659"> + <comment>AllTypes/testDevice2/MyWOBlock</comment> + </variables> + <variables name="WO_byte_a583_testDevice2" typeName="ARRAY[0..9] OF BYTE" topologicalAddress="%MW1669"> + <comment>AllTypes/testDevice2/MyWOBlock</comment> + </variables> + <variables name="WO_word_a583_testDevice2" typeName="ARRAY[0..9] OF WORD" topologicalAddress="%MW1674"> + <comment>AllTypes/testDevice2/MyWOBlock</comment> + </variables> + <variables name="WO_dword_a583_testDevice2" typeName="ARRAY[0..9] OF DWORD" topologicalAddress="%MW1684"> + <comment>AllTypes/testDevice2/MyWOBlock</comment> + </variables> + <variables name="WO_int_a583_testDevice2" typeName="ARRAY[0..9] OF INT" topologicalAddress="%MW1704"> + <comment>AllTypes/testDevice2/MyWOBlock</comment> + </variables> + <variables name="WO_dint_a583_testDevice2" typeName="ARRAY[0..9] OF DINT" topologicalAddress="%MW1714"> + <comment>AllTypes/testDevice2/MyWOBlock</comment> + </variables> + <variables name="WO_real_a583_testDevice2" typeName="ARRAY[0..9] OF REAL" topologicalAddress="%MW1734"> + <comment>AllTypes/testDevice2/MyWOBlock</comment> + </variables> + <variables name="WO_dt_a583_testDevice2" typeName="ARRAY[0..9] OF DT" topologicalAddress="%MW1754"> + <comment>AllTypes/testDevice2/MyWOBlock</comment> + </variables> + </dataBlock> +</VariablesExchangeFile> \ No newline at end of file diff --git a/silecs-codegen/src/xml/test/generated_temp/controller/Siemens_Step7Block.scl b/silecs-codegen/src/xml/test/generated_temp/controller/Siemens_Step7Block.scl new file mode 100644 index 0000000..d3f7d11 --- /dev/null +++ b/silecs-codegen/src/xml/test/generated_temp/controller/Siemens_Step7Block.scl @@ -0,0 +1,150 @@ +//--------------------------------------------------------------------- +// SilecsHeader/ v1.0.0 +// BLOCK Type definition +//--------------------------------------------------------------------- +TYPE _SilecsHeader_hdrBlk +AUTHOR: schwinn +FAMILY: SILECS +NAME: UDTB + STRUCT + _version: STRING[16] := 'SILECS_DEV'; + _checksum: DWORD := DW#16#eae21021; + _user: STRING[16] := 'schwinn'; + _date: DT := DT#2016-7-26-15:37:54; + + END_STRUCT; +END_TYPE + +//--------------------------------------------------------------------- +// SilecsHeader/ v1.0.0 +// Block instance definition +//--------------------------------------------------------------------- +// SilecsHeader_SilecsHeader ........................................... +DATA_BLOCK DB0 +{ S7_Optimized_Access := 'FALSE' } +AUTHOR: schwinn +FAMILY: SILECS +NAME: DEV_MODE +STRUCT + hdrBlk: _SilecsHeader_hdrBlk; + +END_STRUCT; +BEGIN +END_DATA_BLOCK + +//--------------------------------------------------------------------- +// AllTypes/ v0.1.0 +// BLOCK Type definition +//--------------------------------------------------------------------- +TYPE _AllTypes_MyROBlock +AUTHOR: schwinn +FAMILY: SILECS +NAME: UDTB + STRUCT + RO_int8: CHAR; + RO_uint8: BYTE; + RO_int16: INT; + RO_uint16: WORD; + RO_int32: DINT; + RO_uint32: DWORD; + RO_float32: REAL; + RO_string: STRING[64]; + RO_date: DT; + RO_char: CHAR; + RO_byte: BYTE; + RO_word: WORD; + RO_dword: DWORD; + RO_int: INT; + RO_dint: DINT; + RO_real: REAL; + RO_dt: DT; + + END_STRUCT; +END_TYPE + +TYPE _AllTypes_MyRWBlock +AUTHOR: schwinn +FAMILY: SILECS +NAME: UDTB + STRUCT + RW_int8: ARRAY[0..1, 0..1] OF CHAR; + RW_uint8: ARRAY[0..1, 0..1] OF BYTE; + RW_int16: ARRAY[0..1, 0..1] OF INT; + RW_uint16: ARRAY[0..1, 0..1] OF WORD; + RW_int32: ARRAY[0..1, 0..1] OF DINT; + RW_uint32: ARRAY[0..1, 0..1] OF DWORD; + RW_float32: ARRAY[0..1, 0..1] OF REAL; + RW_string: ARRAY[0..1, 0..1] OF STRING[64]; + RW_date: ARRAY[0..1, 0..1] OF DT; + RW_char: ARRAY[0..1, 0..1] OF CHAR; + RW_byte: ARRAY[0..1, 0..1] OF BYTE; + RW_word: ARRAY[0..1, 0..1] OF WORD; + RW_dword: ARRAY[0..1, 0..1] OF DWORD; + RW_int: ARRAY[0..1, 0..1] OF INT; + RW_dint: ARRAY[0..1, 0..1] OF DINT; + RW_real: ARRAY[0..1, 0..1] OF REAL; + RW_dt: ARRAY[0..1, 0..1] OF DT; + + END_STRUCT; +END_TYPE + +TYPE _AllTypes_MyWOBlock +AUTHOR: schwinn +FAMILY: SILECS +NAME: UDTB + STRUCT + WO_int8: ARRAY[0..9] OF CHAR; + WO_uint8: ARRAY[0..9] OF BYTE; + WO_int16: ARRAY[0..9] OF INT; + WO_uint16: ARRAY[0..9] OF WORD; + WO_int32: ARRAY[0..9] OF DINT; + WO_uint32: ARRAY[0..9] OF DWORD; + WO_float32: ARRAY[0..9] OF REAL; + WO_string: ARRAY[0..9] OF STRING[64]; + WO_date: ARRAY[0..9] OF DT; + WO_char: ARRAY[0..9] OF CHAR; + WO_byte: ARRAY[0..9] OF BYTE; + WO_word: ARRAY[0..9] OF WORD; + WO_dword: ARRAY[0..9] OF DWORD; + WO_int: ARRAY[0..9] OF INT; + WO_dint: ARRAY[0..9] OF DINT; + WO_real: ARRAY[0..9] OF REAL; + WO_dt: ARRAY[0..9] OF DT; + + END_STRUCT; +END_TYPE + +//--------------------------------------------------------------------- +// AllTypes/ v0.1.0 +// Block instance definition +//--------------------------------------------------------------------- +// AllTypes_testDevice1 ........................................... +DATA_BLOCK DB1 +{ S7_Optimized_Access := 'FALSE' } +AUTHOR: schwinn +FAMILY: SILECS +NAME: DEV_MODE +STRUCT + MyROBlock: _AllTypes_MyROBlock; + MyRWBlock: _AllTypes_MyRWBlock; + MyWOBlock: _AllTypes_MyWOBlock; + +END_STRUCT; +BEGIN +END_DATA_BLOCK + +// AllTypes_testDevice2 ........................................... +DATA_BLOCK DB2 +{ S7_Optimized_Access := 'FALSE' } +AUTHOR: schwinn +FAMILY: SILECS +NAME: DEV_MODE +STRUCT + MyROBlock: _AllTypes_MyROBlock; + MyRWBlock: _AllTypes_MyRWBlock; + MyWOBlock: _AllTypes_MyWOBlock; + +END_STRUCT; +BEGIN +END_DATA_BLOCK + diff --git a/silecs-codegen/src/xml/test/generated_temp/controller/Siemens_Step7Block.sdf b/silecs-codegen/src/xml/test/generated_temp/controller/Siemens_Step7Block.sdf new file mode 100644 index 0000000..e5d2ddb --- /dev/null +++ b/silecs-codegen/src/xml/test/generated_temp/controller/Siemens_Step7Block.sdf @@ -0,0 +1,7 @@ +"_SilecsHeader_hdrBlk","UDT 0","UDT 0","[SilecsHeader/1.0.0] UDT symbol: _<class-name>_<block-name>" +"SilecsHeader_SilecsHeader","DB 0","DB 0","[SilecsHeader/1.0.0] DB symbol: <class-name>_<device-label | device-id>" +"_AllTypes_MyROBlock","UDT 1","UDT 1","[AllTypes/0.1.0] UDT symbol: _<class-name>_<block-name>" +"_AllTypes_MyRWBlock","UDT 2","UDT 2","" +"_AllTypes_MyWOBlock","UDT 3","UDT 3","" +"AllTypes_testDevice1","DB 1","DB 1","[AllTypes/0.1.0] DB symbol: <class-name>_<device-label | device-id>" +"AllTypes_testDevice2","DB 2","DB 2","" diff --git a/silecs-codegen/src/xml/test/generated_temp/controller/Siemens_Step7Device.scl b/silecs-codegen/src/xml/test/generated_temp/controller/Siemens_Step7Device.scl new file mode 100644 index 0000000..2023307 --- /dev/null +++ b/silecs-codegen/src/xml/test/generated_temp/controller/Siemens_Step7Device.scl @@ -0,0 +1,162 @@ +//--------------------------------------------------------------------- +// SilecsHeader/ v1.0.0 +// BLOCK Type definition +//--------------------------------------------------------------------- +TYPE _SilecsHeader_hdrBlk +AUTHOR: schwinn +FAMILY: SILECS +NAME: UDTB + STRUCT + _version: STRING[16] := 'SILECS_DEV'; + _checksum: DWORD := DW#16#eae21021; + _user: STRING[16] := 'schwinn'; + _date: DT := DT#2016-7-26-15:37:54; + + END_STRUCT; +END_TYPE + +//--------------------------------------------------------------------- +// SilecsHeader/ v1.0.0 +// Block instance definition +//--------------------------------------------------------------------- +// SilecsHeader_hdrBlk ........................................... +DATA_BLOCK DB0 +{ S7_Optimized_Access := 'FALSE' } +AUTHOR: schwinn +FAMILY: SILECS +NAME: BLK_MODE +STRUCT + SilecsHeader: _SilecsHeader_hdrBlk; + +END_STRUCT; +BEGIN +END_DATA_BLOCK + +//--------------------------------------------------------------------- +// AllTypes/ v0.1.0 +// BLOCK Type definition +//--------------------------------------------------------------------- +TYPE _AllTypes_MyROBlock +AUTHOR: schwinn +FAMILY: SILECS +NAME: UDTB + STRUCT + RO_int8: CHAR; + RO_uint8: BYTE; + RO_int16: INT; + RO_uint16: WORD; + RO_int32: DINT; + RO_uint32: DWORD; + RO_float32: REAL; + RO_string: STRING[64]; + RO_date: DT; + RO_char: CHAR; + RO_byte: BYTE; + RO_word: WORD; + RO_dword: DWORD; + RO_int: INT; + RO_dint: DINT; + RO_real: REAL; + RO_dt: DT; + + END_STRUCT; +END_TYPE + +TYPE _AllTypes_MyRWBlock +AUTHOR: schwinn +FAMILY: SILECS +NAME: UDTB + STRUCT + RW_int8: ARRAY[0..1, 0..1] OF CHAR; + RW_uint8: ARRAY[0..1, 0..1] OF BYTE; + RW_int16: ARRAY[0..1, 0..1] OF INT; + RW_uint16: ARRAY[0..1, 0..1] OF WORD; + RW_int32: ARRAY[0..1, 0..1] OF DINT; + RW_uint32: ARRAY[0..1, 0..1] OF DWORD; + RW_float32: ARRAY[0..1, 0..1] OF REAL; + RW_string: ARRAY[0..1, 0..1] OF STRING[64]; + RW_date: ARRAY[0..1, 0..1] OF DT; + RW_char: ARRAY[0..1, 0..1] OF CHAR; + RW_byte: ARRAY[0..1, 0..1] OF BYTE; + RW_word: ARRAY[0..1, 0..1] OF WORD; + RW_dword: ARRAY[0..1, 0..1] OF DWORD; + RW_int: ARRAY[0..1, 0..1] OF INT; + RW_dint: ARRAY[0..1, 0..1] OF DINT; + RW_real: ARRAY[0..1, 0..1] OF REAL; + RW_dt: ARRAY[0..1, 0..1] OF DT; + + END_STRUCT; +END_TYPE + +TYPE _AllTypes_MyWOBlock +AUTHOR: schwinn +FAMILY: SILECS +NAME: UDTB + STRUCT + WO_int8: ARRAY[0..9] OF CHAR; + WO_uint8: ARRAY[0..9] OF BYTE; + WO_int16: ARRAY[0..9] OF INT; + WO_uint16: ARRAY[0..9] OF WORD; + WO_int32: ARRAY[0..9] OF DINT; + WO_uint32: ARRAY[0..9] OF DWORD; + WO_float32: ARRAY[0..9] OF REAL; + WO_string: ARRAY[0..9] OF STRING[64]; + WO_date: ARRAY[0..9] OF DT; + WO_char: ARRAY[0..9] OF CHAR; + WO_byte: ARRAY[0..9] OF BYTE; + WO_word: ARRAY[0..9] OF WORD; + WO_dword: ARRAY[0..9] OF DWORD; + WO_int: ARRAY[0..9] OF INT; + WO_dint: ARRAY[0..9] OF DINT; + WO_real: ARRAY[0..9] OF REAL; + WO_dt: ARRAY[0..9] OF DT; + + END_STRUCT; +END_TYPE + +//--------------------------------------------------------------------- +// AllTypes/ v0.1.0 +// Block instance definition +//--------------------------------------------------------------------- +// AllTypes_MyROBlock ........................................... +DATA_BLOCK DB1 +{ S7_Optimized_Access := 'FALSE' } +AUTHOR: schwinn +FAMILY: SILECS +NAME: BLK_MODE +STRUCT + testDevice1: _AllTypes_MyROBlock; + testDevice2: _AllTypes_MyROBlock; + +END_STRUCT; +BEGIN +END_DATA_BLOCK + +// AllTypes_MyRWBlock ........................................... +DATA_BLOCK DB2 +{ S7_Optimized_Access := 'FALSE' } +AUTHOR: schwinn +FAMILY: SILECS +NAME: BLK_MODE +STRUCT + testDevice1: _AllTypes_MyRWBlock; + testDevice2: _AllTypes_MyRWBlock; + +END_STRUCT; +BEGIN +END_DATA_BLOCK + +// AllTypes_MyWOBlock ........................................... +DATA_BLOCK DB3 +{ S7_Optimized_Access := 'FALSE' } +AUTHOR: schwinn +FAMILY: SILECS +NAME: BLK_MODE +STRUCT + testDevice1: _AllTypes_MyWOBlock; + testDevice2: _AllTypes_MyWOBlock; + +END_STRUCT; +BEGIN +END_DATA_BLOCK + diff --git a/silecs-codegen/src/xml/test/generated_temp/controller/Siemens_Step7Device.sdf b/silecs-codegen/src/xml/test/generated_temp/controller/Siemens_Step7Device.sdf new file mode 100644 index 0000000..29a5f58 --- /dev/null +++ b/silecs-codegen/src/xml/test/generated_temp/controller/Siemens_Step7Device.sdf @@ -0,0 +1,8 @@ +"_SilecsHeader_hdrBlk","UDT 0","UDT 0","[SilecsHeader/1.0.0] UDT symbol: _<class-name>_<block-name>" +"SilecsHeader_hdrBlk","DB 0","DB 0","[SilecsHeader/1.0.0] DB symbol: <class-name>_<block-name>" +"_AllTypes_MyROBlock","UDT 1","UDT 1","[AllTypes/0.1.0] UDT symbol: _<class-name>_<block-name>" +"_AllTypes_MyRWBlock","UDT 2","UDT 2","" +"_AllTypes_MyWOBlock","UDT 3","UDT 3","" +"AllTypes_MyROBlock","DB 1","DB 1","[AllTypes/0.1.0] DB symbol: <class-name>_<block-name>" +"AllTypes_MyRWBlock","DB 2","DB 2","" +"AllTypes_MyWOBlock","DB 3","DB 3","" diff --git a/silecs-codegen/src/xml/test/generated_temp/controller/Siemens_TiaBlock.scl b/silecs-codegen/src/xml/test/generated_temp/controller/Siemens_TiaBlock.scl new file mode 100644 index 0000000..8da2cd7 --- /dev/null +++ b/silecs-codegen/src/xml/test/generated_temp/controller/Siemens_TiaBlock.scl @@ -0,0 +1,158 @@ +//--------------------------------------------------------------------- +// SilecsHeader/ v1.0.0 +// BLOCK Type definition +//--------------------------------------------------------------------- +TYPE _SilecsHeader_hdrBlk +AUTHOR: schwinn +FAMILY: SILECS +NAME: UDTB + STRUCT + _version: STRING[16] := 'SILECS_DEV'; + _checksum: DWORD := DW#16#eae21021; + _user: STRING[16] := 'schwinn'; + _date: DT := DT#2016-7-26-15:37:54; + + END_STRUCT; +END_TYPE + +//--------------------------------------------------------------------- +// SilecsHeader/ v1.0.0 +// Block instance definition +//--------------------------------------------------------------------- +DATA_BLOCK SilecsHeader_hdrBlk +{ S7_Optimized_Access := 'FALSE' } +AUTHOR: schwinn +FAMILY: SILECS +NAME: BLK_MODE +STRUCT + SilecsHeader: _SilecsHeader_hdrBlk; + +END_STRUCT; +BEGIN +END_DATA_BLOCK + +//--------------------------------------------------------------------- +// AllTypes/ v0.1.0 +// BLOCK Type definition +//--------------------------------------------------------------------- +TYPE _AllTypes_MyROBlock +AUTHOR: schwinn +FAMILY: SILECS +NAME: UDTB + STRUCT + RO_int8: CHAR; + RO_uint8: BYTE; + RO_int16: INT; + RO_uint16: WORD; + RO_int32: DINT; + RO_uint32: DWORD; + RO_float32: REAL; + RO_string: STRING[64]; + RO_date: DT; + RO_char: CHAR; + RO_byte: BYTE; + RO_word: WORD; + RO_dword: DWORD; + RO_int: INT; + RO_dint: DINT; + RO_real: REAL; + RO_dt: DT; + + END_STRUCT; +END_TYPE + +TYPE _AllTypes_MyRWBlock +AUTHOR: schwinn +FAMILY: SILECS +NAME: UDTB + STRUCT + RW_int8: ARRAY[0..1, 0..1] OF CHAR; + RW_uint8: ARRAY[0..1, 0..1] OF BYTE; + RW_int16: ARRAY[0..1, 0..1] OF INT; + RW_uint16: ARRAY[0..1, 0..1] OF WORD; + RW_int32: ARRAY[0..1, 0..1] OF DINT; + RW_uint32: ARRAY[0..1, 0..1] OF DWORD; + RW_float32: ARRAY[0..1, 0..1] OF REAL; + RW_string: ARRAY[0..1, 0..1] OF STRING[64]; + RW_date: ARRAY[0..1, 0..1] OF DT; + RW_char: ARRAY[0..1, 0..1] OF CHAR; + RW_byte: ARRAY[0..1, 0..1] OF BYTE; + RW_word: ARRAY[0..1, 0..1] OF WORD; + RW_dword: ARRAY[0..1, 0..1] OF DWORD; + RW_int: ARRAY[0..1, 0..1] OF INT; + RW_dint: ARRAY[0..1, 0..1] OF DINT; + RW_real: ARRAY[0..1, 0..1] OF REAL; + RW_dt: ARRAY[0..1, 0..1] OF DT; + + END_STRUCT; +END_TYPE + +TYPE _AllTypes_MyWOBlock +AUTHOR: schwinn +FAMILY: SILECS +NAME: UDTB + STRUCT + WO_int8: ARRAY[0..9] OF CHAR; + WO_uint8: ARRAY[0..9] OF BYTE; + WO_int16: ARRAY[0..9] OF INT; + WO_uint16: ARRAY[0..9] OF WORD; + WO_int32: ARRAY[0..9] OF DINT; + WO_uint32: ARRAY[0..9] OF DWORD; + WO_float32: ARRAY[0..9] OF REAL; + WO_string: ARRAY[0..9] OF STRING[64]; + WO_date: ARRAY[0..9] OF DT; + WO_char: ARRAY[0..9] OF CHAR; + WO_byte: ARRAY[0..9] OF BYTE; + WO_word: ARRAY[0..9] OF WORD; + WO_dword: ARRAY[0..9] OF DWORD; + WO_int: ARRAY[0..9] OF INT; + WO_dint: ARRAY[0..9] OF DINT; + WO_real: ARRAY[0..9] OF REAL; + WO_dt: ARRAY[0..9] OF DT; + + END_STRUCT; +END_TYPE + +//--------------------------------------------------------------------- +// AllTypes/ v0.1.0 +// Block instance definition +//--------------------------------------------------------------------- +DATA_BLOCK AllTypes_MyROBlock +{ S7_Optimized_Access := 'FALSE' } +AUTHOR: schwinn +FAMILY: SILECS +NAME: BLK_MODE +STRUCT + testDevice1: _AllTypes_MyROBlock; + testDevice2: _AllTypes_MyROBlock; + +END_STRUCT; +BEGIN +END_DATA_BLOCK + +DATA_BLOCK AllTypes_MyRWBlock +{ S7_Optimized_Access := 'FALSE' } +AUTHOR: schwinn +FAMILY: SILECS +NAME: BLK_MODE +STRUCT + testDevice1: _AllTypes_MyRWBlock; + testDevice2: _AllTypes_MyRWBlock; + +END_STRUCT; +BEGIN +END_DATA_BLOCK + +DATA_BLOCK AllTypes_MyWOBlock +{ S7_Optimized_Access := 'FALSE' } +AUTHOR: schwinn +FAMILY: SILECS +NAME: BLK_MODE +STRUCT + testDevice1: _AllTypes_MyWOBlock; + testDevice2: _AllTypes_MyWOBlock; + +END_STRUCT; +BEGIN +END_DATA_BLOCK + diff --git a/silecs-codegen/src/xml/test/generated_temp/controller/Siemens_TiaBlock.sdf b/silecs-codegen/src/xml/test/generated_temp/controller/Siemens_TiaBlock.sdf new file mode 100644 index 0000000..29a5f58 --- /dev/null +++ b/silecs-codegen/src/xml/test/generated_temp/controller/Siemens_TiaBlock.sdf @@ -0,0 +1,8 @@ +"_SilecsHeader_hdrBlk","UDT 0","UDT 0","[SilecsHeader/1.0.0] UDT symbol: _<class-name>_<block-name>" +"SilecsHeader_hdrBlk","DB 0","DB 0","[SilecsHeader/1.0.0] DB symbol: <class-name>_<block-name>" +"_AllTypes_MyROBlock","UDT 1","UDT 1","[AllTypes/0.1.0] UDT symbol: _<class-name>_<block-name>" +"_AllTypes_MyRWBlock","UDT 2","UDT 2","" +"_AllTypes_MyWOBlock","UDT 3","UDT 3","" +"AllTypes_MyROBlock","DB 1","DB 1","[AllTypes/0.1.0] DB symbol: <class-name>_<block-name>" +"AllTypes_MyRWBlock","DB 2","DB 2","" +"AllTypes_MyWOBlock","DB 3","DB 3","" diff --git a/silecs-codegen/src/xml/test/generated_temp/controller/Siemens_TiaDevice.scl b/silecs-codegen/src/xml/test/generated_temp/controller/Siemens_TiaDevice.scl new file mode 100644 index 0000000..567fb31 --- /dev/null +++ b/silecs-codegen/src/xml/test/generated_temp/controller/Siemens_TiaDevice.scl @@ -0,0 +1,147 @@ +//--------------------------------------------------------------------- +// SilecsHeader/ v1.0.0 +// BLOCK Type definition +//--------------------------------------------------------------------- +TYPE _SilecsHeader_hdrBlk +AUTHOR: schwinn +FAMILY: SILECS +NAME: UDTB + STRUCT + _version: STRING[16] := 'SILECS_DEV'; + _checksum: DWORD := DW#16#eae21021; + _user: STRING[16] := 'schwinn'; + _date: DT := DT#2016-7-26-15:37:54; + + END_STRUCT; +END_TYPE + +//--------------------------------------------------------------------- +// SilecsHeader/ v1.0.0 +// Block instance definition +//--------------------------------------------------------------------- +DATA_BLOCK SilecsHeader_SilecsHeader +{ S7_Optimized_Access := 'FALSE' } +AUTHOR: schwinn +FAMILY: SILECS +NAME: DEV_MODE +STRUCT + hdrBlk: _SilecsHeader_hdrBlk; + +END_STRUCT; +BEGIN +END_DATA_BLOCK + +//--------------------------------------------------------------------- +// AllTypes/ v0.1.0 +// BLOCK Type definition +//--------------------------------------------------------------------- +TYPE _AllTypes_MyROBlock +AUTHOR: schwinn +FAMILY: SILECS +NAME: UDTB + STRUCT + RO_int8: CHAR; + RO_uint8: BYTE; + RO_int16: INT; + RO_uint16: WORD; + RO_int32: DINT; + RO_uint32: DWORD; + RO_float32: REAL; + RO_string: STRING[64]; + RO_date: DT; + RO_char: CHAR; + RO_byte: BYTE; + RO_word: WORD; + RO_dword: DWORD; + RO_int: INT; + RO_dint: DINT; + RO_real: REAL; + RO_dt: DT; + + END_STRUCT; +END_TYPE + +TYPE _AllTypes_MyRWBlock +AUTHOR: schwinn +FAMILY: SILECS +NAME: UDTB + STRUCT + RW_int8: ARRAY[0..1, 0..1] OF CHAR; + RW_uint8: ARRAY[0..1, 0..1] OF BYTE; + RW_int16: ARRAY[0..1, 0..1] OF INT; + RW_uint16: ARRAY[0..1, 0..1] OF WORD; + RW_int32: ARRAY[0..1, 0..1] OF DINT; + RW_uint32: ARRAY[0..1, 0..1] OF DWORD; + RW_float32: ARRAY[0..1, 0..1] OF REAL; + RW_string: ARRAY[0..1, 0..1] OF STRING[64]; + RW_date: ARRAY[0..1, 0..1] OF DT; + RW_char: ARRAY[0..1, 0..1] OF CHAR; + RW_byte: ARRAY[0..1, 0..1] OF BYTE; + RW_word: ARRAY[0..1, 0..1] OF WORD; + RW_dword: ARRAY[0..1, 0..1] OF DWORD; + RW_int: ARRAY[0..1, 0..1] OF INT; + RW_dint: ARRAY[0..1, 0..1] OF DINT; + RW_real: ARRAY[0..1, 0..1] OF REAL; + RW_dt: ARRAY[0..1, 0..1] OF DT; + + END_STRUCT; +END_TYPE + +TYPE _AllTypes_MyWOBlock +AUTHOR: schwinn +FAMILY: SILECS +NAME: UDTB + STRUCT + WO_int8: ARRAY[0..9] OF CHAR; + WO_uint8: ARRAY[0..9] OF BYTE; + WO_int16: ARRAY[0..9] OF INT; + WO_uint16: ARRAY[0..9] OF WORD; + WO_int32: ARRAY[0..9] OF DINT; + WO_uint32: ARRAY[0..9] OF DWORD; + WO_float32: ARRAY[0..9] OF REAL; + WO_string: ARRAY[0..9] OF STRING[64]; + WO_date: ARRAY[0..9] OF DT; + WO_char: ARRAY[0..9] OF CHAR; + WO_byte: ARRAY[0..9] OF BYTE; + WO_word: ARRAY[0..9] OF WORD; + WO_dword: ARRAY[0..9] OF DWORD; + WO_int: ARRAY[0..9] OF INT; + WO_dint: ARRAY[0..9] OF DINT; + WO_real: ARRAY[0..9] OF REAL; + WO_dt: ARRAY[0..9] OF DT; + + END_STRUCT; +END_TYPE + +//--------------------------------------------------------------------- +// AllTypes/ v0.1.0 +// Block instance definition +//--------------------------------------------------------------------- +DATA_BLOCK AllTypes_testDevice1 +{ S7_Optimized_Access := 'FALSE' } +AUTHOR: schwinn +FAMILY: SILECS +NAME: DEV_MODE +STRUCT + MyROBlock: _AllTypes_MyROBlock; + MyRWBlock: _AllTypes_MyRWBlock; + MyWOBlock: _AllTypes_MyWOBlock; + +END_STRUCT; +BEGIN +END_DATA_BLOCK + +DATA_BLOCK AllTypes_testDevice2 +{ S7_Optimized_Access := 'FALSE' } +AUTHOR: schwinn +FAMILY: SILECS +NAME: DEV_MODE +STRUCT + MyROBlock: _AllTypes_MyROBlock; + MyRWBlock: _AllTypes_MyRWBlock; + MyWOBlock: _AllTypes_MyWOBlock; + +END_STRUCT; +BEGIN +END_DATA_BLOCK + diff --git a/silecs-codegen/src/xml/test/generated_temp/controller/Siemens_TiaDevice.sdf b/silecs-codegen/src/xml/test/generated_temp/controller/Siemens_TiaDevice.sdf new file mode 100644 index 0000000..e5d2ddb --- /dev/null +++ b/silecs-codegen/src/xml/test/generated_temp/controller/Siemens_TiaDevice.sdf @@ -0,0 +1,7 @@ +"_SilecsHeader_hdrBlk","UDT 0","UDT 0","[SilecsHeader/1.0.0] UDT symbol: _<class-name>_<block-name>" +"SilecsHeader_SilecsHeader","DB 0","DB 0","[SilecsHeader/1.0.0] DB symbol: <class-name>_<device-label | device-id>" +"_AllTypes_MyROBlock","UDT 1","UDT 1","[AllTypes/0.1.0] UDT symbol: _<class-name>_<block-name>" +"_AllTypes_MyRWBlock","UDT 2","UDT 2","" +"_AllTypes_MyWOBlock","UDT 3","UDT 3","" +"AllTypes_testDevice1","DB 1","DB 1","[AllTypes/0.1.0] DB symbol: <class-name>_<device-label | device-id>" +"AllTypes_testDevice2","DB 2","DB 2","" diff --git a/silecs-codegen/src/xml/test/generated_temp/controller/Virtual_SiemensBlock.AllTypes.h b/silecs-codegen/src/xml/test/generated_temp/controller/Virtual_SiemensBlock.AllTypes.h new file mode 100644 index 0000000..95bdd54 --- /dev/null +++ b/silecs-codegen/src/xml/test/generated_temp/controller/Virtual_SiemensBlock.AllTypes.h @@ -0,0 +1,1272 @@ + +/* Copyright CERN 2015 + * + * WARNING: This code is automatically generated from your SILECS deploy unit document. + * You should never modify the content of this file as it would break consistency. + * Furthermore, any changes will be overwritten in the next code generation. + * Any modification shall be done using the SILECS development environment + * and regenerating this source code. + */ + +#ifndef ALLTYPES_0_1_0_H_ +#define ALLTYPES_0_1_0_H_ + +#include <silecs-virtual-controller/interface/Block.h> +#include <silecs-virtual-controller/interface/DeployUnit.h> +#include <silecs-virtual-controller/interface/Design.h> +#include <silecs-virtual-controller/interface/Device.h> + +namespace AllTypes_0_1_0 +{ + +class Design; + +class MyROBlock : public SilecsServer::Block +{ +public: + /*! + * \brief MyROBlock constructor. It creates an empty block. + */ + MyROBlock() : SilecsServer::Block("AllTypes:MyROBlock") + { + + } + + ~MyROBlock() + { + } + + /*! + * \brief Get RO_int8 register. + * \return value. + */ + int8_t getRO_int8() const + { + return structData_.RO_int8; + } + + /*! + * \brief Set RO_int8 register. + * \param value to be set. + */ + void setRO_int8(int8_t value) + { + structData_.RO_int8 = value; + } + + /*! + * \brief Get RO_uint8 register. + * \return value. + */ + uint8_t getRO_uint8() const + { + return structData_.RO_uint8; + } + + /*! + * \brief Set RO_uint8 register. + * \param value to be set. + */ + void setRO_uint8(uint8_t value) + { + structData_.RO_uint8 = value; + } + + /*! + * \brief Get RO_int16 register. + * \return value. + */ + int16_t getRO_int16() const + { + return structData_.RO_int16; + } + + /*! + * \brief Set RO_int16 register. + * \param value to be set. + */ + void setRO_int16(int16_t value) + { + structData_.RO_int16 = value; + } + + /*! + * \brief Get RO_uint16 register. + * \return value. + */ + uint16_t getRO_uint16() const + { + return structData_.RO_uint16; + } + + /*! + * \brief Set RO_uint16 register. + * \param value to be set. + */ + void setRO_uint16(uint16_t value) + { + structData_.RO_uint16 = value; + } + + /*! + * \brief Get RO_int32 register. + * \return value. + */ + int32_t getRO_int32() const + { + return structData_.RO_int32; + } + + /*! + * \brief Set RO_int32 register. + * \param value to be set. + */ + void setRO_int32(int32_t value) + { + structData_.RO_int32 = value; + } + + /*! + * \brief Get RO_uint32 register. + * \return value. + */ + uint32_t getRO_uint32() const + { + return structData_.RO_uint32; + } + + /*! + * \brief Set RO_uint32 register. + * \param value to be set. + */ + void setRO_uint32(uint32_t value) + { + structData_.RO_uint32 = value; + } + + /*! + * \brief Get RO_float32 register. + * \return value. + */ + float getRO_float32() const + { + return structData_.RO_float32; + } + + /*! + * \brief Set RO_float32 register. + * \param value to be set. + */ + void setRO_float32(float value) + { + structData_.RO_float32 = value; + } + + /*! + * \brief Get RO_string register. + * \return value. + */ + std::string getRO_string() const + { + size_t len = (size_t)structData_.RO_string[1]; + return std::string((char*)&(structData_.RO_string[2]), len); + } + + /*! + * \brief Set RO_string register. + * \param value to be set. + */ + void setRO_string(const std::string &value) + { + size_t len = (value.length() < RO_stringLen_) ? value.length() : RO_stringLen_; + memcpy((char*)&(structData_.RO_string[2]), value.c_str(), len); + structData_.RO_string[0] = char(0); + structData_.RO_string[1] = char(len); + } + + /*! + * \brief Get RO_date register. + * \return value. + */ + double getRO_date() const + { + return structData_.RO_date; + } + + /*! + * \brief Set RO_date register. + * \param value to be set. + */ + void setRO_date(double value) + { + structData_.RO_date = value; + } + + /*! + * \brief Get RO_char register. + * \return value. + */ + int8_t getRO_char() const + { + return structData_.RO_char; + } + + /*! + * \brief Set RO_char register. + * \param value to be set. + */ + void setRO_char(int8_t value) + { + structData_.RO_char = value; + } + + /*! + * \brief Get RO_byte register. + * \return value. + */ + uint8_t getRO_byte() const + { + return structData_.RO_byte; + } + + /*! + * \brief Set RO_byte register. + * \param value to be set. + */ + void setRO_byte(uint8_t value) + { + structData_.RO_byte = value; + } + + /*! + * \brief Get RO_word register. + * \return value. + */ + uint16_t getRO_word() const + { + return structData_.RO_word; + } + + /*! + * \brief Set RO_word register. + * \param value to be set. + */ + void setRO_word(uint16_t value) + { + structData_.RO_word = value; + } + + /*! + * \brief Get RO_dword register. + * \return value. + */ + uint32_t getRO_dword() const + { + return structData_.RO_dword; + } + + /*! + * \brief Set RO_dword register. + * \param value to be set. + */ + void setRO_dword(uint32_t value) + { + structData_.RO_dword = value; + } + + /*! + * \brief Get RO_int register. + * \return value. + */ + int16_t getRO_int() const + { + return structData_.RO_int; + } + + /*! + * \brief Set RO_int register. + * \param value to be set. + */ + void setRO_int(int16_t value) + { + structData_.RO_int = value; + } + + /*! + * \brief Get RO_dint register. + * \return value. + */ + int32_t getRO_dint() const + { + return structData_.RO_dint; + } + + /*! + * \brief Set RO_dint register. + * \param value to be set. + */ + void setRO_dint(int32_t value) + { + structData_.RO_dint = value; + } + + /*! + * \brief Get RO_real register. + * \return value. + */ + float getRO_real() const + { + return structData_.RO_real; + } + + /*! + * \brief Set RO_real register. + * \param value to be set. + */ + void setRO_real(float value) + { + structData_.RO_real = value; + } + + /*! + * \brief Get RO_dt register. + * \return value. + */ + double getRO_dt() const + { + return structData_.RO_dt; + } + + /*! + * \brief Set RO_dt register. + * \param value to be set. + */ + void setRO_dt(double value) + { + structData_.RO_dt = value; + } + + virtual inline size_t getSize() const + { + return sizeof(structData_); + } + + virtual void getData(unsigned char * data) const + { + memcpy(data, &structData_, this->getSize()); + } + + virtual void setData(unsigned char * data) + { + memcpy(&structData_, data, this->getSize()); + } + + virtual inline size_t getOffset() const { return 1; } + + static const std::size_t RO_stringLen_ = 64; + +private: + +#pragma pack(push, 1) + struct + { + int8_t RO_int8; + uint8_t RO_uint8; + int16_t RO_int16; + uint16_t RO_uint16; + int32_t RO_int32; + uint32_t RO_uint32; + float RO_float32; + char RO_string[RO_stringLen_+2]; + double RO_date; + int8_t RO_char; + uint8_t RO_byte; + uint16_t RO_word; + uint32_t RO_dword; + int16_t RO_int; + int32_t RO_dint; + float RO_real; + double RO_dt; + + } structData_; +#pragma pack(pop) + +}; + +class MyRWBlock : public SilecsServer::Block +{ +public: + /*! + * \brief MyRWBlock constructor. It creates an empty block. + */ + MyRWBlock() : SilecsServer::Block("AllTypes:MyRWBlock") + { + + } + + ~MyRWBlock() + { + } + + /*! + * \brief Get array RW_int8 register. + * \return value. + */ + void getRW_int8(int8_t* value) const + { + memcpy(value, &structData_.RW_int8, RW_int8Dim1_ * RW_int8Dim2_ * sizeof(int8_t)); + } + + /*! + * \brief Set array RW_int8 register. + * \param value to be set. + */ + void setRW_int8(int8_t* value) + { + memcpy(&structData_.RW_int8, value, RW_int8Dim1_ * RW_int8Dim2_ * sizeof(int8_t)); + } + + /*! + * \brief Get array RW_uint8 register. + * \return value. + */ + void getRW_uint8(uint8_t* value) const + { + memcpy(value, &structData_.RW_uint8, RW_uint8Dim1_ * RW_uint8Dim2_ * sizeof(uint8_t)); + } + + /*! + * \brief Set array RW_uint8 register. + * \param value to be set. + */ + void setRW_uint8(uint8_t* value) + { + memcpy(&structData_.RW_uint8, value, RW_uint8Dim1_ * RW_uint8Dim2_ * sizeof(uint8_t)); + } + + /*! + * \brief Get array RW_int16 register. + * \return value. + */ + void getRW_int16(int16_t* value) const + { + memcpy(value, &structData_.RW_int16, RW_int16Dim1_ * RW_int16Dim2_ * sizeof(int16_t)); + } + + /*! + * \brief Set array RW_int16 register. + * \param value to be set. + */ + void setRW_int16(int16_t* value) + { + memcpy(&structData_.RW_int16, value, RW_int16Dim1_ * RW_int16Dim2_ * sizeof(int16_t)); + } + + /*! + * \brief Get array RW_uint16 register. + * \return value. + */ + void getRW_uint16(uint16_t* value) const + { + memcpy(value, &structData_.RW_uint16, RW_uint16Dim1_ * RW_uint16Dim2_ * sizeof(uint16_t)); + } + + /*! + * \brief Set array RW_uint16 register. + * \param value to be set. + */ + void setRW_uint16(uint16_t* value) + { + memcpy(&structData_.RW_uint16, value, RW_uint16Dim1_ * RW_uint16Dim2_ * sizeof(uint16_t)); + } + + /*! + * \brief Get array RW_int32 register. + * \return value. + */ + void getRW_int32(int32_t* value) const + { + memcpy(value, &structData_.RW_int32, RW_int32Dim1_ * RW_int32Dim2_ * sizeof(int32_t)); + } + + /*! + * \brief Set array RW_int32 register. + * \param value to be set. + */ + void setRW_int32(int32_t* value) + { + memcpy(&structData_.RW_int32, value, RW_int32Dim1_ * RW_int32Dim2_ * sizeof(int32_t)); + } + + /*! + * \brief Get array RW_uint32 register. + * \return value. + */ + void getRW_uint32(uint32_t* value) const + { + memcpy(value, &structData_.RW_uint32, RW_uint32Dim1_ * RW_uint32Dim2_ * sizeof(uint32_t)); + } + + /*! + * \brief Set array RW_uint32 register. + * \param value to be set. + */ + void setRW_uint32(uint32_t* value) + { + memcpy(&structData_.RW_uint32, value, RW_uint32Dim1_ * RW_uint32Dim2_ * sizeof(uint32_t)); + } + + /*! + * \brief Get array RW_float32 register. + * \return value. + */ + void getRW_float32(float* value) const + { + memcpy(value, &structData_.RW_float32, RW_float32Dim1_ * RW_float32Dim2_ * sizeof(float)); + } + + /*! + * \brief Set array RW_float32 register. + * \param value to be set. + */ + void setRW_float32(float* value) + { + memcpy(&structData_.RW_float32, value, RW_float32Dim1_ * RW_float32Dim2_ * sizeof(float)); + } + + /*! + * \brief Get std::string RW_string register. + * \param value buffer where the value will be stored. + */ + void getRW_string(std::string* value) const + { + for (std::size_t i = 0; i < RW_stringDim1_; i++) + { + size_t len = (size_t)structData_.RW_string[i][1]; + value[i].assign(&(structData_.RW_string[i][2]), len); + } + } + + /*! + * \brief Set std::string RW_string register. + * \param value to be set. + */ + void setRW_string(std::string* value) + { + for (std::size_t i = 0; i < RW_stringDim1_; i++) + { + size_t len = (value[i].length() < RW_stringLen_) ? value[i].length() : RW_stringLen_; + memcpy(&(structData_.RW_string[i][2]), value[i].c_str(), len); + structData_.RW_string[i][0] = char(0); + structData_.RW_string[i][1] = char(len); + } + } + + /*! + * \brief Get array RW_date register. + * \return value. + */ + void getRW_date(double* value) const + { + memcpy(value, &structData_.RW_date, RW_dateDim1_ * RW_dateDim2_ * sizeof(double)); + } + + /*! + * \brief Set array RW_date register. + * \param value to be set. + */ + void setRW_date(double* value) + { + memcpy(&structData_.RW_date, value, RW_dateDim1_ * RW_dateDim2_ * sizeof(double)); + } + + /*! + * \brief Get array RW_char register. + * \return value. + */ + void getRW_char(int8_t* value) const + { + memcpy(value, &structData_.RW_char, RW_charDim1_ * RW_charDim2_ * sizeof(int8_t)); + } + + /*! + * \brief Set array RW_char register. + * \param value to be set. + */ + void setRW_char(int8_t* value) + { + memcpy(&structData_.RW_char, value, RW_charDim1_ * RW_charDim2_ * sizeof(int8_t)); + } + + /*! + * \brief Get array RW_byte register. + * \return value. + */ + void getRW_byte(uint8_t* value) const + { + memcpy(value, &structData_.RW_byte, RW_byteDim1_ * RW_byteDim2_ * sizeof(uint8_t)); + } + + /*! + * \brief Set array RW_byte register. + * \param value to be set. + */ + void setRW_byte(uint8_t* value) + { + memcpy(&structData_.RW_byte, value, RW_byteDim1_ * RW_byteDim2_ * sizeof(uint8_t)); + } + + /*! + * \brief Get array RW_word register. + * \return value. + */ + void getRW_word(uint16_t* value) const + { + memcpy(value, &structData_.RW_word, RW_wordDim1_ * RW_wordDim2_ * sizeof(uint16_t)); + } + + /*! + * \brief Set array RW_word register. + * \param value to be set. + */ + void setRW_word(uint16_t* value) + { + memcpy(&structData_.RW_word, value, RW_wordDim1_ * RW_wordDim2_ * sizeof(uint16_t)); + } + + /*! + * \brief Get array RW_dword register. + * \return value. + */ + void getRW_dword(uint32_t* value) const + { + memcpy(value, &structData_.RW_dword, RW_dwordDim1_ * RW_dwordDim2_ * sizeof(uint32_t)); + } + + /*! + * \brief Set array RW_dword register. + * \param value to be set. + */ + void setRW_dword(uint32_t* value) + { + memcpy(&structData_.RW_dword, value, RW_dwordDim1_ * RW_dwordDim2_ * sizeof(uint32_t)); + } + + /*! + * \brief Get array RW_int register. + * \return value. + */ + void getRW_int(int16_t* value) const + { + memcpy(value, &structData_.RW_int, RW_intDim1_ * RW_intDim2_ * sizeof(int16_t)); + } + + /*! + * \brief Set array RW_int register. + * \param value to be set. + */ + void setRW_int(int16_t* value) + { + memcpy(&structData_.RW_int, value, RW_intDim1_ * RW_intDim2_ * sizeof(int16_t)); + } + + /*! + * \brief Get array RW_dint register. + * \return value. + */ + void getRW_dint(int32_t* value) const + { + memcpy(value, &structData_.RW_dint, RW_dintDim1_ * RW_dintDim2_ * sizeof(int32_t)); + } + + /*! + * \brief Set array RW_dint register. + * \param value to be set. + */ + void setRW_dint(int32_t* value) + { + memcpy(&structData_.RW_dint, value, RW_dintDim1_ * RW_dintDim2_ * sizeof(int32_t)); + } + + /*! + * \brief Get array RW_real register. + * \return value. + */ + void getRW_real(float* value) const + { + memcpy(value, &structData_.RW_real, RW_realDim1_ * RW_realDim2_ * sizeof(float)); + } + + /*! + * \brief Set array RW_real register. + * \param value to be set. + */ + void setRW_real(float* value) + { + memcpy(&structData_.RW_real, value, RW_realDim1_ * RW_realDim2_ * sizeof(float)); + } + + /*! + * \brief Get array RW_dt register. + * \return value. + */ + void getRW_dt(double* value) const + { + memcpy(value, &structData_.RW_dt, RW_dtDim1_ * RW_dtDim2_ * sizeof(double)); + } + + /*! + * \brief Set array RW_dt register. + * \param value to be set. + */ + void setRW_dt(double* value) + { + memcpy(&structData_.RW_dt, value, RW_dtDim1_ * RW_dtDim2_ * sizeof(double)); + } + + virtual inline size_t getSize() const + { + return sizeof(structData_); + } + + virtual void getData(unsigned char * data) const + { + memcpy(data, &structData_, this->getSize()); + } + + virtual void setData(unsigned char * data) + { + memcpy(&structData_, data, this->getSize()); + } + + virtual inline size_t getOffset() const { return 2; } + + static const std::size_t RW_int8Dim1_ = 2; + static const std::size_t RW_int8Dim2_ = 2; + static const std::size_t RW_uint8Dim1_ = 2; + static const std::size_t RW_uint8Dim2_ = 2; + static const std::size_t RW_int16Dim1_ = 2; + static const std::size_t RW_int16Dim2_ = 2; + static const std::size_t RW_uint16Dim1_ = 2; + static const std::size_t RW_uint16Dim2_ = 2; + static const std::size_t RW_int32Dim1_ = 2; + static const std::size_t RW_int32Dim2_ = 2; + static const std::size_t RW_uint32Dim1_ = 2; + static const std::size_t RW_uint32Dim2_ = 2; + static const std::size_t RW_float32Dim1_ = 2; + static const std::size_t RW_float32Dim2_ = 2; + static const std::size_t RW_stringDim1_ = 2; + static const std::size_t RW_stringDim2_ = 2; + static const std::size_t RW_stringLen_ = 64; + static const std::size_t RW_dateDim1_ = 2; + static const std::size_t RW_dateDim2_ = 2; + static const std::size_t RW_charDim1_ = 2; + static const std::size_t RW_charDim2_ = 2; + static const std::size_t RW_byteDim1_ = 2; + static const std::size_t RW_byteDim2_ = 2; + static const std::size_t RW_wordDim1_ = 2; + static const std::size_t RW_wordDim2_ = 2; + static const std::size_t RW_dwordDim1_ = 2; + static const std::size_t RW_dwordDim2_ = 2; + static const std::size_t RW_intDim1_ = 2; + static const std::size_t RW_intDim2_ = 2; + static const std::size_t RW_dintDim1_ = 2; + static const std::size_t RW_dintDim2_ = 2; + static const std::size_t RW_realDim1_ = 2; + static const std::size_t RW_realDim2_ = 2; + static const std::size_t RW_dtDim1_ = 2; + static const std::size_t RW_dtDim2_ = 2; + +private: + +#pragma pack(push, 1) + struct + { + int8_t RW_int8[RW_int8Dim1_][RW_int8Dim2_]; + uint8_t RW_uint8[RW_uint8Dim1_][RW_uint8Dim2_]; + int16_t RW_int16[RW_int16Dim1_][RW_int16Dim2_]; + uint16_t RW_uint16[RW_uint16Dim1_][RW_uint16Dim2_]; + int32_t RW_int32[RW_int32Dim1_][RW_int32Dim2_]; + uint32_t RW_uint32[RW_uint32Dim1_][RW_uint32Dim2_]; + float RW_float32[RW_float32Dim1_][RW_float32Dim2_]; + char RW_string[RW_stringDim1_][RW_stringDim2_][RW_stringLen_+2]; + double RW_date[RW_dateDim1_][RW_dateDim2_]; + int8_t RW_char[RW_charDim1_][RW_charDim2_]; + uint8_t RW_byte[RW_byteDim1_][RW_byteDim2_]; + uint16_t RW_word[RW_wordDim1_][RW_wordDim2_]; + uint32_t RW_dword[RW_dwordDim1_][RW_dwordDim2_]; + int16_t RW_int[RW_intDim1_][RW_intDim2_]; + int32_t RW_dint[RW_dintDim1_][RW_dintDim2_]; + float RW_real[RW_realDim1_][RW_realDim2_]; + double RW_dt[RW_dtDim1_][RW_dtDim2_]; + + } structData_; +#pragma pack(pop) + +}; + +class MyWOBlock : public SilecsServer::Block +{ +public: + /*! + * \brief MyWOBlock constructor. It creates an empty block. + */ + MyWOBlock() : SilecsServer::Block("AllTypes:MyWOBlock") + { + + } + + ~MyWOBlock() + { + } + + /*! + * \brief Get array WO_int8 register. + * \return value. + */ + void getWO_int8(int8_t* value) const + { + memcpy(value, &structData_.WO_int8, WO_int8Dim1_ * WO_int8Dim2_ * sizeof(int8_t)); + } + + /*! + * \brief Set array WO_int8 register. + * \param value to be set. + */ + void setWO_int8(int8_t* value) + { + memcpy(&structData_.WO_int8, value, WO_int8Dim1_ * WO_int8Dim2_ * sizeof(int8_t)); + } + + /*! + * \brief Get array WO_uint8 register. + * \return value. + */ + void getWO_uint8(uint8_t* value) const + { + memcpy(value, &structData_.WO_uint8, WO_uint8Dim1_ * WO_uint8Dim2_ * sizeof(uint8_t)); + } + + /*! + * \brief Set array WO_uint8 register. + * \param value to be set. + */ + void setWO_uint8(uint8_t* value) + { + memcpy(&structData_.WO_uint8, value, WO_uint8Dim1_ * WO_uint8Dim2_ * sizeof(uint8_t)); + } + + /*! + * \brief Get array WO_int16 register. + * \return value. + */ + void getWO_int16(int16_t* value) const + { + memcpy(value, &structData_.WO_int16, WO_int16Dim1_ * WO_int16Dim2_ * sizeof(int16_t)); + } + + /*! + * \brief Set array WO_int16 register. + * \param value to be set. + */ + void setWO_int16(int16_t* value) + { + memcpy(&structData_.WO_int16, value, WO_int16Dim1_ * WO_int16Dim2_ * sizeof(int16_t)); + } + + /*! + * \brief Get array WO_uint16 register. + * \return value. + */ + void getWO_uint16(uint16_t* value) const + { + memcpy(value, &structData_.WO_uint16, WO_uint16Dim1_ * WO_uint16Dim2_ * sizeof(uint16_t)); + } + + /*! + * \brief Set array WO_uint16 register. + * \param value to be set. + */ + void setWO_uint16(uint16_t* value) + { + memcpy(&structData_.WO_uint16, value, WO_uint16Dim1_ * WO_uint16Dim2_ * sizeof(uint16_t)); + } + + /*! + * \brief Get array WO_int32 register. + * \return value. + */ + void getWO_int32(int32_t* value) const + { + memcpy(value, &structData_.WO_int32, WO_int32Dim1_ * WO_int32Dim2_ * sizeof(int32_t)); + } + + /*! + * \brief Set array WO_int32 register. + * \param value to be set. + */ + void setWO_int32(int32_t* value) + { + memcpy(&structData_.WO_int32, value, WO_int32Dim1_ * WO_int32Dim2_ * sizeof(int32_t)); + } + + /*! + * \brief Get array WO_uint32 register. + * \return value. + */ + void getWO_uint32(uint32_t* value) const + { + memcpy(value, &structData_.WO_uint32, WO_uint32Dim1_ * WO_uint32Dim2_ * sizeof(uint32_t)); + } + + /*! + * \brief Set array WO_uint32 register. + * \param value to be set. + */ + void setWO_uint32(uint32_t* value) + { + memcpy(&structData_.WO_uint32, value, WO_uint32Dim1_ * WO_uint32Dim2_ * sizeof(uint32_t)); + } + + /*! + * \brief Get array WO_float32 register. + * \return value. + */ + void getWO_float32(float* value) const + { + memcpy(value, &structData_.WO_float32, WO_float32Dim1_ * WO_float32Dim2_ * sizeof(float)); + } + + /*! + * \brief Set array WO_float32 register. + * \param value to be set. + */ + void setWO_float32(float* value) + { + memcpy(&structData_.WO_float32, value, WO_float32Dim1_ * WO_float32Dim2_ * sizeof(float)); + } + + /*! + * \brief Get std::string WO_string register. + * \param value buffer where the value will be stored. + */ + void getWO_string(std::string* value) const + { + for (std::size_t i = 0; i < WO_stringDim1_; i++) + { + size_t len = (size_t)structData_.WO_string[i][1]; + value[i].assign(&(structData_.WO_string[i][2]), len); + } + } + + /*! + * \brief Set std::string WO_string register. + * \param value to be set. + */ + void setWO_string(std::string* value) + { + for (std::size_t i = 0; i < WO_stringDim1_; i++) + { + size_t len = (value[i].length() < WO_stringLen_) ? value[i].length() : WO_stringLen_; + memcpy(&(structData_.WO_string[i][2]), value[i].c_str(), len); + structData_.WO_string[i][0] = char(0); + structData_.WO_string[i][1] = char(len); + } + } + + /*! + * \brief Get array WO_date register. + * \return value. + */ + void getWO_date(double* value) const + { + memcpy(value, &structData_.WO_date, WO_dateDim1_ * WO_dateDim2_ * sizeof(double)); + } + + /*! + * \brief Set array WO_date register. + * \param value to be set. + */ + void setWO_date(double* value) + { + memcpy(&structData_.WO_date, value, WO_dateDim1_ * WO_dateDim2_ * sizeof(double)); + } + + /*! + * \brief Get array WO_char register. + * \return value. + */ + void getWO_char(int8_t* value) const + { + memcpy(value, &structData_.WO_char, WO_charDim1_ * WO_charDim2_ * sizeof(int8_t)); + } + + /*! + * \brief Set array WO_char register. + * \param value to be set. + */ + void setWO_char(int8_t* value) + { + memcpy(&structData_.WO_char, value, WO_charDim1_ * WO_charDim2_ * sizeof(int8_t)); + } + + /*! + * \brief Get array WO_byte register. + * \return value. + */ + void getWO_byte(uint8_t* value) const + { + memcpy(value, &structData_.WO_byte, WO_byteDim1_ * WO_byteDim2_ * sizeof(uint8_t)); + } + + /*! + * \brief Set array WO_byte register. + * \param value to be set. + */ + void setWO_byte(uint8_t* value) + { + memcpy(&structData_.WO_byte, value, WO_byteDim1_ * WO_byteDim2_ * sizeof(uint8_t)); + } + + /*! + * \brief Get array WO_word register. + * \return value. + */ + void getWO_word(uint16_t* value) const + { + memcpy(value, &structData_.WO_word, WO_wordDim1_ * WO_wordDim2_ * sizeof(uint16_t)); + } + + /*! + * \brief Set array WO_word register. + * \param value to be set. + */ + void setWO_word(uint16_t* value) + { + memcpy(&structData_.WO_word, value, WO_wordDim1_ * WO_wordDim2_ * sizeof(uint16_t)); + } + + /*! + * \brief Get array WO_dword register. + * \return value. + */ + void getWO_dword(uint32_t* value) const + { + memcpy(value, &structData_.WO_dword, WO_dwordDim1_ * WO_dwordDim2_ * sizeof(uint32_t)); + } + + /*! + * \brief Set array WO_dword register. + * \param value to be set. + */ + void setWO_dword(uint32_t* value) + { + memcpy(&structData_.WO_dword, value, WO_dwordDim1_ * WO_dwordDim2_ * sizeof(uint32_t)); + } + + /*! + * \brief Get array WO_int register. + * \return value. + */ + void getWO_int(int16_t* value) const + { + memcpy(value, &structData_.WO_int, WO_intDim1_ * WO_intDim2_ * sizeof(int16_t)); + } + + /*! + * \brief Set array WO_int register. + * \param value to be set. + */ + void setWO_int(int16_t* value) + { + memcpy(&structData_.WO_int, value, WO_intDim1_ * WO_intDim2_ * sizeof(int16_t)); + } + + /*! + * \brief Get array WO_dint register. + * \return value. + */ + void getWO_dint(int32_t* value) const + { + memcpy(value, &structData_.WO_dint, WO_dintDim1_ * WO_dintDim2_ * sizeof(int32_t)); + } + + /*! + * \brief Set array WO_dint register. + * \param value to be set. + */ + void setWO_dint(int32_t* value) + { + memcpy(&structData_.WO_dint, value, WO_dintDim1_ * WO_dintDim2_ * sizeof(int32_t)); + } + + /*! + * \brief Get array WO_real register. + * \return value. + */ + void getWO_real(float* value) const + { + memcpy(value, &structData_.WO_real, WO_realDim1_ * WO_realDim2_ * sizeof(float)); + } + + /*! + * \brief Set array WO_real register. + * \param value to be set. + */ + void setWO_real(float* value) + { + memcpy(&structData_.WO_real, value, WO_realDim1_ * WO_realDim2_ * sizeof(float)); + } + + /*! + * \brief Get array WO_dt register. + * \return value. + */ + void getWO_dt(double* value) const + { + memcpy(value, &structData_.WO_dt, WO_dtDim1_ * WO_dtDim2_ * sizeof(double)); + } + + /*! + * \brief Set array WO_dt register. + * \param value to be set. + */ + void setWO_dt(double* value) + { + memcpy(&structData_.WO_dt, value, WO_dtDim1_ * WO_dtDim2_ * sizeof(double)); + } + + virtual inline size_t getSize() const + { + return sizeof(structData_); + } + + virtual void getData(unsigned char * data) const + { + memcpy(data, &structData_, this->getSize()); + } + + virtual void setData(unsigned char * data) + { + memcpy(&structData_, data, this->getSize()); + } + + virtual inline size_t getOffset() const { return 3; } + + static const std::size_t WO_int8Dim1_ = 10; + static const std::size_t WO_int8Dim2_ = 1; + static const std::size_t WO_uint8Dim1_ = 10; + static const std::size_t WO_uint8Dim2_ = 1; + static const std::size_t WO_int16Dim1_ = 10; + static const std::size_t WO_int16Dim2_ = 1; + static const std::size_t WO_uint16Dim1_ = 10; + static const std::size_t WO_uint16Dim2_ = 1; + static const std::size_t WO_int32Dim1_ = 10; + static const std::size_t WO_int32Dim2_ = 1; + static const std::size_t WO_uint32Dim1_ = 10; + static const std::size_t WO_uint32Dim2_ = 1; + static const std::size_t WO_float32Dim1_ = 10; + static const std::size_t WO_float32Dim2_ = 1; + static const std::size_t WO_stringDim1_ = 10; + static const std::size_t WO_stringDim2_ = 1; + static const std::size_t WO_stringLen_ = 64; + static const std::size_t WO_dateDim1_ = 10; + static const std::size_t WO_dateDim2_ = 1; + static const std::size_t WO_charDim1_ = 10; + static const std::size_t WO_charDim2_ = 1; + static const std::size_t WO_byteDim1_ = 10; + static const std::size_t WO_byteDim2_ = 1; + static const std::size_t WO_wordDim1_ = 10; + static const std::size_t WO_wordDim2_ = 1; + static const std::size_t WO_dwordDim1_ = 10; + static const std::size_t WO_dwordDim2_ = 1; + static const std::size_t WO_intDim1_ = 10; + static const std::size_t WO_intDim2_ = 1; + static const std::size_t WO_dintDim1_ = 10; + static const std::size_t WO_dintDim2_ = 1; + static const std::size_t WO_realDim1_ = 10; + static const std::size_t WO_realDim2_ = 1; + static const std::size_t WO_dtDim1_ = 10; + static const std::size_t WO_dtDim2_ = 1; + +private: + +#pragma pack(push, 1) + struct + { + int8_t WO_int8[WO_int8Dim1_]; + uint8_t WO_uint8[WO_uint8Dim1_]; + int16_t WO_int16[WO_int16Dim1_]; + uint16_t WO_uint16[WO_uint16Dim1_]; + int32_t WO_int32[WO_int32Dim1_]; + uint32_t WO_uint32[WO_uint32Dim1_]; + float WO_float32[WO_float32Dim1_]; + char WO_string[WO_stringDim1_][WO_stringLen_+2]; + double WO_date[WO_dateDim1_]; + int8_t WO_char[WO_charDim1_]; + uint8_t WO_byte[WO_byteDim1_]; + uint16_t WO_word[WO_wordDim1_]; + uint32_t WO_dword[WO_dwordDim1_]; + int16_t WO_int[WO_intDim1_]; + int32_t WO_dint[WO_dintDim1_]; + float WO_real[WO_realDim1_]; + double WO_dt[WO_dtDim1_]; + + } structData_; +#pragma pack(pop) + +}; + + + +class Device : public SilecsServer::Device +{ +public: + Device(const std::string& label, size_t number):SilecsServer::Device(label, number) + { + blockMap_["AllTypes:MyROBlock"] = new MyROBlock(); + blockMap_["AllTypes:MyRWBlock"] = new MyRWBlock(); + blockMap_["AllTypes:MyWOBlock"] = new MyWOBlock(); + } + + ~Device() + { + delete (blockMap_["AllTypes:MyROBlock"]); + delete (blockMap_["AllTypes:MyRWBlock"]); + delete (blockMap_["AllTypes:MyWOBlock"]); + } +}; + + +class Design : public SilecsServer::Design +{ +public: + + Design():SilecsServer::Design("AllTypes", "0.1.0") + { + deviceMap_["AllTypes:testDevice1"] = new Device("AllTypes:testDevice1", 0); + deviceMap_["AllTypes:testDevice2"] = new Device("AllTypes:testDevice2", 1); + } + + ~Design() + { + delete(deviceMap_["AllTypes:testDevice1"]); + delete(deviceMap_["AllTypes:testDevice2"]); + } + + /*! + * \brief Return pointer to the requested device. + * \param label Device label. + */ + AllTypes_0_1_0::Device* getDevice(const std::string& label) + { + if (deviceMap_.find(label) != deviceMap_.end()) + { + return dynamic_cast<AllTypes_0_1_0::Device*>(deviceMap_[label]); + } + return NULL; + } +}; + +} /* namespace */ +#endif diff --git a/silecs-codegen/src/xml/test/generated_temp/controller/Virtual_SiemensBlock.SilecsHeader.h b/silecs-codegen/src/xml/test/generated_temp/controller/Virtual_SiemensBlock.SilecsHeader.h new file mode 100644 index 0000000..85ecca6 --- /dev/null +++ b/silecs-codegen/src/xml/test/generated_temp/controller/Virtual_SiemensBlock.SilecsHeader.h @@ -0,0 +1,203 @@ + +/* Copyright CERN 2015 + * + * WARNING: This code is automatically generated from your SILECS deploy unit document. + * You should never modify the content of this file as it would break consistency. + * Furthermore, any changes will be overwritten in the next code generation. + * Any modification shall be done using the SILECS development environment + * and regenerating this source code. + */ + +#ifndef SILECSHEADER_1_0_0_H_ +#define SILECSHEADER_1_0_0_H_ + +#include <silecs-virtual-controller/interface/Block.h> +#include <silecs-virtual-controller/interface/DeployUnit.h> +#include <silecs-virtual-controller/interface/Design.h> +#include <silecs-virtual-controller/interface/Device.h> + +namespace SilecsHeader_1_0_0 +{ + +class Design; + +class HdrBlk : public SilecsServer::Block +{ +public: + /*! + * \brief hdrBlk constructor. It creates an empty block. + */ + HdrBlk() : SilecsServer::Block("SilecsHeader:hdrBlk") + { + set_version("DEV"); + set_checksum(0X2110E2EA); + set_user("schwinn"); + set_date(0.0); + } + + ~HdrBlk() + { + } + + /*! + * \brief Get _version register. + * \return value. + */ + std::string get_version() const + { + size_t len = (size_t)structData_._version[1]; + return std::string((char*)&(structData_._version[2]), len); + } + + /*! + * \brief Set _version register. + * \param value to be set. + */ + void set_version(const std::string &value) + { + size_t len = (value.length() < _versionLen_) ? value.length() : _versionLen_; + memcpy((char*)&(structData_._version[2]), value.c_str(), len); + structData_._version[0] = char(0); + structData_._version[1] = char(len); + } + + /*! + * \brief Get _checksum register. + * \return value. + */ + uint32_t get_checksum() const + { + return structData_._checksum; + } + + /*! + * \brief Set _checksum register. + * \param value to be set. + */ + void set_checksum(uint32_t value) + { + structData_._checksum = value; + } + + /*! + * \brief Get _user register. + * \return value. + */ + std::string get_user() const + { + size_t len = (size_t)structData_._user[1]; + return std::string((char*)&(structData_._user[2]), len); + } + + /*! + * \brief Set _user register. + * \param value to be set. + */ + void set_user(const std::string &value) + { + size_t len = (value.length() < _userLen_) ? value.length() : _userLen_; + memcpy((char*)&(structData_._user[2]), value.c_str(), len); + structData_._user[0] = char(0); + structData_._user[1] = char(len); + } + + /*! + * \brief Get _date register. + * \return value. + */ + double get_date() const + { + return structData_._date; + } + + /*! + * \brief Set _date register. + * \param value to be set. + */ + void set_date(double value) + { + structData_._date = value; + } + + virtual inline size_t getSize() const + { + return sizeof(structData_); + } + + virtual void getData(unsigned char * data) const + { + memcpy(data, &structData_, this->getSize()); + } + + virtual void setData(unsigned char * data) + { + memcpy(&structData_, data, this->getSize()); + } + + virtual inline size_t getOffset() const { return 0; } + + static const std::size_t _versionLen_ = 16; + static const std::size_t _userLen_ = 16; + +private: + +#pragma pack(push, 1) + struct + { + char _version[_versionLen_+2]; + uint32_t _checksum; + char _user[_userLen_+2]; + double _date; + + } structData_; +#pragma pack(pop) + +}; + + + +class Device : public SilecsServer::Device +{ +public: + Device(const std::string& label, size_t number):SilecsServer::Device(label, number) + { + blockMap_["SilecsHeader:hdrBlk"] = new HdrBlk(); + } + + ~Device() + { + delete (blockMap_["SilecsHeader:hdrBlk"]); + } +}; + + +class Design : public SilecsServer::Design +{ +public: + + Design():SilecsServer::Design("SilecsHeader", "1.0.0") + { + deviceMap_["SilecsHeader:SilecsHeader"] = new Device("SilecsHeader:SilecsHeader", 0); + } + + ~Design() + { + delete(deviceMap_["SilecsHeader:SilecsHeader"]); + } + + /*! + * \brief Return pointer to the requested device. + * \param label Device label. + */ + SilecsHeader_1_0_0::Device* getDevice(const std::string& label) + { + if (deviceMap_.find(label) != deviceMap_.end()) + { + return dynamic_cast<SilecsHeader_1_0_0::Device*>(deviceMap_[label]); + } + return NULL; + } +}; + +} /* namespace */ +#endif diff --git a/silecs-codegen/src/xml/test/generated_temp/controller/Virtual_SiemensBlock.cpp b/silecs-codegen/src/xml/test/generated_temp/controller/Virtual_SiemensBlock.cpp new file mode 100644 index 0000000..d7e2a30 --- /dev/null +++ b/silecs-codegen/src/xml/test/generated_temp/controller/Virtual_SiemensBlock.cpp @@ -0,0 +1,33 @@ + +#include <stdio.h> +#include <stdlib.h> +#include <cstring> +#include <iostream> + +#include <silecs-virtual-controller/core/SilecsSnap7Server.h> +#include "Virtual_SiemensBlock.h" + +class UserSnap7Server : public SilecsServer::SilecsSnap7Server +{ +public: + UserSnap7Server(Virtual_SiemensBlock::DeployUnit* du) : SilecsSnap7Server(du, true) {} + virtual ~UserSnap7Server() {} + + virtual void userFunction() + { + // Implement the specific process control here! + // Look at SILECS Wikis: 'Create a virtual controller' chapter + } +}; + +int main(int argc, char*argv[]) +{ + Virtual_SiemensBlock::DeployUnit du; + UserSnap7Server server(&du); + if (server.startServer() < 0) + { + std::cout << "Failed to start the VC server: " << du.getName() << std::endl; + return -1; + } + return 0; +} diff --git a/silecs-codegen/src/xml/test/generated_temp/controller/Virtual_SiemensBlock.h b/silecs-codegen/src/xml/test/generated_temp/controller/Virtual_SiemensBlock.h new file mode 100644 index 0000000..819405b --- /dev/null +++ b/silecs-codegen/src/xml/test/generated_temp/controller/Virtual_SiemensBlock.h @@ -0,0 +1,53 @@ + +/* Copyright CERN 2015 + * + * WARNING: This code is automatically generated from your SILECS deploy unit document. + * You should never modify the content of this file as it would break consistency. + * Furthermore, any changes will be overwritten in the next code generation. + * Any modification shall be done using the SILECS development environment + * and regenerating this source code. + */ + +#ifndef VIRTUAL_SIEMENSBLOCK_H_ +#define VIRTUAL_SIEMENSBLOCK_H_ + +#include <silecs-virtual-controller/interface/DeployUnit.h> +#include <silecs-virtual-controller/interface/Design.h> +#include "SilecsHeader_1.0.0.h" +#include "AllTypes_0.1.0.h" + + +namespace Virtual_SiemensBlock +{ + +class DeployUnit : public SilecsServer::DeployUnit +{ +public: + + DeployUnit() : SilecsServer::DeployUnit("Virtual_SiemensBlock", SilecsServer::S7Protocol, SilecsServer::BlockMode, 0) + { + mapDesigns_["SilecsHeader"] = new SilecsHeader_1_0_0::Design(); + mapDesigns_["AllTypes"] = new AllTypes_0_1_0::Design(); + } + + ~DeployUnit() + { + delete mapDesigns_["SilecsHeader"]; + delete mapDesigns_["AllTypes"]; + } + + SilecsHeader_1_0_0::Design* getSilecsHeader() + { + return dynamic_cast<SilecsHeader_1_0_0::Design*>(mapDesigns_["SilecsHeader"]); + } + + AllTypes_0_1_0::Design* getAllTypes() + { + return dynamic_cast<AllTypes_0_1_0::Design*>(mapDesigns_["AllTypes"]); + } + +}; + +} + +#endif diff --git a/silecs-codegen/src/xml/test/generated_temp/controller/Virtual_SiemensDevice.AllTypes.h b/silecs-codegen/src/xml/test/generated_temp/controller/Virtual_SiemensDevice.AllTypes.h new file mode 100644 index 0000000..3883554 --- /dev/null +++ b/silecs-codegen/src/xml/test/generated_temp/controller/Virtual_SiemensDevice.AllTypes.h @@ -0,0 +1,1272 @@ + +/* Copyright CERN 2015 + * + * WARNING: This code is automatically generated from your SILECS deploy unit document. + * You should never modify the content of this file as it would break consistency. + * Furthermore, any changes will be overwritten in the next code generation. + * Any modification shall be done using the SILECS development environment + * and regenerating this source code. + */ + +#ifndef ALLTYPES_0_1_0_H_ +#define ALLTYPES_0_1_0_H_ + +#include <silecs-virtual-controller/interface/Block.h> +#include <silecs-virtual-controller/interface/DeployUnit.h> +#include <silecs-virtual-controller/interface/Design.h> +#include <silecs-virtual-controller/interface/Device.h> + +namespace AllTypes_0_1_0 +{ + +class Design; + +class MyROBlock : public SilecsServer::Block +{ +public: + /*! + * \brief MyROBlock constructor. It creates an empty block. + */ + MyROBlock() : SilecsServer::Block("AllTypes:MyROBlock") + { + + } + + ~MyROBlock() + { + } + + /*! + * \brief Get RO_int8 register. + * \return value. + */ + int8_t getRO_int8() const + { + return structData_.RO_int8; + } + + /*! + * \brief Set RO_int8 register. + * \param value to be set. + */ + void setRO_int8(int8_t value) + { + structData_.RO_int8 = value; + } + + /*! + * \brief Get RO_uint8 register. + * \return value. + */ + uint8_t getRO_uint8() const + { + return structData_.RO_uint8; + } + + /*! + * \brief Set RO_uint8 register. + * \param value to be set. + */ + void setRO_uint8(uint8_t value) + { + structData_.RO_uint8 = value; + } + + /*! + * \brief Get RO_int16 register. + * \return value. + */ + int16_t getRO_int16() const + { + return structData_.RO_int16; + } + + /*! + * \brief Set RO_int16 register. + * \param value to be set. + */ + void setRO_int16(int16_t value) + { + structData_.RO_int16 = value; + } + + /*! + * \brief Get RO_uint16 register. + * \return value. + */ + uint16_t getRO_uint16() const + { + return structData_.RO_uint16; + } + + /*! + * \brief Set RO_uint16 register. + * \param value to be set. + */ + void setRO_uint16(uint16_t value) + { + structData_.RO_uint16 = value; + } + + /*! + * \brief Get RO_int32 register. + * \return value. + */ + int32_t getRO_int32() const + { + return structData_.RO_int32; + } + + /*! + * \brief Set RO_int32 register. + * \param value to be set. + */ + void setRO_int32(int32_t value) + { + structData_.RO_int32 = value; + } + + /*! + * \brief Get RO_uint32 register. + * \return value. + */ + uint32_t getRO_uint32() const + { + return structData_.RO_uint32; + } + + /*! + * \brief Set RO_uint32 register. + * \param value to be set. + */ + void setRO_uint32(uint32_t value) + { + structData_.RO_uint32 = value; + } + + /*! + * \brief Get RO_float32 register. + * \return value. + */ + float getRO_float32() const + { + return structData_.RO_float32; + } + + /*! + * \brief Set RO_float32 register. + * \param value to be set. + */ + void setRO_float32(float value) + { + structData_.RO_float32 = value; + } + + /*! + * \brief Get RO_string register. + * \return value. + */ + std::string getRO_string() const + { + size_t len = (size_t)structData_.RO_string[1]; + return std::string((char*)&(structData_.RO_string[2]), len); + } + + /*! + * \brief Set RO_string register. + * \param value to be set. + */ + void setRO_string(const std::string &value) + { + size_t len = (value.length() < RO_stringLen_) ? value.length() : RO_stringLen_; + memcpy((char*)&(structData_.RO_string[2]), value.c_str(), len); + structData_.RO_string[0] = char(0); + structData_.RO_string[1] = char(len); + } + + /*! + * \brief Get RO_date register. + * \return value. + */ + double getRO_date() const + { + return structData_.RO_date; + } + + /*! + * \brief Set RO_date register. + * \param value to be set. + */ + void setRO_date(double value) + { + structData_.RO_date = value; + } + + /*! + * \brief Get RO_char register. + * \return value. + */ + int8_t getRO_char() const + { + return structData_.RO_char; + } + + /*! + * \brief Set RO_char register. + * \param value to be set. + */ + void setRO_char(int8_t value) + { + structData_.RO_char = value; + } + + /*! + * \brief Get RO_byte register. + * \return value. + */ + uint8_t getRO_byte() const + { + return structData_.RO_byte; + } + + /*! + * \brief Set RO_byte register. + * \param value to be set. + */ + void setRO_byte(uint8_t value) + { + structData_.RO_byte = value; + } + + /*! + * \brief Get RO_word register. + * \return value. + */ + uint16_t getRO_word() const + { + return structData_.RO_word; + } + + /*! + * \brief Set RO_word register. + * \param value to be set. + */ + void setRO_word(uint16_t value) + { + structData_.RO_word = value; + } + + /*! + * \brief Get RO_dword register. + * \return value. + */ + uint32_t getRO_dword() const + { + return structData_.RO_dword; + } + + /*! + * \brief Set RO_dword register. + * \param value to be set. + */ + void setRO_dword(uint32_t value) + { + structData_.RO_dword = value; + } + + /*! + * \brief Get RO_int register. + * \return value. + */ + int16_t getRO_int() const + { + return structData_.RO_int; + } + + /*! + * \brief Set RO_int register. + * \param value to be set. + */ + void setRO_int(int16_t value) + { + structData_.RO_int = value; + } + + /*! + * \brief Get RO_dint register. + * \return value. + */ + int32_t getRO_dint() const + { + return structData_.RO_dint; + } + + /*! + * \brief Set RO_dint register. + * \param value to be set. + */ + void setRO_dint(int32_t value) + { + structData_.RO_dint = value; + } + + /*! + * \brief Get RO_real register. + * \return value. + */ + float getRO_real() const + { + return structData_.RO_real; + } + + /*! + * \brief Set RO_real register. + * \param value to be set. + */ + void setRO_real(float value) + { + structData_.RO_real = value; + } + + /*! + * \brief Get RO_dt register. + * \return value. + */ + double getRO_dt() const + { + return structData_.RO_dt; + } + + /*! + * \brief Set RO_dt register. + * \param value to be set. + */ + void setRO_dt(double value) + { + structData_.RO_dt = value; + } + + virtual inline size_t getSize() const + { + return sizeof(structData_); + } + + virtual void getData(unsigned char * data) const + { + memcpy(data, &structData_, this->getSize()); + } + + virtual void setData(unsigned char * data) + { + memcpy(&structData_, data, this->getSize()); + } + + virtual inline size_t getOffset() const { return 0; } + + static const std::size_t RO_stringLen_ = 64; + +private: + +#pragma pack(push, 1) + struct + { + int8_t RO_int8; + uint8_t RO_uint8; + int16_t RO_int16; + uint16_t RO_uint16; + int32_t RO_int32; + uint32_t RO_uint32; + float RO_float32; + char RO_string[RO_stringLen_+2]; + double RO_date; + int8_t RO_char; + uint8_t RO_byte; + uint16_t RO_word; + uint32_t RO_dword; + int16_t RO_int; + int32_t RO_dint; + float RO_real; + double RO_dt; + + } structData_; +#pragma pack(pop) + +}; + +class MyRWBlock : public SilecsServer::Block +{ +public: + /*! + * \brief MyRWBlock constructor. It creates an empty block. + */ + MyRWBlock() : SilecsServer::Block("AllTypes:MyRWBlock") + { + + } + + ~MyRWBlock() + { + } + + /*! + * \brief Get array RW_int8 register. + * \return value. + */ + void getRW_int8(int8_t* value) const + { + memcpy(value, &structData_.RW_int8, RW_int8Dim1_ * RW_int8Dim2_ * sizeof(int8_t)); + } + + /*! + * \brief Set array RW_int8 register. + * \param value to be set. + */ + void setRW_int8(int8_t* value) + { + memcpy(&structData_.RW_int8, value, RW_int8Dim1_ * RW_int8Dim2_ * sizeof(int8_t)); + } + + /*! + * \brief Get array RW_uint8 register. + * \return value. + */ + void getRW_uint8(uint8_t* value) const + { + memcpy(value, &structData_.RW_uint8, RW_uint8Dim1_ * RW_uint8Dim2_ * sizeof(uint8_t)); + } + + /*! + * \brief Set array RW_uint8 register. + * \param value to be set. + */ + void setRW_uint8(uint8_t* value) + { + memcpy(&structData_.RW_uint8, value, RW_uint8Dim1_ * RW_uint8Dim2_ * sizeof(uint8_t)); + } + + /*! + * \brief Get array RW_int16 register. + * \return value. + */ + void getRW_int16(int16_t* value) const + { + memcpy(value, &structData_.RW_int16, RW_int16Dim1_ * RW_int16Dim2_ * sizeof(int16_t)); + } + + /*! + * \brief Set array RW_int16 register. + * \param value to be set. + */ + void setRW_int16(int16_t* value) + { + memcpy(&structData_.RW_int16, value, RW_int16Dim1_ * RW_int16Dim2_ * sizeof(int16_t)); + } + + /*! + * \brief Get array RW_uint16 register. + * \return value. + */ + void getRW_uint16(uint16_t* value) const + { + memcpy(value, &structData_.RW_uint16, RW_uint16Dim1_ * RW_uint16Dim2_ * sizeof(uint16_t)); + } + + /*! + * \brief Set array RW_uint16 register. + * \param value to be set. + */ + void setRW_uint16(uint16_t* value) + { + memcpy(&structData_.RW_uint16, value, RW_uint16Dim1_ * RW_uint16Dim2_ * sizeof(uint16_t)); + } + + /*! + * \brief Get array RW_int32 register. + * \return value. + */ + void getRW_int32(int32_t* value) const + { + memcpy(value, &structData_.RW_int32, RW_int32Dim1_ * RW_int32Dim2_ * sizeof(int32_t)); + } + + /*! + * \brief Set array RW_int32 register. + * \param value to be set. + */ + void setRW_int32(int32_t* value) + { + memcpy(&structData_.RW_int32, value, RW_int32Dim1_ * RW_int32Dim2_ * sizeof(int32_t)); + } + + /*! + * \brief Get array RW_uint32 register. + * \return value. + */ + void getRW_uint32(uint32_t* value) const + { + memcpy(value, &structData_.RW_uint32, RW_uint32Dim1_ * RW_uint32Dim2_ * sizeof(uint32_t)); + } + + /*! + * \brief Set array RW_uint32 register. + * \param value to be set. + */ + void setRW_uint32(uint32_t* value) + { + memcpy(&structData_.RW_uint32, value, RW_uint32Dim1_ * RW_uint32Dim2_ * sizeof(uint32_t)); + } + + /*! + * \brief Get array RW_float32 register. + * \return value. + */ + void getRW_float32(float* value) const + { + memcpy(value, &structData_.RW_float32, RW_float32Dim1_ * RW_float32Dim2_ * sizeof(float)); + } + + /*! + * \brief Set array RW_float32 register. + * \param value to be set. + */ + void setRW_float32(float* value) + { + memcpy(&structData_.RW_float32, value, RW_float32Dim1_ * RW_float32Dim2_ * sizeof(float)); + } + + /*! + * \brief Get std::string RW_string register. + * \param value buffer where the value will be stored. + */ + void getRW_string(std::string* value) const + { + for (std::size_t i = 0; i < RW_stringDim1_; i++) + { + size_t len = (size_t)structData_.RW_string[i][1]; + value[i].assign(&(structData_.RW_string[i][2]), len); + } + } + + /*! + * \brief Set std::string RW_string register. + * \param value to be set. + */ + void setRW_string(std::string* value) + { + for (std::size_t i = 0; i < RW_stringDim1_; i++) + { + size_t len = (value[i].length() < RW_stringLen_) ? value[i].length() : RW_stringLen_; + memcpy(&(structData_.RW_string[i][2]), value[i].c_str(), len); + structData_.RW_string[i][0] = char(0); + structData_.RW_string[i][1] = char(len); + } + } + + /*! + * \brief Get array RW_date register. + * \return value. + */ + void getRW_date(double* value) const + { + memcpy(value, &structData_.RW_date, RW_dateDim1_ * RW_dateDim2_ * sizeof(double)); + } + + /*! + * \brief Set array RW_date register. + * \param value to be set. + */ + void setRW_date(double* value) + { + memcpy(&structData_.RW_date, value, RW_dateDim1_ * RW_dateDim2_ * sizeof(double)); + } + + /*! + * \brief Get array RW_char register. + * \return value. + */ + void getRW_char(int8_t* value) const + { + memcpy(value, &structData_.RW_char, RW_charDim1_ * RW_charDim2_ * sizeof(int8_t)); + } + + /*! + * \brief Set array RW_char register. + * \param value to be set. + */ + void setRW_char(int8_t* value) + { + memcpy(&structData_.RW_char, value, RW_charDim1_ * RW_charDim2_ * sizeof(int8_t)); + } + + /*! + * \brief Get array RW_byte register. + * \return value. + */ + void getRW_byte(uint8_t* value) const + { + memcpy(value, &structData_.RW_byte, RW_byteDim1_ * RW_byteDim2_ * sizeof(uint8_t)); + } + + /*! + * \brief Set array RW_byte register. + * \param value to be set. + */ + void setRW_byte(uint8_t* value) + { + memcpy(&structData_.RW_byte, value, RW_byteDim1_ * RW_byteDim2_ * sizeof(uint8_t)); + } + + /*! + * \brief Get array RW_word register. + * \return value. + */ + void getRW_word(uint16_t* value) const + { + memcpy(value, &structData_.RW_word, RW_wordDim1_ * RW_wordDim2_ * sizeof(uint16_t)); + } + + /*! + * \brief Set array RW_word register. + * \param value to be set. + */ + void setRW_word(uint16_t* value) + { + memcpy(&structData_.RW_word, value, RW_wordDim1_ * RW_wordDim2_ * sizeof(uint16_t)); + } + + /*! + * \brief Get array RW_dword register. + * \return value. + */ + void getRW_dword(uint32_t* value) const + { + memcpy(value, &structData_.RW_dword, RW_dwordDim1_ * RW_dwordDim2_ * sizeof(uint32_t)); + } + + /*! + * \brief Set array RW_dword register. + * \param value to be set. + */ + void setRW_dword(uint32_t* value) + { + memcpy(&structData_.RW_dword, value, RW_dwordDim1_ * RW_dwordDim2_ * sizeof(uint32_t)); + } + + /*! + * \brief Get array RW_int register. + * \return value. + */ + void getRW_int(int16_t* value) const + { + memcpy(value, &structData_.RW_int, RW_intDim1_ * RW_intDim2_ * sizeof(int16_t)); + } + + /*! + * \brief Set array RW_int register. + * \param value to be set. + */ + void setRW_int(int16_t* value) + { + memcpy(&structData_.RW_int, value, RW_intDim1_ * RW_intDim2_ * sizeof(int16_t)); + } + + /*! + * \brief Get array RW_dint register. + * \return value. + */ + void getRW_dint(int32_t* value) const + { + memcpy(value, &structData_.RW_dint, RW_dintDim1_ * RW_dintDim2_ * sizeof(int32_t)); + } + + /*! + * \brief Set array RW_dint register. + * \param value to be set. + */ + void setRW_dint(int32_t* value) + { + memcpy(&structData_.RW_dint, value, RW_dintDim1_ * RW_dintDim2_ * sizeof(int32_t)); + } + + /*! + * \brief Get array RW_real register. + * \return value. + */ + void getRW_real(float* value) const + { + memcpy(value, &structData_.RW_real, RW_realDim1_ * RW_realDim2_ * sizeof(float)); + } + + /*! + * \brief Set array RW_real register. + * \param value to be set. + */ + void setRW_real(float* value) + { + memcpy(&structData_.RW_real, value, RW_realDim1_ * RW_realDim2_ * sizeof(float)); + } + + /*! + * \brief Get array RW_dt register. + * \return value. + */ + void getRW_dt(double* value) const + { + memcpy(value, &structData_.RW_dt, RW_dtDim1_ * RW_dtDim2_ * sizeof(double)); + } + + /*! + * \brief Set array RW_dt register. + * \param value to be set. + */ + void setRW_dt(double* value) + { + memcpy(&structData_.RW_dt, value, RW_dtDim1_ * RW_dtDim2_ * sizeof(double)); + } + + virtual inline size_t getSize() const + { + return sizeof(structData_); + } + + virtual void getData(unsigned char * data) const + { + memcpy(data, &structData_, this->getSize()); + } + + virtual void setData(unsigned char * data) + { + memcpy(&structData_, data, this->getSize()); + } + + virtual inline size_t getOffset() const { return 118; } + + static const std::size_t RW_int8Dim1_ = 2; + static const std::size_t RW_int8Dim2_ = 2; + static const std::size_t RW_uint8Dim1_ = 2; + static const std::size_t RW_uint8Dim2_ = 2; + static const std::size_t RW_int16Dim1_ = 2; + static const std::size_t RW_int16Dim2_ = 2; + static const std::size_t RW_uint16Dim1_ = 2; + static const std::size_t RW_uint16Dim2_ = 2; + static const std::size_t RW_int32Dim1_ = 2; + static const std::size_t RW_int32Dim2_ = 2; + static const std::size_t RW_uint32Dim1_ = 2; + static const std::size_t RW_uint32Dim2_ = 2; + static const std::size_t RW_float32Dim1_ = 2; + static const std::size_t RW_float32Dim2_ = 2; + static const std::size_t RW_stringDim1_ = 2; + static const std::size_t RW_stringDim2_ = 2; + static const std::size_t RW_stringLen_ = 64; + static const std::size_t RW_dateDim1_ = 2; + static const std::size_t RW_dateDim2_ = 2; + static const std::size_t RW_charDim1_ = 2; + static const std::size_t RW_charDim2_ = 2; + static const std::size_t RW_byteDim1_ = 2; + static const std::size_t RW_byteDim2_ = 2; + static const std::size_t RW_wordDim1_ = 2; + static const std::size_t RW_wordDim2_ = 2; + static const std::size_t RW_dwordDim1_ = 2; + static const std::size_t RW_dwordDim2_ = 2; + static const std::size_t RW_intDim1_ = 2; + static const std::size_t RW_intDim2_ = 2; + static const std::size_t RW_dintDim1_ = 2; + static const std::size_t RW_dintDim2_ = 2; + static const std::size_t RW_realDim1_ = 2; + static const std::size_t RW_realDim2_ = 2; + static const std::size_t RW_dtDim1_ = 2; + static const std::size_t RW_dtDim2_ = 2; + +private: + +#pragma pack(push, 1) + struct + { + int8_t RW_int8[RW_int8Dim1_][RW_int8Dim2_]; + uint8_t RW_uint8[RW_uint8Dim1_][RW_uint8Dim2_]; + int16_t RW_int16[RW_int16Dim1_][RW_int16Dim2_]; + uint16_t RW_uint16[RW_uint16Dim1_][RW_uint16Dim2_]; + int32_t RW_int32[RW_int32Dim1_][RW_int32Dim2_]; + uint32_t RW_uint32[RW_uint32Dim1_][RW_uint32Dim2_]; + float RW_float32[RW_float32Dim1_][RW_float32Dim2_]; + char RW_string[RW_stringDim1_][RW_stringDim2_][RW_stringLen_+2]; + double RW_date[RW_dateDim1_][RW_dateDim2_]; + int8_t RW_char[RW_charDim1_][RW_charDim2_]; + uint8_t RW_byte[RW_byteDim1_][RW_byteDim2_]; + uint16_t RW_word[RW_wordDim1_][RW_wordDim2_]; + uint32_t RW_dword[RW_dwordDim1_][RW_dwordDim2_]; + int16_t RW_int[RW_intDim1_][RW_intDim2_]; + int32_t RW_dint[RW_dintDim1_][RW_dintDim2_]; + float RW_real[RW_realDim1_][RW_realDim2_]; + double RW_dt[RW_dtDim1_][RW_dtDim2_]; + + } structData_; +#pragma pack(pop) + +}; + +class MyWOBlock : public SilecsServer::Block +{ +public: + /*! + * \brief MyWOBlock constructor. It creates an empty block. + */ + MyWOBlock() : SilecsServer::Block("AllTypes:MyWOBlock") + { + + } + + ~MyWOBlock() + { + } + + /*! + * \brief Get array WO_int8 register. + * \return value. + */ + void getWO_int8(int8_t* value) const + { + memcpy(value, &structData_.WO_int8, WO_int8Dim1_ * WO_int8Dim2_ * sizeof(int8_t)); + } + + /*! + * \brief Set array WO_int8 register. + * \param value to be set. + */ + void setWO_int8(int8_t* value) + { + memcpy(&structData_.WO_int8, value, WO_int8Dim1_ * WO_int8Dim2_ * sizeof(int8_t)); + } + + /*! + * \brief Get array WO_uint8 register. + * \return value. + */ + void getWO_uint8(uint8_t* value) const + { + memcpy(value, &structData_.WO_uint8, WO_uint8Dim1_ * WO_uint8Dim2_ * sizeof(uint8_t)); + } + + /*! + * \brief Set array WO_uint8 register. + * \param value to be set. + */ + void setWO_uint8(uint8_t* value) + { + memcpy(&structData_.WO_uint8, value, WO_uint8Dim1_ * WO_uint8Dim2_ * sizeof(uint8_t)); + } + + /*! + * \brief Get array WO_int16 register. + * \return value. + */ + void getWO_int16(int16_t* value) const + { + memcpy(value, &structData_.WO_int16, WO_int16Dim1_ * WO_int16Dim2_ * sizeof(int16_t)); + } + + /*! + * \brief Set array WO_int16 register. + * \param value to be set. + */ + void setWO_int16(int16_t* value) + { + memcpy(&structData_.WO_int16, value, WO_int16Dim1_ * WO_int16Dim2_ * sizeof(int16_t)); + } + + /*! + * \brief Get array WO_uint16 register. + * \return value. + */ + void getWO_uint16(uint16_t* value) const + { + memcpy(value, &structData_.WO_uint16, WO_uint16Dim1_ * WO_uint16Dim2_ * sizeof(uint16_t)); + } + + /*! + * \brief Set array WO_uint16 register. + * \param value to be set. + */ + void setWO_uint16(uint16_t* value) + { + memcpy(&structData_.WO_uint16, value, WO_uint16Dim1_ * WO_uint16Dim2_ * sizeof(uint16_t)); + } + + /*! + * \brief Get array WO_int32 register. + * \return value. + */ + void getWO_int32(int32_t* value) const + { + memcpy(value, &structData_.WO_int32, WO_int32Dim1_ * WO_int32Dim2_ * sizeof(int32_t)); + } + + /*! + * \brief Set array WO_int32 register. + * \param value to be set. + */ + void setWO_int32(int32_t* value) + { + memcpy(&structData_.WO_int32, value, WO_int32Dim1_ * WO_int32Dim2_ * sizeof(int32_t)); + } + + /*! + * \brief Get array WO_uint32 register. + * \return value. + */ + void getWO_uint32(uint32_t* value) const + { + memcpy(value, &structData_.WO_uint32, WO_uint32Dim1_ * WO_uint32Dim2_ * sizeof(uint32_t)); + } + + /*! + * \brief Set array WO_uint32 register. + * \param value to be set. + */ + void setWO_uint32(uint32_t* value) + { + memcpy(&structData_.WO_uint32, value, WO_uint32Dim1_ * WO_uint32Dim2_ * sizeof(uint32_t)); + } + + /*! + * \brief Get array WO_float32 register. + * \return value. + */ + void getWO_float32(float* value) const + { + memcpy(value, &structData_.WO_float32, WO_float32Dim1_ * WO_float32Dim2_ * sizeof(float)); + } + + /*! + * \brief Set array WO_float32 register. + * \param value to be set. + */ + void setWO_float32(float* value) + { + memcpy(&structData_.WO_float32, value, WO_float32Dim1_ * WO_float32Dim2_ * sizeof(float)); + } + + /*! + * \brief Get std::string WO_string register. + * \param value buffer where the value will be stored. + */ + void getWO_string(std::string* value) const + { + for (std::size_t i = 0; i < WO_stringDim1_; i++) + { + size_t len = (size_t)structData_.WO_string[i][1]; + value[i].assign(&(structData_.WO_string[i][2]), len); + } + } + + /*! + * \brief Set std::string WO_string register. + * \param value to be set. + */ + void setWO_string(std::string* value) + { + for (std::size_t i = 0; i < WO_stringDim1_; i++) + { + size_t len = (value[i].length() < WO_stringLen_) ? value[i].length() : WO_stringLen_; + memcpy(&(structData_.WO_string[i][2]), value[i].c_str(), len); + structData_.WO_string[i][0] = char(0); + structData_.WO_string[i][1] = char(len); + } + } + + /*! + * \brief Get array WO_date register. + * \return value. + */ + void getWO_date(double* value) const + { + memcpy(value, &structData_.WO_date, WO_dateDim1_ * WO_dateDim2_ * sizeof(double)); + } + + /*! + * \brief Set array WO_date register. + * \param value to be set. + */ + void setWO_date(double* value) + { + memcpy(&structData_.WO_date, value, WO_dateDim1_ * WO_dateDim2_ * sizeof(double)); + } + + /*! + * \brief Get array WO_char register. + * \return value. + */ + void getWO_char(int8_t* value) const + { + memcpy(value, &structData_.WO_char, WO_charDim1_ * WO_charDim2_ * sizeof(int8_t)); + } + + /*! + * \brief Set array WO_char register. + * \param value to be set. + */ + void setWO_char(int8_t* value) + { + memcpy(&structData_.WO_char, value, WO_charDim1_ * WO_charDim2_ * sizeof(int8_t)); + } + + /*! + * \brief Get array WO_byte register. + * \return value. + */ + void getWO_byte(uint8_t* value) const + { + memcpy(value, &structData_.WO_byte, WO_byteDim1_ * WO_byteDim2_ * sizeof(uint8_t)); + } + + /*! + * \brief Set array WO_byte register. + * \param value to be set. + */ + void setWO_byte(uint8_t* value) + { + memcpy(&structData_.WO_byte, value, WO_byteDim1_ * WO_byteDim2_ * sizeof(uint8_t)); + } + + /*! + * \brief Get array WO_word register. + * \return value. + */ + void getWO_word(uint16_t* value) const + { + memcpy(value, &structData_.WO_word, WO_wordDim1_ * WO_wordDim2_ * sizeof(uint16_t)); + } + + /*! + * \brief Set array WO_word register. + * \param value to be set. + */ + void setWO_word(uint16_t* value) + { + memcpy(&structData_.WO_word, value, WO_wordDim1_ * WO_wordDim2_ * sizeof(uint16_t)); + } + + /*! + * \brief Get array WO_dword register. + * \return value. + */ + void getWO_dword(uint32_t* value) const + { + memcpy(value, &structData_.WO_dword, WO_dwordDim1_ * WO_dwordDim2_ * sizeof(uint32_t)); + } + + /*! + * \brief Set array WO_dword register. + * \param value to be set. + */ + void setWO_dword(uint32_t* value) + { + memcpy(&structData_.WO_dword, value, WO_dwordDim1_ * WO_dwordDim2_ * sizeof(uint32_t)); + } + + /*! + * \brief Get array WO_int register. + * \return value. + */ + void getWO_int(int16_t* value) const + { + memcpy(value, &structData_.WO_int, WO_intDim1_ * WO_intDim2_ * sizeof(int16_t)); + } + + /*! + * \brief Set array WO_int register. + * \param value to be set. + */ + void setWO_int(int16_t* value) + { + memcpy(&structData_.WO_int, value, WO_intDim1_ * WO_intDim2_ * sizeof(int16_t)); + } + + /*! + * \brief Get array WO_dint register. + * \return value. + */ + void getWO_dint(int32_t* value) const + { + memcpy(value, &structData_.WO_dint, WO_dintDim1_ * WO_dintDim2_ * sizeof(int32_t)); + } + + /*! + * \brief Set array WO_dint register. + * \param value to be set. + */ + void setWO_dint(int32_t* value) + { + memcpy(&structData_.WO_dint, value, WO_dintDim1_ * WO_dintDim2_ * sizeof(int32_t)); + } + + /*! + * \brief Get array WO_real register. + * \return value. + */ + void getWO_real(float* value) const + { + memcpy(value, &structData_.WO_real, WO_realDim1_ * WO_realDim2_ * sizeof(float)); + } + + /*! + * \brief Set array WO_real register. + * \param value to be set. + */ + void setWO_real(float* value) + { + memcpy(&structData_.WO_real, value, WO_realDim1_ * WO_realDim2_ * sizeof(float)); + } + + /*! + * \brief Get array WO_dt register. + * \return value. + */ + void getWO_dt(double* value) const + { + memcpy(value, &structData_.WO_dt, WO_dtDim1_ * WO_dtDim2_ * sizeof(double)); + } + + /*! + * \brief Set array WO_dt register. + * \param value to be set. + */ + void setWO_dt(double* value) + { + memcpy(&structData_.WO_dt, value, WO_dtDim1_ * WO_dtDim2_ * sizeof(double)); + } + + virtual inline size_t getSize() const + { + return sizeof(structData_); + } + + virtual void getData(unsigned char * data) const + { + memcpy(data, &structData_, this->getSize()); + } + + virtual void setData(unsigned char * data) + { + memcpy(&structData_, data, this->getSize()); + } + + virtual inline size_t getOffset() const { return 590; } + + static const std::size_t WO_int8Dim1_ = 10; + static const std::size_t WO_int8Dim2_ = 1; + static const std::size_t WO_uint8Dim1_ = 10; + static const std::size_t WO_uint8Dim2_ = 1; + static const std::size_t WO_int16Dim1_ = 10; + static const std::size_t WO_int16Dim2_ = 1; + static const std::size_t WO_uint16Dim1_ = 10; + static const std::size_t WO_uint16Dim2_ = 1; + static const std::size_t WO_int32Dim1_ = 10; + static const std::size_t WO_int32Dim2_ = 1; + static const std::size_t WO_uint32Dim1_ = 10; + static const std::size_t WO_uint32Dim2_ = 1; + static const std::size_t WO_float32Dim1_ = 10; + static const std::size_t WO_float32Dim2_ = 1; + static const std::size_t WO_stringDim1_ = 10; + static const std::size_t WO_stringDim2_ = 1; + static const std::size_t WO_stringLen_ = 64; + static const std::size_t WO_dateDim1_ = 10; + static const std::size_t WO_dateDim2_ = 1; + static const std::size_t WO_charDim1_ = 10; + static const std::size_t WO_charDim2_ = 1; + static const std::size_t WO_byteDim1_ = 10; + static const std::size_t WO_byteDim2_ = 1; + static const std::size_t WO_wordDim1_ = 10; + static const std::size_t WO_wordDim2_ = 1; + static const std::size_t WO_dwordDim1_ = 10; + static const std::size_t WO_dwordDim2_ = 1; + static const std::size_t WO_intDim1_ = 10; + static const std::size_t WO_intDim2_ = 1; + static const std::size_t WO_dintDim1_ = 10; + static const std::size_t WO_dintDim2_ = 1; + static const std::size_t WO_realDim1_ = 10; + static const std::size_t WO_realDim2_ = 1; + static const std::size_t WO_dtDim1_ = 10; + static const std::size_t WO_dtDim2_ = 1; + +private: + +#pragma pack(push, 1) + struct + { + int8_t WO_int8[WO_int8Dim1_]; + uint8_t WO_uint8[WO_uint8Dim1_]; + int16_t WO_int16[WO_int16Dim1_]; + uint16_t WO_uint16[WO_uint16Dim1_]; + int32_t WO_int32[WO_int32Dim1_]; + uint32_t WO_uint32[WO_uint32Dim1_]; + float WO_float32[WO_float32Dim1_]; + char WO_string[WO_stringDim1_][WO_stringLen_+2]; + double WO_date[WO_dateDim1_]; + int8_t WO_char[WO_charDim1_]; + uint8_t WO_byte[WO_byteDim1_]; + uint16_t WO_word[WO_wordDim1_]; + uint32_t WO_dword[WO_dwordDim1_]; + int16_t WO_int[WO_intDim1_]; + int32_t WO_dint[WO_dintDim1_]; + float WO_real[WO_realDim1_]; + double WO_dt[WO_dtDim1_]; + + } structData_; +#pragma pack(pop) + +}; + + + +class Device : public SilecsServer::Device +{ +public: + Device(const std::string& label, size_t number):SilecsServer::Device(label, number) + { + blockMap_["AllTypes:MyROBlock"] = new MyROBlock(); + blockMap_["AllTypes:MyRWBlock"] = new MyRWBlock(); + blockMap_["AllTypes:MyWOBlock"] = new MyWOBlock(); + } + + ~Device() + { + delete (blockMap_["AllTypes:MyROBlock"]); + delete (blockMap_["AllTypes:MyRWBlock"]); + delete (blockMap_["AllTypes:MyWOBlock"]); + } +}; + + +class Design : public SilecsServer::Design +{ +public: + + Design():SilecsServer::Design("AllTypes", "0.1.0") + { + deviceMap_["AllTypes:testDevice1"] = new Device("AllTypes:testDevice1", 0); + deviceMap_["AllTypes:testDevice2"] = new Device("AllTypes:testDevice2", 1); + } + + ~Design() + { + delete(deviceMap_["AllTypes:testDevice1"]); + delete(deviceMap_["AllTypes:testDevice2"]); + } + + /*! + * \brief Return pointer to the requested device. + * \param label Device label. + */ + AllTypes_0_1_0::Device* getDevice(const std::string& label) + { + if (deviceMap_.find(label) != deviceMap_.end()) + { + return dynamic_cast<AllTypes_0_1_0::Device*>(deviceMap_[label]); + } + return NULL; + } +}; + +} /* namespace */ +#endif diff --git a/silecs-codegen/src/xml/test/generated_temp/controller/Virtual_SiemensDevice.SilecsHeader.h b/silecs-codegen/src/xml/test/generated_temp/controller/Virtual_SiemensDevice.SilecsHeader.h new file mode 100644 index 0000000..85ecca6 --- /dev/null +++ b/silecs-codegen/src/xml/test/generated_temp/controller/Virtual_SiemensDevice.SilecsHeader.h @@ -0,0 +1,203 @@ + +/* Copyright CERN 2015 + * + * WARNING: This code is automatically generated from your SILECS deploy unit document. + * You should never modify the content of this file as it would break consistency. + * Furthermore, any changes will be overwritten in the next code generation. + * Any modification shall be done using the SILECS development environment + * and regenerating this source code. + */ + +#ifndef SILECSHEADER_1_0_0_H_ +#define SILECSHEADER_1_0_0_H_ + +#include <silecs-virtual-controller/interface/Block.h> +#include <silecs-virtual-controller/interface/DeployUnit.h> +#include <silecs-virtual-controller/interface/Design.h> +#include <silecs-virtual-controller/interface/Device.h> + +namespace SilecsHeader_1_0_0 +{ + +class Design; + +class HdrBlk : public SilecsServer::Block +{ +public: + /*! + * \brief hdrBlk constructor. It creates an empty block. + */ + HdrBlk() : SilecsServer::Block("SilecsHeader:hdrBlk") + { + set_version("DEV"); + set_checksum(0X2110E2EA); + set_user("schwinn"); + set_date(0.0); + } + + ~HdrBlk() + { + } + + /*! + * \brief Get _version register. + * \return value. + */ + std::string get_version() const + { + size_t len = (size_t)structData_._version[1]; + return std::string((char*)&(structData_._version[2]), len); + } + + /*! + * \brief Set _version register. + * \param value to be set. + */ + void set_version(const std::string &value) + { + size_t len = (value.length() < _versionLen_) ? value.length() : _versionLen_; + memcpy((char*)&(structData_._version[2]), value.c_str(), len); + structData_._version[0] = char(0); + structData_._version[1] = char(len); + } + + /*! + * \brief Get _checksum register. + * \return value. + */ + uint32_t get_checksum() const + { + return structData_._checksum; + } + + /*! + * \brief Set _checksum register. + * \param value to be set. + */ + void set_checksum(uint32_t value) + { + structData_._checksum = value; + } + + /*! + * \brief Get _user register. + * \return value. + */ + std::string get_user() const + { + size_t len = (size_t)structData_._user[1]; + return std::string((char*)&(structData_._user[2]), len); + } + + /*! + * \brief Set _user register. + * \param value to be set. + */ + void set_user(const std::string &value) + { + size_t len = (value.length() < _userLen_) ? value.length() : _userLen_; + memcpy((char*)&(structData_._user[2]), value.c_str(), len); + structData_._user[0] = char(0); + structData_._user[1] = char(len); + } + + /*! + * \brief Get _date register. + * \return value. + */ + double get_date() const + { + return structData_._date; + } + + /*! + * \brief Set _date register. + * \param value to be set. + */ + void set_date(double value) + { + structData_._date = value; + } + + virtual inline size_t getSize() const + { + return sizeof(structData_); + } + + virtual void getData(unsigned char * data) const + { + memcpy(data, &structData_, this->getSize()); + } + + virtual void setData(unsigned char * data) + { + memcpy(&structData_, data, this->getSize()); + } + + virtual inline size_t getOffset() const { return 0; } + + static const std::size_t _versionLen_ = 16; + static const std::size_t _userLen_ = 16; + +private: + +#pragma pack(push, 1) + struct + { + char _version[_versionLen_+2]; + uint32_t _checksum; + char _user[_userLen_+2]; + double _date; + + } structData_; +#pragma pack(pop) + +}; + + + +class Device : public SilecsServer::Device +{ +public: + Device(const std::string& label, size_t number):SilecsServer::Device(label, number) + { + blockMap_["SilecsHeader:hdrBlk"] = new HdrBlk(); + } + + ~Device() + { + delete (blockMap_["SilecsHeader:hdrBlk"]); + } +}; + + +class Design : public SilecsServer::Design +{ +public: + + Design():SilecsServer::Design("SilecsHeader", "1.0.0") + { + deviceMap_["SilecsHeader:SilecsHeader"] = new Device("SilecsHeader:SilecsHeader", 0); + } + + ~Design() + { + delete(deviceMap_["SilecsHeader:SilecsHeader"]); + } + + /*! + * \brief Return pointer to the requested device. + * \param label Device label. + */ + SilecsHeader_1_0_0::Device* getDevice(const std::string& label) + { + if (deviceMap_.find(label) != deviceMap_.end()) + { + return dynamic_cast<SilecsHeader_1_0_0::Device*>(deviceMap_[label]); + } + return NULL; + } +}; + +} /* namespace */ +#endif diff --git a/silecs-codegen/src/xml/test/generated_temp/controller/Virtual_SiemensDevice.cpp b/silecs-codegen/src/xml/test/generated_temp/controller/Virtual_SiemensDevice.cpp new file mode 100644 index 0000000..43c2286 --- /dev/null +++ b/silecs-codegen/src/xml/test/generated_temp/controller/Virtual_SiemensDevice.cpp @@ -0,0 +1,33 @@ + +#include <stdio.h> +#include <stdlib.h> +#include <cstring> +#include <iostream> + +#include <silecs-virtual-controller/core/SilecsSnap7Server.h> +#include "Virtual_SiemensDevice.h" + +class UserSnap7Server : public SilecsServer::SilecsSnap7Server +{ +public: + UserSnap7Server(Virtual_SiemensDevice::DeployUnit* du) : SilecsSnap7Server(du, true) {} + virtual ~UserSnap7Server() {} + + virtual void userFunction() + { + // Implement the specific process control here! + // Look at SILECS Wikis: 'Create a virtual controller' chapter + } +}; + +int main(int argc, char*argv[]) +{ + Virtual_SiemensDevice::DeployUnit du; + UserSnap7Server server(&du); + if (server.startServer() < 0) + { + std::cout << "Failed to start the VC server: " << du.getName() << std::endl; + return -1; + } + return 0; +} diff --git a/silecs-codegen/src/xml/test/generated_temp/controller/Virtual_SiemensDevice.h b/silecs-codegen/src/xml/test/generated_temp/controller/Virtual_SiemensDevice.h new file mode 100644 index 0000000..1827c94 --- /dev/null +++ b/silecs-codegen/src/xml/test/generated_temp/controller/Virtual_SiemensDevice.h @@ -0,0 +1,53 @@ + +/* Copyright CERN 2015 + * + * WARNING: This code is automatically generated from your SILECS deploy unit document. + * You should never modify the content of this file as it would break consistency. + * Furthermore, any changes will be overwritten in the next code generation. + * Any modification shall be done using the SILECS development environment + * and regenerating this source code. + */ + +#ifndef VIRTUAL_SIEMENSDEVICE_H_ +#define VIRTUAL_SIEMENSDEVICE_H_ + +#include <silecs-virtual-controller/interface/DeployUnit.h> +#include <silecs-virtual-controller/interface/Design.h> +#include "SilecsHeader_1.0.0.h" +#include "AllTypes_0.1.0.h" + + +namespace Virtual_SiemensDevice +{ + +class DeployUnit : public SilecsServer::DeployUnit +{ +public: + + DeployUnit() : SilecsServer::DeployUnit("Virtual_SiemensDevice", SilecsServer::S7Protocol, SilecsServer::DeviceMode, 0) + { + mapDesigns_["SilecsHeader"] = new SilecsHeader_1_0_0::Design(); + mapDesigns_["AllTypes"] = new AllTypes_0_1_0::Design(); + } + + ~DeployUnit() + { + delete mapDesigns_["SilecsHeader"]; + delete mapDesigns_["AllTypes"]; + } + + SilecsHeader_1_0_0::Design* getSilecsHeader() + { + return dynamic_cast<SilecsHeader_1_0_0::Design*>(mapDesigns_["SilecsHeader"]); + } + + AllTypes_0_1_0::Design* getAllTypes() + { + return dynamic_cast<AllTypes_0_1_0::Design*>(mapDesigns_["AllTypes"]); + } + +}; + +} + +#endif diff --git a/silecs-codegen/src/xml/test/generated_temp/wrapper/AllTypes.h b/silecs-codegen/src/xml/test/generated_temp/wrapper/AllTypes.h new file mode 100644 index 0000000..5900b5b --- /dev/null +++ b/silecs-codegen/src/xml/test/generated_temp/wrapper/AllTypes.h @@ -0,0 +1,38 @@ +/* Copyright CERN 2015 + * + * WARNING: This code is automatically generated from your SILECS deploy unit document. + * You should never modify the content of this file as it would break consistency. + * Furthermore, any changes will be overwritten in the next code generation. + * Any modification shall be done using the SILECS development environment + * and regenerating this source code. + */ + +#ifndef ALLTYPES_H_ +#define ALLTYPES_H_ + +#include <silecs-communication/wrapper/Block.h> +#include <silecs-communication/wrapper/DeployUnit.h> +#include <silecs-communication/wrapper/Design.h> +#include <silecs-communication/wrapper/Device.h> + +namespace AllTypes +{ + + +class Design : public SilecsWrapper::Design +{ +public: + + Design(SilecsWrapper::DeployUnit *deployUnit) : + SilecsWrapper::Design("AllTypes", "0.1.0", deployUnit) + { + } + + ~Design() + { + } +}; + +} /* namespace AllTypes */ + +#endif /* ALLTYPES_H_ */ diff --git a/silecs-codegen/src/xml/test/generated_temp/wrapper/Beckhoff_BC9020.h b/silecs-codegen/src/xml/test/generated_temp/wrapper/Beckhoff_BC9020.h new file mode 100644 index 0000000..0434b10 --- /dev/null +++ b/silecs-codegen/src/xml/test/generated_temp/wrapper/Beckhoff_BC9020.h @@ -0,0 +1,153 @@ +/* Copyright CERN 2015 + * + * WARNING: This code is automatically generated from your SILECS deploy unit document. + * You should never modify the content of this file as it would break consistency. + * Furthermore, any changes will be overwritten in the next code generation. + * Any modification shall be done using the SILECS development environment + * and regenerating this source code. + */ + +#ifndef ALLTYPESDU_H_ +#define ALLTYPESDU_H_ + +#include <silecs-communication/interface/equipment/SilecsCluster.h> +#include <silecs-communication/wrapper/DeployUnit.h> +#include <silecs-communication/wrapper/Design.h> + +#include "AllTypes.h" + +namespace AllTypesDU +{ + +typedef SilecsWrapper::DeployConfig DeployConfig; +typedef SilecsWrapper::DesignConfig DesignConfig; + +class DeployUnit : public SilecsWrapper::DeployUnit +{ +public: + + /*! + * \brief Use this method to create/get the unique instance of the Deploy Unit. + * + * \param logTopics This parameter can be used to enable/disable log topics + * valid topics are ERROR[,INFO,DEBUG,SETUP,ALLOC,RECV,SEND,COMM,DATA,LOCK]. + * + * \param globalConfig This parameter can be used to pass different parameters to + * the library. I.e. enabling automatic connection. + */ + static DeployUnit* getInstance(const std::string& logTopics = "", + const SilecsWrapper::DeployConfig& globalConfig = SilecsWrapper::DeployConfig()) + { + if (_instance == NULL) + { + _instance = new DeployUnit(logTopics, globalConfig); + } + else + { + if (logTopics.empty() == false) + { + _instance->getService()->setLogTopics(logTopics); + } + } + return dynamic_cast<DeployUnit*>(_instance); + } + + /*! + * \brief Use this method to create/get the unique instance of the Deploy Unit. + * + * \param globalConfig This parameter can be used to pass different parameters to + * the library. I.e. enabling automatic connection. + */ + static DeployUnit* getInstance(const SilecsWrapper::DeployConfig& globalConfig) + { + return getInstance("", globalConfig); + } + + /*! + * \brief Return pointer to the deployed design AllTypes. + */ + AllTypes::Design* getAllTypes() + { + return _AllTypes; + } + +private: + + AllTypes::Design* _AllTypes; + + DeployUnit(const std::string& logTopics, const SilecsWrapper::DeployConfig& globalConfig) : + SilecsWrapper::DeployUnit("AllTypesDU", "0.1.0", logTopics, globalConfig) + { + // Construct Design AllTypes + _AllTypes = new AllTypes::Design((SilecsWrapper::DeployUnit*) this); + + } + + ~DeployUnit() + { + delete _AllTypes; + } +}; + + +class Controller : public SilecsWrapper::Controller +{ +public: + Controller(SilecsWrapper::Design *design, const std::string parameterFile) : + SilecsWrapper::Controller("Beckhoff_BC9020", "", design, parameterFile) + { + _deviceMap.insert(std::pair<std::string, SilecsWrapper::Device*>("testDevice1", new SilecsWrapper::Device("testDevice1", this))); + _deviceMap.insert(std::pair<std::string, SilecsWrapper::Device*>("testDevice2", new SilecsWrapper::Device("testDevice2", this))); + } + + ~Controller() + { + map<std::string, SilecsWrapper::Device*>::iterator it; + for (it = _deviceMap.begin(); it != _deviceMap.end(); it++) + { + delete it->second; + } + } + + /*! + * \brief Return pointer to the requested device. + * \param label Device label. + */ + SilecsWrapper::Device* getDevice(const std::string& label) + { + if (_deviceMap.find(label) != _deviceMap.end()) + { + return _deviceMap[label]; + } + throw Silecs::SilecsException(__FILE__, __LINE__, Silecs::PARAM_UNKNOWN_DEVICE_NAME, label); + } + + std::map<std::string, SilecsWrapper::Device*>& getDeviceMap() + { + return _deviceMap; + } + + /*! + * \brief Get pointer to device testDevice1. + */ + SilecsWrapper::Device* getTestDevice1() + { + return _deviceMap["testDevice1"]; + } + + /*! + * \brief Get pointer to device testDevice2. + */ + SilecsWrapper::Device* getTestDevice2() + { + return _deviceMap["testDevice2"]; + } + +private: + std::map<std::string, SilecsWrapper::Device*> _deviceMap; +}; + + +} /* namespace AllTypesDU */ + +#endif /* ALLTYPESDU_H_ */ diff --git a/silecs-codegen/src/xml/test/generated_temp/wrapper/Beckhoff_CX9020.h b/silecs-codegen/src/xml/test/generated_temp/wrapper/Beckhoff_CX9020.h new file mode 100644 index 0000000..7feef99 --- /dev/null +++ b/silecs-codegen/src/xml/test/generated_temp/wrapper/Beckhoff_CX9020.h @@ -0,0 +1,153 @@ +/* Copyright CERN 2015 + * + * WARNING: This code is automatically generated from your SILECS deploy unit document. + * You should never modify the content of this file as it would break consistency. + * Furthermore, any changes will be overwritten in the next code generation. + * Any modification shall be done using the SILECS development environment + * and regenerating this source code. + */ + +#ifndef ALLTYPESDU_H_ +#define ALLTYPESDU_H_ + +#include <silecs-communication/interface/equipment/SilecsCluster.h> +#include <silecs-communication/wrapper/DeployUnit.h> +#include <silecs-communication/wrapper/Design.h> + +#include "AllTypes.h" + +namespace AllTypesDU +{ + +typedef SilecsWrapper::DeployConfig DeployConfig; +typedef SilecsWrapper::DesignConfig DesignConfig; + +class DeployUnit : public SilecsWrapper::DeployUnit +{ +public: + + /*! + * \brief Use this method to create/get the unique instance of the Deploy Unit. + * + * \param logTopics This parameter can be used to enable/disable log topics + * valid topics are ERROR[,INFO,DEBUG,SETUP,ALLOC,RECV,SEND,COMM,DATA,LOCK]. + * + * \param globalConfig This parameter can be used to pass different parameters to + * the library. I.e. enabling automatic connection. + */ + static DeployUnit* getInstance(const std::string& logTopics = "", + const SilecsWrapper::DeployConfig& globalConfig = SilecsWrapper::DeployConfig()) + { + if (_instance == NULL) + { + _instance = new DeployUnit(logTopics, globalConfig); + } + else + { + if (logTopics.empty() == false) + { + _instance->getService()->setLogTopics(logTopics); + } + } + return dynamic_cast<DeployUnit*>(_instance); + } + + /*! + * \brief Use this method to create/get the unique instance of the Deploy Unit. + * + * \param globalConfig This parameter can be used to pass different parameters to + * the library. I.e. enabling automatic connection. + */ + static DeployUnit* getInstance(const SilecsWrapper::DeployConfig& globalConfig) + { + return getInstance("", globalConfig); + } + + /*! + * \brief Return pointer to the deployed design AllTypes. + */ + AllTypes::Design* getAllTypes() + { + return _AllTypes; + } + +private: + + AllTypes::Design* _AllTypes; + + DeployUnit(const std::string& logTopics, const SilecsWrapper::DeployConfig& globalConfig) : + SilecsWrapper::DeployUnit("AllTypesDU", "0.1.0", logTopics, globalConfig) + { + // Construct Design AllTypes + _AllTypes = new AllTypes::Design((SilecsWrapper::DeployUnit*) this); + + } + + ~DeployUnit() + { + delete _AllTypes; + } +}; + + +class Controller : public SilecsWrapper::Controller +{ +public: + Controller(SilecsWrapper::Design *design, const std::string parameterFile) : + SilecsWrapper::Controller("Beckhoff_CX9020", "", design, parameterFile) + { + _deviceMap.insert(std::pair<std::string, SilecsWrapper::Device*>("testDevice1", new SilecsWrapper::Device("testDevice1", this))); + _deviceMap.insert(std::pair<std::string, SilecsWrapper::Device*>("testDevice2", new SilecsWrapper::Device("testDevice2", this))); + } + + ~Controller() + { + map<std::string, SilecsWrapper::Device*>::iterator it; + for (it = _deviceMap.begin(); it != _deviceMap.end(); it++) + { + delete it->second; + } + } + + /*! + * \brief Return pointer to the requested device. + * \param label Device label. + */ + SilecsWrapper::Device* getDevice(const std::string& label) + { + if (_deviceMap.find(label) != _deviceMap.end()) + { + return _deviceMap[label]; + } + throw Silecs::SilecsException(__FILE__, __LINE__, Silecs::PARAM_UNKNOWN_DEVICE_NAME, label); + } + + std::map<std::string, SilecsWrapper::Device*>& getDeviceMap() + { + return _deviceMap; + } + + /*! + * \brief Get pointer to device testDevice1. + */ + SilecsWrapper::Device* getTestDevice1() + { + return _deviceMap["testDevice1"]; + } + + /*! + * \brief Get pointer to device testDevice2. + */ + SilecsWrapper::Device* getTestDevice2() + { + return _deviceMap["testDevice2"]; + } + +private: + std::map<std::string, SilecsWrapper::Device*> _deviceMap; +}; + + +} /* namespace AllTypesDU */ + +#endif /* ALLTYPESDU_H_ */ diff --git a/silecs-codegen/src/xml/test/generated_temp/wrapper/Rabbit_BlockMode.h b/silecs-codegen/src/xml/test/generated_temp/wrapper/Rabbit_BlockMode.h new file mode 100644 index 0000000..c562005 --- /dev/null +++ b/silecs-codegen/src/xml/test/generated_temp/wrapper/Rabbit_BlockMode.h @@ -0,0 +1,153 @@ +/* Copyright CERN 2015 + * + * WARNING: This code is automatically generated from your SILECS deploy unit document. + * You should never modify the content of this file as it would break consistency. + * Furthermore, any changes will be overwritten in the next code generation. + * Any modification shall be done using the SILECS development environment + * and regenerating this source code. + */ + +#ifndef ALLTYPESDU_H_ +#define ALLTYPESDU_H_ + +#include <silecs-communication/interface/equipment/SilecsCluster.h> +#include <silecs-communication/wrapper/DeployUnit.h> +#include <silecs-communication/wrapper/Design.h> + +#include "AllTypes.h" + +namespace AllTypesDU +{ + +typedef SilecsWrapper::DeployConfig DeployConfig; +typedef SilecsWrapper::DesignConfig DesignConfig; + +class DeployUnit : public SilecsWrapper::DeployUnit +{ +public: + + /*! + * \brief Use this method to create/get the unique instance of the Deploy Unit. + * + * \param logTopics This parameter can be used to enable/disable log topics + * valid topics are ERROR[,INFO,DEBUG,SETUP,ALLOC,RECV,SEND,COMM,DATA,LOCK]. + * + * \param globalConfig This parameter can be used to pass different parameters to + * the library. I.e. enabling automatic connection. + */ + static DeployUnit* getInstance(const std::string& logTopics = "", + const SilecsWrapper::DeployConfig& globalConfig = SilecsWrapper::DeployConfig()) + { + if (_instance == NULL) + { + _instance = new DeployUnit(logTopics, globalConfig); + } + else + { + if (logTopics.empty() == false) + { + _instance->getService()->setLogTopics(logTopics); + } + } + return dynamic_cast<DeployUnit*>(_instance); + } + + /*! + * \brief Use this method to create/get the unique instance of the Deploy Unit. + * + * \param globalConfig This parameter can be used to pass different parameters to + * the library. I.e. enabling automatic connection. + */ + static DeployUnit* getInstance(const SilecsWrapper::DeployConfig& globalConfig) + { + return getInstance("", globalConfig); + } + + /*! + * \brief Return pointer to the deployed design AllTypes. + */ + AllTypes::Design* getAllTypes() + { + return _AllTypes; + } + +private: + + AllTypes::Design* _AllTypes; + + DeployUnit(const std::string& logTopics, const SilecsWrapper::DeployConfig& globalConfig) : + SilecsWrapper::DeployUnit("AllTypesDU", "0.1.0", logTopics, globalConfig) + { + // Construct Design AllTypes + _AllTypes = new AllTypes::Design((SilecsWrapper::DeployUnit*) this); + + } + + ~DeployUnit() + { + delete _AllTypes; + } +}; + + +class Controller : public SilecsWrapper::Controller +{ +public: + Controller(SilecsWrapper::Design *design, const std::string parameterFile) : + SilecsWrapper::Controller("Rabbit_BlockMode", "", design, parameterFile) + { + _deviceMap.insert(std::pair<std::string, SilecsWrapper::Device*>("testDevice1", new SilecsWrapper::Device("testDevice1", this))); + _deviceMap.insert(std::pair<std::string, SilecsWrapper::Device*>("testDevice2", new SilecsWrapper::Device("testDevice2", this))); + } + + ~Controller() + { + map<std::string, SilecsWrapper::Device*>::iterator it; + for (it = _deviceMap.begin(); it != _deviceMap.end(); it++) + { + delete it->second; + } + } + + /*! + * \brief Return pointer to the requested device. + * \param label Device label. + */ + SilecsWrapper::Device* getDevice(const std::string& label) + { + if (_deviceMap.find(label) != _deviceMap.end()) + { + return _deviceMap[label]; + } + throw Silecs::SilecsException(__FILE__, __LINE__, Silecs::PARAM_UNKNOWN_DEVICE_NAME, label); + } + + std::map<std::string, SilecsWrapper::Device*>& getDeviceMap() + { + return _deviceMap; + } + + /*! + * \brief Get pointer to device testDevice1. + */ + SilecsWrapper::Device* getTestDevice1() + { + return _deviceMap["testDevice1"]; + } + + /*! + * \brief Get pointer to device testDevice2. + */ + SilecsWrapper::Device* getTestDevice2() + { + return _deviceMap["testDevice2"]; + } + +private: + std::map<std::string, SilecsWrapper::Device*> _deviceMap; +}; + + +} /* namespace AllTypesDU */ + +#endif /* ALLTYPESDU_H_ */ diff --git a/silecs-codegen/src/xml/test/generated_temp/wrapper/Rabbit_DeviceMode.h b/silecs-codegen/src/xml/test/generated_temp/wrapper/Rabbit_DeviceMode.h new file mode 100644 index 0000000..a90d775 --- /dev/null +++ b/silecs-codegen/src/xml/test/generated_temp/wrapper/Rabbit_DeviceMode.h @@ -0,0 +1,153 @@ +/* Copyright CERN 2015 + * + * WARNING: This code is automatically generated from your SILECS deploy unit document. + * You should never modify the content of this file as it would break consistency. + * Furthermore, any changes will be overwritten in the next code generation. + * Any modification shall be done using the SILECS development environment + * and regenerating this source code. + */ + +#ifndef ALLTYPESDU_H_ +#define ALLTYPESDU_H_ + +#include <silecs-communication/interface/equipment/SilecsCluster.h> +#include <silecs-communication/wrapper/DeployUnit.h> +#include <silecs-communication/wrapper/Design.h> + +#include "AllTypes.h" + +namespace AllTypesDU +{ + +typedef SilecsWrapper::DeployConfig DeployConfig; +typedef SilecsWrapper::DesignConfig DesignConfig; + +class DeployUnit : public SilecsWrapper::DeployUnit +{ +public: + + /*! + * \brief Use this method to create/get the unique instance of the Deploy Unit. + * + * \param logTopics This parameter can be used to enable/disable log topics + * valid topics are ERROR[,INFO,DEBUG,SETUP,ALLOC,RECV,SEND,COMM,DATA,LOCK]. + * + * \param globalConfig This parameter can be used to pass different parameters to + * the library. I.e. enabling automatic connection. + */ + static DeployUnit* getInstance(const std::string& logTopics = "", + const SilecsWrapper::DeployConfig& globalConfig = SilecsWrapper::DeployConfig()) + { + if (_instance == NULL) + { + _instance = new DeployUnit(logTopics, globalConfig); + } + else + { + if (logTopics.empty() == false) + { + _instance->getService()->setLogTopics(logTopics); + } + } + return dynamic_cast<DeployUnit*>(_instance); + } + + /*! + * \brief Use this method to create/get the unique instance of the Deploy Unit. + * + * \param globalConfig This parameter can be used to pass different parameters to + * the library. I.e. enabling automatic connection. + */ + static DeployUnit* getInstance(const SilecsWrapper::DeployConfig& globalConfig) + { + return getInstance("", globalConfig); + } + + /*! + * \brief Return pointer to the deployed design AllTypes. + */ + AllTypes::Design* getAllTypes() + { + return _AllTypes; + } + +private: + + AllTypes::Design* _AllTypes; + + DeployUnit(const std::string& logTopics, const SilecsWrapper::DeployConfig& globalConfig) : + SilecsWrapper::DeployUnit("AllTypesDU", "0.1.0", logTopics, globalConfig) + { + // Construct Design AllTypes + _AllTypes = new AllTypes::Design((SilecsWrapper::DeployUnit*) this); + + } + + ~DeployUnit() + { + delete _AllTypes; + } +}; + + +class Controller : public SilecsWrapper::Controller +{ +public: + Controller(SilecsWrapper::Design *design, const std::string parameterFile) : + SilecsWrapper::Controller("Rabbit_DeviceMode", "", design, parameterFile) + { + _deviceMap.insert(std::pair<std::string, SilecsWrapper::Device*>("testDevice1", new SilecsWrapper::Device("testDevice1", this))); + _deviceMap.insert(std::pair<std::string, SilecsWrapper::Device*>("testDevice2", new SilecsWrapper::Device("testDevice2", this))); + } + + ~Controller() + { + map<std::string, SilecsWrapper::Device*>::iterator it; + for (it = _deviceMap.begin(); it != _deviceMap.end(); it++) + { + delete it->second; + } + } + + /*! + * \brief Return pointer to the requested device. + * \param label Device label. + */ + SilecsWrapper::Device* getDevice(const std::string& label) + { + if (_deviceMap.find(label) != _deviceMap.end()) + { + return _deviceMap[label]; + } + throw Silecs::SilecsException(__FILE__, __LINE__, Silecs::PARAM_UNKNOWN_DEVICE_NAME, label); + } + + std::map<std::string, SilecsWrapper::Device*>& getDeviceMap() + { + return _deviceMap; + } + + /*! + * \brief Get pointer to device testDevice1. + */ + SilecsWrapper::Device* getTestDevice1() + { + return _deviceMap["testDevice1"]; + } + + /*! + * \brief Get pointer to device testDevice2. + */ + SilecsWrapper::Device* getTestDevice2() + { + return _deviceMap["testDevice2"]; + } + +private: + std::map<std::string, SilecsWrapper::Device*> _deviceMap; +}; + + +} /* namespace AllTypesDU */ + +#endif /* ALLTYPESDU_H_ */ diff --git a/silecs-codegen/src/xml/test/generated_temp/wrapper/Schneider_M340.h b/silecs-codegen/src/xml/test/generated_temp/wrapper/Schneider_M340.h new file mode 100644 index 0000000..d31fa17 --- /dev/null +++ b/silecs-codegen/src/xml/test/generated_temp/wrapper/Schneider_M340.h @@ -0,0 +1,153 @@ +/* Copyright CERN 2015 + * + * WARNING: This code is automatically generated from your SILECS deploy unit document. + * You should never modify the content of this file as it would break consistency. + * Furthermore, any changes will be overwritten in the next code generation. + * Any modification shall be done using the SILECS development environment + * and regenerating this source code. + */ + +#ifndef ALLTYPESDU_H_ +#define ALLTYPESDU_H_ + +#include <silecs-communication/interface/equipment/SilecsCluster.h> +#include <silecs-communication/wrapper/DeployUnit.h> +#include <silecs-communication/wrapper/Design.h> + +#include "AllTypes.h" + +namespace AllTypesDU +{ + +typedef SilecsWrapper::DeployConfig DeployConfig; +typedef SilecsWrapper::DesignConfig DesignConfig; + +class DeployUnit : public SilecsWrapper::DeployUnit +{ +public: + + /*! + * \brief Use this method to create/get the unique instance of the Deploy Unit. + * + * \param logTopics This parameter can be used to enable/disable log topics + * valid topics are ERROR[,INFO,DEBUG,SETUP,ALLOC,RECV,SEND,COMM,DATA,LOCK]. + * + * \param globalConfig This parameter can be used to pass different parameters to + * the library. I.e. enabling automatic connection. + */ + static DeployUnit* getInstance(const std::string& logTopics = "", + const SilecsWrapper::DeployConfig& globalConfig = SilecsWrapper::DeployConfig()) + { + if (_instance == NULL) + { + _instance = new DeployUnit(logTopics, globalConfig); + } + else + { + if (logTopics.empty() == false) + { + _instance->getService()->setLogTopics(logTopics); + } + } + return dynamic_cast<DeployUnit*>(_instance); + } + + /*! + * \brief Use this method to create/get the unique instance of the Deploy Unit. + * + * \param globalConfig This parameter can be used to pass different parameters to + * the library. I.e. enabling automatic connection. + */ + static DeployUnit* getInstance(const SilecsWrapper::DeployConfig& globalConfig) + { + return getInstance("", globalConfig); + } + + /*! + * \brief Return pointer to the deployed design AllTypes. + */ + AllTypes::Design* getAllTypes() + { + return _AllTypes; + } + +private: + + AllTypes::Design* _AllTypes; + + DeployUnit(const std::string& logTopics, const SilecsWrapper::DeployConfig& globalConfig) : + SilecsWrapper::DeployUnit("AllTypesDU", "0.1.0", logTopics, globalConfig) + { + // Construct Design AllTypes + _AllTypes = new AllTypes::Design((SilecsWrapper::DeployUnit*) this); + + } + + ~DeployUnit() + { + delete _AllTypes; + } +}; + + +class Controller : public SilecsWrapper::Controller +{ +public: + Controller(SilecsWrapper::Design *design, const std::string parameterFile) : + SilecsWrapper::Controller("Schneider_M340", "", design, parameterFile) + { + _deviceMap.insert(std::pair<std::string, SilecsWrapper::Device*>("testDevice1", new SilecsWrapper::Device("testDevice1", this))); + _deviceMap.insert(std::pair<std::string, SilecsWrapper::Device*>("testDevice2", new SilecsWrapper::Device("testDevice2", this))); + } + + ~Controller() + { + map<std::string, SilecsWrapper::Device*>::iterator it; + for (it = _deviceMap.begin(); it != _deviceMap.end(); it++) + { + delete it->second; + } + } + + /*! + * \brief Return pointer to the requested device. + * \param label Device label. + */ + SilecsWrapper::Device* getDevice(const std::string& label) + { + if (_deviceMap.find(label) != _deviceMap.end()) + { + return _deviceMap[label]; + } + throw Silecs::SilecsException(__FILE__, __LINE__, Silecs::PARAM_UNKNOWN_DEVICE_NAME, label); + } + + std::map<std::string, SilecsWrapper::Device*>& getDeviceMap() + { + return _deviceMap; + } + + /*! + * \brief Get pointer to device testDevice1. + */ + SilecsWrapper::Device* getTestDevice1() + { + return _deviceMap["testDevice1"]; + } + + /*! + * \brief Get pointer to device testDevice2. + */ + SilecsWrapper::Device* getTestDevice2() + { + return _deviceMap["testDevice2"]; + } + +private: + std::map<std::string, SilecsWrapper::Device*> _deviceMap; +}; + + +} /* namespace AllTypesDU */ + +#endif /* ALLTYPESDU_H_ */ diff --git a/silecs-codegen/src/xml/test/generated_temp/wrapper/Schneider_PremiumQuantum.h b/silecs-codegen/src/xml/test/generated_temp/wrapper/Schneider_PremiumQuantum.h new file mode 100644 index 0000000..58576f6 --- /dev/null +++ b/silecs-codegen/src/xml/test/generated_temp/wrapper/Schneider_PremiumQuantum.h @@ -0,0 +1,153 @@ +/* Copyright CERN 2015 + * + * WARNING: This code is automatically generated from your SILECS deploy unit document. + * You should never modify the content of this file as it would break consistency. + * Furthermore, any changes will be overwritten in the next code generation. + * Any modification shall be done using the SILECS development environment + * and regenerating this source code. + */ + +#ifndef ALLTYPESDU_H_ +#define ALLTYPESDU_H_ + +#include <silecs-communication/interface/equipment/SilecsCluster.h> +#include <silecs-communication/wrapper/DeployUnit.h> +#include <silecs-communication/wrapper/Design.h> + +#include "AllTypes.h" + +namespace AllTypesDU +{ + +typedef SilecsWrapper::DeployConfig DeployConfig; +typedef SilecsWrapper::DesignConfig DesignConfig; + +class DeployUnit : public SilecsWrapper::DeployUnit +{ +public: + + /*! + * \brief Use this method to create/get the unique instance of the Deploy Unit. + * + * \param logTopics This parameter can be used to enable/disable log topics + * valid topics are ERROR[,INFO,DEBUG,SETUP,ALLOC,RECV,SEND,COMM,DATA,LOCK]. + * + * \param globalConfig This parameter can be used to pass different parameters to + * the library. I.e. enabling automatic connection. + */ + static DeployUnit* getInstance(const std::string& logTopics = "", + const SilecsWrapper::DeployConfig& globalConfig = SilecsWrapper::DeployConfig()) + { + if (_instance == NULL) + { + _instance = new DeployUnit(logTopics, globalConfig); + } + else + { + if (logTopics.empty() == false) + { + _instance->getService()->setLogTopics(logTopics); + } + } + return dynamic_cast<DeployUnit*>(_instance); + } + + /*! + * \brief Use this method to create/get the unique instance of the Deploy Unit. + * + * \param globalConfig This parameter can be used to pass different parameters to + * the library. I.e. enabling automatic connection. + */ + static DeployUnit* getInstance(const SilecsWrapper::DeployConfig& globalConfig) + { + return getInstance("", globalConfig); + } + + /*! + * \brief Return pointer to the deployed design AllTypes. + */ + AllTypes::Design* getAllTypes() + { + return _AllTypes; + } + +private: + + AllTypes::Design* _AllTypes; + + DeployUnit(const std::string& logTopics, const SilecsWrapper::DeployConfig& globalConfig) : + SilecsWrapper::DeployUnit("AllTypesDU", "0.1.0", logTopics, globalConfig) + { + // Construct Design AllTypes + _AllTypes = new AllTypes::Design((SilecsWrapper::DeployUnit*) this); + + } + + ~DeployUnit() + { + delete _AllTypes; + } +}; + + +class Controller : public SilecsWrapper::Controller +{ +public: + Controller(SilecsWrapper::Design *design, const std::string parameterFile) : + SilecsWrapper::Controller("Schneider_PremiumQuantum", "", design, parameterFile) + { + _deviceMap.insert(std::pair<std::string, SilecsWrapper::Device*>("testDevice1", new SilecsWrapper::Device("testDevice1", this))); + _deviceMap.insert(std::pair<std::string, SilecsWrapper::Device*>("testDevice2", new SilecsWrapper::Device("testDevice2", this))); + } + + ~Controller() + { + map<std::string, SilecsWrapper::Device*>::iterator it; + for (it = _deviceMap.begin(); it != _deviceMap.end(); it++) + { + delete it->second; + } + } + + /*! + * \brief Return pointer to the requested device. + * \param label Device label. + */ + SilecsWrapper::Device* getDevice(const std::string& label) + { + if (_deviceMap.find(label) != _deviceMap.end()) + { + return _deviceMap[label]; + } + throw Silecs::SilecsException(__FILE__, __LINE__, Silecs::PARAM_UNKNOWN_DEVICE_NAME, label); + } + + std::map<std::string, SilecsWrapper::Device*>& getDeviceMap() + { + return _deviceMap; + } + + /*! + * \brief Get pointer to device testDevice1. + */ + SilecsWrapper::Device* getTestDevice1() + { + return _deviceMap["testDevice1"]; + } + + /*! + * \brief Get pointer to device testDevice2. + */ + SilecsWrapper::Device* getTestDevice2() + { + return _deviceMap["testDevice2"]; + } + +private: + std::map<std::string, SilecsWrapper::Device*> _deviceMap; +}; + + +} /* namespace AllTypesDU */ + +#endif /* ALLTYPESDU_H_ */ diff --git a/silecs-codegen/src/xml/test/generated_temp/wrapper/Siemens_Step7Block.h b/silecs-codegen/src/xml/test/generated_temp/wrapper/Siemens_Step7Block.h new file mode 100644 index 0000000..9e32650 --- /dev/null +++ b/silecs-codegen/src/xml/test/generated_temp/wrapper/Siemens_Step7Block.h @@ -0,0 +1,153 @@ +/* Copyright CERN 2015 + * + * WARNING: This code is automatically generated from your SILECS deploy unit document. + * You should never modify the content of this file as it would break consistency. + * Furthermore, any changes will be overwritten in the next code generation. + * Any modification shall be done using the SILECS development environment + * and regenerating this source code. + */ + +#ifndef ALLTYPESDU_H_ +#define ALLTYPESDU_H_ + +#include <silecs-communication/interface/equipment/SilecsCluster.h> +#include <silecs-communication/wrapper/DeployUnit.h> +#include <silecs-communication/wrapper/Design.h> + +#include "AllTypes.h" + +namespace AllTypesDU +{ + +typedef SilecsWrapper::DeployConfig DeployConfig; +typedef SilecsWrapper::DesignConfig DesignConfig; + +class DeployUnit : public SilecsWrapper::DeployUnit +{ +public: + + /*! + * \brief Use this method to create/get the unique instance of the Deploy Unit. + * + * \param logTopics This parameter can be used to enable/disable log topics + * valid topics are ERROR[,INFO,DEBUG,SETUP,ALLOC,RECV,SEND,COMM,DATA,LOCK]. + * + * \param globalConfig This parameter can be used to pass different parameters to + * the library. I.e. enabling automatic connection. + */ + static DeployUnit* getInstance(const std::string& logTopics = "", + const SilecsWrapper::DeployConfig& globalConfig = SilecsWrapper::DeployConfig()) + { + if (_instance == NULL) + { + _instance = new DeployUnit(logTopics, globalConfig); + } + else + { + if (logTopics.empty() == false) + { + _instance->getService()->setLogTopics(logTopics); + } + } + return dynamic_cast<DeployUnit*>(_instance); + } + + /*! + * \brief Use this method to create/get the unique instance of the Deploy Unit. + * + * \param globalConfig This parameter can be used to pass different parameters to + * the library. I.e. enabling automatic connection. + */ + static DeployUnit* getInstance(const SilecsWrapper::DeployConfig& globalConfig) + { + return getInstance("", globalConfig); + } + + /*! + * \brief Return pointer to the deployed design AllTypes. + */ + AllTypes::Design* getAllTypes() + { + return _AllTypes; + } + +private: + + AllTypes::Design* _AllTypes; + + DeployUnit(const std::string& logTopics, const SilecsWrapper::DeployConfig& globalConfig) : + SilecsWrapper::DeployUnit("AllTypesDU", "0.1.0", logTopics, globalConfig) + { + // Construct Design AllTypes + _AllTypes = new AllTypes::Design((SilecsWrapper::DeployUnit*) this); + + } + + ~DeployUnit() + { + delete _AllTypes; + } +}; + + +class Controller : public SilecsWrapper::Controller +{ +public: + Controller(SilecsWrapper::Design *design, const std::string parameterFile) : + SilecsWrapper::Controller("Siemens_Step7Block", "", design, parameterFile) + { + _deviceMap.insert(std::pair<std::string, SilecsWrapper::Device*>("testDevice1", new SilecsWrapper::Device("testDevice1", this))); + _deviceMap.insert(std::pair<std::string, SilecsWrapper::Device*>("testDevice2", new SilecsWrapper::Device("testDevice2", this))); + } + + ~Controller() + { + map<std::string, SilecsWrapper::Device*>::iterator it; + for (it = _deviceMap.begin(); it != _deviceMap.end(); it++) + { + delete it->second; + } + } + + /*! + * \brief Return pointer to the requested device. + * \param label Device label. + */ + SilecsWrapper::Device* getDevice(const std::string& label) + { + if (_deviceMap.find(label) != _deviceMap.end()) + { + return _deviceMap[label]; + } + throw Silecs::SilecsException(__FILE__, __LINE__, Silecs::PARAM_UNKNOWN_DEVICE_NAME, label); + } + + std::map<std::string, SilecsWrapper::Device*>& getDeviceMap() + { + return _deviceMap; + } + + /*! + * \brief Get pointer to device testDevice1. + */ + SilecsWrapper::Device* getTestDevice1() + { + return _deviceMap["testDevice1"]; + } + + /*! + * \brief Get pointer to device testDevice2. + */ + SilecsWrapper::Device* getTestDevice2() + { + return _deviceMap["testDevice2"]; + } + +private: + std::map<std::string, SilecsWrapper::Device*> _deviceMap; +}; + + +} /* namespace AllTypesDU */ + +#endif /* ALLTYPESDU_H_ */ diff --git a/silecs-codegen/src/xml/test/generated_temp/wrapper/Siemens_Step7Device.h b/silecs-codegen/src/xml/test/generated_temp/wrapper/Siemens_Step7Device.h new file mode 100644 index 0000000..be5bd8a --- /dev/null +++ b/silecs-codegen/src/xml/test/generated_temp/wrapper/Siemens_Step7Device.h @@ -0,0 +1,153 @@ +/* Copyright CERN 2015 + * + * WARNING: This code is automatically generated from your SILECS deploy unit document. + * You should never modify the content of this file as it would break consistency. + * Furthermore, any changes will be overwritten in the next code generation. + * Any modification shall be done using the SILECS development environment + * and regenerating this source code. + */ + +#ifndef ALLTYPESDU_H_ +#define ALLTYPESDU_H_ + +#include <silecs-communication/interface/equipment/SilecsCluster.h> +#include <silecs-communication/wrapper/DeployUnit.h> +#include <silecs-communication/wrapper/Design.h> + +#include "AllTypes.h" + +namespace AllTypesDU +{ + +typedef SilecsWrapper::DeployConfig DeployConfig; +typedef SilecsWrapper::DesignConfig DesignConfig; + +class DeployUnit : public SilecsWrapper::DeployUnit +{ +public: + + /*! + * \brief Use this method to create/get the unique instance of the Deploy Unit. + * + * \param logTopics This parameter can be used to enable/disable log topics + * valid topics are ERROR[,INFO,DEBUG,SETUP,ALLOC,RECV,SEND,COMM,DATA,LOCK]. + * + * \param globalConfig This parameter can be used to pass different parameters to + * the library. I.e. enabling automatic connection. + */ + static DeployUnit* getInstance(const std::string& logTopics = "", + const SilecsWrapper::DeployConfig& globalConfig = SilecsWrapper::DeployConfig()) + { + if (_instance == NULL) + { + _instance = new DeployUnit(logTopics, globalConfig); + } + else + { + if (logTopics.empty() == false) + { + _instance->getService()->setLogTopics(logTopics); + } + } + return dynamic_cast<DeployUnit*>(_instance); + } + + /*! + * \brief Use this method to create/get the unique instance of the Deploy Unit. + * + * \param globalConfig This parameter can be used to pass different parameters to + * the library. I.e. enabling automatic connection. + */ + static DeployUnit* getInstance(const SilecsWrapper::DeployConfig& globalConfig) + { + return getInstance("", globalConfig); + } + + /*! + * \brief Return pointer to the deployed design AllTypes. + */ + AllTypes::Design* getAllTypes() + { + return _AllTypes; + } + +private: + + AllTypes::Design* _AllTypes; + + DeployUnit(const std::string& logTopics, const SilecsWrapper::DeployConfig& globalConfig) : + SilecsWrapper::DeployUnit("AllTypesDU", "0.1.0", logTopics, globalConfig) + { + // Construct Design AllTypes + _AllTypes = new AllTypes::Design((SilecsWrapper::DeployUnit*) this); + + } + + ~DeployUnit() + { + delete _AllTypes; + } +}; + + +class Controller : public SilecsWrapper::Controller +{ +public: + Controller(SilecsWrapper::Design *design, const std::string parameterFile) : + SilecsWrapper::Controller("Siemens_Step7Device", "", design, parameterFile) + { + _deviceMap.insert(std::pair<std::string, SilecsWrapper::Device*>("testDevice1", new SilecsWrapper::Device("testDevice1", this))); + _deviceMap.insert(std::pair<std::string, SilecsWrapper::Device*>("testDevice2", new SilecsWrapper::Device("testDevice2", this))); + } + + ~Controller() + { + map<std::string, SilecsWrapper::Device*>::iterator it; + for (it = _deviceMap.begin(); it != _deviceMap.end(); it++) + { + delete it->second; + } + } + + /*! + * \brief Return pointer to the requested device. + * \param label Device label. + */ + SilecsWrapper::Device* getDevice(const std::string& label) + { + if (_deviceMap.find(label) != _deviceMap.end()) + { + return _deviceMap[label]; + } + throw Silecs::SilecsException(__FILE__, __LINE__, Silecs::PARAM_UNKNOWN_DEVICE_NAME, label); + } + + std::map<std::string, SilecsWrapper::Device*>& getDeviceMap() + { + return _deviceMap; + } + + /*! + * \brief Get pointer to device testDevice1. + */ + SilecsWrapper::Device* getTestDevice1() + { + return _deviceMap["testDevice1"]; + } + + /*! + * \brief Get pointer to device testDevice2. + */ + SilecsWrapper::Device* getTestDevice2() + { + return _deviceMap["testDevice2"]; + } + +private: + std::map<std::string, SilecsWrapper::Device*> _deviceMap; +}; + + +} /* namespace AllTypesDU */ + +#endif /* ALLTYPESDU_H_ */ diff --git a/silecs-codegen/src/xml/test/generated_temp/wrapper/Siemens_TiaBlock.h b/silecs-codegen/src/xml/test/generated_temp/wrapper/Siemens_TiaBlock.h new file mode 100644 index 0000000..63877a3 --- /dev/null +++ b/silecs-codegen/src/xml/test/generated_temp/wrapper/Siemens_TiaBlock.h @@ -0,0 +1,153 @@ +/* Copyright CERN 2015 + * + * WARNING: This code is automatically generated from your SILECS deploy unit document. + * You should never modify the content of this file as it would break consistency. + * Furthermore, any changes will be overwritten in the next code generation. + * Any modification shall be done using the SILECS development environment + * and regenerating this source code. + */ + +#ifndef ALLTYPESDU_H_ +#define ALLTYPESDU_H_ + +#include <silecs-communication/interface/equipment/SilecsCluster.h> +#include <silecs-communication/wrapper/DeployUnit.h> +#include <silecs-communication/wrapper/Design.h> + +#include "AllTypes.h" + +namespace AllTypesDU +{ + +typedef SilecsWrapper::DeployConfig DeployConfig; +typedef SilecsWrapper::DesignConfig DesignConfig; + +class DeployUnit : public SilecsWrapper::DeployUnit +{ +public: + + /*! + * \brief Use this method to create/get the unique instance of the Deploy Unit. + * + * \param logTopics This parameter can be used to enable/disable log topics + * valid topics are ERROR[,INFO,DEBUG,SETUP,ALLOC,RECV,SEND,COMM,DATA,LOCK]. + * + * \param globalConfig This parameter can be used to pass different parameters to + * the library. I.e. enabling automatic connection. + */ + static DeployUnit* getInstance(const std::string& logTopics = "", + const SilecsWrapper::DeployConfig& globalConfig = SilecsWrapper::DeployConfig()) + { + if (_instance == NULL) + { + _instance = new DeployUnit(logTopics, globalConfig); + } + else + { + if (logTopics.empty() == false) + { + _instance->getService()->setLogTopics(logTopics); + } + } + return dynamic_cast<DeployUnit*>(_instance); + } + + /*! + * \brief Use this method to create/get the unique instance of the Deploy Unit. + * + * \param globalConfig This parameter can be used to pass different parameters to + * the library. I.e. enabling automatic connection. + */ + static DeployUnit* getInstance(const SilecsWrapper::DeployConfig& globalConfig) + { + return getInstance("", globalConfig); + } + + /*! + * \brief Return pointer to the deployed design AllTypes. + */ + AllTypes::Design* getAllTypes() + { + return _AllTypes; + } + +private: + + AllTypes::Design* _AllTypes; + + DeployUnit(const std::string& logTopics, const SilecsWrapper::DeployConfig& globalConfig) : + SilecsWrapper::DeployUnit("AllTypesDU", "0.1.0", logTopics, globalConfig) + { + // Construct Design AllTypes + _AllTypes = new AllTypes::Design((SilecsWrapper::DeployUnit*) this); + + } + + ~DeployUnit() + { + delete _AllTypes; + } +}; + + +class Controller : public SilecsWrapper::Controller +{ +public: + Controller(SilecsWrapper::Design *design, const std::string parameterFile) : + SilecsWrapper::Controller("Siemens_TiaBlock", "", design, parameterFile) + { + _deviceMap.insert(std::pair<std::string, SilecsWrapper::Device*>("testDevice1", new SilecsWrapper::Device("testDevice1", this))); + _deviceMap.insert(std::pair<std::string, SilecsWrapper::Device*>("testDevice2", new SilecsWrapper::Device("testDevice2", this))); + } + + ~Controller() + { + map<std::string, SilecsWrapper::Device*>::iterator it; + for (it = _deviceMap.begin(); it != _deviceMap.end(); it++) + { + delete it->second; + } + } + + /*! + * \brief Return pointer to the requested device. + * \param label Device label. + */ + SilecsWrapper::Device* getDevice(const std::string& label) + { + if (_deviceMap.find(label) != _deviceMap.end()) + { + return _deviceMap[label]; + } + throw Silecs::SilecsException(__FILE__, __LINE__, Silecs::PARAM_UNKNOWN_DEVICE_NAME, label); + } + + std::map<std::string, SilecsWrapper::Device*>& getDeviceMap() + { + return _deviceMap; + } + + /*! + * \brief Get pointer to device testDevice1. + */ + SilecsWrapper::Device* getTestDevice1() + { + return _deviceMap["testDevice1"]; + } + + /*! + * \brief Get pointer to device testDevice2. + */ + SilecsWrapper::Device* getTestDevice2() + { + return _deviceMap["testDevice2"]; + } + +private: + std::map<std::string, SilecsWrapper::Device*> _deviceMap; +}; + + +} /* namespace AllTypesDU */ + +#endif /* ALLTYPESDU_H_ */ diff --git a/silecs-codegen/src/xml/test/generated_temp/wrapper/Siemens_TiaDevice.h b/silecs-codegen/src/xml/test/generated_temp/wrapper/Siemens_TiaDevice.h new file mode 100644 index 0000000..e6a3029 --- /dev/null +++ b/silecs-codegen/src/xml/test/generated_temp/wrapper/Siemens_TiaDevice.h @@ -0,0 +1,153 @@ +/* Copyright CERN 2015 + * + * WARNING: This code is automatically generated from your SILECS deploy unit document. + * You should never modify the content of this file as it would break consistency. + * Furthermore, any changes will be overwritten in the next code generation. + * Any modification shall be done using the SILECS development environment + * and regenerating this source code. + */ + +#ifndef ALLTYPESDU_H_ +#define ALLTYPESDU_H_ + +#include <silecs-communication/interface/equipment/SilecsCluster.h> +#include <silecs-communication/wrapper/DeployUnit.h> +#include <silecs-communication/wrapper/Design.h> + +#include "AllTypes.h" + +namespace AllTypesDU +{ + +typedef SilecsWrapper::DeployConfig DeployConfig; +typedef SilecsWrapper::DesignConfig DesignConfig; + +class DeployUnit : public SilecsWrapper::DeployUnit +{ +public: + + /*! + * \brief Use this method to create/get the unique instance of the Deploy Unit. + * + * \param logTopics This parameter can be used to enable/disable log topics + * valid topics are ERROR[,INFO,DEBUG,SETUP,ALLOC,RECV,SEND,COMM,DATA,LOCK]. + * + * \param globalConfig This parameter can be used to pass different parameters to + * the library. I.e. enabling automatic connection. + */ + static DeployUnit* getInstance(const std::string& logTopics = "", + const SilecsWrapper::DeployConfig& globalConfig = SilecsWrapper::DeployConfig()) + { + if (_instance == NULL) + { + _instance = new DeployUnit(logTopics, globalConfig); + } + else + { + if (logTopics.empty() == false) + { + _instance->getService()->setLogTopics(logTopics); + } + } + return dynamic_cast<DeployUnit*>(_instance); + } + + /*! + * \brief Use this method to create/get the unique instance of the Deploy Unit. + * + * \param globalConfig This parameter can be used to pass different parameters to + * the library. I.e. enabling automatic connection. + */ + static DeployUnit* getInstance(const SilecsWrapper::DeployConfig& globalConfig) + { + return getInstance("", globalConfig); + } + + /*! + * \brief Return pointer to the deployed design AllTypes. + */ + AllTypes::Design* getAllTypes() + { + return _AllTypes; + } + +private: + + AllTypes::Design* _AllTypes; + + DeployUnit(const std::string& logTopics, const SilecsWrapper::DeployConfig& globalConfig) : + SilecsWrapper::DeployUnit("AllTypesDU", "0.1.0", logTopics, globalConfig) + { + // Construct Design AllTypes + _AllTypes = new AllTypes::Design((SilecsWrapper::DeployUnit*) this); + + } + + ~DeployUnit() + { + delete _AllTypes; + } +}; + + +class Controller : public SilecsWrapper::Controller +{ +public: + Controller(SilecsWrapper::Design *design, const std::string parameterFile) : + SilecsWrapper::Controller("Siemens_TiaDevice", "", design, parameterFile) + { + _deviceMap.insert(std::pair<std::string, SilecsWrapper::Device*>("testDevice1", new SilecsWrapper::Device("testDevice1", this))); + _deviceMap.insert(std::pair<std::string, SilecsWrapper::Device*>("testDevice2", new SilecsWrapper::Device("testDevice2", this))); + } + + ~Controller() + { + map<std::string, SilecsWrapper::Device*>::iterator it; + for (it = _deviceMap.begin(); it != _deviceMap.end(); it++) + { + delete it->second; + } + } + + /*! + * \brief Return pointer to the requested device. + * \param label Device label. + */ + SilecsWrapper::Device* getDevice(const std::string& label) + { + if (_deviceMap.find(label) != _deviceMap.end()) + { + return _deviceMap[label]; + } + throw Silecs::SilecsException(__FILE__, __LINE__, Silecs::PARAM_UNKNOWN_DEVICE_NAME, label); + } + + std::map<std::string, SilecsWrapper::Device*>& getDeviceMap() + { + return _deviceMap; + } + + /*! + * \brief Get pointer to device testDevice1. + */ + SilecsWrapper::Device* getTestDevice1() + { + return _deviceMap["testDevice1"]; + } + + /*! + * \brief Get pointer to device testDevice2. + */ + SilecsWrapper::Device* getTestDevice2() + { + return _deviceMap["testDevice2"]; + } + +private: + std::map<std::string, SilecsWrapper::Device*> _deviceMap; +}; + + +} /* namespace AllTypesDU */ + +#endif /* ALLTYPESDU_H_ */ diff --git a/silecs-codegen/src/xml/test/generated_temp/wrapper/Virtual_SiemensBlock.h b/silecs-codegen/src/xml/test/generated_temp/wrapper/Virtual_SiemensBlock.h new file mode 100644 index 0000000..1681d8b --- /dev/null +++ b/silecs-codegen/src/xml/test/generated_temp/wrapper/Virtual_SiemensBlock.h @@ -0,0 +1,153 @@ +/* Copyright CERN 2015 + * + * WARNING: This code is automatically generated from your SILECS deploy unit document. + * You should never modify the content of this file as it would break consistency. + * Furthermore, any changes will be overwritten in the next code generation. + * Any modification shall be done using the SILECS development environment + * and regenerating this source code. + */ + +#ifndef ALLTYPESDU_H_ +#define ALLTYPESDU_H_ + +#include <silecs-communication/interface/equipment/SilecsCluster.h> +#include <silecs-communication/wrapper/DeployUnit.h> +#include <silecs-communication/wrapper/Design.h> + +#include "AllTypes.h" + +namespace AllTypesDU +{ + +typedef SilecsWrapper::DeployConfig DeployConfig; +typedef SilecsWrapper::DesignConfig DesignConfig; + +class DeployUnit : public SilecsWrapper::DeployUnit +{ +public: + + /*! + * \brief Use this method to create/get the unique instance of the Deploy Unit. + * + * \param logTopics This parameter can be used to enable/disable log topics + * valid topics are ERROR[,INFO,DEBUG,SETUP,ALLOC,RECV,SEND,COMM,DATA,LOCK]. + * + * \param globalConfig This parameter can be used to pass different parameters to + * the library. I.e. enabling automatic connection. + */ + static DeployUnit* getInstance(const std::string& logTopics = "", + const SilecsWrapper::DeployConfig& globalConfig = SilecsWrapper::DeployConfig()) + { + if (_instance == NULL) + { + _instance = new DeployUnit(logTopics, globalConfig); + } + else + { + if (logTopics.empty() == false) + { + _instance->getService()->setLogTopics(logTopics); + } + } + return dynamic_cast<DeployUnit*>(_instance); + } + + /*! + * \brief Use this method to create/get the unique instance of the Deploy Unit. + * + * \param globalConfig This parameter can be used to pass different parameters to + * the library. I.e. enabling automatic connection. + */ + static DeployUnit* getInstance(const SilecsWrapper::DeployConfig& globalConfig) + { + return getInstance("", globalConfig); + } + + /*! + * \brief Return pointer to the deployed design AllTypes. + */ + AllTypes::Design* getAllTypes() + { + return _AllTypes; + } + +private: + + AllTypes::Design* _AllTypes; + + DeployUnit(const std::string& logTopics, const SilecsWrapper::DeployConfig& globalConfig) : + SilecsWrapper::DeployUnit("AllTypesDU", "0.1.0", logTopics, globalConfig) + { + // Construct Design AllTypes + _AllTypes = new AllTypes::Design((SilecsWrapper::DeployUnit*) this); + + } + + ~DeployUnit() + { + delete _AllTypes; + } +}; + + +class Controller : public SilecsWrapper::Controller +{ +public: + Controller(SilecsWrapper::Design *design, const std::string parameterFile) : + SilecsWrapper::Controller("Virtual_SiemensBlock", "", design, parameterFile) + { + _deviceMap.insert(std::pair<std::string, SilecsWrapper::Device*>("testDevice1", new SilecsWrapper::Device("testDevice1", this))); + _deviceMap.insert(std::pair<std::string, SilecsWrapper::Device*>("testDevice2", new SilecsWrapper::Device("testDevice2", this))); + } + + ~Controller() + { + map<std::string, SilecsWrapper::Device*>::iterator it; + for (it = _deviceMap.begin(); it != _deviceMap.end(); it++) + { + delete it->second; + } + } + + /*! + * \brief Return pointer to the requested device. + * \param label Device label. + */ + SilecsWrapper::Device* getDevice(const std::string& label) + { + if (_deviceMap.find(label) != _deviceMap.end()) + { + return _deviceMap[label]; + } + throw Silecs::SilecsException(__FILE__, __LINE__, Silecs::PARAM_UNKNOWN_DEVICE_NAME, label); + } + + std::map<std::string, SilecsWrapper::Device*>& getDeviceMap() + { + return _deviceMap; + } + + /*! + * \brief Get pointer to device testDevice1. + */ + SilecsWrapper::Device* getTestDevice1() + { + return _deviceMap["testDevice1"]; + } + + /*! + * \brief Get pointer to device testDevice2. + */ + SilecsWrapper::Device* getTestDevice2() + { + return _deviceMap["testDevice2"]; + } + +private: + std::map<std::string, SilecsWrapper::Device*> _deviceMap; +}; + + +} /* namespace AllTypesDU */ + +#endif /* ALLTYPESDU_H_ */ diff --git a/silecs-codegen/src/xml/test/generated_temp/wrapper/Virtual_SiemensDevice.h b/silecs-codegen/src/xml/test/generated_temp/wrapper/Virtual_SiemensDevice.h new file mode 100644 index 0000000..8b1ef27 --- /dev/null +++ b/silecs-codegen/src/xml/test/generated_temp/wrapper/Virtual_SiemensDevice.h @@ -0,0 +1,153 @@ +/* Copyright CERN 2015 + * + * WARNING: This code is automatically generated from your SILECS deploy unit document. + * You should never modify the content of this file as it would break consistency. + * Furthermore, any changes will be overwritten in the next code generation. + * Any modification shall be done using the SILECS development environment + * and regenerating this source code. + */ + +#ifndef ALLTYPESDU_H_ +#define ALLTYPESDU_H_ + +#include <silecs-communication/interface/equipment/SilecsCluster.h> +#include <silecs-communication/wrapper/DeployUnit.h> +#include <silecs-communication/wrapper/Design.h> + +#include "AllTypes.h" + +namespace AllTypesDU +{ + +typedef SilecsWrapper::DeployConfig DeployConfig; +typedef SilecsWrapper::DesignConfig DesignConfig; + +class DeployUnit : public SilecsWrapper::DeployUnit +{ +public: + + /*! + * \brief Use this method to create/get the unique instance of the Deploy Unit. + * + * \param logTopics This parameter can be used to enable/disable log topics + * valid topics are ERROR[,INFO,DEBUG,SETUP,ALLOC,RECV,SEND,COMM,DATA,LOCK]. + * + * \param globalConfig This parameter can be used to pass different parameters to + * the library. I.e. enabling automatic connection. + */ + static DeployUnit* getInstance(const std::string& logTopics = "", + const SilecsWrapper::DeployConfig& globalConfig = SilecsWrapper::DeployConfig()) + { + if (_instance == NULL) + { + _instance = new DeployUnit(logTopics, globalConfig); + } + else + { + if (logTopics.empty() == false) + { + _instance->getService()->setLogTopics(logTopics); + } + } + return dynamic_cast<DeployUnit*>(_instance); + } + + /*! + * \brief Use this method to create/get the unique instance of the Deploy Unit. + * + * \param globalConfig This parameter can be used to pass different parameters to + * the library. I.e. enabling automatic connection. + */ + static DeployUnit* getInstance(const SilecsWrapper::DeployConfig& globalConfig) + { + return getInstance("", globalConfig); + } + + /*! + * \brief Return pointer to the deployed design AllTypes. + */ + AllTypes::Design* getAllTypes() + { + return _AllTypes; + } + +private: + + AllTypes::Design* _AllTypes; + + DeployUnit(const std::string& logTopics, const SilecsWrapper::DeployConfig& globalConfig) : + SilecsWrapper::DeployUnit("AllTypesDU", "0.1.0", logTopics, globalConfig) + { + // Construct Design AllTypes + _AllTypes = new AllTypes::Design((SilecsWrapper::DeployUnit*) this); + + } + + ~DeployUnit() + { + delete _AllTypes; + } +}; + + +class Controller : public SilecsWrapper::Controller +{ +public: + Controller(SilecsWrapper::Design *design, const std::string parameterFile) : + SilecsWrapper::Controller("Virtual_SiemensDevice", "", design, parameterFile) + { + _deviceMap.insert(std::pair<std::string, SilecsWrapper::Device*>("testDevice1", new SilecsWrapper::Device("testDevice1", this))); + _deviceMap.insert(std::pair<std::string, SilecsWrapper::Device*>("testDevice2", new SilecsWrapper::Device("testDevice2", this))); + } + + ~Controller() + { + map<std::string, SilecsWrapper::Device*>::iterator it; + for (it = _deviceMap.begin(); it != _deviceMap.end(); it++) + { + delete it->second; + } + } + + /*! + * \brief Return pointer to the requested device. + * \param label Device label. + */ + SilecsWrapper::Device* getDevice(const std::string& label) + { + if (_deviceMap.find(label) != _deviceMap.end()) + { + return _deviceMap[label]; + } + throw Silecs::SilecsException(__FILE__, __LINE__, Silecs::PARAM_UNKNOWN_DEVICE_NAME, label); + } + + std::map<std::string, SilecsWrapper::Device*>& getDeviceMap() + { + return _deviceMap; + } + + /*! + * \brief Get pointer to device testDevice1. + */ + SilecsWrapper::Device* getTestDevice1() + { + return _deviceMap["testDevice1"]; + } + + /*! + * \brief Get pointer to device testDevice2. + */ + SilecsWrapper::Device* getTestDevice2() + { + return _deviceMap["testDevice2"]; + } + +private: + std::map<std::string, SilecsWrapper::Device*> _deviceMap; +}; + + +} /* namespace AllTypesDU */ + +#endif /* ALLTYPESDU_H_ */ diff --git a/silecs-codegen/src/xml/test/testBase.py b/silecs-codegen/src/xml/test/testBase.py new file mode 100644 index 0000000..7d9b487 --- /dev/null +++ b/silecs-codegen/src/xml/test/testBase.py @@ -0,0 +1,96 @@ +import sys +import os +import difflib + +import inspect #get caller name + +def assertEqual( a, b ): + if a != b: + callerInfo = str(inspect.stack()[1][3]) + ":" + str(inspect.stack()[1][2]) + print "Test Failed: " + callerInfo + "\nVariables are different. Var1: '" + str(a) + "' Var2: '" + str(b) + "'" + sys.exit(1) + else: + print "success: " + str(inspect.stack()[1][3]) + +def assertTrue( condition ): + if not condition: + callerInfo = str(inspect.stack()[1][3]) + ":" + str(inspect.stack()[1][2]) + print "Test Failed: " + callerInfo + "\nCondition expected to be True, but was False" + sys.exit(1) + else: + print "success: " + str(inspect.stack()[1][3]) + +def assertFalse( condition ): + if condition: + callerInfo = str(inspect.stack()[1][3]) + ":" + str(inspect.stack()[1][2]) + print "Test Failed: " + callerInfo + "\nCondition expected to be False, but was True" + sys.exit(1) + else: + print "success: " + str(inspect.stack()[1][3]) + +def assertPLCCodeEqual(filePath1,filePath2): + with open(filePath1) as a: a_content = a.readlines() + with open(filePath2) as b: b_content = b.readlines() + diff = difflib.unified_diff(a_content,b_content) + isDifferent = False + for i,line in enumerate(diff): + if i < 2: + print("first 2 lines ignored .. unknown reason why they differ") + elif ("DT#" in line) or ("SILECS_set_dt" in line) : #ignore timestamps in silecsheader + print("date ignored") + elif line.startswith("-"): + isDifferent = True + print(i,' '+line) + elif line.startswith("+"): + isDifferent = True + print(i,' '+line) + if isDifferent: + print "Test Failed: The files: " + filePath1 + ", " + filePath2 + " are different from each other !" + sys.exit(1) + else: + print "success: " + str(inspect.stack()[1][3]) + +def assertParameterFileEqual(filePath1,filePath2): + with open(filePath1) as a: a_content = a.readlines() + with open(filePath2) as b: b_content = b.readlines() + diff = difflib.unified_diff(a_content,b_content) + isDifferent = False + for i,line in enumerate(diff): + if i < 2: + print("first 2 lines ignored .. unknown reason why they differ") + elif ("<Generation date=" in line) : #ignore timestamps + print("date ignored") + elif line.startswith("-"): + isDifferent = True + print(i,' '+line) + elif line.startswith("+"): + isDifferent = True + print(i,' '+line) + if isDifferent: + print "Test Failed: The files: " + filePath1 + ", " + filePath2 + " are different from each other !" + sys.exit(1) + else: + print "success: " + str(inspect.stack()[1][3]) + +def assertFileEqual(filePath1,filePath2): + with open(filePath1) as a: a_content = a.readlines() + with open(filePath2) as b: b_content = b.readlines() + diff = difflib.unified_diff(a_content,b_content) + isDifferent = False + for i,line in enumerate(diff): + if i < 2: + print("first 2 lines ignored .. unknown reason why they differ") + elif line.startswith("-"): + isDifferent = True + print(i,' '+line) + elif line.startswith("+"): + isDifferent = True + print(i,' '+line) + if isDifferent: + print "Test Failed: The files: " + filePath1 + ", " + filePath2 + " are different from each other !" + sys.exit(1) + else: + print "success: " + str(inspect.stack()[1][3]) + +def allTestsOk( ): + print "All tests for module: " + str(inspect.stack()[1][1]) + " run green! " diff --git a/silecs-codegen/src/xml/test/testBase.pyc b/silecs-codegen/src/xml/test/testBase.pyc new file mode 100644 index 0000000000000000000000000000000000000000..33c9ce59bed3581ab2a4b5dfcd393bf3aa0d69e8 GIT binary patch literal 4945 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 O&Xh~?Jy||kKK?s;ANjBV literal 0 HcmV?d00001 diff --git a/silecs-codegen/src/xml/virtualS7Template.py b/silecs-codegen/src/xml/virtualS7Template.py new file mode 100644 index 0000000..abdd3fa --- /dev/null +++ b/silecs-codegen/src/xml/virtualS7Template.py @@ -0,0 +1,498 @@ +#!/usr/bin/python +# Copyright 2016 CERN and GSI +# +# 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 3 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, see <http://www.gnu.org/licenses/>. + + +# Description: +# This module implement the methods to build each components of the sources. +# A component source consists of one 'parameterizable' text that can +# be specialized on call to append the string to be stored in the file. +# + +import string +import struct +import iecommon + +#------------------------------------------------------------------------- +# Hash-Table + +whichRegisterFormat = { + 'uint8' : 'uint8_t', + 'int8' : 'int8_t', + 'uint16' : 'uint16_t', + 'int16' : 'int16_t', + 'uint32' : 'uint32_t', + 'int32' : 'int32_t', + 'float32' : 'float', + 'uint64' : 'uint64_t', + 'int64' : 'int64_t', + 'string' : 'string', + 'float64' : 'double', + 'date' : 'double', + 'char' :'int8_t', + 'byte' :'uint8_t', + 'word' :'uint16_t', + 'dword' :'uint32_t', + 'int' :'int16_t', + 'dint' :'int32_t', + 'real' :'float', + 'dt' :'double' +} + +#========================================================================= +# Virtual S7 DEPLOY-UNIT template +#========================================================================= + +duDesignInclude = """#include "%s_%s.h" +""" + +duConstructor = """DeployUnit() : SilecsServer::DeployUnit("%s", SilecsServer::S7Protocol, SilecsServer::%s, %s) +""" + +duDesignAlloc = """ mapDesigns_["%s"] = new %s_%s::Design(); +""" + +duDesignDelete = """ delete mapDesigns_["%s"]; +""" + +duDesignGet = """ %s_%s::Design* get%s() + { + return dynamic_cast<%s_%s::Design*>(mapDesigns_["%s"]); + } + +""" + +duHeader = """ +/* Copyright CERN 2015 + * + * WARNING: This code is automatically generated from your SILECS deploy unit document. + * You should never modify the content of this file as it would break consistency. + * Furthermore, any changes will be overwritten in the next code generation. + * Any modification shall be done using the SILECS development environment + * and regenerating this source code. + */ + +#ifndef %s_H_ +#define %s_H_ + +#include <silecs-virtual-controller/interface/DeployUnit.h> +#include <silecs-virtual-controller/interface/Design.h> +%s + +namespace %s +{ + +class DeployUnit : public SilecsServer::DeployUnit +{ +public: + + %s { + %s } + + ~DeployUnit() + { + %s } + +%s}; + +} + +#endif +""" + +mainCode = """ +#include <stdio.h> +#include <stdlib.h> +#include <cstring> +#include <iostream> + +#include <silecs-virtual-controller/core/SilecsSnap7Server.h> +#include "%s.h" + +class UserSnap7Server : public SilecsServer::SilecsSnap7Server +{ +public: + UserSnap7Server(%s::DeployUnit* du) : SilecsSnap7Server(du, true) {} + virtual ~UserSnap7Server() {} + + virtual void userFunction() + { + // Implement the specific process control here! + // Look at SILECS Wikis: 'Create a virtual controller' chapter + } +}; + +int main(int argc, char*argv[]) +{ + %s::DeployUnit du; + UserSnap7Server server(&du); + if (server.startServer() < 0) + { + std::cout << "Failed to start the VC server: " << du.getName() << std::endl; + return -1; + } + return 0; +} +""" + + +#========================================================================= +# Virtual S7 CLASS template +#========================================================================= +classScalarGetSet = """ + /*! + * \\brief Get %s register. + * \\return value. + */ + %s get%s() const + { + return structData_.%s; + } + + /*! + * \\brief Set %s register. + * \\param value to be set. + */ + void set%s(%s value) + { + structData_.%s = value; + } +""" + +classArrayGetSet = """ + /*! + * \\brief Get array %s register. + * \\return value. + */ + void get%s(%s* value) const + { + memcpy(value, &structData_.%s, %sDim1_ * %sDim2_ * sizeof(%s)); + } + + /*! + * \\brief Set array %s register. + * \\param value to be set. + */ + void set%s(%s* value) + { + memcpy(&structData_.%s, value, %sDim1_ * %sDim2_ * sizeof(%s)); + } +""" + +classScalarStringGetSet = """ + /*! + * \\brief Get %s register. + * \\return value. + */ + std::string get%s() const + { + size_t len = (size_t)structData_.%s[1]; + return std::string((char*)&(structData_.%s[2]), len); + } + + /*! + * \\brief Set %s register. + * \\param value to be set. + */ + void set%s(const std::string &value) + { + size_t len = (value.length() < %sLen_) ? value.length() : %sLen_; + memcpy((char*)&(structData_.%s[2]), value.c_str(), len); + structData_.%s[0] = char(0); + structData_.%s[1] = char(len); + } +""" + +classArrayStringGetSet = """ + /*! + * \\brief Get std::string %s register. + * \\param value buffer where the value will be stored. + */ + void get%s(std::string* value) const + { + for (std::size_t i = 0; i < %sDim1_; i++) + { + size_t len = (size_t)structData_.%s[i][1]; + value[i].assign(&(structData_.%s[i][2]), len); + } + } + + /*! + * \\brief Set std::string %s register. + * \\param value to be set. + */ + void set%s(std::string* value) + { + for (std::size_t i = 0; i < %sDim1_; i++) + { + size_t len = (value[i].length() < %sLen_) ? value[i].length() : %sLen_; + memcpy(&(structData_.%s[i][2]), value[i].c_str(), len); + structData_.%s[i][0] = char(0); + structData_.%s[i][1] = char(len); + } + } +""" + +classHeaderInit = """ set_version("%s"); + set_checksum(%s); + set_user("%s"); + set_date(0.0);""" + +classBlock = """ +class %s : public SilecsServer::Block +{ +public: + /*! + * \\brief %s constructor. It creates an empty block. + */ + %s() : SilecsServer::Block("%s:%s") + { + %s + } + + ~%s() + { + } + %s + virtual inline size_t getSize() const + { + return sizeof(structData_); + } + + virtual void getData(unsigned char * data) const + { + memcpy(data, &structData_, this->getSize()); + } + + virtual void setData(unsigned char * data) + { + memcpy(&structData_, data, this->getSize()); + } + + virtual inline size_t getOffset() const { return %s; } + +%s +private: + +#pragma pack(push, 1) + struct + { +%s + } structData_; +#pragma pack(pop) + +}; +""" + +classArrayDim = """ static const std::size_t %sDim1_ = %s; + static const std::size_t %sDim2_ = %s; +""" + +classStringLen = """ static const std::size_t %sLen_ = %s; +""" + +classCreateBlock = """ + blockMap_["%s:%s"] = new %s();""" + +classDeleteBlock = """ + delete (blockMap_["%s:%s"]);""" + +classDevice = """ +class Device : public SilecsServer::Device +{ +public: + Device(const std::string& label, size_t number):SilecsServer::Device(label, number) + { %s + } + + ~Device() + { %s + } +};""" + +classCreateDevice = """ + deviceMap_["%s:%s"] = new Device("%s:%s", %s);""" + +classDeleteDevice = """ + delete(deviceMap_["%s:%s"]);""" + +classDesign = """ +class Design : public SilecsServer::Design +{ +public: + + Design():SilecsServer::Design("%s", "%s") + { %s + } + + ~Design() + { %s + } + + /*! + * \\brief Return pointer to the requested device. + * \\param label Device label. + */ + %s_%s::Device* getDevice(const std::string& label) + { + if (deviceMap_.find(label) != deviceMap_.end()) + { + return dynamic_cast<%s_%s::Device*>(deviceMap_[label]); + } + return NULL; + } +};""" + +classHeader = """ +/* Copyright CERN 2015 + * + * WARNING: This code is automatically generated from your SILECS deploy unit document. + * You should never modify the content of this file as it would break consistency. + * Furthermore, any changes will be overwritten in the next code generation. + * Any modification shall be done using the SILECS development environment + * and regenerating this source code. + */ + +#ifndef %s_%s_H_ +#define %s_%s_H_ + +#include <silecs-virtual-controller/interface/Block.h> +#include <silecs-virtual-controller/interface/DeployUnit.h> +#include <silecs-virtual-controller/interface/Design.h> +#include <silecs-virtual-controller/interface/Device.h> + +namespace %s_%s +{ + +class Design; +%s + +%s + +%s + +} /* namespace */ +#endif +""" + + +#========================================================================= +# Virtual S7 generation Sub-function +#========================================================================= + +# SERVER MAIN code generation --------------------------------------------- +def vs7MainCode(deployName): + return mainCode %(deployName, deployName, deployName) + +# DEPLOY-UNIT generation ------------------------------------------------- +def vs7DuHeader(deployName, duConstructor, designIncludes, designAllocs, designDeletes, designGetters): + return duHeader %(deployName.upper(), deployName.upper(), designIncludes, deployName, duConstructor, designAllocs, designDeletes, designGetters) + +def vs7DuDesignInclude(designName, designVersion): + return duDesignInclude %(designName, designVersion) + +def vs7DuConstructor(deployName, mode, baseAddr): + return duConstructor %(deployName, mode, baseAddr) + +def vs7DuDesignAlloc(designName, designVersion): + designVersion = designVersion.replace(".", "_") + return duDesignAlloc %(designName, designName, designVersion) + +def vs7DuDesignDelete(designName): + return duDesignDelete %(designName) + +def vs7DuDesignGet(designName, designVersion): + designVersion = designVersion.replace(".", "_") + return duDesignGet %(designName, designVersion, designName, designName, designVersion, designName) + +# CLASSES generation ----------------------------------------------------- +def hexSwap32(input): + input = format(input, '#02X') + hexswap = input[0:2]+input[8:10]+input[6:8]+input[4:6]+input[2:4] + return hexswap + +def vs7ClassHeader(designName, designVersion, classBlocks, classDevice, classDesign): + designVersion = designVersion.replace(".", "_") + return classHeader %(designName.upper(), designVersion, designName.upper(), designVersion, designName, designVersion, classBlocks, classDevice, classDesign) + +def vs7ClassBlock(framework, owner, checksum, className, blockName, regsCode, blockOffset, regsDim, regsDef): + BlockName = iecommon.capitalizeString(blockName); + initCodeString = "" + if className == "SilecsHeader": + initCodeString = classHeaderInit %(framework, hexSwap32(checksum), owner) + return classBlock %(BlockName, blockName, BlockName, className, blockName, initCodeString, BlockName, regsCode, blockOffset, regsDim, regsDef) + +def vs7ClassGetSet(regName, regFormat, regDim1, regDim2, regLen): + RegName = iecommon.capitalizeString(regName) + regFormat = whichRegisterFormat[regFormat] + if regDim1 == 1 and regDim2 == 1: # scalar + if regFormat == 'string': + return classScalarStringGetSet %(regName, RegName, regName, regName, regName, RegName, regName, regName, regName, regName, regName) + else: + return classScalarGetSet %(regName, regFormat, RegName, regName, regName, RegName, regFormat, regName) + else: + if regFormat == 'string': + return classArrayStringGetSet %(regName, RegName, regName, regName, regName, regName, RegName, regName, regName, regName, regName, regName, regName) + else: + return classArrayGetSet %(regName, RegName, regFormat, regName, regName, regName, regFormat, regName, RegName, regFormat, regName, regName, regName, regFormat) + +def vs7ClassDimension(regName, regFormat, regDim1, regDim2, regLen): + dimCodeString = '' + if regDim1 > 1 or regDim2 > 1: # not a scalar ==> define dimension constants + dimCodeString += classArrayDim %(regName, regDim1, regName, regDim2) + if regFormat == 'string': + dimCodeString += classStringLen %(regName, regLen) + return dimCodeString + +def vs7ClassDummyRegister(curRegAddress, prevRegMemSize, regMemSize, dummyIndex): + dummyCodeString = '' + if curRegAddress % 2 != 0: #is current register address an odd address? + if prevRegMemSize > 1 or regMemSize > 1: #only 8bit scalar (not following array) uses 8bit alignment! + dummyCodeString = " uint8_t dummy%s;\n" %(dummyIndex) + return dummyCodeString + +def vs7ClassDataRegister(regName, regFormat, regDim1, regDim2, regLen): + length = '' + regFormat = whichRegisterFormat[regFormat] + if regFormat == 'string': + length = "[%sLen_+2]" %(regName) + regFormat = 'char' + dataCodeString = " %s %s" %(regFormat, regName) + if regDim1 > 1 or regDim2 > 1: # not scalar + dataCodeString += "[%sDim1_]" %(regName) + if regDim2 > 1: # not scalar + dataCodeString += "[%sDim2_]" %(regName) + dataCodeString += "%s;\n" %(length) + return dataCodeString + +def vs7ClassCreateBlock(className, blockName): + BlockName = iecommon.capitalizeString(blockName); + return classCreateBlock %(className, blockName, BlockName) + +def vs7ClassDeleteBlock(className, blockName): + return classDeleteBlock %(className, blockName) + +def vs7ClassCreateDevice(className, deviceLabel, deviceIndex): + return classCreateDevice %(className, deviceLabel, className, deviceLabel, deviceIndex) + +def vs7ClassDeleteDevice(className, deviceLabel): + return classDeleteDevice %(className, deviceLabel) + +def vs7ClassDevice(createBlocks, deleteBlocks): + return classDevice %(createBlocks, deleteBlocks) + +def vs7ClassDesign(className, classVersion, createDevices, deleteDevices): + class_version = classVersion.replace(".", "_") + return classDesign %(className, classVersion, createDevices, deleteDevices, className, class_version, className, class_version) diff --git a/silecs-codegen/src/xml/virtualS7Template.pyc b/silecs-codegen/src/xml/virtualS7Template.pyc new file mode 100644 index 0000000000000000000000000000000000000000..14d69d4be02f12e948ad1b478c0404b33e6a1da7 GIT binary patch literal 13802 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 BLX`jj literal 0 HcmV?d00001 diff --git a/silecs-codegen/src/xml/xmltemplate$py.class b/silecs-codegen/src/xml/xmltemplate$py.class new file mode 100644 index 0000000000000000000000000000000000000000..34dd9a3fce4319d640e1fe4cf9f38d94e2eaccd6 GIT binary patch literal 5708 zcmeHL>vtPh5&vDww$`eeI%=CZNs}t71CC{R?SwXMEIaX&D9Ey~91|x2v6fcyCaYbs zyNY98<x!xNH<a?GJPVXp>ZFQKLwJ7Uf8k6201k8ap~}|EDW`{T_?-3Ly?18r%-osz z&DB5u{l=dGjN%^*fl~hn!{R_%H_Bpl!&=idv7j5WnBAB&q>4P&vaqyf$Wk$9NtQfz zyk#}Jv9NkoE?8p>``d^NBES$dWlL2wnW1wab$mIDE_8>`i6DcZ$YoVul~e&e3=i*= zqExCuJiyRH1KqF|xQufH>8sLpNmM1REaogj(aNogdlsd3(K?I=u_uHu9wI%sih4m( z8N|0I-!+|^vlkI=&ckG%rBq}AkCM%0*{VvWDPTYAK=RCuiW<Ex8>XUb<FV1<kyupL z3VM;0ACFyFnoB$#J2MeV=2Gd|>0Dw)HkGm#H5FAZn2844$nfY0=Pb~nSaNYZcFc@L zYt`agAE7Ay(N>yy`i7~D$JQ*XdRi3M*Vl*FPY!eMo){S!6)(=GbA>gzA|({fv?Q${ z#~e;mIj!j#3I($&6=a7dO>VJlwQ0Kvn=YBsO1e?8r=1zTZ*pN>lZ|N2l#PU{mlZOU zIK(D`*`i|U?I@CBi&W1a(<*r~s*zrf&CMR+4k_vtiEp=%on4$<N-bn2)2^nrUQ=|k z*If2kw4xVDOw+nevnZDp(<1eqU1CwkKq8Eq8(Lw_&}rCgi)c%A{UN#sXDdqQ=zTi} zIS~?YfT3?^bZ0l5@D1V+L%3w<m6S#*XmXKZ*e448V%bfAFb?BL2#?`$hCM|)e3s-& zRi)4naFij^x_1yy(5|zUs^zA!$#Cd$`y>zJ7~a)`e!QFEV5_*fnpWUp62x)J*HYd| zYm#|zH<57+^-$_0DEBF09Cvw&_m7ewnsp?-eV4eI8O8`kd0w92>1`P$CpX{Ydk_v! z5Kl2Ykk8Yml4TkBd>Bu28K>|JL&vcj0;tpp`8?GLHJ@k5wU*N6irL<9zmsgJJ&p;! z<r#(}1F2nP*p+9JTR7#^8=iRrW*DB?U9bD>KF4=|uWwCXs#R4vh!lB&eB>6)!&KDU zs~N`okmgFxGjt~vO|d4pVY>txFR2U2hHxJ5r;?hdgk^ZD)uaae?7DjnOWd9d<f2lZ z>WHN<uv8cyz(pQ;E0ix(FfBJ(`l}m3T&585F=(0!$5<F5KG=gR_z=U@U3A*TzILL0 z=9@rf0Ur)w5E8@QmP`>)V1YOPYmlj``o{l3COIQ>M<gy#Xtu|gCKSslaz)n6L^eH5 z*g&9B8ILWcCKK6(#U%nB8(`G&SS~eBSTvo_ol2Y>A&{yXx}_I%TA7($PEF6|=ND#X zW6@Q~loK;k39VLHl@00*Jd{a_O^UfV<Ibd9)HXe>lGD0o8M>+xfUW7Km2gqa1+0ds z9gLpoHf+faY0;#MV;mX1zhqIqt`y{iN-*hd>#Y&?&)BO`Ra%v~?RMvKj(SJg@a*x3 zlVV#*Nv`%pGjme3r|hnyA;5+I32LK;N0OrV=@BKx?drc{Yvwl`>l#PX(Byum?5h5K zG;bVQ<8+$Z3Lde%t)PCG;GTbZs41ZAfobz}|A{aZr*d8ON=Wm%0BU_ZGrA^+p>a^| zhtBY*Ul+2>@OXRtUy@ciL>P447;q}N6@rNxNjGJ+#L%1GUT>+SuHyzTsT;Jov$YT6 zV+1xy!ho78PYCz~)p1Q;=e3yO<$=^?pUc2b8Dp(9sY{o9%B|PK*fxy$$@bYU<%@nU zSUihQg~*kk4ud()|13ku>CZA0>jFMU-=^J*XC-S*z!%6*yrCEHMTRb&chmyDWHa&O za+tp2;Qc%`z0_X~_~D<uKgr^aF~dH>+ZL}JUlwqgL+wXG<op-I_!_>>M=$yGcU)Xr z=jj~8cPTEMD@cy6WvV=->lXD_Qq{Nd$ZpuGwCc#G8>|!r-^UL^_#S>pwiz|evF*uL zgx${OYgQOP#>?F8KcRpku-wMNaMZ_P+eoO%d!jYK7i*fvW4obq5WiqJPV(od+VL_) zMVS0hE6^QhQ7+NljrYS1a)uMl*<@$6&!u|1CSkmSUxn~X{F>oGyX`EweKzktQ+_f0 zj&AZiPCIxI{Ejy|_UI41aM+`pK7o<l@ca_QCPQ?)MwKeL#t<j7sb%NxORnv@E~zy+ zKtD?K(}lyAetwCr(PLczyO4Ra{5<uGzGR-?N$5rTA)`{E-!s<qiYyWaiIi09il&LG zc0*j(jcfLeHsM~WE0SS~?zlj4Se7->GzubBCjNNc;Bb{n(xIK9(A44w@h8eLeq;;} zrRgV*jE&-U{h+c%Kb#b<&GW<v<@B0Skh#VT2gqgoGP10g3I)`prs;Iwpja_+lw5Dp z8Qh}QRN!@y+|<WwhyAA3(|%JSr?)`!bXxTAUwHn7ZsGy%#XIW|BB6N47J4)BNGMUq zBP<i|;<Nj_*?sP8H=phEX8YXPUV%>^+(MKD#JtJ<G`Wd^%v}tw#BXCbv57ppgH@s_ zdNfhaSaKNGyvehzjMrSoic8b+IxcOZdXo%b_zV3%f}lMH83^!b5$M@ZPn4dsL`C80 zntq$sxalv(d;4gscw}E4CnHbRae63{Bwgw_OZL-F)8vQV12zc}o{Y?Lk~+?1;@#fr zL3=eut9NmJrMLSYPOSvE^D?=WPWRo#T}<EIadIEMgYH|12l)3LEY`7{iF2D0Z&|d* zwxW;pJV4Ju(w)+()q=_UTQIe&1=IHG+W*XgNz#6bo@vsZu*0?BCHgUqpVAA1cW{01 z7CssX+{4G`hvJb>1_FUi`erP!w-;OZ%q=|E6|@%vk<aIbIwQ~LhPomz<c7K<U(OLj zv3I}C(P?uqn<L-g_^J;_rT47O(bdFp?KRSdM-!o%t79*{8O?QW;yHdUKo7owZ@Q~d z(x0zBau-)tBHy}$Z`bjiE&OP33qN&a_26gtxl0|fX@Ty@l`Z_nk;d>Ue(SEkLJ`Sh za(Hkkap+aP7ck(w?1+Ah#!-6u>-hc6I{rw{Yd4t_Eq|r?5^+b-8N?M9<ga@O(AXXJ sw_6x!w=mRhp#y)T-8yg=f2a3h^1*Gg;Pn*hxWfnM>BQdP0~2@u1E`)W$N&HU literal 0 HcmV?d00001 diff --git a/silecs-codegen/src/xml/xmltemplate.py b/silecs-codegen/src/xml/xmltemplate.py new file mode 100644 index 0000000..19bdc3f --- /dev/null +++ b/silecs-codegen/src/xml/xmltemplate.py @@ -0,0 +1,92 @@ +#!/usr/bin/python +# Copyright 2016 CERN and GSI +# +# 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 3 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, see <http://www.gnu.org/licenses/>. + +import time +import getpass + +#========================================================= +# SILECS Header +#========================================================= +silecsHeader = """<?xml version="1.0" encoding="UTF-8"?> +<SILECS-Design silecs-version="%s" created="%s" updated="%s" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> + <Information> + <Owner user-login="%s"/> + <Editor user-login="%s"/> + </Information> + <SILECS-Class domain="TEST" name="SilecsHeader" version="1.0.0"> + <Block mode="READ-ONLY" name="hdrBlk"> + <Register array-dim1="1" array-dim2="1" format="string" name="_version" string-len="16" synchro="MASTER"/> + <Register array-dim1="1" array-dim2="1" format="uint32" name="_checksum" synchro="MASTER"/> + <Register array-dim1="1" array-dim2="1" format="string" name="_user" string-len="16" synchro="MASTER"/> + <Register array-dim1="1" array-dim2="1" format="dt" name="_date" synchro="MASTER"/> + </Block> + </SILECS-Class> +</SILECS-Design> +""" +def getSilecsHeader(silecsVersion): + date = time.strftime("%x") + owner = getpass.getuser() + return silecsHeader%(silecsVersion,date,date,owner,owner) + +#========================================================= +# DESIGN TEMPLATE +#========================================================= +designTemplate = """<?xml version="1.0" encoding="UTF-8"?> +<SILECS-Design silecs-version="%s" created="%s" updated="%s" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="%s"> + <Information> + <Owner user-login="%s"/> + <Editor user-login="%s"/> + </Information> + <SILECS-Class name="%s" version="0.1.0" domain="OPERATIONAL" > + <Block name="MyBlock" mode="READ-ONLY" generateFesaProperty="true"> + <Register name="myRegister" format="int32" synchro="MASTER" generateFesaValueItem="true" /> + </Block> + </SILECS-Class> +</SILECS-Design> +""" +def getDesignTemplate(designName,schemaPath,silecsVersion): + date = time.strftime("%x") + owner = getpass.getuser() + return designTemplate%(silecsVersion,date,date,schemaPath,owner,owner,designName) + + +#========================================================= +# DEPLOY TEMPLATE +#========================================================= +deployTemplate = """<?xml version="1.0" encoding="UTF-8"?> +<SILECS-Deploy silecs-version="%s" created="%s" updated="%s" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="%s"> + <Information> + <Owner user-login="%s"/> + <Editor user-login="%s"/> + </Information> + <Deploy-Unit name="%s" version="0.1.0"/> + <Controller host-name=""> + <Siemens-PLC system="TIA-PORTAL" model="SIMATIC_S7-300" protocol="DEVICE_MODE" base-DB-number="1"/> + <SilecsDesign silecs-design-version="" silecs-design-name=""> + <Device device-name="" /> + </SilecsDesign> + </Controller> +</SILECS-Deploy> +""" + +def getDeployTemplate(deployName, schemaPath, silecsVersion): + date = time.strftime("%x") + owner = getpass.getuser() + return deployTemplate%(silecsVersion,date,date,schemaPath,owner,owner,deployName) diff --git a/silecs-codegen/src/xml/xmltemplate.pyc b/silecs-codegen/src/xml/xmltemplate.pyc new file mode 100644 index 0000000000000000000000000000000000000000..46d3c492178e07ac49213bf454153fc49bf7aa15 GIT binary patch literal 3346 zcmds(-EP}96vrvsNt!HOF`y{0J3&A(-^j`buoZ!w&aqw0fMXkyo3+7!K#>?*utXXp zUB^Ir)xE<WWzVr!*$ZsvP?D`=3$Pab0A@%uNlAx1<oW%1{`m9Z&hJOR{Tz_&SBC!| z;g($}LbwbvCFFcnH^{j`!V)<zk+4jDg-2x)R>*mUgd4iKLBdUPzDdF@-P}S8UiAT3 zi~fRNU)EuW`t$1~Hs4SoBhDJuer?Y(DGPWQv2nwCIeK9~vz{OC)V*%6)AH;#mC=}) zGKy&+?bT;brDX<!`ih1P3mfxUxNg7*Odeg!s9{Z%njJaLVzH<#4r^SDorAr-edpC_ z&kH6r@$HC7<+FfV$2%tc>RoolMdB-%UD~622Mb1pIhRz}F&{@TaTwGoywC|F#qWEg z?%c7Od)JD6Db0{4KAIeLypd%xKcNlF(+>Yc{g4Xl)^fpuWm7$gc`!8-9>V)>r`fg# z{od=`z$6qW@icoC{Br3yk_w#gh47bl7$y6#`qsL6pqr`l4NEEk8<HEl$QIr*(|$Xq zxOd+}d&z={;0^1v>5V$>dQIMUz<I>f;lXM^*qmT0=gCJL;f_nVnV-;~P_2By$h_B& zx}&!dx3unLL9fFC7|7cx1jjpp0W2Y=n{c<_mIqKM;0wSs$UB3)HHa#as7&4w^0q`& zh1?KwW9X|yZc5~8gFNx7CHSl_v3z=6-9Q@^ETV)e#1&TRN;kHkF{Ww;QL3^!E}PoL zmkJSD#Yw4$tKPE|Z*3L5S2zYohN@5@x{$A+<^()RICCaEq0S|Z9T`j(5o1owuAK!J zQ#tbkYG?Q-zK~8<2gRUc${Z;I2YAO@(PS3GXtmi=Jp$t}^CCvyL6^jpBgP|R*O0$} z|DQvRw61)RB&A=<=!o$?sDfULRJM9N&=RF}D3gOb8iTq8G4+v^3oI6cG*c^7;FUJ- z)wHPRsx}yQ+~%k|=r?<oSy0SWy;8M1UFw$gPcefnrULf#1(p6#@EHW(vSBGP&jmYm zvnX(>$z+);o@M5umPyQA%`%IFocZybb|I9qQOu&suUY*sv?3H3_=uFI^%+!d(ONFh zTG6xuq-A{pvjDH=_iF23nRUS$aZwUnB-zyrehsxypP8eKhLrD}RX;|O!X}^w2jI|G z6BlRcA{s7I{<#?a2F3zLQ+3OydkmdLO8JLSI*a-8J#&Wt8>MZEi(tQGk-8sJi0$oq zi!&v797Ap};ZoTtKae?WYXR{hnouU~VXp<JJ){so#;Du0hXZ$nNMrsHL&DNM1<G3& z-VgTS9^`a0!4(fUJZX2%x~<N|>7d=Q%u8QVyM1D_d2&ewrW`nj?RqNIx3j%8j@L;a zoS|tNm_1le6b!WKn<$`WsQ+>w5MFrZ6s@Dn&f4c&$1E-x9J5~zT%15oLJ?f-M{wP* z5YjJ<YjKjVZ{w=7{ZyE=CSh9PqW-ztSYY1ZVw&LM`MlN{UHh~N0ZyV0u{w|GF$#}F SrQ9`kA8#7lPvHJ`v-CHzoRpFP literal 0 HcmV?d00001 diff --git a/silecs-communication-cpp/.cproject b/silecs-communication-cpp/.cproject new file mode 100644 index 0000000..b71572d --- /dev/null +++ b/silecs-communication-cpp/.cproject @@ -0,0 +1,162 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<?fileVersion 4.0.0?><cproject storage_type_id="org.eclipse.cdt.core.XmlProjectDescriptionStorage"> + <storageModule moduleId="org.eclipse.cdt.core.settings"> + <cconfiguration id="cdt.managedbuild.config.gnu.exe.debug.512849333"> + <storageModule buildSystemId="org.eclipse.cdt.managedbuilder.core.configurationDataProvider" id="cdt.managedbuild.config.gnu.exe.debug.512849333" moduleId="org.eclipse.cdt.core.settings" name="Debug"> + <externalSettings/> + <extensions> + <extension id="org.eclipse.cdt.core.ELF" point="org.eclipse.cdt.core.BinaryParser"/> + <extension id="org.eclipse.cdt.core.GASErrorParser" point="org.eclipse.cdt.core.ErrorParser"/> + <extension id="org.eclipse.cdt.core.GmakeErrorParser" point="org.eclipse.cdt.core.ErrorParser"/> + <extension id="org.eclipse.cdt.core.GLDErrorParser" point="org.eclipse.cdt.core.ErrorParser"/> + <extension id="org.eclipse.cdt.core.CWDLocator" point="org.eclipse.cdt.core.ErrorParser"/> + <extension id="org.eclipse.cdt.core.GCCErrorParser" point="org.eclipse.cdt.core.ErrorParser"/> + </extensions> + </storageModule> + <storageModule moduleId="cdtBuildSystem" version="4.0.0"> + <configuration artifactName="${ProjName}" buildArtefactType="org.eclipse.cdt.build.core.buildArtefactType.exe" buildProperties="org.eclipse.cdt.build.core.buildArtefactType=org.eclipse.cdt.build.core.buildArtefactType.exe,org.eclipse.cdt.build.core.buildType=org.eclipse.cdt.build.core.buildType.debug" cleanCommand="rm -rf" description="" id="cdt.managedbuild.config.gnu.exe.debug.512849333" name="Debug" parent="cdt.managedbuild.config.gnu.exe.debug"> + <folderInfo id="cdt.managedbuild.config.gnu.exe.debug.512849333." name="/" resourcePath=""> + <toolChain id="cdt.managedbuild.toolchain.gnu.exe.debug.291928248" name="Linux GCC" superClass="cdt.managedbuild.toolchain.gnu.exe.debug"> + <targetPlatform id="cdt.managedbuild.target.gnu.platform.exe.debug.787865719" name="Debug Platform" superClass="cdt.managedbuild.target.gnu.platform.exe.debug"/> + <builder buildPath="${workspace_loc:/silecs-communication-cpp}" id="cdt.managedbuild.target.gnu.builder.exe.debug.1509177360" keepEnvironmentInBuildfile="false" managedBuildOn="false" name="Gnu Make Builder" superClass="cdt.managedbuild.target.gnu.builder.exe.debug"/> + <tool id="cdt.managedbuild.tool.gnu.archiver.base.1070762906" name="GCC Archiver" superClass="cdt.managedbuild.tool.gnu.archiver.base"/> + <tool id="cdt.managedbuild.tool.gnu.cpp.compiler.exe.debug.290909559" name="GCC C++ Compiler" superClass="cdt.managedbuild.tool.gnu.cpp.compiler.exe.debug"> + <option id="gnu.cpp.compiler.exe.debug.option.optimization.level.1848198526" name="Optimization Level" superClass="gnu.cpp.compiler.exe.debug.option.optimization.level" value="gnu.cpp.compiler.optimization.level.none" valueType="enumerated"/> + <option id="gnu.cpp.compiler.exe.debug.option.debugging.level.240667535" name="Debug Level" superClass="gnu.cpp.compiler.exe.debug.option.debugging.level" value="gnu.cpp.compiler.debugging.level.max" valueType="enumerated"/> + <option id="gnu.cpp.compiler.option.include.paths.773424835" name="Include paths (-I)" superClass="gnu.cpp.compiler.option.include.paths" valueType="includePath"> + <listOptionValue builtIn="false" value="/acc/sys/L866/usr/include/libxml2"/> + <listOptionValue builtIn="false" value="/acc/sys/L866/usr/local/natinst/ninetv/include"/> + </option> + <inputType id="cdt.managedbuild.tool.gnu.cpp.compiler.input.1806199416" superClass="cdt.managedbuild.tool.gnu.cpp.compiler.input"/> + </tool> + <tool id="cdt.managedbuild.tool.gnu.c.compiler.exe.debug.926882765" name="GCC C Compiler" superClass="cdt.managedbuild.tool.gnu.c.compiler.exe.debug"> + <option defaultValue="gnu.c.optimization.level.none" id="gnu.c.compiler.exe.debug.option.optimization.level.116711054" name="Optimization Level" superClass="gnu.c.compiler.exe.debug.option.optimization.level" valueType="enumerated"/> + <option id="gnu.c.compiler.exe.debug.option.debugging.level.1551801327" name="Debug Level" superClass="gnu.c.compiler.exe.debug.option.debugging.level" value="gnu.c.debugging.level.max" valueType="enumerated"/> + <inputType id="cdt.managedbuild.tool.gnu.c.compiler.input.2005171832" superClass="cdt.managedbuild.tool.gnu.c.compiler.input"/> + </tool> + <tool id="cdt.managedbuild.tool.gnu.c.linker.exe.debug.1604657084" name="GCC C Linker" superClass="cdt.managedbuild.tool.gnu.c.linker.exe.debug"/> + <tool id="cdt.managedbuild.tool.gnu.cpp.linker.exe.debug.2022173025" name="GCC C++ Linker" superClass="cdt.managedbuild.tool.gnu.cpp.linker.exe.debug"> + <inputType id="cdt.managedbuild.tool.gnu.cpp.linker.input.1144333070" superClass="cdt.managedbuild.tool.gnu.cpp.linker.input"> + <additionalInput kind="additionalinputdependency" paths="$(USER_OBJS)"/> + <additionalInput kind="additionalinput" paths="$(LIBS)"/> + </inputType> + </tool> + <tool id="cdt.managedbuild.tool.gnu.assembler.exe.debug.713866492" name="GCC Assembler" superClass="cdt.managedbuild.tool.gnu.assembler.exe.debug"> + <inputType id="cdt.managedbuild.tool.gnu.assembler.input.1838795874" superClass="cdt.managedbuild.tool.gnu.assembler.input"/> + </tool> + </toolChain> + </folderInfo> + <sourceEntries> + <entry excluding="src" flags="VALUE_WORKSPACE_PATH|RESOLVED" kind="sourcePath" name=""/> + <entry flags="VALUE_WORKSPACE_PATH|RESOLVED" kind="sourcePath" name="src"/> + </sourceEntries> + </configuration> + </storageModule> + <storageModule moduleId="org.eclipse.cdt.core.externalSettings"/> + </cconfiguration> + <cconfiguration id="cdt.managedbuild.config.gnu.exe.release.10628772"> + <storageModule buildSystemId="org.eclipse.cdt.managedbuilder.core.configurationDataProvider" id="cdt.managedbuild.config.gnu.exe.release.10628772" moduleId="org.eclipse.cdt.core.settings" name="Release"> + <externalSettings/> + <extensions> + <extension id="org.eclipse.cdt.core.ELF" point="org.eclipse.cdt.core.BinaryParser"/> + <extension id="org.eclipse.cdt.core.GASErrorParser" point="org.eclipse.cdt.core.ErrorParser"/> + <extension id="org.eclipse.cdt.core.GmakeErrorParser" point="org.eclipse.cdt.core.ErrorParser"/> + <extension id="org.eclipse.cdt.core.GLDErrorParser" point="org.eclipse.cdt.core.ErrorParser"/> + <extension id="org.eclipse.cdt.core.CWDLocator" point="org.eclipse.cdt.core.ErrorParser"/> + <extension id="org.eclipse.cdt.core.GCCErrorParser" point="org.eclipse.cdt.core.ErrorParser"/> + </extensions> + </storageModule> + <storageModule moduleId="cdtBuildSystem" version="4.0.0"> + <configuration artifactName="${ProjName}" buildArtefactType="org.eclipse.cdt.build.core.buildArtefactType.exe" buildProperties="org.eclipse.cdt.build.core.buildArtefactType=org.eclipse.cdt.build.core.buildArtefactType.exe,org.eclipse.cdt.build.core.buildType=org.eclipse.cdt.build.core.buildType.release" cleanCommand="rm -rf" description="" id="cdt.managedbuild.config.gnu.exe.release.10628772" name="Release" parent="cdt.managedbuild.config.gnu.exe.release"> + <folderInfo id="cdt.managedbuild.config.gnu.exe.release.10628772." name="/" resourcePath=""> + <toolChain id="cdt.managedbuild.toolchain.gnu.exe.release.1581125062" name="Linux GCC" superClass="cdt.managedbuild.toolchain.gnu.exe.release"> + <targetPlatform id="cdt.managedbuild.target.gnu.platform.exe.release.2014534690" name="Debug Platform" superClass="cdt.managedbuild.target.gnu.platform.exe.release"/> + <builder buildPath="${workspace_loc:/silecs-communication-cpp}/Release" id="cdt.managedbuild.target.gnu.builder.exe.release.1372487654" keepEnvironmentInBuildfile="false" managedBuildOn="false" name="Gnu Make Builder" superClass="cdt.managedbuild.target.gnu.builder.exe.release"/> + <tool id="cdt.managedbuild.tool.gnu.archiver.base.1846481553" name="GCC Archiver" superClass="cdt.managedbuild.tool.gnu.archiver.base"/> + <tool id="cdt.managedbuild.tool.gnu.cpp.compiler.exe.release.1485392940" name="GCC C++ Compiler" superClass="cdt.managedbuild.tool.gnu.cpp.compiler.exe.release"> + <option id="gnu.cpp.compiler.exe.release.option.optimization.level.1550802779" name="Optimization Level" superClass="gnu.cpp.compiler.exe.release.option.optimization.level" value="gnu.cpp.compiler.optimization.level.most" valueType="enumerated"/> + <option id="gnu.cpp.compiler.exe.release.option.debugging.level.298964746" name="Debug Level" superClass="gnu.cpp.compiler.exe.release.option.debugging.level" value="gnu.cpp.compiler.debugging.level.none" valueType="enumerated"/> + <inputType id="cdt.managedbuild.tool.gnu.cpp.compiler.input.2075338207" superClass="cdt.managedbuild.tool.gnu.cpp.compiler.input"/> + </tool> + <tool id="cdt.managedbuild.tool.gnu.c.compiler.exe.release.1258122871" name="GCC C Compiler" superClass="cdt.managedbuild.tool.gnu.c.compiler.exe.release"> + <option defaultValue="gnu.c.optimization.level.most" id="gnu.c.compiler.exe.release.option.optimization.level.674087208" name="Optimization Level" superClass="gnu.c.compiler.exe.release.option.optimization.level" valueType="enumerated"/> + <option id="gnu.c.compiler.exe.release.option.debugging.level.391864083" name="Debug Level" superClass="gnu.c.compiler.exe.release.option.debugging.level" value="gnu.c.debugging.level.none" valueType="enumerated"/> + <inputType id="cdt.managedbuild.tool.gnu.c.compiler.input.1302098703" superClass="cdt.managedbuild.tool.gnu.c.compiler.input"/> + </tool> + <tool id="cdt.managedbuild.tool.gnu.c.linker.exe.release.1792257196" name="GCC C Linker" superClass="cdt.managedbuild.tool.gnu.c.linker.exe.release"/> + <tool id="cdt.managedbuild.tool.gnu.cpp.linker.exe.release.121789533" name="GCC C++ Linker" superClass="cdt.managedbuild.tool.gnu.cpp.linker.exe.release"> + <inputType id="cdt.managedbuild.tool.gnu.cpp.linker.input.1798359589" superClass="cdt.managedbuild.tool.gnu.cpp.linker.input"> + <additionalInput kind="additionalinputdependency" paths="$(USER_OBJS)"/> + <additionalInput kind="additionalinput" paths="$(LIBS)"/> + </inputType> + </tool> + <tool id="cdt.managedbuild.tool.gnu.assembler.exe.release.1548384146" name="GCC Assembler" superClass="cdt.managedbuild.tool.gnu.assembler.exe.release"> + <inputType id="cdt.managedbuild.tool.gnu.assembler.input.317662810" superClass="cdt.managedbuild.tool.gnu.assembler.input"/> + </tool> + </toolChain> + </folderInfo> + <sourceEntries> + <entry excluding="src" flags="VALUE_WORKSPACE_PATH|RESOLVED" kind="sourcePath" name=""/> + <entry flags="VALUE_WORKSPACE_PATH|RESOLVED" kind="sourcePath" name="src"/> + </sourceEntries> + </configuration> + </storageModule> + <storageModule moduleId="org.eclipse.cdt.core.externalSettings"/> + </cconfiguration> + </storageModule> + <storageModule moduleId="cdtBuildSystem" version="4.0.0"> + <project id="silecs-communication-cpp.cdt.managedbuild.target.gnu.exe.86499621" name="Executable" projectType="cdt.managedbuild.target.gnu.exe"/> + </storageModule> + <storageModule moduleId="scannerConfiguration"> + <autodiscovery enabled="true" problemReportingEnabled="true" selectedProfileId=""/> + <scannerConfigBuildInfo instanceId="cdt.managedbuild.config.gnu.exe.debug.512849333;cdt.managedbuild.config.gnu.exe.debug.512849333.;cdt.managedbuild.tool.gnu.cpp.compiler.exe.debug.290909559;cdt.managedbuild.tool.gnu.cpp.compiler.input.1806199416"> + <autodiscovery enabled="true" problemReportingEnabled="true" selectedProfileId=""/> + </scannerConfigBuildInfo> + <scannerConfigBuildInfo instanceId="cdt.managedbuild.config.gnu.exe.release.10628772;cdt.managedbuild.config.gnu.exe.release.10628772.;cdt.managedbuild.tool.gnu.c.compiler.exe.release.1258122871;cdt.managedbuild.tool.gnu.c.compiler.input.1302098703"> + <autodiscovery enabled="true" problemReportingEnabled="true" selectedProfileId=""/> + </scannerConfigBuildInfo> + <scannerConfigBuildInfo instanceId="cdt.managedbuild.config.gnu.exe.release.10628772;cdt.managedbuild.config.gnu.exe.release.10628772.;cdt.managedbuild.tool.gnu.cpp.compiler.exe.release.1485392940;cdt.managedbuild.tool.gnu.cpp.compiler.input.2075338207"> + <autodiscovery enabled="true" problemReportingEnabled="true" selectedProfileId=""/> + </scannerConfigBuildInfo> + <scannerConfigBuildInfo instanceId="cdt.managedbuild.config.gnu.exe.debug.512849333;cdt.managedbuild.config.gnu.exe.debug.512849333.;cdt.managedbuild.tool.gnu.c.compiler.exe.debug.926882765;cdt.managedbuild.tool.gnu.c.compiler.input.2005171832"> + <autodiscovery enabled="true" problemReportingEnabled="true" selectedProfileId=""/> + </scannerConfigBuildInfo> + </storageModule> + <storageModule moduleId="org.eclipse.cdt.core.LanguageSettingsProviders"/> + <storageModule moduleId="refreshScope" versionNumber="2"> + <configuration configurationName="Debug"> + <resource resourceType="PROJECT" workspacePath="/silecs-communication-cpp"/> + </configuration> + <configuration configurationName="Release"> + <resource resourceType="PROJECT" workspacePath="/silecs-communication-cpp"/> + </configuration> + </storageModule> + <storageModule moduleId="org.eclipse.cdt.internal.ui.text.commentOwnerProjectMappings"/> + <storageModule moduleId="org.eclipse.cdt.make.core.buildtargets"> + <buildTargets> + <target name="clean" path="" targetID="org.eclipse.cdt.build.MakeTargetBuilder"> + <buildCommand>make</buildCommand> + <buildArguments/> + <buildTarget>clean</buildTarget> + <stopOnError>true</stopOnError> + <useDefaultCommand>true</useDefaultCommand> + <runAllBuilders>true</runAllBuilders> + </target> + <target name="x86_64" path="" targetID="org.eclipse.cdt.build.MakeTargetBuilder"> + <buildCommand>make</buildCommand> + <buildTarget>CPU=x86_64 -j4</buildTarget> + <stopOnError>true</stopOnError> + <useDefaultCommand>true</useDefaultCommand> + <runAllBuilders>true</runAllBuilders> + </target> + <target name="release" path="" targetID="org.eclipse.cdt.build.MakeTargetBuilder"> + <buildCommand>make</buildCommand> + <buildArguments/> + <buildTarget>release RELEASE_GROUP=bel RELEASE_LOCATION=~ SVN_REPOSITORY=https://www-acc.gsi.de/svn/silecs/silecs-communication-cpp</buildTarget> + <stopOnError>true</stopOnError> + <useDefaultCommand>true</useDefaultCommand> + <runAllBuilders>true</runAllBuilders> + </target> + </buildTargets> + </storageModule> +</cproject> diff --git a/silecs-communication-cpp/.project b/silecs-communication-cpp/.project new file mode 100644 index 0000000..230d8b7 --- /dev/null +++ b/silecs-communication-cpp/.project @@ -0,0 +1,33 @@ +<?xml version="1.0" encoding="UTF-8"?> +<projectDescription> + <name>silecs-communication-cpp</name> + <comment></comment> + <projects> + </projects> + <buildSpec> + <buildCommand> + <name>org.python.pydev.PyDevBuilder</name> + <arguments> + </arguments> + </buildCommand> + <buildCommand> + <name>org.eclipse.cdt.managedbuilder.core.genmakebuilder</name> + <triggers>clean,full,incremental,</triggers> + <arguments> + </arguments> + </buildCommand> + <buildCommand> + <name>org.eclipse.cdt.managedbuilder.core.ScannerConfigBuilder</name> + <triggers>full,incremental,</triggers> + <arguments> + </arguments> + </buildCommand> + </buildSpec> + <natures> + <nature>org.eclipse.cdt.core.cnature</nature> + <nature>org.eclipse.cdt.core.ccnature</nature> + <nature>org.eclipse.cdt.managedbuilder.core.managedBuildNature</nature> + <nature>org.eclipse.cdt.managedbuilder.core.ScannerConfigNature</nature> + <nature>org.python.pydev.pythonNature</nature> + </natures> +</projectDescription> diff --git a/silecs-communication-cpp/LICENSE b/silecs-communication-cpp/LICENSE new file mode 100644 index 0000000..20d40b6 --- /dev/null +++ b/silecs-communication-cpp/LICENSE @@ -0,0 +1,674 @@ + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/> + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + <one line to give the program's name and a brief idea of what it does.> + Copyright (C) <year> <name of author> + + 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 3 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, see <http://www.gnu.org/licenses/>. + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + <program> Copyright (C) <year> <name of author> + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +<http://www.gnu.org/licenses/>. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +<http://www.gnu.org/philosophy/why-not-lgpl.html>. \ No newline at end of file diff --git a/silecs-communication-cpp/Makefile b/silecs-communication-cpp/Makefile new file mode 100644 index 0000000..b6f166c --- /dev/null +++ b/silecs-communication-cpp/Makefile @@ -0,0 +1,32 @@ +# Copyright 2016 CERN and GSI +# +# 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 3 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, see <http://www.gnu.org/licenses/>. + +PROJECT = silecs +PRODUCT = communication +VERSION = 1.0.4 + +COMMON_MAKE_PATH ?= /opt/cern/buildsystem/generic/2.8.20 + +# product configuration +LIB_NAME = comm +DBG = true + +COMPILER_FLAGS = -Os -fno-strict-aliasing -fexceptions -DLINUX -DARM_FIX -DDAVE_LITTLE_ENDIAN -D_GNU_SOURCE -DMAJOR=$(MAJOR) -DMINOR=$(MINOR) -DPATCH=$(PATCH) + +# Comment IN/Out to enable NI-Support +#COMPILER_FLAGS += -DNI_SUPPORT_ENABLED=TRUE + +# Include the generic make file +include $(COMMON_MAKE_PATH)/Make.generic \ No newline at end of file diff --git a/silecs-communication-cpp/Makefile.dep b/silecs-communication-cpp/Makefile.dep new file mode 100644 index 0000000..09e8471 --- /dev/null +++ b/silecs-communication-cpp/Makefile.dep @@ -0,0 +1,9 @@ +BOOST_VERSION ?= 1.54.0 + +LIBXML_PATH = /usr/include/libxml2/ +SNAP7_BASE = ../snap7/snap7-full +BOOST_HOME ?= /acc/local/$(CPU)/3rdparty/boost/$(BOOST_VERSION) + +DEPENDENT_COMPILER_OPTIONS += -I$(LIBXML_PATH) +DEPENDENT_COMPILER_OPTIONS += -I$(SNAP7_BASE)/release/Wrappers/c-cpp +DEPENDENT_COMPILER_OPTIONS += -I$(BOOST_HOME)/include \ No newline at end of file diff --git a/silecs-communication-cpp/README.md b/silecs-communication-cpp/README.md new file mode 100644 index 0000000..62bc0e1 --- /dev/null +++ b/silecs-communication-cpp/README.md @@ -0,0 +1,19 @@ +# silecs-codegen + +This component of the SILECS PLC-framework establishes a PLC-connection by using brand-specific protocols + +## Getting Started + +Please check the lab-specific SILECS-Wikis for more information: + +[CERN SILECS Wiki Page][CERN_Wiki] + +[GSI SILECS Wiki Page][GSI_Wiki] + +## License + +Licensed under the GNU GENERAL PUBLIC LICENSE Version 3. See the [LICENSE file][license] for details. + +[license]: LICENSE +[CERN_Wiki]: https://wikis.cern.ch/display/SIL/SILECs+Home +[GSI_Wiki]: https://www-acc.gsi.de/wiki/Frontend/SILECS \ No newline at end of file diff --git a/silecs-communication-cpp/docs/Doxyfile b/silecs-communication-cpp/docs/Doxyfile new file mode 100644 index 0000000..a158944 --- /dev/null +++ b/silecs-communication-cpp/docs/Doxyfile @@ -0,0 +1,1519 @@ +# Doxyfile 1.6.1 + +# This file describes the settings to be used by the documentation system +# doxygen (www.doxygen.org) for a project +# +# All text after a hash (#) is considered a comment and will be ignored +# The format is: +# TAG = value [value, ...] +# For lists items can also be appended using: +# TAG += value [value, ...] +# Values that contain spaces should be placed between quotes (" ") + +#--------------------------------------------------------------------------- +# Project related configuration options +#--------------------------------------------------------------------------- + +# This tag specifies the encoding used for all characters in the config file +# that follow. The default is UTF-8 which is also the encoding used for all +# text before the first occurrence of this tag. Doxygen uses libiconv (or the +# iconv built into libc) for the transcoding. See +# http://www.gnu.org/software/libiconv for the list of possible encodings. + +DOXYFILE_ENCODING = UTF-8 + +# The PROJECT_NAME tag is a single word (or a sequence of words surrounded +# by quotes) that should identify the project. + +PROJECT_NAME = SILECS + +# The PROJECT_NUMBER tag can be used to enter a project or revision number. +# This could be handy for archiving the generated documentation or +# if some version control system is used. + +PROJECT_NUMBER = 1.m.p + +# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) +# base path where the generated documentation will be put. +# If a relative path is entered, it will be relative to the location +# where doxygen was started. If left blank the current directory will be used. + +OUTPUT_DIRECTORY = ../API + +# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create +# 4096 sub-directories (in 2 levels) under the output directory of each output +# format and will distribute the generated files over these directories. +# Enabling this option can be useful when feeding doxygen a huge amount of +# source files, where putting all generated files in the same directory would +# otherwise cause performance problems for the file system. + +CREATE_SUBDIRS = NO + +# The OUTPUT_LANGUAGE tag is used to specify the language in which all +# documentation generated by doxygen is written. Doxygen will use this +# information to generate all constant output in the proper language. +# The default language is English, other supported languages are: +# Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese-Traditional, +# Croatian, Czech, Danish, Dutch, Esperanto, Farsi, Finnish, French, German, +# Greek, Hungarian, Italian, Japanese, Japanese-en (Japanese with English +# messages), Korean, Korean-en, Lithuanian, Norwegian, Macedonian, Persian, +# Polish, Portuguese, Romanian, Russian, Serbian, Serbian-Cyrilic, Slovak, +# Slovene, Spanish, Swedish, Ukrainian, and Vietnamese. + +OUTPUT_LANGUAGE = English + +# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will +# include brief member descriptions after the members that are listed in +# the file and class documentation (similar to JavaDoc). +# Set to NO to disable this. + +BRIEF_MEMBER_DESC = NO + +# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend +# the brief description of a member or function before the detailed description. +# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the +# brief descriptions will be completely suppressed. + +REPEAT_BRIEF = NO + +# This tag implements a quasi-intelligent brief description abbreviator +# that is used to form the text in various listings. Each string +# in this list, if found as the leading text of the brief description, will be +# stripped from the text and the result after processing the whole list, is +# used as the annotated text. Otherwise, the brief description is used as-is. +# If left blank, the following values are used ("$name" is automatically +# replaced with the name of the entity): "The $name class" "The $name widget" +# "The $name file" "is" "provides" "specifies" "contains" +# "represents" "a" "an" "the" + +ABBREVIATE_BRIEF = + +# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then +# Doxygen will generate a detailed section even if there is only a brief +# description. + +ALWAYS_DETAILED_SEC = NO + +# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all +# inherited members of a class in the documentation of that class as if those +# members were ordinary class members. Constructors, destructors and assignment +# operators of the base classes will not be shown. + +INLINE_INHERITED_MEMB = NO + +# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full +# path before files name in the file list and in the header files. If set +# to NO the shortest path that makes the file name unique will be used. + +FULL_PATH_NAMES = NO + +# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag +# can be used to strip a user-defined part of the path. Stripping is +# only done if one of the specified strings matches the left-hand part of +# the path. The tag can be used to show relative paths in the file list. +# If left blank the directory from which doxygen is run is used as the +# path to strip. + +STRIP_FROM_PATH = + +# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of +# the path mentioned in the documentation of a class, which tells +# the reader which header file to include in order to use a class. +# If left blank only the name of the header file containing the class +# definition is used. Otherwise one should specify the include paths that +# are normally passed to the compiler using the -I flag. + +STRIP_FROM_INC_PATH = + +# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter +# (but less readable) file names. This can be useful is your file systems +# doesn't support long names like on DOS, Mac, or CD-ROM. + +SHORT_NAMES = NO + +# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen +# will interpret the first line (until the first dot) of a JavaDoc-style +# comment as the brief description. If set to NO, the JavaDoc +# comments will behave just like regular Qt-style comments +# (thus requiring an explicit @brief command for a brief description.) + +JAVADOC_AUTOBRIEF = NO + +# If the QT_AUTOBRIEF tag is set to YES then Doxygen will +# interpret the first line (until the first dot) of a Qt-style +# comment as the brief description. If set to NO, the comments +# will behave just like regular Qt-style comments (thus requiring +# an explicit \brief command for a brief description.) + +QT_AUTOBRIEF = NO + +# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen +# treat a multi-line C++ special comment block (i.e. a block of //! or /// +# comments) as a brief description. This used to be the default behaviour. +# The new default is to treat a multi-line C++ comment block as a detailed +# description. Set this tag to YES if you prefer the old behaviour instead. + +MULTILINE_CPP_IS_BRIEF = YES + +# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented +# member inherits the documentation from any documented member that it +# re-implements. + +INHERIT_DOCS = YES + +# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce +# a new page for each member. If set to NO, the documentation of a member will +# be part of the file/class/namespace that contains it. + +SEPARATE_MEMBER_PAGES = NO + +# The TAB_SIZE tag can be used to set the number of spaces in a tab. +# Doxygen uses this value to replace tabs by spaces in code fragments. + +TAB_SIZE = 8 + +# This tag can be used to specify a number of aliases that acts +# as commands in the documentation. An alias has the form "name=value". +# For example adding "sideeffect=\par Side Effects:\n" will allow you to +# put the command \sideeffect (or @sideeffect) in the documentation, which +# will result in a user-defined paragraph with heading "Side Effects:". +# You can put \n's in the value part of an alias to insert newlines. + +ALIASES = + +# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C +# sources only. Doxygen will then generate output that is more tailored for C. +# For instance, some of the names that are used will be different. The list +# of all members will be omitted, etc. + +OPTIMIZE_OUTPUT_FOR_C = NO + +# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java +# sources only. Doxygen will then generate output that is more tailored for +# Java. For instance, namespaces will be presented as packages, qualified +# scopes will look different, etc. + +OPTIMIZE_OUTPUT_JAVA = NO + +# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran +# sources only. Doxygen will then generate output that is more tailored for +# Fortran. + +OPTIMIZE_FOR_FORTRAN = NO + +# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL +# sources. Doxygen will then generate output that is tailored for +# VHDL. + +OPTIMIZE_OUTPUT_VHDL = NO + +# Doxygen selects the parser to use depending on the extension of the files it parses. +# With this tag you can assign which parser to use for a given extension. +# Doxygen has a built-in mapping, but you can override or extend it using this tag. +# The format is ext=language, where ext is a file extension, and language is one of +# the parsers supported by doxygen: IDL, Java, Javascript, C#, C, C++, D, PHP, +# Objective-C, Python, Fortran, VHDL, C, C++. For instance to make doxygen treat +# .inc files as Fortran files (default is PHP), and .f files as C (default is Fortran), +# use: inc=Fortran f=C. Note that for custom extensions you also need to set FILE_PATTERNS otherwise the files are not read by doxygen. + +EXTENSION_MAPPING = + +# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want +# to include (a tag file for) the STL sources as input, then you should +# set this tag to YES in order to let doxygen match functions declarations and +# definitions whose arguments contain STL classes (e.g. func(std::string); v.s. +# func(std::string) {}). This also make the inheritance and collaboration +# diagrams that involve STL classes more complete and accurate. + +BUILTIN_STL_SUPPORT = NO + +# If you use Microsoft's C++/CLI language, you should set this option to YES to +# enable parsing support. + +CPP_CLI_SUPPORT = NO + +# Set the SIP_SUPPORT tag to YES if your project consists of sip sources only. +# Doxygen will parse them like normal C++ but will assume all classes use public +# instead of private inheritance when no explicit protection keyword is present. + +SIP_SUPPORT = NO + +# For Microsoft's IDL there are propget and propput attributes to indicate getter +# and setter methods for a property. Setting this option to YES (the default) +# will make doxygen to replace the get and set methods by a property in the +# documentation. This will only work if the methods are indeed getting or +# setting a simple type. If this is not the case, or you want to show the +# methods anyway, you should set this option to NO. + +IDL_PROPERTY_SUPPORT = YES + +# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC +# tag is set to YES, then doxygen will reuse the documentation of the first +# member in the group (if any) for the other members of the group. By default +# all members of a group must be documented explicitly. + +DISTRIBUTE_GROUP_DOC = NO + +# Set the SUBGROUPING tag to YES (the default) to allow class member groups of +# the same type (for instance a group of public functions) to be put as a +# subgroup of that type (e.g. under the Public Functions section). Set it to +# NO to prevent subgrouping. Alternatively, this can be done per class using +# the \nosubgrouping command. + +SUBGROUPING = YES + +# When TYPEDEF_HIDES_STRUCT is enabled, a typedef of a struct, union, or enum +# is documented as struct, union, or enum with the name of the typedef. So +# typedef struct TypeS {} TypeT, will appear in the documentation as a struct +# with name TypeT. When disabled the typedef will appear as a member of a file, +# namespace, or class. And the struct will be named TypeS. This can typically +# be useful for C code in case the coding convention dictates that all compound +# types are typedef'ed and only the typedef is referenced, never the tag name. + +TYPEDEF_HIDES_STRUCT = NO + +# The SYMBOL_CACHE_SIZE determines the size of the internal cache use to +# determine which symbols to keep in memory and which to flush to disk. +# When the cache is full, less often used symbols will be written to disk. +# For small to medium size projects (<1000 input files) the default value is +# probably good enough. For larger projects a too small cache size can cause +# doxygen to be busy swapping symbols to and from disk most of the time +# causing a significant performance penality. +# If the system has enough physical memory increasing the cache will improve the +# performance by keeping more symbols in memory. Note that the value works on +# a logarithmic scale so increasing the size by one will rougly double the +# memory usage. The cache size is given by this formula: +# 2^(16+SYMBOL_CACHE_SIZE). The valid range is 0..9, the default is 0, +# corresponding to a cache size of 2^16 = 65536 symbols + +SYMBOL_CACHE_SIZE = 0 + +#--------------------------------------------------------------------------- +# Build related configuration options +#--------------------------------------------------------------------------- + +# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in +# documentation are documented, even if no documentation was available. +# Private class members and static file members will be hidden unless +# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES + +EXTRACT_ALL = YES + +# If the EXTRACT_PRIVATE tag is set to YES all private members of a class +# will be included in the documentation. + +EXTRACT_PRIVATE = NO + +# If the EXTRACT_STATIC tag is set to YES all static members of a file +# will be included in the documentation. + +EXTRACT_STATIC = NO + +# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) +# defined locally in source files will be included in the documentation. +# If set to NO only classes defined in header files are included. + +EXTRACT_LOCAL_CLASSES = NO + +# This flag is only useful for Objective-C code. When set to YES local +# methods, which are defined in the implementation section but not in +# the interface are included in the documentation. +# If set to NO (the default) only methods in the interface are included. + +EXTRACT_LOCAL_METHODS = NO + +# If this flag is set to YES, the members of anonymous namespaces will be +# extracted and appear in the documentation as a namespace called +# 'anonymous_namespace{file}', where file will be replaced with the base +# name of the file that contains the anonymous namespace. By default +# anonymous namespace are hidden. + +EXTRACT_ANON_NSPACES = NO + +# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all +# undocumented members of documented classes, files or namespaces. +# If set to NO (the default) these members will be included in the +# various overviews, but no documentation section is generated. +# This option has no effect if EXTRACT_ALL is enabled. + +HIDE_UNDOC_MEMBERS = NO + +# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all +# undocumented classes that are normally visible in the class hierarchy. +# If set to NO (the default) these classes will be included in the various +# overviews. This option has no effect if EXTRACT_ALL is enabled. + +HIDE_UNDOC_CLASSES = NO + +# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all +# friend (class|struct|union) declarations. +# If set to NO (the default) these declarations will be included in the +# documentation. + +HIDE_FRIEND_COMPOUNDS = YES + +# If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any +# documentation blocks found inside the body of a function. +# If set to NO (the default) these blocks will be appended to the +# function's detailed documentation block. + +HIDE_IN_BODY_DOCS = NO + +# The INTERNAL_DOCS tag determines if documentation +# that is typed after a \internal command is included. If the tag is set +# to NO (the default) then the documentation will be excluded. +# Set it to YES to include the internal documentation. + +INTERNAL_DOCS = NO + +# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate +# file names in lower-case letters. If set to YES upper-case letters are also +# allowed. This is useful if you have classes or files whose names only differ +# in case and if your file system supports case sensitive file names. Windows +# and Mac users are advised to set this option to NO. + +CASE_SENSE_NAMES = YES + +# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen +# will show members with their full class and namespace scopes in the +# documentation. If set to YES the scope will be hidden. + +HIDE_SCOPE_NAMES = NO + +# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen +# will put a list of the files that are included by a file in the documentation +# of that file. + +SHOW_INCLUDE_FILES = NO + +# If the INLINE_INFO tag is set to YES (the default) then a tag [inline] +# is inserted in the documentation for inline members. + +INLINE_INFO = NO + +# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen +# will sort the (detailed) documentation of file and class members +# alphabetically by member name. If set to NO the members will appear in +# declaration order. + +SORT_MEMBER_DOCS = NO + +# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the +# brief documentation of file, namespace and class members alphabetically +# by member name. If set to NO (the default) the members will appear in +# declaration order. + +SORT_BRIEF_DOCS = NO + +# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen will sort the (brief and detailed) documentation of class members so that constructors and destructors are listed first. If set to NO (the default) the constructors will appear in the respective orders defined by SORT_MEMBER_DOCS and SORT_BRIEF_DOCS. This tag will be ignored for brief docs if SORT_BRIEF_DOCS is set to NO and ignored for detailed docs if SORT_MEMBER_DOCS is set to NO. + +SORT_MEMBERS_CTORS_1ST = NO + +# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the +# hierarchy of group names into alphabetical order. If set to NO (the default) +# the group names will appear in their defined order. + +SORT_GROUP_NAMES = NO + +# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be +# sorted by fully-qualified names, including namespaces. If set to +# NO (the default), the class list will be sorted only by class name, +# not including the namespace part. +# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES. +# Note: This option applies only to the class list, not to the +# alphabetical list. + +SORT_BY_SCOPE_NAME = NO + +# The GENERATE_TODOLIST tag can be used to enable (YES) or +# disable (NO) the todo list. This list is created by putting \todo +# commands in the documentation. + +GENERATE_TODOLIST = NO + +# The GENERATE_TESTLIST tag can be used to enable (YES) or +# disable (NO) the test list. This list is created by putting \test +# commands in the documentation. + +GENERATE_TESTLIST = NO + +# The GENERATE_BUGLIST tag can be used to enable (YES) or +# disable (NO) the bug list. This list is created by putting \bug +# commands in the documentation. + +GENERATE_BUGLIST = NO + +# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or +# disable (NO) the deprecated list. This list is created by putting +# \deprecated commands in the documentation. + +GENERATE_DEPRECATEDLIST = YES + +# The ENABLED_SECTIONS tag can be used to enable conditional +# documentation sections, marked by \if sectionname ... \endif. + +ENABLED_SECTIONS = + +# The MAX_INITIALIZER_LINES tag determines the maximum number of lines +# the initial value of a variable or define consists of for it to appear in +# the documentation. If the initializer consists of more lines than specified +# here it will be hidden. Use a value of 0 to hide initializers completely. +# The appearance of the initializer of individual variables and defines in the +# documentation can be controlled using \showinitializer or \hideinitializer +# command in the documentation regardless of this setting. + +MAX_INITIALIZER_LINES = 30 + +# Set the SHOW_USED_FILES tag to NO to disable the list of files generated +# at the bottom of the documentation of classes and structs. If set to YES the +# list will mention the files that were used to generate the documentation. + +SHOW_USED_FILES = NO + +# If the sources in your project are distributed over multiple directories +# then setting the SHOW_DIRECTORIES tag to YES will show the directory hierarchy +# in the documentation. The default is NO. + +SHOW_DIRECTORIES = NO + +# Set the SHOW_FILES tag to NO to disable the generation of the Files page. +# This will remove the Files entry from the Quick Index and from the +# Folder Tree View (if specified). The default is YES. + +SHOW_FILES = YES + +# Set the SHOW_NAMESPACES tag to NO to disable the generation of the +# Namespaces page. +# This will remove the Namespaces entry from the Quick Index +# and from the Folder Tree View (if specified). The default is YES. + +SHOW_NAMESPACES = YES + +# The FILE_VERSION_FILTER tag can be used to specify a program or script that +# doxygen should invoke to get the current version for each file (typically from +# the version control system). Doxygen will invoke the program by executing (via +# popen()) the command <command> <input-file>, where <command> is the value of +# the FILE_VERSION_FILTER tag, and <input-file> is the name of an input file +# provided by doxygen. Whatever the program writes to standard output +# is used as the file version. See the manual for examples. + +FILE_VERSION_FILTER = + +# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed by +# doxygen. The layout file controls the global structure of the generated output files +# in an output format independent way. The create the layout file that represents +# doxygen's defaults, run doxygen with the -l option. You can optionally specify a +# file name after the option, if omitted DoxygenLayout.xml will be used as the name +# of the layout file. + +LAYOUT_FILE = + +#--------------------------------------------------------------------------- +# configuration options related to warning and progress messages +#--------------------------------------------------------------------------- + +# The QUIET tag can be used to turn on/off the messages that are generated +# by doxygen. Possible values are YES and NO. If left blank NO is used. + +QUIET = NO + +# The WARNINGS tag can be used to turn on/off the warning messages that are +# generated by doxygen. Possible values are YES and NO. If left blank +# NO is used. + +WARNINGS = YES + +# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings +# for undocumented members. If EXTRACT_ALL is set to YES then this flag will +# automatically be disabled. + +WARN_IF_UNDOCUMENTED = YES + +# If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for +# potential errors in the documentation, such as not documenting some +# parameters in a documented function, or documenting parameters that +# don't exist or using markup commands wrongly. + +WARN_IF_DOC_ERROR = YES + +# This WARN_NO_PARAMDOC option can be abled to get warnings for +# functions that are documented, but have no documentation for their parameters +# or return value. If set to NO (the default) doxygen will only warn about +# wrong or incomplete parameter documentation, but not about the absence of +# documentation. + +WARN_NO_PARAMDOC = NO + +# The WARN_FORMAT tag determines the format of the warning messages that +# doxygen can produce. The string should contain the $file, $line, and $text +# tags, which will be replaced by the file and line number from which the +# warning originated and the warning text. Optionally the format may contain +# $version, which will be replaced by the version of the file (if it could +# be obtained via FILE_VERSION_FILTER) + +WARN_FORMAT = "$file:$line: $text" + +# The WARN_LOGFILE tag can be used to specify a file to which warning +# and error messages should be written. If left blank the output is written +# to stderr. + +WARN_LOGFILE = + +#--------------------------------------------------------------------------- +# configuration options related to the input files +#--------------------------------------------------------------------------- + +# The INPUT tag can be used to specify the files and/or directories that contain +# documented source files. You may enter file names like "myfile.cpp" or +# directories like "/usr/src/myproject". Separate the files or directories +# with spaces. + +INPUT = ../../src/interface/equipment ../../src/interface/utility/SilecsException.h ../../src/interface/core/SilecsService.h + +# This tag can be used to specify the character encoding of the source files +# that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is +# also the default input encoding. Doxygen uses libiconv (or the iconv built +# into libc) for the transcoding. See http://www.gnu.org/software/libiconv for +# the list of possible encodings. + +INPUT_ENCODING = UTF-8 + +# If the value of the INPUT tag contains directories, you can use the +# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp +# and *.h) to filter out the source-files in the directories. If left +# blank the following patterns are tested: +# *.c *.cc *.cxx *.cpp *.c++ *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh *.hxx +# *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.py *.f90 + +FILE_PATTERNS = + +# The RECURSIVE tag can be used to turn specify whether or not subdirectories +# should be searched for input files as well. Possible values are YES and NO. +# If left blank NO is used. + +RECURSIVE = YES + +# The EXCLUDE tag can be used to specify files and/or directories that should +# excluded from the INPUT source files. This way you can easily exclude a +# subdirectory from a directory tree whose root is specified with the INPUT tag. + +EXCLUDE = + +# The EXCLUDE_SYMLINKS tag can be used select whether or not files or +# directories that are symbolic links (a Unix filesystem feature) are excluded +# from the input. + +EXCLUDE_SYMLINKS = NO + +# If the value of the INPUT tag contains directories, you can use the +# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude +# certain files from those directories. Note that the wildcards are matched +# against the file with absolute path, so to exclude all test directories +# for example use the pattern */test/* + +EXCLUDE_PATTERNS = *Block* + +# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names +# (namespaces, classes, functions, etc.) that should be excluded from the +# output. The symbol name can be a fully qualified name, a word, or if the +# wildcard * is used, a substring. Examples: ANamespace, AClass, +# AClass::ANamespace, ANamespace::*Test + +EXCLUDE_SYMBOLS = + +# The EXAMPLE_PATH tag can be used to specify one or more files or +# directories that contain example code fragments that are included (see +# the \include command). + +EXAMPLE_PATH = + +# If the value of the EXAMPLE_PATH tag contains directories, you can use the +# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp +# and *.h) to filter out the source-files in the directories. If left +# blank all files are included. + +EXAMPLE_PATTERNS = + +# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be +# searched for input files to be used with the \include or \dontinclude +# commands irrespective of the value of the RECURSIVE tag. +# Possible values are YES and NO. If left blank NO is used. + +EXAMPLE_RECURSIVE = NO + +# The IMAGE_PATH tag can be used to specify one or more files or +# directories that contain image that are included in the documentation (see +# the \image command). + +IMAGE_PATH = + +# The INPUT_FILTER tag can be used to specify a program that doxygen should +# invoke to filter for each input file. Doxygen will invoke the filter program +# by executing (via popen()) the command <filter> <input-file>, where <filter> +# is the value of the INPUT_FILTER tag, and <input-file> is the name of an +# input file. Doxygen will then use the output that the filter program writes +# to standard output. +# If FILTER_PATTERNS is specified, this tag will be +# ignored. + +INPUT_FILTER = + +# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern +# basis. +# Doxygen will compare the file name with each pattern and apply the +# filter if there is a match. +# The filters are a list of the form: +# pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further +# info on how filters are used. If FILTER_PATTERNS is empty, INPUT_FILTER +# is applied to all files. + +FILTER_PATTERNS = + +# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using +# INPUT_FILTER) will be used to filter the input files when producing source +# files to browse (i.e. when SOURCE_BROWSER is set to YES). + +FILTER_SOURCE_FILES = NO + +#--------------------------------------------------------------------------- +# configuration options related to source browsing +#--------------------------------------------------------------------------- + +# If the SOURCE_BROWSER tag is set to YES then a list of source files will +# be generated. Documented entities will be cross-referenced with these sources. +# Note: To get rid of all source code in the generated output, make sure also +# VERBATIM_HEADERS is set to NO. + +SOURCE_BROWSER = NO + +# Setting the INLINE_SOURCES tag to YES will include the body +# of functions and classes directly in the documentation. + +INLINE_SOURCES = NO + +# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct +# doxygen to hide any special comment blocks from generated source code +# fragments. Normal C and C++ comments will always remain visible. + +STRIP_CODE_COMMENTS = YES + +# If the REFERENCED_BY_RELATION tag is set to YES +# then for each documented function all documented +# functions referencing it will be listed. + +REFERENCED_BY_RELATION = YES + +# If the REFERENCES_RELATION tag is set to YES +# then for each documented function all documented entities +# called/used by that function will be listed. + +REFERENCES_RELATION = YES + +# If the REFERENCES_LINK_SOURCE tag is set to YES (the default) +# and SOURCE_BROWSER tag is set to YES, then the hyperlinks from +# functions in REFERENCES_RELATION and REFERENCED_BY_RELATION lists will +# link to the source code. +# Otherwise they will link to the documentation. + +REFERENCES_LINK_SOURCE = YES + +# If the USE_HTAGS tag is set to YES then the references to source code +# will point to the HTML generated by the htags(1) tool instead of doxygen +# built-in source browser. The htags tool is part of GNU's global source +# tagging system (see http://www.gnu.org/software/global/global.html). You +# will need version 4.8.6 or higher. + +USE_HTAGS = NO + +# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen +# will generate a verbatim copy of the header file for each class for +# which an include is specified. Set to NO to disable this. + +VERBATIM_HEADERS = NO + +#--------------------------------------------------------------------------- +# configuration options related to the alphabetical class index +#--------------------------------------------------------------------------- + +# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index +# of all compounds will be generated. Enable this if the project +# contains a lot of classes, structs, unions or interfaces. + +ALPHABETICAL_INDEX = NO + +# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then +# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns +# in which this list will be split (can be a number in the range [1..20]) + +COLS_IN_ALPHA_INDEX = 5 + +# In case all classes in a project start with a common prefix, all +# classes will be put under the same header in the alphabetical index. +# The IGNORE_PREFIX tag can be used to specify one or more prefixes that +# should be ignored while generating the index headers. + +IGNORE_PREFIX = + +#--------------------------------------------------------------------------- +# configuration options related to the HTML output +#--------------------------------------------------------------------------- + +# If the GENERATE_HTML tag is set to YES (the default) Doxygen will +# generate HTML output. + +GENERATE_HTML = YES + +# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `html' will be used as the default path. + +HTML_OUTPUT = html + +# The HTML_FILE_EXTENSION tag can be used to specify the file extension for +# each generated HTML page (for example: .htm,.php,.asp). If it is left blank +# doxygen will generate files with .html extension. + +HTML_FILE_EXTENSION = .html + +# The HTML_HEADER tag can be used to specify a personal HTML header for +# each generated HTML page. If it is left blank doxygen will generate a +# standard header. + +HTML_HEADER = + +# The HTML_FOOTER tag can be used to specify a personal HTML footer for +# each generated HTML page. If it is left blank doxygen will generate a +# standard footer. + +HTML_FOOTER = + +# If the HTML_TIMESTAMP tag is set to YES then the generated HTML +# documentation will contain the timesstamp. + +HTML_TIMESTAMP = NO + +# The HTML_STYLESHEET tag can be used to specify a user-defined cascading +# style sheet that is used by each HTML page. It can be used to +# fine-tune the look of the HTML output. If the tag is left blank doxygen +# will generate a default style sheet. Note that doxygen will try to copy +# the style sheet file to the HTML output directory, so don't put your own +# stylesheet in the HTML output directory as well, or it will be erased! + +HTML_STYLESHEET = + +# If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes, +# files or namespaces will be aligned in HTML using tables. If set to +# NO a bullet list will be used. + +HTML_ALIGN_MEMBERS = YES + +# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML +# documentation will contain sections that can be hidden and shown after the +# page has loaded. For this to work a browser that supports +# JavaScript and DHTML is required (for instance Mozilla 1.0+, Firefox +# Netscape 6.0+, Internet explorer 5.0+, Konqueror, or Safari). + +HTML_DYNAMIC_SECTIONS = NO + +# If the GENERATE_DOCSET tag is set to YES, additional index files +# will be generated that can be used as input for Apple's Xcode 3 +# integrated development environment, introduced with OSX 10.5 (Leopard). +# To create a documentation set, doxygen will generate a Makefile in the +# HTML output directory. Running make will produce the docset in that +# directory and running "make install" will install the docset in +# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find +# it at startup. +# See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html for more information. + +GENERATE_DOCSET = NO + +# When GENERATE_DOCSET tag is set to YES, this tag determines the name of the +# feed. A documentation feed provides an umbrella under which multiple +# documentation sets from a single provider (such as a company or product suite) +# can be grouped. + +DOCSET_FEEDNAME = "Doxygen generated docs" + +# When GENERATE_DOCSET tag is set to YES, this tag specifies a string that +# should uniquely identify the documentation set bundle. This should be a +# reverse domain-name style string, e.g. com.mycompany.MyDocSet. Doxygen +# will append .docset to the name. + +DOCSET_BUNDLE_ID = org.doxygen.Project + +# If the GENERATE_HTMLHELP tag is set to YES, additional index files +# will be generated that can be used as input for tools like the +# Microsoft HTML help workshop to generate a compiled HTML help file (.chm) +# of the generated HTML documentation. + +GENERATE_HTMLHELP = NO + +# If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can +# be used to specify the file name of the resulting .chm file. You +# can add a path in front of the file if the result should not be +# written to the html output directory. + +CHM_FILE = + +# If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can +# be used to specify the location (absolute path including file name) of +# the HTML help compiler (hhc.exe). If non-empty doxygen will try to run +# the HTML help compiler on the generated index.hhp. + +HHC_LOCATION = + +# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag +# controls if a separate .chi index file is generated (YES) or that +# it should be included in the master .chm file (NO). + +GENERATE_CHI = NO + +# If the GENERATE_HTMLHELP tag is set to YES, the CHM_INDEX_ENCODING +# is used to encode HtmlHelp index (hhk), content (hhc) and project file +# content. + +CHM_INDEX_ENCODING = + +# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag +# controls whether a binary table of contents is generated (YES) or a +# normal table of contents (NO) in the .chm file. + +BINARY_TOC = NO + +# The TOC_EXPAND flag can be set to YES to add extra items for group members +# to the contents of the HTML help documentation and to the tree view. + +TOC_EXPAND = NO + +# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and QHP_VIRTUAL_FOLDER +# are set, an additional index file will be generated that can be used as input for +# Qt's qhelpgenerator to generate a Qt Compressed Help (.qch) of the generated +# HTML documentation. + +GENERATE_QHP = NO + +# If the QHG_LOCATION tag is specified, the QCH_FILE tag can +# be used to specify the file name of the resulting .qch file. +# The path specified is relative to the HTML output folder. + +QCH_FILE = + +# The QHP_NAMESPACE tag specifies the namespace to use when generating +# Qt Help Project output. For more information please see +# http://doc.trolltech.com/qthelpproject.html#namespace + +QHP_NAMESPACE = + +# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating +# Qt Help Project output. For more information please see +# http://doc.trolltech.com/qthelpproject.html#virtual-folders + +QHP_VIRTUAL_FOLDER = doc + +# If QHP_CUST_FILTER_NAME is set, it specifies the name of a custom filter to add. +# For more information please see +# http://doc.trolltech.com/qthelpproject.html#custom-filters + +QHP_CUST_FILTER_NAME = + +# The QHP_CUST_FILT_ATTRS tag specifies the list of the attributes of the custom filter to add.For more information please see +# <a href="http://doc.trolltech.com/qthelpproject.html#custom-filters">Qt Help Project / Custom Filters</a>. + +QHP_CUST_FILTER_ATTRS = + +# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this project's +# filter section matches. +# <a href="http://doc.trolltech.com/qthelpproject.html#filter-attributes">Qt Help Project / Filter Attributes</a>. + +QHP_SECT_FILTER_ATTRS = + +# If the GENERATE_QHP tag is set to YES, the QHG_LOCATION tag can +# be used to specify the location of Qt's qhelpgenerator. +# If non-empty doxygen will try to run qhelpgenerator on the generated +# .qhp file. + +QHG_LOCATION = + +# The DISABLE_INDEX tag can be used to turn on/off the condensed index at +# top of each HTML page. The value NO (the default) enables the index and +# the value YES disables it. + +DISABLE_INDEX = NO + +# This tag can be used to set the number of enum values (range [1..20]) +# that doxygen will group on one line in the generated HTML documentation. + +ENUM_VALUES_PER_LINE = 4 + +# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index +# structure should be generated to display hierarchical information. +# If the tag value is set to YES, a side panel will be generated +# containing a tree-like index structure (just like the one that +# is generated for HTML Help). For this to work a browser that supports +# JavaScript, DHTML, CSS and frames is required (i.e. any modern browser). +# Windows users are probably better off using the HTML help feature. + +GENERATE_TREEVIEW = NO + +# By enabling USE_INLINE_TREES, doxygen will generate the Groups, Directories, +# and Class Hierarchy pages using a tree view instead of an ordered list. + +USE_INLINE_TREES = NO + +# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be +# used to set the initial width (in pixels) of the frame in which the tree +# is shown. + +TREEVIEW_WIDTH = 250 + +# Use this tag to change the font size of Latex formulas included +# as images in the HTML documentation. The default is 10. Note that +# when you change the font size after a successful doxygen run you need +# to manually remove any form_*.png images from the HTML output directory +# to force them to be regenerated. + +FORMULA_FONTSIZE = 10 + +# When the SEARCHENGINE tag is enable doxygen will generate a search box for the HTML output. The underlying search engine uses javascript +# and DHTML and should work on any modern browser. Note that when using HTML help (GENERATE_HTMLHELP) or Qt help (GENERATE_QHP) +# there is already a search function so this one should typically +# be disabled. + +SEARCHENGINE = NO + +#--------------------------------------------------------------------------- +# configuration options related to the LaTeX output +#--------------------------------------------------------------------------- + +# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will +# generate Latex output. + +GENERATE_LATEX = NO + +# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `latex' will be used as the default path. + +LATEX_OUTPUT = latex + +# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be +# invoked. If left blank `latex' will be used as the default command name. + +LATEX_CMD_NAME = latex + +# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to +# generate index for LaTeX. If left blank `makeindex' will be used as the +# default command name. + +MAKEINDEX_CMD_NAME = makeindex + +# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact +# LaTeX documents. This may be useful for small projects and may help to +# save some trees in general. + +COMPACT_LATEX = NO + +# The PAPER_TYPE tag can be used to set the paper type that is used +# by the printer. Possible values are: a4, a4wide, letter, legal and +# executive. If left blank a4wide will be used. + +PAPER_TYPE = a4wide + +# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX +# packages that should be included in the LaTeX output. + +EXTRA_PACKAGES = + +# The LATEX_HEADER tag can be used to specify a personal LaTeX header for +# the generated latex document. The header should contain everything until +# the first chapter. If it is left blank doxygen will generate a +# standard header. Notice: only use this tag if you know what you are doing! + +LATEX_HEADER = + +# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated +# is prepared for conversion to pdf (using ps2pdf). The pdf file will +# contain links (just like the HTML output) instead of page references +# This makes the output suitable for online browsing using a pdf viewer. + +PDF_HYPERLINKS = NO + +# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of +# plain latex in the generated Makefile. Set this option to YES to get a +# higher quality PDF documentation. + +USE_PDFLATEX = NO + +# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode. +# command to the generated LaTeX files. This will instruct LaTeX to keep +# running if errors occur, instead of asking the user for help. +# This option is also used when generating formulas in HTML. + +LATEX_BATCHMODE = NO + +# If LATEX_HIDE_INDICES is set to YES then doxygen will not +# include the index chapters (such as File Index, Compound Index, etc.) +# in the output. + +LATEX_HIDE_INDICES = NO + +# If LATEX_SOURCE_CODE is set to YES then doxygen will include source code with syntax highlighting in the LaTeX output. Note that which sources are shown also depends on other settings such as SOURCE_BROWSER. + +LATEX_SOURCE_CODE = NO + +#--------------------------------------------------------------------------- +# configuration options related to the RTF output +#--------------------------------------------------------------------------- + +# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output +# The RTF output is optimized for Word 97 and may not look very pretty with +# other RTF readers or editors. + +GENERATE_RTF = NO + +# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `rtf' will be used as the default path. + +RTF_OUTPUT = rtf + +# If the COMPACT_RTF tag is set to YES Doxygen generates more compact +# RTF documents. This may be useful for small projects and may help to +# save some trees in general. + +COMPACT_RTF = NO + +# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated +# will contain hyperlink fields. The RTF file will +# contain links (just like the HTML output) instead of page references. +# This makes the output suitable for online browsing using WORD or other +# programs which support those fields. +# Note: wordpad (write) and others do not support links. + +RTF_HYPERLINKS = NO + +# Load stylesheet definitions from file. Syntax is similar to doxygen's +# config file, i.e. a series of assignments. You only have to provide +# replacements, missing definitions are set to their default value. + +RTF_STYLESHEET_FILE = + +# Set optional variables used in the generation of an rtf document. +# Syntax is similar to doxygen's config file. + +RTF_EXTENSIONS_FILE = + +#--------------------------------------------------------------------------- +# configuration options related to the man page output +#--------------------------------------------------------------------------- + +# If the GENERATE_MAN tag is set to YES (the default) Doxygen will +# generate man pages + +GENERATE_MAN = NO + +# The MAN_OUTPUT tag is used to specify where the man pages will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `man' will be used as the default path. + +MAN_OUTPUT = man + +# The MAN_EXTENSION tag determines the extension that is added to +# the generated man pages (default is the subroutine's section .3) + +MAN_EXTENSION = .3 + +# If the MAN_LINKS tag is set to YES and Doxygen generates man output, +# then it will generate one additional man file for each entity +# documented in the real man page(s). These additional files +# only source the real man page, but without them the man command +# would be unable to find the correct page. The default is NO. + +MAN_LINKS = NO + +#--------------------------------------------------------------------------- +# configuration options related to the XML output +#--------------------------------------------------------------------------- + +# If the GENERATE_XML tag is set to YES Doxygen will +# generate an XML file that captures the structure of +# the code including all documentation. + +GENERATE_XML = NO + +# The XML_OUTPUT tag is used to specify where the XML pages will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `xml' will be used as the default path. + +XML_OUTPUT = xml + +# The XML_SCHEMA tag can be used to specify an XML schema, +# which can be used by a validating XML parser to check the +# syntax of the XML files. + +XML_SCHEMA = + +# The XML_DTD tag can be used to specify an XML DTD, +# which can be used by a validating XML parser to check the +# syntax of the XML files. + +XML_DTD = + +# If the XML_PROGRAMLISTING tag is set to YES Doxygen will +# dump the program listings (including syntax highlighting +# and cross-referencing information) to the XML output. Note that +# enabling this will significantly increase the size of the XML output. + +XML_PROGRAMLISTING = YES + +#--------------------------------------------------------------------------- +# configuration options for the AutoGen Definitions output +#--------------------------------------------------------------------------- + +# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will +# generate an AutoGen Definitions (see autogen.sf.net) file +# that captures the structure of the code including all +# documentation. Note that this feature is still experimental +# and incomplete at the moment. + +GENERATE_AUTOGEN_DEF = NO + +#--------------------------------------------------------------------------- +# configuration options related to the Perl module output +#--------------------------------------------------------------------------- + +# If the GENERATE_PERLMOD tag is set to YES Doxygen will +# generate a Perl module file that captures the structure of +# the code including all documentation. Note that this +# feature is still experimental and incomplete at the +# moment. + +GENERATE_PERLMOD = NO + +# If the PERLMOD_LATEX tag is set to YES Doxygen will generate +# the necessary Makefile rules, Perl scripts and LaTeX code to be able +# to generate PDF and DVI output from the Perl module output. + +PERLMOD_LATEX = NO + +# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be +# nicely formatted so it can be parsed by a human reader. +# This is useful +# if you want to understand what is going on. +# On the other hand, if this +# tag is set to NO the size of the Perl module output will be much smaller +# and Perl will parse it just the same. + +PERLMOD_PRETTY = YES + +# The names of the make variables in the generated doxyrules.make file +# are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. +# This is useful so different doxyrules.make files included by the same +# Makefile don't overwrite each other's variables. + +PERLMOD_MAKEVAR_PREFIX = + +#--------------------------------------------------------------------------- +# Configuration options related to the preprocessor +#--------------------------------------------------------------------------- + +# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will +# evaluate all C-preprocessor directives found in the sources and include +# files. + +ENABLE_PREPROCESSING = YES + +# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro +# names in the source code. If set to NO (the default) only conditional +# compilation will be performed. Macro expansion can be done in a controlled +# way by setting EXPAND_ONLY_PREDEF to YES. + +MACRO_EXPANSION = NO + +# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES +# then the macro expansion is limited to the macros specified with the +# PREDEFINED and EXPAND_AS_DEFINED tags. + +EXPAND_ONLY_PREDEF = NO + +# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files +# in the INCLUDE_PATH (see below) will be search if a #include is found. + +SEARCH_INCLUDES = YES + +# The INCLUDE_PATH tag can be used to specify one or more directories that +# contain include files that are not input files but should be processed by +# the preprocessor. + +INCLUDE_PATH = + +# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard +# patterns (like *.h and *.hpp) to filter out the header-files in the +# directories. If left blank, the patterns specified with FILE_PATTERNS will +# be used. + +INCLUDE_FILE_PATTERNS = + +# The PREDEFINED tag can be used to specify one or more macro names that +# are defined before the preprocessor is started (similar to the -D option of +# gcc). The argument of the tag is a list of macros of the form: name +# or name=definition (no spaces). If the definition and the = are +# omitted =1 is assumed. To prevent a macro definition from being +# undefined via #undef or recursively expanded use the := operator +# instead of the = operator. + +PREDEFINED = + +# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then +# this tag can be used to specify a list of macro names that should be expanded. +# The macro definition that is found in the sources will be used. +# Use the PREDEFINED tag if you want to use a different macro definition. + +EXPAND_AS_DEFINED = + +# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then +# doxygen's preprocessor will remove all function-like macros that are alone +# on a line, have an all uppercase name, and do not end with a semicolon. Such +# function macros are typically used for boiler-plate code, and will confuse +# the parser if not removed. + +SKIP_FUNCTION_MACROS = YES + +#--------------------------------------------------------------------------- +# Configuration::additions related to external references +#--------------------------------------------------------------------------- + +# The TAGFILES option can be used to specify one or more tagfiles. +# Optionally an initial location of the external documentation +# can be added for each tagfile. The format of a tag file without +# this location is as follows: +# +# TAGFILES = file1 file2 ... +# Adding location for the tag files is done as follows: +# +# TAGFILES = file1=loc1 "file2 = loc2" ... +# where "loc1" and "loc2" can be relative or absolute paths or +# URLs. If a location is present for each tag, the installdox tool +# does not have to be run to correct the links. +# Note that each tag file must have a unique name +# (where the name does NOT include the path) +# If a tag file is not located in the directory in which doxygen +# is run, you must also specify the path to the tagfile here. + +TAGFILES = + +# When a file name is specified after GENERATE_TAGFILE, doxygen will create +# a tag file that is based on the input files it reads. + +GENERATE_TAGFILE = + +# If the ALLEXTERNALS tag is set to YES all external classes will be listed +# in the class index. If set to NO only the inherited external classes +# will be listed. + +ALLEXTERNALS = NO + +# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed +# in the modules index. If set to NO, only the current project's groups will +# be listed. + +EXTERNAL_GROUPS = YES + +# The PERL_PATH should be the absolute path and name of the perl script +# interpreter (i.e. the result of `which perl'). + +PERL_PATH = /usr/bin/perl + +#--------------------------------------------------------------------------- +# Configuration options related to the dot tool +#--------------------------------------------------------------------------- + +# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will +# generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base +# or super classes. Setting the tag to NO turns the diagrams off. Note that +# this option is superseded by the HAVE_DOT option below. This is only a +# fallback. It is recommended to install and use dot, since it yields more +# powerful graphs. + +CLASS_DIAGRAMS = YES + +# You can define message sequence charts within doxygen comments using the \msc +# command. Doxygen will then run the mscgen tool (see +# http://www.mcternan.me.uk/mscgen/) to produce the chart and insert it in the +# documentation. The MSCGEN_PATH tag allows you to specify the directory where +# the mscgen tool resides. If left empty the tool is assumed to be found in the +# default search path. + +MSCGEN_PATH = + +# If set to YES, the inheritance and collaboration graphs will hide +# inheritance and usage relations if the target is undocumented +# or is not a class. + +HIDE_UNDOC_RELATIONS = YES + +# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is +# available from the path. This tool is part of Graphviz, a graph visualization +# toolkit from AT&T and Lucent Bell Labs. The other options in this section +# have no effect if this option is set to NO (the default) + +HAVE_DOT = NO + +# By default doxygen will write a font called FreeSans.ttf to the output +# directory and reference it in all dot files that doxygen generates. This +# font does not include all possible unicode characters however, so when you need +# these (or just want a differently looking font) you can specify the font name +# using DOT_FONTNAME. You need need to make sure dot is able to find the font, +# which can be done by putting it in a standard location or by setting the +# DOTFONTPATH environment variable or by setting DOT_FONTPATH to the directory +# containing the font. + +DOT_FONTNAME = FreeSans + +# The DOT_FONTSIZE tag can be used to set the size of the font of dot graphs. +# The default size is 10pt. + +DOT_FONTSIZE = 10 + +# By default doxygen will tell dot to use the output directory to look for the +# FreeSans.ttf font (which doxygen will put there itself). If you specify a +# different font using DOT_FONTNAME you can set the path where dot +# can find it using this tag. + +DOT_FONTPATH = + +# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen +# will generate a graph for each documented class showing the direct and +# indirect inheritance relations. Setting this tag to YES will force the +# the CLASS_DIAGRAMS tag to NO. + +CLASS_GRAPH = YES + +# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen +# will generate a graph for each documented class showing the direct and +# indirect implementation dependencies (inheritance, containment, and +# class references variables) of the class with other documented classes. + +COLLABORATION_GRAPH = YES + +# If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen +# will generate a graph for groups, showing the direct groups dependencies + +GROUP_GRAPHS = YES + +# If the UML_LOOK tag is set to YES doxygen will generate inheritance and +# collaboration diagrams in a style similar to the OMG's Unified Modeling +# Language. + +UML_LOOK = NO + +# If set to YES, the inheritance and collaboration graphs will show the +# relations between templates and their instances. + +TEMPLATE_RELATIONS = NO + +# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT +# tags are set to YES then doxygen will generate a graph for each documented +# file showing the direct and indirect include dependencies of the file with +# other documented files. + +INCLUDE_GRAPH = YES + +# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and +# HAVE_DOT tags are set to YES then doxygen will generate a graph for each +# documented header file showing the documented files that directly or +# indirectly include this file. + +INCLUDED_BY_GRAPH = YES + +# If the CALL_GRAPH and HAVE_DOT options are set to YES then +# doxygen will generate a call dependency graph for every global function +# or class method. Note that enabling this option will significantly increase +# the time of a run. So in most cases it will be better to enable call graphs +# for selected functions only using the \callgraph command. + +CALL_GRAPH = NO + +# If the CALLER_GRAPH and HAVE_DOT tags are set to YES then +# doxygen will generate a caller dependency graph for every global function +# or class method. Note that enabling this option will significantly increase +# the time of a run. So in most cases it will be better to enable caller +# graphs for selected functions only using the \callergraph command. + +CALLER_GRAPH = NO + +# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen +# will graphical hierarchy of all classes instead of a textual one. + +GRAPHICAL_HIERARCHY = YES + +# If the DIRECTORY_GRAPH, SHOW_DIRECTORIES and HAVE_DOT tags are set to YES +# then doxygen will show the dependencies a directory has on other directories +# in a graphical way. The dependency relations are determined by the #include +# relations between the files in the directories. + +DIRECTORY_GRAPH = YES + +# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images +# generated by dot. Possible values are png, jpg, or gif +# If left blank png will be used. + +DOT_IMAGE_FORMAT = png + +# The tag DOT_PATH can be used to specify the path where the dot tool can be +# found. If left blank, it is assumed the dot tool can be found in the path. + +DOT_PATH = + +# The DOTFILE_DIRS tag can be used to specify one or more directories that +# contain dot files that are included in the documentation (see the +# \dotfile command). + +DOTFILE_DIRS = + +# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of +# nodes that will be shown in the graph. If the number of nodes in a graph +# becomes larger than this value, doxygen will truncate the graph, which is +# visualized by representing a node as a red box. Note that doxygen if the +# number of direct children of the root node in a graph is already larger than +# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note +# that the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH. + +DOT_GRAPH_MAX_NODES = 50 + +# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the +# graphs generated by dot. A depth value of 3 means that only nodes reachable +# from the root by following a path via at most 3 edges will be shown. Nodes +# that lay further from the root node will be omitted. Note that setting this +# option to 1 or 2 may greatly reduce the computation time needed for large +# code bases. Also note that the size of a graph can be further restricted by +# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction. + +MAX_DOT_GRAPH_DEPTH = 0 + +# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent +# background. This is disabled by default, because dot on Windows does not +# seem to support this out of the box. Warning: Depending on the platform used, +# enabling this option may lead to badly anti-aliased labels on the edges of +# a graph (i.e. they become hard to read). + +DOT_TRANSPARENT = NO + +# Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output +# files in one run (i.e. multiple -o and -T options on the command line). This +# makes dot run faster, but since only newer versions of dot (>1.8.10) +# support this, this feature is disabled by default. + +DOT_MULTI_TARGETS = NO + +# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will +# generate a legend page explaining the meaning of the various boxes and +# arrows in the dot generated graphs. + +GENERATE_LEGEND = YES + +# If the DOT_CLEANUP tag is set to YES (the default) Doxygen will +# remove the intermediate dot files that are used to generate +# the various graphs. + +DOT_CLEANUP = YES diff --git a/silecs-communication-cpp/install.sh b/silecs-communication-cpp/install.sh new file mode 100755 index 0000000..002fbec --- /dev/null +++ b/silecs-communication-cpp/install.sh @@ -0,0 +1,11 @@ +#!/bin/sh +set -e + +INSTALL_DIR=$1 + +SCRIPT=$(readlink -f "$0") +SCRIPTPATH=$(dirname "$SCRIPT") # path where this script is located in + +mkdir -p ${INSTALL_DIR} +cp -r ${SCRIPTPATH}/build/include ${INSTALL_DIR} +cp -r ${SCRIPTPATH}/build/lib ${INSTALL_DIR} \ No newline at end of file diff --git a/silecs-communication-cpp/make-ctb.py b/silecs-communication-cpp/make-ctb.py new file mode 100644 index 0000000..a93fdae --- /dev/null +++ b/silecs-communication-cpp/make-ctb.py @@ -0,0 +1,29 @@ +#!/usr/bin/python + +import os +import sys + +depVersion = 'SILECS_MAKEFILE_VERSION=DEV RDA_VERSION=DEV' +ctbPaths = 'RELEASE_LOCATION=/local/RELEASE_LOCATION' +makeFlags = ' RELEASE_GROUP=si ' + depVersion + ' ' + ctbPaths + +# compile first as we can't use -j in local-devrelease +cmd = 'make -j4' + makeFlags +rc = os.system(cmd + ' CPU=L865') +if(rc != 0): + sys.exit(-1) + +rc = os.system(cmd + ' CPU=L866') +if(rc != 0): + sys.exit(-1) + +# now release ========================================== +cmd = 'make local-devrelease' + makeFlags + ' TMP_DIR=.' +rc = os.system(cmd + ' CPU=L865') +if(rc != 0): + sys.exit(-1) + +rc = os.system(cmd + ' CPU=L866') +if(rc != 0): + sys.exit(-1) + \ No newline at end of file diff --git a/silecs-communication-cpp/releaseSilecs.sh b/silecs-communication-cpp/releaseSilecs.sh new file mode 100755 index 0000000..999031f --- /dev/null +++ b/silecs-communication-cpp/releaseSilecs.sh @@ -0,0 +1,87 @@ +#!/bin/sh +set -e + +# Usage examples: +# first you need to source this script, so that you can use it's methods: +# $ source releaseSilecs.sh +# +# release a new version v1.0.0 +# $ release 1.0.0 /common/usr/cscofe/silecs /home/bel/schwinn/lnx/workspace-silecs-mars +# +# patch 2 packages of an existing version 1.2.3 +# $ patch silecs-codegen 1.2.4 1.2.3 /common/usr/cscofe/silecs /home/bel/schwinn/lnx/workspace-silecs-mars +# $ patch silecs-model 1.2.4 1.2.3 /common/usr/cscofe/silecs /home/bel/schwinn/lnx/workspace-silecs-mars +# +# release a new version of the silecs-eclipse plugin +# $ plugin_release /common/usr/cscofe/silecs /home/bel/schwinn/lnx/workspace-silecs-mars + +# List of silecs packages which is released or patched +PACKAGES="silecs-codegen silecs-model silecs-communication-cpp silecs-diagnostic-cpp snap7" + +# releases all silecs-packages to release-dir +function release +{ + VERSION=$1 + RELEASE_DIR_BASE=$2 + WORKSPACE=$3 + + for PACKAGE in $PACKAGES; do + INSTALL_DIR=${RELEASE_DIR_BASE}/${PACKAGE}/${VERSION} + if [ -d ${INSTALL_DIR} ]; then + echo "Error: Silecs version ${VERSION} is already installed in ${INSTALL_DIR}. Exiting now." + return 1 + else + echo "installing ${INSTALL_DIR} from ${WORKSPACE}/${PACKAGE}" + ${WORKSPACE}/${PACKAGE}/install.sh ${INSTALL_DIR} + fi + done + return 0 +} + +function plugin_release +{ + RELEASE_DIR_BASE=$1 + WORKSPACE=$2 + PACKAGE=silecs-eclipse-plugin-update-site + INSTALL_DIR=${RELEASE_DIR_BASE}/${PACKAGE} + echo "installing ${INSTALL_DIR} from ${WORKSPACE}/${PACKAGE}" + ${WORKSPACE}/${PACKAGE}/install.sh ${INSTALL_DIR} +} + +# releases a specific package to release-dir. For all other packages symlinks to the base-version are generated +function patch +{ + PACKAGE_TO_PATCH=$1 + NEW_VERSION=$2 + BASE_VERSION=$3 + RELEASE_DIR_BASE=$4 + WORKSPACE=$5 + + for PACKAGE in $PACKAGES; do + INSTALL_DIR=${RELEASE_DIR_BASE}/${PACKAGE}/${NEW_VERSION} + BASE_DIR=${RELEASE_DIR_BASE}/${PACKAGE}/${BASE_VERSION} + if [ "$PACKAGE" == "$PACKAGE_TO_PATCH" ]; then + if [ -d ${INSTALL_DIR} ]; then + if [ -L ${INSTALL_DIR} ]; then + # Replace Sym-Link with patch-version ... needed if more than one package is patched for the same version + unlink ${INSTALL_DIR} + echo "installing ${INSTALL_DIR} from ${WORKSPACE}/${PACKAGE}" + ${WORKSPACE}/${PACKAGE}/install.sh ${INSTALL_DIR} + else + echo "Error: Silecs version ${NEW_VERSION} of package ${PACKAGE} is already installed in ${INSTALL_DIR}. Exiting now." + return 1 + fi + else + echo "installing ${INSTALL_DIR} from ${WORKSPACE}/${PACKAGE}" + ${WORKSPACE}/${PACKAGE}/install.sh ${INSTALL_DIR} + fi + else + if [ ! -d ${INSTALL_DIR} ]; then + # no patched version for this package available --> link to base-version + echo "Symbolic link to base version '${BASE_VERSION}' created for package '${PACKAGE}' of version '${NEW_VERSION}'" + ln -s ${BASE_VERSION} ${INSTALL_DIR} + fi + fi + done + return 0 +} \ No newline at end of file diff --git a/silecs-communication-cpp/src/demo/Cfp774Simatic400_1_0_0.h b/silecs-communication-cpp/src/demo/Cfp774Simatic400_1_0_0.h new file mode 100644 index 0000000..257e9d2 --- /dev/null +++ b/silecs-communication-cpp/src/demo/Cfp774Simatic400_1_0_0.h @@ -0,0 +1,108 @@ +/* Copyright CERN 2015 + * + * WARNING: This code is automatically generated from your SILECS deploy unit document. + * You should never modify the content of this file as it would break consistency. + * Furthermore, any changes will be overwritten in the next code generation. + * Any modification shall be done using the SILECS development environment + * and regenerating this source code. + */ + +#ifndef CFP774SIMATIC400_1_0_0_H_ +#define CFP774SIMATIC400_1_0_0_H_ + +#include <silecs-communication/interface/equipment/SilecsCluster.h> +#include <silecs-communication/wrapper/DeployUnit.h> +#include <silecs-communication/wrapper/Design.h> + +#include "SilecsHeader_1_0_0.h" +#include "SilecsValid_1_0_0.h" + +namespace Cfp774Simatic400_1_0_0 +{ + +typedef SilecsWrapper::DeployConfig DeployConfig; +typedef SilecsWrapper::DesignConfig DesignConfig; +class DeployUnit : public SilecsWrapper::DeployUnit +{ +public: + + /*! + * \brief Use this method to create/get the unique instance of the Deploy Unit. + * + * \param logTopics This parameter can be used to enable/disable log topics + * valid topics are ERROR[,INFO,DEBUG,SETUP,ALLOC,RECV,SEND,COMM,DATA,LOCK]. + * + * \param globalConfig This parameter can be used to pass different parameters to + * the library. I.e. enabling automatic connection. + */ + static DeployUnit* getInstance(const std::string& logTopics = "", + const SilecsWrapper::DeployConfig& globalConfig = SilecsWrapper::DeployConfig()) + { + if (_instance == NULL) + { + _instance = new DeployUnit(logTopics, globalConfig); + } + else + { + if (not logTopics.empty()) + { + _instance->getService()->setLogTopics(logTopics); + } + } +// DeployUnit::_globalConfig = globalConfig; + return dynamic_cast<DeployUnit*>(_instance); + } + + /*! + * \brief Use this method to create/get the unique instance of the Deploy Unit. + * + * \param globalConfig This parameter can be used to pass different parameters to + * the library. I.e. enabling automatic connection. + */ + static DeployUnit* getInstance(const SilecsWrapper::DeployConfig& globalConfig) + { + return getInstance("", globalConfig); + } + + /*! + * \brief Return pointer to the deployed design SilecsHeader. + */ + SilecsHeader_1_0_0::Design* getSilecsHeader() + { + return _SilecsHeader; + } + + /*! + * \brief Return pointer to the deployed design SilecsValid. + */ + SilecsValid_1_0_0::Design* getSilecsValid() + { + return _SilecsValid; + } + +private: + + SilecsHeader_1_0_0::Design* _SilecsHeader; + SilecsValid_1_0_0::Design* _SilecsValid; + + DeployUnit(const std::string& logTopics, const SilecsWrapper::DeployConfig& globalConfig) : + SilecsWrapper::DeployUnit("Cfp774Simatic400_1_0_0", "1.0.0", logTopics, globalConfig) + { + // Construct Design SilecsHeader_1_0_0 + _SilecsHeader = new SilecsHeader_1_0_0::Design((SilecsWrapper::DeployUnit*) this); + + // Construct Design SilecsValid_1_0_0 + _SilecsValid = new SilecsValid_1_0_0::Design((SilecsWrapper::DeployUnit*) this); + + } + + ~DeployUnit() + { + delete _SilecsHeader; + delete _SilecsValid; + } +}; + +} /* namespace Cfp774Simatic400_1_0_0 */ + +#endif /* CFP774SIMATIC400_1_0_0_H_ */ diff --git a/silecs-communication-cpp/src/demo/Doxyfile b/silecs-communication-cpp/src/demo/Doxyfile new file mode 100644 index 0000000..3cc4af2 --- /dev/null +++ b/silecs-communication-cpp/src/demo/Doxyfile @@ -0,0 +1,1519 @@ +# Doxyfile 1.6.1 + +# This file describes the settings to be used by the documentation system +# doxygen (www.doxygen.org) for a project +# +# All text after a hash (#) is considered a comment and will be ignored +# The format is: +# TAG = value [value, ...] +# For lists items can also be appended using: +# TAG += value [value, ...] +# Values that contain spaces should be placed between quotes (" ") + +#--------------------------------------------------------------------------- +# Project related configuration options +#--------------------------------------------------------------------------- + +# This tag specifies the encoding used for all characters in the config file +# that follow. The default is UTF-8 which is also the encoding used for all +# text before the first occurrence of this tag. Doxygen uses libiconv (or the +# iconv built into libc) for the transcoding. See +# http://www.gnu.org/software/libiconv for the list of possible encodings. + +DOXYFILE_ENCODING = UTF-8 + +# The PROJECT_NAME tag is a single word (or a sequence of words surrounded +# by quotes) that should identify the project. + +PROJECT_NAME = demo + +# The PROJECT_NUMBER tag can be used to enter a project or revision number. +# This could be handy for archiving the generated documentation or +# if some version control system is used. + +PROJECT_NUMBER = 1.m.p + +# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) +# base path where the generated documentation will be put. +# If a relative path is entered, it will be relative to the location +# where doxygen was started. If left blank the current directory will be used. + +OUTPUT_DIRECTORY = ../../demo/doc + +# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create +# 4096 sub-directories (in 2 levels) under the output directory of each output +# format and will distribute the generated files over these directories. +# Enabling this option can be useful when feeding doxygen a huge amount of +# source files, where putting all generated files in the same directory would +# otherwise cause performance problems for the file system. + +CREATE_SUBDIRS = NO + +# The OUTPUT_LANGUAGE tag is used to specify the language in which all +# documentation generated by doxygen is written. Doxygen will use this +# information to generate all constant output in the proper language. +# The default language is English, other supported languages are: +# Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese-Traditional, +# Croatian, Czech, Danish, Dutch, Esperanto, Farsi, Finnish, French, German, +# Greek, Hungarian, Italian, Japanese, Japanese-en (Japanese with English +# messages), Korean, Korean-en, Lithuanian, Norwegian, Macedonian, Persian, +# Polish, Portuguese, Romanian, Russian, Serbian, Serbian-Cyrilic, Slovak, +# Slovene, Spanish, Swedish, Ukrainian, and Vietnamese. + +OUTPUT_LANGUAGE = English + +# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will +# include brief member descriptions after the members that are listed in +# the file and class documentation (similar to JavaDoc). +# Set to NO to disable this. + +BRIEF_MEMBER_DESC = NO + +# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend +# the brief description of a member or function before the detailed description. +# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the +# brief descriptions will be completely suppressed. + +REPEAT_BRIEF = NO + +# This tag implements a quasi-intelligent brief description abbreviator +# that is used to form the text in various listings. Each string +# in this list, if found as the leading text of the brief description, will be +# stripped from the text and the result after processing the whole list, is +# used as the annotated text. Otherwise, the brief description is used as-is. +# If left blank, the following values are used ("$name" is automatically +# replaced with the name of the entity): "The $name class" "The $name widget" +# "The $name file" "is" "provides" "specifies" "contains" +# "represents" "a" "an" "the" + +ABBREVIATE_BRIEF = + +# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then +# Doxygen will generate a detailed section even if there is only a brief +# description. + +ALWAYS_DETAILED_SEC = NO + +# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all +# inherited members of a class in the documentation of that class as if those +# members were ordinary class members. Constructors, destructors and assignment +# operators of the base classes will not be shown. + +INLINE_INHERITED_MEMB = NO + +# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full +# path before files name in the file list and in the header files. If set +# to NO the shortest path that makes the file name unique will be used. + +FULL_PATH_NAMES = NO + +# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag +# can be used to strip a user-defined part of the path. Stripping is +# only done if one of the specified strings matches the left-hand part of +# the path. The tag can be used to show relative paths in the file list. +# If left blank the directory from which doxygen is run is used as the +# path to strip. + +STRIP_FROM_PATH = + +# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of +# the path mentioned in the documentation of a class, which tells +# the reader which header file to include in order to use a class. +# If left blank only the name of the header file containing the class +# definition is used. Otherwise one should specify the include paths that +# are normally passed to the compiler using the -I flag. + +STRIP_FROM_INC_PATH = + +# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter +# (but less readable) file names. This can be useful is your file systems +# doesn't support long names like on DOS, Mac, or CD-ROM. + +SHORT_NAMES = NO + +# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen +# will interpret the first line (until the first dot) of a JavaDoc-style +# comment as the brief description. If set to NO, the JavaDoc +# comments will behave just like regular Qt-style comments +# (thus requiring an explicit @brief command for a brief description.) + +JAVADOC_AUTOBRIEF = NO + +# If the QT_AUTOBRIEF tag is set to YES then Doxygen will +# interpret the first line (until the first dot) of a Qt-style +# comment as the brief description. If set to NO, the comments +# will behave just like regular Qt-style comments (thus requiring +# an explicit \brief command for a brief description.) + +QT_AUTOBRIEF = NO + +# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen +# treat a multi-line C++ special comment block (i.e. a block of //! or /// +# comments) as a brief description. This used to be the default behaviour. +# The new default is to treat a multi-line C++ comment block as a detailed +# description. Set this tag to YES if you prefer the old behaviour instead. + +MULTILINE_CPP_IS_BRIEF = YES + +# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented +# member inherits the documentation from any documented member that it +# re-implements. + +INHERIT_DOCS = YES + +# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce +# a new page for each member. If set to NO, the documentation of a member will +# be part of the file/class/namespace that contains it. + +SEPARATE_MEMBER_PAGES = NO + +# The TAB_SIZE tag can be used to set the number of spaces in a tab. +# Doxygen uses this value to replace tabs by spaces in code fragments. + +TAB_SIZE = 8 + +# This tag can be used to specify a number of aliases that acts +# as commands in the documentation. An alias has the form "name=value". +# For example adding "sideeffect=\par Side Effects:\n" will allow you to +# put the command \sideeffect (or @sideeffect) in the documentation, which +# will result in a user-defined paragraph with heading "Side Effects:". +# You can put \n's in the value part of an alias to insert newlines. + +ALIASES = + +# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C +# sources only. Doxygen will then generate output that is more tailored for C. +# For instance, some of the names that are used will be different. The list +# of all members will be omitted, etc. + +OPTIMIZE_OUTPUT_FOR_C = NO + +# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java +# sources only. Doxygen will then generate output that is more tailored for +# Java. For instance, namespaces will be presented as packages, qualified +# scopes will look different, etc. + +OPTIMIZE_OUTPUT_JAVA = NO + +# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran +# sources only. Doxygen will then generate output that is more tailored for +# Fortran. + +OPTIMIZE_FOR_FORTRAN = NO + +# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL +# sources. Doxygen will then generate output that is tailored for +# VHDL. + +OPTIMIZE_OUTPUT_VHDL = NO + +# Doxygen selects the parser to use depending on the extension of the files it parses. +# With this tag you can assign which parser to use for a given extension. +# Doxygen has a built-in mapping, but you can override or extend it using this tag. +# The format is ext=language, where ext is a file extension, and language is one of +# the parsers supported by doxygen: IDL, Java, Javascript, C#, C, C++, D, PHP, +# Objective-C, Python, Fortran, VHDL, C, C++. For instance to make doxygen treat +# .inc files as Fortran files (default is PHP), and .f files as C (default is Fortran), +# use: inc=Fortran f=C. Note that for custom extensions you also need to set FILE_PATTERNS otherwise the files are not read by doxygen. + +EXTENSION_MAPPING = + +# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want +# to include (a tag file for) the STL sources as input, then you should +# set this tag to YES in order to let doxygen match functions declarations and +# definitions whose arguments contain STL classes (e.g. func(std::string); v.s. +# func(std::string) {}). This also make the inheritance and collaboration +# diagrams that involve STL classes more complete and accurate. + +BUILTIN_STL_SUPPORT = NO + +# If you use Microsoft's C++/CLI language, you should set this option to YES to +# enable parsing support. + +CPP_CLI_SUPPORT = NO + +# Set the SIP_SUPPORT tag to YES if your project consists of sip sources only. +# Doxygen will parse them like normal C++ but will assume all classes use public +# instead of private inheritance when no explicit protection keyword is present. + +SIP_SUPPORT = NO + +# For Microsoft's IDL there are propget and propput attributes to indicate getter +# and setter methods for a property. Setting this option to YES (the default) +# will make doxygen to replace the get and set methods by a property in the +# documentation. This will only work if the methods are indeed getting or +# setting a simple type. If this is not the case, or you want to show the +# methods anyway, you should set this option to NO. + +IDL_PROPERTY_SUPPORT = YES + +# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC +# tag is set to YES, then doxygen will reuse the documentation of the first +# member in the group (if any) for the other members of the group. By default +# all members of a group must be documented explicitly. + +DISTRIBUTE_GROUP_DOC = NO + +# Set the SUBGROUPING tag to YES (the default) to allow class member groups of +# the same type (for instance a group of public functions) to be put as a +# subgroup of that type (e.g. under the Public Functions section). Set it to +# NO to prevent subgrouping. Alternatively, this can be done per class using +# the \nosubgrouping command. + +SUBGROUPING = YES + +# When TYPEDEF_HIDES_STRUCT is enabled, a typedef of a struct, union, or enum +# is documented as struct, union, or enum with the name of the typedef. So +# typedef struct TypeS {} TypeT, will appear in the documentation as a struct +# with name TypeT. When disabled the typedef will appear as a member of a file, +# namespace, or class. And the struct will be named TypeS. This can typically +# be useful for C code in case the coding convention dictates that all compound +# types are typedef'ed and only the typedef is referenced, never the tag name. + +TYPEDEF_HIDES_STRUCT = NO + +# The SYMBOL_CACHE_SIZE determines the size of the internal cache use to +# determine which symbols to keep in memory and which to flush to disk. +# When the cache is full, less often used symbols will be written to disk. +# For small to medium size projects (<1000 input files) the default value is +# probably good enough. For larger projects a too small cache size can cause +# doxygen to be busy swapping symbols to and from disk most of the time +# causing a significant performance penality. +# If the system has enough physical memory increasing the cache will improve the +# performance by keeping more symbols in memory. Note that the value works on +# a logarithmic scale so increasing the size by one will rougly double the +# memory usage. The cache size is given by this formula: +# 2^(16+SYMBOL_CACHE_SIZE). The valid range is 0..9, the default is 0, +# corresponding to a cache size of 2^16 = 65536 symbols + +SYMBOL_CACHE_SIZE = 0 + +#--------------------------------------------------------------------------- +# Build related configuration options +#--------------------------------------------------------------------------- + +# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in +# documentation are documented, even if no documentation was available. +# Private class members and static file members will be hidden unless +# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES + +EXTRACT_ALL = YES + +# If the EXTRACT_PRIVATE tag is set to YES all private members of a class +# will be included in the documentation. + +EXTRACT_PRIVATE = NO + +# If the EXTRACT_STATIC tag is set to YES all static members of a file +# will be included in the documentation. + +EXTRACT_STATIC = NO + +# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) +# defined locally in source files will be included in the documentation. +# If set to NO only classes defined in header files are included. + +EXTRACT_LOCAL_CLASSES = NO + +# This flag is only useful for Objective-C code. When set to YES local +# methods, which are defined in the implementation section but not in +# the interface are included in the documentation. +# If set to NO (the default) only methods in the interface are included. + +EXTRACT_LOCAL_METHODS = NO + +# If this flag is set to YES, the members of anonymous namespaces will be +# extracted and appear in the documentation as a namespace called +# 'anonymous_namespace{file}', where file will be replaced with the base +# name of the file that contains the anonymous namespace. By default +# anonymous namespace are hidden. + +EXTRACT_ANON_NSPACES = NO + +# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all +# undocumented members of documented classes, files or namespaces. +# If set to NO (the default) these members will be included in the +# various overviews, but no documentation section is generated. +# This option has no effect if EXTRACT_ALL is enabled. + +HIDE_UNDOC_MEMBERS = NO + +# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all +# undocumented classes that are normally visible in the class hierarchy. +# If set to NO (the default) these classes will be included in the various +# overviews. This option has no effect if EXTRACT_ALL is enabled. + +HIDE_UNDOC_CLASSES = NO + +# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all +# friend (class|struct|union) declarations. +# If set to NO (the default) these declarations will be included in the +# documentation. + +HIDE_FRIEND_COMPOUNDS = YES + +# If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any +# documentation blocks found inside the body of a function. +# If set to NO (the default) these blocks will be appended to the +# function's detailed documentation block. + +HIDE_IN_BODY_DOCS = NO + +# The INTERNAL_DOCS tag determines if documentation +# that is typed after a \internal command is included. If the tag is set +# to NO (the default) then the documentation will be excluded. +# Set it to YES to include the internal documentation. + +INTERNAL_DOCS = NO + +# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate +# file names in lower-case letters. If set to YES upper-case letters are also +# allowed. This is useful if you have classes or files whose names only differ +# in case and if your file system supports case sensitive file names. Windows +# and Mac users are advised to set this option to NO. + +CASE_SENSE_NAMES = YES + +# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen +# will show members with their full class and namespace scopes in the +# documentation. If set to YES the scope will be hidden. + +HIDE_SCOPE_NAMES = NO + +# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen +# will put a list of the files that are included by a file in the documentation +# of that file. + +SHOW_INCLUDE_FILES = NO + +# If the INLINE_INFO tag is set to YES (the default) then a tag [inline] +# is inserted in the documentation for inline members. + +INLINE_INFO = NO + +# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen +# will sort the (detailed) documentation of file and class members +# alphabetically by member name. If set to NO the members will appear in +# declaration order. + +SORT_MEMBER_DOCS = NO + +# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the +# brief documentation of file, namespace and class members alphabetically +# by member name. If set to NO (the default) the members will appear in +# declaration order. + +SORT_BRIEF_DOCS = NO + +# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen will sort the (brief and detailed) documentation of class members so that constructors and destructors are listed first. If set to NO (the default) the constructors will appear in the respective orders defined by SORT_MEMBER_DOCS and SORT_BRIEF_DOCS. This tag will be ignored for brief docs if SORT_BRIEF_DOCS is set to NO and ignored for detailed docs if SORT_MEMBER_DOCS is set to NO. + +SORT_MEMBERS_CTORS_1ST = NO + +# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the +# hierarchy of group names into alphabetical order. If set to NO (the default) +# the group names will appear in their defined order. + +SORT_GROUP_NAMES = NO + +# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be +# sorted by fully-qualified names, including namespaces. If set to +# NO (the default), the class list will be sorted only by class name, +# not including the namespace part. +# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES. +# Note: This option applies only to the class list, not to the +# alphabetical list. + +SORT_BY_SCOPE_NAME = NO + +# The GENERATE_TODOLIST tag can be used to enable (YES) or +# disable (NO) the todo list. This list is created by putting \todo +# commands in the documentation. + +GENERATE_TODOLIST = NO + +# The GENERATE_TESTLIST tag can be used to enable (YES) or +# disable (NO) the test list. This list is created by putting \test +# commands in the documentation. + +GENERATE_TESTLIST = NO + +# The GENERATE_BUGLIST tag can be used to enable (YES) or +# disable (NO) the bug list. This list is created by putting \bug +# commands in the documentation. + +GENERATE_BUGLIST = NO + +# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or +# disable (NO) the deprecated list. This list is created by putting +# \deprecated commands in the documentation. + +GENERATE_DEPRECATEDLIST = YES + +# The ENABLED_SECTIONS tag can be used to enable conditional +# documentation sections, marked by \if sectionname ... \endif. + +ENABLED_SECTIONS = + +# The MAX_INITIALIZER_LINES tag determines the maximum number of lines +# the initial value of a variable or define consists of for it to appear in +# the documentation. If the initializer consists of more lines than specified +# here it will be hidden. Use a value of 0 to hide initializers completely. +# The appearance of the initializer of individual variables and defines in the +# documentation can be controlled using \showinitializer or \hideinitializer +# command in the documentation regardless of this setting. + +MAX_INITIALIZER_LINES = 30 + +# Set the SHOW_USED_FILES tag to NO to disable the list of files generated +# at the bottom of the documentation of classes and structs. If set to YES the +# list will mention the files that were used to generate the documentation. + +SHOW_USED_FILES = NO + +# If the sources in your project are distributed over multiple directories +# then setting the SHOW_DIRECTORIES tag to YES will show the directory hierarchy +# in the documentation. The default is NO. + +SHOW_DIRECTORIES = NO + +# Set the SHOW_FILES tag to NO to disable the generation of the Files page. +# This will remove the Files entry from the Quick Index and from the +# Folder Tree View (if specified). The default is YES. + +SHOW_FILES = YES + +# Set the SHOW_NAMESPACES tag to NO to disable the generation of the +# Namespaces page. +# This will remove the Namespaces entry from the Quick Index +# and from the Folder Tree View (if specified). The default is YES. + +SHOW_NAMESPACES = YES + +# The FILE_VERSION_FILTER tag can be used to specify a program or script that +# doxygen should invoke to get the current version for each file (typically from +# the version control system). Doxygen will invoke the program by executing (via +# popen()) the command <command> <input-file>, where <command> is the value of +# the FILE_VERSION_FILTER tag, and <input-file> is the name of an input file +# provided by doxygen. Whatever the program writes to standard output +# is used as the file version. See the manual for examples. + +FILE_VERSION_FILTER = + +# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed by +# doxygen. The layout file controls the global structure of the generated output files +# in an output format independent way. The create the layout file that represents +# doxygen's defaults, run doxygen with the -l option. You can optionally specify a +# file name after the option, if omitted DoxygenLayout.xml will be used as the name +# of the layout file. + +LAYOUT_FILE = + +#--------------------------------------------------------------------------- +# configuration options related to warning and progress messages +#--------------------------------------------------------------------------- + +# The QUIET tag can be used to turn on/off the messages that are generated +# by doxygen. Possible values are YES and NO. If left blank NO is used. + +QUIET = NO + +# The WARNINGS tag can be used to turn on/off the warning messages that are +# generated by doxygen. Possible values are YES and NO. If left blank +# NO is used. + +WARNINGS = YES + +# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings +# for undocumented members. If EXTRACT_ALL is set to YES then this flag will +# automatically be disabled. + +WARN_IF_UNDOCUMENTED = YES + +# If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for +# potential errors in the documentation, such as not documenting some +# parameters in a documented function, or documenting parameters that +# don't exist or using markup commands wrongly. + +WARN_IF_DOC_ERROR = YES + +# This WARN_NO_PARAMDOC option can be abled to get warnings for +# functions that are documented, but have no documentation for their parameters +# or return value. If set to NO (the default) doxygen will only warn about +# wrong or incomplete parameter documentation, but not about the absence of +# documentation. + +WARN_NO_PARAMDOC = NO + +# The WARN_FORMAT tag determines the format of the warning messages that +# doxygen can produce. The string should contain the $file, $line, and $text +# tags, which will be replaced by the file and line number from which the +# warning originated and the warning text. Optionally the format may contain +# $version, which will be replaced by the version of the file (if it could +# be obtained via FILE_VERSION_FILTER) + +WARN_FORMAT = "$file:$line: $text" + +# The WARN_LOGFILE tag can be used to specify a file to which warning +# and error messages should be written. If left blank the output is written +# to stderr. + +WARN_LOGFILE = + +#--------------------------------------------------------------------------- +# configuration options related to the input files +#--------------------------------------------------------------------------- + +# The INPUT tag can be used to specify the files and/or directories that contain +# documented source files. You may enter file names like "myfile.cpp" or +# directories like "/usr/src/myproject". Separate the files or directories +# with spaces. + +INPUT = . + +# This tag can be used to specify the character encoding of the source files +# that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is +# also the default input encoding. Doxygen uses libiconv (or the iconv built +# into libc) for the transcoding. See http://www.gnu.org/software/libiconv for +# the list of possible encodings. + +INPUT_ENCODING = UTF-8 + +# If the value of the INPUT tag contains directories, you can use the +# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp +# and *.h) to filter out the source-files in the directories. If left +# blank the following patterns are tested: +# *.c *.cc *.cxx *.cpp *.c++ *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh *.hxx +# *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.py *.f90 + +FILE_PATTERNS = + +# The RECURSIVE tag can be used to turn specify whether or not subdirectories +# should be searched for input files as well. Possible values are YES and NO. +# If left blank NO is used. + +RECURSIVE = YES + +# The EXCLUDE tag can be used to specify files and/or directories that should +# excluded from the INPUT source files. This way you can easily exclude a +# subdirectory from a directory tree whose root is specified with the INPUT tag. + +EXCLUDE = + +# The EXCLUDE_SYMLINKS tag can be used select whether or not files or +# directories that are symbolic links (a Unix filesystem feature) are excluded +# from the input. + +EXCLUDE_SYMLINKS = NO + +# If the value of the INPUT tag contains directories, you can use the +# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude +# certain files from those directories. Note that the wildcards are matched +# against the file with absolute path, so to exclude all test directories +# for example use the pattern */test/* + +EXCLUDE_PATTERNS = *Block* + +# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names +# (namespaces, classes, functions, etc.) that should be excluded from the +# output. The symbol name can be a fully qualified name, a word, or if the +# wildcard * is used, a substring. Examples: ANamespace, AClass, +# AClass::ANamespace, ANamespace::*Test + +EXCLUDE_SYMBOLS = + +# The EXAMPLE_PATH tag can be used to specify one or more files or +# directories that contain example code fragments that are included (see +# the \include command). + +EXAMPLE_PATH = + +# If the value of the EXAMPLE_PATH tag contains directories, you can use the +# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp +# and *.h) to filter out the source-files in the directories. If left +# blank all files are included. + +EXAMPLE_PATTERNS = + +# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be +# searched for input files to be used with the \include or \dontinclude +# commands irrespective of the value of the RECURSIVE tag. +# Possible values are YES and NO. If left blank NO is used. + +EXAMPLE_RECURSIVE = NO + +# The IMAGE_PATH tag can be used to specify one or more files or +# directories that contain image that are included in the documentation (see +# the \image command). + +IMAGE_PATH = + +# The INPUT_FILTER tag can be used to specify a program that doxygen should +# invoke to filter for each input file. Doxygen will invoke the filter program +# by executing (via popen()) the command <filter> <input-file>, where <filter> +# is the value of the INPUT_FILTER tag, and <input-file> is the name of an +# input file. Doxygen will then use the output that the filter program writes +# to standard output. +# If FILTER_PATTERNS is specified, this tag will be +# ignored. + +INPUT_FILTER = + +# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern +# basis. +# Doxygen will compare the file name with each pattern and apply the +# filter if there is a match. +# The filters are a list of the form: +# pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further +# info on how filters are used. If FILTER_PATTERNS is empty, INPUT_FILTER +# is applied to all files. + +FILTER_PATTERNS = + +# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using +# INPUT_FILTER) will be used to filter the input files when producing source +# files to browse (i.e. when SOURCE_BROWSER is set to YES). + +FILTER_SOURCE_FILES = NO + +#--------------------------------------------------------------------------- +# configuration options related to source browsing +#--------------------------------------------------------------------------- + +# If the SOURCE_BROWSER tag is set to YES then a list of source files will +# be generated. Documented entities will be cross-referenced with these sources. +# Note: To get rid of all source code in the generated output, make sure also +# VERBATIM_HEADERS is set to NO. + +SOURCE_BROWSER = NO + +# Setting the INLINE_SOURCES tag to YES will include the body +# of functions and classes directly in the documentation. + +INLINE_SOURCES = NO + +# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct +# doxygen to hide any special comment blocks from generated source code +# fragments. Normal C and C++ comments will always remain visible. + +STRIP_CODE_COMMENTS = YES + +# If the REFERENCED_BY_RELATION tag is set to YES +# then for each documented function all documented +# functions referencing it will be listed. + +REFERENCED_BY_RELATION = YES + +# If the REFERENCES_RELATION tag is set to YES +# then for each documented function all documented entities +# called/used by that function will be listed. + +REFERENCES_RELATION = YES + +# If the REFERENCES_LINK_SOURCE tag is set to YES (the default) +# and SOURCE_BROWSER tag is set to YES, then the hyperlinks from +# functions in REFERENCES_RELATION and REFERENCED_BY_RELATION lists will +# link to the source code. +# Otherwise they will link to the documentation. + +REFERENCES_LINK_SOURCE = YES + +# If the USE_HTAGS tag is set to YES then the references to source code +# will point to the HTML generated by the htags(1) tool instead of doxygen +# built-in source browser. The htags tool is part of GNU's global source +# tagging system (see http://www.gnu.org/software/global/global.html). You +# will need version 4.8.6 or higher. + +USE_HTAGS = NO + +# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen +# will generate a verbatim copy of the header file for each class for +# which an include is specified. Set to NO to disable this. + +VERBATIM_HEADERS = NO + +#--------------------------------------------------------------------------- +# configuration options related to the alphabetical class index +#--------------------------------------------------------------------------- + +# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index +# of all compounds will be generated. Enable this if the project +# contains a lot of classes, structs, unions or interfaces. + +ALPHABETICAL_INDEX = NO + +# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then +# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns +# in which this list will be split (can be a number in the range [1..20]) + +COLS_IN_ALPHA_INDEX = 5 + +# In case all classes in a project start with a common prefix, all +# classes will be put under the same header in the alphabetical index. +# The IGNORE_PREFIX tag can be used to specify one or more prefixes that +# should be ignored while generating the index headers. + +IGNORE_PREFIX = + +#--------------------------------------------------------------------------- +# configuration options related to the HTML output +#--------------------------------------------------------------------------- + +# If the GENERATE_HTML tag is set to YES (the default) Doxygen will +# generate HTML output. + +GENERATE_HTML = YES + +# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `html' will be used as the default path. + +HTML_OUTPUT = html + +# The HTML_FILE_EXTENSION tag can be used to specify the file extension for +# each generated HTML page (for example: .htm,.php,.asp). If it is left blank +# doxygen will generate files with .html extension. + +HTML_FILE_EXTENSION = .html + +# The HTML_HEADER tag can be used to specify a personal HTML header for +# each generated HTML page. If it is left blank doxygen will generate a +# standard header. + +HTML_HEADER = + +# The HTML_FOOTER tag can be used to specify a personal HTML footer for +# each generated HTML page. If it is left blank doxygen will generate a +# standard footer. + +HTML_FOOTER = + +# If the HTML_TIMESTAMP tag is set to YES then the generated HTML +# documentation will contain the timesstamp. + +HTML_TIMESTAMP = NO + +# The HTML_STYLESHEET tag can be used to specify a user-defined cascading +# style sheet that is used by each HTML page. It can be used to +# fine-tune the look of the HTML output. If the tag is left blank doxygen +# will generate a default style sheet. Note that doxygen will try to copy +# the style sheet file to the HTML output directory, so don't put your own +# stylesheet in the HTML output directory as well, or it will be erased! + +HTML_STYLESHEET = + +# If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes, +# files or namespaces will be aligned in HTML using tables. If set to +# NO a bullet list will be used. + +HTML_ALIGN_MEMBERS = YES + +# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML +# documentation will contain sections that can be hidden and shown after the +# page has loaded. For this to work a browser that supports +# JavaScript and DHTML is required (for instance Mozilla 1.0+, Firefox +# Netscape 6.0+, Internet explorer 5.0+, Konqueror, or Safari). + +HTML_DYNAMIC_SECTIONS = NO + +# If the GENERATE_DOCSET tag is set to YES, additional index files +# will be generated that can be used as input for Apple's Xcode 3 +# integrated development environment, introduced with OSX 10.5 (Leopard). +# To create a documentation set, doxygen will generate a Makefile in the +# HTML output directory. Running make will produce the docset in that +# directory and running "make install" will install the docset in +# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find +# it at startup. +# See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html for more information. + +GENERATE_DOCSET = NO + +# When GENERATE_DOCSET tag is set to YES, this tag determines the name of the +# feed. A documentation feed provides an umbrella under which multiple +# documentation sets from a single provider (such as a company or product suite) +# can be grouped. + +DOCSET_FEEDNAME = "Doxygen generated docs" + +# When GENERATE_DOCSET tag is set to YES, this tag specifies a string that +# should uniquely identify the documentation set bundle. This should be a +# reverse domain-name style string, e.g. com.mycompany.MyDocSet. Doxygen +# will append .docset to the name. + +DOCSET_BUNDLE_ID = org.doxygen.Project + +# If the GENERATE_HTMLHELP tag is set to YES, additional index files +# will be generated that can be used as input for tools like the +# Microsoft HTML help workshop to generate a compiled HTML help file (.chm) +# of the generated HTML documentation. + +GENERATE_HTMLHELP = NO + +# If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can +# be used to specify the file name of the resulting .chm file. You +# can add a path in front of the file if the result should not be +# written to the html output directory. + +CHM_FILE = + +# If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can +# be used to specify the location (absolute path including file name) of +# the HTML help compiler (hhc.exe). If non-empty doxygen will try to run +# the HTML help compiler on the generated index.hhp. + +HHC_LOCATION = + +# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag +# controls if a separate .chi index file is generated (YES) or that +# it should be included in the master .chm file (NO). + +GENERATE_CHI = NO + +# If the GENERATE_HTMLHELP tag is set to YES, the CHM_INDEX_ENCODING +# is used to encode HtmlHelp index (hhk), content (hhc) and project file +# content. + +CHM_INDEX_ENCODING = + +# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag +# controls whether a binary table of contents is generated (YES) or a +# normal table of contents (NO) in the .chm file. + +BINARY_TOC = NO + +# The TOC_EXPAND flag can be set to YES to add extra items for group members +# to the contents of the HTML help documentation and to the tree view. + +TOC_EXPAND = NO + +# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and QHP_VIRTUAL_FOLDER +# are set, an additional index file will be generated that can be used as input for +# Qt's qhelpgenerator to generate a Qt Compressed Help (.qch) of the generated +# HTML documentation. + +GENERATE_QHP = NO + +# If the QHG_LOCATION tag is specified, the QCH_FILE tag can +# be used to specify the file name of the resulting .qch file. +# The path specified is relative to the HTML output folder. + +QCH_FILE = + +# The QHP_NAMESPACE tag specifies the namespace to use when generating +# Qt Help Project output. For more information please see +# http://doc.trolltech.com/qthelpproject.html#namespace + +QHP_NAMESPACE = + +# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating +# Qt Help Project output. For more information please see +# http://doc.trolltech.com/qthelpproject.html#virtual-folders + +QHP_VIRTUAL_FOLDER = doc + +# If QHP_CUST_FILTER_NAME is set, it specifies the name of a custom filter to add. +# For more information please see +# http://doc.trolltech.com/qthelpproject.html#custom-filters + +QHP_CUST_FILTER_NAME = + +# The QHP_CUST_FILT_ATTRS tag specifies the list of the attributes of the custom filter to add.For more information please see +# <a href="http://doc.trolltech.com/qthelpproject.html#custom-filters">Qt Help Project / Custom Filters</a>. + +QHP_CUST_FILTER_ATTRS = + +# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this project's +# filter section matches. +# <a href="http://doc.trolltech.com/qthelpproject.html#filter-attributes">Qt Help Project / Filter Attributes</a>. + +QHP_SECT_FILTER_ATTRS = + +# If the GENERATE_QHP tag is set to YES, the QHG_LOCATION tag can +# be used to specify the location of Qt's qhelpgenerator. +# If non-empty doxygen will try to run qhelpgenerator on the generated +# .qhp file. + +QHG_LOCATION = + +# The DISABLE_INDEX tag can be used to turn on/off the condensed index at +# top of each HTML page. The value NO (the default) enables the index and +# the value YES disables it. + +DISABLE_INDEX = NO + +# This tag can be used to set the number of enum values (range [1..20]) +# that doxygen will group on one line in the generated HTML documentation. + +ENUM_VALUES_PER_LINE = 4 + +# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index +# structure should be generated to display hierarchical information. +# If the tag value is set to YES, a side panel will be generated +# containing a tree-like index structure (just like the one that +# is generated for HTML Help). For this to work a browser that supports +# JavaScript, DHTML, CSS and frames is required (i.e. any modern browser). +# Windows users are probably better off using the HTML help feature. + +GENERATE_TREEVIEW = NO + +# By enabling USE_INLINE_TREES, doxygen will generate the Groups, Directories, +# and Class Hierarchy pages using a tree view instead of an ordered list. + +USE_INLINE_TREES = NO + +# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be +# used to set the initial width (in pixels) of the frame in which the tree +# is shown. + +TREEVIEW_WIDTH = 250 + +# Use this tag to change the font size of Latex formulas included +# as images in the HTML documentation. The default is 10. Note that +# when you change the font size after a successful doxygen run you need +# to manually remove any form_*.png images from the HTML output directory +# to force them to be regenerated. + +FORMULA_FONTSIZE = 10 + +# When the SEARCHENGINE tag is enable doxygen will generate a search box for the HTML output. The underlying search engine uses javascript +# and DHTML and should work on any modern browser. Note that when using HTML help (GENERATE_HTMLHELP) or Qt help (GENERATE_QHP) +# there is already a search function so this one should typically +# be disabled. + +SEARCHENGINE = NO + +#--------------------------------------------------------------------------- +# configuration options related to the LaTeX output +#--------------------------------------------------------------------------- + +# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will +# generate Latex output. + +GENERATE_LATEX = NO + +# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `latex' will be used as the default path. + +LATEX_OUTPUT = latex + +# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be +# invoked. If left blank `latex' will be used as the default command name. + +LATEX_CMD_NAME = latex + +# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to +# generate index for LaTeX. If left blank `makeindex' will be used as the +# default command name. + +MAKEINDEX_CMD_NAME = makeindex + +# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact +# LaTeX documents. This may be useful for small projects and may help to +# save some trees in general. + +COMPACT_LATEX = NO + +# The PAPER_TYPE tag can be used to set the paper type that is used +# by the printer. Possible values are: a4, a4wide, letter, legal and +# executive. If left blank a4wide will be used. + +PAPER_TYPE = a4wide + +# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX +# packages that should be included in the LaTeX output. + +EXTRA_PACKAGES = + +# The LATEX_HEADER tag can be used to specify a personal LaTeX header for +# the generated latex document. The header should contain everything until +# the first chapter. If it is left blank doxygen will generate a +# standard header. Notice: only use this tag if you know what you are doing! + +LATEX_HEADER = + +# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated +# is prepared for conversion to pdf (using ps2pdf). The pdf file will +# contain links (just like the HTML output) instead of page references +# This makes the output suitable for online browsing using a pdf viewer. + +PDF_HYPERLINKS = NO + +# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of +# plain latex in the generated Makefile. Set this option to YES to get a +# higher quality PDF documentation. + +USE_PDFLATEX = NO + +# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode. +# command to the generated LaTeX files. This will instruct LaTeX to keep +# running if errors occur, instead of asking the user for help. +# This option is also used when generating formulas in HTML. + +LATEX_BATCHMODE = NO + +# If LATEX_HIDE_INDICES is set to YES then doxygen will not +# include the index chapters (such as File Index, Compound Index, etc.) +# in the output. + +LATEX_HIDE_INDICES = NO + +# If LATEX_SOURCE_CODE is set to YES then doxygen will include source code with syntax highlighting in the LaTeX output. Note that which sources are shown also depends on other settings such as SOURCE_BROWSER. + +LATEX_SOURCE_CODE = NO + +#--------------------------------------------------------------------------- +# configuration options related to the RTF output +#--------------------------------------------------------------------------- + +# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output +# The RTF output is optimized for Word 97 and may not look very pretty with +# other RTF readers or editors. + +GENERATE_RTF = NO + +# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `rtf' will be used as the default path. + +RTF_OUTPUT = rtf + +# If the COMPACT_RTF tag is set to YES Doxygen generates more compact +# RTF documents. This may be useful for small projects and may help to +# save some trees in general. + +COMPACT_RTF = NO + +# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated +# will contain hyperlink fields. The RTF file will +# contain links (just like the HTML output) instead of page references. +# This makes the output suitable for online browsing using WORD or other +# programs which support those fields. +# Note: wordpad (write) and others do not support links. + +RTF_HYPERLINKS = NO + +# Load stylesheet definitions from file. Syntax is similar to doxygen's +# config file, i.e. a series of assignments. You only have to provide +# replacements, missing definitions are set to their default value. + +RTF_STYLESHEET_FILE = + +# Set optional variables used in the generation of an rtf document. +# Syntax is similar to doxygen's config file. + +RTF_EXTENSIONS_FILE = + +#--------------------------------------------------------------------------- +# configuration options related to the man page output +#--------------------------------------------------------------------------- + +# If the GENERATE_MAN tag is set to YES (the default) Doxygen will +# generate man pages + +GENERATE_MAN = NO + +# The MAN_OUTPUT tag is used to specify where the man pages will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `man' will be used as the default path. + +MAN_OUTPUT = man + +# The MAN_EXTENSION tag determines the extension that is added to +# the generated man pages (default is the subroutine's section .3) + +MAN_EXTENSION = .3 + +# If the MAN_LINKS tag is set to YES and Doxygen generates man output, +# then it will generate one additional man file for each entity +# documented in the real man page(s). These additional files +# only source the real man page, but without them the man command +# would be unable to find the correct page. The default is NO. + +MAN_LINKS = NO + +#--------------------------------------------------------------------------- +# configuration options related to the XML output +#--------------------------------------------------------------------------- + +# If the GENERATE_XML tag is set to YES Doxygen will +# generate an XML file that captures the structure of +# the code including all documentation. + +GENERATE_XML = NO + +# The XML_OUTPUT tag is used to specify where the XML pages will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `xml' will be used as the default path. + +XML_OUTPUT = xml + +# The XML_SCHEMA tag can be used to specify an XML schema, +# which can be used by a validating XML parser to check the +# syntax of the XML files. + +XML_SCHEMA = + +# The XML_DTD tag can be used to specify an XML DTD, +# which can be used by a validating XML parser to check the +# syntax of the XML files. + +XML_DTD = + +# If the XML_PROGRAMLISTING tag is set to YES Doxygen will +# dump the program listings (including syntax highlighting +# and cross-referencing information) to the XML output. Note that +# enabling this will significantly increase the size of the XML output. + +XML_PROGRAMLISTING = YES + +#--------------------------------------------------------------------------- +# configuration options for the AutoGen Definitions output +#--------------------------------------------------------------------------- + +# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will +# generate an AutoGen Definitions (see autogen.sf.net) file +# that captures the structure of the code including all +# documentation. Note that this feature is still experimental +# and incomplete at the moment. + +GENERATE_AUTOGEN_DEF = NO + +#--------------------------------------------------------------------------- +# configuration options related to the Perl module output +#--------------------------------------------------------------------------- + +# If the GENERATE_PERLMOD tag is set to YES Doxygen will +# generate a Perl module file that captures the structure of +# the code including all documentation. Note that this +# feature is still experimental and incomplete at the +# moment. + +GENERATE_PERLMOD = NO + +# If the PERLMOD_LATEX tag is set to YES Doxygen will generate +# the necessary Makefile rules, Perl scripts and LaTeX code to be able +# to generate PDF and DVI output from the Perl module output. + +PERLMOD_LATEX = NO + +# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be +# nicely formatted so it can be parsed by a human reader. +# This is useful +# if you want to understand what is going on. +# On the other hand, if this +# tag is set to NO the size of the Perl module output will be much smaller +# and Perl will parse it just the same. + +PERLMOD_PRETTY = YES + +# The names of the make variables in the generated doxyrules.make file +# are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. +# This is useful so different doxyrules.make files included by the same +# Makefile don't overwrite each other's variables. + +PERLMOD_MAKEVAR_PREFIX = + +#--------------------------------------------------------------------------- +# Configuration options related to the preprocessor +#--------------------------------------------------------------------------- + +# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will +# evaluate all C-preprocessor directives found in the sources and include +# files. + +ENABLE_PREPROCESSING = YES + +# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro +# names in the source code. If set to NO (the default) only conditional +# compilation will be performed. Macro expansion can be done in a controlled +# way by setting EXPAND_ONLY_PREDEF to YES. + +MACRO_EXPANSION = NO + +# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES +# then the macro expansion is limited to the macros specified with the +# PREDEFINED and EXPAND_AS_DEFINED tags. + +EXPAND_ONLY_PREDEF = NO + +# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files +# in the INCLUDE_PATH (see below) will be search if a #include is found. + +SEARCH_INCLUDES = YES + +# The INCLUDE_PATH tag can be used to specify one or more directories that +# contain include files that are not input files but should be processed by +# the preprocessor. + +INCLUDE_PATH = + +# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard +# patterns (like *.h and *.hpp) to filter out the header-files in the +# directories. If left blank, the patterns specified with FILE_PATTERNS will +# be used. + +INCLUDE_FILE_PATTERNS = + +# The PREDEFINED tag can be used to specify one or more macro names that +# are defined before the preprocessor is started (similar to the -D option of +# gcc). The argument of the tag is a list of macros of the form: name +# or name=definition (no spaces). If the definition and the = are +# omitted =1 is assumed. To prevent a macro definition from being +# undefined via #undef or recursively expanded use the := operator +# instead of the = operator. + +PREDEFINED = + +# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then +# this tag can be used to specify a list of macro names that should be expanded. +# The macro definition that is found in the sources will be used. +# Use the PREDEFINED tag if you want to use a different macro definition. + +EXPAND_AS_DEFINED = + +# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then +# doxygen's preprocessor will remove all function-like macros that are alone +# on a line, have an all uppercase name, and do not end with a semicolon. Such +# function macros are typically used for boiler-plate code, and will confuse +# the parser if not removed. + +SKIP_FUNCTION_MACROS = YES + +#--------------------------------------------------------------------------- +# Configuration::additions related to external references +#--------------------------------------------------------------------------- + +# The TAGFILES option can be used to specify one or more tagfiles. +# Optionally an initial location of the external documentation +# can be added for each tagfile. The format of a tag file without +# this location is as follows: +# +# TAGFILES = file1 file2 ... +# Adding location for the tag files is done as follows: +# +# TAGFILES = file1=loc1 "file2 = loc2" ... +# where "loc1" and "loc2" can be relative or absolute paths or +# URLs. If a location is present for each tag, the installdox tool +# does not have to be run to correct the links. +# Note that each tag file must have a unique name +# (where the name does NOT include the path) +# If a tag file is not located in the directory in which doxygen +# is run, you must also specify the path to the tagfile here. + +TAGFILES = + +# When a file name is specified after GENERATE_TAGFILE, doxygen will create +# a tag file that is based on the input files it reads. + +GENERATE_TAGFILE = + +# If the ALLEXTERNALS tag is set to YES all external classes will be listed +# in the class index. If set to NO only the inherited external classes +# will be listed. + +ALLEXTERNALS = NO + +# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed +# in the modules index. If set to NO, only the current project's groups will +# be listed. + +EXTERNAL_GROUPS = YES + +# The PERL_PATH should be the absolute path and name of the perl script +# interpreter (i.e. the result of `which perl'). + +PERL_PATH = /usr/bin/perl + +#--------------------------------------------------------------------------- +# Configuration options related to the dot tool +#--------------------------------------------------------------------------- + +# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will +# generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base +# or super classes. Setting the tag to NO turns the diagrams off. Note that +# this option is superseded by the HAVE_DOT option below. This is only a +# fallback. It is recommended to install and use dot, since it yields more +# powerful graphs. + +CLASS_DIAGRAMS = YES + +# You can define message sequence charts within doxygen comments using the \msc +# command. Doxygen will then run the mscgen tool (see +# http://www.mcternan.me.uk/mscgen/) to produce the chart and insert it in the +# documentation. The MSCGEN_PATH tag allows you to specify the directory where +# the mscgen tool resides. If left empty the tool is assumed to be found in the +# default search path. + +MSCGEN_PATH = + +# If set to YES, the inheritance and collaboration graphs will hide +# inheritance and usage relations if the target is undocumented +# or is not a class. + +HIDE_UNDOC_RELATIONS = YES + +# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is +# available from the path. This tool is part of Graphviz, a graph visualization +# toolkit from AT&T and Lucent Bell Labs. The other options in this section +# have no effect if this option is set to NO (the default) + +HAVE_DOT = NO + +# By default doxygen will write a font called FreeSans.ttf to the output +# directory and reference it in all dot files that doxygen generates. This +# font does not include all possible unicode characters however, so when you need +# these (or just want a differently looking font) you can specify the font name +# using DOT_FONTNAME. You need need to make sure dot is able to find the font, +# which can be done by putting it in a standard location or by setting the +# DOTFONTPATH environment variable or by setting DOT_FONTPATH to the directory +# containing the font. + +DOT_FONTNAME = FreeSans + +# The DOT_FONTSIZE tag can be used to set the size of the font of dot graphs. +# The default size is 10pt. + +DOT_FONTSIZE = 10 + +# By default doxygen will tell dot to use the output directory to look for the +# FreeSans.ttf font (which doxygen will put there itself). If you specify a +# different font using DOT_FONTNAME you can set the path where dot +# can find it using this tag. + +DOT_FONTPATH = + +# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen +# will generate a graph for each documented class showing the direct and +# indirect inheritance relations. Setting this tag to YES will force the +# the CLASS_DIAGRAMS tag to NO. + +CLASS_GRAPH = YES + +# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen +# will generate a graph for each documented class showing the direct and +# indirect implementation dependencies (inheritance, containment, and +# class references variables) of the class with other documented classes. + +COLLABORATION_GRAPH = YES + +# If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen +# will generate a graph for groups, showing the direct groups dependencies + +GROUP_GRAPHS = YES + +# If the UML_LOOK tag is set to YES doxygen will generate inheritance and +# collaboration diagrams in a style similar to the OMG's Unified Modeling +# Language. + +UML_LOOK = NO + +# If set to YES, the inheritance and collaboration graphs will show the +# relations between templates and their instances. + +TEMPLATE_RELATIONS = NO + +# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT +# tags are set to YES then doxygen will generate a graph for each documented +# file showing the direct and indirect include dependencies of the file with +# other documented files. + +INCLUDE_GRAPH = YES + +# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and +# HAVE_DOT tags are set to YES then doxygen will generate a graph for each +# documented header file showing the documented files that directly or +# indirectly include this file. + +INCLUDED_BY_GRAPH = YES + +# If the CALL_GRAPH and HAVE_DOT options are set to YES then +# doxygen will generate a call dependency graph for every global function +# or class method. Note that enabling this option will significantly increase +# the time of a run. So in most cases it will be better to enable call graphs +# for selected functions only using the \callgraph command. + +CALL_GRAPH = NO + +# If the CALLER_GRAPH and HAVE_DOT tags are set to YES then +# doxygen will generate a caller dependency graph for every global function +# or class method. Note that enabling this option will significantly increase +# the time of a run. So in most cases it will be better to enable caller +# graphs for selected functions only using the \callergraph command. + +CALLER_GRAPH = NO + +# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen +# will graphical hierarchy of all classes instead of a textual one. + +GRAPHICAL_HIERARCHY = YES + +# If the DIRECTORY_GRAPH, SHOW_DIRECTORIES and HAVE_DOT tags are set to YES +# then doxygen will show the dependencies a directory has on other directories +# in a graphical way. The dependency relations are determined by the #include +# relations between the files in the directories. + +DIRECTORY_GRAPH = YES + +# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images +# generated by dot. Possible values are png, jpg, or gif +# If left blank png will be used. + +DOT_IMAGE_FORMAT = png + +# The tag DOT_PATH can be used to specify the path where the dot tool can be +# found. If left blank, it is assumed the dot tool can be found in the path. + +DOT_PATH = + +# The DOTFILE_DIRS tag can be used to specify one or more directories that +# contain dot files that are included in the documentation (see the +# \dotfile command). + +DOTFILE_DIRS = + +# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of +# nodes that will be shown in the graph. If the number of nodes in a graph +# becomes larger than this value, doxygen will truncate the graph, which is +# visualized by representing a node as a red box. Note that doxygen if the +# number of direct children of the root node in a graph is already larger than +# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note +# that the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH. + +DOT_GRAPH_MAX_NODES = 50 + +# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the +# graphs generated by dot. A depth value of 3 means that only nodes reachable +# from the root by following a path via at most 3 edges will be shown. Nodes +# that lay further from the root node will be omitted. Note that setting this +# option to 1 or 2 may greatly reduce the computation time needed for large +# code bases. Also note that the size of a graph can be further restricted by +# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction. + +MAX_DOT_GRAPH_DEPTH = 0 + +# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent +# background. This is disabled by default, because dot on Windows does not +# seem to support this out of the box. Warning: Depending on the platform used, +# enabling this option may lead to badly anti-aliased labels on the edges of +# a graph (i.e. they become hard to read). + +DOT_TRANSPARENT = NO + +# Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output +# files in one run (i.e. multiple -o and -T options on the command line). This +# makes dot run faster, but since only newer versions of dot (>1.8.10) +# support this, this feature is disabled by default. + +DOT_MULTI_TARGETS = NO + +# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will +# generate a legend page explaining the meaning of the various boxes and +# arrows in the dot generated graphs. + +GENERATE_LEGEND = YES + +# If the DOT_CLEANUP tag is set to YES (the default) Doxygen will +# remove the intermediate dot files that are used to generate +# the various graphs. + +DOT_CLEANUP = YES diff --git a/silecs-communication-cpp/src/demo/SilecsHeader_1_0_0.h b/silecs-communication-cpp/src/demo/SilecsHeader_1_0_0.h new file mode 100644 index 0000000..31bce37 --- /dev/null +++ b/silecs-communication-cpp/src/demo/SilecsHeader_1_0_0.h @@ -0,0 +1,269 @@ +/* Copyright CERN 2015 + * + * WARNING: This code is automatically generated from your SILECS deploy unit document. + * You should never modify the content of this file as it would break consistency. + * Furthermore, any changes will be overwritten in the next code generation. + * Any modification shall be done using the SILECS development environment + * and regenerating this source code. + */ + +#ifndef SILECSHEADER_1_0_0_H_ +#define SILECSHEADER_1_0_0_H_ + +#include <silecs-communication/wrapper/Block.h> +#include <silecs-communication/wrapper/DeployUnit.h> +#include <silecs-communication/wrapper/Design.h> +#include <silecs-communication/wrapper/Device.h> + +namespace SilecsHeader_1_0_0 +{ + +class Design; + +class HdrBlk : public SilecsWrapper::Block +{ +public: + /*! + * \brief hdrBlk constructor. It creates an empty block. + */ + HdrBlk() : + SilecsWrapper::Block("hdrBlk"), + _checksum(0), + _date(0) + { + } + + ~HdrBlk() + { + } + + /*! + * \brief Get _version register. + * \return value. + */ + const std::string& get_version() const + { + return _version; + } + + /*! + * \brief Set _version register. + * \param value to be set. + */ + void set_version(const std::string& value) + { + _version = value; + } + + /*! + * \brief Get _checksum register. + * \return value. + */ + uint32_t get_checksum() const + { + return _checksum; + } + + /*! + * \brief Set _checksum register. + * \param value to be set. + */ + void set_checksum(uint32_t value) + { + _checksum = value; + } + + /*! + * \brief Get _user register. + * \return value. + */ + const std::string& get_user() const + { + return _user; + } + + /*! + * \brief Set _user register. + * \param value to be set. + */ + void set_user(const std::string& value) + { + _user = value; + } + + /*! + * \brief Get _date register. + * \return value. + */ + double get_date() const + { + return _date; + } + + /*! + * \brief Set _date register. + * \param value to be set. + */ + void set_date(double value) + { + _date = value; + } +private: + std::string _version; + uint32_t _checksum; + std::string _user; + double _date; + +}; +class Device : public SilecsWrapper::Device +{ +public: + Device(const std::string& label, SilecsWrapper::Controller *controller) : + SilecsWrapper::Device(label, controller) + { + } + + ~Device() + { + } + + /*! + * \brief Get hdrBlk block. + * \param block HdrBlk reference where to store returned value. + */ + void getHdrBlk(HdrBlk &block) + { + // Copy register _version + block.set_version(getSilecsDevice()->getRegister("_version")->getValString()); + // Copy register _checksum + block.set_checksum(getSilecsDevice()->getRegister("_checksum")->getValUInt32()); + // Copy register _user + block.set_user(getSilecsDevice()->getRegister("_user")->getValString()); + // Copy register _date + block.set_date(getSilecsDevice()->getRegister("_date")->getValDate()); + } + + + /*! + * \brief Receive hdrBlk block for current device. + */ + void receiveHdrBlk() + { + _silecsDevice->recv("hdrBlk"); + } + + +}; + +class Controller : public SilecsWrapper::Controller +{ +public: + Controller(const std::string& name, const std::string& domain, Design *design) : + SilecsWrapper::Controller(name, domain, (SilecsWrapper::Design*) design) + { + _deviceMap.insert(std::pair<std::string, Device*>("0", new Device("0", this))); + } + + ~Controller() + { + map<std::string, Device*>::iterator it; + for (it = _deviceMap.begin(); it != _deviceMap.end(); it++) + { + delete it->second; + } + } + + /*! + * \brief Return pointer to the requested device. + * \param label Device label. + */ + Device* getDevice(const std::string& label) + { + if (_deviceMap.find(label) != _deviceMap.end()) + { + return _deviceMap[label]; + } + throw Silecs::SilecsException(__FILE__, __LINE__, Silecs::PARAM_UNKNOWN_DEVICE_NAME, label); + } + + std::map<std::string, Device*>& getDeviceMap() + { + return _deviceMap; + } + /*! + * \brief Receive hdrBlk blocks from all devices of current controller. + */ + void receiveHdrBlkAllDevices() + { + _silecsPLC->recv("hdrBlk"); + } + +private: + std::map<std::string, Device*> _deviceMap; +}; + +class Design : public SilecsWrapper::Design +{ +public: + + Design(SilecsWrapper::DeployUnit *deployUnit) : + SilecsWrapper::Design("SilecsHeader", "1.0.0", deployUnit) + { + + _controllerMap.insert( + std::pair<std::string, Controller*>("cfp-774-csimatic-s7-02", + new Controller("cfp-774-csimatic-s7-02", "TST", this))); + + } + + ~Design() + { + map<std::string, Controller*>::iterator it; + for (it = _controllerMap.begin(); it != _controllerMap.end(); it++) + { + delete it->second; + } + } + + /*! + * \brief Return pointer to the requested controller. + * \param name Controller's name. + */ + Controller* getController(const std::string& name) + { + if (_controllerMap.find(name) != _controllerMap.end()) + { + return _controllerMap[name]; + } + throw Silecs::SilecsException(__FILE__, __LINE__, Silecs::PARAM_UNKNOWN_PLC_HOSTNAME, name); + } + + /*! + * \brief Return pointer to the controller cfp-774-csimatic-s7-02. + */ + Controller* getCfp_774_csimatic_s7_02() + { + return _controllerMap["cfp-774-csimatic-s7-02"]; + } + + /*! + * \brief Receive hdrBlk blocks from all connected controllers. + */ + void receiveHdrBlkAllControllers() + { + _silecsCluster->recv("hdrBlk"); + } + + std::map<std::string, Controller*>& getControllerMap() + { + return _controllerMap; + } + +private: + std::map<std::string, Controller*> _controllerMap; + +}; + +} /* namespace SilecsHeader_1_0_0 */ + +#endif /* SILECSHEADER_1_0_0_H_ */ diff --git a/silecs-communication-cpp/src/demo/SilecsValid_1_0_0.h b/silecs-communication-cpp/src/demo/SilecsValid_1_0_0.h new file mode 100644 index 0000000..2ef4e1f --- /dev/null +++ b/silecs-communication-cpp/src/demo/SilecsValid_1_0_0.h @@ -0,0 +1,1859 @@ +/* Copyright CERN 2015 + * + * WARNING: This code is automatically generated from your SILECS deploy unit document. + * You should never modify the content of this file as it would break consistency. + * Furthermore, any changes will be overwritten in the next code generation. + * Any modification shall be done using the SILECS development environment + * and regenerating this source code. + */ + +#ifndef SILECSVALID_1_0_0_H_ +#define SILECSVALID_1_0_0_H_ + +#include <silecs-communication/wrapper/Block.h> +#include <silecs-communication/wrapper/DeployUnit.h> +#include <silecs-communication/wrapper/Design.h> +#include <silecs-communication/wrapper/Device.h> + +namespace SilecsValid_1_0_0 +{ + +class Design; + +class ReadBlock : public SilecsWrapper::Block +{ +public: + /*! + * \brief readBlock constructor. It creates an empty block. + */ + ReadBlock() : + SilecsWrapper::Block("readBlock"), + b1_ro(0), + b2_ro(0), + w1_ro(0), + b3_ro(0), + dw1_ro(0), + c1_ro(0), + c2_ro(0), + c3_ro(0), + di1_ro(0), + b6_ro(0) + { + } + + ~ReadBlock() + { + } + + /*! + * \brief Get b1_ro register. + * \return value. + */ + uint8_t getB1_ro() const + { + return b1_ro; + } + + /*! + * \brief Set b1_ro register. + * \param value to be set. + */ + void setB1_ro(uint8_t value) + { + b1_ro = value; + } + + /*! + * \brief Get b2_ro register. + * \return value. + */ + uint8_t getB2_ro() const + { + return b2_ro; + } + + /*! + * \brief Set b2_ro register. + * \param value to be set. + */ + void setB2_ro(uint8_t value) + { + b2_ro = value; + } + + /*! + * \brief Get w1_ro register. + * \return value. + */ + uint16_t getW1_ro() const + { + return w1_ro; + } + + /*! + * \brief Set w1_ro register. + * \param value to be set. + */ + void setW1_ro(uint16_t value) + { + w1_ro = value; + } + + /*! + * \brief Get b3_ro register. + * \return value. + */ + uint8_t getB3_ro() const + { + return b3_ro; + } + + /*! + * \brief Set b3_ro register. + * \param value to be set. + */ + void setB3_ro(uint8_t value) + { + b3_ro = value; + } + + /*! + * \brief Set array b4_ro register. + * \param value to be set. + */ + void getB4_ro(uint8_t* value) const + { + memcpy(value, (void *) b4_ro, b4_roDim1); + } + + /*! + * \brief Set 2D array b4_ro register. + * \param value to be set. + */ + void setB4_ro(uint8_t* value) const + { + memcpy((void *) b4_ro, value, b4_roDim1); + } + + /*! + * \brief Get dw1_ro register. + * \return value. + */ + uint32_t getDw1_ro() const + { + return dw1_ro; + } + + /*! + * \brief Set dw1_ro register. + * \param value to be set. + */ + void setDw1_ro(uint32_t value) + { + dw1_ro = value; + } + + /*! + * \brief Set array i1_ro register. + * \param value to be set. + */ + void getI1_ro(int16_t* value) const + { + memcpy(value, (void *) i1_ro, i1_roDim1); + } + + /*! + * \brief Set 2D array i1_ro register. + * \param value to be set. + */ + void setI1_ro(int16_t* value) const + { + memcpy((void *) i1_ro, value, i1_roDim1); + } + + /*! + * \brief Get c1_ro register. + * \return value. + */ + int8_t getC1_ro() const + { + return c1_ro; + } + + /*! + * \brief Set c1_ro register. + * \param value to be set. + */ + void setC1_ro(int8_t value) + { + c1_ro = value; + } + + /*! + * \brief Get c2_ro register. + * \return value. + */ + int8_t getC2_ro() const + { + return c2_ro; + } + + /*! + * \brief Set c2_ro register. + * \param value to be set. + */ + void setC2_ro(int8_t value) + { + c2_ro = value; + } + + /*! + * \brief Get c3_ro register. + * \return value. + */ + int8_t getC3_ro() const + { + return c3_ro; + } + + /*! + * \brief Set c3_ro register. + * \param value to be set. + */ + void setC3_ro(int8_t value) + { + c3_ro = value; + } + + /*! + * \brief Get di1_ro register. + * \return value. + */ + int32_t getDi1_ro() const + { + return di1_ro; + } + + /*! + * \brief Set di1_ro register. + * \param value to be set. + */ + void setDi1_ro(int32_t value) + { + di1_ro = value; + } + + /*! + * \brief Set array r1_ro register. + * \param value to be set. + */ + void getR1_ro(float* value) const + { + memcpy(value, (void *) r1_ro, r1_roDim1); + } + + /*! + * \brief Set 2D array r1_ro register. + * \param value to be set. + */ + void setR1_ro(float* value) const + { + memcpy((void *) r1_ro, value, r1_roDim1); + } + + /*! + * \brief Set array b5_ro register. + * \param value to be set. + */ + void getB5_ro(uint8_t* value) const + { + memcpy(value, (void *) b5_ro, b5_roDim1); + } + + /*! + * \brief Set 2D array b5_ro register. + * \param value to be set. + */ + void setB5_ro(uint8_t* value) const + { + memcpy((void *) b5_ro, value, b5_roDim1); + } + + /*! + * \brief Get b6_ro register. + * \return value. + */ + uint8_t getB6_ro() const + { + return b6_ro; + } + + /*! + * \brief Set b6_ro register. + * \param value to be set. + */ + void setB6_ro(uint8_t value) + { + b6_ro = value; + } + + /*! + * \brief Get 2D array i2_ro register. + * \param value buffer where the value will be stored. + */ + void getI2_ro(int16_t* value) const + { + memcpy(value, static_cast<const void *>(i2_ro), i2_roDim1 * i2_roDim2); + } + + /*! + * \brief Get array i2_ro register. + * \param value buffer where the value will be stored. + */ + void setI2_ro(int16_t* value) const + { + memcpy((void *) i2_ro, value, i2_roDim1 * i2_roDim2); + } + + /*! + * \brief Get 2D array dw2_ro register. + * \param value buffer where the value will be stored. + */ + void getDw2_ro(uint32_t* value) const + { + memcpy(value, static_cast<const void *>(dw2_ro), dw2_roDim1 * dw2_roDim2); + } + + /*! + * \brief Get array dw2_ro register. + * \param value buffer where the value will be stored. + */ + void setDw2_ro(uint32_t* value) const + { + memcpy((void *) dw2_ro, value, dw2_roDim1 * dw2_roDim2); + } + + /*! + * \brief Get s1_ro register. + * \return value. + */ + const std::string& getS1_ro() const + { + return s1_ro; + } + + /*! + * \brief Set s1_ro register. + * \param value to be set. + */ + void setS1_ro(const std::string& value) + { + s1_ro = value; + } + + /*! + * \brief Get std::string s2_ro register. + * \param value buffer where the value will be stored. + */ + void getS2_ro(std::string* value) const + { + for (std::size_t i = 0; i < s2_roDim1; i++) + { + value[i] = s2_ro[i]; + } + } + + /*! + * \brief Set std::string s2_ro register. + * \param value to be set. + */ + void setS2_ro(const std::string* value) + { + for (std::size_t i = 0; i < s2_roDim1; i++) + { + s2_ro[i] = value[i]; + } + } + + /*! + * \brief Get s3_ro register. + * \return value. + */ + const std::string& getS3_ro() const + { + return s3_ro; + } + + /*! + * \brief Set s3_ro register. + * \param value to be set. + */ + void setS3_ro(const std::string& value) + { + s3_ro = value; + } + + /*! + * \brief Get s4_ro register. + * \return value. + */ + const std::string& getS4_ro() const + { + return s4_ro; + } + + /*! + * \brief Set s4_ro register. + * \param value to be set. + */ + void setS4_ro(const std::string& value) + { + s4_ro = value; + } + + /*! + * \brief Get 2D array r2_ro register. + * \param value buffer where the value will be stored. + */ + void getR2_ro(float* value) const + { + memcpy(value, static_cast<const void *>(r2_ro), r2_roDim1 * r2_roDim2); + } + + /*! + * \brief Get array r2_ro register. + * \param value buffer where the value will be stored. + */ + void setR2_ro(float* value) const + { + memcpy((void *) r2_ro, value, r2_roDim1 * r2_roDim2); + } + static const std::size_t b4_roDim1 = 3; + static const std::size_t i1_roDim1 = 2; + static const std::size_t r1_roDim1 = 3; + static const std::size_t b5_roDim1 = 3; + static const std::size_t i2_roDim2 = 5; + static const std::size_t i2_roDim1 = 2; + static const std::size_t dw2_roDim2 = 3; + static const std::size_t dw2_roDim1 = 1; + static const std::size_t s2_roDim1 = 3; + static const std::size_t r2_roDim2 = 2; + static const std::size_t r2_roDim1 = 1; +private: + uint8_t b1_ro; + uint8_t b2_ro; + uint16_t w1_ro; + uint8_t b3_ro; + uint8_t b4_ro[b4_roDim1]; + uint32_t dw1_ro; + int16_t i1_ro[i1_roDim1]; + int8_t c1_ro; + int8_t c2_ro; + int8_t c3_ro; + int32_t di1_ro; + float r1_ro[r1_roDim1]; + uint8_t b5_ro[b5_roDim1]; + uint8_t b6_ro; + int16_t i2_ro[i2_roDim1][i2_roDim2]; + uint32_t dw2_ro[dw2_roDim1][dw2_roDim2]; + std::string s1_ro; + std::string s2_ro[s2_roDim1]; + std::string s3_ro; + std::string s4_ro; + float r2_ro[r2_roDim1][r2_roDim2]; + +}; + +class WriteBlock : public SilecsWrapper::Block +{ +public: + /*! + * \brief writeBlock constructor. It creates an empty block. + */ + WriteBlock() : + SilecsWrapper::Block("writeBlock"), + b1_wo(0), + b2_wo(0), + w1_wo(0), + b3_wo(0), + dw1_wo(0), + c1_wo(0), + c2_wo(0), + c3_wo(0), + di1_wo(0), + b6_wo(0) + { + } + + ~WriteBlock() + { + } + + /*! + * \brief Get b1_wo register. + * \return value. + */ + uint8_t getB1_wo() const + { + return b1_wo; + } + + /*! + * \brief Set b1_wo register. + * \param value to be set. + */ + void setB1_wo(uint8_t value) + { + b1_wo = value; + } + + /*! + * \brief Get b2_wo register. + * \return value. + */ + uint8_t getB2_wo() const + { + return b2_wo; + } + + /*! + * \brief Set b2_wo register. + * \param value to be set. + */ + void setB2_wo(uint8_t value) + { + b2_wo = value; + } + + /*! + * \brief Get w1_wo register. + * \return value. + */ + uint16_t getW1_wo() const + { + return w1_wo; + } + + /*! + * \brief Set w1_wo register. + * \param value to be set. + */ + void setW1_wo(uint16_t value) + { + w1_wo = value; + } + + /*! + * \brief Get b3_wo register. + * \return value. + */ + uint8_t getB3_wo() const + { + return b3_wo; + } + + /*! + * \brief Set b3_wo register. + * \param value to be set. + */ + void setB3_wo(uint8_t value) + { + b3_wo = value; + } + + /*! + * \brief Set array b4_wo register. + * \param value to be set. + */ + void getB4_wo(uint8_t* value) const + { + memcpy(value, (void *) b4_wo, b4_woDim1); + } + + /*! + * \brief Set 2D array b4_wo register. + * \param value to be set. + */ + void setB4_wo(uint8_t* value) const + { + memcpy((void *) b4_wo, value, b4_woDim1); + } + + /*! + * \brief Get dw1_wo register. + * \return value. + */ + uint32_t getDw1_wo() const + { + return dw1_wo; + } + + /*! + * \brief Set dw1_wo register. + * \param value to be set. + */ + void setDw1_wo(uint32_t value) + { + dw1_wo = value; + } + + /*! + * \brief Set array i1_wo register. + * \param value to be set. + */ + void getI1_wo(int16_t* value) const + { + memcpy(value, (void *) i1_wo, i1_woDim1); + } + + /*! + * \brief Set 2D array i1_wo register. + * \param value to be set. + */ + void setI1_wo(int16_t* value) const + { + memcpy((void *) i1_wo, value, i1_woDim1); + } + + /*! + * \brief Get c1_wo register. + * \return value. + */ + int8_t getC1_wo() const + { + return c1_wo; + } + + /*! + * \brief Set c1_wo register. + * \param value to be set. + */ + void setC1_wo(int8_t value) + { + c1_wo = value; + } + + /*! + * \brief Get c2_wo register. + * \return value. + */ + int8_t getC2_wo() const + { + return c2_wo; + } + + /*! + * \brief Set c2_wo register. + * \param value to be set. + */ + void setC2_wo(int8_t value) + { + c2_wo = value; + } + + /*! + * \brief Get c3_wo register. + * \return value. + */ + int8_t getC3_wo() const + { + return c3_wo; + } + + /*! + * \brief Set c3_wo register. + * \param value to be set. + */ + void setC3_wo(int8_t value) + { + c3_wo = value; + } + + /*! + * \brief Get di1_wo register. + * \return value. + */ + int32_t getDi1_wo() const + { + return di1_wo; + } + + /*! + * \brief Set di1_wo register. + * \param value to be set. + */ + void setDi1_wo(int32_t value) + { + di1_wo = value; + } + + /*! + * \brief Set array r1_wo register. + * \param value to be set. + */ + void getR1_wo(float* value) const + { + memcpy(value, (void *) r1_wo, r1_woDim1); + } + + /*! + * \brief Set 2D array r1_wo register. + * \param value to be set. + */ + void setR1_wo(float* value) const + { + memcpy((void *) r1_wo, value, r1_woDim1); + } + + /*! + * \brief Set array b5_wo register. + * \param value to be set. + */ + void getB5_wo(uint8_t* value) const + { + memcpy(value, (void *) b5_wo, b5_woDim1); + } + + /*! + * \brief Set 2D array b5_wo register. + * \param value to be set. + */ + void setB5_wo(uint8_t* value) const + { + memcpy((void *) b5_wo, value, b5_woDim1); + } + + /*! + * \brief Get b6_wo register. + * \return value. + */ + uint8_t getB6_wo() const + { + return b6_wo; + } + + /*! + * \brief Set b6_wo register. + * \param value to be set. + */ + void setB6_wo(uint8_t value) + { + b6_wo = value; + } + + /*! + * \brief Get 2D array i2_wo register. + * \param value buffer where the value will be stored. + */ + void getI2_wo(int16_t* value) const + { + memcpy(value, static_cast<const void *>(i2_wo), i2_woDim1 * i2_woDim2); + } + + /*! + * \brief Get array i2_wo register. + * \param value buffer where the value will be stored. + */ + void setI2_wo(int16_t* value) const + { + memcpy((void *) i2_wo, value, i2_woDim1 * i2_woDim2); + } + + /*! + * \brief Get 2D array dw2_wo register. + * \param value buffer where the value will be stored. + */ + void getDw2_wo(uint32_t* value) const + { + memcpy(value, static_cast<const void *>(dw2_wo), dw2_woDim1 * dw2_woDim2); + } + + /*! + * \brief Get array dw2_wo register. + * \param value buffer where the value will be stored. + */ + void setDw2_wo(uint32_t* value) const + { + memcpy((void *) dw2_wo, value, dw2_woDim1 * dw2_woDim2); + } + + /*! + * \brief Get s1_wo register. + * \return value. + */ + const std::string& getS1_wo() const + { + return s1_wo; + } + + /*! + * \brief Set s1_wo register. + * \param value to be set. + */ + void setS1_wo(const std::string& value) + { + s1_wo = value; + } + + /*! + * \brief Get std::string s2_wo register. + * \param value buffer where the value will be stored. + */ + void getS2_wo(std::string* value) const + { + for (std::size_t i = 0; i < s2_woDim1; i++) + { + value[i] = s2_wo[i]; + } + } + + /*! + * \brief Set std::string s2_wo register. + * \param value to be set. + */ + void setS2_wo(const std::string* value) + { + for (std::size_t i = 0; i < s2_woDim1; i++) + { + s2_wo[i] = value[i]; + } + } + + /*! + * \brief Get s3_wo register. + * \return value. + */ + const std::string& getS3_wo() const + { + return s3_wo; + } + + /*! + * \brief Set s3_wo register. + * \param value to be set. + */ + void setS3_wo(const std::string& value) + { + s3_wo = value; + } + + /*! + * \brief Get s4_wo register. + * \return value. + */ + const std::string& getS4_wo() const + { + return s4_wo; + } + + /*! + * \brief Set s4_wo register. + * \param value to be set. + */ + void setS4_wo(const std::string& value) + { + s4_wo = value; + } + + /*! + * \brief Get 2D array r2_wo register. + * \param value buffer where the value will be stored. + */ + void getR2_wo(float* value) const + { + memcpy(value, static_cast<const void *>(r2_wo), r2_woDim1 * r2_woDim2); + } + + /*! + * \brief Get array r2_wo register. + * \param value buffer where the value will be stored. + */ + void setR2_wo(float* value) const + { + memcpy((void *) r2_wo, value, r2_woDim1 * r2_woDim2); + } + static const std::size_t b4_woDim1 = 3; + static const std::size_t i1_woDim1 = 2; + static const std::size_t r1_woDim1 = 3; + static const std::size_t b5_woDim1 = 3; + static const std::size_t i2_woDim2 = 5; + static const std::size_t i2_woDim1 = 2; + static const std::size_t dw2_woDim2 = 3; + static const std::size_t dw2_woDim1 = 1; + static const std::size_t s2_woDim1 = 3; + static const std::size_t r2_woDim2 = 2; + static const std::size_t r2_woDim1 = 1; +private: + uint8_t b1_wo; + uint8_t b2_wo; + uint16_t w1_wo; + uint8_t b3_wo; + uint8_t b4_wo[b4_woDim1]; + uint32_t dw1_wo; + int16_t i1_wo[i1_woDim1]; + int8_t c1_wo; + int8_t c2_wo; + int8_t c3_wo; + int32_t di1_wo; + float r1_wo[r1_woDim1]; + uint8_t b5_wo[b5_woDim1]; + uint8_t b6_wo; + int16_t i2_wo[i2_woDim1][i2_woDim2]; + uint32_t dw2_wo[dw2_woDim1][dw2_woDim2]; + std::string s1_wo; + std::string s2_wo[s2_woDim1]; + std::string s3_wo; + std::string s4_wo; + float r2_wo[r2_woDim1][r2_woDim2]; + +}; + +class RwBlock : public SilecsWrapper::Block +{ +public: + /*! + * \brief rwBlock constructor. It creates an empty block. + */ + RwBlock() : + SilecsWrapper::Block("rwBlock"), + b1_rw(0), + b2_rw(0), + w1_rw(0), + b3_rw(0), + dw1_rw(0), + c1_rw(0), + c2_rw(0), + c3_rw(0), + di1_rw(0), + b6_rw(0) + { + } + + ~RwBlock() + { + } + + /*! + * \brief Get b1_rw register. + * \return value. + */ + uint8_t getB1_rw() const + { + return b1_rw; + } + + /*! + * \brief Set b1_rw register. + * \param value to be set. + */ + void setB1_rw(uint8_t value) + { + b1_rw = value; + } + + /*! + * \brief Get b2_rw register. + * \return value. + */ + uint8_t getB2_rw() const + { + return b2_rw; + } + + /*! + * \brief Set b2_rw register. + * \param value to be set. + */ + void setB2_rw(uint8_t value) + { + b2_rw = value; + } + + /*! + * \brief Get w1_rw register. + * \return value. + */ + uint16_t getW1_rw() const + { + return w1_rw; + } + + /*! + * \brief Set w1_rw register. + * \param value to be set. + */ + void setW1_rw(uint16_t value) + { + w1_rw = value; + } + + /*! + * \brief Get b3_rw register. + * \return value. + */ + uint8_t getB3_rw() const + { + return b3_rw; + } + + /*! + * \brief Set b3_rw register. + * \param value to be set. + */ + void setB3_rw(uint8_t value) + { + b3_rw = value; + } + + /*! + * \brief Set array b4_rw register. + * \param value to be set. + */ + void getB4_rw(uint8_t* value) const + { + memcpy(value, (void *) b4_rw, b4_rwDim1); + } + + /*! + * \brief Set 2D array b4_rw register. + * \param value to be set. + */ + void setB4_rw(uint8_t* value) const + { + memcpy((void *) b4_rw, value, b4_rwDim1); + } + + /*! + * \brief Get dw1_rw register. + * \return value. + */ + uint32_t getDw1_rw() const + { + return dw1_rw; + } + + /*! + * \brief Set dw1_rw register. + * \param value to be set. + */ + void setDw1_rw(uint32_t value) + { + dw1_rw = value; + } + + /*! + * \brief Set array i1_rw register. + * \param value to be set. + */ + void getI1_rw(int16_t* value) const + { + memcpy(value, (void *) i1_rw, i1_rwDim1); + } + + /*! + * \brief Set 2D array i1_rw register. + * \param value to be set. + */ + void setI1_rw(int16_t* value) const + { + memcpy((void *) i1_rw, value, i1_rwDim1); + } + + /*! + * \brief Get c1_rw register. + * \return value. + */ + int8_t getC1_rw() const + { + return c1_rw; + } + + /*! + * \brief Set c1_rw register. + * \param value to be set. + */ + void setC1_rw(int8_t value) + { + c1_rw = value; + } + + /*! + * \brief Get c2_rw register. + * \return value. + */ + int8_t getC2_rw() const + { + return c2_rw; + } + + /*! + * \brief Set c2_rw register. + * \param value to be set. + */ + void setC2_rw(int8_t value) + { + c2_rw = value; + } + + /*! + * \brief Get c3_rw register. + * \return value. + */ + int8_t getC3_rw() const + { + return c3_rw; + } + + /*! + * \brief Set c3_rw register. + * \param value to be set. + */ + void setC3_rw(int8_t value) + { + c3_rw = value; + } + + /*! + * \brief Get di1_rw register. + * \return value. + */ + int32_t getDi1_rw() const + { + return di1_rw; + } + + /*! + * \brief Set di1_rw register. + * \param value to be set. + */ + void setDi1_rw(int32_t value) + { + di1_rw = value; + } + + /*! + * \brief Set array r1_rw register. + * \param value to be set. + */ + void getR1_rw(float* value) const + { + memcpy(value, (void *) r1_rw, r1_rwDim1); + } + + /*! + * \brief Set 2D array r1_rw register. + * \param value to be set. + */ + void setR1_rw(float* value) const + { + memcpy((void *) r1_rw, value, r1_rwDim1); + } + + /*! + * \brief Set array b5_rw register. + * \param value to be set. + */ + void getB5_rw(uint8_t* value) const + { + memcpy(value, (void *) b5_rw, b5_rwDim1); + } + + /*! + * \brief Set 2D array b5_rw register. + * \param value to be set. + */ + void setB5_rw(uint8_t* value) const + { + memcpy((void *) b5_rw, value, b5_rwDim1); + } + + /*! + * \brief Get b6_rw register. + * \return value. + */ + uint8_t getB6_rw() const + { + return b6_rw; + } + + /*! + * \brief Set b6_rw register. + * \param value to be set. + */ + void setB6_rw(uint8_t value) + { + b6_rw = value; + } + + /*! + * \brief Get 2D array i2_rw register. + * \param value buffer where the value will be stored. + */ + void getI2_rw(int16_t* value) const + { + memcpy(value, static_cast<const void *>(i2_rw), i2_rwDim1 * i2_rwDim2); + } + + /*! + * \brief Get array i2_rw register. + * \param value buffer where the value will be stored. + */ + void setI2_rw(int16_t* value) const + { + memcpy((void *) i2_rw, value, i2_rwDim1 * i2_rwDim2); + } + + /*! + * \brief Get 2D array dw2_rw register. + * \param value buffer where the value will be stored. + */ + void getDw2_rw(uint32_t* value) const + { + memcpy(value, static_cast<const void *>(dw2_rw), dw2_rwDim1 * dw2_rwDim2); + } + + /*! + * \brief Get array dw2_rw register. + * \param value buffer where the value will be stored. + */ + void setDw2_rw(uint32_t* value) const + { + memcpy((void *) dw2_rw, value, dw2_rwDim1 * dw2_rwDim2); + } + + /*! + * \brief Get s1_rw register. + * \return value. + */ + const std::string& getS1_rw() const + { + return s1_rw; + } + + /*! + * \brief Set s1_rw register. + * \param value to be set. + */ + void setS1_rw(const std::string& value) + { + s1_rw = value; + } + + /*! + * \brief Get std::string s2_rw register. + * \param value buffer where the value will be stored. + */ + void getS2_rw(std::string* value) const + { + for (std::size_t i = 0; i < s2_rwDim1; i++) + { + value[i] = s2_rw[i]; + } + } + + /*! + * \brief Set std::string s2_rw register. + * \param value to be set. + */ + void setS2_rw(const std::string* value) + { + for (std::size_t i = 0; i < s2_rwDim1; i++) + { + s2_rw[i] = value[i]; + } + } + + /*! + * \brief Get s3_rw register. + * \return value. + */ + const std::string& getS3_rw() const + { + return s3_rw; + } + + /*! + * \brief Set s3_rw register. + * \param value to be set. + */ + void setS3_rw(const std::string& value) + { + s3_rw = value; + } + + /*! + * \brief Get s4_rw register. + * \return value. + */ + const std::string& getS4_rw() const + { + return s4_rw; + } + + /*! + * \brief Set s4_rw register. + * \param value to be set. + */ + void setS4_rw(const std::string& value) + { + s4_rw = value; + } + + /*! + * \brief Get 2D array r2_rw register. + * \param value buffer where the value will be stored. + */ + void getR2_rw(float* value) const + { + memcpy(value, static_cast<const void *>(r2_rw), r2_rwDim1 * r2_rwDim2); + } + + /*! + * \brief Get array r2_rw register. + * \param value buffer where the value will be stored. + */ + void setR2_rw(float* value) const + { + memcpy((void *) r2_rw, value, r2_rwDim1 * r2_rwDim2); + } + static const std::size_t b4_rwDim1 = 3; + static const std::size_t i1_rwDim1 = 2; + static const std::size_t r1_rwDim1 = 3; + static const std::size_t b5_rwDim1 = 3; + static const std::size_t i2_rwDim2 = 5; + static const std::size_t i2_rwDim1 = 2; + static const std::size_t dw2_rwDim2 = 3; + static const std::size_t dw2_rwDim1 = 1; + static const std::size_t s2_rwDim1 = 3; + static const std::size_t r2_rwDim2 = 2; + static const std::size_t r2_rwDim1 = 1; +private: + uint8_t b1_rw; + uint8_t b2_rw; + uint16_t w1_rw; + uint8_t b3_rw; + uint8_t b4_rw[b4_rwDim1]; + uint32_t dw1_rw; + int16_t i1_rw[i1_rwDim1]; + int8_t c1_rw; + int8_t c2_rw; + int8_t c3_rw; + int32_t di1_rw; + float r1_rw[r1_rwDim1]; + uint8_t b5_rw[b5_rwDim1]; + uint8_t b6_rw; + int16_t i2_rw[i2_rwDim1][i2_rwDim2]; + uint32_t dw2_rw[dw2_rwDim1][dw2_rwDim2]; + std::string s1_rw; + std::string s2_rw[s2_rwDim1]; + std::string s3_rw; + std::string s4_rw; + float r2_rw[r2_rwDim1][r2_rwDim2]; + +}; +class Device : public SilecsWrapper::Device +{ +public: + Device(const std::string& label, SilecsWrapper::Controller *controller) : + SilecsWrapper::Device(label, controller) + { + } + + ~Device() + { + } + + /*! + * \brief Get readBlock block. + * \param block ReadBlock reference where to store returned value. + */ + void getReadBlock(ReadBlock &block) + { + // Copy register b1_ro + block.setB1_ro(getSilecsDevice()->getRegister("b1_ro")->getValUInt8()); + // Copy register b2_ro + block.setB2_ro(getSilecsDevice()->getRegister("b2_ro")->getValUInt8()); + // Copy register w1_ro + block.setW1_ro(getSilecsDevice()->getRegister("w1_ro")->getValUInt16()); + // Copy register b3_ro + block.setB3_ro(getSilecsDevice()->getRegister("b3_ro")->getValUInt8()); + // Copy register b4_ro + uint8_t *__b4_ro = new uint8_t[block.b4_roDim1]; + getSilecsDevice()->getRegister("b4_ro")->getValUInt8Array(__b4_ro, block.b4_roDim1); + block.setB4_ro(__b4_ro); + delete[] __b4_ro; + // Copy register dw1_ro + block.setDw1_ro(getSilecsDevice()->getRegister("dw1_ro")->getValUInt32()); + // Copy register i1_ro + int16_t *__i1_ro = new int16_t[block.i1_roDim1]; + getSilecsDevice()->getRegister("i1_ro")->getValInt16Array(__i1_ro, block.i1_roDim1); + block.setI1_ro(__i1_ro); + delete[] __i1_ro; + // Copy register c1_ro + block.setC1_ro(getSilecsDevice()->getRegister("c1_ro")->getValInt8()); + // Copy register c2_ro + block.setC2_ro(getSilecsDevice()->getRegister("c2_ro")->getValInt8()); + // Copy register c3_ro + block.setC3_ro(getSilecsDevice()->getRegister("c3_ro")->getValInt8()); + // Copy register di1_ro + block.setDi1_ro(getSilecsDevice()->getRegister("di1_ro")->getValInt32()); + // Copy register r1_ro + float *__r1_ro = new float[block.r1_roDim1]; + getSilecsDevice()->getRegister("r1_ro")->getValFloat32Array(__r1_ro, block.r1_roDim1); + block.setR1_ro(__r1_ro); + delete[] __r1_ro; + // Copy register b5_ro + uint8_t *__b5_ro = new uint8_t[block.b5_roDim1]; + getSilecsDevice()->getRegister("b5_ro")->getValUInt8Array(__b5_ro, block.b5_roDim1); + block.setB5_ro(__b5_ro); + delete[] __b5_ro; + // Copy register b6_ro + block.setB6_ro(getSilecsDevice()->getRegister("b6_ro")->getValUInt8()); + // Copy register i2_ro + int16_t *__i2_ro = new int16_t[block.i2_roDim1 * block.i2_roDim2]; + getSilecsDevice()->getRegister("i2_ro")->getValInt16Array2D(__i2_ro, block.i2_roDim1, block.i2_roDim2); + block.setI2_ro(__i2_ro); + delete[] __i2_ro; + // Copy register dw2_ro + uint32_t *__dw2_ro = new uint32_t[block.dw2_roDim1 * block.dw2_roDim2]; + getSilecsDevice()->getRegister("dw2_ro")->getValUInt32Array2D(__dw2_ro, block.dw2_roDim1, block.dw2_roDim2); + block.setDw2_ro(__dw2_ro); + delete[] __dw2_ro; + // Copy register s1_ro + block.setS1_ro(getSilecsDevice()->getRegister("s1_ro")->getValString()); + // Copy register s2_ro + std::string *__s2_ro = new std::string[block.s2_roDim1]; + getSilecsDevice()->getRegister("s2_ro")->getValStringArray(__s2_ro, block.s2_roDim1); + block.setS2_ro(__s2_ro); + delete[] __s2_ro; + // Copy register s3_ro + block.setS3_ro(getSilecsDevice()->getRegister("s3_ro")->getValString()); + // Copy register s4_ro + block.setS4_ro(getSilecsDevice()->getRegister("s4_ro")->getValString()); + // Copy register r2_ro + float *__r2_ro = new float[block.r2_roDim1 * block.r2_roDim2]; + getSilecsDevice()->getRegister("r2_ro")->getValFloat32Array2D(__r2_ro, block.r2_roDim1, block.r2_roDim2); + block.setR2_ro(__r2_ro); + delete[] __r2_ro; + } + + /*! + * \brief Set writeBlock block. + * \param block WriteBlock reference from where value are copied. + */ + void setWriteBlock(WriteBlock &block) + { + // Copy register b1_wo + getSilecsDevice()->getRegister("b1_wo")->setValUInt8(block.getB1_wo()); + // Copy register b2_wo + getSilecsDevice()->getRegister("b2_wo")->setValUInt8(block.getB2_wo()); + // Copy register w1_wo + getSilecsDevice()->getRegister("w1_wo")->setValUInt16(block.getW1_wo()); + // Copy register b3_wo + getSilecsDevice()->getRegister("b3_wo")->setValUInt8(block.getB3_wo()); + // Copy register b4_wo + uint8_t *__b4_wo = new uint8_t[block.b4_woDim1]; + block.getB4_wo(__b4_wo); + getSilecsDevice()->getRegister("b4_wo")->setValUInt8Array(__b4_wo, block.b4_woDim1); + delete[] __b4_wo; + // Copy register dw1_wo + getSilecsDevice()->getRegister("dw1_wo")->setValUInt32(block.getDw1_wo()); + // Copy register i1_wo + int16_t *__i1_wo = new int16_t[block.i1_woDim1]; + block.getI1_wo(__i1_wo); + getSilecsDevice()->getRegister("i1_wo")->setValInt16Array(__i1_wo, block.i1_woDim1); + delete[] __i1_wo; + // Copy register c1_wo + getSilecsDevice()->getRegister("c1_wo")->setValInt8(block.getC1_wo()); + // Copy register c2_wo + getSilecsDevice()->getRegister("c2_wo")->setValInt8(block.getC2_wo()); + // Copy register c3_wo + getSilecsDevice()->getRegister("c3_wo")->setValInt8(block.getC3_wo()); + // Copy register di1_wo + getSilecsDevice()->getRegister("di1_wo")->setValInt32(block.getDi1_wo()); + // Copy register r1_wo + float *__r1_wo = new float[block.r1_woDim1]; + block.getR1_wo(__r1_wo); + getSilecsDevice()->getRegister("r1_wo")->setValFloat32Array(__r1_wo, block.r1_woDim1); + delete[] __r1_wo; + // Copy register b5_wo + uint8_t *__b5_wo = new uint8_t[block.b5_woDim1]; + block.getB5_wo(__b5_wo); + getSilecsDevice()->getRegister("b5_wo")->setValUInt8Array(__b5_wo, block.b5_woDim1); + delete[] __b5_wo; + // Copy register b6_wo + getSilecsDevice()->getRegister("b6_wo")->setValUInt8(block.getB6_wo()); + // Copy register i2_wo + int16_t *__i2_wo = new int16_t[block.i2_woDim1 * block.i2_woDim2]; + block.getI2_wo(__i2_wo); + getSilecsDevice()->getRegister("i2_wo")->setValInt16Array2D(__i2_wo, block.i2_woDim1, block.i2_woDim2); + delete[] __i2_wo; + // Copy register dw2_wo + uint32_t *__dw2_wo = new uint32_t[block.dw2_woDim1 * block.dw2_woDim2]; + block.getDw2_wo(__dw2_wo); + getSilecsDevice()->getRegister("dw2_wo")->setValUInt32Array2D(__dw2_wo, block.dw2_woDim1, block.dw2_woDim2); + delete[] __dw2_wo; + // Copy register s1_wo + getSilecsDevice()->getRegister("s1_wo")->setValString(block.getS1_wo()); + // Copy register s2_wo + std::string *__s2_wo = new std::string[block.s2_woDim1]; + block.getS2_wo(__s2_wo); + getSilecsDevice()->getRegister("s2_wo")->setValStringArray(__s2_wo, block.s2_woDim1); + delete[] __s2_wo; + // Copy register s3_wo + getSilecsDevice()->getRegister("s3_wo")->setValString(block.getS3_wo()); + // Copy register s4_wo + getSilecsDevice()->getRegister("s4_wo")->setValString(block.getS4_wo()); + // Copy register r2_wo + float *__r2_wo = new float[block.r2_woDim1 * block.r2_woDim2]; + block.getR2_wo(__r2_wo); + getSilecsDevice()->getRegister("r2_wo")->setValFloat32Array2D(__r2_wo, block.r2_woDim1, block.r2_woDim2); + delete[] __r2_wo; + } + + /*! + * \brief Get rwBlock block. + * \param block RwBlock reference where to store returned value. + */ + void getRwBlock(RwBlock &block) + { + // Copy register b1_rw + block.setB1_rw(getSilecsDevice()->getRegister("b1_rw")->getValUInt8()); + // Copy register b2_rw + block.setB2_rw(getSilecsDevice()->getRegister("b2_rw")->getValUInt8()); + // Copy register w1_rw + block.setW1_rw(getSilecsDevice()->getRegister("w1_rw")->getValUInt16()); + // Copy register b3_rw + block.setB3_rw(getSilecsDevice()->getRegister("b3_rw")->getValUInt8()); + // Copy register b4_rw + uint8_t *__b4_rw = new uint8_t[block.b4_rwDim1]; + getSilecsDevice()->getRegister("b4_rw")->getValUInt8Array(__b4_rw, block.b4_rwDim1); + block.setB4_rw(__b4_rw); + delete[] __b4_rw; + // Copy register dw1_rw + block.setDw1_rw(getSilecsDevice()->getRegister("dw1_rw")->getValUInt32()); + // Copy register i1_rw + int16_t *__i1_rw = new int16_t[block.i1_rwDim1]; + getSilecsDevice()->getRegister("i1_rw")->getValInt16Array(__i1_rw, block.i1_rwDim1); + block.setI1_rw(__i1_rw); + delete[] __i1_rw; + // Copy register c1_rw + block.setC1_rw(getSilecsDevice()->getRegister("c1_rw")->getValInt8()); + // Copy register c2_rw + block.setC2_rw(getSilecsDevice()->getRegister("c2_rw")->getValInt8()); + // Copy register c3_rw + block.setC3_rw(getSilecsDevice()->getRegister("c3_rw")->getValInt8()); + // Copy register di1_rw + block.setDi1_rw(getSilecsDevice()->getRegister("di1_rw")->getValInt32()); + // Copy register r1_rw + float *__r1_rw = new float[block.r1_rwDim1]; + getSilecsDevice()->getRegister("r1_rw")->getValFloat32Array(__r1_rw, block.r1_rwDim1); + block.setR1_rw(__r1_rw); + delete[] __r1_rw; + // Copy register b5_rw + uint8_t *__b5_rw = new uint8_t[block.b5_rwDim1]; + getSilecsDevice()->getRegister("b5_rw")->getValUInt8Array(__b5_rw, block.b5_rwDim1); + block.setB5_rw(__b5_rw); + delete[] __b5_rw; + // Copy register b6_rw + block.setB6_rw(getSilecsDevice()->getRegister("b6_rw")->getValUInt8()); + // Copy register i2_rw + int16_t *__i2_rw = new int16_t[block.i2_rwDim1 * block.i2_rwDim2]; + getSilecsDevice()->getRegister("i2_rw")->getValInt16Array2D(__i2_rw, block.i2_rwDim1, block.i2_rwDim2); + block.setI2_rw(__i2_rw); + delete[] __i2_rw; + // Copy register dw2_rw + uint32_t *__dw2_rw = new uint32_t[block.dw2_rwDim1 * block.dw2_rwDim2]; + getSilecsDevice()->getRegister("dw2_rw")->getValUInt32Array2D(__dw2_rw, block.dw2_rwDim1, block.dw2_rwDim2); + block.setDw2_rw(__dw2_rw); + delete[] __dw2_rw; + // Copy register s1_rw + block.setS1_rw(getSilecsDevice()->getRegister("s1_rw")->getValString()); + // Copy register s2_rw + std::string *__s2_rw = new std::string[block.s2_rwDim1]; + getSilecsDevice()->getRegister("s2_rw")->getValStringArray(__s2_rw, block.s2_rwDim1); + block.setS2_rw(__s2_rw); + delete[] __s2_rw; + // Copy register s3_rw + block.setS3_rw(getSilecsDevice()->getRegister("s3_rw")->getValString()); + // Copy register s4_rw + block.setS4_rw(getSilecsDevice()->getRegister("s4_rw")->getValString()); + // Copy register r2_rw + float *__r2_rw = new float[block.r2_rwDim1 * block.r2_rwDim2]; + getSilecsDevice()->getRegister("r2_rw")->getValFloat32Array2D(__r2_rw, block.r2_rwDim1, block.r2_rwDim2); + block.setR2_rw(__r2_rw); + delete[] __r2_rw; + } + + /*! + * \brief Set rwBlock block. + * \param block RwBlock reference from where value are copied. + */ + void setRwBlock(RwBlock &block) + { + // Copy register b1_rw + getSilecsDevice()->getRegister("b1_rw")->setValUInt8(block.getB1_rw()); + // Copy register b2_rw + getSilecsDevice()->getRegister("b2_rw")->setValUInt8(block.getB2_rw()); + // Copy register w1_rw + getSilecsDevice()->getRegister("w1_rw")->setValUInt16(block.getW1_rw()); + // Copy register b3_rw + getSilecsDevice()->getRegister("b3_rw")->setValUInt8(block.getB3_rw()); + // Copy register b4_rw + uint8_t *__b4_rw = new uint8_t[block.b4_rwDim1]; + block.getB4_rw(__b4_rw); + getSilecsDevice()->getRegister("b4_rw")->setValUInt8Array(__b4_rw, block.b4_rwDim1); + delete[] __b4_rw; + // Copy register dw1_rw + getSilecsDevice()->getRegister("dw1_rw")->setValUInt32(block.getDw1_rw()); + // Copy register i1_rw + int16_t *__i1_rw = new int16_t[block.i1_rwDim1]; + block.getI1_rw(__i1_rw); + getSilecsDevice()->getRegister("i1_rw")->setValInt16Array(__i1_rw, block.i1_rwDim1); + delete[] __i1_rw; + // Copy register c1_rw + getSilecsDevice()->getRegister("c1_rw")->setValInt8(block.getC1_rw()); + // Copy register c2_rw + getSilecsDevice()->getRegister("c2_rw")->setValInt8(block.getC2_rw()); + // Copy register c3_rw + getSilecsDevice()->getRegister("c3_rw")->setValInt8(block.getC3_rw()); + // Copy register di1_rw + getSilecsDevice()->getRegister("di1_rw")->setValInt32(block.getDi1_rw()); + // Copy register r1_rw + float *__r1_rw = new float[block.r1_rwDim1]; + block.getR1_rw(__r1_rw); + getSilecsDevice()->getRegister("r1_rw")->setValFloat32Array(__r1_rw, block.r1_rwDim1); + delete[] __r1_rw; + // Copy register b5_rw + uint8_t *__b5_rw = new uint8_t[block.b5_rwDim1]; + block.getB5_rw(__b5_rw); + getSilecsDevice()->getRegister("b5_rw")->setValUInt8Array(__b5_rw, block.b5_rwDim1); + delete[] __b5_rw; + // Copy register b6_rw + getSilecsDevice()->getRegister("b6_rw")->setValUInt8(block.getB6_rw()); + // Copy register i2_rw + int16_t *__i2_rw = new int16_t[block.i2_rwDim1 * block.i2_rwDim2]; + block.getI2_rw(__i2_rw); + getSilecsDevice()->getRegister("i2_rw")->setValInt16Array2D(__i2_rw, block.i2_rwDim1, block.i2_rwDim2); + delete[] __i2_rw; + // Copy register dw2_rw + uint32_t *__dw2_rw = new uint32_t[block.dw2_rwDim1 * block.dw2_rwDim2]; + block.getDw2_rw(__dw2_rw); + getSilecsDevice()->getRegister("dw2_rw")->setValUInt32Array2D(__dw2_rw, block.dw2_rwDim1, block.dw2_rwDim2); + delete[] __dw2_rw; + // Copy register s1_rw + getSilecsDevice()->getRegister("s1_rw")->setValString(block.getS1_rw()); + // Copy register s2_rw + std::string *__s2_rw = new std::string[block.s2_rwDim1]; + block.getS2_rw(__s2_rw); + getSilecsDevice()->getRegister("s2_rw")->setValStringArray(__s2_rw, block.s2_rwDim1); + delete[] __s2_rw; + // Copy register s3_rw + getSilecsDevice()->getRegister("s3_rw")->setValString(block.getS3_rw()); + // Copy register s4_rw + getSilecsDevice()->getRegister("s4_rw")->setValString(block.getS4_rw()); + // Copy register r2_rw + float *__r2_rw = new float[block.r2_rwDim1 * block.r2_rwDim2]; + block.getR2_rw(__r2_rw); + getSilecsDevice()->getRegister("r2_rw")->setValFloat32Array2D(__r2_rw, block.r2_rwDim1, block.r2_rwDim2); + delete[] __r2_rw; + } + + + /*! + * \brief Receive readBlock block for current device. + */ + void receiveReadBlock() + { + _silecsDevice->recv("readBlock"); + } + + /*! + * \brief Send writeBlock blocks to current device. + */ + void sendWriteBlock() + { + _silecsDevice->send("writeBlock"); + } + + /*! + * \brief Receive rwBlock block for current device. + */ + void receiveRwBlock() + { + _silecsDevice->recv("rwBlock"); + } + + /*! + * \brief Send rwBlock blocks to current device. + */ + void sendRwBlock() + { + _silecsDevice->send("rwBlock"); + } + + +}; + +class Controller : public SilecsWrapper::Controller +{ +public: + Controller(const std::string& name, const std::string& domain, Design *design) : + SilecsWrapper::Controller(name, domain, (SilecsWrapper::Design*) design) + { + _deviceMap.insert(std::pair<std::string, Device*>("0", new Device("0", this))); + _deviceMap.insert(std::pair<std::string, Device*>("1", new Device("1", this))); + _deviceMap.insert(std::pair<std::string, Device*>("2", new Device("2", this))); + } + + ~Controller() + { + map<std::string, Device*>::iterator it; + for (it = _deviceMap.begin(); it != _deviceMap.end(); it++) + { + delete it->second; + } + } + + /*! + * \brief Return pointer to the requested device. + * \param label Device label. + */ + Device* getDevice(const std::string& label) + { + if (_deviceMap.find(label) != _deviceMap.end()) + { + return _deviceMap[label]; + } + throw Silecs::SilecsException(__FILE__, __LINE__, Silecs::PARAM_UNKNOWN_DEVICE_NAME, label); + } + + std::map<std::string, Device*>& getDeviceMap() + { + return _deviceMap; + } + /*! + * \brief Receive readBlock blocks from all devices of current controller. + */ + void receiveReadBlockAllDevices() + { + _silecsPLC->recv("readBlock"); + } + + /*! + * \brief Send writeBlock blocks to all devices of current controller. + */ + void sendWriteBlockAllDevices() + { + _silecsPLC->send("writeBlock"); + } + + /*! + * \brief Receive rwBlock blocks from all devices of current controller. + */ + void receiveRwBlockAllDevices() + { + _silecsPLC->recv("rwBlock"); + } + + /*! + * \brief Send rwBlock blocks to all devices of current controller. + */ + void sendRwBlockAllDevices() + { + _silecsPLC->send("rwBlock"); + } + +private: + std::map<std::string, Device*> _deviceMap; +}; + +class Design : public SilecsWrapper::Design +{ +public: + + Design(SilecsWrapper::DeployUnit *deployUnit) : + SilecsWrapper::Design("SilecsValid", "1.0.0", deployUnit) + { + + _controllerMap.insert( + std::pair<std::string, Controller*>("cfp-774-csimatic-s7-02", + new Controller("cfp-774-csimatic-s7-02", "TST", this))); + + } + + ~Design() + { + map<std::string, Controller*>::iterator it; + for (it = _controllerMap.begin(); it != _controllerMap.end(); it++) + { + delete it->second; + } + } + + /*! + * \brief Return pointer to the requested controller. + * \param name Controller's name. + */ + Controller* getController(const std::string& name) + { + if (_controllerMap.find(name) != _controllerMap.end()) + { + return _controllerMap[name]; + } + throw Silecs::SilecsException(__FILE__, __LINE__, Silecs::PARAM_UNKNOWN_PLC_HOSTNAME, name); + } + + /*! + * \brief Return pointer to the controller cfp-774-csimatic-s7-02. + */ + Controller* getCfp_774_csimatic_s7_02() + { + return _controllerMap["cfp-774-csimatic-s7-02"]; + } + + /*! + * \brief Receive readBlock blocks from all connected controllers. + */ + void receiveReadBlockAllControllers() + { + _silecsCluster->recv("readBlock"); + } + + /*! + * \brief Send writeBlock blocks to all connected controllers. + */ + void sendWriteBlockAllControllers() + { + _silecsCluster->send("writeBlock"); + } + + /*! + * \brief Receive rwBlock blocks from all connected controllers. + */ + void receiveRwBlockAllControllers() + { + _silecsCluster->recv("rwBlock"); + } + + /*! + * \brief Send rwBlock blocks to all connected controllers. + */ + void sendRwBlockAllControllers() + { + _silecsCluster->send("rwBlock"); + } + + std::map<std::string, Controller*>& getControllerMap() + { + return _controllerMap; + } + +private: + std::map<std::string, Controller*> _controllerMap; + +}; + +} /* namespace SilecsValid_1_0_0 */ + +#endif /* SILECSVALID_1_0_0_H_ */ diff --git a/silecs-communication-cpp/src/demo/main.cpp b/silecs-communication-cpp/src/demo/main.cpp new file mode 100644 index 0000000..6137959 --- /dev/null +++ b/silecs-communication-cpp/src/demo/main.cpp @@ -0,0 +1,63 @@ +#include "Cfp774Simatic400_1_0_0.h" + +#include <iostream> + +int main(void) +{ + + Cfp774Simatic400_1_0_0::DeployConfig config(); + config.setAutomaticConnect(false); + const std::string logTopics = "ERROR,COMM,SEND,RECV"; + Cfp774Simatic400_1_0_0::DeployUnit* du = Cfp774Simatic400_1_0_0::DeployUnit::getInstance(logTopics, config); + + Cfp774Simatic400_1_0_0::DesignConfig designConfig(false); + du->getSilecsValid()->setConfiguration(designConfig); + + du->deleteInstance(); +} + + +//int main(void) +//{ +// +// Cfp774Simatic400_1_0_0::DeployConfig config; +// config.setAutomaticConnect(false); +// const std::string logTopics = "ERROR,COMM,SEND,RECV"; +// Cfp774Simatic400_1_0_0::DeployUnit* du = Cfp774Simatic400_1_0_0::DeployUnit::getInstance(logTopics, config); +// +// Cfp774Simatic400_1_0_0::DesignConfig designConfig(false); +// du->getSilecsValid()->setConfiguration(designConfig); +// du->getSilecsValid()->getControllerMap()["cfp-774-csimatic-s7-02"]->connect(); +// +// // read block +// SilecsValid_1_0_0::RwBlock rwblock; +// du->getSilecsValid()->getCfp_774_csimatic_s7_02()->getDevice("0")->receiveRwBlock(); +// du->getSilecsValid()->getCfp_774_csimatic_s7_02()->getDevice("0")->getRwBlock(rwblock); +// +// int32_t b1_rw = rwblock.getB1_rw(); +// uint8_t b4_rw[rwblock.b4_rwDim1]; +// rwblock.getB4_rw(b4_rw); +// std::cout << "Value of register b1_rw = " << b1_rw << std::endl; +// std::cout << "Value of register b4_rw[0] = " << (int32_t) b4_rw[0] << std::endl; +// std::cout << "Value of register b4_rw[1] = " << (int32_t) b4_rw[1] << std::endl; +// +// // increment b1_rw +// b4_rw[0] = b4_rw[0] + 1; +// b4_rw[1] = b4_rw[1] + 2; +// rwblock.setB4_rw(b4_rw); +// rwblock.setB1_rw(b1_rw + 2); +// std::cout << "Increment 2" << std::endl; +// du->getSilecsValid()->getCfp_774_csimatic_s7_02()->getDevice("0")->setRwBlock(rwblock); +// du->getSilecsValid()->getCfp_774_csimatic_s7_02()->getDevice("0")->sendRwBlock(); +// +// // read b1_rw +// du->getSilecsValid()->getCfp_774_csimatic_s7_02()->getDevice("0")->receiveRwBlock(); +// du->getSilecsValid()->getCfp_774_csimatic_s7_02()->getDevice("0")->getRwBlock(rwblock); +// b1_rw = rwblock.getB1_rw(); +// rwblock.getB4_rw(b4_rw); +// std::cout << "Value of register b1_rw = " << b1_rw << std::endl; +// std::cout << "Value of register b4_rw[0] = " << (int32_t) b4_rw[0] << std::endl; +// std::cout << "Value of register b4_rw[1] = " << (int32_t) b4_rw[1] << std::endl; +// +// du->deleteInstance(); +//} diff --git a/silecs-communication-cpp/src/silecs-communication/interface/communication/CNVConnection.cpp b/silecs-communication-cpp/src/silecs-communication/interface/communication/CNVConnection.cpp new file mode 100644 index 0000000..f807d5d --- /dev/null +++ b/silecs-communication-cpp/src/silecs-communication/interface/communication/CNVConnection.cpp @@ -0,0 +1,146 @@ +// Copyright 2016 CERN and GSI +// +// 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 3 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, see <http://www.gnu.org/licenses/>. + +#ifdef NI_SUPPORT_ENABLED + +#include <silecs-communication/interface/communication/CNVConnection.h> + +#include <silecs-communication/interface/communication/SilecsConnection.h> +#include <silecs-communication/interface/equipment/CNVBlock.h> +#include <silecs-communication/interface/equipment/SilecsBlock.h> +#include <silecs-communication/interface/equipment/SilecsPLC.h> +#include <silecs-communication/interface/utility/SilecsException.h> +#include <silecs-communication/interface/utility/SilecsLog.h> +#include <silecs-communication/interface/utility/StringUtilities.h> + +namespace Silecs +{ + + CNVConnection::CNVConnection(PLC* thePLC) : Connection(thePLC) + { + LOG(ALLOC) << "CNVConnection (create): " << thePLC->getName(); + } + + + CNVConnection::~CNVConnection() + { + //Close the connection before removing resources + //disable(); must be done before removing resource + } + + /* Check for errors */ + int CNVConnection::errChk(PLC* thePLC, int code)// throw (std::string*) + { + if(code != 0) + { LOG(DEBUG) << "CNV error occurred: " << code << ": " << CNVGetErrorDescription(code); + //Do not close the connection if it's only for data missing (when deleting empty Data object) + if (code != CNVInvalidDataHandleError) + { + LOG(COMM) << "Transaction failure with PXI: " << thePLC->getName() << ". CNV[" << code << "]: " << CNVGetErrorDescription(code); + doClose(thePLC, /*withLock =*/true); + throw SilecsException(__FILE__, __LINE__, CNV_INTERNAL_ERROR, std::string(CNVGetErrorDescription(code))+" in CNVConnection"); + } + } + return code; + } + + /* Read Data */ + int CNVConnection::readData(PLC* thePLC, CNVBufferedSubscriber *handle,CNVData *data) + { + CNVBufferDataStatus status; + + /* Buffer is used only for performance reason. + * Always return the last value in the buffer discarding the oldest ones. + */ + + //read the oldest data in the buffer + int errorCode = errChk(thePLC, CNVGetDataFromBuffer(*handle, data, &status)); + + if ((errorCode == 0) && (status != CNVStaleData)) + { + if (status != CNVNoData) + { //buffer was not empty, try to read again to get the very last data if any + errChk(thePLC, CNVDisposeData(*data)); //CNV requires to free the buffer on every CNVGetDataFromBuffer + errorCode = errChk(thePLC, CNVGetDataFromBuffer(*handle, data, &status)); + } + else + { LOG(DEBUG) << "CNVConnection::readData() : buffer is empty (variables may not be initialized properly)"; + errorCode = CNVEmptyDataError; + } + } + return errorCode; + } + + /* Write Data */ + int CNVConnection::writeData(PLC* thePLC, const char *networkVariablePathname, CNVData data) + { + CNVWriter writer; + + int errorCode = errChk(thePLC, CNVCreateWriter(networkVariablePathname , NULL, NULL, CNVWaitForever , 0, &writer)); + + if (errorCode ==0) + { CNVWrite (writer, data, 0); + CNVDispose(writer); + } + return errorCode; + } + + bool CNVConnection::open(PLC* thePLC) + { + bool isOK = false; + + if (IeRfcPing((char *) thePLC->getName().c_str(), 0) == 0) + { + LOG(DEBUG) << "CNVConnection::open(): Controller is reachable (ping), then subscribe input variables"; + + isOK = true; //all subscription is fine a priori + + // Create all the subscriptions + blockMapType::iterator pBlockIter; + for(pBlockIter = thePLC->getBlockMap().begin(); pBlockIter != thePLC->getBlockMap().end(); ++pBlockIter) + { + //Attention: only CNVInputBlock has doSubscribe/unSubscribe feature (key-map can be used to select appropriate object) + if (pBlockIter->first.find(Block::whichAccessType(Input)) != std::string::npos) + { if (static_cast<CNVInputBlock*>(pBlockIter->second)->doSubscribe() == false) + { isOK = false; + break; + } + } + } + } + return isOK; + } + + + bool CNVConnection::close(PLC* thePLC) + { + LOG(DEBUG) << "CNVConnection::close(): unSubscribe input variables"; + + // Delete all the subscription + blockMapType::iterator pBlockIter; + for(pBlockIter = thePLC->getBlockMap().begin(); pBlockIter != thePLC->getBlockMap().end(); ++pBlockIter) + { + //Attention: only CNVInputBlock has doSubscribe/unSubscribe feature (key-map can be used to select appropriate object) + if (pBlockIter->first.find(Block::whichAccessType(Input)) != std::string::npos) + { static_cast<CNVInputBlock*>(pBlockIter->second)->unSubscribe(); + } + } + isConnected_ = false; + return true; + } + +} // namespace + +#endif //NI_SUPPORT_ENABLED diff --git a/silecs-communication-cpp/src/silecs-communication/interface/communication/CNVConnection.h b/silecs-communication-cpp/src/silecs-communication/interface/communication/CNVConnection.h new file mode 100644 index 0000000..c864b30 --- /dev/null +++ b/silecs-communication-cpp/src/silecs-communication/interface/communication/CNVConnection.h @@ -0,0 +1,111 @@ +// Copyright 2016 CERN and GSI +// +// 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 3 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, see <http://www.gnu.org/licenses/>. + +#ifdef NI_SUPPORT_ENABLED +#ifndef _CNV_CONNECTION_H_ +#define _CNV_CONNECTION_H_ + +#include <silecs-communication/interface/communication/SilecsConnection.h> + +#include <silecs-communication/protocol/core/silecs.h> + +#include <iostream> +#include <string.h> + +#ifdef __cplusplus +extern "C" { +#endif + +#include <nilibnetv.h> + +#ifdef __cplusplus +} +#endif + +namespace Silecs +{ + /*! + * \class CNVConnection + * \brief CNV-communication object for PXI Shared Variable Protocol + */ + class CNVConnection : public Connection + { + + public: + CNVConnection(PLC* thePLC); + virtual ~CNVConnection(); + + /*! + * \brief Read Data from the specified buffer handler + * \return the read CNVData and error code (0 = everything is ok) + */ + //CNVData readData(CNVBufferedSubscriber *handle); + int readData(PLC* thePLC, CNVBufferedSubscriber *handle,CNVData *data); + + /*! + * \brief Write the specified variable, data must be already in CNVData format. + * In case of error raises a std::string* exception containing the error message + * \return error code (0 = everything is ok) + */ + int writeData(PLC* thePLC, const char *networkVariablePathname, CNVData data); + + /*! + * \brief Subscribes for changes on the the specified variable. + * In case of error raises a std::string* exception containing the error message + */ + void monitorData(const char *networkVariablePathname); + + // not implemented. here because of virtual in super class + // TODO: review in order to get read of it + int readData(PLC* thePLC, unsigned long address, + unsigned long offset, + unsigned long size, + unsigned char* buffer){ return -1;}; + + // not implemented. here because of virtual in super class + // TODO: review in order to get read of it + int writeData(PLC* thePLC, unsigned long address, + unsigned long offset, + unsigned long size, + unsigned char* buffer){return -1;}; + + private: + // Subscriber + CNVSubscriber subscriber; + + /*! + * \brief Print the error message related to the code and throw exception if needed + * \return the error code itself (0 everything is ok) + */ + int errChk(PLC* thePLC, int code); + + /*! + * \brief Open the connection + * It actually return a boolean which indicates if the server responded to a ping operation + */ + bool open(PLC* thePLC); + + /*! + * \brief Close the connection with the server + */ + bool close(PLC* thePLC); + + }; + +} // namespace + +#endif // _CNV_CONNECTION_H_ + +#endif //NI_SUPPORT_ENABLED diff --git a/silecs-communication-cpp/src/silecs-communication/interface/communication/MBConnection.cpp b/silecs-communication-cpp/src/silecs-communication/interface/communication/MBConnection.cpp new file mode 100644 index 0000000..5bf3374 --- /dev/null +++ b/silecs-communication-cpp/src/silecs-communication/interface/communication/MBConnection.cpp @@ -0,0 +1,121 @@ +// Copyright 2016 CERN and GSI +// +// 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 3 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, see <http://www.gnu.org/licenses/>. + +#include <silecs-communication/interface/utility/SilecsLog.h> +#include <silecs-communication/interface/utility/StringUtilities.h> +#include <silecs-communication/interface/communication/SilecsConnection.h> +#include <silecs-communication/interface/equipment/SilecsPLC.h> +#include <silecs-communication/interface/communication/MBConnection.h> +#include <silecs-communication/interface/utility/SilecsException.h> + +namespace Silecs +{ + + MBConnection::MBConnection(PLC* thePLC) : Connection(thePLC) + { + LOG(ALLOC) << "MBConnection (create): " << thePLC->getName(); + } + + + MBConnection::~MBConnection() + { + //Close the connection before removing resources + //disable(); must be done before removing resource + } + + + bool MBConnection::open(PLC* thePLC) + { + //Open read and write Modbus channels (using IP address to limit the naming-server accesses) + readCh_ = IeMdbOpen(0, (char *) thePLC->getIPAddress().c_str(), (int)thePLC->getBaseAddress()); + writeCh_ = IeMdbOpen(0, (char *) thePLC->getIPAddress().c_str(), (int)thePLC->getBaseAddress()); + return ((readCh_ >= 0) && (writeCh_ >= 0)); + } + + + bool MBConnection::close(PLC* thePLC) + { + int err = 0; + err |= IeMdbClose(readCh_); + err |= IeMdbClose(writeCh_); + return (err == 0); + } + + + int MBConnection::readData(PLC* thePLC, unsigned long address, unsigned long offset, unsigned long size, unsigned char* pBuffer) + { + //Schneider uses 16bit alignment memory. Block address is expressed in bytes, must be an even value! + if (address % 2) throw SilecsException(__FILE__, __LINE__, PARAM_INCORRECT_BLOCK_ADDRESS, StringUtilities::toString(address)); + + /* . There is one read-channel per PLC connection. It must be protected against concurrent access. + * . The write-channel is independent and can be accessed in parallel. + * . The global action (open,close,etc.) must be protected from any concurrent access. + * Attention! + * Mutexes are defined with recursive option. It allows doOpen method re-calling readData + * method by executing register synchronization if required. + */ + + //(re)connect the PLC if needed and (re)synchronize the retentive registers + if (doOpen(thePLC)) + { + //connection is established then acquire data + Lock lock(readMux_); + //Schneider uses 16bit alignment memory. Block address is expressed in bytes (==> /2) + unsigned short addr = ((unsigned short)address + (unsigned short)offset)/2; + + //DATA topic makes sense with RECV one + if (RECV & Log::topics_) LOG(DATA) << "Read data, address: %MW" << addr << ", byte-size: " << size; + + int error = IeMBreadData(readCh_, addr, (unsigned short)size, pBuffer); + if(error) + throw SilecsException(__FILE__, __LINE__, UNEXPECTED_ERROR," ModBus Error: " + string(IeGetErrorMessage(error))); + } + return 0; + } + + + int MBConnection::writeData(PLC* thePLC, unsigned long address, unsigned long offset, unsigned long size, unsigned char* pBuffer) + { + //Schneider uses 16bit alignment memory. Block address is expressed in bytes, must be an even value! + if (address % 2) throw SilecsException(__FILE__, __LINE__, PARAM_INCORRECT_BLOCK_ADDRESS, StringUtilities::toString(address)); + + /* . There is one read-channel per PLC connection. It must be protected against concurrent access. + * . The write-channel is independent and can be accessed in parallel. + * . The global action (open,close,etc.) must be protected from any concurrent access. + * Attention! + * Mutexes are defined with recursive option. It allows doOpen method re-calling sendData + * method by executing register synchronization if required. + */ + + //(re)connect the PLC if needed and (re)synchronize the retentive registers + if (doOpen(thePLC)) + { + //connection is established then send data + + Lock lock(writeMux_); + //Schneider uses 16bit alignment memory. Block address is expressed in bytes (==> /2) + unsigned short addr = ((unsigned short)address + (unsigned short)offset)/2; + + //DATA topic makes sense with SEND one + if (SEND & Log::topics_) LOG(DATA) << "Write data, address: %MW" << addr << ", byte-size: " << size; + + int error = IeMBwriteData(writeCh_, (unsigned short)addr, (unsigned short)size, pBuffer); + if(error) + throw SilecsException(__FILE__, __LINE__, UNEXPECTED_ERROR," ModBus Error: " + string(IeGetErrorMessage(error))); + } + return 0; + } + +} // namespace diff --git a/silecs-communication-cpp/src/silecs-communication/interface/communication/MBConnection.h b/silecs-communication-cpp/src/silecs-communication/interface/communication/MBConnection.h new file mode 100644 index 0000000..953cdd8 --- /dev/null +++ b/silecs-communication-cpp/src/silecs-communication/interface/communication/MBConnection.h @@ -0,0 +1,50 @@ +// Copyright 2016 CERN and GSI +// +// 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 3 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, see <http://www.gnu.org/licenses/>. + +#ifndef _MB_CONNECTION_H_ +#define _MB_CONNECTION_H_ + +#include <silecs-communication/interface/communication/SilecsConnection.h> +#include <silecs-communication/protocol/core/silecs.h> + +namespace Silecs +{ + class PLC; + class Connection; + + /*! + * \class MBConnection + * \brief Plc-communication object for specific Modbus protocol + */ + class MBConnection : public Connection + { + + public: + MBConnection(PLC* thePLC); + virtual ~MBConnection(); + + int readData(PLC* thePLC, unsigned long address, unsigned long offset, unsigned long size, unsigned char* pBuffer); + int writeData(PLC* thePLC, unsigned long address, unsigned long offset, unsigned long size, unsigned char* pBuffer); + + private: + bool open(PLC* thePLC); + bool close(PLC* thePLC); + + }; + +} // namespace + +#endif // _MB_CONNECTION_H_ + diff --git a/silecs-communication-cpp/src/silecs-communication/interface/communication/SNAP7Connection.cpp b/silecs-communication-cpp/src/silecs-communication/interface/communication/SNAP7Connection.cpp new file mode 100644 index 0000000..7276087 --- /dev/null +++ b/silecs-communication-cpp/src/silecs-communication/interface/communication/SNAP7Connection.cpp @@ -0,0 +1,201 @@ +// Copyright 2016 CERN and GSI +// +// 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 3 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, see <http://www.gnu.org/licenses/>. + +#include <silecs-communication/interface/utility/SilecsLog.h> +#include <silecs-communication/interface/utility/StringUtilities.h> +#include <silecs-communication/interface/communication/SilecsConnection.h> +#include <silecs-communication/interface/equipment/SilecsPLC.h> +#include <silecs-communication/interface/communication/SNAP7Connection.h> +#include <silecs-communication/interface/utility/SilecsException.h> + +namespace Silecs +{ + + SNAP7Connection::SNAP7Connection(PLC* thePLC) : Connection(thePLC) + { + recvClient_ = Cli_Create(); + sendClient_ = Cli_Create(); + LOG(ALLOC) << "SNAP7Connection (create) PLC/Cluster: " << thePLC->getName() << "/" << thePLC->theCluster_->getClassName(); + } + + + SNAP7Connection::~SNAP7Connection() + { + Cli_Destroy(&recvClient_); + Cli_Destroy(&sendClient_); + } + + bool SNAP7Connection::open(PLC* thePLC) + { + int err = 0; + + //Slot number is not required, so try to connect on different slots (1..31), depending on hardware layout. + int *slotsScan; + int slotsS7400[4] = { 3,4,2,1 }; //slot scan - most common layout S7-400 + int slotsS71x00[4] = { 1,2,3,4 }; //slot scan - most common layout S7-1200, S7-1500 + int slotsDefault[4] = { 2,3,4,1 }; //slot scan - most common layout S7-other (S7-300, ET200S) + int rackNb = 0; //rackNb - common rack is 0 so far + int slotNb; + + switch (thePLC->getModelID()) + { + case S7400: + slotsScan = slotsS7400; break; + case S71200: + case S71500: + slotsScan = slotsS71x00; break; + default: + slotsScan = slotsDefault; //S7-300, ET200S + } + + for(int i=0; i<4; i++) + { + slotNb = slotsScan[i]; + err = Cli_ConnectTo(recvClient_, thePLC->getIPAddress().c_str(), rackNb, slotNb); + if (err) // next slot + { + LOG(DEBUG) << "SNAP7 connection (channel-2) failed on PLC/rack/slot: " << thePLC->getName() << "/" << rackNb << "/" << slotNb <<". SNAP7[" << err << "]: " << getSNAP7ErrorMessage(err); + break; + } + LOG(DEBUG) << "SNAP7 connect (channel-1) successful on PLC/rack/slot: " << thePLC->getName() << "/" << rackNb << "/" << slotNb; + //We managed to open the first channel, just open the second one on the same slot. + err = Cli_ConnectTo(sendClient_, thePLC->getIPAddress().c_str(), rackNb, slotNb); + if (err) // next slot + { + LOG(DEBUG) << "SNAP7 connection (channel-2) failed on PLC/rack/slot: " << thePLC->getName() << "/" << rackNb << "/" << slotNb <<". SNAP7[" << err << "]: " << getSNAP7ErrorMessage(err); + break; + } + LOG(DEBUG) << "SNAP7 connect (channel-2) successful on PLC/rack/slot: " << thePLC->getName() << "/" << rackNb << "/" << slotNb; + return true; + } + return false; + } + + + bool SNAP7Connection::close(PLC* thePLC) + { + bool ret = (Cli_Disconnect(recvClient_) == 0) && + (Cli_Disconnect(sendClient_) == 0); + return ret; + } + + + std::string SNAP7Connection::getSNAP7ErrorMessage(int err) + { + char text[100]; + Cli_ErrorText(err, text, 100); + return std::string(text); + } + + + //------------------------------------------------------------------------------------------------------------------- + int SNAP7Connection::readUnitCode(PLC* thePLC, UnitCodeType& dataStruct) + { + TS7OrderCode S7data; + int error = Cli_GetOrderCode(recvClient_, &S7data); + if(error) + throw SilecsException(__FILE__, __LINE__, UNEXPECTED_ERROR," SNAP7 Error: " + getSNAP7ErrorMessage(error)); + std::ostringstream os; + os << S7data.Code; + dataStruct.code = os.str(); + os.str().clear(); + os << (int)S7data.V1 << "." << (int)S7data.V2 << "." << (int)S7data.V3; + dataStruct.version = os.str(); + LOG(DEBUG) << "Unit order-code received: " << dataStruct.code << ", " << dataStruct.version; + return 0; + } + + + int SNAP7Connection::readUnitStatus(PLC* thePLC, UnitStatusType& dataStruct) + { + int status; + int error = Cli_GetPlcStatus(recvClient_, &status); + if(error) + throw SilecsException(__FILE__, __LINE__, UNEXPECTED_ERROR," SNAP7 Error: " + getSNAP7ErrorMessage(error)); + dataStruct.status = status; + LOG(DEBUG) << "Unit status received: " << (int)dataStruct.status; + return 0; + } + + int SNAP7Connection::readCPUInfo(PLC* thePLC, CPUInfoType& dataStruct) + { + TS7CpuInfo S7data; + int error = Cli_GetCpuInfo(recvClient_, &S7data); + if(error) + throw SilecsException(__FILE__, __LINE__, UNEXPECTED_ERROR," SNAP7 Error: " + getSNAP7ErrorMessage(error)); + dataStruct.moduleName = std::string(S7data.ModuleName); + dataStruct.moduleTypeName = std::string(S7data.ModuleTypeName); + dataStruct.serialNumber = std::string(S7data.SerialNumber); + dataStruct.asName = std::string(S7data.ASName); + dataStruct.copyright = std::string(S7data.Copyright); + LOG(DEBUG) << "CPU info received: " << dataStruct.moduleName << ", " << dataStruct.moduleTypeName << ", " + << dataStruct.serialNumber << ", " << dataStruct.asName << ", " << dataStruct.copyright; + return 0; + } + + int SNAP7Connection::readCPInfo(PLC* thePLC, CPInfoType& dataStruct) + { + TS7CpInfo S7data; + int error = Cli_GetCpInfo(recvClient_, &S7data); + if(error) + throw SilecsException(__FILE__, __LINE__, UNEXPECTED_ERROR," SNAP7 Error: " + getSNAP7ErrorMessage(error)); + dataStruct.maxPduLength = S7data.MaxPduLengt; + dataStruct.maxConnections = S7data.MaxConnections; + dataStruct.maxMPIRate = S7data.MaxMpiRate; + dataStruct.maxBusRate = S7data.MaxBusRate; + LOG(DEBUG) << "CP info received: " << dataStruct.maxPduLength << ", " << dataStruct.maxConnections << ", " + << dataStruct.maxMPIRate << ", " << dataStruct.maxBusRate; + return 0; + } + + + //------------------------------------------------------------------------------------------------------------------- + int SNAP7Connection::readData(PLC* thePLC, unsigned long DBn, unsigned long offset, unsigned long size, unsigned char* pBuffer) + { + //(re)connect the PLC if needed and (re)synchronize the retentive registers + if (doOpen(thePLC)) + { + //connection is established then acquire data + Lock lock(readMux_); + + //DATA topic makes sense with RECV one + if (RECV & Log::topics_) LOG(DATA) << "Read data, DBn: " << DBn << ", ofs: " << offset << ", byte-size: " << size; + + int error = Cli_DBRead(recvClient_, (int)DBn, (int)offset, (int)size, (void *)pBuffer); + if(error) + throw SilecsException(__FILE__, __LINE__, UNEXPECTED_ERROR," SNAP7 Error: " + getSNAP7ErrorMessage(error)); + } + return 0; + } + + int SNAP7Connection::writeData(PLC* thePLC, unsigned long DBn, unsigned long offset, unsigned long size, unsigned char* pBuffer) + { + //(re)connect the PLC if needed and (re)synchronize the retentive registers + if (doOpen(thePLC)) + { + //connection is established then send data + Lock lock(writeMux_); + + //DATA topic makes sense with SEND one + if (SEND & Log::topics_) LOG(DATA) << "Write data, DBn: " << DBn << ", ofs: " << offset << ", byte-size: " << size; + + int error = Cli_DBWrite(sendClient_, (int)DBn, (int)offset, (int)size, (void *)pBuffer); + if(error) + throw SilecsException(__FILE__, __LINE__, UNEXPECTED_ERROR," SNAP7 Error: " + getSNAP7ErrorMessage(error)); + } + return 0; + } + +} // namespace diff --git a/silecs-communication-cpp/src/silecs-communication/interface/communication/SNAP7Connection.h b/silecs-communication-cpp/src/silecs-communication/interface/communication/SNAP7Connection.h new file mode 100644 index 0000000..5d14818 --- /dev/null +++ b/silecs-communication-cpp/src/silecs-communication/interface/communication/SNAP7Connection.h @@ -0,0 +1,58 @@ +// Copyright 2016 CERN and GSI +// +// 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 3 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, see <http://www.gnu.org/licenses/>. + +#ifndef _SNAP7_CONNECTION_H_ +#define _SNAP7_CONNECTION_H_ + +#include <silecs-communication/protocol/core/silecs.h> +#include <snap7.h> + +namespace Silecs +{ + class PLC; + class Connection; + + /*! + * \class SNAP7Connection + * \brief Plc-communication object for specific SNAP7 protocol + */ + class SNAP7Connection : public Connection + { + + public: + SNAP7Connection(PLC* thePLC); + virtual ~SNAP7Connection(); + + int readUnitCode(PLC* thePLC, UnitCodeType& dataStruct); + int readUnitStatus(PLC* thePLC, UnitStatusType& dataStruct); + int readCPUInfo(PLC* thePLC, CPUInfoType& dataStruct); + int readCPInfo(PLC* thePLC, CPInfoType& dataStruct); + + int readData(PLC* thePLC, unsigned long DBn, unsigned long offset, unsigned long size, unsigned char* pBuffer); + int writeData(PLC* thePLC, unsigned long DBn, unsigned long offset, unsigned long size, unsigned char* pBuffer); + + private: + S7Object recvClient_; + S7Object sendClient_; + bool open(PLC* thePLC); + bool close(PLC* thePLC); + + std::string getSNAP7ErrorMessage(int err); + }; + +} // namespace + +#endif // _SNAP7_CONNECTION_H_ + diff --git a/silecs-communication-cpp/src/silecs-communication/interface/communication/SilecsConnection.cpp b/silecs-communication-cpp/src/silecs-communication/interface/communication/SilecsConnection.cpp new file mode 100644 index 0000000..fc9c803 --- /dev/null +++ b/silecs-communication-cpp/src/silecs-communication/interface/communication/SilecsConnection.cpp @@ -0,0 +1,387 @@ +// Copyright 2016 CERN and GSI +// +// 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 3 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, see <http://www.gnu.org/licenses/>. + +#include <silecs-communication/interface/utility/SilecsLog.h> +#include <silecs-communication/interface/communication/SilecsConnection.h> +#include <silecs-communication/interface/equipment/SilecsPLC.h> +#include <silecs-communication/protocol/core/silecs.h> + +namespace Silecs +{ + + // static definition + bool Connection::isInit_ = false; + bool Connection::isAlive_ = false; + const unsigned int Connection::numberConn_ = 3; + + //------------------------------------------------------------------------------------------------------------------------------------------------ + Connection::Connection(PLC* thePLC) + { + // Start the PLC Thread + readMux_ = new Mutex("readMux"); + writeMux_ = new Mutex("writeMux"); + connMux_ = new Mutex("connMux"); + + //Not yet allowed, not yet connected! + isEnabled_ = false; + isConnected_ = false; + + //Reset the Reconnection mechanism + timeConn_ = NULL; + delayConn_ = UrgentConnection; //initial reconnection delay + remainConn_ = numberConn_; //initial number of attempt + + // Silecs initialization has to be invoked only once per process + if (isInit_== false) + { IeInit(); + isInit_ = true; + } + } + + + //------------------------------------------------------------------------------------------------------------------------------------------------ + Connection::~Connection() + { + //Connection has been closed before from the concrete connection object + if (timeConn_ != NULL) delete timeConn_; + + delete connMux_; + delete writeMux_; + delete readMux_; + } + + //------------------------------------------------------------------------------------------------------------------------------------------------ + bool Connection::enable(PLC* thePLC, bool connectNow) + { + { + Lock lock(connMux_); + isEnabled_ = true; + } + if (connectNow) doOpen(thePLC); + return isConnected_; + } + + //------------------------------------------------------------------------------------------------------------------------------------------------ + void Connection::disable(PLC* thePLC) + { + if (!isEnabled_) { + LOG(DEBUG) << "Trying to disconnect a PLC that is not enabled: " << thePLC->getName(); + return; + } + + Lock lock(connMux_); + { + Lock lock(readMux_); + { + Lock lock(writeMux_); + isEnabled_ = false; + doClose(thePLC, /*withLock =*/false); + } + } + } + + //------------------------------------------------------------------------------------------------------------------------------------------------ + bool Connection::doOpen(PLC* thePLC) + { + LOG((COMM|DIAG)) << "Start attempt to open connection ..."; + bool justConnected = false; + + { + Lock lock(connMux_); + if (isConnected_) + { if (!isEnabled_) + { + LOG((COMM|DIAG)) << "The PLC is connected but the client wants to disable the transactions"; + doClose(thePLC, /*withLock =*/false); + } + return isConnected_; + } + + if (!isEnabled_) + { + LOG((COMM|DIAG)) << "The communication currently is not enabled"; + return isConnected_; + } + + if (isTimeToReconnect()) + { + LOG((COMM|DIAG)) << "It's time to reconnect"; + if ((thePLC->synchroMode_ == FULL_SYNCHRO) || (thePLC->synchroMode_ == SLAVE_SYNCHRO)) + { + //Retentive registers synchronization is requested: + //connection is not allowed if Slave Registers are not all initialized + std::string registerNotInitialized; + if (thePLC->checkSlaveRegistersInit(registerNotInitialized) == false) + { + logError(thePLC); + throw SilecsException(__FILE__, __LINE__, DIAG_SLAVE_REGISTER_NOT_INITIALIZED, registerNotInitialized); + } + } + + // It's time to open the connection according to the (re)connection timing + // Let's try several times with limited delay (some ms). + // It allows wake-up frozen PLC (SIEMENS in particular) after long stop period. + bool isOpen = false; + unsigned int nbConn = 2; //for fast low-level iteration + for(unsigned int i = 0; i<nbConn; i++) + { + LOG((COMM|DIAG)) << "Attempt to open PLC connection ...."; + isOpen = open(thePLC); + if(isOpen) + { + LOG((COMM|DIAG)) << "Connection opened successfully"; + break; + } + usleep(100000); // wait 100ms + } + if(!isOpen) + { + logError(thePLC); + return isConnected_; + } + + if (thePLC->isSharedConnection()) + { + LOG((COMM|DIAG)) << "Shared connection with " << thePLC->getName() << " is established."; + } + else + { + LOG((COMM|DIAG)) << "Connection with " << thePLC->getName() << + ":" << thePLC->theCluster_->getClassName() << + "/v" << thePLC->theCluster_->getClassVersion() << + " is established."; + } + + isAlive_ = true; + isConnected_ = true; + justConnected = true; //retentive registers synchronization is required! + + //Connection status has changed: update the diagnostic variables + LOG((COMM|DIAG)) << "Updating PLC status"; + updateStatus(thePLC); + } + }//release lock + + /* Process the Retentive registers synchronization each time the PLC is just (re)connected. + * This is a recursive call: performs task::execute method from doOpen that is + * called into execute itself. The recursion is terminated when SilecsHeader connection is closed finally. + */ + if (justConnected) + { + LOG((COMM|DIAG)) << "First connection - performing registers synchronization"; + if ((thePLC->synchroMode_ == FULL_SYNCHRO) || (thePLC->synchroMode_ == MASTER_SYNCHRO)) + { + thePLC->downloadMasterRegisters(); + } + + if ((thePLC->synchroMode_ == FULL_SYNCHRO) || (thePLC->synchroMode_ == SLAVE_SYNCHRO)) + { + thePLC->uploadSlaveRegisters(); + } + } + LOG((COMM|DIAG)) << "isConnected_:" << isConnected_; + return isConnected_; + } + + + //------------------------------------------------------------------------------------------------------------------------------------------------ + void Connection::doClose(PLC* thePLC, bool withLock) + { + //This process that can be called inside and outside protected section. + //withLock argument is used to avoid Recursive mutex that is not supported + //by LynxOS platform. + + if(withLock) + Lock lock(connMux_); + + if (isConnected_) + { + if (close(thePLC)) + { + readCh_ = writeCh_ = 0; + isConnected_ = false; + + //Connection status has changed: update the diagnostic variables + updateStatus(thePLC); + + if (thePLC->isSharedConnection()) + { + LOG((COMM|DIAG)) << "Shared connection with " << thePLC->getName() << " is closed."; + } + else + { + LOG((COMM|DIAG)) << "Connection with " << thePLC->getName() << + " (" << thePLC->theCluster_->getClassName() << + "/v" << thePLC->theCluster_->getClassVersion() << + ")" << " is closed."; + } + } + else + { LOG(COMM) << "Close connection with " << thePLC->getName() << + " (" << thePLC->theCluster_->getClassName() << + "/v" << thePLC->theCluster_->getClassVersion() << + ")" << " has failed."; + } + } + + } + + + //------------------------------------------------------------------------------------------------------------------------------------------------ + bool Connection::reOpen(PLC* thePLC) + { + if (IeRfcPing((char *) thePLC->getName().c_str(), 0) == 0) + { doClose(thePLC, /*withLock =*/true); + return doOpen(thePLC); + } + isAlive_ = false; + return false; + } + + bool Connection::isEnabled() { return isEnabled_; } + bool Connection::isConnected() { return isConnected_; } + + + //------------------------------------------------------------------------------------------------------------------- + int Connection::readUnitCode(PLC* thePLC, UnitCodeType& dataStruct) + { + throw SilecsException(__FILE__, __LINE__, DIAG_PLC_REPORT_NOT_SUPPORTED, thePLC->getName()); + return -1; + } + + + int Connection::readUnitStatus(PLC* thePLC, UnitStatusType& dataStruct) + { + throw SilecsException(__FILE__, __LINE__, DIAG_PLC_REPORT_NOT_SUPPORTED, thePLC->getName()); + return -1; + } + + + int Connection::readCPUInfo(PLC* thePLC, CPUInfoType& dataStruct) + { + throw SilecsException(__FILE__, __LINE__, DIAG_PLC_REPORT_NOT_SUPPORTED, thePLC->getName()); + return -1; + } + + + int Connection::readCPInfo(PLC* thePLC, CPInfoType& dataStruct) + { + throw SilecsException(__FILE__, __LINE__, DIAG_PLC_REPORT_NOT_SUPPORTED, thePLC->getName()); + return -1; + } + + + //------------------------------------------------------------------------------------------------------------------- + bool Connection::checkError(PLC* thePLC, int err, bool retry) + { + if (err < 0) + { + LOG(COMM) << "Transaction failure with PLC: " << thePLC->getName() << ". SILECS[" << err << "]: " << IeGetErrorMessage(err); + + switch(err) + { + case IE_TIMEOUT_ERROR: + case IE_EPIPE_ERROR: + case IE_DISCONNECT_ERROR: + if (retry) + { + LOG(COMM) << "Try to reconnect the PLC: " << thePLC->getName(); + if (reOpen(thePLC)) + { // can repeat the request after the connection was successfully reopened + return true; + } + // reconnection has failed again, just close the connection + LOG(COMM) << "Unable to reconnect the PLC: " << thePLC->getName(); + } + // else { // no retry, we just want to close (use default case) + default: + doClose(thePLC, /*withLock =*/true); + } + } + return false; // no particular error + } + + + //------------------------------------------------------------------------------------------------------------------------------------------------ + void Connection::updateStatus(PLC* thePLC) + { + //Connection status has changed (opened/closed) + //Update the PLC diagnostic variables + thePLC->updateStatus(); + + //Reset reconnection mecanisme in case of connection succeed + if (isConnected_) + { delayConn_ = UrgentConnection; //initial reconnection delay + remainConn_ = numberConn_; //initial number of attempt + } + } + + + //------------------------------------------------------------------------------------------------------------------------------------------------ + void Connection::logError(PLC* thePLC) + { + std::string errorMsg = "Connection with " + thePLC->getName() + + ":" + thePLC->theCluster_->getClassName() + + "/v" + thePLC->theCluster_->getClassVersion() + + " has failed. "; + + if (delayConn_ == LongTermConnection) + { if (remainConn_ > 0) + { LOG((COMM|DIAG)) << errorMsg << "Periodic attempt to reconnect, delay " << delayConn_ << "s (logging off)."; + remainConn_ = 1; //Try to reconnect again and again (=1 means disable logging). + } + else + { + LOG((COMM|DIAG)) << errorMsg << "PLC does not respond anymore. It's probably stopped for a long time. Trying to reconnect with long-term delay"; + } + } + else + LOG((COMM|DIAG)) << errorMsg << "Next attempt to reconnect in " << delayConn_ << "s if requested. Remains: " << remainConn_; + } + + //------------------------------------------------------------------------------------------------------------------------------------------------ + bool Connection::isTimeToReconnect() + { + bool toBeReconnected = false; + if (timeConn_ != NULL) + { //how many time from the last connect attempt + double delay = timeConn_->getDelay(S_UNIT); + if (delay >= double(delayConn_)) + { timeConn_->getValue(S_UNIT); //restart delay counting from now + toBeReconnected = true; + + if (remainConn_ > 0) --remainConn_; + if (remainConn_ == 0) + { if (delayConn_ != LongTermConnection) + { if (delayConn_ == UrgentConnection) + delayConn_ = ShortTermConnection; + else //(delayConn_ == ShortTermConnection) + delayConn_ = LongTermConnection; + remainConn_ = numberConn_; + } + } + } + } + else + { + //This is the first connection attempt, just start the Time counter. + timeConn_ = new TsCounter(true); //using hardware clock + timeConn_->getValue(S_UNIT); //start delay counting from now + toBeReconnected = true; + } + return toBeReconnected; + } + +} // end namespace diff --git a/silecs-communication-cpp/src/silecs-communication/interface/communication/SilecsConnection.h b/silecs-communication-cpp/src/silecs-communication/interface/communication/SilecsConnection.h new file mode 100644 index 0000000..ca2319a --- /dev/null +++ b/silecs-communication-cpp/src/silecs-communication/interface/communication/SilecsConnection.h @@ -0,0 +1,175 @@ +// Copyright 2016 CERN and GSI +// +// 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 3 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, see <http://www.gnu.org/licenses/>. + +#ifndef _SILECS_CONNECTION_H_ +#define _SILECS_CONNECTION_H_ + +#include <silecs-communication/interface/core/SilecsService.h> +#include <silecs-communication/interface/utility/Mutex.h> +#include <silecs-communication/interface/utility/TimeStamp.h> +#include <silecs-communication/protocol/core/silecs.h> + +namespace Silecs +{ + class PLC; + + // Time to wait (second) before next reconnection attempt + typedef enum + { UrgentConnection=2, ShortTermConnection=20, LongTermConnection=60 + } ConnectionDelay; + +#ifdef __x86_64__ + typedef long ChannelID; //pointer is 64bits word +#else + typedef int ChannelID; //pointer is 32bits word +#endif + + class Lock + { + + public: + + Lock(Mutex* mutex): mutex_(mutex) + { + mutex_->lock(); + } + + ~Lock() + { + mutex_->unlock(); + } + Mutex* mutex_; + }; + + class Connection + { + + public: + Connection(PLC* thePLC); + virtual ~Connection(); + + virtual int readData(PLC* thePLC, + unsigned long address, + unsigned long offset, + unsigned long size, + unsigned char* buffer) = 0; + + virtual int writeData(PLC* thePLC, + unsigned long address, + unsigned long offset, + unsigned long size, + unsigned char* buffer) = 0; + + /*! + * \fn enable/disable + * \brief The client can suspend the data transmission by disabling the connection if required. + * enable/disable methods are used from the high-level Cluster API: connect/disconnect. + * \param connectNow can be used to force immediate connection (true) + */ + virtual bool enable(PLC* thePLC, bool connectNow); + void disable(PLC* thePLC); + bool isEnabled(); + + static inline bool isAlive() { return isAlive_; } + bool isConnected(); + + virtual int readUnitCode(PLC* thePLC, UnitCodeType& dataStruct); + virtual int readUnitStatus(PLC* thePLC, UnitStatusType& dataStruct); + virtual int readCPUInfo(PLC* thePLC, CPUInfoType& dataStruct); + virtual int readCPInfo(PLC* thePLC, CPInfoType& dataStruct); + + protected: + friend class Cluster; + friend class PLC; + friend class CNVRecvDeviceMode; + friend class CNVSendDeviceMode; + + /*! + * \fn doOpen + * \brief This method check the current state of the connection and open it if required. + * doOpen that is called on each transaction is reponsible of the automatic reconnection mechanism. + */ + virtual bool doOpen(PLC* thePLC); + void doClose(PLC* thePLC, bool withLock); + bool reOpen(PLC* thePLC); + + virtual bool open(PLC* thePLC) = 0; //open the connection for a particular PLC brand + virtual bool close(PLC* thePLC) = 0; //close the connection for a particular PLC brand + + /*! + * \fn checkError + * \brief This method attempts to reconnect the PLC in case of "expected" transaction failure. + * If the returned value is true the request must be repeated. + * The retry flag defines whether the transaction will be repeated or not + * IE_CONNECT_ERROR - TCP/IP connect() failed: IeOpen() (PLC is off or the max. number of open connection is reached) + * Retry required: + * IE_DISCONNECT_ERROR - Explicit/unexpected disconnect request (when the connection has been unactive for some time) + * IE_EPIPE_ERROR - TCP/IP send/recv failed (when one of the channel (get/set) has been unactive for some time or PLC is off) + * IE_TIMEOUT_ERROR - PLC is connected but does not reply (In mean time the PLC gets off or data is lost) + */ + virtual bool checkError(PLC* thePLC, int err, bool retry); + + /*! + * \fn updatePLCStatus + * \brief Responsible to update the diagnostic variables each time PLC states have changed + */ + void updateStatus(PLC* thePLC); + + void logError(PLC* thePLC); + + /*! + * \fn isTimeToReconnect + * \brief In order to not overload the network the reconnection attempts are gradually slowed + * down from second scale to several minutes. This method checks the elapsed time since connection. + * \return true if it's time to try to reconnect (time unit is second). + */ + bool isTimeToReconnect(); + + // flag used to enable/disable the transactions independently from the scheduling + bool isEnabled_; + + // Silecs descriptor for send/recv channels + ChannelID readCh_; + ChannelID writeCh_; + + /* . read-channel and write channel are independent and can be accessed in parallel. + * . Each channel must be protected against respective concurrent access. + * . The global action (open,close,etc.) must be protected from any concurrent access. + */ + Mutex* readMux_; //Mutex used to protect the PLC read-channel resource + Mutex* writeMux_; //Mutex used to protect the PLC write-channel resource + Mutex* connMux_; //Mutex used to protect the global PLC connection resource (for open/close, etc.) + + // Time counter to manage the automatic reconnection + TsCounter* timeConn_; + ConnectionDelay delayConn_; //current delay between two connection + unsigned long remainConn_; //number of attempt before next slow-down + static const unsigned int numberConn_; //number of connection attempt for each connection delay + + // Communication Diagnostic & Monitoring + static bool isAlive_; // PLC has repliyed to the ping: true/false + bool isConnected_; // State of this particular connection: FEC/PLC/Class + + // Silecs initialization has to be invoked only once per process + static bool isInit_; + + // not copyable object + Connection(const Connection&); + Connection& operator=(const Connection&); + }; + +} // end namespace + +#endif // _SILECS_CONNECTION_H_ diff --git a/silecs-communication-cpp/src/silecs-communication/interface/core/CNVRecvAction.cpp b/silecs-communication-cpp/src/silecs-communication/interface/core/CNVRecvAction.cpp new file mode 100644 index 0000000..57b4259 --- /dev/null +++ b/silecs-communication-cpp/src/silecs-communication/interface/core/CNVRecvAction.cpp @@ -0,0 +1,171 @@ +// Copyright 2016 CERN and GSI +// +// 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 3 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, see <http://www.gnu.org/licenses/>. + +#ifdef NI_SUPPORT_ENABLED +#include <silecs-communication/interface/core/SilecsService.h> +#include <silecs-communication/interface/core/PLCAction.h> +#include <silecs-communication/interface/core/CNVRecvAction.h> +#include <silecs-communication/interface/communication/SilecsConnection.h> +#include <silecs-communication/interface/equipment/SilecsPLC.h> +#include <silecs-communication/interface/equipment/SilecsDevice.h> +#include <silecs-communication/interface/equipment/SilecsBlock.h> +#include <silecs-communication/interface/core/Context.h> +#include <silecs-communication/interface/utility/SilecsLog.h> +#include "../communication/CNVConnection.h.obsolete" +#include "../equipment/CNVBlock.h.obsolete" + +namespace Silecs +{ + + CNVRecvBlockMode::CNVRecvBlockMode(Block* block) : PLCAction(block) + { + if (DEBUG & Log::topics_) LOG(ALLOC) << "Action CNVRecvBlockMode (create): " << theBlock_->getName(); + } + + CNVRecvBlockMode::~CNVRecvBlockMode() + { + if (DEBUG & Log::topics_) LOG(ALLOC) << "Action CNVRecvBlockMode (delete): " << theBlock_->getName(); + } + + CNVRecvDeviceMode::CNVRecvDeviceMode(Block* block) : PLCAction(block) + { + if (DEBUG & Log::topics_) LOG(ALLOC) << "Action CNVRecvDeviceMode (create): " << theBlock_->getName(); + } + + CNVRecvDeviceMode::~CNVRecvDeviceMode() + { + if (DEBUG & Log::topics_) LOG(ALLOC) << "Action CNVRecvDeviceMode (delete): " << theBlock_->getName(); + } + + int CNVRecvBlockMode::execute(Context* pContext) + { + //Block mode cannot be implemented with CNV + return 0; + } + + int CNVRecvDeviceMode::execute(Context* pContext) + { + timeval tod; //Time-of-day for register time-stampng + + CNVData buffer; + + int errorCode = 0; + Connection* pConn = theBlock_->getPLC()->getConnection(); + + //(re)connect the PLC if needed and (re)synchronize the retentive registers + if (pConn->doOpen(theBlock_->getPLC())) + { + try + { + //if transaction is for one device only, pContext contains its reference + if (pContext->isForOneDevice()) + { + //Device context: get block of one device only ==================================== + Device* pDev = pContext->getDevice(); + + if (RECV & Log::topics_) + { if (pConn->isEnabled()) + { Log(RECV).getLog() << "RecvAction (execute/ DeviceMode): " << theBlock_->getName() << ", device: " << pDev->getLabel(); + } + } + + bufferLock(); + + // read data from the buffer subscriber + CNVBufferedSubscriber* handle = ((CNVInputBlock*)theBlock_)->getHandle(pDev->getLabel()); + errorCode = ((CNVConnection*)pConn)->readData(theBlock_->getPLC(), handle,&buffer); + + if (pConn->isConnected() && (errorCode == 0)) + { //Data have just been received: get time-of-day to time-stamp the registers + gettimeofday(&tod, 0); + + //Device context: Extract all the device registers from that block + pDev->importRegisters(theBlock_, &buffer, tod, pContext); + } + + bufferUnlock(); + + //Deleting Null Data object raised a CNV exception + if (errorCode != CNVEmptyDataError) errChk(CNVDisposeData(buffer)); + + LOG_DELAY(RECV) << "done: " << theBlock_->getName(); + } + else + { + //Cluster/PLC context: get block of all devices one by one ========================= + deviceVectorType::iterator pDeviceIter; + deviceVectorType& deviceCol = theBlock_->getPLC()->getDeviceMap(); + for(pDeviceIter = deviceCol.begin(); pDeviceIter != deviceCol.end(); ++pDeviceIter) + { + Device* pDev = pDeviceIter->second; + + if (RECV & Log::topics_) + { if (pConn->isEnabled()) + { Log(RECV).getLog() << "RecvAction (execute/ DeviceMode): " << theBlock_->getName() << ", device: " << pDev->getLabel(); + } + } + + bufferLock(); + + // read data from the buffer subscriber + CNVBufferedSubscriber* handle = ((CNVInputBlock*)theBlock_)->getHandle(pDev->getLabel()); + errorCode = ((CNVConnection*)pConn)->readData(theBlock_->getPLC(), handle,&buffer); + + if (pConn->isConnected() && (errorCode == 0)) + { //Data have just been received: get time-of-day to time-stamp the registers + gettimeofday(&tod, 0); + + //PLC context: Extract all registers value of the current device of the PLC from that block + pDev->importRegisters(theBlock_, &buffer, tod, pContext); + } + + bufferUnlock(); + + //Deleting Null Data object raised a CNV exception + if (errorCode != CNVEmptyDataError) errChk(CNVDisposeData(buffer)); + + LOG_DELAY(RECV) << "done: " << theBlock_->getName(); + } + } + } + catch (const SilecsException& ex) + { + bufferUnlock(); + + errorCode = ex.getCode(); + } + } //doOpen + + return errorCode; + } + + void CNVRecvBlockMode::errChk(int code) + { + if(code != 0) + { + throw SilecsException(__FILE__, __LINE__, CNV_INTERNAL_ERROR, std::string(CNVGetErrorDescription(code))+" in CNVRecvBlockMode"); + } + } + + void CNVRecvDeviceMode::errChk(int code) + { + if(code != 0) + { + throw SilecsException(__FILE__, __LINE__, CNV_INTERNAL_ERROR, std::string(CNVGetErrorDescription(code))+" in CNVRecvDeviceMode"); + } + } + +} // namespace +#endif //NI_SUPPORT_ENABLED diff --git a/silecs-communication-cpp/src/silecs-communication/interface/core/CNVRecvAction.h b/silecs-communication-cpp/src/silecs-communication/interface/core/CNVRecvAction.h new file mode 100644 index 0000000..e07dce9 --- /dev/null +++ b/silecs-communication-cpp/src/silecs-communication/interface/core/CNVRecvAction.h @@ -0,0 +1,95 @@ +// Copyright 2016 CERN and GSI +// +// 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 3 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, see <http://www.gnu.org/licenses/>. + +#ifdef NI_SUPPORT_ENABLED + +#ifndef _RECV_CNV_ACTION_H_ +#define _RECV_CNV_ACTION_H_ + +#include <silecs-communication/interface/core/PLCAction.h> + +#ifdef __cplusplus +extern "C" { +#endif + +#include <nilibnetv.h> + +#ifdef __cplusplus +} +#endif + +namespace Silecs +{ + class Action; + class Block; + class Context; + + /*! + * \class CNVRecvBlockMode + * \brief Concrete action responsible to get a data block from the CNV (Block mode configuration) + */ + class CNVRecvBlockMode : public PLCAction + { + + public: + CNVRecvBlockMode(Block* block); + virtual ~CNVRecvBlockMode(); + + /*! + * \fn execute + * Connect the CNV if necessary and Get data-block from its memory. + * Overwrite the abstract method + * \return 0 if no error occurred. else return a error status from low level library + */ + int execute(Context* pContext); + + private: + + /* generate a string exception out of a CNV error code*/ + void errChk(int code); + + }; + + /*! + * \class CNVRecvDeviceMode + * \brief Concrete action responsible to get a data block from the CNV (Device mode configuration) + */ + class CNVRecvDeviceMode : public PLCAction + { + + public: + CNVRecvDeviceMode(Block* block); + virtual ~CNVRecvDeviceMode(); + + /*! + * \fn execute + * Connect the CNV if necessary and Get data-block from its memory. + * Overwrite the abstract method + * \return 0 if no error occurred. else return a error status from low level library + */ + int execute(Context* pContext); + + private: + + /* generate a string exception out of a CNV error code*/ + void errChk(int code); + + }; + +} // namespace + +#endif // _RECV_CNV_ACTION_H_ + +#endif //NI_SUPPORT_ENABLED diff --git a/silecs-communication-cpp/src/silecs-communication/interface/core/CNVSendAction.cpp b/silecs-communication-cpp/src/silecs-communication/interface/core/CNVSendAction.cpp new file mode 100644 index 0000000..8c834e8 --- /dev/null +++ b/silecs-communication-cpp/src/silecs-communication/interface/core/CNVSendAction.cpp @@ -0,0 +1,175 @@ +// Copyright 2016 CERN and GSI +// +// 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 3 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, see <http://www.gnu.org/licenses/>. + +#ifdef NI_SUPPORT_ENABLED +#include <silecs-communication/interface/core/SilecsService.h> +#include <silecs-communication/interface/core/SilecsAction.h> +#include <silecs-communication/interface/core/PLCAction.h> +#include <silecs-communication/interface/communication/SilecsConnection.h> +#include <silecs-communication/interface/equipment/SilecsPLC.h> +#include <silecs-communication/interface/equipment/SilecsDevice.h> +#include <silecs-communication/interface/equipment/SilecsBlock.h> +#include <silecs-communication/interface/core/CNVSendAction.h> +#include <silecs-communication/interface/core/Context.h> +#include <silecs-communication/interface/utility/SilecsLog.h> +#include "../communication/CNVConnection.h.obsolete" +#include "../equipment/CNVBlock.h.obsolete" + +namespace Silecs +{ + + CNVSendBlockMode::CNVSendBlockMode(Block* block) : PLCAction(block) + { + if (DEBUG & Log::topics_) LOG(ALLOC) << "Action CNVSendBlockMode (create): " << theBlock_->getName(); + } + + CNVSendBlockMode::~CNVSendBlockMode() + { + if (DEBUG & Log::topics_) LOG(ALLOC) << "Action CNVSendBlockMode (delete): " << theBlock_->getName(); + } + + CNVSendDeviceMode::CNVSendDeviceMode(Block* block) : PLCAction(block) + { + if (DEBUG & Log::topics_) LOG(ALLOC) << "Action CNVSendDeviceMode (create): " << theBlock_->getName(); + } + + CNVSendDeviceMode::~CNVSendDeviceMode() + { + if (DEBUG & Log::topics_) LOG(ALLOC) << "Action CNVSendDeviceMode (delete): " << theBlock_->getName(); + } + + int CNVSendBlockMode::execute(Context* pContext) + { + return 0; + } + + int CNVSendDeviceMode::execute(Context* pContext) + { + CNVData* pBuffer; + int errorCode = 0; + Connection* pConn = theBlock_->getPLC()->getConnection(); + + //(re)connect the PLC if needed and (re)synchronize the retentive registers + if (pConn->doOpen(theBlock_->getPLC())) + { + try + { + //if transaction is for one device only, pContext contains its reference + if (pContext->isForOneDevice()) + { + + Device* pDev = pContext->getDevice(); + + pBuffer = (CNVData*)theBlock_->getBuffer(); + + bufferLock(); + + if (pConn->isEnabled()) + { + LOG(SEND) << "SendAction (execute/ DeviceMode): " << theBlock_->getName() << ", device: " << pDev->getLabel(); + + //Device context: Export all the device registers to that block + pDev->exportRegisters(theBlock_, pBuffer, pContext); + } + + // compute the block address + std::string blockAddress = "\\\\"+pDev->getPLC()->getName()+"\\'" + +pDev->getPLC()->theCluster_->getClassName()+"-"+pDev->getPLC()->theCluster_->getClassVersion()+"'\\" + + pDev->getLabel()+"\\"+theBlock_->getName(); + + // call CNV write + ((CNVConnection*)pConn)->writeData(theBlock_->getPLC(), blockAddress.c_str(),*pBuffer); + + bufferUnlock(); + + if (SEND & Log::topics_) + { + if (pConn->isEnabled()) + { + Log(SEND).getLogDelay() << "done: " << theBlock_->getName(); + } + } + } + else + { + //Cluster/PLC context: set block of all devices one by one ========================= + deviceVectorType::iterator pDeviceIter; + deviceVectorType& deviceCol = theBlock_->getPLC()->getDeviceMap(); + for(pDeviceIter = deviceCol.begin(); pDeviceIter != deviceCol.end(); ++pDeviceIter) + { + Device* pDev = pDeviceIter->second; + + pBuffer = (CNVData*)theBlock_->getBuffer(); + + bufferLock(); + + if (pConn->isEnabled()) + { LOG(SEND) << "SendAction (execute/ DeviceMode): " << theBlock_->getName() << ", device:" << pDev->getLabel(); + + //PLC context: Export all registers value of the current device of the PLC to that block + pDev->exportRegisters(theBlock_, pBuffer, pContext); + } + + // compute the block address + std::string blockAddress = "\\\\"+pDev->getPLC()->getName()+"\\'" + +pDev->getPLC()->theCluster_->getClassName()+"-"+pDev->getPLC()->theCluster_->getClassVersion()+"'\\" + + pDev->getLabel()+"\\"+theBlock_->getName(); + + // call CNV write + ((CNVConnection*)pConn)->writeData(theBlock_->getPLC(), blockAddress.c_str(),*pBuffer); + + bufferUnlock(); + + if (SEND & Log::topics_) + { if (pConn->isEnabled()) + { Log(SEND).getLogDelay() << "done: " << theBlock_->getName(); + } + } + } + } + } + catch (const SilecsException& ex) + { + bufferUnlock(); + + //LOG(DEBUG) << "CNV SendAction (execute/ DeviceMode) failed: "<< ex.getMessage(); + //errorCode = ex.getCode(); + LOG(DEBUG) << "CNV SendAction (execute/ DeviceMode) failed"; + errorCode = -1; //no SilecsException expected so far + } + + } //doOpen + + return errorCode; + } + + void CNVSendBlockMode::errChk(int code) throw (std::string*) + { + if(code != 0) + { + throw SilecsException(__FILE__, __LINE__, CNV_INTERNAL_ERROR, std::string(CNVGetErrorDescription(code))+" in CNVSendBlockMode"); + } + } + + void CNVSendDeviceMode::errChk(int code) throw (std::string*) + { + if(code != 0) + { + throw SilecsException(__FILE__, __LINE__, CNV_INTERNAL_ERROR, std::string(CNVGetErrorDescription(code))+" in CNVSendDeviceMode"); + } + } + +} // namespace +#endif //NI_SUPPORT_ENABLED diff --git a/silecs-communication-cpp/src/silecs-communication/interface/core/CNVSendAction.h b/silecs-communication-cpp/src/silecs-communication/interface/core/CNVSendAction.h new file mode 100644 index 0000000..bda46c2 --- /dev/null +++ b/silecs-communication-cpp/src/silecs-communication/interface/core/CNVSendAction.h @@ -0,0 +1,81 @@ +// Copyright 2016 CERN and GSI +// +// 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 3 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, see <http://www.gnu.org/licenses/>. + +#ifdef NI_SUPPORT_ENABLED +#ifndef _CNV_SEND_ACTION_H_ +#define _CNV_SEND_ACTION_H_ + +#include <silecs-communication/interface/core/PLCAction.h> + +namespace Silecs +{ + class Action; + class Block; + class Context; + + /*! + * \class CNVSendBlockMode + * \brief Concrete action responsible to send a data block to the CNV (Block mode configuration) + */ + class CNVSendBlockMode : public PLCAction + { + + public: + CNVSendBlockMode(Block* block); + virtual ~CNVSendBlockMode(); + + /*! + * \fn execute + * Connect the CNV if necessary and send data-block to its memory. + * Overwrite the abstract method + * \return 0 if no error occurred. else return a error status from low level library + */ + int execute(Context* pContext); + + private: + /* generate a string exception out of a CNV error code*/ + void errChk(int code) throw (std::string*); + + }; + + /*! + * \class CNVSendDeviceMode + * \brief Concrete action responsible to send a data block to the CNV (Device mode configuration) + */ + class CNVSendDeviceMode : public PLCAction + { + + public: + CNVSendDeviceMode(Block* block); + virtual ~CNVSendDeviceMode(); + + /*! + * \fn execute + * Connect the CNV if necessary and Get data-block to its memory. + * Overwrite the abstract method + * \return 0 if no error occurred. else return a error status from low level library + */ + int execute(Context* pContext); + + private: + /* generate a string exception out of a CNV error code*/ + void errChk(int code) throw (std::string*); + + }; + +} // namespace + +#endif // _CNV_SEND_ACTION_H_ +#endif //NI_SUPPORT_ENABLED diff --git a/silecs-communication-cpp/src/silecs-communication/interface/core/Context.cpp b/silecs-communication-cpp/src/silecs-communication/interface/core/Context.cpp new file mode 100644 index 0000000..a6c2de2 --- /dev/null +++ b/silecs-communication-cpp/src/silecs-communication/interface/core/Context.cpp @@ -0,0 +1,35 @@ +// Copyright 2016 CERN and GSI +// +// 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 3 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, see <http://www.gnu.org/licenses/>. + +#include <silecs-communication/interface/core/SilecsService.h> +#include <silecs-communication/interface/core/Context.h> +#include <silecs-communication/interface/equipment/SilecsDevice.h> +#include <silecs-communication/interface/utility/SilecsLog.h> + +namespace Silecs +{ + Context::Context(Device* pDev, bool isForSynchronization): + pDevice_(pDev), isForSynchro_(isForSynchronization) + { + //LOG(ALLOC) << "Context (create) for Device: " << pDevice_->getLabel() << ", isForSynchronization: " << (isForSynchro_ ? "yes" : "no"); + } + + Context::~Context() + { + //LOG(ALLOC) << "Context (delete) for Device: " << pDevice_->getLabel() << ", isForSynchronization: " << (isForSynchro_ ? "yes" : "no"); + } + +} // namespace + diff --git a/silecs-communication-cpp/src/silecs-communication/interface/core/Context.h b/silecs-communication-cpp/src/silecs-communication/interface/core/Context.h new file mode 100644 index 0000000..78fdd9e --- /dev/null +++ b/silecs-communication-cpp/src/silecs-communication/interface/core/Context.h @@ -0,0 +1,54 @@ +// Copyright 2016 CERN and GSI +// +// 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 3 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, see <http://www.gnu.org/licenses/>. + +#ifndef _CONTEXT_H_ +#define _CONTEXT_H_ + +namespace Silecs +{ + class Device; + + /*! + * \class Context + * \brief This class defines the context of the Silecs Transaction. + * A transaction can be done from Cluster or PLC levels for all-devices + * and from Device level for a particular device. + * A transaction can be executed by the client process (normal transaction) or + * can be executed at the Cluster set-up for retentive registers synchronization. + */ + class Context + { + public: + Context(Device* pDev, bool isForSynchronization); + virtual ~Context(); + + inline bool isForAllDevices() { return pDevice_ == NULL; } + inline bool isForOneDevice() { return pDevice_ != NULL; } + inline Device* getDevice() { return pDevice_; } + + inline bool isForSynchronization() { return isForSynchro_; } + + private: + /// Device reference used for Device context + Device* pDevice_; + + /// true for synchronization transaction. + /// In this case only retentive registers will be updated (Master & Slave). + bool isForSynchro_; + }; + +} // namespace + +#endif // _USER_CONTEXT_H_ diff --git a/silecs-communication-cpp/src/silecs-communication/interface/core/Diagnostic.cpp b/silecs-communication-cpp/src/silecs-communication/interface/core/Diagnostic.cpp new file mode 100644 index 0000000..373d8ed --- /dev/null +++ b/silecs-communication-cpp/src/silecs-communication/interface/core/Diagnostic.cpp @@ -0,0 +1,32 @@ +// Copyright 2016 CERN and GSI +// +// 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 3 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, see <http://www.gnu.org/licenses/>. + +#include <silecs-communication/interface/core/Diagnostic.h> + +namespace Silecs +{ + Status::Status() + { + // Device context: only one particular device to be treated + connStatus_ = Undefined; + plcStatus_ = Unknown; + } + + Status::~Status() + { + } + +} // namespace + diff --git a/silecs-communication-cpp/src/silecs-communication/interface/core/Diagnostic.h b/silecs-communication-cpp/src/silecs-communication/interface/core/Diagnostic.h new file mode 100644 index 0000000..9471b8a --- /dev/null +++ b/silecs-communication-cpp/src/silecs-communication/interface/core/Diagnostic.h @@ -0,0 +1,67 @@ +// Copyright 2016 CERN and GSI +// +// 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 3 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, see <http://www.gnu.org/licenses/>. + +#ifndef _DIAGNOSTIC_H_ +#define _DIAGNOSTIC_H_ + +#include <string> +#include <iostream> + +namespace Silecs +{ + // Possible state of the FEC/PLC/Class connection + static const std::string ConnectionStatusString[] = + { "Connected", "Disconnected", "Undefined" + }; + + typedef enum + { Connected, Disconnected, Undefined + } ConnectionStatus; + + static const std::string PLCStatusString[] = + { "On", "Off", "Unknown" + }; + + typedef enum + { On, Off, Unknown + } PLCStatus; + + /*! + * \class Status + * \brief This class is used to manage the PLC connection status + */ + class Status + { + public: + Status(); + virtual ~Status(); + + inline ConnectionStatus getConnectionStatus() { return connStatus_; } + inline PLCStatus getPLCStatus() { return plcStatus_; } + inline std::string getConnectionStatusAsString() const { return ConnectionStatusString[connStatus_]; } + inline std::string getPLCStatusAsString() const { return PLCStatusString[plcStatus_]; } + + private: + friend class PLC; + + /// Current status of the FEC/PLC/Class connection (Connected/Disconnected) + ConnectionStatus connStatus_; + /// Current status of the PLC (on/off) + PLCStatus plcStatus_; + }; + +} // namespace + +#endif // _DIAGNOSTIC_H_ diff --git a/silecs-communication-cpp/src/silecs-communication/interface/core/PLCAction.h b/silecs-communication-cpp/src/silecs-communication/interface/core/PLCAction.h new file mode 100644 index 0000000..b3fa280 --- /dev/null +++ b/silecs-communication-cpp/src/silecs-communication/interface/core/PLCAction.h @@ -0,0 +1,63 @@ +// Copyright 2016 CERN and GSI +// +// 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 3 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, see <http://www.gnu.org/licenses/>. + +#ifndef _SILECS_PLC_ACTION_H_ +#define _SILECS_PLC_ACTION_H_ + +#include <string> +#include <silecs-communication/interface/utility/Mutex.h> +#include <silecs-communication/interface/core/SilecsAction.h> + +namespace Silecs +{ + class Block; + class Context; + + /*! + * \class PLCAction + * \brief PLCAction defines the abstract level of any PLC actions (recv and send) + */ + class PLCAction: public Action + { + + public: + PLCAction(Block* block) : Action(block){ + bufferMux_ = new Mutex("bufferMux"); + }; + virtual ~PLCAction() { + delete bufferMux_; + }; + + /*! + * \fn execute + * It contains the code to be executed for this action. + * Overwrites the code from Action class + */ + virtual int execute(Context* pContext) = 0; + + protected: + //The frame buffer update (import/export registers) and related read/write data must be done + //in a critical section (the same buffer is used to send/recv data to all devices). + inline void bufferLock() { bufferMux_->lock(); } + inline void bufferUnlock() { bufferMux_->unlock(); } + + private: + Mutex* bufferMux_; + + }; + +} // namespace + +#endif // _SILECS_PLC_ACTION_H_ diff --git a/silecs-communication-cpp/src/silecs-communication/interface/core/PLCRecvAction.cpp b/silecs-communication-cpp/src/silecs-communication/interface/core/PLCRecvAction.cpp new file mode 100644 index 0000000..84f0a9b --- /dev/null +++ b/silecs-communication-cpp/src/silecs-communication/interface/core/PLCRecvAction.cpp @@ -0,0 +1,274 @@ +// Copyright 2016 CERN and GSI +// +// 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 3 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, see <http://www.gnu.org/licenses/>. + +#include <silecs-communication/interface/core/SilecsService.h> +#include <silecs-communication/interface/core/PLCAction.h> +#include <silecs-communication/interface/core/PLCRecvAction.h> +#include <silecs-communication/interface/communication/SilecsConnection.h> +#include <silecs-communication/interface/equipment/SilecsPLC.h> +#include <silecs-communication/interface/equipment/SilecsDevice.h> +#include <silecs-communication/interface/equipment/SilecsBlock.h> +#include <silecs-communication/interface/equipment/PLCBlock.h> +#include <silecs-communication/interface/core/Context.h> +#include <silecs-communication/interface/utility/SilecsLog.h> + +namespace Silecs +{ + + PLCRecvBlockMode::PLCRecvBlockMode(Block* block) : PLCAction(block) + { + if (DEBUG & Log::topics_) LOG(ALLOC) << "Action PLCRecvBlockMode (create): " << block->getName(); + } + + PLCRecvBlockMode::~PLCRecvBlockMode() + { + if (DEBUG & Log::topics_) LOG(ALLOC) << "Action PLCRecvBlockMode (delete): " << theBlock_->getName(); + } + + PLCRecvDeviceMode::PLCRecvDeviceMode(Block* block) : PLCAction(block) + { + if (DEBUG & Log::topics_) LOG(ALLOC) << "Action PLCRecvDeviceMode (create): " << theBlock_->getName(); + } + + PLCRecvDeviceMode::~PLCRecvDeviceMode() + { + if (DEBUG & Log::topics_) LOG(ALLOC) << "Action PLCRecvDeviceMode (delete): " << theBlock_->getName(); + } + + int PLCRecvBlockMode::execute(Context* pContext) + { + timeval tod; //Time-of-day for register time-stamping + int errorCode = 0; + + Connection* pConn = theBlock_->getPLC()->getConnection(); + + try + { + //if transaction is for one device only, pContext contains its reference + if (pContext->isForOneDevice()) + { + //Device context: get block of one device only ==================================== + Device* pDev = pContext->getDevice(); + + //Base attributes of the device within the complete data block containing all devices. + unsigned long usedAddress = theBlock_->getAddress(); + unsigned long usedSize = theBlock_->getMemSize(); + unsigned long usedDeviceOffset = pDev->getAddress() * usedSize; + unsigned char* pBuffer = ((unsigned char*)theBlock_->getBuffer()) + usedDeviceOffset; + + // Overwrite device-block address, offset & size in case user wants to resize the block dynamically + if (theBlock_->withCustomAttributes() == true) + { usedAddress = theBlock_->getCustomAddress(); + usedSize = theBlock_->getCustomSize(); + usedDeviceOffset = theBlock_->getCustomOffset(); + } + + if (RECV & Log::topics_) + { if (pConn->isEnabled()) + { + Log(RECV).getLog() << "RecvAction (execute/ BlockMode): " << ", device: " << pDev->getLabel() << ", block: " << theBlock_->getName(); + } + } + + bufferLock(); + + errorCode = pConn->readData( + theBlock_->getPLC(), + usedAddress, //Base address (or DBn) of the block + usedDeviceOffset, //Device data address within the block + usedSize, //Get one device-block only + pBuffer //Buffer to store the data + ); + + if (pConn->isConnected() && (errorCode == 0)) + { //Data have just been received: get time-of-day to time-stamp the registers + gettimeofday(&tod, 0); + + //Device context: Extract all the device registers from that block + pDev->importRegisters(theBlock_, pBuffer, tod, pContext); + + LOG_DELAY(RECV) << "done for block: " << theBlock_->getName(); + } + + bufferUnlock(); + + } + else + { + //Dynamic resizing of the block is not possible in BLOCK_MODE + if (theBlock_->withCustomAttributes() == true) + throw SilecsException(__FILE__, __LINE__, COMM_BLOCK_RESIZING_NOT_ALLOWED); + + deviceVectorType::iterator pDeviceIter; + deviceVectorType& deviceCol = theBlock_->getPLC()->getDeviceMap(); + + //Cluster/PLC context: get block of all devices in one go ========================= + if (RECV & Log::topics_) + { if (pConn->isEnabled()) + { + Log(RECV).getLog() << "RecvAction (execute/ BlockMode): " << theBlock_->getName() << ", " << deviceCol.size() << " device(s)"; + } + } + + bufferLock(); + + errorCode = pConn->readData( + theBlock_->getPLC(), + theBlock_->getAddress(), //Base address (or DBn) of the block + 0, //Get all devices from the first one + ((PLCBlock*)theBlock_)->getBufferSize(), //Get blocks of all devices (full buffer size) + (unsigned char*)theBlock_->getBuffer() //Buffer to store the data (full buffer) + ); + + if (pConn->isConnected() && (errorCode == 0)) + { //Data have just been received: get time-of-day to time-stamp the registers + gettimeofday(&tod, 0); + + //PLC context: Extract all registers value of all devices of the PLC from that block + for(pDeviceIter = deviceCol.begin(); pDeviceIter != deviceCol.end(); ++pDeviceIter) + { + Device* pDev = pDeviceIter->second; + unsigned long deviceOffset = pDev->getAddress() * theBlock_->getMemSize(); + unsigned char* pBuffer = ((unsigned char*)theBlock_->getBuffer()) + deviceOffset; + pDev->importRegisters(theBlock_, pBuffer, tod, pContext); + } + + LOG_DELAY(RECV) << "done for block: " << theBlock_->getName(); + } + + bufferUnlock(); + + } + } + catch (const SilecsException& ex) + { + bufferUnlock(); + LOG(ERROR) << ex.what(); + LOG(ERROR) << "RecvAction (execute/ BlockMode) for block " << theBlock_->getName() << " has failed"; + return ex.getCode(); + } + return 0; + } + + int PLCRecvDeviceMode::execute(Context* pContext) + { + timeval tod; //Time-of-day for register time-stamping + int errorCode = 0; + Connection* pConn = theBlock_->getPLC()->getConnection(); + + try + { + //if transaction is for one device only, pContext contains its reference + if (pContext->isForOneDevice()) + { + //Device context: get block of one device only ==================================== + Device* pDev = pContext->getDevice(); + + //Set base attributes of the device blocks + unsigned long usedDeviceAddress = pDev->getAddress(); + unsigned long usedBlockAddress = theBlock_->getAddress(); + unsigned long usedSize = theBlock_->getMemSize(); + + // Overwrite device-block address, offset & size in case user wants to resize the block dynamically + if (theBlock_->withCustomAttributes() == true) + { usedDeviceAddress = theBlock_->getCustomAddress(); + usedBlockAddress = theBlock_->getCustomOffset(); + usedSize = theBlock_->getCustomSize(); + } + + if (RECV & Log::topics_) + { if (pConn->isEnabled()) + { Log(RECV).getLog() << "RecvAction (execute/ DeviceMode): device: " << pDev->getLabel() << ", block: " << theBlock_->getName(); + } + } + + bufferLock(); + + errorCode = pConn->readData( + theBlock_->getPLC(), + usedDeviceAddress, //Base address (or DBn) of the device + usedBlockAddress, //Block data address within the device + usedSize, //Get one device-block only + (unsigned char*)theBlock_->getBuffer() //Buffer to store the data + ); + + if (pConn->isConnected() && (errorCode == 0)) + { //Data have just been received: get time-of-day to time-stamp the registers + gettimeofday(&tod, 0); + + //Device context: Extract all the device registers from that block + pDev->importRegisters(theBlock_, (unsigned char*)theBlock_->getBuffer(), tod, pContext); + + LOG_DELAY(RECV) << "done for block: " << theBlock_->getName(); + } + + bufferUnlock(); + + } + else + { + //Dynamic resizing of the block is not possible in multiple access + if (theBlock_->withCustomAttributes() == true) + throw SilecsException(__FILE__, __LINE__, COMM_BLOCK_RESIZING_NOT_ALLOWED); + + //Cluster/PLC context: get block of all devices one by one ========================= + deviceVectorType::iterator pDeviceIter; + deviceVectorType& deviceCol = theBlock_->getPLC()->getDeviceMap(); + for(pDeviceIter = deviceCol.begin(); pDeviceIter != deviceCol.end(); ++pDeviceIter) + { + Device* pDev = pDeviceIter->second; + + if (RECV & Log::topics_) + { if (pConn->isEnabled()) + { Log(RECV).getLog() << "RecvAction (execute/ DeviceMode): device: " << pDev->getLabel() << ", block: " << theBlock_->getName(); + } + } + + bufferLock(); + + errorCode = pConn->readData( + theBlock_->getPLC(), + pDev->getAddress(), //Base address (or DBn) of the device + theBlock_->getAddress(), //Block data address within the device + theBlock_->getMemSize(), //Get one device-block only + (unsigned char*)theBlock_->getBuffer() //Buffer to store the data + ); + + if (pConn->isConnected() && (errorCode == 0)) + { //Data have just been received: get time-of-day to time-stamp the registers + gettimeofday(&tod, 0); + + //PLC context: Extract all registers value of the current device of the PLC from that block + pDev->importRegisters(theBlock_, (unsigned char*)theBlock_->getBuffer(), tod, pContext); + + LOG_DELAY(RECV) << "done for block: " << theBlock_->getName(); + } + + bufferUnlock(); + + } + } + } + catch (const SilecsException& ex) + { + bufferUnlock(); + LOG(ERROR) << ex.what(); + LOG(ERROR) << "RecvAction (execute/ DeviceMode) failed"; + return ex.getCode(); + } + return 0; + } + +} // namespace diff --git a/silecs-communication-cpp/src/silecs-communication/interface/core/PLCRecvAction.h b/silecs-communication-cpp/src/silecs-communication/interface/core/PLCRecvAction.h new file mode 100644 index 0000000..e7bcc5a --- /dev/null +++ b/silecs-communication-cpp/src/silecs-communication/interface/core/PLCRecvAction.h @@ -0,0 +1,76 @@ +// Copyright 2016 CERN and GSI +// +// 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 3 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, see <http://www.gnu.org/licenses/>. + +#ifndef _RECV_PLC_ACTION_H_ +#define _RECV_PLC_ACTION_H_ + +#include <silecs-communication/interface/core/PLCAction.h> + +namespace Silecs +{ + class Action; + class Block; + class Context; + + /*! + * \class PLCRecvBlockMode + * \brief Concrete action responsible to get a data block from the PLC (Block mode configuration) + */ + class PLCRecvBlockMode : public PLCAction + { + + public: + PLCRecvBlockMode(Block* block); + virtual ~PLCRecvBlockMode(); + + /*! + * \fn execute + * Connect the PLC if necessary and Get data-block from its memory. + * Overwrite the abstract method + * \return 0 if no error occurred. else return a error status from low level library + */ + int execute(Context* pContext); + + private: + + }; + + /*! + * \class PLCRecvDeviceMode + * \brief Concrete action responsible to get a data block from the PLC (Device mode configuration) + */ + class PLCRecvDeviceMode : public PLCAction + { + + public: + PLCRecvDeviceMode(Block* block); + virtual ~PLCRecvDeviceMode(); + + /*! + * \fn execute + * Connect the PLC if necessary and Get data-block from its memory. + * Overwrite the abstract method + * \return 0 if no error occurred. else return a error status from low level library + */ + int execute(Context* pContext); + + private: + + }; + +} // namespace + +#endif // _RECV_PLC_ACTION_H_ + diff --git a/silecs-communication-cpp/src/silecs-communication/interface/core/PLCSendAction.cpp b/silecs-communication-cpp/src/silecs-communication/interface/core/PLCSendAction.cpp new file mode 100644 index 0000000..ff07954 --- /dev/null +++ b/silecs-communication-cpp/src/silecs-communication/interface/core/PLCSendAction.cpp @@ -0,0 +1,253 @@ +// Copyright 2016 CERN and GSI +// +// 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 3 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, see <http://www.gnu.org/licenses/>. + +#include <silecs-communication/interface/core/SilecsService.h> +#include <silecs-communication/interface/core/SilecsAction.h> +#include <silecs-communication/interface/core/PLCAction.h> +#include <silecs-communication/interface/core/PLCSendAction.h> +#include <silecs-communication/interface/communication/SilecsConnection.h> +#include <silecs-communication/interface/equipment/SilecsPLC.h> +#include <silecs-communication/interface/equipment/SilecsDevice.h> +#include <silecs-communication/interface/equipment/SilecsBlock.h> +#include <silecs-communication/interface/equipment/PLCBlock.h> +#include <silecs-communication/interface/core/Context.h> +#include <silecs-communication/interface/utility/SilecsLog.h> + +namespace Silecs +{ + + PLCSendBlockMode::PLCSendBlockMode(Block* block) : PLCAction(block) + { + if (DEBUG & Log::topics_) LOG(ALLOC) << "Action PLCSendBlockMode (constructor): " << block->getName(); + } + + PLCSendBlockMode::~PLCSendBlockMode() + { + if (DEBUG & Log::topics_) LOG(ALLOC) << "Action PLCSendBlockMode (destructor): " << theBlock_->getName(); + } + + PLCSendDeviceMode::PLCSendDeviceMode(Block* block) : PLCAction(block) + { + if (DEBUG & Log::topics_) LOG(ALLOC) << "Action PLCSendDeviceMode (constructor): " << theBlock_->getName(); + } + + PLCSendDeviceMode::~PLCSendDeviceMode() + { + if (DEBUG & Log::topics_) LOG(ALLOC) << "Action PLCSendDeviceMode (delete): " << theBlock_->getName(); + } + + int PLCSendBlockMode::execute(Context* pContext) + { + int errorCode = 0; + Connection* pConn = theBlock_->getPLC()->getConnection(); + + try + { + //if transaction is for one device only, pContext contains its reference + if (pContext->isForOneDevice()) + { + //Device context: send block of one device only ==================================== + Device* pDev = pContext->getDevice(); + + //Base attributes of the device within the complete data block containing all devices. + unsigned long usedAddress = theBlock_->getAddress(); + unsigned long usedSize = theBlock_->getMemSize(); + unsigned long usedDeviceOffset = pDev->getAddress() * usedSize; + unsigned char* pBuffer = ((unsigned char*)theBlock_->getBuffer()) + usedDeviceOffset; + + // Overwrite device-block address, offset & size in case user wants to resize the block dynamically + if (theBlock_->withCustomAttributes() == true) + { usedAddress = theBlock_->getCustomAddress(); + usedSize = theBlock_->getCustomSize(); + usedDeviceOffset = theBlock_->getCustomOffset(); + } + + bufferLock(); + + if (pConn->isEnabled()) + { LOG(SEND) << "SendAction (execute/ BlockMode): device: " << pDev->getLabel() << ", block: " << theBlock_->getName(); + + //Device context: Export all the device registers to that block + pDev->exportRegisters(theBlock_, pBuffer, pContext); + } + + errorCode = pConn->writeData( + theBlock_->getPLC(), + usedAddress, //Base address (or DBn) of the block + usedDeviceOffset, //Device data address within the block + usedSize, //Set one device-block only + pBuffer //Buffer which contain the data + ); + + bufferUnlock(); + + if (SEND & Log::topics_) + { if (pConn->isEnabled()) + { Log(SEND).getLogDelay() << "done for block: " << theBlock_->getName(); + } + } + } + else + { + //Dynamic resizing of the block is not possible in BLOCK_MODE + if (theBlock_->withCustomAttributes() == true) + throw SilecsException(__FILE__, __LINE__, COMM_BLOCK_RESIZING_NOT_ALLOWED); + + bufferLock(); + + if (pConn->isEnabled()) + { deviceVectorType::iterator pDeviceIter; + deviceVectorType& deviceCol = theBlock_->getPLC()->getDeviceMap(); + + //Cluster/PLC context: set block of all devices in one go =========================== + LOG(SEND) << "SendAction (execute/ BlockMode): block: " << theBlock_->getName() << ", " << deviceCol.size() << " device(s)"; + + //PLC context: Export all registers value of all devices of the PLC to that block + for(pDeviceIter = deviceCol.begin(); pDeviceIter != deviceCol.end(); ++pDeviceIter) + { + Device* pDev = pDeviceIter->second; + unsigned long deviceOffset = pDev->getAddress() * theBlock_->getMemSize(); + unsigned char* pBuffer = ((unsigned char*)theBlock_->getBuffer()) + deviceOffset; + pDev->exportRegisters(theBlock_, pBuffer, pContext); + } + } + + errorCode = pConn->writeData( + theBlock_->getPLC(), + theBlock_->getAddress(), //Base address (or DBn) of the block + 0, //Set all devices from the first one + ((PLCBlock*)theBlock_)->getBufferSize(), //Set blocks of all devices (full buffer size) + (unsigned char*)theBlock_->getBuffer() //Buffer which contain the data (full buffer) + ); + + bufferUnlock(); + + if (SEND & Log::topics_) + { if (pConn->isEnabled()) + { Log(SEND).getLogDelay() << "done for block: " << theBlock_->getName(); + } + } + } + } + catch (const SilecsException& ex) + { + bufferUnlock(); + LOG(ERROR) << ex.what(); + LOG(ERROR) << "SendAction (execute/ DeviceMode) on block: " << theBlock_->getName() << " has failed"; + return ex.getCode(); + } + return 0; + } + + int PLCSendDeviceMode::execute(Context* pContext) + { + Connection* pConn = theBlock_->getPLC()->getConnection(); + int errorCode = 0; + try + { + //if transaction is for one device only, pContext contains its reference + if (pContext->isForOneDevice()) + { + //Device context: set block of one device only ==================================== + Device* pDev = pContext->getDevice(); + + //Set base attributes of the device blocks + unsigned long usedDeviceAddress = pDev->getAddress(); + unsigned long usedBlockAddress = theBlock_->getAddress(); + unsigned long usedSize = theBlock_->getMemSize(); + + // Overwrite device-block address, offset & size in case user wants to resize the block dynamically + if (theBlock_->withCustomAttributes() == true) + { usedDeviceAddress = theBlock_->getCustomAddress(); + usedBlockAddress = theBlock_->getCustomOffset(); + usedSize = theBlock_->getCustomSize(); + } + + bufferLock(); + + if (pConn->isEnabled()) + { LOG(SEND) << "SendAction (execute/ DeviceMode): device: " << pDev->getLabel() << ", block: " << theBlock_->getName(); + + //Device context: Export all the device registers to that block + pDev->exportRegisters(theBlock_, (unsigned char*)theBlock_->getBuffer(), pContext); + } + + errorCode = pConn->writeData( + theBlock_->getPLC(), + usedDeviceAddress, //Base address (or DBn) of the device + usedBlockAddress, //Block data address within the device + usedSize, //Set one device-block only + (unsigned char*)theBlock_->getBuffer() //Buffer which contain the data + ); + + bufferUnlock(); + + if (SEND & Log::topics_) + { if (pConn->isEnabled()) + { Log(SEND).getLogDelay() << "done for block: " << theBlock_->getName(); + } + } + } + else + { + //Dynamic resizing of the block is not possible in multiple access + if (theBlock_->withCustomAttributes() == true) + throw SilecsException(__FILE__, __LINE__, COMM_BLOCK_RESIZING_NOT_ALLOWED); + + //Cluster/PLC context: set block of all devices one by one ========================= + deviceVectorType::iterator pDeviceIter; + deviceVectorType& deviceCol = theBlock_->getPLC()->getDeviceMap(); + for(pDeviceIter = deviceCol.begin(); pDeviceIter != deviceCol.end(); ++pDeviceIter) + { + Device* pDev = pDeviceIter->second; + + bufferLock(); + + if (pConn->isEnabled()) + { LOG(SEND) << "SendAction (execute/ DeviceMode): device: " << pDev->getLabel() << ", block: " << theBlock_->getName(); + + //PLC context: Export all registers value of the current device of the PLC to that block + pDev->exportRegisters(theBlock_, (unsigned char*)theBlock_->getBuffer(), pContext); + } + + errorCode = pConn->writeData( + theBlock_->getPLC(), + pDev->getAddress(), //Base address (or DBn) of the device + theBlock_->getAddress(), //Block data address within the device + theBlock_->getMemSize(), //Set one device-block only + (unsigned char*)theBlock_->getBuffer() //Buffer which contain the data + ); + + bufferUnlock(); + + if (SEND & Log::topics_) + { if (pConn->isEnabled()) + { Log(SEND).getLogDelay() << "done for block: " << theBlock_->getName(); + } + } + } + } + } + catch (const SilecsException& ex) + { + bufferUnlock(); + LOG(ERROR) << ex.what(); + LOG(ERROR) << "SendAction (execute/ DeviceMode) failed"; + return ex.getCode(); + } + return 0; + } + +} // namespace diff --git a/silecs-communication-cpp/src/silecs-communication/interface/core/PLCSendAction.h b/silecs-communication-cpp/src/silecs-communication/interface/core/PLCSendAction.h new file mode 100644 index 0000000..92aff05 --- /dev/null +++ b/silecs-communication-cpp/src/silecs-communication/interface/core/PLCSendAction.h @@ -0,0 +1,76 @@ +// Copyright 2016 CERN and GSI +// +// 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 3 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, see <http://www.gnu.org/licenses/>. + +#ifndef _PLC_SEND_ACTION_H_ +#define _PLC_SEND_ACTION_H_ + +#include <silecs-communication/interface/core/PLCAction.h> + +namespace Silecs +{ + class Action; + class Block; + class Context; + + /*! + * \class PLCSendBlockMode + * \brief Concrete action responsible to send a data block to the PLC (Block mode configuration) + */ + class PLCSendBlockMode : public PLCAction + { + + public: + PLCSendBlockMode(Block* block); + virtual ~PLCSendBlockMode(); + + /*! + * \fn execute + * Connect the PLC if necessary and send data-block to its memory. + * Overwrite the abstract method + * \return 0 if no error occurred. else return a error status from low level library + */ + int execute(Context* pContext); + + private: + + }; + + /*! + * \class PLCSendDeviceMode + * \brief Concrete action responsible to send a data block to the PLC (Device mode configuration) + */ + class PLCSendDeviceMode : public PLCAction + { + + public: + PLCSendDeviceMode(Block* block); + virtual ~PLCSendDeviceMode(); + + /*! + * \fn execute + * Connect the PLC if necessary and Get data-block to its memory. + * Overwrite the abstract method + * \return 0 if no error occurred. else return a error status from low level library + */ + int execute(Context* pContext); + + private: + + }; + +} // namespace + +#endif // _PLC_SEND_ACTION_H_ + diff --git a/silecs-communication-cpp/src/silecs-communication/interface/core/SilecsAction.h b/silecs-communication-cpp/src/silecs-communication/interface/core/SilecsAction.h new file mode 100644 index 0000000..4aa663d --- /dev/null +++ b/silecs-communication-cpp/src/silecs-communication/interface/core/SilecsAction.h @@ -0,0 +1,54 @@ +// Copyright 2016 CERN and GSI +// +// 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 3 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, see <http://www.gnu.org/licenses/>. + +#ifndef _SILECS_ACTION_H_ +#define _SILECS_ACTION_H_ + +#include <string> + +namespace Silecs +{ + class Block; + class Context; + + /*! + * \class Action + * \brief Action defines the abstract level of any action + */ + class Action + { + + public: + Action(Block* block) : theBlock_(block) {}; + virtual ~Action() {}; + + /*! + * \fn execute + * It contains the code to be executed for this action. + * Has to be overriden for concrete PLC action. + * \return 0 if no error occurred. else return a error status from low level library + */ + virtual int execute(Context* pContext) = 0; + + protected: + /// Parent block reference of that action + Block* theBlock_; + + }; + +} // namespace + +#endif // _SILECS_ACTION_H_ + diff --git a/silecs-communication-cpp/src/silecs-communication/interface/core/SilecsService.cpp b/silecs-communication-cpp/src/silecs-communication/interface/core/SilecsService.cpp new file mode 100644 index 0000000..82774b4 --- /dev/null +++ b/silecs-communication-cpp/src/silecs-communication/interface/core/SilecsService.cpp @@ -0,0 +1,283 @@ +// Copyright 2016 CERN and GSI +// +// 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 3 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, see <http://www.gnu.org/licenses/>. + +#include <silecs-communication/interface/equipment/SilecsCluster.h> +#include <silecs-communication/interface/utility/SilecsLog.h> +#include <silecs-communication/interface/utility/XMLParser.h> +#include <silecs-communication/interface/utility/StringUtilities.h> +#include <unistd.h> + +/* ---------------------------------------------------------------------- + * RELEASE + * 3.1.0: initial + * 3.2.0: Code refactor to easily integrate new hardware equipment; + * NI via shared library supported (32 bit only); + * 64bits CPU support (for SLC6 migration); + * 3.2.1: Missing and safe free (Mutex, Thread) + * Safe free in libS7 + * Fix in libS7: + * Do not recv/send empty packet in case of data-size multiple frame size. + * 3.3.0: Library Conditional compilation WITH_CHN={YES/NO} + * Silecsop is editor of each design and deploy + * SVN Support (can be enable from ieglobal.py) + * Automated compilation procedure + * CNV receive via buffer subscriber + * 3.3.1: Fix memory leak using correct disposal of CNV data + * 3.4.0: Support Rabbit Microcontroller via MB connection. + * MB read baseAddress instead of address 000 at connection time. + * 3.4.1: FIX: consider uint8 as numeric and int8 as ASCII value while setting register value + * 3.5.0: FIX: add missing method to allow dynamic resizing of the send/recv data-block. + * Look at: PLC::[set/reset][Read/Write]BlockAttributes() methods and related components (SilecsPLC.h) + * 3.5.1: FIX: Dynamic resizing didn't work properly with SCHNEIDER using BLOKC-MODE. + * Full custom adressing is required to fix the problem. + * 3.6.0: FEATURE: Input arguments setting for FESA3 development. + * 3.7.0: Support Beckhoff PLC via MB connection. + * FIX: single init/cleanup of libxml2 (not reentrant) + * 3.8.5: Look at release 3.8.5 content + * 3.8.6: Look at release 3.8.6 content + * --------------------------------------------------------------------*/ + + +/* ********************************************************************** + * Global data definition related to the software install and versioning + * Must be up-to-date for each release in connection with others packages + * (Java tool and Environment software (Python scripts, ..) + * ********************************************************************** + */ +#ifndef MAJOR + #error "Silecs::Service: MAJOR SYMBOL NOT DEFINED! Make sure to define symbols MAJOR, MINOR and PATCH in your Makefile." +#endif + +namespace Silecs +{ +#define STRINGIFY2(X) #X +#define STRINGIFY(X) STRINGIFY2(X) + + //Semantic versioning for SILECS packages (Tools, Environment and client library have consistent major number) + const std::string Service::semverMajor_ = STRINGIFY(MAJOR); //Major release, not backward compatible + const std::string Service::semverMinor_ = STRINGIFY(MINOR); //Minor release, backward compatible + const std::string Service::semverPatch_ = STRINGIFY(PATCH); //Bug fixes, backward compatible + + +} // namespace + +/* ********************************************************************** + * ********************************************************************** + */ +namespace Silecs +{ + // static definition + Service* Service::instance_ = NULL; + bool Service::isShutingDown_ = false; + + Service* Service::getInstance(int argc, char ** argv) + { + if (instance_ == NULL) + { + instance_ = new Service(argc, argv); + LOG((ALLOC|DIAG)) << "SILECS Service create"; + + XMLParser::init(); + + //ACET start-up message (once per process) + TRACE("process") << "Version=" << semverMajor_ << "." << semverMinor_ << "." << semverPatch_; + } + return instance_; + } + + void Service::deleteInstance() + { + if (!isShutingDown_) + { isShutingDown_ = true; + LOG((ALLOC|DIAG)) << "SILECS Resources release"; + + XMLParser::init(); + + if (instance_ != NULL) delete instance_; + instance_ = NULL; + } + } + + void Service::setArguments(std::string usrArgs) + { + size_t pos = usrArgs.find("-plcLog"); + if (pos != std::string::npos) + { std::string topics = usrArgs.substr(pos+8); + char *argv[3] = { (char*)"dummy", (char*)"-plcLog", (char*)topics.c_str() }; + if (setArgs(3, argv) == false) + { throw SilecsException(__FILE__, __LINE__, PARAM_INCORRECT_ARGUMENTS); + } + } + } + + bool Service::setLogTopics(std::string topics) + { + bool isOK = Log::getTopicsFromString(topics); + return isOK; + } + + Service::Service(int argc, char ** argv) + { + isShutingDown_ = false; + + //Default client process name (in case arguments are not transmitted) + char *ident = (char*)"SILECS-Client"; + + //Start the sys-logger at first + if (argc>0) + { //Real process name + ident = basename(argv[0]); + } + + //No particular topics to log to syslog in addition to the mandatory ones (if any) + Log::startSyslog(ident, 0); + + //Then, interpret and set the 'plc' parameters of the command line, if any + if ((argc>0) && (argv != NULL)) + { + if (setArgs(argc, argv) == false) + { printArgs(); + /* or as following if required + std::cerr << std::endl; + std::cerr << "PLC expected arguments: " << std::endl; + std::cerr << Silecs::whichArgs() << std::endl; + */ + throw SilecsException(__FILE__, __LINE__, PARAM_INCORRECT_ARGUMENTS); + } + } + } + + Service::~Service() + { + //Disconnect and remove all shared-connection if any (one per PLC) + PLC::deleteConnection(); + + // Remove all the Cluster instances of this SILECS Service + clusterMapType::iterator clusterMapIter; + for(clusterMapIter = clusterMap_.begin(); clusterMapIter != clusterMap_.end(); clusterMapIter++) + { delete clusterMapIter->second; + } + clusterMap_.clear(); + + //close the syslog resource + Log::stopSyslog(); + } + + + Cluster* Service::getCluster(std::string className, std::string classVersion) + { + std::string clusterName = className + "_" + classVersion; + clusterMapType::iterator iter = clusterMap_.find(clusterName); + if (iter == clusterMap_.end()) + { + // Does not exist yet, create a new one for this className + Cluster* theCluster = new Cluster(className, classVersion); + clusterMap_.insert(std::make_pair(clusterName, theCluster)); + return theCluster; + } + // Already created, return the unique reference + return iter->second; + } + + + std::string Service::getSemverMajor() + { + return semverMajor_; + } + + std::string Service::getSemverMinor() + { + return semverMinor_; + } + + std::string Service::getSemverPatch() + { + return semverPatch_; + } + + SynchroType Service::whichSynchroType(std::string type) + { + StringUtilities::toLower(type); + if (type == "master") return Master; + else if (type == "slave") return Slave; + else if (type == "none") return No; + else throw SilecsException(__FILE__, __LINE__, DATA_UNKNOWN_SYNCHRO_TYPE, type); + } + + bool Service::withInputAccess(AccessType& accessType) + { return (accessType != Output); + } + + bool Service::withOutputAccess(AccessType& accessType) + { return (accessType != Input); + } + + bool Service::fileExists(std::string filename) + { + struct stat fileInfo; + + // Attempt to get the file attributes + if (stat(filename.c_str(),&fileInfo) == 0) + { //No error: the file exists + return true; + } + else + { + if (errno == ENOENT) + { //No such file or directory + return false; + } + } + //Unexpected error + throw SilecsException(__FILE__, __LINE__, errno, strerror(errno)); + } + + bool Service::checkArgs(int argc, char ** argv) + { + if ((argc>=2) && (argv != NULL)) + { for(int i=0; i< argc; i++) + if(strcmp(argv[i], "-plcHelp") == 0) return false; + } + return true; //help is not required + } + + bool Service::setArgs(int argc, char ** argv) + { + if (checkArgs(argc, argv)) + if (Log::setLogArguments(argc, argv)) + //if .. + //if .. + return true; + return false; + } + + std::string Service::whichArgs() + { + return std::string("-plcHelp") + std::string("\n") + + Log::getLogArguments() + std::string("\n") + // + .. + ; + } + + void Service::printArgs() + { + std::cerr << std::endl; + std::cerr << "SILECS expected arguments: " << std::endl; + std::cerr << whichArgs() << std::endl; + } + +} // namespace + + diff --git a/silecs-communication-cpp/src/silecs-communication/interface/core/SilecsService.h b/silecs-communication-cpp/src/silecs-communication/interface/core/SilecsService.h new file mode 100644 index 0000000..3eb7c8b --- /dev/null +++ b/silecs-communication-cpp/src/silecs-communication/interface/core/SilecsService.h @@ -0,0 +1,182 @@ +// Copyright 2016 CERN and GSI +// +// 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 3 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, see <http://www.gnu.org/licenses/>. + +#ifndef _SILECS_SERVICE_H_ +#define _SILECS_SERVICE_H_ + +#include <sys/types.h> +#include <sys/stat.h> +#include <unistd.h> +#include <errno.h> +#include <set> +#include <map> + +namespace Silecs +{ + // Register and Block synchronization type + typedef enum + { Master, Slave, No + } SynchroType; + + /// @cond + // Register and Block access types + typedef enum + { + Output, Input, InOut + } AccessType; + /// @endcond + + /*! + * \brief Defines the category of the SILECS Exception. + * Can be used in the Exception catch to dispatch emergency actions. + * Use Exception::getCategory() to retrieve it. + */ + typedef enum + { + ///Default mode: Do not synchronize the retentive Registers at the PLC connection + NO_SYNCHRO = 0, + ///Synchronize the Master Registers at the PLC connection (downloaded from the PLC) + MASTER_SYNCHRO = 1, + ///Synchronize the Slave Registers at the PLC connection (uploaded from the client) + SLAVE_SYNCHRO = 2, + ///Synchronize all the retentive Registers at the PLC connection (download Masters and upload Slaves) + FULL_SYNCHRO = 3, + } SynchroMode; +} + +#include <silecs-communication/interface/equipment/CNVRegister.h> +#include <silecs-communication/interface/equipment/SilecsCluster.h> +#include <silecs-communication/interface/equipment/SilecsPLC.h> +#include <silecs-communication/interface/equipment/SilecsDevice.h> +#include <silecs-communication/interface/equipment/SilecsRegister.h> +#include <silecs-communication/interface/equipment/PLCRegister.h> +#include <silecs-communication/interface/utility/SilecsException.h> + +namespace Silecs +{ + /// @cond + typedef std::map<std::string, Cluster*> clusterMapType; + /// @endcond + + /*! + * \class Service + * \brief This class is the entry point of the SILECS service. + * Service class is a singleton that the client process must instantiate at first. + * It provides services to set-up the general tasks (set process arguments for instance) + * and create the required PLC Clusters and related resources of each SILECS class: + * PLC, Device and Register. + */ + class Service + { + + public: + /*! + * \brief Use this method to create/get the unique process instance of the SILECS Service. + * By creating that object it's possible to transmit specific arguments to the SILECS Service, + * typically the SILECS logging options: + * -plcLog ERROR[,INFO,DEBUG,SETUP,ALLOC,RECV,SEND,COMM,DATA,LOCK] + * + * (argc=0, argv=NULL) means no arguments for SILECS Service + */ + static Service* getInstance(int argc=0, char ** argv=NULL); + + /*! + * \brief This method releases all the SILECS resources and finally removes + * the Service singleton itself. + * Attention! This method is responsible to disconnect all the PLCs but mostly to remove + * all the SILECS resources (Clusters and related components: PLCs, Devices, Registers, ..) + * Client implementation must ensure that no process is currently accessing to + * these resources before calling. + */ + static void deleteInstance(); + + /*! + * \brief Use this method to either get an existing Cluster object, + * or to create a new one for a given className/version, if not existing. + * The client is responsible to delete all the Cluster instances and related + * components by deleting the Service object. + * \param className name of the class + * \param classVersion version number of the class + * \return reference to the unique Cluster instance for this class/version + */ + Silecs::Cluster* getCluster(std::string className, std::string classVersion); + + + /*! + * \brief Use this method to get the library Semantic version (Major) + * \return the Major number of the current release: <Major>.<Minor>.<Patch> + */ + static std::string getSemverMajor(); + + /*! + * \brief Use this method to get the library Semantic version (Minor) + * \return the Minor number of the current release: <Major>.<Minor>.<Patch> + */ + static std::string getSemverMinor(); + + /*! + * \brief Use this method to get the library Semantic version (Patch) + * \return the Patch number of the current release: <Major>.<Minor>.<Patch> + */ + static std::string getSemverPatch(); + + /*! + * \brief Use this method to propagate the input arguments to the SILECS library (-plcLog in particular) + */ + void setArguments(std::string usrArgs); + + /// @cond + // TODO: For python Diagnostic only, to be improved + bool setLogTopics(std::string topics); + /// @endcond + + private: + friend class PLC; + friend class Block; + friend class Register; + friend class PLCRegister; + friend class CNVRegister; + + Service(int argc, char ** argv); + virtual ~Service(); + + bool checkArgs(int argc, char ** argv); + bool setArgs(int argc, char ** argv); + std::string whichArgs(); + void printArgs(); + + static const std::string getParamsFilesPath(); + static SynchroType whichSynchroType(std::string type); + static bool withInputAccess(AccessType& accessType); + static bool withOutputAccess(AccessType& accessType); + static bool fileExists(std::string filename); + + /// Cluster collection of the Service + clusterMapType clusterMap_; + + //unique instance of the Silecs service + static Service* instance_; + + //Semantic versioning for SILECS packages (Tools, Environment and client library consistency) + static const std::string semverMajor_; //Major release, not backward compatible + static const std::string semverMinor_; //Minor release, backward compatible + static const std::string semverPatch_; //Bug fixes, backward compatible + + static bool isShutingDown_; + }; + +} // namespace + +#endif // _SILECS_SERVICE_H_ diff --git a/silecs-communication-cpp/src/silecs-communication/interface/core/WrapperAction.h b/silecs-communication-cpp/src/silecs-communication/interface/core/WrapperAction.h new file mode 100644 index 0000000..f6f8870 --- /dev/null +++ b/silecs-communication-cpp/src/silecs-communication/interface/core/WrapperAction.h @@ -0,0 +1,55 @@ +// Copyright 2016 CERN and GSI +// +// 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 3 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, see <http://www.gnu.org/licenses/>. + +#ifndef _WRAPPER_ACTION_H_ +#define _WRAPPER_ACTION_H_ + +#include <silecs-communication/interface/core/SilecsAction.h> + +namespace Silecs +{ + class Context; + + /*! + * \class WrapperAction + * \brief + */ + class WrapperAction + { + + public: + WrapperAction() {}; + WrapperAction(Action* plcAction) : pAction_(plcAction) {}; + virtual ~WrapperAction() {}; + + /*! + * \fn function + * It contains the code to be executed for this action. + * Has to be overriden for concrete PLC action. + */ + static int function(WrapperAction plcWrapperAction, Context* pContext) + { + return plcWrapperAction.pAction_->execute(pContext); + } + + private: + Action *pAction_; + + }; + +} // namespace + +#endif // _WRAPPER_ACTION_H_ + diff --git a/silecs-communication-cpp/src/silecs-communication/interface/equipment/CNVBlock.cpp b/silecs-communication-cpp/src/silecs-communication/interface/equipment/CNVBlock.cpp new file mode 100644 index 0000000..53080f5 --- /dev/null +++ b/silecs-communication-cpp/src/silecs-communication/interface/equipment/CNVBlock.cpp @@ -0,0 +1,346 @@ +// Copyright 2016 CERN and GSI +// +// 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 3 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, see <http://www.gnu.org/licenses/>. + +#ifdef NI_SUPPORT_ENABLED +#include "CNVBlock.h" + +#include <silecs-communication/interface/core/SilecsService.h> +#include <silecs-communication/interface/utility/Thread.h> +#include <silecs-communication/interface/utility/XMLParser.h> +#include <silecs-communication/interface/equipment/SilecsPLC.h> +#include <silecs-communication/interface/equipment/SilecsBlock.h> +#include <silecs-communication/interface/equipment/SilecsRegister.h> +#include <silecs-communication/interface/core/SilecsAction.h> +#include <silecs-communication/interface/core/CNVRecvAction.h> +#include <silecs-communication/interface/core/CNVSendAction.h> +#include <silecs-communication/interface/core/WrapperAction.h> +#include <silecs-communication/interface/utility/SilecsException.h> +#include <silecs-communication/interface/utility/SilecsLog.h> +#include <silecs-communication/interface/utility/StringUtilities.h> + +namespace Silecs +{ + + /* Check for errors */ + void CNVBlock::errChk(int code) + { + if(code != 0) + { + LOG(DEBUG) << "CNV Exception raised: " << std::string(CNVGetErrorDescription(code)); + throw SilecsException(__FILE__, __LINE__, CNV_INTERNAL_ERROR, std::string(CNVGetErrorDescription(code))+" in block "+ name_); + } + } + + //------------------------------------------------------------------------------------------- + //------ CNVBlock + //------------------------------------------------------------------------------------------- + + CNVBlock::CNVBlock(PLC* thePLC, ElementXML blockNode, AccessType accessType): + Block(thePLC, blockNode,accessType) + { + // associate buffer pointer with created buffer + pBuffer_ = (CNVData*)& buffer_; + } + + CNVBlock::~CNVBlock() + { + } + + //------------------------------------------------------------------------------------------- + //------ CNVInputBlock + //------------------------------------------------------------------------------------------- + + CNVInputBlock::CNVInputBlock(PLC* thePLC, ElementXML blockNode, AccessType accessType) : + CNVBlock(thePLC, blockNode, accessType) + { + if (DEBUG & Log::topics_) LOG(ALLOC) << "Block (create): " << name_ << ", CNV: " << getPLC()->getName() << ", access: Input" << ", hasMaster: " << (hasMasterRegister() ? "yes" : "no") << ", hasSlave: " << (hasSlaveRegister() ? "yes" : "no") << ", address: " << address_ << ", mem-size: " << memSize_ ;//<< ", buffer-size: " << bufferSize_; + + handle_ = NULL; + subscriptionFlag_ = false; + + // Creates receive task which relies on the block exchange + if (getPLC()->getProtocolID() == BlockMode) + pAction_ = new CNVRecvBlockMode(this, name_ + "_" + getPLC()->getName()); + else + pAction_ = new CNVRecvDeviceMode(this, name_ + "_" + getPLC()->getName()); + + WrapperAction wrapperAction(pAction_); + pTask_ = new Task<WrapperAction>(WrapperAction::function, wrapperAction); + } + + CNVInputBlock::~CNVInputBlock() + { + } + + bool CNVInputBlock::doSubscribe() + { + if(!subscriptionFlag_) + { + LOG(ALLOC) << "CNVInputBlock::doSubscribe (create-buffer):" << name_ << std::endl; + + int numberOfDevice = thePLC_->getDeviceMap().size(); + handle_ = (CNVBufferedSubscriber*)calloc(numberOfDevice,sizeof(CNVBufferedSubscriber)); + + subscriptionFlag_ = true; //subscription is fine a priori + + deviceVectorType::iterator pDeviceIter; + int i=0; + for(pDeviceIter = thePLC_->getDeviceMap().begin(); pDeviceIter != thePLC_->getDeviceMap().end(); ++pDeviceIter) + { + + std::string blockAddress = "\\\\"+thePLC_->getName()+"\\'" + +thePLC_->theCluster_->getClassName()+"-"+thePLC_->theCluster_->getClassVersion()+"'\\" + + pDeviceIter->second->getLabel()+"\\"+name_; + + LOG(DEBUG) << "doSubscribe(): Subscribing to address: " << blockAddress; + + int code = CNVCreateBufferedSubscriber(blockAddress.c_str(), 0 , 0, 2, CNVWaitForever, 0, &handle_[i]); + + if(code != 0) + { LOG(DEBUG) << "doSubscribe(): CNV Exception raised: " << std::string(CNVGetErrorDescription(code)); + unSubscribe(); //dispose subscription resources if any and update subscriptionFlag_ + break; + } + i++; + } + } + return subscriptionFlag_; + } + + void CNVInputBlock::unSubscribe() + { + if(handle_!=NULL) + { + LOG(ALLOC) << "CNVInputBlock::unSubscribe (dispose):" << name_ << std::endl; + + for(unsigned int i=0; i<thePLC_->getDeviceMap().size(); i++) + { + int code = CNVDispose(handle_[i]); + if(code != 0) + { LOG(DEBUG) << "unSubscribe(): CNV Exception raised: " << std::string(CNVGetErrorDescription(code)); + break; + } + } + free(handle_); + handle_ = NULL; + subscriptionFlag_ = false; + } + } + + + CNVBufferedSubscriber* CNVInputBlock::getHandle(std::string deviceName) + { + int i=0; + deviceVectorType::iterator pDeviceIter; + for(pDeviceIter = thePLC_->getDeviceMap().begin(); pDeviceIter != thePLC_->getDeviceMap().end(); ++pDeviceIter) + { + if(pDeviceIter->second->getLabel()==deviceName) + return &handle_[i]; + i++; + } + return NULL; + } + + //------------------------------------------------------------------------------------------- + //------ CNVOutputBlock + //------------------------------------------------------------------------------------------- + void CNVOutputBlock::createDataValue(Silecs::Register* regRef, CNVData* builderRef) + { + if(regRef->isScalar()) + { // allocate space for a scalar + switch(regRef->getFormat()) + { + /* type Buffer element CNVType DefaultValue*/ + case uInt8: { errChk(CNVCreateScalarDataValue(builderRef, CNVUInt8, 0 )); break; } + case Int8: { errChk(CNVCreateScalarDataValue(builderRef, CNVInt8, 0 )); break; } + case uInt16: { errChk(CNVCreateScalarDataValue(builderRef, CNVUInt16, 0 )); break; } + case Int16: { errChk(CNVCreateScalarDataValue(builderRef, CNVInt16, 0 )); break; } + case uInt32: { errChk(CNVCreateScalarDataValue(builderRef, CNVUInt32, 0 )); break; } + case Int32: { errChk(CNVCreateScalarDataValue(builderRef, CNVInt32, 0 )); break; } + case uInt64: { errChk(CNVCreateScalarDataValue(builderRef, CNVUInt64, 0 )); break; } + case Int64: { errChk(CNVCreateScalarDataValue(builderRef, CNVInt64, 0 )); break; } + case Float32: { errChk(CNVCreateScalarDataValue(builderRef, CNVSingle, 0 )); break; } + case Float64: { errChk(CNVCreateScalarDataValue(builderRef, CNVDouble, 0 )); break; } + // CNV does not support date. Double is used instead + case Date: { errChk(CNVCreateScalarDataValue(builderRef, CNVDouble, 0 )); break; } + case String: { errChk(CNVCreateScalarDataValue(builderRef, CNVString, "" )); break; } + } + } + else + { //allocate space for an array (up to 2 dimensions) + long unsigned int dimension[2]; + dimension[0] = regRef->getDimension1(); + dimension[1] = regRef->getDimension2(); + long unsigned int flatDimension = dimension[0] * dimension[1]; + void* array; + + switch(regRef->getFormat()) + { + /* type Buffer element CNVType array? Dimensions*/ + case uInt8: + { + array = (uint8_t*)calloc(flatDimension,sizeof(uint8_t)); + errChk(CNVCreateArrayDataValue(builderRef, CNVInt8, array ,2 , dimension)); + break; + } + case Int8: + { + array = (int8_t*)calloc(flatDimension,sizeof(int8_t)); + errChk(CNVCreateArrayDataValue(builderRef, CNVUInt8, array ,2 , dimension)); + break; + } + case uInt16: + { + array = (uint16_t*)calloc(flatDimension,sizeof(uint16_t)); + errChk(CNVCreateArrayDataValue(builderRef, CNVUInt16, array ,2 , dimension)); + break; + } + case Int16: + { + array = (int16_t*)calloc(flatDimension,sizeof(int16_t)); + errChk(CNVCreateArrayDataValue(builderRef, CNVInt16, array ,2 , dimension)); + break; + } + case uInt32: + { + array = (uint32_t*)calloc(flatDimension,sizeof(uint32_t)); + errChk(CNVCreateArrayDataValue(builderRef, CNVUInt32, array ,2 , dimension)); + break; + } + case Int32: + { + array = (int32_t*)calloc(flatDimension,sizeof(int32_t)); + errChk(CNVCreateArrayDataValue(builderRef, CNVInt32, array ,2 , dimension)); + break; + } + case uInt64: + { + array = (uint64_t*)calloc(flatDimension,sizeof(uint64_t)); + errChk(CNVCreateArrayDataValue(builderRef, CNVUInt64, array ,2 , dimension)); + break; + } + case Int64: + { + array = (int64_t*)calloc(flatDimension,sizeof(int64_t)); + errChk(CNVCreateArrayDataValue(builderRef, CNVInt64,array ,2 , dimension)); + break; + } + case Float32: + { + array = (float*)calloc(flatDimension,sizeof(float)); + errChk(CNVCreateArrayDataValue(builderRef, CNVSingle, array ,2 , dimension)); + break; + } + case Float64: + { + array = (double*)calloc(flatDimension,sizeof(double)); + errChk(CNVCreateArrayDataValue(builderRef, CNVDouble, array ,2 , dimension)); + break; + } + case Date: + { + array = (double*)calloc(flatDimension,sizeof(double)); + errChk(CNVCreateArrayDataValue(builderRef, CNVDouble, array ,2 , dimension)); + break; + } + case String: + { + array = (char*)calloc(flatDimension,sizeof(char*)); + errChk(CNVCreateArrayDataValue(builderRef, CNVString, array ,2 , dimension)); + break; + } + } + free(array); + } + } + + CNVOutputBlock::CNVOutputBlock(PLC* thePLC, ElementXML blockNode, AccessType accessType) : + CNVBlock(thePLC, blockNode, accessType) + { + if (DEBUG & Log::topics_) LOG(ALLOC) << "Block (create): " << name_ << ", CNV: " << getPLC()->getName() << ", access: Output" << ", hasMaster: " << (hasMasterRegister() ? "yes" : "no") << ", hasSlave: " << (hasSlaveRegister() ? "yes" : "no") << ", address: " << address_ << ", mem-size: " << memSize_;// << ", buffer-size: " << bufferSize_; + + /* ALLOCATE THE BUFFER */ + deviceVectorType deviceCol = thePLC->getDeviceMap(); + Device* currentDev = deviceCol[0].second; + std::vector<Register*> regCol = currentDev->getRegisterCollection(name_); + + //Allocate the CNVStruct for the buffer + int numberOfReg = regCol.size(); + CNVData *structBuilder = (CNVData*)calloc(numberOfReg,sizeof(CNVData)); //allocate space for number of register in the block + + // Creates send task which relies on the block exchange + if (getPLC()->getProtocolID() == BlockMode) + { + // ALLOCATE A OUTPUT BLOCK IN BLOCK MODE + int numberOfDevice = thePLC->getDeviceMap().size(); + + CNVData *arrayBuilder = (CNVData*)calloc(numberOfDevice,sizeof(CNVData)*numberOfReg); //allocate space for number of device in the device array + + for(int j=0;j<numberOfDevice;j++) + { + // for each register in the current block + for(int i=0;i<numberOfReg;i++) + { + createDataValue(regCol[i], &structBuilder[i]); + } + + errChk(CNVCreateStructDataValue (&arrayBuilder[j], // data handler + structBuilder, // input structure + numberOfReg)); // number of fields + } + + long unsigned int dimensions[1] = {numberOfDevice}; + errChk(CNVCreateArrayDataValue (&buffer_, // data handler + CNVStruct, // array type + arrayBuilder, // input array + 1, // mono-dimensional array + dimensions)); // array length + + pAction_ = new CNVSendBlockMode(this, name_ + "_" + getPLC()->getName()); + + free(arrayBuilder); + } + else + { + // ALLOCATE A OUTPUT BLOCK IN DEVICE MODE + // for each register in the current block + for(int i=0;i<numberOfReg;i++) + { + createDataValue(regCol[i], &structBuilder[i]); + } + errChk(CNVCreateStructDataValue (&buffer_, // data handler + structBuilder, // input structure + numberOfReg)); // number of fields + + pAction_ = new CNVSendDeviceMode(this, name_ + "_" + getPLC()->getName()); + } + + for(int i=0;i<numberOfReg;i++) // TO check if works + CNVDisposeData(structBuilder[i]); + + free(structBuilder); + + WrapperAction wrapperAction(pAction_); + pTask_ = new Task<WrapperAction>(WrapperAction::function, wrapperAction); + } + + CNVOutputBlock::~CNVOutputBlock() + { + if (DEBUG & Log::topics_) LOG(ALLOC) << "CNVOutputBlock (delete): " << name_; + + CNVDisposeData(*((CNVData*)pBuffer_)); + } +} +#endif //NI_SUPPORT_ENABLED diff --git a/silecs-communication-cpp/src/silecs-communication/interface/equipment/CNVBlock.h b/silecs-communication-cpp/src/silecs-communication/interface/equipment/CNVBlock.h new file mode 100644 index 0000000..4f84afc --- /dev/null +++ b/silecs-communication-cpp/src/silecs-communication/interface/equipment/CNVBlock.h @@ -0,0 +1,109 @@ +// Copyright 2016 CERN and GSI +// +// 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 3 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, see <http://www.gnu.org/licenses/>. + +#ifdef NI_SUPPORT_ENABLED +#ifndef _SILECS_CNV_BLOCK_H_ +#define _SILECS_CNV_BLOCK_H_ + +#include <silecs-communication/interface/core/SilecsService.h> +#include <silecs-communication/interface/utility/Thread.h> +#include <silecs-communication/interface/equipment/SilecsBlock.h> + +#ifdef __cplusplus +extern "C" { +#endif + +#include <nilibnetv.h> + +#ifdef __cplusplus +} +#endif + +namespace Silecs +{ + + class CNVBlock : public Block + { + + public: + CNVBlock(PLC* thePLC, ElementXML blockNode, AccessType accessType); + ~CNVBlock(); + + protected: + // Check for CNV errors, log and create an exception + void errChk(int code); + + friend class Device; + CNVData buffer_; + }; + + /*! ----------------------------------------------------------------------- + * \class InputBlock + * \brief This is a specific Block for Acquisition data (from NI to client) + */ + class CNVInputBlock : public CNVBlock + { + + public: + CNVInputBlock(PLC* thePLC, ElementXML blockNode, AccessType accessType); + virtual ~CNVInputBlock(); + + /*! + * \brief Creates subscription + * Allocates memory for the subscriber, subscribes. + * if subscription was already in place does nothing. + * \return True if subscription (all variables) is successful. + */ + bool doSubscribe(); + + /*! + * \brief Delete subscription + * Free memory for the subscriber, and unsubscribe. + */ + void unSubscribe(); + + /*! + * \brief Get buffer Handler + * Return a pointer to the buffer for current block / required device + * \param deviceName device name as a string + * \return pointer to the handler buffer + */ + CNVBufferedSubscriber* getHandle(std::string deviceName); + + private: + // Handler + CNVBufferedSubscriber *handle_; + // Flag to avoid creating multiple buffer subscriber to the same block + bool subscriptionFlag_; + }; + + /*! ----------------------------------------------------------------------- + * \class OutputBlock + * \brief This is a specific Block for Settings (from client to NI) + */ + class CNVOutputBlock : public CNVBlock + { + + public: + CNVOutputBlock(PLC* thePLC, ElementXML blockNode, AccessType accessType); + virtual ~CNVOutputBlock(); + private: + void createDataValue(Silecs::Register* regRef, CNVData* builderRef); + }; + +} // namespace + +#endif // _SILECS_BLOCK_H_ +#endif //NI_SUPPORT_ENABLED diff --git a/silecs-communication-cpp/src/silecs-communication/interface/equipment/CNVRegister.cpp b/silecs-communication-cpp/src/silecs-communication/interface/equipment/CNVRegister.cpp new file mode 100644 index 0000000..d27cdd3 --- /dev/null +++ b/silecs-communication-cpp/src/silecs-communication/interface/equipment/CNVRegister.cpp @@ -0,0 +1,784 @@ +// Copyright 2016 CERN and GSI +// +// 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 3 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, see <http://www.gnu.org/licenses/>. + +#ifdef NI_SUPPORT_ENABLED +#include "CNVRegister.h" + +namespace Silecs +{ + // Constructor from super class + CNVRegister::CNVRegister(Device* theDevice, ElementXML* pDesignEl) : Register(theDevice, pDesignEl) + { + } + + // Specialized Destructor + CNVRegister::~CNVRegister() + { + + } + + /* Check for errors */ + void CNVRegister::errChk(int code) + { + if(code != 0) + { + LOG(DEBUG) << "CNV Exception raised: " << CNVGetErrorDescription(code); + throw SilecsException(__FILE__, __LINE__, CNV_INTERNAL_ERROR, std::string(CNVGetErrorDescription(code))+" in register "+ name_); + } + } + + template <typename T> + inline void CNVRegister::swapInputArray2D(FormatType F, uint32_t dim1, uint32_t dim2) + { + T *temp = (T*)calloc(dim1*dim2, size_); + unsigned long i = 0; + unsigned long index = 0; + for (unsigned long j=0; j < dimension1_; j++) + { + i = j; + while(i < (dimension1_*dimension2_)) + { + temp[index] = ((T*)pRecvValue_)[i]; + index++; + i += dimension1_; + } + } + + memcpy(pRecvValue_, (void *)temp, size_*dimension1_*dimension2_); + free(temp); + } + + template <typename T> + inline void CNVRegister::swapOutputArray2D(FormatType F, uint32_t dim1, uint32_t dim2) + { + T *temp = (T*)calloc(dim1*dim2, size_); + unsigned long i = 0; + unsigned long index = 0; + for (unsigned long j=0; j < dimension2_; j++) + { + i = j; + while(i < (dimension1_*dimension2_)) + { + temp[index] = ((T*)pSendValue_)[i]; + index++; + i += dimension2_; + } + } + + memcpy(pSendValue_, (void *)temp, size_*dimension1_*dimension2_); + free(temp); + } + + void CNVRegister::swapInputUInt8Array2D(uint32_t dim1, uint32_t dim2) {swapInputArray2D<uint8_t>(uInt8, dim1, dim2); } + void CNVRegister::swapInputInt8Array2D(uint32_t dim1, uint32_t dim2) {swapInputArray2D<int8_t>(Int8, dim1, dim2); } + void CNVRegister::swapInputUInt16Array2D(uint32_t dim1, uint32_t dim2) {swapInputArray2D<uint16_t>(uInt16, dim1, dim2); } + void CNVRegister::swapInputInt16Array2D(uint32_t dim1, uint32_t dim2) {swapInputArray2D<int16_t>(Int16, dim1, dim2); } + void CNVRegister::swapInputUInt32Array2D(uint32_t dim1, uint32_t dim2) {swapInputArray2D<uint32_t>(uInt32, dim1, dim2); } + void CNVRegister::swapInputInt32Array2D(uint32_t dim1, uint32_t dim2) {swapInputArray2D<int32_t>(Int32, dim1, dim2); } + void CNVRegister::swapInputUInt64Array2D(uint32_t dim1, uint32_t dim2) {swapInputArray2D<uint64_t>(uInt64, dim1, dim2); } + void CNVRegister::swapInputInt64Array2D(uint32_t dim1, uint32_t dim2) {swapInputArray2D<int64_t>(Int64, dim1, dim2); } + void CNVRegister::swapInputFloat32Array2D(uint32_t dim1, uint32_t dim2) {swapInputArray2D<float>(Float32, dim1, dim2); } + void CNVRegister::swapInputFloat64Array2D(uint32_t dim1, uint32_t dim2) {swapInputArray2D<double>(Float64, dim1, dim2); } + void CNVRegister::swapInputDateArray2D(uint32_t dim1, uint32_t dim2) {swapInputArray2D<double>(Date, dim1, dim2); } + + void CNVRegister::swapOutputUInt8Array2D(uint32_t dim1, uint32_t dim2) {swapOutputArray2D<uint8_t>(uInt8, dim1, dim2); } + void CNVRegister::swapOutputInt8Array2D(uint32_t dim1, uint32_t dim2) {swapOutputArray2D<int8_t>(Int8, dim1, dim2); } + void CNVRegister::swapOutputUInt16Array2D(uint32_t dim1, uint32_t dim2) {swapOutputArray2D<uint16_t>(uInt16, dim1, dim2); } + void CNVRegister::swapOutputInt16Array2D(uint32_t dim1, uint32_t dim2) {swapOutputArray2D<int16_t>(Int16, dim1, dim2); } + void CNVRegister::swapOutputUInt32Array2D(uint32_t dim1, uint32_t dim2) {swapOutputArray2D<uint32_t>(uInt32, dim1, dim2); } + void CNVRegister::swapOutputInt32Array2D(uint32_t dim1, uint32_t dim2) {swapOutputArray2D<int32_t>(Int32, dim1, dim2); } + void CNVRegister::swapOutputUInt64Array2D(uint32_t dim1, uint32_t dim2) {swapOutputArray2D<uint64_t>(uInt64, dim1, dim2); } + void CNVRegister::swapOutputInt64Array2D(uint32_t dim1, uint32_t dim2) {swapOutputArray2D<int64_t>(Int64, dim1, dim2); } + void CNVRegister::swapOutputFloat32Array2D(uint32_t dim1, uint32_t dim2) {swapOutputArray2D<float>(Float32, dim1, dim2); } + void CNVRegister::swapOutputFloat64Array2D(uint32_t dim1, uint32_t dim2) {swapOutputArray2D<double>(Float64, dim1, dim2); } + void CNVRegister::swapOutputDateArray2D(uint32_t dim1, uint32_t dim2) {swapOutputArray2D<double>(Date, dim1, dim2); } + + void CNVRegister::setRegIntoStructBuffer(CNVData *buffer,int bufferSize, CNVData reg, int regOffset) + { + + CNVData *temp = (CNVData*)calloc(bufferSize,sizeof(CNVData)); + try{ + // split struct into fields + errChk(CNVGetStructFields (*buffer,temp,bufferSize)); + + // Dispose the single value that will be replaced + errChk(CNVDisposeData(temp[regOffset])); + + // substitute value inside the appropriated field + temp[regOffset] = reg; + + // re-packs up the struct + errChk(CNVSetStructDataValue(*buffer,temp,bufferSize)); + } + catch (const SilecsException& ex) + { + // Cleanup before forwarding the exception + for(int i=0;i<bufferSize;i++) + CNVDisposeData(temp[i]); + free(temp); + throw; + } + // Dispose the temporary CNV data + for(int i=0;i<bufferSize;i++) + CNVDisposeData(temp[i]); + // Free the pointer + free(temp); + } + + + CNVData CNVRegister::getRegfromStructBuffer(CNVData buffer,int bufferSize, int regOffset) + { + + CNVData *allFields = (CNVData*)calloc(bufferSize,sizeof(CNVData)); + CNVData returnValue; + try{ + // split struct into fields + errChk(CNVGetStructFields(buffer,allFields,bufferSize)); + + returnValue = allFields[regOffset]; + } + catch (const SilecsException& ex) + { + // Cleanup before forwarding the exception + for(int i=0;i<bufferSize;i++) + if(i!=regOffset) + errChk(CNVDisposeData(allFields[i])); + free(allFields); + throw; + } + + for(int i=0;i<bufferSize;i++) + if(i!=regOffset) + errChk(CNVDisposeData(allFields[i])); + + free(allFields); + // return the researched index + return returnValue; + } + + void CNVRegister::importValue(void* pBuffer, timeval ts) + { + LOG(DEBUG) << "CNVRegister::importValue Reg " << name_ << " dim1: " << dimension1_ << " dim2: " << dimension2_; + + unsigned long structBufferSize = this->getDevice()->getRegisterCollection(this->getBlockName()).size(); + + CNVData regContent; // will contain the register value in a CNVData format. + + if (this->getDevice()->getPLC()->getProtocolID()==DeviceMode) + { + // DEVICE MODE { BlockStruct.reg(1-n) } + regContent = getRegfromStructBuffer((CNVData)(*(CNVData*) pBuffer), structBufferSize, address_); + } + else + { + // BLOCK MODE { Device[BlockStruct.reg(1-n)] } + LOG(ERROR) << "Block mode not supported for shared variables."; + throw SilecsException(__FILE__, __LINE__, CNV_INTERNAL_ERROR, "Block mode not supported for shared variables. Error in register "+ name_); + } + + if( dimension2_ == 1) // scalar or 1d array + { + if( dimension1_== 1 ) // the register contains a scalar + { + // extract the register out of the struct + switch(format_) + { + case uInt8: { errChk(CNVGetScalarDataValue(regContent, CNVUInt8, pRecvValue_)); break; } + case Int8: { errChk(CNVGetScalarDataValue(regContent, CNVInt8, pRecvValue_)); break; } + case uInt16:{ errChk(CNVGetScalarDataValue(regContent, CNVUInt16, pRecvValue_)); break; } + case Int16: { errChk(CNVGetScalarDataValue(regContent, CNVInt16, pRecvValue_)); break; } + case uInt32:{ errChk(CNVGetScalarDataValue(regContent, CNVUInt32, pRecvValue_)); break; } + case Int32: { errChk(CNVGetScalarDataValue(regContent, CNVInt32, pRecvValue_)); break; } + case uInt64:{ errChk(CNVGetScalarDataValue(regContent, CNVUInt64, pRecvValue_)); break; } + case Int64: { errChk(CNVGetScalarDataValue(regContent, CNVInt64, pRecvValue_)); break; } + case Float32:{errChk(CNVGetScalarDataValue(regContent, CNVSingle, pRecvValue_)); break; } + case Float64:{errChk(CNVGetScalarDataValue(regContent, CNVDouble, pRecvValue_)); break; } + // CNV does not support date. Double is used instead + case Date: { errChk(CNVGetScalarDataValue(regContent, CNVDouble, pRecvValue_)); break; } + default: + { + LOG(ERROR) << "Unknown shared variable format."; + throw SilecsException(__FILE__, __LINE__, CNV_INTERNAL_ERROR, "Unknown shared variable format. Error in register "+ name_); + } + } + } + else // the register contains a 1D array + { + // retrieve dimension of the array + long unsigned int dimension[1]; + errChk(CNVGetArrayDataDimensions (regContent, 1, dimension)); + + // if received register dimension do not match with one retrieved from the XML throw an exception + if(dimension1_!=dimension[0]) + { + LOG(ERROR) << "Reg " << name_ << " mismatching dimension1. Expected: " << dimension1_ << " received: " << dimension[0]; + throw SilecsException(__FILE__, __LINE__, DATA_ARRAY_LENGTH_MISMATCH, name_); + } + + // extract the vector content + switch(format_) + { + case uInt8: { errChk(CNVGetArrayDataValue (regContent, CNVUInt8, pRecvValue_, dimension1_)); break; } + case Int8: { errChk(CNVGetArrayDataValue (regContent, CNVInt8, pRecvValue_, dimension1_)); break; } + case uInt16:{ errChk(CNVGetArrayDataValue (regContent, CNVUInt16, pRecvValue_, dimension1_)); break; } + case Int16: { errChk(CNVGetArrayDataValue (regContent, CNVInt16, pRecvValue_, dimension1_)); break; } + case uInt32:{ errChk(CNVGetArrayDataValue (regContent, CNVUInt32, pRecvValue_, dimension1_)); break; } + case Int32: { errChk(CNVGetArrayDataValue (regContent, CNVInt32, pRecvValue_, dimension1_)); break; } + case uInt64:{ errChk(CNVGetArrayDataValue (regContent, CNVUInt64, pRecvValue_, dimension1_)); break; } + case Int64: { errChk(CNVGetArrayDataValue (regContent, CNVInt64, pRecvValue_, dimension1_)); break; } + case Float32:{errChk(CNVGetArrayDataValue (regContent, CNVSingle, pRecvValue_, dimension1_)); break; } + case Float64:{errChk(CNVGetArrayDataValue (regContent, CNVDouble, pRecvValue_, dimension1_)); break; } + // CNV does not support date. Double is used instead + case Date: { errChk(CNVGetArrayDataValue (regContent, CNVDouble, pRecvValue_, dimension1_)); break; } + default: + { + LOG(ERROR) << "Unknown shared variable format."; + throw SilecsException(__FILE__, __LINE__, CNV_INTERNAL_ERROR, "Unknown shared variable format. Error in register "+ name_); + } + } + } + } + else // dim2 >1: the register contains a 2d array + { + long unsigned int dimension[2]; + errChk(CNVGetArrayDataDimensions (regContent, 2, dimension)); + LOG(DEBUG) << "CNVRegister::importValue Reg " << name_ << " received dim1: " << dimension[0] << " dim2: " << dimension[1]; + + // if received register dimension do not match with one retrieved from the XML throw an exception + if((dimension1_!=dimension[0]) || (dimension2_ != dimension[1])) + throw SilecsException(__FILE__, __LINE__, DATA_ARRAY_LENGTH_MISMATCH, name_); + + // extract the vector content + switch(format_) + { + case uInt8: + { + errChk(CNVGetArrayDataValue (regContent, CNVUInt8, pRecvValue_, dimension1_*dimension2_)); + swapInputUInt8Array2D(dimension1_, dimension2_); + break; + } + case Int8: + { + errChk(CNVGetArrayDataValue (regContent, CNVInt8, pRecvValue_, dimension1_*dimension2_)); + swapInputInt8Array2D(dimension1_, dimension2_); + break; + } + case uInt16: + { + errChk(CNVGetArrayDataValue (regContent, CNVUInt16, pRecvValue_, dimension1_*dimension2_)); + swapInputUInt16Array2D(dimension1_, dimension2_); + break; + } + case Int16: + { + errChk(CNVGetArrayDataValue (regContent, CNVInt16, pRecvValue_, dimension1_*dimension2_)); + swapInputInt16Array2D(dimension1_, dimension2_); + break; + } + case uInt32: + { + errChk(CNVGetArrayDataValue (regContent, CNVUInt32, pRecvValue_, dimension1_*dimension2_)); + swapInputUInt32Array2D(dimension1_, dimension2_); + break; + } + case Int32: + { + errChk(CNVGetArrayDataValue (regContent, CNVInt32, pRecvValue_, dimension1_*dimension2_)); + swapInputInt32Array2D(dimension1_, dimension2_); + break; + } + case uInt64: + { + errChk(CNVGetArrayDataValue (regContent, CNVUInt64, pRecvValue_, dimension1_*dimension2_)); + swapInputUInt64Array2D(dimension1_, dimension2_); + break; + } + case Int64: + { + errChk(CNVGetArrayDataValue (regContent, CNVInt64, pRecvValue_, dimension1_*dimension2_)); + swapInputInt64Array2D(dimension1_, dimension2_); + break; + } + case Float32: + { + errChk(CNVGetArrayDataValue (regContent, CNVSingle, pRecvValue_, dimension1_*dimension2_)); + swapInputFloat32Array2D(dimension1_, dimension2_); + break; + } + case Float64: + { + errChk(CNVGetArrayDataValue (regContent, CNVDouble, pRecvValue_, dimension1_*dimension2_)); + swapInputFloat64Array2D(dimension1_, dimension2_); + break; + } + case Date: // CNV does not support date. Double is used instead + { + errChk(CNVGetArrayDataValue (regContent, CNVDouble, pRecvValue_, dimension1_*dimension2_)); + swapInputDateArray2D(dimension1_, dimension2_); + break; + } + default: + { + LOG(ERROR) << "Unknown shared variable format."; + throw SilecsException(__FILE__, __LINE__, CNV_INTERNAL_ERROR, "Unknown shared variable format. Error in register "+ name_); + } + } + } + //Set the register time-stamp + tod_ = ts; + // free the register content temporary variable + errChk(CNVDisposeData(regContent)); + } + + void CNVRegister::exportValue(void* pBuffer) + { + CNVData regContent; // will contain the register value in a CNVData format. + + if(dimension2_ == 1) // scalar or 1d arrray + { + if( dimension1_== 1 ) // the register contains a scalar + { + // extract the register out of the struct + // generate the correct CNVData register content converting from the SILECS Type + switch(format_) + { + case uInt8: + { + errChk(CNVCreateScalarDataValue (®Content, CNVUInt8, (uint8_t)(*((uint8_t *)pSendValue_)))); + errChk(CNVSetScalarDataValue(regContent, CNVUInt8, (uint8_t)(*((uint8_t *)pSendValue_)))); + break; + } + case Int8: + { + errChk(CNVCreateScalarDataValue (®Content, CNVInt8, (int8_t)(*((int8_t *)pSendValue_)))); + errChk(CNVSetScalarDataValue(regContent, CNVInt8, (int8_t)(*((int8_t *)pSendValue_)))); + break; + } + case uInt16: + { + errChk(CNVCreateScalarDataValue (®Content, CNVUInt16,(uint16_t)(*((uint16_t *)pSendValue_))) ); + errChk(CNVSetScalarDataValue(regContent, CNVUInt16, (uint16_t)(*((uint16_t *)pSendValue_)))); + break; + } + case Int16: + { + errChk(CNVCreateScalarDataValue (®Content, CNVInt16, (int16_t)(*((int16_t *)pSendValue_)))); + errChk(CNVSetScalarDataValue(regContent, CNVInt16, (int16_t)(*((int16_t *)pSendValue_)))); + break; + } + case uInt32: + { + errChk(CNVCreateScalarDataValue (®Content, CNVUInt32, (uint32_t)(*((uint32_t *)pSendValue_)))); + errChk(CNVSetScalarDataValue(regContent, CNVUInt32, (uint32_t)(*((uint32_t *)pSendValue_)))); + break; + } + case Int32: + { + errChk(CNVCreateScalarDataValue (®Content, CNVInt32, (int32_t)(*((int32_t *)pSendValue_)))); + errChk(CNVSetScalarDataValue(regContent, CNVInt32, (int32_t)(*((int32_t *)pSendValue_)))); + break; + } + case uInt64: + { + errChk(CNVCreateScalarDataValue (®Content, CNVUInt64, (uint64_t)(*((uint64_t *)pSendValue_)))); + errChk(CNVSetScalarDataValue(regContent, CNVUInt64, (uint64_t)(*((uint64_t *)pSendValue_)))); + break; + } + case Int64: + { + errChk(CNVCreateScalarDataValue (®Content, CNVInt64, (int64_t)(*((int64_t *)pSendValue_)))); + errChk(CNVSetScalarDataValue(regContent, CNVInt64, (int64_t)(*((int64_t *)pSendValue_)))); + break; + } + case Float32: + { + errChk(CNVCreateScalarDataValue (®Content, CNVSingle, (float)(*((float*)pSendValue_)))); + errChk(CNVSetScalarDataValue(regContent, CNVSingle, (float)(*((float*)pSendValue_)))); + break; + } + case Float64: + { + errChk(CNVCreateScalarDataValue (®Content, CNVDouble, (double)(*((double *)pSendValue_)))); + errChk(CNVSetScalarDataValue(regContent, CNVDouble, (double)(*((double *)pSendValue_)))); + break; + } + case Date: // CNV does not support date. Double is used instead + { + errChk(CNVCreateScalarDataValue (®Content, CNVDouble, (double)(*((double *)pSendValue_)))); + errChk(CNVSetScalarDataValue(regContent, CNVDouble, (double)(*((double *)pSendValue_)))); + break; + } + default: + { + LOG(ERROR) << "Unknown shared variable format."; + throw SilecsException(__FILE__, __LINE__, CNV_INTERNAL_ERROR, "Unknown shared variable format. Error in register "+ name_); + } + } + } + else // the register contains an array + { + long unsigned int dimensions[1]; + dimensions[0] = dimension1_; + + switch(format_) + { + case uInt8: + { + errChk(CNVCreateArrayDataValue (®Content, CNVUInt8, (uint8_t *)pSendValue_, 1, dimensions)); + errChk(CNVSetArrayDataValue (regContent, CNVUInt8, (uint8_t *)pSendValue_, 1, dimensions)); + break; + } + case Int8: + { + errChk(CNVCreateArrayDataValue (®Content, CNVInt8, (int8_t *)pSendValue_, 1, dimensions)); + errChk(CNVSetArrayDataValue (regContent, CNVInt8, (int8_t *)pSendValue_, 1, dimensions)); + break; + } + case uInt16: + { + errChk(CNVCreateArrayDataValue (®Content, CNVUInt16, (uint16_t *)pSendValue_, 1, dimensions)); + errChk(CNVSetArrayDataValue (regContent, CNVUInt16, (uint16_t *)pSendValue_, 1, dimensions)); + break; + } + case Int16: + { + errChk(CNVCreateArrayDataValue (®Content, CNVInt16, (int16_t *)pSendValue_, 1, dimensions)); + errChk(CNVSetArrayDataValue (regContent, CNVInt16, (int16_t *)pSendValue_, 1, dimensions)); + break; + } + case uInt32: + { + errChk(CNVCreateArrayDataValue (®Content, CNVUInt32, (uint32_t *)pSendValue_, 1, dimensions)); + errChk(CNVSetArrayDataValue (regContent, CNVUInt32, (uint32_t *)pSendValue_, 1, dimensions)); + break; + } + case Int32: + { + errChk(CNVCreateArrayDataValue (®Content, CNVInt32, (int32_t *)pSendValue_, 1, dimensions)); + errChk(CNVSetArrayDataValue (regContent, CNVInt32, (int32_t *)pSendValue_, 1, dimensions)); + break; + } + case uInt64: + { + errChk(CNVCreateArrayDataValue (®Content, CNVUInt64, (uint64_t *)pSendValue_, 1, dimensions)); + errChk(CNVSetArrayDataValue (regContent, CNVUInt64, (uint64_t *)pSendValue_, 1, dimensions)); + break; + } + case Int64: + { + errChk(CNVCreateArrayDataValue (®Content, CNVInt64, (int64_t *)pSendValue_, 1, dimensions)); + errChk(CNVSetArrayDataValue (regContent, CNVInt64, (int64_t *)pSendValue_, 1, dimensions)); + break; + } + case Float32: + { + errChk(CNVCreateArrayDataValue (®Content, CNVSingle, (float *)pSendValue_, 1, dimensions)); + errChk(CNVSetArrayDataValue (regContent, CNVSingle, (float *)pSendValue_, 1, dimensions)); + break; + } + case Float64: + { + errChk(CNVCreateArrayDataValue (®Content, CNVDouble, (double *)pSendValue_, 1, dimensions)); + errChk(CNVSetArrayDataValue (regContent, CNVDouble, (double *)pSendValue_, 1, dimensions)); + break; + } + case Date: // CNV does not support date. Double is used instead + { + errChk(CNVCreateArrayDataValue (®Content, CNVDouble, (double *)pSendValue_, 1, dimensions)); + errChk(CNVSetArrayDataValue (regContent, CNVDouble, (double *)pSendValue_, 1, dimensions)); + break; + } + default: + { + LOG(ERROR) << "Unknown shared variable format."; + throw SilecsException(__FILE__, __LINE__, CNV_INTERNAL_ERROR, "Unknown shared variable format. Error in register "+ name_); + } + } + } + } + else // 2d array + { + long unsigned int dimensions[2]; + dimensions[0] = dimension1_; + dimensions[1] = dimension2_; + + switch(format_) + { + case uInt8: + { + swapOutputUInt8Array2D(dimension1_, dimension2_); + errChk(CNVCreateArrayDataValue (®Content, CNVUInt8, (uint8_t *)pSendValue_, 2, dimensions)); + errChk(CNVSetArrayDataValue (regContent, CNVUInt8, (uint8_t *)pSendValue_, 2, dimensions)); + break; + } + case Int8: + { + swapOutputInt8Array2D(dimension1_, dimension2_); + errChk(CNVCreateArrayDataValue (®Content, CNVInt8, (int8_t *)pSendValue_, 2, dimensions)); + errChk(CNVSetArrayDataValue (regContent, CNVInt8, (int8_t *)pSendValue_, 2, dimensions)); + break; + } + case uInt16: + { + swapOutputUInt16Array2D(dimension1_, dimension2_); + errChk(CNVCreateArrayDataValue (®Content, CNVUInt16, (uint16_t *)pSendValue_, 2, dimensions)); + errChk(CNVSetArrayDataValue (regContent, CNVUInt16, (uint16_t *)pSendValue_, 2, dimensions)); + break; + } + case Int16: + { + swapOutputInt16Array2D(dimension1_, dimension2_); + errChk(CNVCreateArrayDataValue (®Content, CNVInt16, (int16_t *)pSendValue_, 2, dimensions)); + errChk(CNVSetArrayDataValue (regContent, CNVInt16, (int16_t *)pSendValue_, 2, dimensions)); + break; + } + case uInt32: + { + swapOutputUInt32Array2D(dimension1_, dimension2_); + errChk(CNVCreateArrayDataValue (®Content, CNVUInt32, (uint32_t *)pSendValue_, 2, dimensions)); + errChk(CNVSetArrayDataValue (regContent, CNVUInt32, (uint32_t *)pSendValue_, 2, dimensions)); + break; + } + case Int32: + { + swapOutputInt32Array2D(dimension1_, dimension2_); + errChk(CNVCreateArrayDataValue (®Content, CNVInt32, (int32_t *)pSendValue_, 2, dimensions)); + errChk(CNVSetArrayDataValue (regContent, CNVInt32, (int32_t *)pSendValue_, 2, dimensions)); + break; + } + case uInt64: + { + swapOutputUInt64Array2D(dimension1_, dimension2_); + errChk(CNVCreateArrayDataValue (®Content, CNVUInt64, (uint64_t *)pSendValue_, 2, dimensions)); + errChk(CNVSetArrayDataValue (regContent, CNVUInt64, (uint64_t *)pSendValue_, 2, dimensions)); + break; + } + case Int64: + { + swapOutputInt64Array2D(dimension1_, dimension2_); + errChk(CNVCreateArrayDataValue (®Content, CNVInt64, (int64_t *)pSendValue_, 2, dimensions)); + errChk(CNVSetArrayDataValue (regContent, CNVInt64, (int64_t *)pSendValue_, 2, dimensions)); + break; + } + case Float32: + { + swapOutputFloat32Array2D(dimension1_, dimension2_); + errChk(CNVCreateArrayDataValue (®Content, CNVSingle, (float *)pSendValue_, 2, dimensions)); + errChk(CNVSetArrayDataValue (regContent, CNVSingle, (float *)pSendValue_, 2, dimensions)); + break; + } + case Float64: + { + swapOutputFloat64Array2D(dimension1_, dimension2_); + errChk(CNVCreateArrayDataValue (®Content, CNVDouble, (double *)pSendValue_, 2, dimensions)); + errChk(CNVSetArrayDataValue (regContent, CNVDouble, (double *)pSendValue_, 2, dimensions)); + break; + } + case Date: + { + swapOutputDateArray2D(dimension1_, dimension2_); + // CNV does not support date. Double is used instead + errChk(CNVCreateArrayDataValue (®Content, CNVDouble, (double *)pSendValue_, 2, dimensions)); + errChk(CNVSetArrayDataValue (regContent, CNVDouble, (double *)pSendValue_, 2, dimensions)); + break; + } + default: + { + LOG(ERROR) << "Unknown shared variable format."; + throw SilecsException(__FILE__, __LINE__, CNV_INTERNAL_ERROR, "Unknown shared variable format. Error in register "+ name_); + } + } + } + + unsigned long structBufferSize = this->getDevice()->getRegisterCollection(this->getBlockName()).size(); + if (this->getDevice()->getPLC()->getProtocolID()==DeviceMode) + { + // DEVICE MODE { BlockStruct.reg(1-n) } + setRegIntoStructBuffer((CNVData*) pBuffer,structBufferSize, regContent, address_); + } + else + { + // BLOCK MODE { Device[BlockStruct.reg(1-n)] } + + LOG(ERROR) << "Block mode not supported for shared variables."; + throw SilecsException(__FILE__, __LINE__, CNV_INTERNAL_ERROR, "Block mode not supported for shared variables. Error in register "+ name_); + } + } + + void CNVRegister::importString(void* pBuffer, timeval ts) + { + unsigned long structBufferSize = this->getDevice()->getRegisterCollection(this->getBlockName()).size(); + std::string** pRecvStringValue_ = static_cast<std::string**>(pRecvValue_); + CNVData regContent; // will contain the register value in a CNVData format + + if (this->getDevice()->getPLC()->getProtocolID()==DeviceMode) + { + // DEVICE MODE { BlockStruct.reg(1-n) } + regContent = getRegfromStructBuffer((CNVData)(*(CNVData*) pBuffer), structBufferSize, address_); + } + else + { + // BLOCK MODE { Device[BlockStruct.reg(1-n)] } + LOG(ERROR) << "Block mode not supported for shared variables."; + throw SilecsException(__FILE__, __LINE__, CNV_INTERNAL_ERROR, "Block mode not supported for shared variables. Error in register "+ name_); + } + + char *temp[dimension1_*dimension2_]; + + if( dimension2_ == 1) // scalar or 1D array + { + if( dimension1_== 1 ) // the register contains a scalar + { + errChk(CNVGetScalarDataValue(regContent, CNVString, temp)); + pRecvStringValue_[0]->assign((const char*)temp[0]); + } + else // the register contains a 1D array + { + // retrieve dimension of the mono-dimensional array + long unsigned int dimension[1]; + errChk(CNVGetArrayDataDimensions (regContent, 1, dimension)); + + // if received register dimension do not match with one retrieved from the XML throw an exception + if(dimension1_!=dimension[0]) + throw SilecsException(__FILE__, __LINE__, DATA_ARRAY_LENGTH_MISMATCH, name_); + + errChk(CNVGetArrayDataValue(regContent, CNVString, temp, dimension1_)); + for (unsigned long i = 0; i < dimension1_; i++) + pRecvStringValue_[i]->assign((const char*)temp[i]); + } + } + else // the register contains a 2D array + { + // retrieve dimensions of double array + long unsigned int dimensions[2]; + errChk(CNVGetArrayDataDimensions (regContent, 2, dimensions)); + + // if received register dimensions do not match with the ones retrieved from the XML throw an exception + if((dimension1_!=dimensions[0]) || (dimension2_!=dimensions[1])) + throw SilecsException(__FILE__, __LINE__, DATA_ARRAY_LENGTH_MISMATCH, name_); + + // Warning: this method returns the element of the matrix in row-major order + errChk(CNVGetArrayDataValue(regContent, CNVString, temp, dimension1_*dimension2_)); + + // The CNV library reads the element in row-major order, whereas the SILECS CLIB works in column-major order. + // The following code swaps rows and columns, returning the content of pRecvValue_ correctly ordered + unsigned long i = 0; + unsigned long index = 0; + for (unsigned long j=0; j < dimension1_; j++) + { + i = j; + while(i < (dimension1_*dimension2_)) + { + pRecvStringValue_[index]->assign((const char*)temp[i]); + index++; + i += dimension1_; + } + } + } + + // Set the register time-stamp + tod_ = ts; + + // free the register content temporary variable + errChk(CNVDisposeData(regContent)); + } + + void CNVRegister::exportString(void* pBuffer) + { + std::string** pSendStringValue_ = static_cast<std::string**>(pSendValue_); + CNVData regContent; // will contain the register value in a CNVData format. + char *temp[dimension1_*dimension2_]; + + if(dimension2_ == 1) // scalar or 1D arrray + { + if( dimension1_== 1 ) // the register contains a scalar + { + // generate the correct CNVData register content + errChk(CNVCreateScalarDataValue (®Content, CNVString, (*pSendStringValue_[0]).data())); + errChk(CNVSetScalarDataValue(regContent, CNVString, (*pSendStringValue_[0]).data())); + } + else // the register contains a 1D array + { + long unsigned int dimensions[1]; + dimensions[0] = dimension1_; + + for (unsigned long i = 0; i < dimension1_; i++) + temp[i] = (char*)(*pSendStringValue_[i]).data(); + + errChk(CNVCreateArrayDataValue (®Content, CNVString, temp, 1, dimensions)); + errChk(CNVSetArrayDataValue(regContent, CNVString, temp, 1, dimensions)); + } + } + else // the register contains a 2D array + { + long unsigned int dimensions[2]; + dimensions[0] = dimension1_; + dimensions[1] = dimension2_; + + // The CNV library reads the element in row-major order, whereas the SILECS CLIB works in column-major order. + // The following code swaps rows and columns, returning the content of pSendValue_ correctly ordered + unsigned long i = 0; + unsigned long index = 0; + for (unsigned long j=0; j < dimension2_; j++) + { + i = j; + while(i < (dimension1_*dimension2_)) + { + temp[index] = (char*)(*pSendStringValue_[i]).c_str(); + index++; + i += dimension2_; + } + } + + errChk(CNVCreateArrayDataValue (®Content, CNVString, temp, 2, dimensions)); + errChk(CNVSetArrayDataValue(regContent, CNVString, temp, 2, dimensions)); + } + + unsigned long structBufferSize = this->getDevice()->getRegisterCollection(this->getBlockName()).size(); + if (this->getDevice()->getPLC()->getProtocolID()==DeviceMode) + { + // DEVICE MODE { BlockStruct.reg(1-n) } + setRegIntoStructBuffer((CNVData*) pBuffer,structBufferSize, regContent, address_); + } + else + { + // BLOCK MODE { Device[BlockStruct.reg(1-n)] } + LOG(ERROR) << "Block mode not supported for shared variables."; + throw SilecsException(__FILE__, __LINE__, CNV_INTERNAL_ERROR, "Block mode not supported for shared variables. Error in register "+ name_); + } + + // free the register content temporary variable +// errChk(CNVDisposeData(regContent)); + } + + //Transfer the value of the recvBuffer to to the sendBuffer + void CNVRegister::copyValue() + { + if (format_ == String) + { + std::string** pRecvStringValue_ = static_cast<std::string**>(pRecvValue_); + std::string** pSendStringValue_ = static_cast<std::string**>(pSendValue_); + for(unsigned int i=0; i<(dimension1_*dimension2_); i++) + { + *(pSendStringValue_[i]) = *(pRecvStringValue_[i]); + } + } + else + { + memcpy(pSendValue_, pRecvValue_, (size_*dimension1_*dimension2_)); + } + } +} +#endif //NI_SUPPORT_ENABLED diff --git a/silecs-communication-cpp/src/silecs-communication/interface/equipment/CNVRegister.h b/silecs-communication-cpp/src/silecs-communication/interface/equipment/CNVRegister.h new file mode 100644 index 0000000..5e8df44 --- /dev/null +++ b/silecs-communication-cpp/src/silecs-communication/interface/equipment/CNVRegister.h @@ -0,0 +1,151 @@ +// Copyright 2016 CERN and GSI +// +// 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 3 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, see <http://www.gnu.org/licenses/>. + +#ifdef NI_SUPPORT_ENABLED +#ifndef _SILECS_CNV_REGISTER_H_ +#define _SILECS_CNV_REGISTER_H_ + +#include <silecs-communication/interface/core/SilecsService.h> +#include <silecs-communication/interface/utility/XMLParser.h> +#include <silecs-communication/interface/equipment/SilecsPLC.h> +#include <silecs-communication/interface/equipment/SilecsDevice.h> +#include <silecs-communication/interface/equipment/SilecsRegister.h> +#include <silecs-communication/interface/utility/SilecsException.h> +#include <silecs-communication/interface/utility/SilecsLog.h> +#include <silecs-communication/interface/utility/StringUtilities.h> +#include <silecs-communication/protocol/core/silecs.h> + +#ifdef __cplusplus +extern "C" { +#endif + + +#include <nilibnetv.h> + +#ifdef __cplusplus +} +#endif + + +namespace Silecs +{ + + /// @cond + class CNVRegister : public Register + { + private: + + void setRegIntoStructBuffer(CNVData *buffer,int bufferSize, CNVData reg, int regOffset); + CNVData getRegfromStructBuffer(CNVData buffer,int bufferSize, int regOffset); + + void swapInputUInt8Array2D(uint32_t dim1, uint32_t dim2); + void swapInputInt8Array2D(uint32_t dim1, uint32_t dim2); + void swapInputUInt16Array2D(uint32_t dim1, uint32_t dim2); + void swapInputInt16Array2D(uint32_t dim1, uint32_t dim2); + void swapInputUInt32Array2D(uint32_t dim1, uint32_t dim2); + void swapInputInt32Array2D(uint32_t dim1, uint32_t dim2); + void swapInputUInt64Array2D(uint32_t dim1, uint32_t dim2); + void swapInputInt64Array2D(uint32_t dim1, uint32_t dim2); + void swapInputFloat32Array2D(uint32_t dim1, uint32_t dim2); + void swapInputFloat64Array2D(uint32_t dim1, uint32_t dim2); + void swapInputDateArray2D(uint32_t dim1, uint32_t dim2); + + void swapOutputUInt8Array2D(uint32_t dim1, uint32_t dim2); + void swapOutputInt8Array2D(uint32_t dim1, uint32_t dim2); + void swapOutputUInt16Array2D(uint32_t dim1, uint32_t dim2); + void swapOutputInt16Array2D(uint32_t dim1, uint32_t dim2); + void swapOutputUInt32Array2D(uint32_t dim1, uint32_t dim2); + void swapOutputInt32Array2D(uint32_t dim1, uint32_t dim2); + void swapOutputUInt64Array2D(uint32_t dim1, uint32_t dim2); + void swapOutputInt64Array2D(uint32_t dim1, uint32_t dim2); + void swapOutputFloat32Array2D(uint32_t dim1, uint32_t dim2); + void swapOutputFloat64Array2D(uint32_t dim1, uint32_t dim2); + void swapOutputDateArray2D(uint32_t dim1, uint32_t dim2); + + // Check for CNV errors, log and create an exception + void errChk(int code); + + protected: + + // export register extraction methods + friend class PLC; + friend class Device; + + /*! + * \fn importValue + * \brief Used to convert and transfered data from the data-block receiver to the register value + * Overloads the virtual method inherited from the class SilecsRegister. + * \param pBuffer points the data-block buffer + * \param ts is the time-of-day to time-stamp the register + */ + void importValue(void* pBuffer, timeval ts); + + /*! + * \fn exportValue + * \brief Used to transfered the register value to the data data-block to be sent + * Overloads the virtual method inherited from the class SilecsRegister. + * \param pBuffer points the data-block buffer + */ + void exportValue(void* pBuffer); + + /*! + * \fn importString + * \brief Import values from the received buffer to the register. Pure vistual to be implemented by the inheriting classes. + * \param pBuffer received data buffer + * \param ts register time-stamp + */ + void importString(void* pBuffer, timeval ts); + + /*! + * \fn exportString + * \brief Export the string from the register to the correct position in the buffer. Pure virtual to be implemented by inheriting classes. + * \param pBuffer the output buffer where to update the data + */ + void exportString(void* pBuffer); + + /*! + * \fn copyValue + * \brief Copies the register content from the input buffer the output buffer. + * Overloads the virtual method inherited from the class SilecsRegister. + * This method is used for Retentive InOut registers synchronization. + */ + void copyValue(); + + /*! + * \fn swapInputArray2D + * \brief The CNV library reads the element in row-major order, whereas the SILECS CLIB works in column-major order. + * The following code swaps rows and columns, returning the content of pRecvValue_ correctly ordered + */ + template <typename T> void swapInputArray2D(FormatType F, uint32_t dim1, uint32_t dim2); + + /*! + * \fn swapOutputArray2D + * \brief The CNV library reads the element in row-major order, whereas the SILECS CLIB works in column-major order. + * The following code swaps rows and columns, returning the content of pSendValue_ correctly ordered + */ + template <typename T> void swapOutputArray2D(FormatType F, uint32_t dim1, uint32_t dim2); + + public: + // Constructor from super class + CNVRegister(Device* theDevice, ElementXML* pDesignEl); + + // Destructor from super class + ~CNVRegister(); + + }; + /// @endcond +} +#endif // _SILECS_CNV_REGISTER_H_ +#endif //NI_SUPPORT_ENABLED diff --git a/silecs-communication-cpp/src/silecs-communication/interface/equipment/PLCBlock.cpp b/silecs-communication-cpp/src/silecs-communication/interface/equipment/PLCBlock.cpp new file mode 100644 index 0000000..69a3b8a --- /dev/null +++ b/silecs-communication-cpp/src/silecs-communication/interface/equipment/PLCBlock.cpp @@ -0,0 +1,92 @@ +// Copyright 2016 CERN and GSI +// +// 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 3 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, see <http://www.gnu.org/licenses/>. + +#include <silecs-communication/interface/core/SilecsService.h> +#include <silecs-communication/interface/utility/Thread.h> +#include <silecs-communication/interface/utility/XMLParser.h> +#include <silecs-communication/interface/equipment/SilecsPLC.h> +#include <silecs-communication/interface/equipment/SilecsBlock.h> +#include <silecs-communication/interface/equipment/SilecsRegister.h> +#include <silecs-communication/interface/core/SilecsAction.h> +#include <silecs-communication/interface/core/PLCRecvAction.h> +#include <silecs-communication/interface/core/PLCSendAction.h> +#include <silecs-communication/interface/core/WrapperAction.h> +#include <silecs-communication/interface/utility/SilecsException.h> +#include <silecs-communication/interface/utility/SilecsLog.h> +#include <silecs-communication/interface/utility/StringUtilities.h> +#include <silecs-communication/interface/equipment/PLCBlock.h> + +namespace Silecs +{ + + PLCBlock::PLCBlock(PLC* thePLC,ElementXML blockNode, AccessType accessType): + Block(thePLC, blockNode,accessType) + { + // Create buffer for the block exchanges + bufferSize_ = memSize_; //size of one block type (including alignements) + if (getPLC()->getProtocolID() == BlockMode) + { //BlockMode ==> access all devices in once + bufferSize_ *= getPLC()->getDeviceMap().size(); + } + pBuffer_ = (unsigned char*)calloc(bufferSize_, sizeof(unsigned char)); + } + + PLCBlock::~PLCBlock() + { + //Remove the buffer + if (pBuffer_ != NULL) free(pBuffer_); pBuffer_ = NULL; + } + + InputBlock::InputBlock(PLC* thePLC,ElementXML blockNode, AccessType accessType) : + PLCBlock(thePLC, blockNode, accessType) + { + if (DEBUG & Log::topics_) LOG(ALLOC) << "Block (create): " << name_ << ", plc: " << getPLC()->getName() << ", access: Input" << ", hasMaster: " << (hasMasterRegister() ? "yes" : "no") << ", hasSlave: " << (hasSlaveRegister() ? "yes" : "no") << ", address: " << address_ << ", mem-size: " << memSize_ << ", buffer-size: " << bufferSize_; + + // Creates receive task which relies on the block exchange + if (getPLC()->getProtocolID() == BlockMode) + pAction_ = new PLCRecvBlockMode(this); + else + pAction_ = new PLCRecvDeviceMode(this); + + WrapperAction wrapperAction(pAction_); + pTask_ = new Task<WrapperAction>(WrapperAction::function, wrapperAction); + } + + + InputBlock::~InputBlock() + { + } + + + OutputBlock::OutputBlock(PLC* thePLC,ElementXML blockNode, AccessType accessType) : + PLCBlock(thePLC, blockNode, accessType) + { + if (DEBUG & Log::topics_) LOG(ALLOC) << "Block (create): " << name_ << ", plc: " << getPLC()->getName() << ", access: Output" << ", hasMaster: " << (hasMasterRegister() ? "yes" : "no") << ", hasSlave: " << (hasSlaveRegister() ? "yes" : "no") << ", address: " << address_ << ", mem-size: " << memSize_ << ", buffer-size: " << bufferSize_; + + // Creates send task which relies on the block exchange + if (getPLC()->getProtocolID() == BlockMode) + pAction_ = new PLCSendBlockMode(this); + else + pAction_ = new PLCSendDeviceMode(this); + + WrapperAction wrapperAction(pAction_); + pTask_ = new Task<WrapperAction>(WrapperAction::function, wrapperAction); + } + + OutputBlock::~OutputBlock() + { + } + +} diff --git a/silecs-communication-cpp/src/silecs-communication/interface/equipment/PLCBlock.h b/silecs-communication-cpp/src/silecs-communication/interface/equipment/PLCBlock.h new file mode 100644 index 0000000..432145c --- /dev/null +++ b/silecs-communication-cpp/src/silecs-communication/interface/equipment/PLCBlock.h @@ -0,0 +1,71 @@ +// Copyright 2016 CERN and GSI +// +// 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 3 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, see <http://www.gnu.org/licenses/>. + +#ifndef _SILECS_PLC_BLOCK_H_ +#define _SILECS_PLC_BLOCK_H_ + +#include <silecs-communication/interface/core/SilecsService.h> +#include <silecs-communication/interface/utility/Thread.h> +#include <silecs-communication/interface/equipment/SilecsBlock.h> + +namespace Silecs +{ + + class PLCBlock : public Block + { + + public: + PLCBlock(PLC* thePLC,ElementXML blockNode, AccessType accessType); + ~PLCBlock(); + + inline unsigned long& getBufferSize() { return bufferSize_; } + + protected: + friend class Device; + + /// Send/Receive data size (size of block * nb of device) + unsigned long bufferSize_; + + }; + + /*! ----------------------------------------------------------------------- + * \class InputBlock + * \brief This is a specific Block for Acquisition data (from PLC to client) + */ + class InputBlock : public PLCBlock + { + + public: + InputBlock(PLC* thePLC,ElementXML blockNode, AccessType accessType); + virtual ~InputBlock(); + + }; + + /*! ----------------------------------------------------------------------- + * \class OutputBlock + * \brief This is a specific Block for Settings (from client to PLC) + */ + class OutputBlock : public PLCBlock + { + + public: + OutputBlock(PLC* thePLC,ElementXML blockNode, AccessType accessType); + virtual ~OutputBlock(); + + }; + +} // namespace + +#endif // _SILECS_BLOCK_H_ diff --git a/silecs-communication-cpp/src/silecs-communication/interface/equipment/PLCRegister.cpp b/silecs-communication-cpp/src/silecs-communication/interface/equipment/PLCRegister.cpp new file mode 100644 index 0000000..d4773eb --- /dev/null +++ b/silecs-communication-cpp/src/silecs-communication/interface/equipment/PLCRegister.cpp @@ -0,0 +1,505 @@ +// Copyright 2016 CERN and GSI +// +// 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 3 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, see <http://www.gnu.org/licenses/>. + +#include "PLCRegister.h" + +namespace Silecs +{ + + PLCRegister::PLCRegister(Device* theDevice,const boost::shared_ptr<ElementXML>& registerNode) : Register(theDevice, registerNode) {} + PLCRegister::~PLCRegister() {} + + BigEndianRegister::BigEndianRegister(Device* theDevice,const boost::shared_ptr<ElementXML>& registerNode) : PLCRegister(theDevice, registerNode) {} + BigEndianRegister::~BigEndianRegister() {} + + LittleEndianRegister::LittleEndianRegister(Device* theDevice,const boost::shared_ptr<ElementXML>& registerNode) : PLCRegister(theDevice, registerNode) {} + LittleEndianRegister::~LittleEndianRegister() {} + + S7Register::S7Register(Device* theDevice,const boost::shared_ptr<ElementXML>& registerNode) : BigEndianRegister(theDevice, registerNode) {} + S7Register::~S7Register() {} + + UnityRegister::UnityRegister(Device* theDevice,const boost::shared_ptr<ElementXML>& registerNode) : LittleEndianRegister(theDevice, registerNode) {} + UnityRegister::~UnityRegister() {} + + TwinCATRegister::TwinCATRegister(Device* theDevice,const boost::shared_ptr<ElementXML>& registerNode) : UnityRegister(theDevice, registerNode) {} + TwinCATRegister::~TwinCATRegister() {} + + + /// Generic methods for byte-swapping ---------------------------------------------- + uint16_t PLCRegister::_swaps(uint16_t s) + { + return ( ((s & 0x00ff) << 8) + ((s & 0xff00) >> 8) ); + } + + uint32_t PLCRegister::_swapl(uint32_t l) + { + uint32_t ul; + void *pl = &l; + void *pul = &ul; + *((uint16_t *)pul) = _swaps(*((uint16_t *)pl+1)); + *((uint16_t *)pul+1) = _swaps(*((uint16_t *)pl)); + return(ul); + } + + //Beckhoff/BC9020 PLC uses the same memory swapping than Unity PLCs except for float32 data + //This method is used to specialized the 32bits data swapping inherited from the UnityRegister class. + uint32_t TwinCATRegister::_swapl(uint32_t l) + { + uint32_t ul; + void *pl = &l; + void *pul = &ul; + + if ( (getPLC()->getModel() == "BC9020") && (getFormat() == Silecs::Float32) ) + { //Particular case for BC9020 PLC: swap only bytes together (not the words) + *((uint16_t *)pul) = _swaps(*((uint16_t *)pl)); + *((uint16_t *)pul+1) = _swaps(*((uint16_t *)pl+1)); + } + else + { //Same as base-class methods for other controllers + ul = PLCRegister::_swapl(l); + } + return(ul); + } + + float PLCRegister::_swapf(float f) + { + uint32_t l; + void *pl = &l; + void *pf = &f; + l = _swapl(*((uint32_t *)pf)); + return(*((float *)pl)); + } + + double PLCRegister::_swapd(double d) + { + uint64_t ld; + void *pd = &d; + void *pld = &ld; + *((uint32_t *)pld) = _swapl(*((uint32_t *)pd+1)); + *((uint32_t *)pld+1) = _swapl(*((uint32_t *)pd)); + return(*((double *)pld)); + } + + + // BIG-ENDIANNESS --------------------------------------------------------------------------- + void BigEndianRegister::swapBytesNToH(unsigned char *data, unsigned long size) + { + switch(size) + { + case 1: + //for CHAR and BYTE, nothing to do in that case. + break; + case 2: { + //WORD or INT type + uint16_t s = ntohs(*(uint16_t *)data); + //no swap, just convert to network format + *(uint16_t *)data = s; + break; + } + case 4: { + //DWORD, DINT or REAL type + uint32_t l = ntohl(*(uint32_t *)data); + //no swap, just convert to network format + *(uint32_t *)data = l; + break; + } + #ifdef __x86_64__ + case 8: { + //uInt64, Int64 or Float64 + //direct conversion from little-endian to host exists only from SLC6 version + uint64_t l64 = le64toh(*(uint64_t *)data); + *(uint64_t *)data = l64; + break; + } + #endif + default: + //nothing to do unknown type + break; + } + } + + void BigEndianRegister::swapBytesHToN(unsigned char *data, unsigned long size) + { + switch(size) + { + case 1: + //for CHAR and BYTE, nothing to do in that case. + break; + case 2: { + //WORD or INT type + uint16_t s = htons(*(uint16_t *)data); + //no swap, just convert to network format + *(uint16_t *)data = s; + break; + } + case 4: { + //DWORD, DINT or REAL type + uint32_t l = htonl(*(uint32_t *)data); + //no swap, just convert to network format + *(uint32_t *)data = l; + break; + } + #ifdef __x86_64__ + case 8: { + //uInt64, Int64 or Float64 + //direct conversion from host to little-endian exists only from SLC6 version + uint64_t l64 = htole64(*(uint64_t *)data); + *(uint64_t *)data = l64; + break; + } + #endif + default: + //nothing to do unknown type + break; + } + } + + // LITTLE-ENDIANNESS --------------------------------------------------------------------------- + void LittleEndianRegister::swapBytesNToH(unsigned char *data, unsigned long size) + { + switch(size) + { + case 1: + //for CHAR and BYTE, nothing to do in that case. + break; + case 2: { + //WORD or INT type + uint16_t s = ntohs(*(uint16_t *)data); + //convert to network format and word swapping + *(uint16_t *)data = _swaps(s); + break; + } + case 4: { + //DWORD, DINT or REAL type + uint32_t l = ntohl(*(uint32_t *)data); + //convert to network format and word swapping + *(uint32_t *)data = _swapl(l); + break; + } + #ifdef __x86_64__ + case 8: { + //uInt64, Int64 or Float64 + //direct conversion from big-endian to host exists only from SLC6 version + uint64_t l64 = be64toh(*(uint64_t *)data); + *(uint64_t *)data = l64; + break; + } + #endif + default: + //nothing to do unknown type + break; + } + } + + void LittleEndianRegister::swapBytesHToN(unsigned char *data, unsigned long size) + { + switch(size) + { + case 1: + //for CHAR and BYTE, nothing to do in that case. + break; + case 2: { + //WORD or INT type + uint16_t s = htons(*(uint16_t *)data); + //convert to network format and word swapping + *(uint16_t *)data = _swaps(s); + break; + } + case 4: { + //DWORD, DINT or REAL type + uint32_t l = htonl(*(uint32_t *)data); + //convert to network format and word swapping + *(uint32_t *)data = _swapl(l); + break; + } + #ifdef __x86_64__ + case 8: { + //uInt64, Int64 or Float64 + //direct conversion from host to big-endian exists only from SLC6 version + uint64_t l64 = htobe64(*(uint64_t *)data); + *(uint64_t *)data = l64; + break; + } + #endif + default: + //nothing to do unknown type + break; + } + } + + + // ---------------------------------------------------------------------------------------- + void PLCRegister::importValue(void* pBuffer, timeval ts) + { + //Compute the register address within the block: block-address + register-offset + unsigned char* pDataBase = ((unsigned char*)pBuffer) + address_; + unsigned char* pData = pDataBase; + + if ((format_ == Int8) || (format_ == uInt8)) + { + //Some PLC use more than 1 byte for this format (exp.: SCHNEIDER aligns char on 16bits) + unsigned int step = memSize_ / dimension1_ / dimension2_ / size_; + /*TODO: + * Optimization a tester: utiliser un memcpy si (step == 1) au lieu du for + * (idem pour l'export) + */ + for (unsigned int i=0; i<(dimension1_); i++) + { + for (unsigned int j=0; j<(dimension2_); j++) // works also for 1d, in this case j is always 0 and points to the element on the array + { + // compact the array by removing the alignment added + ((unsigned char*)pRecvValue_)[(i*dimension2_)+j] = pData[(i*step*dimension2_)+j]; + } + } + } + else + { + if (format_ != Date) + { //Short, uShort, Long, uLong, Float + for (unsigned int i=0; i<(dimension1_*dimension2_); i++) + { + swapBytesNToH(pData, size_); + pData += size_; + } + + //The buffer is correctly aligned and swapped now. We can transfer the value to the register cell. + memcpy(pRecvValue_, (void*)pDataBase, (size_*dimension1_*dimension2_)); + } + else + { + //Date&Time + unsigned long dtSize = size_; //Most of controllers use 64bits coding for DT type + //Beckhoff controller uses 32bits (see below) + + for (unsigned int i=0; i<dimension1_; i++) + { + for (unsigned int j=0; j<dimension2_; j++) // works also for 1d, in this case j is always 0 and points to the element on the array + { + switch(getPLC()->getBrandID()) + { + case Siemens: + ((double *)pRecvValue_)[i*dimension2_+j] = IeRfcGetTime(pData); + break; + case Schneider: + case Digi: + ((double *)pRecvValue_)[i*dimension2_+j] = IeMdbGetTime(pData); + break; + case Ni: + //TODO + break; + case Beckhoff: + //Beckhoff controller implement the standard EPOCH on 32bits word + dtSize = sizeof(uint32_t); + uint32_t *timeVal = (uint32_t *)pData; + swapBytesNToH((unsigned char *)&(timeVal[0]), sizeof(uint32_t)); + ((double *)pRecvValue_)[i*dimension2_+j] = static_cast<double>(timeVal[0]); + break; + } + pData += dtSize; + } + } + } + } + + //Set the register time-stamp + tod_ = ts; + + //DATA topic makes sense with RECV one + if (RECV & Log::topics_) LOG(DATA) << theDevice_->getPLC()->getName() << "/" << theDevice_->getLabel() << "/" << getName() << ", len: " << getLength() << ", dim1: " << getDimension1() << ", dim2: " << getDimension2() << ", ts: " << getTimeStampAsString() << ", value: " << getValAsByteString(pRecvValue_, 10); + } + + + void PLCRegister::exportValue(void* pBuffer) + { + //DATA topic makes sense with SEND one + if (SEND & Log::topics_) LOG(DATA) << theDevice_->getPLC()->getName() << "/" << theDevice_->getLabel() << "/" << getName() << ", len: " << getLength() << ", dim1: " << getDimension1() << ", dim2: " << getDimension2() << ", value: " << getValAsByteString(pSendValue_, 10); + + //Compute the register address within the block: block-address + register-offset + unsigned char* pData = ((unsigned char*)pBuffer) + address_; + + if ((format_ == Int8) || (format_ == uInt8)) + { + //Some PLC use more than 1 byte for this format (exp.: SCHNEIDER aligns char on 16bits) + unsigned int step = memSize_ / dimension1_ / dimension2_ / size_; + + for (unsigned int i=0; i<dimension1_; i++) + { + for (unsigned int j=0; j<(dimension2_); j++) + { + // expand the array by adding required space + pData[(i*step*dimension2_)+j] = ((unsigned char*)pSendValue_)[(i*dimension2_)+j]; + } + } + } + else + { + if (format_ != Date) + { + //Short, uShort, Long, uLong, Float + //Transfert the value of the register cell to the buffer + memcpy((void*)pData, pSendValue_, (size_*dimension1_*dimension2_)); + + for (unsigned int i=0; i<(dimension1_*dimension2_); i++) + { + swapBytesHToN(pData, size_); + pData += size_; + } + } + else + { //Date&Time + unsigned long dtSize = size_; //Most of controllers use 64bits coding for DT type + //Beckhoff controller uses 32bits (see below) + + for (unsigned int i=0; i<(dimension1_*dimension2_); i++) + { + time_t epoch = static_cast<time_t>((double)((double *)pSendValue_)[i]); + switch(getPLC()->getBrandID()) + { + case Siemens: + IeRfcSetTime(pData, epoch); + break; + case Schneider: + case Digi: + IeMdbSetTime(pData, epoch); + break; + case Ni: + //TODO + break; + case Beckhoff: + //Beckhoff controller implement the standard EPOCH on 32bits word + dtSize = sizeof(uint32_t); + uint32_t *timeVal = (uint32_t *)pData; + timeVal[0] = static_cast<uint32_t>(epoch); + swapBytesHToN((unsigned char *)&(timeVal[0]), sizeof(uint32_t)); + break; + } + pData += dtSize; + } + } + } + } + + void PLCRegister::copyValue() + { + //Transfer the value of the recvBuffer to to the sendBuffer + if (format_ == String) + { + std::string** pRecvStringValue_ = static_cast<std::string**>(pRecvValue_); + std::string** pSendStringValue_ = static_cast<std::string**>(pSendValue_); + for(unsigned int i=0; i<(dimension1_*dimension2_); i++) + { + *(pSendStringValue_[i]) = *(pRecvStringValue_[i]); + } + } + else + { + memcpy(pSendValue_, pRecvValue_, (size_*dimension1_*dimension2_)); + } + } + + + // S7 METHODS ------------------------------------------------------------------------------- + void S7Register::importString(void* pBuffer, timeval ts) + { + // Compute the register address within the block: block-address + register-offset + unsigned char* pDataBase = ((unsigned char*)pBuffer) + address_; + std::string** pRecvStringValue_ = static_cast<std::string**>(pRecvValue_); + + //Some PLC use more than 1 byte for this format (exp.: SIEMENS aligns string on 16bits address) + unsigned int step = memSize_ / dimension1_ / dimension2_ / size_; + + // for each string of the single/double array - + for (unsigned long i=0; i<(dimension1_*dimension2_); i++) // scalar has dim1=dim2=1 + { unsigned char* pData = &(pDataBase[i*step]); + pRecvStringValue_[i]->assign((const char*)&(pData[2]), (size_t)pData[1]); + } + //Set the register time-stamp + tod_ = ts; + + //DATA topic makes sense with RECV one + if (RECV & Log::topics_) LOG(DATA) << theDevice_->getPLC()->getName() << "/" << theDevice_->getLabel() << "/" << getName() << ", len: " << getLength() << ", dim1: " << getDimension1() << ", dim2: " << getDimension2() << ", ts: " << getTimeStampAsString() << ", value: " << getValAsByteString(pRecvValue_, 10); + } + + void S7Register::exportString(void* pBuffer) + { + //DATA topic makes sense with SEND one + if (SEND & Log::topics_) LOG(DATA) << theDevice_->getPLC()->getName() << "/" << theDevice_->getLabel() << "/" << getName() << ", len: " << getLength() << ", dim1: " << getDimension1() << ", dim2: " << getDimension2() << ", value: " << getValAsByteString(pSendValue_, 10); + + //Compute the register address within the block: block-address + register-offset + unsigned char* pData = ((unsigned char*)pBuffer) + address_; + std::string** pSendStringValue_ = static_cast<std::string**>(pSendValue_); + + //Some PLC use more than 1 byte for this format (exp.: SIEMENS aligns string on 16bits address) + unsigned int step = memSize_ / dimension1_ / dimension2_ / size_; + + // for each string of the single/double array - + for (unsigned long i=0; i<dimension1_*dimension2_; i++) // scalar has dim1=dim2=1 + { //Current size of the sent string should not exceed the register string max length + std::string sendStringValue = *(pSendStringValue_[i]); + if (sendStringValue.size() > length_) sendStringValue = sendStringValue.substr(0, length_); + // S7 requires that the first two bytes of string are reserved for length and max length of string + pData[(i*step)+0] = (unsigned char)length_ & 0XFF; // convert to byte (max length is 254 (+2) = 1 byte) + pData[(i*step)+1] = (unsigned char)sendStringValue.size() & 0XFF; + memcpy((void *)&(pData[(i*step)+2]), (void *)sendStringValue.c_str(), sendStringValue.size()); + } + } + + // UNITY METHODS ----------------------------------------------------------------------------------- + // TwinCAT object inherit from the same methods than UNITY. + void UnityRegister::importString(void* pBuffer, timeval ts) + { + // Compute the register address within the block: block-address + register-offset + unsigned char* pDataBase = ((unsigned char*)pBuffer) + address_; + std::string** pRecvStringValue_ = static_cast<std::string**>(pRecvValue_); + + //Some PLC use more than 1 byte for this format (exp.: SCHNEIDER aligns char on 16bits) + unsigned int step = memSize_ / dimension1_ / dimension2_ / size_; + + // for each string of the single/double array - + for (unsigned long i=0; i<(dimension1_*dimension2_); i++) // scalar has dim1=dim2=1 + { unsigned char* pData = &(pDataBase[i*step]); + size_t strSize = min((size_t)length_, strlen((const char*)pData)); + pRecvStringValue_[i]->assign((const char*)pData, strSize); + } + tod_ = ts; + + //DATA topic makes sense with RECV one + if (RECV & Log::topics_) LOG(DATA) << theDevice_->getPLC()->getName() << "/" << theDevice_->getLabel() << "/" << getName() << ", len: " << getLength() << ", dim1: " << getDimension1() << ", dim2: " << getDimension2() << ", ts: " << getTimeStampAsString() << ", value: " << getValAsByteString(pRecvValue_, 10); + } + + void UnityRegister::exportString(void* pBuffer) + { + //DATA topic makes sense with SEND one + if (SEND & Log::topics_) LOG(DATA) << theDevice_->getPLC()->getName() << "/" << theDevice_->getLabel() << "/" << getName() << ", len: " << getLength() << ", dim1: " << getDimension1() << ", dim2: " << getDimension2() << ", value: " << getValAsByteString(pSendValue_, 10); + + //Compute the register address within the block: block-address + register-offset + unsigned char* pData = ((unsigned char*)pBuffer) + address_; + std::string** pSendStringValue_ = static_cast<std::string**>(pSendValue_); + + // Some PLC use more than 1 byte for this format (exp.: SCHNEIDER aligns char on 16bits) + unsigned int step = memSize_ / dimension1_ / dimension2_ / size_; + + // for each string of the single/double array - + for (unsigned long i=0; i<dimension1_*dimension2_; i++) // scalar has dim1=dim2=1 + { //Current size of the sent string should not exceed the register string max length + size_t strSize = pSendStringValue_[i]->size(); + std::string sendStringValue = pSendStringValue_[i]->substr(0, min((size_t)length_, strSize)); + bzero((void *)&(pData[i*step]), step); //TwinCAT string requires '\0' terminator (mem-size of the string (~step) has been properly dimensioned in the mapping). + memcpy((void *)&(pData[i*step]), (void *)sendStringValue.c_str(), sendStringValue.size()); + } + } + +} // namespace + diff --git a/silecs-communication-cpp/src/silecs-communication/interface/equipment/PLCRegister.h b/silecs-communication-cpp/src/silecs-communication/interface/equipment/PLCRegister.h new file mode 100644 index 0000000..86dc939 --- /dev/null +++ b/silecs-communication-cpp/src/silecs-communication/interface/equipment/PLCRegister.h @@ -0,0 +1,195 @@ +// Copyright 2016 CERN and GSI +// +// 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 3 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, see <http://www.gnu.org/licenses/>. + +#ifndef _SILECS_PLC_REGISTER_H_ +#define _SILECS_PLC_REGISTER_H_ + +#include <silecs-communication/interface/core/SilecsService.h> +#include <silecs-communication/interface/utility/XMLParser.h> +#include <silecs-communication/interface/equipment/SilecsPLC.h> +#include <silecs-communication/interface/equipment/SilecsDevice.h> +#include <silecs-communication/interface/equipment/SilecsRegister.h> +#include <silecs-communication/interface/utility/SilecsException.h> +#include <silecs-communication/interface/utility/SilecsLog.h> +#include <silecs-communication/interface/utility/StringUtilities.h> +#include <silecs-communication/protocol/core/silecs.h> + +#ifdef __x86_64__ +#include <endian.h> +#endif + +namespace Silecs +{ + /// @cond + class PLCRegister : public Register + { + private: + + protected: + PLCRegister(Device* theDevice,const boost::shared_ptr<ElementXML>& registerNode); + virtual ~PLCRegister(); + + // export register extraction methods + friend class PLC; + friend class Device; + + /*! + * \fn importValue + * \brief Used to convert and transfered data from the data-block receiver to the register value + * Overloads the virtual method inherited from the class SilecsRegister. + * \param pBuffer points the data-block buffer + * \param ts is the time-of-day to time-stamp the register + */ + void importValue(void* pBuffer, timeval ts); + + /*! + * \fn exportValue + * \brief Used to transfer the register value to the data data-block to be sent + * Overloads the virtual method inherited from the class SilecsRegister. + * \param pBuffer points the data-block buffer + */ + void exportValue(void* pBuffer); + + /*! + * \fn copyValue + * \brief Copies the register content from the input buffer the output buffer. + * Overloads the virtual method inherited from the class SilecsRegister. + * This method is used for Retentive InOut registers synchronization. + */ + void copyValue(); + + /// Generic methods for byte-swapping --------------------------------- + virtual uint16_t _swaps(uint16_t s); + virtual uint32_t _swapl(uint32_t l); + virtual float _swapf(float f); + virtual double _swapd(double d); + + virtual void swapBytesNToH(unsigned char *data, unsigned long size) = 0; + virtual void swapBytesHToN(unsigned char *data, unsigned long size) = 0; + + }; + + + /*! + * \class BigEndianRegister + * \brief Specific register using Big-endian memory convention + */ + class BigEndianRegister : public PLCRegister + { + + public: + BigEndianRegister(Silecs::Device* theDevice,const boost::shared_ptr<ElementXML>& registerNode); + virtual ~BigEndianRegister(); + + protected: + void swapBytesNToH(unsigned char *data, unsigned long size); + void swapBytesHToN(unsigned char *data, unsigned long size); + + }; + + + /*! + * \class LittleEndianRegister + * \brief Specific register using Little-endian memory convention + */ + class LittleEndianRegister : public PLCRegister + { + + public: + LittleEndianRegister(Silecs::Device* theDevice,const boost::shared_ptr<ElementXML>& registerNode); + virtual ~LittleEndianRegister(); + + protected: + void swapBytesNToH(unsigned char *data, unsigned long size); + void swapBytesHToN(unsigned char *data, unsigned long size); + + }; + + /*! + * \class S7Register + * \brief Specific register for S7 hardware + */ + class S7Register : public BigEndianRegister + { + public: + S7Register(Silecs::Device* theDevice,const boost::shared_ptr<ElementXML>& registerNode); + virtual ~S7Register(); + + private: + /*! + * \fn importString + * \brief Used to convert and transfer strings from the data-block receiver to the register value + * \param pBuffer points the data-block buffer + * \param ts is the time-of-day to timestamp the register + */ + void importString(void* pBuffer, timeval ts); + + /*! + * \fn exportString + * \brief Used to transfer the register value to the data-block to be sent + * \param pBuffer points the data-block buffer + */ + void exportString(void* pBuffer); + + }; + + /*! + * \class UnityRegister + * \brief Specific register for Schneider hardware + */ + class UnityRegister : public LittleEndianRegister + { + public: + UnityRegister(Silecs::Device* theDevice,const boost::shared_ptr<ElementXML>& registerNode); + virtual ~UnityRegister(); + + private: + /*! + * \fn importString + * \brief Used to convert and transfer strings from the data-block receiver to the register value + * \param pBuffer points the data-block buffer + * \param ts is the time-of-day to timestamp the register + */ + void importString(void* pBuffer, timeval ts); + + /*! + * \fn exportString + * \brief Used to transfer the register value to the data-block to be sent + * \param pBuffer points the data-block buffer + */ + void exportString(void* pBuffer); + + }; + + /*! + * \class TwinCATRegister + * \brief Beckhoff BCxx/CXxx PLC use the same memory swapping than Unity PLCs except for float32 data + * This class is used to specialized the 32bits data swapping inherited from the UnityRegister class. + * It overwrites the swapl() method responsible for 32bits data swapping. + */ + class TwinCATRegister : public UnityRegister + { + public: + TwinCATRegister(Silecs::Device* theDevice,const boost::shared_ptr<ElementXML>& registerNode); + virtual ~TwinCATRegister(); + + protected: + //Dedicated method for specific 64bit swapping (other come from the base-class) + uint32_t _swapl(uint32_t l); + }; + /// @endcond + +} +#endif // _SILECS_PLC_REGISTER_H_ diff --git a/silecs-communication-cpp/src/silecs-communication/interface/equipment/SilecsBlock.cpp b/silecs-communication-cpp/src/silecs-communication/interface/equipment/SilecsBlock.cpp new file mode 100644 index 0000000..bb4ee71 --- /dev/null +++ b/silecs-communication-cpp/src/silecs-communication/interface/equipment/SilecsBlock.cpp @@ -0,0 +1,114 @@ +// Copyright 2016 CERN and GSI +// +// 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 3 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, see <http://www.gnu.org/licenses/>. + +#include <silecs-communication/interface/core/SilecsService.h> +#include <silecs-communication/interface/utility/Thread.h> +#include <silecs-communication/interface/utility/XMLParser.h> +#include <silecs-communication/interface/equipment/SilecsPLC.h> +#include <silecs-communication/interface/equipment/SilecsBlock.h> +#include <silecs-communication/interface/equipment/SilecsRegister.h> +#include <silecs-communication/interface/core/SilecsAction.h> +#include <silecs-communication/interface/core/WrapperAction.h> +#include <silecs-communication/interface/utility/SilecsException.h> +#include <silecs-communication/interface/utility/SilecsLog.h> +#include <silecs-communication/interface/utility/StringUtilities.h> + +namespace Silecs +{ + + Block::Block(PLC* thePLC, ElementXML blockNode, AccessType accessType) : + thePLC_ (thePLC), hasMaster_(false), hasSlave_(false) + { + std::string designName = blockNode.getAttribute("name"); + + name_ = designName; + StringUtilities::fromString(size_,blockNode.getAttribute("size")); + StringUtilities::fromString(memSize_,blockNode.getAttribute("mem-size")); + StringUtilities::fromString(address_,blockNode.getAttribute("address")); + + resetCustomAttributes(); //by default custom-size of the block is the maximum size + + /*In case of InOut block we will instantiate 2 different blocks (input/output) + * and the accessType is given by the caller. + */ + accessType_ = accessType; + + // Adjust the synchro-type of the block relying on its own registers + // . hasMaster if the block contains 1 MASTER register at least + // . hasSlave if the block contains 1 SLAVE register at least + // can be a mix or none if only Volatile registers + std::vector< boost::shared_ptr<ElementXML> > registerNodes = blockNode.childList_; + std::vector< boost::shared_ptr<ElementXML> >::const_iterator registerIter; + for(registerIter = registerNodes.begin(); registerIter != registerNodes.end(); registerIter++) + { + std::string synchro = (*registerIter)->getAttribute("synchro"); + if (!hasMaster_ && Service::whichSynchroType(synchro) == Master) + hasMaster_ = true; + if (!hasSlave_ && Service::whichSynchroType(synchro) == Slave) + hasSlave_ = true; + } + } + + Block::~Block() + { + if (DEBUG & Log::topics_) LOG(ALLOC) << "Block (delete): " << name_; + + if (pAction_ != NULL) delete pAction_; + if (pTask_ != NULL) delete pTask_; + } + + + AccessType Block::whichAccessType(std::string type) + { + StringUtilities::toLower(type); + if (type == "write-only") return Output; + else if (type == "read-only") return Input; + else if (type == "read-write") return InOut; + else throw SilecsException(__FILE__, __LINE__, DATA_UNKNOWN_ACCESS_TYPE, type); + } + + + std::string Block::whichAccessType(AccessType type) + { + switch(type) + { + case Output: return "WRITE-ONLY"; break; + case Input: return "READ-ONLY"; break; + case InOut: return "READ-WRITE"; break; + default: throw SilecsException(__FILE__, __LINE__, DATA_UNKNOWN_ACCESS_TYPE, StringUtilities::toString(type)); + } + } + + void Block::setCustomAttributes(const unsigned long customAddress, const unsigned long customOffset, const unsigned long customSize) + { + //user wants to limit the size of data to be sent/receive - check that it is lower than design allocation size + if (customSize > memSize_) + throw SilecsException(__FILE__, __LINE__, PARAM_EXCEEDED_BLOCK_SIZE, StringUtilities::toString(memSize_)); + + customAddress_ = customAddress; + customOffset_ = customOffset; + customSize_ = customSize; + customAttributes_ = true; + LOG(DEBUG) << "Set custom attributes of block: " << name_ << ", memSize: " << memSize_ << ", customSize: " << customSize << ", customAddress: " << customAddress << ", customOffset: " << customOffset; + } + + void Block::resetCustomAttributes() + { + customAttributes_ = false; + LOG(DEBUG) << "Reset custom attributes of block: " << name_; + } + + +} // namespace diff --git a/silecs-communication-cpp/src/silecs-communication/interface/equipment/SilecsBlock.h b/silecs-communication-cpp/src/silecs-communication/interface/equipment/SilecsBlock.h new file mode 100644 index 0000000..01dbdac --- /dev/null +++ b/silecs-communication-cpp/src/silecs-communication/interface/equipment/SilecsBlock.h @@ -0,0 +1,122 @@ +// Copyright 2016 CERN and GSI +// +// 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 3 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, see <http://www.gnu.org/licenses/>. + +#ifndef _SILECS_BLOCK_H_ +#define _SILECS_BLOCK_H_ + +#include <silecs-communication/interface/core/SilecsService.h> +#include <silecs-communication/interface/utility/Thread.h> + +#include <boost/shared_ptr.hpp> + +namespace Silecs +{ + class Action; + class WrapperAction; + class PLC; + class ElementXML; + + /*! ----------------------------------------------------------------------- + * \class Block + * \brief This object maintains a reference of all the device registers. + * It is responsible to serialize, de-serialize data for the network transfer + * (alignment, data swapping, ..). It can be used also to trig the communication + * for a particular device (make sense for DEVICE-MODE only) if needed. + */ + class Block + { + + public: + Block(PLC* thePLC, ElementXML blockNode, AccessType accessType); + virtual ~Block(); + + /*! + * \fn whichAccessType + * \return the enumeration value of the given access-type string + */ + static AccessType whichAccessType(std::string type); + static std::string whichAccessType(AccessType type); + + inline bool hasInputAccess() { return (accessType_ != Output); } + inline bool hasOutputAccess() { return (accessType_ != Input); } + + inline PLC* getPLC() { return thePLC_; } + inline std::string& getName() { return name_; } + inline AccessType getAccessType() { return (accessType_); } + inline unsigned long& getAddress() { return address_; } + inline unsigned long& getMemSize() { return memSize_; } + inline Task<WrapperAction>* getTask() { return pTask_; } + inline void* getBuffer() { return pBuffer_; } + inline bool hasMasterRegister() { return hasMaster_; } + inline bool hasSlaveRegister() { return hasSlave_; } + + /// @cond + void setCustomAttributes(const unsigned long customAddress, const unsigned long customOffset, const unsigned long customSize); + void resetCustomAttributes(); + inline bool& withCustomAttributes() { return customAttributes_; } + inline unsigned long& getCustomAddress() { return customAddress_; } + inline unsigned long& getCustomOffset() { return customOffset_; } + inline unsigned long& getCustomSize() { return customSize_; } + /// @endcond + + protected: + friend class Device; + + /// Parent PLC reference of that device + PLC* thePLC_; + + /// Block attributes + std::string name_; + + /// Block access-type: Input, Output or InOut + AccessType accessType_; + + /// Block size + unsigned long size_; + + /// Block memory size (including alignments) + unsigned long memSize_; + + /* Block custom attributes + * Can be used to limit dynamically the size of sent/received data. + * Interesting for specific application. (e.g. Cryo) which design maximum size of the block and adjust + * the real data size at runtime (using PLC::setCustomBlockAttributes() method. + * !! This mechanism can be used only with device access mode (DEVICE-MODE or BLOCK-MODE from device) + */ + // Flag used to enable/disable use of custom attributes + bool customAttributes_; + unsigned long customAddress_; + unsigned long customOffset_; + unsigned long customSize_; + + unsigned long address_; + + /// Related PLC task to this data-block + Action* pAction_; + Task<WrapperAction>* pTask_; + + // Send/Receive data buffer + void *pBuffer_; + + /// True if the block contains 1 MASTER and/or 1 Slave register at least + /// MASTER en SLAVE registers can be mixed in the same block. + /// Only Volatile (NONE) ==> both are false + bool hasMaster_; + bool hasSlave_; + }; + +} // namespace + +#endif // _SILECS_BLOCK_H_ diff --git a/silecs-communication-cpp/src/silecs-communication/interface/equipment/SilecsCluster.cpp b/silecs-communication-cpp/src/silecs-communication/interface/equipment/SilecsCluster.cpp new file mode 100644 index 0000000..843649f --- /dev/null +++ b/silecs-communication-cpp/src/silecs-communication/interface/equipment/SilecsCluster.cpp @@ -0,0 +1,250 @@ +// Copyright 2016 CERN and GSI +// +// 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 3 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, see <http://www.gnu.org/licenses/>. + +#include <silecs-communication/interface/equipment/SilecsCluster.h> +#include <silecs-communication/interface/equipment/SilecsPLC.h> +#include <silecs-communication/interface/equipment/SilecsDevice.h> +#include <silecs-communication/interface/equipment/SilecsBlock.h> +#include <silecs-communication/interface/utility/SilecsException.h> +#include <silecs-communication/interface/utility/SilecsLog.h> +#include <silecs-communication/protocol/core/silecs.h> + +namespace Silecs +{ + bool ClusterConfig::getSharedConnection() const + { + return sharedConnection; + } + + void ClusterConfig::setSharedConnection(bool sharedConnectionFlag) + { + sharedConnection = sharedConnectionFlag; + } + + + Cluster::Cluster(const std::string className, const std::string classVersion) : className_ (className), classVersion_ (classVersion) + { + char hostName[128]; + if (gethostname(hostName, 128) == -1) + throw SilecsException(__FILE__, __LINE__, errno, strerror(errno)); + + //store the hostname by removing the domain-name (.cern.ch) if any. + hostName_ = std::string(hostName); + removeDomainName(hostName_); + + //Default run-time configuration setup + configuration.sharedConnection = false; //Do not shared connection with other clusters by default + + LOG((ALLOC|DIAG)) << "CLUSTER (create): " << className_ << "/" << classVersion_; + } + + Cluster::~Cluster() + { + LOG(ALLOC) << "CLUSTER (delete): " << className_ << "/" << classVersion_; + + // Remove the PLCs instances related to this Cluster (hostName_/className_) + plcMapType::iterator plcMapIter; + for(plcMapIter = plcMap_.begin(); plcMapIter != plcMap_.end(); ++plcMapIter) + { delete plcMapIter->second; + } + plcMap_.clear(); + IPAddrMap_.clear(); //this map refer the same PLC object (not necessary to delete them) + } + + void Cluster::removeDomainName(std::string& hostName) + { size_t domain = hostName.find_first_of('.'); + if (domain != std::string::npos) hostName.erase(domain); + } + + bool Cluster::getHostNameByAddress(const std::string IPAddress, std::string& hostName) + { + struct hostent *he = NULL; + struct in_addr ipv4addr; + + if (inet_pton(AF_INET, IPAddress.c_str(), &ipv4addr) == 1) + { he = gethostbyaddr(&ipv4addr, sizeof ipv4addr, AF_INET); + } + + if (he) + { hostName = std::string(he->h_name); + if (DEBUG & Log::topics_) LOG(COMM) << "getHostNameByAddress() IPaddr: " << IPAddress << ", host-name: " << hostName; + return true; + } + return false; + } + + bool Cluster::getAddressByHostName(const std::string hostName, std::string& IPAddress) + { + struct in_addr addr; + struct hostent *hp; + char *ipstr; + + hp = gethostbyname(hostName.c_str()); + if (hp) + { + addr.s_addr = *((unsigned long int *) hp->h_addr); + ipstr = inet_ntoa(addr); + IPAddress = std::string(ipstr); + if (DEBUG & Log::topics_) LOG(COMM) << "getAddressByHostName() host-name: " << hostName << ", IPaddr: " << IPAddress; + return true; + } + return false; + } + + + Block* Cluster::getBlock(const std::string blockName, AccessType accessType) + { // Retrieve the block from the first PLC (same for each of them) + return plcMap_.begin()->second->getBlock(blockName, accessType); + } + + + std::string Cluster::getBlockList(AccessType accessType) + { + std::string blockList = ""; + //At first, check this class/version is already deployed (one PLC in the Cluster at least) + if (plcMap_.size() > 0) + { // Retrieve the block-map from the first PLC (same for each of them) + blockMapType blockMap = plcMap_.begin()->second->getBlockMap(); + + blockMapType::iterator blockMapIter; + //Retrieve the name of each Block object of the Map that has selected access-type + for(blockMapIter = blockMap.begin(); blockMapIter != blockMap.end(); ++blockMapIter) + { Block* pBlock = blockMapIter->second; + if (pBlock->getAccessType() == accessType) + { std::string blockName = pBlock->getName(); + //Do not append the same name twice (read-write Block has two instances) + if (blockList.find(blockName) == std::string::npos) + { //Do not insert blank before the first name + if (!blockList.empty()) blockList.append(" "); + blockList.append(blockName); + } + } + } + } + return blockList; + } + + PLC* Cluster::getPLC(std::string plcID, string parameterFile) + { + //getPLC() supports IP and host-name addressing, but both are required to register the PLC object: + //Host-name will be used to manage related configuration documents. + //IP-addr is used to connect PLC in order to reduce the naming-server accesses. + + //Force PLC hostname lower-case + StringUtilities::toLower(plcID); + + //At first, check if the given ID is already registered in that Cluster (host-name or IP-address) + bool plcNotFound = false; + plcMapType::iterator iter = plcMap_.find(plcID); //check the host-name map at first + if (iter == plcMap_.end()) + { //we didn't find PLC by host-name, try to find it by IP address + iter = IPAddrMap_.find(plcID); + plcNotFound = (iter == IPAddrMap_.end()); + } + + if (plcNotFound) + { + //Retrieve Host-name & IP-address of the PLC + std::string hostName; + std::string IPAddress; + + if (isdigit(plcID[0])) + { //user provided an IP address (start with digit character) + IPAddress = plcID; + if (!getHostNameByAddress(IPAddress, hostName)) + throw SilecsException(__FILE__, __LINE__, PARAM_UNKNOWN_IP_ADDRESS, IPAddress); + } + else + { //user provided an PLC network name (start with alpha-character) + hostName = plcID; + if (!getAddressByHostName(hostName, IPAddress)) + throw SilecsException(__FILE__, __LINE__, PARAM_UNKNOWN_PLC_HOSTNAME, hostName); + } + removeDomainName(hostName); //remove ".cern.ch" if any + + //Then create the new instance of the PLC + + PLC* pPLC = new PLC(this, hostName, IPAddress, parameterFile); + plcMap_.insert(std::make_pair(hostName, pPLC)); //update host-name map + IPAddrMap_.insert(std::make_pair(IPAddress, pPLC)); //update IP address map + return pPLC; + } + return iter->second; + } + + + std::string Cluster::getHostName() { return hostName_; } + std::string Cluster::getClassName() { return className_; } + std::string Cluster::getClassVersion() { return classVersion_; } + + + std::string Cluster::getPLCList() + { + std::string PLCList = ""; + plcMapType::iterator plcMapIter; + for(plcMapIter = plcMap_.begin(); plcMapIter != plcMap_.end(); ++plcMapIter) + { if (!PLCList.empty()) PLCList.append(" "); + PLCList.append(plcMapIter->second->getName()); + } + return PLCList; + } + + + const plcMapType& Cluster::getPLCMap() { return plcMap_; } + + + void Cluster::recv(std::string blockName) + { + //Asynchronous data receive + plcMapType::iterator plcMapIter; + + // Schedule task on each PLC using asynchronous call for parallelism + for(plcMapIter = plcMap_.begin(); plcMapIter != plcMap_.end(); ++plcMapIter) + { plcMapIter->second->recvAsync(blockName); + } + + // then wait for the completion of each PLC thread (finally, maximum delay will be the longest one). + for(plcMapIter = plcMap_.begin(); plcMapIter != plcMap_.end(); ++plcMapIter) + { plcMapIter->second->waitAsync(); + } + } + + + void Cluster::send(std::string blockName) + { + //Asynchronous data send + plcMapType::iterator plcMapIter; + + // Schedule task on each PLC using asynchronous call for parallelism + for(plcMapIter = plcMap_.begin(); plcMapIter != plcMap_.end(); ++plcMapIter) + { plcMapIter->second->sendAsync(blockName); + } + + // then wait for the completion of each PLC thread (finally, maximum delay will be the longest one). + for(plcMapIter = plcMap_.begin(); plcMapIter != plcMap_.end(); ++plcMapIter) + { plcMapIter->second->waitAsync(); + } + } + + void Cluster::copyInToOut(const std::string blockName) + { + plcMapType::iterator plcMapIter; + for(plcMapIter = plcMap_.begin(); plcMapIter != plcMap_.end(); ++plcMapIter) + plcMapIter->second->copyInToOut(blockName); + } + + +} // namespace + diff --git a/silecs-communication-cpp/src/silecs-communication/interface/equipment/SilecsCluster.h b/silecs-communication-cpp/src/silecs-communication/interface/equipment/SilecsCluster.h new file mode 100644 index 0000000..2d523ec --- /dev/null +++ b/silecs-communication-cpp/src/silecs-communication/interface/equipment/SilecsCluster.h @@ -0,0 +1,202 @@ +// Copyright 2016 CERN and GSI +// +// 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 3 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, see <http://www.gnu.org/licenses/>. + +#ifndef _SILECS_CLUSTER_H_ +#define _SILECS_CLUSTER_H_ + +#include <silecs-communication/interface/core/SilecsService.h> +#include <silecs-communication/interface/utility/Thread.h> +#include <map> +#include <vector> + +namespace Silecs +{ + class Cluster; + class PLC; + class Device; + class Block; + class WrapperAction; + + /// @cond + typedef std::map<std::string, std::vector<Task<WrapperAction> >* > taskMapType; + /// @endcond + typedef std::map<std::string, PLC*> plcMapType; + + /*! + * \class ClusterConfig + * \brief Run-time configuration of the cluster. + * The default parameters of the cluster can be changed by setting the public Cluster::configuration structure. + * \param sharedConnection = true to share the same connection with other clusters deployed on that PLC. + * By default the sharedConnection of the cluster is false, and it uses a dedicated connection (2 channels: r/w) + * to communicate with the controller. + * Setting the configuration parameters must be done at first just after getting the cluster from the service. + */ + class ClusterConfig + { + public: + ClusterConfig():sharedConnection(false) {}; + ClusterConfig(bool sharedConnectionFlag):sharedConnection(sharedConnectionFlag) {}; + + bool getSharedConnection() const; + void setSharedConnection(bool sharedConnectionFlag); + + //private: direct access of the variable is deprecated - should be private from next MAJOR release (use set/get only) + bool sharedConnection; //default: not shared (1 dedicated connection (r+w) per class per PLC. + }; + + //deprecated type - User should use directly Silecs::ClusterConfig class + typedef ClusterConfig clusterConfigType; + + /*! + * \class Cluster + * \brief An SILECS configuration is defined by a class name and a version number. + * A Cluster is a tree that defines the set of components for a given configuration. + * It's the root component of the tree that is used to instantiate each PLC object + * in which is deployed the given class/version configuration. + * Finally, the Cluster is the entry point to create and clean-up all the SILECS resources + * within the process. + * It can be used to trig the data-block exchanges for all PLCs of the Cluster at the same time. + */ + class Cluster + { + + public: + /*! + * \brief Returns the network name of the client process host + * \return client host-name + */ + std::string getHostName(); + + /*! + * \brief Returns the name of the SILECS class attached to the Cluster + * \return class name + */ + std::string getClassName(); + + /*! + * \brief Returns the version number of the SILECS class attached to the Cluster + * \return class version + */ + std::string getClassVersion(); + + /*! + * \brief Provides the list of Blocks defined in the corresponding Class/Version. + * At least one PLC must be attached (connected) to the Cluster, otherwise getBlockList() + * returns an empty string. + * \param select access-type of the blocks (Input, Output, InOut) + * \return String list (space separated value) of Blocks name that have selected access-type + */ + std::string getBlockList(AccessType accessType); + + /*! + * \brief Returns a PLC instance of the Cluster, by its name or IP-address + * Instantiates a new PLC object if required, on the first call. + * The related class/version must be deployed in that PLC (else generate an Exception). + * The PLC connection is disabled for the time being. + * \param plcID host-name or IP-address of the PLC + * \param parameterFile parameterFile whixch should be used to configure this PLC + * \return Reference of the PLC object + */ + PLC* getPLC(std::string plcID, string parameterFile); + + /*! + * \brief Provides the list of the PLCs attached to the Cluster (using getPLC() method) + * \return String list (space separated value) of PLCs name + */ + std::string getPLCList(); + + /*! + * \brief Provides the map of the PLC objects attached to the Cluster (using getPLC() method) + * \return PLC object map + */ + const plcMapType& getPLCMap(); + + /*! + * \brief Acquires one particular registers block of all devices of all enabled PLCs of that cluster. + * The method tries to (re)connect each PLC if the connection is not established yet or unexpectedly interrupted (network failure, PLC down, etc.). + * \param blockName name of the block to be acquired + */ + void recv(std::string blockName); + + /*! + * \brief Transmits the registers block to all devices of all enabled PLCs of that cluster. + * The method tries to (re)connect each PLC if the connection is not established yet or unexpectedly interrupted (network failure, PLC down, etc.). + * \param blockName name of the block to be transmitted + */ + void send(std::string blockName); + + /*! + * \brief Copies input buffer in output buffer + * The method copies the input buffer in the output buffer for each READ-WRITE register register in the cluster for the block passed as parameter + * \param blockName name of the block for which the copy must be performed + */ + void copyInToOut(const std::string blockName); + + /*! + * \struct configuration + * \brief Run-time configuration of the cluster. + * The default parameters of the cluster can be changed by setting the public Cluster::configuration structure. + * \param sharedConnection = true to share the same connection with other clusters deployed on that PLC. + * By default the sharedConnection of the cluster is false, and it uses a dedicated connection (2 channels: r/w) + * to communicate with the controller. + */ + clusterConfigType configuration; + + private: + friend class Service; + friend class PLC; + friend class Device; + + // private, because this class is a unique per className + Cluster(const std::string className, const std::string classVersion); + + /*! + * \brief The client process is responsible to delete the Cluster object that has been + * instantiated with getCluster() call. + * Deleting the Cluster object delete also all the related components of that Cluster + * (PLCs, Devices and Registers) + */ + ~Cluster(); + + /*! + * \brief returns the input hostname without domain-name extension (cern.ch for instance) + */ + void removeDomainName(std::string& hostName); + + bool getHostNameByAddress(const std::string IPAddress, std::string& hostName); + bool getAddressByHostName(const std::string hostName, std::string& IPAddress); + + /*! + * \fn getBlock + * \brief returns one instance of the requested block checking its access-type + */ + Block* getBlock(const std::string blockName, AccessType accessType = InOut); + + /// Store the current FEC name + std::string hostName_; + + /// Class related to the cluster + std::string className_; + std::string classVersion_; + + /// PLC collection of the cluster + plcMapType plcMap_; //by plc hostname + plcMapType IPAddrMap_; //by plc IP address + + }; + +} // namespace + +#endif // _SILECS_CLUSTER_H_ diff --git a/silecs-communication-cpp/src/silecs-communication/interface/equipment/SilecsDevice.cpp b/silecs-communication-cpp/src/silecs-communication/interface/equipment/SilecsDevice.cpp new file mode 100644 index 0000000..e609f60 --- /dev/null +++ b/silecs-communication-cpp/src/silecs-communication/interface/equipment/SilecsDevice.cpp @@ -0,0 +1,284 @@ +// Copyright 2016 CERN and GSI +// +// 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 3 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, see <http://www.gnu.org/licenses/>. + +#include <silecs-communication/interface/equipment/SilecsDevice.h> + +#include <silecs-communication/interface/core/Context.h> +#include <silecs-communication/interface/core/SilecsService.h> +#include <silecs-communication/interface/core/WrapperAction.h> +#include <silecs-communication/interface/equipment/SilecsBlock.h> +#include <silecs-communication/interface/equipment/SilecsCluster.h> +#include <silecs-communication/interface/equipment/SilecsPLC.h> +#include <silecs-communication/interface/equipment/SilecsRegister.h> +#include <silecs-communication/interface/equipment/PLCRegister.h> +#include <silecs-communication/interface/utility/SilecsException.h> +#include <silecs-communication/interface/utility/SilecsLog.h> +#include <silecs-communication/interface/utility/XMLParser.h> + +#include <silecs-communication/interface/equipment/CNVRegister.h> + +namespace Silecs +{ + Device::Device(PLC* thePLC, std::string deviceName, std::string deviceAddress, boost::ptr_vector<ElementXML>& blockNodes) : thePLC_ (thePLC) + { + // Update Device ElementXML attributes + label_ = deviceName; + StringUtilities::fromString(address_,deviceAddress ); + + LOG(ALLOC) << "Device (create): " << label_; + + boost::ptr_vector<ElementXML>::const_iterator blockIter; + for(blockIter = blockNodes.begin(); blockIter != blockNodes.end(); blockIter++) + { + std::string blockName = blockIter->getAttribute("name"); + AccessType accessType = Block::whichAccessType(blockIter->getAttribute("mode")); + std::vector< boost::shared_ptr<ElementXML> > registerNodes = blockIter->childList_; + instantiateRegisters(blockName, accessType, registerNodes); + } + } + + Device::~Device() + { + LOG(ALLOC) << "Device (delete): " << label_; + + // Remove the register instances related to this Device + registerVectorType::iterator pRegisterIter; + for(pRegisterIter = registerCol_.begin(); pRegisterIter != registerCol_.end(); ++pRegisterIter) delete pRegisterIter->second; + registerCol_.clear(); + + // Register instances have been deleted before, just clear the block-register Map. + blockRegisterMap_.clear(); + } + + + PLC* Device::getPLC() + { return thePLC_; + } + + + Register* Device::getRegister(std::string registerName) + { + registerVectorType::iterator iter; + for(iter = registerCol_.begin(); iter != registerCol_.end(); ++iter) + { + if (iter->first == registerName) + { + return iter->second; + } + } + throw SilecsException(__FILE__, __LINE__, PARAM_UNKNOWN_REGISTER_NAME, registerName); + return NULL; // to suppress warning + } + + + std::vector<Register*>& Device::getRegisterCollection(std::string blockName) + { + blockRegisterMapType::iterator iter = blockRegisterMap_.find(blockName); + if (iter == blockRegisterMap_.end()) + { throw SilecsException(__FILE__, __LINE__, PARAM_UNKNOWN_BLOCK_NAME, blockName); + } + return iter->second; + } + + + int Device::recv(std::string blockName) + { + //Synchronous device data receive + + //Context of the transaction: + //this = the device to be treated, + //false = is not for registers synchronization (normal transaction) + Context context(this, false); + + //Execute the receive action for the required device (from the current thread) + return getBlock(blockName, Input)->getTask()->execute(&context); + } + + + int Device::send(std::string blockName) + { + //Synchronous device data send + + //Context of the transaction: + //this = the device to be treated, + //false = is not for registers synchronization (normal transaction) + Context context(this, false); + + //Execute the receive action for the required device (from the current thread) + return getBlock(blockName, Output)->getTask()->execute(&context); + } + + + std::string Device::getLabel() { return label_; } + + + std::string Device::getRegisterList() + { + std::string registerList = ""; + registerVectorType::iterator pRegisterIter; + for(pRegisterIter = registerCol_.begin(); pRegisterIter != registerCol_.end(); ++pRegisterIter) + { if (!registerList.empty()) registerList.append(" "); + registerList.append(pRegisterIter->second->getName()); + } + return registerList; + } + + + Register* Device::instantiateRegister(const boost::shared_ptr<ElementXML>& registerNode) + { + switch (getPLC()->getBrandID()) + { + // SIEMENS PLCs use Motorola memory convention (BigEndianRegister) + case Siemens: + return new S7Register(this, registerNode); + + // SCHNEIDER PLCs use Intel memory convention (LittleEndianRegister) + // RABBIT microcontrollers use Intel memory convention (LittleEndianRegister) + case Schneider: + case Digi: + return new UnityRegister(this, registerNode); + + // BECKHOFF PLCs use different memory convention depending on PLC type: + // . CX model: same convention than Unity + // . BC model: special convention for 64 bits data (float, ..): swap only the two 16bits words together (no bytes swap). + case Beckhoff: + return new TwinCATRegister(this, registerNode); + +#ifdef NI_SUPPORT_ENABLED + //NI Shared variables use specific convention + case Ni: + return new CNVRegister(this, registerNode); +#endif + + default: + throw SilecsException(__FILE__, __LINE__, DATA_UNKNOWN_PLC_MANUFACTURER, getPLC()->getBrand()); + + } //switch + } + + + void Device::instantiateRegisters(std::string blockName, AccessType accessType, std::vector< boost::shared_ptr<ElementXML> >& registerNodes) + { + std::vector<Register*> registerCol; + + //LOG(SETUP) << "Ordering registers for block: " << blockName << " on Device: " << getLabel(); + + std::vector< boost::shared_ptr<ElementXML> >::const_iterator registerIter; + for(registerIter = registerNodes.begin(); registerIter != registerNodes.end(); registerIter++) + { + std::string registerName = (*registerIter)->getAttribute("name"); + Register* pReg = instantiateRegister(*registerIter); + pReg->setAccessType(accessType); + pReg->setBlockName(blockName); + registerCol.push_back(pReg); + registerCol_.push_back(std::make_pair(registerName, pReg)); + } + blockRegisterMap_.insert(std::make_pair(blockName, registerCol)); + } + + void Device::keepMasterRegisters(std::string blockName) + { + blockRegisterMapType::iterator iter = blockRegisterMap_.find(blockName); + if (iter == blockRegisterMap_.end()) + { throw SilecsException(__FILE__, __LINE__, PARAM_UNKNOWN_BLOCK_NAME, blockName); + } + + for (unsigned int i=0; i<iter->second.size(); i++) + { Register* pReg = iter->second[i]; + if (pReg->getSynchroType() == Master) pReg->copyValue(); + } + } + + Block* Device::getBlock(const std::string blockName, AccessType accessType) + { return thePLC_->getBlock(blockName, accessType); + } + + + void Device::importRegisters(Block* pBlock, void* pBuffer, timeval ts, Context* pContext) + { + std::vector<Register*>& registerCol = getRegisterCollection(pBlock->getName()); + + if (pContext->isForSynchronization()) + { // Transaction has been done within the context of retentive registers synchronization, + // do not update volatile registers (client has to force a transaction himself if required). + for (unsigned int i=0; i<registerCol.size(); i++) + { + Register* pReg = registerCol[i]; + if (pReg->isRetentive()) + { + if(pReg->getFormat() == String) + pReg->importString(pBuffer, ts); + else // all registers but those having string format + pReg->importValue(pBuffer, ts); + } + } + } + else + { // It's a normal transaction from the client process, + // all registers of the block have to be updated. + for (unsigned int i=0; i<registerCol.size(); i++) + { + if(registerCol[i]->getFormat() == String) + registerCol[i]->importString(pBuffer, ts); + else // all registers but those having string format + registerCol[i]->importValue(pBuffer, ts); + } + } + } + + void Device::exportRegisters(Block* pBlock, void* pBuffer, Context* pContext) + { + std::vector<Register*>& registerCol = getRegisterCollection(pBlock->getName()); + + if (pContext->isForSynchronization()) + { // Transaction has been done within the context of retentive registers synchronization, + // do not update volatile register (client has to force a transaction himself if required). + for (unsigned int i=0; i<registerCol.size(); i++) + { + Register* pReg = registerCol[i]; + if (pReg->isRetentive()) + { + if(pReg->getFormat() == String) + pReg->exportString(pBuffer); + else // all registers but those having string format + pReg->exportValue(pBuffer); + } + } + } + else + { // It's a normal transaction from the client process, + // all registers of the block have to be updated. + for (unsigned int i=0; i<registerCol.size(); i++) + { + if(registerCol[i]->getFormat() == String) + registerCol[i]->exportString(pBuffer); + else + registerCol[i]->exportValue(pBuffer); + } + } + } + + void Device::copyInToOut(const std::string blockName) + { + std::vector<Register*>& registerCol = getRegisterCollection(blockName); + for (unsigned int i=0; i<registerCol.size(); i++) + { Register* pReg = registerCol[i]; + if (pReg->hasInputAccess() && pReg->hasOutputAccess()) + pReg->copyValue(); + } + + } + +} // namespace diff --git a/silecs-communication-cpp/src/silecs-communication/interface/equipment/SilecsDevice.h b/silecs-communication-cpp/src/silecs-communication/interface/equipment/SilecsDevice.h new file mode 100644 index 0000000..11014b1 --- /dev/null +++ b/silecs-communication-cpp/src/silecs-communication/interface/equipment/SilecsDevice.h @@ -0,0 +1,184 @@ +// Copyright 2016 CERN and GSI +// +// 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 3 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, see <http://www.gnu.org/licenses/>. + +#ifndef _SILECS_DEVICE_H_ +#define _SILECS_DEVICE_H_ + +#include <silecs-communication/interface/core/SilecsService.h> + +#include <string> +#include <vector> +#include <map> + +#include <boost/shared_ptr.hpp> +#include <boost/ptr_container/ptr_vector.hpp> + +namespace Silecs +{ + class PLC; + class Block; + class ElementXML; + class Register; + class Context; + + /// @cond + typedef std::vector<std::pair<std::string, Register*> > registerVectorType; + typedef std::map<std::string, std::vector<Register*> > blockRegisterMapType; + /// @endcond + + /*! + * \class Device + * \brief This object maintains a reference of all the device registers. + * It is responsible to serialize, de-serialize data for the network transfer (alignment, data swapping, ..). + * It can be used to trig the data-block exchange for one particular device (make sense for DEVICE-MODE only). + */ + class Device + { + public: + + /*! + * \brief Returns reference of the PLC where the device is instantiated + * \return Reference of the PLC object + */ + PLC* getPLC(); + + /*! + * \brief Returns the label of the device as defined in the Deployment document. + * A device label is not visible from the supervision. It's the device identifier within + * the PLC/Class scope. If label has not been defined, the device is identified by its + * corresponding index [1..n] in the device collection. + * \return label or index of the device as string + */ + std::string getLabel(); + + /*! + * \brief Returns one register instance of the device by its name + * \param registerName name of the register + * \return Reference of the register object + */ + Register* getRegister(std::string registerName); + + /*! + * \brief Acquires one particular registers block of the device. + * The method tries to (re)connect the PLC if the connection is not established yet or unexpectedly interrupted (network failure, PLC down, etc.). + * It generates an Silecs::SilecsException if the related PLC has not been enabled (using the connect() method). + * \param blockName name of the block to be acquired + * \return 0 if operation was successful else an error code (when available). + */ + int recv(std::string blockName); + + /*! + * \brief Transmits the registers block to the device + * The method tries to (re)connect the PLC if the connection is not established yet or unexpectedly interrupted (network failure, PLC down, etc.). + * It generates an Silecs::SilecsException if the related PLC has not been enabled (using the connect() method). + * \param blockName name of the block to be transmitted + * \return 0 if operation was successful else an error code (when available). + */ + int send(std::string blockName); + + /*! + * \brief Copies input buffer in output buffer + * The method copies the input buffer in the output buffer for each READ-WRITE register for the block passed as parameter + * \param blockName name of the block for which the copy must be performed + */ + void copyInToOut(const std::string blockName); + + /// @cond + /*! + * \return all registers of the device for a given block + */ + std::vector<Register*>& getRegisterCollection(std::string blockName); + + /*! + * \return String list (space separated value) of the Device registers + */ + std::string getRegisterList(); + /// @endcond + + private: + // export device attributes to the Actions + friend class PLC; + friend class Register; + friend class PLCRegister; + friend class PLCRecvBlockMode; + friend class PLCRecvDeviceMode; + friend class PLCSendBlockMode; + friend class PLCSendDeviceMode; + friend class Context; + + friend class CNVRegister; + friend class CNVRecvBlockMode; + friend class CNVRecvDeviceMode; + friend class CNVSendBlockMode; + friend class CNVSendDeviceMode; + + Device(PLC* thePLC, std::string deviceName, std::string deviceAddress, boost::ptr_vector<ElementXML>& blockNodes); + virtual ~Device(); + + inline unsigned long& getAddress() { return address_; } + + Register* instantiateRegister(const boost::shared_ptr<ElementXML>& registerNode); + + void instantiateRegisters(std::string blockName, AccessType accessType, std::vector< boost::shared_ptr<ElementXML> >& registerNodes); + + /*! + * \fn keepMasterRegisters + * \brief This method is used for Retentive registers synchronization on each PLC (re)connection. + * Update local value of the RW Master registers to maintain the PLC values during + * the synchronization of Slave registers. + */ + void keepMasterRegisters(std::string blockName); + + /*! + * \fn getBlock + * \brief returns one instance of the requested block checking its access-type + */ + Block* getBlock(const std::string blockName, AccessType accessType = InOut); + + /*! + * \fn importRegisters + * \brief Extract all the concerned registers data of that device from a given block and set the registers value. + * \param pBlock: block which contain list of registers to be imported + * \param pBuffer: direct pointer on the buffer which contain the registers data + * \param ts is the time-of-day to time-stamp each register + */ + void importRegisters(Block* pBlock, void* pBuffer, timeval ts, Context* pContext); + + /*! + * \fn exportRegisters + * \brief Export all the concerned registers value of that device to a given block. + * \param pBlock: block which contain list of registers to be exported + * \param pBuffer: direct pointer on the buffer which will contain the registers data + */ + void exportRegisters(Block* pBlock, void* pBuffer, Context* pContext); + + /// Parent PLC reference of that device + PLC* thePLC_; + + /// Device attributes + std::string label_; + unsigned long address_; + + /// Register collection of that device + registerVectorType registerCol_; + + /// Collections of the device registers by block + blockRegisterMapType blockRegisterMap_; + + }; + +} // namespace + +#endif // _SILECS_DEVICE_H_ diff --git a/silecs-communication-cpp/src/silecs-communication/interface/equipment/SilecsPLC.cpp b/silecs-communication-cpp/src/silecs-communication/interface/equipment/SilecsPLC.cpp new file mode 100644 index 0000000..57884b5 --- /dev/null +++ b/silecs-communication-cpp/src/silecs-communication/interface/equipment/SilecsPLC.cpp @@ -0,0 +1,725 @@ +// Copyright 2016 CERN and GSI +// +// 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 3 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, see <http://www.gnu.org/licenses/>. + +#include <silecs-communication/interface/equipment/SilecsPLC.h> + +#include <silecs-communication/interface/core/Diagnostic.h> +#include <silecs-communication/interface/core/SilecsService.h> +#include <silecs-communication/interface/core/WrapperAction.h> +#include <silecs-communication/interface/equipment/SilecsCluster.h> +#include <silecs-communication/interface/equipment/SilecsDevice.h> +#include <silecs-communication/interface/equipment/SilecsBlock.h> +#include <silecs-communication/interface/equipment/SilecsRegister.h> +#include <silecs-communication/interface/equipment/PLCBlock.h> +#include <silecs-communication/interface/equipment/PLCRegister.h> +#include <silecs-communication/interface/utility/SilecsException.h> +#include <silecs-communication/interface/utility/SilecsLog.h> +#include <silecs-communication/interface/utility/StringUtilities.h> +#include <silecs-communication/interface/utility/XMLParser.h> + +//Supported protocol +#include <silecs-communication/interface/communication/MBConnection.h> +#include <silecs-communication/interface/communication/SNAP7Connection.h> + +#include <silecs-communication/interface/communication/CNVConnection.h> +#include <silecs-communication/interface/equipment/CNVBlock.h> + +#include <fstream> + +namespace Silecs +{ + connMapType PLC::connMap_; + PLC::PLC(Cluster* theCluster, std::string plcName, std::string plcIPaddr, string parameterFile) : + theCluster_ (theCluster), IPaddr_(plcIPaddr), parameterFile_(parameterFile) + { + //Force PLC hostname lower-case + name_ = plcName; + StringUtilities::toLower(name_); + + LOG(ALLOC) << "PLC (create): " << name_ << "/ " << IPaddr_; + + // Upload the parameters file and build the PLC configuration + extractDatabase(); + + //Do not synchronize retentive Registers by default (overwritten at connection time) + synchroMode_ = NO_SYNCHRO; + + // Start the PLC Thread + pThread_ = new Thread<WrapperAction>::Thread(); + + // create default contexts for all-devices transaction (normal and for synchronization) + allDevicesTransaction_ = new Context(NULL/*no Device: for all devices)*/, false); + allDevicesSynchronization_ = new Context(NULL/*no Device: for all devices)*/, true); + + // Instantiate the communication interface + plcConn_ = NULL; + isSharedConn_ = false; // No shared connection by default and for CNV protocol (PXI platform). + } + + + PLC::~PLC() + { + LOG(ALLOC) << "PLC (delete): " << name_; + + //Before removing the PLC resources, we need to interrupt all the related accesses (if connection is not shared) + if (isSharedConn_ == false) disconnect(); + + // Remove PLC communication resources + if (pThread_ != NULL) { delete pThread_; pThread_ = NULL; } + if ((plcConn_ != NULL) && (isSharedConn_ == false)) { delete plcConn_; plcConn_ = NULL; } + + //theHeader object and the shared-connection objects (if any) must not be delete from the PLC since + //it is shared between all the PLC instances. It will be removed by the Service destructor at the end. + + delete allDevicesTransaction_; + delete allDevicesSynchronization_; + + // Remove the Device instances related to this PLC + deviceVectorType::iterator pDeviceIter; + for(pDeviceIter = deviceCol_.begin(); pDeviceIter != deviceCol_.end(); ++pDeviceIter) delete pDeviceIter->second; + deviceCol_.clear(); + + // Remove the Block instances related to this PLC + blockMapType::iterator pBlockIter; + for(pBlockIter = blockMap_.begin(); pBlockIter != blockMap_.end(); ++pBlockIter) + { delete pBlockIter->second; + pBlockIter->second = NULL; + } + blockMap_.clear(); + + // Clear Blocks collection used for retentive registers synchronization + masterInputBlockCol_.clear(); + slaveOutputBlockCol_.clear(); + } + + void PLC::connect(SynchroMode synchroMode, bool connectNow, bool compareChecksums) + { + //At first, Instantiate the PLC connection object if needed + LOG((COMM|DIAG)) << "Attempt to establish connection ... "; + /*plcConn_ =*/ getConnection(); + //Check PLC is not already Enabled + std::string connStr = name_ + "(" + IPaddr_ + ")" + ":" + theCluster_->getClassName() + "/v" + theCluster_->getClassVersion(); + LOG(ERROR) << connStr; + + if ( (connectNow == false) && plcConn_->isEnabled() ) + { //Trying to connect a connected PLC should not be necessary an ERROR + //throw SilecsException(__FILE__, __LINE__, COMM_ALREADY_ENABLED, connStr); + LOG(ERROR) << "This PLC connection is already enabled: " << connStr; + return; + } + + LOG(COMM) << (connectNow ? "Open" : "Enable") << " Connection request for " << connStr; + + //Store the synchonization mode for this particular PLC/Cluster connection request (can change at any connect() call. + synchroMode_ = synchroMode; + + // Whatever the outcome of the connection that will follow, the PLC must be Enabled in any case. + // Thus, even if the PLC is off and rejects the first connection to upload the Header (see updateHeader), + // we will automatically attempt to reconnect later at the next PLC accesses (send/recv) ... again and again. + plcConn_->enable(this, connectNow); + + if( compareChecksums ) + { + /* PLC memory could have change during a disconnection time (downloading or other). + The Header registers must be reloaded for consistency checking. + Do not continue the connection sequence if it is not even possible to load the header. + */ + LOG(COMM) << "getting checksum"; + remoteChecksum_ = theHeader_->getRegister("_checksum")->getValULong(); + if (remoteChecksum_ != localChecksum_) + { //Client and PLC mapping are not consistent ... no transaction are possible! + disconnect(); + std::ostringstream message; + message << "Checksum comparison failed. Checksum in parameter file: '" << localChecksum_ << "' Checksum in PLC: '" << remoteChecksum_<< "' Disconnecting PLC now."; + throw SilecsException(__FILE__, __LINE__, CONFIG_CLIENT_PLC_NOT_CONSISTENT, message.str()); + } + } + }; + + + void PLC::disconnect() + { + LOG(COMM) << "Disconnection request for " << name_ << ":" << theCluster_->getClassName() << "/v" << theCluster_->getClassVersion(); + //close the connection (also close the connection if shared with other cluster on the same PLC!) + getConnection()->disable(this); + synchroMode_ = NO_SYNCHRO; //Do not synchronize retentive Registers by default + }; + + bool PLC::isEnabled() { return ((plcConn_ == NULL) ? false : plcConn_->isEnabled()); /*do not use getConnection() here*/} + bool PLC::isConnected(bool connectNow) + { + return (connectNow ? getConnection()->doOpen(this): getConnection()->isConnected()); + } + + + unsigned int PLC::getThreadPriority() + { + LOG(SETUP) << "Thread RT-priority of PLC " << name_ << " is: " << pThread_->getPriority(); + return pThread_->getPriority(); + } + + + void PLC::setThreadPriority(unsigned int rtprio) + { + LOG(SETUP) << "Set Thread RT-priority of PLC " << name_ << ": " << rtprio; + return pThread_->setPriority(rtprio); + } + + + const std::string PLC::getParamsFileName() + { + return parameterFile_; + } + + + Device* PLC::getDevice(std::string deviceName) + { + deviceVectorType::iterator iter; + + for(iter = deviceCol_.begin(); iter != deviceCol_.end(); ++iter) + { + if (DEBUG & Log::topics_) LOG(COMM) << "getDevice - deviceName: '" << iter->first << "'"; + } + + for(iter = deviceCol_.begin(); iter != deviceCol_.end(); ++iter) + { + if (iter->first == deviceName) + { + return iter->second; + } + } + + throw SilecsException(__FILE__, __LINE__, PARAM_UNKNOWN_DEVICE_NAME, deviceName+"/"+name_); + return NULL;//to suppress warning + } + + + std::vector<std::string> PLC::getDeviceList() + { + std::vector<std::string> deviceList; + deviceVectorType::iterator pDeviceIter; + for(pDeviceIter = deviceCol_.begin(); pDeviceIter != deviceCol_.end(); ++pDeviceIter) + { + deviceList.push_back(pDeviceIter->first); + } + return deviceList; + } + + + std::string PLC::getName() { return name_; } + std::string PLC::getIPAddress() { return IPaddr_; } + std::string PLC::getDomain() { return domain_; } + std::string PLC::getBrand() { return brand_; } + std::string PLC::getSystem() { return system_; } + std::string PLC::getModel() { return model_; } + std::string PLC::getProtocolType() { return protocolType_; } + std::string PLC::getProtocolMode() { return protocolMode_; } + unsigned long PLC::getBaseAddress() { return baseAddr_; } + + deviceVectorType& PLC::getDeviceMap() { return deviceCol_; } + std::string PLC::getLocalRelease() { return localRelease_; } + std::string PLC::getLocalOwner() { return localOwner_; } + std::string PLC::getLocalDate() { return localDate_; } + unsigned long PLC::getLocalChecksum() { return localChecksum_; } + + + void PLC::downloadMasterRegisters() + { + if (masterInputBlockCol_.size()) + { + if (DEBUG & Log::topics_) LOG(COMM) << "Download Master registers of " << name_ << ":" << theCluster_->getClassName() << "/v" << theCluster_->getClassVersion(); + } + + // Read all the Master Blocks (containing 1 MASTER register at least) + // to update retentive values on client side. + for (unsigned int i=0; i<masterInputBlockCol_.size(); i++) + { + Block* pBlock = masterInputBlockCol_[i]; + LOG(COMM) << "Attempt to download Block: " << pBlock->getName(); + pBlock->getTask()->execute(allDevicesSynchronization_); + + // Then update local RW Master registers with values coming from PLC source + if (pBlock->hasOutputAccess()) + { // Perform keepMasterRegisters for each device of the Cluster. + deviceVectorType::iterator pDeviceIter; + for(pDeviceIter = deviceCol_.begin(); pDeviceIter != deviceCol_.end(); ++pDeviceIter) + { + pDeviceIter->second->keepMasterRegisters(pBlock->getName()); + } + } + } + } + + + bool PLC::checkSlaveRegistersInit(std::string& registerNotInitialized) + { + //We should not allow update Slave Registers if only one of them has never been setted (not initialized) + //for each Block that contains Slave register(s) + for (unsigned int i=0; i<slaveOutputBlockCol_.size(); i++) + { //for each Device of the collection + for(deviceVectorType::iterator pDeviceIter = deviceCol_.begin(); pDeviceIter != deviceCol_.end(); ++pDeviceIter) + { //for each register of this block + std::vector<Register*>& registerCol = pDeviceIter->second->getRegisterCollection(slaveOutputBlockCol_[i]->getName()); + for (unsigned int i=0; i<registerCol.size(); i++) + { //check that Slave register is initialized and stop the connection process if needed + Register* pReg = registerCol[i]; + if ((pReg->getSynchroType() == Slave) && (pReg->isInitialized() == false)) + { //Slave registers synchronization is not allowed + registerNotInitialized = pDeviceIter->first + "/" + pReg->getName(); + return false; + } + } + } + } + return true; + } + + + void PLC::uploadSlaveRegisters() + { + if (slaveOutputBlockCol_.size()) + { // There are Slave registers and they are all well-initialized, PLC memory can be updated with their local values + LOG((COMM|DIAG)) << "Upload Slave registers to " << name_ << ":" << theCluster_->getClassName() << "/v" << theCluster_->getClassVersion(); + } + + // Write all the Slave Blocks (containing 1 SLAVE register at least) + // to update retentive values on PLC side. + for (unsigned int i=0; i<slaveOutputBlockCol_.size(); i++) + { + LOG(COMM) << "Attempt to upload Block: " << slaveOutputBlockCol_[i]->getName(); + slaveOutputBlockCol_[i]->getTask()->execute(allDevicesSynchronization_); + } + } + + + int PLC::recvUnitCode(UnitCodeType& dataStruct) + { + return getConnection()->readUnitCode(this, dataStruct); + } + + + int PLC::recvUnitStatus(UnitStatusType& dataStruct) + { + return getConnection()->readUnitStatus(this, dataStruct); + } + + + int PLC::recvCPUInfo(CPUInfoType& dataStruct) + { + return getConnection()->readCPUInfo(this, dataStruct); + } + + + int PLC::recvCPInfo(CPInfoType& dataStruct) + { + return getConnection()->readCPInfo(this, dataStruct); + } + + + int PLC::recv(std::string blockName) + { + //Synchronous data receive + + //Execute the receive action for all the PLC devices (from the current thread) + return getBlock(blockName, Input)->getTask()->execute(allDevicesTransaction_); + } + + + int PLC::send(std::string blockName) + { + //Synchronous data send + + //Execute the send action for all the PLC devices (from the current thread) + return getBlock(blockName, Output)->getTask()->execute(allDevicesTransaction_); + } + + + void PLC::recvAsync(std::string blockName) + { + //Asynchronous data receive (used from Cluster level only) + + //Schedule task using asynchronous call for parallelism (submit to thread) + pThread_->schedule(getBlock(blockName, Input)->getTask(), allDevicesTransaction_); + } + + + void PLC::sendAsync(std::string blockName) + { + //Asynchronous data send (used from Cluster level only) + + //Schedule task using asynchronous call for parallelism (submit to thread) + pThread_->schedule(getBlock(blockName, Output)->getTask(), allDevicesTransaction_); + } + + void PLC::waitAsync() + { + pThread_->waitForTaskCompletion(); + } + + void PLC::extractDatabase() + { + LOG(SETUP) << "Extract SILECS configuration from: " << parameterFile_; + XMLParser xmlParser(parameterFile_,true); + + // Extract general information =========================================== + ElementXML rootNode = xmlParser.getFirstElementFromXPath("/SILECS-Param"); + localRelease_ = rootNode.getAttribute("silecs-version"); + + ElementXML ownerNode = xmlParser.getFirstElementFromXPath("/SILECS-Param/Mapping-Info/Owner"); + localOwner_ = ownerNode.getAttribute("user-login"); + + ElementXML generationNode = xmlParser.getFirstElementFromXPath("/SILECS-Param/Mapping-Info/Generation"); + localDate_ = generationNode.getAttribute("date"); + + ElementXML deploymentNode = xmlParser.getFirstElementFromXPath("/SILECS-Param/Mapping-Info/Deployment"); + StringUtilities::fromString(localChecksum_,deploymentNode.getAttribute("checksum") ); + + // Extract PLC general configuration ====================================== + ElementXML mappingNode = xmlParser.getFirstElementFromXPath("/SILECS-Param/SILECS-Mapping"); + //name_ = pEl->getStringAttribute("name"); already done before + domain_ = mappingNode.getAttribute("domain"); + brand_ = mappingNode.getAttribute("plc-brand"); + system_ = mappingNode.getAttribute("plc-system"); + protocolMode_ = mappingNode.getAttribute("protocol"); + brandID_ = whichPLCBrand(brand_); + systemID_ = whichPLCSystem(system_); + protocolModeID_ = whichProtocolMode(protocolMode_); + protocolTypeID_ = whichProtocolType(system_); + + switch(protocolTypeID_) + { + case MBProtocol: protocolType_ = "MODBUS-TCP"; break; + case S7Protocol: protocolType_ = "SNAP7-TCP"; break; + case CNVProtocol: protocolType_ = "CNV-TCP"; break; + }; + + model_ = mappingNode.getAttribute("plc-model"); + modelID_ = whichPLCModel(model_); + StringUtilities::fromString(baseAddr_,mappingNode.getAttribute("address") ); + usedMem_ = mappingNode.getAttribute("used-mem"); + + std::vector< boost::shared_ptr<ElementXML> > classNodes = mappingNode.childList_; + std::vector< boost::shared_ptr<ElementXML> >::const_iterator classIter; + for(classIter = classNodes.begin(); classIter != classNodes.end(); classIter++) + { + std::string className = (*classIter)->getAttribute("name"); + + boost::ptr_vector<ElementXML> blockNodes = xmlParser.getElementsFromXPath_throwIfEmpty("/SILECS-Param/SILECS-Mapping/SILECS-Class[@name='"+ className + "']/Block"); + boost::ptr_vector<ElementXML>::const_iterator blockIter; + + boost::ptr_vector<ElementXML> instanceNodes = xmlParser.getElementsFromXPath_throwIfEmpty("/SILECS-Param/SILECS-Mapping/SILECS-Class[@name='"+ className + "']/Instance"); + boost::ptr_vector<ElementXML>::const_iterator instanceIter; + for(instanceIter = instanceNodes.begin(); instanceIter != instanceNodes.end(); instanceIter++) + { + std::string deviceName = (*instanceIter).getAttribute("label"); + std::string deviceAddress = (*instanceIter).getAttribute("address"); + Device* pDevice = new Device(this, deviceName, deviceAddress, blockNodes); + deviceCol_.push_back(std::make_pair(deviceName, pDevice)); + if(deviceName == "SilecsHeader") + theHeader_ = pDevice; + } + + for(blockIter = blockNodes.begin(); blockIter != blockNodes.end(); blockIter++) + { + std::string blockNameFull; //"block-name" + "access-type" + std::string blockName = (*blockIter).getAttribute("name"); + AccessType accessType = Block::whichAccessType((*blockIter).getAttribute("mode")); + + Block* pBlock = 0; + // Instantiate Input blocks ------------------------------------------------------ + if (Service::withInputAccess(accessType)) //Input or InOut access + { //Instantiate the block, forcing it to Input access for InOut case + + if(whichPLCBrand(brand_)==Ni) +#ifdef NI_SUPPORT_ENABLED + pBlock = new CNVInputBlock(this, (*pBlockElCol)[i], accessType, pCurrentBlockElCol); +#else + throw SilecsException(__FILE__, __LINE__, "Support for NI-Devices is disabled"); +#endif + else + pBlock = new InputBlock(this,*blockIter, accessType); + blockNameFull = blockName + Block::whichAccessType(Input); + + //Store references of Input Master blocks for retentive registers synchronization + if (pBlock->hasMasterRegister()) masterInputBlockCol_.push_back(pBlock); + } + + // Instantiate Output blocks ------------------------------------------------------ + if (Service::withOutputAccess(accessType)) //Output or InOut accessprotocol + { //Instantiate the block, forcing it to Output access for InOut case + + + if(whichPLCBrand(brand_)==Ni) +#ifdef NI_SUPPORT_ENABLED + pBlock = new CNVOutputBlock(this, (*pBlockElCol)[i], accessType, pCurrentBlockElCol); +#else + throw SilecsException(__FILE__, __LINE__, "Support for NI-Devices is disabled"); +#endif + else + pBlock = new OutputBlock(this, *blockIter, accessType); + + blockNameFull = blockName + Block::whichAccessType(Output); + + //Store references of Ouput Slave blocks for retentive registers synchronization + if (pBlock->hasSlaveRegister()) slaveOutputBlockCol_.push_back(pBlock); + } + + //Store reference of the block for general communication purpose + blockMap_.insert(std::make_pair(blockNameFull, pBlock)); + } //for blocks + } //for classes + } + + + Connection* PLC::createConnection() + { + Connection* theConn = NULL; + try + { + switch(protocolTypeID_) + { + case S7Protocol: + theConn = new SNAP7Connection(this); break; + case MBProtocol: + theConn = new MBConnection(this); break; + case CNVProtocol: +#ifdef NI_SUPPORT_ENABLED + theConn = new CNVConnection(this);break; +#else + throw SilecsException(__FILE__, __LINE__, "Support for NI-Devices is disabled"); +#endif + default: + throw SilecsException(__FILE__, __LINE__, "Unknown protocolTypeID_"); + } + } + catch (const SilecsException& ex) + { //Something has failed. Nothing to do, we trust the re-open mechanism from now. + LOG(ERROR) << ex.what(); + throw ex; + } + + if (DEBUG & Log::topics_) LOG(COMM) << "PLC::createConnection(): " << connID_ << ", isShared: " << (isSharedConn_? "true":"false"); + return theConn; + } + + + Connection* PLC::getConnection() + { + if (plcConn_ == NULL) + { + LOG((COMM|DIAG)) << "No connection found. Attempt to establish connection ... "; + //Connection not instantiated yet. Check if it will be shared or not? + if (protocolTypeID_ != CNVProtocol) + { + /*TODO: get from the param file (extractDatabase): Major release??*/ + isSharedConn_ = theCluster_->configuration.sharedConnection; + } + connID_ = (isSharedConn_) ? name_+"SharedConnection" : name_+theCluster_->getClassName(); + + if (isSharedConn_) + { + LOG((COMM|DIAG)) << "Creating shared connection"; + //Create/re-used the shared connection + connMapType::iterator iter = connMap_.find(connID_); + if (iter == connMap_.end()) //one shared-connection per PLC + { Connection* theConn = createConnection(); + connMap_.insert(std::make_pair(connID_, theConn)); + plcConn_ = theConn; + } + else + { plcConn_ = iter->second; + } + } + else + { //Create the specific PLC/Cluster connection + LOG((COMM|DIAG)) << "Creating non-shared connection"; + plcConn_ = createConnection(); + } + } + return plcConn_; + } + + + void PLC::deleteConnection() + { + // Remove all shared-connection if any (one per PLC) + connMapType::iterator iter; + for(iter = connMap_.begin(); iter != connMap_.end(); ++iter) + { delete iter->second; + } + connMap_.clear(); + } + + + Block* PLC::getBlock(const std::string blockName, AccessType accessType) + { + blockMapType::iterator pBlockMapIter; + + switch(accessType) + { case Input: + //Doest the block exist with the Input access-type? + pBlockMapIter = blockMap_.find(blockName + Block::whichAccessType(Input)); + if (pBlockMapIter == blockMap_.end()) + { + //No! then check if it exists with other access-type + pBlockMapIter = blockMap_.find(blockName + Block::whichAccessType(Output)); + if (pBlockMapIter == blockMap_.end()) + //This block does not exist at all? + throw SilecsException(__FILE__, __LINE__, PARAM_UNKNOWN_BLOCK_NAME, blockName); + else + //This block exists but with the opposite access-type + throw SilecsException(__FILE__, __LINE__, PARAM_ACCESS_TYPE_MISMATCH, blockName); + } + break; + case Output: + //Doest the block exist with the Output access-type? + pBlockMapIter = blockMap_.find(blockName + Block::whichAccessType(Output)); + if (pBlockMapIter == blockMap_.end()) + { + //No! then check if it exists with other access-type + pBlockMapIter = blockMap_.find(blockName + Block::whichAccessType(Input)); + if (pBlockMapIter == blockMap_.end()) + //This block does not exist at all? + throw SilecsException(__FILE__, __LINE__, PARAM_UNKNOWN_BLOCK_NAME, blockName); + else + //This block exists but with the opposite access-type + throw SilecsException(__FILE__, __LINE__, PARAM_ACCESS_TYPE_MISMATCH, blockName); + } + break; + default: + //should never occure! + throw SilecsException(__FILE__, __LINE__, (int)UNEXPECTED_ERROR, "Input or Output argument is required!"); + } + + //block with expected access-type has been found + return pBlockMapIter->second; + } + + + blockMapType& PLC::getBlockMap() { return blockMap_; } + + + PLCBrand PLC::whichPLCBrand(std::string brand) + { + StringUtilities::toLower(brand); + if (brand == "siemens") return Siemens; + else if (brand == "schneider") return Schneider; + else if (brand == "beckhoff") return Beckhoff; + else if (brand == "rabbit") return Digi; + else if (brand == "ni") return Ni; + else throw SilecsException(__FILE__, __LINE__, DATA_UNKNOWN_PLC_MANUFACTURER, brand); + } + + PLCModel PLC::whichPLCModel(std::string model) + { + StringUtilities::toLower(model); + if (model == "simatic_et-200s") return ET200S; + else if (model == "simatic_s7-300") return S7300; + else if (model == "simatic_s7-400") return S7400; + else if (model == "simatic_s7-1200") return S71200; + else if (model == "simatic_s7-1500") return S71500; + else if (model == "premium") return Premium; + else if (model == "quantum") return Quantum; + else if (model == "m340") return M340; + else if (model == "bc9020") return BC9020; + else if (model == "cx9020") return CX9020; + else if (model == "rcm_4010") return RCM4010; + else if (model == "rcm_2000") return RCM2000; + else if (model == "compact_rio") return CompactRIO; + else if (model == "pxi_rt") return PXIRT; + else if (model == "pxi_windows") return PXIWindows; + else if (model == "pc_windows") return PCWindows; + else if (model == "other_support_cnv") return OtherSupportCNV; + else throw SilecsException(__FILE__, __LINE__, DATA_UNKNOWN_PLC_MODEL, model); + } + + PLCSystem PLC::whichPLCSystem(std::string system) + { + StringUtilities::toLower(system); + if (system == "step-7") return Step7; + if (system == "tia-portal") return TiaPortal; + else if (system == "unity pro") return Unity; + else if (system == "twincat") return TwinCat; + else if (system == "standard-c") return StdC; + else if (system == "labview") return Labview; + else throw SilecsException(__FILE__, __LINE__, DATA_UNKNOWN_PLC_SYSTEM, system); + } + + + ProtocolType PLC::whichProtocolType(std::string system) + { + StringUtilities::toLower(system); + if (system == "step-7") return S7Protocol; + if (system == "tia-portal") return S7Protocol; + else if (system == "unity pro") return MBProtocol; + else if (system == "twincat") return MBProtocol; + else if (system == "standard-c") return MBProtocol; + else if (system == "labview") return CNVProtocol; + else throw SilecsException(__FILE__, __LINE__, DATA_UNKNOWN_PLC_SYSTEM, system); + } + + + ProtocolMode PLC::whichProtocolMode(std::string mode) + { + StringUtilities::toLower(mode); + if (mode == "block_mode") return BlockMode; + else if (mode == "device_mode") return DeviceMode; + else throw SilecsException(__FILE__, __LINE__, DATA_UNKNOWN_PROTOCOL_MODE, mode); + } + + + void PLC::updateStatus() + { + status_.connStatus_ = (getConnection()->isConnected()) ? Connected : Disconnected; + status_.plcStatus_ = (getConnection()->isAlive()) ? On : Off; + //#FLO problem: qui remet Undefined/Unknown pour ces 2 variables le cas echeant? + + if (DEBUG & Log::topics_) LOG(COMM) << "PLC Status:\n\t" << + getName() << " mode: " << status_.getPLCStatusAsString() << "\n\t" << + theCluster_->getHostName() << "/" << getName() << "/" << theCluster_->getClassName() << " connection: " << status_.getConnectionStatusAsString(); + } + + void PLC::copyInToOut(const std::string blockName) + { + deviceVectorType::iterator pDeviceIter; + for(pDeviceIter = deviceCol_.begin(); pDeviceIter != deviceCol_.end(); ++pDeviceIter) + pDeviceIter->second->copyInToOut(blockName); + } + + void PLC::setReadBlockAttributes(const std::string blockName, const unsigned long customAddress, const unsigned long customOffset, const unsigned long customSize) + { + //Set the custom offset/size of the referred Input block if any. + //Will throw an exception if that block-name does not exist. + getBlock(blockName, Input)->setCustomAttributes(customAddress, customOffset, customSize); + } + + void PLC::resetReadBlockAttributes(const std::string blockName) + { + getBlock(blockName, Input)->resetCustomAttributes(); + } + + void PLC::setWriteBlockAttributes(const std::string blockName, const unsigned long customAddress, const unsigned long customOffset, const unsigned long customSize) + { + //Set the custom address/offset/size of the referred Output block if any. + //Will throw an exception if that block-name does not exist. + getBlock(blockName, Output)->setCustomAttributes(customAddress, customOffset, customSize); + } + + void PLC::resetWriteBlockAttributes(const std::string blockName) + { + getBlock(blockName, Output)->resetCustomAttributes(); + } + +} // namespace diff --git a/silecs-communication-cpp/src/silecs-communication/interface/equipment/SilecsPLC.h b/silecs-communication-cpp/src/silecs-communication/interface/equipment/SilecsPLC.h new file mode 100644 index 0000000..d969a79 --- /dev/null +++ b/silecs-communication-cpp/src/silecs-communication/interface/equipment/SilecsPLC.h @@ -0,0 +1,553 @@ +// Copyright 2016 CERN and GSI +// +// 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 3 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, see <http://www.gnu.org/licenses/>. + +#ifndef _SILECS_PLC_H_ +#define _SILECS_PLC_H_ + +#include <silecs-communication/interface/core/Diagnostic.h> +#include <silecs-communication/interface/core/SilecsService.h> +#include <silecs-communication/interface/utility/Thread.h> + +#include <stdint.h> +#include <string> + +namespace Silecs +{ + class Connection; + class Cluster; + class Device; + class Block; + class WrapperAction; + + /// @cond + typedef std::vector<std::pair<std::string, Device*> > deviceVectorType; + typedef std::map<std::string, Block*> blockMapType; + typedef std::vector<Block*> blockVectorType; + typedef std::map<std::string, Connection*> connMapType; + + // PLC brand, system, protocol type and mode + typedef enum + { + Siemens, Schneider, Ni, Digi, Beckhoff + } PLCBrand; + + typedef enum + { + ET200S, S7300, S7400, S71200, S71500, + S7VIRTUAL, + Premium, Quantum, + M340, + BC9020, CX9020, + RCM4010, RCM2000, + CompactRIO, + PXIRT, PXIWindows, PCWindows, OtherSupportCNV + } PLCModel; + + typedef enum + { + Step7, TiaPortal, Unity, TwinCat, StdC, ServerS7, Labview + } PLCSystem; + + typedef enum + { + MBProtocol, S7Protocol, CNVProtocol + } ProtocolType; + + typedef enum + { + BlockMode, DeviceMode + } ProtocolMode; + /// @endcond + + // PLC unit status + typedef struct { + int status; //bit-pattern hardware specific (look at the related documentation) + } UnitStatusType; + + // Order code + typedef struct { + std::string code; + std::string version; + } UnitCodeType; + + // CPU Info + typedef struct { + std::string moduleName; + std::string moduleTypeName; + std::string serialNumber; + std::string asName; + std::string copyright; + } CPUInfoType; + + // CP Info + typedef struct { + int maxPduLength; + int maxConnections; + int maxMPIRate; + int maxBusRate; + } CPInfoType; + + /*! + * \class PLC + * \brief This object provides all services related to a PLC. It provides the information + * of the PLC hardware configuration, connection status and diagnostic. + * It maintains a reference of all the PLC devices. + * It can be used to trig the data-block exchanges for all devices of the PLC at the same time. + */ + class PLC + { + + public: + /// @cond + /*! + * \return List of the related Cluster instances (Class/Version) for the PLC. + */ + std::vector<std::string> getDeviceList(); + + deviceVectorType& getDeviceMap(); + /// @endcond + + // Diagnostic features ---------------------------------------- + + /*! + * \brief Returns the PLC network name + * \return PLC host-name + */ + std::string getName(); + + /*! + * \brief Returns the PLC network address + * \return PLC TCP-IP address + */ + std::string getIPAddress(); + + /*! + * \brief Returns the PLC configuration domain: CPS, PSB, ADE, .., TST + * \return Accelerator domain + */ + std::string getDomain(); + + /*! + * \brief Returns the PLC manufacturer: SIEMENS, SCHNEIDER, BECKHOFF, RABBIT, NI + * \return PLC brand + */ + std::string getBrand(); + + /*! + * \brief Returns the PLC development system: STEP-7, TIA-PORTAL, UNITY Pro, TWINCat, Standard-C, Labview + * \return PLC development system + */ + std::string getSystem(); + + /*! + * \brief Returns PLC hardware model: UNITY_Premium, SIMATIC_S7-300, .. + * \return PLC hardware model + */ + std::string getModel(); + + /*! + * \brief Returns the protocol type used for the PLC communication: MODBUS-TCP, S7-TCP, CNV-TCP + * \return PLC protocol type + */ + std::string getProtocolType(); + + /*! + * \brief Returns the SILECS mode used to map the data within the PLC memory: DEVICE_MODE, BLOCK_MODE + * \return PLC protocol mode + */ + std::string getProtocolMode(); + + /*! + * \brief Returns the base address of the SILECS configuration within the PLC memory + * \return DB number for SIMATIC-S7 + * \return 16bits absolute memory address for UNITY Premium/Quantum + * \return 32bits absolute memory address for UNITY M340 + */ + unsigned long getBaseAddress(); + + /*! + * \brief Extracts SILECS release information from the client configuration parameters. + * Provides detail about SILECS software used to generate the client documents. + * \return SILECS release number + */ + std::string getLocalRelease(); + + /*! + * \brief Extracts Owner information from the client configuration parameters. + * Owner of the deployment document is not necessary responsible for the 'Generate' action + * who can be done by any Editor of the document. + * \return Owner name + */ + std::string getLocalOwner(); + + /*! + * \brief Extracts the Date information from the client configuration parameters. + * Date of the client parameters file generation. + * \return Coordinate Universal Time (UTC) + */ + std::string getLocalDate(); + + /*! + * \brief Extracts the Checksum information from the client configuration parameters. + * CRC-32 Checksum relies on Classes and Deployment documents that have been used to + * design the client configuration. + * \return CRC32 checksum + */ + unsigned long getLocalChecksum(); + + // Miscellaneous features ---------------------------------------- + + /*! + * \brief Returns one device instance of that PLC by label or index + * \param deviceName label or index of the device + * \return Reference of the device object + */ + Device* getDevice(std::string deviceName); + + /*! + * \brief Used to get the rt-priority of the PLC related thread + * \return rt-priority value + */ + unsigned int getThreadPriority(); + + /*! + * \brief Used to set the real-time priority of the PLC related thread + * \param rtPrio value of the priority + */ + void setThreadPriority(unsigned int rtprio); + + /*! + * \brief Used to Enable the Client/PLC connection and connect the PLC immediately if needed (connectNow=true). + * Just Enabling the connection (connectNow=false) means the connection is allowed and systematically checked on each PLC access (send/recv). + * In any case, connect() method downloads the Diagnostic data from the PLC Header memory and checks the Client/PLC configuration consistency. + * The 'synchroMode' parameter is used to select the synchronization mode of the retentive Registers. + * It must be used carefully since it can overwrite all the PLC Slave registers at the connection time. + * \param connectNow = true: Connection is maintained immediately after the Header data update. + * connectNow = false: delay the real data connection to the first access attempt (send/recv blocks). + * \param synchroMode = NO_SYNCHRO: connect() method does not synchronize any retentive Registers at connection time. + * synchroMode = MASTER_SYNCHRO: connect() method downloads all the Master Registers from the PLC memory and updates local Register values at connection time. + * synchroMode = SLAVE_SYNCHRO: connect() method transmits all the local Slave Registers values to the PLC at connection time. + * synchroMode = FULL_SYNCHRO: connect() method executes MASTER and SLAVE Registers synchronizationat connection time (see above). + * \param compareChecksums: Set to false if you want to skip the checksum comparison. Default is true + */ + void connect(SynchroMode synchroMode, bool connectNow, bool compareChecksums = true); + + /*! + * \brief Used to disable the Client/PLC connection. + * Connection is closed (if needed) and send/recv transaction are not possible anymore (PLC connection is Disabled). + * The PLC object still exists on the Cluster and the Registers are available locally. + */ + void disconnect(); + + /*! + * \brief Returns true if the PLC connection has been requested using connect() method. + * \return Enable status + */ + bool isEnabled(); + + /*! + * \brief Check the connection status and reconnect the controller if required (optional) + * Returns true if the PLC connection is established. + * \param reconnectNow can be used to force reconnection before checking (false by default). + * \return Connection status + */ + bool isConnected(bool reconnectNow=false); + bool isSharedConnection() { return isSharedConn_; } + + int recvUnitCode(UnitCodeType& dataStruct); + int recvUnitStatus(UnitStatusType& dataStruct); + int recvCPUInfo(CPUInfoType& dataStruct); + int recvCPInfo(CPInfoType& dataStruct); + + /*! + * \brief Acquires one particular registers block of all devices of that PLC. + * The method tries to (re)connect the PLC if the connection is not established yet or unexpectedly interrupted (network failure, PLC down, etc.). + * It generates an Silecs::SilecsException if the PLC has not been enabled (using the connect() method). + * \param blockName name of the block to be acquired + * \return 0 if operation was successful else an error code (when available). + */ + int recv(std::string blockName); + + /*! + * \brief Transmits the registers block to all devices of that PLC. + * The method tries to (re)connect the PLC if the connection is not established yet or unexpectedly interrupted (network failure, PLC down, etc.). + * It generates an Silecs::SilecsException if the PLC has not been enabled (using the connect() method). + * \param blockName name of the block to be transmitted + * \return 0 if operation was successful else an error code (when available). + */ + int send(std::string blockName); + + /*! + * \brief Copies input buffer in output buffer + * The method copies the input buffer in the output buffer for each READ-WRITE register in the PLC for the block passed as parameter + * \param blockName name of the block for which the copy must be performed + */ + void copyInToOut(const std::string blockName); + + /*! + * \brief Used to change designed attributes of data block. + * In that version, can be used to limit dynamically size of data to be received (recv). + * Interesting for specific application that uses general purpose data block with maximum size and adjusts the real data size at communication time. + * Caution! This option can be used only with single device access (using DEVICE_MODE or send/recv from the Device level). + * \param blockName name of the related block + * \param customAddress base address (DBn or absolute in byte) of the data block to be received + * \param customOffset offset (in byte) of the data block to be received + * \param customSize real size (in byte) of the data block to be received + */ + void setReadBlockAttributes(const std::string blockName, const unsigned long customAddress, const unsigned long customOffset, const unsigned long customSize); + + /*! + * \brief Sets back the default attributes of the data block (the ones defined by the design) + * \param blockName name of the related block + */ + void resetReadBlockAttributes(const std::string blockName); + + /*! + * \brief Used to change designed attributes of a data block. + * In that version, can be used to limit dynamically size of data to be sent (send). + * Interesting for specific application that uses general purpose data block with maximum size and adjusts the real data size at communication time. + * Caution! This option can be used only with single device access (using DEVICE_MODE or send/recv from the Device level). + * \param blockName name of the related block + * \param customAddress base address (DBn or absolute in byte) of the data block to be sent + * \param customOffset offset (in byte) of the data block to be sent + * \param customSize real size (in byte) of the data block to be sent + */ + void setWriteBlockAttributes(const std::string blockName, const unsigned long customAddress, const unsigned long customOffset, const unsigned long customSize); + + /*! + * \brief Sets back the default attributes of the data block (the ones defined by the design) + * \param blockName name of the related block + */ + void resetWriteBlockAttributes(const std::string blockName); + + /// @cond + /*! + * \fn getConnection + * \brief Use this method to either get an existing Connection object, + * or to create a new one for a given PLC, if not existing. + * Allow sharing connection pipe between different classes if required (from mapping configuration) + * \return reference to the [shared-]connection instance of this PLC instance + */ + Connection* createConnection(); //just to instantiate the object + Connection* getConnection(); + static void deleteConnection(); //just to remove shared-connection objects + /// @endcond + + const std::string getParamsFileName(); + + private: + friend class Cluster; + friend class Device; + friend class Register; + friend class Connection; + friend class S7Connection; + friend class MBConnection; + friend class SNAP7Connection; + + // export plcConn_ to Silecs Action + friend class Block; + + friend class PLCBlock; + friend class InputBlock; + friend class OutputBlock; + friend class PLCRegister; + friend class PLCRecvBlockMode; + friend class PLCRecvDeviceMode; + friend class PLCSendBlockMode; + friend class PLCSendDeviceMode; + + friend class CNVBlock; + friend class CNVConnection; + friend class CNVInputBlock; + friend class CNVOutputBlock; + friend class CNVRegister; + friend class CNVRecvBlockMode; + friend class CNVRecvDeviceMode; + friend class CNVSendBlockMode; + friend class CNVSendDeviceMode; + + PLC(Cluster* theCluster, std::string plcName, std::string plcIPaddr, string parameterFile); + virtual ~PLC(); + + inline PLCBrand& getBrandID() { return brandID_; } + inline PLCModel& getModelID() { return modelID_; } + inline PLCSystem& getSystemID() { return systemID_; } + inline ProtocolMode& getProtocolID() { return protocolModeID_; } + + /*! + * \fn downloadMasterRegisters + * \brief This method is used for Retentive registers synchronization on each PLC (re)connection. + * Connects PLC and acquires all Input blocks which contain at least one MASTER retentive register. + */ + void downloadMasterRegisters(); + + /*! + * \fn checkSlaveRegistersInit + * \brief This method checks that all of the retentive Slave Registers are initialized and return + * false if not. For obvious security reason, immediate connection of the PLC is not allowed in this case. + * \param registerNotInitialized receive first name of the register that is not initialized yet. + */ + bool checkSlaveRegistersInit(std::string& registerNotInitialized); + + /*! + * \fn uploadSlaveRegisters + * \brief This method is used for Retentive registers synchronization on each PLC (re)connection. + * Connects PLC and transmits all Output blocks which contain at least one SLAVE retentive register. + */ + void uploadSlaveRegisters(); + + /*! + * \fn updateHeader + * \brief This method is used to update the unique 'SilecsHeader' Device data of the PLC config. + * It consists to create the corresponding Cluster if needed, connect the current PLC, + * upload the diagnostic block registers ('hdrBlk') then disconnect the PLC. + * \return True if uploading was correctly done. + */ + bool updateHeader(); + + /*! + * \fn recvAsync/ recvWait + * \brief Acquires the 'blockname' data block of all devices of that PLC using asynchronous mode + */ + void recvAsync(std::string blockName); + + /*! + * \fn sendAsync/ sendWait + * \brief Sends the 'blockname' data block to all devices of that PLC using asynchronous mode + */ + void sendAsync(std::string blockName); + + /*! + * \fn waitAsync + * \brief Wait for asynchronous call completion (recv/send) + */ + void waitAsync(); + + /*! + * \fn whichPLC, whichProtocol... + * \return the enumeration value of the given Protocol type/mode string + */ + static PLCBrand whichPLCBrand(std::string brand); //SIEMENS, SCHNEIDER, BECKHOFF, ... + static PLCModel whichPLCModel(std::string model); //S7-400, S7-300, ... + static PLCSystem whichPLCSystem(std::string system); //STEP-7, UNITY, TWINCAT, ... + static ProtocolType whichProtocolType(std::string system); //S7, Modbus, CNV, ... + static ProtocolMode whichProtocolMode(std::string mode); //Device or Block + + /*! + * \fn ExtractDatabase + * \brief Parse the Silecs params file and extract the configuration of that PLC. + */ + void extractDatabase(); + + /*! + * \fn getBlock + * \brief returns one instance of the requested block checking its access-type + */ + Block* getBlock(const std::string blockName, AccessType accessType); + + /*! + * \brief Provides the map of the Block objects attached to the underlying PLC(s) + * \return Block object map + */ + blockMapType& getBlockMap(); + + /*! + * \fn updateStatus + * \brief update all the status variables of the PLC. + */ + void updateStatus(); + + /// Parent cluster reference of that PLC + Cluster* theCluster_; + + /// PLC attributes + std::string name_; + std::string IPaddr_; + std::string domain_; //TST, ADE, PSB, CPS, .. + std::string brand_; //SIEMENS, SCHNEIDER, .. + std::string system_; //STEP-7, UNITY, TWINCAT, .. + std::string model_; //SIMATIC S7-300, Premium, .. + std::string protocolMode_; //Device, Block + std::string protocolType_; //MODBUS-TCP, S7-TCP, .. + + PLCBrand brandID_; //Siemens, Schneider, ... enumeration + PLCModel modelID_; //S7-400, S7-300, ... enumeration + PLCSystem systemID_; //Step7, Unity, TwinCat, ... enumeration + ProtocolMode protocolModeID_; //BlockMode, DeviceMode enumeration + ProtocolType protocolTypeID_; //Modbus, S7 enumeration + + long baseAddr_; + std::string usedMem_; + + string parameterFile_; + + // Unique instance of the Header Device for diagnostic purpose + Device* theHeader_; + + /* Diagnostic registers are used to check the consistency between the + * PLC memory (remote data) and the client parameters (local data). + */ + //Local data, extracted from the parameters file + std::string localRelease_; //Release number of the SILECS software + std::string localOwner_; //Owner of the deployment document + std::string localDate_; //Date of the Generation (Client parameters and PLC Sources) + uint32_t localChecksum_; //Checksum of the deployed configuration + + //Remote data, uploaded from the PLC memory + std::string remoteVersion_; + std::string remoteOwner_; + std::string remoteDate_; + uint32_t remoteChecksum_; + + Context* allDevicesTransaction_; + Context* allDevicesSynchronization_; + + /// Related thread allowing cluster PLCs parallelism + Thread<WrapperAction>* pThread_; + + /// Device collection of the PLC + deviceVectorType deviceCol_; + + /// Block collection of the PLC listed by name. + blockMapType blockMap_; + + /// Store references of Slave and Master Blocks for retentive registers synchronization + blockVectorType masterInputBlockCol_; + blockVectorType slaveOutputBlockCol_; + + /// Object to manage the plc communication + /* By default, we instantiate 1 connection (2 channels: r/w) per PLC/Cluster + * In order to safe PLC resources it's possible to share 1 connection between clusters of the same PLC. + * A connection ID is used to define if the connection is shared or not. + */ + Connection* plcConn_; // the connection object that can be individual per PLC/Cluster or shared + std::string connID_; // use to identify the connection object in the map (connMap_): + // individual connection: <plcName>+<ClassName> + // shared connection: <plcName>+"SharedConnection" + bool isSharedConn_; // use to know if plcConn_ is shared with others Cluster or not + + /// Connection collection to allow sharing connection channels between different clusters + static connMapType connMap_; + + // synchronization mode for each occurence of PLC/Cluster connection: [NO|FULL|SLAVE|MASTER]_SYNCHRO + SynchroMode synchroMode_; + + /// Diagnostic status + Status status_; + }; + +} // namespace + +#endif // _SILECS_PLC_H_ diff --git a/silecs-communication-cpp/src/silecs-communication/interface/equipment/SilecsRegister.cpp b/silecs-communication-cpp/src/silecs-communication/interface/equipment/SilecsRegister.cpp new file mode 100644 index 0000000..901fb36 --- /dev/null +++ b/silecs-communication-cpp/src/silecs-communication/interface/equipment/SilecsRegister.cpp @@ -0,0 +1,890 @@ +// Copyright 2016 CERN and GSI +// +// 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 3 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, see <http://www.gnu.org/licenses/>. + +#include <silecs-communication/interface/core/SilecsService.h> +#include <silecs-communication/interface/utility/XMLParser.h> +#include <silecs-communication/interface/equipment/SilecsPLC.h> +#include <silecs-communication/interface/equipment/SilecsDevice.h> +#include <silecs-communication/interface/equipment/SilecsRegister.h> +#include <silecs-communication/interface/utility/SilecsException.h> +#include <silecs-communication/interface/utility/SilecsLog.h> +#include <silecs-communication/interface/utility/StringUtilities.h> +#include <silecs-communication/protocol/core/silecs.h> + +#include <arpa/inet.h> +#include <math.h> + +namespace Silecs +{ + + Register::Register(Device* theDevice,const boost::shared_ptr<ElementXML>& registerNode) : theDevice_ (theDevice) + { + name_ = registerNode->getAttribute("name"); + format_ = whichFormatType(registerNode->getAttribute("format")); + StringUtilities::fromString(dimension1_,registerNode->getAttribute("array-dim1") ); + StringUtilities::fromString(dimension2_,registerNode->getAttribute("array-dim2") ); + StringUtilities::fromString(size_,registerNode->getAttribute("size") ); + StringUtilities::fromString(memSize_,registerNode->getAttribute("mem-size") ); + StringUtilities::fromString(address_,registerNode->getAttribute("address") ); + synchro_ = Service::whichSynchroType(registerNode->getAttribute("synchro")); + isInitialized_ = false; //register not initialized yet (used for output registers) + + // if format is string, retrieve also string-len attribute + if (format_ == String) + { + StringUtilities::fromString(length_,registerNode->getAttribute("string-len") ); + if (DEBUG & Log::topics_) LOG(ALLOC) << "Register (create): " << name_ << ", format: " << getFormatAsString() << ", string-len: " << length_ << ", dim: " << dimension1_ << ", dim2: " << dimension2_ << ", synchro: " << getSynchroTypeAsString() << ", offset: " << address_; + } + else + { + length_ = 1; + if (DEBUG & Log::topics_) LOG(ALLOC) << "Register (create): " << name_ << ", format: " << getFormatAsString() << ", dim: " << dimension1_ << ", dim2: " << dimension2_ << ", synchro: " << getSynchroTypeAsString() << ", offset: " << address_; + } + } + + Register::~Register() + { + if (DEBUG & Log::topics_) LOG(ALLOC) << "Register (delete): " << name_; + + //Remove the value buffers + if (pRecvValue_ != NULL) + { + if (format_ == String) + { + // loop through array of pointers and delete them + std::string** pRecvStringValue = static_cast<std::string**>(pRecvValue_); + for (unsigned int i=0; i<dimension1_*dimension2_; i++) + { + delete pRecvStringValue[i]; + } + pRecvStringValue = NULL; + } + free(pRecvValue_); + pRecvValue_ = NULL; + } + + if (pSendValue_ != NULL) + { + if(format_ == String) + { + // loop through array of pointers and delete them + std::string** pSendStringValue = static_cast<std::string**>(pSendValue_); + for (unsigned int i=0; i<dimension1_*dimension2_; i++) + { + delete pSendStringValue[i]; + } + pSendStringValue = NULL; + } + free(pSendValue_); + pSendValue_ = NULL; + } + } + + PLC* Register::getPLC() { return theDevice_->getPLC(); } + Device* Register::getDevice() { return theDevice_; } + + // GET methods ============================================================= + template <typename T> + inline T Register::getVal(FormatType F) + { + if (!hasInputAccess()) + throw SilecsException(__FILE__, __LINE__, DATA_READ_ACCESS_TYPE_MISMATCH, getName()); + if ((format_ != F) || !isScalar()) + throw SilecsException(__FILE__, __LINE__, PARAM_FORMAT_TYPE_MISMATCH, getName()); + return *((T*)pRecvValue_); + } + + template <typename T> + inline void Register::getValArray(FormatType F, T* pValue, uint32_t dim) + { + if (!hasInputAccess()) + throw SilecsException(__FILE__, __LINE__, DATA_READ_ACCESS_TYPE_MISMATCH, getName()); + if ((format_ != F) || !isSingleArray()) + throw SilecsException(__FILE__, __LINE__, PARAM_FORMAT_TYPE_MISMATCH, getName()); + if (dimension1_ != dim) + throw SilecsException(__FILE__, __LINE__, PARAM_ARRAY_DIMENSION_MISMATCH, getName()); + memcpy((void *)pValue, pRecvValue_, size_*dimension1_); + } + + template <typename T> + inline void Register::getValArray2D(FormatType F, T* pValue, uint32_t dim1, uint32_t dim2) + { + if(!hasInputAccess()) + throw SilecsException(__FILE__, __LINE__, DATA_READ_ACCESS_TYPE_MISMATCH, getName()); + if((format_ != F) || !isDoubleArray()) + throw SilecsException(__FILE__, __LINE__, PARAM_FORMAT_TYPE_MISMATCH, getName()); + if ((dimension1_ != dim1) || (dimension2_ != dim2)) + throw SilecsException(__FILE__, __LINE__, PARAM_ARRAY_DIMENSION_MISMATCH, getName()); + memcpy((void *)pValue, pRecvValue_, size_*dimension1_*dimension2_); + } + + template <typename Tsrc, typename Tdst> + inline void Register::convGetValArray(FormatType F, Tdst* pValue, uint32_t dim) + { + if (!hasInputAccess()) + throw SilecsException(__FILE__, __LINE__, DATA_READ_ACCESS_TYPE_MISMATCH, getName()); + if ((format_ != F) || !isSingleArray()) + throw SilecsException(__FILE__, __LINE__, PARAM_FORMAT_TYPE_MISMATCH, getName()); + if (dimension1_ != dim) + throw SilecsException(__FILE__, __LINE__, PARAM_ARRAY_DIMENSION_MISMATCH, getName()); + //automatic conversion from T to F + for(unsigned long i=0; i<dimension1_; i++) + pValue[i] = ((Tsrc*)pRecvValue_)[i]; + } + + template <typename Tsrc, typename Tdst> + inline void Register::convGetValArray2D(FormatType F, Tdst* pValue, uint32_t dim1, uint32_t dim2) + { + if (!hasInputAccess()) + throw SilecsException(__FILE__, __LINE__, DATA_READ_ACCESS_TYPE_MISMATCH, getName()); + if((format_ != F) || !isDoubleArray()) + throw SilecsException(__FILE__, __LINE__, PARAM_FORMAT_TYPE_MISMATCH, getName()); + if ((dimension1_ != dim1) || (dimension2_ != dim2)) + throw SilecsException(__FILE__, __LINE__, PARAM_ARRAY_DIMENSION_MISMATCH, getName()); + //automatic conversion from T to F + for (unsigned int i=0; i<(dimension1_*dimension2_); i++) + ((Tdst*)pValue)[i] = ((Tsrc*)pRecvValue_)[i]; + } + + template <typename T> + inline T* Register::getRefArray(FormatType F, uint32_t& dim) + { + if (!hasInputAccess()) + throw SilecsException(__FILE__, __LINE__, DATA_READ_ACCESS_TYPE_MISMATCH, getName()); + if ((format_ != F) || !isSingleArray()) + throw SilecsException(__FILE__, __LINE__, PARAM_FORMAT_TYPE_MISMATCH, getName()); + dim = dimension1_; + return (T*)pRecvValue_; + } + + template <typename T> + inline T* Register::getRefArray2D(FormatType F, uint32_t& dim1, uint32_t& dim2) + { + if (!hasInputAccess()) + throw SilecsException(__FILE__, __LINE__, DATA_READ_ACCESS_TYPE_MISMATCH, getName()); + if((format_ != F) || !isDoubleArray()) + throw SilecsException(__FILE__, __LINE__, PARAM_FORMAT_TYPE_MISMATCH, getName()); + dim1 = dimension1_; + dim2 = dimension2_; + return (T*)pRecvValue_; + } + + // ......................................................................... + // No template for string format + std::string Register::getValString() + { + if (!hasInputAccess()) + throw SilecsException(__FILE__, __LINE__, DATA_READ_ACCESS_TYPE_MISMATCH, getName()); + if ((format_ != String) || (dimension1_ != 1)|| (dimension2_ != 1)) + throw SilecsException(__FILE__, __LINE__, PARAM_FORMAT_TYPE_MISMATCH, getName()); + std::string** pRecvStringValue = static_cast<std::string**>(pRecvValue_); + return *(pRecvStringValue[0]); + } + + void Register::getValStringArray(std::string* pVal, uint32_t dim) + { + if (!hasInputAccess()) + throw SilecsException(__FILE__, __LINE__, DATA_READ_ACCESS_TYPE_MISMATCH, getName()); + if (format_ != String) + throw SilecsException(__FILE__, __LINE__, PARAM_FORMAT_TYPE_MISMATCH, getName()); + if ((dimension1_ != dim) || (dimension2_ > 1)) + throw SilecsException(__FILE__, __LINE__, PARAM_ARRAY_DIMENSION_MISMATCH, getName()); + std::string** pRecvStringValue = static_cast<std::string**>(pRecvValue_); + for(unsigned long i=0; i<dimension1_; i++) + { pVal[i] = *(pRecvStringValue[i]); + } + } + + void Register::getValStringArray2D(std::string* pVal, uint32_t dim1, uint32_t dim2) + { + if (!hasInputAccess()) + throw SilecsException(__FILE__, __LINE__, DATA_READ_ACCESS_TYPE_MISMATCH, getName()); + if (format_ != String) + throw SilecsException(__FILE__, __LINE__, PARAM_FORMAT_TYPE_MISMATCH, getName()); + if ((dimension1_ != dim1) || (dimension2_ != dim2)) + throw SilecsException(__FILE__, __LINE__, PARAM_ARRAY_DIMENSION_MISMATCH, getName()); + std::string** pRecvStringValue = static_cast<std::string**>(pRecvValue_); + for(unsigned long i=0; i<dimension1_; i++) + { for(unsigned long j=0; j<dimension2_; j++) + { pVal[(i*dimension2_)+j] = *(pRecvStringValue[(i*dimension2_)+j]); + } + } + } + + const std::string** Register::getRefStringArray(uint32_t& dim) + { + if (!hasInputAccess()) + throw SilecsException(__FILE__, __LINE__, DATA_READ_ACCESS_TYPE_MISMATCH, getName()); + if (dimension1_ <= 1) + throw SilecsException(__FILE__, __LINE__, PARAM_ARRAY_DIMENSION_MISMATCH, getName()); + dim = dimension1_; + return (const std::string**)pRecvValue_; + } + + const std::string** Register::getRefStringArray2D(uint32_t& dim1, uint32_t& dim2) + { + if (!hasInputAccess()) + throw SilecsException(__FILE__, __LINE__, DATA_READ_ACCESS_TYPE_MISMATCH, getName()); + if (dimension2_ <= 1) + throw SilecsException(__FILE__, __LINE__, PARAM_ARRAY_DIMENSION_MISMATCH, getName()); + dim1 = dimension1_; + dim2 = dimension2_; + return (const std::string**)pRecvValue_; + } + + // ......................................................................... + //Deprecated: initially for SLC5 (32bits platform) + char Register::getValChar() { return (char)getVal<int8_t>(Char);} + void Register::getValCharArray(char* pVal, uint32_t dim) { getValArray<int8_t>(Char, (int8_t*)pVal, dim); } + void Register::getValCharArray2D(char* pVal, uint32_t dim1, uint32_t dim2) { getValArray2D<int8_t>(Char, (int8_t*)pVal, dim1, dim2); } + const char* Register::getRefCharArray(uint32_t& dim) { return (const char*)getRefArray<int8_t>(Char, dim); } + const char* Register::getRefCharArray2D(uint32_t& dim1, uint32_t& dim2) { return (const char*)getRefArray2D<int8_t>(Char, dim1, dim2); } + + unsigned char Register::getValUChar() { return getVal<uint8_t>(uChar); } + void Register::getValUCharArray(unsigned char* pVal, uint32_t dim) { getValArray<uint8_t>(uChar, (uint8_t*)pVal, dim); } + void Register::getValUCharArray2D(unsigned char* pVal, uint32_t dim1, uint32_t dim2) { getValArray2D<uint8_t>(uChar, (uint8_t*)pVal, dim1, dim2); } + void Register::getValUCharArray(short* pVal, uint32_t dim) { convGetValArray<unsigned char,short>(uChar, pVal, dim); } + void Register::getValUCharArray2D(short* pVal, uint32_t dim1, uint32_t dim2) { convGetValArray2D<unsigned char,short>(uChar, pVal, dim1, dim2); } + const unsigned char* Register::getRefUCharArray(uint32_t& dim) { return (const unsigned char*)getRefArray<uint8_t>(uChar, dim); } + const unsigned char* Register::getRefUCharArray2D(uint32_t& dim1, uint32_t& dim2) { return (const unsigned char*)getRefArray2D<uint8_t>(uChar, dim1, dim2); } + + short Register::getValShort() { return (short)getVal<int16_t>(Short); } + void Register::getValShortArray(short* pVal, uint32_t dim) { getValArray<int16_t>(Short, (int16_t*)pVal, dim); } + void Register::getValShortArray2D(short* pVal, uint32_t dim1, uint32_t dim2) { getValArray2D<int16_t>(Short, (int16_t*)pVal, dim1, dim2); } + const short* Register::getRefShortArray(uint32_t& dim) { return (short*)getRefArray<int16_t>(Short, dim); } + short* Register::getRefShortArray2D(uint32_t& dim1, uint32_t& dim2) { return (short*)getRefArray2D<int16_t>(Short, dim1, dim2); } + + unsigned short Register::getValUShort() { return (unsigned short)getVal<uint16_t>(uShort); } + void Register::getValUShortArray(unsigned short* pVal, uint32_t dim) { getValArray<uint16_t>(uShort, (uint16_t*)pVal, dim); } + void Register::getValUShortArray2D(unsigned short* pVal, uint32_t dim1, uint32_t dim2) { getValArray2D<uint16_t>(uShort, (uint16_t*)pVal, dim1, dim2); } + void Register::getValUShortArray(long* pVal, uint32_t dim) { convGetValArray<unsigned short, long>(uShort, pVal, dim); } + void Register::getValUShortArray2D(long* pVal, uint32_t dim1, uint32_t dim2) { convGetValArray2D<unsigned short, long>(uShort, pVal, dim1, dim2); } + const unsigned short* Register::getRefUShortArray(uint32_t& dim) { return (const unsigned short*)getRefArray<uint16_t>(uShort, dim); } + const unsigned short* Register::getRefUShortArray2D(uint32_t& dim1, uint32_t& dim2) { return (const unsigned short*)getRefArray2D<uint16_t>(uShort, dim1, dim2); } + + #ifndef __x86_64__ + //not supported anymore from SLC6 platform (look at <.h> comments) + long Register::getValLong() { return (long)getVal<int32_t>(Long); } + void Register::getValLongArray(long* pVal, uint32_t dim) { getValArray<int32_t>(Long, (int32_t*)pVal, dim); } + void Register::getValLongArray2D(long* pVal, uint32_t dim1, uint32_t dim2) { getValArray2D<int32_t>(Long, (int32_t*)pVal, dim1, dim2); } + const long* Register::getRefLongArray(uint32_t& dim) { return (const long*)getRefArray<int32_t>(Long, dim); } + const long* Register::getRefLongArray2D(uint32_t& dim1, uint32_t& dim2) { return (const long*)getRefArray2D<int32_t>(Long, dim1, dim2); } + + unsigned long Register::getValULong() { return (unsigned long)getVal<uint32_t>(uLong); } + void Register::getValULongArray(unsigned long* pVal, uint32_t dim) { getValArray<uint32_t>(uLong, (uint32_t*)pVal, dim); } + void Register::getValULongArray2D(unsigned long* pVal, uint32_t dim1, uint32_t dim2) { getValArray2D<uint32_t>(uLong, (uint32_t*)pVal, dim1, dim2); } + void Register::getValULongArray(long long* pVal, uint32_t dim) { convGetValArray<unsigned long, long long>(uLong, pVal, dim); } + void Register::getValULongArray2D(long long* pVal, uint32_t dim1, uint32_t dim2) { convGetValArray2D<unsigned long, long long>(uLong, pVal, dim1, dim2); } + const unsigned long* Register::getRefULongArray(uint32_t& dim) { return (const unsigned long*)getRefArray<uint32_t>(uLong, dim); } + const unsigned long* Register::getRefULongArray2D(uint32_t& dim1, uint32_t& dim2) { return (const unsigned long*)getRefArray2D<uint32_t>(uLong, dim1, dim2); } + #endif + + float Register::getValFloat() { return getVal<float>(Float); } + void Register::getValFloatArray(float* pVal, uint32_t dim) { getValArray<float>(Float, pVal, dim); } + void Register::getValFloatArray2D(float* pVal, uint32_t dim1, uint32_t dim2) { getValArray2D<float>(Float, pVal, dim1, dim2); } + const float* Register::getRefFloatArray(uint32_t& dim) { return getRefArray<float>(Float, dim); } + const float* Register::getRefFloatArray2D(uint32_t& dim1, uint32_t& dim2) { return getRefArray2D<const float>(Float, dim1, dim2); } + + double Register::getValDate() { return getVal<double>(Date); } + void Register::getValDateArray(double* pVal, uint32_t dim) { getValArray<double>(Date, pVal, dim); } + void Register::getValDateArray2D(double* pVal, uint32_t dim1, uint32_t dim2) { getValArray2D<double>(Date, pVal, dim1, dim2); } + const double* Register::getRefDateArray(uint32_t& dim) { return getRefArray<double>(Date, dim); } + double* Register::getRefDateArray2D(uint32_t& dim1, uint32_t& dim2) { return getRefArray2D<double>(Date, dim1, dim2); } + + // ......................................................................... + //Recommended: from SLC6 (32bits and 64bits platform) + int8_t Register::getValInt8() { return getVal<int8_t>(Int8); } + void Register::getValInt8Array(int8_t* pVal, uint32_t dim) { getValArray<int8_t>(Int8, pVal, dim); } + void Register::getValInt8Array2D(int8_t* pVal, uint32_t dim1, uint32_t dim2) { getValArray2D<int8_t>(Int8, pVal, dim1, dim2); } + const int8_t* Register::getRefInt8Array(uint32_t& dim) { return getRefArray<int8_t>(Int8, dim); } + int8_t* Register::getRefInt8Array2D(uint32_t& dim1, uint32_t& dim2) { return getRefArray2D<int8_t>(Int8, dim1, dim2); } + + uint8_t Register::getValUInt8() { return getVal<uint8_t>(uInt8); } + void Register::getValUInt8Array(uint8_t* pVal, uint32_t dim) { getValArray<uint8_t>(uInt8, pVal, dim); } + void Register::getValUInt8Array2D(uint8_t* pVal, uint32_t dim1, uint32_t dim2) { getValArray2D<uint8_t>(uInt8, pVal, dim1, dim2); } + void Register::getValUInt8Array(int16_t* pVal, uint32_t dim) { convGetValArray<uint8_t, int16_t>(uInt8, pVal, dim); } + void Register::getValUInt8Array2D(int16_t* pVal, uint32_t dim1, uint32_t dim2) { convGetValArray2D<uint8_t, int16_t>(uInt8, pVal, dim1, dim2); } + const uint8_t* Register::getRefUInt8Array(uint32_t& dim) { return getRefArray<uint8_t>(uInt8, dim); } + uint8_t* Register::getRefUInt8Array2D(uint32_t& dim1, uint32_t& dim2) { return getRefArray2D<uint8_t>(uInt8, dim1, dim2); } + + int16_t Register::getValInt16() { return getVal<int16_t>(Int16); } + void Register::getValInt16Array(int16_t* pVal, uint32_t dim) { getValArray<int16_t>(Int16, pVal, dim); } + void Register::getValInt16Array2D(int16_t* pVal, uint32_t dim1, uint32_t dim2) { getValArray2D<int16_t>(Int16, pVal, dim1, dim2); } + const int16_t* Register::getRefInt16Array(uint32_t& dim) { return getRefArray<int16_t>(Int16, dim); } + int16_t* Register::getRefInt16Array2D(uint32_t& dim1, uint32_t& dim2) { return getRefArray2D<int16_t>(Int16, dim1, dim2); } + + uint16_t Register::getValUInt16() { return getVal<uint16_t>(uInt16); } + void Register::getValUInt16Array(uint16_t* pVal, uint32_t dim) { getValArray<uint16_t>(uInt16, pVal, dim); } + void Register::getValUInt16Array2D(uint16_t* pVal, uint32_t dim1, uint32_t dim2) { getValArray2D<uint16_t>(uInt16, pVal, dim1, dim2); } + void Register::getValUInt16Array(int32_t* pVal, uint32_t dim) { convGetValArray<uint16_t, int32_t>(uInt16, pVal, dim); } + void Register::getValUInt16Array2D(int32_t* pVal, uint32_t dim1, uint32_t dim2) { convGetValArray2D<uint16_t, int32_t>(uInt16, pVal, dim1, dim2); } + const uint16_t* Register::getRefUInt16Array(uint32_t& dim) { return getRefArray<uint16_t>(uInt16, dim); } + uint16_t* Register::getRefUInt16Array2D(uint32_t& dim1, uint32_t& dim2) { return getRefArray2D<uint16_t>(uInt16, dim1, dim2); } + + int32_t Register::getValInt32() { return getVal<int32_t>(Int32); } + void Register::getValInt32Array(int32_t* pVal, uint32_t dim) { getValArray<int32_t>(Int32, pVal, dim); } + void Register::getValInt32Array2D(int32_t* pVal, uint32_t dim1, uint32_t dim2) { getValArray2D<int32_t>(Int32, pVal, dim1, dim2); } + const int32_t* Register::getRefInt32Array(uint32_t& dim) { return getRefArray<int32_t>(Int32, dim); } + int32_t* Register::getRefInt32Array2D(uint32_t& dim1, uint32_t& dim2) { return getRefArray2D<int32_t>(Int32, dim1, dim2); } + + uint32_t Register::getValUInt32() { return getVal<uint32_t>(uInt32); } + void Register::getValUInt32Array(uint32_t* pVal, uint32_t dim) { getValArray<uint32_t>(uInt32, pVal, dim); } + void Register::getValUInt32Array2D(uint32_t* pVal, uint32_t dim1, uint32_t dim2) { getValArray2D<uint32_t>(uInt32, pVal, dim1, dim2); } + void Register::getValUInt32Array(int64_t* pVal, uint32_t dim) { convGetValArray<uint32_t, int64_t>(uInt32, pVal, dim); } + void Register::getValUInt32Array2D(int64_t* pVal, uint32_t dim1, uint32_t dim2) { convGetValArray2D<uint32_t, int64_t>(uInt32, pVal, dim1, dim2); } + const uint32_t* Register::getRefUInt32Array(uint32_t& dim) { return getRefArray<uint32_t>(uInt32, dim); } + uint32_t* Register::getRefUInt32Array2D(uint32_t& dim1, uint32_t& dim2) { return getRefArray2D<uint32_t>(uInt32, dim1, dim2); } + + int64_t Register::getValInt64() { return getVal<int64_t>(Int64); } + void Register::getValInt64Array(int64_t* pVal, uint32_t dim) { getValArray<int64_t>(Int64, pVal, dim); } + void Register::getValInt64Array2D(int64_t* pVal, uint32_t dim1, uint32_t dim2) { getValArray2D<int64_t>(Int64, pVal, dim1, dim2); } + const int64_t* Register::getRefInt64Array(uint32_t& dim) { return getRefArray<int64_t>(Int64, dim); } + int64_t* Register::getRefInt64Array2D(uint32_t& dim1, uint32_t& dim2) { return getRefArray2D<int64_t>(Int64, dim1, dim2); } + + uint64_t Register::getValUInt64() { return getVal<uint64_t>(uInt64); } + void Register::getValUInt64Array(uint64_t* pVal, uint32_t dim) { getValArray<uint64_t>(uInt64, pVal, dim); } + void Register::getValUInt64Array2D(uint64_t* pVal, uint32_t dim1, uint32_t dim2) { getValArray2D<uint64_t>(uInt64, pVal, dim1, dim2); } + const uint64_t* Register::getRefUInt64Array(uint32_t& dim) { return getRefArray<uint64_t>(uInt64, dim); } + uint64_t* Register::getRefUInt64Array2D(uint32_t& dim1, uint32_t& dim2) { return getRefArray2D<uint64_t>(uInt64, dim1, dim2); } + + float Register::getValFloat32() { return getVal<float>(Float32); } + void Register::getValFloat32Array(float* pVal, uint32_t dim) { getValArray<float>(Float32, pVal, dim); } + void Register::getValFloat32Array2D(float* pVal, uint32_t dim1, uint32_t dim2) { getValArray2D<float>(Float32, pVal, dim1, dim2); } + const float* Register::getRefFloat32Array(uint32_t& dim) { return getRefArray<float>(Float32, dim); } + float* Register::getRefFloat32Array2D(uint32_t& dim1, uint32_t& dim2) { return getRefArray2D<float>(Float32, dim1, dim2); } + + double Register::getValFloat64() { return getVal<double>(Float64); } + void Register::getValFloat64Array(double* pVal, uint32_t dim) { getValArray<double>(Float64, pVal, dim); } + void Register::getValFloat64Array2D(double* pVal, uint32_t dim1, uint32_t dim2) { getValArray2D<double>(Float64, pVal, dim1, dim2); } + const double* Register::getRefFloat64Array(uint32_t& dim) { return getRefArray<double>(Float64, dim); } + double* Register::getRefFloat64Array2D(uint32_t& dim1, uint32_t& dim2) { return getRefArray2D<double>(Float64, dim1, dim2); } + + // SET methods ============================================================= + void Register::setAccessType(AccessType accessType) + { + accessType_ = accessType; + + // By knowing the register type we can allocate 1 or 2 buffers for data exchanges. + pRecvValue_ = pSendValue_ = NULL; + + if (Service::withInputAccess(accessType)) + { + if (format_ == String) + { + pRecvValue_ = calloc(dimension1_*dimension2_, sizeof(void*)); + std::string** pRecvStringValue = static_cast<std::string**>(pRecvValue_); + + // allocate memory for the required pointers to the strings + for (unsigned long i=0; i<dimension1_*dimension2_; i++) + { pRecvStringValue[i] = new std::string(); + } + } + else // If not string register just allocate space for data + { + pRecvValue_ = calloc(dimension1_*dimension2_, size_); + } + } + + if (Service::withOutputAccess(accessType)) + { + if (format_ == String) + { + pSendValue_ = calloc(dimension1_*dimension2_, sizeof(void*)); + std::string** pSendStringValue = static_cast<std::string**>(pSendValue_); + + //allocate memory for the required pointers to the strings + for (unsigned long i=0; i<dimension1_*dimension2_; i++) + { // allocate space for the string object + pSendStringValue[i] = new std::string(); + } + } + else // if not string register just allocate space for data + { + pSendValue_ = calloc(dimension1_*dimension2_, size_); + } + } + + /* The synchronization mode and the Access type of the register must be compatible: + * - Read-only register cannot have SLAVE synchronization (not supported: has to be Read-Write register) + * - Write-only register cannot have MASTER synchronization (does not make sense) + */ + if ( ((accessType_ == Input) && (synchro_ == Slave) ) || + ((accessType_ == Output) && (synchro_ == Master) )) + throw SilecsException(__FILE__, __LINE__, DATA_SYNCHRO_ACCESS_TYPE_MISMATCH, name_); + } + + template <typename T> + inline void Register::setVal(FormatType F, T val) + { + if (!hasOutputAccess()) + throw SilecsException(__FILE__, __LINE__, DATA_WRITE_ACCESS_TYPE_MISMATCH, getName()); + if ((format_ != F) || (dimension1_ != 1)) + throw SilecsException(__FILE__, __LINE__, PARAM_FORMAT_TYPE_MISMATCH, getName()); + *((T*)pSendValue_) = val; + isInitialized_ = true; //the register value has been set once at least + } + + template <typename T> + inline void Register::setValArray(FormatType F, const T* pVal, uint32_t dim) + { + if (!hasOutputAccess()) + throw SilecsException(__FILE__, __LINE__, DATA_WRITE_ACCESS_TYPE_MISMATCH, getName()); + if (format_ != F) + throw SilecsException(__FILE__, __LINE__, PARAM_FORMAT_TYPE_MISMATCH, getName()); + if (dimension1_ != dim) + throw SilecsException(__FILE__, __LINE__, PARAM_ARRAY_DIMENSION_MISMATCH, getName()); + memcpy(pSendValue_, (void *)pVal, size_*dimension1_); + isInitialized_ = true; //the register value has been set once at least + } + + template <typename T> + inline void Register::setValArray2D(FormatType F, const T* pVal, uint32_t dim1, uint32_t dim2) + { + if (!hasOutputAccess()) + throw SilecsException(__FILE__, __LINE__, DATA_WRITE_ACCESS_TYPE_MISMATCH, getName()); + if (format_ != F) + throw SilecsException(__FILE__, __LINE__, PARAM_FORMAT_TYPE_MISMATCH, getName()); + if ((dimension1_ != dim1) || (dimension2_ != dim2)) + throw SilecsException(__FILE__, __LINE__, PARAM_ARRAY_DIMENSION_MISMATCH, getName()); + memcpy(pSendValue_, (void *)pVal, size_*dimension1_*dimension2_); + isInitialized_ = true; //the register value has been set once at least + } + + template <typename Tsrc, typename Tdst> + inline void Register::convSetValArray(FormatType F, const Tsrc* pVal, uint32_t dim) + { + if (!hasOutputAccess()) + throw SilecsException(__FILE__, __LINE__, DATA_WRITE_ACCESS_TYPE_MISMATCH, getName()); + if (format_ != F) + throw SilecsException(__FILE__, __LINE__, PARAM_FORMAT_TYPE_MISMATCH, getName()); + if (dimension1_ != dim) + throw SilecsException(__FILE__, __LINE__, PARAM_ARRAY_DIMENSION_MISMATCH, getName()); + // conversion from Type-source to Type-destination + for(unsigned long i=0; i<dimension1_; i++) + ((Tdst*)pSendValue_)[i] = pVal[i]; + isInitialized_ = true; //the register value has been set once at least + } + + template <typename Tsrc, typename Tdst> + inline void Register::convSetValArray2D(FormatType F, const Tsrc* pVal, uint32_t dim1, uint32_t dim2) + { + if (!hasOutputAccess()) + throw SilecsException(__FILE__, __LINE__, DATA_WRITE_ACCESS_TYPE_MISMATCH, getName()); + if (format_ != F) + throw SilecsException(__FILE__, __LINE__, PARAM_FORMAT_TYPE_MISMATCH, getName()); + if ((dimension1_ != dim1) || (dimension2_ != dim2)) + throw SilecsException(__FILE__, __LINE__, PARAM_ARRAY_DIMENSION_MISMATCH, getName()); + // conversion from Type-source to Type-destination + for(unsigned long i=0; i<(dimension1_*dimension2_); i++) + ((Tdst*)pSendValue_)[i] = ((Tsrc*)pVal)[i]; + isInitialized_ = true; //the register value has been set once at least + } + + // ......................................................................... + // No template for string format + void Register::setValString(std::string val) + { + if (!hasOutputAccess()) + throw SilecsException(__FILE__, __LINE__, DATA_WRITE_ACCESS_TYPE_MISMATCH, getName()); + if ((format_ != String) || (dimension1_ != 1)|| (dimension2_ != 1)) + throw SilecsException(__FILE__, __LINE__, PARAM_FORMAT_TYPE_MISMATCH, getName()); + + std::string** pSendStringValue = static_cast<std::string**>(pSendValue_); + *(pSendStringValue[0]) = val; + isInitialized_ = true; //the register value has been set once at least + } + + void Register::setValStringArray(const std::string* pVal, uint32_t dim) + { + if (!hasOutputAccess()) + throw SilecsException(__FILE__, __LINE__, DATA_WRITE_ACCESS_TYPE_MISMATCH, getName()); + if (format_ != String) + throw SilecsException(__FILE__, __LINE__, PARAM_FORMAT_TYPE_MISMATCH, getName()); + if (dimension1_ != dim || dimension2_ > 1) + throw SilecsException(__FILE__, __LINE__, PARAM_ARRAY_DIMENSION_MISMATCH, getName()); + + std::string** pSendStringValue = static_cast<std::string**>(pSendValue_); + for(unsigned long i=0; i<dimension1_; i++) + { *(pSendStringValue[i]) = pVal[i]; + } + isInitialized_ = true; //the register value has been set once at least + } + + void Register::setValStringArray2D(const std::string* pVal, uint32_t dim1, uint32_t dim2) + { + if (!hasOutputAccess()) + throw SilecsException(__FILE__, __LINE__, DATA_WRITE_ACCESS_TYPE_MISMATCH, getName()); + if (format_ != String) + throw SilecsException(__FILE__, __LINE__, PARAM_FORMAT_TYPE_MISMATCH, getName()); + if (dimension1_ != dim1 || dimension2_ != dim2) + throw SilecsException(__FILE__, __LINE__, PARAM_ARRAY_DIMENSION_MISMATCH, getName()); + + std::string** pSendStringValue = static_cast<std::string**>(pSendValue_); + for (unsigned long i=0; i<dimension1_; i++) + { for (unsigned long j=0; j<dimension2_; j++) + { *(pSendStringValue[(i*dimension2_)+j]) = pVal[(i*dimension2_)+j]; + } + } + isInitialized_ = true; //the register value has been set once at least + } + + // ......................................................................... + //Deprecated: initially for SLC5 (32bits platform) + void Register::setValChar(char val) { setVal<int8_t>(Int8, (int8_t)val); } + void Register::setValCharArray(const char* pVal, uint32_t dim) { setValArray<int8_t>(Char, (int8_t*)pVal, dim); } + void Register::setValCharArray2D(const char* pVal, uint32_t dim1, uint32_t dim2) { setValArray2D<int8_t>(Char, (const int8_t*)pVal, dim1, dim2); } + + void Register::setValUChar(unsigned char val) { setVal<uint8_t>(uChar, (uint8_t)val); } + void Register::setValUCharArray(const unsigned char* pVal, uint32_t dim) { setValArray<uint8_t>(uChar, (uint8_t*)pVal, dim); } + void Register::setValUCharArray2D(const unsigned char* pVal, uint32_t dim1, uint32_t dim2) { setValArray2D<uint8_t>(uChar, (const uint8_t*)pVal, dim1, dim2); } + void Register::setValUCharArray(const short* pVal, uint32_t dim) { convSetValArray<short,unsigned char>(uChar, pVal, dim); } + void Register::setValUCharArray2D(const short* pVal, uint32_t dim1, uint32_t dim2) { convSetValArray2D<short,unsigned char>(uChar, pVal, dim1, dim2); } + + void Register::setValShort(short val) { setVal<int16_t>(Short, (int16_t)val); } + void Register::setValShortArray(const short* pVal, uint32_t dim) { setValArray<int16_t>(Short, (int16_t*)pVal, dim); } + void Register::setValShortArray2D(const short* pVal, uint32_t dim1, uint32_t dim2) { setValArray2D<int16_t>(Short, (const int16_t*)pVal, dim1, dim2); } + + void Register::setValUShort(unsigned short val) { setVal<uint16_t>(uShort, (uint16_t)val); } + void Register::setValUShortArray(const unsigned short* pVal, uint32_t dim) { setValArray<uint16_t>(uShort, (uint16_t*)pVal, dim); } + void Register::setValUShortArray2D(const unsigned short* pVal, uint32_t dim1, uint32_t dim2) { setValArray2D<uint16_t>(uShort, (const uint16_t*)pVal, dim1, dim2); } + void Register::setValUShortArray(const long* pVal, uint32_t dim) { convSetValArray<long,unsigned short>(uShort, pVal, dim); } + void Register::setValUShortArray2D(const long* pVal, uint32_t dim1, uint32_t dim2) { convSetValArray2D<long,unsigned short>(uShort, pVal, dim1, dim2); } + + #ifndef __x86_64__ + //not supported anymore from SLC6 platform (look at <.h> comments) + void Register::setValLong(long val) { setVal<int32_t>(Long, (int32_t)val); } + void Register::setValLongArray(const long* pVal, uint32_t dim) { setValArray<int32_t>(Long, (int32_t*)pVal, dim); } + void Register::setValLongArray2D(const long* pVal, uint32_t dim1, uint32_t dim2) { setValArray2D<int32_t>(Long, (int32_t*)pVal, dim1, dim2); } + + void Register::setValULong(unsigned long val) { setVal<uint32_t>(uLong, (uint32_t)val); } + void Register::setValULongArray(const unsigned long* pVal, uint32_t dim) { setValArray<uint32_t>(uLong, (uint32_t*)pVal, dim); } + void Register::setValULongArray2D(const unsigned long* pVal, uint32_t dim1, uint32_t dim2) { setValArray2D<uint32_t>(uLong, (uint32_t*)pVal, dim1, dim2); } + void Register::setValULongArray(const long long* pVal, uint32_t dim) { convSetValArray<long long,unsigned long>(uLong, pVal, dim); } + void Register::setValULongArray2D(const long long* pVal, uint32_t dim1, uint32_t dim2) { convSetValArray2D<long long,unsigned long>(uLong, pVal, dim1, dim2); } + #endif + + void Register::setValFloat(float val) { setVal<float>(Float, val); } + void Register::setValFloatArray(const float* pVal, uint32_t dim) { setValArray<float>(Float, pVal, dim); } + void Register::setValFloatArray2D(const float* pVal, uint32_t dim1, uint32_t dim2) { setValArray2D<float>(Float, pVal, dim1, dim2); } + + //Set date is not required for the time being + void Register::setValDate(double val) { setVal<double>(Date, val); } + void Register::setValDateArray(const double* pVal, uint32_t dim) { setValArray<double>(Date, pVal, dim); } + void Register::setValDateArray2D(const double* pVal, uint32_t dim1, uint32_t dim2) { setValArray2D<double>(Date, pVal, dim1, dim2); } + + // ......................................................................... + //Recommended: from SLC6 (32bits and 64bits platform) + void Register::setValInt8(int8_t val) { setVal<int8_t>(Int8, val); } + void Register::setValInt8Array(const int8_t* pVal, uint32_t dim) { setValArray<int8_t>(Int8, pVal, dim); } + void Register::setValInt8Array2D(const int8_t* pVal, uint32_t dim1, uint32_t dim2) { setValArray2D<int8_t>(Int8, pVal, dim1, dim2); } + + void Register::setValUInt8(uint8_t val) { setVal<uint8_t>(uInt8, val); } + void Register::setValUInt8Array(const uint8_t* pVal, uint32_t dim) { setValArray<uint8_t>(uInt8, pVal, dim); } + void Register::setValUInt8Array2D(const uint8_t* pVal, uint32_t dim1, uint32_t dim2) { setValArray2D<uint8_t>(uInt8, pVal, dim1, dim2); } + void Register::setValUInt8Array(const int16_t* pVal, uint32_t dim) { convSetValArray<int16_t, uint8_t>(uInt8, pVal, dim); } + void Register::setValUInt8Array2D(const int16_t* pVal, uint32_t dim1, uint32_t dim2) { convSetValArray2D<int16_t, uint8_t>(uInt8, pVal, dim1, dim2); } + + void Register::setValInt16(int16_t val) { setVal<int16_t>(Int16, val); } + void Register::setValInt16Array(const int16_t* pVal, uint32_t dim) { setValArray<int16_t>(Int16, pVal, dim); } + void Register::setValInt16Array2D(const int16_t* pVal, uint32_t dim1, uint32_t dim2) { setValArray2D<int16_t>(Int16, pVal, dim1, dim2); } + + void Register::setValUInt16(uint16_t val) { setVal<uint16_t>(uInt16, val); } + void Register::setValUInt16Array(const uint16_t* pVal, uint32_t dim) { setValArray<uint16_t>(uInt16, pVal, dim); } + void Register::setValUInt16Array2D(const uint16_t* pVal, uint32_t dim1, uint32_t dim2) { setValArray2D<uint16_t>(uInt16, pVal, dim1, dim2); } + void Register::setValUInt16Array(const int32_t* pVal, uint32_t dim) { convSetValArray<int32_t, uint16_t>(uInt16, pVal, dim); } + void Register::setValUInt16Array2D(const int32_t* pVal, uint32_t dim1, uint32_t dim2) { convSetValArray2D<int32_t, uint16_t>(uInt16, pVal, dim1, dim2); } + + void Register::setValInt32(int32_t val) { setVal<int32_t>(Int32, val); } + void Register::setValInt32Array(const int32_t* pVal, uint32_t dim) { setValArray<int32_t>(Int32, pVal, dim); } + void Register::setValInt32Array2D(const int32_t* pVal, uint32_t dim1, uint32_t dim2) { setValArray2D<int32_t>(Int32, pVal, dim1, dim2); } + + void Register::setValUInt32(uint32_t val) { setVal<uint32_t>(uInt32, val); } + void Register::setValUInt32Array(const uint32_t* pVal, uint32_t dim) { setValArray<uint32_t>(uInt32, pVal, dim); } + void Register::setValUInt32Array2D(const uint32_t* pVal, uint32_t dim1, uint32_t dim2) { setValArray2D<uint32_t>(uInt32, pVal, dim1, dim2); } + void Register::setValUInt32Array(const int64_t* pVal, uint32_t dim) { convSetValArray<int64_t, uint32_t>(uInt32, pVal, dim); } + void Register::setValUInt32Array2D(const int64_t* pVal, uint32_t dim1, uint32_t dim2) { convSetValArray2D<int64_t, uint32_t>(uInt32, pVal, dim1, dim2); } + + void Register::setValInt64(int64_t val) { setVal<int64_t>(Int64, val); } + void Register::setValInt64Array(const int64_t* pVal, uint32_t dim) { setValArray<int64_t>(Int64, pVal, dim); } + void Register::setValInt64Array2D(const int64_t* pVal, uint32_t dim1, uint32_t dim2) { setValArray2D<int64_t>(Int64, pVal, dim1, dim2); } + + void Register::setValUInt64(uint64_t val) { setVal<uint64_t>(uInt64, val); } + void Register::setValUInt64Array(const uint64_t* pVal, uint32_t dim) { setValArray<uint64_t>(uInt64, pVal, dim); } + void Register::setValUInt64Array2D(const uint64_t* pVal, uint32_t dim1, uint32_t dim2) { setValArray2D<uint64_t>(uInt64, pVal, dim1, dim2); } + + void Register::setValFloat32(float val) { setVal<float>(Float32, val); } + void Register::setValFloat32Array(const float* pVal, uint32_t dim) { setValArray<float>(Float32, pVal, dim); } + void Register::setValFloat32Array2D(const float* pVal, uint32_t dim1, uint32_t dim2) { setValArray2D<float>(Float32, pVal, dim1, dim2); } + + void Register::setValFloat64(double val) { setVal<double>(Float64, val); } + void Register::setValFloat64Array(const double* pVal, uint32_t dim) { setValArray<double>(Float64, pVal, dim); } + void Register::setValFloat64Array2D(const double* pVal, uint32_t dim1, uint32_t dim2) { setValArray2D<double>(Float64, pVal, dim1, dim2); } + + // ......................................................................... + std::string Register::getName() { return name_; } + unsigned long Register::getDimension(uint16_t whichDim) { return ((whichDim == 2) ? dimension2_ : dimension1_); } + uint32_t Register::getDimension1() { return dimension1_; } + uint32_t Register::getDimension2() { return dimension2_; } + uint32_t Register::getLength() {return length_; }; + FormatType Register::getFormat() { return format_; } + std::string Register::getBlockName() { return blockName_; } + std::string Register::getFormatAsString() { return FormatTypeString[format_]; } + SynchroType Register::getSynchroType() { return synchro_; } + std::string Register::getSynchroTypeAsString() { return SynchroTypeString[synchro_]; } + + bool Register::hasInputAccess() { return (accessType_ != Output); } + bool Register::hasOutputAccess() { return (accessType_ != Input); } + + bool Register::isRetentive() { return (synchro_ != No); } + bool Register::isVolatile() { return (synchro_ == No); } + bool Register::isScalar() { return ((dimension1_ == 1) && (dimension2_ == 1)); } + bool Register::isSingleArray() { return ((dimension1_ > 1) && (dimension2_ == 1)); } + bool Register::isDoubleArray() { return (dimension2_ > 1); } + bool Register::isInitialized() { return isInitialized_; } + + FormatType Register::whichFormatType(std::string type) + { + StringUtilities::toLower(type); +#ifndef __x86_64__ +//SLC5 (32bits platform) still uses deprecated types ======== + if (type == "byte") return uChar; + else if (type == "int") return Short; + else if (type == "word") return uShort; + else if (type == "dint") return Long; + else if (type == "dword") return uLong; + else if (type == "real") return Float; +#else +//SLC6 (64bits platform) ==================================== + if (type == "byte") return uInt8; + else if (type == "int") return Int16; + else if (type == "word") return uInt16; + else if (type == "dint") return Int32; + else if (type == "dword") return uInt32; + else if (type == "real") return Float32; +#endif +// ANY platform ============================================= + if (type == "char") return Char; + + else if (type == "dt") return Date; + else if (type == "date") return Date; + + else if (type == "int8") return Int8; + else if (type == "uint8") return uInt8; + else if (type == "int16") return Int16; + else if (type == "uint16") return uInt16; + else if (type == "int32") return Int32; + else if (type == "uint32") return uInt32; + else if (type == "int64") return Int64; + else if (type == "uint64") return uInt64; + else if (type == "float32") return Float32; + else if (type == "float64") return Float64; + else if (type == "string") return String; + else throw SilecsException(__FILE__, __LINE__, DATA_UNKNOWN_FORMAT_TYPE, type); + } + + + std::string Register::getValAsByteString(void* pValue, unsigned long maxSize) + { + std::ostringstream os; + std::string** pStringValue = static_cast<std::string**>(pValue); + unsigned long nbElement = dimension1_*dimension2_; + unsigned long byteSize = nbElement*size_; + unsigned long nbLoop = (getFormat() == String) ? nbElement : byteSize; + + for (unsigned int i=0; i<nbLoop; i++) + { + if ((i==maxSize) && (nbLoop > 2*maxSize)) + { i = nbLoop - maxSize; + os << ".... "; + } + + if (getFormat() == String) { + os << *pStringValue[i] << " "; + } + else { + os << (unsigned int)((unsigned char*)pValue)[i] << " "; + } + } + return os.str(); + } + + + std::string Register::getValAsString(void* pValue, unsigned long i, unsigned long j) + { + struct tm dscst; + std::ostringstream os; + + //get element whatever is the value dimension (scalar, single array or flat 2D-array) + unsigned long index = (i*dimension2_)+j; + + if ((i>=dimension1_) || (j>=dimension2_)) + { throw SilecsException(__FILE__, __LINE__, PARAM_ARRAY_DIMENSION_MISMATCH, getName()); + } + + switch (format_) + { // -------- Deprecated types (32bits platform only) + //case Char: os << (char)((char*)pValue)[index]; break; + //case uChar: os << (unsigned int)((unsigned char*)pValue)[index]; break; + //case Short: os << (short)((short*)pValue)[index]; break; + //case uShort: os << (unsigned short)((unsigned short*)pValue)[index]; break; + //case Long: os << (long)((long*)pValue)[index]; break; + //case uLong: os << (unsigned long)((unsigned long*)pValue)[index]; break; + //case Float: os << (float)((float*)pValue)[index]; break; + //-------- Supported types (32 and 64bits platform) + case Int8: os << (int8_t)((int8_t*)pValue)[index]; break; + case uInt8: os << (uint16_t)((uint8_t*)pValue)[index]; break; + case Int16: os << (int16_t)((int16_t*)pValue)[index]; break; + case uInt16: os << (uint16_t)((uint16_t*)pValue)[index]; break; + case Int32: os << (int32_t)((int32_t*)pValue)[index]; break; + case uInt32: os << (uint32_t)((uint32_t*)pValue)[index]; break; + case Int64: os << (int64_t)((int64_t*)pValue)[index]; break; + case uInt64: os << (uint64_t)((uint64_t*)pValue)[index]; break; + case Float32: os << (float)((float*)pValue)[index]; break; + case Float64: os << (double)((double*)pValue)[index]; break; + case String: + { std::string** pStringValue = static_cast<std::string**>(pValue); + os << *(pStringValue[index]); + break; + } + case Date: + { dscst = getTMDate(((double*)pValue)[index]); + os << dscst.tm_year+1900 << "-" << dscst.tm_mon+1 << "-" << dscst.tm_mday << "-" << dscst.tm_hour << ":" << dscst.tm_min << ":" << dscst.tm_sec << " "; + break; + } + default: + throw SilecsException(__FILE__, __LINE__, DATA_UNKNOWN_FORMAT_TYPE, StringUtilities::toString(format_)); + } + return os.str(); + } + + + std::string Register::getInputValAsString() { return getInputValAsString(0, 0); }; + std::string Register::getInputValAsString(unsigned long i) { return getInputValAsString(i, 0); }; + std::string Register::getInputValAsString(unsigned long i, unsigned long j) + { + if (hasInputAccess()) + { return getValAsString(pRecvValue_,i,j); + } + else + throw SilecsException(__FILE__, __LINE__, DATA_READ_ACCESS_TYPE_MISMATCH, getName()); + } + + + std::string Register::getOutputValAsString() { return getOutputValAsString(0, 0); }; + std::string Register::getOutputValAsString(unsigned long i) { return getOutputValAsString(i, 0); }; + std::string Register::getOutputValAsString(unsigned long i, unsigned long j) + { + if (hasOutputAccess()) + { return getValAsString(pSendValue_,i,j); + } + else + throw SilecsException(__FILE__, __LINE__, DATA_READ_ACCESS_TYPE_MISMATCH, getName()); + } + + + std::string Register::dumpInputVal(bool asAsciiChar) + { + std::ostringstream os; + unsigned long byteSize = dimension1_*dimension2_*size_; + for (unsigned int i=0; i<byteSize; i++) + { + if (asAsciiChar) + { + // Returns when end of string is found + // TODO Release 4.0.0: add this check only for String registers + if(((char)((unsigned char*)pRecvValue_)[i]) == 0) // returns as soon as it reaches the end of the string + break; + os << (char)((unsigned char*)pRecvValue_)[i]; + } + else + os << hex << (unsigned int)((unsigned char*)pRecvValue_)[i] << " "; + } + return os.str(); + } + + + std::string Register::dumpOutputVal(bool asAsciiChar) + { + std::ostringstream os; + unsigned long byteSize = dimension1_*dimension2_*size_; + for (unsigned int i=0; i<byteSize; i++) + { + if (asAsciiChar) + os << (char)((unsigned char*)pSendValue_)[i]; + else + os << hex << (unsigned int)((unsigned char*)pSendValue_)[i] << " "; + } + return os.str(); + } + + + struct tm Register::getTMDate(double date) + { + struct tm dscst; + time_t dt = (time_t)date; + localtime_r(&dt, &dscst); + return dscst; + } + + time_t Register::getEpochDate(double date) + { + return static_cast<time_t>(round(date)); + } + + + timeval Register::getTimeStamp() + { + if (hasInputAccess()) return tod_; + throw SilecsException(__FILE__, __LINE__, PARAM_NO_TIME_STAMP, getName()); + } + + + std::string Register::getTimeStampAsString() + { + if (hasInputAccess()) + { + std::ostringstream os; + double ts = (double)tod_.tv_sec + (double)tod_.tv_usec/1000000.0; //second + os << std::setprecision(20) << ts << "s"; + return os.str(); + } + else + return "not defined"; + } + + + void Register::printVal() + { + std::ostringstream os; + os << getName() << " " << getFormatAsString() << "[" << dimension1_ << "][" << dimension2_ << "] " << getSynchroTypeAsString(); + if(getFormat() == String) os << ", string-length: " << getLength(); + + if (hasInputAccess()) { + os << ", input: "; + for (unsigned int i=0; i<dimension1_; i++) + for (unsigned int j=0; j<dimension2_; j++) + os << getValAsString(pRecvValue_, i, j) << " "; + } + + if (hasOutputAccess()) { + os << ", output: "; + for (unsigned int i=0; i<dimension1_; i++) + for (unsigned int j=0; j<dimension2_; j++) + os << getValAsString(pSendValue_, i, j) << " "; + } + std::cout << os.str() << std::endl; + } + +} // namespace diff --git a/silecs-communication-cpp/src/silecs-communication/interface/equipment/SilecsRegister.h b/silecs-communication-cpp/src/silecs-communication/interface/equipment/SilecsRegister.h new file mode 100644 index 0000000..5a5023c --- /dev/null +++ b/silecs-communication-cpp/src/silecs-communication/interface/equipment/SilecsRegister.h @@ -0,0 +1,1727 @@ +// Copyright 2016 CERN and GSI +// +// 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 3 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, see <http://www.gnu.org/licenses/>. + +#ifndef _SILECS_REGISTER_H_ +#define _SILECS_REGISTER_H_ + +#include <stdint.h> +#include <boost/shared_ptr.hpp> + +namespace Silecs +{ + class PLC; + class Device; + class ElementXML; + + /// @cond + // Register supported format + static const std::string FormatTypeString[] = + { //!!Must be synchronized with FormatType enumeration + + //"uChar", /*!<: SLC5 deprecated: 8-bits unsigned char = PLC BYTE */ + //"Char", /*!<: 8-bits ascii char = PLC CHAR */ + //"uShort", /*!<: SLC5 deprecated: 16-bits unsigned int = PLC WORD */ + //"Short", /*!<: SLC5 deprecated: 16-bits signed int = PLC INT */ + //"uLong", /*!<: SLC5 deprecated: 32-bits unsigned long = PLC DWORD*/ + //"Long", /*!<: SLC5 deprecated: 32-bits signed long = PLC DINT */ + //"Float", /*!<: SLC5 deprecated: 32-bits signed float = PLC REAL */ + + "uInt8", /*!<: 8-bits unsigned integer*/ + "Int8", /*!<: 8-bits integer*/ + "uInt16", /*!<: 16-bits unsigned integer*/ + "Int16", /*!<: 16-bits integer*/ + "uInt32", /*!<: 32-bits unsigned integer*/ + "Int32", /*!<: 32-bits integer*/ + "Float32",/*!<: 32-bits signed float*/ + "Date", /*!<: 64-bits time (elapsed time since the POSIX.1 Epoch (00:00:00 UTC, January 1, 1970) = dt */ + + "uInt64", /*!<: 64-bits unsigned integer*/ + "Int64", /*!<: 64-bits integer*/ + "Float64", /*!<: 64-bits signed float*/ + "String" /*!<: String of ASCII characters*/ + }; + + // Register synchronization type + static const std::string SynchroTypeString[] = + { + "Master", //register is retentive, PLC is the source + "Slave", //register is retentive, client is the source + "NoSynchro" //register is volatile + }; + /// @endcond + + + /*! + * \brief Enumeration for the Register data type. Used by Register::getFormat() method. + * Each type has a PLC type equivalent (see below) + */ + typedef enum + { + //!!Must be synchronized with FormatTypeString[] + uChar=0, /*!<: SLC5 deprecated: 8-bits unsigned char = PLC BYTE */ + Char=1, /*!<: 8-bits ascii char = PLC CHAR */ + uShort=2, /*!<: SLC5 deprecated: 16-bits unsigned int = PLC WORD */ + Short=3, /*!<: SLC5 deprecated: 16-bits signed int = PLC INT */ + uLong=4, /*!<: SLC5 deprecated: 32-bits unsigned long = PLC DWORD*/ + Long=5, /*!<: SLC5 deprecated: 32-bits signed long = PLC DINT */ + Float=6, /*!<: SLC5 deprecated: 32-bits signed float = PLC REAL */ + Date=7, /*!<: 64-bits double (elapsed time since the POSIX.1 Epoch (00:00:00 UTC, January 1, 1970) = dt */ + + uInt8=0, /*!<: 8-bits unsigned integer*/ + Int8=1, /*!<: 8-bits integer*/ + uInt16=2, /*!<: 16-bits unsigned integer*/ + Int16=3, /*!<: 16-bits integer*/ + uInt32=4, /*!<: 32-bits unsigned integer*/ + Int32=5, /*!<: 32-bits integer*/ + Float32=6,/*!<: 32-bits signed float*/ + + uInt64=8, /*!<: 64-bits unsigned integer*/ + Int64=9, /*!<: 64-bits integer*/ + Float64=10, /*!<: 64-bits signed float*/ + String=11 + + } FormatType; + + /*! + * \class Register + * \brief This object stores the final device data. + * It provides interface to update and extract the register value. + * The Register name is unique within the scope of the device class. + */ + class Register + { + public: + + /*! + * \brief Returns reference of the Device where the register is instantiated + * \return Reference of the Device object + */ + Device* getDevice(); + + /*! + * \brief Returns the register name as defined in the Class design + * \return Register name + */ + std::string getName(); + + /*! + * \brief Returns the format of the register data + * \return value from the FormatType enumeration + */ + FormatType getFormat(); + + /*! + * \brief Returns number of elements in case of array register (1 in case of scalar register) + * \return Register dimension1 + */ + unsigned long getDimension(uint16_t whichDim=1 /*1,2*/); //for backward compatibility getDimension() ~= getDimension1() + uint32_t getDimension1(); + + /*! + * \brief Returns second dimension in case of 2D-array (1 in case of array register) + * \return Register dimension2 + */ + uint32_t getDimension2(); + + /*! + * \brief Returns length of string in case of a string/array of strings register + * \return Register length + */ + uint32_t getLength(); + + /*! + * \brief Returns the synchronization type of the current register (Master, Slave or No) + * \return value from the SynchroType enumeration + */ + SynchroType getSynchroType(); + + /*! + * \brief Returns the synchronization type of the current register + * \return String value of the Synchronization type ("Master", "Slave" or "NoSynchro") + */ + std::string getSynchroTypeAsString(); + + /*! + * \brief Returns the name of the block which contains the register as defined in the Class design + * \return Block name of the register + */ + std::string getBlockName(); + + /*! + * \brief Time-of-day: number of seconds and microseconds since the POSIX.1 Epoch (00:00:00 UTC, January 1, 1970) + * Use to time-stamp the register coming from PLC (no time-stamping on send). + * FEC clock and Timing are synchronized using SNTP (common GPS source) + * \return Register time-stamping as timeval structure + */ + timeval getTimeStamp(); + + /*! + * \brief A register can have read-only, write-only or read-write access mode as defined in the Class design. + * \return true if register has read-only or read-write access mode + */ + bool hasInputAccess(); + + /*! + * \brief A register can have read-only, write-only or read-write access mode as defined in the Class design. + * \return true if the register has write-only or read-write access mode + */ + bool hasOutputAccess(); + + /*! + * \brief A retentive register can be a persistent or a constant data. + * Its value must be initialized at the system start-up. + * - From the client side if the synchro register is 'Slave' + * - From the PLC side if the synchro register is 'Master' + * \return true if the register has Master or Slave synchro as defined in the Class design + */ + bool isRetentive(); + + /*! + * \brief A register that has not persistent or constant value is Volatile. + * Its value is not initialized at the system start-up. + * \return true if the register has 'No' synchro as defined in the Class design + */ + bool isVolatile(); + + /*! + * \brief A scalar is a single value register (dimension1_ and dimension2_ attributes == 1) + * \return true if register is a scalar + */ + bool isScalar(); + + /*! + * \brief A single array is a register with dimension1_ attribute > 1 + * \return true if register is a single array + */ + bool isSingleArray(); + + /*! + * \brief A double array is a register with dimension2_ attribute > 1 + * \return true if register has second dimension + */ + bool isDoubleArray(); + + // GET methods ============================================================= + + // ......................................................................... + //Deprecated: initially for SLC5 (32bits platform) + + /*! + * \brief Extracts the current value from the register input buffer. + * \return the buffer content in a char format + * \deprecated This method is supported for backward compatibility (version <= 3.2.*). Suggested usage of getValInt8 instead. + */ + char getValChar(); + + /*! + * \brief Extracts the vector of values from the register input buffer. + * \param pVal a char* pointer to a memory location where the method will store a copy of the array + * \param dim vector length in unsigned long format + * \deprecated This method is supported for backward compatibility (version <= 3.2.*). Suggested usage of getValInt8Array instead. + */ + void getValCharArray(char* pVal, uint32_t dim); + + /*! + * \brief Extracts the 2D-array of values from the register input buffer. + * \param pVal a char* pointer to a memory location where the method will store a copy of the flat 2D-array + * \param dim1 first dimension of flat 2D-array in unsigned long format + * \param dim2 second dimension of flat 2D-array in unsigned long format + * \deprecated This method is supported for backward compatibility (version <= 3.2.*). Suggested usage of getValInt8Array2D instead. + */ + void getValCharArray2D(char* pVal, uint32_t dim1, uint32_t dim2); + + /*! + * \brief Return a reference to register input buffer. + * The usage of this method can speed up reading and writing operations when the buffer is very big and a small part of + * information is requested. This method give direct access on the buffer and his adoption is not recommended. + * \param dim Reference where to store the vector dimension in format unsigned long + * \return a char* reference directly to the memory location where the array begins in the buffer + * \deprecated This method is supported for backward compatibility (version <= 3.2.*). Suggested usage of getRefInt8Array instead. + */ + const char* getRefCharArray(uint32_t& dim); + + /*! + * \brief Return a reference to register input buffer. + * The usage of this method can speed up reading and writing operations when the buffer is very big and a small part of + * information is requested. This method gives direct access on the buffer and his adoption is not recommended. + * \param dim1 Reference where to store the first dimension of flat 2D-array in unsigned long format + * \param dim2 Reference where to store the second dimension of flat 2D-array in unsigned long format + * \return a char* reference directly to the memory location where the flat 2D-array begins in the buffer + * \deprecated This method is supported for backward compatibility (version <= 3.2.*). Suggested usage of getRefInt8Array2D instead. + */ + const char* getRefCharArray2D(uint32_t& dim1, uint32_t& dim2); + + /*! + * \brief Extracts the current value from the register input buffer. + * \return the buffer content in a unsigned char format + * \deprecated This method is supported for backward compatibility (version <= 3.2.*). Suggested usage of getValUInt8 instead. + */ + unsigned char getValUChar(); + + /*! + * \brief Extracts the vector of values from the register input buffer. + * \param pVal a unsigned char* pointer to a memory location where the method will store a copy of the array + * \param dim vector length in unsigned long format + * \deprecated This method is supported for backward compatibility (version <= 3.2.*). Suggested usage of getValUInt8Array instead. + */ + void getValUCharArray(unsigned char* pVal, uint32_t dim); + + /*! + * \brief Extracts the 2D-array of values from the register input buffer. + * \param pVal a unsigned char* pointer to a memory location where the method will store a copy of the flat 2D-array + * \param dim1 first dimension of flat 2D-array in unsigned long format + * \param dim2 second dimension of flat 2D-array in unsigned long format + * \deprecated This method is supported for backward compatibility (version <= 3.2.*). Suggested usage of getValUInt8Array2D instead. + */ + void getValUCharArray2D(unsigned char* pVal, uint32_t dim1, uint32_t dim2); + + //specific methods with automatic conversion (JAVA does not support unsigned type) + void getValUCharArray(short* pVal, uint32_t dim); + void getValUCharArray2D(short* pVal, uint32_t dim1, uint32_t dim2); + + /*! + * \brief Return a reference to register input buffer. + * The usage of this method can speed up reading and writing operations when the buffer is very big and a small part of + * information is requested. This method gives direct access on the buffer and his adoption is not recommended. + * \param dim Reference where to store the vector dimension in format unsigned long + * \return a unsigned char* reference directly to the memory location where the array begins in the buffer + * \deprecated This method is supported for backward compatibility (version <= 3.2.*). Suggested usage of getRefUInt8Array instead. + */ + const unsigned char* getRefUCharArray(uint32_t& dim); + + /*! + * \brief Return a reference to register input buffer. + * The usage of this method can speed up reading and writing operations when the buffer is very big and a small part of + * information is requested. This method gives direct access on the buffer and his adoption is not recommended. + * \param dim1 Reference where to store the first dimension of flat 2D-array in unsigned long format + * \param dim2 Reference where to store the second dimension of flat 2D-array in unsigned long format + * \return a unsigned char* reference directly to the memory location where the flat 2D-array begins in the buffer + * \deprecated This method is supported for backward compatibility (version <= 3.2.*). Suggested usage of getRefUInt8Array2D instead. + */ + const unsigned char* getRefUCharArray2D(uint32_t& dim1, uint32_t& dim2); + + + /*! + * \brief Extracts the current value from the register input buffer. + * \return the buffer content in a short format + * \deprecated This method is supported for backward compatibility (version <= 3.2.*). Suggested usage of getValInt16 instead. + */ + short getValShort(); + + /*! + * \brief Extracts the vector of values from the register input buffer. + * \param pVal a short* pointer to a memory location where the method will store a copy of the array + * \param dim vector length in unsigned long format + * \deprecated This method is supported for backward compatibility (version <= 3.2.*). Suggested usage of getValInt16Array instead. + */ + void getValShortArray(short* pVal, uint32_t dim); + + /*! + * \brief Extracts the 2D-array of values from the register input buffer. + * \param pVal a short* pointer to a memory location where the method will store a copy of the flat 2D-array + * \param dim1 first dimension of flat 2D-array in unsigned long format + * \param dim2 second dimension of flat 2D-array in unsigned long format + * \deprecated This method is supported for backward compatibility (version <= 3.2.*). Suggested usage of getValInt16Array2D instead. + */ + void getValShortArray2D(short* pVal, uint32_t dim1, uint32_t dim2); + + /*! + * \brief Return a reference to register input buffer. + * The usage of this method can sped up reading and writing operation when the buffer is very big and a small part of + * information is requested. This method give direct access on the buffer and his adoption is not recommended. + * \param dim Reference where to store the vector dimension in format unsigned long + * \return a short* reference directly to the memory location where the array begins in the buffer + * \deprecated This method is supported for backward compatibility (version <= 3.2.*). Suggested usage of getRefInt16Array instead. + */ + const short* getRefShortArray(uint32_t& dim); + + /*! + * \brief Return a reference to register input buffer. + * The usage of this method can speed up reading and writing operations when the buffer is very big and a small part of + * information is requested. This method gives direct access on the buffer and his adoption is not recommended. + * \param dim1 Reference where to store the first dimension of flat 2D-array in unsigned long format + * \param dim2 Reference where to store the second dimension of flat 2D-array in unsigned long format + * \return a short* reference directly to the memory location where the flat 2D-array begins in the buffer + * \deprecated This method is supported for backward compatibility (version <= 3.2.*). Suggested usage of getRefInt16Array2D instead. + */ + short* getRefShortArray2D(uint32_t& dim1, uint32_t& dim2); + + /*! + * \brief Extracts the current value from the register input buffer. + * \return the buffer content in a unsigned short format + * \deprecated This method is supported for backward compatibility (version <= 3.2.*). Suggested usage of getValUInt16 instead. + */ + unsigned short getValUShort(); + /*! + * \brief Extracts the vector of values from the register input buffer. + * \param pVal a unsigned short* pointer to a memory location where the method will store a copy of the array + * \param dim vector length in unsigned long format + * \deprecated This method is supported for backward compatibility (version <= 3.2.*). Suggested usage of getValUInt16Array instead. + */ + void getValUShortArray(unsigned short* pVal, uint32_t dim); + + /*! + * \brief Extracts the 2D-array of values from the register input buffer. + * \param pVal a unsigned short* pointer to a memory location where the method will store a copy of the flat 2D-array + * \param dim1 first dimension of flat 2D-array in unsigned long format + * \param dim2 second dimension of flat 2D-array in unsigned long format + * \deprecated This method is supported for backward compatibility (version <= 3.2.*). Suggested usage of getValUInt16Array2D instead. + */ + void getValUShortArray2D(unsigned short* pVal, uint32_t dim1, uint32_t dim2); + + //specific method with automatic conversion (JAVA does not support unsigned type) + void getValUShortArray(long* pVal, uint32_t dim); + void getValUShortArray2D(long* pVal, uint32_t dim1, uint32_t dim2); + + /*! + * \brief Return a reference to register input buffer. + * The usage of this method can sped up reading and writing operation when the buffer is very big and a small part of + * information is requested. This method give direct access on the buffer and his adoption is not recommended. + * \param dim Reference where to store the vector dimension in format unsigned long + * \return a unsigned short* reference directly to the memory location where the array begins in the buffer + * \deprecated This method is supported for backward compatibility (version <= 3.2.*). Suggested usage of getRefUInt16Array instead. + */ + const unsigned short* getRefUShortArray(uint32_t& dim); + + /*! + * \brief Return a reference to register input buffer. + * The usage of this method can speed up reading and writing operations when the buffer is very big and a small part of + * information is requested. This method gives direct access on the buffer and his adoption is not recommended. + * \param dim1 Reference where to store the first dimension of flat 2D-array in unsigned long format + * \param dim2 Reference where to store the second dimension of flat 2D-array in unsigned long format + * \return a unsigned short* reference directly to the memory location where the flat 2D-array begins in the buffer + * \deprecated This method is supported for backward compatibility (version <= 3.2.*). Suggested usage of getRefUInt16Array2D instead. + */ + const unsigned short* getRefUShortArray2D(uint32_t& dim1, uint32_t& dim2); + + + #ifndef __x86_64__ //long type is platform dependent (32bits or 64bits integer) + //SLC5: support for 'long' type as 32bits + /*! + * \brief Extracts the current value from the register input buffer. + * \return the buffer content in a long format + * \deprecated This method is supported for backward compatibility (version <= 3.2.*). Suggested usage of getValInt32 instead. + */ + long getValLong(); + + /*! + * \brief Extracts the vector of values from the register input buffer. + * \param pVal a long* pointer to a memory location where the method will store a copy of the array + * \param dim vector length in unsigned long format + * \deprecated This method is supported for backward compatibility (version <= 3.2.*). Suggested usage of getValInt32Array instead. + */ + void getValLongArray(long* pVal, uint32_t dim); + + /*! + * \brief Extracts the 2D-array of values from the register input buffer. + * \param pVal a long* pointer to a memory location where the method will store a copy of the flat 2D-array + * \param dim1 first dimension of flat 2D-array in unsigned long format + * \param dim2 second dimension of flat 2D-array in unsigned long format + * \deprecated This method is supported for backward compatibility (version <= 3.2.*). Suggested usage of getValInt32Array2D instead. + */ + void getValLongArray2D(long* pVal, uint32_t dim1, uint32_t dim2); + + /*! + * \brief Return a reference to register input buffer. + * The usage of this method can sped up reading and writing operation when the buffer is very big and a small part of + * information is requested. This method give direct access on the buffer and his adoption is not recommended. + * \param dim Reference where to store the vector dimension in format unsigned long + * \return a long* reference directly to the memory location where the array begins in the buffer + * \deprecated This method is supported for backward compatibility (version <= 3.2.*). Suggested usage of getRefInt32Array instead. + */ + const long* getRefLongArray(uint32_t& dim); + + /*! + * \brief Return a reference to register input buffer. + * The usage of this method can speed up reading and writing operations when the buffer is very big and a small part of + * information is requested. This method gives direct access on the buffer and his adoption is not recommended. + * \param dim1 Reference where to store the first dimension of flat 2D-array in unsigned long format + * \param dim2 Reference where to store the second dimension of flat 2D-array in unsigned long format + * \return a long* reference directly to the memory location where the flat 2D-array begins in the buffer + * \deprecated This method is supported for backward compatibility (version <= 3.2.*). Suggested usage of getRefInt32Array2D instead. + */ + const long* getRefLongArray2D(uint32_t& dim1, uint32_t& dim2); + + /*! + * \brief Extracts the current value from the register input buffer. + * \return the buffer content in a unsigned long format + * \deprecated This method is supported for backward compatibility (version <= 3.2.*). Suggested usage of getValUInt32 instead. + */ + unsigned long getValULong(); + + /*! + * \brief Extracts the vector of values from the register input buffer. + * \param pVal a unsigned long* pointer to a memory location where the method will store a copy of the array + * \param dim vector length in unsigned long format + * \deprecated This method is supported for backward compatibility (version <= 3.2.*). Suggested usage of getValUInt32Array instead. + */ + void getValULongArray(unsigned long* pVal, uint32_t dim); + + /*! + * \brief Extracts the 2D-array of values from the register input buffer. + * \param pVal a unsigned long* pointer to a memory location where the method will store a copy of the flat 2D-array + * \param dim1 first dimension of flat 2D-array in unsigned long format + * \param dim2 second dimension of flat 2D-array in unsigned long format + * \deprecated This method is supported for backward compatibility (version <= 3.2.*). Suggested usage of getValUInt32Array2D instead. + */ + void getValULongArray2D(unsigned long* pVal, uint32_t dim1, uint32_t dim2); + + //specific method with automatic conversion (JAVA does not support unsigned type) + void getValULongArray(long long* pVal, uint32_t dim); + void getValULongArray2D(long long* pVal, uint32_t dim1, uint32_t dim2); + + /*! + * \brief Return a reference to register input buffer. + * The usage of this method can sped up reading and writing operation when the buffer is very big and a small part of + * information is requested. This method give direct access on the buffer and his adoption is not recommended. + * \param dim Reference where to store the vector dimension in format unsigned long + * \return a unsigned long* reference directly to the memory location where the array begins in the buffer + * \deprecated This method is supported for backward compatibility (version <= 3.2.*). Suggested usage of getRefUInt32Array instead. + */ + const unsigned long* getRefULongArray(uint32_t& dim); + + /*! + * \brief Return a reference to register input buffer. + * The usage of this method can speed up reading and writing operations when the buffer is very big and a small part of + * information is requested. This method gives direct access on the buffer and his adoption is not recommended. + * \param dim1 Reference where to store the first dimension of flat 2D-array in unsigned long format + * \param dim2 Reference where to store the second dimension of flat 2D-array in unsigned long format + * \return a unsigned long* reference directly to the memory location where the flat 2D-array begins in the buffer + * \deprecated This method is supported for backward compatibility (version <= 3.2.*). Suggested usage of getRefUInt32Array2D instead. + */ + const unsigned long* getRefULongArray2D(uint32_t& dim1, uint32_t& dim2); + + #else + //from SLC6: 'long' methods still used as 32bits but with explicit typing instead + //It's recommended to use new appropriate methods instead: Int32/UInt32 + #define getValLong getValInt32 + #define getValLongArray getValInt32Array + #define getRefLongArray getRefInt32Array + + #define getValULong getValUInt32 + #define getValULongArray getValUInt32Array + #define getRefULongArray getRefUInt32Array + #endif + + /*! + * \brief Extracts the current value from the register input buffer. + * \return the buffer content in a unsigned float format + * \deprecated This method is supported for backward compatibility (version <= 3.2.*). Suggested usage of getValFloat32 instead. + */ + float getValFloat(); + + /*! + * \brief Extracts the vector of values from the register input buffer. + * \param pVal a float* pointer to a memory location where the method will store a copy of the array + * \param dim vector length in unsigned long format + * \deprecated This method is supported for backward compatibility (version <= 3.2.*). Suggested usage of getValFloat32Array instead. + */ + void getValFloatArray(float* pVal, uint32_t dim); + + /*! + * \brief Extracts the 2D-array of values from the register input buffer. + * \param pVal a float* pointer to a memory location where the method will store a copy of the flat 2D-array + * \param dim1 first dimension of flat 2D-array in unsigned long format + * \param dim2 second dimension of flat 2D-array in unsigned long format + * \deprecated This method is supported for backward compatibility (version <= 3.2.*). Suggested usage of getValFloat32Array2D instead. + */ + void getValFloatArray2D(float* pVal, uint32_t dim1, uint32_t dim2); + + /*! + * \brief Return a reference to register input buffer. + * The usage of this method can sped up reading and writing operation when the buffer is very big and a small part of + * information is requested. This method give direct access on the buffer and his adoption is not recommended. + * \param dim Reference where to store the vector dimension in format unsigned long + * \return a float* reference directly to the memory location where the array begins in the buffer + * \deprecated This method is supported for backward compatibility (version <= 3.2.*). Suggested usage of getRefFloat32Array instead. + */ + const float* getRefFloatArray(uint32_t& dim); + + /*! + * \brief Return a reference to register input buffer. + * The usage of this method can speed up reading and writing operations when the buffer is very big and a small part of + * information is requested. This method gives direct access on the buffer and his adoption is not recommended. + * \param dim1 Reference where to store the first dimension of flat 2D-array in unsigned long format + * \param dim2 Reference where to store the second dimension of flat 2D-array in unsigned long format + * \return a float* reference directly to the memory location where the flat 2D-array begins in the buffer + * \deprecated This method is supported for backward compatibility (version <= 3.2.*). Suggested usage of getRefFloat32Array2D instead. + */ + const float* getRefFloatArray2D(uint32_t& dim1, uint32_t& dim2); + + /*! + * \brief Extracts the current value from the register input buffer. + * Date type represents the number of millisecond elapsed since 00:00:00 + * on January 1, 1970, Coordinated Universal Time (UTC) + * \return the buffer content in a unsigned double format + */ + double getValDate(); + + /*! + * \brief Extracts the vector of values from the register input buffer. + * Date type represents the number of millisecond elapsed since 00:00:00 + * on January 1, 1970, Coordinated Universal Time (UTC) + * \param pVal a double* pointer to a memory location where the method will store a copy of the array + * \param dim vector length in unsigned long format + */ + void getValDateArray(double* pVal, uint32_t dim); + + /*! + * \brief Extracts the 2D-array of values from the register input buffer. + * Date type represents the number of millisecond elapsed since 00:00:00 + * on January 1, 1970, Coordinated Universal Time (UTC) + * \param pVal a double* pointer to a memory location where the method will store a copy of the flat 2D-array + * \param dim1 first dimension of 2D-array in unsigned long format + * \param dim2 second dimension of 2D-array in unsigned long format + */ + void getValDateArray2D(double* pVal, uint32_t dim1, uint32_t dim2); + + /*! + * \brief Return a reference to register input buffer. + * Date type represents the number of millisecond elapsed since 00:00:00 + * on January 1, 1970, Coordinated Universal Time (UTC) + * The usage of this method can speed up reading and writing operations when the buffer is very big and a small part of + * information is requested. This method gives direct access on the buffer and his adoption is not recommended. + * \param dim reference location where to store the array dimension in unsigned long format + * \return a double* reference directly to the memory location where the flat 2D-array begins in the buffer + */ + const double* getRefDateArray(uint32_t& dim); + + /*! + * \brief Return a reference to register input buffer. + * Date type represents the number of millisecond elapsed since 00:00:00 + * on January 1, 1970, Coordinated Universal Time (UTC) + * The usage of this method can speed up reading and writing operations when the buffer is very big and a small part of + * information is requested. This method gives direct access on the buffer and his adoption is not recommended. + * \param dim1 Reference where to store the first dimension of flat 2D-array in unsigned long format + * \param dim2 Reference where to store the second dimension of flat 2D-array in unsigned long format + * \return a double* reference directly to the memory location where the flat 2D-array begins in the buffer + */ + double* getRefDateArray2D(uint32_t& dim1, uint32_t& dim2); + + // ......................................................................... + //Recommended: from SLC6 (32bits and 64bits platform) + /*! + * \brief Extracts the current value from the register input buffer. + * \return the buffer content in a int8_t format + */ + int8_t getValInt8(); + + /*! + * \brief Extracts the vector of values from the register input buffer. + * \param pVal a int8_t* pointer to a memory location where the method will store a copy of the array + * \param dim vector length in unsigned long format + */ + void getValInt8Array(int8_t* pVal, uint32_t dim); + + /*! + * \brief Extracts the 2D-array of values from the register input buffer. + * \param pVal a int8_t* pointer to a memory location where the method will store a copy of the flat 2D-array + * \param dim1 first dimension of flat 2D-array in unsigned long format + * \param dim2 second dimension of flat 2D-array in unsigned long format + */ + void getValInt8Array2D(int8_t* pVal, uint32_t dim1, uint32_t dim2); + + /*! + * \brief Return a reference to register input buffer. + * The usage of this method can speed up reading and writing operations when the buffer is very big and a small part of + * information is requested. This method gives direct access on the buffer and his adoption is not recommended. + * \param dim Reference where to store the vector dimension in unsigned long format + * \return a int8_t* reference directly to the memory location where the array begins in the buffer + */ + const int8_t* getRefInt8Array(uint32_t& dim); + + /*! + * \brief Return a reference to register input buffer. + * The usage of this method can speed up reading and writing operations when the buffer is very big and a small part of + * information is requested. This method gives direct access on the buffer and his adoption is not recommended. + * \param dim1 Reference where to store the first dimension of flat 2D-array in unsigned long format + * \param dim2 reference where to store the second dimension of flat 2D-array in unsigned long format + * \return a int8_t* reference directly to the memory location where the flat 2D-array begins in the buffer + */ + int8_t* getRefInt8Array2D(uint32_t& dim1, uint32_t& dim2); + + /*! + * \brief Extracts the current value from the register input buffer. + * \return the buffer content in a uint8_t format + */ + uint8_t getValUInt8(); + + /*! + * \brief Extracts the vector of values from the register input buffer. + * \param pVal a uint8_t* pointer to a memory location where the method will store a copy of the array + * \param dim vector length in unsigned long format + */ + void getValUInt8Array(uint8_t* pVal, uint32_t dim); + + /*! + * \brief Extracts the 2D-array of values from the register input buffer. + * \param pVal a uint8_t* pointer to a memory location where the method will store a copy of the flat 2D-array + * \param dim1 first dimension of flat 2D-array in unsigned long format + * \param dim2 second dimension of flat 2D-array in unsigned long format + */ + void getValUInt8Array2D(uint8_t* pVal, uint32_t dim1, uint32_t dim2); + + //specific method with automatic conversion (JAVA does not support unsigned type) + void getValUInt8Array(int16_t* pVal, uint32_t dim); + void getValUInt8Array2D(int16_t* pVal, uint32_t dim1, uint32_t dim2); + + /*! + * \brief Return a reference to register input buffer. + * The usage of this method can sped up reading and writing operation when the buffer is very big and a small part of + * information is requested. This method give direct access on the buffer and his adoption is not recommended. + * \param dim Reference where to store the vector dimension in format unsigned long + * \return a uint8_t* reference directly to the memory location where the array begins in the buffer + */ + const uint8_t* getRefUInt8Array(uint32_t& dim); + + /*! + * \brief Return a reference to register input buffer. + * The usage of this method can speed up reading and writing operations when the buffer is very big and a small part of + * information is requested. This method gives direct access on the buffer and his adoption is not recommended. + * \param dim1 Reference where to store the first dimension of flat 2D-array in unsigned long format + * \param dim2 Reference where to store the second dimension of flat 2D-array in unsigned long format + * \return a uint8_t* reference directly to the memory location where the flat 2D-array begins in the buffer + */ + uint8_t* getRefUInt8Array2D(uint32_t& dim1, uint32_t& dim2); + + /*! + * \brief Extracts the current value from the register input buffer. + * \return the buffer content in a int16_t format + */ + int16_t getValInt16(); + + /*! + * \brief Extracts the vector of values from the register input buffer. + * \param pVal a int16_t* pointer to a memory location where the method will store a copy of the array + * \param dim vector length in unsigned long format + */ + void getValInt16Array(int16_t* pval, uint32_t dim); + + /*! + * \brief Extracts the 2D-array of values from the register input buffer. + * \param pVal a int16_t* pointer to a memory location where the method will store a copy of the flat 2D-array + * \param dim1 first dimension of flat 2D-array in unsigned long format + * \param dim2 second dimension of flat 2D-array in unsigned long format + */ + void getValInt16Array2D(int16_t* pVal, uint32_t dim1, uint32_t dim2); + + /*! + * \brief Return a reference to register input buffer. + * The usage of this method can sped up reading and writing operation when the buffer is very big and a small part of + * information is requested. This method give direct access on the buffer and his adoption is not recommended. + * \param dim Reference where to store the vector dimension in format unsigned long + * \return a int16_t* reference directly to the memory location where the array begins in the buffer + */ + const int16_t* getRefInt16Array(uint32_t& dim); + + /*! + * \brief Return a reference to register input buffer. + * The usage of this method can speed up reading and writing operations when the buffer is very big and a small part of + * information is requested. This method gives direct access on the buffer and his adoption is not recommended. + * \param dim1 Reference where to store the first dimension of flat 2D-array in unsigned long format + * \param dim2 Reference where to store the second dimension of flat 2D-array in unsigned long format + * \return a int16_t* reference directly to the memory location where the flat 2D-array begins in the buffer + */ + int16_t* getRefInt16Array2D(uint32_t& dim1, uint32_t& dim2); + + /*! + * \brief Extracts the current value from the register input buffer. + * \return the buffer content in a uint16_t format + */ + uint16_t getValUInt16(); + + /*! + * \brief Extracts the vector of values from the register input buffer. + * \param pVal a uint16_t* pointer to a memory location where the method will store a copy of the array + * \param dim vector length in unsigned long format + */ + void getValUInt16Array(uint16_t* pVal, uint32_t dim); + + /*! + * \brief Extracts the 2D-array of values from the register input buffer. + * \param pVal a uint16_t* pointer to a memory location where the method will store a copy of the flat 2D-array + * \param dim1 first dimension of flat 2D-array in unsigned long format + * \param dim2 second dimension of flat 2D-array in unsigned long format + */ + void getValUInt16Array2D(uint16_t* pVal, uint32_t dim1, uint32_t dim2); + + //specific method with automatic conversion (JAVA does not support unsigned type) + void getValUInt16Array(int32_t* pVal, uint32_t dim); + void getValUInt16Array2D(int32_t* pVal, uint32_t dim1, uint32_t dim2); + + /*! + * \brief Return a reference to register input buffer. + * The usage of this method can sped up reading and writing operation when the buffer is very big and a small part of + * information is requested. This method give direct access on the buffer and his adoption is not recommended. + * \param dim Reference where to store the vector dimension in format unsigned long + * \return a uint16_t* reference directly to the memory location where the array begins in the buffer + */ + const uint16_t* getRefUInt16Array(uint32_t& dim); + + /*! + * \brief Return a reference to register input buffer. + * The usage of this method can speed up reading and writing operations when the buffer is very big and a small part of + * information is requested. This method gives direct access on the buffer and his adoption is not recommended. + * \param dim1 Reference where to store the first dimension of flat 2D-array in unsigned long format + * \param dim2 Reference where to store the second dimension of flat 2D-array in unsigned long format + * \return a uint16_t* reference directly to the memory location where the flat 2D-array begins in the buffer + */ + uint16_t* getRefUInt16Array2D(uint32_t& dim1, uint32_t& dim2); + + /*! + * \brief Extracts the current value from the register input buffer. + * \return the buffer content in a int32_t format + */ + int32_t getValInt32(); + + /*! + * \brief Extracts the vector of values from the register input buffer. + * \param pVal a int32_t* pointer to a memory location where the method will store a copy of the array + * \param dim vector length in unsigned long format + */ + void getValInt32Array(int32_t* pVal, uint32_t dim); + + /*! + * \brief Extracts the 2D-array of values from the register input buffer. + * \param pVal a int32_t* pointer to a memory location where the method will store a copy of the flat 2D-array + * \param dim1 first dimension of flat 2D-array in unsigned long format + * \param dim2 second dimension of flat 2D-array in unsigned long format + */ + void getValInt32Array2D(int32_t* pVal, uint32_t dim1, uint32_t dim2); + + /*! + * \brief Return a reference to register input buffer. + * The usage of this method can sped up reading and writing operation when the buffer is very big and a small part of + * information is requested. This method give direct access on the buffer and his adoption is not recommended. + * \param dim Reference where to store the vector dimension in format unsigned long + * \return a int32_t* reference directly to the memory location where the array begins in the buffer + */ + const int32_t* getRefInt32Array(uint32_t& dim); + + /*! + * \brief Return a reference to register input buffer. + * The usage of this method can speed up reading and writing operations when the buffer is very big and a small part of + * information is requested. This method gives direct access on the buffer and his adoption is not recommended. + * \param dim1 Reference where to store the first dimension of flat 2D-array in unsigned long format + * \param dim2 Reference where to store the second dimension of flat 2D-array in unsigned long format + * \return a int32_t* reference directly to the memory location where the flat 2D-array begins in the buffer + */ + int32_t* getRefInt32Array2D(uint32_t& dim1, uint32_t& dim2); + + /*! + * \brief Extracts the current value from the register input buffer. + * \return the buffer content in a uint32_t format + */ + uint32_t getValUInt32(); + + /*! + * \brief Extracts the vector of values from the register input buffer. + * \param pVal a uint32_t* pointer to a memory location where the method will store a copy of the array + * \param dim vector length in unsigned long format + */ + void getValUInt32Array(uint32_t* pVal, uint32_t dim); + + /*! + * \brief Extracts the 2D-array of values from the register input buffer. + * \param pVal a uint32_t* pointer to a memory location where the method will store a copy of the flat 2D-array + * \param dim1 first dimension of flat 2D-array in unsigned long format + * \param dim2 second dimension of flat 2D-array in unsigned long format + */ + void getValUInt32Array2D(uint32_t* pVal, uint32_t dim1, uint32_t dim2); + + //specific method with automatic conversion (JAVA does not support unsigned type) + void getValUInt32Array(int64_t* pVal, uint32_t dim); + void getValUInt32Array2D(int64_t* pVal, uint32_t dim1, uint32_t dim2); + + /*! + * \brief Return a reference to register input buffer. + * The usage of this method can sped up reading and writing operation when the buffer is very big and a small part of + * information is requested. This method give direct access on the buffer and his adoption is not recommended. + * \param dim Reference where to store the vector dimension in format unsigned long + * \return a uint32_t* reference directly to the memory location where the array begins in the buffer + */ + const uint32_t* getRefUInt32Array(uint32_t& dim); + + /*! + * \brief Return a reference to register input buffer. + * The usage of this method can speed up reading and writing operations when the buffer is very big and a small part of + * information is requested. This method gives direct access on the buffer and his adoption is not recommended. + * \param dim1 Reference where to store the first dimension of flat 2D-array in unsigned long format + * \param dim2 Reference where to store the second dimension of flat 2D-array in unsigned long format + * \return a uint32_t* reference directly to the memory location where the flat 2D-array begins in the buffer + */ + uint32_t* getRefUInt32Array2D(uint32_t& dim1, uint32_t& dim2); + + /*! + * \brief Extracts the current value from the register input buffer. + * \return the buffer content in a int64_t format + */ + int64_t getValInt64(); + + /*! + * \brief Extracts the vector of values from the register input buffer. + * \param pVal a int64_t* pointer to a memory location where the method will store a copy of the array + * \param dim vector length in unsigned long format + */ + void getValInt64Array(int64_t* pVal, uint32_t dim); + + /*! + * \brief Extracts the 2D-array of values from the register input buffer. + * \param pVal a int8_t* pointer to a memory location where the method will store a copy of the flat 2D-array + * \param dim1 first dimension of flat 2D-array in unsigned long format + * \param dim2 second dimension of flat 2D-array in unsigned long format + */ + void getValInt64Array2D(int64_t* pVal, uint32_t dim1, uint32_t dim2); + + /*! + * \brief Return a reference to register input buffer. + * The usage of this method can sped up reading and writing operation when the buffer is very big and a small part of + * information is requested. This method give direct access on the buffer and his adoption is not recommended. + * \param dim Reference where to store the vector dimension in format unsigned long + * \return a int64_t* reference directly to the memory location where the array begins in the buffer + */ + const int64_t* getRefInt64Array(uint32_t& dim); + + /*! + * \brief Return a reference to register input buffer. + * The usage of this method can speed up reading and writing operations when the buffer is very big and a small part of + * information is requested. This method gives direct access on the buffer and his adoption is not recommended. + * \param dim1 Reference where to store the first dimension of flat 2D-array in unsigned long format + * \param dim2 Reference where to store the second dimension of flat 2D-array in unsigned long format + * \return a int64_t* reference directly to the memory location where the flat 2D-array begins in the buffer + */ + int64_t* getRefInt64Array2D(uint32_t& dim1, uint32_t& dim2); + + /*! + * \brief Extracts the current value from the register input buffer. + * \return the buffer content in a uint64_t format + */ + uint64_t getValUInt64(); + + /*! + * \brief Extracts the vector of values from the register input buffer. + * \param pVal a uint64_t* pointer to a memory location where the method will store a copy of the array + * \param dim vector length in unsigned long format + */ + void getValUInt64Array(uint64_t* pVal, uint32_t dim); + + /*! + * \brief Extracts the 2D-array of values from the register input buffer. + * \param pVal a uint64_t* pointer to a memory location where the method will store a copy of the flat 2D-array + * \param dim1 first dimension of flat 2D-array in unsigned long format + * \param dim2 second dimension of flat 2D-array in unsigned long format + */ + void getValUInt64Array2D(uint64_t* pVal, uint32_t dim1, uint32_t dim2); + + //specific method with automatic conversion (JAVA does not support unsigned type) + //void getValUInt64Array(int128_t* pVal, uint32_t dim); not supported (128bits)! + /*! + * \brief Return a reference to register input buffer. + * The usage of this method can sped up reading and writing operation when the buffer is very big and a small part of + * information is requested. This method give direct access on the buffer and his adoption is not recommended. + * \param dim Reference where to store the vector dimension in format unsigned long + * \return a uint64_t* reference directly to the memory location where the array begins in the buffer + */ + const uint64_t* getRefUInt64Array(uint32_t& dim); + + /*! + * \brief Return a reference to register input buffer. + * The usage of this method can speed up reading and writing operations when the buffer is very big and a small part of + * information is requested. This method gives direct access on the buffer and his adoption is not recommended. + * \param dim1 Reference where to store the first dimension of flat 2D-array in unsigned long format + * \param dim2 Reference where to store the second dimension of flat 2D-array in unsigned long format + * \return a uint64_t* reference directly to the memory location where the flat 2D-array begins in the buffer + */ + uint64_t* getRefUInt64Array2D(uint32_t& dim1, uint32_t& dim2); + + /*! + * \brief Extracts the current value from the register input buffer. + * \return the buffer content in a float format + */ + float getValFloat32(); + + /*! + * \brief Extracts the vector of values from the register input buffer. + * \param pVal a float* pointer to a memory location where the method will store a copy of the array + * \param dim vector length in unsigned long format + */ + void getValFloat32Array(float* pVal, uint32_t dim); + + /*! + * \brief Extracts the 2D-array of values from the register input buffer. + * \param pVal a float* pointer to a memory location where the method will store a copy of the flat 2D-array + * \param dim1 first dimension of flat 2D-array in unsigned long format + * \param dim2 second dimension of flat 2D-array in unsigned long format + */ + void getValFloat32Array2D(float* pVal, uint32_t dim1, uint32_t dim2); + + /*! + * \brief Return a reference to register input buffer. + * The usage of this method can sped up reading and writing operation when the buffer is very big and a small part of + * information is requested. This method give direct access on the buffer and his adoption is not recommended. + * \param dim Reference where to store the vector dimension in format unsigned long + * \return a float* reference directly to the memory location where the array begins in the buffer + */ + const float* getRefFloat32Array(uint32_t& dim); + + /*! + * \brief Return a reference to register input buffer. + * The usage of this method can speed up reading and writing operations when the buffer is very big and a small part of + * information is requested. This method gives direct access on the buffer and his adoption is not recommended. + * \param dim1 Reference where to store the first dimension of flat 2D-array in unsigned long format + * \param dim2 Reference where to store the second dimension of flat 2D-array in unsigned long format + * \return a float* reference directly to the memory location where the flat 2D-array begins in the buffer + */ + float* getRefFloat32Array2D(uint32_t& dim1, uint32_t& dim2); + + /*! + * \brief Extracts the current value from the register input buffer. + * \return the buffer content in a double format + */ + double getValFloat64(); + + /*! + * \brief Extracts the vector of values from the register input buffer. + * \param pVal a double* pointer to a memory location where the method will store a copy of the array + * \param dim vector length in unsigned long format + */ + void getValFloat64Array(double* pVal, uint32_t dim); + + /*! + * \brief Extracts the 2D-array of values from the register input buffer. + * \param pVal a double* pointer to a memory location where the method will store a copy of the flat 2D-array + * \param dim1 first dimension of flat 2D-array in unsigned long format + * \param dim2 second dimension of flat 2D-array in unsigned long format + */ + void getValFloat64Array2D(double* pVal, uint32_t dim1, uint32_t dim2); + + /*! + * \brief Return a reference to register input buffer. + * The usage of this method can speed up reading and writing operations when the buffer is very big and a small part of + * information is requested. This method give direct access on the buffer and his adoption is not recommended. + * \param dim Reference where to store the vector dimension in unsigned long format + * \return a double* reference directly to the memory location where the array begins in the buffer + */ + const double* getRefFloat64Array(uint32_t& dim); + + /*! + * \brief Return a reference to register input buffer. + * The usage of this method can speed up reading and writing operations when the buffer is very big and a small part of + * information is requested. This method gives direct access on the buffer and his adoption is not recommended. + * \param dim1 Reference where to store the first dimension of flat 2D-array in unsigned long format + * \param dim2 Reference where to store the second dimension of flat 2D-array in unsigned long format + * \return a double* reference directly to the memory location where the flat 2D-array begins in the buffer + */ + double* getRefFloat64Array2D(uint32_t& dim1, uint32_t& dim2); + + /*! + * \brief Extracts the current value from the register input buffer. (receive must be done ahead) + * \return the buffer content in a string format + */ + std::string getValString(); + + /*! + * \brief Extracts the vector of values from the register input buffer. + * \param pVal a std::string* pointer to a memory location where the method will store a copy of the string + * \param dim vector length in unsigned long format + */ + void getValStringArray(std::string* pVal, uint32_t dim); + + /*! + * \brief Extracts the string array from the register input buffer. + * \param pVal a std::string* pointer to a memory location where the method will store a copy of the 2D (flat) array + * \param dim1 first dimension of flat 2D-array in unsigned long format + * \param dim2 second dimension of flat 2D-array in unsigned long format + */ + void getValStringArray2D(std::string* pVal, uint32_t dim1, uint32_t dim2); + + /*! + * \brief Return a reference to register input buffer. + * The usage of this method can speed up reading and writing operations when the buffer us very big and a small part of + * information is requested. This methos give direct access on the buffer and his adoption is not recommended. + * \param dim Location where to store the vector dimension in unsigned long format + * \return a str::string** reference directly to the memory location where the array of pointers begins in the buffer + */ + const std::string** getRefStringArray(uint32_t& dim); + + /*! + * \brief Return a reference to register input buffer. + * The usage of this method can speed up reading and writing operations when the buffer is very big and a small part of + * information is requested. This method gives direct access on the buffer and his adoption is not recommended. + * \param dim1 Location where to store the first dimension of flat 2D-array in unsigned long format + * \param dim2 Location where to store the second dimension of flat 2D-array in unsigned long format + * \return a str::string** reference directly to the memory location where the flat 2D-array of pointers begins in the buffer + */ + const std::string** getRefStringArray2D(uint32_t& dim1, uint32_t& dim2); + + /*! + * \brief Converts the double Date type to tm broken-down time structure + * conforming to POSIX convention (look at localtime() manpages) + * \return tm broken-down time structure + */ + static struct tm getTMDate(double date); + static time_t getEpochDate(double date); + + // SET methods ======================================================== + + // ......................................................................... + //Deprecated: initially for SLC5 (32bits platform) + /*! + * \brief Set the value for the register output buffer. (Send must be done afterwards) + * \param val Value to be written in the buffer in a char format + * \deprecated This method is supported for backward compatibility (version <= 3.2.*). Suggested usage of setValInt8 instead. + */ + void setValChar(char val); + + /*! + * \brief Set the value for the array register output buffer. (Send must be done afterwards) + * \param pVal A char* pointer to a memory location from where the method will get the array values + * \param dim Vector length in unsigned long format + * \deprecated This method is supported for backward compatibility (version <= 3.2.*). Suggested usage of setValInt8Array instead. + */ + void setValCharArray(const char* pVal, uint32_t dim); + + /*! + * \brief Set the value for the 2D-array register output buffer. (Send must be done afterwards) + * \param pVal A char* pointer to a memory location from where the method will get the flat 2D-array values + * \param dim1 First dimension of flat 2D-array in unsigned long format + * \param dim2 Second dimension of flat 2D-array in unsigned long format + * \deprecated This method is supported for backward compatibility (version <= 3.2.*). Suggested usage of setValInt8Array2D instead. + */ + void setValCharArray2D(const char* pVal, uint32_t dim1, uint32_t dim2); + + /*! + * \brief Set the value for the register output buffer.(Send must be done afterwards) + * \param val Value to be written in the buffer in a unsigned char format + * \deprecated This method is supported for backward compatibility (version <= 3.2.*). Suggested usage of setValUInt8 instead. + */ + void setValUChar(unsigned char val); + + /*! + * \brief Set the value for the array register output buffer.(Send must be done afterwards) + * \param pVal A unsigned char* pointer to a memory location from where the method will get the array values + * \param dim Vector length in unsigned long format + * \deprecated This method is supported for backward compatibility (version <= 3.2.*). Suggested usage of setValUInt8Array instead. + */ + void setValUCharArray(const unsigned char* pVal, uint32_t dim); + + /*! + * \brief Set the value for the 2D-array register output buffer. (Send must be done afterwards) + * \param pVal A unsigned char* pointer to a memory location from where the method will get the flat 2D-array values + * \param dim1 First dimension of flat 2D-array in unsigned long format + * \param dim2 Second dimension of flat 2D-array in unsigned long format + * \deprecated This method is supported for backward compatibility (version <= 3.2.*). Suggested usage of setValUInt8Array2D instead. + */ + void setValUCharArray2D(const unsigned char* pVal, uint32_t dim1, uint32_t dim2); + + //specific method with automatic conversion (JAVA does not support unsigned type) + void setValUCharArray(const short* pVal, uint32_t dim); + void setValUCharArray2D(const short* pVal, uint32_t dim1, uint32_t dim2); + + /*! + * \brief Set the value for the register output buffer.(Send must be done afterwards) + * \param val Value to be written in the buffer in a short format + * \deprecated This method is supported for backward compatibility (version <= 3.2.*). Suggested usage of setValInt16 instead. + */ + void setValShort(short val); + + /*! + * \brief Set the value for the array register output buffer.(Send must be done afterwards) + * \param pVal A short* pointer to a memory location from where the method will get the array values + * \param dim Vector length in unsigned long format + * \deprecated This method is supported for backward compatibility (version <= 3.2.*). Suggested usage of setValInt16Array instead. + */ + void setValShortArray(const short* pVal, uint32_t dim); + + /*! + * \brief Set the value for the 2D-array register output buffer. (Send must be done afterwards) + * \param pVal A short* pointer to a memory location from where the method will get the flat 2D-array values + * \param dim1 First dimension of flat 2D-array in unsigned long format + * \param dim2 Second dimension of flat 2D-array in unsigned long format + * \deprecated This method is supported for backward compatibility (version <= 3.2.*). Suggested usage of setValInt16Array2D instead. + */ + void setValShortArray2D(const short* pVal, uint32_t dim1, uint32_t dim2); + + /*! + * \brief Set the value for the register output buffer.(Send must be done afterwards) + * \param val Value to be written in the buffer in a unsigned short format + * \deprecated This method is supported for backward compatibility (version <= 3.2.*). Suggested usage of setValUInt16 instead. + */ + void setValUShort(unsigned short val); + + /*! + * \brief Set the value for the array register output buffer.(Send must be done afterwards) + * \param pVal A unsigned short* pointer to a memory location from where the method will get the array values + * \param dim Vector length in unsigned long format + * \deprecated This method is supported for backward compatibility (version <= 3.2.*). Suggested usage of setValUInt16Array instead. + */ + void setValUShortArray(const unsigned short* pVal, uint32_t dim); + + /*! + * \brief Set the value for the 2D-array register output buffer. (Send must be done afterwards) + * \param pVal A unsigned short* pointer to a memory location from where the method will get the flat 2D-array values + * \param dim1 First dimension of flat 2D-array in unsigned long format + * \param dim2 Second dimension of flat 2D-array in unsigned long format + * \deprecated This method is supported for backward compatibility (version <= 3.2.*). Suggested usage of setValUInt16Array2D instead. + */ + void setValUShortArray2D(const unsigned short* pVal, uint32_t dim1, uint32_t dim2); + + //specific method with automatic conversion (JAVA does not support unsigned type) + void setValUShortArray(const long* pVal, uint32_t dim); + void setValUShortArray2D(const long* pVal, uint32_t dim1, uint32_t dim2); + + #ifndef __x86_64__ //long type is platform dependant (32bits or 64bits integer) + //SLC5: support for 'long' type as 32bits + /*! + * \brief Set the value for the register output buffer.(Send must be done afterwards) + * \param val Value to be written in the buffer in a long format + * \deprecated This method is supported for backward compatibility (version <= 3.2.*). Suggested usage of setValInt32 instead. + */ + void setValLong(long val); + + /*! + * \brief Set the value for the array register output buffer.(Send must be done afterwards) + * \param pVal A long* pointer to a memory location from where the method will get the array values + * \param dim Vector length in unsigned long format + * \deprecated This method is supported for backward compatibility (version <= 3.2.*). Suggested usage of setValInt32Array instead. + */ + void setValLongArray(const long* pVal, uint32_t dim); + + /*! + * \brief Set the value for the 2D-array register output buffer. (Send must be done afterwards) + * \param pVal A long* pointer to a memory location from where the method will get the flat 2D-array values + * \param dim1 First dimension of flat 2D-array in unsigned long format + * \param dim2 Second dimension of flat 2D-array in unsigned long format + * \deprecated This method is supported for backward compatibility (version <= 3.2.*). Suggested usage of setValInt32Array2D instead. + */ + void setValLongArray2D(const long* pVal, uint32_t dim1, uint32_t dim2); + + /*! + * \brief Set the value for the register output buffer.(Send must be done afterwards) + * \param val Value to be written in the buffer in a unsigned long format + * \deprecated This method is supported for backward compatibility (version <= 3.2.*). Suggested usage of setValUInt32 instead. + */ + void setValULong(unsigned long val); + + /*! + * \brief Set the value for the array register output buffer.(Send must be done afterwards) + * \param pVal A unsigned long* pointer to a memory location from where the method will get the array values + * \param dim Vector length in unsigned long format + * \deprecated This method is supported for backward compatibility (version <= 3.2.*). Suggested usage of setValUInt32Array instead. + */ + void setValULongArray(const unsigned long* pVal, uint32_t dim); + + /*! + * \brief Set the value for the 2D-array register output buffer. (Send must be done afterwards) + * \param pVal A unsigned long* pointer to a memory location from where the method will get the flat 2D-array values + * \param dim1 First dimension of flat 2D-array in unsigned long format + * \param dim2 Second dimension of flat 2D-array in unsigned long format + * \deprecated This method is supported for backward compatibility (version <= 3.2.*). Suggested usage of setValUInt32Array2D instead. + */ + void setValULongArray2D(const unsigned long* pVal, uint32_t dim1, uint32_t dim2); + + //specific method with automatic conversion (JAVA does not support unsigned type) + void setValULongArray(const long long* pVal, uint32_t dim); + void setValULongArray2D(const long long* pVal, uint32_t dim1, uint32_t dim2); + + #else + //from SLC6: 'long' methods still used as 32bits but with explicit typing instead + //It's recommended to use new appropriate methods instead: Int32/UInt32 + #define setValLong setValInt32 + #define setValLongArray setValInt32Array + #define setValULong setValUInt32 + #define setValULongArray setValUInt32Array + #endif + + /*! + * \brief Set the value for the register output buffer.(Send must be done afterwards) + * \param val Value to be written in the buffer in a float format + * \deprecated This method is supported for backward compatibility (version <= 3.2.*). Suggested usage of setValFloat32 instead. + */ + void setValFloat(float val); + + /*! + * \brief Set the value for the array register output buffer.(Send must be done afterwards) + * \param pVal A float* pointer to a memory location from where the method will get the array values + * \param dim Vector length in unsigned long format + * \deprecated This method is supported for backward compatibility (version <= 3.2.*). Suggested usage of setValFloat32Array instead. + */ + void setValFloatArray(const float* pVal, uint32_t dim); + + /*! + * \brief Set the value for the 2D-array register output buffer. (Send must be done afterwards) + * \param pVal A float* pointer to a memory location from where the method will get the flat 2D-array values + * \param dim1 First dimension of flat 2D-array in unsigned long format + * \param dim2 Second dimension of flat 2D-array in unsigned long format + * \deprecated This method is supported for backward compatibility (version <= 3.2.*). Suggested usage of setValFloat32Array2D instead. + */ + void setValFloatArray2D(const float* pVal, uint32_t dim1, uint32_t dim2); + + //Set date is not required for the time being + void setValDate(double val); + void setValDateArray(const double* pVal, uint32_t dim); + void setValDateArray2D(const double* pVal, uint32_t dim1, uint32_t dim2); + + + // ......................................................................... + //Recommended: from SLC6 (32bits and 64bits platform) + /*! + * \brief Set the value for the register output buffer.(Send must be done afterwards) + * \param val Value to be written in the buffer in a int8_t format + */ + void setValInt8(int8_t val); + + /*! + * \brief Set the value for the array register output buffer.(Send must be done afterwards) + * \param pVal A int8_t* pointer to a memory location from where the method will get the array values + * \param dim Vector length in unsigned long format + */ + void setValInt8Array(const int8_t* pVal, uint32_t dim); + + /*! + * \brief Set the value for the 2D-array register output buffer. (Send must be done afterwards) + * \param pVal A int8_t* pointer to a memory location from where the method will get the flat 2D-array values + * \param dim1 First dimension of flat 2D-array in unsigned long format + * \param dim2 Second dimension of flat 2D-array in unsigned long format + */ + void setValInt8Array2D(const int8_t* pVal, uint32_t dim1, uint32_t dim2); + + /*! + * \brief Set the value for the register output buffer.(Send must be done afterwards) + * \param val Value to be written in the buffer in a uint8_t format + */ + void setValUInt8(uint8_t val); + /*! + * \brief Set the value for the array register output buffer.(Send must be done afterwards) + * \param pVal A uint8_t* pointer to a memory location from where the method will get the array values + * \param dim Vector length in unsigned long format + */ + void setValUInt8Array(const uint8_t* pVal, uint32_t dim); + + /*! + * \brief Set the value for the 2D-array register output buffer. (Send must be done afterwards) + * \param pVal A uint8_t* pointer to a memory location from where the method will get the flat 2D-array values + * \param dim1 First dimension of flat 2D-array in unsigned long format + * \param dim2 Second dimension of flat 2D-array in unsigned long format + */ + void setValUInt8Array2D(const uint8_t* pVal, uint32_t dim1, uint32_t dim2); + + //specific method with automatic conversion (JAVA does not support unsigned type) + void setValUInt8Array(const int16_t* pVal, uint32_t dim); + void setValUInt8Array2D(const int16_t* pVal, uint32_t dim1, uint32_t dim2); + + /*! + * \brief Set the value for the register output buffer.(Send must be done afterwards) + * \param val Value to be written in the buffer in a int16_t format + */ + void setValInt16(int16_t val); + + /*! + * \brief Set the value for the array register output buffer.(Send must be done afterwards) + * \param pVal A int16_t* pointer to a memory location from where the method will get the array values + * \param dim Vector length in unsigned long format + */ + void setValInt16Array(const int16_t* pVal, uint32_t dim); + + /*! + * \brief Set the value for the 2D-array register output buffer. (Send must be done afterwards) + * \param pVal A int16_t* pointer to a memory location from where the method will get the flat 2D-array values + * \param dim1 First dimension of flat 2D-array in unsigned long format + * \param dim2 Second dimension of flat 2D-array in unsigned long format + */ + void setValInt16Array2D(const int16_t* pVal, uint32_t dim1, uint32_t dim2); + + /*! + * \brief Set the value for the register output buffer.(Send must be done afterwards) + * \param val Value to be written in the buffer in a uint16_t format + */ + void setValUInt16(uint16_t val); + + /*! + * \brief Set the value for the array register output buffer.(Send must be done afterwards) + * \param pVal A uint16_t* pointer to a memory location from where the method will get the array values + * \param dim Vector length in unsigned long format + */ + void setValUInt16Array(const uint16_t* pVal, uint32_t dim); + + /*! + * \brief Set the value for the 2D-array register output buffer. (Send must be done afterwards) + * \param pVal A uint16_t* pointer to a memory location from where the method will get the flat 2D-array values + * \param dim1 First dimension of flat 2D-array in unsigned long format + * \param dim2 Second dimension of flat 2D-array in unsigned long format + */ + void setValUInt16Array2D(const uint16_t* pVal, uint32_t dim1, uint32_t dim2); + + //specific method with automatic conversion (JAVA does not support unsigned type) + void setValUInt16Array(const int32_t* pVal, uint32_t dim); + void setValUInt16Array2D(const int32_t* pVal, uint32_t dim1, uint32_t dim2); + + /*! + * \brief Set the value for the register output buffer.(Send must be done afterwards) + * \param val Value to be written in the buffer in a int32_t format + */ + void setValInt32(int32_t val); + + /*! + * \brief Set the value for the array register output buffer. (Send must be done afterwards) + * \param pVal A int32_t* pointer to a memory location from where the method will get the array values + * \param dim Vector length in unsigned long format + */ + void setValInt32Array(const int32_t* pVal, uint32_t dim); + + /*! + * \brief Set the value for the 2D-array register output buffer. (Send must be done afterwards) + * \param pVal A int32_t* pointer to a memory location from where the method will get the flat 2D-array values + * \param dim1 First dimension of flat 2D-array in unsigned long format + * \param dim2 Second dimension of flat 2D-array in unsigned long format + */ + void setValInt32Array2D(const int32_t* pVal, uint32_t dim1, uint32_t dim2); + + /*! + * \brief Set the value for the register output buffer. (Send must be done afterwards) + * \param val Value to be written in the buffer in a uint32_t format + */ + void setValUInt32(uint32_t val); + + /*! + * \brief Set the value for the array register output buffer.(Send must be done afterwards) + * \param pVal A uint32_t* pointer to a memory location from where the method will get the array values + * \param dim Vector length in unsigned long format + */ + void setValUInt32Array(const uint32_t* pVal, uint32_t dim); + + /*! + * \brief Set the value for the 2D-array register output buffer. (Send must be done afterwards) + * \param pVal A uint32_t* pointer to a memory location from where the method will get the flat 2D-array values + * \param dim1 First dimension of flat 2D-array in unsigned long format + * \param dim2 Second dimension of flat 2D-array in unsigned long format + */ + void setValUInt32Array2D(const uint32_t* pVal, uint32_t dim1, uint32_t dim2); + + //specific method with automatic conversion (JAVA does not support unsigned type) + void setValUInt32Array(const int64_t* pVal, uint32_t dim); + void setValUInt32Array2D(const int64_t* pVal, uint32_t dim1, uint32_t dim2); + + /*! + * \brief Set the value for the register output buffer.(Send must be done afterwards) + * \param val Value to be written in the buffer in a int64_t format + */ + void setValInt64(int64_t val); + + /*! + * \brief Set the value for the array register output buffer.(Send must be done afterwards) + * \param pVal A int64_t* pointer to a memory location from where the method will get the array values + * \param dim Vector length in unsigned long format + */ + void setValInt64Array(const int64_t* pVal, uint32_t dim); + + /*! + * \brief Set the value for the 2D-array register output buffer. (Send must be done afterwards) + * \param pVal A int64_t* pointer to a memory location from where the method will get the flat 2D-array values + * \param dim1 First dimension of flat 2D-array in unsigned long format + * \param dim2 Second dimension of flat 2D-array in unsigned long format + */ + void setValInt64Array2D(const int64_t* pVal, uint32_t dim1, uint32_t dim2); + + /*! + * \brief Set the value for the register output buffer.(Send must be done afterwards) + * \param val Value to be written in the buffer in a uint64_t format + */ + void setValUInt64(uint64_t val); + + /*! + * \brief Set the value for the array register output buffer.(Send must be done afterwards) + * \param pVal A uint64_t* pointer to a memory location from where the method will get the array values + * \param dim Vector length in unsigned long format + */ + void setValUInt64Array(const uint64_t* pVal, uint32_t dim); + + /*! + * \brief Set the value for the 2D-array register output buffer. (Send must be done afterwards) + * \param pVal A uint64_t* pointer to a memory location from where the method will get the flat 2D-array values + * \param dim1 First dimension of flat 2D-array in unsigned long format + * \param dim2 Second dimension of flat 2D-array in unsigned long format + */ + void setValUInt64Array2D(const uint64_t* pVal, uint32_t dim1, uint32_t dim2); + + //specific method with automatic conversion (JAVA does not support unsigned type) + //void setValUInt64Array(const int128_t* pVal, uint32_t dim); not supported (128bits)! + + /*! + * \brief Set the value for the register output buffer.(Send must be done afterwards) + * \param val Value to be written in the buffer in a float format + */ + void setValFloat32(float val); + + /*! + * \brief Set the value for the array register output buffer.(Send must be done afterwards) + * \param pVal A float* pointer to a memory location from where the method will get the array values + * \param dim Vector length in unsigned long format + */ + void setValFloat32Array(const float* pVal, uint32_t dim); + + /*! + * \brief Set the value for the 2D-array register output buffer. (Send must be done afterwards) + * \param pVal A float* pointer to a memory location from where the method will get the flat 2D-array values + * \param dim1 First dimension of flat 2D-array in unsigned long format + * \param dim2 Second dimension of flat 2D-array in unsigned long format + */ + void setValFloat32Array2D(const float* pVal, uint32_t dim1, uint32_t dim2); + + /*! + * \brief Set the value for the register output buffer.(Send must be done afterwards) + * \param val Value to be written in the buffer in a double format + */ + void setValFloat64(double val); + + /*! + * \brief Set the value for the array register output buffer.(Send must be done afterwards) + * \param pVal A double* pointer to a memory location from where the method will get the array values + * \param dim Vector length in unsigned long format + */ + void setValFloat64Array(const double* pVal, uint32_t dim); + + /*! + * \brief Set the value for the 2D-array register output buffer. (Send must be done afterwards) + * \param pVal A double* pointer to a memory location from where the method will get the flat 2D-array values + * \param dim1 First dimension of flat 2D-array in unsigned long format + * \param dim2 Second dimension of flat 2D-array in unsigned long format + */ + void setValFloat64Array2D(const double* pVal, uint32_t dim1, uint32_t dim2); + + /*! + * \brief Set the value for the register output buffer. (Send must be done afterwards) + * \param val string to be written in the buffer + */ + void setValString(std::string val); + + /*! + * \brief Set the value for the array register output buffer. (Send must be done afterwards) + * \param pVal A std::string* pointer to a memory location from where the method will get the array + * \param dim Vector length in unsigned long format + */ + void setValStringArray(const std::string* pVal, uint32_t dim); + + /*! + * \brief Set the value for the 2D-array register output buffer. (Send must be done afterwards) + * \param pVal A std::string* pointer to a memory location from where the method will get the flat 2D-array + * \param dim1 First dimension of flat 2D-array in unsigned long format + * \param dim2 Second dimension of flat 2D-array in unsigned long format + */ + void setValStringArray2D(const std::string* pVal, uint32_t dim1, uint32_t dim2); + + // ......................................................................... + /*! + * \brief Returns the format of the register data as string value + * \return Format-type of the register (Enumeration: "char", "uChar", "short", "uShort", ..) + */ + std::string getFormatAsString(); + + /*! + * \brief Returns the register time-stamping as readable value + * \return number of seconds since the Epoch (floating point value) + */ + std::string getTimeStampAsString(); + + /*! + * \brief Interprets the input register value and return the corresponding string. + * In case of array or 2D-array, it return string value of the appropriate element. + * Generates an Exception if register is write-only or if index(es) exceed the array dimension(s) + * \param i,j indexes of the element in the (2D)array if any (optional) + * \return input register value or element as string + */ + std::string getInputValAsString(); //for scalar + std::string getInputValAsString(unsigned long i); //for single array + std::string getInputValAsString(unsigned long i, unsigned long j); //for 2D array (flat) + + /*! + * \brief Interprets the output register value and return the corresponding string. + * In case of array or 2D-array, it return string value of the appropriate element. + * Generates an Exception if register is read-only or if index(es) exceed the array dimension(s) + * \param i,j indexes of the element in the (2D)array if any (optional) + * \return input register value or element as string + */ + std::string getOutputValAsString(); //for scalar + std::string getOutputValAsString(unsigned long i); //for single array + std::string getOutputValAsString(unsigned long i, unsigned long j); //for 2D array (flat) + + /*! + * \brief Returns the Input register value as sequence of 8-bit words + * \param asAsciiChar = true to dump the buffer as Ascii characters (default is Hexadecimal dump) + * \return string blank-separated value + */ + std::string dumpInputVal(bool asAsciiChar = false); + + /*! + * \brief Returns the Output register value as sequence of 8-bit word + * \param asAsciiChar = true to dump the buffer as Ascii characters (default is Hexadecimal dump) + * \return string blank-separated value + */ + std::string dumpOutputVal(bool asAsciiChar = false); + + /*! + * \brief Display all the register information to the standard output for debugging purpose: + * name, format, dimension, synchro and input/output value(s). + */ + void printVal(); + + /// @cond + /*! + * \fn whichFormatType + * \return Enumeration value of the given format-type string + */ + FormatType whichFormatType(std::string type); + + bool isInitialized(); + /// @endcond + + /// @cond + protected: + Register(Device* theDevice,const boost::shared_ptr<ElementXML>& registerNode); + virtual ~Register(); + + // export register extraction methods + friend class PLC; + friend class Device; + + /*! + * \brief Set access type. + * \param accessType Input, Ouput or InOut + */ + void setAccessType(AccessType accessType); + + inline void setBlockName(const std::string blockName) { blockName_ = blockName; } + + /*! + * \fn getValAsString + * \return return a copy of the corresponding string from the buffer (scalar, array or 2D-array) + */ + std::string getValAsString(void* pValue, unsigned long i, unsigned long j); + + /*! + * \fn getValAsByteString + * \brief Debug purpose: return the register value as array of bytes + * \param maxSize is the used to limit the string size in case of huge data array. + * \return interprets the register value and return the corresponding string + */ + std::string getValAsByteString(void* pValue, unsigned long maxSize); + + inline unsigned long getAddress() { return address_; } + + /*! + * \brief Import values from the received buffer to the register. Pure virtual to be implemented by the inheriting classes. + * \param pBuffer received data buffer + * \param ts register time-stamp + */ + virtual void importValue(void* pBuffer, timeval ts) = 0 ; + + /*! + * \brief Export the value from the register to the correct position in the buffer. Pure virtual to be implemented by the inheriting classes. + * \param pBuffer the output buffer where to update the data + */ + virtual void exportValue(void* pBuffer) = 0 ; + + /*! + * \brief Import values from the received buffer to the register. Pure vistual to be implemented by the inheriting classes. + * \param pBuffer received data buffer + * \param ts register time-stamp + */ + virtual void importString(void* pBuffer, timeval ts) = 0; + + /*! + * \brief Export the string from the register to the correct position in the buffer. Pure virtual to be implemented by inheriting classes. + * \param pBuffer the output buffer where to update the data + */ + virtual void exportString(void* pBuffer) = 0; + + /*! + * \brief Copies the register content from the input buffer to the output buffer. Pure virtual to be implemented by the inheriting classes. + */ + virtual void copyValue() = 0 ; + + /// Parent reference of that register + Device* theDevice_; + + /// Register name + std::string name_; + + /// Register access-type: Input, Ouput or InOut (following its related block) + AccessType accessType_; + + /// Enum format: char, uchar, short, ushort, long, ulong, float, double + FormatType format_; + + /// Data first dimension (>1 for single array) + uint32_t dimension1_; + + /// Data second dimension (>1 for double array) + uint32_t dimension2_; + + // String length + unsigned long length_; + + /// Data size (relies on format) + unsigned long size_; + + /// Data memory size (relies on format, including alignments) + unsigned long memSize_; + + /// data address within the PLC memory (from the block base-address) + unsigned long address_; + + /// Synchronization mode: Master, Slave, No + SynchroType synchro_; + + /// Flag used to check if the register has been setted once at least. + /// Uploading Slave registers at connection time is allowed only if all + /// the retentive Slave registers are initialized! + bool isInitialized_; + + /// Buffer to store the value of the register + /// 2 different buffers are used in case of InOut access. + void* pRecvValue_; + void* pSendValue_; + + /// Name of the "parent" Block name (for general information) + std::string blockName_; + + // Time-of-day: number of seconds and microseconds since the POSIX.1 Epoch (00:00:00 UTC, January 1, 1970) + // Use to time-stamp the register coming from PLC (no time-stamping on send). + // FEC clock and Timing are synchronized using SNTP (common GPS source) + timeval tod_; + + PLC* getPLC(); + /// @endcond + + //private: + //template <typename T> inline T getVal(FormatType F, unsigned char* pValue); + template <typename T> T getVal(FormatType F); + template <typename T> void getValArray(FormatType F, T* pValue, uint32_t dim); + template <typename T> void getValArray2D(FormatType F, T* pValue, uint32_t dim1, uint32_t dim2); + template <typename Tsrc, typename Tdst> void convGetValArray(FormatType F, Tdst* pValue, uint32_t dim); + template <typename Tsrc, typename Tdst> void convGetValArray2D(FormatType F, Tdst* pValue, uint32_t dim1, uint32_t dim2); + template <typename T> T* getRefArray(FormatType F, uint32_t& dim); + template <typename T> T* getRefArray2D(FormatType F, uint32_t& dim1, uint32_t& dim2); + + template <typename T> void setVal(FormatType F, T val); + template <typename T> void setValArray(FormatType F, const T* pVal, uint32_t dim); + template <typename T> void setValArray2D(FormatType F, const T* pVal, uint32_t dim1, uint32_t dim2); + template <typename Tsrc, typename Tdst> void convSetValArray(FormatType F, const Tsrc* pVal, uint32_t dim); + template <typename Tsrc, typename Tdst> void convSetValArray2D(FormatType F, const Tsrc* pVal, uint32_t dim1, uint32_t dim2); + }; + +} // namespace + +#endif // _SILECS_REGISTER_H_ diff --git a/silecs-communication-cpp/src/silecs-communication/interface/utility/Condition.cpp b/silecs-communication-cpp/src/silecs-communication/interface/utility/Condition.cpp new file mode 100644 index 0000000..ec1caa8 --- /dev/null +++ b/silecs-communication-cpp/src/silecs-communication/interface/utility/Condition.cpp @@ -0,0 +1,81 @@ +// Copyright 2016 CERN and GSI +// +// 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 3 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, see <http://www.gnu.org/licenses/>. + +#include <silecs-communication/interface/utility/SilecsLog.h> +#include <string.h> +#include <silecs-communication/interface/utility/Condition.h> + +namespace Silecs +{ + + Condition::Condition(std::string name) + { + int err; + + // Condition name if any, used for logging in particular + name_ = name; + + //create the related mutex using the same name + pMutex_ = new Mutex(name_); + + if ((err = pthread_cond_init(&condVar_, NULL)) != 0) + throw SilecsException(__FILE__, __LINE__, errno, strerror(errno)); + } + + Condition::~Condition() + { + int err; + if ((err = pthread_cond_destroy(&condVar_)) != 0) + { //can be broken by SIGKILL (just leave with no Exception) + //throw SilecsException(__FILE__, __LINE__, errno, strerror(errno)); + } + delete pMutex_; + } + + void Condition::lock() + { + pMutex_->lock(); + } + + void Condition::unlock() + { + pMutex_->unlock(); + } + + void Condition::signal() + { + int err; + if ((err = pthread_cond_signal(&condVar_)) != 0) + throw SilecsException(__FILE__, __LINE__, errno, strerror(errno)); + LOG(LOCK) << "Has signaled condition: " << this->name_; + } + + void Condition::broadcast() + { + int err; + if ((err = pthread_cond_broadcast(&condVar_)) != 0) + throw SilecsException(__FILE__, __LINE__, errno, strerror(errno)); + } + + void Condition::wait() + { + int err; + LOG(LOCK) << "Waiting for condition: " << this->name_; + if ((err = pthread_cond_wait(&condVar_, pMutex_->pMutex_)) != 0) + throw SilecsException(__FILE__, __LINE__, errno, strerror(errno)); + LOG(LOCK) << "Has get condition: " << this->name_; + } + +}// end namespace diff --git a/silecs-communication-cpp/src/silecs-communication/interface/utility/Condition.h b/silecs-communication-cpp/src/silecs-communication/interface/utility/Condition.h new file mode 100644 index 0000000..38e41a2 --- /dev/null +++ b/silecs-communication-cpp/src/silecs-communication/interface/utility/Condition.h @@ -0,0 +1,54 @@ +// Copyright 2016 CERN and GSI +// +// 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 3 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, see <http://www.gnu.org/licenses/>. + +#ifndef _CONDITION_H_ +#define _CONDITION_H_ + +#include <pthread.h> +#include <errno.h> + +#include <silecs-communication/interface/utility/Mutex.h> + +namespace Silecs { + + /*! + * \class Condition + * \brief This class implement the basic methods to manage the thread synchronization + * with Conditional Variable. In particular, it manages the related mutex. + */ + class Condition + { + public: + Condition(std::string name = "undefined"); + virtual ~Condition(); + + void lock(); + void unlock(); + + void signal(); + void broadcast(); + void wait(); + + private: + // Condition name if any, used for logging in particular + std::string name_; + + pthread_cond_t condVar_; + Mutex* pMutex_; + }; + +} // namespace + +#endif /* _CONDITION_H_ */ diff --git a/silecs-communication-cpp/src/silecs-communication/interface/utility/Mutex.cpp b/silecs-communication-cpp/src/silecs-communication/interface/utility/Mutex.cpp new file mode 100644 index 0000000..9573a22 --- /dev/null +++ b/silecs-communication-cpp/src/silecs-communication/interface/utility/Mutex.cpp @@ -0,0 +1,92 @@ +// Copyright 2016 CERN and GSI +// +// 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 3 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, see <http://www.gnu.org/licenses/>. + +#include <silecs-communication/interface/utility/Mutex.h> +#include <silecs-communication/interface/utility/SilecsLog.h> +#include <string.h> + +namespace Silecs +{ + + Mutex::Mutex(std::string name) + { + int err; + + // Mutex name if any, used for logging in particular + name_ = name; + + if (DEBUG & Log::topics_) LOG(ALLOC) << "Mutex (create): " << name_; + + //create the pthread-mutex using the default parameters + recursive option + pMutex_ = new pthread_mutex_t(); + + if ((err = pthread_mutexattr_init(&attr_)) != 0) + throw SilecsException(__FILE__, __LINE__, errno, strerror(errno)); + + //Mutex supports re-entrance for re-open mechanism inside send/recv action (doOpen() method call) + if ((err = pthread_mutexattr_settype(&attr_, PTHREAD_MUTEX_RECURSIVE)) !=0) + throw SilecsException(__FILE__, __LINE__, errno, strerror(errno)); + + if ((err = pthread_mutex_init(pMutex_, &attr_)) != 0) + throw SilecsException(__FILE__, __LINE__, errno, strerror(errno)); + } + + Mutex::~Mutex() + { + int err; + + if (DEBUG & Log::topics_) LOG(ALLOC) << "Mutex (delete): " << name_; + + if ((err = pthread_mutexattr_destroy(&attr_)) != 0) + throw SilecsException(__FILE__, __LINE__, errno, strerror(errno)); + + if ((err = pthread_mutex_destroy(pMutex_)) != 0) + { //can be broken by SIGKILL (just leave with no Exception) + //throw SilecsException(__FILE__, __LINE__, errno, strerror(errno)); + } + + // patch by Stefano Magnoni (20-03-2012) + // avoid memory leak when deallocating the mutex + if(pMutex_!=NULL) + { + delete pMutex_; + pMutex_ = NULL; + } + } + + void Mutex::lock() + { + int err; + LOG(LOCK) << "Waiting for lock: " << this->name_; + if ((err = pthread_mutex_lock(pMutex_)) != 0) + { // lock can be broken by SIGKILL (just release it with no Exception) + pthread_mutex_unlock(pMutex_); + //throw SilecsException(__FILE__, __LINE__, errno, strerror(errno)); + } + LOG(LOCK) << "Has locked: " << this->name_; + } + + void Mutex::unlock() + { + int err; + if ((err = pthread_mutex_unlock(pMutex_)) != 0) + { // unlock can be broken by SIGKILL (just force release again but no Exception) + pthread_mutex_unlock(pMutex_); + //throw SilecsException(__FILE__, __LINE__, errno, strerror(errno)); + } + LOG(LOCK) << "Has unlocked: " << this->name_; + } + +} diff --git a/silecs-communication-cpp/src/silecs-communication/interface/utility/Mutex.h b/silecs-communication-cpp/src/silecs-communication/interface/utility/Mutex.h new file mode 100644 index 0000000..ecf693d --- /dev/null +++ b/silecs-communication-cpp/src/silecs-communication/interface/utility/Mutex.h @@ -0,0 +1,55 @@ +// Copyright 2016 CERN and GSI +// +// 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 3 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, see <http://www.gnu.org/licenses/>. + +#ifndef _MUTEX_H_ +#define _MUTEX_H_ + +#include <pthread.h> +#include <errno.h> +#include <string> +#include <map> + +#include <silecs-communication/interface/utility/SilecsException.h> + +namespace Silecs +{ + + class Condition; + + class Mutex + { + public: + Mutex(std::string name = "undefined"); + ~Mutex(); + + void lock(); + void unlock(); + + private: + friend class Condition; + + // Mutex name if any, used for logging in particular + std::string name_; + + // Mutex object + pthread_mutex_t* pMutex_; + + // Mutex Attributes + pthread_mutexattr_t attr_; + }; + +} // namespace + +#endif /* _MUTEX_H_ */ diff --git a/silecs-communication-cpp/src/silecs-communication/interface/utility/SilecsException.cpp b/silecs-communication-cpp/src/silecs-communication/interface/utility/SilecsException.cpp new file mode 100644 index 0000000..ae114f7 --- /dev/null +++ b/silecs-communication-cpp/src/silecs-communication/interface/utility/SilecsException.cpp @@ -0,0 +1,331 @@ +// Copyright 2016 CERN and GSI +// +// 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 3 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, see <http://www.gnu.org/licenses/>. + +#include "SilecsException.h" +#include "SilecsLog.h" + +#include <string> + +namespace Silecs +{ + + SilecsException::SilecsException(const std::string& file, const uint32_t line, const ErrorCode code, const std::string& extMsg) + { + errFile_ = file; + errLine_ = line; + errCode_ = code; + fillCategoryMessageFromCode(code); + errMessage_ += extMsg; + buildFullMessage(); + //Log the error to the std. output (if ERROR topic is enable) + log(); + } + + + SilecsException::SilecsException(const std::string& file, const uint32_t line, const int err, const char *str) + { + errFile_ = file; + errLine_ = line; + errCategory_ = CLIENT_SYSTEM_FAULT; + errCode_ = UNEXPECTED_ERROR; + errMessage_ = str; + buildFullMessage(); + + //Log the error to the std. output (if ERROR topic is enable) + log(); + } + + SilecsException::SilecsException(const std::string& file, const uint32_t line, const std::string& msg) + { + errFile_ = file; + errLine_ = line; + errCategory_ = CLIENT_SYSTEM_FAULT; + errCode_ = UNEXPECTED_ERROR; + errMessage_ = msg; + buildFullMessage(); + //Log the error to the std. output (if ERROR topic is enable) + log(); + } + + SilecsException::SilecsException(const SilecsException& ex) + { + errMessage_ = ex.errMessage_; + + //---------------------------------- + // Not used... initialized for safety. suggested by static analysis + errFile_ = ""; + errLine_ = -1; + errCategory_ = CLIENT_SYSTEM_FAULT; + errCode_ = UNEXPECTED_ERROR; + //---------------------------------- + + //Log the error to the std. output (if ERROR topic is enable) + log(); + } + + SilecsException::~SilecsException() throw() + { + } + + const char* SilecsException::what() const throw() + { + return errFullMessage_.c_str(); + } + + + ErrorCategory SilecsException::getCategory() const + { + return errCategory_; + } + + + ErrorCode SilecsException::getCode() const + { + return errCode_; + } + + + const char* SilecsException::getMessage() const + { + return errMessage_.c_str(); + } + + + void SilecsException::fillCategoryMessageFromCode(ErrorCode code) + { + switch(code) + { + case XML_FILE_NOT_WELLFORMED: + errCategory_ = XML_PARSING_FAULT; + errMessage_ = "This XML parameters file is not well-formed: "; + break; + case XML_ELEMENT_NOT_FOUND: + errCategory_ = XML_PARSING_FAULT; + errMessage_ = "XML Element not found within the parameters file: "; + break; + case XML_EXPRESSION_MISMATCH: + errCategory_ = XML_PARSING_FAULT; + errMessage_ = "The following rule does not match any XML Element within the parameters file:\n"; + break; + case XML_CREATE_XPATH_FAULT: + errCategory_ = XML_PARSING_FAULT; + errMessage_ = "Cannot create the XML path context."; + break; + case XML_EVALUATE_XPATH_FAULT: + errCategory_ = XML_PARSING_FAULT; + errMessage_ = "Cannot find evaluate xPath expression."; + break; + case XML_ATTRIBUTE_NOT_FOUND: + errCategory_ = XML_PARSING_FAULT; + errMessage_ = "XML Attribute not found within the parameters file."; + break; + case XML_DATA_NOT_CONSISTENT: + errCategory_ = XML_PARSING_FAULT; + errMessage_ = "Design and Deployment data are not consistent (Registers and Blocks list."; + break; + case XML_DATA_TYPE_MISMATCH: + errCategory_ = XML_PARSING_FAULT; + errMessage_ = "XML data type mismatch within the parameters file."; + break; + case DATA_UNKNOWN_FORMAT_TYPE: + errCategory_ = DATA_FAULT; + errMessage_ = "Register Design has a wrong data format: "; + break; + case DATA_UNKNOWN_ACCESS_TYPE: + errCategory_ = DATA_FAULT; + errMessage_ = "Block Design has a wrong access-type: "; + break; + case DATA_UNKNOWN_SYNCHRO_TYPE: + errCategory_ = DATA_FAULT; + errMessage_ = "Register Design has a wrong synchronization type: "; + break; + case DATA_UNKNOWN_PLC_MANUFACTURER: + errCategory_ = DATA_FAULT; + errMessage_ = "Controller Deployment has a wrong manufacturer: "; + break; + case DATA_UNKNOWN_PLC_MODEL: + errCategory_ = DATA_FAULT; + errMessage_ = "Controller Deployment has a wrong model: "; + break; + case DATA_UNKNOWN_PLC_SYSTEM: + errCategory_ = DATA_FAULT; + errMessage_ = "Controller Deployment has a wrong system: "; + break; + case DATA_UNKNOWN_PROTOCOL_MODE: + errCategory_ = DATA_FAULT; + errMessage_ = "Controller Deployment has a wrong protocol mode: "; + break; + case DATA_READ_ACCESS_TYPE_MISMATCH: + errCategory_ = DATA_FAULT; + errMessage_ = "Trying to read a write-only register: "; + break; + case DATA_WRITE_ACCESS_TYPE_MISMATCH: + errCategory_ = DATA_FAULT; + errMessage_ = "Trying to write a read-only register: "; + break; + case DATA_SYNCHRO_ACCESS_TYPE_MISMATCH: + errCategory_ = DATA_FAULT; + errMessage_ = "Synchronization and Access types of this register are not compatible: "; + break; + case DATA_ARRAY_LENGTH_MISMATCH: + errCategory_ = DATA_FAULT; + errMessage_ = "ArrCOMM_BLOCK_RESIZING_NOT_ALLOWEDay length is not compatible: "; + break; + case PARAM_INCORRECT_ARGUMENTS: + errCategory_ = PARAM_FAULT; + errMessage_ = "Incorrect SILECS service arguments."; + break; + case PARAM_FILE_NOT_FOUND: + errCategory_ = PARAM_FAULT; + errMessage_ = "This parameters file does not exist: "; + break; + case PARAM_UNKNOWN_BLOCK_NAME: + errCategory_ = PARAM_FAULT; + errMessage_ = "Unknown block-name: "; + break; + case PARAM_UNKNOWN_DEVICE_NAME: + errCategory_ = PARAM_FAULT; + errMessage_ = "Unknown device-name: "; + break; + case PARAM_UNKNOWN_REGISTER_NAME: + errCategory_ = PARAM_FAULT; + errMessage_ = "Unknown register-name: "; + break; + case PARAM_ACCESS_TYPE_MISMATCH: + errCategory_ = PARAM_FAULT; + errMessage_ = "Use of inappropriate method (access-type) to access the block: "; + break; + case PARAM_FORMAT_TYPE_MISMATCH: + errCategory_ = PARAM_FAULT; + errMessage_ = "Use of inappropriate method (format/dimension) to access the register: "; + break; + case PARAM_ARRAY_DIMENSION_MISMATCH: + errCategory_ = PARAM_FAULT; + errMessage_ = "Trying to access the following array-register with wrong index or dimension: "; + break; + case PARAM_NO_TIME_STAMP: + errCategory_ = PARAM_FAULT; + errMessage_ = "Trying to access the Time-Stamp of a Write-Only register: "; + break; + case PARAM_INCORRECT_BLOCK_ADDRESS: + errCategory_ = PARAM_FAULT; + errMessage_ = "Schneider uses 16bit alignment addressing. The Block address should be an even value: "; + break; + case PARAM_EXCEEDED_BLOCK_SIZE: + errCategory_ = PARAM_FAULT; + errMessage_ = "The specified block-size exceeds the one allocated: "; + break; + case PARAM_UNKNOWN_IP_ADDRESS: + errCategory_ = PARAM_FAULT; + errMessage_ = "This IP address is unknown or not well-formed: "; + break; + case PARAM_UNKNOWN_PLC_HOSTNAME: + errCategory_ = PARAM_FAULT; + errMessage_ = "This controller hostname is unknown or not well-formed: "; + break; + case COMM_CONNECT_FAILURE: + errCategory_ = COMM_FAULT; + errMessage_ = "Unable to connect the controller: "; + break; + case COMM_RECONNECT_FAILURE: + errCategory_ = COMM_FAULT; + errMessage_ = "Unable to re-connect the controller: "; + break; + case COMM_CONNECT_CLOSED: + errCategory_ = COMM_FAULT; + errMessage_ = "Connection has been closed with the controller: "; + break; + case COMM_ALREADY_ENABLED: + errCategory_ = COMM_FAULT; + errMessage_ = "Controller connection already enabled: "; + break; + case COMM_NOT_CONNECTED_YET: + errCategory_ = COMM_FAULT; + errMessage_ = "Trying to access (send/recv) a controller that is not connected yet: "; + break; + case COMM_ALREADY_CONNECTED: + errCategory_ = COMM_FAULT; + errMessage_ = "Controller already connected: "; + break; + + case COMM_BLOCK_RESIZING_NOT_ALLOWED: + errCategory_ = COMM_FAULT; + errMessage_ = "Data-block resizing is allowed only with single device access (send/recv)."; + break; + case CONFIG_CLASS_NOT_DEPLOYED: + errCategory_ = CONFIG_FAULT; + errMessage_ = "This controller/Design deployment does not exist: "; + break; + case CONFIG_CLIENT_PLC_NOT_CONSISTENT: + errCategory_ = CONFIG_FAULT; + errMessage_ = "The client configuration is not consistent with the mapping of the controller: "; + break; + case CONFIG_CLIENT_PLC_NOT_AVAILABLE: + errCategory_ = CONFIG_FAULT; + errMessage_ = "Reading the controller Header data has failed: IP address of that client is not allowed or the controller memory is empty: "; + break; + case DIAG_SLAVE_REGISTER_NOT_INITIALIZED: + errCategory_ = DIAG_FAULT; + errMessage_ = "Connection is not allowed now because some of retentive slave registers are not initialized yet: "; + break; + case DIAG_PLC_REPORT_NOT_SUPPORTED: + errCategory_ = DIAG_FAULT; + errMessage_ = "Diagnostic and status report are not supported with this controller type: "; + break; + case CNV_INTERNAL_ERROR: + errCategory_ = CNV_SYSTEM_FAULT; + errMessage_ = "CNV library error: "; + break; + case UNEXPECTED_ERROR: + errCategory_ = CLIENT_SYSTEM_FAULT; + errMessage_ = "Unexpected error: "; + break; + default: + errCategory_ = UNKNOWN_FAULT; + errMessage_ = "Unknown fault."; + } + } + + void SilecsException::buildFullMessage() + { + errFullMessage_ = errCategory_ + "/" + errCode_; + errFullMessage_ += " "; + + char errLineAsString[5] = {0}; + sprintf(errLineAsString, "%d", int(errLine_)); + + errFullMessage_ += errFile_ + ":" + errLineAsString; + errFullMessage_ += " " + errMessage_; + } + + void SilecsException::print() const + { + std::cerr << "Silecs::SilecsException [" << errCategory_ << "/" << errCode_ << "] " + << errFile_ << ":" << errLine_ << ", " + << errMessage_ + << std::endl; + } + + + void SilecsException::log() const + { + unsigned long topic = ERROR; //Exception means ERROR topic + if (errCategory_ == DIAG_FAULT) topic |= DIAG; //and DIAG topic if required for syslog purpose + LOG(topic) << "[" << errCategory_ << "/" << errCode_ << "] " + << errFile_ << ":" << errLine_ << ", " + << errMessage_; + } + +} // namespace diff --git a/silecs-communication-cpp/src/silecs-communication/interface/utility/SilecsException.h b/silecs-communication-cpp/src/silecs-communication/interface/utility/SilecsException.h new file mode 100644 index 0000000..5d1f5f8 --- /dev/null +++ b/silecs-communication-cpp/src/silecs-communication/interface/utility/SilecsException.h @@ -0,0 +1,185 @@ +// Copyright 2016 CERN and GSI +// +// 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 3 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, see <http://www.gnu.org/licenses/>. + +#ifndef _SILECS_EXCEPTION_H_ +#define _SILECS_EXCEPTION_H_ + +#include <stdexcept> +#include <stdint.h> + + +namespace Silecs +{ + + /*! + * \brief Defines the category of the SILECS Exception. + * Can be used in the Exception catch to dispatch emergency actions. + * Use Exception::getCategory() to retrieve it. + */ + typedef enum + { + CLIENT_SYSTEM_FAULT = 1, + PLC_SYSTEM_FAULT, + CNV_SYSTEM_FAULT, + XML_PARSING_FAULT, + DATA_FAULT, + PARAM_FAULT, + COMM_FAULT, + CONFIG_FAULT, + DIAG_FAULT, + NO_FAULT, + UNKNOWN_FAULT + } ErrorCategory; + + /*! + * \brief Defines the detailed code of the SILECS Exception. + * Can be used in the Exception catch to execute the appropriate action. + * Use SilecsException::getCode() to retrieve it. + */ + typedef enum + { + XML_FILE_NOT_WELLFORMED = 1, + XML_ELEMENT_NOT_FOUND, + XML_EXPRESSION_MISMATCH, + XML_CREATE_XPATH_FAULT, + XML_EVALUATE_XPATH_FAULT, + XML_ATTRIBUTE_NOT_FOUND, + XML_DATA_NOT_CONSISTENT, + XML_DATA_TYPE_MISMATCH, + DATA_UNKNOWN_FORMAT_TYPE, + DATA_UNKNOWN_ACCESS_TYPE, + DATA_UNKNOWN_SYNCHRO_TYPE, + DATA_UNKNOWN_PLC_MANUFACTURER, + DATA_UNKNOWN_PLC_MODEL, + DATA_UNKNOWN_PLC_SYSTEM, + DATA_UNKNOWN_PROTOCOL_MODE, + DATA_READ_ACCESS_TYPE_MISMATCH, + DATA_WRITE_ACCESS_TYPE_MISMATCH, + DATA_SYNCHRO_ACCESS_TYPE_MISMATCH, + DATA_ARRAY_LENGTH_MISMATCH, + PARAM_INCORRECT_ARGUMENTS, + PARAM_FILE_NOT_FOUND, + PARAM_UNKNOWN_BLOCK_NAME, + PARAM_UNKNOWN_DEVICE_NAME, + PARAM_UNKNOWN_REGISTER_NAME, + PARAM_ACCESS_TYPE_MISMATCH, + PARAM_FORMAT_TYPE_MISMATCH, + PARAM_ARRAY_DIMENSION_MISMATCH, + PARAM_NO_TIME_STAMP, + PARAM_INCORRECT_BLOCK_ADDRESS, + PARAM_EXCEEDED_BLOCK_SIZE, + PARAM_UNKNOWN_IP_ADDRESS, + PARAM_UNKNOWN_PLC_HOSTNAME, + COMM_CONNECT_FAILURE, + COMM_RECONNECT_FAILURE, + COMM_CONNECT_CLOSED, + COMM_ALREADY_ENABLED, + COMM_ALREADY_CONNECTED, + COMM_NOT_CONNECTED_YET, + COMM_BLOCK_RESIZING_NOT_ALLOWED, + CONFIG_CLASS_NOT_DEPLOYED, + CONFIG_CLIENT_PLC_NOT_CONSISTENT, + CONFIG_CLIENT_PLC_NOT_AVAILABLE, + DIAG_SLAVE_REGISTER_NOT_INITIALIZED, + DIAG_PLC_REPORT_NOT_SUPPORTED, + CNV_INTERNAL_ERROR, + UNEXPECTED_ERROR, + UNKNOWN_ERROR + } ErrorCode; + + /*! + * \class SilecsException + * \brief This class is the based class for the Exceptions generated by the SILECS library. + * An error belongs to a category, it has a code identifier within the category and + * a description message. + */ + class SilecsException : public std::exception + { + public: + + /// @cond + SilecsException(const SilecsException & ex); + virtual ~SilecsException() throw(); + + /*! + * \brief Constructor and copy-constructors + * \param file-name, line-number and error-code for specific faults + * \param file-name, line-number, error-no and error-str for system faults or extra-str if needed + */ + SilecsException(const std::string& file, const uint32_t line, const ErrorCode code, const std::string& extMsg = std::string()); + SilecsException(const std::string& file, const uint32_t line, const int err, const char *str); + SilecsException(const std::string& file, const uint32_t line, const std::string& msg); + + /*! + * \return a string with the error description + */ + const char* what() const throw(); + + /*! + * \brief This method displays a warning for a not defined exception + */ + //static void unknown(const std::string file, const long line); + /// @endcond + + /*! + * \brief Returns the category of the Exception object. + * \return value from the ErrorCategory enumeration + */ + ErrorCategory getCategory() const; + + /*! + * \brief Returns the error code of the Exception object. + * \return value from the ErrorCode enumeration + */ + ErrorCode getCode() const; + + /*! + * \brief Returns string message describing the Exception object. + * \return Error message as string + */ + const char* getMessage() const; + + /*! + * \brief Print readable message of the exception to the standard output (console): + * Time-stamp, Category, Code, Source File/Line and extra message + */ + void print() const; + + private: + /*! + * \fn fillCategoryMessageFromCode + * \brief This method assign the appropriate message to a given errCode + */ + void fillCategoryMessageFromCode(ErrorCode code); + + void buildFullMessage(); + + /*! + * \brief Log readable message of the exception to the standard output (if ERROR topic enable): + * Time-stamp, Category, Code, Source File/Line and extra message + */ + void log() const; + + std::string errFile_; + long errLine_; + ErrorCategory errCategory_; + ErrorCode errCode_; + std::string errMessage_; + std::string errFullMessage_; + }; + +} // namespace + +#endif //_SILECS_EXCEPTION_H_ diff --git a/silecs-communication-cpp/src/silecs-communication/interface/utility/SilecsLog.cpp b/silecs-communication-cpp/src/silecs-communication/interface/utility/SilecsLog.cpp new file mode 100644 index 0000000..0891e46 --- /dev/null +++ b/silecs-communication-cpp/src/silecs-communication/interface/utility/SilecsLog.cpp @@ -0,0 +1,169 @@ +// Copyright 2016 CERN and GSI +// +// 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 3 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, see <http://www.gnu.org/licenses/>. + +#include <silecs-communication/interface/utility/SilecsLog.h> +#include <silecs-communication/interface/utility/StringUtilities.h> +#include <silecs-communication/interface/utility/TimeStamp.h> +#include <syslog.h> +#include <string.h> + + +namespace Silecs +{ + //TRACE is a particular topic used to feed ACET tracing service with static information + //of the running program (SILECS library in that case). Sys-logging of it is mandatory and + //cannot be disabled to insure ACET does not miss sources. + //DIAG is a particular topic used to feed the standard syslog with minimal information for + //debugging purpose, sys-logging cannot be disabled as well + unsigned long Log::topics_ = 0; + unsigned long Log::systopics_ = TRACE|DIAG; + + bool Log::syslogIsStarted_ = false; //syslog not yet started + TsCounter Log::timeStamp_(true); + + Log::Log(unsigned long topic) + { topic_ = topic; + } + + Log::~Log() + { + if (topic_ & topics_) { + //this topic is enabled for std. output + std::cerr << os.str().c_str() << std::endl; + } + + if (topic_ & systopics_) + //this topic is enabled for syslog output + syslog(LOG_INFO, os.str().c_str()); + } + + bool Log::getTopicsFromString(const std::string& topicArgv) + { + unsigned long topicsTemp = NO_TOPIC; // Remove all the topics + + unsigned int i; int j; + bool wrongTopic = false; + std::vector<std::string> topicCol; + StringUtilities::tokenize(topicArgv, topicCol, ","); + for (i=0; i<topicCol.size(); ++i) + { for (j=0; j<topicNb; ++j) + { if (topicCol[i] == topicList[j]) + { topicsTemp |= 1<<j; + break; + } + } + if (j==topicNb) + { wrongTopic = true; + std::cerr << "SILECS setup failed: Unknown diagnostic topic: " << topicCol[i] << std::endl; + break; + } + + } + //Return false if topic parameters are not correct or empty + //if (!(wrongTopic || topicCol.size()==0)) // replaced for performance + if (!(wrongTopic || topicCol.empty())) + { + topics_ = topicsTemp; + return true; + } + return false; + } + + std::string Log::setTopicToString(unsigned long topic) + { + int i=0; + while(topic > 1) { topic >>=1; i++; } + if (i>=topicNb) + { std::cerr << "Unknown topic id: '" << topic << "'. Giving ERROR topic as default." << std::endl; + i = 0; + } + return ("/"+topicList[i]); + } + + std::ostringstream& Log::getLog() + { + os << "TIME " << std::setprecision(5) << timeStamp_.getValue(S_UNIT); + os << "s SILECS" << setTopicToString(topic_) << "(thread " << pthread_self() << "): "; + return os; + } + + std::ostringstream& Log::getTrace(std::string source) + { + os << "Environment=prod|MessageType=static|MessageSeverity=info|SenderType=library|SenderDomain=silecs|SenderSubdomain=client|"; + os << "SenderSource=" << source << "||"; + return os; + } + + std::ostringstream& Log::getLogDelay() + { + os << "DELAY " << std::setprecision(5) << timeStamp_.getDelay(MS_UNIT); + os << "ms SILECS" << setTopicToString(topic_) << "(thread " << pthread_self() << "): "; + return os; + } + + bool Log::setLogArguments(int argc, char ** argv) + { + bool argsOk = true; + for(int i=0; i< argc; i++) + { if((strcmp(argv[i], "-plcLog") == 0) && (i+1 < argc)) + { argsOk = Log::getTopicsFromString(argv[i+1]); + break; + } + } + return argsOk; + } + + std::string Log::getLogArguments() + { + int j; + std::string argsList; + argsList = "-plcLog " + topicList[0] + "[,"; + for (j=1; j<topicNb-1; ++j) argsList += topicList[j] + ","; + argsList += topicList[j] + "] "; + return argsList; + } + + void Log::startSyslog(char* ident, unsigned long topics) + { + if (!syslogIsStarted_) + { + systopics_ |= topics; + + /* syslog service uses file configuration (required root access): + * /etc/<syslog.conf> : to define the ouput channel (file, console, host) + * /etc/<sysconfig/syslog>: to set-up the syslogd daemon + * For SILECS log we use LOCAL2 facility that is required for ACET service. + * LOCAL2 is also compliant with SILECS diagnostic purpose since by default + * LOG_LOCAL[1..5] are stored into /var/log/messages NFS files, as required. + * Ask to system expert (Nmn) to know about syslogd redirection details. + */ + openlog (ident, LOG_NDELAY, LOG_LOCAL2); + syslogIsStarted_ = true; + } + } + + void Log::stopSyslog() + { + if (syslogIsStarted_) + { + syslogIsStarted_ = false; + //remove syslog resources + closelog(); + + LOG(SETUP) << "syslog service has been stopped."; + } + } + +} // namespace diff --git a/silecs-communication-cpp/src/silecs-communication/interface/utility/SilecsLog.h b/silecs-communication-cpp/src/silecs-communication/interface/utility/SilecsLog.h new file mode 100644 index 0000000..bf0ae83 --- /dev/null +++ b/silecs-communication-cpp/src/silecs-communication/interface/utility/SilecsLog.h @@ -0,0 +1,115 @@ +// Copyright 2016 CERN and GSI +// +// 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 3 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, see <http://www.gnu.org/licenses/>. + +#ifndef _SILECS_LOG_H_ +#define _SILECS_LOG_H_ + +#include <iostream> +#include <sstream> +#include <string> +#include <stdio.h> +#include <iomanip> + + +namespace Silecs +{ + class TsCounter; + + #define NO_TOPIC 0 //used to call LOG without filtering: LOG(NO_TOPIC) + #define LOG(topic) if (topic & (Log::topics_ | Log::systopics_)) Log(topic).getLog() + #define LOG_DELAY(topic) if (topic & (Log::topics_ | Log::systopics_)) Log(topic).getLogDelay() + #define TRACE(source) if (TRACE & Log::systopics_) Log(TRACE).getTrace(source) + + //Different topics can be used to filter the log messages to print on the std. output (console) + //In addition, 'DIAG' messages are sent to the syslog for post-diagnostic to ease tracking of + //unexpected process behavior (general messages to trace the process sequencing (not ERRORs)). + //By default, console logging is disabled for all topics but can be enable using '-plcLog' arguments. + //The DIAG console output can be enable/disable as well while DIAG syslog output is mandatory. + enum LogTopic + { + TRACE = 1<<0, //special topic sent to the ACET tracing service + DIAG = 1<<1, //special topic sent to the console (if enable) and to the syslog (everytime) + ERROR = 1<<2, //std. topic to trace the SILECS processing errors, sent to the console (if enable) + DEBUG = 1<<3, //std. topic to trace the SILECS debug info, sent to the console (if enable) + SETUP = 1<<4, //std. topic to trace details of SILECS start-up, sent to the console (if enable) + ALLOC = 1<<5, //std. topic to trace allocation memory, sent to the console (if enable) + RECV = 1<<6, //std. topic to trace transaction from PLC, sent to the console (if enable) + SEND = 1<<7, //std. topic to trace transaction toward PLC, sent to the console (if enable) + COMM = 1<<8, //std. topic to trace PLC communication stuff, sent to the console (if enable) + DATA = 1<<9, //std. topic to trace transaction details (need SEND/RECV), sent to the console (if enable and ) + LOCK = 1<<10, //std. topic to trace resources lock details, sent to the console (if enable and ) + }; + + const int topicNb = 11; + const std::string topicList[topicNb] = + { + "TRACE", + "DIAG", + "ERROR", + "DEBUG", + "SETUP", + "ALLOC", + "RECV", + "SEND", + "COMM", + "DATA", + "LOCK", + }; + + class Log + { + public: + Log(unsigned long topic); + virtual ~Log(); + + std::ostringstream& getLog(); + std::ostringstream& getLogDelay(); + std::ostringstream& getTrace(std::string source); + + // set log arguments: '-plcLog topic1[,topic2,..]' + static bool setLogArguments(int argc, char ** argv); + + /*! + * \fn startSyslog + * \brief Used to enable the standard syslog mechanism + * \parameter topics: bit-set of the topics to be stored using the syslog (in addition to mandatory TRACE and DIAG) + */ + static void startSyslog(char* ident, unsigned long systopics); + static void stopSyslog(); + + // return valid log arguments as string: '-plcLog topic1[,topic2,..]' + static std::string getLogArguments(); + + static std::string setTopicToString(unsigned long topic); + + static bool getTopicsFromString(const std::string& topicArgv); + + unsigned long topic_; //current topic of the logger + static unsigned long topics_; //enabled topics (coming from the process arguments) + static unsigned long systopics_;//set of topics to be logged using the syslog mechanism + + private: + Log(const Log&); + Log& operator =(const Log&); + std::ostringstream os; + static TsCounter timeStamp_; + static bool syslogIsStarted_; + }; + +} // namespace + +#endif //_SILECS_LOG_H_ + + diff --git a/silecs-communication-cpp/src/silecs-communication/interface/utility/StringUtilities.cpp b/silecs-communication-cpp/src/silecs-communication/interface/utility/StringUtilities.cpp new file mode 100644 index 0000000..2dbcffc --- /dev/null +++ b/silecs-communication-cpp/src/silecs-communication/interface/utility/StringUtilities.cpp @@ -0,0 +1,120 @@ +// Copyright 2016 CERN and GSI +// +// 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 3 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, see <http://www.gnu.org/licenses/>. + +#include "StringUtilities.h" +#include <stdio.h> + + +namespace Silecs +{ + const unsigned int StringUtilities::c_emptyStringArraySize = 1; + const char StringUtilities::c_emptyString[] = "\0"; + const char* StringUtilities::c_emptyStringArray[1] = {"\0"}; + + void StringUtilities::tokenize(const std::string& str, std::vector<std::string>& tokens, + const std::string& delimiters) { + + size_t startPos = 0; + size_t endPos = str.find_first_of(delimiters, 0); + if (endPos == std::string::npos) { + //no delimiters + tokens.push_back(str); + return; + } + size_t maxLenght = str.size(); + while (startPos != std::string::npos && endPos != std::string::npos) { + // Found a token, add it to the vector. + std::string s = str.substr(startPos, endPos - startPos); + tokens.push_back(s); + // Next start delimiter + if (endPos < maxLenght -1) + startPos = endPos+1; + else + // string size exceeded + break; + endPos = str.find_first_of(delimiters, startPos); + if (endPos == std::string::npos) { + // no delimiter at the end : last token + std::string s = str.substr(startPos, maxLenght - startPos); + tokens.push_back(s); + } + } + } + + void StringUtilities::trimWhiteSpace(std::string& str) { + size_t pos = str.find(" "); + while (pos != std::string::npos) { + str.erase(pos, 1); + pos = str.find(" "); + } + } + + std::string StringUtilities::toString(unsigned int data) + { + char tmp[32]; + sprintf(tmp, "%u", data); + return tmp; + } + + std::string StringUtilities::toString(int data) + { + char tmp[32]; + sprintf(tmp, "%d", data); + return tmp; + } + + std::string StringUtilities::toString(long data) + { + char tmp[32]; + sprintf(tmp, "%ld", data); + return tmp; + } + + std::string StringUtilities::toString(unsigned long data) + { + char tmp[32]; + sprintf(tmp, "%lu", data); + return tmp; + } + + std::string StringUtilities::toString(long long data) + { + char tmp[32]; + sprintf(tmp, "%lld", data); + return tmp; + } + + std::string StringUtilities::toString(double data) + { + char tmp[32]; + sprintf(tmp, "%f", data); + return tmp; + } + + std::string StringUtilities::toString(const void * ptr) + { + char tmp[32]; + sprintf(tmp, "%p", ptr); + return tmp; + } + + void StringUtilities::toLower(std::string& str) + { //cannot used std::transform() method because of ppc4 support! + for(unsigned int i=0;i<str.length();i++) + { str[i] = tolower(str[i]); + } + } + +} // namespace diff --git a/silecs-communication-cpp/src/silecs-communication/interface/utility/StringUtilities.h b/silecs-communication-cpp/src/silecs-communication/interface/utility/StringUtilities.h new file mode 100644 index 0000000..a6bea35 --- /dev/null +++ b/silecs-communication-cpp/src/silecs-communication/interface/utility/StringUtilities.h @@ -0,0 +1,74 @@ +// Copyright 2016 CERN and GSI +// +// 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 3 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, see <http://www.gnu.org/licenses/>. + +#ifndef _STRING_UTILITIES_H_ +#define _STRING_UTILITIES_H_ + +#include <string> +#include <vector> +#include <silecs-communication/interface/utility/SilecsException.h> +#include <sstream> + +namespace Silecs +{ + + class StringUtilities + { + public: + static void tokenize(const std::string& str, std::vector<std::string>& tokens, + const std::string& delimiters = " "); + + static void trimWhiteSpace(std::string& str); + + // define an array of one pointer on an empty string + static const unsigned int c_emptyStringArraySize; + static const char* c_emptyStringArray[1]; + // define an empty string + static const char c_emptyString[]; + + static std::string toString(unsigned int data); + static std::string toString(int data); + static std::string toString(unsigned long data); + static std::string toString(long data); + static std::string toString(long long data); + static std::string toString(double data); + static std::string toString(const void * ptr); + static void toLower(std::string& str); + + /*! + * \brief transform a string into any integer-type + * \param str the string to transform + * \param value that will receive the conversion + */ + template<typename T> static void fromString(T& value, const std::string& str); + + }; + + template<typename T> + inline void StringUtilities::fromString(T& value, const std::string& str) + { + std::istringstream iss(str); + if ((iss >> value).fail()) + { + std::ostringstream message; + message << "Failed to convert the string: '" << str << "' to numeric type"; + throw SilecsException(__FILE__, __LINE__,message.str().c_str()); + } + } + +} // namespace + + +#endif //_STRING_UTILITIES_H_ diff --git a/silecs-communication-cpp/src/silecs-communication/interface/utility/Thread.h b/silecs-communication-cpp/src/silecs-communication/interface/utility/Thread.h new file mode 100644 index 0000000..fd2adbc --- /dev/null +++ b/silecs-communication-cpp/src/silecs-communication/interface/utility/Thread.h @@ -0,0 +1,250 @@ +// Copyright 2016 CERN and GSI +// +// 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 3 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, see <http://www.gnu.org/licenses/>. + +#ifndef _THREAD_H_ +#define _THREAD_H_ + +#include <iostream> +#include <string> +#include <vector> +#include <list> +#include <utility> +#include <map> +#include <queue> +#include <pthread.h> +#include <signal.h> +#include <malloc.h> +#include <string.h> + + +#include <silecs-communication/interface/core/Context.h> +#include <silecs-communication/interface/utility/Condition.h> + + +using namespace std; + + +namespace Silecs +{ + class Context; + + /*! ------------------------------------------------------------------------- + * \class Task + * \brief Template for the Task class. + * A Task class is defined by what the user wants to execute (user_function) + * and by the data he wants to use (user_data). + * It is up to the user to specify the Task template according to + * his data type. + */ + template<typename UserDataType> + class Task + { + public: + Task(int (*pFunc)(UserDataType, Context* pContext), UserDataType data); + int execute(Context* pContext); + + private: + int (*userFunc)(UserDataType, Context* pContext); //function user + UserDataType userData_; //data user + }; + + template<typename UserDataType> + Task<UserDataType>::Task::Task(int (*pFunc)(UserDataType, Context* pContext), UserDataType data): + userFunc(pFunc), userData_(data) + { + } + + template<typename UserDataType> + int Task<UserDataType>::execute(Context* pContext) + { + return userFunc(userData_, pContext); + } + + /*! ------------------------------------------------------------------------- + * \class Thread + * \brief Template for the Thread class. + * One Thread instance is required per PLC connection. + * The thread allows delegated transaction from the Cluster API level. + * Thus, a Send/Recv Cluster call can start action on each PLC in parallel. + */ + template<typename UserDataType> + class Thread + { + public: + Thread(); + ~Thread(); + unsigned int getPriority(); + void setPriority(unsigned int rtprio); + void schedule(Task<UserDataType> *pt, Context* pContext); + void waitForTaskCompletion(); + private: + static void *run(void *arg); + void execute(); + Task<UserDataType> *pTask_; + Context* pContext_; //to transmit data from the caller context: Cluster, PLC or Device + pthread_t *pTid_; + Condition* pThreadCompletion_; //condition-variable for thread loop synchronization + bool endThread_; //boolean predicate associated with pThreadCompletion + Condition* pTaskCompletion_; //condition-variable for task process synchronization + bool endTask_; //boolean predicate associated with pTaskCompletion + Mutex* pThreadBusy_; //mutex to protect thread against concurrent asynchronous call + }; + + template<typename UserDataType> + Thread<UserDataType>::Thread(): endThread_(false), endTask_(true) + { + int err; + pThreadBusy_ = new Mutex("threadBusy"); + pThreadCompletion_ = new Condition("threadCompletion"); + pTaskCompletion_ = new Condition("taskCompletion"); + + pTid_ = (pthread_t *)malloc(sizeof(pthread_t)); + pThreadCompletion_->lock(); // The constructor will wait until thread is ready + if ((err = pthread_create(pTid_, NULL, run, this)) != 0) + throw SilecsException(__FILE__, __LINE__, errno, strerror(err)); + //err = pthread_detach(*pTid_); not necessary because PLC thread are infinite loop + pThreadCompletion_->wait(); // Wait until thread is ready + pThreadCompletion_->unlock(); // Thread is ready + }; + + template<typename UserDataType> + void *Thread<UserDataType>::run(void *pThisThread) + { + Thread *pthis = (Thread*) pThisThread; + + //An SILECS thread should not be disturbed by signals that may come from the host process. + //Then, block signals which are generated by the system itself (means RT signals). + sigset_t smask; + sigemptyset(&smask); + for(int snum=SIGRTMIN; snum<=SIGRTMAX; sigaddset(&smask, snum++)) + { int err; + if ((err = pthread_sigmask(SIG_BLOCK, &smask, NULL)) != 0) + throw SilecsException(__FILE__, __LINE__, errno, strerror(err)); + } + pthis->execute(); + return 0; + }; + + template<typename UserDataType> + void Thread<UserDataType>::execute() + { + pThreadCompletion_->lock(); // The constructor will waiting until thread is ready + pThreadCompletion_->signal(); // Thread is ready (for constructor waiting) + + while (endThread_ != true) + { + pThreadCompletion_->wait(); // Wait for schedule or end-Thread request + if (endThread_ == true) break; // end-thread request: exit infinite loop + + try + { pTaskCompletion_->lock(); // To protect the enTask_ condition variable + //check if pThreadCompletion.wait has not been canceled by spurious signal + if (endTask_ == false) + { //ok, the task has to be executed + pTask_->execute(pContext_); // Schedule request: task execution + endTask_ = true; // Task is finished + pTaskCompletion_->signal(); // Inform caller thread that task has been completed + } + pTaskCompletion_->unlock(); + } + catch(std::exception& ex) + { + std::cerr << "[Thread::execute] ERROR: during execution:" << ex.what() << std::endl; + } + catch(...) + { + std::cerr << "[Thread::execute] ERROR: during execution - unknown exception received" << std::endl; + } + } + + pThreadCompletion_->unlock(); // Thread is terminated + }; + + template<typename UserDataType> + unsigned int Thread<UserDataType>::getPriority() + { + int policy; + sched_param params; + + if (pthread_getschedparam(*pTid_, &policy, ¶ms) != 0) + { string errMsg(string("Cannot get dynamically schedparams: ") + strerror(errno)); + throw errMsg; + } + return params.sched_priority; + } + + template<typename UserDataType> + void Thread<UserDataType>::setPriority(unsigned int rtprio) + { + int policy; + sched_param params; + + if (pthread_getschedparam(*pTid_, &policy, ¶ms) == 0) + { params.sched_priority = rtprio; + if (pthread_setschedparam(*pTid_, sched_getscheduler(getpid()), ¶ms) == 0) + return; + } + string errMsg(string("Cannot set dynamically schedparams: ") + strerror(errno)); + throw errMsg; + } + + template<typename UserDataType> + void Thread<UserDataType>::waitForTaskCompletion() + { + pTaskCompletion_->lock(); // To protect the enTask_ condition variable check + while (endTask_ == false) + { pTaskCompletion_->wait(); // Wait for task completion + } + pTaskCompletion_->unlock(); // Task has been completed + pThreadBusy_->unlock(); // Thread has finished to execute the current task (resource is free) + } + + template<typename UserDataType> + void Thread<UserDataType>::schedule(Task<UserDataType> *pt, Context* pContext) + { + pThreadBusy_->lock(); // Thread resource must be locked until full task completion + pThreadCompletion_->lock(); // To protect the endThread_ condition variable update + pContext_ = pContext; // Update the caller context and + pTask_ = pt; // the task reference to be executed + endTask_ = false; // Task is not completed yet + pThreadCompletion_->signal(); // Wake-up the thread to execute this referred task + pThreadCompletion_->unlock(); + }; + + template<typename UserDataType> + Thread<UserDataType>::~Thread() + { + int err; + pThreadCompletion_->lock(); // To protect the endThread_ condition variable + endThread_ = true; // Thread shall stop on the next loop + pThreadCompletion_->signal(); // Wake-up the thread to execute this referred task + pThreadCompletion_->unlock(); + + err = pthread_join(*pTid_, NULL); // Wait for thread end before continuing clean-up + + delete pTaskCompletion_; + delete pThreadCompletion_; + delete pThreadBusy_; + + // patch by Stefano Magnoni (20-03-2012) + // avoid memory leak when deallocating the thread + free(pTid_); + pTid_ = NULL; + + }; + +} // namespace + +#endif // _THREAD_H_ diff --git a/silecs-communication-cpp/src/silecs-communication/interface/utility/TimeStamp.cpp b/silecs-communication-cpp/src/silecs-communication/interface/utility/TimeStamp.cpp new file mode 100644 index 0000000..5d4605d --- /dev/null +++ b/silecs-communication-cpp/src/silecs-communication/interface/utility/TimeStamp.cpp @@ -0,0 +1,126 @@ +/* + * Piece of code adapted for SILECS. + * Original version references: + * + * Portable Agile C++ Classes (PACC) + * Copyright (C) 2004 by Marc Parizeau + * http://manitou.gel.ulaval.ca/~parizeau/PACC + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Contact: + * Laboratoire de Vision et Systemes Numeriques + * Departement de genie electrique et de genie informatique + * Universite Laval, Quebec, Canada, G1K 7P4 + * http://vision.gel.ulaval.ca + * +*/ + +#include <silecs-communication/interface/utility/TimeStamp.h> +#include <iostream> + +namespace Silecs +{ + + double TsCounter::mPeriod = 0; + + void + TsCounter::calibrateCountPeriod(unsigned int inDelay/*ms*/, unsigned int inTimes) { + + if(mHardware) { + #if defined (__GNUG__) && (defined (__i386__) || defined (__PPC__)) + double lPeriod = 0; + // calibrate by matching the time-stamps with the micro-seconds of gettimeofday + for(unsigned int i = 0; i < inTimes; ++ i) { + timeval lStartTime, lTime; + ::gettimeofday(&lStartTime, 0); + unsigned long long lStartCount = getCount(); + + struct timespec theDelay, time_left_before_wakeup; + int sec = inDelay/1000; // number of seconds since delay is expressed in ms + long nsec = 0; + if ((nsec = inDelay%1000)) // check remainder + nsec *= (long)1E6; // convert remainder into ns + theDelay.tv_sec = sec; + theDelay.tv_nsec = nsec; + #ifdef __Lynx__ + //UNIX variants often use a kernel timer resolution (HZ value) + //of about 10ms. So it' not possible to manage delays less than 10ms + //to wait 10ms you need specify a delay 0 othewhise your delay will b 20ms + if((inDelay%10)<5){ + theDelay.tv_nsec -= 20000000; + }else{ + theDelay.tv_nsec -= 10000000; + } + if (theDelay.tv_nsec < 0) + theDelay.tv_nsec = 0; + #endif + nanosleep(&theDelay, &time_left_before_wakeup) ; + + ::gettimeofday(&lTime, 0); + unsigned long long lCount = getCount() - lStartCount; + lTime.tv_sec -= lStartTime.tv_sec; + lTime.tv_usec -= lStartTime.tv_usec; + // dismiss the first run of the loop + if(i != 0) lPeriod += (lTime.tv_sec + lTime.tv_usec*0.000001)/lCount; + } + mPeriod = lPeriod/(inTimes-1); + #else + // use the microseconds of gettimeofday + mPeriod = 0.000001; + #endif + } else { + // use the microseconds of gettimeofday + mPeriod = 0.000001; + } + } + + unsigned long long + TsCounter::getCount(void) const { + unsigned long long lCount = 0; + + if(mHardware) { + #if defined (__GNUG__) && defined (__i386__) + __asm__ volatile("rdtsc" : "=A" (lCount)); + #else + #if defined (__GNUG__) && defined (__PPC__) + register unsigned int lLow; + register unsigned int lHigh1; + register unsigned int lHigh2; + do { + // make sure that high bits have not changed + __asm__ volatile ( "mftbu %0" : "=r" (lHigh1) ); + __asm__ volatile ( "mftb %0" : "=r" (lLow) ); + __asm__ volatile ( "mftbu %0" : "=r" (lHigh2) ); + } while(lHigh1 != lHigh2); + // transfer to lCount + unsigned int *lPtr = (unsigned int*) &lCount; + *lPtr++ = lHigh1; *lPtr = lLow; + #else + timeval lCurrent; + ::gettimeofday(&lCurrent, 0); + lCount = (unsigned long long)lCurrent.tv_sec*1000000 + lCurrent.tv_usec; + #endif + #endif + } else { + timeval lCurrent; + ::gettimeofday(&lCurrent, 0); + lCount = (unsigned long long)lCurrent.tv_sec*1000000 + lCurrent.tv_usec; + } + + return lCount; + } + +} // namespace diff --git a/silecs-communication-cpp/src/silecs-communication/interface/utility/TimeStamp.h b/silecs-communication-cpp/src/silecs-communication/interface/utility/TimeStamp.h new file mode 100644 index 0000000..e17dea7 --- /dev/null +++ b/silecs-communication-cpp/src/silecs-communication/interface/utility/TimeStamp.h @@ -0,0 +1,91 @@ +/* + * Piece of code adapted for SILECS. + * Original version references: + * + * Portable Agile C++ Classes (PACC) + * Copyright (C) 2004 by Marc Parizeau + * http://manitou.gel.ulaval.ca/~parizeau/PACC + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Contact: + * Laboratoire de Vision et Systemes Numeriques + * Departement de genie electrique et de genie informatique + * Universite Laval, Quebec, Canada, G1K 7P4 + * http://vision.gel.ulaval.ca + * +*/ + +#ifndef _TimeStamp_H_ +#define _TimeStamp_H_ + +#include <unistd.h> +#ifdef __Lynx__ +#include <time.h> +#else +#include <sys/time.h> +#endif + + +namespace Silecs { + +#define S_UNIT 1.0 //express delay in second +#define MS_UNIT 1.e3 //express delay in milli-second +#define YS_UNIT 1.e6 //express delay in micro-second +#define NS_UNIT 1.e9 //express delay in nano-second + + class TsCounter { + + public: + TsCounter(bool inHardware=true) : mHardware(inHardware) { + if (mPeriod == 0) calibrateCountPeriod(); + mValueCount = 0; + reset(); + } + + void calibrateCountPeriod(unsigned int inDelay=50/*ms*/, unsigned int inTimes=10); + static double getCountPeriod(void) { return mPeriod; } + static void setCountPeriod(double period) { mPeriod = period; } + void reset(void) { mValueCount = getCount(); mDelayCount = 0; } + + unsigned long long getCount(void) const; + double getCount(double unit) const { return (double)getCount()*mPeriod*unit; } + + double getValue(double unit) + { unsigned long long count = getCount(); + mDelayCount = count; + return (double)(count-mValueCount)*mPeriod*unit; + } + + double getDelay(double unit) + { return (double)(getCount()-mDelayCount)*mPeriod*unit; + } + + double getTimeOfDay(double unit) { + timeval lCurrent; + ::gettimeofday(&lCurrent, 0); + return ((lCurrent.tv_sec*YS_UNIT + lCurrent.tv_usec)*(unit/YS_UNIT)); + } + + protected: + bool mHardware; + unsigned long long mValueCount; //duration from start + unsigned long long mDelayCount; //duration from previous getCount + static double mPeriod; + }; + +} //namespace Silecs + +#endif // _TimeStamp_H_ diff --git a/silecs-communication-cpp/src/silecs-communication/interface/utility/XMLParser.cpp b/silecs-communication-cpp/src/silecs-communication/interface/utility/XMLParser.cpp new file mode 100644 index 0000000..488c853 --- /dev/null +++ b/silecs-communication-cpp/src/silecs-communication/interface/utility/XMLParser.cpp @@ -0,0 +1,242 @@ +// Copyright 2016 CERN and GSI +// +// 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 3 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, see <http://www.gnu.org/licenses/>. + + +#include <silecs-communication/interface/utility/XMLParser.h> +#include <silecs-communication/interface/utility/SilecsException.h> +#include <silecs-communication/interface/utility/StringUtilities.h> + +#include <cstring> +#include <fstream> + +namespace +{ + bool isInitialized_ = false; +} +namespace Silecs +{ + +XMLParser::XMLParser(const std::string& fileName, bool validateFile) : + fileName_(fileName) +{ + if( !isInitialized_) + { + throw SilecsException(__FILE__, __LINE__, "Silecs XML-Parser needs to be initialized before usage!"); + } + if (validateFile) + { + const std::ifstream file(fileName.c_str()); + if (file.fail()) + { + std::ostringstream message; + message << "The Parameter File " << fileName << " was not found"; + throw SilecsException(__FILE__, __LINE__, message.str().c_str()); + } + // Check if file is valid + } +} + +XMLParser::~XMLParser() +{ +} + +void XMLParser::init() +{ + xmlInitParser(); + isInitialized_ = true; +} + +void XMLParser::cleanUp() +{ + xmlCleanupParser(); +} + +void XMLParser::trimCarrierReturn(std::string& s) const +{ + size_t startPos = 0; + while ((startPos = s.find("\n", startPos)) != std::string::npos) + { + s.erase(startPos, 2); + } +} + +void XMLParser::fillElement(xmlNodePtr node, ElementXML& element) const +{ + xmlChar* value = xmlNodeListGetString(node->doc, node->children, 1); + // If the node contains text, the carrier return is removed + if (value) + { + std::string trimString(reinterpret_cast<const char*>(value)); + trimCarrierReturn(trimString); + element.value_ = trimString.c_str(); + xmlFree(value); + value = NULL; + } + element.name_ = reinterpret_cast<const char*>(node->name); + // Loop over all the attributes of the XML element + if (node->properties != NULL) + { + xmlAttrPtr curAttr; + for (curAttr = node->properties; curAttr != NULL; curAttr = curAttr->next) + { + boost::shared_ptr<AttributeXML> attribute(new AttributeXML()); + attribute->name_ = reinterpret_cast<const char*>(curAttr->name); + value = xmlGetProp(node, reinterpret_cast<const xmlChar*>(attribute->name_.c_str())); + attribute->value_ = reinterpret_cast<const char*>(value); + xmlFree(value); + value = NULL; + element.attributeList_.push_back(attribute); + } + } + // Loop over all the child nodes of the XML element + if (node->xmlChildrenNode != NULL) + { + xmlNodePtr curNode; + for (curNode = node->xmlChildrenNode; curNode != NULL; curNode = curNode->next) + { + if ((curNode->type == XML_ELEMENT_NODE)) + { + boost::shared_ptr<ElementXML> child(new ElementXML()); + fillElement(curNode, *child); + element.childList_.push_back(child); + } + } + } +} + +boost::optional<boost::ptr_vector<ElementXML> > XMLParser::getElementsFromXPath(const std::string& xpathExpression) const +{ + boost::optional<boost::ptr_vector<ElementXML> > elements; + // Load the XML document + const xmlDocPtr document = xmlParseFile(fileName_.c_str()); + if (document == NULL) + { + std::ostringstream message; + message << "The Parameter File " << fileName_ << " could not be parsed"; + throw SilecsException(__FILE__, __LINE__, message.str().c_str()); + } + // Create an XPath evaluation context + const xmlXPathContextPtr xpathContext = xmlXPathNewContext(document); + if (xpathContext == NULL) + { + xmlFreeDoc(document); + return elements; + } + // Evaluate the XPath expression + const xmlXPathObjectPtr xpathObject = xmlXPathEvalExpression(reinterpret_cast<const xmlChar*>(xpathExpression.c_str()), xpathContext); + if (xpathObject == NULL) + { + xmlXPathFreeContext(xpathContext); + xmlFreeDoc(document); + return elements; + } + // Loop over the node set returned by XPath + if (xmlXPathNodeSetIsEmpty(xpathObject->nodesetval) == false) + { + for (int i = 0; i < xpathObject->nodesetval->nodeNr; ++i) + { + std::auto_ptr<ElementXML> element(new ElementXML()); + fillElement(xpathObject->nodesetval->nodeTab[i], *element); + if (!elements) + { + elements = boost::ptr_vector<ElementXML>(); + } + elements->push_back(element.release()); + } + } + // Cleanup + xmlXPathFreeObject(xpathObject); + xmlXPathFreeContext(xpathContext); + xmlFreeDoc(document); + return elements; +} + +boost::ptr_vector<ElementXML> XMLParser::getElementsFromXPath_throwIfEmpty(const std::string& xpathExpression) const +{ + boost::optional<boost::ptr_vector<ElementXML> > result = getElementsFromXPath(xpathExpression); + if( !result ) + { + std::ostringstream message; + message << "The xpathExpression: '" << xpathExpression << "' did not find a match"; + throw SilecsException(__FILE__, __LINE__, message.str().c_str()); + } + if( result.get().size() == 0) + { + std::ostringstream message; + message << "The xpathExpression: '" << xpathExpression << "' returned an empty collection of xml-Elements"; + throw SilecsException(__FILE__, __LINE__, message.str().c_str()); + } + return result.get(); +} + +ElementXML XMLParser::getFirstElementFromXPath(const std::string& xpathExpression) const +{ + boost::optional<boost::ptr_vector<ElementXML> > result = getElementsFromXPath_throwIfEmpty(xpathExpression); + return result.get()[0]; +} + +xmlChar* XMLParser::ConvertInput(const char *in, const char *encoding) +{ + xmlChar *out; + int32_t ret; + int32_t size; + int32_t out_size; + int32_t temp; + xmlCharEncodingHandlerPtr handler; + + if (in == 0) + return 0; + + handler = xmlFindCharEncodingHandler(encoding); + + if (!handler) + { + std::ostringstream message; + message << "The encoding: '" << encoding << "' was not found"; + throw SilecsException(__FILE__, __LINE__, message.str().c_str()); + } + + size = (int32_t)std::strlen(in) + 1; + out_size = size * 2 - 1; + out = (unsigned char *) xmlMalloc((size_t) out_size); + + if (out == 0) + { + std::ostringstream message; + message << "Failed to convert the xml to: '" << encoding << "'"; + throw SilecsException(__FILE__, __LINE__, message.str().c_str()); + } + + temp = size - 1; + ret = handler->input(out, &out_size, (const xmlChar *) in, &temp); + if ((ret < 0) || (temp - size + 1)) + { + std::ostringstream message; + message << "Failed to convert the xml to: '" << encoding << "'"; + throw SilecsException(__FILE__, __LINE__, message.str().c_str()); + xmlFree(out); + out = 0; + } + else + { + out = (unsigned char *) xmlRealloc(out, out_size + 1); + out[out_size] = 0; /*null terminating out */ + } + + + return out; +} + +} // fesa diff --git a/silecs-communication-cpp/src/silecs-communication/interface/utility/XMLParser.h b/silecs-communication-cpp/src/silecs-communication/interface/utility/XMLParser.h new file mode 100644 index 0000000..b403b40 --- /dev/null +++ b/silecs-communication-cpp/src/silecs-communication/interface/utility/XMLParser.h @@ -0,0 +1,191 @@ +// Copyright 2016 CERN and GSI +// +// 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 3 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, see <http://www.gnu.org/licenses/>. + + +#ifndef _XMLPARSER_HPP_ +#define _XMLPARSER_HPP_ + +#include <boost/optional.hpp> +#include <boost/ptr_container/ptr_vector.hpp> +#include <boost/shared_ptr.hpp> +#include <string> +#include <vector> +#include <iostream> +#include <unistd.h> +#include <sstream> + +#include <libxml/tree.h> +#include <libxml/parser.h> +#include <libxml/xpath.h> +#include <libxml/xpathInternals.h> +#include <libxml/encoding.h> + +#include <silecs-communication/interface/utility/SilecsException.h> + +#define MY_ENCODING "UTF-8" + +namespace Silecs +{ + +/*! + * \class AttributeXML + * \brief This class represents an XML attribute containing name and value + */ +class AttributeXML +{ + public: + /*! + * \brief name_ of the attribute + */ + std::string name_; + + /*! + * \brief value_ of the attribute + */ + std::string value_; +}; + +/*! + * \class ElementXML + * \brief This class represents an XML element containing name, value, a list of attributes + * and a list of child XML elements + */ +class ElementXML +{ + public: + /*! + * \brief name of the element + */ + std::string name_; + + /*! + * \brief value of the element + */ + std::string value_; + + /*! + * \brief list of attributes of the element + */ + std::vector<boost::shared_ptr<AttributeXML> > attributeList_; + + /*! + * \brief list of children of the element + */ + std::vector<boost::shared_ptr<ElementXML> > childList_; + + bool hasAttribute(const std::string& attributeName) const + { + std::vector<boost::shared_ptr<AttributeXML> >::const_iterator attributeIter; + for(attributeIter = attributeList_.begin();attributeIter != attributeList_.end();++attributeIter) + { + if((*attributeIter)->name_ == attributeName) + { + return true; + } + } + return false; + } + + std::string getAttribute(const std::string& attributeName) const + { + std::vector<boost::shared_ptr<AttributeXML> >::const_iterator attributeIter; + for(attributeIter = attributeList_.begin();attributeIter != attributeList_.end();++attributeIter) + { + if((*attributeIter)->name_ == attributeName) + { + return (*attributeIter)->value_; + } + } + std::ostringstream message; + message << "The XML Attribute " << (*attributeIter)->name_ << " was not found"; + throw SilecsException(__FILE__, __LINE__, message.str().c_str()); + } +}; + + +/*! + * \class XMLParser + * \brief This class offers functions to extract information from an XML file. + * It uses the xPath functions of the library libXML + */ +class XMLParser +{ + public: + + /*! + * \brief constructor + * \param fileName path of the file that represents the xml element + * \param validateFile if true, file is validated + */ + XMLParser(const std::string& fileName, bool validateFile); + + /*! + * \brief destructor + */ + virtual ~XMLParser(); + + /*! + * \brief Retrieve the elements identified by the XPath expression from the XML file + * \param xpathExpression The XPath expression + */ + virtual boost::optional<boost::ptr_vector<ElementXML> > getElementsFromXPath(const std::string& xpathExpression) const; + + virtual ElementXML getFirstElementFromXPath(const std::string& xpathExpression) const; + + virtual boost::ptr_vector<ElementXML> getElementsFromXPath_throwIfEmpty(const std::string& xpathExpression) const; + + + /*! + * \brief Has to be executed from the main-thread before this class can be used + */ + static void init(); + + /*! + * \brief Has to be executed from the main-thread on shutdown + */ + static void cleanUp(); + + private: + + /*! + * \brief removes carrier return from string + * \param s the string to remove the carrier from + */ + void trimCarrierReturn(std::string& s) const; + + /*! + * \brief fills instance of the class ElementXML with nodes from an XML file + * \param node that contains the xml info + * \param [out] pElement into which the info will be put + */ + void fillElement(xmlNodePtr node, ElementXML& element) const; + + /*! + * \brief converts a char array to a xmlChar array + * \param in The char array + * \param encoding the coding format + * \return the xmlChararray + */ + xmlChar* ConvertInput(const char *in, const char *encoding); + + /*! + * \brief path of the file + */ + std::string fileName_; +}; + +} // fesa + +#endif // XML_PARSER_H_ diff --git a/silecs-communication-cpp/src/silecs-communication/protocol/core/ietype.h b/silecs-communication-cpp/src/silecs-communication/protocol/core/ietype.h new file mode 100644 index 0000000..6d07415 --- /dev/null +++ b/silecs-communication-cpp/src/silecs-communication/protocol/core/ietype.h @@ -0,0 +1,166 @@ +// Copyright 2016 CERN and GSI +// +// 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 3 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, see <http://www.gnu.org/licenses/>. + + +/* + * Revision : v1.0 + * Date : 08/2003 - F.Locci + * Objet : original version for SCHNEIDER and SIMATIC PLCs + * Action : + * + * Revision : v1.1 + * Date : 10/2003 - F.Locci + * Objet : original version for SCHNEIDER and SIMATIC PLCs + * Action : + * + * Revision : v1.2 + * Date : 10/2005 - F.Locci + * Objet : Allow absolute offset for eveyr protocol + * Action : To prevent interface modification we use + * : following convention: + * : . negative constant to use relative offset (BLK_..) + * : . positive value to use absolute offset + * + * Revision : v1.3 + * Date : 03/2007 - F.Locci + * Objet : Increase receive buffer size (MAX_DATA_REP_..) to 64kb + * Action : Increase cosntant from 21504 to 64kb to fulfill some + * : specific user requirement (BOFISOP class) - adjust timeout + * + * Revision : v1.4 + * Date : 04/2007 - F.Locci + * Objet : Prevent SIEMENS PLC disconnection + * Action : Provide Keep-Alive transaction to be called periodically + * +*/ + +#ifndef _IETYPE_H_ +#define _IETYPE_H_ + +/* ---------------------------------------------------------*/ +/* INCLUDE FILES */ +/* ---------------------------------------------------------*/ +#include <stdio.h> +#include <stdlib.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <string.h> +#include <unistd.h> +#include <netinet/in.h> +#include <netinet/tcp.h> +#include <netdb.h> +#include <arpa/inet.h> +#include <errno.h> +#ifdef __Lynx__ +#include <time.h> +#else +#include <sys/time.h> +#endif +#include <pthread.h> + +/* ---------------------------------------------------------*/ +/* LOCAL CONSTANT DEFINITIONS */ +/* ---------------------------------------------------------*/ + +/* protocol parameters */ +/*v1.1 modif. + Create individual constant for defer cmd data in order to + allow large command for fetch/write & modbus protocol. +*/ +/*v1.1 modif. (previous one, still valid) + DATA_CMD_DEFER_SIZE: 8192 --> 4096 (RFC) to support deferred + mode with S7-300 PLC. This modification was necessary to avoid + S7-341 ethernet coupler crashing when receiving to big command + defer frame. + Size = 8192 had been choosen for S7-400 ISOLDE project but is too + large for S7-300 memory. + Attention! This v1.1 modification double the number of + deferred transation with pisobeam if we recompile 'plcgenrt' process + with this new version (normally we woudln't have to do it) +*/ +#define MAX_RFC_CMD_DEFER_SIZE 4096 /*byte - see PLC code */ +#define MAX_FEW_CMD_DEFER_SIZE 16384 /*byte - no constraint on PLC side */ +#define MAX_MDB_CMD_DEFER_SIZE 16384 /*byte - no constraint on PLC side */ +#define MAX_S7_CMD_DEFER_SIZE 16384 /*byte - no constraint on PLC side */ +#define MAX_DATA_CMD_DEFER_SIZE 16384 /*byte - MUST BE the max 3 above constants*/ + +#define MAX_DATA_REP_DEFER_SIZE 65536 /*v1.3, byte - see PLC code*/ +#define MAX_DATA_REP_ASYNC_SIZE 4096 /*byte - see PLC code*/ + +/* error constant */ +// silecs internal error ................................... +// don't forget to modify IeGetErrorMessage(..) function +#define RFC_SYS_ERROR (int)-1 +#define RFC_PARAM_ERROR (int)-2 +#define RFC_CONNECT_ERROR (int)-3 +#define RFC_DISCONNECT_ERROR (int)-4 +#define RFC_TIMEOUT_ERROR (int)-5 +#define RFC_EPIPE_ERROR (int)-6 +#define RFC_FRAME_ERROR (int)-7 + +#define IE_SYS_ERROR RFC_SYS_ERROR +#define IE_PARAM_ERROR RFC_PARAM_ERROR +#define IE_CONNECT_ERROR RFC_CONNECT_ERROR +#define IE_DISCONNECT_ERROR RFC_DISCONNECT_ERROR +#define IE_TIMEOUT_ERROR RFC_TIMEOUT_ERROR +#define IE_EPIPE_ERROR RFC_EPIPE_ERROR +#define IE_FRAME_ERROR RFC_FRAME_ERROR +#define IE_DEFER_CMD_BUFFER_FULL (int)-100 +#define IE_DEFER_REP_BUFFER_EMPTY (int)-101 +#define IE_NB_MONITORING_ERROR (int)-102 +#define IE_HOST_PING_ERROR (int)-103 +#define IE_CONFIG_FILE_ERROR (int)-104 +#define IE_BLOCK_SIZE_ERROR (int)-105 +#define IE_HOST_UNKNOWN_ERROR (int)-106 + +// PLC report error ....................................... +#define IE_EQUIPMENT_UNKNOWN_ERROR (int)-200 // Class/Eqp unknow +#define IE_MEMORY_OVERFLOW_ERROR (int)-201 // get data buffer too long +#define IE_ACCESS_VIOLATION_ERROR (int)-202 // DB unknown or get/set access violation +#define IE_MD_MONITORING_ERROR (int)-203 // bad monitoring desc. or already used +#define IE_ALLOC_MONITORING_ERROR (int)-204 // monitoring record allocation failed +#define IE_UNALLOC_MONITORING_ERROR (int)-205 // monitoring record unallocation failed +#define IE_SET_TIME_IOCTL_ERROR (int)-206 // PLC date_time SET failed +#define IE_KEEP_ALIVE_IOCTL_ERROR (int)-207 // PLC keep-alive transaction failed + +/* protocol parameters */ +#define MAX_CONNECT_TIMEOUT 2 /*s */ +#define MAX_DATA_TIMEOUT 12 /*s v1.3*/ + +/* ---------------------------------------------------------*/ +/* MACRO DEFINITIONS */ +/* ---------------------------------------------------------*/ + +// Used to convert DT PLC format to/from DSC time format +// see convert functions below +#define _frombcd(a) (int)(((a>>4)*10)+(a&0x0F)) +#define _tobcd(a) (((unsigned char)((a)/10)<<4)+((a)%10)) + +/* ---------------------------------------------------------*/ +/* TYPE DEFINITIONS */ +/* ---------------------------------------------------------*/ + +/* PLCs data format ........................................*/ +typedef char _CHAR; +typedef unsigned char _BYTE; +typedef unsigned short _WORD; +typedef unsigned long _DWORD; +typedef short _INT; +typedef long _DINT; +typedef float _REAL; +typedef unsigned char _DT[8]; + + +#endif /* _IETYPE_H_ */ diff --git a/silecs-communication-cpp/src/silecs-communication/protocol/core/silecs.cpp b/silecs-communication-cpp/src/silecs-communication/protocol/core/silecs.cpp new file mode 100644 index 0000000..def46b4 --- /dev/null +++ b/silecs-communication-cpp/src/silecs-communication/protocol/core/silecs.cpp @@ -0,0 +1,360 @@ +// Copyright 2016 CERN and GSI +// +// 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 3 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, see <http://www.gnu.org/licenses/>. + + +/* + * + * Revision : v1.0 + * Date : 01/2010 - F.Locci + * Objet : Initial version - From previous Silecs-2 + * Action : + */ + +/* + * This library was developped to provide communication between + * Linux/LynxOS active host (client) and a PLC passive server. + * Based on S7 or MODBUS std. protocole, it defines generic + * set and get functions to read and write data into/from PLC + * memory. + * + */ + +/* ---------------------------------------------------------*/ +/* INCLUDE FILES */ +/* ---------------------------------------------------------*/ +#include <fcntl.h> +#include <signal.h> + +#include <silecs-communication/protocol/core/silecs.h> + +#ifdef __cplusplus +extern "C" { +#endif + +/* ---------------------------------------------------------*/ +/* MACRO DEFINITION */ +/* ---------------------------------------------------------*/ + +/* This macro is used to trap the unexpected broken pipe and + return an error instead of exit process. +*/ +static __sighandler_t sigpipeHandler = (__sighandler_t)-1; +#define _DISABLE_SIGPIPE sigpipeHandler = signal(SIGPIPE, SIG_IGN) +#define _ENABLE_SIGPIPE signal(SIGPIPE, sigpipeHandler) + +/*----------------------------------------------------------*/ +/* Time funtion + * IeRfcSetTime: Convert lynxos time_t format to PLC _DT format + * (SIMATIC). + * + * Details: + * PLC DATE_AND_TIME (or DT) format is coded on 8 byte in BCD + * format: + * 0 1 2 3 4 5 6 7 + * YY MM DD HH MN SC SC/100 SC/10e4 + */ +void IeRfcSetTime(unsigned char *dt, time_t epoch) // to PLC +{ + struct tm *dscst; + dscst = localtime(&epoch); + + dt[7] = 0; // not used at the moment + dt[6] = 0; // not used at the moment + dt[5] = _tobcd(dscst->tm_sec); + dt[4] = _tobcd(dscst->tm_min); + dt[3] = _tobcd(dscst->tm_hour); + dt[2] = _tobcd(dscst->tm_mday); + dt[1] = _tobcd(dscst->tm_mon+1); + dt[0] = _tobcd(dscst->tm_year-100); +} + +/*----------------------------------------------------------*/ +/* Time funtion + * IeRfcGetTime: Convert PLC _DT format to time_t format (SIMATIC). + * + * Details: + * PLC DATE_AND_TIME (or DT) format is coded on 8 byte in BCD + * format: + * 0 1 2 3 4 5 6 7 + * YY MM DD HH MN SC SC/100 SC/10e4 + */ +double IeRfcGetTime(unsigned char *dt) // from PLC +{ + struct tm plcst; + time_t plctm; + double ms; + int year; + + plcst.tm_sec = _frombcd(dt[5]); + plcst.tm_min = _frombcd(dt[4]); + plcst.tm_hour = _frombcd(dt[3]); + plcst.tm_mday = _frombcd(dt[2]); + plcst.tm_mon = _frombcd(dt[1])-1; + year = _frombcd(dt[0]); + //look at Siemens DATA_AND_TIME type documentation + plcst.tm_year = ((year >= 90) ? year : year+100); + + ms = ((double)_frombcd(dt[6])/100.)+((double)_frombcd(dt[7])/10000.); + plcst.tm_isdst = -1; // daylight saving time unavailable + plctm = mktime(&plcst); + + return((double)plctm + ms); +} + +/*----------------------------------------------------------*/ +/* This is a function used to connect an host on a port. + * 'ip' is the ip address string + * 'port' is the port number (102 for rfc1006 server) + * 'dst' is the TSAP destination string (exp: "TCP-1") + * 'src' is the TSAP source string (exp: "TCP-1") + * 'ts' timeout in second (1s minimum) + * return a socket descriptor or <0 on error + * (see constant error) + * + * Details: + * intermediate connect_nonb() function is used to perform a non-blockant connection. + * intermediate rfcPing() function is used to check if PLC is ON + */ +int connect_nonb(int sockfd, struct sockaddr *saptr, socklen_t salen, int nsec) +{ + int flags, n, error; + socklen_t len; + fd_set rset, wset; + struct timeval tval; + + flags = fcntl(sockfd, F_GETFL, 0); + fcntl(sockfd, F_SETFL, flags | O_NONBLOCK); + + error = 0; + /*v1.1*/ + _DISABLE_SIGPIPE; + n = connect(sockfd, (struct sockaddr *) saptr, salen); + _ENABLE_SIGPIPE; + if (n < 0){ + if (errno != EINPROGRESS) + return(-1); + } + + /* Do whatever we want while the connect is taking place. */ + + if (n == 0) + goto done; /* connect completed immediately */ + + FD_ZERO(&rset); + FD_SET(sockfd, &rset); + wset = rset; + tval.tv_sec = nsec; + tval.tv_usec = 0; + + if ( (n = select(sockfd+1, &rset, &wset, NULL, + nsec ? &tval : NULL)) == 0) { + close(sockfd); /* timeout */ + errno = ETIMEDOUT; + return(-1); + } + + if (FD_ISSET(sockfd, &rset) || FD_ISSET(sockfd, &wset)) { + len = sizeof(error); + if (getsockopt(sockfd, SOL_SOCKET, SO_ERROR, &error, &len) < 0) { + return(-1); /* Solaris pending error */ + } + } + +done: + fcntl(sockfd, F_SETFL, flags); /* restore file status flags */ + + if (error) { + /*close(sockfd); just in case */ + errno = error; + return(-1); + } + + return(0); +} + +/*----------------------------------------------------------*/ +int rfcPing(char *ip, long ts) +{ + int err, s, val = 1; + struct protoent *pent; + struct sockaddr_in rsock; + + /* Socket create/connect */ + memset ((char *)&rsock,0,sizeof(rsock)); + + if ((s=socket(AF_INET,SOCK_STREAM,0)) == -1) + { + #ifdef COMMENT + printf("#Error - Can't create socket: %s\n", strerror(errno)); + #endif + return RFC_SYS_ERROR; + } + + /* Set TCP_NODELAY option to force immediate TCP/IP acknowledgement */ + if ((pent=getprotobyname("TCP")) == NULL) + { + #ifdef COMMENT + printf("#Error - Can't configure socket: %s\n", strerror(errno)); + #endif + return RFC_SYS_ERROR; + } + if (setsockopt(s,pent->p_proto,TCP_NODELAY,&val,4) == -1) + { + #ifdef COMMENT + printf("#Error - Can't configure socket: %s\n", strerror(errno)); + #endif + return RFC_SYS_ERROR; + } + + #ifdef COMMENT + printf("#Comment - Socket created: %i\n", s); + #endif + + rsock.sin_addr.s_addr=inet_addr(ip); + rsock.sin_family=AF_INET; + /*check any port to detect if the host is OFF*/ + rsock.sin_port=htons(102); + + err = 0; + if (connect_nonb(s,(struct sockaddr *)(&rsock),sizeof(rsock), ts) == -1) + { + /*if hostname is OFF, connect() fails on TIMEOUT*/ + if ((errno == ETIMEDOUT) || (errno == EHOSTDOWN) || (errno == EHOSTUNREACH)) { + err = RFC_TIMEOUT_ERROR; + } + } + + close(s); + return err; +} + +/*..........................................................*/ +int IeRfcPing (char *hostName, char *plcIP) +{ + struct in_addr addr; + struct hostent *hp; + char *ipstr = plcIP; + + if ((hostName == NULL) && (plcIP == NULL)) + return(IE_PARAM_ERROR); + + // use hostName reference in priority else plcIP + if (hostName) + { + hp = gethostbyname(hostName); + if (hp) + { + addr.s_addr = *((unsigned long int *) hp->h_addr); + ipstr = inet_ntoa(addr); + } + } + + if (ipstr == NULL) + return(IE_HOST_UNKNOWN_ERROR); + + /*trying to connect PLC (1 second max)*/ + return (rfcPing(ipstr, 1)); +} + +/*----------------------------------------------------------*/ +/* This function return the string which describes the + * error given by 'error' parameter. + * 'error': error from ie library or PLC server (in) + * return string pointer + * + * Details: + */ +char *IeGetErrorMessage(int err) +{ + int i; + + static struct + { + int ie_code; + char * ie_mes; + } errorMap[] = + { + {IE_SYS_ERROR, "[RFC lib.] function system error"}, + {IE_PARAM_ERROR, "[IE/RFC lib.] bad parameter(s) value/format"}, + {IE_CONNECT_ERROR, "[RFC lib.] PLC connection failed"}, + {IE_DISCONNECT_ERROR, "[RFC lib.] PLC disconnection requested"}, + {IE_TIMEOUT_ERROR, "[RFC lib.] communication (connect/send/recv) timeout occurred"}, + {IE_EPIPE_ERROR, "[RFC lib.] PLC communication broken"}, + {IE_FRAME_ERROR, "[RFC lib.] PLC data frame error"}, + {IE_DEFER_CMD_BUFFER_FULL, "[IE lib.] deferred commands buffer overflow"}, + {IE_DEFER_REP_BUFFER_EMPTY, "[IE lib.] deferred replies empty"}, + {IE_BLOCK_SIZE_ERROR, "[IE lib.] block size exceed PLC memory allocation"}, + {IE_NB_MONITORING_ERROR, "[IE lib.] monitoring descriptor out of limit"}, + {IE_HOST_PING_ERROR, "[IE lib.] PLC does not reply to ping"}, + {IE_HOST_UNKNOWN_ERROR, "[IE lib.] PLC hostname unknown"}, + {IE_CONFIG_FILE_ERROR, "[IE lib.] pair PLC/FEC not found in the config. file"}, + {IE_EQUIPMENT_UNKNOWN_ERROR, "[PLC] equipment id (devclass+eqp) unknown"}, + {IE_MEMORY_OVERFLOW_ERROR, "[PLC] get data buffer overflow"}, + {IE_ACCESS_VIOLATION_ERROR, "[PLC] DB unknown or get/set access violation"}, + {IE_MD_MONITORING_ERROR, "[PLC] bad monitoring descriptor or already used"}, + {IE_ALLOC_MONITORING_ERROR, "[PLC] monitoring record allocation failed"}, + {IE_UNALLOC_MONITORING_ERROR, "[PLC] monitoring record unallocation failed"}, + {IE_SET_TIME_IOCTL_ERROR, "[PLC] PLC date and time setting failed"}, + {IE_KEEP_ALIVE_IOCTL_ERROR, "[PLC] PLC keep-alive transactions failed"}, + }; + + static int errorMapSize = sizeof(errorMap)/sizeof(errorMap[0]); + + if (err == 0) + return ("No error"); + + for (i=0; i<errorMapSize; i++) + if (errorMap[i].ie_code == err) + return (errorMap[i].ie_mes); + + return ("Unknown IE error"); +} + +/*----------------------------------------------------------*/ +/* This function initializes the DSC-PLC communication. + * return 0 or <0 on error (see constant error) + * + * Details: + * Must be executed at first. + */ +int IeInit (void) +{ + int err=0; + + err |= IeMdbInit(); + + return (err); +} + +/*----------------------------------------------------------*/ +/* This function de-initializes the DSC-PLC communication. + * return 0 or <0 on error (see constant error) + * + * Details: + * Must be executed at end. + */ +int IeExit (void) +{ + int err=0; + + err |= IeMdbExit(); + + return (err); +} + +#ifdef __cplusplus +} +#endif + diff --git a/silecs-communication-cpp/src/silecs-communication/protocol/core/silecs.h b/silecs-communication-cpp/src/silecs-communication/protocol/core/silecs.h new file mode 100644 index 0000000..782495b --- /dev/null +++ b/silecs-communication-cpp/src/silecs-communication/protocol/core/silecs.h @@ -0,0 +1,114 @@ +// Copyright 2016 CERN and GSI +// +// 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 3 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, see <http://www.gnu.org/licenses/>. + +/* + * + * Revision : v1.0 + * Date : 01/2010 - F.Locci + * Objet : Initial version - From previous Silecs-2 + * Action : + */ + +#ifndef _SILECS_H_ +#define _SILECS_H_ + +/* + * This library was developped to provide communication between + * Linux/LynxOS active host (client) and a PLC passive server. + * Based on S7 or MODBUS std. protocole, it defines generic + * set and get functions to read and write data into/from PLC + * memory. + * + */ + +#ifdef __cplusplus +extern "C" { +#endif + +/* ---------------------------------------------------------*/ +/* INCLUDE FILES */ +/* ---------------------------------------------------------*/ +#include "ietype.h" + +/* ---------------------------------------------------------*/ +/* PROTOTYPE DEFINITIONS */ +/* ---------------------------------------------------------*/ +#include <silecs-communication/protocol/modbus/iemdb.h> /* modbus interface */ + +/*----------------------------------------------------------*/ +/* Time funtion + * IeRfcSetTime: Convert time_t epoch date to PLC _DT format + * (SIMATIC). + * + * Details: + * PLC DATE_AND_TIME (or DT) format is coded on 8 byte in BCD + * format: + * 0 1 2 3 4 5 6 7 + * YY MM DD HH MN SC SC/100 SC/10e4 + */ +void IeRfcSetTime(unsigned char *dt, time_t epoch); // to PLC + +/*----------------------------------------------------------*/ +/* Time funtion + * IeRfcGetTime: Convert PLC _DT format to lynxOS time_t format + * (SIMATIC). + * + * Details: + * PLC DATE_AND_TIME (or DT) format is coded on 8 byte in BCD + * format: + * 0 1 2 3 4 5 6 7 + * YY MM DD HH MN SC SC/100 SC/10e4 + */ +double IeRfcGetTime(unsigned char *dt); // from PLC + +/*----------------------------------------------------------*/ +/* IeRfcPing function is a function used to check + * if PLC is ON (~ping) before trying to connect it. + */ +int IeRfcPing (char *hostName, char *plcIP); + +/*----------------------------------------------------------*/ +/* This function return the string which describes the + * error given by 'error' parameter. + * 'error': error from ie library or PLC server (in) + * return string pointer + * + * Details: + */ +char *IeGetErrorMessage(int err); + +/*----------------------------------------------------------*/ +/* This function initializes the DSC-PLC communication. + * return 0 or <0 on error (see constant error) + * + * Details: + * Must be executed at first. + */ +int IeInit (void); + +/*----------------------------------------------------------*/ +/* This function initializes the DSC-PLC communication. + * return 0 or <0 on error (see constant error) + * + * Details: + * Must be executed at end. + */ +int IeExit (void); + +#ifdef __cplusplus +} +#endif + +#endif /* _SILECS_H_ */ diff --git a/silecs-communication-cpp/src/silecs-communication/protocol/modbus/iemdb.cpp b/silecs-communication-cpp/src/silecs-communication/protocol/modbus/iemdb.cpp new file mode 100644 index 0000000..94a55b1 --- /dev/null +++ b/silecs-communication-cpp/src/silecs-communication/protocol/modbus/iemdb.cpp @@ -0,0 +1,441 @@ +// Copyright 2016 CERN and GSI +// +// 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 3 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, see <http://www.gnu.org/licenses/>. + +/* + * Revision : v1.0 + * Date : 08/2003 - F.Locci + * Objet : original version for PS7-SCHNEIDER PLC + * Action : + * + * Revision : v1.1 + * Date : 05/2004 - F.Locci + * Objet : .remove when data size = 0 + * .set err on read/write error + * Look at v1.1 comments + * + * Revision : v1.2 + * Date : 11/2004 - F.Locci + * Objet : .move mb_master_init() call to IeMdbInit() function + * to make modbus code reentrant. + * Look at v1.2 comments + * + * Revision : v1.3 + * Date : 10/2004 - F.Locci + * Objet : .Allow absolute offset for read/write action + * .Allow variable size for read/write action + * => use offset sign convention for absolute/relative + * => use application size instead of config.table one + * Look at v1.3 comments + * + * Revision : v1.4 + * Date : 03/2006 - F.Locci + * Objet : .Extend the number of possible connection (7 --> 32) + * in order to allow more than 7 connections with + * DIFFERENT PLC (SPS/EA project in particular). + * We keep 7 connection for SIEMENS (F/W) protocole + * to respect material constraint (14 ISO-ON-TCP max.) + * + * Revision : v1.5 + * Date : 01/2007 - F.Locci + * Objet : implement BLOCK mode + * Action : .Add IeMdbGetBlock() and IeMdbSetBlock() function + * .Upgrade mdbFindEqp() function + * Look at v1.5 comments + * + * Revision : v1.6 + * Date : 03/2007 - F.Locci + * Objet : Protect Get data buffer overflow + * Look at v1.5 comments + * + * Revision : v1.7 + * Date : 04/2007 - F.Locci + * Objet : Direct byte swapping into MdbSetTime function + * Look at v1.5 comments + */ + +/* + * This library was developped to provide communication between + * Linux/LynxOS active host (client) and a PLC passive server. + * Based on MODBUS std. protocole, it defines generic + * set and get functions to read and write data into/from PLC + * memory. + */ + +/* ---------------------------------------------------------*/ +/* INCLUDE FILES */ +/* ---------------------------------------------------------*/ +#include <silecs-communication/protocol/core/ietype.h> +#include "mb_addr.h" +#include "mb_master.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* ---------------------------------------------------------*/ +/* LOCAL CONSTANT DEFINITIONS */ +/* ---------------------------------------------------------*/ + +/* For Modbus protocol */ +#define MODBUS_MAX_CONNECTION 64 /*v1.4*/ +#define MODBUS_SENDRETRIES_DEF 1 +#define MODBUS_TIMEOUT_DEF 2 /* in seconds */ + +/*Config.Table entries offset - SCHNEIDER memory implementation - word alignment*/ +#define FEC_CMD_OFS 0 /* Command from FEC: first entry of cfg.table*/ +#define PARAMS_CMD_OFS 2/2 /* Params of FEC command */ +#define CURRENT_DATE_OFS 10/2 /* PLC current dat&time */ +#define SYS_INFO_OFS 18/2 /* HW/SW info variables */ +#define DIAG_INFO_OFS 78/2 /* PLC SW/HW diagnostic */ +#define NB_EQP_OFS 132/2 /*nb table row */ +#define ADDR_TBL_OFS 134/2 /*table data (addr/size)*/ + +#define swap16(w) ((((unsigned short)w & 0x00ff)<<8)+(((unsigned short)w & 0xff00)>>8)) + +/* ---------------------------------------------------------*/ +/* TYPE DEFINITIONS */ +/* ---------------------------------------------------------*/ +/* an entry in the network array */ +typedef struct +{ + const char *name; + node_addr_t addr; + int nd; /* the node descriptor... */ + struct timespec timeout; + u32 send_retries; +} network_t; + +/* ---------------------------------------------------------*/ +/* GLOBAL DECLARATIONS */ +/* ---------------------------------------------------------*/ + +/* ---------------------------------------------------------*/ +/* FUNCTIONS CODE */ +/* ---------------------------------------------------------*/ + +/*----------------------------------------------------------*/ +/* Local functions */ +/* ---------------------------------------------------------*/ + +/* Function to load a struct timeval correctly + * from a double. + */ +static inline struct timespec d_to_timespec(double time) { + struct timespec tmp; + + tmp.tv_sec = time; + tmp.tv_nsec = 1e9*(time - tmp.tv_sec); + return tmp; +} + +/*----------------------------------------------------------*/ +/* Glocal functions */ +/* ---------------------------------------------------------*/ + +/*----------------------------------------------------------*/ +/* Time funtion + * IeMdbSetTime: Convert lynxos time_t format to PLC SCHNEIDER + * format. + * + * Details: + * PLC SCHNEIER format is coded on 8 bytes BCD + * format: + * + * 0 1 2 3 4 5 6 7 + * SC 00 HH MN MM DD YY YY + * + * byte 1 is used by gateway to synchronize time setting. + */ +void IeMdbSetTime(unsigned char *dt, time_t epoch) // to PLC +{ + struct tm *dscst; + dscst = localtime(&epoch); + + /*v1.7*/ + /*In fact, each 16bits word is swapped with SCHNEIDER PLC + 1 0 3 2 5 4 7 6 + SC 00 HH MN MM DD YY YY + + Swapping can do it directly during data transferring + */ + + dt[1] = _tobcd(dscst->tm_sec); + dt[0] = 0x00; /*not used*/ + dt[3] = _tobcd(dscst->tm_hour); + dt[2] = _tobcd(dscst->tm_min); + dt[5] = _tobcd(dscst->tm_mon+1); + dt[4] = _tobcd(dscst->tm_mday); + dt[7] = _tobcd(2000/100); + dt[6] = _tobcd(dscst->tm_year-100); +} + +/*----------------------------------------------------------*/ +/* Time funtion + * IeMdbGetTime: Convert PLC SCHNEIDER format to time_t format. + * + * Details: + * PLC SCHNEIER format is coded on 8 bytes BCD + * format: + * + * 0 1 2 3 4 5 6 7 + * SC SC/100 HH MN MM DD YY YY + * + */ +double IeMdbGetTime(unsigned char *dt) // from PLC +{ + struct tm plcst; + time_t plctm; + double ms; + int year; + + /*In fact, each 16bits word is swapped with SCHNEIDER PLC + 1 0 3 2 5 4 7 6 + SC SC/100 HH MN MM DD YY YY + + Swapping can do it directly during data transferring + */ + + plcst.tm_sec = _frombcd(dt[1]); + plcst.tm_hour = _frombcd(dt[3]); + plcst.tm_min = _frombcd(dt[2]); + plcst.tm_mon = _frombcd(dt[5])-1; + plcst.tm_mday = _frombcd(dt[4]); + year = _frombcd(dt[6]); + //look at Schneider DATA_AND_TIME type documentation + plcst.tm_year = ((year >= 90) ? year : year+100); + /*plcst.tm_wday = no used in PLC*/ + /*plcst.tm_yday = no used in PLC*/ + + ms = ((double)_frombcd(dt[0])/100.); + plcst.tm_isdst = -1; // daylight saving time unavailable + plctm = mktime(&plcst); + + return((double)plctm + ms); +} + +/*----------------------------------------------------------*/ +/* This function initializes the DSC-PLC communication. + * return 0 or <0 on error (see constant error) + * + * Details: + * Must be executed at first. + */ +int IeMdbInit (void) +{ + /*v1.2*/ + if (mb_master_init(MODBUS_MAX_CONNECTION) < 0) + { + #ifdef DEBUG + /* could not init network! */ + printf("\n#Error: mb_master_init() failed"); + #endif + return (IE_SYS_ERROR); + } + + return 0; +} + +/*----------------------------------------------------------*/ +/* This function de-initializes the DSC-PLC communication. + * return 0 or <0 on error (see constant error) + * + * Details: + * Must be executed at end. + */ +int IeMdbExit (void) +{ + mb_master_done(); + return 0; +} + +/*----------------------------------------------------------*/ +/* This function creates a synchronous OSI-ON-TCP socket + * channel used for sending/receiving communication with PLC. + * 'hostName': Name of the host (in) + * 'plcIP': PLC ip address string (in) + * return socket descriptor or <0 on error (see const. error) + * + * Details: + * 'plcIP' parameter is necessary only when 'hostName' is NULL. + * Only one synchronous channel per PLC at the same time + * supported in that version. + */ +int IeMdbOpen (char *hostName, char *plcIP, int baseAddress) +{ + network_t net; + char *ipstr = plcIP; + _WORD dummy; + + // use hostName reference in priority else plcIP + if (hostName) ipstr = hostName; + + if (ipstr == NULL) + { + printf("#Error: ipstr NULL\n"); + return(IE_PARAM_ERROR); + } + + /* init network .........................................*/ + /*net.name = not used here*/ + net.addr.naf = naf_tcp; + net.addr.addr.tcp.host = ipstr; + net.addr.addr.tcp.service = "502"; //specific modbus + net.addr.addr.tcp.close_on_silence = 1; // TRUE + net.timeout = d_to_timespec(MODBUS_TIMEOUT_DEF); + net.send_retries = MODBUS_SENDRETRIES_DEF; + + /* connection ......................................*/ + if ( (net.nd = mb_master_connect(net.addr)) >= 0) + { + /*Try to access PLC memory, just to confirm modbus connection (for example, + read config. table address. + */ + if (read_bdata( + 1, /*int slave,*/ + baseAddress/2, /*int start_addr (/2 is used to convert the byte alignment to 16bit alignment) */ + sizeof(dummy), /*int byte count,*/ + (_BYTE *)&dummy, /*uchar *dest,*/ + net.nd, /*int ttyfd,*/ + net.send_retries, /*int send_retries,*/ + &net.timeout /*const struct timespec *response_timeout*/ + ) >= 0) + { + /* node opened successfully! */ + #ifdef DEBUG + printf("Connecting to network %s: OK\n", net.addr.addr.tcp.host); + #endif + + return (net.nd); + } + #ifdef DEBUG + else + { + /* could not read registers from slave! */ + printf("#Error: could not establish connection to %s\n", net.addr.addr.tcp.host); + } + #endif + + mb_master_close(net.nd); + } + #ifdef DEBUG + else + { + /* could not connect to slave! */ + printf("#Error: could not establish connection to %s\n", net.addr.addr.tcp.host); + } + #endif + + return(IE_CONNECT_ERROR); +} + +/*----------------------------------------------------------*/ +int IeMBwriteData(int cid, _WORD dataOfs, _WORD dataSize, _BYTE* dataBuffer) +{ + int err; + network_t net; + + /* init network .........................................*/ + net.timeout = d_to_timespec(MODBUS_TIMEOUT_DEF); + net.send_retries = MODBUS_SENDRETRIES_DEF; + + /*then SET&DATE cmd into command word*/ + if (write_bdata(1, /*int slave,*/ + dataOfs, /*int start_addr (!16 bits alignment)*/ + dataSize, /*int byte count */ + dataBuffer, /*uchar *src */ + cid, /*int connection id */ + net.send_retries, /*int send_retries,*/ + &net.timeout /*const struct timespec *response_timeout*/ + ) >= 0) + { + #ifdef DEBUG + printf("IeMBwriteData has been done successfully\n"); + #endif + err = 0; /*no problem*/ + } + else + { + #ifdef DEBUG + printf("#Error on IeMBwriteData\n"); + #endif + err = IE_EPIPE_ERROR; + } + + return err; +} + +/*----------------------------------------------------------*/ +int IeMBreadData(int cid, _WORD dataOfs, _WORD dataSize, _BYTE* dataBuffer) +{ + int err; + network_t net; + + /* init network .........................................*/ + net.timeout = d_to_timespec(MODBUS_TIMEOUT_DEF); + net.send_retries = MODBUS_SENDRETRIES_DEF; + + /*unusefull to read empty data buffer*/ + if (dataSize > 0) + { + err = read_bdata(1, /*int slave,*/ + dataOfs, /*int start_addr (!16 bits alignment)*/ + dataSize, /*int byte count */ + dataBuffer, /*uchar *src */ + cid, /*int connection id */ + net.send_retries, /*int send_retries,*/ + &net.timeout /*const struct timespec *response_timeout*/ + ); + } + + if ((dataSize == 0) || (err >= 0)) + { + #ifdef DEBUG + printf("IeMBreadData has been done successfully\n"); + #endif + err = 0; /*no problem*/ + } + else + { + #ifdef DEBUG + printf("#Error on IeMBreadData\n"); + #endif + err = IE_EPIPE_ERROR; + } + + return err; +} + +/*----------------------------------------------------------*/ +/* This function closes the synchronous OSI-ON-TCP socket + * channel. + * 'sk': socket descriptor (in) - MUST BE a synch. pipe + * return 0 or <0 on error (see constant error) + * + * Details: + */ +int IeMdbClose(int cid) +{ + int err = 0; + + err |= mb_master_close(cid); + + if (err != 0) err = IE_DISCONNECT_ERROR; + return(err); +} + +#ifdef __cplusplus +} +#endif + diff --git a/silecs-communication-cpp/src/silecs-communication/protocol/modbus/iemdb.h b/silecs-communication-cpp/src/silecs-communication/protocol/modbus/iemdb.h new file mode 100644 index 0000000..8a055c7 --- /dev/null +++ b/silecs-communication-cpp/src/silecs-communication/protocol/modbus/iemdb.h @@ -0,0 +1,156 @@ +// Copyright 2016 CERN and GSI +// +// 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 3 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, see <http://www.gnu.org/licenses/>. + +/* + * Revision : v1.0 + * Date : 08/2003 - F.Locci + * Objet : original version for PS7-SCHNEIDER PLC + * Action : + * + * Revision : v1.5 + * Date : 01/2007 - F.Locci + * Objet : implement BLOCK mode + * Action : Add IeMdbGetBlock() and IeMdbSetBlock() function + * Look at v1.5 comments + * + */ + +#ifndef _IEMDB_H_ +#define _IEMDB_H_ + +/* + * This library was developped to provide communication between + * Linux/LynxOS active host (client) and a PLC passive server. + * Based on MODBUS std. protocole, it defines generic + * set and get functions to read and write data into/from PLC + * memory. + */ + +/* ---------------------------------------------------------*/ +/* LOCAL CONSTANT DEFINITIONS */ +/* ---------------------------------------------------------*/ + +/* ---------------------------------------------------------*/ +/* TYPE DEFINITIONS */ +/* ---------------------------------------------------------*/ + +/* ---------------------------------------------------------*/ +/* PROTOTYPE DEFINITIONS */ +/* ---------------------------------------------------------*/ + +#ifdef __cplusplus +extern "C" { +#endif + +/*----------------------------------------------------------*/ +/* Time funtion + * IeMdbSetTime: Convert time_t epoch date to PLC SCHNEIDER + * format. + * + * Details: + * PLC SCHNEIER format is coded on 8 bytes BCD + * format: + * + * 0 1 2 3 4 5 6 7 + * SC -- HH MN MM DD YY YY + * + * byte 1 is used by gateway to synchronize time setting. + */ +void IeMdbSetTime(unsigned char *dt, time_t epoch); // to PLC + +/*----------------------------------------------------------*/ +/* Time funtion + * IeMdbGetTime: Convert PLC SCHNEIDER format to lynxOS + * time_t format. + * + * Details: + * PLC SCHNEIER format is coded on 8 bytes BCD + * format: + * + * 0 1 2 3 4 5 6 7 + * SC SC/100 HH MN MM DD YY YY + * + */ +double IeMdbGetTime(unsigned char *dt); // from PLC + +/*----------------------------------------------------------*/ +/* This function initializes the DSC-PLC communication. + * return 0 or <0 on error (see constant error) + * + * Details: + * Must be executed at first. + */ +int IeMdbInit (void); + +/*----------------------------------------------------------*/ +/* This function initializes the DSC-PLC communication. + * return 0 or <0 on error (see constant error) + * + * Details: + * Must be executed at end. + */ +int IeMdbExit (void); + +/*----------------------------------------------------------*/ +/* This function creates a synchronous OSI-ON-TCP socket + * channel used for sending/receiving communication with PLC. + * 'hostName': Name of the host (in) + * 'plcIP': PLC ip address string (in) + * return socket descriptor or <0 on error (see const. error) + * + * Details: + * 'plcIP' parameter is necessary only when 'hostName' is NULL. + * Only one synchronous channel per PLC at the same time + * supported in that version. + */ +int IeMdbOpen (char *hostName, char *plcIP, int baseAddress); + +/*----------------------------------------------------------*/ +/* This function send a data segment to the PLC using the + * MODBUS protocole. + * 'cid': write channel id of the MB connection + * 'dataOfs': target adress of the data segment within the PLC memory + * 'dataSize': byte size of the data segment to be sent + * 'dataBuffer': buffer of the data to be sent + * return 0 or <0 on error (see constant error) + */ +int IeMBwriteData(int cid, _WORD dataOfs, _WORD dataSize, _BYTE* dataBuffer); + +/*----------------------------------------------------------*/ +/* This function read a data segment from the PLC using the + * MODBUS protocole. + * 'cid': read channel id of the MB connection + * 'dataOfs': adress of the data segment within the PLC memory + * 'dataSize': byte size of the data segment to be read + * 'dataBuffer': buffer to store the data + * return 0 or <0 on error (see constant error) + */ +int IeMBreadData(int cid, _WORD dataOfs, _WORD dataSize, _BYTE* dataBuffer); + +/*----------------------------------------------------------*/ +/* This function closes the synchronous OSI-ON-TCP socket + * channel. + * 'cid1': connection id (in) - MUST BE a synch. pipe + * return 0 or <0 on error (see constant error) + * + * Details: + */ +int IeMdbClose(int cid); + +#ifdef __cplusplus +} +#endif + +#endif /* _IEMDB_H_ */ diff --git a/silecs-communication-cpp/src/silecs-communication/protocol/modbus/mb_addr.h b/silecs-communication-cpp/src/silecs-communication/protocol/modbus/mb_addr.h new file mode 100644 index 0000000..3536396 --- /dev/null +++ b/silecs-communication-cpp/src/silecs-communication/protocol/modbus/mb_addr.h @@ -0,0 +1,111 @@ +/* + * (c) 2002 Mario de Sousa + * + * Offered to the public 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. + * + * This code is made available on the understanding that it will not be + * used in safety-critical situations without a full and competent review. + */ + + +#ifndef MODBUS_LAYER2_H +#define MODBUS_LAYER2_H + +/*F.Locci #include <plc.h>*/ /* get the plc data types */ +#include <time.h> /* struct timespec data type */ + +/*F.Locci - 28/10/2003*/ +/*types only defined with linux version: <asm/types.h>*/ +#ifndef __Lynx__ +#include <asm/types.h> + +typedef unsigned char u8; +typedef unsigned short u16; +typedef unsigned int u32; + +#else + +typedef unsigned char u8; +typedef unsigned short u16; +typedef unsigned int u32; + +#ifndef __ppc4__ /*new <socket.h> with ppc4 environment*/ +/*F.Locci - 03/11/2004, add x86 platform support*/ +#ifndef __x86__ +typedef unsigned short int sa_family_t; + +/* The following constants should be used for the second parameter of + `shutdown'. */ +enum +{ + SHUT_RD = 0, /* No more receptions. */ +#define SHUT_RD SHUT_RD + SHUT_WR, /* No more transmissions. */ +#define SHUT_WR SHUT_WR + SHUT_RDWR /* No more receptions or transmissions. */ +#define SHUT_RDWR SHUT_RDWR +}; +#endif +#endif + +/*constant conversion for LynxOS*/ +#define AF_ROSE 11 +#define AF_X25 9 +#define AF_AX25 3 +#define SOL_TCP 6 +#define SOL_IP 0 +#endif + +typedef enum {optimize_speed, optimize_size} optimization_t; + + +typedef enum { + naf_ascii, + naf_rtu, + naf_tcp, + } node_addr_family_t; + +typedef struct { + const char *host; + const char *service; + int close_on_silence; + } node_addr_tcp_t; + +typedef struct { + const char *device; + int baud; /* plain baud rate, eg 2400; zero for the default 9600 */ + int parity; /* 0 for none, 1 for odd, 2 for even */ + int data_bits; + int stop_bits; + int ignore_echo; /* 1 => ignore echo; 0 => do not ignore echo */ + } node_addr_rtu_t; + +typedef node_addr_rtu_t node_addr_ascii_t; + +typedef union { + node_addr_ascii_t ascii; + node_addr_rtu_t rtu; + node_addr_tcp_t tcp; + } node_addr_common_t; + +typedef struct { + node_addr_family_t naf; + node_addr_common_t addr; + } node_addr_t; + +#endif /* MODBUS_LAYER2_H */ + + + + + + + + diff --git a/silecs-communication-cpp/src/silecs-communication/protocol/modbus/mb_layer1.h b/silecs-communication-cpp/src/silecs-communication/protocol/modbus/mb_layer1.h new file mode 100644 index 0000000..9a33508 --- /dev/null +++ b/silecs-communication-cpp/src/silecs-communication/protocol/modbus/mb_layer1.h @@ -0,0 +1,127 @@ +/* + * (c) 2001 Mario de Sousa + * + * Offered to the public 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. + * + * This code is made available on the understanding that it will not be + * used in safety-critical situations without a full and competent review. + * + * Revision : v1.0 + * Date : 11/2004 - F.Locci + * Objet : move global recv_buf_ to local one into read/write_bdata() + * to make module reentrant. + * Look at v1.0 comment + */ + + +#ifndef MODBUS_LAYER1_H +#define MODBUS_LAYER1_H + +#ifdef __cplusplus +extern "C" { +#endif + +/*F.Locci #include <plc.h>*/ /* get the plc data types */ +#include <time.h> /* struct timespec data type */ + +#include "mb_addr.h" /* get definitions of common variable types */ + + + /* write a modbus frame */ + /* WARNING: when calling this functio, the *frame_data buffer + * must be allocated with an extra *extra_bytes + * beyond those required for the frame_length. + * This is because the extra bytes will be used + * to store the crc before sending the frame. + * + * The *extra_bytes value will be returned by the + * modbus_init() function call. + */ + /* NOTE: calling this function will flush the input stream, + * which means any frames that may have arrived + * but have not yet been read using modbus_read() + * will be permanently lost... + */ +int modbus_write(int nd, + u8 *frame_data, + size_t frame_length, + u16 transaction_id); + + /* read a modbus frame */ + /* NOTE: calling modbus_write() will flush the input stream, + * which means any frames that may have arrived + * but have not yet been read using modbus_read() + * will be permanently lost... + * + * NOTE: Ususal select semantics for (a: recv_timeout == NULL) and + * (b: *recv_timeout == 0) also apply. + * + * (a) Indefinite timeout + * (b) Try once, and and quit if no data available. + */ +int modbus_read(int *nd, /* node descriptor */ + u8 *recv_data_ptr/*v1.0*/, + u16 *transaction_id, + u8 *send_data, /* ignored ! */ + int send_length, /* ignored ! */ + const struct timespec *recv_timeout); + + + /* init the library */ +int modbus_init(int nd_count, /* maximum number of nodes... */ + optimization_t opt, + int *extra_bytes); + + /* shutdown the library...*/ +int modbus_done(void); + + +/* Open a node for master / slave operation. + * Returns the node descriptor, or -1 on error. + */ +int modbus_connect(node_addr_t node_addr); +int modbus_listen(node_addr_t node_addr); + +/* Close a node, needs a node descriptor as argument... */ +int modbus_close(int nd); + +/* Tell the library that the user will probably not be communicating + * for some time... + * This will allow the library to release any resources it will not + * be needing during the silence. + * NOTE: This is onlyused by the TCP version to close down tcp connections + * when the silence will going to be longer than second. + */ +int modbus_silence_init(void); + + /* determine the minmum acceptable timeout... */ + /* NOTE: timeout values passed to modbus_read() lower than the value returned + * by this function may result in frames being aborted midway, since they + * take at least modbus_get_min_timeout() seconds to transmit. + */ +double modbus_get_min_timeout(int baud, + int parity, + int data_bits, + int stop_bits); + + +#ifdef __cplusplus +} +#endif + +#endif /* MODBUS_LAYER1_H */ + + + + + + + + diff --git a/silecs-communication-cpp/src/silecs-communication/protocol/modbus/mb_master.cpp b/silecs-communication-cpp/src/silecs-communication/protocol/modbus/mb_master.cpp new file mode 100644 index 0000000..e443601 --- /dev/null +++ b/silecs-communication-cpp/src/silecs-communication/protocol/modbus/mb_master.cpp @@ -0,0 +1,483 @@ +/* mb_master.c + + By P.Costigan email: phil@pcscada.com.au http://pcscada.com.au + + These library of functions are designed to enable a program send and + receive data from a device that communicates using the Modbus protocol. + + Copyright (C) 2000 Philip Costigan P.C. SCADA LINK PTY. LTD. + + 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., 675 Mass Ave, Cambridge, MA 02139, USA. + + + The functions included here have been derived from the + Modicon Modbus Protocol Reference Guide + which can be obtained from Schneider at www.schneiderautomation.com. + + This code has its origins with + paul@pmcrae.freeserve.co.uk (http://www.pmcrae.freeserve.co.uk) + who wrote a small program to read 100 registers from a modbus slave. + + I have used his code as a catalist to produce this more functional set + of functions. Thanks paul. + + + + 10/2001 - Mario de Sousa + Slightly re-organized the code. + Miscelaneous cleanups + Removed layer1 functions (i.e. write and read to /dev/ttySx) + Added support for transaction id + + TODO + add retries at layer2 (i.e. in this file) + check response frame for correctness +* +* +* Revision : v1.0 +* Date : 11/2004 - F.Locci +* Objet : .remove static prefix into modbus_tcp_write() declaration +* to make code reentrant. +* .move global recv_buf_ to local one into read/write_bdata() +* Look at v1.0 comments +* +* Revision : v2.0 +* Date : 11/2006 - F.Locci +* Objet : swap16 bits from SILECS client instead of application level +* Look at v2.0 comments +*/ + +#include <fcntl.h> /* File control definitions */ +#include <stdio.h> /* Standard input/output */ +#include <string.h> +#include <stdlib.h> +#include <termio.h> /* POSIX terminal control definitions */ +#include <time.h> /* Time structures for select() */ +#include <unistd.h> /* POSIX Symbolic Constants */ +#include <errno.h> /* Error definitions */ + +#include <netinet/in.h> /* required for htons() and ntohs() */ +#include "mb_layer1.h" +#include "mb_master.h" +#include "mb_master_private.h" +/*v1.0*/ +#include "mb_tcp_private.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* #define DEBUG */ /* uncomment to see the data sent and received */ + + +#ifndef TRUE +#define TRUE 1 +#endif + +#ifndef FALSE +#define FALSE 0 +#endif + + +/******************************************/ +/******************************************/ +/** **/ +/** Global Variables... **/ +/** **/ +/******************************************/ +/******************************************/ + +/*v1.0 +static u8 *query_buffer_ = NULL; +*/ +#ifndef __Lynx__ +#if RECV_BUFFER_SIZE < 5 //TCP_HEADER_LENGTH +#error The receive buffer is smaller than the frame header length. +#endif +#endif +/**/ + +/******************************************/ +/******************************************/ +/** **/ +/** Local Utility functions... **/ +/** **/ +/******************************************/ +/******************************************/ + + +/* + * Function to determine next transaction id. + * + * We use a library wide transaction id, which means that we + * use a new transaction id no matter what slave to which we will + * be sending the request... + */ +static inline u16 next_transaction_id(void) { + + static u16 next_id = 0; + + return next_id++; +} + + +/* + * Functions to convert u16 variables + * between network and host byte order + * + * NOTE: Modbus uses MSByte first, just like + * tcp/ip, so we use the htons() and + * ntoh() functions to guarantee + * code portability. + */ + +static inline u16 mb_hton(u16 h_value) { +/* return h_value; */ + return htons(h_value); +} + +static inline u16 mb_ntoh(u16 m_value) { +/* return m_value; */ + return ntohs(m_value); +} + + + +static inline u8 msb(u16 value) { +/* return Most Significant Byte of value; */ + return (value >> 8) & 0xFF; +} + +static inline u8 lsb(u16 value) { +/* return Least Significant Byte of value; */ + return value & 0xFF; +} + +#define u16_v(char_ptr) (*((u16 *)(&(char_ptr)))) + + +/*********************************************************************** + + The following functions construct the required query into + a modbus query packet. + +***********************************************************************/ + +static inline int build_query_packet(u8 slave, + u8 function, + u16 start_addr, + u16 count, + u8 *packet) +{ + packet[ 0 ] = slave, + packet[ 1 ] = function; + /* NOTE: + * Modbus uses high level addressing starting off from 1, but + * this is sent as 0 on the wire! + */ + u16_v(packet[2]) = mb_hton(start_addr - 1); + u16_v(packet[4]) = mb_hton(count); + + return 6; +} + + +/************************************************************************ + + read_bdata + + F.Locci: just read raw byte array. Take care of frame which exceeds + modbus frame std. length. + +*************************************************************************/ +/*v2.0*/ +#define swap16(w) ((((unsigned short)w & 0x00ff)<<8)+(((unsigned short)w & 0xff00)>>8)) + +int read_bdata(int slave, /* slave id */ + int start_addr, /* word pointer addr. */ + int count, /* byte count to read */ + u8 *dest, /* byte array */ + int ttyfd, /* connection id */ + int send_retries, /* number of request retries */ + const struct timespec *response_timeout) /* timeout value */ +{ + /*v1.0*/ + u8 data[RECV_BUFFER_SIZE]; + u8 packet[QUERY_BUFFER_SIZE]; + /**/ + int rl, response_length=0; + int query_length; + u16 send_transaction_id, recv_transaction_id; + u8 *destp = dest; + int global_length, length; /* word count for read */ + + /*Attention! ModBus travaille sur une zone memoire [1..n] tandis que l'espace memoire + du PLC est definie [0..n-1] => start_addr = start_addr +1 + start_addr est exprime en word pour le PLC (alignement 16bits). + */ + start_addr+=1; + + + /*'global_length' is a word counter*/ + global_length = (count/2) + (count%2); + + while(count) { + + if (count > MAX_READ_BDATA) + /*'length' is a word counter*/ + length = MAX_READ_BDATA/2; + else + /*'length' is a word counter*/ + length = (count/2) + (count%2); + + /* We must also initialize the recv_transaction_id with the same value, + * since some layer 1 protocols do not support transaction id's, so + * simply return the recv_transaction_id variable without any changes... + */ + send_transaction_id = recv_transaction_id = next_transaction_id(); + + query_length = build_query_packet(slave, 0x03, /*function*/ + start_addr, length, + packet); + if (query_length < 0) + return -1; + + if (modbus_write(ttyfd, packet, query_length, send_transaction_id) < 0 ) + return PORT_FAILURE; + + rl = modbus_read(&ttyfd, data/*v1.0*/, &recv_transaction_id, + packet, query_length, + response_timeout); + + if( rl <= 0 ) return PORT_FAILURE; + + /* first check whther we have correct transaction id */ + if (send_transaction_id != recv_transaction_id) + return PORT_FAILURE; + + if( rl > 0 ) + { rl -= 3; /*F.Locci, bug: 2->3*/ + if (count<MAX_READ_BDATA) + rl -= (count%2); + } + + if( rl > 0 ) { + memcpy(destp, (u8 *)&(data[3]), rl); + destp += rl; + start_addr += length; /*F.Locci, bug if rl = 0 */ + } + + /* start_addr += length; F.Locci, bug if rl = 0 */ + response_length += rl; + count -= rl; + } + + /*v2.0: + Independamment de son mapping memoire (Little-endian), le PLC SCHNEIDER + swap chaque mot de 16bits qu'il transmet. Cette ligne permet de redresser + les donnees pour transmettre l'image exacte du mapping memoire. Charge + a l'application ensuite d'appliquer le swapping necessaire relatif a son + "Endianness". + */ + { + int j; + u16 *wdestp = (u16 *)dest; /* for swapping 16bit */ + for(j=0; j<global_length; j++){ wdestp[j] = swap16(wdestp[j]); } + } + /**/ + + #ifdef DEBUG + { int i; + printf("read_bdata: "); + for(i=0; i<response_length; printf("%02x ", dest[i++])); + printf("\n"); + } + #endif + + return response_length; +} + +/************************************************************************* + + write_bdata + + F.Locci: just write raw byte array. Take care of frame which exceeds + modbus frame std. length. + !!byte count MUST be even value - 16 bits alignment in that PLC + +***************************************************************************/ + +int write_bdata(int slave, /* slave id */ + int start_addr, /* word pointer addr. */ + int count, /* byte count to write - MUST be even value */ + u8 *data, /* byte array */ + int ttyfd, /* connection id */ + int send_retries, /* number of request retries */ + const struct timespec *response_timeout) /* timeout value */ +{ + int byte_count; + int i, rl, response_length=0; + int query_length; + /*v1.0*/ + u8 rdata[RECV_BUFFER_SIZE]; + u8 packet[QUERY_BUFFER_SIZE]; + u16 send_transaction_id, recv_transaction_id; + int length; /* word count */ + u8 *destp, *srcp = data; + + /*Attention! ModBus travaille sur une zone memoire [1..n] tandis que l'espace memoire + du PLC est definie [0..n-1] => start_addr = start_addr +1 + start_addr est exprime en word pour le PLC (alignement 16bits). + */ + start_addr+=1; + + while(count) { + + if (count > MAX_WRITE_BDATA) + { + /*'length' is a word counter*/ + length = MAX_WRITE_BDATA/2; + } + else + { + /*'length' is a word counter*/ + length = (count/2) + (count%2); + } + + /* We must also initialize the recv_transaction_id with the same value, + * since some layer 1 protocols do not support transaction id's, so + * simply return the recv_transaction_id variable without any changes... + */ + send_transaction_id = recv_transaction_id = next_transaction_id(); + + query_length = build_query_packet(slave, 0x10 /* function */, + start_addr, length, + packet); + if (query_length < 0) + return -1; + + byte_count = (length * 2); + packet[ query_length ] = byte_count; + + destp = &(packet[ ++query_length ]); + memcpy(destp, srcp, byte_count-(count%2)); + + /*v2.0: + Independamment de son mapping memoire (Little-endian), le PLC SCHNEIDER + swap chaque mot de 16bits qu'il transmet. Cette ligne permet de redresser + les donnees pour transmettre l'image exacte du mapping memoire. Charge + a l'application ensuite d'appliquer le swapping necessaire relatif a son + "Endianness". + */ + { + u16 *wdestp = (u16 *)destp; + for(i=0; i<length; i++){ wdestp[i] = swap16(wdestp[i]); } + } + /**/ + + srcp += byte_count-(count%2); + query_length += byte_count; + + if( modbus_write( ttyfd, packet, query_length, send_transaction_id) < 0 ) + return PORT_FAILURE; + + rl = modbus_read(&ttyfd, rdata/*v1.0*/, &recv_transaction_id, + packet, query_length, response_timeout); + + if( rl <= 0 ) return PORT_FAILURE; + + /* first check whther we have correct transaction id */ + if (send_transaction_id != recv_transaction_id) + return PORT_FAILURE; + + start_addr += length; + response_length += byte_count; + count -= (byte_count - (count%2)); + } + + return response_length; +} + +/************************************************************************ + + initialise / shutdown the library + + These functions sets up/shut down the library state + (allocate memory for buffers, initialise data strcutures, etc) + +**************************************************************************/ + +int mb_master_init(int nd_count) { + int extra_bytes; + +#ifdef DEBUG + fprintf( stderr, "mb_master_init()\n"); + fprintf( stderr, "creating %d nodes\n", nd_count); +#endif + + /* initialise layer 1 library */ + if (modbus_init(nd_count, DEF_OPTIMIZATION, &extra_bytes) + < 0) + goto error_exit_0; + + /*v1.0 initialise send buffer + query_buffer_ = (u8 *)malloc(QUERY_BUFFER_SIZE + extra_bytes); + if (query_buffer_ == NULL) + goto error_exit_1; + */ + + return 0; + +error_exit_0: + return -1; +} + + +int mb_master_done(void) { +/*v1.0 + free(query_buffer_); + query_buffer_ = NULL; +*/ + return modbus_done(); +} + +/************************************************************************ + + open/close master connection + + This function opens/closes a connection to the remote slave. + +**************************************************************************/ + +int mb_master_connect(node_addr_t node_addr) { +#ifdef DEBUG + fprintf( stderr, "mb_master_connect()\n"); +#endif + /* call layer 1 library */ + return modbus_connect(node_addr); +} + + +int mb_master_close(int nd) { +#ifdef DEBUG + fprintf( stderr, "mb_master_close(): nd = %d\n", nd); +#endif + /* call layer 1 library */ + return modbus_close(nd); +} + +#ifdef __cplusplus +} +#endif diff --git a/silecs-communication-cpp/src/silecs-communication/protocol/modbus/mb_master.h b/silecs-communication-cpp/src/silecs-communication/protocol/modbus/mb_master.h new file mode 100644 index 0000000..7745985 --- /dev/null +++ b/silecs-communication-cpp/src/silecs-communication/protocol/modbus/mb_master.h @@ -0,0 +1,157 @@ +/* modbus_rtu.h + + By P.Costigan email: phil@pcscada.com.au http://pcscada.com.au + + These library of functions are designed to enable a program send and + receive data from a device that communicates using the Modbus protocol. + + Copyright (C) 2000 Philip Costigan P.C. SCADA LINK PTY. LTD. + + 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., 675 Mass Ave, Cambridge, MA 02139, USA. + + + + + The functions included here have been derived from the + Modicon Modbus Protocol Reference Guide + which can be obtained from Schneider at www.schneiderautomation.com. + + This code has its origins with + paul@pmcrae.freeserve.co.uk (http://www.pmcrae.freeserve.co.uk) + who wrote a small program to read 100 registers from a modbus slave. + + I have used his code as a catalist to produce this more functional set + of functions. Thanks paul. + + + */ + + +#ifndef MODBUS_MASTER_H +#define MODBUS_MASTER_H + +#ifdef __cplusplus +extern "C" { +#endif + +/*F.Locci #include <plc.h>*/ /* get the plc data types */ +#include <time.h> /* struct timespec data structure */ + +#include "mb_addr.h" /* get definition of common variable types */ + + + +/*********************************************************************** + + Note: All functions used for sending or receiving data via + modbus return these return values. + + + Returns: string_length if OK + 0 if failed + Less than 0 for exception errors + +***********************************************************************/ + + +/*F.Locci: error constants adjustement to be SILECS conformed +#define COMMS_FAILURE 0 +#define ILLEGAL_FUNCTION -1 +#define ILLEGAL_DATA_ADDRESS -2 +#define ILLEGAL_DATA_VALUE -3 +#define SLAVE_DEVICE_FAILURE -4 +#define ACKNOWLEDGE -5 +#define SLAVE_DEVICE_BUSY -6 +#define NEGATIVE_ACKNOWLEDGE -7 +#define MEMORY_PARITY_ERROR -8 + +#define PORT_FAILURE -11 +*/ +#define PORT_FAILURE -3 + + +/************************************************************************ + + read_bdata + + F.Locci: just read raw byte array. Take care of frame longer than + 125 words. + +*************************************************************************/ + +#define MAX_READ_BDATA 200 + +int read_bdata(int slave, /* slave id */ + int start_addr, /* word pointer addr. */ + int count, /* byte count to read */ + u8 *dest, /* byte array */ + int ttyfd, /* connection id */ + int send_retries, /* number of request retries */ + const struct timespec *response_timeout); /* timeout value */ + + +/************************************************************************* + + write_bdata + + F.Locci: just write raw byte array. Take care of frame which exceeds + modbus frame std. length. + !!byte count MUST be even value - 16 bits alignment in that PLC + +***************************************************************************/ + +#define MAX_WRITE_BDATA 200 + +int write_bdata(int slave, /* slave id */ + int start_addr, /* word pointer addr. */ + int count, /* byte count to write - MUST be even value */ + u8 *data, /* byte array */ + int ttyfd, /* connection id */ + int send_retries, /* number of request retries */ + const struct timespec *response_timeout); /* timeout value */ + + +/************************************************************************ + + initialise + + This function sets up the libraries + (allocate memory for buffers, initialise data strcutures, etc) + +**************************************************************************/ +int mb_master_init(int nd_count); + +int mb_master_done(void); + + +/*************************************************************************** + + set_up_comms + + This function sets up (closes) a connection to a remote modbus + slave. + + +***************************************************************************/ +int mb_master_connect(node_addr_t node_addr); + +int mb_master_close(int nd); + +#ifdef __cplusplus +} +#endif + +#endif /* MODBUS_MASTER_H */ + diff --git a/silecs-communication-cpp/src/silecs-communication/protocol/modbus/mb_master_private.h b/silecs-communication-cpp/src/silecs-communication/protocol/modbus/mb_master_private.h new file mode 100644 index 0000000..5f9d4b7 --- /dev/null +++ b/silecs-communication-cpp/src/silecs-communication/protocol/modbus/mb_master_private.h @@ -0,0 +1,43 @@ +/* + * (c) 2002 Mario de Sousa + * + * Offered to the public 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. + * + * This code is made available on the understanding that it will not be + * used in safety-critical situations without a full and competent review. + */ + + +#ifndef MODBUS_MASTER_PRIVATE_H +#define MODBUS_MASTER_PRIVATE_H + +/*F.Locci #include <plc.h>*/ /* get the plc data types */ +#include "mb_util.h" +#include "mb_master.h" + + +#define QUERY_BUFFER_SIZE MAX_L2_FRAME_LENGTH + +#define DEF_LAYER2_SEND_RETRIES 1 + +#define DEF_IGNORE_ECHO 0 + +#define DEF_OPTIMIZATION optimize_speed + + +#endif /* MODBUS_MASTER_PRIVATE_H */ + + + + + + + + diff --git a/silecs-communication-cpp/src/silecs-communication/protocol/modbus/mb_tcp.cpp b/silecs-communication-cpp/src/silecs-communication/protocol/modbus/mb_tcp.cpp new file mode 100644 index 0000000..f918409 --- /dev/null +++ b/silecs-communication-cpp/src/silecs-communication/protocol/modbus/mb_tcp.cpp @@ -0,0 +1,1407 @@ +/* + * (c) 2002 Mario de Sousa + * + * Offered to the public 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. + * + * This code is made available on the understanding that it will not be + * used in safety-critical situations without a full and competent review. + * + * + * Revision : v1.0 + * Date : 11/2004 - F.Locci + * Objet : .remove static prefix into modbus_tcp_write() declaration + * to make code reentrant. + * .move global recv_buf_ to local one into read/write_bdata() + * Look at v1.0 comments + * + * Revision : v1.1 + * Date : 12/2006 - F.Locci + * Objet : .modify code (pointing things) to be Lces platform compatible + * Look at v1.1 comments + */ + + +/* TODO: + * - clean up the code (access to nw_array_, etc...) + * - closing sockets that will be idle for more than 1 second... + */ + + +#include <fcntl.h> /* File control definitions */ +#include <stdio.h> /* Standard input/output */ +#include <string.h> +#include <stdlib.h> +#include <termio.h> /* POSIX terminal control definitions */ +#include <unistd.h> /* POSIX Symbolic Constants */ +#include <assert.h> +#include <errno.h> /* Error definitions */ +#include <time.h> /* clock_gettime() */ +#include <sys/types.h> +#ifdef __Lynx__ +#include <bsd/in_systm.h> +#include <uio.h> +#endif +#include <sys/socket.h> +#include <netinet/in.h> /* required for htons() and ntohs() */ +#include <netinet/tcp.h> /* TCP level socket options */ +#include <netinet/ip.h> /* IP level socket options */ + +/*F.Locci, +#include <plc.h> +#include <misc/sin_util.h> +*/ +#include <silecs-communication/protocol/core/ietype.h> + +#include "sin_util.h" +/*F.Locci end*/ + +#include "mb_layer1.h" /* The public interface this file implements... */ +#include "mb_tcp_private.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* #define DEBUG */ /* uncomment to see the data sent and received */ + + +#define modbus_tcp_write modbus_write +#define modbus_tcp_read modbus_read +#define modbus_tcp_init modbus_init +#define modbus_tcp_done modbus_done +#define modbus_tcp_connect modbus_connect +#define modbus_tcp_listen modbus_listen +#define modbus_tcp_close modbus_close +#define modbus_tcp_silence_init modbus_silence_init +#define modbus_tcp_get_min_timeout modbus_get_min_timeout + + + + +/************************************/ +/** **/ +/** Include common code... **/ +/** **/ +/************************************/ + +#include "mb_time_util.h" + + + + +/**************************************************************/ +/**************************************************************/ +/**** ****/ +/**** ****/ +/**** Forward Declarations ****/ +/**** and Defaults ****/ +/**** ****/ +/**************************************************************/ +/**************************************************************/ + + + /* A Node Descriptor metadata, + * Due to the fact that modbus TCP is connection oriented, + * and that if the client detects an error the connection + * must be shut down and re-established automatically, + * the modbus TCP layer needs to keep the address of the remote server. + * + * We do this by implementing a node descriptor table, in which each + * entry will have the remote address, and the file descriptor + * of the socket currently in use. + * + * We do not pass the file descriptor up to the next higher layer. We + * send them the node descriptor instead... + */ +#define MB_MASTER_NODE AF_INET /* This MUST be set to AF_INET !! */ +#define MB_LISTEN_NODE AF_AX25 /* actually any value will do, as long as it is != AF_INET */ +#define MB_SLAVE_NODE AF_X25 /* actually any value will do, as long as it is != AF_INET */ +#define MB_FREE_NODE AF_ROSE /* actually any value will do, as long as it is != AF_INET */ +typedef sa_family_t nd_type_t; + +typedef struct { + int fd; /* socket descriptor == file descriptor */ + /* NOTE: + * Modbus TCP says that on error, we should close + * a connection and retry with a new connection. + * Since it takes time for a socket to close + * a connection if the remote server is down, + * we close the connection on the socket, close the + * socket itself, and create a new one for the new + * connection. There will be times when the node will + * not have any valid socket, and it will have to + * be created on the fly. + * When the node does not have a valid socket, + * fd will be set to -1 + */ + struct sockaddr_in addr; /* NOTE: + * We re-use the addr.sin_family member to define the + * state of the node descriptor. + * If addr.sin_family == MB_MASTER_NODE + * The node descriptor was initialised by the + * modbus_connect() function. + * The node descriptor is being used by a master + * device, and the addr contains the address of the slave. + * Remember that in this case fd may be >= 0 while + * we have a valid connection, or it may be < 0 when + * the connection needs to be reset. + * If addr.sin_family == MB_LISTEN_NODE + * The node descriptor was initialised by the + * modbus_listen() function. + * The node is merely used to accept() new connection + * requests. The new slave connections will use another + * node to transfer data. + * In this case fd must be >= 0. + * fd < 0 is an ilegal state and should never occur. + * If addr.sin_family == MB_SLAVE_NODE + * The node descriptor was initialised when a new + * connection request arrived on a MB_LISTEN type node. + * The node descriptor is being used by a slave device, + * and is currently being used to connect to a master. + * In this case fd must be >= 0. + * fd < 0 is an ilegal state and should never occur. + * If addr.sin_family == FREE_ND + * The node descriptor is currently not being used. + * In this case fd is set to -1, but is really irrelevant. + */ + int close_on_silence; /* A flag used only by Master Nodes. + * When (close_on_silence > 0), then the connection to the + * slave device will be shut down whenever the + * modbus_tcp_silence_init() function is called. + * Remember that the connection will be automatically + * re-established the next time the user wishes to communicate + * with the same slave (using this same node descripto). + * If the user wishes to comply with the sugestion + * in the OpenModbus Spec, (s)he should set this flag + * if a silence interval longer than 1 second is expected. + */ +} nd_entry_t; + + +static void nd_entry_init(nd_entry_t *nde) { + nde->addr.sin_family = MB_FREE_NODE; + nde->fd = -1; /* not currently connected... */ +} + + + + +typedef struct { + /* the array of node descriptors, and current size... */ + nd_entry_t *node; + int node_count; /* total number of nodes in the node[] array */ + int free_node_count; /* number of free nodes in the node[] array */ + /* fd set with all the fd in the node array already set + * This saves time in not having to re-initialize a fd_set every time + * the modbus_read() function is called... + */ + fd_set all_fds; + /* the highest fd in the fds set... This is used for the select() call */ + int all_fd_high; + /* fd set with all the fd belonging to MB_MASTER_NODE and MB_SLAVE_NODE + * type nodes already set. + * This saves time in not having to re-initialize a fd_set every time + * the modbus_read() function is called... + */ + fd_set ms_fds; + /* the highest fd in the fds set... This is used for the select() call */ + int ms_fd_high; +} nd_table_t; + + +/*F.Locci, add connection timeout - look at <rfcsock.c> file*/ +extern int connect_nonb(int sockfd, struct sockaddr *saptr, socklen_t salen, int nsec); + + +static int nd_table_init(nd_table_t *ndt, int nd_count) { + int count; + + /* initialise the node table with default values... */ + ndt->node = NULL; + ndt->node_count = 0; + ndt->free_node_count = 0; + FD_ZERO(&(ndt->all_fds)); + ndt->all_fd_high = -1; + FD_ZERO(&(ndt->ms_fds)); + ndt->ms_fd_high = -1; + + /* initialise the node descriptor metadata array... */ + ndt->node = (nd_entry_t*) malloc(sizeof(nd_entry_t) * nd_count); + if (ndt->node == NULL) { + /*F.Locci + plc_log_errmsg(1, "Out of memory: error initializing node address buffer"); + */ + printf("\nOut of memory: error initializing node address buffer\n"); + return -1; + } + ndt->node_count = nd_count; + ndt->free_node_count = nd_count; + + /* initialise the state of each node in the array... */ + for (count = 0; count < nd_count; count++) { + nd_entry_init(&ndt->node[count]); + } /* for() */ + + return nd_count; /* number of succesfully created nodes! */ +} + + + +static int nd_table_get_free_node(nd_table_t *ndt, nd_type_t nd_type) { + int count; + + /* check for free nodes... */ + if (ndt->free_node_count <= 0) + /* no free nodes... */ + return -1; + + /* Decrement the free node counter...*/ + ndt->free_node_count--; + + /* search for a free node... */ + for (count = 0; count < ndt->node_count; count++) { + if(ndt->node[count].addr.sin_family == MB_FREE_NODE) { + /* found one!! */ + ndt->node[count].addr.sin_family = nd_type; + return count; + } + } /* for() */ + + /* Strange... We should have free nodes, but we didn't finda any! */ + /* Let's try to get into a consistent state, and return an error! */ + ndt->free_node_count = 0; + return -1; +} + + + +static void nd_table_close_node(nd_table_t *ndt, int nd) { + + if(ndt->node[nd].addr.sin_family == MB_FREE_NODE) + /* Node already free... */ + return; + + /* Increment the free node counter...*/ + ndt->free_node_count++; + /* Mark the node as being free. */ + ndt->node[nd].addr.sin_family = MB_FREE_NODE; + + return; +} + + + +/**************************************************************/ +/**************************************************************/ +/**** ****/ +/**** ****/ +/**** Global Library State ****/ +/**** ****/ +/**** ****/ +/**************************************************************/ +/**************************************************************/ + + /* The receive buffer... */ + /* NOTE: The library supports multiple simultaneous connections, + * but will only read a message from one at a time. + * (i.e. once it starts receiving a message from one node, it + * will read that message to the end, even though another message + * may start arriving later on another node, but finish arriving + * earlier than the first. The second message will be ignored until + * the first has been completely received, or a timeout occurs...) + * This means we can re-use the same buffer for all the nodes. + * It doesn't seem to be worth the hassle and increased memory + * use to implement it properly with one buffer per node... + v1.0 +static u8 *recv_buf_ = NULL; +*/ + + /* The node descriptor table... */ + /* NOTE: This variable is also used to check whether the library + * has been previously initialised. + * If == NULL, �> library not yet initialised... + */ +static nd_table_t *nd_table_ = NULL; + + + +/**************************************************************/ +/**************************************************************/ +/**** ****/ +/**** ****/ +/**** Local Utility functions... ****/ +/**** ****/ +/**** ****/ +/**************************************************************/ +/**************************************************************/ + + +#define min(a,b) ((a<b)?a:b) +#define max(a,b) ((a>b)?a:b) + +/************************************/ +/** **/ +/** Configure socket for Modbus **/ +/** **/ +/************************************/ + + +static int configure_socket(int socket_id) { + + /* configure the socket */ + /* set the TCP no delay flag. */ + {int bool_opt = 1; + if (setsockopt(socket_id, SOL_TCP, TCP_NODELAY, + (const void *)&bool_opt, sizeof(bool_opt)) + < 0) + return -1; + } + + /* set the IP low delay option. */ + {int priority_opt = IPTOS_LOWDELAY; + if (setsockopt(socket_id, SOL_IP, IP_TOS, + (const void *)&priority_opt, sizeof(priority_opt)) + < 0) + return -1; + } + +#if 0 + /* send buffer */ + /* NOTE: For slave devices, that may be receiving multiple + * requests before they have a chance to reply to the first, + * it probably is a good idea to have a larger receive buffer. + * + * For the send buffer, it probably does not make sense to + * waste time asking for a smaller buffer, since the larger + * default buffer has already been allocated (the socket has already + * been created!) + * + * We might just as well leave out the configuration of the socket + * buffer size... + */ +#define SOCK_BUF_SIZE 300 /* The size proposed in the Modbus TCP spec. */ + {int sock_buf_size; + sock_buf_size = SOCK_BUF_SIZE; + if (setsockopt(socket_id, SOL_SOCKET, SO_SNDBUF, + (const void *)&sock_buf_size, sizeof(sock_buf_size)) + < 0) + return -1; + /* recv buffer */ + sock_buf_size = SOCK_BUF_SIZE; + if (setsockopt(socket_id, SOL_SOCKET, SO_RCVBUF, + (const void *)&sock_buf_size, sizeof(sock_buf_size)) + < 0) + return -1; + } +#endif + + return 0; +} + + +/************************************/ +/** **/ +/** Connect socket to remote host **/ +/** **/ +/************************************/ + +/* This function will create a new socket, and connect it to a remote host... */ +static inline int open_connection(int nd) { + int socket_id; + + if (nd_table_->node[nd].fd >= 0) + /* nd already connected) */ + return nd_table_->node[nd].fd; + + if (nd_table_->node[nd].addr.sin_family != AF_INET) + /* invalid remote address, or invalid nd */ + return -1; + + /* lets try to connect... */ + /* create the socket */ + if ((socket_id = socket(PF_INET, DEF_TYPE, 0 /* protocol_num */)) < 0) + return -1; + + /* configure the socket */ + if (configure_socket(socket_id) < 0) { + close(socket_id); + return -1; + }; + + /* establish the connection to remote host */ + if (connect_nonb(socket_id, + (struct sockaddr *)&(nd_table_->node[nd].addr), + sizeof(nd_table_->node[nd].addr), MAX_CONNECT_TIMEOUT) < 0) { + close(socket_id); + return -1; + } + + nd_table_->node[nd].fd = socket_id; + FD_SET(socket_id, &(nd_table_->all_fds)); + nd_table_->all_fd_high = max(nd_table_->all_fd_high, socket_id); + FD_SET(socket_id, &(nd_table_->ms_fds)); + nd_table_->ms_fd_high = max(nd_table_->ms_fd_high, socket_id); + + return socket_id; +} + + +/* This function will accept a new connection request, and attribute it to a new node... */ +static inline int accept_connection(int nd) { + int socket_id, new_nd; + + if ((new_nd = nd_table_get_free_node(nd_table_, MB_SLAVE_NODE)) < 0) + /* no available free nodes for the new connection... */ + return -1; + + /* lets accept new connection request... */ + if ((socket_id = accept(nd_table_->node[nd].fd, NULL, NULL)) < 0) { + /* error establishing new connection... */ + nd_table_close_node(nd_table_, new_nd); /* first free up the un-used node. */ + return -1; + } + + /* configure the socket */ + if (configure_socket(socket_id) < 0) { + nd_table_close_node(nd_table_, new_nd); /* first free up the un-used node. */ + close(socket_id); + return -1; + }; + + /* set up the node entry and update the fd sets */ + nd_table_->node[new_nd].fd = socket_id; + FD_SET(socket_id, &(nd_table_->all_fds)); + nd_table_->all_fd_high = max(nd_table_->all_fd_high, socket_id); + FD_SET(socket_id, &(nd_table_->ms_fds)); + nd_table_->ms_fd_high = max(nd_table_->ms_fd_high, socket_id); + + return new_nd; +} + + +static inline void close_connection(int nd) { + if (nd_table_->node[nd].fd < 0) + /* nd already disconnected */ + return; + + int res = shutdown(nd_table_->node[nd].fd, SHUT_RDWR); +#ifdef DEBUG +{ + /* could not read registers from slave! */ + printf("shutdown() returned %d\n",res); +} +#endif + + close(nd_table_->node[nd].fd); + FD_CLR(nd_table_->node[nd].fd, &nd_table_->all_fds); + FD_CLR(nd_table_->node[nd].fd, &nd_table_->ms_fds); + nd_table_->node[nd].fd = -1; +} + + + +/************************************/ +/** **/ +/** Data format conversion **/ +/** **/ +/************************************/ + +/* + * Functions to convert u16 variables + * between network and host byte order + * + * NOTE: Modbus uses MSByte first, just like + * tcp/ip, so we use the htons() and + * ntoh() functions to guarantee + * code portability. + */ + +static inline u16 mb_hton(u16 h_value) { +/* return h_value; */ + return htons(h_value); +} + +static inline u16 mb_ntoh(u16 m_value) { +/* return m_value; */ + return ntohs(m_value); +} + +static inline u8 msb(u16 value) { +/* return Most Significant Byte of value; */ + return (value >> 8) & 0xFF; +} + +static inline u8 lsb(u16 value) { +/* return Least Significant Byte of value; */ + return value & 0xFF; +} + +#define u16_v(char_ptr) (*((u16 *)(&(char_ptr)))) + + +/************************************/ +/** **/ +/** Build/Check a frame header **/ +/** **/ +/************************************/ + +/* A modbus TCP frame header has 6 bytes... + * header[0-1] -> transaction id + * header[2-3] -> must be 0 + * header[4-5] -> frame data length (must be <= 255) + */ +#if TCP_HEADER_LENGTH < 6 +#error This code assumes a header size of 6 bytes, but TCP_HEADER_LENGTH < 6 +#endif + +static inline void build_header(u8 *header, + u16 transaction_id, + u16 byte_count) +{ + u16_v(header[0]) = mb_hton(transaction_id); + header[2] = 0; + header[3] = 0; + u16_v(header[4]) = mb_hton(byte_count); +} + + +static inline int check_header(u8 *header, + u16 *transaction_id, + u16 *byte_count) +{ + if ((header[2] != 0) || (header[3] != 0)) + return -1; + + *transaction_id = mb_ntoh(*(u16 *)(header + 0)); + *byte_count = mb_ntoh(*(u16 *)(header + 4)); + + if (*byte_count > MAX_L2_FRAME_LENGTH) + return -1; + + return 0; +} + + + + + +/**************************************************************/ +/**************************************************************/ +/**** ****/ +/**** ****/ +/**** Sending of Modbus TCP Frames ****/ +/**** ****/ +/**** ****/ +/**************************************************************/ +/**************************************************************/ + +int modbus_tcp_write(int nd, /* node descriptor */ + u8 *data, + size_t data_length, + u16 transaction_id) +{ +#define data_vector_size 2 + + /* NOTE: The following variables do not have to be static for the code to work + * correctly. It simply does not make sense to re-initialize these + * structures with the same values every time the function is called. + */ + /*v1.0*/ + u8 header[TCP_HEADER_LENGTH], *ptriovec/*v1.1*/; + struct iovec data_vector[data_vector_size] = {{(void *)header, TCP_HEADER_LENGTH},{NULL, 0}}; + struct msghdr msg = {NULL, 0, data_vector, data_vector_size, NULL, 0, 0}; + int res, bytes_sent; + +#ifdef DEBUG + printf("modbus_tcp_write(): called... nd=%d\n", nd); +#endif + + if ((nd >= nd_table_->node_count) || (nd < 0)) + /* invalid node descriptor... */ + return -1; + + /************************* + * prepare the header... * + *************************/ + build_header(header, transaction_id, data_length); +#ifdef DEBUG +/* Print the hex value of each character that is about to be + * sent over the bus. + */ + { int i; + printf("modbus_tcp_write(): sending data...\n"); + for(i = 0; i < TCP_HEADER_LENGTH; i++) + printf("[0x%2X]", header[i]); + for(i = 0; i < data_length; i++) + printf("[0x%2X]", data[i]); + printf("\n"); + } +#endif + + /****************************************** + * do we need to re-establish connection? * + ******************************************/ + if (open_connection(nd) < 0) { +#ifdef DEBUG + printf("modbus_tcp_write(): could not establish connection...\n"); +#endif + return -1; + } + + /********************** + * write to output... * + **********************/ + /* We are optimising for the most likely case, and in doing that + * we are making the least likely case have worse behaviour! + * Read on for an explanation... + * + * - The optimised behaviour for the most likely case: + * We have set the NO_DELAY flag on the socket, so the IP datagram + * is not delayed and is therefore sent as soon as any data is written to + * the socket. + * In order to send the whole message in a single IP datagram, we have to + * write both the the header and the data with a single call to write() + * In order to not to have to copy the data around just to add the + * message header, we use sendmsg() instead of write()! + * + * - The worse behaviour for the least likely case: + * If for some reason only part of the data is sent with the first call to + * write(), a datagram is sent right away, and the subsequent data will + * be sent in another datagram. :-( + */ + data_vector[data_vector_size - 1].iov_base = data; + data_vector[data_vector_size - 1].iov_len = data_length; + bytes_sent = 0; + while (1) { + /* Please see the comment just above the main loop!! */ + res = sendmsg(nd_table_->node[nd].fd, &msg, 0); + if (res < 0) { + if ((errno != EAGAIN ) && (errno != EINTR )) { + /* error sending message... */ + close_connection(nd); + return -1; + } else { + continue; + } + } else { + /* res >= 0 */ + bytes_sent += res; + if (bytes_sent >= data_length + TCP_HEADER_LENGTH) { + /* query succesfully sent! */ +#ifdef DEBUG + printf("modbus_tcp_write(): sent %d bytes\n", bytes_sent); +#endif + return data_length; + } + + /* adjust the data_vector... */ + /*v1.1*/ + if (res < data_vector[0].iov_len) { + data_vector[0].iov_len -= res; + ptriovec = (u8 *)data_vector[0].iov_base; + ptriovec += res; + data_vector[0].iov_base = (void *)ptriovec; + } else { + res -= data_vector[0].iov_len; + data_vector[0].iov_len = 0; + data_vector[1].iov_len -= res; + ptriovec = (u8 *)data_vector[1].iov_base; + ptriovec += res; + data_vector[1].iov_base = (void *)ptriovec; + } + } + } /* while (1) */ + + /* humour the compiler... */ + return -1; +} + + + +/**************************************************************/ +/**************************************************************/ +/**** ****/ +/**** ****/ +/**** Receiving Modbus TCP Frames ****/ +/**** ****/ +/**** ****/ +/**************************************************************/ +/**************************************************************/ + + +/* A helper function to modbus_tcp_read() + * + * WARNING: The semantics of this function are not what you would expect! + * + * if (data_already_available != 0) + * It assumes that select() has already been called before + * this function got called, and we are therefore guaranteed + * to have at least one byte to read off the socket (the fd). + * + * if (data_already_available == 0) + * it starts off by calling select()! + * + * + * NOTE: Ususal select semantics for (a: end_time == NULL) and + * (b: *end_time == 0) also apply. + * + * (a) Indefinite timeout + * (b) Try once, and and quit if no data available. + */ +static int read_bytes(int fd, + u8 *data, + int max_data_count, + const struct timespec *end_time, + int data_already_available) +{ + fd_set rfds; + int res, data_count; + + data_count = 0; + while (data_count < max_data_count) { + /*============================* + * wait for data availability * + *============================*/ + if (data_already_available == 0) { + FD_ZERO(&rfds); + FD_SET(fd, &rfds); + if (my_select(fd + 1, &rfds, end_time) < 0) + return -1; + } + + /*============================* + * read the available data... * + *============================*/ + res = read(fd, data + data_count, max_data_count - data_count); + if (res == 0) { + /* We are guaranteed to have data to read off the fd since we called + * select(), but read() returned 0 bytes. + * This means that the remote process has closed down the connection, + * so we return 0. + */ + return 0; + } + + if (res < 0) { + if (errno != EINTR) + return -1; + else + res = 0; + } + #ifdef DEBUG + {/* display the hex code of each character received */ + int i; + for (i=0; i < res; i++) + printf("%2X ", *(data + data_count + i)); + } + #endif + data_count += res; + data_already_available = 0; + } /* while ()*/ + + /* data read succesfully... */ + return data_count; +} + + + + +/************************************/ +/** **/ +/** Read a Modbus TCP frame **/ +/** **/ +/************************************/ + +/* The public function that reads a valid modbus frame. + * The frame is read from: + * - the node descriptor nd, if nd >= 0 + * - any valid and initialised node descriptor, if nd = -1 + * In this case, the node where the data is eventually read from + * is returned in *nd. + * + * The send_data and send_length parameters are ignored... + * + * return value: The length (in bytes) of the valid frame, + * -1 on error + * + * NOTE: Ususal select semantics for (a: recv_timeout == NULL) and + * (b: *recv_timeout == 0) also apply. + * + * (a) Indefinite timeout + * (b) Try once, and and quit if no data available. + */ + +/* NOTES: + * - We re-use the recv_buf_ to load the frame header, so we have to make + * sure that the buffer is large enough to take it... + */ +/*v1.0 +#ifndef __Lynx__ +#if RECV_BUFFER_SIZE < 5 //TCP_HEADER_LENGTH +#error The receive buffer is smaller than the frame header length. +#endif +#endif +*/ + +int modbus_tcp_read(int *nd, /* node descriptor */ + u8 *recv_data_ptr/*v1.0*/, + u16 *transaction_id, + u8 *send_data, /* ignored ! */ + int send_length, /* ignored ! */ + const struct timespec *recv_timeout) { + + struct timespec cur_time, end_time, *ts_ptr; + /*v1.0 + u8 *local_recv_data_ptr; + */ + u16 local_transaction_id = 0; + u16 frame_length; + int orig_nd, fd, fd_high, data_already_available; + +#ifdef DEBUG + printf("modbus_tcp_read(): called... nd=%d\n", *nd); +#endif + + if (nd == NULL) + return -1; + + if (*nd >= nd_table_->node_count) + /* invalid *nd */ + /* remember that *nd < 0 is valid!! */ + return -1; + + /*v1.0 + if (recv_data_ptr == NULL) + recv_data_ptr = &local_recv_data_ptr; + */ + if (transaction_id == NULL) + transaction_id = &local_transaction_id; + + /* We will potentially call read() multiple times to read in a single frame. + * We therefore determine the absolute time_out, and use this as a parameter + * for each call to read_bytes() instead of using a relative timeout. + * + * NOTE: see also the timeout related comment in the read_bytes() function! + * + * NOTE: clock_gettime() is rather expensive, between 7000 and 7500 clock + * cycles (measured with rdtsc on an Intel Pentium) + * gettimeofday() is half as expensive (3000 to 3500 clock cycles), + * but is not POSIX compliant... :-( + * Nevertheless this is peanuts (20 us on a 350 MHz cpu) compared to + * the timescales required to read a modbus frame over a serial bus + * (aprox. 10 ms for a 10 byte frame on a 9600 baud bus!) + */ + /* get the current time... */ + if (recv_timeout == NULL) { + ts_ptr = NULL; + } else { + ts_ptr = &end_time; + if ((recv_timeout->tv_sec == 0) && (recv_timeout->tv_nsec == 0)) { + end_time = *recv_timeout; + } else { + if (clock_gettime(CLOCK_REALTIME, &cur_time) < 0) + return -1; + end_time = timespec_add(cur_time, *recv_timeout); + } + } + + /* We will loop forever... + * We jump out of the loop and return from the function as soon as: + * - we receive a valid modbus message; + * OR + * - we time out. + */ + orig_nd = *nd; + while(1) { + *nd = orig_nd; + + /* If we must read off a single node... */ + if (*nd >= 0) + /* but the node does not have a valid fd */ + if ((nd_table_->node[*nd].addr.sin_family == MB_FREE_NODE) || + (nd_table_->node[*nd].fd < 0)) + /* then we return an error... */ + return -1; + + /* We want to call the read_bytes() function only after we are sure there + * is data waiting to be read on the socket, so we call select here. + * + * We only call select() here for the case when (*nd >= 0), + * since for the other case select() will be called later on... + */ + data_already_available = 1; + if (*nd >= 0) + data_already_available = 0; + + /* if *nd < 0, we will be: + * - reading off any valid node descriptor!! + * - and accepting new connection requests, if we have free nodes available!! + */ + while (*nd < 0) { + int nd_count; + fd_set rfds; + + if (nd_table_->free_node_count > 0) { + /* We have free nodes, so we will also listen on nodes + * that will accept new connections requests... + */ + rfds = nd_table_->all_fds; + fd_high = nd_table_->all_fd_high; + } else { + /* We do not have free nodes, so we will only listen on nodes + * that do not accept new connections requests... + */ + rfds = nd_table_->ms_fds; + fd_high = nd_table_->ms_fd_high; + } + + if (my_select(fd_high + 1, &rfds, ts_ptr) < 0) + return -1; + + /* figure out which nd is ready to be read... */ + for (nd_count = 0; nd_count < nd_table_->node_count; nd_count++) { + if (nd_table_->node[nd_count].addr.sin_family != MB_FREE_NODE) { + if (FD_ISSET(nd_table_->node[nd_count].fd, &rfds)) { + /* Found the node descriptor... */ + if (nd_table_->node[nd_count].addr.sin_family == MB_LISTEN_NODE) { + /* We must accept a new connection... + * No need to check for errors. + * If one occurs, there is nothing we can do... + */ + *nd = accept_connection(nd_count); +#ifdef DEBUG + printf("modbus_tcp_read(): new connection request on nd=%d\n", nd_count); + printf("modbus_tcp_read(): new connection accepted on nd=%d", *nd); +#endif + *nd = -1; /* this will keep us in the while loop */ + } else { + /* We will read a frame off this nd */ + *nd = nd_count; /* this will get us out of the while loop later on. */ + } + /* we have found the node descriptor, so let's jump out of the for(;;) loop */ + break; + } + } + } /* for(;;) */ + } /* while (*nd < 0) */ + + /* Just a consistency check... */ + if (*nd < 0) + /* If the code is correct, this should never occur... */ + return -1; + +#ifdef DEBUG + printf("modbus_tcp_read(): reading off nd=%d\n", *nd); +#endif + /*=========================* + * read a Modbus TCP frame * + *=========================*/ + /* assume error... */ + fd = nd_table_->node[*nd].fd; + /*v1.0 + *recv_data_ptr = NULL; + */ + + /*-------------* + * read header * + *-------------*/ + if (read_bytes(fd, recv_data_ptr/*v1.0*/, TCP_HEADER_LENGTH, ts_ptr, data_already_available) + == TCP_HEADER_LENGTH) { + /* let's check for header consistency... */ + if (check_header(recv_data_ptr/*v1.0*/, transaction_id, &frame_length) < 0) { +#ifdef DEBUG + printf("modbus_tcp_read(): frame with non valid header...\n"); +#endif + /* We let the code fall through to the error handler, that will + * close the connection! + * This is exactly what the modbus TCP protocol specifies! + */ + } else { + /*-----------* + * read data * + *-----------*/ + /* NOTE: the function read_bytes() assumes that there is data ready to be + * read off the socket, so we have to call select() ourselves + * before calling it. + */ + + data_already_available = 0; + if (read_bytes(fd, recv_data_ptr/*v1.0*/, frame_length, ts_ptr, data_already_available) + == frame_length) { + /* frame received succesfully... */ +#ifdef DEBUG + printf("\n"); +#endif + /*v1.0 + *recv_data_ptr = recv_buf_; + */ + return frame_length; + } + } + } + + /* We had an error reading the frame... + * We handle it by closing the connection, as specified by + * the modbus TCP protocol! + */ + +#ifdef DEBUG + printf("modbus_tcp_read(): error reading frame. Closing connection...\n"); +#endif + /* We close the socket... */ + close_connection(*nd); + + /* If it is a slave, we free the node... */ + if(nd_table_->node[*nd].addr.sin_family == MB_SLAVE_NODE) + nd_table_close_node(nd_table_, *nd); + + /* We try to read another frame... */ + } /* while(1) */ + + /* humour the compiler... */ + return -1; +} + + + + + + +/**************************************************************/ +/**************************************************************/ +/**** ****/ +/**** ****/ +/**** Initialising and Shutting Down Library ****/ +/**** ****/ +/**** ****/ +/**************************************************************/ +/**************************************************************/ + + +/******************************/ +/** **/ +/** Load Default Values **/ +/** **/ +/******************************/ + +static void set_defaults(const char **service) { + /* Set the default values, if required... */ + if (*service == NULL) + *service = DEF_SERVICE; +} + + +/******************************/ +/** **/ +/** Initialise Library **/ +/** **/ +/******************************/ +/* returns the number of nodes succesfully initialised... + * returns -1 on error. + */ +int modbus_tcp_init(int nd_count, + optimization_t opt /* ignored... */, + int *extra_bytes) { +#ifdef DEBUG + printf("modbus_tcp_init(): called...\n"); + printf("creating %d nodes:\n", nd_count); +#endif + + if (nd_table_ != NULL) + /* library already previously initialised! */ + return -1; + + if (nd_count <= 0) + /* invalid node count... */ + goto error_exit_0; + + /* set the extra_bytes value... */ + /* Please see note before the modbus_rtu_write() function for a + * better understanding of this extremely ugly hack... This will be + * in the mb_rtu.c file!! + * + * The number of extra bytes that must be allocated to the data buffer + * before calling modbus_tcp_write() + */ + if (extra_bytes != NULL) + *extra_bytes = 0; + + /* V1.0: initialise recv buffer + recv_buf_ = malloc(sizeof(u8) * RECV_BUFFER_SIZE); + if (recv_buf_ == NULL) { + //plc_log_errmsg(1, "Out of memory: error initializing receive buffer"); + printf("\nOut of memory: error initializing receive buffer\n"); + goto error_exit_0; + } + */ + + /* create the node table structure... */ + nd_table_ = (nd_table_t*) malloc(sizeof(nd_table_t)); + if (nd_table_ == NULL) { + /*F.Locci + plc_log_errmsg(1, "Out of memory: error initializing node table"); + */ + printf("\nOut of memory: error initializing node table\n"); + goto error_exit_1; + } + + /* initialise the node table... */ + if (nd_table_init(nd_table_, nd_count) < 0) + goto error_exit_2; + +#ifdef DEBUG + printf("modbus_tcp_init(): %d node(s) opened succesfully\n", nd_count); +#endif + return nd_count; /* number of succesfully created nodes! */ + +/* +error_exit_3: + free(nd_table_->node); + nd_table_->node = NULL; + nd_table_->count = 0; +*/ +error_exit_2: + free(nd_table_); nd_table_ = NULL; +error_exit_1: + /*V1.0 + free(recv_buf_); recv_buf_ = NULL; + */ +error_exit_0: + return -1; +} + + + + + + +/******************************/ +/** **/ +/** Open a Master Node **/ +/** **/ +/******************************/ + +int modbus_tcp_connect(node_addr_t node_addr) { + int node_descriptor; + struct sockaddr_in tmp_addr; + +#ifdef DEBUG + printf("modbus_tcp_connect(): called...\n"); + printf(" %s:%s\n", + node_addr.addr.tcp.host, + node_addr.addr.tcp.service); +#endif + + /* Check for valid address family */ + if (node_addr.naf != naf_tcp) + /* wrong address type... */ + return -1; + + /* set the default values... */ + set_defaults(&(node_addr.addr.tcp.service)); + + /* Check the parameters we were passed... */ + if(sin_init_addr(&tmp_addr, + node_addr.addr.tcp.host, + node_addr.addr.tcp.service, + DEF_PROTOCOL) + < 0) { + /* + plc_log_wrnmsg(1, "Error parsing/resolving address %s:%s", + node_addr.addr.tcp.host, + node_addr.addr.tcp.service); + */ + return -1; + } + + /* find a free node descriptor */ + /* NOTE: The following code line works beacuse MB_MASTER_NODE is set to AF_INET! */ +#if MB_MASTER_NODE != AF_INET +#error The code only works if MB_MASTER_NODE == AF_INET, which they are not! +#endif + if ((node_descriptor = nd_table_get_free_node(nd_table_, MB_MASTER_NODE)) < 0) + /* if no free nodes to initialize, then we are finished... */ + return -1; + + nd_table_->node[node_descriptor].addr = tmp_addr; + nd_table_->node[node_descriptor].fd = -1; /* not currently connected... */ + nd_table_->node[node_descriptor].close_on_silence = node_addr.addr.tcp.close_on_silence; + + if (nd_table_->node[node_descriptor].close_on_silence < 0) + nd_table_->node[node_descriptor].close_on_silence = DEF_CLOSE_ON_SILENCE; + +#ifdef DEBUG + printf("modbus_tcp_connect(): returning nd=%d\n", node_descriptor); +#endif + return node_descriptor; +} + + + + +/******************************/ +/** **/ +/** Open a Slave Node **/ +/** **/ +/******************************/ + +int modbus_tcp_listen(node_addr_t node_addr) { + int fd, nd; + +#ifdef DEBUG + printf("modbus_tcp_listen(): called...\n"); + printf(" %s:%s\n", + node_addr.addr.tcp.host, + node_addr.addr.tcp.service); +#endif + + /* Check for valid address family */ + if (node_addr.naf != naf_tcp) + /* wrong address type... */ + goto error_exit_0; + + /* set the default values... */ + set_defaults(&(node_addr.addr.tcp.service)); + + /* create a socket and bind it to the appropriate port... */ + fd = bind_socket(node_addr.addr.tcp.host, + node_addr.addr.tcp.service, + DEF_PROTOCOL); + if (fd < 0) + goto error_exit_0; + if (listen(fd, DEF_MAX_PENDING_CONNECTION_REQUESTS) < 0) + goto error_exit_0; + + /* find a free node descriptor */ + if ((nd = nd_table_get_free_node(nd_table_, MB_LISTEN_NODE)) < 0) { + /* if no free nodes to initialize, then we are finished... */ + goto error_exit_1; + } + + /* nd_table_->node[nd].addr = tmp_addr; */ /* does not apply for MB_LISTEN_NODE */ + nd_table_->node[nd].fd = fd; /* not currently connected... */ + + /* update the fd sets...*/ + FD_SET(fd, &(nd_table_->all_fds)); + nd_table_->all_fd_high = max(nd_table_->all_fd_high, fd); + +#ifdef DEBUG + printf("modbus_tcp_listen(): returning nd=%d\n", nd); +#endif + return nd; + +error_exit_1: + close(fd); +error_exit_0: + return -1; +} + + + +/******************************/ +/** **/ +/** Close a node **/ +/** **/ +/******************************/ + +int modbus_tcp_close(int nd) { +#ifdef DEBUG + printf("modbus_tcp_close(): called... nd=%d\n", nd); +#endif + +/*F.Locci*/ + if (nd_table_ == NULL) return -1; +/**/ + + if ((nd < 0) || (nd >= nd_table_->node_count)) + /* invalid nd */ + return -1; + + if (nd_table_->node[nd].addr.sin_family == MB_FREE_NODE) + /* already free node */ + return 0; + + close_connection(nd); + + nd_table_->node[nd].addr.sin_family = MB_FREE_NODE; + nd_table_->free_node_count++; + + return 0; +} + + + +/**********************************/ +/** **/ +/** Close all open connections **/ +/** **/ +/**********************************/ + +int modbus_tcp_silence_init(void) { + int nd; + +#ifdef DEBUG + printf("modbus_tcp_silence_init(): called...\n"); +#endif + + /* close all master connections that remain open... */ + for (nd = 0; nd < nd_table_->node_count; nd++) + if (nd_table_->node[nd].addr.sin_family == MB_MASTER_NODE) + if (nd_table_->node[nd].close_on_silence > 0) + /* node is is being used for a master device, + * and wishes to be closed... ...so we close it! + */ + close_connection(nd); + + return 0; +} + + + +/******************************/ +/** **/ +/** Shutdown the Library **/ +/** **/ +/******************************/ + +int modbus_tcp_done(void) { + int i; + +/*F.Locci*/ + if (nd_table_ == NULL) return -1; +/**/ + + /* close all the connections... */ + for (i = 0; i < nd_table_->node_count; i++) + modbus_tcp_close(i); + + /* Free memory... */ + free(nd_table_->node); + /*V1.0 + free(recv_buf_); recv_buf_ = NULL; + */ + free(nd_table_); nd_table_ = NULL; + + return 0; +} + + + + +double modbus_tcp_get_min_timeout(int baud, + int parity, + int data_bits, + int stop_bits) { + return 0; +} + +#ifdef __cplusplus +} +#endif diff --git a/silecs-communication-cpp/src/silecs-communication/protocol/modbus/mb_tcp_private.h b/silecs-communication-cpp/src/silecs-communication/protocol/modbus/mb_tcp_private.h new file mode 100644 index 0000000..b05ca22 --- /dev/null +++ b/silecs-communication-cpp/src/silecs-communication/protocol/modbus/mb_tcp_private.h @@ -0,0 +1,84 @@ +/* + * (c) 2002 Mario de Sousa + * + * Offered to the public 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. + * + * This code is made available on the understanding that it will not be + * used in safety-critical situations without a full and competent review. + */ + + +#ifndef MODBUS_TCP_PRIVATE_H +#define MODBUS_TCP_PRIVATE_H + +/*F.Locci #include <plc.h>*/ /* get the plc data types */ +#include "mb_util.h" + + +/* tcp port default configuration... */ +#define DEF_SERVICE "502" /* port used by modbus */ +#define DEF_PROTOCOL "tcp" /* protocol used by modbus tcp */ +#define DEF_TYPE SOCK_STREAM /* Quality of service required of the socket... */ +#define DEF_MAX_PENDING_CONNECTION_REQUESTS 5 + /* maximum number of pending connection requests + * that have not yet been accept()'ed + */ +#define DEF_CLOSE_ON_SILENCE 1 /* Used only by master nodes. + * Flag indicating whether, by default, the connection + * to the slave device should be closed whenever the + * modbus_tcp_silence_init() function is called. + * + * 0 -> do not close connection + * >0 -> close connection + * + * The spec sugests that connections that will not + * be used for longer than 1 second should be closed. + * Even though we expect most connections to have + * silence intervals much shorted than 1 second, we + * decide to use the default of shuting down the + * connections because it is safer, and most other + * implementations seem to do the same. + * If we do not close we risk using up all the possible + * connections that the slave can simultaneouly handle, + * effectively locking out every other master that + * wishes to communicate with that same slave. + */ + + /* Since the receive buffer is also re-used to store the frame header, + * we set it to the larger of the two. + */ +#ifndef __Lynx__ + +#if TCP_HEADER_LENGTH > MAX_L2_FRAME_LENGTH +#define RECV_BUFFER_SIZE TCP_HEADER_LENGTH +#else +#define RECV_BUFFER_SIZE MAX_L2_FRAME_LENGTH +#endif + +#else + +#if defined(TCP_HEADER_LENGTH) > defined(MAX_L2_FRAME_LENGTH) +#define RECV_BUFFER_SIZE TCP_HEADER_LENGTH +#else +#define RECV_BUFFER_SIZE MAX_L2_FRAME_LENGTH +#endif + +#endif + + +#endif /* MODBUS_TCP_PRIVATE_H */ + + + + + + + + diff --git a/silecs-communication-cpp/src/silecs-communication/protocol/modbus/mb_time_util.h b/silecs-communication-cpp/src/silecs-communication/protocol/modbus/mb_time_util.h new file mode 100644 index 0000000..e17dc52 --- /dev/null +++ b/silecs-communication-cpp/src/silecs-communication/protocol/modbus/mb_time_util.h @@ -0,0 +1,159 @@ +/* + * (c) 2002 Mario de Sousa + * + * Offered to the public 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. + * + * This code is made available on the understanding that it will not be + * used in safety-critical situations without a full and competent review. + */ + + + /* Time handling functions used by the modbus protocols... */ +#include <time.h> + +#ifndef __MODBUS_TIME_UTIL_H +#define __MODBUS_TIME_UTIL_H + + +/************************************/ +/** **/ +/** Time format conversion **/ +/** **/ +/************************************/ + +/* Function to load a struct timeval correctly + * from a double. + */ +static inline struct timeval d_to_timeval(double time) { + struct timeval tmp; + + tmp.tv_sec = time; + tmp.tv_usec = 1e6*(time - tmp.tv_sec); + return tmp; +} + +/* Function to ... */ +static inline struct timespec timespec_dif(struct timespec ts1, struct timespec ts2) { + struct timespec ts; + + ts.tv_sec = ts1.tv_sec - ts2.tv_sec; + if(ts1.tv_nsec > ts2.tv_nsec) { + ts.tv_nsec = ts1.tv_nsec - ts2.tv_nsec; + } else { + ts.tv_nsec = 1000000000 + ts1.tv_nsec - ts2.tv_nsec; + ts.tv_sec--; + } + + if (ts.tv_sec < 0) + ts.tv_sec = ts.tv_nsec = 0; + + return ts; +} + +/* Function to ... */ +static inline struct timespec timespec_add(struct timespec ts1, struct timespec ts2) { + struct timespec ts; + + ts.tv_sec = ts1.tv_sec + ts2.tv_sec; + ts.tv_nsec = ts1.tv_nsec + ts2.tv_nsec; + ts.tv_sec += ts.tv_nsec / 1000000000; + ts.tv_nsec = ts.tv_nsec % 1000000000; + return ts; +} + +/* Function to convert a struct timespec to a struct timeval. */ +static inline struct timeval timespec_to_timeval(struct timespec ts) { + struct timeval tv; + + tv.tv_sec = ts.tv_sec; + tv.tv_usec = ts.tv_nsec/1000; + return tv; +} + + + +/************************************/ +/** **/ +/** select() with absolute timeout **/ +/** **/ +/************************************/ + + +/* My private version of select using an absolute timeout, instead of the + * usual relative timeout. + * + * NOTE: Ususal select semantics for (a: end_time == NULL) and + * (b: *end_time == 0) also apply. + * + * (a) Indefinite timeout + * (b) Try once, and and quit if no data available. + */ +static int my_select(int fd, fd_set *rfds, const struct timespec *end_time) { + + int res; + struct timespec cur_time; + struct timeval timeout, *tv_ptr; + fd_set tmp_fds; + + /*============================* + * wait for data availability * + *============================*/ + do { + tmp_fds = *rfds; + /* NOTE: To do the timeout correctly we would have to revert to timers + * and asociated signals. That is not very thread friendly, and is + * probably too much of a hassle trying to figure out which signal + * to use. What if we don't have any free signals? + * + * The following solution is not correct, as it includes a race + * condition. The following five lines of code should really + * be atomic! + * + * NOTE: see also the timeout related comment in the + * modbus_tcp_read() function! + */ + if (end_time == NULL) { + tv_ptr = NULL; + } else { + tv_ptr = &timeout; + if ((end_time->tv_sec == 0) && (end_time->tv_nsec == 0)) { + timeout.tv_sec = timeout.tv_usec = 0; + } else { + /* ATOMIC - start */ + if (clock_gettime(CLOCK_REALTIME, &cur_time) < 0) + return -1; + timeout = timespec_to_timeval(timespec_dif(*end_time, cur_time)); + } + } + + res = select(fd, &tmp_fds, NULL, NULL, tv_ptr); + /* ATOMIC - end */ + + if (res == 0) { +#ifdef DEBUG + printf("Comms time out\n"); +#endif + return -1; + } + if ((res < 0) && (errno != EINTR)) { + return -1; + } + } while (res <= 0); + + *rfds = tmp_fds; + return res; +} + + + + + + +#endif /* __MODBUS_TIME_UTIL_H */ diff --git a/silecs-communication-cpp/src/silecs-communication/protocol/modbus/mb_util.h b/silecs-communication-cpp/src/silecs-communication/protocol/modbus/mb_util.h new file mode 100644 index 0000000..9d8ea08 --- /dev/null +++ b/silecs-communication-cpp/src/silecs-communication/protocol/modbus/mb_util.h @@ -0,0 +1,92 @@ +/* + * (c) 2002 Mario de Sousa + * + * Offered to the public 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. + * + * This code is made available on the understanding that it will not be + * used in safety-critical situations without a full and competent review. + */ + + +#ifndef MB_UTIL_H +#define MB_UTIL_H + +/* This file has constants related to the modbus protocol */ +/* + * Some of these constants are specific to the layer two protocols + * (i.e. master and slave), while others are specific of the + * layer one protocols (i.e. rtu, ascii, tcp). + * + * a) Unfortunately, due to the nature of the modbus protocol, that does not + * include a frame size field in the layer 1 frame (see note 1), and the + * fact that we are implementing it at the user level, the implementation + * of some layer 1 protocols need to know the content of the layer 2 protocol + * in order to determine the size of the frame. + * + * b) The layer two message formats are in fact the same, just reversing the role + * being played (master or slave). + * + * Bothe a) and b) mean we need the same modbus protocol constants in several files. + * It ends up making more sense to put them all together in a single file, which + * makes updating easier, even though we are trying to strictly seperate the layer 1 + * and layer 2 protocols. + * + * + * + * Notes: + * (1) There is no layer 1 field with the frame size, nevertheless this + * size can be determined indirectly due to timing restrictions on the rtu + * protocol. Unfortunately, due to the fact that we are implementing + * it at the user level, we are not guaranteed to detect these timings + * correctly, and therefore have to rely on layer 2 protocol info to + * determine the frame size. + * For the ascii protocol, the frame size is determined indirectly by + * a frame header and tail, so we do not use layer 2 protocol info. + */ + + + /* Layer 2 Frame Structure... */ + /* Valid for both master and slave protocols */ +#define L2_FRAME_HEADER_LENGTH 6 +#define L2_FRAME_BYTECOUNT_LENGTH 1 +#define L2_FRAME_DATABYTES_LENGTH 255 +#define MAX_L2_FRAME_LENGTH (L2_FRAME_HEADER_LENGTH + L2_FRAME_BYTECOUNT_LENGTH + L2_FRAME_DATABYTES_LENGTH) + +#define L2_FRAME_SLAVEID_OFS 0 +#define L2_FRAME_FUNCTION_OFS 1 + + /* Layer 1 - Ascii Frame sizes... */ +#define L2_TO_ASC_CODING 2 /* number of ascii bytes used to code a Layer 2 frame byte */ +#define ASC_FRAME_HEADER_LENGTH 1 +#define ASC_FRAME_HEADER ':' +#define ASC_FRAME_TAIL_LENGTH 2 +#define ASC_FRAME_TAIL_0 '\13' /* 'CR' */ +#define ASC_FRAME_TAIL_1 '\10' /* 'LF' */ +#define ASC_FRAME_LRC_LENGTH 2 + + /* Layer 1 - RTU Frame sizes... */ +#define RTU_FRAME_CRC_LENGTH 2 + + /* Layer 1 - TCP Frame sizes... */ +#define TCP_HEADER_LENGTH 6 + + /* Global Frame sizes */ +#define MAX_RTU_FRAME_LENGTH MAX_L2_FRAME_LENGTH + RTU_FRAME_CRC_LENGTH +#define MAX_ASC_FRAME_LENGTH ((MAX_L2_FRAME_LENGTH * L2_TO_ASC_CODING) + ASC_FRAME_HEADER_LENGTH + ASC_FRAME_TAIL_LENGTH + ASC_FRAME_LRC_LENGTH) + +#endif /* MB_UTIL_H */ + + + + + + + + diff --git a/silecs-communication-cpp/src/silecs-communication/protocol/modbus/sin_util.cpp b/silecs-communication-cpp/src/silecs-communication/protocol/modbus/sin_util.cpp new file mode 100644 index 0000000..682f4bb --- /dev/null +++ b/silecs-communication-cpp/src/silecs-communication/protocol/modbus/sin_util.cpp @@ -0,0 +1,229 @@ +/* + * (c) 2000 Jiri Baum + * Mario de Sousa + * + * Offered to the public 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. + * + * This code is made available on the understanding that it will not be + * used in safety-critical situations without a full and competent review. + */ + + +/* + * Socket INET utility routines + * + * This file implements the routines in sin_util.h + * + * These routines merely make life simpler when working with + * internet protocol sockets + */ +#include "sin_util.h" + +#include <stdio.h> +#include <stdlib.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <arpa/inet.h> +#include <netdb.h> +#include <string.h> + + +#ifdef __cplusplus +extern "C" { +#endif + + +#define ERR_EXIT(mesg, err_num) {perror(mesg);return err_num;} +#define MSG_EXIT(mesg, err_num) {fprintf(stderr, "%s\n", mesg);return err_num;} + + +int sin_init_dot_addr(struct sockaddr_in *sad_in, + char *dot_addr, + unsigned short int port) +{ +sad_in->sin_family = AF_INET; + +if( inet_aton(dot_addr, &(sad_in->sin_addr)) == 0 ) + ERR_EXIT("inet_aton", -1); + +sad_in->sin_port = htons(port); + +return 1; +} /* sin_init_dot_addr */ + + + + + +int sin_init_addr(struct sockaddr_in *addr, + const char *host, + const char *service, + const char *protocol) +/* initialize an address structure */ +{ +int port_flag; +long int tmp_numb; +long long int lli = 1; +char *error_char; + +struct servent *serv_entry_ptr; +struct hostent *host_entry_ptr; + +bzero ((char *)addr, sizeof(*addr)); +addr->sin_family = AF_INET; + +/* Map service name to port number */ +port_flag = 0; +if (port_flag == 0) + if ((service == NULL) || (strcmp(service, "") == 0)) + {addr->sin_port = htons(0); /* OS will sugest a port when binding */ + port_flag = 1; + } + +if (port_flag == 0) + if ((serv_entry_ptr = getservbyname ((char *)service, (char *)protocol)) ) + {addr->sin_port = serv_entry_ptr->s_port; + port_flag = 1; + } + +if (port_flag == 0) + {tmp_numb = strtol(service, &error_char, 0); + if ((*error_char == '\0') && (error_char != service) && + (tmp_numb >= 0) && (tmp_numb < (lli << (8*sizeof(addr->sin_port))))) + {addr->sin_port = htons(tmp_numb); + port_flag = 1; + } + } + +if (port_flag == 0) + MSG_EXIT("sin_init_addr: Could not determine the port number.", -1); + +/* Map host name to IP address, allowing dotted decimal */ +addr->sin_addr.s_addr = INADDR_NONE; + +if (addr->sin_addr.s_addr == INADDR_NONE) + if ( (host_entry_ptr = gethostbyname ((char *)host)) ) + bcopy (host_entry_ptr->h_addr, + (char *)&(addr->sin_addr), + host_entry_ptr->h_length); + +if (addr->sin_addr.s_addr == INADDR_NONE) + inet_aton (host, (struct in_addr *)addr); + +if (addr->sin_addr.s_addr == INADDR_NONE) + MSG_EXIT("sin_init_addr: Could not determine the host IP address.", -1); + +return 1; +} /* sin_init_addr(...) */ + + + + +int sin_init_proto(int *type, + int *protocol_num, + const char *protocol) +{ +struct protoent *proto_entry_ptr; + +/* determine the protocol */ +*type = SOCK_RDM; +if (strcasecmp (protocol, "udp") == 0) *type = SOCK_DGRAM; +if (strcasecmp (protocol, "tcp") == 0) *type = SOCK_STREAM; +if (strcasecmp (protocol, "raw") == 0) *type = SOCK_RAW; +if (*type == SOCK_RDM) + MSG_EXIT ("sin_init_proto: protocol not supported.", -1); + +/* map protocol name to protocol number */ +if ( (proto_entry_ptr = getprotobyname ((char *)protocol)) == NULL ) + MSG_EXIT ("sin_init_proto: can't get protocol number.", -1); +*protocol_num = proto_entry_ptr->p_proto; + +return 1; +} /* sin_init_proto(...) */ + + +int bind_socket(const char *host, + const char *service, + const char *protocol) +/* create a socket and bind to a local port */ +{ +struct sockaddr_in sock_addr; +int socket_id, type, protocol_num; + +/* initialize the sock_addr sturcture */ +if ( (sin_init_addr (&sock_addr, host, service, protocol)) < 0) + MSG_EXIT ("bind_socket: wrong address format", -1); + +/* determine the protocol */ +if ( (sin_init_proto (&type, &protocol_num, protocol)) < 0) + MSG_EXIT ("bind_socket: wrong protocol format", -1); + +/* create the socket */ +if ( (socket_id = socket (PF_INET, type, protocol_num)) < 0) + ERR_EXIT ("socket", -1); + +/* bind the socket */ +if ( bind (socket_id, (struct sockaddr *)&sock_addr, sizeof (sock_addr)) < 0) + ERR_EXIT ("bind", -1); + +return socket_id; +} /* bind_socket(...) */ + + + +int connect_socket(const char *host, + const char *service, + const char *protocol) +/* create a socket and connect to a remote host */ +{ +struct sockaddr_in sock_addr; +int socket_id, type, protocol_num; + +/* initialize the sock_addr sturcture */ +if ( (sin_init_addr (&sock_addr, host, service, protocol)) < 0) + MSG_EXIT ("bind_socket: wrong address format", -1); + +/* determine the protocol */ +if ( (sin_init_proto (&type, &protocol_num, protocol)) < 0) + MSG_EXIT ("bind_socket: wrong protocol format", -1); + +/* create the socket */ +if ( (socket_id = socket (PF_INET, type, protocol_num)) < 0) + ERR_EXIT ("socket", -1); + +/* bind the socket */ +if ( connect(socket_id, (struct sockaddr *)&sock_addr, sizeof (sock_addr)) < 0) + ERR_EXIT ("bind", -1); + +return socket_id; +} /* connect_socket(...) */ + + + +int get_socket_port(int sock) +/* returns the port to which the socket is bound */ +{ + int length; + struct sockaddr_in srv_addr; + + length = sizeof(srv_addr); + if (getsockname(sock, (struct sockaddr *)&srv_addr, (socklen_t *)&length) < 0) + return -1; + + if (srv_addr.sin_family == AF_INET) + return ntohs(srv_addr.sin_port); + + return -1; /* not INET socket... */ +} /* get_socket_port(...) */ + +#ifdef __cplusplus +} +#endif diff --git a/silecs-communication-cpp/src/silecs-communication/protocol/modbus/sin_util.h b/silecs-communication-cpp/src/silecs-communication/protocol/modbus/sin_util.h new file mode 100644 index 0000000..5e6a6b6 --- /dev/null +++ b/silecs-communication-cpp/src/silecs-communication/protocol/modbus/sin_util.h @@ -0,0 +1,59 @@ +/* + * (c) 2000 Jiri Baum + * Mario de Sousa + * + * Offered to the public 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. + * + * This code is made available on the understanding that it will not be + * used in safety-critical situations without a full and competent review. + */ + + +#ifndef SIN_UTIL_H +#define SIN_UTIL_H + +#ifdef __cplusplus +extern "C" { +#endif + + +#include <sys/types.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <arpa/inet.h> + + + +int sin_init_addr(struct sockaddr_in *addr, + const char *host, + const char *service, + const char *protocol); +/* initialize an address structure */ + + +int bind_socket(const char *host, + const char *service, + const char *protocol); +/* create a socket and bind to a local port */ + + +int connect_socket(const char *host, + const char *service, + const char *protocol); +/* create a socket and connect to a remote host */ + + +int get_socket_port(int sock); +/* returns the port to which the socket is bound */ + +#ifdef __cplusplus +} +#endif +#endif diff --git a/silecs-communication-cpp/src/silecs-communication/wrapper/Block.h b/silecs-communication-cpp/src/silecs-communication/wrapper/Block.h new file mode 100644 index 0000000..c1e1300 --- /dev/null +++ b/silecs-communication-cpp/src/silecs-communication/wrapper/Block.h @@ -0,0 +1,46 @@ +// Copyright 2016 CERN and GSI +// +// 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 3 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, see <http://www.gnu.org/licenses/>. + +#ifndef SILECSWRAPER_BLOCK_H_ +#define SILECSWRAPER_BLOCK_H_ + +#include <string> + +namespace SilecsWrapper +{ +class Block +{ +public: + Block(const std::string& name) : + _name(name) + { + } + + virtual ~Block() + { + } + + const std::string& getName() const + { + return _name; + } + +protected: + const std::string _name; +}; + +} //namespace SilecsWrapper + +#endif diff --git a/silecs-communication-cpp/src/silecs-communication/wrapper/Controller.cpp b/silecs-communication-cpp/src/silecs-communication/wrapper/Controller.cpp new file mode 100644 index 0000000..73d19dd --- /dev/null +++ b/silecs-communication-cpp/src/silecs-communication/wrapper/Controller.cpp @@ -0,0 +1,52 @@ +// Copyright 2016 CERN and GSI +// +// 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 3 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, see <http://www.gnu.org/licenses/>. + +#include <silecs-communication/wrapper/Controller.h> +#include <silecs-communication/wrapper/Design.h> + +namespace SilecsWrapper +{ + +Controller::Controller(const std::string& name, const std::string& domain, Design *design, const std::string parameterFile) : + _name(name), + _domain(domain), + _silecsPLC(design->getSilecsCluster()->getPLC(_name, parameterFile)) +{ + +} + +Controller::~Controller() +{ + +} + +void Controller::connect() +{ + //By default: Controller connected right-away and Master registers download. + _silecsPLC->connect(Silecs::MASTER_SYNCHRO, true); +} + +void Controller::connect(Silecs::SynchroMode synchroMode, bool connectNow) +{ + //Connect parameters can be set in manual connection mode (Automatic connect==false) + _silecsPLC->connect(synchroMode, connectNow); +} + +void Controller::disconnect() +{ + _silecsPLC->disconnect(); +} + +} //namespace SilecsWrapper diff --git a/silecs-communication-cpp/src/silecs-communication/wrapper/Controller.h b/silecs-communication-cpp/src/silecs-communication/wrapper/Controller.h new file mode 100644 index 0000000..ec4f74f --- /dev/null +++ b/silecs-communication-cpp/src/silecs-communication/wrapper/Controller.h @@ -0,0 +1,64 @@ +// Copyright 2016 CERN and GSI +// +// 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 3 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, see <http://www.gnu.org/licenses/>. + +#ifndef SILECSWRAPER_CONTROLLER_H_ +#define SILECSWRAPER_CONTROLLER_H_ + +#include <silecs-communication/interface/equipment/SilecsPLC.h> + +#include <string> + +namespace SilecsWrapper +{ + +class Design; + +class Controller +{ +public: + Controller(const std::string& name, const std::string& domain, Design *design,const std::string parameterFile); + + const std::string& getName() const + { + return _name; + } + + Silecs::PLC* getSilecsPLC() + { + return _silecsPLC; + } + + void connect(); + void connect(Silecs::SynchroMode synchroMode, bool connectNow); + + void disconnect(); + + virtual ~Controller(); + +protected: + const std::string _name; + const std::string _domain; + + Silecs::PLC* _silecsPLC; + +private: + // Non copyable + Controller(const Controller& other); + Controller& operator=(const Controller&); +}; + +} //namespace SilecsWrapper + +#endif diff --git a/silecs-communication-cpp/src/silecs-communication/wrapper/DeployUnit.cpp b/silecs-communication-cpp/src/silecs-communication/wrapper/DeployUnit.cpp new file mode 100644 index 0000000..a73e1dc --- /dev/null +++ b/silecs-communication-cpp/src/silecs-communication/wrapper/DeployUnit.cpp @@ -0,0 +1,98 @@ +// Copyright 2016 CERN and GSI +// +// 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 3 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, see <http://www.gnu.org/licenses/>. + +#include <silecs-communication/wrapper/DeployUnit.h> + +namespace SilecsWrapper +{ + +DeployConfig::DeployConfig() : + _automaticConnect(true) +{ +} + +DeployConfig::DeployConfig(bool automaticConnect) : + _automaticConnect(automaticConnect) +{ +} + +bool DeployConfig::getAutomaticConnect() const +{ + return _automaticConnect; +} + +void DeployConfig::setAutomaticConnect(bool automaticConnect) +{ + _automaticConnect = automaticConnect; +} + +//=============================================== + +DeployUnit* DeployUnit::_instance = NULL; +//SilecsWrapper::DeployConfig DeployUnit::_globalConfig = SilecsWrapper::DeployConfig(); + +DeployUnit::DeployUnit(const std::string& name, const std::string& version, const std::string& logTopics,const DeployConfig& globalConfig) : + _name(name), + _version(version), + _globalConfig(globalConfig) +{ + // Process log topics + char *argv[2] = + { (char *) "-plcLog", const_cast<char*>(logTopics.c_str()) }; + + // Get singleton instance + _silecsService = Silecs::Service::getInstance(2, argv); +} + +void DeployUnit::deleteInstance() +{ + if (_instance != NULL) + { + delete _instance; + _instance = NULL; + } +} + +const std::string& DeployUnit::getName() const +{ + return _name; +} + +const std::string& DeployUnit::getVersion() const +{ + return _version; +} + +Silecs::Service* DeployUnit::getService() const +{ + return _silecsService; +} + +DeployConfig& DeployUnit::getGlobalConfig() +{ + return _globalConfig; +} + +void DeployUnit::setGlobalConfig(DeployConfig& globalConfig) +{ + _globalConfig = globalConfig; +} + +DeployUnit::~DeployUnit() +{ +} + +} + //namespace SilecsWrapper diff --git a/silecs-communication-cpp/src/silecs-communication/wrapper/DeployUnit.h b/silecs-communication-cpp/src/silecs-communication/wrapper/DeployUnit.h new file mode 100644 index 0000000..2902536 --- /dev/null +++ b/silecs-communication-cpp/src/silecs-communication/wrapper/DeployUnit.h @@ -0,0 +1,72 @@ +// Copyright 2016 CERN and GSI +// +// 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 3 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, see <http://www.gnu.org/licenses/>. + +#ifndef SILECSWRAPER_DEPLOY_UNIT_H_ +#define SILECSWRAPER_DEPLOY_UNIT_H_ + +#include <silecs-communication/interface/core/SilecsService.h> + +#include <string> + +namespace SilecsWrapper +{ + + class DeployConfig + { + public: + DeployConfig(); + DeployConfig(bool automaticConnect); + bool getAutomaticConnect() const; + void setAutomaticConnect(bool automaticConnect); + + private: + bool _automaticConnect; + + }; + + class DeployUnit + { + public: + DeployUnit(const std::string& name, const std::string& version, const std::string& logTopics, + const DeployConfig& globalConfig); + virtual ~DeployUnit(); + + void deleteInstance(); + + const std::string& getName() const; + const std::string& getVersion() const; + Silecs::Service* getService() const; + DeployConfig& getGlobalConfig(); + + void setGlobalConfig(DeployConfig& globalConfig); + + protected: + const std::string _name; + const std::string _version; + DeployConfig _globalConfig; + Silecs::Service* _silecsService; + //singleton instance + static DeployUnit* _instance; + + private: + // Non copyable + DeployUnit(const DeployUnit& other); + DeployUnit& operator=(const DeployUnit&); + + }; + +} //namespace SilecsWrapper + +#endif diff --git a/silecs-communication-cpp/src/silecs-communication/wrapper/Design.cpp b/silecs-communication-cpp/src/silecs-communication/wrapper/Design.cpp new file mode 100644 index 0000000..415b346 --- /dev/null +++ b/silecs-communication-cpp/src/silecs-communication/wrapper/Design.cpp @@ -0,0 +1,77 @@ +// Copyright 2016 CERN and GSI +// +// 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 3 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, see <http://www.gnu.org/licenses/>. + +#include <silecs-communication/wrapper/DeployUnit.h> +#include <silecs-communication/wrapper/Design.h> + +namespace SilecsWrapper +{ + +Design::Design(const std::string& name, const std::string& version, DeployUnit *deployUnit) : + _name(name), + _version(version), + _deployUnit(deployUnit) +{ + _silecsCluster = _deployUnit->getService()->getCluster(_name, _version); +} + +Design::~Design() +{ + +} + +const std::string& Design::getName() const +{ + return _name; +} + +const std::string& Design::getVersion() const +{ + return _version; +} + +Silecs::Cluster* Design::getSilecsCluster() const +{ + return _silecsCluster; +} + +DeployUnit* Design::getDeployUnit() const +{ + return _deployUnit; +} + +void Design::setConfiguration(const DesignConfig& configuration) +{ + Silecs::plcMapType plcMap = _silecsCluster->getPLCMap(); + Silecs::plcMapType::iterator plcMapIter; + for (plcMapIter = plcMap.begin(); plcMapIter != plcMap.end(); ++plcMapIter) + { + //if (plcMapIter->second->isConnected({*connectNow = *}false)) + if (plcMapIter->second->isEnabled()) + { + //at least one PLC is already enabled (PLC object created). Does not make sense to set configuration after. + throw Silecs::SilecsException(__FILE__, __LINE__, Silecs::COMM_ALREADY_ENABLED, + std::string("Design configuration must be set before instantiating any controller! Disable the 'Automatic connect' flag of the deploy configuration if needed.")); + } + } + _silecsCluster->configuration = configuration; +} + +const DesignConfig& Design::getConfiguration() +{ + return _silecsCluster->configuration; +} + +} //namespace SilecsWrapper diff --git a/silecs-communication-cpp/src/silecs-communication/wrapper/Design.h b/silecs-communication-cpp/src/silecs-communication/wrapper/Design.h new file mode 100644 index 0000000..ded6b7a --- /dev/null +++ b/silecs-communication-cpp/src/silecs-communication/wrapper/Design.h @@ -0,0 +1,65 @@ +// Copyright 2016 CERN and GSI +// +// 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 3 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, see <http://www.gnu.org/licenses/>. + +#ifndef SILECSWRAPER_DESIGN_H_ +#define SILECSWRAPER_DESIGN_H_ + +#include <silecs-communication/interface/equipment/SilecsCluster.h> +#include <silecs-communication/wrapper/DeployUnit.h> + +#include <string> + +namespace SilecsWrapper +{ +class DeployUnit; +class Controller; + +typedef Silecs::ClusterConfig DesignConfig; + +class Design +{ +public: + Design(const std::string& name, const std::string& version, DeployUnit *deployUnit); + + const std::string& getName() const; + + const std::string& getVersion() const; + + Silecs::Cluster* getSilecsCluster() const; + + DeployUnit* getDeployUnit() const; + + void setConfiguration(const DesignConfig& configuration); + + const DesignConfig& getConfiguration(); + + virtual ~Design(); + +protected: + const std::string _name; + const std::string _version; + DeployUnit* _deployUnit; + Silecs::Cluster* _silecsCluster; + const DeployConfig _config; + +private: + // Non copyable + Design(const Design& other); + Design& operator=(const Design&); +}; + +} //namespace SilecsWrapper + +#endif diff --git a/silecs-communication-cpp/src/silecs-communication/wrapper/Device.h b/silecs-communication-cpp/src/silecs-communication/wrapper/Device.h new file mode 100644 index 0000000..774cb71 --- /dev/null +++ b/silecs-communication-cpp/src/silecs-communication/wrapper/Device.h @@ -0,0 +1,65 @@ +// Copyright 2016 CERN and GSI +// +// 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 3 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, see <http://www.gnu.org/licenses/>. + +#ifndef SILECSWRAPER_DEVICE_H_ +#define SILECSWRAPER_DEVICE_H_ + +#include <silecs-communication/interface/core/SilecsService.h> +#include <silecs-communication/interface/equipment/SilecsDevice.h> +#include <silecs-communication/wrapper/Controller.h> + +#include <string> + +namespace SilecsWrapper +{ + +class Device +{ +public: + Device(const std::string& label, Controller *controller) : + _label(label), + _controller(controller) + { + _silecsDevice = _controller->getSilecsPLC()->getDevice(label); + } + + const std::string& getLabel() const + { + return _label; + } + + Silecs::Device* getSilecsDevice() + { + return _silecsDevice; + } + + virtual ~Device() + { + } + +protected: + std::string _label; + Controller* _controller; + Silecs::Device* _silecsDevice; + +private: + // Non copyable + Device(const Device& other); + Device& operator=(const Device&); +}; + +} //namespace SilecsWrapper + +#endif diff --git a/silecs-diagnostic-cpp/.cproject b/silecs-diagnostic-cpp/.cproject new file mode 100644 index 0000000..bf123f3 --- /dev/null +++ b/silecs-diagnostic-cpp/.cproject @@ -0,0 +1,160 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<?fileVersion 4.0.0?><cproject storage_type_id="org.eclipse.cdt.core.XmlProjectDescriptionStorage"> + <storageModule moduleId="org.eclipse.cdt.core.settings"> + <cconfiguration id="cdt.managedbuild.config.gnu.exe.debug.1063983837"> + <storageModule buildSystemId="org.eclipse.cdt.managedbuilder.core.configurationDataProvider" id="cdt.managedbuild.config.gnu.exe.debug.1063983837" moduleId="org.eclipse.cdt.core.settings" name="Debug"> + <externalSettings/> + <extensions> + <extension id="org.eclipse.cdt.core.ELF" point="org.eclipse.cdt.core.BinaryParser"/> + <extension id="org.eclipse.cdt.core.GASErrorParser" point="org.eclipse.cdt.core.ErrorParser"/> + <extension id="org.eclipse.cdt.core.GmakeErrorParser" point="org.eclipse.cdt.core.ErrorParser"/> + <extension id="org.eclipse.cdt.core.GLDErrorParser" point="org.eclipse.cdt.core.ErrorParser"/> + <extension id="org.eclipse.cdt.core.CWDLocator" point="org.eclipse.cdt.core.ErrorParser"/> + <extension id="org.eclipse.cdt.core.GCCErrorParser" point="org.eclipse.cdt.core.ErrorParser"/> + </extensions> + </storageModule> + <storageModule moduleId="cdtBuildSystem" version="4.0.0"> + <configuration artifactName="${ProjName}" buildArtefactType="org.eclipse.cdt.build.core.buildArtefactType.exe" buildProperties="org.eclipse.cdt.build.core.buildArtefactType=org.eclipse.cdt.build.core.buildArtefactType.exe,org.eclipse.cdt.build.core.buildType=org.eclipse.cdt.build.core.buildType.debug" cleanCommand="rm -rf" description="" id="cdt.managedbuild.config.gnu.exe.debug.1063983837" name="Debug" parent="cdt.managedbuild.config.gnu.exe.debug"> + <folderInfo id="cdt.managedbuild.config.gnu.exe.debug.1063983837." name="/" resourcePath=""> + <toolChain id="cdt.managedbuild.toolchain.gnu.exe.debug.940654093" name="Linux GCC" superClass="cdt.managedbuild.toolchain.gnu.exe.debug"> + <targetPlatform id="cdt.managedbuild.target.gnu.platform.exe.debug.530430318" name="Debug Platform" superClass="cdt.managedbuild.target.gnu.platform.exe.debug"/> + <builder buildPath="${workspace_loc:/silecs-diagnostic-cpp}" id="cdt.managedbuild.target.gnu.builder.exe.debug.153658845" keepEnvironmentInBuildfile="false" managedBuildOn="false" name="Gnu Make Builder" superClass="cdt.managedbuild.target.gnu.builder.exe.debug"/> + <tool id="cdt.managedbuild.tool.gnu.archiver.base.160739010" name="GCC Archiver" superClass="cdt.managedbuild.tool.gnu.archiver.base"/> + <tool id="cdt.managedbuild.tool.gnu.cpp.compiler.exe.debug.1203858904" name="GCC C++ Compiler" superClass="cdt.managedbuild.tool.gnu.cpp.compiler.exe.debug"> + <option id="gnu.cpp.compiler.exe.debug.option.optimization.level.894792522" name="Optimization Level" superClass="gnu.cpp.compiler.exe.debug.option.optimization.level" value="gnu.cpp.compiler.optimization.level.none" valueType="enumerated"/> + <option id="gnu.cpp.compiler.exe.debug.option.debugging.level.2108944082" name="Debug Level" superClass="gnu.cpp.compiler.exe.debug.option.debugging.level" value="gnu.cpp.compiler.debugging.level.max" valueType="enumerated"/> + <option id="gnu.cpp.compiler.option.include.paths.464457323" name="Include paths (-I)" superClass="gnu.cpp.compiler.option.include.paths" valueType="includePath"> + <listOptionValue builtIn="false" value=""${workspace_loc:/silecs-communication-cpp/build/include}""/> + <listOptionValue builtIn="false" value="/usr/lib64/qt4/mkspecs/linux-g++-64"/> + <listOptionValue builtIn="false" value="/usr/include/QtCore"/> + <listOptionValue builtIn="false" value="/usr/include/QtGui"/> + <listOptionValue builtIn="false" value="/acc/local/L866/cmw/cmw-rbac/6.1.0/include"/> + </option> + <option id="gnu.cpp.compiler.option.preprocessor.def.1628203586" name="Defined symbols (-D)" superClass="gnu.cpp.compiler.option.preprocessor.def" valueType="definedSymbols"> + <listOptionValue builtIn="false" value="WITH_RBAC=1"/> + </option> + <inputType id="cdt.managedbuild.tool.gnu.cpp.compiler.input.2102143749" superClass="cdt.managedbuild.tool.gnu.cpp.compiler.input"/> + </tool> + <tool id="cdt.managedbuild.tool.gnu.c.compiler.exe.debug.77525709" name="GCC C Compiler" superClass="cdt.managedbuild.tool.gnu.c.compiler.exe.debug"> + <option defaultValue="gnu.c.optimization.level.none" id="gnu.c.compiler.exe.debug.option.optimization.level.2144307006" name="Optimization Level" superClass="gnu.c.compiler.exe.debug.option.optimization.level" valueType="enumerated"/> + <option id="gnu.c.compiler.exe.debug.option.debugging.level.1892440763" name="Debug Level" superClass="gnu.c.compiler.exe.debug.option.debugging.level" value="gnu.c.debugging.level.max" valueType="enumerated"/> + <inputType id="cdt.managedbuild.tool.gnu.c.compiler.input.2107742755" superClass="cdt.managedbuild.tool.gnu.c.compiler.input"/> + </tool> + <tool id="cdt.managedbuild.tool.gnu.c.linker.exe.debug.790245700" name="GCC C Linker" superClass="cdt.managedbuild.tool.gnu.c.linker.exe.debug"/> + <tool id="cdt.managedbuild.tool.gnu.cpp.linker.exe.debug.257658351" name="GCC C++ Linker" superClass="cdt.managedbuild.tool.gnu.cpp.linker.exe.debug"> + <inputType id="cdt.managedbuild.tool.gnu.cpp.linker.input.789035040" superClass="cdt.managedbuild.tool.gnu.cpp.linker.input"> + <additionalInput kind="additionalinputdependency" paths="$(USER_OBJS)"/> + <additionalInput kind="additionalinput" paths="$(LIBS)"/> + </inputType> + </tool> + <tool id="cdt.managedbuild.tool.gnu.assembler.exe.debug.2055585130" name="GCC Assembler" superClass="cdt.managedbuild.tool.gnu.assembler.exe.debug"> + <inputType id="cdt.managedbuild.tool.gnu.assembler.input.2041912470" superClass="cdt.managedbuild.tool.gnu.assembler.input"/> + </tool> + </toolChain> + </folderInfo> + <sourceEntries> + <entry excluding="src" flags="VALUE_WORKSPACE_PATH|RESOLVED" kind="sourcePath" name=""/> + <entry flags="VALUE_WORKSPACE_PATH|RESOLVED" kind="sourcePath" name="src"/> + </sourceEntries> + </configuration> + </storageModule> + <storageModule moduleId="org.eclipse.cdt.core.externalSettings"/> + </cconfiguration> + <cconfiguration id="cdt.managedbuild.config.gnu.exe.release.1657185205"> + <storageModule buildSystemId="org.eclipse.cdt.managedbuilder.core.configurationDataProvider" id="cdt.managedbuild.config.gnu.exe.release.1657185205" moduleId="org.eclipse.cdt.core.settings" name="Release"> + <externalSettings/> + <extensions> + <extension id="org.eclipse.cdt.core.ELF" point="org.eclipse.cdt.core.BinaryParser"/> + <extension id="org.eclipse.cdt.core.GASErrorParser" point="org.eclipse.cdt.core.ErrorParser"/> + <extension id="org.eclipse.cdt.core.GmakeErrorParser" point="org.eclipse.cdt.core.ErrorParser"/> + <extension id="org.eclipse.cdt.core.GLDErrorParser" point="org.eclipse.cdt.core.ErrorParser"/> + <extension id="org.eclipse.cdt.core.CWDLocator" point="org.eclipse.cdt.core.ErrorParser"/> + <extension id="org.eclipse.cdt.core.GCCErrorParser" point="org.eclipse.cdt.core.ErrorParser"/> + </extensions> + </storageModule> + <storageModule moduleId="cdtBuildSystem" version="4.0.0"> + <configuration artifactName="${ProjName}" buildArtefactType="org.eclipse.cdt.build.core.buildArtefactType.exe" buildProperties="org.eclipse.cdt.build.core.buildArtefactType=org.eclipse.cdt.build.core.buildArtefactType.exe,org.eclipse.cdt.build.core.buildType=org.eclipse.cdt.build.core.buildType.release" cleanCommand="rm -rf" description="" id="cdt.managedbuild.config.gnu.exe.release.1657185205" name="Release" parent="cdt.managedbuild.config.gnu.exe.release"> + <folderInfo id="cdt.managedbuild.config.gnu.exe.release.1657185205." name="/" resourcePath=""> + <toolChain id="cdt.managedbuild.toolchain.gnu.exe.release.560150810" name="Linux GCC" superClass="cdt.managedbuild.toolchain.gnu.exe.release"> + <targetPlatform id="cdt.managedbuild.target.gnu.platform.exe.release.912642921" name="Debug Platform" superClass="cdt.managedbuild.target.gnu.platform.exe.release"/> + <builder buildPath="${workspace_loc:/silecs-diagnostic-cpp}/Release" id="cdt.managedbuild.target.gnu.builder.exe.release.1380387983" keepEnvironmentInBuildfile="false" managedBuildOn="true" name="Gnu Make Builder" superClass="cdt.managedbuild.target.gnu.builder.exe.release"/> + <tool id="cdt.managedbuild.tool.gnu.archiver.base.778967991" name="GCC Archiver" superClass="cdt.managedbuild.tool.gnu.archiver.base"/> + <tool id="cdt.managedbuild.tool.gnu.cpp.compiler.exe.release.1778190641" name="GCC C++ Compiler" superClass="cdt.managedbuild.tool.gnu.cpp.compiler.exe.release"> + <option id="gnu.cpp.compiler.exe.release.option.optimization.level.398288828" name="Optimization Level" superClass="gnu.cpp.compiler.exe.release.option.optimization.level" value="gnu.cpp.compiler.optimization.level.most" valueType="enumerated"/> + <option id="gnu.cpp.compiler.exe.release.option.debugging.level.1708164638" name="Debug Level" superClass="gnu.cpp.compiler.exe.release.option.debugging.level" value="gnu.cpp.compiler.debugging.level.none" valueType="enumerated"/> + <inputType id="cdt.managedbuild.tool.gnu.cpp.compiler.input.21478264" superClass="cdt.managedbuild.tool.gnu.cpp.compiler.input"/> + </tool> + <tool id="cdt.managedbuild.tool.gnu.c.compiler.exe.release.360129580" name="GCC C Compiler" superClass="cdt.managedbuild.tool.gnu.c.compiler.exe.release"> + <option defaultValue="gnu.c.optimization.level.most" id="gnu.c.compiler.exe.release.option.optimization.level.1415471960" name="Optimization Level" superClass="gnu.c.compiler.exe.release.option.optimization.level" valueType="enumerated"/> + <option id="gnu.c.compiler.exe.release.option.debugging.level.2119369567" name="Debug Level" superClass="gnu.c.compiler.exe.release.option.debugging.level" value="gnu.c.debugging.level.none" valueType="enumerated"/> + <inputType id="cdt.managedbuild.tool.gnu.c.compiler.input.1744674238" superClass="cdt.managedbuild.tool.gnu.c.compiler.input"/> + </tool> + <tool id="cdt.managedbuild.tool.gnu.c.linker.exe.release.1223430146" name="GCC C Linker" superClass="cdt.managedbuild.tool.gnu.c.linker.exe.release"/> + <tool id="cdt.managedbuild.tool.gnu.cpp.linker.exe.release.888395652" name="GCC C++ Linker" superClass="cdt.managedbuild.tool.gnu.cpp.linker.exe.release"> + <inputType id="cdt.managedbuild.tool.gnu.cpp.linker.input.1851287355" superClass="cdt.managedbuild.tool.gnu.cpp.linker.input"> + <additionalInput kind="additionalinputdependency" paths="$(USER_OBJS)"/> + <additionalInput kind="additionalinput" paths="$(LIBS)"/> + </inputType> + </tool> + <tool id="cdt.managedbuild.tool.gnu.assembler.exe.release.41779867" name="GCC Assembler" superClass="cdt.managedbuild.tool.gnu.assembler.exe.release"> + <inputType id="cdt.managedbuild.tool.gnu.assembler.input.727371022" superClass="cdt.managedbuild.tool.gnu.assembler.input"/> + </tool> + </toolChain> + </folderInfo> + <sourceEntries> + <entry excluding="src" flags="VALUE_WORKSPACE_PATH|RESOLVED" kind="sourcePath" name=""/> + <entry flags="VALUE_WORKSPACE_PATH|RESOLVED" kind="sourcePath" name="src"/> + </sourceEntries> + </configuration> + </storageModule> + <storageModule moduleId="org.eclipse.cdt.core.externalSettings"/> + </cconfiguration> + </storageModule> + <storageModule moduleId="cdtBuildSystem" version="4.0.0"> + <project id="silecs-diagnostic-cpp.cdt.managedbuild.target.gnu.exe.694059999" name="Executable" projectType="cdt.managedbuild.target.gnu.exe"/> + </storageModule> + <storageModule moduleId="scannerConfiguration"> + <autodiscovery enabled="true" problemReportingEnabled="true" selectedProfileId=""/> + <scannerConfigBuildInfo instanceId="cdt.managedbuild.config.gnu.exe.release.1657185205;cdt.managedbuild.config.gnu.exe.release.1657185205.;cdt.managedbuild.tool.gnu.c.compiler.exe.release.360129580;cdt.managedbuild.tool.gnu.c.compiler.input.1744674238"> + <autodiscovery enabled="true" problemReportingEnabled="true" selectedProfileId=""/> + </scannerConfigBuildInfo> + <scannerConfigBuildInfo instanceId="cdt.managedbuild.config.gnu.exe.release.1657185205;cdt.managedbuild.config.gnu.exe.release.1657185205.;cdt.managedbuild.tool.gnu.cpp.compiler.exe.release.1778190641;cdt.managedbuild.tool.gnu.cpp.compiler.input.21478264"> + <autodiscovery enabled="true" problemReportingEnabled="true" selectedProfileId=""/> + </scannerConfigBuildInfo> + <scannerConfigBuildInfo instanceId="cdt.managedbuild.config.gnu.exe.debug.1063983837;cdt.managedbuild.config.gnu.exe.debug.1063983837.;cdt.managedbuild.tool.gnu.cpp.compiler.exe.debug.1203858904;cdt.managedbuild.tool.gnu.cpp.compiler.input.2102143749"> + <autodiscovery enabled="true" problemReportingEnabled="true" selectedProfileId=""/> + </scannerConfigBuildInfo> + <scannerConfigBuildInfo instanceId="cdt.managedbuild.config.gnu.exe.debug.1063983837;cdt.managedbuild.config.gnu.exe.debug.1063983837.;cdt.managedbuild.tool.gnu.c.compiler.exe.debug.77525709;cdt.managedbuild.tool.gnu.c.compiler.input.2107742755"> + <autodiscovery enabled="true" problemReportingEnabled="true" selectedProfileId=""/> + </scannerConfigBuildInfo> + </storageModule> + <storageModule moduleId="org.eclipse.cdt.core.LanguageSettingsProviders"/> + <storageModule moduleId="refreshScope" versionNumber="2"> + <configuration configurationName="Debug"> + <resource resourceType="PROJECT" workspacePath="/silecs-diagnostic-cpp"/> + </configuration> + <configuration configurationName="Release"> + <resource resourceType="PROJECT" workspacePath="/silecs-diagnostic-cpp"/> + </configuration> + </storageModule> + <storageModule moduleId="org.eclipse.cdt.make.core.buildtargets"> + <buildTargets> + <target name="clean LOCAL" path="" targetID="org.eclipse.cdt.build.MakeTargetBuilder"> + <buildCommand>make</buildCommand> + <buildArguments/> + <buildTarget>clean LOCAL=TRUE</buildTarget> + <stopOnError>true</stopOnError> + <useDefaultCommand>true</useDefaultCommand> + <runAllBuilders>true</runAllBuilders> + </target> + <target name="x86_64 LOCAL" path="" targetID="org.eclipse.cdt.build.MakeTargetBuilder"> + <buildCommand>make</buildCommand> + <buildArguments/> + <buildTarget>CPU=x86_64 -j1 LOCAL=TRUE</buildTarget> + <stopOnError>true</stopOnError> + <useDefaultCommand>true</useDefaultCommand> + <runAllBuilders>true</runAllBuilders> + </target> + </buildTargets> + </storageModule> +</cproject> diff --git a/silecs-diagnostic-cpp/.project b/silecs-diagnostic-cpp/.project new file mode 100644 index 0000000..ba5f221 --- /dev/null +++ b/silecs-diagnostic-cpp/.project @@ -0,0 +1,27 @@ +<?xml version="1.0" encoding="UTF-8"?> +<projectDescription> + <name>silecs-diagnostic-cpp</name> + <comment></comment> + <projects> + </projects> + <buildSpec> + <buildCommand> + <name>org.eclipse.cdt.managedbuilder.core.genmakebuilder</name> + <triggers>clean,full,incremental,</triggers> + <arguments> + </arguments> + </buildCommand> + <buildCommand> + <name>org.eclipse.cdt.managedbuilder.core.ScannerConfigBuilder</name> + <triggers>full,incremental,</triggers> + <arguments> + </arguments> + </buildCommand> + </buildSpec> + <natures> + <nature>org.eclipse.cdt.core.cnature</nature> + <nature>org.eclipse.cdt.core.ccnature</nature> + <nature>org.eclipse.cdt.managedbuilder.core.managedBuildNature</nature> + <nature>org.eclipse.cdt.managedbuilder.core.ScannerConfigNature</nature> + </natures> +</projectDescription> diff --git a/silecs-diagnostic-cpp/LICENSE b/silecs-diagnostic-cpp/LICENSE new file mode 100644 index 0000000..20d40b6 --- /dev/null +++ b/silecs-diagnostic-cpp/LICENSE @@ -0,0 +1,674 @@ + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/> + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + <one line to give the program's name and a brief idea of what it does.> + Copyright (C) <year> <name of author> + + 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 3 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, see <http://www.gnu.org/licenses/>. + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + <program> Copyright (C) <year> <name of author> + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +<http://www.gnu.org/licenses/>. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +<http://www.gnu.org/philosophy/why-not-lgpl.html>. \ No newline at end of file diff --git a/silecs-diagnostic-cpp/Makefile b/silecs-diagnostic-cpp/Makefile new file mode 100644 index 0000000..6ce3be8 --- /dev/null +++ b/silecs-diagnostic-cpp/Makefile @@ -0,0 +1,63 @@ +# Copyright 2016 CERN and GSI +# +# 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 3 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, see <http://www.gnu.org/licenses/>. + +PROJECT = silecs +PRODUCT = diagnostic +VERSION = 1.0.2 + +COMMON_MAKE_PATH ?= /opt/cern/buildsystem/generic/2.8.20 + +# product configuration +BIN_NAME = $(PROJECT)-$(PRODUCT) +DBG = false + +#DEFINES = -DWITH_RBAC -D_REENTRANT -DQT_NO_DEBUG_OUTPUT -DQT_NO_WARNING_OUTPUT -DQT_NO_DEBUG -DQT_GUI_LIB -DQT_CORE_LIB -DQT_SHARED +DEFINES = -D_REENTRANT -DQT_NO_DEBUG_OUTPUT -DQT_NO_WARNING_OUTPUT -DQT_NO_DEBUG -DQT_GUI_LIB -DQT_CORE_LIB -DQT_SHARED +COMPILER_FLAGS = -O2 -Wp,-D_FORTIFY_SOURCE=2 -fstack-protector --param=ssp-buffer-size=4 -mtune=generic $(DEFINES) +LINKER_FLAGS = -Wl,-O1 + +# list Qt generated files +EXTRA_HEADERS = generated/ui_diagnostictoolmainview.h\ + generated/ui_displayarraydialog.h\ + generated/ui_logindialog.h + +EXTRA_SRCS = generated/qrc_images.cpp\ + generated/moc_diagnostictoolmainview.cpp\ + generated/moc_displayarraydialog.cpp\ + generated/moc_logindialog.cpp\ + generated/moc_stderrredirect.cpp + +# Include the generic make file +include $(COMMON_MAKE_PATH)/Make.generic + +QT_RCC = /usr/bin/rcc +QT_UIC = /usr/bin/uic-qt4 +QT_MOC = /usr/bin/moc-qt4 + +# rules to generate Qt files +before_compile:: + $(QT_RCC) -name images src/silecs-diagnostic/resources/images.qrc -o src/silecs-diagnostic/generated/qrc_images.cpp + + $(QT_UIC) src/silecs-diagnostic/resources/gui/diagnostictoolmainview.ui -o src/silecs-diagnostic/generated/ui_diagnostictoolmainview.h + $(QT_UIC) src/silecs-diagnostic/resources/gui/displayarraydialog.ui -o src/silecs-diagnostic/generated/ui_displayarraydialog.h + $(QT_UIC) src/silecs-diagnostic/resources/gui/logindialog.ui -o src/silecs-diagnostic/generated/ui_logindialog.h + + $(QT_MOC) $(DEFINES) $(DEPENDENT_COMPILER_OPTIONS) src/silecs-diagnostic/diagnostictoolmainview.h -o src/silecs-diagnostic/generated/moc_diagnostictoolmainview.cpp + $(QT_MOC) $(DEFINES) $(DEPENDENT_COMPILER_OPTIONS) src/silecs-diagnostic/displayarraydialog.h -o src/silecs-diagnostic/generated/moc_displayarraydialog.cpp + $(QT_MOC) $(DEFINES) $(DEPENDENT_COMPILER_OPTIONS) src/silecs-diagnostic/logindialog.h -o src/silecs-diagnostic/generated/moc_logindialog.cpp + $(QT_MOC) $(DEFINES) $(DEPENDENT_COMPILER_OPTIONS) src/silecs-diagnostic/stderrredirect.h -o src/silecs-diagnostic/generated/moc_stderrredirect.cpp + +after_clean:: + rm -f src/silecs-diagnostic/generated/* \ No newline at end of file diff --git a/silecs-diagnostic-cpp/Makefile.dep b/silecs-diagnostic-cpp/Makefile.dep new file mode 100644 index 0000000..7454b8d --- /dev/null +++ b/silecs-diagnostic-cpp/Makefile.dep @@ -0,0 +1,27 @@ +BOOST_VERSION ?= 1.54.0 +RBAC_VERSION ?= 6.1.0 +SILECS_COMM_VERSION = 1.0.2 + +BOOST_HOME ?= /acc/local/$(CPU)/3rdparty/boost/$(BOOST_VERSION) +RBACK_HOME ?= /acc/local/$(CPU)/cmw/cmw-rbac/$(RBAC_VERSION) + +SILECS_COMM_HOME ?= ../silecs-communication-cpp/build + +LIBXML_PATH = /usr/include/libxml2/ + +SNAP7_BASE = ../snap7/snap7-full + +DEPENDENT_COMPILER_OPTIONS += -I$(RBACK_HOME)/include +DEPENDENT_COMPILER_OPTIONS += -I$(SILECS_COMM_HOME)/include +DEPENDENT_COMPILER_OPTIONS += -I$(LIBXML_PATH) +DEPENDENT_COMPILER_OPTIONS += -I$(BOOST_HOME)/include +DEPENDENT_COMPILER_OPTIONS += -I/usr/lib64/qt4/mkspecs/linux-g++-64 +DEPENDENT_COMPILER_OPTIONS += -I/usr/include/QtCore +DEPENDENT_COMPILER_OPTIONS += -I/usr/include/QtGui + +DEPENDENT_LINKER_OPTIONS += -L$(RBACK_HOME)/lib +DEPENDENT_LINKER_OPTIONS += -L$(SILECS_COMM_HOME)/lib/$(CPU) +DEPENDENT_LINKER_OPTIONS += -L$(SNAP7_BASE)/build/bin/$(CPU)-linux -lsnap7 +DEPENDENT_LINKER_OPTIONS += -L/usr/lib64 -lxml2 +DEPENDENT_LINKER_OPTIONS += -lsilecs-comm +DEPENDENT_LINKER_OPTIONS += -lstdc++ -lxml2 -lcurl -lQtGui -lQtCore diff --git a/silecs-diagnostic-cpp/README.md b/silecs-diagnostic-cpp/README.md new file mode 100644 index 0000000..f16ec42 --- /dev/null +++ b/silecs-diagnostic-cpp/README.md @@ -0,0 +1,19 @@ +# silecs-codegen + +This component of the SILECS PLC-framework allows easy visible access to PLC variables for existing silecs-projects by making use of the package silecs-communication-cpp + +## Getting Started + +Please check the lab-specific SILECS-Wikis for more information: + +[CERN SILECS Wiki Page][CERN_Wiki] + +[GSI SILECS Wiki Page][GSI_Wiki] + +## License + +Licensed under the GNU GENERAL PUBLIC LICENSE Version 3. See the [LICENSE file][license] for details. + +[license]: LICENSE +[CERN_Wiki]: https://wikis.cern.ch/display/SIL/SILECs+Home +[GSI_Wiki]: https://www-acc.gsi.de/wiki/Frontend/SILECS \ No newline at end of file diff --git a/silecs-diagnostic-cpp/SILECS.pro b/silecs-diagnostic-cpp/SILECS.pro new file mode 100644 index 0000000..7891341 --- /dev/null +++ b/silecs-diagnostic-cpp/SILECS.pro @@ -0,0 +1,106 @@ +#------------------------------------------------- +# +# Project created by QtCreator 2011-09-27T14:25:35 +# +#------------------------------------------------- + +QT += core gui +TEMPLATE = app +SOURCES += src/silecs-diagnostic/*.cpp +HEADERS += src/silecs-diagnostic/*.h +FORMS += src/silecs-diagnostic/resources/gui/diagnostictoolmainview.ui \ + src/silecs-diagnostic/resources/gui/displayarraydialog.ui \ + src/silecs-diagnostic/resources/gui/logindialog.ui + +INCLUDEPATH += src/ # Source directory to be included +RESOURCES += src/silecs-diagnostic/resources/images.qrc # Resource file +DESTDIR = bin # Target file directory +OBJECTS_DIR = build # Intermediate object files directory +MOC_DIR = build # Intermediate moc files directory + +UI_DIR = build # Store ui generated source file with other headers +INCLUDEPATH += build/ # Build includes the header for the gui + +# Disable debugger +DEFINES += QT_NO_DEBUG_OUTPUT QT_NO_WARNING_OUTPUT + +# Enable console +CONFIG += console + +# Define RBAC support +#QMAKE_CXXFLAGS += -DWITH_RBAC + +#Settings +CPU = L866 +SILECS_VERSION = 1.m.p +CONFIG += SILECSLOCAL + + +#====================================================== +#------------------TARGET------------------------------ +#====================================================== +equals( CPU, L865 ){ + TARGET = silecs-diagnostic-32 +} else { + TARGET = silecs-diagnostic-64 +} + +#====================================================== +#------------------LIBRARIES--------------------------- +#====================================================== +#RBAC Library +#BOOST_VERSION = 1.54.0 +#RBAC_VERSION = 6.1.0 +#RBAC_HOME = /acc/local/$${CPU}/cmw/cmw-rbac/$${RBAC_VERSION} +#BOOST_HOME = /acc/local/$${CPU}/3rdparty/boost/$${BOOST_VERSION} + +#DEPENDENT_COMPILER_OPTIONS = $${RBAC_HOME}/include \ +# $${BOOST_HOME}/include + +#DEPENDENT_LINKER_OPTIONS = $${RBAC_HOME}/lib/libcmw-rbac.a \ +# $${RBAC_HOME}/lib/libcmw-serializer.a \ +# $${RBAC_HOME}/lib/libcmw-log.a \ +# $${RBAC_HOME}/lib/libcmw-util.a \ +# $${BOOST_HOME}/lib/libboost_1_54_0_thread.a \ +# $${BOOST_HOME}/lib/libboost_1_54_0_system.a \ +# $${BOOST_HOME}/lib/libboost_1_54_0_filesystem.a + +LIBS += -L/usr/lib64 $${DEPENDENT_LINKER_OPTIONS} -lcurl +INCLUDEPATH += $${DEPENDENT_COMPILER_OPTIONS} +DEPENDPATH += $${DEPENDENT_LINKER_OPTIONS} + +#-------SILECS Operational Library------- +SILECSLOCAL{ + SILECS_HOME = ../silecs-communication-cpp/build + message("linking with local silecs library") +} else { + SILECS_HOME = /acc/local/$${CPU}/silecs/$${SILECS_VERSION}/library/ + message("linking with operational silecs library") +} + +SILECS_LIBS = $${SILECS_HOME}/lib/$${CPU} -lsilecs-comm + +LIBS += -L$${SILECS_LIBS} +INCLUDEPATH += $${SILECS_HOME}/include/ +DEPENDPATH += $${SILECS_HOME}/include/ + +#-------Lib XML 2------- +XML2_HOME = /usr/lib/ +XML2_LIBS = $${XML2_HOME} -lxml2 +XML2_INCLUDES = /usr/include/libxml2 +LIBS += -L$${XML2_LIBS} +INCLUDEPATH += $${XML2_INCLUDES} +DEPENDPATH += $${XML2_INCLUDES} + +#-------CNV------- +#CNV_HOME = /acc/sys/$${CPU}/usr/local/natinst/ninetv +CNV_PATH = /home/sd/rhaseitl/lnx/workspace.luna/CNV/ninetv +CNV_INC = $${CNV_HOME}/include +equals( CPU, L865 ){ + CNV_LIBS = $${CNV_HOME}/lib -lstdc++ -lninetv -llkdynam -llkrealt -llksec -llksock +} else { + CNV_LIBS = $${CNV_HOME}/lib64 -lstdc++ -lninetv -llkdynam -llkrealt -llksec -llksock -llkbrow +} +LIBS += -L$${CNV_LIBS} +INCLUDEPATH += $${CNV_INC} +DEPENDPATH += $${CNV_INC} diff --git a/silecs-diagnostic-cpp/SILECS.pro.user b/silecs-diagnostic-cpp/SILECS.pro.user new file mode 100644 index 0000000..485219c --- /dev/null +++ b/silecs-diagnostic-cpp/SILECS.pro.user @@ -0,0 +1,434 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE QtCreatorProject> +<!-- Written by Qt Creator 2.5.2, 2015-03-11T11:36:51. --> +<qtcreator> + <data> + <variable>ProjectExplorer.Project.ActiveTarget</variable> + <value type="int">0</value> + </data> + <data> + <variable>ProjectExplorer.Project.EditorSettings</variable> + <valuemap type="QVariantMap"> + <value type="bool" key="EditorConfiguration.AutoIndent">true</value> + <value type="bool" key="EditorConfiguration.AutoSpacesForTabs">false</value> + <value type="bool" key="EditorConfiguration.CamelCaseNavigation">true</value> + <valuemap type="QVariantMap" key="EditorConfiguration.CodeStyle.0"> + <value type="QString" key="language">Cpp</value> + <valuemap type="QVariantMap" key="value"> + <value type="QString" key="CurrentPreferences">CppGlobal</value> + </valuemap> + </valuemap> + <valuemap type="QVariantMap" key="EditorConfiguration.CodeStyle.1"> + <value type="QString" key="language">QmlJS</value> + <valuemap type="QVariantMap" key="value"> + <value type="QString" key="CurrentPreferences">QmlJSGlobal</value> + </valuemap> + </valuemap> + <value type="int" key="EditorConfiguration.CodeStyle.Count">2</value> + <value type="QByteArray" key="EditorConfiguration.Codec">System</value> + <value type="bool" key="EditorConfiguration.ConstrainTooltips">false</value> + <value type="int" key="EditorConfiguration.IndentSize">4</value> + <value type="bool" key="EditorConfiguration.KeyboardTooltips">false</value> + <value type="bool" key="EditorConfiguration.MouseNavigation">true</value> + <value type="int" key="EditorConfiguration.PaddingMode">1</value> + <value type="bool" key="EditorConfiguration.ScrollWheelZooming">true</value> + <value type="int" key="EditorConfiguration.SmartBackspaceBehavior">0</value> + <value type="bool" key="EditorConfiguration.SpacesForTabs">true</value> + <value type="int" key="EditorConfiguration.TabKeyBehavior">0</value> + <value type="int" key="EditorConfiguration.TabSize">8</value> + <value type="bool" key="EditorConfiguration.UseGlobal">true</value> + <value type="int" key="EditorConfiguration.Utf8BomBehavior">1</value> + <value type="bool" key="EditorConfiguration.addFinalNewLine">true</value> + <value type="bool" key="EditorConfiguration.cleanIndentation">true</value> + <value type="bool" key="EditorConfiguration.cleanWhitespace">true</value> + <value type="bool" key="EditorConfiguration.inEntireDocument">false</value> + </valuemap> + </data> + <data> + <variable>ProjectExplorer.Project.PluginSettings</variable> + <valuemap type="QVariantMap"/> + </data> + <data> + <variable>ProjectExplorer.Project.Target.0</variable> + <valuemap type="QVariantMap"> + <value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Desktop</value> + <value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Desktop</value> + <value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qt4ProjectManager.Target.DesktopTarget</value> + <value type="int" key="ProjectExplorer.Target.ActiveBuildConfiguration">0</value> + <value type="int" key="ProjectExplorer.Target.ActiveDeployConfiguration">0</value> + <value type="int" key="ProjectExplorer.Target.ActiveRunConfiguration">0</value> + <valuemap type="QVariantMap" key="ProjectExplorer.Target.BuildConfiguration.0"> + <value type="QString" key="ProjectExplorer.BuildCOnfiguration.ToolChain">ProjectExplorer.ToolChain.Gcc:{4c7374d2-29fb-477e-9f85-559f725c99c9}</value> + <valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.0"> + <valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0"> + <value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value> + <value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">qmake</value> + <value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value> + <value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">QtProjectManager.QMakeBuildStep</value> + <value type="bool" key="QtProjectManager.QMakeBuildStep.LinkQmlDebuggingLibrary">false</value> + <value type="bool" key="QtProjectManager.QMakeBuildStep.LinkQmlDebuggingLibraryAuto">false</value> + <value type="QString" key="QtProjectManager.QMakeBuildStep.QMakeArguments"></value> + <value type="bool" key="QtProjectManager.QMakeBuildStep.QMakeForced">false</value> + </valuemap> + <valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.1"> + <value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value> + <value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Make</value> + <value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value> + <value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qt4ProjectManager.MakeStep</value> + <value type="bool" key="Qt4ProjectManager.MakeStep.Clean">false</value> + <value type="QString" key="Qt4ProjectManager.MakeStep.MakeArguments"></value> + <value type="QString" key="Qt4ProjectManager.MakeStep.MakeCommand"></value> + </valuemap> + <value type="int" key="ProjectExplorer.BuildStepList.StepsCount">2</value> + <value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Build</value> + <value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value> + <value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Build</value> + </valuemap> + <valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.1"> + <valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0"> + <value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value> + <value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Make</value> + <value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value> + <value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qt4ProjectManager.MakeStep</value> + <value type="bool" key="Qt4ProjectManager.MakeStep.Clean">true</value> + <value type="QString" key="Qt4ProjectManager.MakeStep.MakeArguments">clean</value> + <value type="QString" key="Qt4ProjectManager.MakeStep.MakeCommand"></value> + </valuemap> + <value type="int" key="ProjectExplorer.BuildStepList.StepsCount">1</value> + <value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Clean</value> + <value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value> + <value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Clean</value> + </valuemap> + <value type="int" key="ProjectExplorer.BuildConfiguration.BuildStepListCount">2</value> + <value type="bool" key="ProjectExplorer.BuildConfiguration.ClearSystemEnvironment">false</value> + <valuelist type="QVariantList" key="ProjectExplorer.BuildConfiguration.UserEnvironmentChanges"/> + <value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Qt 4.6.2 (System) Release</value> + <value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value> + <value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qt4ProjectManager.Qt4BuildConfiguration</value> + <value type="int" key="Qt4ProjectManager.Qt4BuildConfiguration.BuildConfiguration">0</value> + <value type="QString" key="Qt4ProjectManager.Qt4BuildConfiguration.BuildDirectory">/nfs/cs-ccr-nfsdev/vol1/u1/smagnoni/jython/workspace/IEPLC-4/branches/IEPLC-4/tools/app/IEPLCDiagnosticToolRBAC6</value> + <value type="int" key="Qt4ProjectManager.Qt4BuildConfiguration.QtVersionId">4</value> + <value type="bool" key="Qt4ProjectManager.Qt4BuildConfiguration.UseShadowBuild">false</value> + </valuemap> + <valuemap type="QVariantMap" key="ProjectExplorer.Target.BuildConfiguration.1"> + <value type="QString" key="ProjectExplorer.BuildCOnfiguration.ToolChain">ProjectExplorer.ToolChain.Gcc:{4c7374d2-29fb-477e-9f85-559f725c99c9}</value> + <valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.0"> + <valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0"> + <value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value> + <value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">qmake</value> + <value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value> + <value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">QtProjectManager.QMakeBuildStep</value> + <value type="bool" key="QtProjectManager.QMakeBuildStep.LinkQmlDebuggingLibrary">false</value> + <value type="bool" key="QtProjectManager.QMakeBuildStep.LinkQmlDebuggingLibraryAuto">false</value> + <value type="QString" key="QtProjectManager.QMakeBuildStep.QMakeArguments"></value> + <value type="bool" key="QtProjectManager.QMakeBuildStep.QMakeForced">false</value> + </valuemap> + <valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.1"> + <value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value> + <value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Make</value> + <value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value> + <value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qt4ProjectManager.MakeStep</value> + <value type="bool" key="Qt4ProjectManager.MakeStep.Clean">false</value> + <value type="QString" key="Qt4ProjectManager.MakeStep.MakeArguments"></value> + <value type="QString" key="Qt4ProjectManager.MakeStep.MakeCommand"></value> + </valuemap> + <value type="int" key="ProjectExplorer.BuildStepList.StepsCount">2</value> + <value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Build</value> + <value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value> + <value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Build</value> + </valuemap> + <valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.1"> + <valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0"> + <value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value> + <value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Make</value> + <value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value> + <value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qt4ProjectManager.MakeStep</value> + <value type="bool" key="Qt4ProjectManager.MakeStep.Clean">true</value> + <value type="QString" key="Qt4ProjectManager.MakeStep.MakeArguments">clean</value> + <value type="QString" key="Qt4ProjectManager.MakeStep.MakeCommand"></value> + </valuemap> + <value type="int" key="ProjectExplorer.BuildStepList.StepsCount">1</value> + <value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Clean</value> + <value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value> + <value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Clean</value> + </valuemap> + <value type="int" key="ProjectExplorer.BuildConfiguration.BuildStepListCount">2</value> + <value type="bool" key="ProjectExplorer.BuildConfiguration.ClearSystemEnvironment">false</value> + <valuelist type="QVariantList" key="ProjectExplorer.BuildConfiguration.UserEnvironmentChanges"/> + <value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Qt 4.6.2 (System) Release2</value> + <value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value> + <value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qt4ProjectManager.Qt4BuildConfiguration</value> + <value type="int" key="Qt4ProjectManager.Qt4BuildConfiguration.BuildConfiguration">0</value> + <value type="QString" key="Qt4ProjectManager.Qt4BuildConfiguration.BuildDirectory">/nfs/cs-ccr-nfsdev/vol1/u1/smagnoni/jython/workspace/IEPLC-4/branches/IEPLC-4/tools/app/IEPLCDiagnosticToolRBAC6</value> + <value type="int" key="Qt4ProjectManager.Qt4BuildConfiguration.QtVersionId">4</value> + <value type="bool" key="Qt4ProjectManager.Qt4BuildConfiguration.UseShadowBuild">false</value> + </valuemap> + <value type="int" key="ProjectExplorer.Target.BuildConfigurationCount">2</value> + <valuemap type="QVariantMap" key="ProjectExplorer.Target.DeployConfiguration.0"> + <valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.0"> + <value type="int" key="ProjectExplorer.BuildStepList.StepsCount">0</value> + <value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Deploy</value> + <value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value> + <value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Deploy</value> + </valuemap> + <value type="int" key="ProjectExplorer.BuildConfiguration.BuildStepListCount">1</value> + <value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">No deployment</value> + <value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value> + <value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.DefaultDeployConfiguration</value> + </valuemap> + <value type="int" key="ProjectExplorer.Target.DeployConfigurationCount">1</value> + <valuemap type="QVariantMap" key="ProjectExplorer.Target.RunConfiguration.0"> + <value type="bool" key="Analyzer.Project.UseGlobal">true</value> + <valuelist type="QVariantList" key="Analyzer.Valgrind.AddedSuppressionFiles"/> + <value type="bool" key="Analyzer.Valgrind.Callgrind.CollectBusEvents">false</value> + <value type="bool" key="Analyzer.Valgrind.Callgrind.CollectSystime">false</value> + <value type="bool" key="Analyzer.Valgrind.Callgrind.EnableBranchSim">false</value> + <value type="bool" key="Analyzer.Valgrind.Callgrind.EnableCacheSim">false</value> + <value type="bool" key="Analyzer.Valgrind.Callgrind.EnableEventToolTips">true</value> + <value type="double" key="Analyzer.Valgrind.Callgrind.MinimumCostRatio">0.01</value> + <value type="double" key="Analyzer.Valgrind.Callgrind.VisualisationMinimumCostRatio">10</value> + <value type="bool" key="Analyzer.Valgrind.FilterExternalIssues">true</value> + <value type="int" key="Analyzer.Valgrind.NumCallers">25</value> + <valuelist type="QVariantList" key="Analyzer.Valgrind.RemovedSuppressionFiles"/> + <value type="bool" key="Analyzer.Valgrind.TrackOrigins">true</value> + <value type="QString" key="Analyzer.Valgrind.ValgrindExecutable">valgrind</value> + <valuelist type="QVariantList" key="Analyzer.Valgrind.VisibleErrorKinds"> + <value type="int">0</value> + <value type="int">1</value> + <value type="int">2</value> + <value type="int">3</value> + <value type="int">4</value> + <value type="int">5</value> + <value type="int">6</value> + <value type="int">7</value> + <value type="int">8</value> + <value type="int">9</value> + <value type="int">10</value> + <value type="int">11</value> + <value type="int">12</value> + <value type="int">13</value> + <value type="int">14</value> + </valuelist> + <value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">SILECS</value> + <value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value> + <value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qt4ProjectManager.Qt4RunConfiguration</value> + <value type="int" key="Qt4ProjectManager.Qt4RunConfiguration.BaseEnvironmentBase">2</value> + <value type="QString" key="Qt4ProjectManager.Qt4RunConfiguration.CommandLineArguments"></value> + <value type="QString" key="Qt4ProjectManager.Qt4RunConfiguration.ProFile">SILECS.pro</value> + <value type="bool" key="Qt4ProjectManager.Qt4RunConfiguration.UseDyldImageSuffix">false</value> + <value type="bool" key="Qt4ProjectManager.Qt4RunConfiguration.UseTerminal">true</value> + <valuelist type="QVariantList" key="Qt4ProjectManager.Qt4RunConfiguration.UserEnvironmentChanges"/> + <value type="QString" key="Qt4ProjectManager.Qt4RunConfiguration.UserWorkingDirectory"></value> + <value type="uint" key="RunConfiguration.QmlDebugServerPort">3768</value> + <value type="bool" key="RunConfiguration.UseCppDebugger">true</value> + <value type="bool" key="RunConfiguration.UseQmlDebugger">false</value> + <value type="bool" key="RunConfiguration.UseQmlDebuggerAuto">true</value> + </valuemap> + <value type="int" key="ProjectExplorer.Target.RunConfigurationCount">1</value> + </valuemap> + </data> + <data> + <variable>ProjectExplorer.Project.Target.1</variable> + <valuemap type="QVariantMap"> + <value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Embedded Linux</value> + <value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Embedded Linux</value> + <value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">RemoteLinux.EmbeddedLinuxTarget</value> + <value type="int" key="ProjectExplorer.Target.ActiveBuildConfiguration">0</value> + <value type="int" key="ProjectExplorer.Target.ActiveDeployConfiguration">0</value> + <value type="int" key="ProjectExplorer.Target.ActiveRunConfiguration">0</value> + <valuemap type="QVariantMap" key="ProjectExplorer.Target.BuildConfiguration.0"> + <value type="QString" key="ProjectExplorer.BuildCOnfiguration.ToolChain">ProjectExplorer.ToolChain.Gcc:{4c7374d2-29fb-477e-9f85-559f725c99c9}</value> + <valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.0"> + <valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0"> + <value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value> + <value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">qmake</value> + <value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value> + <value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">QtProjectManager.QMakeBuildStep</value> + <value type="bool" key="QtProjectManager.QMakeBuildStep.LinkQmlDebuggingLibrary">false</value> + <value type="bool" key="QtProjectManager.QMakeBuildStep.LinkQmlDebuggingLibraryAuto">false</value> + <value type="QString" key="QtProjectManager.QMakeBuildStep.QMakeArguments"></value> + <value type="bool" key="QtProjectManager.QMakeBuildStep.QMakeForced">false</value> + </valuemap> + <valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.1"> + <value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value> + <value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Make</value> + <value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value> + <value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qt4ProjectManager.MakeStep</value> + <value type="bool" key="Qt4ProjectManager.MakeStep.Clean">false</value> + <value type="QString" key="Qt4ProjectManager.MakeStep.MakeArguments"></value> + <value type="QString" key="Qt4ProjectManager.MakeStep.MakeCommand"></value> + </valuemap> + <value type="int" key="ProjectExplorer.BuildStepList.StepsCount">2</value> + <value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Build</value> + <value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value> + <value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Build</value> + </valuemap> + <valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.1"> + <valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0"> + <value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value> + <value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Make</value> + <value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value> + <value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qt4ProjectManager.MakeStep</value> + <value type="bool" key="Qt4ProjectManager.MakeStep.Clean">true</value> + <value type="QString" key="Qt4ProjectManager.MakeStep.MakeArguments">clean</value> + <value type="QString" key="Qt4ProjectManager.MakeStep.MakeCommand"></value> + </valuemap> + <value type="int" key="ProjectExplorer.BuildStepList.StepsCount">1</value> + <value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Clean</value> + <value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value> + <value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Clean</value> + </valuemap> + <value type="int" key="ProjectExplorer.BuildConfiguration.BuildStepListCount">2</value> + <value type="bool" key="ProjectExplorer.BuildConfiguration.ClearSystemEnvironment">false</value> + <valuelist type="QVariantList" key="ProjectExplorer.BuildConfiguration.UserEnvironmentChanges"/> + <value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Qt 4.6.2 (System) Release</value> + <value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value> + <value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qt4ProjectManager.Qt4BuildConfiguration</value> + <value type="int" key="Qt4ProjectManager.Qt4BuildConfiguration.BuildConfiguration">0</value> + <value type="QString" key="Qt4ProjectManager.Qt4BuildConfiguration.BuildDirectory">/nfs/cs-ccr-nfsdev/vol1/u1/smagnoni/jython/workspace/IEPLC-4/branches/IEPLC-4/tools/app/IEPLCDiagnosticToolRBAC6</value> + <value type="int" key="Qt4ProjectManager.Qt4BuildConfiguration.QtVersionId">4</value> + <value type="bool" key="Qt4ProjectManager.Qt4BuildConfiguration.UseShadowBuild">false</value> + </valuemap> + <valuemap type="QVariantMap" key="ProjectExplorer.Target.BuildConfiguration.1"> + <value type="QString" key="ProjectExplorer.BuildCOnfiguration.ToolChain">ProjectExplorer.ToolChain.Gcc:{4c7374d2-29fb-477e-9f85-559f725c99c9}</value> + <valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.0"> + <valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0"> + <value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value> + <value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">qmake</value> + <value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value> + <value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">QtProjectManager.QMakeBuildStep</value> + <value type="bool" key="QtProjectManager.QMakeBuildStep.LinkQmlDebuggingLibrary">false</value> + <value type="bool" key="QtProjectManager.QMakeBuildStep.LinkQmlDebuggingLibraryAuto">false</value> + <value type="QString" key="QtProjectManager.QMakeBuildStep.QMakeArguments"></value> + <value type="bool" key="QtProjectManager.QMakeBuildStep.QMakeForced">false</value> + </valuemap> + <valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.1"> + <value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value> + <value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Make</value> + <value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value> + <value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qt4ProjectManager.MakeStep</value> + <value type="bool" key="Qt4ProjectManager.MakeStep.Clean">false</value> + <value type="QString" key="Qt4ProjectManager.MakeStep.MakeArguments"></value> + <value type="QString" key="Qt4ProjectManager.MakeStep.MakeCommand"></value> + </valuemap> + <value type="int" key="ProjectExplorer.BuildStepList.StepsCount">2</value> + <value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Build</value> + <value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value> + <value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Build</value> + </valuemap> + <valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.1"> + <valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0"> + <value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value> + <value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Make</value> + <value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value> + <value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qt4ProjectManager.MakeStep</value> + <value type="bool" key="Qt4ProjectManager.MakeStep.Clean">true</value> + <value type="QString" key="Qt4ProjectManager.MakeStep.MakeArguments">clean</value> + <value type="QString" key="Qt4ProjectManager.MakeStep.MakeCommand"></value> + </valuemap> + <value type="int" key="ProjectExplorer.BuildStepList.StepsCount">1</value> + <value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Clean</value> + <value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value> + <value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Clean</value> + </valuemap> + <value type="int" key="ProjectExplorer.BuildConfiguration.BuildStepListCount">2</value> + <value type="bool" key="ProjectExplorer.BuildConfiguration.ClearSystemEnvironment">false</value> + <valuelist type="QVariantList" key="ProjectExplorer.BuildConfiguration.UserEnvironmentChanges"/> + <value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Qt 4.6.2 (System) Release2</value> + <value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value> + <value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qt4ProjectManager.Qt4BuildConfiguration</value> + <value type="int" key="Qt4ProjectManager.Qt4BuildConfiguration.BuildConfiguration">0</value> + <value type="QString" key="Qt4ProjectManager.Qt4BuildConfiguration.BuildDirectory">/nfs/cs-ccr-nfsdev/vol1/u1/smagnoni/jython/workspace/IEPLC-4/branches/IEPLC-4/tools/app/IEPLCDiagnosticToolRBAC6</value> + <value type="int" key="Qt4ProjectManager.Qt4BuildConfiguration.QtVersionId">4</value> + <value type="bool" key="Qt4ProjectManager.Qt4BuildConfiguration.UseShadowBuild">false</value> + </valuemap> + <value type="int" key="ProjectExplorer.Target.BuildConfigurationCount">2</value> + <valuemap type="QVariantMap" key="ProjectExplorer.Target.DeployConfiguration.0"> + <valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.0"> + <valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0"> + <value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value> + <value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Upload files via SFTP</value> + <value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value> + <value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">RemoteLinux.DirectUploadStep</value> + <valuelist type="QVariantList" key="Qt4ProjectManager.MaemoRunConfiguration.LastDeployedFiles"/> + <valuelist type="QVariantList" key="Qt4ProjectManager.MaemoRunConfiguration.LastDeployedHosts"/> + <valuelist type="QVariantList" key="Qt4ProjectManager.MaemoRunConfiguration.LastDeployedRemotePaths"/> + <valuelist type="QVariantList" key="Qt4ProjectManager.MaemoRunConfiguration.LastDeployedSysroots"/> + <valuelist type="QVariantList" key="Qt4ProjectManager.MaemoRunConfiguration.LastDeployedTimes"/> + <value type="bool" key="RemoteLinux.GenericDirectUploadStep.Incremental">true</value> + </valuemap> + <value type="int" key="ProjectExplorer.BuildStepList.StepsCount">1</value> + <value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Deploy</value> + <value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value> + <value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Deploy</value> + </valuemap> + <value type="int" key="ProjectExplorer.BuildConfiguration.BuildStepListCount">1</value> + <value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Deploy to Remote Linux Host</value> + <value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value> + <value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">DeployToGenericLinux</value> + <value type="qulonglong" key="Qt4ProjectManager.MaemoRunConfiguration.DeviceId">0</value> + </valuemap> + <value type="int" key="ProjectExplorer.Target.DeployConfigurationCount">1</value> + <valuemap type="QVariantMap" key="ProjectExplorer.Target.RunConfiguration.0"> + <value type="bool" key="Analyzer.Project.UseGlobal">true</value> + <valuelist type="QVariantList" key="Analyzer.Valgrind.AddedSuppressionFiles"/> + <value type="bool" key="Analyzer.Valgrind.Callgrind.CollectBusEvents">false</value> + <value type="bool" key="Analyzer.Valgrind.Callgrind.CollectSystime">false</value> + <value type="bool" key="Analyzer.Valgrind.Callgrind.EnableBranchSim">false</value> + <value type="bool" key="Analyzer.Valgrind.Callgrind.EnableCacheSim">false</value> + <value type="bool" key="Analyzer.Valgrind.Callgrind.EnableEventToolTips">true</value> + <value type="double" key="Analyzer.Valgrind.Callgrind.MinimumCostRatio">0.01</value> + <value type="double" key="Analyzer.Valgrind.Callgrind.VisualisationMinimumCostRatio">10</value> + <value type="bool" key="Analyzer.Valgrind.FilterExternalIssues">true</value> + <value type="int" key="Analyzer.Valgrind.NumCallers">25</value> + <valuelist type="QVariantList" key="Analyzer.Valgrind.RemovedSuppressionFiles"/> + <value type="bool" key="Analyzer.Valgrind.TrackOrigins">true</value> + <value type="QString" key="Analyzer.Valgrind.ValgrindExecutable">valgrind</value> + <valuelist type="QVariantList" key="Analyzer.Valgrind.VisibleErrorKinds"> + <value type="int">0</value> + <value type="int">1</value> + <value type="int">2</value> + <value type="int">3</value> + <value type="int">4</value> + <value type="int">5</value> + <value type="int">6</value> + <value type="int">7</value> + <value type="int">8</value> + <value type="int">9</value> + <value type="int">10</value> + <value type="int">11</value> + <value type="int">12</value> + <value type="int">13</value> + <value type="int">14</value> + </valuelist> + <value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">SILECS (on Remote Device)</value> + <value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value> + <value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">RemoteLinuxRunConfiguration</value> + <value type="QString" key="Qt4ProjectManager.MaemoRunConfiguration.Arguments"></value> + <value type="int" key="Qt4ProjectManager.MaemoRunConfiguration.BaseEnvironmentBase">1</value> + <value type="QString" key="Qt4ProjectManager.MaemoRunConfiguration.ProFile">SILECS.pro</value> + <valuelist type="QVariantList" key="Qt4ProjectManager.MaemoRunConfiguration.UserEnvironmentChanges"/> + <value type="QString" key="RemoteLinux.RunConfig.AlternateRemoteExecutable"></value> + <value type="bool" key="RemoteLinux.RunConfig.UseAlternateRemoteExecutable">false</value> + <value type="QString" key="RemoteLinux.RunConfig.WorkingDirectory"></value> + <value type="uint" key="RunConfiguration.QmlDebugServerPort">3768</value> + <value type="bool" key="RunConfiguration.UseCppDebugger">true</value> + <value type="bool" key="RunConfiguration.UseQmlDebugger">false</value> + <value type="bool" key="RunConfiguration.UseQmlDebuggerAuto">true</value> + </valuemap> + <value type="int" key="ProjectExplorer.Target.RunConfigurationCount">1</value> + </valuemap> + </data> + <data> + <variable>ProjectExplorer.Project.TargetCount</variable> + <value type="int">2</value> + </data> + <data> + <variable>ProjectExplorer.Project.Updater.EnvironmentId</variable> + <value type="QString">{44ef3bd6-a242-4916-ba41-2b32f74f7189}</value> + </data> + <data> + <variable>ProjectExplorer.Project.Updater.FileVersion</variable> + <value type="int">11</value> + </data> +</qtcreator> diff --git a/silecs-diagnostic-cpp/install.sh b/silecs-diagnostic-cpp/install.sh new file mode 100755 index 0000000..837fe86 --- /dev/null +++ b/silecs-diagnostic-cpp/install.sh @@ -0,0 +1,11 @@ +#!/bin/sh +set -e + +INSTALL_DIR=$1 + +SCRIPT=$(readlink -f "$0") +SCRIPTPATH=$(dirname "$SCRIPT") # path where this script is located in + +mkdir -p ${INSTALL_DIR} +cp -r ${SCRIPTPATH}/build/bin ${INSTALL_DIR} +cp -r ${SCRIPTPATH}/build/resources ${INSTALL_DIR} \ No newline at end of file diff --git a/silecs-diagnostic-cpp/src/silecs-diagnostic/constants.h b/silecs-diagnostic-cpp/src/silecs-diagnostic/constants.h new file mode 100755 index 0000000..f92c82a --- /dev/null +++ b/silecs-diagnostic-cpp/src/silecs-diagnostic/constants.h @@ -0,0 +1,59 @@ +// Copyright 2016 CERN and GSI +// +// 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 3 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, see <http://www.gnu.org/licenses/>. + +#ifndef CONSTANTS_H +#define CONSTANTS_H +#include <string> +#include <silecs-communication/interface/core/SilecsService.h> + +using namespace Silecs; + +/* + * CHANGE THE MAJOR HERE TO ADAPT THE TOOL WITH THE CURRENT VERSION + */ +const std::string MAJOR = Service::getSemverMajor(); +const std::string MINOR = Service::getSemverMinor(); +const std::string PATCH = Service::getSemverPatch(); + +/* + * Different string type + */ +const std::string CLUSTER_TYPE = "CLUSTER"; +const std::string PLC_TYPE = "PLC"; +const std::string DEVICE_TYPE = "DEVICE"; +const std::string REGISTER_TYPE = "REGISTER"; + +/* +* Different project path +*/ + +// SILECS HEADER +const std::string HEADER_NAME = "SilecsHeader"; +const std::string HEADER_VERSION = "1.0.0"; +const std::string HEADER_DEVICE = "0"; +const std::string HEADER_BLOCK = "hdrBlk"; +const std::string HEADER_RELEASE_REG = "_version"; +const std::string HEADER_OWNER_REG = "_user"; +const std::string HEADER_DATE_REG = "_date"; +const std::string HEADER_CHECKSUM_REG = "_checksum"; + +//splash screen time (in seconds) +const unsigned long SPLASH_SCREEN_TIME = 1; +const int NUMBER_PASSWORD_ATTEMPTS = 3; + +// max buffer lenght for PLC name +const int MAX_BUFFER = 1024; + +#endif // CONSTANTS_H diff --git a/silecs-diagnostic-cpp/src/silecs-diagnostic/diagnostictoolmainview.cpp b/silecs-diagnostic-cpp/src/silecs-diagnostic/diagnostictoolmainview.cpp new file mode 100755 index 0000000..6539ecc --- /dev/null +++ b/silecs-diagnostic-cpp/src/silecs-diagnostic/diagnostictoolmainview.cpp @@ -0,0 +1,1095 @@ +// Copyright 2016 CERN and GSI +// +// 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 3 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, see <http://www.gnu.org/licenses/>. + +#include <silecs-diagnostic/diagnostictoolmainview.h> +#include <silecs-diagnostic/generated/ui_diagnostictoolmainview.h> +#include <silecs-diagnostic/utils.h> + +#include <silecs-communication/interface/utility/XMLParser.h> + +#include <exception> +extern silecsModule *mysilecs; +extern std::string UserName; + +template <class T>bool from_string(T& t, const std::string& s, std::ios_base& (*f)(std::ios_base&)) +{ + std::istringstream iss(s); + return !(iss >> f >> t).fail(); +} + +diagnosticToolMainView::diagnosticToolMainView(QWidget *parent) : + QMainWindow(parent), + ui(new Ui::diagnosticToolMainView) +{ + ui->setupUi(this); + + this->redirector = NULL; + mysilecs = NULL; + + ui->dbVersionLabel->setText("SILECS service: "+QString::fromStdString(MAJOR)+"."+QString::fromStdString(MINOR)+"."+QString::fromStdString(PATCH)); + + // Set tree widget coloumn and headers + ui->treeWidget->setColumnCount(3); + QStringList headers; + headers << "Resource name"<< "Block name" << "PLC Value" << "Local Value"; + ui->treeWidget->setHeaderLabels(headers); + + // Create context menu to let the user the posibility of cleaning the console + ui->console->setReadOnly(true); + ui->InformationMessage->setReadOnly(true); + connect(ui->console, SIGNAL(customContextMenuRequested(const QPoint &)), this, SLOT(ctxMenu(const QPoint &))); + + //set vertical/horizontal splitter + ui->verticalSplitter->setStretchFactor(1,1); + ui->verticalSplitter->setStretchFactor(0,0); +} + +diagnosticToolMainView::~diagnosticToolMainView() +{ + // If closing application without closing cluster + if(redirector!=NULL) delete redirector; + + delete ui; +} + +std::string diagnosticToolMainView::generateLogTopics() +{ + // generate string of log parameters + std::ostringstream logTopics; + if(ui->checkERROR->isChecked()) logTopics << "ERROR"; + if(ui->checkDEBUG->isChecked()) logTopics << ",DEBUG"; + if(ui->checkSETUP->isChecked()) logTopics << ",SETUP"; + if(ui->checkALLOC->isChecked()) logTopics << ",ALLOC"; + if(ui->checkLOCK->isChecked()) logTopics << ",LOCK"; + if(ui->checkCOMM->isChecked()) logTopics << ",COMM"; + if(ui->checkSEND->isChecked()) logTopics << ",SEND"; + if(ui->checkRECV->isChecked()) logTopics << ",RECV"; + if(ui->checkDATA->isChecked()) logTopics << ",DATA"; + if(ui->checkDIAG->isChecked()) logTopics << ",DIAG"; + return logTopics.str(); +} + +void diagnosticToolMainView::resetGUI() +{ + try + { + //Stop periodic receiving if any + if(ui->periodicReceiveButton->isChecked()==true) + { + ui->periodicReceiveButton->setChecked(false); + Utils::logInfo(ui->console,"Monitoring was stopped due to cluster closure."); + } + ui->sendButton->setEnabled(false); + ui->receiveButton->setEnabled(false); + ui->periodicReceiveButton->setEnabled(false); + ui->copyButton->setEnabled(false); + //Clear the tree + ui->treeWidget->clear(); + + ui->sendComboBox->clear(); + ui->receiveComboBox->clear(); + ui->copyComboBox->clear(); + // disable connect and disconnect + ui->connectButton->setEnabled(false); + ui->disconnectButton->setEnabled(false); + + if(mysilecs!=NULL) + { + delete mysilecs; + mysilecs = NULL; + } + + if(redirector!=NULL) + { + delete redirector; + redirector = NULL; + } + } + catch(std::string *str) + { + Utils::logError(ui->console,QString::fromStdString(*str)); + } + catch(std::exception& ex) + { + Utils::logError(ui->console,QString::fromStdString(ex.what())); + } + catch(...) + { + Utils::logError(ui->console,"Unexpected error while reseting GUI. Please notify SILECS support"); + } +} + + +void diagnosticToolMainView::loadFiles() +{ + resetGUI(); + try + { + this->redirector = new StdErrRedirect(ui->console); + mysilecs = new silecsModule(generateLogTopics(), ui->console); + + ui->treeWidget->clear(); + Item * root = mysilecs->generateTree(designName.toStdString(),deployFile.toStdString()); + + if(root == NULL) + { + Utils::logError(ui->console,"Error while opening the design/deploy"); + } + else + { + ui->treeWidget->addTopLevelItem(root); + /* + * Create Block List for combo boxes + */ + Item* topLevelItem = dynamic_cast<Item*>(ui->treeWidget->topLevelItem(0)); + Silecs::Cluster* cluster = (Silecs::Cluster*)topLevelItem->getLinkedObject(); + + std::string writeBlockList = cluster->getBlockList(Output)+" "+cluster->getBlockList(InOut); + + istringstream blockListSplitted(writeBlockList); + Utils::logInfo(ui->console,"[Info:] - " + QString::fromStdString(writeBlockList)); + do + { + std::string blockName; + blockListSplitted >> blockName; + // avoid last empty block + if(!blockName.compare("")) break; + + ui->sendComboBox->addItem(QString::fromStdString(blockName)); + }while(blockListSplitted); + + // Receive combo box + std::string readBlockList = cluster->getBlockList(Input)+" "+cluster->getBlockList(InOut); + istringstream blockListSplitted2(readBlockList); + Utils::logInfo(ui->console,QString::fromStdString(readBlockList)); + do + { + std::string blockName; + blockListSplitted2 >> blockName; + // avoid last empty block + if(!blockName.compare("")) break; + + ui->receiveComboBox->addItem(QString::fromStdString(blockName)); + }while(blockListSplitted2); + + // Send combo box + std::string copyBlockList = cluster->getBlockList(InOut); + istringstream blockListSplitted3(copyBlockList); + Utils::logInfo(ui->console, QString::fromStdString(copyBlockList)); + do + { + std::string blockName; + blockListSplitted3 >> blockName; + // avoid last empty block + if(!blockName.compare("")) break; + + ui->copyComboBox->addItem(QString::fromStdString(blockName)); + }while(blockListSplitted3); + + // Disable opening button + // close must be pressed before opening again + //GSI-Hack - file dialog + //ui->openButton->setEnabled(false); + + + //ui->closeButton->setEnabled(true); + + } + } + catch(std::string *str) + { + Utils::logError(ui->console,QString::fromStdString(*str)); + } + catch(std::exception& ex) + { + Utils::logError(ui->console,QString::fromStdString(ex.what())); + } + catch (...) //catch any exception + { + Utils::logError(ui->console,"Error while opening the specified Class. Please contact SILECS support"); + } +} + +void diagnosticToolMainView::on_connectButton_clicked() +{ + // Connect button + + // Get current Item + Item *currentItem = dynamic_cast<Item*>(ui->treeWidget->currentItem()); + + // Cast the linked object PLC type + Silecs::PLC* plc = (Silecs::PLC*)(currentItem->getLinkedObject()); + + try + { + plc->connect(Silecs::MASTER_SYNCHRO,true,ui->compareChecksums->isChecked()); + if(!plc->isConnected()) + { + Utils::logError(ui->console,"Connection to PLC failed."); + return; + } + mysilecs->updatePLCItem(currentItem,false); + if(!plc->isConnected()) + { + Utils::logError(ui->console,"Updating PLC-items failed."); + return; + } + + // disable connect button + ui->connectButton->setEnabled(false); + ui->disconnectButton->setEnabled(true); + + // enable send and receive + ui->sendBox->setEnabled(true); + ui->receiveBox->setEnabled(true); + ui->copyBox->setEnabled(true); + + //refresh console + Utils::displayPLCInformation(plc,ui->InformationMessage); + + //highlight PLC background in green + ui->treeWidget->currentItem()->setBackgroundColor(0,Qt::green); + + // Increment number of connected PLC + mysilecs->counterConnectedPLC++; + } + catch(std::string *str) + { + Utils::logError(ui->console,QString::fromStdString(*str)); + } + catch(std::exception& ex) + { + Utils::logError(ui->console,QString::fromStdString(ex.what())); + } + catch(...) + { + Utils::logError(ui->console,"Unknown error while connecting to the selected PLC."); + } + +} + +void diagnosticToolMainView::on_disconnectButton_clicked() +{ + // Disconnect button + try + { + // Get current Item + Item *currentItem = dynamic_cast<Item*>(ui->treeWidget->currentItem()); + + // Cast the linked object PLC type + Silecs::PLC* plc = (Silecs::PLC*)(currentItem->getLinkedObject()); + + // Disconnect + plc->disconnect(); + + // disable disconnect button + ui->disconnectButton->setEnabled(false); + ui->connectButton->setEnabled(true); + + // disable send and receive + ui->sendBox->setEnabled(false); + ui->receiveBox->setEnabled(false); + ui->copyBox->setEnabled(false); + + // refresh console + Utils::displayPLCInformation(plc,ui->InformationMessage); + + // remove green background + ui->treeWidget->currentItem()->setBackgroundColor(0,Qt::white); + + // Decrement number of connected PLC + mysilecs->counterConnectedPLC--; + if(mysilecs->counterConnectedPLC==0) + { + // if there are no more plc connected stop monitoring + if(ui->periodicReceiveButton->isChecked()==true) + { + ui->periodicReceiveButton->setChecked(false); + Utils::logInfo(ui->console,"Monitoring was stopped because no more PLC are connected."); + } + } + } + catch(std::string *str) + { + Utils::logError(ui->console,QString::fromStdString(*str)); + } + catch(std::exception& ex) + { + Utils::logError(ui->console,QString::fromStdString(ex.what())); + } + catch(...) + { + Utils::logError(ui->console,"Unknown Error while disconnecting to the selected PLC."); + } +} + +void diagnosticToolMainView::on_treeWidget_currentItemChanged(QTreeWidgetItem *current, QTreeWidgetItem *previous) +{ + (void)current; // to suppress unused warning + (void)previous; // to suppress unused warning + try + { + if(current == NULL) + { + qDebug()<< "Current item does not exist. probably the tree has bean cleared"; + ui->InformationMessage->clear(); + ui->treeWidget->resizeColumnToContents(0); + return; + } + + Item *currentItem = dynamic_cast<Item*>(current); + + /* + * If the selected item is a Cluster + */ + if(!currentItem->whatsThis(0).compare(QString::fromStdString(CLUSTER_TYPE))) + { + qDebug() << "Cluster selected"; + Utils::displayClusterInformation(((Silecs::Cluster*)(currentItem->getLinkedObject())),ui->InformationMessage); + } + + /* + * If the selected item is a PLC + */ + if(!currentItem->whatsThis(0).compare(QString::fromStdString(PLC_TYPE))) + { + qDebug() << "Plc selected"; + Utils::displayPLCInformation(((Silecs::PLC*)(currentItem->getLinkedObject())),ui->InformationMessage); + + bool connected = ((Silecs::PLC*)(currentItem->getLinkedObject()))->isConnected(); + ui->connectButton->setEnabled(!connected); + ui->disconnectButton->setEnabled(connected); + } + else + { + ui->connectButton->setEnabled(false); + ui->disconnectButton->setEnabled(false); + } + + /* + * If the selected item is a device + */ + if(!currentItem->whatsThis(0).compare(QString::fromStdString(DEVICE_TYPE))) + { + qDebug() << "Device selected"; + Utils::displayDeviceInformation(((Silecs::Device*)(currentItem->getLinkedObject())),ui->InformationMessage); + + bool connected = ((Silecs::PLC*)dynamic_cast<Item*>(currentItem->parent())->getLinkedObject())->isConnected(); + + ui->sendBox->setEnabled(connected); + ui->receiveBox->setEnabled(connected); + ui->copyBox->setEnabled(connected); + ui->sendButton->setEnabled(connected); + ui->receiveButton->setEnabled(connected); + ui->copyButton->setEnabled(connected); + ui->periodicReceiveButton->setEnabled(connected); + } + else + { + ui->sendBox->setEnabled(false); + ui->receiveBox->setEnabled(false); + ui->copyBox->setEnabled(false); + ui->sendButton->setEnabled(false); + ui->receiveButton->setEnabled(false); + ui->copyButton->setEnabled(false); + ui->periodicReceiveButton->setEnabled(false); + } + + /* + * If the selected item is a register + */ + if(!currentItem->whatsThis(0).compare(QString::fromStdString(REGISTER_TYPE))) + { + qDebug() << "Register selected"; + Utils::displayRegisterInformation(((Silecs::Register*)(currentItem->getLinkedObject())),ui->InformationMessage); + + //bool connected = ((Silecs::PLC*)dynamic_cast<Item*>(currentItem->parent()->parent())->getLinkedObject())->isConnected(); + Utils::displayRegisterValue((Silecs::Register*)(currentItem->getLinkedObject()), + ui->binValueLabel, + ui->HexValueLabel, + ui->DecValueLabel, + ui->asciiValueLabel); + } + else + { + ui->binValueLabel->setText("--Not relevant--"); + ui->HexValueLabel->setText("--Not relevant--"); + ui->DecValueLabel->setText("--Not relevant--"); + ui->asciiValueLabel->setText("--Not relevant--"); + } + // Automaticaly resize the coloumn with the item name + ui->treeWidget->resizeColumnToContents(0); + } + catch(std::string *str) + { + Utils::logError(ui->console,QString::fromStdString(*str)); + } + catch(std::exception& ex) + { + Utils::logError(ui->console,QString::fromStdString(ex.what())); + } + catch(...) + { + Utils::logError(ui->console,"Unknown error in currentItemChanged. Please notify SILECS support"); + } +} + +std::vector<QString> diagnosticToolMainView::openArrayDialogBase(Silecs::Register* reg, std::vector<QString> dataVector, bool localData) +{ + DisplayArrayDialog arrayDialog; + arrayDialog.setDataVector(dataVector,localData,reg->getDimension2()); + arrayDialog.setWindowTitle("Array View"); + arrayDialog.setModal(true); + if(arrayDialog.exec()==1) // ok pressed + { + return arrayDialog.getDataVector(); + } + return dataVector; +} + +std::vector<QString> diagnosticToolMainView::open1DArrayDialog(Silecs::Register* reg, bool localData) +{ + std::vector<QString> dataVector; + for(unsigned long i=0;i<reg->getDimension1();i++) + { + if( localData ) + dataVector.push_back(QString::fromStdString(reg->getOutputValAsString(i))); + else + dataVector.push_back(QString::fromStdString(reg->getInputValAsString(i))); + } + + return openArrayDialogBase(reg, dataVector, localData); +} + +std::vector<QString> diagnosticToolMainView::open2DArrayDialog(Silecs::Register* reg, bool localData) +{ + std::vector<QString> dataVector; + for(unsigned long i=0; i<reg->getDimension1(); i++) + { + for(unsigned long j=0; j<reg->getDimension2(); j++) + { + if( localData ) + dataVector.push_back(QString::fromStdString(reg->getOutputValAsString(i,j))); + else + dataVector.push_back(QString::fromStdString(reg->getInputValAsString(i,j))); + } + } + return openArrayDialogBase(reg, dataVector, localData); +} + +void diagnosticToolMainView::markItemNotEdiable(QTreeWidgetItem *item) +{ + item->setFlags(Qt::ItemIsSelectable | Qt::ItemIsUserCheckable | Qt::ItemIsEnabled | Qt::ItemIsDragEnabled); + qDebug()<< "item marked as not editable"; +} + +void diagnosticToolMainView::on_treeWidget_doubleClicked(const QModelIndex &index) +{ + (void)index; // to suppress unused warning + try + { + QTreeWidgetItem *itm = ui->treeWidget->currentItem(); + if( itm->whatsThis(0).toStdString().compare(REGISTER_TYPE) != 0 ) + { + markItemNotEdiable(itm); + return; + } + Item *registerItem = dynamic_cast<Item*>(itm); + Silecs::Register* reg = (Silecs::Register*)registerItem->getLinkedObject(); + + switch(ui->treeWidget->currentColumn()) + { + case 2:// double click performed on 2th column (PLC value) --> open non-editable ArrayDialog for arrays + if(reg->getDimension2()<=1) // scalar or 1d array (noting happens for scalar) + { + if(reg->getDimension1()<=1) //scalar + { + return; + } + open1DArrayDialog(reg,false); + } + else // 2d array + { + open2DArrayDialog(reg,false); + } + markItemNotEdiable(itm); + return; + case 3:// double click performed on 3th column (local value) + if(!reg->hasOutputAccess() )// is READ only for silecs or is wrong column + { + markItemNotEdiable(itm); + return; + } + if(reg->getDimension2()<=1) // scalar or 1d array + { + if(reg->getDimension1()<=1) //scalar + { + itm->setFlags(Qt::ItemIsSelectable | Qt::ItemIsUserCheckable | Qt::ItemIsEnabled | Qt::ItemIsDragEnabled | Qt::ItemIsEditable); + return; + } + std::vector<QString> dataVector = open1DArrayDialog(reg,true); + mysilecs->setArrayRegValue(registerItem,&dataVector); + } + else // 2d array + { + std::vector<QString> dataVector= open2DArrayDialog(reg,true); + mysilecs->setArrayRegValue(registerItem,&dataVector); + } + return; + default: // other columns are not editable + markItemNotEdiable(itm); + return; + } + } + catch(std::string *str) + { + Utils::logError(ui->console,QString::fromStdString(*str)); + } + catch(std::exception& ex) + { + Utils::logError(ui->console,QString::fromStdString(ex.what())); + } + catch(...) + { + Utils::logError(ui->console,"Unknown error in treeWidget_doubleClicked. Please notify SILECS support"); + } +} + +void diagnosticToolMainView::on_sendButton_clicked() +{ + try{ + Item *currentItem = dynamic_cast<Item*>(ui->treeWidget->currentItem()); + + /* + * If the selected item is a cluster + */ + if(!currentItem->whatsThis(0).compare(QString::fromStdString(CLUSTER_TYPE))) + { + // Cast the linked object to cluster type + Silecs::Cluster* cluster = (Silecs::Cluster*)(currentItem->getLinkedObject()); + int numberOfPLC = currentItem->childCount(); + + // Set all the PLC whithin the cluster + for(int i=0;i<numberOfPLC;i++) + { + int numberOfdevice = currentItem->childCount(); + Item* plcItem = (Item*)currentItem->child(i); + // Set all the device whithin the PLC + for(int j=0;j<numberOfdevice;j++) + { + Silecs::PLC* plc = (Silecs::PLC*)(plcItem->getLinkedObject()); + if (plc->isConnected()) + mysilecs->setScalarDataInDeviceFromItem((Item*)plcItem->child(i),ui->sendComboBox->currentText().toStdString()); + } + } + try{ + //send and mesure sending time + QTime mytimer; + mytimer.start(); + cluster->send(ui->sendComboBox->currentText().toStdString()); + logCommunicationSuccess(mytimer.elapsed()); + } + catch(...) + { + qDebug()<<"Error while calling cluster.send()"; + Utils::logError(ui->console,"Error while sending the block to the selected cluster."); + } + } + + /* + * If the selected item is a plc + */ + if(!currentItem->whatsThis(0).compare(QString::fromStdString(PLC_TYPE))) + { + // Cast the linked object to PLC type + Silecs::PLC* plc = (Silecs::PLC*)(currentItem->getLinkedObject()); + int numberOfdevice = currentItem->childCount(); + + // Set all the device whithin the PLC + for(int i=0;i<numberOfdevice;i++) + mysilecs->setScalarDataInDeviceFromItem((Item*)currentItem->child(i),ui->sendComboBox->currentText().toStdString()); + try{ + //send and mesure sending time + QTime mytimer; + mytimer.start(); + int ret = plc->send(ui->sendComboBox->currentText().toStdString()); + if(ret != 0) + { + Utils::logError(ui->console,QString::fromStdString("Error while receiving the block to the selected device")); + return; + } + logCommunicationSuccess(mytimer.elapsed()); + } + catch(...) + { + qDebug()<<"Error while calling plc.send()"; + Utils::logError(ui->console,"Error while sending the block to the selected plc."); + } + } + + /* + * If the selected item is a device + */ + if(!currentItem->whatsThis(0).compare(QString::fromStdString(DEVICE_TYPE))) + { + try{ + mysilecs->setScalarDataInDeviceFromItem(currentItem,ui->sendComboBox->currentText().toStdString()); + Silecs::Device* device = (Silecs::Device*)(currentItem->getLinkedObject()); + + //send and mesure sending time + QTime mytimer; + mytimer.start(); + int ret = device->send(ui->sendComboBox->currentText().toStdString()); + if(ret != 0) + { + Utils::logError(ui->console,QString::fromStdString("Error while receiving the block to the selected device")); + return; + } + logCommunicationSuccess( mytimer.elapsed()); + } + catch(...) + { + qDebug()<<"Error while calling plc.send()"; + Utils::logError(ui->console,"Error while sending the block to the selected device."); + } + } + } + catch(std::string *str) + { + Utils::logError(ui->console,QString::fromStdString(*str)); + } + catch(std::exception& ex) + { + Utils::logError(ui->console,QString::fromStdString(ex.what())); + } + catch(...) + { + Utils::logError(ui->console,"Unexpected error while sending. Please notify SILECS support"); + } +} + +void diagnosticToolMainView::on_receiveButton_clicked() +{ + // Receive Button + try{ + Item *currentItem = dynamic_cast<Item*>(ui->treeWidget->currentItem()); + + // block to be received + std::string blockName = ui->receiveComboBox->currentText().toStdString(); + + if( currentItem->whatsThis(0).toStdString().compare(DEVICE_TYPE) != 0 ) // actually this should not be possible at all + { + Utils::logError(ui->console,"Please select a device"); + return; + } + + this->receiveDevice(blockName,currentItem); + } + catch(std::string *str) + { + Utils::logError(ui->console,QString::fromStdString(*str)); + } + catch(std::exception& ex) + { + Utils::logError(ui->console,QString::fromStdString(ex.what())); + } + catch(...) + { + Utils::logError(ui->console,"Unknown error while receiving. Please notify SILECS support"); + } +} + + +void diagnosticToolMainView::on_classNameComboBox_currentIndexChanged(const QString &arg1) +{ + if( !deployFile.isEmpty() ) + { + ui->DesignName->setText(""); + designName = ui->classNameComboBox->currentText(); + loadFiles(); + } + return; +} + +void diagnosticToolMainView::on_loadDeployButton_clicked() +{ + deployFile = QFileDialog::getOpenFileName(this, tr("Deploy to Open"), "" ,tr("Silecs Deploy Files (*.silecsdeploy)")); + if( !deployFile.isEmpty() ) + { + ui->DeployName->setText(deployFile); + ui->DesignName->setText("pick a design"); + fillClassNameComboBox(); + } + return; +} + +void diagnosticToolMainView::setDeployFile(QString file) +{ + deployFile = file; + ui->DeployName->setText(deployFile); + ui->DesignName->setText("pick a design"); + fillClassNameComboBox(); +} + +void diagnosticToolMainView::fillClassNameComboBox() +{ + Utils::logInfo(ui->console,"Loading deploy file: " + deployFile); + XMLParser parserDeploy(deployFile.toStdString(),true); + boost::ptr_vector<ElementXML> classNodes = parserDeploy.getElementsFromXPath_throwIfEmpty("/SILECS-Deploy/Controller/SilecsDesign"); + if(classNodes.size() == 0) + { + Utils::logError(ui->console,"No classes found for this Deploy"); + return; + } + QStringList list; + + boost::ptr_vector<ElementXML>::const_iterator classIter; + for(classIter = classNodes.begin(); classIter != classNodes.end(); classIter++) + { + QString className(classIter->getAttribute("silecs-design-name").c_str()); + if(!list.contains(className)) + list += className; + } + ui->classNameComboBox->clear(); + ui->classNameComboBox->addItems(list); +} + +void diagnosticToolMainView::ctxMenu(const QPoint &pos) +{ + QMenu *menu = new QMenu; + menu->addAction(tr("Clear information console"), this, SLOT(clearConsole_slot())); + menu->exec(ui->console->mapToGlobal(pos)); +} + +void diagnosticToolMainView::clearConsole_slot() +{ + ui->console->clear(); +} + +void diagnosticToolMainView::on_treeWidget_itemExpanded(QTreeWidgetItem *item) +{ + (void)item;// to supress unused warning + // Automaticaly resize the coloumn with the item name + ui->treeWidget->resizeColumnToContents(0); +} + +void diagnosticToolMainView::logBlockReceived(std::string blockName, int elapsedTime) +{ + std::ostringstream message; + message << "Block '" << blockName << "' received successfully from the device in " << elapsedTime << " milliseconds"; + Utils::logInfo(ui->console,message.str().c_str()); +} + +void diagnosticToolMainView::logCommunicationSuccess(int elapsedTime) +{ + std::ostringstream message; + message << "PLC communication successful. Elapsed time: " << elapsedTime << " milliseconds"; + Utils::logInfo(ui->console,message.str().c_str()); +} + + +void diagnosticToolMainView::receiveDevice(std::string blockName, Item* deviceItem) +{ + Silecs::Device *device = (Silecs::Device*)deviceItem->getLinkedObject(); + qDebug() << "try to receive " << QString::fromStdString(blockName); + try{ + //receive device and mesure sending time + QTime mytimer; + mytimer.start(); + int ret = device->recv(blockName); + int elapsedTime = mytimer.elapsed(); + if(ret != 0) + { + Utils::logError(ui->console,QString::fromStdString("Error while receiving the block to the selected device")); + return; + } + logBlockReceived(blockName, elapsedTime); + } + catch(std::string *str) + { + Utils::logError(ui->console,QString::fromStdString(*str)); + } + catch(std::exception& ex) + { + Utils::logError(ui->console,QString::fromStdString(ex.what())); + } + catch (...) + { + Utils::logError(ui->console,"unknown error in diagnosticToolMainView::receiveDevice"); + } + mysilecs->updateDeviceItem(deviceItem,true); +} + +void diagnosticToolMainView::periodicReceiveDevice() +{ + Silecs::Device *device = (Silecs::Device*)currentItemForPeriodicReceive->getLinkedObject(); + qDebug()<< "try to receive "<< QString::fromStdString(blockNameForPeriodicReceive); + try{ + //receive device and mesure sending time + QTime mytimer; + mytimer.start(); + device->recv(blockNameForPeriodicReceive); + int elapsedTime = mytimer.elapsed(); + logBlockReceived(blockNameForPeriodicReceive,elapsedTime); + } + catch(std::string *str) + { + Utils::logError(ui->console,"error while receiving block: " + QString::fromStdString(blockNameForPeriodicReceive)); + Utils::logError(ui->console,QString::fromStdString(*str)); + } + catch(std::exception& ex) + { + Utils::logError(ui->console,"error while receiving block: " + QString::fromStdString(blockNameForPeriodicReceive)); + Utils::logError(ui->console,QString::fromStdString(ex.what())); + } + catch (...) + { + Utils::logError(ui->console,"error while receiving block: " + QString::fromStdString(blockNameForPeriodicReceive)); + Utils::logError(ui->console,"unknown error in diagnosticToolMainView::periodicReceiveDevice"); + } + mysilecs->updateDeviceItem(currentItemForPeriodicReceive,true); +} + +void diagnosticToolMainView::on_periodicReceiveButton_toggled(bool checked) +{ + if(checked) + { + // receive periodic Button + try{ + this->currentItemForPeriodicReceive = dynamic_cast<Item*>(ui->treeWidget->currentItem()); + + // block to be received + this->blockNameForPeriodicReceive = ui->receiveComboBox->currentText().toStdString(); + + periodicReceiveTimer = new QTimer(this); + /* + * If the selected item is a cluster + */ + if(!currentItemForPeriodicReceive->whatsThis(0).compare(QString::fromStdString(CLUSTER_TYPE))) + { + connect(periodicReceiveTimer,SIGNAL(timeout()),SLOT(periodicReceiveCluster())); + ui->monitoringLabel->setText("<font color='blue'>"+ui->treeWidget->currentItem()->text(0)+"</font>"); + } + + /* + * If the selected item is a plc + */ + if(!currentItemForPeriodicReceive->whatsThis(0).compare(QString::fromStdString(PLC_TYPE))) + { + connect(periodicReceiveTimer,SIGNAL(timeout()),SLOT(periodicReceivePLC())); + ui->monitoringLabel->setText("<font color='blue'>"+currentItemForPeriodicReceive->parent()->text(0)+"/" + +ui->treeWidget->currentItem()->text(0)+"</font>"); + } + + /* + * If the selected item is a device + */ + if(!currentItemForPeriodicReceive->whatsThis(0).compare(QString::fromStdString(DEVICE_TYPE))) + { + connect(periodicReceiveTimer,SIGNAL(timeout()),SLOT(periodicReceiveDevice())); + ui->monitoringLabel->setText("<font color='blue'>"+currentItemForPeriodicReceive->parent()->parent()->text(0)+"/" + +currentItemForPeriodicReceive->parent()->text(0)+"/" + +ui->treeWidget->currentItem()->text(0)+"</font>"); + } + periodicReceiveTimer->start((int)(ui->timeSpinBox->value()*1000)); + } + catch(...) + { + Utils::logError(ui->console,"Unexpected error while setting up the timed operation."); + ui->periodicReceiveButton->setChecked(false); + } + ui->timeSpinBox->setEnabled(false); + } + else + { + // better checking if button was enabled because code is called as well + // when a cluster is closed + if(periodicReceiveTimer->isActive()) + periodicReceiveTimer->stop(); + delete periodicReceiveTimer; + + //delete monitoring label text + ui->monitoringLabel->setText(""); + + ui->timeSpinBox->setEnabled(true); + } + +} + +void diagnosticToolMainView::on_copyButton_clicked() +{ + // copy input value to output Button + + try{ + std::string blockName = ui->copyComboBox->currentText().toStdString(); + + Item *currentItem = dynamic_cast<Item*>(ui->treeWidget->currentItem()); + + /* + * If the selected item is a cluster + */ + if(!currentItem->whatsThis(0).compare(QString::fromStdString(CLUSTER_TYPE))) + { + Silecs::Cluster* cluster = (Silecs::Cluster*)(currentItem->getLinkedObject()); + if(QMessageBox::question(this,"Copy input value to output ", + "You are trying to copy all the input value to the output values.\nThe copy will effect all the register of the block "+ui->copyComboBox->currentText()+" of all the connected PLC.\nDo you confirm this operation?", + QMessageBox::Yes,QMessageBox::No)==QMessageBox::Yes) + { + cluster->copyInToOut(blockName); + mysilecs->updateClusterItem(currentItem,false); + } + } + + /* + * If the selected item is a plc + */ + if(!currentItem->whatsThis(0).compare(QString::fromStdString(PLC_TYPE))) + { + Silecs::PLC* plc = (Silecs::PLC*)(currentItem->getLinkedObject()); + if(QMessageBox::question(this,"Copy input value to output ", + "You are trying to copy all the input value to the output values.\nThe copy will effect all the register of the block "+ui->copyComboBox->currentText()+" in the PLC "+QString::fromStdString(plc->getName())+".\nDo you confirm this operation?", + QMessageBox::Yes,QMessageBox::No)==QMessageBox::Yes) + { + plc->copyInToOut(blockName); + mysilecs->updatePLCItem(currentItem,false); + } + } + + /* + * If the selected item is a device + */ + if(!currentItem->whatsThis(0).compare(QString::fromStdString(DEVICE_TYPE))) + { + Silecs::Device* device = (Silecs::Device*)(currentItem->getLinkedObject()); + if(QMessageBox::question(this,"Copy input value to output ", + "You are trying to copy all the input value to the output values.\nThe copy will effect all the register of the block "+ui->copyComboBox->currentText()+" in the device "+QString::fromStdString(device->getLabel())+".\nDo you confirm this operation?", + QMessageBox::Yes,QMessageBox::No)==QMessageBox::Yes) + { + device->copyInToOut(blockName); + mysilecs->updateDeviceItem(currentItem,false); + } + } + + } + catch(...) + { + Utils::logError(ui->console,"Unexpected error while trying to copy input value to output value."); + } +} + +void diagnosticToolMainView::on_checkERROR_stateChanged(int arg1) +{ + (void) arg1; + qDebug()<<"checkERROR changed"; + if(mysilecs != NULL) + { + mysilecs->setLogTopics(this->generateLogTopics()); + } +} +void diagnosticToolMainView::on_checkDEBUG_stateChanged(int arg1) +{ + (void) arg1; + qDebug()<<"checkDEBUG changed"; + if(mysilecs != NULL) + { + mysilecs->setLogTopics(this->generateLogTopics()); + mysilecs->enableDebugLog(); + } +} + +void diagnosticToolMainView::on_checkSETUP_stateChanged(int arg1) +{ + (void) arg1; + qDebug()<<"checkSETUP changed"; + if(mysilecs != NULL) + { + mysilecs->setLogTopics(this->generateLogTopics()); + } +} + +void diagnosticToolMainView::on_checkALLOC_stateChanged(int arg1) +{ + (void) arg1; + qDebug()<<"checkALLOC changed"; + if(mysilecs != NULL) + { + mysilecs->setLogTopics(this->generateLogTopics()); + } +} + +void diagnosticToolMainView::on_checkLOCK_stateChanged(int arg1) +{ + (void) arg1; + qDebug()<<"checkLOCK changed"; + if(mysilecs != NULL) + { + mysilecs->setLogTopics(this->generateLogTopics()); + } +} + +void diagnosticToolMainView::on_checkCOMM_stateChanged(int arg1) +{ + (void) arg1; + qDebug()<<"checkCOMM changed"; + if(mysilecs != NULL) + { + mysilecs->setLogTopics(this->generateLogTopics()); + } +} + +void diagnosticToolMainView::on_checkSEND_stateChanged(int arg1) +{ + (void) arg1; + qDebug()<<"checkSEND changed"; + if(mysilecs != NULL) + { + mysilecs->setLogTopics(this->generateLogTopics()); + } +} + +void diagnosticToolMainView::on_checkRECV_stateChanged(int arg1) +{ + (void) arg1; + qDebug()<<"checkRECV changed"; + if(mysilecs != NULL) + { + mysilecs->setLogTopics(this->generateLogTopics()); + } +} + +void diagnosticToolMainView::on_checkDATA_stateChanged(int arg1) +{ + (void) arg1; + qDebug()<<"checkDATA changed"; + if(mysilecs != NULL) + { + mysilecs->setLogTopics(this->generateLogTopics()); + } +} + +void diagnosticToolMainView::on_checkDIAG_stateChanged(int arg1) +{ + (void) arg1; + qDebug()<<"checkDIAG changed"; + if(mysilecs != NULL) + { + mysilecs->setLogTopics(this->generateLogTopics()); + } +} + +void diagnosticToolMainView::on_treeWidget_clicked() +{ + +} diff --git a/silecs-diagnostic-cpp/src/silecs-diagnostic/diagnostictoolmainview.h b/silecs-diagnostic-cpp/src/silecs-diagnostic/diagnostictoolmainview.h new file mode 100755 index 0000000..b177412 --- /dev/null +++ b/silecs-diagnostic-cpp/src/silecs-diagnostic/diagnostictoolmainview.h @@ -0,0 +1,120 @@ +// Copyright 2016 CERN and GSI +// +// 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 3 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, see <http://www.gnu.org/licenses/>. + +#ifndef DIAGNOSTICTOOLMAINVIEW_H +#define DIAGNOSTICTOOLMAINVIEW_H + +#include <QMainWindow> + +#include <silecs-diagnostic/displayarraydialog.h> +#include <silecs-diagnostic/item.h> +#include <silecs-diagnostic/silecsmodule.h> +#include <silecs-diagnostic/stderrredirect.h> + +#include <iostream> +#include <typeinfo> +#include <map> + + +namespace Ui { + class diagnosticToolMainView; +} + +using namespace Silecs; + + +class diagnosticToolMainView : public QMainWindow +{ + Q_OBJECT + +public: + explicit diagnosticToolMainView(QWidget *parent = 0); + ~diagnosticToolMainView(); + + void setDeployFile(QString file); + +private slots: + + // Tree view + void on_treeWidget_currentItemChanged(QTreeWidgetItem *current, QTreeWidgetItem *previous); + void on_treeWidget_doubleClicked(const QModelIndex &index); + void on_treeWidget_itemExpanded(QTreeWidgetItem *item); + + // Class name combo + void on_classNameComboBox_currentIndexChanged(const QString &arg1); + + // Buttons + void on_sendButton_clicked(); + void on_receiveButton_clicked(); + void on_connectButton_clicked(); + void on_loadDeployButton_clicked(); + void on_disconnectButton_clicked(); + void on_copyButton_clicked(); + + // Context menu for the console + void ctxMenu(const QPoint &pos); + void clearConsole_slot(); + + // different way of receiving + void receiveDevice(std::string blockName,Item* currentItem); + void periodicReceiveDevice(); + + // monitor + void on_periodicReceiveButton_toggled(bool checked); + + // Log Topics change + void on_checkERROR_stateChanged(int arg1); + void on_checkDEBUG_stateChanged(int arg1); + void on_checkSETUP_stateChanged(int arg1); + void on_checkALLOC_stateChanged(int arg1); + void on_checkLOCK_stateChanged(int arg1); + void on_checkCOMM_stateChanged(int arg1); + void on_checkSEND_stateChanged(int arg1); + void on_checkRECV_stateChanged(int arg1); + void on_checkDATA_stateChanged(int arg1); + void on_checkDIAG_stateChanged(int arg1); + + void on_treeWidget_clicked(); + +private: + + // GSI-Hack - load directly from file + QString designName; + QString deployFile; + void resetGUI(); + void loadFiles(); + + void fillClassNameComboBox(); + + void logBlockReceived(std::string blockName, int elapsedTime); + void logCommunicationSuccess(int elapsedTime); + + std::vector<QString> openArrayDialogBase(Silecs::Register* reg, std::vector<QString> dataVector, bool localData); + std::vector<QString> open1DArrayDialog(Silecs::Register* reg, bool localData); + std::vector<QString> open2DArrayDialog(Silecs::Register* reg, bool localData); + void markItemNotEdiable(QTreeWidgetItem *item); + + Ui::diagnosticToolMainView *ui; + + //BlockName and current item for periodic receive + std::string blockNameForPeriodicReceive; + Item* currentItemForPeriodicReceive; + QTimer *periodicReceiveTimer; + + StdErrRedirect *redirector; + std::string generateLogTopics(); +}; + +#endif // DIAGNOSTICTOOLMAINVIEW_H diff --git a/silecs-diagnostic-cpp/src/silecs-diagnostic/displayarraydialog.cpp b/silecs-diagnostic-cpp/src/silecs-diagnostic/displayarraydialog.cpp new file mode 100755 index 0000000..71a41ac --- /dev/null +++ b/silecs-diagnostic-cpp/src/silecs-diagnostic/displayarraydialog.cpp @@ -0,0 +1,87 @@ +// Copyright 2016 CERN and GSI +// +// 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 3 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, see <http://www.gnu.org/licenses/>. + +#include <silecs-diagnostic/displayarraydialog.h> +#include <silecs-diagnostic/generated/ui_displayarraydialog.h> + +#include <QDebug> + +DisplayArrayDialog::DisplayArrayDialog(QWidget *parent) : + QDialog(parent), + ui(new Ui::DisplayArrayDialog) +{ + ui->setupUi(this); + +} + +DisplayArrayDialog::~DisplayArrayDialog() +{ + delete ui; +} + +void DisplayArrayDialog::setDataVector(std::vector<QString> dataVector, bool editable, unsigned long dim2) +{ + this->dataVector = dataVector; + + // display informations + if(dim2 <= 1) // 1d array + { + int numberOfValues = this->dataVector.size(); + ui->tableWidget->setColumnCount(1); + ui->tableWidget->setRowCount(numberOfValues); + + for(int i= 0; i< numberOfValues; i++) + { + QTableWidgetItem *item = new QTableWidgetItem(dataVector[i],1); + + if(!editable) // default flag contain editable + item->setFlags(Qt::ItemIsSelectable|Qt::ItemIsEnabled); + + ui->tableWidget->setItem(0,i,item); + } + } + else // 2d array + { + unsigned long dim1 = (this->dataVector.size())/dim2; + ui->tableWidget->setColumnCount(dim2); + ui->tableWidget->setRowCount(dim1); + + for(unsigned long i=0; i<dim1; i++) + { + for(unsigned long j=0; j<dim2; j++) + { + QTableWidgetItem *item = new QTableWidgetItem(dataVector[i*dim2+j],1); + if(!editable) // default flag contains editable + item->setFlags(Qt::ItemIsSelectable|Qt::ItemIsEnabled); + + ui->tableWidget->setItem(i,j,item); + } + } + } + // display informations end +} + +std::vector<QString> DisplayArrayDialog::getDataVector() +{ + return this->dataVector; +} + +void DisplayArrayDialog::on_buttonBox_accepted() +{ + int numberOfValues = this->dataVector.size(); + for(int i= 0; i< numberOfValues; i++) + this->dataVector[i] = ui->tableWidget->item(0,i)->text(); + +} diff --git a/silecs-diagnostic-cpp/src/silecs-diagnostic/displayarraydialog.h b/silecs-diagnostic-cpp/src/silecs-diagnostic/displayarraydialog.h new file mode 100755 index 0000000..ff42544 --- /dev/null +++ b/silecs-diagnostic-cpp/src/silecs-diagnostic/displayarraydialog.h @@ -0,0 +1,47 @@ +// Copyright 2016 CERN and GSI +// +// 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 3 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, see <http://www.gnu.org/licenses/>. + +#ifndef DISPLAYARRAYDIALOG_H +#define DISPLAYARRAYDIALOG_H + +#include <QDialog> + +namespace Ui { + class DisplayArrayDialog; +} + +class DisplayArrayDialog : public QDialog +{ + Q_OBJECT + +public: + explicit DisplayArrayDialog(QWidget *parent = 0); + ~DisplayArrayDialog(); + + void setDataVector(std::vector<QString> dataVector, bool editable, unsigned long dim2); + + std::vector<QString> getDataVector(); + +private slots: + void on_buttonBox_accepted(); + +private: + Ui::DisplayArrayDialog *ui; + + std::vector<QString> dataVector; + +}; + +#endif // DISPLAYARRAYDIALOG_H diff --git a/silecs-diagnostic-cpp/src/silecs-diagnostic/headerinformations.cpp b/silecs-diagnostic-cpp/src/silecs-diagnostic/headerinformations.cpp new file mode 100755 index 0000000..14c44bc --- /dev/null +++ b/silecs-diagnostic-cpp/src/silecs-diagnostic/headerinformations.cpp @@ -0,0 +1,63 @@ +// Copyright 2016 CERN and GSI +// +// 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 3 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, see <http://www.gnu.org/licenses/>. + +#include <silecs-diagnostic/headerinformations.h> + +HeaderInformations::HeaderInformations() +{ +} + +// String setter +void HeaderInformations::setheaderRelease(std::string headerRelease) +{ + this->headerRelease = headerRelease; +} + +void HeaderInformations::setheaderOwner(std::string headerOwner) +{ + this->headerOwner = headerOwner; +} + +void HeaderInformations::setheaderDate(std::string headerDate) +{ + this->headerDate = headerDate; +} + +void HeaderInformations::setHeaderChecksum(std::string HeaderChecksum) +{ + this->HeaderChecksum = HeaderChecksum; +} + + +// String getter +std::string HeaderInformations::getheaderRelease() +{ + return this->headerRelease; +} + +std::string HeaderInformations::getheaderOwner() +{ + return this->headerOwner; +} + +std::string HeaderInformations::getheaderDate() +{ + return this->headerDate; +} + +std::string HeaderInformations::getHeaderChecksum() +{ + return this->HeaderChecksum; +} diff --git a/silecs-diagnostic-cpp/src/silecs-diagnostic/headerinformations.h b/silecs-diagnostic-cpp/src/silecs-diagnostic/headerinformations.h new file mode 100755 index 0000000..b3750cc --- /dev/null +++ b/silecs-diagnostic-cpp/src/silecs-diagnostic/headerinformations.h @@ -0,0 +1,46 @@ +// Copyright 2016 CERN and GSI +// +// 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 3 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, see <http://www.gnu.org/licenses/>. + +#ifndef HEADERINFORMATIONS_H +#define HEADERINFORMATIONS_H + +#include <string> + +class HeaderInformations +{ + +private: + std::string headerRelease; + std::string headerOwner; + std::string headerDate; + std::string HeaderChecksum; + +public: + HeaderInformations(); + + // String setter + void setheaderRelease(std::string headerRelease); + void setheaderOwner(std::string headerOwner); + void setheaderDate(std::string headerDate); + void setHeaderChecksum(std::string HeaderChecksum); + + // String getter + std::string getheaderRelease(); + std::string getheaderOwner(); + std::string getheaderDate(); + std::string getHeaderChecksum(); +}; + +#endif // HEADERINFORMATIONS_H diff --git a/silecs-diagnostic-cpp/src/silecs-diagnostic/item.cpp b/silecs-diagnostic-cpp/src/silecs-diagnostic/item.cpp new file mode 100755 index 0000000..4232b67 --- /dev/null +++ b/silecs-diagnostic-cpp/src/silecs-diagnostic/item.cpp @@ -0,0 +1,33 @@ +// Copyright 2016 CERN and GSI +// +// 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 3 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, see <http://www.gnu.org/licenses/>. + +#include <silecs-diagnostic/item.h> + + +Item::Item(void* linkedObject) +{ + this->linkedObject = linkedObject; +} + +void Item::setLinkedObject(void* linkedObject) +{ + this->linkedObject = linkedObject; +} + +void* Item::getLinkedObject() +{ + return this->linkedObject; +} + diff --git a/silecs-diagnostic-cpp/src/silecs-diagnostic/item.h b/silecs-diagnostic-cpp/src/silecs-diagnostic/item.h new file mode 100755 index 0000000..be317ae --- /dev/null +++ b/silecs-diagnostic-cpp/src/silecs-diagnostic/item.h @@ -0,0 +1,37 @@ +// Copyright 2016 CERN and GSI +// +// 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 3 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, see <http://www.gnu.org/licenses/>. + +#ifndef ITEM_H +#define ITEM_H + +#include <QTreeWidgetItem> + +class QDomDocument; +class Item : public QTreeWidgetItem { +// Q_PROPERTY( QString Name READ name WRITE setName ); + private: + void *linkedObject; + public: + Item(void* linkedObject); + Item(); + + // set the pointer to the related object + void setLinkedObject(void* linkedObject); + + // return the pointer to the related object + void* getLinkedObject(); +}; + +#endif // ITEM_H diff --git a/silecs-diagnostic-cpp/src/silecs-diagnostic/logindialog.cpp b/silecs-diagnostic-cpp/src/silecs-diagnostic/logindialog.cpp new file mode 100755 index 0000000..d460b0a --- /dev/null +++ b/silecs-diagnostic-cpp/src/silecs-diagnostic/logindialog.cpp @@ -0,0 +1,59 @@ +// Copyright 2016 CERN and GSI +// +// 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 3 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, see <http://www.gnu.org/licenses/>. + +#include <silecs-diagnostic/logindialog.h> +#include <silecs-diagnostic/generated/ui_logindialog.h> + + +LoginDialog::LoginDialog(QWidget *parent) : + QDialog(parent), + ui(new Ui::LoginDialog) +{ + ui->setupUi(this); +} + +LoginDialog::~LoginDialog() +{ + delete ui; +} + +//set and get username +//void LoginDialog::setUsername(std::string username) +//{ +// this->username = username; +//} + +std::string LoginDialog::getUsername() +{ + return this->username; +} + +//set and get password +//void LoginDialog::setPassword(std::string password) +//{ +// this->password = password; +//} + +std::string LoginDialog::getPassword() +{ + return this->password; +} + +void LoginDialog::on_buttonBox_accepted() +{ + this->username = ui->usernameLineEdit->text().toStdString(); + this->password = ui->passwordLineEdit->text().toStdString(); +} + diff --git a/silecs-diagnostic-cpp/src/silecs-diagnostic/logindialog.h b/silecs-diagnostic-cpp/src/silecs-diagnostic/logindialog.h new file mode 100755 index 0000000..d337ea7 --- /dev/null +++ b/silecs-diagnostic-cpp/src/silecs-diagnostic/logindialog.h @@ -0,0 +1,54 @@ +// Copyright 2016 CERN and GSI +// +// 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 3 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, see <http://www.gnu.org/licenses/>. + +#ifndef LOGINDIALOG_H +#define LOGINDIALOG_H + +#include <QDialog> + +#include <silecs-diagnostic/constants.h> + +namespace Ui { + class LoginDialog; +} + +class LoginDialog : public QDialog +{ + Q_OBJECT + +public: + explicit LoginDialog(QWidget *parent = 0); + ~LoginDialog(); + + //set and get username +// void setUsername(std::string username); + std::string getUsername(); + + //set and get password +// void setPassword(std::string password); + std::string getPassword(); + +private slots: + void on_buttonBox_accepted(); + +private: + Ui::LoginDialog *ui; + + // login and password + std::string username; + std::string password; +}; + +#endif // LOGINDIALOG_H diff --git a/silecs-diagnostic-cpp/src/silecs-diagnostic/loginhandler.cpp b/silecs-diagnostic-cpp/src/silecs-diagnostic/loginhandler.cpp new file mode 100755 index 0000000..962bd5e --- /dev/null +++ b/silecs-diagnostic-cpp/src/silecs-diagnostic/loginhandler.cpp @@ -0,0 +1,71 @@ +// Copyright 2016 CERN and GSI +// +// 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 3 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, see <http://www.gnu.org/licenses/>. + +#include <silecs-diagnostic/loginhandler.h> + +#ifdef WITH_RBAC + extern std::string UserName; + + loginHandler::loginHandler() + { + } + + bool loginHandler::requestLogin() + { + LoginDialog *loginDialog = new LoginDialog(); + + for(int i=0;i<NUMBER_PASSWORD_ATTEMPTS;i++) + { + try + { + //Popup interface requesting password + + loginDialog->setModal(true); + + if(loginDialog->exec()==1) + { + auto_ptr<cmw::rbac::TokenClass> token = cmw::rbac::LoginContext::login("SILECS Diagnostic Tool", + loginDialog->getUsername(), + loginDialog->getPassword()); + if (token.get() != NULL) + { + //password correct + extern std::string UserName; + UserName = loginDialog->getUsername(); + delete loginDialog; + return true; + } + } + else + { + //cancell button was pressed + delete loginDialog; + return false; + } + } + catch (const cmw::rbac::AuthenticationFailure & ex) + { + qDebug() << "Autentication failure!"; + } + catch(...) + { + qDebug() << "unknown exception"; + } + } + + delete loginDialog; + return false; + } +#endif diff --git a/silecs-diagnostic-cpp/src/silecs-diagnostic/loginhandler.h b/silecs-diagnostic-cpp/src/silecs-diagnostic/loginhandler.h new file mode 100755 index 0000000..aad9937 --- /dev/null +++ b/silecs-diagnostic-cpp/src/silecs-diagnostic/loginhandler.h @@ -0,0 +1,46 @@ +// Copyright 2016 CERN and GSI +// +// 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 3 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, see <http://www.gnu.org/licenses/>. + +#ifndef LOGINHANDLER_H +#define LOGINHANDLER_H + +#include <QtGui> +#include <QtCore> + +#include <silecs-diagnostic/logindialog.h> +#include <silecs-diagnostic/constants.h> + +#include <iostream> + +#ifdef WITH_RBAC + #include <cmw-rbac/LoginContext.h> + #include <cmw-rbac/AuthenticationFailure.h> +#endif + +using namespace std; + +#ifdef WITH_RBAC + extern std::string USER_NAME; + + class loginHandler + { + public: + loginHandler(); + bool requestLogin(); + }; +#endif + + +#endif // LOGINHANDLER_H diff --git a/silecs-diagnostic-cpp/src/silecs-diagnostic/main.cpp b/silecs-diagnostic-cpp/src/silecs-diagnostic/main.cpp new file mode 100755 index 0000000..1ac7fa0 --- /dev/null +++ b/silecs-diagnostic-cpp/src/silecs-diagnostic/main.cpp @@ -0,0 +1,88 @@ +// Copyright 2016 CERN and GSI +// +// 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 3 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, see <http://www.gnu.org/licenses/>. + +#include <QtGui/QApplication> + +#include <silecs-diagnostic/constants.h> +#include <silecs-diagnostic/diagnostictoolmainview.h> +#include <silecs-diagnostic/loginhandler.h> +#include <silecs-diagnostic/silecsmodule.h> + + +silecsModule *mysilecs; + +class I : public QThread +{ +public: + static void sleep(unsigned long secs) { + QThread::sleep(secs); + } +}; + +// Logged in user. (To be set at runtime) +std::string UserName; + + + // main with splash screen and login + int main(int argc, char *argv[]) + { + mysilecs = NULL; + try + { + Silecs::XMLParser::init(); +#ifdef WITH_RBAC + //Login + loginHandler* login = new loginHandler(); + if(!login->requestLogin()) + { + return 0; + } +#endif + + QApplication app(argc, argv); + QPixmap pixmap( ":/Images/splash-silecs.png" ); + + QSplashScreen splash(pixmap); + splash.show(); + + diagnosticToolMainView mainWin; + mainWin.setWindowTitle("SILECS Diagnostic Tool"); + + if (argc >= 3) // an argument was passed + { + if (strcmp(argv[1],"-d") == 0) + mainWin.setDeployFile(QString::fromStdString(argv[2])); + } + + I::sleep(SPLASH_SCREEN_TIME); + + mainWin.showMaximized(); + splash.finish(&mainWin); + return app.exec(); + } + catch(std::string *str) + { + std::cout << str; + } + catch(std::exception& ex) + { + std::cout << ex.what(); + } + catch(...) + { + std::cout << "Unexpected error caught in Main. Please notify SILECS support"; + } + return -1; + } diff --git a/silecs-diagnostic-cpp/src/silecs-diagnostic/resources/gui/ArrayVisualizationDialog.ui b/silecs-diagnostic-cpp/src/silecs-diagnostic/resources/gui/ArrayVisualizationDialog.ui new file mode 100755 index 0000000..eaebf5f --- /dev/null +++ b/silecs-diagnostic-cpp/src/silecs-diagnostic/resources/gui/ArrayVisualizationDialog.ui @@ -0,0 +1,67 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> + <class>Dialog</class> + <widget class="QDialog" name="Dialog"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>180</width> + <height>481</height> + </rect> + </property> + <property name="windowTitle"> + <string>Dialog</string> + </property> + <layout class="QVBoxLayout" name="verticalLayout"> + <item> + <widget class="QTableWidget" name="tableWidget"/> + </item> + <item> + <widget class="QDialogButtonBox" name="buttonBox"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="standardButtons"> + <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set> + </property> + </widget> + </item> + </layout> + </widget> + <resources/> + <connections> + <connection> + <sender>buttonBox</sender> + <signal>accepted()</signal> + <receiver>Dialog</receiver> + <slot>accept()</slot> + <hints> + <hint type="sourcelabel"> + <x>248</x> + <y>254</y> + </hint> + <hint type="destinationlabel"> + <x>157</x> + <y>274</y> + </hint> + </hints> + </connection> + <connection> + <sender>buttonBox</sender> + <signal>rejected()</signal> + <receiver>Dialog</receiver> + <slot>reject()</slot> + <hints> + <hint type="sourcelabel"> + <x>316</x> + <y>260</y> + </hint> + <hint type="destinationlabel"> + <x>286</x> + <y>274</y> + </hint> + </hints> + </connection> + </connections> +</ui> diff --git a/silecs-diagnostic-cpp/src/silecs-diagnostic/resources/gui/diagnostictoolmainview.ui b/silecs-diagnostic-cpp/src/silecs-diagnostic/resources/gui/diagnostictoolmainview.ui new file mode 100755 index 0000000..cc67f78 --- /dev/null +++ b/silecs-diagnostic-cpp/src/silecs-diagnostic/resources/gui/diagnostictoolmainview.ui @@ -0,0 +1,684 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> + <class>diagnosticToolMainView</class> + <widget class="QMainWindow" name="diagnosticToolMainView"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>909</width> + <height>805</height> + </rect> + </property> + <property name="windowTitle"> + <string>diagnosticToolMainView</string> + </property> + <widget class="QWidget" name="centralWidget"> + <layout class="QVBoxLayout" name="verticalLayout_11"> + <item> + <widget class="QGroupBox" name="clusterGroupBox"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Preferred" vsizetype="Minimum"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="maximumSize"> + <size> + <width>16777215</width> + <height>16777215</height> + </size> + </property> + <property name="title"> + <string>Cluster operations</string> + </property> + <property name="flat"> + <bool>true</bool> + </property> + <layout class="QHBoxLayout" name="horizontalLayout"> + <item> + <layout class="QVBoxLayout" name="verticalLayout_5"> + <item> + <widget class="QPushButton" name="loadDeployButton"> + <property name="toolTip"> + <string>Select a Deploy to load</string> + </property> + <property name="text"> + <string>Load Deploy</string> + </property> + </widget> + </item> + <item> + <widget class="QComboBox" name="classNameComboBox"/> + </item> + </layout> + </item> + <item> + <layout class="QVBoxLayout" name="verticalLayout_2"> + <item> + <widget class="QLabel" name="DeployName"> + <property name="text"> + <string>< Please Load a Deploy ></string> + </property> + </widget> + </item> + <item> + <widget class="QLabel" name="DesignName"> + <property name="text"> + <string>< and Pick a Design ></string> + </property> + </widget> + </item> + </layout> + </item> + <item> + <layout class="QGridLayout" name="gridLayout_4"> + <item row="0" column="0"> + <spacer name="horizontalSpacer"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>88</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + <item row="0" column="2"> + <widget class="QCheckBox" name="checkERROR"> + <property name="enabled"> + <bool>false</bool> + </property> + <property name="toolTip"> + <string>standard topic to trace the IEPLC processing errors, sent to the console (if enable)</string> + </property> + <property name="text"> + <string>ERROR</string> + </property> + <property name="checked"> + <bool>true</bool> + </property> + </widget> + </item> + <item row="1" column="0"> + <spacer name="horizontalSpacer_2"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>88</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + <item row="0" column="6"> + <widget class="QCheckBox" name="checkDATA"> + <property name="toolTip"> + <string>standard topic to trace transaction details, sent to the console (if enable with SEND/RECV)</string> + </property> + <property name="text"> + <string>DATA</string> + </property> + </widget> + </item> + <item row="0" column="5"> + <widget class="QCheckBox" name="checkSEND"> + <property name="toolTip"> + <string>standard topic to trace transaction toward PLC, sent to the console (if enable)</string> + </property> + <property name="text"> + <string>SEND</string> + </property> + </widget> + </item> + <item row="1" column="5"> + <widget class="QCheckBox" name="checkRECV"> + <property name="toolTip"> + <string>standard topic to trace transaction from PLC, sent to the console (if enable)</string> + </property> + <property name="text"> + <string>RECV</string> + </property> + </widget> + </item> + <item row="1" column="4"> + <widget class="QCheckBox" name="checkCOMM"> + <property name="toolTip"> + <string>standard topic to trace PLC communication, sent to the console (if enable)</string> + </property> + <property name="text"> + <string>COMM</string> + </property> + <property name="checked"> + <bool>true</bool> + </property> + </widget> + </item> + <item row="1" column="2"> + <widget class="QCheckBox" name="checkDEBUG"> + <property name="toolTip"> + <string>standard topic to trace the IEPLC debug info, sent to the console (if enable)</string> + </property> + <property name="text"> + <string>DEBUG</string> + </property> + </widget> + </item> + <item row="0" column="3"> + <widget class="QCheckBox" name="checkSETUP"> + <property name="toolTip"> + <string>standard topic to trace details of IEPLC client start-up, sent to the console (if enable)</string> + </property> + <property name="text"> + <string>SETUP</string> + </property> + </widget> + </item> + <item row="1" column="3"> + <widget class="QCheckBox" name="checkALLOC"> + <property name="toolTip"> + <string>standard topic to trace allocation memory, sent to the console (if enable)</string> + </property> + <property name="text"> + <string>ALLOC</string> + </property> + <property name="checked"> + <bool>false</bool> + </property> + </widget> + </item> + <item row="0" column="4"> + <widget class="QCheckBox" name="checkLOCK"> + <property name="toolTip"> + <string>standard topic to trace resources lock details, sent to the console (if enable)</string> + </property> + <property name="text"> + <string>LOCK</string> + </property> + </widget> + </item> + <item row="1" column="6"> + <widget class="QCheckBox" name="checkDIAG"> + <property name="toolTip"> + <string>special topic sent to the console (if enable) and to the syslog (in any cases)</string> + </property> + <property name="text"> + <string>DIAG</string> + </property> + </widget> + </item> + <item row="1" column="1"> + <widget class="QCheckBox" name="compareChecksums"> + <property name="enabled"> + <bool>true</bool> + </property> + <property name="text"> + <string>compare Checksums</string> + </property> + <property name="checked"> + <bool>true</bool> + </property> + </widget> + </item> + </layout> + </item> + </layout> + </widget> + </item> + <item> + <widget class="QSplitter" name="splitter_2"> + <property name="orientation"> + <enum>Qt::Vertical</enum> + </property> + <widget class="QSplitter" name="splitter"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <widget class="QWidget" name="layoutWidget"> + <layout class="QVBoxLayout" name="verticalLayout_10"> + <item> + <widget class="QTreeWidget" name="treeWidget"> + <property name="cursor" stdset="0"> + <cursorShape>ArrowCursor</cursorShape> + </property> + <property name="frameShadow"> + <enum>QFrame::Sunken</enum> + </property> + <property name="alternatingRowColors"> + <bool>false</bool> + </property> + <property name="columnCount"> + <number>3</number> + </property> + <column> + <property name="text"> + <string notr="true"/> + </property> + </column> + <column> + <property name="text"> + <string notr="true"/> + </property> + </column> + <column> + <property name="text"> + <string notr="true"/> + </property> + </column> + </widget> + </item> + <item> + <widget class="QGroupBox" name="groupBox_2"> + <property name="title"> + <string>PLC Value</string> + </property> + <layout class="QVBoxLayout" name="verticalLayout_7"> + <item> + <layout class="QGridLayout" name="gridLayout_5"> + <item row="0" column="0"> + <widget class="QLabel" name="label_7"> + <property name="text"> + <string>Binary value:</string> + </property> + </widget> + </item> + <item row="0" column="1"> + <widget class="QLabel" name="binValueLabel"> + <property name="text"> + <string>--value--</string> + </property> + </widget> + </item> + <item row="1" column="0"> + <widget class="QLabel" name="label_8"> + <property name="text"> + <string>Hexadecimal value:</string> + </property> + </widget> + </item> + <item row="1" column="1"> + <widget class="QLabel" name="HexValueLabel"> + <property name="text"> + <string>--value--</string> + </property> + </widget> + </item> + <item row="3" column="0"> + <widget class="QLabel" name="label_13"> + <property name="text"> + <string>ASCII representation:</string> + </property> + </widget> + </item> + <item row="2" column="0"> + <widget class="QLabel" name="label_9"> + <property name="text"> + <string>Decimal value</string> + </property> + </widget> + </item> + <item row="3" column="1"> + <widget class="QLabel" name="asciiValueLabel"> + <property name="text"> + <string>--value--</string> + </property> + </widget> + </item> + <item row="2" column="1"> + <widget class="QLabel" name="DecValueLabel"> + <property name="text"> + <string>--value--</string> + </property> + </widget> + </item> + </layout> + </item> + </layout> + </widget> + </item> + </layout> + </widget> + <widget class="QSplitter" name="verticalSplitter"> + <property name="orientation"> + <enum>Qt::Vertical</enum> + </property> + <widget class="QWidget" name="layoutWidget"> + <layout class="QVBoxLayout" name="verticalLayout_4"> + <property name="spacing"> + <number>10</number> + </property> + <item> + <layout class="QHBoxLayout" name="horizontalLayout_3"> + <property name="spacing"> + <number>6</number> + </property> + <item> + <widget class="QPushButton" name="disconnectButton"> + <property name="enabled"> + <bool>false</bool> + </property> + <property name="toolTip"> + <string><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Sans Serif'; font-size:9pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Disconnect from PLC.<br />Available only if a PLC element is selected.</p></body></html></string> + </property> + <property name="text"> + <string>Disconnect PLC</string> + </property> + <property name="icon"> + <iconset> + <normaloff>:/Images/disconnect.png</normaloff>:/Images/disconnect.png</iconset> + </property> + </widget> + </item> + </layout> + </item> + <item> + <widget class="QPushButton" name="connectButton"> + <property name="enabled"> + <bool>false</bool> + </property> + <property name="toolTip"> + <string><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Sans Serif'; font-size:9pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Connect to PLC.<br />Available only if a PLC element is selected.</p></body></html></string> + </property> + <property name="text"> + <string>Connect PLC</string> + </property> + <property name="icon"> + <iconset> + <normaloff>:/Images/connect.png</normaloff>:/Images/connect.png</iconset> + </property> + </widget> + </item> + <item> + <widget class="QGroupBox" name="copyBox"> + <property name="title"> + <string>Copy Value from PLC to Local</string> + </property> + <property name="flat"> + <bool>true</bool> + </property> + <layout class="QGridLayout" name="gridLayout_3"> + <property name="topMargin"> + <number>0</number> + </property> + <property name="bottomMargin"> + <number>0</number> + </property> + <property name="verticalSpacing"> + <number>6</number> + </property> + <item row="0" column="0"> + <widget class="QLabel" name="label_6"> + <property name="text"> + <string>Block:</string> + </property> + <property name="alignment"> + <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set> + </property> + </widget> + </item> + <item row="0" column="1"> + <widget class="QComboBox" name="copyComboBox"/> + </item> + <item row="1" column="1"> + <widget class="QPushButton" name="copyButton"> + <property name="enabled"> + <bool>false</bool> + </property> + <property name="toolTip"> + <string><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Sans Serif'; font-size:9pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Copy the input buffer value of the selected BLOCK to theoutput values.</p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Copying is available at:</p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"> - Cluster level.</p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"> - PLC level.</p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"> - Device level.<br /></p></body></html></string> + </property> + <property name="text"> + <string>Copy</string> + </property> + <property name="icon"> + <iconset> + <normaloff>:/Images/copy.png</normaloff>:/Images/copy.png</iconset> + </property> + </widget> + </item> + </layout> + </widget> + </item> + <item> + <widget class="QGroupBox" name="sendBox"> + <property name="title"> + <string>Send</string> + </property> + <property name="flat"> + <bool>true</bool> + </property> + <layout class="QGridLayout" name="gridLayout_2"> + <property name="topMargin"> + <number>0</number> + </property> + <property name="bottomMargin"> + <number>0</number> + </property> + <property name="verticalSpacing"> + <number>6</number> + </property> + <item row="0" column="0"> + <widget class="QLabel" name="label_5"> + <property name="text"> + <string>Block:</string> + </property> + <property name="alignment"> + <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set> + </property> + </widget> + </item> + <item row="0" column="1"> + <widget class="QComboBox" name="sendComboBox"/> + </item> + <item row="1" column="1"> + <widget class="QPushButton" name="sendButton"> + <property name="enabled"> + <bool>false</bool> + </property> + <property name="toolTip"> + <string><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Sans Serif'; font-size:9pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Send the selected BLOCK to the selected item just one time.</p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Sending is available at:</p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"> - Cluster level.</p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"> - PLC level.</p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"> - Device level.<br /></p></body></html></string> + </property> + <property name="text"> + <string> Send </string> + </property> + <property name="icon"> + <iconset> + <normaloff>:/Images/send1.png</normaloff>:/Images/send1.png</iconset> + </property> + </widget> + </item> + </layout> + </widget> + </item> + <item> + <widget class="QGroupBox" name="receiveBox"> + <property name="title"> + <string>Receive</string> + </property> + <property name="flat"> + <bool>true</bool> + </property> + <layout class="QGridLayout" name="gridLayout"> + <property name="topMargin"> + <number>0</number> + </property> + <property name="bottomMargin"> + <number>0</number> + </property> + <item row="0" column="0"> + <widget class="QLabel" name="label_4"> + <property name="text"> + <string>Block:</string> + </property> + <property name="alignment"> + <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set> + </property> + </widget> + </item> + <item row="0" column="1"> + <widget class="QComboBox" name="receiveComboBox"/> + </item> + <item row="1" column="0"> + <widget class="QLabel" name="label_3"> + <property name="text"> + <string>Sec:</string> + </property> + <property name="alignment"> + <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set> + </property> + </widget> + </item> + <item row="1" column="1"> + <widget class="QDoubleSpinBox" name="timeSpinBox"/> + </item> + <item row="4" column="1"> + <widget class="QPushButton" name="receiveButton"> + <property name="enabled"> + <bool>false</bool> + </property> + <property name="toolTip"> + <string><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Sans Serif'; font-size:9pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Receive the selected BLOCK from the selected item just one time.</p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Receiving is available at:</p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"> - Cluster level.</p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"> - PLC level.</p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"> - Device level.<br /></p></body></html></string> + </property> + <property name="text"> + <string>Receive</string> + </property> + <property name="icon"> + <iconset> + <normaloff>:/Images/glasses1.png</normaloff>:/Images/glasses1.png</iconset> + </property> + </widget> + </item> + <item row="2" column="1"> + <widget class="QPushButton" name="periodicReceiveButton"> + <property name="enabled"> + <bool>false</bool> + </property> + <property name="toolTip"> + <string>Receive the selected BLOCK from the selected item periodicaly (every "Interval" seconds). +Receiving is available at: + - Cluster level. + - PLC level. + - Device level.</string> + </property> + <property name="text"> + <string>Monitor</string> + </property> + <property name="icon"> + <iconset> + <normaloff>:/Images/glasses.png</normaloff> + <normalon>:/Images/stop.png</normalon>:/Images/glasses.png</iconset> + </property> + <property name="checkable"> + <bool>true</bool> + </property> + <property name="checked"> + <bool>false</bool> + </property> + </widget> + </item> + <item row="2" column="0"> + <widget class="QLabel" name="monitoringLabel"> + <property name="font"> + <font> + <pointsize>7</pointsize> + </font> + </property> + <property name="text"> + <string/> + </property> + </widget> + </item> + </layout> + </widget> + </item> + </layout> + </widget> + <widget class="QTextEdit" name="InformationMessage"> + <property name="enabled"> + <bool>true</bool> + </property> + </widget> + </widget> + </widget> + <widget class="QGroupBox" name="groupBox"> + <property name="title"> + <string/> + </property> + <layout class="QVBoxLayout" name="verticalLayout"> + <item> + <widget class="QTextBrowser" name="console"/> + </item> + </layout> + </widget> + </widget> + </item> + <item> + <widget class="QLabel" name="dbVersionLabel"> + <property name="text"> + <string>Loaded database version:</string> + </property> + </widget> + </item> + </layout> + </widget> + <action name="actionOperation_1"> + <property name="icon"> + <iconset> + <normaloff>:/new/prefix1/Images/array.png</normaloff>:/new/prefix1/Images/array.png</iconset> + </property> + <property name="text"> + <string>operation 1</string> + </property> + </action> + </widget> + <layoutdefault spacing="6" margin="11"/> + <tabstops> + <tabstop>treeWidget</tabstop> + <tabstop>disconnectButton</tabstop> + <tabstop>sendComboBox</tabstop> + <tabstop>sendButton</tabstop> + <tabstop>receiveComboBox</tabstop> + <tabstop>timeSpinBox</tabstop> + <tabstop>periodicReceiveButton</tabstop> + <tabstop>receiveButton</tabstop> + <tabstop>InformationMessage</tabstop> + </tabstops> + <resources/> + <connections/> +</ui> diff --git a/silecs-diagnostic-cpp/src/silecs-diagnostic/resources/gui/displayarraydialog.ui b/silecs-diagnostic-cpp/src/silecs-diagnostic/resources/gui/displayarraydialog.ui new file mode 100755 index 0000000..cdca18f --- /dev/null +++ b/silecs-diagnostic-cpp/src/silecs-diagnostic/resources/gui/displayarraydialog.ui @@ -0,0 +1,67 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> + <class>DisplayArrayDialog</class> + <widget class="QDialog" name="DisplayArrayDialog"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>474</width> + <height>437</height> + </rect> + </property> + <property name="windowTitle"> + <string>Buffer data</string> + </property> + <layout class="QVBoxLayout" name="verticalLayout"> + <item> + <widget class="QTableWidget" name="tableWidget"/> + </item> + <item> + <widget class="QDialogButtonBox" name="buttonBox"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="standardButtons"> + <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set> + </property> + </widget> + </item> + </layout> + </widget> + <resources/> + <connections> + <connection> + <sender>buttonBox</sender> + <signal>accepted()</signal> + <receiver>DisplayArrayDialog</receiver> + <slot>accept()</slot> + <hints> + <hint type="sourcelabel"> + <x>248</x> + <y>254</y> + </hint> + <hint type="destinationlabel"> + <x>157</x> + <y>274</y> + </hint> + </hints> + </connection> + <connection> + <sender>buttonBox</sender> + <signal>rejected()</signal> + <receiver>DisplayArrayDialog</receiver> + <slot>reject()</slot> + <hints> + <hint type="sourcelabel"> + <x>316</x> + <y>260</y> + </hint> + <hint type="destinationlabel"> + <x>286</x> + <y>274</y> + </hint> + </hints> + </connection> + </connections> +</ui> diff --git a/silecs-diagnostic-cpp/src/silecs-diagnostic/resources/gui/logindialog.ui b/silecs-diagnostic-cpp/src/silecs-diagnostic/resources/gui/logindialog.ui new file mode 100755 index 0000000..363ef4f --- /dev/null +++ b/silecs-diagnostic-cpp/src/silecs-diagnostic/resources/gui/logindialog.ui @@ -0,0 +1,99 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> + <class>LoginDialog</class> + <widget class="QDialog" name="LoginDialog"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>299</width> + <height>134</height> + </rect> + </property> + <property name="windowTitle"> + <string>Login dialog</string> + </property> + <layout class="QVBoxLayout" name="verticalLayout"> + <item> + <layout class="QGridLayout" name="gridLayout"> + <item row="0" column="0"> + <widget class="QLabel" name="label"> + <property name="text"> + <string>Login:</string> + </property> + </widget> + </item> + <item row="0" column="1"> + <widget class="QLineEdit" name="usernameLineEdit"> + <property name="text"> + <string/> + </property> + </widget> + </item> + <item row="1" column="0"> + <widget class="QLabel" name="label_2"> + <property name="text"> + <string>Password:</string> + </property> + </widget> + </item> + <item row="1" column="1"> + <widget class="QLineEdit" name="passwordLineEdit"> + <property name="inputMask"> + <string/> + </property> + <property name="echoMode"> + <enum>QLineEdit::Password</enum> + </property> + </widget> + </item> + </layout> + </item> + <item> + <widget class="QDialogButtonBox" name="buttonBox"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="standardButtons"> + <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set> + </property> + </widget> + </item> + </layout> + </widget> + <resources/> + <connections> + <connection> + <sender>buttonBox</sender> + <signal>accepted()</signal> + <receiver>LoginDialog</receiver> + <slot>accept()</slot> + <hints> + <hint type="sourcelabel"> + <x>248</x> + <y>254</y> + </hint> + <hint type="destinationlabel"> + <x>157</x> + <y>274</y> + </hint> + </hints> + </connection> + <connection> + <sender>buttonBox</sender> + <signal>rejected()</signal> + <receiver>LoginDialog</receiver> + <slot>reject()</slot> + <hints> + <hint type="sourcelabel"> + <x>316</x> + <y>260</y> + </hint> + <hint type="destinationlabel"> + <x>286</x> + <y>274</y> + </hint> + </hints> + </connection> + </connections> +</ui> diff --git a/silecs-diagnostic-cpp/src/silecs-diagnostic/resources/images.qrc b/silecs-diagnostic-cpp/src/silecs-diagnostic/resources/images.qrc new file mode 100755 index 0000000..e7af029 --- /dev/null +++ b/silecs-diagnostic-cpp/src/silecs-diagnostic/resources/images.qrc @@ -0,0 +1,17 @@ +<RCC> + <qresource prefix="/silecs-diagnostic/resources/images"> + <file alias="splash-silecs.png">images/splash-silecs.png</file> + <file alias="array.png">images/array.png</file> + <file alias="DEV.png">images/DEV.png</file> + <file alias="PLC.png">images/PLC.png</file> + <file alias="REG.png">images/REG.png</file> + <file alias="glasses.png">images/glasses.png</file> + <file alias="glasses1.png">images/glasses1.png</file> + <file alias="send.png">images/send.png</file> + <file alias="send1.png">images/send1.png</file> + <file alias="stop.png">images/stop.png</file> + <file alias="disconnect.png">images/disconnect.png</file> + <file alias="connect.png">images/connect.png</file> + <file alias="copy.png">images/copy.png</file> + </qresource> +</RCC> diff --git a/silecs-diagnostic-cpp/src/silecs-diagnostic/resources/images/DEV.png b/silecs-diagnostic-cpp/src/silecs-diagnostic/resources/images/DEV.png new file mode 100755 index 0000000000000000000000000000000000000000..9d0e4417bb6583f06a4657f66c8b537f61555a7f GIT binary patch literal 2454 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 literal 0 HcmV?d00001 diff --git a/silecs-diagnostic-cpp/src/silecs-diagnostic/resources/images/PLC.png b/silecs-diagnostic-cpp/src/silecs-diagnostic/resources/images/PLC.png new file mode 100755 index 0000000000000000000000000000000000000000..cd18f5420ca4038577bfe04fb2669e3992504999 GIT binary patch literal 2373 zcmeHI`#aMM82@UU%g{)Y%UC877HW#gHq59U<Pw{c>#AoiP3|Vz=29Lt<Q#L!R7_LM z+zLf=Np9UpNs*J>PQ!AFoY2u9anAFc=jnZ(&-;1b&-1+R^FE(n-b{B_qB2wq3IKqz zi?gH0Cinb+JZLi)W%yTZl1#J*(H;;!(V5$9z^C!Q-~pgETX8K20stVuo#aK>)aB&l zU@(}vy1IsjhPJjg91ce!kw!*F#>U1bCMITPW)>C}R#sLvHZ~Xx28+ew@pyZCdnYF+ zB9Z9g;^OA!=IQC_<Ksi2P)?jU5fBg%5)wkA(LzH*!@|NMA|mK?dTeZLVqzkL!AMF< zVzF4Msi|pcX<1oW+1c5-xw%{}x45{N$K#cjmX?>7^Z9&%Kp+$fYierh>gvAV<7^)J zGk!YoZ#Zz!cujY6uR^3VIT`@AcK(3OBf5aPDQd<Ld}BQ6r()uRqD}(tL9{b5C|80P zB5pqljk3nsiuwTnQt9G|_e$`eFAnojvrx&no9?0Ei1K#FnH<Nb^$|wCe;*pi2T={V z3j>Bj;=+{jUJ`GmggO*1C_1=QIWA8uL-4IDIRa$i_Gg2A2Bw%Qn~r>xCo$F_Pb3lj zDeu=pf)D4CI_f%aA;ae^W4(x$3jJGeb42|97suee|KY$RHoUoH_{%lRQhe*-djZ`r z{OFnMPn(1v=Ok9!q%Rg)>P@3Re_Kt8-<fy57Bz<FAz=^Xwitpwx!az?DwUbzNMhJH zGZXhRIJQ>X{tuSdu#cPA0HGJWb3PuszUSARP)YYuAgWoZ^W0)@cz1_vrIpT=4TK&h zvcP*_MnSJ@_nfljLRXMhqBDc(^=*%TK+a{Mj@=bI#4yBQPQiXc>gBUfg?bj7v%Zj0 zkl&=mAT3)hDu~K8<Y(^(YUyGLrSz7ZR{|lDGoguo7u(4Pwbwq^{{}gq%|&gwsM(;l zFlab8*<+(K8@OOfN`RKM?>LZCK@KMd*!gARo&@@?Xr5fU=8|T5oqeF^y(0pCNau=n zpn~QH=rjqm<#fwR@0cNb3b?iFPAFu#P*gNenSPopIuxh^%Z;NFixgGnU-Wg!viu&F zJ#%fP#o^9KZ7Wj6<Rvpm55~OB{KD%=yW|YD2H_V-?fK_*a2cJ_5JVQ)vS`ri@^vO6 z0;=L$Wx<)IE*VLa6*$a37>ayMJPW(+%8~3YK#Jd|?gnk;K<&IG1tmC-Dhlx7h|&j* zp0LG)g1mM54BDiHmkVcQzq+@<{}O^mn49^U6mTTfvfzljYLZ6rWMr{5L6B6f-LMM5 zsups<rAG}6N29x}Wx>rJ%n?5x39&MyT32RI^fSgurfk(O?hjvq!Fu6jWqF3&QYgIr z%?%$#c6PqMiM)+@M3E2leWZa*ZTyh_?Uw+`H|wggPS68~le)o40s0jH+30m3`V=et z?|KXTooKoi2-ej|c0OR(!!qp=SgpXGly&dNPc+jr2K6sc*>BU`#@_C_w2gNIEK`V( zcI|5mZ@f^kF<KEZIcaznKao9y8pcE}M*RjvfkXTMVlsm23yh>GZVCu#&bsI4s;*OZ zBENiq?XOF~P0;QqvmMqSkMo&&gfa=*wS|Z7AZpw8>X(M4lbiC!7=EIiG;`27J?Oi# z?Z+sOcjVZ_a4!2lbQrh9Ju`hRWke|}Dx&v-!L5wtT(L6Fn^pOQQJu5aJ1*;pdBKWS zRf7-PaI2ta!L7k)-`SfTDvJ+4Mb~dvIakwuDe3FlE$K+RK-?J_L=#TMuYS_qd#o?k zY&5w#<xPU6eB1Ok<q1x;4)LlYMs?fDf;*mn(lPEPTd(_Y=3W}7VR&%9$hgU1*^9dS z_k7K~==#Tv1|pWR5;ZY#wPuQYoDxy8=EVKXGzx3yHyk1kIPY`Fvx_uuVw$LSDSaGS zf0s3Ze^%y_&TeqPV5{`1HD7r?O$Diwzs~GjZEqXh3az88bLSh6Xv2eSDHL$6W6>?7 kzNOj~0rLM{-`6B=fJ#~*RmFQkEPlKZ7lNy!&_0m;4}U!TYXATM literal 0 HcmV?d00001 diff --git a/silecs-diagnostic-cpp/src/silecs-diagnostic/resources/images/REG.png b/silecs-diagnostic-cpp/src/silecs-diagnostic/resources/images/REG.png new file mode 100755 index 0000000000000000000000000000000000000000..a11048a58c704d2429d296a5a28c9984f776e5a5 GIT binary patch literal 2524 zcmeH|`&ZJ38^>|tEi1trlcs)BkfmX1q9!qgKtNHvr#QrGHVv<UlDPyab$(TJnJrDT z>2z6M@KWFGn}fM9%``8SS`n!!^Ol=m{jN}Ff5gtt_nbZFJkR?)uOFWCoc9mUQ{d-I z-m?q73j_k~p;CweJKFa#bv1YDl?xF!cSIvSfJ^{2KmJU$(}3ggK6ntQtwdiPr3C_M zg8XPfq#drKqhnxT0EI$LOiW-fn7O&RwY4=0g*tHHfSsKk8jW^vaBy^Vbar-jb92LD zvF`5fcs!m!Ab5IulF4KmjYg-_0|Ns?LP8h}29wETu~?Cjkufnb2?+^_iHU4BJ2^R- z%jNR<{H(03$?bCjfgm?GS0oY@78aJ2l$4g1R#a3}R#sM5SJ%|k)YaA1*Vi{THa0gm zx3siKB$Aya|A~Jb_$wUHm`EtwnX8vV2}=io_Wt}aHRQ>Su{+R=Lki^tCZFVFM5V=n z{Gz@};@JC=f&ktTdyM^2k7KO^Adt2Pm52|@j998n%o_ECoSz*-+`0G(60IF@P5ezb z{3nrmyCy^~i5py8jC;KN`WW9vLE%0A6&HVqLFH_k|DjseC9eRt(Nub`kwe-~d6!Dt zT5qC036Bq&FZk3<f8dN&E7$XUb^hOj7uocg-zTD<u)ls=s2DmlT@@~_Wvk~-wYlQ9 zt2*pZP&F<!_&9mM8lV2P4U4qDuQAiG{;S;*+B{mz6y3+zqV^i1skWtLvo^960|J;E z1j3UvPO2ED#Zbcm@p5Q?*R_lhgmxOnE+G0@j(|hnPxW6J^@NJcT%8@;7gVGifM8SP zVPVU;Pp9~am(7NVsT#)v9ZF-$Y5L+~aCb-$6Th1%e=@j^NU?f}Go|W7kYpD#r7LBl zsLTn(hbKI`)WmdY3al-pclUS!Z!X+^Uo>!xk`tTkUiXE4uKsM+3Mq5+x^@_>s<oJr zn^J5fa1O0fB<(XnrHxjT=<Gw2i!<Go%G)JoeOYa*F2#j8Ya99f-XnqNK1?^^zU{Kx z^imh^hM`LJ`F(}4=vL_J;`5+M-(Yjyse=sR*#<#fh`zHdugOpN0`;;J%=frh^Mj31 zd-@%Jf8ns+grP{gY-XNSR5Um3oF4A6g#>;Rb~a2oMV!6-=9MYrj5bwgWa9(y;F1^Q z?w0dsi~=r>tmVTSQB3oIn*5a0`qcd@!&>V<m{_s<o2IBRpg*|K9zAyF##LNthZZI6 zceYMhcstQ)a5$Ro65)@Z<%^6*KQyTP?;S4rZO^JaEX6o7dn`wN0!QjS8o;Bjy*iP7 z66Jgk2lUOn=wbE^{4e8{Zr^~W5S)8Lj%URql9XO3z4z~w3qxA9F(v%2f6waRMgMu` z1hs~!e#}|dFsC|UJ7^v!EoaTCu!mCoTUe>8VcO4k{b@lj>)!a1wR^^?&9Vr+#N|%O zzUV39$%i_%7+@uRpOv;GeM?@}1O9LX>b0j27NABh*6)qIwNdO7r7WLneg=o!<&A1i zdG^5TR>D4)qMy!3U?FEjNm?@Mb;a2r0m33-#^u&L+UxB#e@V$HMajL#gX?3Ma^bsG zGc#sz!7!?)JHukN9=UjPrqTO$Q}ef$k3s~)6Baf3tL61z#AO?qM8@MS4M!*QpD#Q- zY<3X3&WJ@@#YI%;W<$AESYH94z8bz2Zp^h>G!{3J@j@w*CcjIxY1x$|N^1veN3DEY zCk@t<Sy6jbwME_)iowk62g|`S|1b4rXDBb9{&z@86o!}EXEulF%ZB=grj4p`c0tII zc%2g%T}7s)Cq<a7%>ktSzmQWgl-BF{b2aB=)}4lk`8-@=vyPr+@1vGbTRP!iOL;63 z_QSRH@`6@mz^_)D-LH8}H*QsNc)zXd9DBC20GzvkX=~D;3?KjQ2RI_z>A(VK(#zFD zk99hZn<qd2O|8jZd&zgP*xhhlz{6(BASW2WyG(B+x?E~Jhk$fFi^IqZZfH`kzHZMp zMUHI1;I*3@&%Ge`(|o?TGQQ^CVPX^(KhQH)XuFLGV_yWMukTuPP72m4NS5W>KCnS0 zYsR*$0sd6J_5H*JAbZ;(&v6cA%C?erxmsjZ3fDHrTT-Rprz_tz`5-?15<B<+NSqk| zQ9N+EXWaX^-O($1-^&f+3zueC2VWt!(u3BdN_>mO{0ls2l;(X58knV#N(Ubv?ASS) joiNA-@&6O|94Sy6NH3>a`tfD-kKc_-@+CGCB87hf2x?CY literal 0 HcmV?d00001 diff --git a/silecs-diagnostic-cpp/src/silecs-diagnostic/resources/images/array.png b/silecs-diagnostic-cpp/src/silecs-diagnostic/resources/images/array.png new file mode 100755 index 0000000000000000000000000000000000000000..8fd9bededea4babc1428f98121cd3e5f677f0827 GIT binary patch literal 1689 zcmZuyX;c$e7@Z{0u!gju1;x>*$Rdg;SZU*u2m)aVSW=`)gaoJy1VTs?Jz)vjMR1`u zP(%spu^2@K0tg}?AYrr0QM8&E*_7o3hC~R991L^_C|3L9-FfGm@6G$Zd+&Rb8bI+h zHCk*00Dvjk%l$h5K>P)dH3mpHf_f0}41O50yncuW0At+jKmccREa4!UL-yN&Ru~zX z+S>MQTKxnLft($|9Jg2|Gctw)xUnPYoX7|~?*L~%p1MC0?@9IxP)Dqa0f5iU$nGTS zq31*GB(}oIg!rhrekwGZ<|6d7y=g5pH>fISiiOQ>W?jJpkN7jlW>qg1V4(5bk3b+p z90Nav|H*_GE@ZktygWVF6qhp@Rn05ZbK2yo*&bia=|8Xn>&UJ55eta7WNRHn=E(F0 zM~ae~PFwePoW*J9<RFOgXDgZbpsfNcrKkgLv$Nckva3tIclEQegladXcZmH1@_2l{ z5)4Tj*_(AjrUXsSd8`a2F~qz8h6+ari+OW|>JJJ2QK(j)E0iJP0$qzz8R(4Qv@KOQ zFIU4fP_H)}DB(Z5d#7=#;{>9-P+zQ_?4W6fAFil*ZFH<-eLjy_8Axy35SvL<w?(zI z{^6f5=0p#>X@{y_0hDxFk62QpeV%d3=;HO9yIIaerCsLT8eeV@%8vJq`J#zm8(Ina zVVaF{ghI@k7)S+K$-s*%g0)@UsQZcagY;sQcXTBKeckHTQeV0;KR_^QA0pqHeh8U6 zOjgF6@P=!}b78)v@#>)@32G#Z0s&ELYF!4;7ddbREf^vM1gVM`XgkrYFh!@$mVqng z<6Jqt0TX;sdlJV$2Ztl1n6O@q!<?SA9v<5B*BIzC5CDg>z#s?^&Z$allWpN!7+^bJ zWje_bHUvO|!p?##y=w^P-xvdxBiz60Mp@YqY8M;B?zqY5A2+Oxm^Dg`<#dXv1m!!o z#kKOdxo_&MA=ayC@t)trJWb@83)m0@gdbn<;O2BqNHG@@pv@zC@TNM~+)ooJY~K~7 z^BeJZSw$k!J5`fyDg?ud=gQL6mUeD5`{a~FV-Cy}GH*t#H8&Rt=vstXlFm{!-;8e6 z0_a|S1n)BiUT57{OPXSnpYVAJwGmlWoY)z2Y^6!wV*<8vHH=>2N<OzKPVcY<bg(8@ zd$0PMflcKA?#fl1wBTOB4Y<QeA2E#Id(R@!shat^Y$E2Y(@)d<AlI#Dpyry;sYy?n zh6GtAs0Kj!Q`rq#dmVFMs6{ei$@npO-3`f?d@)Bee)^0?1cpGP6y@k{wX}ex&M4@^ zs91SD-6GQQK3c;*9;?Z@bIgu=F?3A0>#9S^?n~7#pUTp<_2x|Ii+5I*$ub8;ZJF(r zW37w#aPC~9DwC!!$Ja-oTYUE2!4bCmX4zn*r`}cvev71t7)@Or_Mi=6WWo`$EgkB5 z!(8)N@p(_wxFJ&r?k{ai1!Z-T#v@=3Z7(PUqZ4jMmCH!e9rmIRu-!C?gixqUbP_Dk z{o(ALFgo^&rK+A}s>wTTXJbj-$=i_gj)E_gXnfZYYMmznc8T?)rOV<Hll1M@%jE}C zN`>u;jztrKI??22hbRx{$)los>@CJ6g~MfIl0ahf&fBY_pjS;)m*v%cSWBym$nzzN zXmd1tsQ{8$A<goVV|~<NW%`Q_4~_hSgpW&5Ln{kS&4xxX22)EXx;6%>1z*6a_{;X? z$F*YK)<y(ZW-Sy|m|fW*rw!3w$N66%K{ijVy%3ogc1R@ik~%qYIs@a&wd$XVaLGJ{ zf4e*OKAl58+LqTzuX$l*?7iz}SqjYK1<ogzr(Wp@#&Pbj6Akhcjxx~ffR}qTPjCin z<%!{DpEX6G2LfL5*UJ&BU~b=Abz$}&S{I!CK2u;f4J=n!`~AjF34#A10C@++y<mIT Gk$(XsGu|!$ literal 0 HcmV?d00001 diff --git a/silecs-diagnostic-cpp/src/silecs-diagnostic/resources/images/connect.png b/silecs-diagnostic-cpp/src/silecs-diagnostic/resources/images/connect.png new file mode 100755 index 0000000000000000000000000000000000000000..5141d635a797f07630840dbc3061cdf4e1d7a37e GIT binary patch literal 2880 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 TH$`Iq99%#fVW3f|W*`1PET&o$ literal 0 HcmV?d00001 diff --git a/silecs-diagnostic-cpp/src/silecs-diagnostic/resources/images/copy.png b/silecs-diagnostic-cpp/src/silecs-diagnostic/resources/images/copy.png new file mode 100755 index 0000000000000000000000000000000000000000..2293a0127066c31aec2a1da71e16e8ac8a25afa1 GIT binary patch literal 23145 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 U3oCsaLI3~&07*qoM6N<$g6kR!uK)l5 literal 0 HcmV?d00001 diff --git a/silecs-diagnostic-cpp/src/silecs-diagnostic/resources/images/disconnect.png b/silecs-diagnostic-cpp/src/silecs-diagnostic/resources/images/disconnect.png new file mode 100755 index 0000000000000000000000000000000000000000..f472534f444b10f0ac3f4ec694ce4c8faddf59f4 GIT binary patch literal 3337 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 RMUOufkU8cWy3Uvo{lDaxGlu{G literal 0 HcmV?d00001 diff --git a/silecs-diagnostic-cpp/src/silecs-diagnostic/resources/images/glasses.png b/silecs-diagnostic-cpp/src/silecs-diagnostic/resources/images/glasses.png new file mode 100755 index 0000000000000000000000000000000000000000..f3b17afe95961106d96bda5c1535dfaff1346a9d GIT binary patch literal 5252 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 E2QfDcR{#J2 literal 0 HcmV?d00001 diff --git a/silecs-diagnostic-cpp/src/silecs-diagnostic/resources/images/glasses1.png b/silecs-diagnostic-cpp/src/silecs-diagnostic/resources/images/glasses1.png new file mode 100755 index 0000000000000000000000000000000000000000..aa97fa591444dcc11211fdf855d492d0bd5a7ff1 GIT binary patch literal 5504 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 M+6K@XO`C}S0jwQ=Jpcdz literal 0 HcmV?d00001 diff --git a/silecs-diagnostic-cpp/src/silecs-diagnostic/resources/images/send.png b/silecs-diagnostic-cpp/src/silecs-diagnostic/resources/images/send.png new file mode 100755 index 0000000000000000000000000000000000000000..6b3884073d6ff4708e7d61d2adfa3a2570fd8872 GIT binary patch literal 2195 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 literal 0 HcmV?d00001 diff --git a/silecs-diagnostic-cpp/src/silecs-diagnostic/resources/images/send1.png b/silecs-diagnostic-cpp/src/silecs-diagnostic/resources/images/send1.png new file mode 100755 index 0000000000000000000000000000000000000000..8eb536fdb4998958ec892333e53225fb8c6e2c89 GIT binary patch literal 2083 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 KI&kdICH({cwWpW> literal 0 HcmV?d00001 diff --git a/silecs-diagnostic-cpp/src/silecs-diagnostic/resources/images/splash-silecs.png b/silecs-diagnostic-cpp/src/silecs-diagnostic/resources/images/splash-silecs.png new file mode 100644 index 0000000000000000000000000000000000000000..2229d4aa8d6fe11b607f83f70b2ed16f37ddad2f GIT binary patch literal 585383 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%0DKs9pB8@dcW~^pLF|?v^*hk4EV!p9hUln_Lfcn%b z=dEX1-8|p$D>pAi(sIW)H37S8+#A)|E4-FahWJgI2!krtmmv2h%Pgou<evuIQ%OoN zK{mv5R)bpdn}*t?KmzGWsvQaDh->eZEAnK6bkw?;bDhB0eB^W<O=`55<`6nYpe<Q) z5SW7Vcyduu@C|U;IJUC&OjO6wP9Y;Ehe_CEcrO92z)A>t0oHK&M)%EqRvvvg880MB z6JI%gn()NQ1X)@s3J3`N0nke<OTUIz6lptUa-xKn;iA|8pxzO?5MpeAfZK@aP4*>K zw<7^ZB~Rg;ZiwVCpp7SisA<et2^`1w6akMAIrvZ#D@Iz!N6Iw7TlNPy9pea5jPb6c z@)B3Uu<XvVk@%$UlS54=V-E>7#i)`<J8X~e<XQ5h7SwJOL80z&)J4uRX0Kn=M05_@ zIP4*acj<CjsnyxMmOKW2p2~1%eUc${`+cPCj2&ZySD6?L0U@>lE>s6cP6FmI)6m0+ z9~}N^@ffln$ahWYLZ$Z0MLHSV10xBeOgs}ds|D86j9u(72%ag@YBu`44%NT~6=}G! zZ6ds3`XHw#@H;Dj>+raQ($1qILeqc)F~c#1z>bx7cCf=>;jl#L1!gSxI1RZT3b9wf zMu5hNqK&!-#fgj*a(SJH66w#x{lxy1-6w`X6lEfRVm89x!_X@xreqqcfo13c3>4^g z`dgJt(>Z$rAu$P!APtCsQGu-iVQ=(Y5*bM{?9Q+g#<HCf3Q0H=U|=*1AZG#)G?Src zaK$WNt=N^44Wa-tFbplf2*qU6O#UU;6_>-h;3^FM*~JBh5ZywWSg3lVK}vFUsv^tX zcs=ONM_;e*-PelrKHpYI|Iv~3{?p3k4}bn+k_nX4d2xp4z8ztj^|>*go}8YZUEl^X z9E^@nPltoypxf`XI>N8utr1{DCO(>uNc;pohQ1cZBCz->xPZVxOgP1eoZQ>H1(fIZ zMcM(tCGO~iiuEsz0+SS~kq9%HO;2u5`1}(<JrYh220fo&ay%7NX%jFQYcjZ;E<;gn zJL`BTO+1<h#}^;|`boQ5yZid><Tv)CN2Pm*_i<p&Cz897L}-mQyJ}#u&&SnX>kr@g z{k!F(|Mu|blYZB?@<FBl;+H=`09P*T5dn(ngXo2Qv&n4wm%skeasBBZz5RP{?A#^* ze{(qc_kZ=n4?g~g`H8BHhYpMe{;b?>I(?Gejm$kk){Ere^ZDb^INV3jA70P=!~Uq( z?Jh>sTr|UTtUDS#s+^8yg#QY#bh#<t-`&f`Qj=c)`}f}~mXA(b&Bb&y={1-A78$ov zsod_)?oNJBM1X$ZquN=m-M}ii>eY8s*`wlKE?L;k?$!I<|M08-iUt1Gt*^~COL%?R zN1fuD9OJga=HOsL-fnyqk{7k}{-8%>%(*aZ@<<xYMD58fcI{thBguFuHk^%dlZpkR zLlR3Y#yB*vf!3P!dEy9zU^0~(d~d?HIS>C=ckz8mYQ6>ZUy^}*Nt)rM%Ct(#qA8l! zZ>-#0?$0JEl7+(7B+#GqWvl{mWE8w2N_dIiLOJTO${U_3z?y5Lf`^l&OcGqE#GztB zqfHmPLS;6lGztGgiSksE0DLi?LaN;tFpm}C9&C0PoDF^bRgDCprHzhAq8XZ6S?*s! zhJ+Y58g#+^gCUeOhmqb0bvrb+_?QYZ77@EBzwsO(dU~3eVi4gZ`dp%1=lREbh40*; z`76;LVU<LsAkb1`y-A2k$<S%Cj!GMKmxBj@gdH@l2%IkodXmynKr{fTY=h7!JOK!2 z=8~*plgK5+TM?f%ag7xlL!|H+FcOx?Xr{$j5($KebJUDco?hX&aeQ^Km4^P*JqiQ9 zL<ysT6PyX*ypw}u3!YApV49MEmN#?}#4}+tP2lPk`w75w862^rhEGmU@i7Ija{?z5 zC<ezpy!S)~<7c47D;JHE*o|w+Dn+~K0Zo}CJ3<>Dkz$AzW5_v}bs2Va>O8P`3yh}& z7$!5;_}WVT(hebO7IS({=s}PRSrjB`y?B_?AqddH?jU<S4u~ORvMi0sHbwU_bvaj3 zH>HvQZe}dqc>DJ4QfcS(^z`Yor=a=${R29I|KWs62esQxaIHM`LHFYcA{q8TOjwvO z_9)%P!`ti*Z6Mu&yg-aXLBe`6nb|YINI<#H(CbrN%0b8FI+2^Xfe$wxCPbNxU^8GF zhS{Q#y)hXbG2&#aoheOJJ=~f_G%t=Bb6h3>_Av}3N}$z1I^+i!DvYeez+o;C;1VBP zHuUj=#owCt6W&w<*Qz6|EFM3h=;?P<6BL4-3?!;I0qyPGGJ!|d7)BsI64}!KSUU_T z8z7j(Y@U=$MYFA^VWym1)Gx_B@b6s>i{n2}K(84t7~f~0`Ct5GHUgHjfwMqPMx6N0 zphG%}1^JRL&PgD5c3xpLp(Qf$1cxy$%tlr}x8y)@9T2l!UYOenoL5<)M8#oN1Vgn3 zHtjr-E*#yt&s>-<XT)xjG*jX^$~I1ndkGpe!fTO@jR_{VCRRA;ay4V>@)$`*646)^ zwMZ<M8j^r1u*zn4htu#cpPgNv)<*qNsZ@OLzx!_RR_1cuy=32O*hvIP*nB|5n$vcj z;4-_#op<lPeYkt8J04Ow(qa{o#cm%>(Al@&{XI4ZM&m&`7R|;IxGeqf;~#(U=vV*b zz3;!VcQ3pN5)kaK-~YwG`^*1;@;vAZuz}SZ_VG8x;YR~KF?C@#3YnbT6IN@S0r)<j z$>WN`o)b<$98Va^<#aWl%$toyuhXI}!`bL@<8m}(<06-d#cu5!ee2ElnmDMiHMUwk zK7Dk2`8bm<u)~m}<WM+9%&1V{XAj=L8dM%u9)YE^g>qmWj0Pg?>amY8UyknX+`%FF zN6&tStnsabH#(C^b2x}a5_rhg2OWZbvToWfw1WAaon6F2RJ}56F(L<<GOR#6iiR?R zudq?;1kl`f7K2nIfiH4v-e<N9SJPxLhIwXUHfYoarSqJLuNdI(y$ZG`{zH0T3+VqL zy|+F0<{D-t8y7l9d~&T+0b#Es9gOPHmBZG<L<Zo7tJi4s3Xv5b^HPDkVr6@?5Ugxo z1~ji>3Kgjf_A=Z&2NPlsCQnuMD$UokC<HvBntqi4DLCd0Y$Dec))Rzc^gU>MB#q8W zym%F?Yp6{^ggbVKgo_b;q9yaC>?a^8aY;i^6lg{WV^j^PB#alo^08FNLAZ!M-sr!Z z-9CDBLc>uRgzP+GO}KZW5GH_VCW44Gfm6Euq49PVDi~PC@zfS_lp}e=trg`rbwFN1 z#ul2uMI|buVNxx%Z?LOidI|?yny8H-V3*)-Bi-RUu`$f1h`G8X{Sp1NYnT~`u9--T z>0-uIM??n>6wMDj-;7{Jm>fM;!MfTZ!sn6Yga9u{P<jKN4?K8yA~G(((+cAC!QkSm z2AF<EI6A;yrwiLeQ6D{cM6`K=*`pO9><LUcZ4|MJiSJ3c8{u(7;xUY;rufljNi!vo z6lpu(<BEVJm?1#L0Zhj&gKY}>0iijwf`JDtN(RaxQWoq1a5>qI{PXFo*{B&Li4`Ov zYa}|p$)JRE2MkSEMnW+{-yw!66pO%FSoVX11Fo(im9RFjC5n=cXG+$nLb1S!0Q!T& z!+Na-rk7ls(<#tDm&;4=P>ET=%nV>E+`fIsgrGrhAe&3P7*E*)G5U9PJCW3w*c~Qq zBspH0nW9q=2@`uzIHyA4ivcNnS;n-c^J$ETqoWe$k_91o#IQe2JXY#&v`rFx31&`~ zfLO{Rorh>=<w{T~5fh7RqgdLGnI~==tUgAH{s;511U0-V$EYnWS%kxgZAce|JV3HS zV?40agsUyq1po-K2gD&Q!CI3+N~c(mgfb#%Duc~XGAA`B9TiaJ-m4BHyf?Sc?a?A! zf^So8HGlr_*H@Pp^kW4{iNx9>c{3D5R~E5v11&8M@woz<UhP&JIF4)_6feH)%LM}x zC1FJ<z;+f}S>Z?!uWx=LDk@1ynN5>1vo_oq%r2W9_P&_p={Oc9kxWNyX{F*=s<H>j z1jEOaNtDa(V7tm~2S@+a5<JR+70X=q=+*?3!TBPUJNnD_AO7m&NBw5MJ?{O{|L|v% zy?`(7Yc86#?$xwWKdqbxqDg-&K~TqHHgj+1=rDgEnH?}yJFQqGR?O|J!u~r)`?*31 zz&afEhyW9e#{TBn#~+@2^xhj^|K{zlFK0X;!jDhMzg!{eC3l;0u~aVX&_yf+V{G{M z%DZOw3C0BOWr{m5cQrT#3>&<+sW#^QPQD0>f#WRUYlvLmsx^WOAJJ`R;{^uK)9T4& zHmnZ&mHwDK8Mlf%<wEh{#go%Uh43{yg))1$J@kJO|D&@fmHyRaJ=xC||Lp63*cnVw z@eMn5+;*ek08#39b4cemolzqhPLjg*{mMgv;k<S58Y9{o_xAE7w#v{25q^^fgbD4x zoIR*MIV|oHPnKj@MBQu-I~ScwE|KleCz}vr8($(AuTMI&^^#jdb=s5|wZX8FZer@o zF0qU1osc-6+w9$5=td800sVGLd<s3Fk5YwtO2k?kUU8m*?~Yfi0zp;dC<-@OU>&WC zU}Y02lAjcUD~>l*oD+OTOVD~N5I1^jN5;cpoMK~NimZH$zou~T!pDPI9Vnybgot^x zCj3?Q-Nv5hjnM%MY5~EhI7dTI%H>QN6rmb*7gBW05<Xl?FgRQ5uOL{1PO_2BUv=>W zpddM=Od~^=egmADZ&0_#Mg1ap+OHAP#naXA>-UE|I|YF`-->EQf29=|3>YXdsRGkY zRwE;Rk@PN<PBF3@;MPiEI5kw3U58G2bnzk;aN$f0x2q*IqJiY1!&d}v$aXDBjutb< zed&-%F-CVJ2bg0}s{^Y+duTJbT)Wdof=%Wc`UkvzSs@mCMdFQ`q2YZomwWX1DG(nK zIWdBEcM3e|fzj=LpAa{6G2?q{e~+<%Oh%MikgzQ|`bT6@#za9b!w!QH!HXy#`W!q8 zzfRQw?x02<x2Eo7O&XGJRc6X!hBabD=i)UXqaXzWJ<*ehFopt=&@f;4NHc+<pi)@m zot>R_yY;INJ^<rpb2(@_D05IgB6t~J!i?erEdeW%!~m4;#8fj-TL|gN<j&o@^ai1R zm;><f;x;XNO=xl?xIWi{7nj`?!}q&8BuZxbK>6ZBEWXF$NX&V%h*(-Eqas8*U9;n( zKGPC&bBO|2_Mjw0rZ`lH2@MuuM@FqOiIU_;HV`G|9o<Obe1)ArvRJe<oMot4S#dxv zvu4#PMLu#}6kH}qj?@R1UCcpa5Sjo(vIWGy*ao8D_mTKBDxSpX>BA9rGw5@`2N0ef z7gd;qTb*83Yj}?sJ(wh6keouYKZbL&=<&Rpe)i7rDcsjS_aeM^w$JC{tk6ok^|J>b zJvn{GW=*|OhqOlW#MrfaZJbaDOWSNUa7MvKLuoUg&Uf;_deR1u*w@0iWlA83gO&** zBF8s2f`<eC8$^p@XD`OALyiL9z-=Bkcvyydy?b71b%x`7sZ8!Md{Qy;vczwh;W;X< zR@jM5C64ErkWQC~jKiwMJROdQ?5(jom`@)p1Mwe!{N$$}e0X|#$-VF0Kl#?)cklnA zf6`s{nCbUZyI25#<u0M2rb9L%3HY^}FR=@BS-YI{TeycWrkyd?el$k<r%fO-WpjXu z8jXKcKmW<2pWogo|G`_|iTa5cvpl)F_}Q<1_3-HvFfLpNc{9+SVfMnoBjkgS=#K_C z1#wHRHybP*Zc`GfjiiOs2?1o#ufebosGfa8G1upW>zU)=n@{C3(M&d;Aqn=V(@NoS zJM28HpLEB)`k+fMK+ChGfQWAs4#Fpm1MB0;S$)u$uBRv#|HnW0*XThf^D!x4uj=Pm z^7U2?;)10_q~crU!%RHan~a9D9(;c$o_$<@T1e*#DRSyXKRAEJEr3TMF1G#Y=(u(E zd$+$nB>>UdcTzng_ZRVPxM?$H$uOZa*YR+?3X6}g&1!a(++o>c28f(>v+Uu5Ym)n7 z5t%1}v+=5rk1bLE`K)4ll`WwEoICu>d^vp@iM+wh@uV?fG_VYOx8c%+$yN-l;&=gq zCI*g%t>mL+=p~Jl$+e^)L!aDw3B`+!wP09eJy98A!5Jpr0{i|74NZU-!R25<egao< zBo8fXZy0DRFSQ(uv_!HXDTdQs0x$}&o+O$g3U>qDfVyNW0M9>3MGlpY@Id~j4WxXr zC`PE;B?A;#OOiR6pyyE0kWwfx08F4ZadH(16(;x}#IMOoDwxZ}@)vmtC<nY{czRJR zP&mNNgyoSC#e)8g@2SE6CbOvte`B;jKqzr3wQde>EEuuDH20H&az*x_L!c(lZ&gEC zgybF|ZfZtGCCFY;y94W;y;t3VRfzBWCLV04IE?@9$=NAz?W$6vH~9UsQsp4Y95ew? zMv;+2o;5oioJ#2yLjy~|6_ljAXxL3`7Jwj}_f8?t4{%^YAuo|-L+`}^j-Us=q45&K zln{-uYNHXb5->}1v9$~hj~ghNR*@-*Qzqp=nS-Q-A(p*n*~3BZLO)A*nQ$1e&XFRN zGCr@A56YChj{=`#k`4*cIo_ORW5+0(B)cj-4{eVaoow+;IS!M|sZp|AQC=D$3NMZ) zY|HuC#lhjxPO(ILB}<k3-4H*7gGI9*PoU)2%^%sRf#()OmmD=y=skLgtqIZf69Ooi zVqzG0E#x=#<aGYZ=8X7f2L{*;#I$h@Z{`?Qhb}96m97xFUC3`)dIs}L+;LWvz;v@Z zRBaDZw`Q;jV?|dW#8Nv~UYyB_kdBokP~v24)~xY;mq{j@Mg1Ys^h9Px$I=fJ!h+>; zgV6xP)huBNrT^gZ6MBFoQ-mnxNDM!M^czFe2_S3D$X6ZBe{PQlG5C$q-x>`coE)Q5 z<3@vi3;T~4tjv0WpU@MC@uHEFi!<4U;;tBui~-1_Ng^6&^#e??{ei9ACo{Pe=}_6o zBDyWuU#24Aal?M%u_6XzSrN-VpG_g(*`SVJYzXmMZS|%L-2IoqNbKP74j~uW+3ZaQ zaP_eef!Blc4SA-rAVsDZP+tr`p@dnHnV%hB{HMSCNwrcx$d~VZ|DF7IZ~t<Bx|2%H z)|0(Njx<S^vvxL_xfoXP>^9Evvs=Y-W!Od(UT@VK{o2mXKH+F1vJ*)Ttj%;aA!S8# zI{aUM_V1G+-*;d8MmWGe(&*#U)Bo_F|B`61@CX>Agp@tKyo3@bb}uFjf#^rm0e-8) z=@9k>vjg^to?-3d5j&m^$8*$`JWU85Aj&<B!N6*QxIx^4Z%DJ#es=tf1IL3&iV#9( zgPP3_!VNvRIwhRt!NHwWG=FRN@P{A$_0y}TPx`01Snj)Td^_fg%%)?c_A&qZym`?Z zA*~s5FYeFA)piS>o}Cb+NB4J+%DDnhpZ2iXXg6-{9FSP*xO(#D!Ce$MA733mtDn5S zcV{nGp3MlKKWR0ZJBd8|B&5e8_XPgx*=TCAp7*E2-n^d)B~q~jw{?sP_9$!PHaTdK z5jAInR4BIGEEy~(Ot1-3tMFc*FI%Dg=dilBfc|sn<gdyl1RWZzs^Sm@4f;m^0tu95 zS5VG3iX?a`^w*yhBU<iUaRUb!oZvXlf}s`P=;^#y^sL{gVW44T_=up9?~M+@aEj(7 zL?AKp41j=CRP#WSQt4re#pO4NUm!{wz87V%;T^G0RM{f9Uz9r-C&Es`^eUR?x=_7F z<s!lcBk~bQ1lTumB)OqSP<(I<0o@0qq3mNqsTwrRa}=xwqC#?D%prWlc$!LFK!q$0 zf-xa<lrQIHsCqXpkV0ztZzB<YjFMe)gkm6>^G&oH2X~u$uYh}Yin$Qglk8M%cAFy{ zL%`h<F%>Z7x}eZjNk`|#OGnvQ3_hSX2(nUZ5XQ09?E=?O%MkeoK?O`aSKlv}fa&nB z2xBzTA_fY|X%TS8$S{?Fx1*J)Y#DA*mc+@yv;xi|T;ZY1W06*{4^D?85}<|<@LZiC zlfde-t%0svm|aHAklCnKq}!Pjlmoy9uk$OjLXAwih0}@QNM-OXlT=xvND)rj#BY(2 zmE9Z3=Q?71bmp9#oX|&LSx`8&1v1cI2xrkL5C<OOnMomOQ;7(e%Q3s?XO#5!?%l(O z)Qp;$LCh0OT(M>_g2Ey-kZ3R@ZW2R|W@7a*J{&KxW`u^1HkvJ_6C^h}rEa%p#7+Qu zqV$B20?_)kd8#t8HEKVX!qlN~`d<tixJ{w?!x%OqMKf`yVG1P^G90XY5+lLb36kuL z`e=41se`i;#Z8s}LtavOX^WX9m}+K8nu%tdn^}I;odu8DSaY#43TAx7sFs9gxI9LM z--Y#*8;j3}Er&}3;0$?{ItOEY>bkQl;+4MDs^rEBZ$8_$n3>a`jDPv)L5t)^_3G*Q z<;5j=mxt`3v6-iCFO7DKJBsmbXqzl^ejFZHdpMxu^3I0X1Tq?mBoaP6*hlKc!oe{X z>nvX^Fqb48Z9Itv6Ib%m&JG41`#WgLaUjQ0obOLBYmc9vkLT;oa5|bU;>mQ3#Huk; z11HFDoJ!>IqGxK602OYV>{KZ27yj6jM(4l&>?7aUKOPL<`@`=<zjYKU#4^!nd&X2* z-b$B=txh=h+7uURKLmLxnz>y%c(Z&j6G`<~Q>N~d>hUrVO%eE#5bUD~qD0!;_AMWs zJ*{^y|LC3X9_04|3*S|v^_M^TNnjNqV}^K@#v-SeXRLT0DCOdQES<S(U6prt|H%*j zypYObD3dd5FzHj8*ffh73w<&jAVc3N3agE$4QmLWckWloShAEa)LKnOnf*Fg`}uql z@r72CW!x8;qNJHm34Qgnc~%*8o8uw-b@^0gyd3!_^FMgwTe(E$yk1$($Mv(Pk(uP5 z9<A2*?!TD`#mFPOhzCez2e_VWrg5UtkGsW0ra+q8e38e)-#q;Jd-vYiFYX?<uecfX z$D{AO{w*Tb|MKB4hr@9pTfi%t^cwx;xHhO1NkN-QHwRtvZ5^e{n0)bIj2u<0%?PPJ z0-+4Pyvu2Gijqo_5MGU%@kktkU!H@`<4K+u4&$@c)_=CE+P4MtpK%9&m5S#9U{x`q z*>D5Bt11Q%1L)#OtdD<-^AyVKlgy%jJ{m1P&v7|e@x3Wu5<@Ef)co*@ycO#!pwuqc zVomUFG=9!Y_<N(4(b$(t7IHV_7;4V10w&BG-6c@qZ+Pe+%%)V^#3(el&C%yj4)M7q zzYi(v1$A-X7B!J+f~3>|k!!29w!%A_3gdD~ECrLc6=euauoxBEG)GWjt}ez3Xi_Ba z>Pz7ClJ=otz!d}ts^OF2;^jpv2&5xqC`rcUX)NBf1}gcWMNR4?xG#A@=!)jUq|TLU zi}8SUMT836c_j*sb}46y^x8lH?PrzTc*jnSB30L@(#FgKl~?(J3-v~m7@B}HNP6Rq z;DcfZ9MDYaqf&p28IH!am8&C#ht;O>3k2-Kf6qIe4k&>RVc^(9rvq_>1q(_fQ~cFL z&V=4W;=R!Az-9VP>?n!D1F<dU2^_LobhK7lOpunz1OzN@7qV+4Ur9(DGt-Dthi3%{ zgYlJVBO5g)l8+3N*o0;#$V?GG*JuoIkAjHsk;rdk5(4v$_yn^Jo-)bf9MDYsQ0(4d z5dI!X3c(pm#gakuY>dpQF_A_EKAB;qOR;c-&+ZNI!;@(*z*^*6M8uIi!Qu}Pqfz`% zID1mV3`fY&xvu2fHHmDgFufp&JSAzX%r~(`O(&S<7z4sgPTn!#GTWq4EG}6P;(Kil z#+)!Ak0gjE<1Akp8<J|PL|(UnG~9<sjPNxVcWUWUJ{yZy<`M=Ln4e>qqQo|3(n85I z-wY3mNk)8|4Q3lCfhmrK$*;JSfT-vebPgDP<|;bRuLXXe6B_=^?&@}BeP&m13g$w@ z#d>&h{5K!GkNflS`3aF2*+Y`F5zz=e%n);Tg4#wr!mTe6Np!m8EW<$s(HiODi1vtM z_8i;NY*z+QmT;>9=`x0FZ816FJ{TePf7l?CyN+xVNmNq_)09pVCWnw-qv;$)34gkS z@%dHb=|wG*%tMUi^Mzp8pN->VDtBQV-kF<_^YL`~X|?-rfB0jZbz7Cj-q()G|M<;n zVsf#lVTNW{C!z4|)c(iKXYb_iBPgHymhpA)Ydg2^m+$pifvZ_O7`nfI*G~xhO_+OA zsjx#Dra8J6f9R*jA3do&`OclU?iLPM1B2e+!v{~FJUvEFgl9mb*<fFa2}ZKHdx!US z_HJi)cXGMZz1#QS`}+63_04Z_SFN^djaHSWv+-9f75?}i{iCnF`L%kx$s#Rg@%9-& zOY9a)Fb=IQshW{iW~z-ky_ZR*asQ`x!l2|;@Z|D>PA9g*c-)h?pv(Dj>*B0Ydwu`@ z@4xY#Z{C0Bta=#@2PZu=`5kyHY%9WX9qipA8#CDg)45!4Jt6w!olL2m%ydcfM$F1c zs<)hSi!bH((wRc5*RBp4nRxQBeAMW6FY1>*?j6%5F}ZO3y?t~$mWXEY|0(XDwyxU4 z&i&G1DW1xOGrpA{>jOXgd?L#fs&pmG6_R>(()#UwquXKE0<}FhH%|(fDcKx%XS01e zf7a9cD_i~+(0^rz{?l)`0#+r<6@pvJ)*vNvBnf7fC$YyrRi9yANj)|59Ohtj1?~bX z4NTO+718oW?FZfnRW8YQBm|+@18(?Bj&}qwCa$@`!4e+F02<*tIhT*9sNtB@+fP9` zJSZv-VIK_K*S{POtTB;fbmsvuCdW5hO(2V!3hJxJ0SXiK8#PYAJit&b-#DjA>}@(l z;E2FYL6mZ?;$}CfzwCaPO-#Kl8f!;h8a0N0aWEC7Dx|W2aO19OlruupqOc#&*o39m zcoG<qgM^3Ykf}f@0pEP1;0zqe0}1L>G(yHrRyx;on$b##$AaVM>Q+VvLSJeXh--wX zInCYNpf0)sEDP$zW0f}YY=cub@(g2;2#q7X+HAG*xjaBrA{&x~D;^`7Grd7gbkrb+ zBtKD-Y`7wtq8lZZm3cwqf$YuPlj9Xriid@v+qo9hGyJfbKl+%F%PO|Un^uJH63Zr~ zgNs`#CaC1ImynDzt|*3?3De1#;TMRbAJijFhmZpnb0S6s_<e78mrP8I3vO(L<`XRn z)6W+G$CzCOf^~@Qi|R33(FJjJjxpF&vH}y&(d3s+a2Q<)y2ZMXJes3XsVKgN^58W{ z9WKx`XTu=UHIyl)kug``>8Yn^*O^*ID=+OQqn5Gggh-btK$7Q`tE;fhS(vV2j9sS& z8$HFj7;4O8szkN<l5Pi-QwT+Y!chieJ0YDnTRqaRroWAPEsP-{Y`rSnI9R7IaZBlW zakO@f@C~Q44*;mA@X1(EAUiW~o#&TV`@3Z(9<nRZ2u+|=aa|BVuXh_=N@k*cUJUoA zfBV$6{5jR1!F_Oc{2zYw!wlZ6{xI>Bu)7dpGduH{9Fc`iF3!1w64ewJPgwbr^K(Mh zu+VU3#U?jtvJsG&IPsDWZzE}^k#cQT1Tw|yCNC))F5G_!b<VA2Iw!9B6fa6Pu}Z}} zvvj_ggcDHG0ivOUH#^M^oc+~h{i4?8j&*u<k<6r#q%f1=+HrPan-a@+IQRdTAAQhk z_8OO!-}}AyzV^?*SI^IakxhHr3i;MM$$W1*xEj{;(ad1pFQ<y!%wJ3IedpHKv$0Hl z+<R0z-b?S?DjvdQ9PE@csjPTna2t$79w9^T*9+<RpS<yX!Z4Ar<UjuGM;BKJ^fzp# zO=kqiB0AYHpDQqjuNw97dj73%efLkk|A(&~-92qw{p!gBb{f&!eDmG+zW(*MSW@MK z-9P!`fBKzwzX!TKzdQ>Eg5<kpy>|x#b<IL`SIiaJkP!c4HUZhiip027t=3@2BNIyw z+k-fXXafnN^mlr7ZgRw%f7HBuT0PHZ6Gz!{A{=avhL7vDDG9bWo6~A-9@u>C?rVgn zY!3Pd<nm3ViNYIR30nfS@U(IE>*{eizuO+R|LV!lA(8GCZWYtTYOj8$ynC;7i~SP> zg(znT0ED6{pCn^f^Fj6W-Get+)63bikS3cLX5Ey#Tz%N8v}@zp1o01sMRXOK!9xtE z1gXHO04dJcHzx{CJVb10@wRdvTl&oUY?jZq)GeUj&Vf&-2NZ1C$Ex=cYo1bqWmT^% z6tyAmA+UwgbLBUR%he=s0iqD7`oQKVQ3D&)q6cug5%^s5bBai`9MdYf4#-|l)Vir; zT+uTh4G592m7HbJA+Zif=_+CjL7AddCLFWKd-z5Xxw*PiPlJx6A-eC+jS5Az*1;Mo zhLU$=NO~a!-0D6nRZ^D#RmfO~Y;dU7S@aJMh!?nQ8ZD68CClBMyJ+jN9|%rjvdmH- zCBr8fHNI+-C~D0Xv+)g;2rz;IjngW|fY8WbeWTFeM5A{XP^=wg+9Q8eB58-)m>K4K zH?)y8LgXy%2LqZ-!-dRNZn##fLAV<21nIr#7|1_WOp$3dO_RarX3m6>r_-xq!@;%7 z8RC(~RfT((R)`LSb{P{$hTIV6WSCcX4lt-VRqNann@~gUn0_`2E90SIW*6g5pAsU{ zgh)cwEvz%xk)kM{5Rhi%r1G2$qLv^WV#`VDC5U*ykT#hZEL4UPgoeaTIhha^O_ClE z6)uW*9HgglFW7JyV#!lC32Hr?VUfUCO9-R+qQDkL0@pry77DnRNR)9^@T(akA}&Lj z1I0|>JjM|}LjHobWfw@DD;P(b$Z*R-6SysFN@tV=Gr^2w#Enk~Z`F^*=^tH0Mt?5{ z$(Df}Nf%Q?<Ebt4M7j|-bn}g_FGp5qdRXrRCi1BSdZL+hvio$$juMlG`ba>j`3zWt zB8nRW%db|gLesJ%b5*Gh219~z6Y}U_uMG8z$eTCfK55XrU2FD6ruBanUv_4G7L^xq zw;?z%`X8R1{I{R|I2(%(d%e^1a|Vbth_evGNhlYF@UmJ-r{V;=J-fW{E!R16AEa{2 z`LfY$vJsUhM(T9RgeTP$TUX3ylOI9^S|llg*k{RLmUHLCeU`rv$Oz|`YxXLI)xj{t zF`KGjB*Xpmx;+3c)0=5Vc7<xaIU3K-ueuM<E@zv-PH`8B&a-OuVYUA6|LP|nKR7N$ zQ(u4QYvn(@Un_8HUS^`P*JFi6w{a)8f7!3GO75i&)1g#66u~F<e|+!H?`8Ih_=I}C zgiEO0JA8>~5_|G|2##(OF6YNjKYChuSWcyXAZQ+TBlydQk3V|!D6m-#@bj3Ap?T8j z461i|la$m^)q1Vktc4<pOs>=!^aCsZJFmTs4YTks|M+`<h`fa~%dg$OPa<s6OQ5iP z{Pe?SuNjnFR7>LAi#!G6b>oAfCujkEj(CZE0P=HPH3@k?NJZn-dYvRtq<m^rP``IJ z6G^YZns4@NSMB<Ex*o6nZ`^rnue8^lkkth4AhuH|q9$6$V%bD09}51W^7vu(St4D; z?FBpOzkcw;UZ+~?H7N6^r@#7I=@1WucCST{%ENrQlrA>A%{zy8mcjL9_hP@Wvsedy ze)?f4SGr%iGa8`HnIAVR+#z=|`PpjT8uY04QFb>Ljx8q(a^f!MYnl+;__^0**@_G- ziFDZ@Jn3>q$WHZ|H4KWm4Y~eWpT$)F%9gnW^k3Pb|MVN~AZDW{u}>!60FAhF@%UGl zAcfb8|MYpU08t;$9HvydEku73&9{NY_A2J)AgD<9+y$?=x_s9vkPMW9Bh9Z`h(@i} zk1DV+TL&VUpeW-O%YDa>u0wIQDCi9n-)^@#3*5;^Wi$<N(cK1#zYaW#<1l2D7(AZ@ zCK^q@R3=Ddae+!&F*OWqg{A$Xuyk_h>i6Cb<P_~LhqE_qw)CM9B|FqU{VW<A+;an@ zM<qu)+&rF`q8blL*busj?Q~(I+&&cVMQW}=B!vPuaV-rrr2MFWRf*JYde!uvacVR; z%>hidRt6{wnzohKQ3E`yn3AsKFV(0ucv?@8+#tW%DeYWdUVzn%!=<>sf>6P%A|W@f zmB!psH&E$FQ9hY4jgq@YUIIXkBLrEKg8iO^90f8Gh=sm^u-B=@i~SQdoFovZ3Am&K zM>Fky0^~j2izx@n<$7p>r2U~V=o~3Lk8?~3D15Oo*cCU?re&MO^|heAM(!d(nM7V@ z2A!fvSw)7P{-95cQBG+z+lW>;3~8@y1`S8x@>ZuK+cFeIC85=Wfr7XY$UJ1ofWl4} z;LL5%x#<m9yrB3mN`?SY!^>WTyCs6!LHeJF*+!ouQTvTy%ymt;B%xHro)iyONlfOL zT{@l2OY<9>CF6Lr>6U^dWm}3<2NEZp%sRc73-+U=niM5d-Q7UbWukH&F)+l<z=@s8 zNbxn>4n{X6PASYEqH{7>I;L!ol!`^vyu_wo`vO=y%p(3$0-}E^ZLM~#v))y%P2x}g z4)>XtXdCjGT*;t$K=Z@1XFvMj{mV)Pw^nYe%k>h^Rr0J61`ANw>NGAcufXT&Y^u^C zi1`qb6<hKALcU}c;Qu3$A91rGafgJlk~msS7JQ2cVIK;{xD3azqS-6r8*Y;`03Y)4 zG;!Xe63cQn#jabfSKw?yyo;G3w;0(_B1#qWnMBT&YGX9^w_2l*o}5kQ>j%%ye*B9M z<H3}FwqZZ+8~^+V!#xDul4QF*?Ucjm#42#suTI8;H?w!ggZ8rDjI8|sr?>y;$j=tv z<Z3uX@b!A>5au|z2_~b-#(4O{M?bw=Jm@W^9~}RRST}$6%|DCzg5&AD)@c9i{a-ff z^?WjeJPpk~K?ks$yC$;)<|USXGLd=s^ueR!NAG|5!PUhD;+bGn?4N44ijJsQ-n(;j zx0uWW+My$eYsu{n(coazmm6IuM%rU;3#~4qnJz(b_DW^K2XS*~cDrao_liZiHH8A$ z5<G=W4A>Q!re=eAyV2r)9SKBhqaM2&m42%mnBG2oGn!78bGiLOVZolsW?hUW%IR#i zQ;qY%7x}1q{8tZt`g(R}FP6ZO_M_UvyXn0@dH4I3dgX@?e)Rn}zH_g5L=<2i1f%tY zSfwPa&6Re}yVctT^8A*6_4H$ii`Vw=h-d6#zK#VyJb5@<%x>)*mXqa+t2!(g8<C7G z9>aaoXidi5ad)~}>}E@`V3@n5Y(o0whPEQ$uMk6$#>3oN9D3z5nebn|Lbrhat2gGK zO^bO{D7@1p>WwvN9`2$xRurqmJns$05{0g!e8mQ!0mZ=z4V7?JOsVuO5KgIF^Q%Av zb7_&FC{}Zzr2CB50!=g*F)FMfVayCET#FJAW8^Vf0u_UQ0#HI+fxAFv08PLLFi|nR zG|5zw`lw+505&dqs`ZzeQ!H1s9ioaI1@s(aAdXZ(s$@FN&^FEuPT-vz+1<W(dRQ_$ zI-3|2E?dS1%5Xadk^<tnw&;}&5zf<5agL$(1@@VwOh%cn5M20m!H5ddjY{6^KM0fS zY-kv0E-ypJJ1=$r)oPm|KrSL}k%L`y#qHZ2DcM`#MJRdX6L=i}l<7%&l^$+1nx#@n zL*f``O-G``<>*M@J0P^x8{(JN<@qo9646&nTo<{J>&FaWMVbP;Z=%`|Q)O*JD;lo= z+2j$dX&NXmF$9g$#{4Tm+yx`6m?R*wa<Gl6$d!s_?5IEX67?C3rxKe5+%Mo>^jA88 zC4DJ=aDG1(U;+TN37Zc=Cn4TJKanUtofO7y1CDXhQo{8RhYtgWjSHUhB*+v&kxAfX z+D1`Si~$AJQ|I1joQ%dW0}vfCrf~Wa!bk_sbURveX`oLs@&W-&3`x{tPOf61>SfY8 z`%A`hlb3dp=?0k|d^8+9e7)m_E`k{|F=Q9TNY2!|Ks#1@OgCP18JhWQ{%7WaSYFq( zy|}?BwQoiwFzAC|#2$v_#c+|-x#E+%e)jAcU6(5qh?1GhWtcNum(oc4g$@Uzmsuej zf1a$&c4q4Id*xns)qF<vm$C5s>)rP8#d)n(C3L(5RuuIYvDae{j~|nbcsK@(i5`q# zQzC{IVO|)>kC80lq}G1SuxuuUrz8`F`Nq&Ao|f%aw*H2k!RFG8<jG7jJkQDGj2NuE zLmsda_epUZT`mg<>LgioFrP0HRI=0V<q|28kg>Hm9^+3!zGq@0F;xj8P;1oAE0@nI z7p3e@w>@Y#nrPGafB&`28++?`@MLsV9oO6AZo(hgPw%sr`ex>+6iPNKrzL;#pS}C1 z@9w|ZIeom?1gd0nos19iyYtB+PI}k%?5B@^&dMZ=&cA#AKPN()fBLOIkNYs@r|sVK zXCM5cR;8a>IJnfBjh$i<%?<M(4;CgBv-7f6mwT;`u#L-Mx5KLb`0>LZ{p#np_xAqc zkN$#S_QQ5FjMHs0jZQ7--w?QVckhUM=MYN+biPIjDds)52&V94MkE{&;b7z(?(M6a zxHx6SqJZOEIyat9n%$O=3bE9<H$FeRnsi4woUb;4N0sBp&9kds12=%dW_i1Ohim}1 zc6K*2w*Ip3?A-d={=Jny^1uA_|F@Sf|Lbr6@iz|MBr6`SV1MxT_Y$GxS@rz9Te-dW zdZpVUbk@wb`NiX(hJ4FAhj0A#<6jU)>&>G#D$V*ux7Nln0GH%=5S>z`+az55MdOmD zkS3ztXg@nUX1SYiwd|c@sjc_Q<<SCHc((pF7<TD!j09E3qe_1+apxRgCifZr$}QEG zw!&LL|I!Z4t5-3L=Iz7Y!dU}+CAz#q3Lg9_q%k|@4xy<C*r-_?cTWdrxN>|0D22RN z5U<EguVuFSjV9QopLHKV@w&Nh7`=@H+zp17n0JO26*o==)`EN$y>SVl6HJm?6*&MF zO+H#5graDyC4$?S`?8S`hylYl<oM9QDcq(hLi`5IZiA4?ralUuEacS&D!w#8O4@Sc zR|V_#7~O@?6Qxmx?GS;xVeLgf6bzA1N|JqONrqhq5F77avx#8>Q+hkZm;_RQ;xQ>- z4Gcm-YZh1od$nTv(yLp$!U2UwC~uIV%e&|nKTfeyA3><#U=w;$EIR0U036*dd;K6h z!{fSUj9gK0wy{G18iL}9$R3Tf2V<V}lm$NKDG0rdZ6Kpyc6cZX4v8eMYI^CWkePTg zMgV=MQ`|n(#_7aRbjvlx@H6XAm~5F@u1ZHX4RHSw+zd=dJ^+7-?;r>sWDYMb!ETJg z8xLNwE>g*v(V_tKg-oP#%qD=@kqAdguaiuuxgb2bkmXL^QwUHsSJYY<veQDO8WWCF z^hU-G(M<+Uk(_NzFJmQ&YlIN`B21@I#_}|i#EhNUo|54+2g_4cptidkrr&F{O`I$g zwac1v{n5=J%BoSYt{X&Jvgs3<hP;<;5H$B<cDfsJW~HgXiArmkMB*WMHU$#uN1z@V z(>ladaY9s)T8p;aJ~}cvj3!4%2OmCo0%F@Ol@Kcch(LG08y8)1GC_r4j19+z)SITx z?N{!lYwEMBJf$C3E`R><hr@oq)o2hth(7EMhs|C~_=`mB^y-}1KuT94x~9@`V#~J% zL-vfo{jGKjur7JjrWoOIrcH-1O6!eeXNZKE_3ZdyX>o%gjVrcUE<>&;<|TIoymYWV zhvI83IlM)@1!^BJ@RsSYhtzF%SxLEUUd(%3CYCD}(b2&Hu%3{YETvIzxLI!6tzH^! z&t~$SKl^^*Yw2ZleKENlPrJkE;C^}^7gA!nU$&}mWsa_z7g)xB_N~82#EbQId%T>Y zM|pbsC>!#J7Slne`K*3H+?a3NdNY$OesKCIwpsk(&F}1GcNa5E_0@m-$=`hN@dv$j z_i+CZGM{xkTTGvwpFpOw1;<nzliYTLKWpUv(XC`SF&g42vmA^%i)nYiy!W;H@9q?H z&n};_8p_226A}Cl!p){KcaQFpkh<GzK6&=2JLr^(IqnDeJ>iP-`fGRZ+&=7fTgMm2 z!LaY3ykE){8to?eWy^&!>#kfXT~se1Oz4MxcW_WDef;pF+Ep{K@}aJqF3?y;5cqv? z`LH_f+}^nx4MmqTl27gSR=)r8<kyWs<*0o42d{lA7>-|dntPdYJd^w1e*B*$LNGDr zaY~qu2pIY!0`M2gzyH>Igw~l1df&SHZUv3a%6GrKKbQEJ;lrK1$IWV|O@z!oi7gh> z<)}a5j&Hn!#5D+;@cykk!`TE~{&+KC*_Sgrv(;j<T*S~P5h@JtCZhgt=0XFRJBU6+ zwy#g62eyFzQ|ZR9dLfG8^iitVNa2xv-t(mQLTyE*ir!R4Z=iz{SjPCXIw~4H%$9G& z5)S6$C(GrFq?|oUL*aw!R9B<mQm>^S74!%j?I>`}GsdWH6!)7dNtiyP{1Nj&O#(gL z1gnu&>Nmg|gcF27;Y5%V;F8O!_+CrnP)96c;)iHkw3oD_v=IKM8x%Yym2S5$t*7@H zZxOT8w+5rDl^__)T-vxl@;&?Ms(Z2Yzd&R=Qs#}>_*8U$jn^INf~l(3RumZKFoFL1 z(bh^&#}d$Q)CO=&6rB~O$9RK8geM}`5xux1`$TsRqIF!20o+Q@gXA=7I;V&eC#D+N zbK}uxmBvvi4=-3q6ZBnlCK|0s#Q!E8n56jS(Vorlk>OAS622aZz8<FIsK%S)%HY~I zV$WDp$MDQ%kHX9%p}i%@kI7EuM=T1;2cQe9D4`ogJI*s3hgW8v$lQ%Z2-KlID!3Qi zX%MYgD8S!^%r}M!=1)8eiDN@-dlk&cmV@ZaxE3K|um{a|M5~)qjZ~bN_i)>eWhIf9 z+!<#2ZHY!-jARqFhM&YDb@fg<{dAPg7|GU(X!K1EW(jU%g4O5(aW|1<Tf;p|qn{e{ zShve0n7mk_BIq)e*J-al6-+xp@M@tM89m1v0uRpta&Gd!iKO5i51A{yPSYfjCBp1T zydBo-%d0D<N2yGX%=w4E{+Ny?+zK@uV3SQJxAt~rCc9`}r<`}yct5@>?{)b&hWe*e zX>((ikn_x`(^~c6@snnoNF?o6r~mfrZ(xgF)vsQ=eH)&h5Q>L;2Zc-y+jxqT^J@9p z-PiFOIXQni7<AHc5)wrwqcP6bu=Uu<CgXCD1VgM&v^o;LM((S@41t>>Q6mN;0||~F zxW<aBHwQD@A+1?UoRyAeyY1m<Na_ig=s3g50%Jw=iGD7jxkwH;B~la8M_}~r!-Hmf zm`Ozw_p)#O<L^x4t57u9CK>8-QCRp>kp#|~$xtk~@?Z9@?iLQe_xd;AJo@H%Jb!w2 zJXtN9{a!K=`TaM(QL7!FTs`W`-dZe?&HulD^l!V(t3UbX_x3Y8lR;-0jQ;eOAN=~^ z2YcB)Zb6sz>S#7vFXvqLwbx(2^V<E<sE-@U6yQ(2aT|~phc9al?4MXTczbvEtaA0! zkKQN6#I60ihs8bY`KjNB0Fv2nEcWnzZtu0b_sCm|&jL?5JVxGn>+Ns<-uDQK|Fze? z`OU9?d$FFkTNmwqv)&yfqZ!G^77RW<JEj8%<DR%7tck8mM6c*S`n~TX)Cu?kt$HUL z$b?pbVk*<@GzR0rU%vlW^k8#2D&_Zodivn$#e?-~R2{Z2T8)c#b-5bf-+S%B#k2mP zi{2d%uy8PP(!A<Tdw0`?Z{B~G_MB9XkBYk_)+M45w~?J>aVMTS$n6}r>OXt<%R)Rw zeqTalW}=B`Alm8oIqdl2jJqb=IGsTkd_VI~2g^}8Uy25!<S-zZQ8XAKq<u0N8<UZC zvzo0%m>2a+pt&uk|CE-yZwu%@t)Bd<mt&ts22YF7Ldj`Gau9fmH3j+@Ew9Q^6kaIo z*6`lCiEr_xKC100E*f(vRgKYZP^KbCA)zhcwoqP?x?!0e3Rx+0dw^B9Q;z<mO;DA* zmam|n!a<L~6eGD7i4MSmN1#RgyivKlDsx0p?c!{0i)>Gu9=OKz*Btz{<VGRB_NpGK z_K%)ud)o{5^-ySaWz=;>%DJY0jVk&Y_h@BIKXaaP&?cdj0l4l~#x*7HmL{c`PL`J) ztQ*a7S#|;As^XCPn9w~i*_<eH^UVfL1<yq+BExE@^)UUboi7l<oCz&0DcJqKY&;H8 z4IKoQw&oT;sF<E7E2jhHwLYlcxt58nCvX|NjZ@6Hi=;}2SZ9u2*XeDYQifDE(e_-I zUjt^96-M)6XmH|eiZQ_@WC|Gtju{2Xze^2?dW7A=fs_yLXe2tJZhuH+fk&WqN&`!= z)xZEyFE~xJ1W+eSW_2zt0Y%p;&<YuG6k+Wgr*O9Ev4vbaS>yId4^tE?kc)~%>e-&M z4O9!3186z_>C&*P)r9yoJ2?`m#&LVqX{cCJ=Z2kK`ks2|9FqPqF;b-$WG~Ka@))yO zt|+F8bUu{_$gyuhpz-l&P%Q1S&w+J^*vX{aiV$!E2k2sPhte^PNKSO`))CSTI9oV- zQWJ>cf!z;t-5Vg-R_|53DSz6PH}?U*uhwmU@c02La5Agy7k7}7As|5p-5d7ycFJUj z?UPk>JjTIeG#!Ux;w6$#rgzdg0=)Ey_m18RE%|i10BIXP`+P3v3y@%F0)S_3A|%5* z9JvT2Hp49%lG$`JpOUAU8wM+ptvO}{f*g}xVAkzG@`CV*+Z*qY?<pEilR1pgE)!hR z!N3!?j{g7b{Rf<6*LB{Dc6W7G&Z(<&o}3eAkaK1LNi&JED9H-8?)9^OmczAlZCSp~ z{`tP=E6cXzc$Fy2B4vsR1OXxrfXR8Lr*p2ZoMVUg-+NV^X$(LTVvqm{C2CN8>YROc zJm*_$f9qShLT03YfSJu>zN2k@&*AOc?%RE)K94*l+cWsK3&rG4&roG^4dwboIg?u} zE|wC<hmSt6`>t%Z)E(~W@`OmGL|bC14C^?zxqfYW#@z06c|(_GZ{&)}hY#LuSI%q_ zK3Lv3clG5{ZzA%#xEw84%UI_5e3rJIIC}iRfrDtY?%s3Y{Kd1e=wjIKbCFK9!@{G0 z{fFV+UNVZ{CeLLuiPhNj!o1t-^9MsW=jIkySA!lOQbJ0Eo;QU`9P94t>fXI$=U~t9 zQhX_0NPFCVU$86O*&U8V4(#6NwtBBlT)`G%{;wuiN!8pP4$myjhy4DoP!}6}ti#n* za<G3i6zp7HjN&7|bn&{+>b`vSx}(h+cKCVq<PhB~7oWd&D!)<cXBBn00(Sp=bPfg2 zzOKHPub(?Tf8)Mg$L<?D;%Mv0mWsq&5hQeC_o3xN^4T-54iAj<2YctEQQQiM?P7R% zt>%?d{L<vLE|1Ey=rDUS#Y!Tb@p=LnYu6^nCDfJO(Ett=kE6A{wYX7&a*3jUDxYAB zhCE-{T4A9O&99e(7B4TGQZ-{$yee|Hzc07c-h+>q4*>mpa8TZVRWe>ef@?KQyd@7W zQZt6rTF&7E0u#TrAWJF4aEA-b0zGJ{?}n5-CkP7X(=4WeGc-yT2d5(33*^{}cLl;4 zcQ;rTTT!y0dCt)l6H}o9sa4pkmb;-4?Kn};P~s-x-iY_tsH*Wrw?RqW%dHJ4FI}{? z-}Gx&b%LN_=@4<0N(Tu>mkJmNMk;T>_hx*sP?^=q>dfYlNbkw5xAdgA)s-P6Y<K~4 za*p(dbhz9_ZpXhw3G+S{RUczS<Ptf@sH#>}R~}q|W;UM}Gk~GRfz7=@bzlKyv4FPu z3EZ!#9eVGgF){cP=af=FM>NKY8uSJ+d`uP4C$|$1J$K~wgTWxG|Av)ixTU4xVrpu9 zsS*auk>(t1bi3*>>EvdIt1gm$)`_|pejp3A;W#QfSgw+(S8N3>>8_#=d9!LRkkVY| zTDUR<wgGchGzGt+3a^v168cLf7s5SdM}XF83sd!hj$u{Wroujw9Sj)-P5U=dj=t|Y zo@=gBlKBn?R2QSwx~tW|8JU=+AGj|e0gb(<Mlf_kL9#JJ)ZA^PV%>_EWd#|NLF^5s z0Nd=z#-@%Az@RsjA6;d?!Vpq3i~nc1s1KchKc1?t)ha}0x?J9JF=tUKerhjbc{w^d zGKN1m7E7S(@Avtp7Z!&4dr|!(VX)p1Xk>~tW}4A6G8^A_pWDomA6osj37X7hmR46F zg&|Yp_jsXm;I+?J3K(}#w1Lt6-M!2?#3N(rIJps+-3USU1PN>O(bsIJDABDpmf^b3 z?V_uJ{>U&nT<i&%RS89cDGB#bnl>tg6Ps<L9ts9o$_m-*0BH1=+%DvCYAMo?W()Y6 zm7_u7{SAl5&c+LIE5&j)9QI+t!L;h`>>|YxPhGTNy9a}#_w1+#O;h!iWHpA(7qWX< zZtRs!7ng>7eYOs3qL$hf-qv2;e0cZ0WJGFjGyC0so5jXLak>JrM7kY8s*a9rBRj4x zjmNXgquqUb`*%VeDYw?nT)GimCXW_bWMf$B@YYyoiYe!C+<*T=1c`u9FI+tjZT-_9 z`Sd`4-?gc8DC1YF1r)fdwF*=d9%62#$gTvYW*28~OphlM@wwS)RNy0>U3Qxb4ql;# zp~CYG^TFYA2SeeW;la^zy?S%<8q$`DT*l+{?HJjO@?|m^otVABsjPjX4l?;%B+%)y zJLl#XS5{Zi<*(K@E?&8I^X6pG<?9NC78jNsWN^l0sJBl~&sNvUB%+#(&e~0&?Hk8; z9`AMq92V1%(^pJo<HZztE(mz_SY7QlbFFo4Ik|Xb`<|9|^X2L5C>nXqp1JvXd_&9} z$Z!3jFgvi%pMQ<m-}?^U-y0fCX9^2TD>rXW#a5HVI<F+@v{o!b9#e=M1pHoWM~B<y z=7pRrCeS*-bMLmg3zc%Zp7V4#*IL$#^{l(Yf!>aOYk$DH`Qa@04*>lSryoBkML@>Z zf93teyI<Jz5)>;3)%yT`h4ux?C4yoF3(BwJqctciT&Vr=4Tx!&2VgV7E`mAb7F(-9 zAp)-jPxF)E>K5;&@ll|yDOw^2#i)=nMG-{T6BGsTRRTEbzADvHqooEA=SC_&RGY$% z(50nH>gA)Gul=JE`l$dQ|7T$0t@oAsh$C5QvbDCi)m%<iZqY{ks`{M{(fs*FL!^3A z8Qn$lZ-Wf2(O1J}Ft9jZvV4@gRPpoWxQtpf8s#a?{;v_sYwRjWZ%dT~Zi<no;!4@9 zce#{v7MTmRhttr?kceR+_GkunL(g6fs_tIA_-a0o))e7vT?gKv6fU(AO9pnYu=BT! zsUY)P)&;*ZAt_cAGo??|=rndeB=A?xSFyRe73ze>ydw6C?H3}mTbKYUL4i&kOIBS) zEK#6VM`p`>24t(dC@O+7Pk=s(Ew75B^6cI)jW(5jsCF__4Q-z^WJ3k4qwc37H<-FG zaLQ`ufqSVb$6&213y1cq5z&MqE>SF_mKI<=$zsV`#eHS|h`}a{MLI`My+&#UFqj^n zhM1DHRKkdjRV?FfOd(?;aRdz4ScAG`;mWK1uO{0~^|0<7>Mgbkr4e#j$Y-%Oe8EoO zLaC7P_`-{`6K=0x540J+Hp-RD(P$=<>+9{N01_VI-=*TX@Y%F6m~yx6T)lsv#xfOu zm>)WR6aA~TnUzJh2IH|+gb}aL&-h#}Fe^Hx$xIq&aHf!3SY8^RnnW$00g41drAi@@ zOQc8?)o!w@4Y69Os**-QvR6R7Wy9lghr^xi7AsWvY&P$(IguuW0Rlj0?*&JP$^@)( ziK<Wyr2z|9OmV!}%(0O2i9lGj(P=Uv3F!@YMk0~1?S1?9j^WB>8vz$dp;R628C{Mh zNX+VVS++lPc+!?$*hpFkhS?~&JFJV@6>hNBwvKFKx{@36^+fFcjcVo2ft|HN`TD}7 z%k8stDD|XFtwe&@u)`DddU_)L*H@>nFHa0a!bi6qtCzBnzt7&7_{PhxwA8Ds@n~<j zYc(0mmx}5sw6T^h7baF$lwW+UC6_Ji-m{lIN8IY{PCW9+lU{cKb2FDCyAw3}BB`I1 z&`o@$Z3FqrdOQ(bT$nz8<pQbch6hF?ULV#gCT$g22s3)J#I;xbKL0@PP<N!)=W!$2 z#j}N|UtI6#;Y>|W;5uM#!@uWAX*OA|T)n=uf-a|>-4d_Uu@YVG>534Y!=BtibQ#G= zuftW!m&PY=Iy$VTjW&<Ze`96h$gTs{R$DR_>$Ew89$R}EQ6QvvO|9!K&!2gbke5O+ zI}+*Z3wD3$&F65?gj~*<@te~Vlh<!tLn1gB#J+N*s-;e+hm`5rd~qonk0w_O*|g1M z@jBeZ88O7&oe^xXWHucjIKb&-ZlT!|&Br!c)`vnv9=npXN4J!y10Etls~1K-Y#eKc zUGr^z*wg-pxrE+NWqknX-%q3UzNo9bWd)1#FTg{>LmSwx>G2i7Cs12_hZ+uQqQw^Z z7v2N{QhBZ!EPMma8wkVjYV*p`SfnAhA}B=87nmZ5L@Fa-MPP^Ee*To2NHwHb1M?}E z-asVEl_~^oK~ZueKFaFQTm`vYy!bet)xSDnssgx8vPYvPt?Gz$i1FEqN)0G4Rh2rc z7B#st4TC}H%&3hKsflW!!lANX(SW2|_az#^o}31|LkR0@N)=HJpQcuG71Dt~L%=sw z*V}5ysKJ@hXthD0mlNb(5^5=S2!FDt!BK!C5+y)$L7!4jQK&R9pQ3>@Rf>&4QQ)|Q z5MH}SX~O7WP@T8PxSiN?a>TH~biXP7i6-Q0r@x*CB3iH5DVl0x46%lt(sdfj>um}F zwQ?ibV9_a2l~D&Sh4i8)u)-@+C3Xq4c#b-s{!x=wH(Wt~Ga$9Dp*$hfDioGN0Qp>H z7`H~FRCb;YrJWBJV*V&=62@*v2eb#K75z#7O9Zy6lFIVa2s+0WQj&ryT2aN0>zXSo zg)`|PZ9_KrMKZHxjKudZ(?%wtC^bpv$Pt-%a<EylnuKa78@ongk1_LAUIiHuIhig} z_0Wl#)d%rA@|WR{S8<AQ)vj{U>QFA<daaBrH@X^!(t!H8atyb&rLwt^!9E=J*gQlM z3uRxFUX5K8snYxR^CPT(YfG+JAX^hur$i=gY6VYrT%Ek(5BOG6G04q1Bn!z(nn`y> zdU=9gy*ZA4JmNR=OUu=Ar85+?dz@P3mVK2ruOFVgqqg2sTd$F+RLLmetgf$H+RZrQ z;X$cn4Md>oT_x5svPFP+o*_KF3WW+*Sq?FsdJT^?yKUKOMny-qSJu|k2X>G7dwSXt z(G2>SCWzj2d%b3R>*&2Z=R#|4uifu(EEJcSLL_+O&C>7dVyTs3$!t_<MY)iFV*3Nf zM~|%4%botN>GbOL*sP-+T`5bCH(;`C;1s`}jE%2eI?%UmXU{gKwbf*unO*wUYp;@* znEfK$4Wv*dJGIK5w^knR?>c(uDBkGP7tiNOjn#sk*+$0JTBY*Q2cL1cT(lgz&aUla z<iJ{7jV9Acs;v#-R$}1kRa=`m;0vTPNuuY?HW#^8F|a`YaBpInG*P7ix4#3oy2FZd zq$}J7>kPU%-144*VeI|r@<K8j5BNGsXtBJ!k}u_m|A*Gp*VRQ#b6;1_QZ&Z;nwp!j znr%D;uqZm9u_=W}CzjM|Av)GI^4Rf*7G`Hc1juHRc3b;;y}~P@R%vawTE}`j=awd* zybv$(;*E<-$>pOv4z_Qa?%s7Y7zpRqOPGIwaQJIypChQ^(60SXi-Ttnu>^@!jD47? zg;|x@q(E#%+3WYTbZm6k)uuI0ik?9CYC4)OWrn&3$>g<?jpgcjo|p(5Sn!Cg)h#U@ zPK%qVsHuAD>7pOq4L8&KcNPEH*8BrN|7Y9(e-7_1us}dY6A3B6%4${KM~!{?2r>|i zZoKskSE#ts1#+?44c!~%(rLz<>cZ7O;@21OZQy=6B0yOnh1{rlTm@Uo8&pu5lq{P7 z#$5#d>e?z*5P?1o^8l)P8}BVeuK-Jl4WQ8*`FfPH3b2&hHH?rZ2g%qI;3u(sw8~$j zOu3ittA>kLz^DSaO&^9T+1Lzeerdq;rkEh*sJO#&8Ng?dR=7%#nWD;6DlkOlAu5ng zI%?~dh1^AOIXo7aMaqG%`nwTltl8mjVN7l5E<F}{0%&yJ2+XA|h+~i@Ng$w%2(RZx z&+8sj{jZ(eTANa3mIWXRUWAkaNRTqsnOdPm)l<iPij$j<KA{24HEE=wk|q<63;7*m zOs6zzAZdM-`c)U8zR0UZW{W^rJr!?(R8TwfS=B-LqJb><q?ExX0ju(#L?WRMs3>f? z5j_5lOeT$tIz>~aPN-FrX(`jV@x5ujLRL_TQQaP@)Xd7HMZS^3M2@<dJy-U-xK@k6 zLKx`aovKtubp8RM!ZR(EyLO9`k{b6Wzf0LX#=L5VwMb`fot6f;H+oY2YV7&wwZ^#9 zI%S8j1EI}Vpqt8Rpmj<0I#p@8pl4Le1r-v#$u1VDZyZ$!A+Z&=H=s0utTwa`8GSl% zIl5X<S~r!&=&D|@Dp!{*c0Ctv?OYkP{d4$W{XUzdW+VLs<%a0+iMbh%!v%i6a^nU@ z6<Lj-wM;L}t+i~1L!ppA7)>N_zoJTsFTTCaYBS^6O%l5bkDBu_!&plsk0Re2W5o0# zu#(*>m6Sk5gOt^Si}kJq$BB?pNt9J8Wg;(?b}C^-bx0#*W`KY}-~<U`%a!7h<9qvu z-L-PU;c>SIBjd}<*uI^8y(4>ec*5SW*WI^oq;*>`(_Zvj&9j*)_N8`&2G@ziZ8zIm zEd<%bN-?*^5w`lhHt*2Tt_wG>p-a=}?|W(bRIZXc-nYBc8zQT7N1J&ilmFw>Ump&1 z?i<+6W&$+-c)D=@>h+sb;|?=CJ!ST@6A42;mP$PS(BpUCeQ#G}fHVl{^eS;XZcAG- zk<69qtsPdo-)pk8#iOe}Z(w+2)E5e_wQOXP$*y2%y=|jV&VlNcucsZo8D(0>VoQ_r z6B`|Ek<K2A#mUNmKiJk`VjB(QU0JWF!2gXl`p4YX!TVrtadLF9*XQr7lnOVeCs(4Y zWZfWup{o<;J(@y14DI*}czR$>5tcLDKZphq(Ym<UXBKC@?%+yv(caN^<mjF4EI1hX zEt_*oQ;f~@a<a17X7dCpwe=oP==koVk<M;pC{IqD>F??Z*!*zZLV@ty;*`%9tlC>H zFWz*!{6SCP%(bg;+`NWR&AP=jHatAojRIBv`qXt)Mgsv)AQ0~A>guqWH%*%!muJ3| zoJdSXJi*ca9r;ReF1MUpEA_e~UW<!3W7e?G?z5SZMG}l4pk6<78_(hIbGrWpzw84* z{}+4${E(Y(c$#^O2(dwUDdMgcoGSmyt5@)Wpcw-zh+|Js6sL%DQBF3Xr{R*9<8p#P ze?cJ{%rwxvfmEcm27)*4qI}ZIwJ#4Bg>D5^gM`F`D|gvyP6*T!X+JI#riV%ds~OU& zElqc?)&aaF!w;AShpB6~Fhis__?LbWH)G>hp-OD|Xq%#Ovh+r&s8ZWXH5zDi%f5ke zke@(=sZ^4?;|(&-l=}jmW#6EITy<$wQmM7*h)>mCmGwybzv*NJNX7fx_{ew}gWDKQ zadI~e1G1q?kf;E3a2}OW8WEa^ubp{{+N52`O0Zl7(rJ@JF_(COtId;!<6qTBgLSH) z8Bh&lK#YziC|Bj^jEoJIQM2n*jDbkZOFuMwqj8!>t9m{)tqy6ObdJ$#I*XSmO`(ef zSrS&LC?!oBiLf@6E~lZZqYNUPpwNw&nPed5S9$=%j^lajWRT1ZI)p=QeL&e#>6WbO z7W9>b|Dw*xc!>oiT`iVgV~t2~vyMns+YP{IwNay#?^UBT1m8MUw!(DdiNFb4YbEnU zZedI|DMXUd$|O-etf6)@nUs1-tF4JzRjfEJR{<#GCn}TG0gt<daV8TGq2gAD+vae? z`hesGhN7Z)=#$CR%-lTiF<&fgA0A>RAX^#q`*j1gMcRCZymcsl$WONSX>nqZQTc3{ zoUo)KO7aj`iN%tsOp2)3RMy<8Q-ZXb()l8fyc`j*r6Ss(7+N6CSS-dgLlkE<wt`?K z+jb~Rnp!(ZA%s1RzraD71v4q4lqeIaUJ;rE(DR^RM~~1L#->;-wXAPyG1)bha1|hr z$ZLTRNoS>A=^g97>%k*;9vIs(II?Z$k&`#akusf5uiRLjZZ)+KaT^{R=;-rZ+gNTl zZ{|0$*bV*GPDcy4(Y9KQN3$y-htF&AEN5dOXXvNz_{sA(UL~L0p8kX97cSki{m1|~ z-`0M0@n)HD`F7I_H(p2M@zB5?zum{<1f%|cJ^%d7!YmTA%K5{jHJPCvb(pOC_TJgw zzZ2ngi`oA5Z+#Uy`@P2>IC|*#^77)D^RHR#){XX#Oe$e*w~vkNXtxm^yK(;9>8?oR zsi&TfrsMT$g{XHdYg|_3kb(e*a1B9N%h8qP#T9G2C0)$3HHm<)sRfq}i$#&hRH80k zG9B$unr3EiZnUiJ-gVgR@w{^KrLfOSrjD_(ZQyuzLYVswyK{Dao{$oog-WVN8R@;) z7@3@%@wvSTGF0WG$M3i^R>>@^EOdMQ-u809Zi&Vg%}#Hzf+`o(pQ=0PdwuTmQZ&)! z3v~qoZa6tMKlWHOl`;{pYPG#NaWP*mZ138Zn_anb=?Xgl<SUp@L@&)xRNFR&hDNuI z?kI0UOiE_fvxSX%SFo$gA7;a3HML5vuF-+9xzy_A)$wZEnuq;1i<3wwZ@VMt2!ZA$ z0R>tB@~o4`u>4Pd-rpN;e<n|i4*>n2Nw@#`ys3a5otsJa_ti&$ul^_pq~TK(@4HZL zj5o2sdX>mVu~s1JC`oJs$8QC}2D0CZVzoO~feBrL0@ge!a1_$rvRxqWez}Vn6&lK` zkKorPWxpW?DDcHF9u!`0lJx~hH4uzqD)V?m!A&`$1R3jo&^cCh6sFh)MxV$X4TNOe zLf8}rW>R%-y6t%%Ya#pw(4+(*UGOT9haVM^iN%dFTJDXPs$wWMAB^X4=~sk*9Z zFf`JDHg`V^XsF@1g4&9IqRwtKS-wc~4afXe1S~ZHM~VWy&^&<h;0bkiT@_JRRG3xq zk#tsFVH0UDte8F6D%?Vd^19EJ?I(}>=Dv#zMMI+0V0kpp(WkyONS8ki`j*iOV=Ux| znjXz%D$}>w*jt1X$`wYL469O~Y-Ayjd9{&DCb)T1$y8aV5M~G(qZ9D1aYt~f+Jew6 zQ{5%e6x!TrrWS6+ldaZ*HgAyar$e-8kCJ=mWoTe-H4tLyHRUh$o|3Xm)F|i=w~+Os zJ=+ahRI_QSo3u65NOLCb6<ddM)TUYUO)Fy|#<_fHE(AR}wQYkcN@D{@8)-P$=^XW| zO7yEzM}g{XHV1!JiaCeN!?pq=%eZrUxHoF(5&b0nWG1t`67_gJ2lwpC6$*$~4)^yG zji9EAN>-}u90Su!eg1qtUcawa359{lMW0`R6g@E!^!XVdgj^uLI6EAZ6SLQ^-$0Z; z=nJsQg8{hQE?nn~Al`2r^GqTL^u(snv0!v4)Wtlp94g5GTa+wC#F}7uBhd(|%oKBK za8;gW74NPR%GTF91LTZr!7w8zlub9ahpEI`>tlPj4;~!J)e_yo{+ikM?3HtgeB6QN zj8d&JTM@8tt9$z*C-V~lo2^#LhfQ|(n(5wccSO9Q)_O~{5DlTg((X=IOM8Pmrc=wK z;o;t3|6q7HUCbrxMXcueL~JxL0<W&!Za#VKA{3z`Bl`wILzVUNMt$x1*H68E<}93# z(H_+6WAS7X0ZqHrf~8nn+j!yROX+-q3HSQhSME7+cOcOF8^8ab;ln)r*u!Ce&(ze^ zxie=x5KRJ|#cJi%S6_@JqK`iC=<;&><eR5=@7(j`qmR)!*QTa2sdT45&>4u>+8u>d zDjHk9I(hBf#nXjSx-%FFx?F6g@(fAUsxQ3$+QsYF=p%E7tEX$&<Mt6W-`&$koCCoK zUSDuzV2G4_P<F`jn?lE@T*VT=zV&<j(1gaPCwA}Jj--~)<y%@#Y#;5u_l`T4W3$Cn zA{kvJc&ER6u->wnueWq|50DPFw>NS%yS$uS?H}CM?T-YVZZ!7oW}DmZY-{BS(>}F0 zO`!8gcyKLNSel>Ss8#1@=Gc_L;2>IhHIpc<mGWz~-oAmOdk^8oT29T<u}kIn8#AZ8 zPW#<EPas%19-oG%#0I9*WM?MP+npq_wY!-?Y_@E!lba0XN>W-WN*)LG6G!{$KUm0r z@+JQPp#PKi*#}pA=N=I3CGU9NvO4NfeKb&3v~uBrD5s$Yl)S<X5{^(-1alZ<8})+M zXG($c!q&w41{+?^m%vA%-w1YTLU!<$y6+b7-4I|gOaeJmC$Ll^fCjeKR)KO-N`$W1 z9>TB}%*U<8*{`VQdNTn?2iOv@E=3teh&mZ|waVMtz(A@A%@AJ77o??idK!pCgXsq4 z1J^9#zJgth-3;~WY;D2or5e~sohv?6MYdM`tU1$iN4ZKzf;QMA3Iy|}<qB;GG;Ngz zB;sBTdrV8;+`?@d+zWt{`bghy1yaUMl^0(>p%vDYRHjPQ1rL*uS{ke*F=O<etCld= zN-so|Ivlv$)Soh}Qmm>cmo`1<G8wgB$LKdhcJnRU8wRPym^`;Px#<)#Frunvvr5v3 zVh3@5Dx+dv%}^0!4y@5Ga=TCwQGQgS(d!#P4mHD7?p0--(qyQ*@DOx!)@w)v>ZO4- zNJG^$1AH`7B9M41o``pbBgA*u$)>52N802@jSknj7bKXO{!k?6#y~WXy~5&J=9&Lf z6HJFy=n&mTXG!-;2(mC|G~Y>C+A;x@xu&~a*;INV$<Rw5ip{fi4v2Zo<(lrLK2(@} z49rMw%JnKdLm9xz#7)MR5gfFTlBQf>Cxc!s6tc`|m($Jv@J;G4%5{9Y>?x7xz9-VT zu)Kn1rPBU~lm##3t%QD=>T=)r=|`ReKS<?ebo4MamIfm@wKO|DH%pqNOuj%iA+O8M z4hexQ;Q$=(U@l+0F+NoymUMC&y&9Fs%-VtCWNo90l+8K`Hyj=Yj|fhCySb1dD^v?H znz*G2k_`p|pkT!dcUb)%4~8e%gV>8HmXW|hk97kj%X|(U9pX5>xMFLSHJH=&>Uy!I zRA{UA_HS>ob-#4^;+2`}`ARKc0g2ZTN^G;Vc8!dfodiF(M2mCn8+BW@^b1Em-eC!h zcm_K?5xd!uEh;O)Z}(<uxgl@QWPA>4%}jiGScO^FUL1epo^3}9*<>)-{p{2m^UKo* zhIaM%yYN!eoabMC^Zdng$n$I)7`Qey-nwogEfntjWG1m=+phcXx<3^3T{!o~!qVK> z(2lW@16Qw|pP0COXxF~&Biq5#r%u1_b6V-W<(1_NXHKteR33ZaDYMD>+NswnrQD9u zv7w<I#AK00mB<%2VnAja>!(o6C`rx|872yBL=6vb3x<2Z&>O8A*KS;V<IQg`%v^u< zm2W3kqa~8;wpnx4+NEpfZj6uPmco)+SeUyxJ`qc%dAe6BwV=<_-PxH)CwyLerCMH1 zr22aY&tAP$t*wpr_io=l($n3ONW|7E>p_3`%}b|emKM5tw|hhVH)gIL9NWWw#Q5@f zhowDRFR_|nQ7tSjprOgG=;a$1TvqG+^1R9F*vKhPpw(`_|E~K80w5_Yo+M;V6VYh4 zkX~F}DpiY$R^)Kqv2%ZUgSgmepC_`fZ?DzvJU4%trt#)Z6MT$9<=Upt0_`Tki<JF` z7Ub!bd!93R+9+_Zc&zep!Uk<nag3d3h4Fuob@3PB+7AHzUxZQq(`zFuUw|(!6#+U8 zDA1(P2u5UO3cln8uO$Q<P+o*A#g(XBq>Xe@&8>WmBm|uc$OFm<6qe(H%Z>QRCgxTk zOkt^}qtSr-Td|1LQ}e1d#A$Mi6~xhXmPQF+Qix}*q3oegRu$0MKNXUbDsiDy%+T|Z z_)(54jlV7Nf&xnTS8gh1fPpnRj#q}OM2*oXR@F);{o$Y(Ld{A_wp~SRFbFZCnlH#( zckC_Nv4Mf4aN}2_y$ZjIoTc*J>SwKXCmXOs`0E1u<hW5!&NNWCswYB|NQ~zTcv#gX z>*O<%APQ1QDsa|t=WCCz6sz!b6Q>#-C3n%ot<WJRjgDcJp1<Xfm;T?<X$`%at(7-^ z)o+UiPBoflw8gkY#!b7Sbv`dmIFTI>c17Tj;D;7FmgxYUMoDw($*HwXIgt$&s6)tB z!du4tv*NQ<;vu@)5?P>q>Z<K%)%5iAGPsa)r~rOVip}S9lrJPJnR^%x7_BhYq0*{w zSTpST4Xr5x+ebU>b@&J81Gbc%sZA7_Ez&@FPa3V3anwLxZLn}H#;us9szaGwThfY2 z0bBc7mW-Ibe3vF`Ggx|#YACW0WmYT2axTTyYt<4;e$`4TlSx7B@^}Mwhf^m2Xo)A1 zD0}pDcT-f*?}hcxrj#P`sk^pdP;Ir!Zfk-x<o)&ep)^58M8-5*DV@7{{l@eZiMh~r z<Ome!l~e`;3A%FzQJHjBX-~G9l8J=Z>58q!oK`zhq3bP#VzXpBkcVe#!5dj)t}_eQ z$_#Izlw<D=qCDg=csPN8KbOxzlmg>|$<o;jCMfufxek<PVUaEsYQD;ipkl$-QM&j0 zt!ta5Ofq}!>e;#FNx#F5R8@6-GiZnUVcoNL-_6a{cs-G>#u0<}v|ErhfAZi11TMWW zab`K0e0=o8or8zj0&sLVHrCpfi^-Yd@=R*V++udwg7D@?ygl8H(3;8om6=oN<)!UC zy?eU1ZI-F6=k;?JUO)4Oy#s}=^@WusMD{_S=%wP}hy+8vPIS^;thcZS8Jp0nr%o<K z=f|fn96NM$$Bw;)!g{67BWLAjKlS;|HpiP6F2<ts<Ud8R^YqzM%PWib-Fg4M-FKY7 zaOw2v*V&OPl?zT42-HS8EuY(6uGVt}p6BbVO)}4!ES5BiLPZ`0mR-Z6+xrFw16=^? zmtXtl()`5o!otmo@rsHbw$IMZEzB*V?H}|7=|)0gScxh_b88C{^%JwRJGbwkt3!St ztf71FJnnFs^HtpW>%mZ<&1yPv>|Wjz(<?J1w<_nWk-^AIXI{cyU#-N^-Mz9flP{Ns z1_zV1;>7gSU3(7VmuuhXK)>kXsq@QAF^Ac~X}GC^fliOhn@s1I7FP)Q4cdKk3yaXV z=2n(6#X@JOci-^#eLcfLPuID{Yw=PX-OY3<?>5`J9l?k#K+-OUmHjs+QlXW_ypCHW zgR-Z&!;Z0s)D=pgDw(V(=&JwUYTteU=)cFq>;pjm{(9QK*J~>%fw#3rCrud>%{k%q zjYkuFW3)j|Hr(e1!jKaLqYJo~?*^S+L6e3((BKWrOI??y7|X`{Oh?lyBDFZH<aU%M z#=ur~KEG-ht%L^!QVV?CidW=MmC#%TK`NO=IU?db@(~=vUF5rblw5K%Gn6<l1?$L5 zS5B6eZo!w0?;N27C1>6=DjEnzlPl!cEvQW3uZEf$bsF%?I7iBnLJY%0^^QJYE;Kyb z8jdUNONDo3H?--Sm+#UETMLvE#OW*T+Is7FA_cAmbV|Qfi#cE%=~kez5@%=lV3a|k zO*<W1sd^Ip$3DI6=g3V}dM1m~fzg{k%777?j2>3GXS22%!pcw5{H>Evx?S3>o8AJu zNruTV3FNr+nA$Z`pjI_gG6~DPQe+s^TB=nc;cy9-7<wR7UX^CGN~El^l+bsolp&65 zZV4fwAQn{&EfOIbq7NwqS`O2U=0{go5bze|P?dca84LZvozK4nW;bazY;Cs{sx{KY zsCleAUe!~RV8jkK+Gs%V#x!WQT~65AMe<!%gqo!~u(jD~s#|0)OZrEymC0=UD~3A9 zb;>EFr~{D7W>R?Stz@0VBkS}6@;WSbZ=jQoayVhqvk{>LJ&8F%gr1^SlWFn(lf;L+ zAQQwN)TBY|Y51gnQ1`YmG5++wY#osw<nDBiVX;^0^$X+IzkTNQp{~A#rC2h)ic}~h zu9=0UNM|@-FO3cl-<Y0YH;Jbv9F<%yi^m>=v{tDjG*m0qy$&zXJYOsm`$2GgCZEv{ zK;>5j%BRq?*P^r}ol<f(O3@Orc^7#HND7T2B$B4<^>tj-Bojsb7JSPQ=K0Ps@*QE- z^Yf<LV<$efebZ7#i@sb41>NDX9*5suGL=@>mN#pa5o_09yX&)e58gR>ZKhf)?CKkP zV8?Mhx|@~SQ=@m^KXgZnsbe}ZXKC5o=O5si5Y5G}uFP$e3q75~ug7MhGvhmhePg}D zE%i;8#TifM&Rn=KH9wWj=h)*M=ov_+Q)5FTM5y=o^nLUrAB$&m-+K84$Vd0xcW<GX z?(ZLRyPfUprhqTRYD>mbtE;OA_8t!SJ5$BfYHVTW_H9GkwyU6#^~&P%w8dtPC*$Me zS8-FA+v$moSTY7P{(%P`=pPuGn7WxxVKUix7|buuU%7sbNCv;Z6J`1v(>IZc+_`V> z{zC^NLEpm6WUW{pzd7l1dKTsv603=@uhZ-Gq7quIk*Bteks=)j5ynUo1w)}~Rf+v? ztXD_JM#GU1s+f~=Qz|c2cTXW-oQua@-7a6yL&)u(eTS}0U$(VWAKrg=vX~`AB9Wa5 zTG~%dU1)FZn9L;n&d^4&M6C0hr_W4W9dE0%oZH5yrlx1-c$M*`y{)4s+!e5U78jzX zdYgsk5MBw(`pxBQeeU3%p51RQT>R$LtHcGckUMSufZ0jNd#|s%%hy8?{MuTT-~pbd z#e5odQ>;XMQ-o_VqjZ{ZB@L`ti0TbzJgddw@&Ts*ZqJ4f0R0d0<ow{;+j~IJfPhzd z$E&xvmbl@)D?rBpWO9PIGmY<Zf&m~D`q9pQIc|VgL6CA4<tsH0{gI+XfKuODGCDOX zBWFrwgyA6dl*>6NDw!Jet0su(jpEXf=TGN_6|^JQ8VzZ9#5Di~+~|KBK6r@?#vLK( zka9qu(k)v-Fy9UHpn>_exR$qK;#)w<pgo9pya~spPqZghl)zMH8d$-=bGOQAg0RMh zLX)*G<0$P_nd3Ewo<B5YLUpdPuk_DN14-`LaH#W>7+nU`(__6JOC$;2LXTM|2FCr% zUOmBfT9i@ujPz=AA_?<e9mgjoEDq@?JzkCA1YOm}mWbN5*b=qbuvoSL(5>~6PH1%3 z7OH~`v@lyJSM^?V=Yb=Fyrp9La_Nr-HAuw+G?G1Ss0hO5LJ-8O^6l_*rJ%B=lEvNX zREenC$uFz5fRtLEtR2}7QgD{pn@lE^ilx^2)DrVK2Qh_}ir&6Zfx_uro~Z>-fx0%L z4RjAmO=OKoO~lrcN=s)-?6_1<$0h4rKU>->#;0oRmN01PSflIoh^P$^8F4r^YEblC zf=u6->Us(_HeNQ?+0CFLWU((~;$)Jy*qkIFqOr6Te98UsSyrl5E+;|k{Bo2Fdm>?W z4A2`95miOV(Z-uG&2Af9sp0$RBLnmUwnB!6Lh2i97pEqovDnRt31r24BR*nk);Fu@ z*p!MnvhvO?&ZkQSyPLF2o>T!&b{ULICT3_M)jEnSXr!(c^5uo4D4h7NaF{}EHjAl^ zB*&YfV3@GaB1uMVcIF;Jlvay991H^ZP__4Z$ffE^A}OEAwr#fN3nd_+hVqIw7V!Bh zYw&ASh6_`hgVjFTyKQA9i3X(C*}nh80Z*6jeENF5TI_WP+#4NF?|(S9l<9H=T<axE zIlf-1%;l4&nmOd{47+^h^^V_t{mZ@%)5rHdxw~^)aijYB;`u;ZdrzRVy~FvHlV2W< zgpT&_u9eAs#twk#<k>f7mS!q2-%0MO$ov}tk2kiu<PCTa9XLEOGoQ>9qS2*&`wm>W zKDB+@9*@ia=9@3>-+$oP;S+!S)&F&A{9H7?G&H!=73rK?o+0T{!0-Rox1X(4*Mh!q zPiNoo@XqOl>3DnzITy0tx?N=Hs{8!DyYIS(=>KxD_|X0L?cKY3c42;LX`w^G`nma) zg`ES#+ee4zR%S1aUn$o%2Zwge&n%rie}+w!SUkaauqYS~9+_U3i`eC$H;_oDc?ck0 zv}<e^WIyCw3#IJwBZmVaztd&Max+`pPQU-+<tv@t-L00kZ=Zc}SKszM+xNaYe){C( z`G*hQlPy*D4ei+3yX~%_!(p?_+S-y&F0-IcT|a-{?&B>Rt=UpxZg#d@uCXhIJ0TiH zQa^)|4~7>{gLJXLmQFUEf!FE{cupKT)LLFUy8Gy4arw=;^J}JhWo<2D4|O~I#4&ff zLIa(H=5~eJ5uSj32<1>&{T*yy;HDw2x?;6^8FX_8!83$TA#X3K-}RG8eQv|_AK?4j zpKTui`uEY({=HsR<2|JP-wpRR&{nIyG+68gj4-g2oUFZ=$|uL`T)e`Piq*i)T*x^B z*$tPWoS@Yy)rP)!0X33oKv?6x@{%*0sbC;|N#i3wX;`LUI!}247W$5g*J1eG<&7(M zF+h@#?A04oT_R?Ja=J@BIbW%rXfs0+$~LR5_5q|QnxMHBjm-@)PPV?<<-S`XvK*1h zG+V8neR5nLenxK_h)3ckjcYaPy0sS}r5U$2>Mu2EjITb2mm%J0BV(8Dx<)m&;ziw9 zB@?9LgVpt|=`=Dg7D(h=u~Dz0kgn4=g4D4Z<O$v|2}H8f=xQa(&U-+I7pnprp`WT( z`4i-)V<nW6UTQ0VPj+m#4z#r0XpZ1ZVS~uN4E?5zPfhe!rbUyWq9z6}e<t9%a#Sm= zo<>oPg()}XUzxO`7b%^lk24w8)#kF*&R%mHT8#u$kc)@yomz$5k(`ES9!pW)Ud&Kk zwHBg6d2M%h_X?p4t4339un$SwiFaS!0&vFFc+`}cw7F3(<vJ|3LNRY@SDN?07L~>e zrb|<}U4<Yw2U?AC(;8GJg$@tU5;C`XQYJ0+GHgqkC(>jCK}xSm7=UyFf9f>1CW1gz zbHubzSp^D3o$FU;zaqzst&~X=ayT5bOcjUA%W9xGOkxlrA(WgsHq?J(a;C34f=;3Y zSEvh{$?1&eiLAKBTz#)UGT%}^qs~8Y<<WI&CG**9*RGzqc#-H&a*_@A^f(<>yyb4M z2d0hB=Yu70x0>UzXeOQ@EmT+EVAsf~#chMiT*~HcZS4+JV%s~ig#yD?gku4;$G_gP z(P6RTy;fAObw<hqZ$$E{GCN>WBf40smXR&bW=TDiWv-&-LdYi5m|Z49_~D>rD+N=F zxxQg4BXCr%wwNu^cs!GewX9Vhd+O0rpyO<AQtx}UBvSJ~bLg2!dl20fs49~a7rSjP zJIT3gXtb{&z!IyJU!HywDtyr4_d7dt^~#>$@UFmU&`Kcc;BP+vhdx{DNB2HhC?zZ= zYe$RycmDXxBq8=V+(`YPjmnNzGLs_rEz0*#J^u7!G#U;@zV_nR`+e@2o7dV*4!5uK z`Io+u$|MgSJaOvMg^8ON9=Z3v2OfBg`T6pT-<-O6#qS9X^$jCFHMcysUMW5P@B?hr zB^3lO4)yhuUv@DOyZf%k9(&+Px6^s*!W*7o*lux;4h+PTt32{Z!^CjMqDyBlz0q#6 z?cILl`t)>py++BWPJUatJJwo#ZcnjT@cVsmbCgU_vDh8%*6BN1(Idia<K+`irPArR z&j;Bk)Ysn|TV1&}bJc?r-RU^EYmeU*n264n*Yc0u`}mj6zBsqK{Ns;*qTAwyd2gz2 zdOe*Bi;GZRoNdmYp3&hz_u=8~1gYOxys>S#AJ!kwL9)Eroz~I8KAym+a;d$}4Jsdm z@250&EN#A!7d6UleIqun<Aw3p7m6$8wOXew*yReFH`+EZ(yIu2w%FNEY#}taRw>}5 zAf5=tBW6~r!)$Xn{n<?1>GC^V{!$?aKM<g=-^jud)lpZPgd;M}O*n5L{tuk@Egt~- z_thi+JzrU46I@>B0%cf@U<&P#ZEVo<8U{2NVWylToAMHwDsY?=IIXGmp@1Dngnc19 z{^B^)7+v8j<Bkd#H5Ez>^e>o$LYmI_22DaRnc)(a@Yd!&fV!y|4C0cPLIm*}0D=-^ z13^W0wu5mSf;Lnh9L8zl=#}$@HDpwED?E~#2!=LLpiwb7D0opSY;>=HKXK9v4@9ue zR(xPoKzU-DT_Mm%+_44>lJbosfC2f*n0it}f}7*<IAZoHFhDy|WH=fCyh+88Bf12Y z9*DbpNC9rMR!T(#OjNeQc1ty%Qi{@myle_Gi|8P6L%1ty6I-$5CFHaNCq2Ma&lVML zs=KSvX-e=%6V1i9EhH=XVtlsZPHB$xk(?l1D&Boz#>jE$b2(oPoCdWLl3{d<FnMIM zftrmAai;6}*^FaWQ3L8NW+r`7wPI?w()^8jrCl+Oa_zho8>>cDn+vsj9&dNW@AvcK zqYq<bT2CfC9<SP4S6kN*$}Lm{$SZ7e<>}w3v3*^yR!P!C#hI2mr;p;S;~?BRMz>nG zWzdbGzb#UN#_HXz#(*k2uxTvm(N}ae?fq9DnYYq#={-%Lf|8A!pZyJG<U8yx9U`17 z<umn4p}to0g?b5~<hnpG%xGZn5JgQ{1YKluMaq}uSkwRj|MW>jK~y2h*~nlo#ta>$ z$Tw;OO|yWSqiM`iW5|pn@0Tw>l$!G(Sc<K_c=}DZ#p1G>*$yf}S#E2cS)5*uEfN~* zb$QABTCP>rTQ=D7Ay8qxwgHobJYReE?CKvG#(k2=#PP?Q+uDKP#P8?x`0w+jY^h#a zV@u8KblP1mHN;@fjScizydEdSdKmVEY?7m?LQuN}g5{>hZ26EcV8W7EFLXtKj%0Mj z@LR7ci<ER!>+M8H*2|B7_{n5vOT3=$clqk|V!e|2?5?N&%AwCC%Bg#{9oej|-B_Oc z+8fW|)ZgB}r`Fc8YjC*TZu#vCU$<{;_V*3@+~L`k@d5vs*VNh_9{A>!SM!C~lVf-J z?4C-!8nXJodGfXSmAOPRhG)PI>7^A>b(Ot26b#;V_k(AyUJrD2rxPjIaQk-e?&<A6 zb?*Ga!aSaWk3I8a(OCX#&wlZa!v~*!;=_e}Wo2PL6<_grT<tBkcq)@E=J8>}U&qE| z+wJ;|^LO5H{DFI)YPZ@@->+if+UyrDo=4Y`AaIgm)hkeq+V<@}e9v7EY__bW(y@TY zefiSWt5>hpH!AIL``0SR4j#4H{iRZcXI+7SWk^k%8+0S;{jAMwA!oDLAW?A;4N~-P zkL=&;^w>_ExN9{Uom-yWy<=}}eQmUFpoS2Uxpih?e9yr<d{+Ot8*hyD5AGk?-RlV0 z+by&4=;HiLF+ORn#%k+r&z^gI0AE0$zp!_tf3W`x-}=g6|2D7PP2}soBgfjUZTH@B z;^DjR@9pk+<Mb)E1(aIR+ByREql5jy5R^H#5Um>?)5V30B?6w?TXV&dr`_gjw^a$i zNTgb-buXa+W|eYFE#0;CmNqk4=<>xZ&+_%PGLgzW_R^{4QZa)kqE=%f!9|33SCeN7 zziL*!AseBe;SCr52WVcup?>98e&zl0r2C+r@BJPS_})M^O3tj2vx%2I-;J180i6QS z1y>2JLcH~IPy*=;51g=H1VRb6mXqajDbPT=hIf!J+*iy1P7rUgxZ&jz!6<L_q~3yn zQb|qiAhKWOh2@B_s|B(c28>~oNWxAs3W++Tz#1-;8wrBfP*u@;q#^POr$FOR!*efY zOcN8U$C^<&;~b+;q)~G6TaXPXPg^)r;jM0d!$Qz>kA}5i;8E3YVk*5=GG9igkp^{3 zx66e_C8Z8cn?xHbMue*p*nunAo?Bh8xcof6xv-eaxP1ZgUeSjXLI=X!P~o$hZ^LVh zo64-vaSn~NN-}nEE{$H&G<0z~s|pws(wINe;kVUOE|=P>F5N<TGBB3t;_KPP^lSL1 z4OlECG`m!%-E9tEW3brqFBets*&K*+uhlB;R%j<{rEJpb1PZVRt*BpmuSS_kGF{== zkUx?tlUqsY{ncubNJJ`$ixfN}{Y-ym6DyF>N&JIn3+N1wg{#CW<sXUMH3o=F=t<Uw zs-*C&bUO`5E^|rMN@H}HHd<g*x$33W(znLEm3bnoPns-8L_1$G?$o%eodg_>$~&lJ zm#p<_iKO*TUnehbvgN>~r571}u7)T-zqrJAypj&PW9R4)!j+hI5~{01C*G2G`7P6a z>oWL@^quXM>E)&C(-X1ys?*Z35?g^YSXm?BI62VMM_eX)^s&^E@Y<2I>Fe!6f~B@r z;b~PbSI|XSO(pGax814a$Q0L$uxxzqHZ&|d@>vXlIuiC+a|F4nRL2&p8U;m=*esOu zc9s3NrCzSrkgOp}TR-=GNFtW2>2#*66Y(MwI_~LA5gUL_CMJ8p<M%q9NLX4&R3@Xm zr539vQ;DVHqX$1c`jDkyDOXbVVxhmYCsxeW+c!r0b{^h+Bw9!#vXkB@zcz9H?)}H= z<yPND`-vS#mlo%(4$oIkeS4!)cyMT6B-qVHnA7Y&dHM3Iuf7V2KY@&6I>ic!XVM5I z^+X~_ySRMe{-NQe<;BxyPNBK<#6wSQwzYig#jh7K%fsD0Y#*GzaUtY(-EsIBS#1dh zyL92q@k56{{N#r%cF*}6S1$tAeSz(xW29GFT8tueW3rew+s(6cQ?oNSmSfQ~m(Jgu zxQ6=vz8(7sNSIrh3j{scbR2JYI$hYa<Ip{K-s^HZR^uyeEgO|wYS-|NJ-ZGulou{t zPA1c+#<N)2>tIokkOB5QWGB`WIp)+;!qf_p$?x|(^WhJT&)iJsvSi0yNyhFvd~{-Q zvSwQU`fFc#;+{uZ?A90Fc<G+wC-!u0JAL6i^qniy(>MY!9)=>F4Ax>UWi#1_2S;DK zd3iCrI+IPrtNCq%W6P^6OrAUT9NIs+Ctc2d{oBt~iSk)n^RVS&Gq;#FRx(TFdTHnG z-HV0QL?s!k##=Yq20i^_-adbaebCd}T3zdCsdd3^a@uR9BGJ#-GfJz>WJZV<;O=$@ z6Y&MSJfZMlv6RKDX0yB014F%1%sSo;@Q>C}N$;uhl-4_$>XG#Ul)v?K`vB1YMS9Zz zskBwz{lbfok1$f?BbZWvLeqJPdmB%@!nkq{zsfmsegm&Gv54RjO=@SuU9pM<ng|q= zOAM<(ev&eqtydKgpSlK24UrtKqMim!7rY`Mn147~LvZDNmohbvNHtAZG+=bT2x`Hl zs^sA{n%B2dS1FZx?c>z!d{u}rh>Qkqxm^Q!8+A6$QRu44FTaJwoAA^)B4`!ox*)Bs z$W?k(y22=yy5VuB+8i;W6a>$KCZ(#XSM@ap>fKra{I$~gGH_B!z+&S|GX#Q*Cue4D zaBfH~sm&@d9BdOrropl#k)(2TokUJkACR0uypg%2bPw0pA!cxbgeCAr;uf~f6G5lq zWLE&W`H@y{?Gq_My23b(%s1S{tYc5*xJpT@_0*d;(r=PxdRL<-CBQ%|3BD73h<9AN zMa%%@QHEW^E;$OO4$^zkr1nZ7kLa7Km^N~hEz#W804*U`iuHnEj+g8(ULU#^sL^u- z?=^c#;3@!<0`9GCHm65sNVSqDPmL-Ya_T1iqlownF*TO@>zb>Vq$q4Qddb+bP-kc{ zqb)g`r2lm#-x63X=g7Y@XJm0ns|}|<>qkjpN_e>XSLy02<?>{dUNu{6$<;aPPf3W= z+w2Y;cqo|`ipYAZ6|EMRQue4L6CRBvQMFW?7@AcjOVSvE+vfJ4$}{i1b(5t;{F`sQ z%0}42%#6$Cm|mRi>+T_(qf#sKzx8UFhh{vx!qC7DhxiuD&G$yS0;B`=Xr@z#X<>S< zl*w5-+Pne(p8fkaOdGi@bnQ~mM?NOtajVDaNXAz4IYe4jt_kS!W-GDUEb9(3t*w>O zBxC~?DjAmf2IB`S-(`2zH`fX1WD+25ST6F+$?e!a+}_a=UtMwad;5=#ZgzLLZMK=z z3d%c=4jp`Y`%_<e<?EI8(&lO`y?Qm5Ng+V<@q3^02Asv(ro-$`+BSdVh5zO-BW)h^ z_=0e1Qu*Xi*XZwG_*T7|+uyY#<n$NvagW_Sy_9(F+b?0O>=@ob9PW<6?HC?pxFR<y z{R1PsTCQKceyN(vjt=$h+O-Wg@;AQq_2Itmhwpjlfx8~OF+2Ur*;ji)!44Dp`fXRo zufUw&y=Ql^q-17Joj-+-|09n)#tzuaZ@xM+KeKP&;jz)Z*+M<GvJ&!#wvUcDJ4}A3 zeRg5CRL)<%c?D77?ISzLhkN?WMS@mI!$dSHi+yf>c5GzZ{YUTIF}!PbVd1yF_}^PM zO(crq)kt<^(rmjN?sgM<8nt{e9|?srx$IzHKQYXmo#D@X;^Sv7y&g@hu4a;KZ0+B* zw~|eD4-8CBj9X3R9lMWAUca<yS?lv}@A3Ag^U1O9-jF-Usv^C^ay&be%w3<kv2FLk zq3$8xuQ#JNSF_7Jc9JBsD;M_;?c6)KYj$NW8dv4>nD%@9i%ZLqNasd--R7_!IdUY| zl3z|mS1Z|mcfZf#>34T^+rp-`wwcMRspQ<gU3&++2jFv&cciVuraTj*&CX@<>mzUK zaCoZh)g~8t0OG1AUVtUfTU711vIkTvvBayDoT&qDJ^Dk)ngIZC8R(?Mko`Y^_4*<7 z0ib_xJ&WJhwGnJ2cuu|uybvFrY>^9L#z6TR1+pd^Z)F8T^*I7|HC7{+lfq^ipEdr~ zg{#0p14hU##1hc#<wgZ4M3A=vSWSwKn)h26^UbRo?tif>jI9G>L<F#Mvasp}q6vcG z(ImVYjwoV-QlwD<pi-2aqb(fZG7*!CN@RrjN*8I!*l>Ircf8G?Dv)I>?w2mw>cSUf z13*`37{SCQ`j=~gbcCgC#i<6IrAokP1MSIiK7eKcOzPGO%r(N74cH|3SQ9$8Xjv+z zhhm?LC7}D0L2rfq%>K2?6}7%zE*4ZkWHt?dx>hMGFo#W5t12E&Qy_&_5DF$FoY}cq zN+a129Sen;Hi}q~v{A6AAb1XH!n*nZ_?pt`{MBfb^o9ZJ^>=l>m?Z#Kx(GBW1J~$w zfxXQOjWIG#kbw}wy^I2_M&(B5jZz;#tcvKMPs~=xMbPCttWLQdq-0)Wsy;e2mX97l zcAS;SJ&t)jHK~;)olfcII~1kW?og2fS{##}QQ4-LnIN|HI<I^@XskDFFfjKzG`PQI z)=FRLeFhyYy9E$S8`Xfm6BkR3b<@l?CW*`eKC<qN)u-ZXb<zX51-F;w&mACV(?E6} z>PT}yz$3qmNjW~_tIH}dU7I3Y%m1;tk1`Typ43H4E3sN#g*N(qLON1K8RKFMiuC{1 zKi?PMWxaoYRaMvOc#&8xdujYe(CM0;n^{<1KzGsUw9ZH87za2laLtiSSzej*`MYxY z5<qHUX{N)p>9ncf>~t<}vA5YA=ItY67y!9!Zh3imeqqtnV(RZ3Y`5DMW3hZ50d?%d zHWE}p`N*U)nM9_gwvhyEmddEhv-QG#h-Kc~s1qX#V-EWr&JTBYI9*VvRFG85y2l@~ zTV3@Ux@T)${o%fQ_YMyXeq#3{clIB$R5uU#hd+P#L*T^&BZsV&w)5A{U7k4Y_4cJR zsh-a5{ozrk%bl#RFRjizvisOGN1p0&hn~Cf?Hdyp_l)kFPiKDjl|Q&|<iP%sy_Svk zpf@<Vyn5!$X*boivLjI;SrW*b1zsu?u8m*q^aY3kn4F)))R|qFw%Z&VEtZM#al769 zv1dLz&^vf(^4c3`Ui#EWKX!26iA<^Z)vx_=Hks-j9FFvk6pFQ%UU`0DetiF)-J{!f zCDMgUm#zZD=N1<Tb-jA^{M8$m$&uXCJJw<KU%h(SY})wbhd<S3w!L=dwR|G;=9_Qi z%H`dA4%i)p8n=Gqxo?ok8(H_Nxx*6<PR!n%o0*002`8!u?WtUb+r+BO7Yj^&{tr)l ztzLFJZ6peK_`y3f#dvvRV>Pkjvit8ia4Z^MXtmkD@%lH2qxtBAKXLNP>1#`uofh{? z=TAYx>S!?$Fbm}=lgSNq_0B9Vcmu&hyN_I69Dn8F8@q;f+<D;cZf{_Ht$K0(+P<N^ z_Z&R#wYUg<e(l1msam$&jto+vyT{jRZ_RJy?>}*Gp|w64ohr4JGPQ!0mq}Y|sKZ14 zuZ6jpcy#u_wz1u#yLi<RCqpEBG)7FsA_h!*2ODu6m0C5rGEHQW*GInE-WoP1qCXBF zn-x5R*K4Tps;8xPbl@7xcUT;_0C>a-!E)<*zwOWOZ#BJtulfMczkkQ>y;yU3Aqj|= z7j2X0svP!)ds`fM%45eXU&}<Y4h>hj@a8E;c}aCrOi>+?BLX_N(s?yHX}Ad~N2m^h z*c3`@QdXL{O7hy=O1H#0vY#NeY5=$<k`ubTv8y1P4~Ctfe2u!2{A=JFDMyMDpd(ia zy<X~XKxd<#!gy)IQ$>sC9O)VHdJ@#Afzd5kDL+vHFkLJM>2tmidkQ?#*?c4oR0Al$ zUD14Wt>4mo6iOj{3>(Y<NphiaveC~*Rpm@zHMN(nR{u6aWE-w}6(tG$QnD^;R;Y}j zJjE?2Hy0glFCZQYieg363KjX<=o}i1oD2SG8jT-JySm%Z&ZF9iL`pN7)Sd|gBnfo& z-36&P+9F@1>04W5oFE6Kje6#+0k0V&_9YlHNm6Tcoph0cts4F}g0J;Kh%iR9t~Mvs zhe-?a7R&9{-3fuMSFH}W$!uG%RYl^4`JwKj%@VaEp+5{a-AE^7b6MCX{14y`Utwlu zTJ<4y+t?&$tO_tKSCpN`l0oYmNX2BcI0!c*U{MTR9g52CldAl!X{iymG4wJS^uL1j zZ+%qXYR0@V!344kf>$Q43Xr=+u;CV%Ba&8G6NlFM&TLeYqtewIE!kYkrS}uk$rbtm z7of%FcDivGV+eJ)y?&hWm{r`A4s;-~(ixhZS>QhWd0@{@q)dfuvvmZGrF7enZEeeY z{QD15bFM{7{Oq+W*T%28Y<9v8VY&BoMG!l60$|M@%h3hmq}jSj<<l$4IH?6-P4ski z=8GAuCJaDALzyG3n{5DdCY;Ab?7EBnH0*7V-00377yxw`5^BEHQ6GW_h14T6mRJ$u zUr8TT%oZ%fZ<H&*dmeX0I~GaBVCnF9+DAvi>uqbWM=U0C!M3$ntx!h_*^Jlc*z?HU zbME@Fo%>rh+GgjcKehjnkL-M?gWy+-ZD*jr6D9bmi<tsB>DKN%^yt*`{Os~{q`Uv0 ze&ydC8QlKlu7@MGP`5i`Hnnc=+PzXMoF6|Mva~+7>pmjTv&A%$s=xQ;KT4)jgl8~i z$?VEAb#`$so=J3tI&Vzf3<mu8=h64%&$;C#LNwQF<(t#jQRG}&i3UPFC(oSPJGSG* z{$tZiE3duzI;j$@9UZID_$#ly4n|L=mX91geBjXW*WP&Jn=gE`RxTqN%ag8D$S*E0 zU_zA2m8;h-Wn#-gujiQ$eJqj7eCbR7^Td&3!-Lx{UO%_AJWr-AhuQV&Yp+brOr%Jt zn@*xWJ2^eGbNhi4NAF)+T3U{-@P1ORi}g(g1-csfq_X)e)n<Fx>9BnA<DaP13iHtg z(s3~;dw1_*i(_<T+eCEAYcfCb@F#A}&;0SpZ}2NmqorJGIUAo`p6?2F*#fS$_2SCn zd`~Fs4f-cjv6;DPldb*I;>4MmiJ-rG|F-=*dPh>3)vvwr;>*|0ctZY5t8<rP<1U}W z>vzS=$&L1n$M1Z!zpwA=;`NnEywz-icGcqyMjXCeI#tf*I_evPU6Er4PB1_qb+Q`F zFV0TQP9Qc9j|kEr=1MfW;BvXUyGO9qqpOn+C%mw*+FM1!3t4(IRDYs1*yJ-;OIfoO zDvkw47sNucrNgl2iJ=2z8?P#P+P}wF`j4o39{~CvQOEv8EY?^>ywSyVD$qo}h*-4( ze<JGFV68Oh>~f|oMY)78Kyw3v@TXvIeiAe<KW#;^oG;Sy2H{7}H@xW-B9O({0T7p= zQ3%CK;R?hkc7WnY=&AzQm2#y3AVEa}VuV_wxipOgw{ngYE1VoLAq1C8GlhoK#E1eB z8}XfD8;F0DOE@!`N-B>`voqzsoDWV~SX|&i2A$oQa8eo0C6ZEVVgOeD1PDrn<)GYD zz?@)lFq5G-FQ?tYZTd{ZSduz4?z=^O$S7IHNKlttr4ma)Ng}V7Cc)Dv7`iH*lI~bT z;zq(As0+f?U}6<7TPkS=wjw^^wnaowovsI3VB%J39WD2+>ZQ+-CP+1nC;lxec@wg$ zpM>+p7lzCT-jMz=TB_Qj3xpPqHK8<Q&?GezQ=zgi$rwqrH>0CMbyZ&Eh9Hcd6-u<5 zma56D9Oo*@4n07D>NMR&oW{l!6evQ)Ku-(vbM!7RJnWW4B92KmIyy#^MZ}X9qKZ%d zRO>agEZLIgPi;jj+W^~1TCNCA%5ZJ0ETcKb&^Je|!KJ6>hVd-(L}r3~k(0GK(6HII zPCxFh6W=PUgF(czi1j6D(d0_J?EHzoin3=EL22C`=;S7e)kP$LRJ63($6#y7#FkDf zouPBcM2S=il|zsuk;()EUM1AiToFc<q+)M3!;I>^$G_ZKP=CUTa$&w&Ie+!a`0Ui~ z!J)aOdG^NAxg<{@_JH!mR5q7nt%QQzK<v#{E8BqpdQg6@oT8^0SU{59<}4_+C_JVW z<{`u6^|(Xf5cGPe4QP~*M7CvZGZF|2zEnIzVq8>Mg|hfuR!6|&V}2q=>GP60KryC5 z0e`htaXB1rH+-11QY~C->F(~r1b10&n|9OgyARj9?7e}mwrZQlV&CZrdHj*zd*$0- zdH!4f>l<IMW(mGrCr|LbhwkYPMgrmfL_NRmY<u>~*;+N{w)=bBT_meZtCSA*jn<BT z_v~+XTCJZs{zUs)N4An3>K}dM^f?kCx$TbGg*oh&Xfh#_5cWI~rAmOu<xFN%4x0<l zH<OTEqkJjPigel?q)eKco#pYgZTrp+lR1^kT)uJ{?}c)i6G~7l<q9c+&`F*)K0Y;r zY<#_pBZ`20cGcjxcLqAULtVU-DwSNNnt$ZcC%StFUwh+Kl$y2;Z=ac+Sz3u>_S7nQ z6t-|@z*EYj`04f}5u{9H2tZqnrB)W^Fqc?UtR^VvP@bywdOAz+afQ$bhr@E>&O6ZR zY3pd4Us+<GWXI^X#pt3d5{Si9uU>fNsYgGYDQtf6<d@hUDVEo__l+&(5_gU4TP<Zz z-aNmSErxCW{;vM+{vo#ZUc2@N<TjGyU0k|SUeBf~8TJ^x#P@g{2S&Er%;syeH`mrn zA&-yzU(3Zb3840k?HSv#{j2AmpUun%0)e^Aa<41WYY(|v?HwB(8-<Fst$t$v;h@`7 z$R|inOg!~wo5kzztP&O63f149NX1D;5e{}CuZ7#*>+SUUI_VG|R~xkg&k}3^#TYE* zYt;fc-hz@6A$fHuthg_Ts9|%drq$aT@1yT~5&a3*+<Wo#4*>mpaa7*Fbut{x20#}8 z-2~_gD{Em2B}ut8T-89j1~Ep%)&@KhlVA%9QNCC}wgR9{RdNHj8OTH9r-nSGAW<p7 zFg7&cRtl9{3m0QUFp!uK+IiYgxsjBa2CU%=HRoT$^==d{a7PIAT&^{6Zb|V-i<;ea z%ULcZOI7)B0>~2o8d(@c;AQL6itiq`M;J;5rZLP6!`d+{7U_hoDBr+p#up<rR)CQJ zKKWIAw34YxFw<5S>D!>;Em=>Ij-l&|<?>2&mC@Id>dIhaBiYJ(T{tCbyGFK9B}kf= z3wyVKLM44e@D_invCy@lE0wV&riktoX%`(X-42cfTW~@uowAs%^u2EWtsn$xm$Xs( zThTE$HxXE*$C_e0SX$bx+*EFn?ob47?cWwLO$4?9Hhjb_P33V&GhUkIFSHQlYiB;H zm<`UaR_KCqUO`m_>ze_l+(%L`aWeAWSPVGkK{K32;k;a9vDm=CfDWftdrB&al^T5F zNX>4C0}P=iiAu+diDALkQH|2t^3=I83QZGEy31IwGB*rXk~T0J)|#=Pw$2<msJr5p zekBJX7*Gwp{8i`BndlW#D}45>opgpK!-8wiE0Juo)8T?h?eqljy=CG{W-FP9ToAEn zj|@6i4LymNCHCFy!m`^%mM#_g67>63i<Fx{#}B-9UC4BO-#ta8&flLk0(au|s~68* zzZ$f;u1{Ve3u#xllZ2)iQb0+SptO>wlb2RkP!A#!(d+PZ(C46h6M&x;gu1^6{2lOx zv9ih}?nQ~Rtp!hkdc<wkf+7D#i)m#!UM*D%D%7<OIL6p!`mu!NF+p$$2Db|BXjS9l zMT@BoT1aB8){;pP0$pK-krxD|6Z8{vwM==fu<yvedmg#BzdPLN3U@jK-FEl!kz;43 zuf2NV<m{EJ<y_^pi>Izn+=xe44vy{JF?O(2Nnt9SygA<1QvB-={kYfS{OX10PA^>U z*ldS^_N6mlBRc0VANz17OH`<JA)b8g9GdYfsQGjTL)3Y0d69Y58|lW@9q8`8IXm6k z)lKIt#a6mPJ=t8|VYP#m!T2n_pf}XfW}aW1E>sF2_{HVL>sN2gEX^_T9cCL6Kb+iQ zhR?lLDXo=C8Re(o(YUdOic8CSowx$DJEQR!$9a1=oStH7?c|wr@l@>NANe@>ZeM== zc{GIz#ms$o-Tm03A3AsbJo)2B$3_(QDXH@EcC@aquFl622_8<2CMg1B<C^g+lv!dt zquM_4%rkx6UC^G2)e^gehj$*Dp1Hnj@8Rfb`uw#wp1Ajk)?m-`r@o#k#P<#D%$7^p zO8M~E?pLPIw|1B!PS^gvL6_OI6kGht`4=y)OjO&7`OSJX5$`m+cK3`H*3+e0@$kr@ zT&0-I<+}ah{X?T2w)R3MwHTWxUgG%9Baa<?XgoG^Eq1fj+`gQTM_ir#uC9>DV{f%* zmJ;mmJb3)Bu-gf7XnoVF)Ku3tN{I8<*AS_M=851EuV9`J*!;P?@>>N0-RORT)z|AK zpnSQQM~}K%E2$uyH9`Z{Emq=Z_zNMg65E*QT{53F$MXAUtiA7^72m1Cw<PNR+%)Nf zhWwfLfN;tME(i!Pz>^?g0Zhh0;n?tc7FaKSP2LfPD_SFOl|&O9!$DEJ(Qv9E@nPIT zJmr$yhcgA~%CCZ51mbHJJO3qywGmd!2>=DHg|8Ufa;+c(*;}}+DDE!CfB+iZDCNi( z7cUfN(Vl<&@yDNi_SxG;1fVIVf`AeM_wpiFqKE3Pio~n}F;#-kw|G@=>(aN6brYd# zxF%>-gMB&Pz+noZHbNK;WG0YZmEX)O)R3rea)IP>!zsHJe;77{47UJ%&X+be?yE69 z-(lFIT*-Oycq|YI3jXFy6;Y}nwetKi(Aonn_}Qqu8V<&Y|5K(82u1OB%E;}3JXDYs zc}yY^2~i+v4M#|<I5RUt*cmF$B4#R>UPe}$U>xVWR*GzcYs|HhoYiQiF<qs?GVVgA z;=7LOW;QnXDk9V)lUz!WjVXnE5TRFzR9bSWsLR)h?hUO_+sA9`Y{THyXM$3ivU6}f z)$8QuLHKXmwjJ?AoO=QBweAgqZfbtoP_-vwLEA$>D{^`24j0iRW2Z>foj+v`G)y#Y z2&v&#TAYT|lG1xt{li9C)BA4hu{1%yDov(}`of-=3R6(AC5`eoHvvGZIXdnf$#aGb z^GZdy^1=>6%te=@EtOdHxV_o*YPp!{>KRSN7R?S1IfI!c#KmI%@S4ZdxwyDwMf=9- zSYAzFA@y~IX*)ahm>Xhv)5-7noO%1wc#j`3mgl>)MwG0--q~Z}yms{>h7=oBFTVV8 zYsW?)<U@Qu;t$R)O^gnX)+)tI<7Ydpu0*CxAZ)&rgPDagVi}iby$VwAiS)3JlDX7+ z%eqZ-n%5Nf%uMtmN;2&hb8)@iQfrT`q+=_IQZ~ng#-A;Al%hGe5z4I6Cy{Z$7YIPT zQA**PJT^=HeVxm(LOO$F>N=^V%9WPBp8iTb*BNn#MgpIG?8gRn@64>DNxGhi#a9x` zj~sgZ55M}gKm6wZGFLZ7dqx+cD?Fu#`vzu~r|;T#*BwWXPZw8E#Jpp;cRIRoWaP-$ z(DvnQ(r0rZC;!^Qxofl6S^jp5udj1>^5zY4uO1lQm0pa)5hsalI2g`mQ_RU+5iXy@ z-Ql7WZq7}i=1wv!yM@He_PM1+D`b$?4V%rC$(B)oVqFt1%#teCs+ieJtIH_l;IL<T z(SiD*rko3Hn~GJ)Mw;L2!c&e>;jq~08#<GBTW2W5^33E5t)}&Xp}`04eRO^?`r7N? za#<}OdFq){7tW1exthu*KmC~>^M!g|dHLkh>@3@H+_%7{3ACn`joz+sEVj(Ufufe9 ztAl-=+jori_4kk|7D3ESM?0(`kI8Y*k-Mid%U^%}n>~K($3Og&|MqMD@0z(DPsa}p z>}qSVgq@*uRb_nG*4YyXg#Y)4Kf6}W&t*~*%X216`^D9nayB);I#;Td4s?yVY)&WY zGyZTXR}2LDv8_8j_L0t>j@FLx=+sIkzP)c-YAyf&p86wtyw4c{tyin1ZcD(k;Vz|W zL`ogqGq%0Ii%uvP0q$#x3Rqu{rIIVLWvi9NZuNWoxk4I)$7Zo~hPp$+5RpPWft1(C zWT_P6X#0{p*zWLYWeVn7V_RE4<yihYOuzZ%J-)#I6sq^9<e?|i;V=H;FaG$C|M=hg zdw=h%U;S!tZ|~UH*q=i4KDfmX-UDCz+Sfk&+0Xvm&;8uL{kQ*iZf@@Q@#Bh_{Z1dj z!NMu$i>OV@TS`usF9w!15Vk-fab_Er^QXww3ko-4TMbO9ea%Mfqo906dePum9P<sg zx>ylH#1~v{ygQ{3fhJI0KzADYG<^12fxh8=--=%a;;4X24Opc`ayx0MVGsP)Z~fNP z)YNUg^$-5RKai#gIfSc)&m&D!pN5#a`eO8(LSl_z(*_ciVl_jWs;guh2C~`O?b1v7 za&-??;iijS`c_WXg(_(i<4<XtbeDiRIZFmbj!X6AyBH@%g{3!S2SW~KvbmLLEEw?d zCzy|a)0s4(QSn3qBn?1E+aC27Lh%6T3MI1*-O{oei%~6H;MicZv$HGFl@y|Oi8#p@ zaYV}i!7sug&HMxG0^+$fvy>6%F5xhu<{OajmAATCVQHFliynf;ln~ghEKE~74#=(Z z)@Z3*E6#YnW4v)YHPwa0uN%t|W2Wh;r7avK?xJ&$sWe+{7OSI@Pum>s^=gqcE{wgJ zwMw3D4R<35nD6k&sZ3{QB%4ih;qvklG$f|D&*!H=HaakNs%tgbpkQ`zTQM`3T1t{q z4~<MIy*$-GD;reDH`4^!e-KMUk6ly2=B--tstGF5l^SA|p|;7q!rC-iCpY3W_D0yU zU=$ccMgie`7N1TI)s7g5TAq5pgF2H?#_bIf=uH0+N5QUoIvJxFJM?;OE935k$4r1G zOUv)|B+{Arg(aFsq9X1^4;wpsGRKT*FMq!8KE_IUS2b790|Y)=rxzC%mRFn>tJ3Q) zq=p9v?J(f&&i2-pR4&FuVq6hQ_qf9VO}Gs<hbNXS%*-zj4vqG7_m%N`XH#@L>7dv{ zA{4`Bg?ZAxR;k#`RxCCs^SNAgVq!LrXBf&(u>`vwsU;Sdv46)}W7g@=jt#4gt*SC| zE}ao?Fla*ppFMyzwl+7{e10#cdcIWc8SMP@Q-5jb=<(k?_2vKPx&NL?qyru9!$SwI zUb*q=8*jKRj$A5hZ!>4pss7GxTqp5d8hyl9-*|m#c_|zU9T?pY@s8|NZ7pps5*O8~ z**a;4?RRav!`y0`SiCtoca6Bx_3HZE+#~`?bMy0IU+2ZkHwJrplesKR52C2tb~2Z3 zF0Rh8ebC$47Yc-#<8e4S<Y=>WWK~>m8~X{6_?Kg=*p^yLR_&p=9L`cXgZ++9zm{RO z;!Hr;o<|uy$x@chC8BV7YGISJ-1B<h4@m%|LgUH!nX~7oXXf2**H8ZVPlL11ox1?@ zX7`>$WQBV5<ri<<xXyFfZYKJm!{_ob$^-xq2u@59Od+?+zP?!>9O&P%eOpU=+r?{_ z$us42di*Ybq`&9->NGZ5sl5DSPk;UoUwv*hAM-e!2L^Vf%jtn|Plv5FQC{*|t-e6l zh@<E9)MdBF#|xl8+)WI0$lW<MFbs7no5*_X-u-*;><ad^mulD*FTVb5)IEp&;WFAi zwM{gFb`I~1l`=1kzf3cOwt%zU-rmyc?Qpc#+6&1lS%7y9cJCP-;CX}f4ecr#TZrd! z>?2fa__LrFwMul5*Bi)W6L{?-;a;zYG+QJq;KfTU5Q(Mm>9iq(gC|~|-nq=Ge&F-m zQ_q{`dTFGvepjpJ&-F=v8XkJkJbubEXU=TxNnrhxPd@qQx^MqHH0}#u_`+vC^O>zJ zL7nRK>C@l6ZKB>NScmtrfLB2SB2KdPa(N|hMWTYR4Ui$;YjK5&ogifjlHgw<#5ZwF z17XW8cra+!euL{GxJr;2MG3*(@FGiT8uKZyjCKq+kgJp?3Ork}f<c?+Dq&8`N4H(s zGfeWgd*}raZv~gP^=HHP*$fhp-Y|MV%9pB&m(Doy_HqPm8^?{CZbkfC52_4&5&+qZ z`+Uop8WQpxg|v;kRK}F@8y)*r863l^(F38HK&Tw7+?CZ>S7%tO0GUAN`is&nC4daK zG=3~nsdGsJwdhP5fKKi4yZ80=6Akv-YbS%j0O$~=@6hlNXA*da>Ob%TaIb<>@nD7V z!;u3gkK+Ks1|<OZW!A|&xeYdLHA47FED&SQWa}l3Ye|PxE-NJ*?IVZgu4W7AVb<7L zQtuw#@k+p_kY`G06;74bbnDPm@=1%+zqwXLR=LgMWXo9LX=LMp<2p%`jt1F)6VEH0 zYay<Hk9q%jJw6>M><0A<GFElaEdmp-)!14nI^BU%F{hHPD%Bg6fmreEN!g|5{U-e; z{jjx45DXL=Qv)jdHtJOA7FmX}WMo#;Kdc(VT;Vj)Y?WopaXOzqXRusucW1bhz9P3k zC=}uZwZjHLtdyx4+gXt2$@H#fkjT5PZ#cbSy9*W>K2Y{8EV(>x;8sKhac#y^S!C&* zcG6Y$Q+xQ|YSA%RTk=TU)~?%@!+ZQssr;Xy3EDGxb!sxnGRfqZRu(%09++0KOpJlf z<x}RiO^eyFl31zZm>_U)qkVd5mSZo!cG}wJm|L9Nw|D1558XR8cMb2UawNC4BZcGO zvevT7>bZfdezQ^oO)?{4;B-Wzu|zaR=r!r#7&S%*zKRgKz^|EXCKB#cHfifR5D=rT zT*){c>m-R-iIwZ+mO$9sKhnLtLbe3g=RW(1ryl$0Z(e-%E9bsGVmF62t^M}CN@=sC zf>*1vi_6J)3W2BnJ9eGDavnRu*M<K!3{z-+C7LVekMBL)?y`>d_wF6-^I@zO@-v0( z^+fW>(C(wV4nY&2UY)u!IkmE~66|z&)}50#XRl67bp|2}D~p6$rgHgR+jqpW%WW;2 zA+H~JivJ!7MPg)m2-!$n4SS}|oXeMcf*~F(3<^oOQn|Fp=}zZ!PP;jtSYjDk%?>2_ zNq@`GVfGM&K(t7)q7rZgy#dhxaN3=TR2I{eiRyAXk(h*RhCvidr3pW9AsthwB+_x0 z$9dnq51l)AZVJW}(Vw-o!LFV}Dpf5jrDGm8fuIjtI+IKHbcIMAfC^-*rFDK~k<xf( zvcP-$d)dmmvV66cP5;7A{jD?CPW|@lUtmD*-hG_aOkTQjd+U5**|J%Gc!+?6;Soo7 zxwX8qyc%|Q#uBS!sv7JWxjb?4o}+h`OdH>P^@UKlx4*l45YfywTYP2C)mGa~$Nj$k z6+}n_oq=%RwaHVLQa9rph4#8BY;yIvJBQqnh1sRp?8?#YqxT=%i@Xs*x&)W;K+6`3 z`RXQFwzV|Pn#av!93!wsf;pZZ0dD|~mVye*8&XPH++>ZlJN<Y)m|cZ@T4h7?h4~4R zzvw>a^C`qGRg_4pB$U;Wv462Yw*&fj<JcG(83ENj@W2C)Jo3o!@bLHS!2kFk|Krd9 z{LkNZ8ih<wPJYj8KRDsfwg*5$=%w6Nhu{0X-~05ZKmCpsGu}o5+zo9(z4@-*+49yG zCId$}1~o<Ci!M<4HnzUfv?b6GZZ`m#KwI&+i?v`tZ7~lFPq|S^33Zif$gTNPtOCJs zf|xbtP(h7qdry06smxaH``a<S0gnXM7%NEH{^+BRKKI;nxAhfe>g|h$)Qr@}K#*Hc ze!ItA(3SS?n;Q9mZV|z60sXCo$R%6h!aEuO3RB`r(*Aofc(xh?#-K=*gd=Xa<PF#- z{VCmRc<2TA@<ICqVmY$MIA#!LB(@cTHI8sD#|a0j5EXx1w)8VH9k6963NLR@Z?D_s zVwmvI^DF%<1KQKw&Hd`N8s)IZ&HEDHBs3m!Q%0jvP2Dj8>ygUQxcn9oW$S~^pxj6s zL7&tI04+VBXJtb|L6@PrQhB&_OOfc&)ECuVs=ZAKdCtnD(>A+}OW8V5y{dC6fvrhf z!&_>tQmmEJR!>CeHxO^oVwPT_$)Z`Qv&O8WfHyk2P4`ThoqTjK`uh86seoflRke>q z#gw0Zz0K-gE8{||sgPUv^z9AfS=NY}a*A=J79Iu(tB>B6T)a>wjA1gSiU#*;U8r{~ zROyyYym4%y@PE=Xawa7!@1x$1;~+yrvE&M1{=<UeB(mNh?GIf6q^|ZoS~s(qlv3%j zT8o)D(s*mtvcIz*76>~PSVVAa_)3+aHRF6^Q7%SfyznRI7NK_U*|81VgI35K`%c#E zZHw-`|L30!&};OPEfrrl^+sQ?^VK(B>+Omxt}N{w8%1LL=G^t6-oB-U$)WyTOYzm2 zm3gvqqW-zwvX)5ZlFRwIiP;@vqvcxZ&byAGBfc12(l+5Hxun_=nzY!>c5A*;Uy7#_ z*>W<O->hm=58SUMZU}O<+pI`fW;1!87xR+oq<C(ef=ng}o1m?S0|E5HO|5mS8;tBA znJGn#?C9$1^X%NU{h3Gp(rbz3fAivRdfPUB>E55*5gIPl)_(hoUwZBA$-Yo`K2wY( zGU!1K_4Sh;i-;MA$F;s$C2YKqt_=0{+C4tCZ?jQN6tc&6@9p>d##g6f+3cf-k92wi z>00r*OV>w7M|Sp(cDf^^hNZfv&%Sx~@@c{V$P9Jn;^m(10kn3I&fhjX$b!IThVe4L zvViw}tamh5%qOy0x5JCHB{L0Fsw`N-e%N7C$uQ`Qy3Z5D`M#QnhWvOFY^#a51;_s; zWF?Tj1G#?uS!{afHyFWAK0M|4*Ktx1XTqF@MME$NX?JnxXUjR2fWgvHE9bFWFaYud zqNoMd5)Oo5;b)6ELgXW%&R8loGThzQAGz!BU6;nMI*Ac4XR5Vggv?l>$WnIo;?$cT zd-5l$){X!A+J7Gj_TRtl`1VNOwQJW;rzY2Z{<&oABRlW9dvL_LW?PIW#$)4$hVCG< z)o*{{x7w>~_nx?SaG);~?o1Z*uTNbx+02=024BV9!v~!$9l;KBF}+l+6c+2PcDMh* zJMNiI&Yw+8#nK60JY)WW)#ysN!&6D*EG@Oi?mF(ZTd)SJYv_8Z)KSQBE=8Af<xMCz zJzYJB>qq0ugjC}k80_2D-Px_;k<_9F@tX-0&gT;zUr(t-4rw0aN|2r?ZNCroo3?x= z&ek<HKj%AKIQ4JsW54&8`H!@Qw^MHZ(Lee}-}8PTJTer2<ttx-gF%qi&Ye49Nq(2B zUU=b!Z++`qx1B&Czw#@;@;&eM!3lr1Jpe`O?G-q7?ATp*-F4e>c^e4^67r0^;|0nn zP^7650?>J{3jh*Rn;#`i*6@EDc#AJ`IpqsX<WFJY8%}x^7T8P_YP{f;qo|>xC{zK( z>M=a}x}FWO8tv?C{6yWP^39v-hw&B`ir52!_%*k_K}r$pLch{fyLgn-M*jTW-~HX` z>FL}0>L32Ye`vJJ*o%-3G#cKpaGLaJF@)p<#n)^~;wTi}u!R~vRHGbyrsCl=K6+bH z1SJh9CYLwQ(5Zx)>f@ZoaRMBZ3G^|Pn2h1F1xMnwGOQgLT;n5Sv~?T7_)a+!)3cmO zl1Od_?51Em*}T|bii5>f1Td=AdK+Y6VS!gEgc;toK!1<NOMgyG+$5M!;x%#4b0(p$ zvDH<;A3&T35w*g7D3%p|;+~!!**OtgP9j-lq6#868l_s%(h5(VN0W|26?LPADI(*d zu4+mQVbUl&q{hCm`WVHEggp30;h$O^^Mk9z>n~E5wL%(#35snNS5S8yOq-2LF=w$t zA18SVzC0CzqRdD|O}0lOUDQOY#Hb)eZiJzNex;f@nz^p#w$2XA<lQJ|RAm@0yPIG# zZN{hxtar#{b49PmRuwHkdqwp~;;oHYDl=K^TNzE%38@&kobQm4C`KZrrB5XAKt8fD z#c=R1X|NLUID8>GBp!<qMi~kPaVV<o0=4{AG;h5^%6FIB-wBzUTT)^w8F#u!F{TzZ z6ou$&Y<g~itq*RuZFqnn0f0{<xLM_vx?Q*D&-Q`&1KwSxneh;~{TVA3lth;3=fLE` z;<c$sm2t`MMJ<FZZJB%q{S{<STo!xC7s(Y%lk>AaPr&Q;BkB?fbwP`^+bo18_VstS zbZoYDv=TcD<Z@WsyHTVeUnmsywL0+}>+RO1Xf~b5R|_R{0U^tyddU>RnsQjJ1i6}F zKD0obDDap;dWDIrEHo@tRvfB3g<QE>iFAe9Z8n(G`En8C)9tq%KXmXTkAM2jeC)r! z`iK6G_TBET#A19gk^S<s&n?c*BB6<JBMPRtT#;o2-TAx$m(z_4+2iyKbPW<nJs(|G zw(({QtoL*>!QG!d^%{{=PFJ9%UTbgNSWL`anHX>Ba7ANt<I~f{wRO_s4)pdO*s;5- zyA#8bZN0_$#rSF_=<zH>m&m{jr=t#J-rVqcya;fzsND|t!s<LiO+H8=z99U22sAvK ztQL?qYs$nV&lIyn0`t_&mka29D#f2RQ?Z0{r5&S}Faw^GXx%Vf3xzEH1mxtwwTRXD zJw9$mHmjDkwrsWlFzpTo5rJWuu_}>qWtL+Z;E8aMN5I;FErCt4nn;;DHg@h9*t>oE zwdwI#I-ba-M*4?&CE8fT{?5zSUVHMM`$qbAeC^r`_wBmpCysrb>GFkd{gJoT{K<zu zovT#?9uIZAvukhA6RFh6?GV5|D`wLD!Om1H6%2>HK7XN>fByUnR<HYP^m>Qg+~f2` zT%prf&LNXo*=Ua!v(?Swu|0R7szh>No;9?(lukM!&23sM$*kMb_RxvDJa)tkI(Qo7 zvdL0?V>J~|q*D;$nH$8?@P7!`s`QKI4xcy7Bf@5Nv~JYNAcagoy`14`W_JbgNu<-O zNC-ILC9>CED{Eo2DqD{(cZld%LT>cCKt1Aqz@_)+<MQtZ&~I%yL>gc{F0{8JJmWN8 z%zyZYe|TGe;i3QQfBmoj`RK$y$F2D7-~R2ld+2}qr+<3So;|m<T3$j5;wW`_^~Mo^ zzV$RYN2R&Zm{<XYrsO<Fv_rR{n_*m~P?7Tg0mW2Ng0{tFt^iUqv{cR)Oewe4mV?k> z8V-9Q#0$w-P6xDT&Wuu_k)ky8Z>VSL!qj0(lYl>kX0%NL-jcvyeib*cd<2O$o2g6` zI7@Hm&;#fND#^}(R9;%d7pb0<qZu`~$m<-}NVEa{rAmU&)FtYj+Yks>*Q$5F6r)M- zD#g-UGVf}sFZB^`w+Q$cPIsvT4isK0hN0D{n=V$&9tC{02)$HZ1@-Djtk@MWs^uIh z4T1zRb}HVtWfL6-@F)*-?hZWz#cN_@;it$bU}asuew|y;dxW&|EDr?yR1d$+#Kbtm zO9qzy{sH9!uGJP75wF<j>gwWN;7AS<c8sq9V*qH*2_R0b?AfFSHH=JEO#$LY4e=jy zQ%EDct##t6M!d3^J<{9KQf|c3knI97=lE#1G3i_!Y%kdCgv6=s9gfT3!dq9FQ7pD< zJ`H$KiHZ@SSJ{_L;Cm8IsmpPeTU93rvxO33vDKB8rBEo$WFyrj<_$5y>_RlmPKC7A zO1V_6oTXkJt`OF-M(`Vjbj<1?cMow0Dtv;@M~TN+DFBW}t(tKZ65S{#NZh$N-TClE zH$)Yy=D9Y%r9=3YjxyFG&4B?$Lzp&1L@=gUXbcDMY!MyO>i($jx2F?vXhtrNFOyi( z$tcjtiz{2j7eKkPPX0Bs8NWWrMx`;X)e#tsC)0k9n{WuR!1cmZ3)ZOi*5zY7L*7SU zWNOL3Z~t&q7P>wOCQJolO33X-K#{bahz90LdFbGz(XG`=>1-Sg_*}8VOorZ_%V&aK zA3UY0`N>ew7x2658<<k;*la*%(7XjAE(qR0Cf-80WTsG>U0h8i5TJ+7u|}!@j4S3$ zsRHLpJvJE>kgKx6)UFf{3YF-TndWghMWVMS(#b$)a;c7%jY<ibuC&YRxbyB4&ph?9 zo13-&dh(B|spuoy_umm7J3P2+d0};Ke);C&tkq;4=^cUK4l$3lHPqXmNF_pnU?dd5 zuESxH%@@N#=qEl{b&8{B>4@Qghn?nNz9mhYrn%@su2Q-4z`casyz<7$%0}(R%$4c6 zsY~NmBB7rByAH#Px$myyT|rN0SI~kU(8fk0p1_dVHMT7h4)Ju#K&oL&A)mn|%tJ1o zOy&wjSm3cl3`3iQeYni=!7s(4Jia<iN|8xrim*ADitvuCaK7>6uhm&@sQsYpqEe%< z0N2+`ifpDj2crU9TPc?y-+Nqcaw;*2*#~3YVb61QBot=&d>#*ze0ephw(Q#5hx-S6 z`?`)CJb+oiBNdbklZ}dbY(C#$@1^Un_V#o>u;=cZ<CpKb>&UQY+geLI*?FN?ZQHXu zu~uE2pZV~C6YfGsuDx|No51ixk>=Ee(|(t?uXlhggg_{0@>u`q)Hi2x3-#7gmp@#o z*G`Nc^xM2corCpqEmtoVD%G*UoxMFn8TR4uns1aZ&s^$phHRUT)N-;`%-?<FaBsM~ zUa4g>5Uo(L!BR3sQ;B#gt=RC|QG(W&*W>c3Z5F4tm%?!DNFL1&J;IdA2Vcl)l`JcI zr#vco&=7Rw^G9g4%}(ZQdX&f|_5RgsLYy;y(fKw!6@EBo&ENgIfA_EbwZ8^e{v97f zFms^j-1ZY@!29Sq`{%5xufF=K;E%1JfB7%}<=dP2fBj$o*KG$G%6H`3816bAYLZ@b z>jIPXOnl_UFXVN;h?<Sq02%@+dqB<<M98y`b3`$QYd`d%4`~)}<DA>-rnw4A9nWZ& z&_bF8D)kR}UrOP84DPQO0EVfc0C1B-ObG@(hJ&1A1bTwWq~Y?B$S}TejzA4DQEvMP zfR@wvS9UGrLZf<(Vl_WrD%=2_3UW2P#e!p0TXZn1K_KKfw-7DxtvxBO;;j`nZYL5k zQUST6F?`ZjQURk|q`PE*c+(gsD>X^|n;bFNJ5q8kUwr+{d2!$=r@vX{&4qoWsOO5C zfrX>U8)6+1_j&T<>yW-Ei7;7hI4Nch=#GS`lm?EM=HQr@SO~$m^6BjC1kH0H2$<KN zZo3MbHu^+{Mz^T(g+GDvoIrunhelr+I9?smHVh{RgF&I@OUSA2%r-T#fx?nGSoe$! zlj=}yl&aWis{{AE#etU{pP>3*2kv?156#D0ud^~yVSYv526qV&0(=44!z&sa+cr2b zC?0oS^D6nQ2?=pj2gA@$mF8e3#>Tz6i>AxN=GSWXYXA|c2LCeLvP|Si!yMHlE@>L= zYBr64Hnr)%7y%7+sw^clFO3pdFQWC$KUJ;+xt8I;%Hj+42k4L@ho6`sT#L&e2nJFt z=F@I}n7|G8D4cE|$*@w%Sh<3anXzo8&e2$WXrLcn$MnJyq-{tz#1~?mU}LE5`esfy zV}Zy_dp~}*J}|#){WY(N`ON;6*9XX+T$mf5nY=tP9twnTHG>qR$<_LLYh?|?2~1hd z=99!ox3@x=$@GQ%-9b`>7D0y|H@borQ|o%b=Vk|}wq8o%t<C4>RtZ=rr((HM4(I(E zOlV*_5iLN|px>(`>QQ7=TR4n@Vv3+A$o30HA0s=zv;-tY`7xP>4qplSLq3mv`#^aA z{%wyw{lMow@~O1b{-0j@{d|1(v0eMjX($zI|KlrPJ#+4SY&90Py4^N=wvb(lEin_Z z_p+tb=(b_jO|??myL}s6a|lI*=FYDycZI_|Mo7yVOD2oO^338~GM#??(uEgJolh59 z%;DhIU;p|ipZdttC+^=qJVdxK(XRjT3;*@k|KK-flgq@OeEK7weCmlu@4EXAi@9}M zZy)G0N0PIJ<x^+Qu9eqtr404-4tDnr^^PLaj(S<4gt)$&tpfnL#cYQ<uck3^0;Jul z5<iejsZ_ZY9Q+D&GS4wtvss=1P{_y;L1UQsI*E8IeYLo<!rX?H#1p7cD)Eenr&8D_ z1HFAXys=$ZldEc9E0I`UU5SLl?AGC-cYEx29y^?`6&DlHbTK<RGD1{|153(n{?c<_ zM9A^!2S4=u#g_s@+rNGC>gkiOKl|p(4CTP!sH??2v#|8!(fjw<2M+By@Y0RbUw-v# z0k_lIwt0ATm#y7?ZTu!?U(s3r=FG_r!jn705pVZOeC46hySMf1akQGpx(Dvqdtl$d z=&@ag>^|QY-uU|ErRk;2%8mIOVT-rK)<UYnyZp%BeM8;D*l(E}X=~S`+5F5RaqKf@ z9PX}Qs|k~@rBo)YzZFfJo=AUh7Z%D8a6vr@H(LvtDE^2w<+5r^repa+nyJOu!JEhI z%w*!EMPnx5zb7-cLiy?eu69e_kL&$MQRg4jLvPdxSN+9{7eDv8&%M2typTTr@sHzL z!`a4*0YvzlzxkUVM8y6mhVxyPIX^%DU;pcWz3pV|uD5Tq;E9J|bMxj+fDtI?Cx7xM z|I2^*FYl;wW1wV%7^9ze%IV9E0E9q$zj*t~>k2?-xT3{9FA$mcv48_1(kMDXTie?S zV2C6A<-h!w@qZY8ba|1>-8D&|;W_4VIY)jKw91V*hdN04hL2ewAdd$1ri2fmX*0UE zAP1c2s^*3xP#_wA>iRdhL()2NZ}VNK_FVgWzxNIv`d|IkUzN@`nEm?hIt6KyA5S4t zNsdV2Qu0<;F?V4>HFP$cqTq5ekc$uR54jPAQxt6n-6}m9{7Ne6tQIKL-J;+T8xH!Q zeAK;kk0>On>&8#2o=qVXsfke~siDAesl!$iMK@%V*H2c3InwhTPKO;IAN64ePbp&L zb3jJ6V)+R`NF~A68ka}FvbcM3K!RdVpFTzR!;Zzq1G3XV`Va;nzd~)|lJ4$q8CD)R z%v%V7U{HL+VmcawC>>%<TA3sYMr*A}DVBqBm7J!&Xd^($Yc}HqqyvrFC}xA=ylipI z8zm?^P!*sum}}os3&awYYD!^TE!d)?y@ezrxS3{>%ci%tk27Gf$lFWTMR`W)F>n=S zV$Y$Hp`7}57m4NB1lVMI+6*C@)ua?AiHX#$kh!4#BT`hx9BT|8U8Ls;zCzVB&Cvle z%KF7$p3OnnReMu_Y3UYD<5%fSnfVmO5e76GUEx>E9(|5kDG}+sU^Kau&*PpXtdJz6 zP^GC=sgO%1Vt^B793&i-77~RYjEQP>c44tls(9V(6q)!Jvxj_{dKXUpW2|(Uv@-YP z-}l!?=E--jytpC>yT*iqxHZ2VJ$3N{GU0f0dqSPxI{6Y~%M#l@xc$c5L|eNRCvG~E z80jCVmPzJHR<b;y=P;F0S*7l;<XP&>u}xxI&F$(DL>M!VE<~Z0mXf7>)zpe0p*fe$ zFr!uCSf%cwQW4{rwp$@(xbfZNxexjMJPh-=v6T}+Nw<=50)I0@ldTpbot~cFQ0Gw3 zhaY~*KQ#0oU;WbSSD!o4HN4#s+TXi-)8u;X)TxzZ;@*26Aa&IE%rzi8)Onk=eZ8fA z^uW=h$BwwYo|(lNWG%CW<l#MgLGuvDupIE6Q~%CjSSdHDHPGU4x(lVMwcS3uJUcWH zfZVdO8hzy0qlHXiWMGgD#AG&o>H4*qxux}%wy?iv*Y;fpcJJQ1b2|~4P?AVwJJ8c_ zYBR5_EW>$+=~r9Zm|dD@e)fbr9Tw|ibOmM+X{Cq*q4{37msXo$yOGUJ1&P&Nq-Emi zv96SG=ucvW5!q$452_eXSbP~k^Qsc%uQJl<Os)#puhkL$VsjNsm2srgum^BUE2m7o zjx0|!7VYW`I^E9h9$%}4+}M>;xtLokIV`r$KoAkkH?O`%Akrrv{!Go%8tECSmo}DW z7oU9S8Rurp+~o9y`3VU7M@IJ9OdYjq{k8GS6PHduwChewebd$oe{sX1BGFv~-JQ`w zCSA*hgTa0;92m0Dsr*<gtIPGa^^mi(vbn}{cw}(o;^K|@+|seJ!!;H!0j#YZLyrEX zxmi*M?;06afz|cGdTaY!G<I$3rq2^{Sez@-CATN&cA<&jl>ivEooH%RnoG9!^;%xP z>reo4;(f?wR$2WBW+Fz!-VopMBrw8Gr<Z3P4-j^Pv?i}?mWt5DTcZ5mUkm?-Slb_t zhh8d#n#V8w(l5PZ<#^rx`mg^wBv+<58Yv&3`5)pC{-}#$uoyB1j^Sev8OrZ;N5OUi zWQByl8Wk5fm%t8`usnedLJL-yM!7;2{YGGckXr;Nz5OGooeMcZLh-~50HbSnk;0|= z9PK{R?p}c}ny1s?|8PM5l-H+Jj}OOn_MZk#LOoz~nol9^$o{^1n`#EXpcW$#mLq)U z1P)RekcTw$9b3T(a$Hc5d>4c*H*0KUH*q}JRG~c$lm(JXKL{&>a8P-o87^mj#hFT2 zr*4#TDN7q^GEQsUrD8`(bEE<WU{&8$PiStv4p0(^Az`2zDBY^C6rx8^ePqO?@=}h% zTus3uju0Y-_@LyC*YAGQ<;$0tS5s4yq*Xn0_B6VvQdOEsAy}T8UDepfpfIR<Y}il_ zqGOStr};pCAUh+)PtXA1%}WW?hsI(s;74FToC?VVlgv$2Rk5<(nkPZImi2TMG|z`A zBwZv;qY(Omtq|2JEdfbSf-e=bs~Kpacau~FsEkYiV~8aVfj3sUkmaSETwTa#l4L*U zeB~F{gUc%%BT~D}m6gj)M}|kx2uH{gz752EK!#?ms3B8*t}?|U+q~I90!2tW>xzB@ zd){PonUoB+LV#KvU%)qUr!wd*7&&5o=zkm8kvUE6SFm$Mb{tG=eG6l!0z4NAhLPuI z3hFi5*h?`^pj_^v2dG7nAe_!hwSvJ$FCjDv{RVE8>iM;GUm&C?#f4n8l()O!6RQe% z{6T_cy?&%EiT73XEnePq#6WM)-tA+MwcuAU`QSxJnpl}-a?`B~&FJuVTz&7^gWs{* zig+h^Bh+48ajiC=jh~ylacS~8r1}1yu9o#GDSK{^Zz0_0arkHEm&T`OyF-J;a>efo z;XqzmnnE=_m5Y{Y`N`R9D~b8B!BG$-ga?Qs!;0ckhmc*U)>hIf^aPieSCg@{rOoUx zw`VeG=p}57K(+yUR$zf+h*!#~LOxk4SUsK=i)k^r)MnnW+0Do)BGpK2IJ8PKemZ<E ztoTf3z18J@;^Bu!cJBW5*Z<(f8{hhgV;_Ee^kBdqx;(x7g)e>)b*5wc4zjvxrj333 z4?OwUN7h?R;Yj2oPyeN!{^9ErGY+f!CqMfOci-`V*X=9h%R!VJF=$(=g>ot!4kh!M z`Q;^G9}&D>m!C-1$=QjPD(>n}rZV*-d++}0YhT-Ya5t>BCm(un$3WkMNAIwh+Rk0M z`2T+K55D@sbL718b$9*jkN?bH{=}z$?(;w16G25W8TJKFoxAw@n`bM9QfHuR+sN)z zv6jPBu##~VYZH6Z%Dyt}n&I9)C_pwlUgp+N&|lf87OEw`*Qc}^308024ESAb?JD6K z`&{gG@$m1CL`VadOr=ORP4J7uX=O`JsbjTn1lSvFZ6%PWWzFRG1%?LtmZK}s%-Hkp ziUh;G-MM0QDZ1Ly-qIZm7Yj+J*KzXZrTNtS(|3PlN7r`tuIA%~Yu6`NCKsRk`d4nw zL|?gjs@LfWTD)`DC&tHTV60kO+Mc-MiCj8&_1u|Md@dPZ{l>Sy-fA&#Y(ijic%A;R z&4=31mF!fWPAn~_mM*+@_M5Lwyg8GNE>yBFOrGiM-F{-nz3F@`nTmQ^ZQYh|bZKGF z=-@{mc$hVrFIVl3uAnb6Ixy5343x@Qj~5*8$>%bQEAxvhb8N~4{hdSo+j@JqLzLP? zP-(rbT1-I`E9Il*LX4mu!XXf`SzfwXgS%6&tgg<qcc8IBb_<Mu{b^NUvg*Gi08naA z?>__nNAVzfS04ITUU>z-EHSJ&M<09aF#y4B8k9!OIP>9$AMWq(|54QSgED_uJ@D>5 z^nao|3jPq3W56;&q5|c?pyJEaDEXE#sf7y_eBqhLzj8is;q8Q<(a}*Rp`0TCSMJD1 zWAO$$7ocX)<@wb>_6kuoInB~K0qBB~`B$j+Qaynz@?CDU<r38vW9LCMZR7-PDm0QM z5rpvepx9si)qkuV|0-0m2}ji1S~>?D1Bg{nMSnObc7;UZ3K*5+f>7mO0hGoN$ae#b z%Adxs0yL#vQkr<3rT)g5@@wPy$ro|bH+Ko74*bgr(o2oLZK{r{u2AWs;O0u#wXz32 zzqA6B?CuN!4iJ??2ZrYfdp=-#1`H>()2SphK*LwBUcn&*gaz?aa$jE`od%BQUif;$ zWR^sG+2i3%AR}k8i8MGkNHrwAB~}n5K#9)eG#SlXJ<td+Q2Pe7Kvj<^RIg(sP#~p= zZ+>eJ7~dr%6ix_7Fiw={3p+o0+Q=pHuXKx^dqyT&>HzJb(AI*krA^Ul(Yw&X@X%vq z63Wo?!B$ZY`1Lh91PDbJ;o-yEhaNVBUG7NX`1aJoVV7EQ@i!@xiQ55xNonugN&%rD zJ64u9wpCQD{>Y@_2u?WqN(6bd16cKj+U%0WrE=mbLcikrLw(gItJ+=weJHY0BW6S9 zv#NtKv6N+t)j?0fcIN!0rA6N898r93#r)YsUQ>-xHbod5(y~?u&bzQ;;*ln{y~A#I z;-05K$O-Xy0-tCg;JZ0Jw_{}R%J>AgQ2B#3+~=ucJV}hXDl=c2`9As>)xNFr+9s3# zwW1|Co?49N($>w^cx+`_B`$62>+A;P;ZOEBU4$M26O+j-l7Nvw7r-2|wo1V9#u~GP zRjzh#TH0|OV+k{SFtCxXK|-B)mev+WI#-&TUx~*ujCK*&UM*X!`0h<z;RyOIc$S$< z5b-h0;GgvN_4xa`U45OFh=<HTCgu-YF`5OjVQK5??Lmm9y=^1h6Zq)EPwYB&?90<< zzk23bTe-5obHr`(;&V88>diA3Pu+Xsejps!j>uhfjyBuYuHLwG_Z|1<v+I|~FG3qn zr>i%{FTZm76`#u$@&$QKU@Ynw-_G91fXnW-Tb)ZQtBBtRy+K$o9=AO_(*5fA=?=fc zWNshn8ie*w!HL2utn{vMzs<fG@C2CJ)3Z|-Z(Kfg={$?j9|;}VcX0QP9Xp4INr^xx z0_hHFm1;VbPG>W0P&iypc93$#0^uiJ;Q+*#d?~Y<iXkzn(x~BD&gWSAEH>yp%uLp- zo!%yxxKvdBdxGp)ttxt^MFCmTrq-b_1>n+fp~HspV@jp77%iCDJjC*)!YYYo%O!~W zJ-uD~_wUUX3v0Ey*>1_^(!HJj;o)85%X7)($}{&qcIV#XuU$Ozm6yL+j1?}PIY%yA z*7fYfyw~RBj@t&udLy0j)mW$7JFz_3vTo{hc!s(<m*;L?p1QtacEjqwIXgix#!#eh zIMU;3w?k}&VPB{gHrrdex`$qydUbqtGFHuATAB2lUByZs@%XllmUK3~Sz8<H>K^Ow zfxLy?81QwfUCgyLYkS9V-v}la^AzuZ+vB&YoxN7#JvzhPejokkY}sTpg9i%_x)$~r zNhXD5gEoCUxvU>GHVk|AY$>i@W0w^jFx+kGJ<GIL+m(o`>X4!L<9h#5JeuAWp#Q0# z`YFNakS^dnJoVI5&ph)CVtj88m*kw6Uw-+6XxAUbQ2h|g{1E|q0W|z8TpEG$&DX7Z zD~XR>SU1ufO@L8a-I{%_BrL@dF3x*{nqssaKo6};pu=rIT)>lnQSm?v9Oqht*<#d? z<Ko&Ezq0bP>bz9SFWR(51VGDae1sn_rik1^V>Pu=AkbD?D&9&tjh}x1_kaKGL9xH| zOMhRgr(L$Uj2!6@wR_ye)`nf7?UM$2mhugFdK;iIV5O=auVo&5%~0d5=-lWl88U%! zThqr<83WN827u~Ze$bqK$x_K*g5$+nlOt3~@okhZ7Cxkc^_nXJ@pqj><vQap+79Vx zba{9fk2_4868>Dg>BLhaGtY<1k+n^w(qL<hCD=6_q}WrZPT`LS7RtDQ?72I@9ji%p z9>iNuQT)nP{6v|OT3k9xTA<Ntqd%nWYCFPYq7VQO)E&l-OJx4YaLCzmUpdIXDxGRG zmSF3Im-A(qi~-V<zYbJ|F|Y2qQMY@7W~;67LQ;9Bl%Jk*g-pVVpdkqRghMFnqwnd2 zM&H90{OSsBa>XMeL`2UtML$t-bz%o1=%zxA)u5=I995>;m1-^!swAv;E(AJ&vgtH6 zAM`TYI{l=(AYt=AQOTq`WqC^Lq=ANIE7L%?cN0f0wS_}Pv?gVuB1&m=ugnd#c-PiE zUZ36RQaN91l}vI)b75O?fwI-E0)^QqP#Yj>Hw4TS4*F>YH2UsHSVi}$x!BO8+B&g~ zq4^;`F#mLl+B&b^a!35U>hD%U$@8VW$Li?yh8AM6*~KYz*^^o1`IYer&@5I}N(7Y+ zs<pK%+%+{f?{ztO0^FFJK|FPXT@aHcU#!?|zD_a(l`E`Z&@fMkWG+)EuRCp_*lL<= zO~V7DRy0f2*CByG5n-f(%j)rngiA3G7mQ~l=sAHNO(K(su3!xe4Gox`2wCO;{dQ+- zFyd|_mSl5dY}eq!Pd;?V@jJhD^Yn{npF7$&^ojisc6azUTO5D*zrK9o!nvdSjs`<L z^K)}=oOxrjwVlnT*G|6T_ak%E5%PC!Y}PXA<lbHTUU>b52k*M?z@CFwCayVcw#zrJ zkc4P-VC>TPIP5SeIv5XV*3K_3+<V8dk-_f!Pu#O^X}P{|vsS9j71En)CZ{h*M%vM# z?H8|~zVpC?nQZ*Tv17?h5?mRLu42qz9ltTVv=j)1!$IF&cixQw(-{gAg3rn#QWZKo zWOqzo1Zse#^a@lQ)+tK^J)Dp~z<Sk59@K6dJAEir@*E_gY=y7}c0II`8_H^!z=VNt zCcqs-9rBXit|Wy7VKYkm0oDyGU+LkLi#?GDkIKP;p5rHu;pez|^E&%;?ALkR$o|&M zb|=9SeQx)YhaNmNH8T_%a<qBQo_?dPPBhI%I-3VGTieZ<L=t8c+ni$~W0x<U85<r+ zW)kH}F`X~BT0EO==C;<3LOjzQ>hxIcXV0CB1R?>auh$j!*gOuqf3}=KGRtdojYY;1 z^)iiBs=82q$cDb&;ofvuHr5V~^!Xi5HeeZY^o4m1vX{dHhiwb$Fo3H*0*8kaYs@R2 z#(3-z4pKV4yd^f<O8FS6GwK^H#8HtHwp7fxUH(#~Ktyc7-<i!N_|tB8tMn8+#I&r9 z-kMX1I5e_<UmEZ~il@r=Nx9j-fB!eX`OSA!s|3EF?D3<h>j!1N$9q85mHeyWroyZZ z{G`%8s>x=s>LpB;6T}s&S=|aEOF->b(0^O2)oWamTsC#(1tJKKMeb+-P%#e#rb{{E z+TVJuL3id-LFaO&c;Dq$u^$YUj!`9UEdn6ik*6F$h3`Tw6ZM;S95O-YT&O{?+L{m~ zBuL$;fYA`;HPz5cwN6O1Dsx_A8$oU%?otEU2-96e{d7_x1%Hf^)xo9)sEmtF7}~&~ zO^C1ll$)vn)fbCxpww~{jid4O5FBrGj))KPE0xxfi{dI)vAlQ?PZAWX_}QC8fN>DO zt<|h?fn_3{5&Tj(q-FmU@(h3A<>du{WQ~>qT}L+MjW^yPDE9jGYq)!*QFJw@p*L^z zw(26yN8%YpTqeMmpL7o^_K>QZjH$s6(u2;N1b0GVYUHVvDJt_=^_WK4x+4Vj3Zms_ zvEt|lnSRn;G8R%pV_p$is{SmbHmmt|n}^y|^JocdkbqrG4DpLID?~g8duH$6{mU!M z;cx`UBw9C@FJHFl2wF~3?3_kKuR;uRI~iG-y)+Vvvwj7tUeYJ91dO;<)}7inYeb^! z9T@q@;EFYZV_kwVXg`cCMuDlW`cvnQm2s#4#nj=8T+Wy%x?OAQ$}+iKO<j?$WGaaf zLbd5@wIt1!bSj=r$I##}<TEbb-07Ih?Mo$Bnck2P=;Umnfb>3m59Q9Y+n1s-ZYml( zI;j@vb+^QeH@))4Jb%a4_ntktwc2l?5NYo`J1l7wA=funG8w4WA*XNWz|LxYBk1un z3#Jz5XcvjwVyT4N<H%PEIDIE(iG*CaIDR7>?7e(*YGIj7ot2^99WJ{EY)U96US}du zJFK?aMl0E)7M5cxD+!X1<+AzdxjBMO*$09&MV>ImQ88`GMW8HRW~Z$q=y%ykqe@h5 zN5{hC^qa4~3Ya}|<iO#(kKTFD!AI{uJk-Z-Tg%b?yPiC9Y$ZP3QP2Fu!Q)3g1Bs;! zp|;n@$EW9}PaL~*+l~XZjW)ud(a7lv`C9Acy?gfW+jRsBHlCj8>+6Mx^}@@~4)qVD z3$;>t^O=u+>dD6*`}l`H)<J|oEWzsn&DC>P&RNW+n{zXEl0dDk9XoKil*)(K9UnXN zz`nkLeurf;J@NIk&-V=Wo}0M2|G>TRY_fk~<oxw>hY#-E(LeIkeGkDsf;;}~OE3J- zul@0V{=@%q<>t*tA9(!!yYBtFzxcOK96NgK(EjdFaI;)5rgCe=ifJ7NKl=l{ySMEn zvXj-1(L;nWI-UeD@ILUXm;@8zm<5ueRqMp9lhKw3T`s4TdD!mYc?phZTuB{8=rFgY zA3MYTfxd`YC8^u6S<t*{!Kcs}4&Hs&J#43(y?BQ7QtI*2-pWmVp}uD?e7oJW{;9{F zS*&C(%w7J{>94)|`U|nu=$_FX%nH&r`F$=Rxz*k=Hag%9`b<{S{{08wusm__@onAP z*Xu3yc1x|pJ~@43d4A&Z=`*QB>fo*esN&qbKDRQPbZxqN13jNU@)5`SdLj#{soigJ z2Tcy%(Dn67#2IQUug6zb?mcv()7J%aFkf0r<yg#YBCgFXEv}Fiu(DoXZ!>o|VS)|x z4;<LPpB)LmH`E!5v_iGV7%F8{vI48u?(O2`$Eyl8B$S9*-M!tTF!5HFCVZZ73t9Jy zNw$czP#X^%c9VEf64rk!#_T=2uKzSE_I(0+sz^$yFMs*V?^xGA`lCPEdK~!_^=f(R z2cebk)K1><<f0<EtQNRXpQA^Q!p;}!!n;>!G0Oki*S>}b56)dFjW7IZRN(D(<JMd2 z#-DFLM^2!SttC@oPJZ|H3@xIih{n*st+${Mily4`ekyQNE_r)76wWP(SC*n=Ebh7I zp0}5bRFP4Kci%Z%%i(fq5n41_07NOw;8-QO(r^66Z!oNaaYa(P5z48v!wCE`;4gO< zS(~?4k~j@P<bb*V`~UvG1yM;Zdhzaa3GP*T<FEeJzxu=zPY5$X5GT>tpZe6N$ciO$ zOxlI1pq<crbj6e{Vce91_%ES_{Lb(E&M*AJFR&{m<?sP5(bb>)<R`fi@SRII0`3tc zilz$ZXrjMzF221Lnyjyd$+!A?n}r)dnG5B+!s<;pE|iI_0+dpIL+D0BI*JtrjsP+p zhIot2Ex18Itt$MTh$Y5B1Kcaxv=%<!T0N<id=%K#Ulb>&nFN4?#Kv(WDR3ngCyfj6 zkV43NN)-TkP_7|ac6Il_?l;b)e;5~1pz}oxBqdaa=-cKdVw7NgV5P)Q^Y6gG!0z3< zWmpBs%1|;f0Q9)Dabd~^LQ_#w$M|Xz5x|DhAodX4Miog(OYDJo`URki3tZa)ihQEg z;W4OGW4Rs0a<V3jHH=9a4mv@Sy$e>BqWA)PzLL*&ID>6=?|QXJrdSJ!QDDB<T--o; zteQIj02&pfQLA0Mc6Ix<9b68Lp524(+qbLSOfAYH!c7Q=Msc+CN1_4@8kinj6~e0q zuB8>LM(GPF1l*XC`~t$pjA3CK_vJSo3a%XO%2HMP1}c>=A6BlCsnG}3NH>jVdQUdN zxFHLZlu~pLp~ZToAav7B;q#00RG3s*j4QK9wNtZn><;9`gPuTyuuF&Ai#L=D2}_Wf zV6&M0Ua!lc3>Y$f4)^!$-?;<#r{X)op{`XWHdj6dAb!V3$J>|Td+o?us=Z}pv2}uP z{z`UvHXEBvM{}jZTw>+Q+{98m#;SPp!a4ZlfV1}2j!3YxP$-?dbj9cLuD7m_jtmU+ zbddxJgK+2IcAwWXF+VxAFpDji!~N-Ytt4Z1hqG31DHN)$>+Ozqd(a(TK`=5Fhf{TE z_ipyZU{4NqbqBp(GKvj#cSiytpR;54sOQjLf*M+YUl1t9_U(51{R@lBxlB6bw)s7- zsp;vJmBk~64m^1Lt~L8+X|v$0w{G`s+u1$1f7_lLQ*+P0@O3OfxIka}@)we;%lr2o z*}L=T^wj+9%nX^60fpf}-%4@?de5~RH-o-VZ}$Lh;i;J$XWw`wn#|mP|5H6ZBcZSl zhj_JKiG%{gZk{->|8t-GSS-Ex(i^WqB21Oj#axjjraj*7j~saDiT%f4zxL{l<oLI5 zo=&ZovA<pJaL5~Ox3%{U_v4j6vVZ^a13O(7)6&xPOQ&A`H~;P5pS*CvY4v^bqaXjt z&wl!2Pd~PA-!8w;PgdT!*%@1F$Hc@GosTFG{2$m!IQ!XZa#_q|NsFiAMC(QZ{+>vX zTnp)36xd4ohV}Z!;?im+T`-%>YEU=YaP6}V#lz6!aH4>@xV*x{Bj^i~cgaaQF01wK zyN>4z$<@`R-tMmct}d7}yM}kPwA)TjpX-f;Klb>C^J^X7x^%fvt6Uzxf+PGdf99v{ zE^m!gtfcj5F~g2dEXOWhz5M&%_`TB?U$(pa4v&As)Z%pqgXG=~b~?=VpZ?5W{oJR1 zlIR1c*Nq70rAw!;p1)wOw?vnto7u{t-qDZldGM({kMdZrRI_$-`*5K1SY(g6-qBKP zdGy#FKK6d9#S&Wv)hb*p@<<SA0R`#e)l<{+<7Rj=?Y2#meVyfs3atapE{n2HiR^+F z*w&FrujbTl?Hs0~jf7SHh{wkho}JZY90n-O^U$@~JvL_$VPEz+<ZYw9Pb!$|y|#+~ zZ0qx`!iiwU-+lMp?^scw=i4*eb0*u|M)V{g60msN<=?4H;Nbu9fBYZsNamr0fAKH= z#hrKF`F1?Y@xSwT{?6NL2#`f!=k1&aIrH!T{lEWD{>eXi`_rE|fp2`{8%AmG*hc2m zJGM)%0z3Yv|MZ{O$M{a83-JBd|N3A5`+xuMzx(hL=Le7cJEdinYk|L?|NQ5_Qyb+R zqeb7P&Rc6@jL!G$9OEkB)c^T^{-58aMX2botF!ek^3DQ+C@iuiw<s-oN0Z~WzWV3? z{GS{1N^mE2_|O0OKXd#$%^xWNkoUL$_TPp`1|`ENQ%JyqR)sbIj(nG;k$wwpe%!hu zqDKjaVepQV2M8tckp?)HegO7KLvCxS9F%h!5WguIE`6x{#BaS&AeV43#Kq1RIa9v8 z<-0I+n~??v)^E}$RCSD632fp|QOi-rL-X!(zBEK40mNgi&sQ$}e4#WoJ2yHwKvVF_ zL#+lo`g~s8^OOT<oSmJ!@4ov`w!sH4#v3kk5IjsjK9s}zNiZd)!k8CwJU(^KlptUk zJ{bkTr8G)}DWzZ4?m=^NL%^;vSa_GUYq?6UE9^rqS0%Iwp<K-kX^VQF=!juHMti0I z`G~-gbP)$7xI(sKAdD7s8N1s@;2gy94m*4yXkBJbE#-5Hs%&-0xX2cYvH{d9O@)AS zoRY!b*k>ABBLq|;1Vd5b_4W=2RmC*8Hzu<lXH{jXyv!e|q>{W;6nQ0yy>%8zAL^|P z`9_=od1nzPRpt|2%`K1w;RrxqXjhU<N)L+K$ihg_LLY0B6BF#WU;?qXz=hr2y_^NN zin)pQoTA1e<WtPzj#pfcLe}An&}P~g?(T1GqyMdtea>IJv~&BmSTaqxFv90ZkN8P7 z<o7X;)s~drDUwFL<Jyttye~e+GS|Tj^sMT9z7twGk&ow#dGf+S313RCE~ew#d|fxM z-M}a!d~-FCgq4FnAht0RC!UOlL%~<hoFWz+8NubH>Gg8<=Rf~>QZb#naA7r_{nneW zb_aomy+t~-R5o=e_4HIK7xDL9x^|uC1tU(JhSTmOG+O;xsXz+H@~f-u9X!bE`*%co zBJDTW0f@H;LjBI5t8S_)CL9;Ew(Z!qBRYN4)Up2KpZQ5^$n!r={qbsa*<RQj_VtDX zJ(*nn%-K`fOpY+eW5@2ea_vSuHhbdEyW3iWvy)dqghvh^x^(SqrBWOi-M_lJn9pbK zzx%=VmbOUefXnB*e(jX0-4b0%KmWoDNA_)BSXp8R3VN2=)Q)!M(@#G7$fFN^>xJiM zR~I*}ZJm*>1G^7w)J&^O^FxCJ#kMtk<lj7Z(&e(DkbZ0zH2u|GL!+5!s=G71xHR7t z8JL>7Mr{0z@wpC*ExNkObPWf>JBGJ)b%o{@ZrCmEXTSM%wA&GGMIq)Uq$W4CCi_5t zAAFEpA%`7~y~(CmCSO3qmibJajML)4L?M9`A`!Uf>0W|ESRf7?$uTy$sw))259Rmy zlDRA*Fm|&wmLM7G`e#1*m)2Tp$#guKiNn@8yzel)Pm9NS;pRmYo}YT)i5>o-FTeOw zzMh?0o-q^eP`BaIC{@ewlrR$ZZQFbF(0=k*Y}kl6w~@qlc;|skIXe{WOUKgJFJE<g zz2|R^KX~kTIv;n~Efy5<%N68H&zw6qwrgzPzJnn@F)*f~&K`JHS5~K=zxw7%A=>W> zcei&<j!*W691kBq?6WzG`FyrmT8u)mgOcR7T3u@`HaIf`R*Vge!k$N2mxn680jJBa zlTJX+(eA2El^HOdO%mWi7Fg16Va(HeknRWt;SJ*Pa6Y?wP;hZZ=v>s0mf+2^`dcW6 zx3=QYZ+T$7FV^~xs*>NohhAy~lzhjkkrd|ps4_n0pa1!v|1M|@0QWcl=HGmmCF4Ck zaNxjqLAw9+pZ-(s_%2Jk?KE}_-fpEB=Kwn%c;JEWB+QTN9mM}V(LAM5`OkdjGXVPU zQWV(tyQ6u^!QlD+n)xoT!f*m_efJg_;B{-6LS|6@K<z*k;38=3dwv9B3iRPB>HvCX zP`*2w=Mql9mV5f?r;UvZ4vJABjz+3_;lc&1pm$jsr*Z2WH*P3Ys>-1d1*4j7%iEhG z4HT#)A1<W%4GbrcR6BH~e+)ElAbvq$a;<zfJd}+;K>|&mu>ei^$gkopzIFE|`jl!I zb(8Pnir)GWt_Ae&t%%>KjNAo3w)CX%EA%tB1p??$f8XLtRKhE{JQxaL{QLa@z%=*a zJH>J#h>)E$_Bxo}yLRmYtZP!1>G0vh{JD=;&B23MP%`uqRx8PFK$E;0X`m?UOV8+! zs-PC%RK|;REPb~XrUTz4aDv!eyx<M<Oc87vgfS^ajj|?j87w32A}Cxny!}?F1I^Lr zi-Cu@Bp}v;exS+fZnt?0nHZKqwUlP>!S3P+Z}&#{fes?4y(Hc;U%!5pW@)v43toTT zi<L2VMq4vcoCOT~b<kj~|x9FeIgA6>~!{O{Bg$w*xOpm}Y;C@oQAA}Kz;{-{{L z4P53*Ss(j>65z!1Mx~9)Hc;(RJ79Fa?5J>p^4}|BaV?k4LAL^w6TXaRe`ItNFNTf} zR^)gfKKF$<s~BOmDn<@HO1Loi+#ifUB(ij<4F{E5$LC#%#iH?KXV8y_9{E4T>TYnl zRHjN}bQ@!Q+hl$J{CTVXGFP>kjmZ*6&81rLS?tAH1<!iG<%#%$`AQLZL^!O9j%Y)) zJB13n!)imEsJE-DqpiI=(nXlU((*#UY5&!~^@|UlIPviDV}Jdpe&Q$p(#QVZPyg&) z`}UU$nU?jn40&GHOy%<06AynF&u+lWQnIdXutU;<&^vQ>dVW5dAhOmz(ib7b)X|~# zUdmN#bhUttqtn(lHGP9rwGpp>&yMY(a3GmnJ#+3Acc<rLANkB?u=D@-#+QHp&9D2z zz7IX}<h^&?YiV<Q^_yQGU!L}cLmr?1+KutuJ9j+w#M5p^&(i$O&Q1s!_S5HIKYI9% zqlfSH5KkG6-+A-|bII=yWr~^87ti?J-H?Kwd-?eTdv>0^dKuzMr$3ZPCim>z{ozL+ zK6U!dH_x0(<f4}L)+bIpm|Bf};Vb{+xwFsr4GkfKV=b<Q&8}bl%wK(E$Kg(o`)hCh z!9;TEw_o`Nbf1Z(xz0!rs5H>o<FI-6?cd+k9qR20<7mHp{mTFMzx>93`TZ~4oL*Vm zw0!KNpZ)7U|2Ln0;?c0*?Xj6H<VbSZrzUv`&*$@1DCriPgXQe=`iFb_eMmx?Ok~ex zov_yQBSLW?2^^0E!YpCjB0OAB=^=P0SICnviy(yQ`588G?>K&hpxR=kfVxnrRvsN0 zU09rNVasBA9NYHpgNN?lw*QYVzB#;O@UA^aLYv-d7J^Gl+eRy@noxZRjfut~5T<*2 zy2x4JvG<rQ&gjzO*$XGnUOMwTfB1WuEU~pYQ*GmS|M-8*M;EcT=a%RCdIleO=%L3R zf219^3B(pNv!f-7>VBRa7pAZ?u+2SC&Q?$ajyT<iwvYLo?tDHC7YnBWyVPAhV;)~O zr(YXChesX*W(nIXtNiUq6!Sn(JDe&<hVnvaL9G_M(;W(Tuhoh?VeEF7#}nx39`m?^ zk#G-@LI}>ow!ti-D0)sy^eWGSeyHI&YG~aw-4E}d)&8TY=?@C%xAIoE)(~arKWT-* z*6#-6ekXyQ+inMF1`2=AI=q`ZzGER61K+)HP$M4ex1WQVK~(Yg1f5$iB(M^^_;yUs zk#`jSzwM@wPrl1u!T0Q<?|A~S80+PGwnzY|5P6Lcpuqr<0ywt*`8{tfu!E~EUAjaa z-sRkoV#Vm9@&XDCY6M?E^AA1r(Al$Rzh?!E6QndQ<Os|J9M62&O5oXAltyEXSXcvI zi(^|LyZX--6(FwFP_3cE!=D1Rjove$z*Zx{@LU?d8ebazT0Et=JA^(VS8mB*B^6VE zcuUpgEHD`mP|`UmaNpDbHfqR?#AZ+?jX~*Yg`{4;c<lzq0UvD80{c?QBnhN&5W>)% znVH5f4v-~;i=sg7Cr;c6eBZWhJ3M&aeB4y@_1Qd0BoK{G@?PNsu^x#Va6B3{%tJoh z9Yij1%(^BLdZ2)KGYM3K0#9YMo4&Czf=M7!q}+~AGd{V|2V!NZOPU=f(YGLMBV<A( zefWU9A)aaTMqi`<L+Vzxywzx$+Fkw#k|PAj@>+r|ieV}P#Ngt|#*GKYCCYHuu00@c z99Mkr40qz{7OoL7vec7enZAH{oj;)w->k<@9aKj&UkHntrs>6{!kM*NrMjJ%i=qRo z=a@3agqQ^Gmm_*6<DfUwMyT+(=Vjs<v!*d)bzHdi)<Ys7FPIku!_ZJ|`s5~=YxGBv z!PLD}7zuhHE?+p@J66i3u?{fEGRasWpGPMVkwp5Db7*5wDPp+hmZB)+BvR?1Upeix z-;NN&w}hSOZob|AeD|yP&-Tn)HP`zd$`o!<=|xSOt(iiO34%UjET4XJ{zkS^fGZCl zV>Ow$bp5KbX<aT>)5PpF$0uiJ-@J6e(%ymY_dwY7mp<~;j%_3BwQMb)?5O4sj1K?! zQy==-PkrQ5Pd~NRT3$*lj89I$d77VH$fhzdI&d(fZjNnm@!GZ3M9k-Lb$3NNJHwSy zVmQ=xV8k)d?M6TS`gEqeW^#EfKA)R}16Rgx6!H}tk34f70jk40_xpMWfA88i&P=_2 zw0p=ItDbq|?3s%<-Z*`>kY2uH+ulRF_x1Hgh6j61t)^_Y{o0kQ+qP}X7K=xZ+;RB8 z(YeKh%i)`wzI^wIyIa;QBf~qL4qqa-S|}!`mJ$~)T}5JMer3^acILAM%uDo7v+2x{ z!^b}J<3IN8*Iz~}>hkPFG`9NKo%alfLyNJ6fAZV^?9`Q$hj;DRJ}~^^nbWoM#zF7E zqy4+u@=1St+nYDuczt<l9zDeh4(4#OQrfiQ1l}aR_Q19sJ9mzH5l^>woV#)Pi_iYi zD;HkJgnIh%5B=4j{@GvtTmPT??>b5nYa}U2sk^is&8EoJK<o{Kra-okM;ZsAUMTX! zp)fZcHaiQ68H%$3seYt#db=Zt*syd+h?^_s=9U)FgTj2;zkhd6cW0Izy<C=MFf=wY zzq&v~!9r|xa(>$4ZT--(M-%1pczWh{zWO^oq5gw=kIY7wuFZ~L9>4DDu=-uT4?q6I zzWqCLg`}_3mCmfDOUa3aNuM+D$@@Ne{`8qaF!b6w{Ql9N?xQ>R)GKS&4yVP`e(L6x zQ<pE!r&qU+?FOO83-P(=Y;~i0Av*Eg*_YDk<%m7dZSD5koOj=`f2@CajcjC<3bDd$ zwpneSbT+jTUtrOWjqRgR%ga+ZBNpbz6Y&M7(~YE=b`n(3pl@q)x3rlNm|Nc@uZ5|< zf0!s|tHo9;XQ~yFR21W}c^vadRl>SK*+wmE6*RB(6;v#33*QaB>G$iB|Diu{eo#RF zov1jxT>nIM1?GO=*!t}^dY4G|PgKM2<78TN8wv+Let&xc;KjF_2mkYb{?E6=XnfE3 z1$o2+F8{-S_z!Fa{NsQ8kH3$~zspN#Af%@6iRJ~88c0+M2kn6*G=Nid7Y(f%)Pi?; zca3}7fN?+bGe7fg>Tp}JT=G}`%3l!@y!I?AXFmsj_Gf?g`zwuV5WZ=k3J~EtHbgiW z{3N!7oFhFTn9SIt5ZAA9j{GG4dr_Ac+$`W*VJrn3Z>d$vPXcPU0v)lMl&_jhw3=<N zDxgP5z^MAF5ij&;5F}Wk3HTd441BxdB;j%ublXJjGRh(oE{zfsMNNQ~R&v=eV3|w~ zOvXkztPdn5R#&4lQ<Ir=x{!nD(xLOD*2yZ$ur4gjfe6trzjEaYf|a;<=jRt#MEr>f zH!(3m^(2y&HwwQ3{(!CGTsKk#G@7FWdU=QOKj9w<(O=KWhL$7q5GzIUAMr(NzucnP zs8(nUtH2hl6}2_I4nn06E)rcPt@GZX<=_GrtlXH`&8Yz4l;IM5ue!*jGP&{}%{Eb+ zRm%CTav>_zPVZqeVDONTg$rme1SHt6oWov(2Hb79`H6g0gQ>jc%4iWFjxS8j3Oxz< zpN-f@=+fFA!{+2)Md49-TNFWFrk`+9xtt>^+a)U5ZHh3XqF_m#Q?Jj?%|=(FGWTRp ziS~-(zLcPIa;cycEgPC(2ZrOC^pEm=QJdcig=3<ynPRb{siz`UFmi~I4Rs9=h(bCY zRO)0xQch<u2vMG;NsAKc%&u)CYKKReXbmkXsjy6S<9oBS-<SVIyj&a7t<}x-xnlZE zbSC2PU5w2{+`gS5$Vi(mvjv%U(i*|5NRS3Lm&7NFGGhh}pmJsBwjFmJJ|6aw5!Q9| zz|Q-Q-bn;DQA(L~?9BN$<|Ze~>2$;&dFJ8Ae(fLpqksLkfAOh%PTaVB;kg%{om-er z;?V8vb~#<}x$iu1c(6OdR*AXY$|h51XSdI5b~!4=!eX(MME<c@wm$O6hkoTB{KNb1 zzAF@PCo|CwtL1_FAAIuR4{bkm^vg4+U%hbhkZ0sGN1u80;G+*6dT41edg{{Uqjx+; z)WqcUwB6#!BYnTwapU@>d_IAymEG!UX}3D;?%qiMg^O<v^bbPfpPQem7mARw{Z{|} zkzGqu*JfuYdxD*o*7j<td~nBscrpFUzxcO%!hwJCAO1yJ<t$yh|ImYv-S_zA$?K;s zU){g&zDTfVN9WM~kx^@h{go>hF3;U4mNIMkinUTd-nDI~H?pIvpEZB!`kBmT?cDr? zClsm`%7l>KSeOWe-Gu6X`Xe6=d%WGD@aB5$=Jd^HUw-M2U--sKEIQmb`ngYh`lFBE z|KZ2)^?N$HLmsQ8HMYDse{*JLV!6%aB9{rz6a2{ab+ypiO&#e}%H^~L{O%GAvRZj* zbw%y=b##;oO>f<BA+eRqkB;^a^>?~m)-@h8Eo<#I3p%7n_8!fx)h^Dw5$-hq{Nq2} z=?e3d{nVY0ed5lC-@JUXyjkA0cP9k5&akgWcGYa=xfi}}G82xwJ{6n)@Pkixv|Fw& zjz?1qXU|?Lrx7@63x`5Bvni2HUb=pLuy>erT_+CTd2rYEdMV!>>Df6l>OpbF?C#jK z)mvJ#`OHXX-?q-NTDew8r4H@f-sN+u+;{c0jT%A0j$FBla1e=IF|pZLi^UeIm4e^j zrL33r^+2e{<@U0mYvp1w$NoVDUQM-3HaViQ)0J{%1EdbQtZmclk63LkVy~13p;jbz z9)^`xnr{f&@I@&}=!crDdRhMRdH>q;Ka@w+4+`jiD3zd)U;gD^{$UkGIsfM0{G0Cs zko^!VU=(#5_2}JDIKERgFb{5vB>widzy0=;i3*VD1-$Y<_j5l-PN=P^polbJ#zT>R z`-RYQ#O224JK1S(zY3Q5_ayunD^27q8<HB$wI^Angn-M+<WE=@27<ipj?iEPyn+lM zU-2)ck@faZ<eT4GCKr-pL2!UL$ocaJDeb@gxBo_I;zQl~pt-Ff%D38dv@3AgB-qGl zf`-*+OVliX8Gd~&htd#QF&<$WaVp%*nOhOOxHF~Sr0e9nbhz>OZ^3D9=b#RtUtD z<`{rU?U^bemWHIG?5n8iHG_8rAPeJ2e$qY_MQR`H>)E|y4C)AonP4(S=V)ym+rER_ z96fdn<3aClD6EWWgrW;`6>yKxs<3fDmcsFX%hA;pp%4Ng$PNqr2Bb>_v%p-80wv7S z)D>kqDfFq@PWCaCBth_~<^tXFG;<miAV!wE1D!DmjHXFP$)D0ipiJhfR%h4tj|^9v z!l1ma$ZpFQ5x0>G4Z{pqG%DAc!P4MmahkTE$ik))Dsc%V<KSnz95+1w5{gG<P^4xc z6uC&p8B?H)3&34m=1M?D*(nYCO{TP}fWABPg0>6tmI;O{ot`F{7aeOXD`{ZUY*Yph zAe%v<f*2<~T|IaZmEEFWsM3Kl$}*$qJ;|UP2n6@+*^h>|)*w>M8IQ+HO)w6W>7wO3 zbLj;918r8e)p3h%Zt^QHe%X|#SiZ2CGc!*>t)*0k$(^PS(4DauL?(-llAbr_?fdtQ zZuF!`PAPqUjK5kXuQdBx2ECoxa;a`=>2(LY9PUVWWU-i9PAqo^{Kz#%NU-D&?Ax(p z0}=XkdVJ~z**EVvc;FLHe5_hrEo7sL-=t(=vu~b0c^*)E{^jJ#M8xI#*rSjC!(aRx z|NdY7)6ae4sXGtv33@$?s|!Rfj*boI>v<Fx8Jmgexy9x5W~;Zj7OZaueSwI@VTq-o z?&lN9%3?BB+{krUTZyVHR7$2=%h<ra=T;_8-8_B7-#g|CUA=teg)`^>(;t5E)zha4 zZ?#$cW=oK%$@Li5<JT@#N|~{-QIFrfI6wR9$yaLi)|026@9F9H`MQ(Y@?(#Es8C&d z_M6YLklr|bYGP)B$H|o&*J1xFo%prN?8ME9sqqhe{3Am<cTZ1U-#s$?@Bino_XUG{ zMuwB++<$)gi|JzQqjx@eVB3*sA!l#vc>35~*sou^^!mlQrF5~<;|=c(3_f%0$%psc zm5D7cr>9QOTv)6YVzriFXs}{xXC<2~roNuYeaBC18yng_I26yv=a&|c#QCF_pMUYn zxj>}%6CeA`-~HeI#^*lzk%QYuLq12gw7M9bjV>&&mDV%K5&^Lxf1hTcwGItLvbj_? zn`8%IH6CYHvl&HD3`P`Du;{pVMFM?&J!tb_^&<pix0%@2KDzgaY149L_6BCm&wu=9 z26_gcn|!0tTFvE3W82tt>G%8WpZn~`pZUboy(7WQM)JU2`#nQplpDIc2R6#4*+lH6 zbKeXF-O~$`lhYHAJ@|OJRwWPD+{z*=(dUNZ&raIP%jaK8mr^6!2ZN!&h2_~ct0Um) z>~PwzFWgv)FS40fE3Hl5BuQCq$JhXycI5HHtgdXBFV9?_SzRnaoVR)$HnIf-Bawkn zsIO8hWsB)Ru*d5Ss+~|KbiGP8tN7|H(F@gLCY@TT)_5P8c;cYxi6?;qQR{WOJTAA= zDb^XaQFwyzQzKEKe!wcX%yKrNgh88RQDfE1<E!!Z{EPRW9~97kC$Sm{R(qEp=rQjI z3VB<DGWm%S;&qNb2|=Rorp)i;?1y}U-&!y$KmpB@cT?Isp0l-X)R2<DXHj?--!XuA zYf)6}t6%*pu=O2F`?X*DwXMeiA8$YH-D~W8&kDbr6No^4$J6K#B*O(I;ClJBU;BRu zVH6ZAD1;AxYTtZ=XTnkhM(F)|^?`x+_L2o^aNJ;<fZP7nzxr42SO@GGXfvQC?sES8 z`R_DF%rQ!X0xYgg;)cIdizq}Y@LfuyL!@proCXR~|4tvl)&kB1X*G~>!w;`C>E&7j zuNbGvG;TQNn_dc|1P$OC(9^)69F*QL;HeZY`y|4LmYNGF6o@9<AV$UHrqU1c=;YVN zcad&vR>p{RhVLQzVs@*A$T<=WGHOU^kaKZ)X_0G@VTQaHi^o_ClmJ#+S&4F!ojZ5K zS`i&d65QbH;z9(c`GV^ggaT4zc457<&9V}W(l#niRq+{vs&Po;?FXWBgzq$wW{N#2 zy(hgYAHI_w)#LRjt;|Z9*Oka(3MI*~f3^-K#VOSrEw^eM*IOTmy`VI&2xi9H#R#YX z!rI980#s6jr-q2T9%Drf0>`R8By6+_V5QpCNCYp}CNYuRh@JskixQ|T1S%#fH%bv- z?PseP0HN#~Rg#v{6~f$7CuvKAYq5)lhK4ZPq!SEFQogHMq}cQ2h7P@w$yYvjH6IAp zTvO(>G*Glk;a_2D>1jqFW%=yc(*!^0!rOel00oj3hmNJUVB^5>#`jyyA(CBBN9XxB zvAReTNGXe-PuE^0Qn)@o5of|!%-e<rc8?7&E=S=iP&13!qNTC4gyohPlC5L$U6$T^ z@F(d>`Ii9JXeE0sy%MlFfbTSFA)9bo9j{GaiMag-Ms``s8&I|HzT;?pv%<d4N-{n= zJWNLo_YJ`D80iTe*fIF|XFk<ZN!RnqY%-or%rcf<ZwQ^!xuwZ#lQ+Ko(zBN@oSq*) zYi`+i^u9a)<uCuOzw-;9|A|k0==lDf`D_eINTr%1bwpRdv1iOXGU$flw!Yy?7c9Zf zzM*XczOc(=?|Aj>sV{xwkC#%beSQ7Cq0Ygc?h_9_GS^Z%J8>?bTa9?U+k<^ioOrCu z6Pdp`;j-9~fb8w|WKuT?h9*)an@z#EAU)~C^aOKk$F7~*#&*sv%=LG7_4N%PW()ZT z-5!$T?mw{a8d01#u9OglYB#xTJU~|J_3GHz@Gt+3zk#Fo55D*ZVV8$+(nELbkMwjs z_u7kvjh3OoAvU(|+_~@gz9VODj(_3HUmWS`+DymYruBn+4iK4+S_%s)l}(J#+=%pa z?;6|l@S(eRMY^xfUN|#%>Skv4=KNg1AK64*+3ml!I5{>n7zlWN_G6#*dfnkjC>CFR z?ev>}{M@%LT)k<sTBzht{rKnqx1amD|NUqF%47GQu(q$CJ$oh>&lWR9_MCR@*fl&h zOqu|j&4OwW(v}VzINk=qCKUA6DrFjFvzZ15yO0gIIWxJGiU)(?L^A942cnty<%R30 z;eYf)A8j{#u0$7JxO(cj@mChjndcU+q&n8S`+L|0*tcVkqc`9i?b+~m6g_L_CNB60 zN^rYp>C(VZw{v)LQF;1HY9nwnkxip%*<rG6AKN!RIosDc=xFblTU^Yo*S~u4g|DA~ z@!R8PPA%WKuy}JZwpgfS*`bRsFWHzacOSQy*2#KHXvcDFE}n>?M9G609s1?f)nq0^ zV8i9BXQt;T$W9dsb$561>UWZBVy%{|S93VvJIHdN^!RfK*eDqsHSN{oOYsMlLrU#8 z;uKKY^CqjZ_e~ZRPonJGqN&ZCuNJ#KL3FW<r>n8*jU(^D1^%Z{r5_Z~e<!XyDsu0> z_H3ZP{bXM4c%bnpqmRk2xS5F!ee=yX;gEdylEKaI=$^+O`1N1^b%RZg6I#R#-+eu| zp83!I**`PtMhz+X9Z~q!{`pR5erq$i#gk7yiN?-5Rtz%z);c`+;Dc|kJdp#~<q&(& z3wnEw((kXa-{~sMxp(a9-}<fJqC*H<REm(B8<=5mQU2Y(`*#X_Xs@lTI=%niaCr(e z;fUdz7loGFK87QZFTzmAF#Ar!4daO6rUD?Cox67a+W+%w2vEMgOfG-@_16JsVAvO5 zeDNJi``zFDU0Sqf&mO@>J9qA67l?!JSlY`kzf8jg49UN@eT;{W_(}!r%9(;7<@{TI z`lcU3007ZIF2A<{(7B7mBp8n~0XGd~(Clp~P0mregH|OQDhD;BY_LQWa&7)8l`-yh z>nW*7IgQpB-dRDGMjaabm8PVl0?-1BHCugrY8ovLPKGyv`x$5{k)60^IRaxI7duX9 zDoMAbQc2Cgslwm5e(gGZ4+z;^J>7uCJX+a>!pV~-;oH3V=4qx4PYgbg=@H#S2UEjw z;#u3tJ1z<^5+iHalY#>E#8d6#JGTP&tLA7XQlkeNv8D}^#<0-1Ms1QbyF&$q)~d?c z%tnMAatqG0oDnt4LE}4u59rR@91261vPtw_q(hZDjm~Z+CI_8>O-sdu42Cg+r<?}r z6{IXc(T0}`)ljPF(h9#cW>M3UR2W`cj3i?c{0-Sj8&S&G;3LDQCqoO3H%vrhCr3Q= zoPgm+qu4Rf_9rt<3k0>Q_F`oLvZ3hk(K<X3jao@DL+&s=Sh(%0LcD<%X0to!Uq%p5 zKXN<ed?wH}(AB>UVU<Yl0Lfw{aT$X{b(m&oa<hq_FBVtgB*cNnrgH0w<))gmWtTwO z-k6~8&;O|K1;q|-E!3(*j)1wvl&_Un^O-`W8nnCUVYF_}FHW_)Y{&N<?&|5;yMJF- zxN~-Sk=_6ZA~FN{e*5U)=Rf^pE$h%D61X<uC9|ysFAMbSLbb4E)8g=zH`*^v-F)-< z_=~T8<L34Ah4}p5p~$D7dGw$EgTMXHe(CS@M*=q3U@d5?E_O#M;ZWLUt6aZ1mCM%F zYptE3;Lg3<BK@7IT6QUca85B<$P*)TXwRO4+5Ee2{84UY{9aeDHC{}t7QXfBnJ<3h zn=S1don3xHb&nms`<ajY)cyB9Ju@}6xIDRM&#qt~)YsqRX9vgaO(fHctK$w&uu`u3 z{BAOmUY)*XwY8&@GdVTc6G4TumDu`ZD!zOBc1wr(%Jr*V{>b2t!CWTW?Qy?;{`8gW zvyU8p?C7DR=VxzTn7G{Sb^h2rA0<rl^=oIVEwvY4e>Rm~3fipq?%enE1CQNv;z4(S z^s-?{F#qNG|MAlK*G%i?V}r*&b?nJei|gElZ@n@5?UOfOdw%ldLM}QoIJlgSvmBPv zvA*736ol^By=Sbqe`;y*8!x~3-@o+xzw_lUj?c{XboG7Y(WgH1iDy3X%oCsc_(yxf z!S%KB#VhBpT)9@vR!<ze>!*L}ryhOe5i;{)8oS&Ur?VrLT*7tD=HTIj2M+Duqqv%F zCL0O5S~h!nMwd|pa+=Rhym5H%|DV180GBko&hyYZm2*BhpU$~^LQlj1laK*|07+96 zMM@;C>noAIvL9Jjwx6p@`LXGw>p<J`;~<NoNQ)3jFn}O(7+^3nn9wslozv-)Lsgy1 zIi35iy{i7M>26>K07=b^rT{eRRQ>h;JMV9;{jG03FuU*M*RQ{NdE??E2ai24zJG1y z+Ez0K9c#0cOGFd%)AJvF;KRTC(VsnW;NVmu+IF`*aqm`P^MMCW{=;AT_YaQj=~f!Q z_b31A{MpwDo~|{j>*<Y17&E)DcYcn1Ri_W!|Jad-9Id9W+eD%M?8@1%zw}M!YRn%# zF}kp|e!bHuK63g5S;;zecr>0ub!cg;L{Xic=IYYbwY4Qq8<?G4PS{A8=L^lx92gs! z<^+k<8>}qk*V-L&kXIM34GX5jMOtWgv6yKR^jqh2r-+-Q(<-r44`BewKF9%MQ;3Z1 zs?F}=rtBhyH7OxSl8~-Xo3tjrF6o1|@jG)F_z_F};{y6W`lCO(>ytq|Z@olk&YZdP z;=6`&0_#y9|G{^@tH2Isz+J^3;g{bvJ=U8R{-=KGr*6CEuJC#=mf)>dlRJOEf(>GH z%5c}h!x-U=0=*!RG~oURNdCWRHGl90YinzFUVvdksIHk&0^>v{LwwbeXWl}$?C!?9 z)^h=>3^o&0LaL10p4az_C{<u&@fqM!-&qE<P_(;w1Sk6@GpYOsYv-<Z*Xru3y4Anm z;GwChk@AALtx=u#e!siXEQ%VfELyjf&~nylMX0(3tpuZ(I6vMf($b5yzIq=Onc)-K z4JU_yr2Z<VHh_XoZZb%f(Phr^G|LkO$qF_UYKl<+RIhFiA&D@UKwZl{FAp+g0INFs zAmy&;8!e1h$1-VDiiBsu@kLe~ffJES1kP3~INI^VkcAP<sha5Vc#MjJ9f`F2*0-L4 zY;)trA_sJ&F#N{Xzrkf_Tv7y1VHq%!lapk5BtZ7enb%fV)}W3+%Aa4DGuf2vSPuAu zb(r;-HbzNFqF~hzYOuU=X7~WlH~&>dQO%{QqeAPefv`$q;ZG51G2C&jEH7B~`bV`= z;ZDfvs|Bmqn|>C&E`8dnx2ijchX-Or%ZXH_c&9oTf!w@jM^WaH<cOYrP(cJAaCLJ- zRNmR|)%q3Wr*<HZ=0Qd<Ua}u_@Y6F^rK(zTEERS^YDZo96_qlwG=xU<q8&`<%9%Ic zNxCW%C9IvOwNo7%bcc{6k{E#g%b0<;+K1y5Oeqcwh<q3uN7jFwEWI?^PG*NkLn~k~ z82Qa6)SBezWHd3+f}m8)=F;oAoo${Aj*)a%re)z&(1}M6AE0#UY;I;^Y~RAHo*Ypy zjlHo>3ACN9{<2E=PI_Z%!2d9FM|`0R>6PVTdMpsHv>JZ5+wXE69hr&wW82x>*_#*E zceX&H^9PR1F3f)7sV6uKftKAJYL$zdKmE}UdEEYP3*|(ItqIh2SK--Lnm%u|(ZcUO zw6eMgM>$`>N~+&n-#CBm+P9zo?)metW!G*b1OAVE;NgGr>;K7r^N;^OA9?!8x%rvI zaMI=Q)au2_nX&QtsdPSf?b0PWi>TK93-c{|Yb=>KJURRDiTiEw<iC9Bi?7~18}$YD zkM4Qm)YDvY`O3B2P6`Nj{p!s>{L|n2gFpKnLO)+U_gbaWI(q0>(C42>PGq*%nQE)s z*_U2^?$Ex&JLxoOLucmZ<IzMi6m3<?+Z&6SLJFcwJQO4g-M+bnOgi-+{heR?=o63s zv)}($E8CfDxdQd&7k}zAomS;@-~4i##H-DMr<(oMPyT!G>esTFW77woe(<SmyYXi) zJ^$Rr*Hb&&<B>S|ab0e7P)9Zk*;=(QJvD-x`A?qvvwSJH5K4Sv-^qKTlVjdk(Ba4y zS8wjD*Sj8nY}^}+#FEM8(C*&7bC2G4`jbyQ4td`1a$mS|?Zww${lEUz?|%04pNCie zfrlUan}6+RKl7Q7J^0|Mxyi9cxwN^y`oI03zxCh!&;R@R8%rnddvJV)!?8rEL_lq8 zetP=8<0mG^r_gjtWeYo{>J`j3kIUz91f#(}`sQcvJ9W>=`yTu1ndhRTBd*~jp{T?J z|Mdqx{lvZp7gw(T@iU(*cS{#;UiIzTx7OEvZSOBV@k<|n=;?`(;q~s;*RFo&pMU*d z#YPe#PcRmatgNq)%<tHqgR}DsQ*-mRX8riFQ{R30`J1WLNGNz{Z2u=7_=%r;;L|h7 zae}Q;-3j6iAV)_y@x%j<96xYWJO?b|&1xo{A%3UOs+H=Ucwz#L8icCW)^6e%S(rP3 z;$$>BGCDG5m~qI27MhKk%LTD03=0r|9*!hEk|R%cI$e~zZOnBCi=mmuvg*LV8Nxm9 z@QJ^oDcmz6OhUe3v(rjf@|dQUPte+T?ws$sGW^@{`mq2#Nb#;-XQ(WLyzMt_$GcKT z$O?4VAHFHQ8w7CY4}bcnfBLR>qnxKtpMKL4-g&{D6`Yxw`N8-3p{n`)3WfvHdI~24 zzw<l4^Mef%z&(`oza$>cU7K1B8v|8$@t`mR4J)9BS=HT$!%xAnqE+R40P?Iq)unpZ z_EgraM)L6#RXM!vMR!{;%VKi#3D-aV_~Un851?0|cGqBT(7ff=RkK7f1b4pc-Qaxl z2;iFrMBe!lU#zLPIzg4QL9=KX6i=)3UfrdN-Yj%(WU8fwL3ks>Biu);rjj+hQDChN z$iK>-(Q7PpE^qpO7{m&uH-O!!nh25;%-sWXf;cTlzVI&OrK&6n8TA6GQQz25T%}J` zPd5JpT;l?#`lV_`$TNW;$L>gB13^K7=~T)Pu3Yff8RytV2M-<uH{;pGUH!!4j}H$g zLHTGPLgU7(2k8Pv$MNIGAdQg0l-ok9jYng6F-?)W&`^Mm<fqpzFr}84DUcM;+6=gy z4<xgx;XV;Iz!SBvt%@rY)@thA2pg3%C}V5U$dbXd)l2uw*#aS<lHZDOH-r1duWSS^ z<hKs@kehf=G~0LRw5B-eH8WUG2$CBDWKBjeImMz`AQ$Or4Cfe{mX(|L(=B5u;L;oN z1R_GAui@yDpj&fCh%s&cRVc3|=Z5?iQV>Io*47VYzL>8xtkzI?<i%Im57=6~L1P;a zy&0L}hBx$9Z3~-9VKV&iUxL@UhBs@gYw)&d2g*q=XLDIn&tUd&rEm)zj@(Wf`^CX3 zVRsQA>-C3GU&I|pkN{^i6bQjP^65xKgvW!@&GluNInp3_2~=Q|TUnOB4mq9py@I_1 z|BqRWZFjA>#Z=m#n239W316_>s7-`oFRoq%H(pFF$Ah7yKfaMqKY!`W`IXD{pmTWd z{2nMBhYq@Z_LBz}LVjnroufZsHQU^YN;#J))G>S`o=7Y-mTwT39Y`0!yly+e$X<Uo zmvgwHOB*}iIrGvBFMfMtd8t#$-+yG^fBGN(+JEzp|Jx6L;HToT1Y90Rpp`G@v&CYr z-rg#=a@8(*T1Ufy+3Dod?|XD)&ynB1_}y2pKl8!)qmNA-CsXN{UwP?&|J{FyzB?l- z91J2)p3m35^X+Fp_ql&@;nMf^ADEY{qLr2_<h}3V4_8~RmtTGHgHL??fm4rFYvnI} z?T`NG^S^!h`jv96_2sXB_3WkBIlUc^kHmwqiNqv$5GU?)FFkYO(4lA`czDmjnc1oT z>39B@+}6gU_nsb`n)<>szkhUi;_v+AFXf9nfAq|kUcB(KGw6c)Keupnc>JI}G;(8S zyS3ZgNoQ6|>DN;?U%mF?Ol<t)CqK#xb7cBpW+ip?%8liXt&<B6-ZOLb<M%v08=ktb zbaAb`{nFCK>pPp3MiUqMHIiv%w$WApz@ra8bl<5b9)1WuT%}R@qp$zjKmF`)|Fb{& z{fp~2j~zeptH1p3{-gi!KlsFlp0wH9@u=Tp>s-Bf;iVV8hbvpcSGu-%B<}XQ4;-3r z@0K{Ta(i8Srl$5y&!Jm8Je_Qow~rn;bn>D1|Jn8LJeNQBKfU<bZ{B$AO09S<vwD4f zDV<9_b^OU+`pn;5TP^(l@Biu7zxl1H#Kg|(wyn|K&Xle$FMs-hk3F#Ww96mauIC&P z&+ObR>ZEhCb4bv7hlqV}k0(cAtpD^!KSgl=PP4RGgEP~CaW(FVy>H=U+~tMz|I(|^ zdfm3+M97ASDtqoOQnvO+yI!tjh(g9O&qPkd5(oDoUV3cL+}>y;Ha;>z?lB4QY1TMs zWXD6hrdA<;?6znEm2;gog1LEdKeQX{Pac0{$mwIza=OWH6&gY<0I4Aqz~t3!b$LXW zux2OAAq$ty9`_0r4OhLc#<%@zZGZatJ9<rc>&w`W4(QphKKaQ{-t|eJ`qZc1dI`AF z$_O*~t1o`>i+8=rpmz9Mf66z$@s00yF;wrjexDz3<@ZzYw0@%8q1#^HubMRPU5zE; z{|4^>KL@Q3xFr}-KLFX|Oa9BC-`v%Pp{W(@0*~03!6Fn`;i)yp1SApR()WNWZcrdQ z$jP~DYqMFa3tt`BcWrj`e=PK-jC{*{|NY<p{X1_vGc&D7nw+C|e#_l>mPTso>YzxS zpWO9sdK11Sj`6Nl(BNRLvZ8i<Z!JmsD?ZnD(|`3tg;~OU835CKF8n2fn-$PV<|DNP z<Y=-dd8x45eAt&??8nFohmjR}fJ1Vp0ifL^fY{vGgkavvY1QjQ1M(=XklD>k`&2;| zoesT{r9bHRZ*8ZT_(Vm~gK*-B3A_LF{ijZzB>V<EjX{e6bLPw|AbY|?SJzfAU%9fd zXAhPkP@9`^K+Mp>J%8rRtJntn_U=JEj%Q`_S@=2XyETp<fUm%4t+fTmwIb3`MwdqS z0~O3s8GCM`I*(ef9<1*pMgCNKQVHe2Ul6AlnO+74Xw?r9AAAoK=ALRBNDwKWS6DIJ zt%=s2M=U6W+nVg({z7g?i@`ACS0*Kv*b>|ymXYBg2{&EMR}E7Za++FMyJT1QRSP24 zgh$rpk2=Vj+^lqJBnqIxL^?<0fUrG`BTNU9jHn?S(E>VK<>=*&P*?|&w3~4Bg-oNV zySbIsjJ<7An-}ZU+?*0&d*Ga>qiIGWdg&?hR1jaym|=)YF*+Ui(=@Ijm`Q{!D&e$) z+ecl4B0k;14zWQKB7-l{lN1D^MK)jHbJ_x-KjQ=tr+|(zYoZOlzw7LK+kPk|=jh3{ z>ymVswv9?ITQ6NquP$Y`Mgw6c-2*cRnEF1K<Lt(bwL)e%jB0!s?eVQt=GiN+FW0j3 zhYuXO@5GU#C+o#*t6Fa%l7c4%3WUSIo!QLgGSyO!z7B>*M@FWb9oOrxU%^)Ekl!>E z&lPgHLLpZwZ)~MsI`hJdFF*JCnP+xV%j1dQr$6?y|M(yL#((|~{^8&F<VS<<W-v75 z3^^N)?n))IQd-+PKmMVI9*fWH``p#<e)r-R=bXM%fth2;g%f*DIT}MnB4^7e@U+D; z_j+TYc+eXmN7lsXC_&!q8!NA0I{TGxe0c}4mDFann0o!(_pUEq`Sd4$`omBER3tDq zJ2k(tx{BYINr<()y0Jz%3Hg2GzWe{lfBs)W%Kq$E|Ln@v(n~LY@6r42`P9>&JiEQ~ z?VFdk>YMlMKm7jFk0plZwzHXid-fvD^MC*G?|$}cp9=<jpZLh9_Ut*(B$m?^9iJS( znZEwJU;6E%W7D6$|HHLnc{UMock7Xuf2Y%U>E_KWnNRa;=dQfGcY6Lm{?xC|L?UZz zmtMc}@|B&{Mz=jaI*sb;<kTEXKrk3Ny#LU>$BumH@y8#!=N??rXD^)pgFpZLfBjGY zhc7?#^<B69lb`yD|Kk7qk3aqKkM5hB+A}$k&t%~Wt}LxPY>xLm_{hEYoDPKinLIh9 zavfJ^r?~Cx*y3X&uU&t2cc}i;AN!efF8%8AONCY{>~*Z<)=2jB(ZdgX<iNdSL(WLM z<1DvZ#q#3iSD$<KJI{RQTl)_lSlQY7y>I;aD`(ES@~v3gI}u3k<WeW^Kb{(@?L9nS zx7UNQP_ACQ|NaNjgnjPCXDf~>9dvp5>dNM7GLgKox_D{rYPOggi;NA`b`MS;T$r2+ z`68|EP_d9Ll=H<(E*J_VV^IiocxIT|lKZTTs)4UuL06y|4w2~Dz1y<4TZArWiSA~- zlLe8}MA<&v1riJAQ=w3Fbaa8muT~>8pL2WE?>VM!u&e>&ad!atS=c--lJJID;1IQB zonf&kR0>Rc((%bU-<KEDo%gn#)LQLz?!Sw{{f`LfLDdgD@W5T!#?U-|aAwmx*VB9M zx#!LgA&uOL-GRC24F2F1nN+fOUH~}0tCt$C`CpkH&Rxae?^;dDe^(8AKEKl{0QwO9 zN$rd{cjo&A`+oJSU;PW;$?giKX==_56fMED0idw&f-9^!rcm3U1g9cn%e+>$13y&9 z=bZ&M_Y_)$I#am`y!JaU<6J_!Tc@tNjd{a|cU704oSf1E-<2w+cQc881g)w$fg2K_ zf7iQBPfv3h=#FP99K7vieW-P`{09bK-ik&Y{H^hv_Jl-kTdge9#jI);xDj`$SOO*~ zl7cgRalHgk_C4-;XYB&(L;Xa`qZqIc?DTW1Yb=PbM-AHGz1}nuDEeXV5k`m*u?Qd- zp_3Ay+7PTcK0dL3|319%$kcGLdR`SEf&w3T<dNaw5iaI9Vr^}8W@Z+-L#<jJ#3DZ* z18puXFLPeR-@sqShDU(4tz5+`%=vr~2Qvm>FSb{6?)IU%;h6LqmN&%U!qUm*bKC?} ztsTebS_RV%y=H{kk8wh2O`wRWCMPX2JR}Z;U*Lr1QVnZXYLkp!kNMCO5)Dl}*)IMR z4}HwAYq(NRtE`rkTN&z<wkl9w+mq(eiD2R<Ig@b)<0Dc!;Co$yfN_c8fump~yrezB z$+VIZI#i5^x3JMj2&$H<nuz)o*&q8{BR-LcWW%ASwJ~xS`8ohBBNMD9JFAeJ95fn6 z2p2Fzh-AgfAX#QfIBK&&rlM-99fXkvZO!BL)yf55WVl?)f)a>rreh#7kx8e4Bi}SW z*-VjbLA>(D@+$wXZ*4PZL}kYe73~^p>}k8*Ipf|DpGe8EkkOvsZO1)<u**B@k3Kkc zU^En^X)~4Lwe;H6^jf3cd~DA#pVOQ4MXHVFa5z33NzBCJ*n(eu{Uw_>*z~xdFg5`~ z^&&miCW_Rbz&p;!s<q3xQVQ}`FyI{@9`m_;!d_^#w|BO3C2|0F<B?%xNvfS@rc%4Q zp8DQP&z^bl+iQy#9qsM|2ao=}pZ{yW_nZH}|MoxqkACK(PaT*VAM-dLJ96l;2kxIZ zaQHjhH@<%98~2YN{>A$~<##);Zl%8PwdbCD>3c1J9k@>tDRj4YHdC3+QmKs9nMjNu zJb3(p(+_NItw(&`rR$fjUwh@gBS+^a=fC&L%m3nc{v{r${rexddUf&I^-B{Y<50$$ z^`_V5LF)10)2Gg#du=O~9-f#k=JFqU>gmqz(05+`UN{greDuV(U;b_>y?uP&iCtIn z>t|jqmFu~D<^A_P{-6AN|G>4|{o`+c{!hO1#ag>Nci_;j!{2P%Zd|^&H<?%%o%#Bi z=bpd%qHnhrvp1#_{*#9fzVD&O$K#WU2#FBJmUD&Aoqe|MwEx^ke)g9?^4Fc+=67Cy z{<ZDv=QB%JGHV=)1;dGKzL?5oIFr8b#PJV3_~?B{j^oneRO=7E_=V4X^{Zd|?z1FD zz4x9|zw#@8>-7DnBN(nWJJRpiR8T!flcU?|9WqRjXbA_l*Gcek;^MW7=NHc(yZ6*) zDt}|`3P)2xR)}5u{^-ndY3F*CgM`&Fe{6nq_R{6+AAJ17|JgtIM<4sxhr@~BN<Dpk z@$ys0?*FMLKelILZhbqI-pbrNdt^E?ynpW=?`U8LlcAmShuzmUZ$5C}gU5~^d*#N3 zo29MEJ$t6c=dN#GE7kHxC-wz~{F&4anIldeJvB8p&%7+xik#9EN~PVQfXRx5xPH** zC8;oL40^#HlG@^naJ%fV=Xb@Q0AH-Z{_hEh_+G76!2yy;OyY<Shm(oK6h4J=r9h6@ zMw7g9OkM(&m19~nV)Np$7dE3%7KI|{_L5poEctja%I+r1sqsx%yOOne>1t*z2-ZHU zpT8?#KOCTEj-f~c2>t;XSXH*~hkD%=f`hZ+Gaxylu4SM+k0!s;n@S4a=EJs1f|r_- zTSkK3?JrRL{!Od=;DZm|dChIr<boeius4<E0o+4Lx~qZo!)69})9P>m&${cez%Ts5 zFZ|lC{ThNoN)(|7(SoG$nU;bmjLTN3*j5OvLPqngJo&CTSbwW-a-F5jWYQ1awG4DO zVHhy%4XASPh64QD&;8t;_2TESlJsN%qwB7BBP!tU{@uT;S*R!*VcdW3@BIhg?`~jF zt;_cd0}#%$(3B0ox$nld*fO%*3@kWS%c%CeB7SKHjv57=nJ8F6j8aXFB<5S*h%0n} zAEMC5V&iBF>%WS^b(ym;z2a8U!R)IpT84o+B<L+2io7idZmpp}%t6<wmZT;pvv$-S zC`v3IE0s%QV-sLF@FFIfI@Fbv#k@d+60IA41^HxQegQuA!2<^w#_W-DXS*FDHe?KF zIY3*DtmQ}qu!m5(;iAC!at=#M7gU@xmcF4prO)rzwxXIAUI+SDD^=7cXjpinI$8!X zqLEXSmP9yHz`7yosKULr9)ALPfwR&J{V0*%pjB3qi3Y1xi||Z9Hn{3ZEopRxZu!os z8Xw>bXM>bvOhz}RFVrZ<9rPp@$S3^B;R44uiiAIQ+m(XT7m<1ipN2yN9Qi`Hr)$Cg zCasp3b6P2V@vYuj-}6#vuHAQQ_=yGX!sy~$Udc9GVA+`xE&|WTfPQlTWlv|)uzIj+ zpvyzMhjUvlmEr$Dpu&t7&`*uqEngrkncksM#fE7X+;`}INaTYFdxf@<OvLA>r!b$8 zAHp}!5TbOH3K+_S&||&9N&U{<txd`0AMBNo%aibj0r7=K1xfgFvwmQBvIIw_J9O{# zAu8_oc$?kUL^%2S`b|Ld)y!JR8>+HA)a&W&8nTu&j4||xy_Q5Dbj!%pks+toJ|xx^ zBOw%Uf8>LY4#R(sO`#IFfA1lVP&T%gSPZ&0Cj>9%{q|1w`s&szXJ2{Yd(Xb|+KbC; zmt8~UCypQgdq4S8|LEs`;nR;ldg9>04?OVXx$@FiFMWNlJG9>wujU)E$bzHeKYQ*> zdMA~PMA`_Fm&j{7M6M`?7O_9Ea13Gjt<B9td+z_lM}CpHbM5-sW5@5=bNIL~7CCxo z?_-ZVa{ls}-}>$U?&a6MU8<m4x>T*w?@loNL~{7A{p4pp`7=NB8~@vHBAkEr(wWgv z?7@3a+HIXb{m!4C-@G0QM?QM`efRFW=TE=>#m{}=k2f~6seJkQS6(hvZD7Ww%=&jO ze)nH~`FH=|>wol>i_iVmGrym$SO4~he#P0vytKu`p>MqW%%!D^gbyE`+5f=d`zEI5 zo!+Q78oQdh`KPaZ>HqxJ@BYT`|94x(?Z5rOpZ_}_|HZK1b7S$<XU>21%;ve9`E@(0 zHL=*P)4rA6_D6%qj~#pL!H3`f&_fU2dm1bCi{JV3Kl`KK`NoUSx0yZ;Ry^-;A~`iS z-rQ}bOR29v^R;v)A5V-Gt2+U&n*iMFD>rVYE<F9%huxv^fBB6+zPYj5u2lCr#{M7o ze&&h2_w3fH|MWZm`db?prl$_PaQ20KDRpJ(%Ej%~u50MPk%M1-?b~k8F2^YLnhh>H zX|0A@_9}S|s-0-9^T6!!Pd@nc^hm5-PrY{Sg?zhwy|{8Ab@@hm>H5uUFI|82%(YiZ zInb?jx7W8Sx!lRa2gc&zR<m4h;bAX9hCxEVSgGK(a16Qp9v{B;@v-UQL;^n>r$+D| z_wP9h`MuMEEQZW{wODPGDp@ajMv>7#Ae@Mgx_!az?4}&qNn*YfI}LFfL+DouS8$hs z%8fbsWB(ys*zNQP%@3xcoFUsgqyuQxg;U6prpac_(xuD5ovVShB@LSWcfx>o$0u(I z&;xgLzsLJdmeU^qg2`(1rX2S>8;+mcRgaQQ9pQGq;?a1{c=Vg1d2Wsm`}@g0QgTcY ztqXU%E2rfzuU`R+cP-dpHGgoye)U&>b+C9CIeG|w+lxl~%d5q0cm9X}@E_jwSu{0v zg>qf!K_YY|?~lvPq*9cxvrCx+yaA;ttW<42(5>bFyY2ppI8}bpfXVjvt1nC>x?3>^ zg+cb`u0^E^3X2tWeZRZu;Gsqo3<00-Hw(C%f_472f@p7hE(Z(>BKcg4r-T^=Ndlma z#=M0ljYqaCV9Y>Cg;^>&uYB=A`FZPEN~u@P933GRjMMjeA8k){u`A-YzO@Qq{ZPwn zMU*O}vwF%Zv%+@^2U{25yuEbgDv=fKuCOwo+<>!5ECn%xKjD)YflH|)un)&D|DsBX zSD3H_<V{daCuJ<^^@>UXc-)!%<$!RW$S*kjrhjNeI!Pj|%#j86A(Rtjsm&l2G=;ND zYq@y&1i}Zx_I!^;1gzI8SPi9(qsdcw0kwrS)@64g<WzCCc#GRDfvvm;r)tB}-V}wF z;#UMC@`=YE^7w>1BrYjY`|d?P&>Q?vvaXvR6L{?)b%SJ$<(~X$a%qYBjfTd`K<I+# z8s5kV5Z)abHkD&yG(7=7w{W|~xjyK|wg^`=KIV&_e)NY;FMG@2Nf9?Oe5KwY3_WEy zR6M#TZwf%CY&zQcA<cry4LbDXmZwiSErIQ`w!Vr)ss04R9;BW~4o9L%Zi^bd-Q_Li zbE`|&iAu&}M=UdgL~_I<;_0;GPrk9df~e?7GJass9Jzd@Q;el&9Sz+Y_HRrybJr>V zcK#3_rN{1K+%A`Q7E5VTa&lyIa%`bkug)b#u^@NKxav0w)$---6|c)R9FAVvUhz16 zn1Dw{XECLoJaQVCMWD%$+t+Fq9sZ=t8|>P;rE-o)2FT5s>^cFUL+zs5F4i$gsRCX< zWUzcb9gmD6AI|AiC=jYt3sq7Gv}%nm;i~D^&Yyqo`R`u1aCv2A(b*~9zkl>+o_zcR z4?eZpZhYzL3+|!X<Ma1U`yzg)`@1i`_Rl~2yM#kT8R5ueiVxM+mF%d5PsjmLb|?4z zv)}#7SHJQ<{?q^Qo8S0yz0y8@?7orV(T$B|m}TWg*%gS+%^znTurk2BfI1J^fB)Rx zLx&G0Be5@k>r1<ij@RiP9v(e*^63Bk`~S<UmtQ@7{E?$aPk!MmpZ)NmdmlXY)U}(d zIP9kqv#*`K{QR>o<|>uX{`ns+Zrog$of$*ueSDn!Wq<s_m#*!sqoUHNH}_4<pWJhT z*>)pe{@%5X7ZFR%l~&d^F0L+5&+W_9D(6-%V_UYp;Nu{tU@u&L{rrt{4^B;daPPvs zkx1s|`E$!>E~YNt%q*1=RZLDmE5DgpD^<&=_uPB(FlP^k_Mt1f{@s_J``j1)<hj>h zSjnu1#-e3cv)FDF8ntt)SDayY$JQMm9v_KMWNP^vsT=c?druyI<d47g`5;S0y}92x z|Cu9?`>;z&)rsNpN2iX=gc9W6J3fE#fs^;&xUuBvxSxFJsriwq2d4MihAKmW-85eO z?Nz(mUhNb%wwB4nynkjo>e#)0?c&11;U}K_*pv4><nzExcP7W;@MqSF>-A1^YGNkp zj|AMIW~JiywWmiCZilx)94_Z+LwH|2nCIDiW;?x=Eo2e7ipP?v%od0{86&fB@W8@R zl&Lz+A}gZ9lW-6S>t#K37fS`E9;*Q%@Z8Jq^^;r-5u0cvIXX5EQ;}ttbyp;PTeaPG zowb(mSynX-UK-e6#Cbq0FVn<C^RO_>|Ldk>xv>VPxrLDiH>S7qI`E^F?JWWNw|Hy( z$7D5nix=N^*>C>lZ~kaMyz8(2V$)Rp1r`j+^B?(cH1BQ3(hrqC>-!lwKXQ5Whrj&G zzx)=H1L*b2v{Ba}e;SH2dEj;>CncwM2C4Ij$qjjT%8kxy017~aIn12@n}73f{!nEY ztTI2O3V;*EY7_uY*N=0zzxB8NmH}kqW>ypB&K6dew$?%~vmD+6iTcP%+Q)E9^gh<V zdc#5Aq~1Z-tR9#)G!M-HC2O2gkBr4)IokC~rOjJ+Q;)m$j(Xxvk$SQ@+Hva0wZ661 zQ2mvbO)QXplj^Pb7o06zDRCa+d=bNd%7Xt$Jwy<x(faHy%3KebN>v&O1BJx|+a9z{ zLRlY*kKqWvipF9G4(yiz)_^~eOpK0=EG^vx@h66d5p^MK4xbxm{gQ*q>t(0t1JGWl z^r5yktTY!RipOCdaPvVjnD&U(mAtVISST<aXjM|u8xr>^Xx`z#4&hdMN@I+GTT~Fd z?P6^S{B7Hv65@r&)DX)BC3AD}kc&IL7dU|hh`5cq(gF0mxQr6Y1#+HaclzP*NYa*G z7j(K%(m}=AUEE4?Ihi!E6oL_HbovQGfU$!%sF3fakYcOw#NLjmBdTY@^(ii5e&Zsu zO9z^mTFKJIWfn(HO%9D3H&$5)!OaRn9`!nhFc>Oa&!g#-Qn`QzCeS|;8-WtfU{4N@ zqKPTi0!$ksiRE+%VpU^xee>X+g-n*OI!LXP&45B;xd}S#hqYK8bk`Yo=Nx<+ej<}p z&nHQn&}klwj7@~1bj$Uft#v|+Yh_lbnfQpb;Ly-;C<?g0p5E{}Tw!luB0T)++TwCP zMSrkn)Qh=Vy#;A35Sk?V2ZfOFiKCHl60$O4Ie|cEVP^mQ#2$DZI7eG;xD6aB)kDaM z+IEfK)Q&7VJPP>D{&0fhRAf$ef!Ec>##ZLsrSmUbc<H&t^Xbm+maXy4rB}W6&ON?a zd!^+g^fD0fJDkx#2sbUZw>ga==oy8jT@fyCv`JZ7EHi+2L3s#^7mKM1dDa>*bHby; z6P*^Zl_MZM2w0=>(V>n#;0`bV_D;{j$U1)L$glq0zk7c1`WL_WCEVCoZ(Mx(p+|rI zQ$M?r%f7ID@k)C6iTfV-&|~jkU(4hQH5A-QH+^kwX>H@?)hm}*Z?5f$&3c+coa<HF zB<rf*clg+Jayahy<q6QVwP~MFDDaD)_?r)(e(dnE(`|=08c!~5F28W~?6=Q8U$j+L zOY0-v$m53|IyH9`OUF6XUAcKPwCg<@pZw6_2M&+V1j7DIIk$vVP!SAmOA^o=4wq|{ z#pN52!XG&G;7@$`WA~jr=??`q3+r=xr%xR}@YG}XKm6da@u}g-iQ#KY7wt}jg5plU z_x$yX`{wq2`~#o(!ZUxqlD%1XHa7BG4;+5%-UIg>n3{?Df;TTN4OQ#Md?QmdW37F2 zd3`uZD%*)%i7XBNr|*68(7qG(Zhm@tWQW01FHP;64J9L^qr>x4({P{yiNxoh`^I** zbZYPEus3{a;l%sq9&R;T2NQe7L&GDE*e*Vba&_P2<OkpPI4e=DR%&&Iu<hEr!0Vw% zd=%pl;!P|v5{)Lpp$Kzbj{bH#qsat*Jd+ZwT(4xh?Hche2rkJ=Vs|lN!(mqS24j+6 zvB)7v21_1%Z?efDaZ?xSJnOB5!`e9AX=46!G(%D=A=5*&!}m8-s#m-&j+-PvOqR7i z;Zu*$bv4t~PqxuMQBpsD8_xZ|s3QG^0ea{S2#x>9#Ui-#N0x-Y^PvFWzrefw$d$VD zhdAkx!~YR(i0tNV%?thGH-6(c-r}u5^LJ(Nzr~;bfXg8H{NW$|;aidZ6!iuZs%Y?E z57sLoS&eUw&iGfgT*Sj|^1$8pQp{>#NsqD34RNXd;UE6NTPeeBcjG7j`d|NRq4`Rw zdYoVmJ>FuC?z|f@vfNFV60nYeHFq&fc${iba+!L#^(P8~g)P&M%4fkcsMnAmM2STf zJ>!+_Ro^Ouu3Q!ZljrJMW@H6b;Y8Q6J|OQoJS-(jt0Sz-^q!`8Z>XzcILqR)-0ED} zTUd>nnEu9qf8_<?QgzMGOwqOQR>T)u#b1c9*(fm#kmK<aQ+Y*)P-}pIY~d)_Fl;1K zsolPB-+p8+1($RBVa|49(HKZ~c6Nq~H`g~Mlvc7mNim4161m0}>XW^Ut$lsNo*?}j z3=)HL6@vmncsi)m+6lBr)M>3BTFoKHO(vW}Z8I^|z_`X*<5ucZ=e-q|EbUL@P(qSM zwIrh|<6JC(-YJS$J{D68kEUjvrKZqVFb}XypcEQYRtfi-Us;X}WYaPsuv7ys3(u6( zgFZh^n%`7VMnZ4K$p9hRmg5T@75XnV?VA%lZo0M`Mg>o27uTp5y_>#F7vHi=VQvTs zYIm3LhH4f4^g5;&T@1&TCy?fy@^doa^FkZ(Qd>#{!~%RyOib?Gvmf6)kjor{?4p{t zvbq+)L%*^L5j&I1iDlAgVgONE28NvVnWf-euutnG6T*RQH|7o%TjgPYP!vE}E;^ln z$2%Dr&eh6W<vdr#e8I!Wua8XcNsLvRHAeaIiTOh#Gk8z)crI<8YN3GRxz(!Ft2uul z5{-{BT1Xh+b^B~~=k?{QfON!iu#Kn3W|08zw%|icuoHUVo9VS$MM4kVo?xz2$d^I# zO@5V#PeLZUa`VE4rNz!}#O)jY^5V-ctiF6=Y<}K94ioy!;*CG}^4HIvI}1BpNOUec zL5o<ajAWjkh{Zjq8F>S+>XDVDm!Ya5vqToP^B2x8-&{(i3vRbaoqX*pgvoBMZ>?7< zHR`}Jm`o<#fBL~^zWI&U&b=Opj=G%QPk;OqiBRy_=U!M_-X0kpzq)i`V{!49AN^Fj z)+!cv(mCRLOTM7vq0`4h5o`+A{P5IJ%~4z_#dqVESFYEF$bDAE{{FcqJ{fR&UcC77 z<(t>Cn<-nRu`s%4c6{0&a_tT^j_o^mY3cR$P(AJqOox*nJn+b)3lG^F_PtZ%qv7b8 zYgb>qwz^bek&I3HX78Ci_OnlZ{K*p!$G!e^W#?*PW4)D4HFLgjkS<DXXA1e!$rHyz z(a_jfd|`Iv$av`V{1~Ryr$6?gPk-p?$By5>d~<O<vw3~}D(m+{ryo0i{mSK)*Gjf3 ze(O&>^zrVH>%aaN|NHC9OAzsnPVU*~8HadNu9cRS*S`7ebD#aQ&;OVI{r~Xa|F8e+ zZ~yB*{PV9q)2{jtOdPX!?8Q>rZEq~Dt>DgaczpR%CEyE{OQreb*nz3(mzOWRzI+*K z-^uyoK5r;XTy!z#Y<KgiT)mP#ynhz+jB`^CNb4x&SL>N_b#n&+%1$&G9UGn!-kh-P z>TajK)vnJ??;RVR7T-d>2Fc3dj&*h&0@fYwfDE>T*B>gDGNR<;_A~2&>3&}b|9vnJ zC)<?7zsefK!5nCw^6rv~kX*XxgL%C{GFq_2Han6|ZX}#!2+2C%cR%UMtn08YN7h1Z z`LL{o?zX-AUGwK(44}vHOxm3vN~-eC7UT|Z1%<z9Vkx~dI__`9C;g+r>mR54i5TXg zKNR|;BBYwSt$E)%uLghfT@xz(IJFr3EvCXZzxmBKt&tI1>|u96EK59R_dN_`5Ut{v zKH?Xq!JQ>!mKxM3SOo8;Ir^9F{MfN$U;Elue<;s77k}+*UpsZ`o<2Mko{VB3t<evA zH+}*qN2{O<2e3x{2e-Wh1sc+kIu34IcLrly4HZXT=FG7NxePeF74D-T%rXh|SxU~4 zS6_Y7`2TvqT)Ev^Unzk3uNni^zlxCbwuY?Od!jyzUDjG04Kcf?3nsTRFD(XtnzIPi zxhG0h61c9X5Sg|SF*!LkB|c#zfCw=|{rb8V<DLiK&&<qSzI^%GwX3jiL>S(LTEf?q zVt2c-XmmTZ%~w2qVPQT_M#u3nb_O6dik5iFC30C5&+9r!s2$snB4(?POf8H8zi9!k zhb6)r_0Y>`G{9BgTfb5pOr$C`MXT9JEIlP{D~30<)x!~O7X4f*h=Z9uO2VckYF6){ zI*|&&^)gBe<Tb60W4>&N^<w3s(aB}(unN8vqVqqe2lxjIg-pPtPe&#~6j60}7*>2= zD2XIP<biUCc50Q>^OCBm7rbH(34WrT$jwEWzn|S11B^otX*4q$b+m}QkFha~?ExW2 z;s?;q$1XA%b9>hqx|&k}D^U~J2B^>HcThhehJYyMQZZ}VTr7DBmv?jMVJGZZ^h{Ao zsa6+erjVuQ7Fa*zximvgDMz<Vi#zAqJLnS~9vZd6|2v7<bht9L!lC4Z+u@iACv)|3 z*c;q8JT;%3yq4Km+}RoqMQGeGO8<7-Y+{(ugSAqjKyHfN7FgV6Lte@44-ZF^lMt6< zoP^-j-))T~NzOJ02t^;0nZQ8XKX>%t-s5gE_u4(NU@RFK;RFp8@mM?=2qt#2`IpYU zhIo9XoGDdy-0`vQ<eq%M({#5c{NV?q2kO=O7gt}{v{l#z$SJY9nb|3pkQamtwwX>L zj5#$qZ+CjP5HM}m3nkR=tMp$gzXLcE1X-yE{l0I0_v`1+y>#L1i+}!SU$}bpd_KEF zBqYpAV!KJ-?Du&7`lo*K=l=T7{@$PcA;|Him!HQT_`v&~&etkuZ(g~HeB{c?|LdoI zX(gZg-npx<Uc7#F@v_6`TG)R$GCaBe(0y)K#2=2>eX+gs_uRYi$m7#bP1eV@uB|o; z?Q7fHO_x1WFJ8F*`u(RKyP8^g;lg(axI8+0vek8c{pDv;TPtCQw_R%{ec>Z>ht6HQ zvbwe6Z#P}d+`-vNBwIGqTe#uNjnakdm)gzF!$(g4JCA?nu@m=2WA3f&swd!Ft)~Jb zk-6#NU?TAK*S>vq{raP)AAbD)BV*xCDZje9y?*Wbl>@`0pL*!=U--<=qj6N(UjN9G zAH0-Z|G!`TQqI+k#zt!`+h-pB<Zd;CseuIkm79x1xjujPwQpX&^0{Z8{oOBquG?vB zuB=2u@$IeDm8(}@dFiF!`t5)I`lTD2naosT=A-w2=#hg*yhEK#Z717BZ?pj==KjO? z9GgDUu2q+|m!G}<^3BX9-td6K4e=$joyupo?>%vNBp!haS*>J2*rgg0!0C<cP5LyG zO>L)E)7g#fosE2fIN;XU$k>rXCrA#4LQSj2abm~jBpY<6R<Gpp`OHqHR;?6@JB3o# z<@Q6mt5%C%a%u%*#!;nm$sGKN8W_PpW>rQiO_G|sB}<*j$07)Rh@fy>7kbpFn~^og zb&1x6OIFmrr%V@ceGOj!4q6=EVo`rwKo11JapML#Q{UqAe(+^r`Y(Lp3qJrF!qI=z z#8UbQ;4dH;OXK_9jn4trKdd0nUr051D8T@4#d-l#Qph{eJjHm6JQJQmdfgw>)_T)g z6Pb#7=9|_C1fxK~AX@Qj0(q64!gRHuOdqx1nuK@GM)iDK>K}ljQ>X4FZzvgj-_*3= zg8%Bj`mdgU{<)JUPpGF~fvjwzrZAL*8olts3!H(xmAf&_xLC5%N<{?e>cOA-FYjzU z4J|NoE^mliRld6b+`btgBx1vnkY&!?Q0e1ZS{6a&<e2Y!u-@Rs-b<|oEyJM3ix#X0 z_|3hnMe!EOe<S6|!svQy?#sV=v7&i>X~3moEWMz2uwZHw4Tlo(7?cSrN+XEqxY4u$ z1=5wc;We;Q@5y2x4u{~`-+S+U>Wqik!Z3kIWAu?kN(Ci8yx;&w#BB(E72y}B6O<2h z6uB672A8Nwa!(Cu;4=l*T0HYcm-yZ%+yUK8URIcg70+PxrbSP}qSU^yu=3z80%+FE zV&a}R*Yumn!9=)a^O%gM>`lg&G`UyJ%jCx`a!PFoHoH*LsRHlSh}H7z8v*`gPQ=)$ zl|b`I6Qb;Hp2+U_h9d=?VoIP=ksMl2GY9wKdv73E<_ABK7+(`I&PyV5`ynot^(Fmo z_D)Iyf;S<Uq<kMSN<scoxyTRU(vT&9$6#Xt({bN2A_#<~gynp?QRNz;%a%!-RTI-i z&ZZ3A7IF>+1<zGD9e_vDYD4*zvzG>H_r@^op9Q_sx9Y*Qg6fAney~f-N4lu;STIto zmqr7jiAa1n7zX+58J?Po4%b?QJ=(?X?eZ*Uw>FB|!{f6ycx~ReK%Zs<GQH0i;|wVf zju56ENhD$rmP3Kb<S-Ox(S~<>7%gO_wYlw6Gy7Z)TO5bB-98*n+Pgz*E0=4PLNXdV zw)f!SJqIM4fj<zQnywG+e)ZMw{p;txHW{7x)Tzf0MW@2Mp6gpTp1Jm&bUWqr*vE%Q zyA0hLiGf@Qz@nWS_Q&P;%jaQEc4Z892#R3FvO@R}VzN8=H<if{|H>ebhrxxCnV1#M zZ?k{=u_w?i|IL5(f90!{dbW6E|Nfu()Th38?t9O^{@j71rx)h;HOjeP{Mf$}@+a1I zs$crfH=q5^SN*;SWv$i-FX>jH$R9YI7#^)QTY<3W#n)aL86LNHJdsYwTep4l)$jb_ zrEi?wxjDXP;q2<UYbzH*K7ZHYJ-c+}_rCbMuUveQW#r=GMF9Oz9{+^B<>=aKg<AUj z)yti7<M`CRpM3HYPrmQNhxZ*DjgK9lKelIl0o|C@TrN2>``CSt{Iw5%W_onGYwzAH zth}^&KHbfYB!=IA>cOLP2Lr*_cB{LTE@DT`CgRoYtL5#BopNT+)ZG8`-~E3(0+BDj z`t6FhNg64KSLBJlbm5z!v5}em2Z)4-u}ayXLk&Os^7(vqcY0!vv+JaT2u;EMDHKcF zJLx<Y^~MHAhBvn}msi$1jn-rLJovz|QzXPYbMxHH=<v}!`_JCIWOq9rI&ykCI=;BN z=o;!Kf}v^&rv2K<!-wXEM<oT^kgsj?Ze-FM>8)nBogAKw#zzQmO^!}4%<UT+o`^-0 zY+3D29S@7kX(v7(-#i;3JR0V&+yI+1%CL=-c`6hLv(ysakcf}K#}f?T@v$0+xJ|bu zbUv3Kr#}l)t$`knP-<nDY0If#&`*LdJ2ALM`=O@~(OY>`Z@|2C9T;>E=_l6wdZ#ZG z{q6lO|9`vQ{#&UkC=)mN<Bvc7^wUq@Ra^bG=b%(`r#l&S#qSqBOROgvi+}vbfBcoN zd_^@SdEy5@_`$#b_y0bRBbyaLy0<+7MD_iQ3hsuyAQ^4Zo7cNhc<u&sn!6FHd8Z@x zw!0yQb7%PM;Nq)=`C$vjPk1^t#j^{($1bueg-f1Xr--G%MEU`p$5#+<DBCx_@eN`J ztvgVoy?ghP;E9Y#ckQ6JUer6sgB}-rzfw^KYD8<l^wLY(+5lowcm3o~{-ox$)hVYK zf}6ADu&RqsuJ4amjHsLRohmU5Ii9Wnf`8S)tfYJe(4b^`oF-*}(W-+{)bu;8%HVn8 z$tR#0DCwDLj@OW94b~JmqJMHv?uH}(+u!~+HM;F?WZ~s*Pd@p?$jGRHr1;~-#jAMT z)T2wThC2t3g@m|FZHYmYsn6wK_512dq)1T#oaL5K5N25pw=Nc+y1WFi8oq}DKqcPj z9jsgRqGktt@Y<MG7weUl&7(ipYU-oa9y7-gf=Z=25)>isc0u#V6qx=sx-`vm7cP;^ zb$o1;&{1gdT#QULURdN)EO?FjDjJlGA41|#mnR^8dwU!7$>)S4Lz?HAJe^E!0Q7h~ z$(cT>r?i|RQ&X+R;s6?H1R%Utzt<Z5H+{e=ybh~125YU=w|=PIG1v~$iN=7j%mW>_ z+9vvQZIHpH!)%q|@rL<hd`*It2_X<kdu?Gp0omZ=$3$d+(ZV3(STxRtO|&lG<6NiR zWG)QZ8nv=F5ZY~4aL6(yh>76T8&?^i3M#7cr|&{W4+f-_B;vd;Q)7)K9U)?gNteCB zKBNl0NC4v$*N6Zed;CTjIBL>xC2z2=s0edh&f;;vdx2$kltBF=&mY>!Wi@0uliCDa z3c#=C;v+NL>x-fI7?2(6Kj}fS?6@9rn=`MS-MeQ27A+ytiz};#_RNC|O}+)05jx(q zg{^k`!E5H*_FHRW_SPZ}B6izrr4;#J#{(nCA*D*$RHcxw*FtUyclIF))Fy+hmopK1 zB3mn6-C2KZ=4jIAO}gFSp-#K*@kPi$Y_oGD62x~&3=14(&@^H}WytH;Pu2Q%zDP=C z!Vn3@t&_fBXz1|XW6etG#?7mlQf}AfCdnrwD2dFX+fzd)JQlr~-Fo%Hg~hGq@W?Q! zYEK=yXTlpv?`)pGe*Wy0v)ebaBd!r>@p%*~hp;zX2<`~xBV(9Ikjo(qagP!;Ww)^f zFeyU*U=k^$Mtvt&1oGn3mD%lf!paJ{-JkiyCqDS(<Nx7r{G*BSiSw5)PEU+~_{pbU zU%qr{aS=CwtJ;8#bM)Yewe{`qyz+7~9NXGn8ylWmO>HF;(R#NX@&-5pLb?3)ix-a` zKbYMq6!}jf#SooICLeh8{^i2TT6!(hsO*VNKf3osGMudMI==G!mtVW_Lap80J9?nn zY7CE#{M3CP&!l&viNM*5FTHf(!fbNv(87L9XkR!IO^gIw{(PlK_~}li`0CZm(Lm(* zz60p7V06VJ(e>@Em#@9Hm0f${-Y0^#z}m{nMrJFWULFsRcI?i5Q={YVB3$uTRyP{< z;KJei{_OQ<UMXDS>?-67ce+sM8!>WE$H%hO`bX}2+_qWV7oS5|>+8=xJ2pD8a^*&& z&NOtVGCLe<>{*!QtN>*IW<Z(0(zwqzci>>DRz5a4Gd@1*MlIOqMGJVVynP@!<8%7B z+cz#gj}mCLRpao-zw2m}%GFeQYHW;Ede7tx)0!L`i;EYot*pmlNgVF6=r{oinOx?? z;d|&lj@fqdTQk%1`{oXiDS`|e5OsEKKBp&w8gI2OnZww}qOlQXX*QSg2yxFB494-u zGzGFl&61oOGD>B^!n+}AHfC+nBh4Y0IczTMB^nP_td@elAo~;R75}v~yL92zCD&Sh zbrH7K;oG*hx9w8!BNyy;K>s7(=pFjQw+?OJp%whAFSf!^ws{a3q&L;;u)wGSBgF^2 z;kaK@^Yp<JerpjNG(qb<q${bB3^7B0VnJI)61w?Wa9luipZ{Rt-8&mWZ2q?JUIuZz zmcjZ&0issKS|EU=6h?sypIdkW)MeZW^3rRxjz*GP0t2*ETHisWs85uln!HZ>AnQYZ zVqtyjxq=Z1AU1L+dc9&ztK<Xi+2_pkq5N&oRu)0_>V9%13m6SHsaC;qgy_w0wUTLN zb~Wqx#VWJa?7EB^)=(Ew8bG!$;IHFsHsUSo>uapnBq?JBr`c$5P%OL`-Vm<|*?Mkn zp0ALpq0h)V1&9Q)ledNTcFNK(8FR6wxH$+|fR4{cz%3X;lNAiM_O0fUPn9tuDUA&r z?8yOX?QUx*wObUn%C|;0Q@h66EsOyp8;mN|h<44uF$nJ^7NSp6(T6e)Ew~S?vCdxf zJOL*?PD)HlY7Ml-LA9~Twkoy?o1)ThWDvGnh17a{VzyD(LUn$~6YVt0%}UN49>u7H z+5-oPF@wQCw7FJI$C8d-Yk2FQhQQMc*S1C@<unIM6sgXP=J3I4Nz3}>6A5f+H0U)j zH=V-0kS1hcGv;~EhZvRlLY}6_sl2thOnxzr=P7LvXEPbcIIC%Ofi0ZBu&MKua=CK( z%GJ5qnbeMCq2jd%3CnhyM81?$SAzj#<L)u&fAwqNkM_htKrcp~T7^Tl?aEH0RriuD z%;8?nuH(?<+-Dm<Y@=~}Z0_9F(!S(Wp;lQbq>_P1(jQ8Cykj1Bqtm3D(KBVK^ZMh> zYL?OK_Jt8yBB+}*1@&qc;zTNwvOBzt>vp3W3lDGSwpTY-4(&PWbL=wk09mR0CJ8;6 zES|Q_&FR?4h&MKTDYdkiTFs`ipi<jtG8ZJ6bLfdZr%z2DuH|;V{>^W!++5k-*mm0` zsWT8B{7klkL_A(7<tsI4(*fj7n8n!POh9Z@a$1chl8g`v#5jky!wC#zxhLQM*wKRr zpZnhPk3aGL&wlw&VlLlDpZ?I-zx$2!PI_v75As;&u0Q|DV^92zpZFVJed*gdQW@;j zPMx?v&*6hRoKA19ZLXp-Gd(&f2XQVpz&e#HguTAa)Y{7C%|vv(U9SA>r$2T2!F$N7 z`qK56pWAqOyO2LIb8o#_%@nrrSZ}Ad2}ziaPuAMiL}>V)Jtq&&A1dT?ublthW@hWi z-h=F3%yUGm7N+MeFW)FMN`$m-=2AgdU@AVnp52}vPCj(#-pkt?OX;<l#Hg#Yo7&!V z*_~_KnT^!uWB0!g5=*s`nM#Jwoqh2}dV6Z_*lSzYF4vdJzV^ZRLb@s{IJ@1-?8L%y ztz4`&AD%wBKbV|y#7HoW%*^?-7b>L&M<N%mUni^?r}*Bvsf*VxKlZ=_=gyyV2Salc z@wmOSck)0v;G{oJpSl<INzP@^kDrN6EoD|--?~t#G-PFlrI;&|l#ZiR!k~{GJmMOv zO^wbuoc<dti#L}SIlDkuvy5hCxr}uXiH4naQoIk%&+Q2XytWPorlghb;AeNDghLQC zX*5XcD(Q%suF8^uKp&5zR?PARrI3jXU69EvaYTd);GS2WYOO{_5jcb%U9xiJeApjC zq>?3+)k79f_>+={wkP3WfeKyob;IS2Y7AIQnYC&DXp{79{wv3?|N5`L&5QV#T0Eo- zapm6j2;9JU$Ny5F`|i8BwHqne?L!%vNZ>P|m42??KE=w4gfy~EXQ1LLf$#nNsd~Ky z%lMVfTm89m!FjK!!r-%BYE|ww=p5As*U4`nR4)`&LH{jyI>2PmI~x*uPm9I^aQYN| zoGu(16#ySVORflBuUD%B+eUw)FJrg70X8Y*6{KiI#P)r?)*96NF;v4I2JIOGT7JE3 zaKY-evx#0Xp|Nl9yIas)k(|}A+8|mCZDgzD+Va+lDZOS+OSGoesJ6<Wy`Ybl3j`*2 z!KUC*LRUpLzSV*yLpvH5J1r?qgo_t2!EHHfGE@`EGDgdATf$^Fx3<ug2Ue1nsNL$M zQmN6=F&28(cMt#|ScH;XUQtNFqhrn`v~2pXBK4jmkO55!<+aS}-LXKn^(*abZ5PXY z(st8YYl{uKi;6|j(_|#bc48V+=EW^`lj&_Kj2IOH_YI)eyD6`R>rEP_A?ipBF-FVk z>I!uy2`gV|LMSLk@=F-KWQRqwJSZfVPNPbtpzs4@+z``E^cc65l4!($u}@&}E7eD7 zQHFP9n$47_KUC#!C6Zy<sV=_GR_hurP$xZ~U{jH|2xJBxqgeRg+1KfPXg2(oE9;G# zw41cLG_^kv!jsoRroMrRM{{}oL`+I#IHSTrCP|n<^j0Do<-CRjKN+kAzhAOYi`o2! z#vh!>)=+#0y%`*(X1w;sN)Q^nCj?a`S1(OQ$B1%eNbMh<j(U7>av1lxgg2okyIk;d z=z@qyv|{ZsegOXg{-rqyCgcP9gTWx;1aPjrF*5rkhbN-wzd8{d9IlcxsFbri0}OFE z;ls&E3}df9uzzlUGB!q+P0vi;chCFi`L*08GD?#p)41Qc`G_yfNy{rYU%jw)2}<0^ z{GMHxb8~xxMK6`-oOWm=It<6W)h25)bCyzckbnZmF@{MPh0Y1i-F&Ig>a+-hCSoKO zij9wqmkQabMDiy-_K{k%_U-4sGddDqTw0tS8-42G57?Zxd^LOR#)Y5$z)ybs$&cay z*xcR(l@fLtiN<zHS@sR=mX}_A84tJH>pOPn1QVo*@?xcO_4;L`B)v{_6`LzttKsqR zE6Zn&&m29p|K2}6`^~efuT`4$&2s8SZY>%}mKvR{Vy50KXG@tIsl^MMOPiHK+vC_j zv-kATQ~r>@-RMLDi39WdXj9T1vzEMk{(Er3=!=`{H#vBG=+NO}rSvbJ{nD4uJ=5Cl zOhpo8P~~_n;6ZGDo?|yA!qvs)byBM}+QXAmH+QyQOJ6QKpt<|&od!M$_t0)Q6yEOE zvHo3M7lu>?$;h3JPB)m}O2c<|ySz76Rzktx<k;8-qE+_J#Bjpa89H#_D2ncZux);J zPnpw?axM~&B%*O|$ls|omQtJT-R6z$)m&yP;f)1d-rP>=^ns%f+;h+T+<wkRve`6e z9fSt}pr=Qt=BM|>6C=%5IT(nHaiZXKl*?JB>ApRO#V|7&Hdw-iZ`UOyNTrO+rXx;} zmaT(iD(e!h?{O3FA?qYi9!8|BNa7qJ{#X_uafy)FxZ5($c-A+(Hlk(6Vqth$vft}r zzHCqZ!&Tj+tmR$bSX+`V-MXFWe*I2gD1N}2_AUhU@K_Kk`Nwy>*c8#8A8ZTwDk!`6 zV!{T#fQ@t4{G;!nz2UF8sJgZ5L;Fx(W)90W7*~DpI-_*gH-f}QO>f}DToIKD%5s5b zCITp^HjYkF^^zJe!JFP!){K>vWPpWon*$zCe{asCm^i>}SKy*QwBVE$*t)ZU>;mEy z@adh!iZI**y{!fyDw^j{u2=g(y{#5FR;R48rS<;$P;H;Sz0va!TbN0kR(E&{Y2EfK z!R&oEv)-z=av9&h7E<K}Z{sp4L)x+j`b}}GYI-Yu4K9vWr(18V6;u05yBmV6U_^rm zuP-hUYzO)S%4bsB!=t0HV@WZH_gZBQ1qGs!P_HAF!f)Z;00Oqm3kD7)XH4;PwD$sj z5ygweNI)po2;IX^6iu4FL8Seq8%--%<+oZ--&mjP8_PtrIz{@|w7E4x%w8fdwNd$# zdg&X5xt675jt*onFb;Yl5CdC_KHg-ilKbPKm(XPMp1WC|Z)ipMyve6)KtHp|N7X>p zns&-;aZZmvNFq(#=zw5hmo}^3@QBA3YBg#m<QO?lc1JUQ`h$U|VE>S|9csG77HDb+ zJY@qh*47qi!Vjc(tTVCR(9*WGnvwn7=oIlnn*v$`<^*Gs1sRk^2!!@5URy~Y>mnf+ zVVR`a5qVW7+UK!huor#m@eoQYGtTGr+*n#>Y(UK8@SY^2@hAd$eo!PW4c33-1d&eB zd30yb-qz7?!#}@ou}xGu-3TcH7iy!^9tkC}U|Bw@jcPI&@i7kEo`Z?0N~2b4RDE`v zB++#F08Wys!pV`Kj42o|Xrxkc-jEWgh2I_3U?}Y_C-Np3N8SL+AvO=utV4j*K$o<# z<$R@KLr~J|az^m=E*vaX$}8(D<zf+^1k!;JD9B$_%x2?uL|{fs&EgB!U%b42oyg1h z_(aRwu5wsZg*Mi#R!WRduiIURDu!t%QmSMm;6$gvoP`S_>qDc(_}j^55ukx0^VdH9 z!F(=#;pSC)z;ph!vmbx_>DkGNmoL4NDP)|%(2eC~x1;m(ANlLomTz<b#|tOMCiXc! zA#OW2HcrU(%JL%SDlDB7r|w<Z$&it%RIBC-<>l42NH7fC%;a_gA<w?ObNi?EEKKkF z({tavy0Zua#1js#H?ke4t=y{Ro28(~7euGO(_9#v->em0-MaSr>c#EM3Nr0pPXsjY z4ETZgtEtqh*Dh5WmG>RGe{Ou?tFL`)GkY`QkEcrYFP(XQqqx;{RL3JD3!$me<TyDZ zlHu@ZBA(5r>g~q(_z0x3<m@aWJ7>0DO?3+`kDVk-wN`bvUTN7{1$%omHktG$Th#`N zrR8>co9VDr2$WjX2ze;ZaB7V@QRDRHNG!a(wL-MgT0S$LOy+hrM}|j&(MZQ-J9Xp) zBdA==I&I#24xf5u@f;wVRMK19o2)>`CimWR<oH+;5ut7@>>rL#jE&AUYW21CC5$iv zS;_A^Ix=ap-|Xh{+g^`vVth6hO`t>EYE*VxoHH}=8!TjGhQhM~xu#y1%xIFeYqt{# zCq&!I!>T2sS?mieX`B%<J_)C%<0uS<y=_;PQ!znp>>zBlj%J5gk)AtDcNYHD`7*d; zT5GSh4(NWwzt&P_EzWPl72wA&(z_7QL)8AA-}xOSa1Xv9Ky!wROf?ta|NGNF{nMZM znV-4yGJXQ-|4l<7fBdF@H{C(!mChn-Lp8t=kS3@6ya4yAt8HMeB-G@Mk|Oj_j5`2~ zlp1To2z%^s3-T&{Qa~w|{lKvrpD5<G%n1XnfzJ3ucVS=P;8l1nGLEtkh$qs5zY5Cr z&RnKQR55{KbVcX-iDDXqu6o{FeXhbm{^d`@PY@rfLT9xEEWFOOe6Bw?w-V2^K1Cm4 z*)4iQt@z-8(Z}7kqUqhN=F;nL-P2GK70_EIhgL+wM~yXN^`Lf{7RLOm>n8v9+{u=~ zV6Bh6Mlijm<Z>yw=EE|*srMRA#36?BSw5d7>=h<uI+fx(fr@exg9jJLhw3mJR2{lJ zNR(-d-Ub?oC^ix!J2f?hQ0Z`T7(<bt_YDkjb^{ERd1)CZyb~DPuZvY|Z5(Yty;$D& zz4!xN)3ap6({ElqSZ{75ckRhX3QpoLV~F-P9-3OdH~*2=GmyQ1G9aH&V*X@USOx?4 zS3yP&wb=G_)^HEn0goo15Us0|h4-c;=3IrLNPZyBF)-&OQM%WKrxu%;gB(%S6paWo z2u1B)`p?*P++0#`ihtA@3WoSl3d10m^7am_wNEv)SB+9@gbbSE#_O*mM8>?ZqD>+3 z6ysUcepPKEJ^{dSP=wkZ#lbg^9fH*n3@79cwxM#VAW5Yp_ZBIoocQ%u*4NEh3zt&> z9CcpuOzAqHb82vE42;;p>GIBa|NQ{H8G=2RJt?=M5++**(EHq87~ZUMqk-6XIKG)r zp=DWV*I0dq!!elZ0D2+K3vC^rh*NS)3#);{LrMB8_P=;Tv5e$Ts9Bh7kx)DlOT;2k zwEl5>bR1q3X-F7=R;b58ID~g2wX?dmQqAuSH5-}yPP$YIcmj5q>`qVA6%6b;!<b<X zGRJjys##>%XXa*XKKph#Q*Bm(>ELxDtVvvoZOEKsq%mcnMCZ%pa3E-G*PKK093YU> zc<}z??|b5j&;9uqqM>N6unl2sZeb2m+0E3-cVGP;`9lBQpZ<kPwfOqAt1L4co9S|Q zHy%sOjZadiT(N>?CU5rbJBWU#6a597Bb82FxO|Z#L5M~!wDz%ZJiFr~BOiL~gEzL; zzH{NZvMrB5;-&l|ptfz_-6>`KE>|QN!DdE#rQWf5LxJgu2_$F3t?p}A&Mw00$!}iU zy7}CtS4k7waCD005)q%993eWopM3O*c5Udh-}>TaJv{*jKb(wuf+rV_K%TmA^E%>A z$#@i~Ev%JY2Mv|#mcDrAYuRod14d#4aQWA(W8p9)LYph#9dcK)nO1HmQ^`B*zTs}7 zv05N2SgFwt`219gm6N?{JCn-fx9rZLk%=*cqTYAk1GQRa&z^lmDNIa`ckR2AW0RcT z49CZoQfuVeo*kWJkM!BRW0A<g*||7NZl}Gyz0$6?qH)$+7T&p7Y&e_UL^Ly(Cmpqo z!@_{y8x4=5QyB>decpf&^4b`iXq&<Z8>-ie3@R3JHwguNA;NIIK91c)_<#Y70q^yN zb)%D|L!^~ChjiB^1vs;w|Ipr88C)L3=^(bN<cO8!U3W>H`__&>IP0xlTer41Ebsm8 zOs{!YzTSm^o_^w-3n}qCJB;W?GFaie2eNa)oxXW~LeS^0{o1d+D?9ryyHYxZlr5l> z&3GAwOl<IaFME*zl)`vce4wyi5tT?2_W!gDYuSYQAYLD#_cs{jRvsb?Qupy$KXJV% z`pJf<NK3f^)@(Phz9*2ca7{ssg=j7E17{6`PF4*AwfK3~uY~b0%ogs@Bfuy+*O$4o z5Ev{yL9MveHP-vy!o;51?x+B{f@2F*2_oztM+{V_w~FyCEoq$$$gj*pRDw`iQ2#b^ zG`$7UU{6JC7H;FcYHJ!aZ+_5sg7%TLe5=hR?+h2n{HoXf*4oL3qEganBQy@dg4Lf8 zNj^l^jF~t(IxbH)r?D*QAV08sNK|fOC{cpxVPOI|^pFDZfv;EPd|3VsPl+9y!`YrW zq<kBpSt|xL?Q8X^wz-ZI>t+3EU8e1z)$G;Ipk5u=0=|t^COq}NLtP_Av|k7V&@K=k zxqdj%P$Hn&x0IB2Zv-%V?XR-~XB8F;M-!Ym0Pz*RU%P${$A3RFtJDv;Cdm}>b>WF8 zevxLR;-VdCN61oYAt}_Q2em1zP0ox5@$On(#zT#cp(yuTXAU}LsEb%y<cBf}mD(&? zPLu4JvKbp&<}cg^{B3O&xHRWxBJj@}r0B&oGWH=ao(@_JgrddlHaK1)OniYxy(-7? z9IQjWDwgoq&d<*9n3;+3e4zxgN1H|aMU9HVZnZ}5V9&l&-s^a~^QE?MpHnYmmyknb z>4{~GkZ%|)Zg=wD4|d<}%tyx(;dr?w`bgMTZg-&FX)?2jp&*8XA*-<?V0xs3RPa+I zk~k^Zg;m8$<ze>0UFHA<<DC)3P>Y5_s1@P4Z#Qe?En3@L%cK?|<rlMst@YG}Ygg07 zJSoJ;`M}~wgoU%c8+SN;?jbT-E$6qoo}u`7!WG35BkQdj3jxMF;S<z|f^i-v=dEBm z;yQuYjTQ+9KJdOrjvQEc{>-a3r~BHq>+wkVV^4fwZENk@uby#5VxefToZtD_`=36! z=hQ1#UVQNW$6k8r+_#^5CR<1ceXxhXl)KT`@SgdFU?7|=l^Ch8$J1LITN|q+NQwr6 zNam}QN~2wW^x=n@Dd(53p4fkIXcr}AF^M;GYx`nTVW$^K&|;^yQ7eQ3@f(HBmZRf# z*czNRU=q7+g;sVWyPB;PQ`MatH?Nh8C3G9tOPR~t*FJpz6A$it=;G3~bDLLcj{1WK z9(ezeM<>D~1R{U?-1lIbg6u0$(Q6H-KalU#QnvCRy!?eix72hy$0MU-!FaKprHvYH zTifl4d1JX!W~f+nmn(j6WG=AaUahqXjRI$El@`?bt2eI)e4Kx{Cx(YNbDQCj$o$OQ zp@o?}bF<Tv69l39W5GhZzL`sJrqff&xoWra+2{XwIyT;E)^>{dd@6f*VRm|Kgjq)f z6LdkxPyji9rZt0v@bszaLq30~RxhA7jRHg|pR(`TAvgsCl4M%KSced=CoeF`hq-`* zLDoIi5{}u~ze;{TxhZ_aO3>7p<YxPWcc;rL3nK%;B)UMZNf=_RqO!ii(g6@Ku2}84 zRGjo?dg$t5?OeCEus(>t%{!*cg>Iei=q2J!m$G*!pocJn{N={R#+%mv&I^9)w|<NG zydU9*|Cay6+KqT4ya>tqsgBQE{@_6Xs!&)+z$Ua*ryT2%1@3j0TE1$X`UXge-%0)G ziYly@S9sC?q!)<`wVIP>J+RZYfH(ZyGV%2(7DiF5X5HDkzd}F@2!iAK0KLbg$MvYr zNUpK?LdKZsMege111$sM(R%3;qt8-v!ZJ3r^#tL*(FhsDm+GO^meF!r&{L}*pWkwh z3(Do1o{yQ!P3)uoT;BAg8|6;=VGr8(A->XP3_!enWgP5%Erud*@%x&Wws1C|UtV2h zdB&vTZe*JmEq2K}BkmSCCXhTq;+oZFktzs=76lkS!Ij0oAbV{$p^qDu2ye6^CeqXZ zR%r;+*S%i5eH}NA(;GP2Xx1ni{8QWXmdVxs&Z2?w6<uaxPkWIbT5|9=pPQ7i)~Sn> zO}kZJywyLo<jP#vuXIeB;Y{Fo4S63xJX@n2Xk^ke)6;xs1aLZdz<4^vkoYjLTU}Bx z(f|&Z#~5PLn0k!B_|(u2Gd|5ZK)t2`+`U|8JlC|N^u-&Gq10m0smjl-pck#I;R<oj zUK?VUh>Vqq3^wOsay^A7mn4&s!*_}VCdg;gSakddJv(St{!o;ST(ZxSas~#G`8ml7 zR@T;{kqFih?pq31E>%WHlGIBWbp6ot!NG6MajTu*DR0yUzDsG%x^?R-bJ|5W`rUp) z8(G`3)qEbz<n_~c`D!6V+8~M8al^7g!<$o^Ql*GZ=k{>2!C+u+c467HTI5?0VN)`C zf|}?_0v<s3a>gYMixC|T_+XoOqLFaGj}Ypv+Z8BPYMEjYf2@-bNFmcjGU?Ll>Q=2( zf#Y2&*QNVBB8=m4pigNhmIZVMdaJwIt*F}(MkmurKqO2IhF`f><9Q7N+%fz*FfOX3 zURqCW&dpAI;v*l*mMR3(>{*z4>GF%H=<nZqnBqKh?z`E{)+ZnT#HmB4uPxsUxQVcj zfBm`Vw>Q_@<tpamwdF<B%p-pCXF13p?ezI4Vu|&18e5@M$-@fwdxA6zXFQWhxbKJO z=NJCqn}2%pz;SQ0^Tg5j&n5R<+*-6Zt6>t%!AR@Yp^-H@Hd5wBLCj9)PGu(^j8NOH zQiibncrb};p<F9Ry@9c4GLuhVfsm8i%+?wgH<l64NunDc8lD=NPHk<uZSG`zn3hJn zw^}T&ZEaN@yPrSz>_2<q55If;rF0|HAct7DLqKh%k|)P12PPd)xZNcuY%%5yMm*t0 zd)Lu&?_5o9EUwd60BF!~BAmdOu{j7LLNCFV92;r**`HdOdg}7#_3UmZ*Fb8sI5jh0 z$!9}}=tO+t^DlnB+{`E42^>|`R0V0+hfW+PDQ^RrBep2W`%Od(2#Ust$l}NcapQ@H za>KA-bhz9>IC3o9tWInr#uvd>?xPbKtjJT!;k*mhJ88v4q8h6ZRu}`>gg$W|$Z%%+ z<EVheip@a&+h|q+?#SdCDvt3~ur+krAzzTOeTzEZ--vYswKha+5wP}XYbxowdfO)T zPFWUysB*qL0X<Fdna_OY|M)-tkGuNde?S8v`u?U$kv~-X{#$jiHEozV#y8)~g=C$H zYsyJhQuWp=lSHQ<)B-C?UD1pJZoQSY)tPI0?mdeGU~S=gu})oUs#}R96^soU73zDH zwWGf-2wpMv{{ZUhDKiRgGh~(CO$-`VprbHdU{RlPqd>>}+tZpf59x*D@Rk0`Lhy1= zNxjr7kF_?*hkbsL^`X{R@vb)DAQ03)Z+&8D(^^e!84Iu~co@X5=FYcPKC2b<(cHoM zx!zDe*KWG)TlEBMTUpJkK6MW6k!>LklH{NuKPD-H>lM!2qY-We+*dPzs>%OMllB63 zv2Em}zUO1+soI9B7-Je-NGz5iVtmrQ`rWcpOxK#y-a3mIEWCdEhM6k@HT_4Juheo= zbjzRhT8+o5{;4UCSevk7-q_}HOJhj%Ze=x~^+ap5D}kPy;2BM)Q^8PBoUBmiCFLbH zuNZ_x6qux1CK<3K#>Ep>1|?|mAfwA6fXS<%z0*4`Fb&H!YLj44p)sOPcdI<63b#T^ zw12fnsFb34s}|;QK=hv4ra6wV!@AL8D65Ab1EG}vhDR18hh>5WhB#=OHGWJ$EZ0;k zRUQ<I#CZg^3iTwNR;gS;&N?28?&J$(IO4%0$)t($yd_zy<4^~N_3s;c@E!8U;Iz7} z$b)mxI+~D~WgCk6!lRKS8D2*t!vzwf)vD43?Uvi=DOF3@$=kV<51&4c1yrQkSkWGu zeF*c}?QhfzknCO1W^ktB2gSYJB%+#W1vaZm!XK36-E=y(0~)C<U^sb&d~UzY+?JzM z9opE=wQNqJrkAg;?`)<~G3UO4Kmy`dy<BncI!D}Lq+L30XN^esfF~UD`4f&N!@=W$ zSjR;2INjkuSbQ`s1kCaL+Edv~jV+;5-q=`q_`!!3#%7+o@a(m%HFqemwR-d5^xj8K zy#LH=7l56)R&6c4-K{n@*4J<oOVWc*XL;#HshBU83V4A%PON~)<mgPf-b!t6L-8ut zWaU8&)Z_OZIdS;R`B(SsS-8A{2Ih^0xxFi?wO22{6!Ql1<@|P@tXM9jTLLbh%Qlp& z?y#cdD>-I|A6mG}od_g0^V{fd27RG`+b5AKyZFnAmGx)Kg|mz2V5>979y#$COF}-k z387_ido%10Ry(brHxi0P&!-ljx$(W4tvno!yZr7#yNG9-X0H%MY9r>rQ|s<l8}<3{ z6voe5B}cX~*Ud(KvqlanxIN4Q&@P%moCkt^AtP2gmGQ}ujq+waXuDe3WX7%**BZOT zOLT`kE)H5yt+~8>87v-h2FC(pjY8Ye8alXd!DTCleQ_A}4!fsPDlogq>RK*kam<?( z!fgcZF^c?wnBN~^3BsDdF)zI&hm^aeVw&j=Y2J`qThRRoL1t+pik^nTQv)ZSMakz6 zbAcQh_BT80>`B&f1{;|}WFeK+4@*yDVXb}2n(5ZQqpl)dudL~BExdz299-20@AD2> z8{See-?e}qJMyQ0`lrb>^w$0K|EBUxy`_$NdtWpNC@lcN?xB;-f{Z%x6sedG1y!&d z^l@-cTHZps3hQy^DI!$(tN#w-4{L7ggSc2PP}rdan7%Y&j}Siy>#gf8(4!@^EDF7+ z+7DV1{ZsF+pY)hK{Y6SY*VRPTNO;rtdJ4eRpAW7?`V<S73}V6C-dojFP}Rq>w>%IE zWUUsk?x~Nk%6uCPvH+0<X5T<b8369qDyeU*;tjTsb?P$sIBK2E<!7fRM2rUK9PBJx zcWY~t_JaV5;)WDSDI6wOtE~D)(uYyf!UQsWafNJ#uOjc{WTD3lm(Pu$q*bI|Zm&CQ zYBhy5IQyT7Nn^@9u;#06Hej@9*Y{2X`d)T5-b^-IVkcbayWpDAv8_+hJDSl&&3XgL zA~I1ytrRx_(Sp}`%Y6v=LAbMAF3}E%bEng39RD=0xXe+2k(ga^(>1DvR=w)vz2V9` zy?*FgI+9I#DI#}OfK?u$AtjQPY{*U|gANsKeEv_*ue1sD$cS&PPwu+8%02rIW}OiR zl#7Q?>@E|kORc$EHkXy45fo0EXr2T~KSRl>jevu8r&!Ddg3z!znGp^TdgSmlOz-31 z_mxVOP|zQX;mb!xqru6Hj%};_TIM%)-rIZWd}HaXL2_H62WOd8<^FmoE)tpu`VCDT z^9l!=v4mnwEEF$Ri;+MC8_?$t0N;V~*<uFP10)+9uA(I(37&$C89{O`PotV=GIG9y zN(r}N(c(x9%vOa&)u`GX{tD!tMvH+`E^e=FY(ZQ{P@d?GL^KicMC~1WK3_;}rE{4) ziZb9hdJ|9WZoTd9*yD~saL9$Ri$lI0^0?vwZ;&X95GOE&N}<7x8}*KJH!>XFDP#-z z{OMDt3gyz3#Vhw5J8}5HiH&UfJFh%@V(-D9{lw3I<x79|-S2*De((OvH*eT$^^=E= zEG{o6k_mA0Xe<c}pTj@|Pp{p$hLu}{)mN>oZY;m_+V|q&P&%6@z|$A@-T&}I&z*ff zl~12MdeYJ89+=y^l->NzKm9-BL4U_(zm&Nd@&#JWM${c_w;M3pbJetC7aoyN$hON{ z5m<rVa57BdC;zqd%1$wdJWi?G*s5efwow8bq9ZO29_qvb4WolO5egH^@AtSe_57KY z%aL%n6LkFEYoE_|3z1OJhPU7CZ0<H#>>9NSClA3;xXAX=Zuo{AA(yX45L(A!TkEuz z>Z73%#A=|+6X1}DB5lNEYDYr&?<-|jGo9O9n42bv6{iQ|@np#BP6UHU!LFq?SdEs} z*N9P$yMsx0EaVQJeeHsz`|{d3gNcUYq<JL(8*U`S%pZ(#h)PJXr2P_$i^iy6gQ>d# z9y|%m*j*(lEJU3W7KQ2`*sz!I!-u2efk1>5f1rF;X#>_Vi_AeUzWLruP7^sLAm*6Z zS-zA!(?++N!HK&;cUx<t8Jr-xE?Icvwkxge&sq(vMR;Ike<v*tZ>6m7T0l?b32enr zPm<JEUU}sQyXxW1L#co2si)pblf8G%oh>jpLv$i3AXYS^D0~nfs0+~G;9km1L!0Y) zUUdQ+=PVG8BV72wx7?rBhOKu{yf}c^#DcIsk?;DnZ~fsQK;e_`w_Ygt*77U8N3oGU zRDUI&(Z1tW3t-_1)o!=I8H*Gy4Fi@0d{|)yT6k-<vJ4)DL{_B+uTc<YJ!^2MxA3BZ zHtWwG2ltJza`1v)bD778cf9ZK)M8jqAME!#%O)jxBMHhne(9Cgm}EFvX--t?f+3D& zovH1uLa{h9GDaf{L4{zhp&``A#UG5L#xA~Ij5Ge_TWKldepe2OX2CTj)Medty(y&> zPii5&qQP~1aH!}&wHkl0c1kxlUm0)x-A-)zT=k2DZZ3&w(QN5?!FdmQrad&**sT%U zYhXkAG8tseSN+nGNJxxZ<qpa5l$k@F<(1{hiAny%CraWr>>N_)N-kBQ%1GpZv=7Ad zd<tp=Bn)44tX0kd=qVukJVi75PWVHGW+3BMqaxTf?T$JL(R2>#T+o?o!eG?qw3=vO zioL-d&XpF{H}w)LLOkf^#7SIqlHV7`lvI|x5$lYrpDOU6W~0_XZQ8@JgI7{+VgHyM zw|MF3ewljh&iTuilc;KlkKZ+#gtO~cVOpKb8dz)<a&S}+cIZ3hz17IK6<FusV0UOg znpHwtR=p22mn3p>xQ3%iTBg#h&W=o7+gh3*nMFTjE1M#|v%+x_x<(EMfZhaGNEo!S zV!Ox)5_<uTGPGt96O@&TL5Xu!U>w4iHW=@D+_t%GxE8HlSGLrE+Y|JMP>g{A&*=bB z_mi<vM`x&%hsW>O+S+zGJmGMJ2gHU*bLI2feNktWd{{Lyi6W^Q2l{!ve)s6`FmbWj zR=#Sh2BY|8yYGA8;n}%`O09hE@@t{dxs}ZF$$fi%`QyI;k)=`H*-39+yt0_t*?RJU z`|mq`>iP3$eZj!^@CfzG?Bw#LY9bneE>g^AyY0p^FFd=tz7!!N7c6bmmOAbId-iS= zGZ(I(Z+BbdY_hrR+m-yeYv;X=p$ajbj5oV0=qBb~WYVL)Xu$1Fm9|M|8umoS!o%eT zJS7{o4Tj>GR*68AvDjELF;REft3&N_x3OL*p!X8<_zLwR)&&;S>P~uXeSKnN1o@X} zEK>8?{@}$wzn;BbK+~q(9uJN-cUzuadzj;ndbQzfqxuAerdg{;J^os|7I#P5YnAr3 zLfD^xcFNko`BlK@sW)NH!KQPf@HM+{W}~<^6^mud+kR|cf2i0%c(V};M4R1asas#m zt!K;mxyU$lf2X8kZtj_!=D4m_&mBE*Qd0A>8VothWn$Aw#VvdoFumxX5~t2}tp?4( z0>OI-Q>?Fe>!Hxlf1wCNu3f7Zu&MZoI4q1?&7=_%u~Z4ja7lYI#;_UK;prEqIY-@Q z2@!f&xmp6&vv3gMz=~lMZ+q*~o#S68yR~T!&K+HKb>Gn~%=+{DO|f^%67hq}`ECaE z)EqxOit@kmE5Aa5N%kjTy(Mb{+<*W3-~YG&_TT;||Ky*LgBEG$cSn!@8?S{<81)|U zzE6x1|D1wU-HDZw%awh|C_YPOsCow#Oc-RNKn;_CeMNMOb(SjBwx+ZqV{?Dm>4a?1 zI~g#HlL56y#UBQ9+){<t{Ze*BO?289z0rk0Uk2_7Q(1wa?50M{{x;;T6_?zoCX`S& zU2}7(f>u@^WGyrnvb=>$dQk5c^Uo^AZRp%8p*D*)h_(HjRjv0^>*j*q`f&fY(IWWw zR^Vozt<t|(;l6c$Yh`@H<1B~$trJywh_+I$P@J9|-%e#@S>MIUR|rRAH*Q>?otuYF zO~KG)G(cRC28~OL)#^w$>_RmWl9CK32PD(JWKK^o@s0RfG%}=+rfzR++aB^87+U7a zH&TfPD%i8BwEKI5&4irldyS6JLEisFds*5BR*5!mUsy>~7|K^FPiYxTVkS!NTSVf; zj@9-w6Nk{d_U7gWa-2wf;GXAmnCPryL<}<*fcQdOCnIQ`Trnjfnd6qHf4dwH)GDPC z(Z!&1(z*b@`0cHmo02Q<Uq`H37rlcWgYT7HrXybmy#8qoB&+GHz;SD0nn`FZ_P&;@ z4tw#$L05qHFK*6Gv5;mUAWaPdaC-wB-_xZ0i(6L>H&kw<HAvW;E6@TW#{}M_o=`(L zoiJ&<2D?~`XBG0c;r;gi(`wSY7FF9{hlhn!jA_<ezG!ptY;rVe0#3Y6H};hnn@(q` zRuNSjyL~J^h9g#(@+6%i4-iKrEwaL)fn%b5#IVCml7Y%X$<&j0Ycq;LbwaprwYD-_ zrCOssMC53p2&8RweJ+n27&U>r<SlM_10ERLbeG>1TwB|O2uAh*@<Viqk#Kv4gE0rX zNwpUDLgk9Fy4@-!XD6rkE$lmbaDHZTer77$%sNA^s~cCS%%KBEc0Kk#dhSnb_442O zcYcLzN~;@Nk3aa>{)L0tdhwByM}F#qKe4p6`NFvu$A%*Wc-LAL1{u7SupbRn@A_uO zLssdXe8lgE0$(gw9A44$S=(5-ymDjj+%&SW>1^uNt7p%gf6Zf;W1>>4ior?i#XLk0 zMCu&`Iwf63$R9F?zbLTyLY`>YA8pt>c_iv<ImAQ9<D-mW%&CCS1$y4B^I=qS`r3E% zrPA4z#Z*2+7N@JZv^x~;I6Ir0t6TYXT=op_5Xq>Ven|O<_H-Hr=;qkjoVX3uTLGJ| z*aoq;165z~e9F^xkHwSKdLzA)LIK7f@D@0{!=v7;%`HrK{3tw@i{+hCr!qM+%k;yh z#^mqV+Ti#^c$m|b(-TJ{4o}RVaJOv_9zXuj$rFiWs9MTl1P0tN^q{c2u?qd+IP@g9 z2l{%*;|l=dak^oFL!n^~l6V-=Q3<)`C`eA;2&N^o0Rb{3<&_Wlk7%UAwDJTQIZSi( zKt-qkTTwjv6bx<^!qW^KA~$3NaxjEdPuP<vGKm%0Vcn5!x_`*83$>cEgEPfim-IuO z8rBT5X3gO8_4Z#1ezX$a+WUXB-@o^(_gX+(z%qh)uP*IDuC0D(!CC$^NoqvgMt>`Q zL9&gCT%DjBoqN0#+#8=_Puo!^tpX86#uk~r@3OkZ+t%qVnRL{ZZW63&Ni37VS|GHL zTsC+^EuMlQF*P`$Hf~ow5x)KqnX#Rg*Ier*v4g}biEfF&CJWQcVWM%atDL1(fZh-i zG~LJ329?MzYW(q5+v*!d<Q5zp+~dvfZb2@oyeJv=Oe6hv5D@57c&gQO)}pEIZEJWd z=TV`9zO2>LS}_%93|3jI(9g+gFBVJc0|sK`bJ=7f$)B&Dd1c@J19+RJrl#2k^a%hp zGUnh*r0ie_$l~k}99Z{sc=QBUe9W4bwdaiKSHI_&A6(p(NYiuN8%S=oYR^ACK-Cy* z1Zg2cFikCtJG9rr+Qnv6h%?Esx@DMhIY7BwE+R{(RC{e(?F)Uf%6jTk7*g7j+`$Ym zagdvQQk-AO8P&CGS9w1?Jj^wWu1scUWMmjAXh1v;3yhrICW`NQgaaG-O@CslT`vRN z(77w*vLjOqJPipvh75%<uJm3lv=haQmYnKxP@v_ZiW-Pw%@ICV!o79WX6={Oa2niS z_0GL;TZcmvOG(q=?ChYkR~4(QS?jWs<DswQ{Q)_<$K-$)K?FrOig4mEBoTlD8AeHt zO93HuOpTAG(mT;maAs;kPh(`!U@Z0HcLxW*HA>$dZ*<NMHnI*X>tCJq#$uF?mc$5R z=}1Bk_%_U-wVmyWIBAk<@j#e7O<P%FL;cX@C7VaHMQ$memPz76mM22G3j(BUb}m4B z1Wzhl3kF2HS;0Mjaq-6L)^@Q{U)tCpFx&6psLipF$*it#*NWw2EO7ead(ye>%~Z<c z4R7rfYqf@)B6V#jx{OYa%<h}&I-6i^9JwftckJynS)zQlQnl!{?>;zp0>tlYxwba9 z*Ye9}F1|c9F|~JU{`!q8|M5@#>dE=zFJHZS=JM;Ajh!R&`wNZq-+1aLTb{uG@VVdK ztz`DiOtF5Sy>u}aoLJjf-O2A{5W%zu+ck0|qnk8TC}*I8lv=eRx8&H`E@mdDlFY+c zFn&F|%v6d7Lmhh;!AE%gK0<q&^&rB^E<3Z4TuBJ{6iBNiLQJi=f3$0FZPvChgvJ9& z@<P;h2^tQr6*i+Tf7BgXDWo|qYZWSE9)GLazPz?{XndyWY+lT7VjIPrt~r0K;%M&d zHcF0Gu~kcW!pPd#JB_K(Fs%ROTDDxTJ4gZmnBH}Gite$TZ~5{vXxs1c`MtrNe1@C= zPPZ7|Xl3G#KY8!5@I<`n9Lkqd<!))Ux#_Wa5`ic#tf}O9t<ya{b+TSA?T^h=Yqf5r zHHlC2^n(b95}LY%NRHQ=jD~^TLk>Ulj#X)w95R8ZFl~stz=C%Bk*V<qqO2PATEXiN z8;CDM2wINdb>duYj6hlH_z{#XCMhO?Y(aP$WO-pZhZRT=e}|QjoWZ1-3lT5tk<8Ns z0pn!ALS%=<3I*yL_k2&tPDi-4d0Cr|&I^MOdN_XYjkOyNF8J?`HQ}zcc$a(V-^D%m z_N<!DA9cr?DfEU=74^O=kkzPAor((F`+1<`q)uyR-KU3#`Ubl0WXj}IIUQL+`noqg z5U-HeFqI7o>-{OPzJE|)wV?&s%^|+g7BQvbPYZl2zd}o80c*XRTx_r&pR4&{*djfj zuG$Z#H9$EC$w{oF6<n(elPqU<cpc;^J;lY|UT%3w#YpL+SnCdbKqen(BdGmg0Uf<^ z@TC>+ML7(x;roTUHOedk&}~bk)kk_1qR+Cr)nH}AxiXfC$L+qpw1jH1a5OpM7r6wN zh@91GBu=8C@X&A@<mDmROXH(%*&%5Rd~}2s8i*bWN-@P1LbiEhflFD(d)Wzk2H|aU zL<?q_B!d-^FpGh!2QL#okKk~D?DBb^!6nY-wm32^0u?(D$Nhx-ax)E()j{4Hz3NqE zY%7TFpCQO}FlR_QF1dy*lKhDMlk*DNgw(LrS_R#GKH14+$k0Tk`3m<u#AZxJ3E34U zddWt9T)WE#0lHfDp(qzgQeZWkX=L5!%xvhDSuAIr8n--K(nOY7t4*Str8SDI5v3n0 zh`jAv{j(>0Zo+xdE0mF7cT}tJsic~<Y6Wyf$>H5qNKon^Bdm;*SUibg&sn@^;~2#r z8mr!Dm8;b_+SkJgok5Bl_&*~G+I!vB<L{b3wR%=NTPC6zs6A4F<v7qTGk6{d-Xe}1 zV;Ee>?0}>UeH<P~sfJItjsW~ba?<Pb=c`4o<|~3|;YCQygP|0Xa~M2F*O*?ATz(9& zN}~moFH~E}*k~?atT&o`j1L*Y^w#<Y66(M7vp+jAmNX7p&*sV|!suat#J=lFuWoPL zTm$Iy>;mb->Hc7-(QOBJo&K&pY<H7g^xF2#<$Nj}8a}?~=;;He_D}AEP+lx%e));N zzISTj+h?91o1ETEZy}^JKQr;chu;^CP5iH4{r&Z|mB0TB|Ni0GgH(})f=E_|QXmMJ z^i@dM6iHmVirA|^9P%GNbinCzom;xpwRiY)eti7&krUw|FETY8a!pQ-llyigF|n9g zOZcPpYS~$9jQbP6^7JpBnmj`4rtM<Z>m;C-WD1=j=THG#VTheeh@r%}?hbXlyY~Ag zjvbmlFddnK`;^LV?3>v8!TX+^h{vFl<IEwUY@t~h2`Av+b6~NUUnf*`EHu)p6>ap0 z*Jt;8Sv6or4Yh`1p!`N@%$5xAxaw=!kS|uK)VL<IlSw4v^e-L|R)*G4cmMu9vGI6w zsD(8Bfg=aEODSwQ)Ohv|&k?79)I;1Chq}|L)TUz-g`G;o;k@tYVNPM%<enq{Y^N59 z4<kW?PHB}EFCm+>W5lmmPTX~T1RRt4!VE217~+jd3x!B7%N?Q8cx}Xg&k80RG4Tcr zAtyRlZN4yAo>?sUp~RJ8PX7S!tSQw-1Fr`Oamj=y1I&a<VacnevkAPBgH~N<^rc&~ zwdv^6)L+<j%j=!d4K7)CE?@7OmEpFEya(vttv&m1pk6wcbn>W^Po||w_}T-G16!|| zd!T`yh@OFEIveHZ>?DduC0ed`;@?Xop#a+2+su}xw3ePOJ6{>#V#wcpx3^*x%iC?0 zM=^)NBRxc_*(<nM`3d^cjnmpwEf=P>d|1nk)|#gSyapp*xu>yY#HTyxo9|=&TPu<E ztU<5C;9hQ4RcfcIIK6f=&{lw<{+vcsZn62?RL^4041hB|z1OcyU)+M@)<QW5d~aJB z2fs4QZLb*z7g;U2Disj*hKjKXC9oypaZ*ZwE0W11G!m2<0dNFpYQ{0PNLlf#71|2q zif_JHD#8)RQo<=~ppDj7UZ%f#l@uR&?_=#&>#y5SBekLQ5;IT+E*GGCJA}0^=>L#R zrBYOS*#vu`o(bnzVkdAfX)ogmQ%OxRHjQABY-nQs849==rBZ&`r8Ip(Z|JfaE29QC zJZBd^FUdgVP#RY&g5NxslX@Yo0oGh>enTW+MLZe~4X~b?_`?ZK#$`8^Qz=OS0j+|} zvNW${6B<jyu-SSs#3F<*`=#;KTL{t`;e&wkwp~;AR~>cwLm9f}B!br0ya&B*GCnu# zI*EoSu*BoR5`m%3dz^f9X)qjP6!`)HI7Hm1g5`&5XD&}uAc#(R835wH6V9F_(o!L$ z!MUm3^v->Kzq)7}-Z2Po4+z%fQCB}R-g;3(a>g<=#Bibw$q#@e&PZe!MfXy*%z()j zb2##8|0;Ty5{!s?2{_MA94+Qvqfs_`m!chxwqU+e+stOmRff8g+`XB6Hj~>P8BUH4 zkHMx(M8Z$K@1aNUyYK$v_pYT2-+t!1)k2Zqisu%kOZv6k+%0yuSGG#UYN1+%sUIOy zR8%u<F0gUSHXIv%asA@=7SEJh)tRxm4;*>)k$v}$jPL#D-}=LU{`?;_ySDiF%)XiV z2M(Sbjm`e^=l=BN>t|-%;eE-y`{s{u1XU}SfriO&lp*O4hI6Hyd)I;Ko6D^qK6v2i zr$4lk+Pb=WBN+A#$HGrN@YpYW;-^m>IF!k5$HSanMBM)1>Q0K^GAzAL=Uj5?;iHd? zkImPs^`rBLqrS+^^`&$(*RrG92~Ez^+O>rPL}@$1uE0()JsL=y8a)b)sb*^ho!(=k z3r81DpfySEwwck{$>@y76|gsLxpZN1b2Hbjv9zI@Z)>*fjWXGxnr=rR9IKNVwbcmO zeIwqu+v#@}ZIP-c7LF+BR-ym^|MW>jK~zIi5`L5mqr+Ki)*%#0q$!69!;$d?I7@Rx z5s=SodFy7en%$R}9*+z+cDt9eD~yAg;7HKrCD=G%3)BkbhfbZ?H#=ok0MbwK&@lFu z(@lnlU9$6%9}2HIsGa{Zr-^AX8-$!Ni@%NTL=IK5l@XZ}U|S_kY^No0wD4^(#dUpP z_^7XlbQt{=L);nNPMuW=Js<*wJubBK4fHn$ZU|r!vLP$H{NVPz%-UA0Ss=c%{sA3V z>&B`}khOxnVPSvgt_yFi<nICcx7JSYUG-)ypfi>!r#^VauWD-ZQg6Cmqi#zx_avlU zebovi6yL}aAc7(KM*cBB6!4+$K%KYN#Q-WrWjdwJ($muulv100P=HH6pOm1MK95{i z4U@5=$BhxB)lWlfm01rEEa1W$b=d2J^oIJa<;a%+wSGh?--6G$gSL#eg9WWj(;82C z|74@L{29DuZO<0;H+~C=1vHnv;Vi!QLv1hPjqc%D^Nw4oVI$w0-||1JYfP8*!flOB z(sO28_tdV@e{Wk`Et|)<dwalChm3_S_!U%IyzhJx4Elvs10Q#D6ZZW2#zroiBa5@> zmrJQk2$hN8gs?$c6BstaD>X{$>XEg~m41<WWgG0HTh-Ufsxti>T{x!q<XbZW)pFBD zlU7m?r9wKqgg#`x5Rxe5(RMFy6rBKjM9v4y?ZBL75Vk3E&nz_kW!?+L-+1kNWT74o z#*>9V)hM*$@RKmaW<z}NMima!&LM^jHjJWb4O|Y{MoJ=kt3-|qO&ZA?kI&@`vs2n# zKoO$NhH7|E!ARWKOf*f*Y{s5R0B1^Nj4-nSo3ynIWlP0UL8P%e`nE@(Nw33RI>J)O zG2N|WL#+ZcRpoJFD$3R?q%|TkF-sVT<x*bS$L<8dkX{OJDxb@&fqK;4y|H+cYBFoi zUARaci{&bmn`k7&@dcS;&3TwSTDJ3n=W6G^Ltk%P5N@x8wH8@*w5FjfAN^HJ`$cB~ zFOAMOqfuDyIvFMT1EHWouXmDRm|r)VEpn3@6Or>UccotDD<C7|2f;}^tlFg#97}$& zHYBdl>c(a&v%}ik={C`4k3~?|X<`e+W8r&_9Xhn{kj>sXyS(z!E3cP|WfBHc#1fiC zJ~-B%Ql(xg5<gikW%AuxmzYt1AQ%lsA!3t<BI-uQ+#PVZRtuZoy!_m1Iol0HzHsry z&tLjl$y2?tz5MLT*>r7ZJ~kEf#{Y{y{_poCCr-^CdHwR)2x9fVP}t|6o0^*%o<b+5 zQZ4M?GdmW;{|!ZC=*h>QJimB_2@;G%$47=4=ckXJZguT&@vq;w^z$G4xg&>8KJ(fO z)oO7*KC+%$jf6wT7mn?p*!SgEo=cVTxczgP6ngWg58WH_;p2AUkwRRExw~CUHQLo= zAo<kZ$3jkDv01scz8D;GzwhvamsbF8K#{+%zkL3C>FsSK{C(c&zOjV~SK`{4%bgwC z);<-V4!ix`R%JXHcVbQi;@mA)%&}Hc7pKh=^(0+|-O0e%=*0ZW#wrr=l{yrEf4Ndz z-P{}=Ns`EGr?FFX*NdGBKsypkTwJ+8ye@)|O~MvD-g>9`z|8SVK9Bb0PQDauxsNVP zJbd4S%<NotiyhTi$v$MJ2$7JbS4gDoXl%smi*THS>z$)V$?eLLg-ATy8;`$UEduDF z*$@HSs+Y+K>-LI4&UEhWEDSkTGdYX)irkjaF2%$b`FUaHNNk2=5j2rVy(6F@MEE;| z$xD_gmQY3J1LRU`ZPx*>i;p!61{b2ct^@Dr#o;ZkY3~90x7bkcUG^p|U?IH0jYqdA z{mO#B7C6w&S3!e90r6h;-Afh_6hL5bylzX1Fsw~WKi3-w!s&;)>Z1)mp{EzAB^g8^ zgJtIT_zbPv4(^NG(|WElaAfT;$W_16r9{EH^{2IbXnnOj)|<gvo5IUsq}Iz?t@I8S zsM6A!2MHn3T-@_UsAtsbA#G9dxEshWKQtv&%99q=U`M%??(|x5Jrn4+QV$bYWze2g znz;6Y5^40&Vj~$&h1JMCBteD~p;8zN#1MQzZ4xpCz0&Q@<&bz2$}hhf9UT>xMUNRG zpc4iQ`Yo*Z$V(&G!nc}=b#QEGx9ZAn4J0!vZozlsE$*G_n9fq)ycMd^Gkf|cC%3eH zq+SEmOdV|cTWLyEAdKZh2?6x%O?bJCUX!7e)T&(Gb0GEoMhdjFNp;w$9jmFeB<7nI zHr=FX6?y&}H?HxXcrzSVhysyeiY=F>kZkK9d~z*SV58JHwy4&{*@v2Yu}~t#CIW&S z5fGcp6S)|CEL~&Th{x&Kj5_H>(?sbv{mG?+%`!f<;?@A>TjSvGDe({b$oWcVfu29m zCdM}`x{A^)h-%lW{3{za!t>=EsbOo?yqqW4hSI4`IJMzO3?j$1>o;a+XZZ=7dlbdd z_=6?Poh9zhjX&3<0vHHT(N@)#ADj!;q<BZXdDHR_USL((nxWR9vH-p5YkBbrJa7Fu zz2o=!&`Ou{4ZDMQ*&4yIUGY$uLl0-ZTwp0J)hl@sl_vzlgX!l1V<U^yXb=mVEmR8- z(z97VQII|_(We;Nz(Ins%k|<tN002CJG`0AeEHkYEMH#%finE$8p-k-Age$H#){K9 zJw6$B2U>;t^3}~|p}V@d?(uqj;V`Js-QG<)d`K&LU5@q2_IGZaT`X_<qU5i2P>Z6Y za&>2gwddH_z8Eo=929gJRjt*Ho1J=XdSrTfa!)cb7L6v5&OCPL_}tWNp|Ulx=kS%a z8{c^5D+^Qm=EoL_JLPzI<eO)o?LzMwayP4u#MtPy^xB!ruN|41tQL2|PXBOt>WO=v z3V1vmTpT=b<hASP*3+xw<I_KR&nFI#?RO(JQ$)(sq*W5t1N*+wJrQ@j)9Q{TCP#hA z`NTxASzcLRe00yrgUQ)WwU*l1THo4Etz?=z^}=Q`P;=Ugtwy0Rl86Mx;v2h_fImX0 za?I|{<WoUgFyM){((UZc%-Z78%^TO5@jQoggJhQrczu;tbN}J}zL0x$>#B`IFK7FE z%jf6<pWB&l<UMv@W7j?si8rg&1MxkfA>UAacY9^?-aY$2aQc3?eb;D&WYD`Da`@~v z6oDl>p2P0r1Pr-&@uzf1-^&pS%0$shIU5QOo6uOv8D)0BA#=Re3Pna8Zhpm20PB(m znpM+qv?K|!amBF~v+sy!pI?b(XcTpYs3e|#S?>5P`vM>O++>q;D}PmIv~DgIcGqRc z(jm}!Z5hLZzp|#hu3hhl72wA#<a>br$85m&e%@<=K{#dMLcUY%sG!!u0bHz*MJFeJ za+yZa>1EbT*1gJ_&k89NgX)6^C#u=Yg^OZ+Zcx!JJsdR{^l=8SaG#zZU65`+Bhg?P zbpKPxVyzugN?D$I7(xRj4KxzGCXX;tn+gz(7vC&!CR425+;ZfbEw;}X8NjBx^}eAU z2I?#B^In22o2tIZB8oq|E(v}5j`kjewTv879(kO$w&c*2<X`gAGZQ(H?<t7O+S>Cj z8-#wVNe70!^?7f_ykpH&grQafZyK#O+SS9!IB99t*4B_UhCDI9u!sFVIXp~fuv;t2 z<RN^RN~iq(0JuM&&+!KDKHi~zzxNP)-<atcLdLGsQK5x0fA*Vhpl5sMA-AsS?;O3K znctY-i%q09fPU4I+$+NT04wue?`is8c6BZQ+!Nu!2V9|!YW4bSVJwuaT`U7kGOhH? z5<LszLl`pBQ($^R-<%Fqx!}RW9N11lZx}($goNl~9kp63B<kGSq=e+$pn*8xW((cg z-pUt?;YfrZ`FviJ{6$hVVHJo>y^*}^MFnX0N)gS7?Vn%i)RU3k_lId|t$AlvL`<80 zpf=x1gY-|pn5pK>K_lDHH4&>U7zmI`jAMr;Fbw`|trChPN`(wWTW<j26K}a%3m|KX z>Ed+YB?SYGjSj~mk@QZ^$JbtuxDibfN{XW=HrDuj=kDBtOXv^SR|YHF8>0OotDU9G zuP#37WzcoW`j^jD3s{yWuobb79Nr-65{il-eWwGIFI7rV>PZCTaZ1DjW~zxLL72pI zGm}1d;~FbxqupT8U}}*opeYW5b{URTr#r$~+wkamHvjprelefUg7YJx5P_T64A=(s zmgGl6z8r@?uR^g*PPS}1hxJg(ls30XZ0aC1zU_1beGzZhmgLZ&)14g~_aoZ_-#<n` zsT60YUWVbeFg}}%M0YuE=yo#oonpJ1DQ59vBkQ`oljF!>E1z#vat}ZJ)EY9EmtQ|P zzkmPi!As{aXVMwAkk!pKf;k+v_Tvveac=qSpMUqym(r_=fcL=g^ue)xyDeM3SSYuf z?oecDdjm=MLkAA5W>U7gt=O!ezj5}ly~p<_VbQpU!((97ja+K8ywkLGD!J_b_;kna zeC67O(O}|z2TvcL*guz?<WOv7W&O2RUoT`!D7kxG-deuAbYqcC<KX_|@o2JC%NO$7 z6T4n_y*(423bn(9#Y}o-dt+m(RcUVTWN2ytFG^6^VqtQ2y6JA0nt8M&5R&)tRlq+S z3fDX3;lS|0@gr#UlpBrx@wsw(XDmFiTkdjt@aYeKC=v~Knw46u2$*L8;E9Jc4{6Wo z^a-a?P`gp2fwKgg2zdfA3vu2P0)zk#<wnPb)u_rMDCUfuvCC?LD3=+WY)&i)w60K0 zNhHINWLFWW-^+j@WH}QBCLDb|Dnyj2%(;-!p4U-rEk4$QqaRv3qjj0CIfHXSmn`dt z`l}x>r`|PRy$9&uHC_2{xFXh^>0uOu9u#~V-@MRlaLg+DF{nr==8ERkZE5+oEdZ@R zQzxp0gUuV+S`0+iIKM&1wzPxpXZn>j{}ppsphO=%2w5aXv#&p>7{x;5T&d``FMuQQ zJGzZZ1!WNwd%)5$(S20mve`I=#-M?c)-q&0TIDQnTeh^E`ns*0>N8fBGDqO*UPaK4 zXAy12M$3w?>(^~aOCPQeQq6c?DmOH!QK*g9vw5@xNQOg`P-M_k;p{D-Djy^zG#(hm z6P5{~m`^&$FgkGWaWl^M@wURB!G1tpp2F{Bvpge!LrRlLnH<BCWv0^}85yN`^=c(5 z8#$~eAvN_~>Ai}W_7Mt(f@WS8)->q!4Rj`J-PgfjZ4%a>eF$sv9K+-4nFqIM<zfc5 zuzc7>V2jEbHJ&J9!FG*MH$UMpf!y}wL^Kv-OQjoiNXS$An~iQc$}Hk3A~y-ra!CYm zwMrIrqkK9vw7#(pw8bq}Di(+(z_v-mMIDGMc{tCKWQ{`T5(Rh4oZZ>svtqG`J3khU za&uZ0-=`?wOR%HVN1klXR)iX3#*cKY88l{Kiy3UXz1Mx##2K6~+Owv$d*^0@yQWSh z><x37(%h*d0ImS31Ji`le7Y4UA0ZMzyHY-jP&JWxd`o%AMF4UKAd2AT&=7|Y6cqnq zA{G_iu*veK;yK!hR`>lIUI%}S$6FN{Y{t9ZPe+cmVpv1kS}v?nt)0m17U?Z3y`AAJ z(>06>x=GRxlflQhCGalOr^RYH8jj{FMP>l0i|QbLudiGyLWih!b{Bz{J1JZuljBov ze;`-R(+Tld(jSQc<w3D8UOs<)b$NArd#8d3V+*YrWML=?h8%(3oVp2Ev~_ZT$Y!0P zpG?L%A_$<iUa0S^WHwi}v*~=LjCyH|kq{5Wymt45Gt?@R9yL;Rw&UJ7r!-6TRH~SL z=H`oqRs~|r^zhVJFpkUMdiv(Y?JMhB>zl=`7q7j1Y5Clf_dL>e`CfVbdmnh@eS4<& z0h!O9e|2VRvTJwyc0-kHW;_{%qqbd4VKRg~0r>uZ=hMIZ^t~T|F~5>pTui5zc2X~1 zdTH<I)I*2vtClNmS9cTD$a?wop_4)M-+eJ>Bzz;alByNfOB+k;=Z}u;BeM3H8?T(- zx|XeEuP)zMTwjN&w7!+SdhycowMC@khm*-_r;cBMCw8i>iQ%cEdyY2Rg)%glLS@7s zKRAAHe{gQ!==7B<S5W`*IQ`{nSwg0EyCiN3MZ!}Hlb2K1hbLnr@sXwMN-{YT3&nyi zPoZ9#8<|6UzR_+IvV70T0Z+%?thek{$L!SD;k^rvAyPnyF$Vicq$gVqa?%mRg3G*G zDN05>)N@P_k%X$t0i@IC4@v?%Ry;ZN<wUW`*^HUj=+%%#jto=cl9$ET1fz)?9!k6+ z+#7nF?BgbaNW5dj9uOQPpBl%43|Ha2$^ow&=k|B%-d5Eo{^{_x_H<q9b>a`sh1>qL zF8eX2<~!!6?*aOEOjo@l3aVI2u`mC!g-F_+TVm}36Z?3*hj$h35A0AqYulQl7KX4| zz)WcYqh>OT28nquv)h7bgB!eVZ#vHfB$+ap5`sB;%zOQ?hd%opAz9H(exIJN)|5b( z5j7|DdIQU-vS3HWK-PT>bzi<RWsu+Y9rnG3vMQz39E6zGzHWVfYoA82UpNv1#n_D{ zkO(N&9rAgF=&ws2Ee{yd!YBeZ)`d`+1;F9tGTb5HvW1Ver??WRt-reEvo|fK1QIQV zHii6aJn9yhus*kzW4UJ!bph1y133fm;yLkmIEZ<~4L?3UR>&7{&kJ4NIM<1iBxMBt zW(rv;mta=_i*W^k{LC4y>3XS!8bb1!cIDtevd(G-%Pb}Dx9s4+(9bN(syF<AK7x5~ zQF_GXEJIGxLh*02RwlnDA!4nj5Nt&F8B-PyR;$j_$*2M}?pqms>(R6nbyvtP?+xWf z$Bdd-S}<TZ9ed&Y`TYkD7{-x%dwY9wa*DPjkqw3o%~PvY_&MLwJmhTJ+JY3@;q(Kn z#syL0h$9h<0TF|ey;3$%5z4fyTxOrWrhSUD)(rLjIJwo=w++QU^yHvPysRcFSm3*C z*J|jRFb@sSP$;PdpvfwgD#t7g8B{ezdYYWC@Tnz{jVBx%F>TY$<_epeTQjpWm_yY{ zjpTsWZ>|XMU$W1LgWrr{vFiKhGyS3X4oCLA3H4^)L><porwlHYI)?db&@pehNVMbh zcu;LE^*HboVlxEgqb?<=4R5Qhh@YDdw%Mzgj96dIX1-R*R7wpT2LyO{Jn?7(A8Xsz znwpqM#uItu(s#T0Tn<u6YGbRMD@~72PmGVRZ>H8awqv0PYKs^KJUzX$6OYGqzB7iy z;V{M0<RSEE!0WFeyF*ybR(2;-s@sMpMrU&69JXdLol16{of^YHg!7}JSfyLLwzK;3 z^7%|P8w`gghR0^&lg&nVyR_Nyb!zS6<M%%L(1{Pcc;&_VZhJUB^6gijTg|TW+%gRQ z(hhN}_a9j}I6Ggg=Y7%0-kH5e#}<xGAJ{)Kv$b)x+Q5>DE=<iO!hwKmh$zu!rA2E1 z+!6hJ@X*Pti#O8cvcngAW%;$&HZOWz&T(J#f%y~n?>qh7YZqT%yOeL0HgYKaEHAHZ z++0j8Uc0%4Kv1zfJ~qM1ChmV!T<y+%b91#uDd-L#oSr{0G9B^7#>OUX<=q1lhweRe z^rhEcmVw@E8xh<gLWrA==FFbi?ONIv+KrAz3$4<S&ow?W5kX3F7j9LkKGb4v4SQm9 zfn=>%j5=fWY_(Qw*j@GEXdvW^bUF=2St-ARf4o-7`+_m@!UD3Zl`Kc3USF);lu&gU zPLlE=C?~>0#=~Vefsplmz6dcDtbWAB%H5#Z$gW7%0#)agG#bWN#k$QwB|$+o4sjrG zDJfCMq1hfG+n8`$bINTE?7`t}E#TI^Gq_jwm!mg8q_;Sg-Vw0strzk=K>ya;>b)!9 zY6~!zbPJIvD?nJ^)y*WdJl})!4b-dG^Pz?QSq^m4TDZ^xlorIdkf`OIHJh3ER@okU zKIT3dK=(NdZYu88$K3)V{hiV%T+2(#%nGH|(L1R9Fz71gbG^TH?4U;zdcCQO98ier zv)n}Nircp2!A;tNfL4KdqfODTg%Bjn<0P(#&+}ClXek8*N(-<Wp1P=`=x+rp_0xM< zPd6WmyN-W>l4_i2cknE&BNwZauV0;89uc{ZV(Pv?zCK89YZ&(0hPvjWS+cgV8H+^- z>QotZ$n<1SWSb{b5{o%oyd1{bAfO{sT!mawDix~bvgo34i0*V2iJuFG^_g5KN4C8l z(ISY8dT`h%NVfI{tNhxY`mbJK0ey=uq7{)g?*l9|u!ZXd=i9`P;hhrKlDM=*@eS89 zTNGQG=(3rAyM&9${%6`yM=}j!$jZGGr&<hi#v)u?MfnUrC=fa<v)LU652R;KGw{Y^ z|BQ}|lA8&76~{7|J?V5Bbj8JdmCa_SrlxT4Z*FaZgYm;fLJ?)!P)+cZb&5iz8RI%s z)QmAeU)*KptUyc-qfP&YzP38ow3t*!$B#Cky4Fl9iO*i`7X8!k?&OFDPP}}}V5k&f zIpZB9(><-k?+S&y00qDQ;>FA1NOW>?f>z>}Td6dh|6-|<j7MpoXgF*R5Ck`1<_*pf zYlX5}`>n27Z-eWsioEr*+*ZxOJ6My>T8OOGOy|D7I4INE%4lW!ixb`HhSyZBR3g3* zCr_*kavX%>c&7y|Mow1k4m4Zv2j^?0OflmN`jf+BB%TE!@8omEY9)@c_>gC7D@A%) zY{qo9Kzf1U(fE+l4r3&h%Z4N2AmlnAImCUDm;{4L4pB~T7#L7^c8AC>+N$hSa$DJa zrclVDjMEuUOaLi^u8^(SspWFx9)<z7q{L&Uo7o$smG3T}Ilp;>xZYEHkMAAb>mKqR zoZNe0X5YX1-WNP>=Xh+iTCHz3i(9*euFr8ZzryM^8V`N^eW#Dl9)PO&(v>qytBW7F z@1aw3hp%6J^~{BDo?BW>?UW~@k^A=S+nbzl?%E5LYNl4cv~;yvFGu~sT)E<pB{J3A z>&s`6o(VeL$l5%#=h4N@t=AV{N7aXvTaLEPYj=g*p`EqN(v=mmK(X${!jYx*RhP#l zD`dU#@ee*VIuU#A@~ceX`H_Vq(}#}F?hD%dh4#?3wZ)C}X29=vJBAL<&mKE`=)|d` zrJ-`u(<ye#o+x1lp2h46X`v9kX||g%0n59Musa0wcQqOTo0~4&Tv-pf0;Oy|mhcWo zgONZ0Cpi-z$uU_2>_h%gj1#kBamVfAz$SzkC1{?NsZp;0!CB}`4n<iI#6_i1WU}(2 zv4fx981N>yD+{4n=41`$8eIN*!YMLd0s~|-(o<sYLcok9KEoYA0)(Eo{tbc(x|rzd zB<paW{?}XU-?*FWcpm)ft<R%(&6V!~`gcuNzAY+Zpox_mwTF`|K&jp!ouX#;_1NSV zs#Yhfg$WEq=+RLI=c=`hae-)n7{F?|#*IgnoU+Xxa_T=+AFU;{_A~V|Yr!anA`(-D zo=aO-E-jK?qXvLkvw99r1%+&!hBYK7l;#tuAlDcuBc~8%i|vX3DBQ6sqW9M>RL;pD zG|^HiNk##d+}dDS+~z`cl-Nic{vjjyEq>5GS`|ON^&sO7=~0*zV=3O!Lh2K>f*Kyj z4=r63Z8xhOtY*|-Y2#?CYWoNm;*GjJe8oeBMA2-aZI{{Ep>r1(ufxC*IE(Am?Lwkn zJmR)4a+chLJ%*!Ru$`PIka!g#OR}8@Lp_O;ehfo@$PKhw@6orQyw$>Qbm89`Z&GwI zLVA`@uP^#Wlo=o@P{T`{?xxz}RBF~rlnx}y`+7O=aC7=ByO^Xt6~{ShGkU6Hoc-pF z_P$|(_h?|+v-s(`F|9;nWOF;<Z>$=eW{e3qGsQv?o9dNUUO8~^5cDL@G?Z0_;wQfR z<>h6-83jY%Qz06t*N1vYh~~244P_+oFBX)sB{Z>`89Bx^W=3W&1%wV}V#IYg>ip`# zJ~KXhZg?fK8}B>cD)nEPHaeX2z5dWtdk9)KrKMi<qd7w$+@K<PB0av$_If(K9SleD z->+|OLH~`%6Vxb`%9LwW4jSUoC?S=EQJ{5WmJbocRLgU41X=^~))e};=H1|Wa@R_$ zOG5jFm#&0#1U;xHbuvyQhPLA&ZvcD@xDi7TtHloN!X?}7_&tF}s~IF|8geHdcOsb> zayyr@sWdu8F85|3%Mt{=8grd662i4BwMwp3oSGW5`)$EcV03I8^>L{A-XSL;A3Mdu z$k?ci^LlN4YZE-m4nXt>IZ!#oV+EJ7RB3K5uD0?u(leFO!0$TnS(KZl0GW(x?O}Tm z;iQ;1<i_c~+e|l$XErZh*tyyqYU3V2MYdEgU0u64niyVOUo5(to@Dau_NC3%M!Azc zw)dpVKjiGTAGqfO3ln>9u3z(t2>s+{CgXMnF5SHN@}<|K(cqDZVOOIJNoF%sh{Td} zvvcHT4xq`13wy}6S;}2Z-Kg(2;x7M@*z5-nK6-8C=F0Nogg;a(mKvpc(jASG3bx$! zw<QH@wF<?NW`+XS-pZsWN5|Q!LXpr1AA3I;EN(2VU0qpUORp{r&+MN+{KDedrOZYs z8s5KWehy*EnF((+;28;BDJ*pfZ3rOlzZ>!g@{JN?q_{6cWv3F8H*@Rmu5&UtY^%41 zLy79v&i?7i51c+dnv9Q*k`C4t32{0KiVjpNB~rqY<xQwHHWrx>j)_Qggmh70appHg zCDm)Wl=AuGO-M2}CLOW$;&<=+QdrW+MTV6JONadq`+z+~PFl!DCVl}i16VQGYec(7 z){lYgC=gZE#h@#yu9Mc#)y+=V5Pj1}4!2fOYhfQ8@NYU1-mOc*dw~Ak+Oz*=>ZKD& zQJroW)@iRo77KhU2p%-P^&nW0qQL+?T&s5*oaz=NvfzTg(Q9<_^DmFKsNu@7(fjB& zX0EwKkFlVwwa@7@`H6LCpnqCsiSeZN0#B`VhZ}Q^)<ugXz_g!e(;$9n2Q7>i)hf1C zc)i<THLXAO8ojN#LMe(vs2h@G#P7j!z?dO@cdw?pg=-9)c87XTxdw+EWNX7gf&?kP z6V)rUTCWFN`$I{etKaHnVmS<$B3AEf=dn_21$!48S#h3Y7~{K$%He=V<pz%|0AhA# z7W9T7y}EXgtIzH1@Fy>jK2P!mLL$yiX2D3T*HFE#6oS5WN}!FYCDAhn?X|%XA_MF8 z6A!7R0qv$yO|fqc3Ar0eL58>`o+e?LOBp1eQyKMlG2yUbL~jxEk|U`OAM#M*S;?G& zIGZ@gm6X~qDjg&P$>c?X*uX9L6C@<}ayr37g+hTqSp3<gQVF%6k&zMn?t~p=(f6E~ z01;((vNR3>i2(f@i;IH7x?R%1U%PgVAv-fO!%ZU52rmvmXaf3LFtmhF8>nsO7sJFv zi>Rqa+8Z%DshV(a#LLzL<$AEDZD{1{jd5Zu8sc=t0zsIfPizyr!nD60YDv8s4F!=H zM1VYri8L&&QX$KQ!BDhOD{-}y&B)j_+Y&1|J~3V>ktud-@4`YRUyMh>2qog#C87YU zmGP=phqa6h&KG_E&U)$mvS!&^EW9<^t<}R?PpoCrS`zt+Ic`l!`b8Hv1_q6(G%W;D z&H5lF8HYkde6lE13W&SgJT5=BezsQJ&SgCIA;=Rw@hrQoF8mBR9gBvdu~0Z3iTOhT znE9M61w($9&p`qvhSS){81bvjizwlip>Qk_Z*vCIZEx?STwp@`P&g1IP?xwMG7d#T zK@5ALak$*2Txn-(XZgnR&T2Z~l$2C?1d)7ER*DYXdPiW)6?eOA1bvQ!-HYp&(~B=` zzOs?p7z-zU>5-or9i95h^=JR^;uqG78<n9#vr|XQ^2uXQdL6Fot2ZmMlserV`y=;0 zRxDO7-@Km6mFnW0anFpz4^2V{Os!<|>!mWrtG!YlCoNPc8S)0I<^0XfYg_rPaxp*S zAAWf6J+{`+&DF(IGy9%8{Lr{J7I6gP{^3r(<!soX?u?BM7fR*rbecH^A98bJJvp4* ztYp%q%;ebk{RdCXjn9|Rze%m{pF5Z>mHzC^SKDse*x1+*vF@T5=_wC2FXooEY&l!V z5puhyqr=s1y))E}`6L1G%;<EzTbuBWkasre3XzB^=?we2yFc;N6MGi+%uY|Fw$~A_ zNhHTybfukjrq*g!eEtZHOngK*IwIz=Nvy8ac6c~uV}U@pEB})I9H~k?L3Z{&Q7M&l zQN7(t)(gY8(L-|inM&82rI^-q*}8m29K7gT>P$Clf-ESS0#a8PodScS_cj1v7OPt{ zTK&`7ecp+4|1D1TH@)mVK>wyq^xg$;-U1dd?a%GrZmK?VYlAUJ$-sm+f@uqCTf`d$ zzGl~d1Fp3;EuHyhQ4qeqwW%wPS1<wFqzAmr8eud&dZC;OrVV$$hsb+QN6W$76PlDI zil-==(NgKnwaS*0ThF!4x+9!>B@yW|#J?I7tPj=J&>vc`-m)=-Yc7glw;cAjmZ|{) zlD2~(9YUS&0;#}2U@i%iG>ju~vo?-GF(p1}Mf4N()|(EJwe?Ogq$zs_zp|_^ZG5ec zwbaVZEgFeLTK3jlMGrl&(wE|)ka*yXIJ$dubPP!rN&@RfB0B~73bUnDEJh+x4hl#q ziU<ccH(3dHF*|5`Df|E%L|HL|OS$Yo#!t+LR>zqObPV1KavdDBy@u!;A<}4O6dFTL z(7fq%+M6v+De2B3+)mhRBs-K{N+f-FrkrTYOI_hc<HbOE=`thx!+UklD@R}7=#b!z z2^bbi5+EK@O|e*@l|by*uU!M6)4AY#fEO2l>=$n?W;pNI+2QA@beb~9<8eSU@d*UT zPE1UIw$(-k5KsW4IYT(L(VFO$L0I)>M##~VX}4Qp15zaO((zypUgQ)=N=q=X5t}pZ zBg8FAr9;a!yO>~9&Y06O{LHyohui|HwJ)>J1l39UIolA{9eH*r<mPr7N&1n|QGRmu z`VD$Kn=etSWIV>*h>PXtW*Cdmo_6|R*WdZ)n=fH+gDdV@k+)th>*s^3ac`l}^|3!; zE!&JwbZ~0lsTL}uMT|q^4dGkd=dvs_Y-|o7EW>?QvITS;ZfCvIO6Srr{6_pCgkmbK zN<11HO^nrsI_Y*9MZ-iieC)v9`%av|XeWOVE1*PRH(R;%4uRy86H}3Bd?US)K{tk& zc(1QfuSMf9a~z!66<}CJ<G8XppJCcyxN;y6@&+4l_}h-1^}Ms?aChDHZj+#DqF4%r zblBmJcD?9DwuMLT?s_H1FhF=Bx$vFyuT&%5^~y%No+cJF<PEo-o_i(^P9{f&BguTJ zNIvHG-SZG;<Zv)SeyKt!d;H+NNA{lD%;q}|*M+r}%|d}BNTH!ls8jUVTNhTAh7*&A z_Z}+dwu0Txo{@>i4nKBe>hP7DSIG4`mz;49d6KcQ(a^|FYUj0cXLH#+xveV=lx16i z0P7eFh;4k70|sX^02RHCLg?hkELpNMnf1p{J#uva;cvb2%vyeBxv-wAmtS7L(sB&N zBC(REo^9nq(O{!nA8{i4yH;#h2!z61LO!&#+sIXS#{DB>-gwC2OSs~jH*fsJQ%@(O z5rkywHTY0S{s+Rrh|3dfBQiy{W)Jimk%VUsx)7MJl~l!xpdgWzbo=qvo0ZIt(!5Cr z>j2slzs}4zA+x%rO2?WdU+n=2r11d#NgLa!nXomZOvHMD)UOOWu__xJpx|8Sv*re; zt?oOrrwj;I>R{I4ZCz}Q>UZd@f9n(ctz7vYpnof^^xidZ-U2$=bZ^kD#X|GeCl)wX zueYJq-9m(lk1YeB2ZMT8TwHy4TNMZE9Oilp6YJB><X2X-xDgGq?;$h;Mtd7SH@VFQ z&>c>1Yk^d2;n2z(_$#hi#V!h2tY2vzbpg^3(eVJD8q}iFkUegI{*bz81uY<=x9w3f zdP~-=WlP@mRp<3n{ZlmNY7G(x2GM<Rxmhnsqp3=r+>I(|b6IwX7E;T=hK)~d5T@(5 zgQc>-fz`i?;CleQf5Kqlbt$I$SNi(&rd4|t!R?nyqfQ7ToFcnmcu!1Dv1ey<S(qgY z3k!NE!#^MjnrLKnOn5A^C9oNEjZh?7+C6hZ97QJ1Qh(K3>&@4Lt*TYfVw=nKe{zJN zMYXD<@8z<A56w|S59|s6GQMrK3Iwp41e~~*&88^dbI`19&OM;HYxB!EHw~gm5PRla z{~U=6OeR?qbGA#}B~2`az(2~C`_fA<j*XAwix(Zw)HY@ho_l=rd<AN!2jS4KuC9Xn z0mO+!(nL+bo~?6@Bv>_Bs7mEBCo&iV8rVRw)yNT}qQ60!kuMH=us(%RwF*gaD|5$0 z1ZeIpGqXg5A4U{1ltxirVqWcb#3&*03p5aaJZ4ElVWOE1QYnrg0E57K5)07#WTin* zgDoFEy<|-=X^%%Irnk1zV1?P)834ul<|YR<l7GNHG&ME~>n0ME<di(!jNzW3(_kkK z4&XOmx!yKcSaZr6y>Go}w@q8?Prc`D4Wb|FlBG*17g)q9I!k2ZP0TuTP+b)ewZVM& z&|zS>cI_zAAi2oF9;h9Gc~<UBVLRgWCjt>h&T@WZyP91XoqFW((c}B)Cz!?~6ZrXI z;c%K%-pRM>O^4UbYM#z!37&lDfzvuRVq~QnPC7gu;BPV(BY=K*IDz@VFq1(HVh#8q z{2=AEy_xQm8kyDYt+kz@w!_OQ-;izGI~ohbunNZA(ISageg0yj;v!;o^ZFlO_)5pw z$~5u_c18lBe7js~R4=VxZrW|WNDRIWfjt<fnQ~!fbiy^{z%1E6cOV)|E^ltFq;@=> z;E}yYCK6+$s&047E18w8VktQ~x18Qw-ds7k_XMu-AgPY)b%NrZHfJVRc=hsyo9k=a zx#BBlU(KXb)pG69rE795D#v$(AQw*_J@oX`kGGtiA<s~g1bUr%x>{J@+L%d>AK8C+ zX?eL+NRNcvoCBt7g$vmmTczztFnDqEqTl1%H!(Y%7++dD7lTyiXYG$+<wOIqRB6Z6 zbtXKK(2#$(-t{&ehvw%_9Nq_jCPE)v9f>AA9%%AG7J+nzN|X?*fpP<s4@MGPR;}ca z=K|Wx4uTFP;y6uVy3+y%k*goa#&RdebISWP1e^Yfs_Uwr_=)`{L(8Cfb1BoB=p*z1 zB=Ly&H3r0yt>w4BP``l>Y0ZVf@qF8?@2$&snD=je9=+4Ad=JpS(|ho3QT{u3Af0Kt zktlSq5UqY_5RXt(EOc%mOKX-Y4ing6oXX$>AQW+vY6e(89Gu~X`z~B)1M+xtD_yI$ z)F49Dn^?ft`bw8A-N_Vo_kSpBj#>^@Ei6!I^#pjv{I-{oUeXVV4q#7z#=1=FYpr5E zJUZad)+?>r3AE}XSMzxf)^n~&tx)ymc7#>RefrN3Mn~UWs?DV>-*dJ0J4kD%C9#TO z^{Le_x0Of#R9ImBT!2D9+m!X8k#G@d8l$A%h(#kX=@Gu6E6KjJvAGGl)Syp-UrphK zD=+(nac^VF(G8I4Yt@qYdIk8(S*;QVthy*}7H&)*!SIG16yztIlYY}#)l{dsoN<W1 z{1#J7+uZ8nKKj>sN%Qd&d{-h#$<14mX@yS(*BbA&XyBNFLzT%Fig*^q6g16htT0jE z7OTK`=;eO>nZi>g7Z_vD9FCYfJE-Hi*U!$*&2u;|9kFX$T3$MO^e8`sb_}5Bf|b>k zD_5@)3k%#&CWn>LPWiEv<X^uZhdt06a7}t9?jWGT91-;9S3ibTY-!x{X0A!@NDjC} z<3hx9IDo)EDv{I1g-;tZb8+v<)F#dwce-)t(%Rh9@Vlgsbhp=W0*A`bp9I-s<nR-I zj`THPo#PE1vw=`l{tZSpH@E3Bw2vSskQ)mdh9<=t1kEGK8VE>+DM^6@)5(n8+m;S% z)>w1x9r4C$t2>v|AFBM;_#d2=I>)u42AfOUikB{Qx>j4$O4ml2S-WHxlJIUUD2!@i zJ^c>(Z_w!@vX!(8#HPmmQFqr~t`s`WI$4>HPVas4#Qg`SW(vhTN1^^;6!>09?QE`Y z+;iXk@nkHW&ox?&drqBv^nH&MN+skkN5;njF-TP&A}dB>k<`u(=Tzi5!kA<bVjdGz zjoSh?T09b^sHIZ1n96UhY<0@rp@uW$j}S!C>@-}>uDd<t205dCTWxk7yLoQ~K_;ij zfFV#hMBb%|@MyMETC1d<TYf3q+SzVbp1pMDYJH=#i@N^qSaNEMtgx9am_uOw1M_<q z#^;C&SSIkCpqBPfd}IR0`FAdSH#s~x5}nOw@~uwQYioITyOfZiVXxbjE9_LdjVv*} zBF4Y#A{xQ#Lv4R+YkedVc=FK)NhndS)z(t$0hhZ*4(LW@GCumg2j0KBwGPKA7Kqdv ztwWRhM`FpK(={7TVhry(+X2o=?7kA=C56>UEL=rPe#qOf+a@Dptgc5B`wk`MlAcI) zyRv_J_VI@v!W3fVtd|R31VH_m01<FCc6_5Hp;xHydOXAx2gGYG7`qz?MA<h<2W#wi zG`oT<NMfJYD_G!sF4FRnvqA{*x^9{wC&H8cGjLo69ipfml7!tX(LLt{QUQ!Z7I9g~ z5lbcZNC)J=t|fzA_Y`X)_YH|#JXLG=9K6_?CO_s3`k|)V+v?)?0R7vlJKm{<8QeK6 zglbJWCDQ28yydp1s@86yb5g%D&g@=T?V#hFYn0?|JW0I?Z+Xh~=PG=mD-73LSX`Uc zS|E%qAulE87?<v?O|HMVsK39*D$zUW>4D)7+>%Do+Zx>2J3UbLj%s2`3B{|cL9xA{ zTU~A}-<Xz7?_-s1a45)Erp_uF(}Sd@lDhCU+8v+pi+W3;daT7*>BA|jgKk^$1~EkM z{Vh>PxmG(-3edl~7FC~XK?nV__Y{K=Zd;(`K8EgsPZ^d7;0yv3AQfPTmuPr+7_^74 z32F@<ZGA58Uc6HxzEQ7B1Bz3}n1aTq$n_EvY0@NV*UDGD^BE&s)H@Q9fuX$N!Mbb7 zxt{9=Mz1upRWEB;>cxU|l|gP?P+SJKffA#9bWV>bDrObi8nhG2k18IXMNqYHu}s~i z$4!=2t)o21lu7Wv!AyX7<MzVxY4CHr?>H&fH#Pw7a-y}no6qGhUb?ujum>?p9?ig7 zUtc?a{ydEULkWurl$_7!#mmmKn;5_yY$Q1M0D7KFD6IxpsQDpz98HL%CRH#;4Q57| ztjSVq_TE+-#xrq>W=M<VB~=q0%(k#=Xj@ob^d=1=YWE&bC=?d{j1h@47I+8vh1;HE z1S}j1Q7V@t{?cwQ6muN7aEyQ~DLLf1n2~|*jacuyw&|H!ju#e}mI$~bjB+!b-7_<V z9f(muT!1kT#a_^$`N3hVy*Ak0@09m<PSU^Fl3R0Dr>eR$bTQEulUdXEV(4KhAM%Oh zsldK7QL{#CTw0hRCkiPo9MTSt-4pZ0IBZE5<a`EwO8mEyNyyH8_cusaj61{OJ^T9E zMzJ(GF)=zf=Jq<vxw1Xr2**P=mTu6Ip+IOYlVYDJmx{h%ph`rL&$kONWqiC)fxIp! zv{;20meDY%)Yl{<S)&p3cw^yM3Mx&mmfcBRxqjWT>qa=AXz*IOjI0ugEl6jZ3`dLg z>O^ovvVoZFMae*-N&>2(N;u@Xmb<=DPPZJ*7dKvB+F8C{%D_j@mvgL9fq-{35yw%o zl}<6#P|2^6bUB(NW5TP8uSa6hCy%_ZTW`gKvC(jZ)3J87h|s6g6G$XSC&vf|9-WyQ zCoxnepCeF-oVmn-huw~+9(?!%4?ozbm6z9-Yvl^%S<fvWn%)1=M?boq&VKf@zZ-V> zAnsjWUmYKte)Q12C*pI{{`hb>o+<CFmbYt-_W9LI<MGjJ`Q<{RH4+-*xGLyGUC4iO z<Nyx;)Cxo(`$wO6ED}YksExC~SSVl+$+?!DzHrlj$oxy<FxD24mWuKf8dTxPXsMX$ zA1rr#kaL_K(VBF*`CinhNCPH9UUCf1{$|`FvX}{!H(@z)xF?oW7Y~Ar6WBWvW{m<S z{th`FWV1Edb%mVM+sg(H39W5f_uoN>QE$yOJ}GOO4^H;M!Tc9Hcit&?dk@gRQ+n#{ zUQTOXS!hpjyv|QW-h-3S0_(c3=rz`4wq~qOX}yLGrhhIhpnq^C>;7c?lJbUU^<wAy zy0%=P@Lh|ch3p#-J*K$&di&d(tWf%Ns{jh+d5Ze5^oCkCtq#96!2Oo)yMD;6v^Dh6 z#to)uyvGsLitGM5xP<9#<yU?2L~8{!h^EIO@o=7P7DwHxxg5U>&J$g1Z^PDBFIb=J z&E;p};_i_{?p$iMg#AanVJ+7F(mPwX?H8}lsxl>EPp;NPZ;?PxBu)^&g9kF497g<v zR4H(36zp=ok=jlX(`oKJ#KAJ#k}n_uvM_A~`x@bPb7fCPrq@sdk-O@5r@sK8+73ES z28(K(`j#<Z28Myu)-aaN!%i@C6Ob#9)Dq$?<7ZeSw0EtJHaF^Xb@izW=rNB52ZM1n zGTRzU!o)YajlA$<X;v~htuj0q)r!H>h6@cqLw>03t!*xVk5mEz=W;-N-0+cTl&=`( zJR+4!(+KE)hj74)IZ*{b6HO=s6%Mq|2jQMzS@0H3&CLPgI2i%rD#0oJ#SU!fHxgB1 z_U3xMDrw*x_{DL$t2JWxh<?0LKtg~TwH!H!_hORqL@6`jb>#}E9Rq->t*xyB;(<@} zY%ZU}@GwGk4dd5`S&QctUoWNe@p#C(flwHrg&{$I#1qMQJV{fK0|-(P1><aCa%_aJ z_!FSdfS0+3Dz33ibR-P^`*vS0?^eFS1??}S{I}ikuB|jUVRbg?W!7peYpD@Dwc1&~ z5@MeTzrkXR2Er~I3glR>PL{}kFAxt$E4A{??bTA1EJX;(G?^U?xzT9s!TU}YD%p+9 z%5H<>9n9|CtLsZauWx#EVl}ntVA<;0c3{vqS_c;vYMrLX=iSciFy$Cv!y`!??S$5( zb6MsBt2||3it!bLqL9vJ)-v{{y;<Ewm4?wB^o2&liQQ)1-RQK7MK{Z^q!xCz>^7+9 zsQ0voIuoI>a;Fh+`D)!7`IqwD>dj(mrLeYH%NA^{QWMQwFF6va!u0US^yruu&Bt)) z?AoPVE%(5lllzA!(cp|l6V+nz#?31`<$}W(+bC4d-Mr3x870%It?P#gG?r}I+s$qb zLC#}Gk39bVC&rQ!naoDDQJNf?fRuu|{D&X=NT+UFA@cX?jqFaYVZ)KJTgk76yRE6j z7%2o}?nGjA{APAF6!AMf-GDDRWcP%8p^?aN)D@bEj*s|am15c7^<Q}X;?I8Ulf=Oi za?CWTR!SssgC8$;HdBlZh#5abm>DaoaOXKfrqi1(l!8NYZWfA5h<_W_sMq-B%P@1q z6dGdJ6Xh<6a5X-8Gg>s(O;!<IHqClM&xj*K)9T6RvU`YAPPvY(GwS%a!q{~C8(hY9 zxz>NJ-Axzp@3*P_g-o1x?oHkU^zYohdmEMfww*&EsRiP#IjPf9zp}`+%uEHi7TB^} z=GJDTKhb~nZd6`(8Z)<5Xwr(N??G*AXS&UJkR_y_0(0<<1<Dn<-nPEzL(RWEtUoCG zsMRqglzdgdAcN=1em_~VZ^gf=Nx&xn)4`u>;T7}Uwu<TJgQ%rnS%F#Vq85mGs}Cfs z)-1Gram4||qqWe6)qj<y(reW|M?yZg{Kw|!1HGeV>Gh))*eagBx4J`~H2|QC#gfEf z)$3A(-7fTQl&3jL2b;1hQw!vlwUNPy;9KKa#}STt9v*rm-ko@U!Gh3pq!~M1&53)f z>isz(W6v%OU_H<2?I?ZNXElQPq1jw|XAv6L+oOJ3-g>ce45Br*oT17Oaez=R6pHX( z@S3y3v2B9Cl}e5iQFx*)aY~VeQ&f7)z>ylMs$*YRMq_4GN>U;XIpB74F{kfU+>x{l z-b!o+x)XmqkbQJ)3^zQom6VwDx{_FTw@XAU2UoD?uU@@Eg4OXcA>1S8&F{GzO*))N znn>bZ62}64wl+8M;*-q>FBukvnF6AE1gU{C@ZKC;2;U65iz=`)(*Zg{7_?X{=~RmI z6aK@MV04kSu@B|4JD3W5PA*#r^8kHGB8GF%?ZP(T+@HB1y!jSc;~OCL-ac)1d0H58 z(t52Shgsq;L=T-5!d=V*$_Iv*+>&l&yWPQn-`Mq%)q(B<E?7|B8q#-;hquvM`Bz(% zTXXe|HqYRCqBCyLE1|2OwE*@V88S^o7^@}HSd!epoLQ+;A5Sk>Jm7FUx{iPg@aL|! zn;?4(OY*+1ZLTnwr^cs9K@sq|V!?2|Qy!j~a(KK`Q!}Xs2r^VgJkf5;l#su4rPDhJ zUl5HWGRS7KIdeE5De#iR352iGnQi`z1jDsT9fcgy5_zH5`+fOhH5QCl@)fjh(rer8 zavLF*us7alSKT%ThX&x*pd%nkHBP$;|L{~vgU}`EvJcZ1GGEvmh8~^_qv`J1X_n8Y zm#$~mR&(i6tq}0ocdO-zi8)N+KR@%WY-#hJ{RhS!zDj<(-Y(agopPhOoZi|f6?R>L zYNNBB+VllIYniQYyz~soU_&_Ur>6HW%-I~x#AsqUy|z=#9hl!U8XqQI*V5MN2Os=s zJTZ3R>cxkT-E-vNv2;1twAJUQN9UuVPCd_2=0>hiY_%sQCzn!-JKe0?>x%lLiBN1j zGKMcaXm`v9M|>zxcKnVq%WLQ3Pe17)RJkj-oO7&7DMz{}j?n08%qwEM=yl>?><+R% znPWGXj|tB&nQ9_DPw;EE<MoBi&p8+&^p^z;h%fX-nPPe#uII#tOK4<##f=2Z)U1;7 z>W?lt+adnJ(BzEgZeZb7-<h>B4Q|RhU94fOtI*)+wI=&}vtB^aumAe5|JANA?>+5Z z-U2$WbmHljpvYe5p+%avwh;YF&)oQF->I)&B8e5WNYV<+EPuJ8O!KGwP$#*r3;Gmu zhaN#iZ(=PO)-o}Oq?JFaWmfEBts{E9R!VQB#n20sW1~AF|LUKL*OmCLN7W|Yu_yg* zomXh7tk%#s7BsPzIj$I7u*@~aw&|gB@!|KEx!w&;k;V3~9-;NJ#$Ufd`YJR7OJ{Ep z9bhk5za3mat(8~nZY{O?6zwl<b8{u(t>hJ|Ntm$Bh9({1omf6MmzQv5NrbNPzRHzC zH1CpT2&xHt3|`zysh~s-U;)>Nn;gHAq+&8k=jLHncW4FmVjRHMS&B6V23vq;Gi_)@ z8v0#qvhZrbO?B0PH2x)h3h)}Vy1kXcCJ{|WmlJ(SwmYhWVmhv8u7NeqUGYJKPyx#N zLmgwr1l2J!#3rW$mD+%nB#Hp_$x4|h;dM#5<#mcV<GOL<1{@m5Gq~!Je*vsx1xYHI zM&st<4H{1T*&yj=lUAIcp9lRIBhx)HJS;ci7HCR)z4Qo12#??s5Vo;ZK<}cpL)jRg z_#>%s1-b%WIJcVzkz<Hw@d*%~gL{5~1b!x+rnZ!yr|>i6;b{||F0sA4yLjqNB&!@g z@Hm=?M5MJE<O^6jyTC80IP?h;bou;PGkk?*K?J6u^GNKooZt`Hcr+$QI-4U7G69ob zym|<jAc8K9sXV2=oA8!NJ2+FUzJB|^`71L>tVKX4^=-|iOPsDk3`@%|qtZ9JDhh)4 z39u7|T(cg^$nnCgar>dyL(*UwY;*$dfY;?KREiQ@+v?`>*^TT5<7of%-0?%lcSG?E zXHiaA@3umd{K2l>Rx?c+HJhDrGLlFZ%N&1oOXbSK)C^Yk*vJTSnQ%BN<s9XPX+u<Q zy<HQ3Few)#QA25bY^(}J4>6@itCA~cR#V+dw_Ix3yB=RC;&37LZf~<J;2UURx;v7= zWO1k!4-IdYGG4ofz}BQM*0ptP_Eyvv%y#lMTm5==b2+n_ujW^>>Gf*;#Tyq^wr`$T zIJ7r3?ruT3Z+e}cR57=j-X0s7CONLqi-x+%WRexF+-Pj%whOfaLBQF1fiw%#voncU ztXe7DSiKgH4g3AUD@%)!MDzm>J%0A`YbchTSUA2@DYR`&WG5=0`)3d3%Gt&3%~H3U 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%0D#^W2AaRNV0G~ZQQ~!B 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�|)qz{rm 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	WjpKaSa1_<^8%wf ze>f}O3(Uw8WG_pxAV_+VE%PZ^(l(SIODjrQB8EFU=uc)tkao>q$vPPQ%0?=KQ)RA8 zhcA0Lnh|A|*){!X>`IWaO6pMI@5bn7g{O@PnxxN|<^C9mcimYJCoGyi<K+aJOlcLy zY`b|B5*j|)=3H95VGbm5j@8j_k82C=qLVqPr=#W;wUn<?QfK^@@>0suDJRGL8p}DM zjbt?jACB%9u0T;sv^f(*G4DcMi2*8KWOF3=EuD{Cr<#D*n_~L(t+d&GKl1?_%hJ*J z^6Soo>5Pl(XnfY}^RMR=a0+;~O6<hVndYzm*1x=S=Wb@LI7LFq!En(3)1MnoPZr*X z3k$Q=+B-t6>`LzKY-5-|*x!2sZbxKH)+<k6t|LD&(m!{pe{I=3={-UHnSC(0tgUbS z@~{8a{K5kC=fgfpxwdyinlo$sdBN`w3Z&>HR)_#z*)rn~$C4S#Ot#L&W9gC~&qR&f z$<`z<Im%CAO?kmfp;g*|tVbE-%G#WY18+<;ARE8*#jy?Z=i{-o8POx}a+I8+khIJc z#5`PJl|faMpN&-7uM}6M_k&hhU$SvbAB!%OF;F^`+3-0*QkasqHYHbfoi;3}otBoi zEhR;;bV~nhIMT0a+fq)*+8I0?Jnu`R$CU<)CM_xNV2sX1O7K~{=v9~9yAwJb^L|Nb zVr|od>AVibAmxGd+Dq^n{l)Cp<bfl?q-<X%W6JQ+o}fv_b&*oWosME2`Nfgbc`=p1 z(1n7O&8%!fc}FtB26@wN#!v<^i!mK}_(VC`oGK4@%9%m8W9(`z@B)KM{x$wa%cDJ6 z3uAy{6jF{ozdolxCc(gw?)5P}GxH0-^6POp^r;hy`3g|JzS94}k0>0LsZBWQ{QT@Y zGS8Ek^59@&?Ex7lGtu$r?MG%@zffyh{z{V5W27Gxe)MOH>Ff3SFaPRq*6Nd3=otb+ zW6PfO=Yamv$MO8hV-$#GBgFyf>XNSIF?nL~OBa}v7Mr-AE=%5sfOP3aiXpOAr3+rb zf)pzR1W6ZKFC^<!JP;tDj9TKwKn7zQoRTG7o1?}Q>y&Aj5i?z?(*~sN%y2_Sy_6th z+jG(!h_*$68O|uvJcUpxe#+WVrdx`if*E26QtXwDR2eg+t&O76j;D=Ddz5iS^e!Ed zw96R-r{s$2Vyw$^Bp5!*Df3=RD4usKb(q`7PK^}&c~3J|NokVN$_q>_);ti^rF1(o zC!3XR)H{_I<6dq_N{x)`yd^=ywAp^sYs?yNz`BSr)sDe&SDbV})9LID3(iURI->lP zGQlK4@aS3;m0o1ynD#VE2vTJ7DrN7C@q)JH2^%epE=L=j%}$!*=l9Pk0RJBz9)c!; z^{>Bq>l@$r7AW(K$O2p9Z}VfH8m`PUqczLPRyoPpRqqTor`-NzEk|<9HmYEH06j+f z4`1&u&62;ef5z!6IaI6m%4@HG^V_d6Nf`nLqTH8rK>uW8dj8hY?tiQ$*%BM8V0yp& zOdyFe$|-}4bajkhGXNCpoUc#m5*xrMMMw$AIKnj9R7qFCtiiE72Tue{c{uVY&&IUn zDNM;AOSb3+ol^uew*9fpM+qsO$mpLHTkdt%-=MY+N7k2=^67O3CcK3Ym$?}`mHU$2 zDPyKUU@`P%8pd1vl;YG!gjr63#C_$+!zxC>s|Y3;eHC2;!v%MxR88J04uXwV@so$c zdM#lrS1lvMc{-FaQo&=<s&szESbL|k7M3|b?N_j6+Nl`jw7TG#loewN2L)30D7QAu z@aaZ@_b%cD)a&Gsscf!AJENQNKv}k=lu4&RB)iNe-PmcBO}%sql;=W5x{QmW@xkQL z=8T2>#gqZknHBvyzc{BrP=LvWvj@57mlhX)?Kgf0XZkZD4s40ld%n^C<KI&SH2ch2 zSeQGb>K?aP&tJ*$Qp#UBGyKRkyl&(k^tk0b?(?V(zw+z9wXm?j5HJvY%}O{2^p8u@ z^XHE!P+o@u1o%>s!G&zW2=o?9OFW-lq!k6k$$&x%GSX&bi*dF<W?hKoHf`!j>s+~m zDg4Sxh;=txt>dvELcoG_Z7#E2N}}j*`IT7LQ#_QxptSIlnitfLi+C~}$8vYFJ24zl zY1;8}r?SV!z8+(mUU*Sifhj|#J$hS$lvy`uo>44oaL}LonJ+s(nO*0|mfUKyK<bT@ zx5sj9TB%o29_VO^LtB^iX-Bf@nf*GJJ}Ddf^JxdmbC5gXVp|+FI(j2s%$ihY^|5UZ zeh!{b8yr087g6T1ug4XtG8>oQ4Y8KZ{dh8Eq-fY!I*(=b^htj`>s`jc@r<`8oswhc zX(|{~s+MVfe&?J583o`j+&sXM#AR|;-tYY07wYxNGo#Y*urv7nmj};ZsVIw#vQ<tu zW~SefzfDO1K5^s0@r!d4mzHZN8%U8)KGSQ|dpbAvjIH#O_4@C9;Y*yGOH49GdK9Xx z#&bab#AAB?;t@WGWy}}0SZ1;{BgHN$GRqe142q@ebh^StY4LnoW;#5vC}!XzUEa#q zQJPm2i=|f=pA=ffD=9cg+ZpdZgnLrVltF<YRNAAUPx@;%&(np!ypU%wBEvC3nR1y< zgp?rZ=%?2{a49Lq4pv%P3Q*EE#2}_z7dKN5%-~CkjgH{Y@jR*-i>CaRa&@poLCoV( z&i)o3(jV~GJwV(qzGG*X^Hs5B?ZXtlb6;nc*e4}*x!!C>WCH|%#<4YTp|z>Z!&!CN z0Hv(u?*?OMGcg9YTtfMdJ$$S&<C$Sx&`3<281a-EezO>qB&a4@8$;t4Sv+6*dXT+b zeiV{E6Yq|09<8luE#<bQ<D1Rp=u3JLeR)XjsdyPnkaDFDkw~Ze6QIy7ixEp*b_G7& z8qZ5R6$&tsar3}7OnR4ZzxKw>o40H4EI#$5R#6cwQLFZU^7{xVDxShTA9Lqay7LYT zQU1y+b^e0sFE0(Azl3Nvbbpo~B+0#d55D$|Z=*^v5CHmY?wkYqvn2lqrfi>S>5?A{ ze7XRqOJf-Yo&;P1nq;efwlv1C=>is*G71?BFUCrWY$5coDbfl+nJxJNn=%-YvO^iM zrR^^>PTH94$#UbP*BQmq`~Fk<Zq}rfP$|&yPNjW}p-)HZq|T-^$*#*yin_AW(xyfq z18!ze%-@Yy#&TwcoU-1<ueQ<@KlU&j>7yS3?tJyf_?>Iydbii>bh?L!-9rQMen641 z9ZAzHOFBN0>59k}bNDYGVuTUiQDu&PGQLfRAX=ODF({V)n&H>-c%=iK&YhU8WirOx zPv4E3*%Z+0)*$GS@ojlrd~HlSo^fn>nxuEi@*#iziTuU0nfUNFlsWtn+x)i0zE2+r zMoRhfecG1~TC)*E0D2N8E-Wl!o+shsnNdLA^B=lC_`Vm5(_tqk>$7vsvxdu$)g9dW zIbmvP&hl4QWu&hTal26>;KwTGaUW(`_?_STgZcS+27*uKb#o5rAD5oz&leO3NRh6@ zejRrlOgswCOCi))p`W6(C@`x!1zuy}h(C})1P2Z2^8q9L$rPP<=c5GwnxU%{9hO)0 zC^KzsiW1V^MRh^RXlfbKWi*Vor7Qq^K!d-VK9lw<qe=QT?Q%MxX#>h#4mL<>7^Kc< zm}0wVVMg|`_$(c`c%a<)qIpO8-H$v^q87bnZ-S(=QRD1!z%_1?olY;9(;c$CE`V~k z-{Y#??ttbeFkIQ0t{p&sl{9A@L{jAk@Or&A0a$Mz_IPEA{Aawv8fmVmd#yG=->J>7 z;QPZ)PjyV_m6Sv=veAHacBHgT`6{~~d>ii`BSpgJF*SlLX>~!6l>XVEA90}l5Yw<c zWa*v2+b2!Kl(EmR-!Bv(j50F+7<cRQerfy%ww=sD0%6^Cn+g1dFMjn*!(scq{!e~p z*fbX#s>VEjcIkAUY)qBEvL;V@<*)23f90hGD0KE-H<R@*e)+2`Nx0lF98{U2k@Jc4 zWTSch*7$@N*^*y|vniwtIFdrofV2K&hI-SbJ$*giO7X7Oo`Hrkp3WNSuXy49H${yx z@F~hEBc2S-#*`}~nCwX}KMIUyq<AiXR~cYsurJ!5k>VsEm69vykhLeHK+q}`D`|hz z5zLwqC8zyOdzaRgmR}~3ldUM<e%6gqCUqM@_c^HmxDmRtsbdjOyw&-cJHTjwI?ovF z?(i2V4|eB2tm(MKaKSTF01DwJo+P(gfRc%t?C#y3oC>DuliUZ*^Ac^LSPDe`cDh}P z+S_lrafPCJW$&OpGd<<i@fZ*AeAwnGf)4OZLG3~V^<EVW^AK8P<jS}@<=&WyPMP@Y zQ^3oKziF}Q1Wad8%$?%mD5GVxcf4|CjkGaLj*HIN`>2TXtM>^7$|HC_rtgcPWBww$ zFbQ|NoqPA!Z{EChMrxQ<G`P6X|KX1#kVP9RI?Zs{C)$@AJ4T+ra@O)!HYO{de3ngF z*?!K{NDnpc+`V`6_FZH#fF1|7bY(mT^zVz=^j>Ua0JRi!W~eKE3ZPJis_B{?03yTF zfm-~23N=!A@encv;5Z5Lj>WhqVVyEa^(IC0%B{+fQ2JyvJH^mmLe_u`?4E>ugFex! zC@n*2S&dn<Q&PuI$3bw>_A*t|ww22{X%xy}vE0J3q?UWi080shNdxVGRw}~IxW2GF z;Jw0MN6#a-Y3_rW;iQCPh0!TMu-@Ebc%IS_(p<C;yA%S>*1(MfwjT@%MwJ-nXpzCN zUaM1Utvb;<>;l}U>NT}OpkF3=dw8NbJw?*Qsj0$F+3U&-PmvhxXByM=17}R@b){ht zA3cT50op%J$~KNGKR^>W7R8a0D4k#Fpl2hSF>pMY;qsWa>3GGv!M6{YTw|wdHu_~% zA?30191QK^Ve|bgMP@L-6IU|wCK^}3Xve-_&PVXd6#?JoF;l~=HXe<?4{iTLJO@T4 zMUju?W^lGH2~RvG<6lha`nHVs&L7C;RQferTg%POmYCBe1UMCsZCq|RPwFdQ`zCh! zY!;tZb@T#%!$115;pJtyr}K4gZe~g+OTFj#h8E3CSD(66_xzO~z1~}Bkdyvx2kM=Y zic$FTSHCekJIh7pMt=_I-zjlFu<vKWD@C6H;CwL-2G7uj{}jKvfCwO%e)anyLHw<# z(SP#7QyiHAnyiHM*YvGuRWv@zkJdhX%0~Coh6SHw1j&$AK&VWVhp;Zgsd5RasLh5c zqq)~IwqMz(1vO$2Pg;A@Ve-OH;(-{g7~hl`MlLW#J@P@XZ~%DWl!8YKuY+{m9fcRU zkSSe3sKa)*C%itW2v{2;w_J{b^#-2h5YuX73I}zA;KLhUDgmF#S`Ayh!*|~0A8h1Q z&3`!6IKe25UkeL;wF(^PaRK)l-ZI0+)D-Qd&3sjqs{J=TDVx1H+f1?scwaE#)6Qn2 zanNqN6Hc=+Ey_$xko1N^X$BDA+scLBHK(A$nLk<QV#;vg5r^)SpU%5%?!=5sd8RxK z)44EmgI7sujVbF!KA&K)C^KzO#!J~04z|fyC~NAdih_?-e&wj+#jj3>5u8nL#`JNd z8x1Z9m0R1?d(-0z%4W}x=&iR;Lb>*nTP32xqk1X25FjIhrZe&Ag=BL^1PNJs9QTZ- zwux4IxyUu7Z^sZ)CIqtC7lg5vyGSp#P`oQyPcjL4ObXc<0HM+(%E)N*=R1MioNSr2 z%*H5PUov=EOg9ZgQOHS=zC{)GPd@y|zsFQf&s8YD5^avj`0!$%;8(8#_{e9v(fG>O zzd1^p^#p~zO{eK>qu&2hpB-(oR;!DP^QT_TX%)y2K7Fai@lpW#rP<*}u4A7eDbLyF zuVgVnr>aj*x{8&u$2p)st&#n}mE+RQ7u`&h#EKjD)1^9=z|n$rgyS=jnu)4nol9_k zT2w6mWypJ65Fg?G^nST9Y2(L2jj;=DN{VcajMkn6gHjP6*Jb!pUUf2(IvIl_Q_7SV zT3fXA2@1r>#^8GQg9!2Uq>6lPJZT`j4Mj@~i)8qZ7Z1AyOb5sceOKfv!?OTf-rfg{ zcX|h{L+Ze<9n=n9o|@#O53jW109qFDYPB&90+vTRbz*2IL=|^Tyj-UE0H!NSc<d`T zZ-TiAzyd>qt+BhyuVy%;F6zYrhIaA}3IN5SJosDugnd59NR8Cg>2<;Pu573w=4t|p zaYuQn3WD-A3N$w!(D?xCzPxepz^T{xm7iqnuhr<RXUm~Uu9ie7?LoW4eU=al#ya}M zOo_YYNt!Zz3`fRn{xxMqyN1X`T^WZ*y}@$vdRj=zkWROtUN!}S70bO#dES~K)0j$T zIW=X5zeikcPa6<-RmTV;#zJwENlo+tq1wszy5m}by&p=E+E$p&^|qe#18)j+9+PN< z_LGCO5?N8S%G;1}emW=~Iqj55MNLc`xX$<Y9UeQaieD3~=)D_FIyse%h#6W*{AzR% zqmC|;(Jzp9YIZR)d!<%{&ub%fakHo@24X}j(<el8@lwd1qLJxfzgyQv%>49F>($ZB z(wEUpPt_qOnumLfi!7Esn@Yj1K1{X?SPW8JWK15+KXw+x!~SbJ9Uelnv2{HPjosfy zPTT##tFOL}0DY9V9`_lV*Xi^>{rvDl*AZ(X==Ai|%uM4H&GRX_9=Cbr=b3+tv&vt| z62*TXf4VzaW8$8zCp|01>u<ct!pA-dgTl~6!_EQyJ0H^zXbFW7Pr=#9!jX!qvIOxL zQyG*!6Dw1B?v2)iV+bG>oyC$+GE-%;GQN6CV&N=5mOfB!XDsJq1!XiWy9m;y-5J}$ zbS+O8>}c~zD@Q8s)8UA<A^H`K$wnlGDeaoBi?JKOVjUSB?JCUJw%}C&xa4Z25P6b} zK7bN%Gr&Dvx4_gCfL!Eazja7i_@WEbPgGm&Ltr<NbyHK5Ao7_R8OK5DJ#7l}2h+PH z^Rjgn;DA57yTucG%JWpq1C#^ma6k-z<}L2yn}azY!##$7C7`Kd;|FJBfKiAl4lq1J zW8~e=iHYV6gBwg6$M<1Hfv|?rDHDMU$fl=mo8LP)bf^Q$r$DUuJNpMT8gS2Jc*gS> zG@)%^dfL-EB%P&n5+4z&m}j3Gy#xwa3uzLjdW!O3LY|~~6zfp|K3?wOs!oo)jKYwU z(m9>QJ|HP;rTiIeU{w@P`YY*A{xzGqDeGpn#MgMyN;|?jF{5LWrt{tT%A4Kq+g1!( z(1g%Np3<i>>~&iGjs_*2@4Oy&0O>p=ji7r7@b9(v`g~2vGU^x%!*=&5(@{YL=ei); zXe?a39JO;qGgpm9kbP8()4^z16q{1O2Q+AI&6&VW%p2*15cQ-y7BqCtb2L)&5VP0e z+2R2eII7Dvgh;m<W@a9BjW^yBJ6WF`)2k30w<8Il>5rm&q+3`=%wx^KZ;V|kVZ5Yw z^Aqz0N@n7;7`V}xI(^GRyO>Z$#9;oh-H3UCV2B4!dNLVOy_Zs{OdnJA^J9k6$DFC2 zjIg|@;2*?mue-jndH=y0Q|QTxdgxoO3ibcY=Z3absn6o#oXP6<?gvUdH_BgmeRc5M z1syVViW*3{=P>H}`sSVc545JB040Z+oCEszE~C8fS{BmKrB5pO%JS%>U(@9(eI^R` zk~8rXPew&)15(i$<@*Eila~;G<FQoQ7J~curi4F`cKP80mlf!hdP}15QPEh5oOU6W zkkNvDtQXNEZ(;gkwwz=G6c48_7GR<f<pQ;8ww3Gv9ZU(F#Wh4yc`yK@bCa)L7jjPE zcv6^EMrfIq1w_C_`|U%%VsYndi|^(G!&f&~;{d}~M3o?#Ac69=W6Wj&qXf!i8NgfJ z;5ClvRe-NDto3?8U<)k;a8#Nz)6<h?lULAc56tdB1RE{Ze*9U8Qso~7#ag9uypgeG zK-3XU!c0ydW%xJJpimIGwcBa|%H7qcWf%N3)1VGvM!-5K9OO-_cK2J`yZg{<t~oPV z)9)w-bgE7|wwY;uf@0fy2ksrD4FL1!nVFg1J!o0bt&)N8I)&TTfifF#2gOE|Az;@c zbSDbXDA#}6kvPVd>6m6*m-1UW1%j)ycl~~90{6Gl85EooTo(_d5687XKl)p=D7p|W z$r#?MEO^_~ZU8>U!*=Z|!-Dy1Sd*-R&VzzBa{V>uztFrb7pyw(5kB28RdTovrTH zdUeoad}{Sc?T>72ae~Vbxa`6KtE!;0-bHy()}yZcp!iMcEehLyuIReG+ZyKd(O;Hi zb6O~XeyA{9X#2oM-_;W7q{Ym&0!*74i92Z~rVkeysXy$VR&k7%?IOfhfIncr+heLx z7+x(g#YPTej>@fC3mP$`UW~9EAmG1B<Fyx$tn#BihCoZvhP_B`)<ToXd4?U8FbO%Y zyeprC>wJLpiA^5wsoz(ZN7`VD*n%J_(F&3s$IvQDdr7_<a8#XlG+Tpg)NB)GMDX-6 zpWyK+25Y2L6h)bcj>daOp6ug*9uvx|uf54xvG1g)lNvxv5&h3!9(?X)a)PPVh}pUM z*~bddc(UHTlegIMy0BPVnMVREYyKyn!O-JdrcbCoy=`L{Mm%j^dG(Fy=?2SF8W(#G z=--xl=MRjhKnemvCWeeo@3@FeMNeF(_x-U{IEHvVF1DiPqeL_rXvk!A$jZ3L<dF;O zu`LW4nl3*MFQR$zHN78VG`rwyMy}C<eI(FRQe@QkDq_7%ON(;KuatY2b|(hMNnpmF zB6XviuKm;L<H;=(yZ`Fh)(K$ZbvGvie*v@D$_?W5Ex1$Qo4NqIg3^E#dy>EAAYS7y zK%07b3$zV%rUW1?ukaO8u_6J(dCUyn>LM0v;5dc5XZh~FlnBhFYNFZB<-Ss{?H?Sn zAISpTn3`k(RmMrV+{go-a=>P+765Ll<Bvg?2`=1!9i0M(;4RQId%oai!d3Yz|4924 z9EY;doSrr-zMOWnWl){K^bQ0EZ_my&7UySK0?`vFx;Zn|oM{j&E9@?#`;?`@sk5|W zzo$nndfuf>DH5P|6bw3|dWnlYR8D%0i<0n=eg~~X5ws33sCsAbz{3OF(l0x`fiZ3x zoDyNu;m+72orBI!F&(m>;#a>&XIVC(;%mmq$twjYjQJI_$?oJ5BW+U5GJh}-v&N!N z3<IhifzbxK4|ck{>$T~oLrxvIH8sti4rcg47fZZuDvdPId7_RQSD#;;s80<J+fowH z>*kkhjTx>4quE{Q_juB+h&<bDHehG@UkwL3Q2=$q=jLdF2f2(0M-DdDYE)L2A;2}j z3pyO(bZlOAjmNbv`zv;^0heqg6?7>q<<dqf{T`aIP<Toc2aTvJfwPTOeAj~FG%IcN zRIXjCHZ~*-f}p+hq-qr7tBg?o%!tnB<Rc=$s@mxqF@n#(qrcYNf)$-;qfD;_13EL< z$O^g2_W$I7Gh^z<_!^QN^Rsux8%C3SlLujwdE-c@Iu89u+MM(r`Ei*-AkVx}Lo^-( zX@F?s3<f2bkSplyZQuqwi~{?%X=y<_8X&7HnZj0eArtIH_s&wYO?&ifzwnZ|FbjU} zQ}l>r;#CKZjhV*lZ{AGZkRGvwM|q55iD>%#Cx?q*cvB$f=9+fa-f1G^5KWKLq(^*) zHa>F&?@f8qzi_30c>$A=ygVQA^(T64_~y-9tWC0?C5dj%0sRvZ^ZX^FfUnjeJ6v%1 zeWy?e7yl{lhs24;{33*Dtl!xKQFzFy7>ba~>5TPCqmikwi<0BTXkOG3ucz&gj%00! zdea7^6v+CL_R$-eu~oUitmL#`fq~3qp5v{k+MTV#`=aO<3$Fn|Ao9`LU^!kK1oIP5 zB5kQr$ko=lQTJt@1kdoIoJQ(3FfpsVd8~-|ayzkvk0=A)429;~SxaDatl->Nw5XiX zac+_Sx`TDDEXl4tR<F6o3m<cssLsz~zn)fIGENH(3FF$YmMOA6N1W-@lv-hDIjJRb zyrGY(j<41VEv|&cVr``gIt#9*bXw&*;;uPpmw*!W7kn>}4PDScFxyipz+KKT9Bo*u zdXvyGXs2bX6i3U?Q9Bq_Qof-WxMIVTKAN<UD$p*L$hB-Cv-~}1wH4H>Q>6x&@G<y! zPys{0;F&*?-trh<3)qzhP8e0)3*Yb){utWsh#||SVK#kyShHE2J>$QQovP(o>5s)H zDJqu|vJ#J6Kho(IO^U)Z;Sjb`pc1&Mci5U-T%v*X=KRD|V_3sCYZ^me)sCs>cVL=8 zd~FgCugpcZ^#P8b0K20MK(+dmr75kW3lg}X7zkrKZ=ZEv8ATbyX;xH=X|`meY`KWr z!*f0rBa~OTn+xf6D}$}da1X9D>@FCsy`Kq`G~zw>s+D~sl+&39fZ)Id*nDp|*l`-7 zT4;3HbEs%q*_g2Dq!)QcZw))c{<>=d1Ky%Wmkbm#JQxmiN-<CBr-}@&=r8J+g?kK# zyUY)-ovCb00fV)yB@W?rpQNnJ7`x8{sLCUk4`EtLKskXwnHiew=Fn1%RVvw>p0QsM z9P+MR1h@P7%5JT2OFa2!`HQY*8yAk!T}l_A*-7C7S9;aN1Y`oo7lwS4|Gu<w|Eq^2 zkC>a3$#6?o6Hfx}jWRNJSk>m#C(hJnqrE4lv8VY%mArx!_6hGioJ~^Wy@D-b;+P`w zBq)=PBZ>izaOtf(_lg;Dx+7$=Ze@1xW1nV0u?aUZfxpe^R&qwAAy2NY*5+mywaUzt zJn22b+8I?R;?!z4Z{23HGAQnK<8_?_`m>|?cX`PfR81jiEcs4?v7G%7{2GKy%ZW80 zC2P9I+nRAqortQ_^&=aVtO~xS9ZCC`HaO5sxp!$hvo^<DQIucA*P=1Dl6y<ksZooM z?i?YiBlzWh8Ul6(#6f#nNaPLP!@O<cSpMa#L|jlh(i1-r9JmoZ!jWp6`?F|CcYshV z+MJ(Zx*I?iFpp(g?k>Xtc4ew?ur6zsfq3&IaT+RHi?3L;f+}c(pOl232}%M`*pfU7 zh3&W7;C0I6Nm?a$7jv^A^oo{IEl}7!DP3}*0~E)s;!D$*2DsB5KdY4*f!gYiB2!5? zAo3~9wKlP{*J3fnIxg#?dFKn(A7XyPT2I;;h0H=AKL<*dS4%-dJ8}L2VT+c10&qJx zUf|(FgCU6ZLg_E5bmu@QoP~CFwlOl5O@P#SOsYj~Viq$$p}P|k8=G4Uh>oDDPRuqN zxC6~J8XgJ2eglKDxG;yYe|>X%eRB(cB+H;9q(z0z=8RVNB6W`tq&qUPkAZMUmmp22 zg~=A0Hl$+^EVj5Xpa#o1tEXI=eodL&c`!II=5@-t{(Q_JFFZcw$(YSVaY_L}3|J;Q zL)1P-q>g;(i<Y1b)hA&mz8+|6V>mgpz%?|q;p5CN2EBTK+6F`7b8HwBi>M*l8vob) z!Gpz!H36odsIgw|?(N&YlP{Mdm|=Tqs+0rYa*OOkwq2v2-12(73*4}%1_5|#pCwwG zn#gwtx?|gE=+L=;7j?2yMd9473~|H)7Idpz^IC7SI^5<hdS)e?CNSKr47Ll4DW-Jb zwT|Fz3<q1)+H|!xuesdc#CxkUF*6)&1K+E)nM!|`x`u=GiCVJ?Mz4^hW34jSF#bTr zr6Zi^BTC?}#I#^0Rd{j2l?SP&bODyPHcYB0aS<o%^oISlVgD{aQL-adI}+H$*vLIE zlZr(st%)6#<KsSNq|fRWm5xBX`_n}ficW(-1I&Xil1(AwI)xIL?kr9a4P^?4s*Eer zK(RoRHS{zDU8fGM*lEMOZt+D9-20}D%cNpyuUui$SKB{<#axj<1|UL<xnUZGGTuts zYrDsHOl-Qj$;Ng(Mw-cJUXR{>Oj`0fvc(dr3~%4Q<IZ5G`;jQ_41VClgJ&+G0&2Zs z2Mlo;>iX$cce<s)1?c`aF4`eegUZKlkiYV5Lu290yZ0VolCqNl<m2iB@Ep*e?#O<y zN=sMk3>Ktou>TZmf3`fwi|GRa3r>>lC!vsHy|p^Lz<4qwb)c5CkhGDp7<(a6P6}3H zq@&ol<K<`lJ!(&Z*9#k`FCqRZT5EX0J-@Zmj8->+b>-;QVRSqUJR!S_WVe#9%d~6` zE%Mm_SXk~9*~qa;<GTVb0BVDVWdouf+rR}h%g4hO5_?OBBFS_#(jvST?~4cSvuc^9 zpjE>yLws7r=}Rt508cvqNTH%;OXhj>0F2pQ7XX^KK(RbZ!$8Es-b0zJ_=|fC4krt9 zO(k<Qo4Rm0Zaqc~OEW*jIi7!c9fT$q0!&%;2@LjhUwLVOVKt26huZR1E(x}AmD&=> zOQmMB7ZQ>lVx5)osoy7D)gUit6UzO@lpi(TGT7i`-`2X_7kZ{ixV8IeL0+$jyK^(s z(x|-BejgVa3NaWjGn);m&L8n$+1c49Kwkm7#NZxw`H}4cdbGK{4MF5`Lnj%y>8T4V zOWHahJq}1+R$;tLHCR&EYy;gWBWEXbz19GsGWfYvwyxtp(%}kzuqux2k~zm_(<BvP z=}#FyI|fR5KBPe~b2|ItI-5=DJUUW1M)S_gjM+41u8nZNPgC{0J_!)uNyu*5vNeL3 z(qW9<?QNlS4J(de9VvAQGy$*d?eAM$axph;D9z1D)_1)KD8nK~O<cDQ(GnE<;jj-T z(Im3HE1%1QUKht6Z-2LqCA)7p)kdZ|#TEj-`*`y7+UtYP`k?jZu-~fImKi{_gJHkR z1F~v&JBM4F@?EJfRp7gc>B>NL^!7J;d-ut4S^=!Pk$z%k(3={x_bI$uokbm1IYYL& zv}?t+HV~?_YDIOibGTofm>V2!3l9#4IIi*4^oLdj`@OIzSl_~954MJ#gKBMYNP?)H z&F;ar@eC7-C+R+HJSBG$fJ`6g57e7yvyWoY6KIkqiKZ?slqeha4&@7E^LN;Xsu&?U z>=c+XXBxx_2B4JLPW{^EQDIW`u}i*ca6y>5?P+k#r^Z;(5*E4A#aHQvJ^G9hfNr*T z)(;PM(NT1i+`%?uIW^g!j0wfhBkL6L(m&is1yqE;1#%4gl8v3cO*p55GgaYpWgOGq zsdNstX(@*6p=fq@)+X4P>>iRL%huOoSHT-5K``0@NTygi!yc82CevVhS%R?_Y;A4Z zM#AZS#At*p{VzUyRICn@Is?s4Lv{wmB7AOKs!!Erq$hvn%U5MTI3wRAm!;d=J3G7k zFoUuooLlHmmmfcXrTMa5UcCKI;NY>iHUkPSL;Y{S0w-y_?iUaF>y>&T>8IS1th%(8 zc->2jR;7)}x*U~8MNxjVR^ZZ-=*jW15GX}RsF&=Pb^kCq3AI$5<)IwMx#Q8ImdAw@ zit@6xhT*@igGDiF0a$^3yoEQpp*q!JL3`TE<$pXT$ZPKG>Y5HVniRanqrl*cIj)TH zVU=l^BUF2eaFu7L=?t<;8)QV1U{J^AtdppfvqgKQl!`qYWXw&=5y`JuUwR<X$(q7v z&FNjHZU^hwr`=mdfv0B6SFZQMw?U{KJnx{NjRyZ!ojquqtBIfh=*k^|%;F^!Px+K) zUhh~OW!$$d?+VHW_ggKYXV**Q$s_xd>~OqK3pRFkS+Q-i8)2!H9Ty%zvgsb`9X>GD zQ|U9boF4Jq&dxsCi0x5`RJ_hEJM97X?H#ljK}^JMLIY=+^<S<v(j17&?R4Zu-#%Pj zUgX>;3nP}{cwx2)<tdg?Ae5HpxA*q31oNw$f2=z9<*=-pL=F%Spj7wt6e>|Kg=6fe z6WcquKolE3<vAO(EZE*zF{WgBB4l&__yb21r#y+$85%7aHK6ck@Y2$Gs%y7~j_wyN zw10R#%%~6=erO*8ult<6;y)Q15A7%xKqu3o2a=qs;c}zna{N?zc4?Y3Ge!YZUabwh z%OqJ^T!7j-y9{@ExzVdF41~R?S;M=yWLa|3Vixc3Y_TbZ-wuWJ4iEShc53bI^g9PU z5B}GtR&8>kHjO>LGBGtVb@5>1UgxlId^a2n1ZS$&rk8H;wY_l{TkfE@U9B~wZ8jHc zjiu@YdqJiE42N6y?o3S1fxL_$07R1XY^w`(z`Y=NwK@m7#7l<~$jjPV-<+6Q5>lrH z^Vg(fAe~HGsPsF-j=XoOJY1h0boK_F4YAqmg?eKNSMWg>FP&+C9w5HoJyfxnqHFV& ziG^xywu{ja!3Eau9aO=o3|ehc@E!O4`m|^(7~Dno7<3M$^QfO-<{0)d){v2OJd=NY zpi|CtS9X_{a)L8n!0O=BqTAl@>~C?WbFd4MTRYpW-7Sqi4ow&bcGvm``?aZ=$!XXL z-=`r?UxRLce{*AR{a&xNtHX!b-%;2?d-L||-PXSLdWhzqYV2>^ZS5m}hV{v5bW2xs zRQL2OJDb)*QLoo&SErgCls9yPK_458nKnG=!aV)-l%~o<7UD-IrMuiv`R?vMmW7m1 zk6y?_o}`i3e?ER=_{nFhI2H00+x+b8%=^MT@BL!&T$rt1S&=&*4F0KSyOW$!c;usX zDs(z3gdxC!u(P`-FE18}k$L6ZLVwDH{y-HM;5%k`25JlVI11D8rS~K}5sPRn<WX!2 zEL`e4odZ?4<Vu^7{+d4QZAe?5il;y}DG(Vo_^9Ran3tU5A^+;&+uLC4m&_+}@Ex6t z#7|&H1#6l&Ia3l4%*76dbaF46C~&7tLLRZ|2z&OivbQM&REkumC;%%JZSS%L&%=02 z%Ra4y!FC9d8R_LlLviGLksaEs`*OuSXrn5CGI^3`fT!}k>Gx?8FA98GmH|1<OWEiH zSNICzWXU&wo1tZ&R8IlKhVKO}=`P5I%JB>VnzIUmX#lb`WO2SZM^tF7HrvFYsI=?K z{h~@0uIk1){L2AJyoiZf^kF}-)1hoYs$28{yF2^)^xA?@mCjO7*HjTcw3f|h9}67l zW$UsGhO&ZpWTdC36s6{Z!Vf#-rIEvgIZHrqzS0d^J~uOC2_pL_9<psygyoB*G4f*S z&?6brK+m?=v#T&g#dyL%88Ecvl<eZwNZS~GqGQom=-EN5<(6{RDyT*8sD*yfV5R0f zI7DHXl;SV}6<`LM`sy2RwOR+1_WGN|KMASR78-yL6}>P~4u0#)b7?Sa;NT=e6cR|5 ze(g5ML7YnGX6Gzg^awGh^Cg`)G1tmiJbR`5z{4kC$i{5?Bm%+bb)ncNGu@h9O!~r< z8>Pi#42nRf_I6+oI1z#h1G#Xh^HoWX@MbZCy*YUBmuI{v;eOAPW9Tj<mET9?*cMiC zG#F(nV8kM!`CzNx+1XJ-XzdBf{Om4U=0?)*!dvZw{he*pN%Ogxo~S9c_U4_NO10U+ z&AkDpA6BQ@2XdzYKFRWJpU%PFowx4v0KSz81vqy%_V2#l+CNykbqjDj=;DY^kEEa? zLlh8VxqZyngRP3@-8bIczWZkPV9iYF0K{s02Nxa8xsy}#^SnNsAfHbkNJ>IaVL`VC z=w`3GzpZOx52O;*hZx|8wa)&Y5bERtx&(?rr8dQj;7bWP+;WBoB>Ftu$Jc+@X&)de zDz%1~u!n_W@^Eiw=g#Y}EC8PtDmy5xtr4ZbOmTOYd?Pm<<uke-tsO=2;X@xT^?JZm z4z^Q7=WeI95826wq)k!w?U;j8jV6kXdnu|%^*Rr=w(etepPZboGI$EXnX1psPBv!I z{NzDjn<T=$xv*sUk-F>~u@f>gzk*~?c&;fJvQTtd=m0z{C$ar4_DMkM5V<x5VU1PA z(gg?mTo4`I=rbZ&OzJ0~A>0B@Xd-fkoRzfg2?}}WE0W&S@ROez#(}Vy=RFbdseg<* zXY!%gXRj!73M2is<-t=cmcQ~;BYM+zvj{$Tu#Q0Ufb4>A&!lJPg?<1ikfGR<dYpm) z7dQM3JRNt^*S%zaCNBKNSf0Juc))+kij5MY@N%2eTBtIxMFKL+x|JLiVbaIJx>7EB z)t;h}dF9r01DYzsa*w!(l|Mk*O>iD>c~PER9E3XCn9_B<#soziV4bCO_o0|0sfseM z<J8;RJ|K~~Zqpb*3QGXBs7hg0;YIH3?JH!HmSEST7Og;-*iFcTLHSR~ALU(-PmZjQ zJOS>fQrX}ql?&1mDTqS!K<E&3Vy>THN=5Nw=2wD9=_H;4Sw25@{*mQs1U`|z#=hFF zpaR0o&t4g0NZw*jBj*0D$WC+>L1$1n=Vi1z<cjfr`96bZvss!a?ZFJ>H!C&DgGvNv zV}3Rpg%lMUMwdN<B)A&ggeoXkqb4V4+3ROqLm*3<at;n@DzF>+(^q+7n6r%^0gGGw z=I)-3Q<39>(2k-IP=Ro&IV8&^Mt4CsH?+e(mKA3b=TB6(-Ms^Kty0<8+L3pY+90(} z3$}JhEwksyTZz87pAW&Zc<Z1-P{``a%J%La)WS-<vDe<Do3;mH=KntGka<s<HiPE^ zyD^GvE{?dOo$@Gh2VArxDCy}4O~cgmF<y)r;S(X|R5sDFCu2=aXIvDO0EvR%lb>`a zTT-)M{herue;fVf!v8z=u_;;jhAGxi$A0;&J2G23<`G4N#T7WsSArtU*URNhL6F#) z^Ob*88SmL%&j=4FksnabP8mZFY&4{EnmQoQ9MBJly5Gfs-C_6$mY!<Npj0S!d0@wl zF~-vZyR{k2<dZn0G*_;GtwHb@@GE$+Ta4-S+|ugh%Um$OWy>evQilg)<d-9d`LBbs zv5~WF#l1s7ymzC!b@PBMoWsuS(sE_ck}nMfB2^ByWG?^_PEJ*NxYInCn4F%RZU`4z zavxmbu<uVa7V8a#B+8sWy)-eoJTbi_g{DbfaB;E-V@3q^VxoTV;H@q#ucAmyVqE3P z`qVTVXT@j=5BDgrxpLW3#ggy8Ju%(v$@2&Ip)Jb?T6{Fc&I)v8j8l9yPLaXo=x1}n z0c2yQ0Kzhf><BSGkE}m|KTJ>BJ_(eh)uCO(PO|8m7N=O{>6!T@s0zKsHgvet5{t~v z>o6^weS>a$vN_*aSkccdsX*}X;qJ!L$|c?=xZ8cS2-l{TL3@{<YmGUq{x~TOI#_>( z@P=XjVsAlv0i#cJBwf+QcmD0}+T_v))%X6|T5>Si+r9Z{ze`K)_OCAWfAFI+&)X!e z&CkQev1$Ei1%0QVO7mADR6hM&$I~61QAgPETi@JdsR}eN(*4v={nU4w4(Ij1Unvm6 zBA~!A9GrA31a$c#6+OPR`!iltxxn}}MdxLtK3Yf&cbnU|iW-$06&<T%6bh+hdQ7wc z(_}%nhj6SgA6ZFHM4arSEN13K&Xd@-<u^jc5_8v%t@o5f6s5yH4IkU;fYnfTDGaXi z%{6Bc{;I8lR%B5mlu8RHV3&7gxi{N0?ZGI<ui#hky^=*vD$}_dtd<KG;uazphjkoi zZtgm?p2=^=pekXDb_X!)D$Z4a#;~|Her3^@F{bF34q;`fQxql+GxE6)Cwnfj(*tTv zH!z%JVOv%*9iloJ>?xD(Kt1g16pGm!1H6pimbL?}25hx^a6nea-TgL5MOJz<a(mlA z4SL-a9^VR(t#m@rSq}Qz^caAB>EqV+F2;K;!RD<*xxg$^CKJ&}2}<CulUB7j`Gtl+ z4zcngR)JHKlm;p2lwevPnpEY@j}Z>A#r6Utj-q18cA%B#y)ox?z0NgQ9MUs<wg;dy zXt#ED@7;T_vA)5u?zD)l+*4F*qv4rzc#~f6I<$p=Runph+<a!6(~KiNQ5c%p;@Cbo zoSRYhOu7u0fEC-_0S9W`-(i!XLMqIqdF6Lw2+XGon=dAOnWDi1isl?vATu2i=NQxa zJn(7j7jY*hVEJbDWIC5K+z>ydvs(mDl4ALFF;7bXF8%dw<)hbL;P@h+df_=EW3&NK zW27PxkYX^*;ojyP#Ak~plCeNT<vy}llY&I%EiJ-C`?)~P<1Y?5E)%rRgKwF+rL|iJ z+?NJ9=!0u<NoQ)YW56{yo+u3Pdhg(le(D`odPJk{SNpq_!(G(DdSiar-<qi5KwKO4 zHz(?I+Ae6XGphCGm5IqE^aUb)QE4Y<7GXmsJpnQkwS__ZUadZjD~>r`02o`7vlkk( z%_*||)KNA-mgo=tdSkZV*_v#C%dsy&2Yh21VCvfR98TS+2l&iX$br*atKhFMOZy%u zot9Mas+S4BGwdBq)bSMJl(hXyhYf+j#57sB+Y^%w%k<x^P0isxBA|(LKmO$y<7FNo zQnoI;vLp?1reEnE)@K%Kc$UlcsP5e0jv{Y6;-~%qmAWK%{Awxom5tQb4(7T6b!8^i z*2fGToZ$k24N0bE=5Tq(7+;wrFE~uVmL^hKoQLC$y2DG8+RC7C7{Rl|SawTAY1byF z*)P#>DD_Qka;9lsb5*6zEe_wnr|FQv#T=q`^2!vX=DM(9OM;D?N>0g>7RN`VA+O`z zvBjATz1~;8_U+&QgD<->d|Drsf7tui{!sr%KZ*TIt;IaQxHNwzcpfRi*6Z%>X*E78 z$JWovopmDJD~rwHH*VJsl$`mPH`i%Z%`)+!mtXqmhhH@PXMSd8rdYF2tAg`#K4=uk zAhoae{)u%uq;uT#pE4=qkEH@AiV9#64+JvM0+77u(#!w&>mwHg%L#x>i4OI&6v`v3 zLkyWiUM>I1eXjF3wTEorPqt43f&zS_RE898Cq))VASt7Z_9X|z=2I6o=CG9pDGaMg z696)jeVhu-AT19Q49}QpNPq}l$68D|?XLNCScslG>HzO%aZFeAyl^SyP$~Bj7l2@$ zsYJvi&Z|l;CWs-waN$n5-hlhTk&1A`(_IE{{9@#OW4^^I-`snYVb1LS6MG!8WS~>} z22ROTK^_>zkE#T!2mZ>|K0^b@q2|G$c<glcbx2d!vp0gO%`3e_;Xa7`U;2XuYihe; zQU-qf!WZUd5qtC<EG^vJ@00a~2t}?54B(adCc%H&$55h1LuTt68^Bi3JJh2kpk9hY zJ#hQFY~+?n5X+e*E3vGXT4CA!7J%j>e+&b(z%H6({x*<ta&Zpt%^6Ji=o5GuvB|+B zBx}2M=k8lKZ*FXCYGYtRaSPIs3jb{BPO{fpULEstVc=@ZiwoDTU4G%YXJ%&SCY8~= zuHXSXD;FqldZW}uuAR4G5Yk!-Yq}=~Ue7Z#bF+<W7nYjSjs4Exa8TX1lL0sPJM0wT zMY1s4xUf7=fj952fe@tN5pp2U9H6`UOOJeF0sye+%RXN+8Kv_sMeRou?Km<Bv>iA; z=214ygZZPV^xgE=cOpEkQUNcqmf<AVy}d5?M6#w@9uhkTsyIy+7d6dF<^q~D=G8%` z-%^^wu**w`fac{+W@F^U)9CnyoA-Brf1fF(B$iXs_oioNh>yeYUB`=>2hC%LkH%D) zF&7j;F}(tR)ldh(awLva1nKJJ40s*5wraU$sCKc^zsDX=jT}ggUS$Gq*}`?6pLnub zxu*v8?y*@_8Qg8)rBL4xF2ooQ^EEHj>JRFZ1kO^<G^LYD66jp3cd?XLD`czWAvS-m zXk%{*t$;9Gln5om!7&Hz+!8GAOw{pxXM2t6xFFXJ$}2QPA_3VO6O%aQ;~><l&*9TQ zU#XBkN2w|&hWDx!Obq*6Ln0-AnrgzZ#Hc$V@zt4V%;WGRElV&+Mr&I+j+T#i!V-`5 zF8t6s*ylgxo|61TkSZ))<7=beZY%YcoV|?Gl;pHdShD~-j!iOz;8!y>Cog*jdkU<N zYZkd}W{6?h$43tZ5)A?6++4B_5EX0<!7I~Xccb$}9q%OmVvJ{urFTmE(T=Ft6~O^* zE%l8SAY7|ZFzh$WBrJo1H_W8jku5BneZD3>7G?Zlw*k{2`3;`3w#CHj&rbJ${Cni7 zVpFWTNFw?(`<$t|sQi^HEMy9eot>_H;>H=~ucRY;d-9?8(eaTz6ECGR8;kRT-&+(I zJ2$eM1(Hil?>=c$pdT2*f3m+tPyI>%X8#uQh<|*Q=042qNk6y=j+P^YdB@rsT$m`_ z&Du@K+Do<M<vg!UgtDvI*>0ZU8)I#~PSO$~Jd3py!~}p&$(4dOSc*V-ien>JCJh{# zfl;!-DWi+BJ>U*LExhY(!;wa(kXo=BCRT?8+FiALg2JN)VOa=vcJ|yi2B?V18)p)H zvhkq@;!_vx-_a3$dL0Rl+1}L>p5NHki&UvBF+hr81%C{4j>qXl`3k|201jxPqbTGb zBFcf(aS(DkC{IqCEkeRcyCn4k%+h+#vyQV3KUr{>h>z_ba7=e__m}XUZ<@D`PGz$E zArpjh0>J^(P|RF&ln#>W%;Q*4n}UeYg%o~}D%Z;WLgsaa&&qQhvZ4&k%rrK)_n^bh zE(a$GpHYP%8j43BE6#!++~KYj8l9OLrF^MWH@9}c`ViI}=4&fU^Nbf+Ao<_D`)i(@ zo=zL4*EvBJYM@91I0!mG8jp5R%1@;dIz&IYa%r{EoV$Mg+Wh=1wJ_R%HzPjan~eev zfs$1ojlwbu^$8uLJ1~+|5%n4uBi8WgcE7T=xx3Tu@n5UcyR)|C*)!#zfpZl8OT9h_ z9$nFQHbDRE!_Z*9EjFjO_uD&%baLY2!VH{yWkCT6Q2plCVPmGrCIBR1Cxq^RQRR8n z>7e;A7VgW0LQ68o&7A{?rt_zK`uJH?qj{Dt`Tjt83j2gjKk?XD2^D2J!j2c?;k42x zz#QIAW-4&dt(z_|Y(Gcf+hL-(Q66Hb%6ih`{Ltz6Rha}CE>h&+<_t^hAM9;yZXFV= z0$|p;yoK+X@a9N5;XvV5G3|6U8gi4fJXAu(vPq+)$rP=91Bou@Qwb#%G9WOfMpmbZ z+U&&S)nV;A8$vXlSIG!D7=X(OIo%x$HY>Fi+;FP(<;vs|UBtV`vfoh1#;}TFKqZ$d z)wxRT;;`17n0#u0)m-j6k}>dewRVm9XX$J3*kS6iy@hu&JULG=HjY}bdw;M=3LOP> z4qM=U^4rh}oZpo_lhilZ@0A6g-y1{%v!PWXj#f!3<y0=^q`smQi=sEty~~ve0+Feh z9R}vY@~{fZ*Vw2K{>mw@2rV6OLGpVEYS|N<H%7vKEFYcWO>rF)zt_W4ke+aqv?bM5 zzwq1hpbKvvcg%;;Jj;vpUpm)-8En6*AQqFZokL8qV1MME!j0M2(8fiTqbPiL5#B@K z=%6@R0S5b)&kO265#*5V*bQ+agpK4XNUIFd6Ptg4#a`zdYnh-i?kwumvGXYOF#}WK zL}U#7gdd-+#a{7gN5sNI%2xTI!HZW5^E^u(lD}|(d%`Av$6jN2a7``pR}PiGvPo`; z#9#LmTLwGs+i;jaQ~~JEU2aa1!XMD0e1-PElIkw?#wDCdg>^jaR7-!dYl$bojp0{i zDr7ANpn&{Fa#dIvKGq4NIyF;eAj;&6Y(C9ah}@L5kel`0mK7x{w1kfUS@X3ZW1yL2 zv{!CECypJh3$o2%73La%r87`FeR)8eRfG~{&z5rqp6DcXke{WevhnB5pWJYUEU9&Q zv`Y=(03)R~_ajL03-|Mq+-eT==P%APU|ilt9=p|<f`IITn93U?3P^px(vJmNS^0)M z!%bc+LMlP(ZPMM~f{*pDiuIabsTYE<IRNNqwQvPP{Waqy6_L7;w^(06@Bl&ZAL|Zn zhB7*w)pRCNMu)s&x7GoxCgs(5`TQKTunn6FjTUS)8%2|v6_XbYtrp254|Rxa7h#0p zmKVF3t7(I>=#ZZc4Md6IWz5F3PADzFT&^ZK!?X_h=FUIDX|}yEVm6JY4wsdizK}7E zgqTYU^DKm9b0^6cng|Q&_Rc=e4;De7tl^ehOrvJ2C*oKEveK_)Ohtu|)m50xg4p)k zJ%&tuB&=4^sL};^O^ThJ?!>$9qvglkvb{h{AUL39fxVY$WmJ5y-#O@uD{k+00Q$`- zZ2{S)i?)Dp!FP8rQOq<<%MPTfc&5oYr<15{^^N_`Tx0U?c59E^`NPUqt9xa!d26SQ zQZ-~dVzPd3`(UZrfGOGhp%095yEm9`PRlY~t?qWTlOX+8e*8o-Xp5kXsGOOdjkCY; zQ+d9}Tu$eB+$>+HaH}8$=tE@4NkZ1mRFvV)5;lv;Nh-PI@qAp!KyFhT4gsc%0_MbJ ziR8ga_>Kem#hwf{yEQ<6O0a#Z!a^T(&>6scdn(z_S+k5!no~MRsRMc|+G#s!t?oW^ zcR~jTF^F=nb3uvGQ@QY!5OW$nWOIu>8wEeqX9df!YFB5Z+t=q?hdXw*ltNTm?M?Z( zlM#}<kX8CfN%eMz^hfjT63G@`oun<T_U=SQn?l^7SZv5%^<fu95?4LtwM6R>ysqNv ztrKfu9GeSFBFqO<oM(U^8J1(PsYH(AbQNPQ#41q=-H6R#CqeBO0PRCA=ug;>+9_Nr zWl65#%uUf>V_%$hp=qm7e!&rU9f>8wE%^TbcjrS*wvQrdZsv~;K@Z%)Ai~tM)cz7T z-WZXwM+Qm7Qqvh%8UymuL!oCsh=Aa1OHO6UsIXR`Z(|D}8d&2m#v4d7E87(=g_!h< zC*dX57#&J2?MJ^7ugoHNShzM~95Lai|Jg`*)B%oO<kLdU#2HKmbxXlyhAlNlW{Bdr zyvHLdMX>?3y}eCQzws}A_qEsG%7Vcjuef7RYoZc9@fZK(@R`f9YV)~xaS4mjJ1Fy^ zuiCP{hs(_q?NmHstD4gjZ#~dv?fgt-ZMS-RQ@IX8?mc25Z~GXeyMFE35B|VsxL9OU zV|G^Vu;)JXZ%erI2Ofn2vEHY!AieenQs^J6WBL;l9D6qKQ6kUs`pKu-mSJvc(^Cr= zP>JMp%0|aewls2xk`l`Ri7=NVdOV|xxzT9ZrZii;RgM{CE7-jK1R{fWmSe&E98?jG zD{YoW;WfVVmuKWz&W@;M`Nl~eA<2{l)XMcj$9Xo)o~y7)UXcg0UC@5e9v4dLvcHe@ z8f3Y5fQ4nSw!Yz8rHY@cDQN~rMd%!&#`J@Y?bW44ykoF}gJM~MDS38=x_W@gyAL+V z6(cjY(D^i$U)tm+IxU#BTNyU+M3faAqmhm}@?1K!P*!}rI)JM3#L)80`Xv7l^EpxW zLlBIezJ!TaZsM$JC>vcRu8BN}*1<Xs;;dUBet8%52ik?`q4vl#hrEy=Z%7ZVNQ^+x zs`9DZ8B9D2#VD3;+G4|!BmB)kx^*1K8#(PXrg06Iv{#&{%vy3#Ht4U^H-@Cma}@t2 zrF;Qin@hZ$j%c2xI8hE6ioz<-T73E9MZ*5@o$^6+?|c9^pv|-E@D@8Y5ZZ&>+_#4+ zoV@P#y0+KG<_Vu|x4NKn7NA=j<Z&Y^QD%MtD+@E=FJ7TSDz>BK;GTxb4XJfNua{?m z+!K3;{f&bjSp1+{nXXSf*xZ?KHsB5=81;=*Sy>ezVTy~&A{R6)gL<O#WqZT<nW^no zZ*gYwt&M$5{x4pX_QFQhes^$rvANaiZGqM?mQKrd2>mwp59#<imO%0!D!r$irJ7SU z6csLvtIfbTLhymHGOPL9&SjSvfy=X*?)Q&Ll|(p<Mf?vJK{U^2Zh>74Bbq{9I7a(@ zf6O6{Y^d^NLqvECdgq|CMX2WF1c4C9oCYjpVBHi)FWmhZtSpO|WGXfI$?c#LNB%Ju zIOy(zn=MpVr$<fIDb|ve+PTSGvuDQC1Q64zcJH7uIk(^0Yc}SAHMpnnm|`EQ1e35~ zHN!p-0W{2CP#>=}8w<eej-BRadzK3G6)0B<)I-!p6>ED5c<Lx{R>lsptSToDeZ<9& zs2#T)nusvmXrVGXBFSR(J7^#vMTA2Q?=@|FjfAAs8#}d#o4A!s8P?Z9(R{@MfT6>= zNc?K>mS#8&<?*HMM^(-4$H9U8lq}3fSlKB&QtjS7H1Ac1vd6W6ks&bs9Wjh+9e{EY z8cDmKK)!*w*?!z@E6EROOu3^i8W;e_I$P@ohdm9%!J(YC;Q<e;wWDW|E$k$-StK>d zLY4@3*|8<4Pysv#myrZr3*!bm22u%lpxxQ3<3^=P%^re#{G$iTiHDo6roxsR8ymB; ze%LBX!qEv?kFuc0Gs^UEaNvOc*MIAG-+b%lX#slEo%%0a?)`;7;n+Z{$)!sx+Ko7) z4^x;VZ@W8Z3g}s{b`OS|dzfPo?87g=si=uUpFO>PvA$fpdgX`y&}SJS0DZIBl(X#V zm49B+2aW=<FsBH>sgNRo48$K<ViH4s+=TN%oCrRlt|BJMoobW@QQpRKU&gd4mlzX^ zLwpQan-Fc3r&C2Oy&w-D7b(KPo8+CR9AOm)#IaIy2m7cQt=W1mVo7N^#(O}OOt5xB z<VYt`q$B0nK}&KvR~wp*tsSg%%H#-G2Nr^%<pFQo2=04BIs1siR!fU9hW4!;d^VIx zrdA`lHOsK?4<K+=;LP-e)ujjPTPPdKO35)5l>x_v;y5#1SBi9klWyL*x4OK*GjH6w zk1>0FTfVSzZMXA8=^7?vykjmd6EH_^#11nYfazemi6b^$wu~sy4a|-I41xye48riy zY&NhwX=&xSQ~tq`okwM+vLHg~R3QF|2{Nu=Usr&Ev>I%3728#)f$}%D_kpl7OoAr+ zeY%OO{mnb~@p!RtTT@@`$SVATz^s(1K{@PV_l9EVM^1da!<QCjv6i8?eDl>eG1Frj zW2A7c0f_L5a&z_-9E{Gx+9?&qJlcgyl!!+90Yxn@FM?|CZz&Nw3oe!2ynFxl{mlov zZAdfUoY~mkC302iZoudks>=e|Ac##0gJ20q%#v0T2778{_L++d@Zs!~_zL>8iI;88 zw0k<d{r>tU?a@(FVn0Q&(g4ik;!?|ng5?a}o}ZdnYEI$;b+EU0ePR09l_oiK4oN^V z)ja6pyn#vv_Nt;DLCm$S9ZosjBgxM}2QA{DS9!44y?-zyT6e3>Tf>X<GaCop2EIf6 z?$!YqvC>i>`}cPb7aFz8^9?kWc2`WxJ^_<vW~w&V(8<0K11OIx7&M)gil+cbNAodx z{W|7mfx1c)JQaM|#E(}}A&{vDX?0I5Lp8fct!3iVI|q?&q%4NO`Xc;onMP3LnA2#g z<_g_xPAyL24M7;=G|tdk8O<RYrW(NuPYq<46Bz1f-oTP9rN}6zXS+-8f0VQbyxW|@ zW+uGb>g^xmq}>J8>1YBzVD9ELUeUd|#sZj;Z4%9(nI%BmG_jAiMG4gI_DBY=KzHe1 zedRfoH%C>8Q+C>$%m5{`M;|r|x*0g?vvOpYa;^y6soA~uI$sUVBfE6s8}8y1j>N)9 z!G4kxocm_}&^Zsbzrog@wgaf>utNeC^G$-oi2Ibu-A-B7o|3$7dPH`Z^sqCyqy{Jz zk7$DXkSleCuI0NK?3>X&yp<Lg7TK_JZvhuRPH1PjC+395eQ{J>k;{dX3Y?KFy|=jl zcR+~0s2eX)EL#xRSSF`9ntINj0luTxO|d7VTmsS$h0A#X$_uG0K^bbYmJWH%=%bYJ zUS_w0pvL^K@$s&+i{c#BW}=h1QkoSt5=zAElxoSgF28nrEzCYpRa;4RFo+GY_JUlu zbj68ES6459=^xy`N2lOej~#nl`uOuUA_~HJve(DHB_j0tf8u+GbA^k|kj2rm>z-mI z$BVLFoSC|CRM)eYB~jss8y5yQRxN+!sk5|)$r-=Jd^xw!pBd|X019?7<l--`M`HOz z`<%ZLkHw1OQc1>Ii=+h5Z*J>|AAqvi$ygO+g4HIt7B7{+HDHdPSSjobBbi+>7<&S8 zO2Z3<2X#DCRcX$tf|7I$ycyT+tK6?WzqlZpZK0CVgpOIB5ZfkKGI)VeK7ef5xdo8r zy+Z>mD3h4WX>XIfHO#UPnC2l{K?et&KE_x4Ec{gYrG+`O=hfstV|Jje-Tf6pVl5mN zd-l~!7uGm6bZ6H?Gq-kjkVC+3p%!A+c35Kdp&FfzEnlF{{H$VLF}+eFF;{o)-Jb<% zHUQ;AoMDt;N9Q65<3L*uq+s#JBSzt{oN_ulgU`3QhHD`P3iFD0oRP&hhCA{Ox704s zP7t4vKP%9;;Ca%?i!3Hn<Q$IUG<aX>d00ePym^>S4+73O+)fIchF`lD?l!|%xWA1Y zRJ3y<wE-JD?lE|?;|0F5wD{)T2lzo?4%exi@-vZMp%K)2HUbWYucQbXhEq0Avzjl? zvjEq24)DvT7c!amCnjItH~@B&D`vB$gpQLF!<}su8y{Syt)xjb+qqS#@r}vZp+R%N zPv+M8HZpr=s?PYMY_yd9a|**ezi!*<P<|$q0wG!$P3v3xt$SPhiYrh^Yy0-5GTv++ z4lc}bOjUnQ*m45PI^4iA@Y+TTqV9I9tw9w(<)zui8=DGEX0@AZOatpLEzHnp8hLN$ z;Hl-gh3VRz^-X-UU<2UP((KgT%{?NUFXHGksUf?wvD2L9?5fV@UJH{fTLerTwh89# zfLoMUDOwf-?Q4Ti&p=w`IU7?rCVo60k}nelQS8{c|4!tk6{wV*W|kJfb`K?;$<W3L zSz{Vq6I|6%3DXLVHCHZP);^U2R3W}xZn$<B<H~JHhad$mHz?|OZ^8U#a<)A~Z3b5N zd%IZK?L1M8+1*ARS1I_q!ThJR!yXd~PZb%+@u6ckfJod%ea>+qW$4&4fiFpt={nF* z)>+*2)T2RbZhCpU{b0Va!j2RhV)RSKbvbWffG<XH_i%&qX#>Zg*_I@DUFfr?EQ*z> z+6=yC9PpsnRB)$!-VvDEsI(mjd7l|1l@EyWqbmWx4zIxYlt57<W54|RNYjc<15X~? z;nQBI0zK6vDNgeI?g{04jHv^9d8M;kb<i@DX>K7FSYTr`W_5TcyzwaSQm;W_34fkP zf;q$3lEf%z*U|hbiJ3l}nL?%4WAs<Kd%AmeM&GPfD4}geR*@Qq-CYRC{)S-v1bT}@ zbImjNkb%cKeWF<qfih&EEODWI0D08Nr^ZK?^SWG}Fy+l14MpdJ&L+A9JG-72h}w5| zcXqaSpeL3Nv`uc}D#Iu&FD;WS%O-5$e)A|aiD%s9hGQ0}`qzH*cW&Ljb1D{kQ<?g! zv%P=s&yYr0<4+eZUtWQU9;<ne{qS(Ow^y99_t@_~+6(lBb!L5s10vZ0Q`f$J+b~P9 z)B0$oyxmib%azNQe&mn*05j{{<>u|Eb^iM!Qy^QO)AzC!J;e%Ri+B43jBjQ$ov?$X z^pzNYanb=}8)14VwAA1l25G@@e7mdULlg!Dwweo#(pm6744HhhlY?}|sv|vRR~bdi zx%JNL0{56<tk(5&h%D;}N(E>Xw2FvF0J%-tymH<Cr?f2?fLZxH64wB_?(ej^EaMd3 zCV~^MI^|cX;-`T}kkUFTCroc)zDa?2+5qw2x_zG#NK?+<g3bw&hdMT05{P%O>jTY~ z7UuyXR7X$EkF&clH+TQR2306Sd7og)CMXTT0jh&IoD9vw$Vqds(Ov{VSzbxnE0EHH zr14-}M1ykbp%igslF=42LJ*v2pa!|$75m#FgC!0LI?M>CcJ~1BKx8=`X%*?rT4*4I z!gS8svCt$}%*^X=-n@Kq^|d$Npg?*@Bb`=MDje>C!bO4?OO0<H`8=%fP+CdCoS6pQ zZ}%rQ_YYU+rsb0(>sbXy@KsFs-L7;MgP^!1DUT-3LX$eG$u|78cEUW27jCHvDN}HB z0~L#EuPx7P?8zx*d4A@>?jfh!GBAYaqVX|;)J-Gt$wB{Vw+{jMv}%p$+ScLrUJGN@ zR=W=%##;stme<!&1}gXVNjzTJ>kRL1w=XU>@9nhj?;XxJ8t5NzU29O|EP>ZH$=^4* z*&guj0@=xH6Fh@UJL)OPDDjh_=;toXy>fr|`tmFm_NAH0uin~x@$$lhodd!)U%R*U zv8R@I4-Pl?TQCw9`Zw-x-nh63JCY2CEFHj18oxT%nB_RIYGq>wM-GA4MfAn#Nus@> zGL%`El_l7TFO*@2^#)oMm>p^9skzi~yidvaTfTT?;qgu%Oxp(MOU+Y;K{cOg&6Wtm zgm>xY#s(3rigA?3o>*7LSNTEVB!=>a*9|G&hoDuUEf`ungGUG<E=6{E6_^so6l!_i zv!#QH9mKP{yGy_YS!9IB0e*dU)yVURG{F0A04y^_L(<05y<<e5ZudA{cpkrY5cXkj zpY4;LA|z>y0_6<^<5s_qO_!6JDVF!qAKTr%#^fwuUHvuxLq088+#CCc>y{fH7%??7 zH4hp@Ke0#*!9H^pl!FZqvu`0=J6aGEcK{=iUlN20vXl#)`N!kOEmOL%yS6%A33myn z3&>%|Y}M%nu|-0(GC%8o0>8L`Yhyq(^XO8k))F=Bdbv{~iCMM7;0l99GuxKHah39& z^2Z~*uikie$bxMMIzkOcs%Q<e{R3^NDnF8z9!w924i*$0@4;74xYRzwqvqAF4N-35 z>{O_QIF|GYUWEE&*EI*EV#@;kfhx?A#vFA<0s4iROraghctdPPo9eKk$ggSS6OYS{ zj8@txQ9KM3gqWlX!0U!V^yAX#0)Jsk*Ik`~AAuyt9x)fnmbu)VCZN}P)an0;PxpS} zGiX6-Ke^|Z$X0pAA4s*oE4AlL>v7+g+iRA;a(3{|+x3?6w-sAer&6_CZmwMU;U78& z^ru43^Fm67_7E0+5u!P+U0yro%0@50&jaSiEE6f<OqQy_5D>*0p~EIDbdikXa5MW& z3X`=HH)SoxaTzGbrmvZTaC6aWsvIf%GNtQ&A7rzSf42d5tyQEu<YXwz!fts*<VV4; z9tcYd0Y9Kga;@NW(IgSL$wxEbYI2f#(sKeLzd5p<+OgO26~TXRM>5*7PqJOm$7R|L zo*+@QbouO>DcbVGRM<ekNeF8;DG^DSc;~^oPI7JO=vH3hM=av_%4;`#F#N{1UgrXE zkKm?{YnxjbVwIGo+s8o&{Rf*qKtrdfVlbAY>H&eF><!?C;jxtlGThqBzPysVo8z?~ z8(s{Mk_7?oYuYLS-?E&bU{D&AL98<*MkQi)mD(kok>mtvCo2IdC>(;XZEW4RcIAyX z-dbE*+-eV=xpq-HhN5^IfO{w@luz%a8HijU4zPfuOr`Mwi^%0&TQu|w7j`hg#xASl z#BNUmfszKU;c>|2nw!o`*O^>qUpLK-#aV_-0u1HEC0ih%9B+&3%X2W*ovnk7JpfH* zugAiO#eIsu9LtI7MfP`{9@W=jPb-Ua5BB98g{idDuQI$V3+xUnc{bkicXkf1EH+k} zQ<S#YoZ3Dd?6l>CaABdbJjc#S<+b&L2YVRp1rFer-S%N!QEnLKW&Hcr-OZJmsc+p{ zLor)koWr$-e%)A|edW&P?advm>Dc4%Z|>Y(-y$~pQ_o+;Rq4(98|W2mkv!Pg#JdaI zETg!&xxKJ3&zR1_TMBp9kzv{dvBPc^iGtq+_BLXd*`tt-p(6;C<x#ULFwL>K87p5I zYz4QZiuw~EhIb-L-8{*MPRNvQL9wHT$#DgS!IZwdysU|-2nuuS>cHCshxj34N-PfK z+B@8stW9G+2lYBdco%)ZjJ0lSE+`{i)Vyxw4R0sMvFS87Hw%7JTnfH_O5lQu%(e?> zOEFW}U6HSax0X_nSVYInOwUt3Fq$X1uq>#|CT$NQ$gCqcsS{8E<ONnMn>z}dA4e){ zy1ACQEVYcZxc_0?)m{%BZy&<d91%SuB<G$6My2-Q{>-E{tfUVR1PoJh+#KHUlLWRF zG5r?FDw~1f+G!JIis`^wVt)MQ-L0f6QUf5G=K;dK#4Y#k>?D9*B%zY1;s02^ot`Mw zMnDKAdyN|}J%Twt?}RHJ>s?=o++{`kJU!Bn5+&T%NdgA@+(1r$6&-_Gh0hbcu=&J` zuK$eKP&X_AgC{yxVgOA#`OnBCFVCn#b8ts3k<p<gPx`UY)FMSfiHU^$Q3dT(y83>L zxM$y0CMHUmnv7PaMi|e-8xR=}&*qFaNV$XXXJ8mXhmtH4ni7wR>FEaLn1#OjTfg&# zw{G4#6$?GZqCx*3|CjaWuHc)b&Gpp_OO|5jY(G#{7JB*JJ+^N17%dxCa9O>(K}^eV zW~#D(Sbgn*Rv+IaIh7BP=EjYue((pr4@xdAEu9C&o(fezxP>4WGAmsm!be%){dFf_ zdhK61V@O`zCgt&V0G6<1G8@31U~4wEl~58STAu`30bWMHbjUU?Fm861wB-^KphlqX z{M;;JP637Zk&|i8)@NUIJfXX}uSn3Dl#vUvvMVaKvcA5xJwMmPDTT*5wiBd9tHF*y zJ^7BCQ~uULcZOZn`h=W16sy`HT5+yHBXPz+JhRj(1q!lUhx?c{MJ5?-B*^`pEbLpm zdrR}PC>xtQI~SG~F=+#N@rq$V#XL-3B~=f*92VPZx8(j&L8f<cs-cCvizB#Fr_aui z;SrRNdkp?N^5Lk}mlpvIl%v!u0s?r{C=5WbLaT^v7iisu)I`YPysk{}q=MN+!cqk` za#pXk4dO6&F|Nz5Z;=ct${O#<5a}AIm;PY2f_eriD1V5ri-2`wdXdctwjq@qQ(BPB z=tBR>IfLO?V?k1D+)?mFusoa6(+EG1RwL~T*C|MczO>!yTwYchN<q>=W&5zVG&{Mq zf4I4Oz^^n68Uhz6%5e+<%Z4qqQB9wPZYL_U<oW3jw#b=3P+aK}-qX!VPLM*gSUbS; zs&-*s>BF(L-`?%c;|GODdw00s#XWs+VRjlAh)t68GIaRn#@^cQ!RqYP{q5G)-oZ1g zbN0*>_?{udzvUh~HTVd1dY2bx-dx)Pn!k2me<9RU%d_9U`Cz(MdE@qjk3D^1ct|#s zofn_F{L1TZVI3xW_0^^3&h{3O6R_^??%v0ryLNST{>?XU-neq1LB_vc=h~$e+-#n? zb{X>R?e1N?uwr43ERYp+LLn!?HbWe2UwC#PrM(j$%Jal_I{dID&xN0UPFnc0`|&jd z!n-UJJ%PE$1zOaNKEO}xtU~0PcNjr+q^^ZnL_QzsGUNi++!xA{8@;TC{TAtN&@?SQ zNwIxrLP@na1Q0|sXJRe{@yxTXFkPeI;jkeS0~sx4v8Hew#N74Eg`3}Jo&xy@x}m9x zW7k<%9P_Mmh|Jl>%5>$#0#YTHdK~{OKOag_G<;9VWZ4SPp;eqs$|0iDO}Vl6IG;h7 zp0rK|;{+>xm=HWD4-~AuKJCi*R-E$Zt1j%pWZ;o08aG80VYU!Crb?1Q+@f4wheXcE zL@nDe&Pjx}a$qW+KLCAY#T6=TdrAW}o31Ksg-o2?E>>RQcMKCcHKIeY0&xl544#f0 zy-a<2cRt3q#i<1b>&aTy@tqm%#M<DB2<E}1QD9rx@)z@ATLys(fVPp+@G2jhvf1l2 zH&<77_xE6&W}^uTcVmC_6b;=rE3_40o5P4MU84YKg|ZDDUZ)xS#D|}B7M0@f6#xxM z%@SYuyCO9B39*Yw9%a>nm1=fP%$T-8d=KPtsmhB~1fb_#0R8C&#mYkeqo11o{!eJv za2{7ea}#>p<~{E7bO#H)=c9YvcOUC{7-ws*$2KZn1$Q<lzI7K(+w*0e&Ig8k_L-+W z%gs5UKOLHWkV}ajd0(ZnJ*;%L#I;{!6RA9}0DGPpP>C9e7d-6Z`pgUj-f3eFP&vis zqqcL+He8#XuI-S}qty|jL;~*Zv0%u}z~bbVmlh@F<U`+JW!l}{M`~j9RV3>kaf$mZ zrgB6F{gd92<OR5ODmgBG5uBsZo}X><7&-+FK$PRdBg2B7#3YT|aySACmAq1Z8tmFD zD+@x~oB}Pe#wfX%TMk)DecP0;7`ge2M-4iFsV<82wWKi$0{}$p$eT*#((1CEG%0k_ zZnfozGNWwS^ptm37UtQhWLC4fKpdR!S&NbTkP944jO_Zx79ap;4?%1rn(Hl8O(TKh zW>WHlsDw-SYFo@~P)sW*mN2?@7cydY=NXdiu(+6Mvv4Gp53UMS5UPnRtvE83;|=LJ z2$x(8-e6Q#riltW2?zb^oqe`1AlGntRwG5pc3`Jc>nN|0&ac&e3~4K^ojS^j@4#+1 zG6CW*EjH|U-63w`tv>rRea@(2NFbE@g`+*@Oj8J<r=lqo!%$h<+6Btr+uVf?L@nUX zjBapmyS;tTzPO+;0EmHaKfV_acG`@Gf(<IT(BS1<ZPY7ouI<2PcQ*I7IhuDke6Y2* zy|+hfG*QpmcImbk$yBp{_|02u7v~#Gv(xuCcHX$ZHB}wH`qu4wr9S~j@9(V4P3>;3 zGhWTfiDxdYJheKHeSOMOTcSUpPCS3@!r}h@g{1{>9P2nS33Q6x0k#DWl<Tm<S*EOi zcnT>|NRQ<G2b6YUbrs5J_zIh%2A3>A;wT$&?fEE=iAF`I)r#9K0hBqbxVbm|jGehY z*|Q0rN`SLoDUUa?0DgXA)XvV92HiLW6hiQZ94Bf5wb+A6>xc2x;glK-&-d`z!?8+^ zI$&AiJLej!Sm=c(jgbw0xqK_o_z09M0MY0mMPh4f6Z*op{OT$M1V=SxAanw)C8D;3 zDJqI2_Yc+{pm|cl=Jw{??3{pZeF~fXUW)@I@c5r{CO5lye|vWau)|kMW9H+v2Snoz zX(drSxQ{5?+`^+8>%%6!US3@Bmb1^dwy_43G|L6Tv_oL}Ohb-9@=<INaa*~+#@^4i z{N<XuZ)2yN>b3={eT?nh?FQ$P>Ie(uE<26t2BoQ9rOmCOlUPCm`AH%!_LRGZtu4;V zg=ZC~&QTb=V$t4M7J#)J+=1Jd7;j^JT`K2DBE`_WYiM3djtwIJqF9-oMOrZCPuoa= z4z^iiKwS4N_ov;L+oX5Id}G)GWv5Y^3>+oxZggU?A$<;w-Uj-^ko0y`sm2!upx3-2 zE55NBi;}c%Q?ZPlG}f*zYSk#rPrgNr`@TG{d~2m`njV%~c)<DGAGVFALYH^~#NsYD z0D6e?`(OOpE3dwODi(SK5eLRB%?^L^v#hOZml|C7%RNCeAN3Un^mOX1#S~e^Ub&@n zgJFeV`RdezJv;dP^t1@N@ceVne(p1$qUQj5&vJ7f6#J-raQ<AG0?wVjmWM2kn}OX& z>qJq&k<?DWefqlLV9v+E-&)vR9@_>CEw6|qCH77osL|_Vuf4rXYOw0XIpWUbJt80a zDKaRNT}-JDg^bOx1Qws4oAXUl*@p~VgX7s&X7OMtVo^63Da?xe)k#jmg)&+rf(eS% z>8DDAD2JRWj$2edO0C~o$Zet`l<-S&mt1hFr(>5Jsd=92j98XH4E#nk$I!OW>+Dsg zIxv^a=}QX>_cyjLE-&%QHleAl)|HDF@c99c%HhWZH=Y?#=Kk6S@Et8>eQS%w7=s^% zvHKfa5CPA1&L}l|d}U#7W@iha%XY20!zrkq)RNB1eF<|87HJ~Y<V~ad!g=PxMEhy8 z4s}B7;83MmT(YYK=|aqV8#}lkk%NU)m5dO*Hbl<;J~pI6he47l-@hD&SnQR%Mw|OW zC6gDI=J8PhRfBg?xu_lmgx0?C)@?Qx1cPKhR_;9aXks~4j!WN~*AU{sJHRDopJWj2 zPE)bDC|47>6Dze5$7Ajt;<a*dahCACSMTqTt8o`U-(Cgh`<?dS?*3qDzWMB>C5&Kq zcgO-M@P?nv{$b~>d+Qq3=_wjU_``0C!Y5YPI@N-%WJ*N4UR$2SPv-K%OtW6WxXxC> z%U4&guFPI&P7T_7?9#B)vbnjrG(EAqwN6MTKg~{bXY17$u3x;oG|$?6d1VQG?COPO zG>_{SmLZ*?>gp@6y}>@l{K7m#52l!D&gc~3xw*~WB;NM0-~EFDZcEQ!B%->;Mi57z z0o74>;3vWxR+fla;N<x}c2}LCWU=E60jCSY*UTeUP*gF?XeaKs1dH0QkQ1(wosW#T z30O}jcs88_)5rAp2TpOtdUTO1C}8LZd!)|NT3;th?9QD#OdkVmLwx9$mX<}6BWt=W z>oAi-BRH^3F4627k)(Z_kViSb+sC>i3$8WB_Vz|X&+Phz{acQ?dt?Ju5=Pfc8B=+u z*x_PKCQB)U2c6^>SPc-rIKO}e9dY7DS#U0fUf4tJG0zGr0s>+xHasWOFEws#ZSwH? z=KAvDlBo^azoH!n?H2mL<<(29>)3R$-&4YajkVRK6%tv>xNA|W=Fm^Z8^J+9B!GLi z39nC~Gw?hWnV{7mqTx7>loycMh8-Y+FEMt|1*RkZdI;Oioh<|fIw#`9lFaHYI?L-y zVqhsX;XOinkYJef<#A)C>y6D#0Iu7@3%+swk$=#m5B@uSQli_WvE1RzR6$3ucDqGp z<l@gsZGHU6W#%w<K@2PGSDGN5L{TK(0!@jY$uiRGqAZz$$7!-8GY}MBTwr<<jKql$ za-_8L2iTAyB8cf+$2HPo!z9Wq3QXGq)-jpwEfH~lXK%+@C8n5gKe;kxNs-w|Da?$p z>`gHdqzZ0t`;k~|86dGO{n}$&h-p0C#a_Uee&buOef8_#l%?i0J~A=%`hWI^EE|Ob zdh>`o>klqBXk%w8sUS0_M80+hFU`t9r}~RuY4mjP<I&i?^FA`ZAN|OOKK=0zqq{qx zml}VbhyI;Y_5)jjujM`!eenxqA2ji4lbZChiIf6@L@{s!mGGsOMl1~E{!mO9``4Z% zUVf`O-UtXagO8z>TDf^zW(nS9ogjAyERMg8{IHcOX99psQgmJf@+#?JuLl%HYw($7 zW)-pxDDyq&O((LLue{Phwv}~9yXTfM(^6qdsM&(242in%q?VQ{Q3W~#;8)8n#ji@b zVx~~aK?u`)`4kzJQp6-_5%%^ukreF%c)`v(5Dlyku4NSjE3g2Ap>?O-dh_-@l$I-( zE<#z>6|6|C&Md1}F0NScE)lW2x9^fE62t9YV_~J<oV&QBmBYln^ch8`nVO-DpUR*w z)x`oP-9JH%=MQ~l`+(hny)GDf>dxIe<Zm2IPH(pd5B7T3FD%}>|3D^5&em-<D26y% zP$p`PZL%vPCFG@pL;$ZW5#l*b>i64Q2N3YXSC?46Uc0|@bxDWU%r~ZRJ12sZ$WE$e zC`ls1IVn;GWYp^rX#nZ?OR*q>w;pWX-P-3IRx-Nap0$T>&T#l`uzY{`%<3$MF1@wY znyybS%{6<~+Tv`3V^+z(zTBL;IFI@<B!-ovbmnL3yRGiVo+4gnr|RIpi9v5`Yv--I zYj@YTJFONmsU*O^b?07lvO4T_E>W3<ypgVlDuk7*1YXbJlmJJeZlR$yXPYD}!qW+p zB=N*8s&C9TZ~~j20+FL|?sw(q(;H3@*h&fn+u9IIKtKmKw(}zo4Rl)8>g%iX1l^*q z%BH0}^g5`E0R!dZSHplxg`1gvu(rl7igA|`C^5K}&L2CUEVyV^=38RvUrcTDy#9ti zggZTDP!=g>_^McIW3p%BuKd86u9PPUTgTrI9z4KZ9$#dl12I*yaznAXx%peSZe6~7 z*&Pqk<|*ea4r2-}Xzh15=cg|+s<<$K$-uslxzoWdiB;MBq(^bF(tEK&cXTeVTj(u` zZIc?g<IX>FMA3m_sLD!s>h@i}I)y#)&b_sJD@!XB0Ul&ZGQkOg2jSXd+D=2qV2F4O z1;B*QA^00qhcbYzU8ZfqQq5@_TsYU1_YN6W<@Ar~ePfNkG<#uADk7DdEqS=LyG_<C zOaZhI+-czz^~Ko*2a7JxeFu+*i8#iNbWni@3bL=@+f#%TNI?;QXr7bW68|6LB|D)R zEz;~SmIsp#LLYE1_|g-wPzCMetDJTc$D3?`-i5W58b|7i0+)@C<acgjTzSmY2kVG* zE4FGaVu|_g3kqfp2AcV88;T;hsmjuVEHe&XRZM*yQl`CG8Fwthy&QYm1nC%0YWa}M zzP3@!MNrPA?ieXWjv2~k%fkEuEwj@pq!z+d4&Rk(%y(QZl@M))q>!0*G7(%a@F%^Z z$0e!Qo8u05cQJ~+_U5fGeDTY^yYkLIw2g$xKl$0oD=V_#NG-9fP4B$qhnGMe`ZEXg z)yl24-u*4&rz^KNCw}W&EP{mj$+7CRddFCQ&!;~A(GS1KaGV4B)1vAJx|~?c%WHhd z<+w;6_GN=l+&p@ocvdAglN3{)aY7O;FC<R_UszgXJXYwc5*Knsk`gea9~&#{ml=u8 z2wlO94X?A<$mpbWX>70iNBJm~=2DL13XPSZ^rK|WJ|umB(^7SME8d4%hP@32wzSzQ zClFFQTS^vYDAJkM3d+l>U7TfWR#H8Qtd$fd<jX`g#c>DZEc}FfA}PlA4(w1W&hKaw z!pqf#m1T}9B-g^5w{COFDNTF&sjH+pUt3=%^&A#I){o_dd2IT(?yo}%4Djs5({3uF zz_krol2}qW5>LmC%r23&hj=;x7j&4}rcNDKc6psvqGO)OU}vT&PnV0I2Kdi|x9IQc z(mdh6cQ*HL?ch{Y1FANsre0g$TbU=}#&GM9-gSxL#pKU&hHDK952D|^i9|O$a*K4I z8bOp17Ww&^NkBPdCyW?Ba>n+XcecsyLQ@y#W^QfDm4(bRn+Ki!!~UJ^gN50-H@Dhz zGc!P8M)3ZDPF$?ir!FkcgN%0%dmPWS+a9dW$UWxyiwo#ioBJJLJy}7w+g*HVZf%j( zrhk30X+Fn829xtvAK={%spqFPJpF#73PA{Coxgfv>B{mv+X&0^%~^tsn+=lsbJjh( z1dDUzKhc6c)tK7vPaJfWYLf_5Jj9ek38XJg5*H2(_vkh#8Pe8>-zB38X${Ff^kBCG z>nQx7+g+HE|LfeWyzSv_2KVaai^^`qrZ6_ZP8U*>>mO|fKP9}D*>AbH01lJlfd2+G zradGxWm^NTB_fv14Q%`t(Wo5{^SzO+6qdkq%t4p~6c0NVlN8qa!aQGIO#{cL^EZ9W zL4P)*-$k)_BuVHO0C8<??dsL5pqcyk?_;Wmw)6Az7cN`?)1&&j!-Gp6b1qlnSGkTW zzs+F%;MNpVK_~4JOmeupw`-{wg@UZhN9v7uzz)2lC_kT$a`Ye`YdAn-(YHN7Pc!Js ze-W1|yMw&TkS=pg221vMjM;XCn$AsgG_PZWb>tal@4@1noCbxn3F@sO(DwS3F3IvO z<j3q6q{8gu{UQ%|^N1(lr`BxD03q1evF$()l;8oOK-<Vt*rn+hc#5e#?smchBdZF@ z7qwfZe3x>iQ^q7yN(xr-umnjEsUmCv;ht8<amY4)+@K-XFNH3c?~+^!iC;1UbMTCy z?I`RaWubQ&);mz9Z4k<`X8D<S*kTkmo$!n_F<iB5A4bX{f0eKpfGa4ke3a(8Bi~Er zglSwlrq{d?C2!Gk-0&pDZ$f8L*%`(x8FKr9WLB)@vp1OT^x;WH(^%2fLI;KXsw_r& zMj4Q#g`!7MIHm+7p`7kvExlL_*%P37U!>6G0Q4-&7>WMn@BP84Sm-sO$ROG3fBN}} zPrXR9)g?9c@l}q;l{Wi(yHM$@H3$4{Fvzek{)N{jzj;^ZlALbW01Q9yx$k@Nxf=*Q z0KFfJac-f1TxK|b{ul*fR-_j$j#HtW{W=!Pd%42m*gHv&E&mXOq5_&_FSpZ78{iv# z)yaHpFv<zIUX?e-1ZU|fQw<LbNn2`5^WoNEvEWqMQms~Qq9(8mnSozc7&Bgi6p<<J zAF0)s(_C%kadW9IK|j6@@m)|rnQF8MhdtFhg}kK=1{c_N=b$3F*l-hcPko3mEbhF* zeI1RYgwqxLSOD=X6`UOle7tt~A_$CNT(af?=~kDQ*;QDWpTip-#Cd;hi{MloiYzK% zT4^IX<UR*>FVGmW%DApX9=++Bs@U#UYts#m7r8Xwm|vK?z0>*n{T30y3(ZOFm)nE~ zXvxQm3AcO2{D}yP&(qSRe3VLyfkrgEabW>EV*g&AV{1?O{x<i>vM6}?^u<LIsN?%V z`#~qlh1ZiN!ywAUCA+l}&d8(a@DR5UlC&_Ew>S2#EHB^{b91Zp;-&e^3#bQ-RrS(B z<E?GdIBK_fXF%ag>#hE^W#v=<%3Z?CD%WMvAELK$LL*#uf2T!+D0$pzZEJrYK3KsI zdJY$wE<aJxt@WL0j_RxqaZ>;0>$jDLa*wL#NI`ShZf$LDbM_J}guF#PfDLpCf$@nz z@NmcpO~k5UJ38n{bGWawT{%Znp`|$AQ>K#Q>v*ybr%z$GW6y_0P)eY}(RvD=u2<)X zxSS%<V09Y4I6PQF0Z@_?on0kkZM}|4077CnpRFWM#{>i*z=I7L?IsaE)@g4MAd3qP z@g#I~=kD_IrF*zt&615#5dw=OF}3r9ML9Dx+R1F18}7wmC!lGw2vlLfMKF|`1yD6_ zl5Eb7oy9(veJ%tz&c1#pq@;|#@)nz(e)Y9iLGakiVNb{lpl9#J0~|Lux8~;N$a}+M z2IC}cq~;AsMYTLTwMgzrkNS|0A4dpTCe|>lM!$gj*qf!Xo0hJaoDO>RfwD)TbGP>U zJ6p;JrSpsj_xA|K5dR2STe5u4o|>G*=XG+>+qMHose#m%1nEw*MPy<3Y95=BcJ6SY zgbaFZr5?vEp}RY*f=KFz?R|Hi!Xu+f&Y8hMeR2*+2_n?7M}zj%6koBL%WF~SzoJA^ z9L;C&Q4Q(#4s;B5=K=Oy%pOEh0>K3<fuX%kX(r|%uAD!XT^{wY*WV-eulzi;9Yod_ zGW>!-<zDY<OTV{ma285}fIa?IDBqr!IJJ|HiUU*Kv}}sdv7=0#$=(G<qIqTnSNa{d zzU#a{+ugNo6|>-s99?`Y24oPz;@<6$Bmq-_S!#67F5Zc9F`7XBqXx`y${h0y%2-Uk z&h{c}kue?7N~n2k?{Ua9ltynv2m|HYj6kK2SUr#qWx>-_XGVS7KpSFXB57M;#-`<H z5&n}yfBquhECUaA`WA!ivB;9}ZN-TDcGKfhl}QAkXT4yz=~sW_U$`E73Lm**4lc|O ze&TaD2&p_%{m$I$=BxodY)fW`Z{H*#vNXG2`s(y1sX9*8fnH2F9De>s{>bHvD{Kt{ z=-s#K9MGQvTYfN$C?j|mE197smi+9(A5LHKuXemq6&M8OCWQboU>01ZY-nI&gUcM! zgw;U_(ODevRGBBsyJhb}(D0&gjL^1RlU16fgasI}Zc&i?%IkC_yrpf9nYBd$jqZ@( z&_r(8mco((0eLz*){wo!Ac;=f_f#~YDIp*&9spCC)E4OXKtt|(+@bt-l$}zro;Ju1 zq--RF@E*K%=fTC5C4yP6U%9ZcCC7QHW^PjNo44<P=}1y(nuEf%l$NJ9N!A&R+(_!x z<t27<vF}2hh1n*RLN6fT#^(AfZ@jsD<=VCDH?$hC>rEbtL3Q(x^KmC>!|m-Z34%JH z(Zd#49QB5dXdm2YB3BKIF110i6nEsxoSWwGQH;l5xxJ}a)yk0EKIDd9+w1K0s;l#j zox{QQK?~pR-k`eEI=s8Sv$4~fBh~uU)CPHBa30vx(nvz|`}=*2@znV0`oT+=<~PaN zU!S<Wv4d~@3zz0FpTD_raCND1b+Pg4y<O5ul12uD`qd@HMt|kj26p{d?`?5>Jy`j| zT!YBex7N11?bhI6uh+(v8EDnQAEwehoEY|Ays~m(Zsx|tWd@B(Z(Jrtd*c9!I~c6Y zHwiXy6FUrX=k9&NvlbTSU<Ql8R-9<PTH8DjWZ^7U`3g@@&SLni4|;5ua}t(qt$@NI zK0GGQVZ&!Iqygj!vDk(^+<pj}gkkR8yT7%$xw^dg)vtd8JaF&s-OgbfGJ2FY?iQB% zP>g1p6gxIxtRaakVTW#O1ChPk-o;5ngTbyyYwzNv%dTglDk<9rx`Zw7j*xuD`8JVn zG(kQ5dK6l%BqthFMS93^tKF^gWDLpXlOm>eI+uOgray&bc((+jSkxT@a2mdS`}VWX zK6~@#P4F2OdW?&NG=S-G#d+h6H$9^^CVZY}8hY+2(M*S$b;(L){@Z*NR1MQ+U?%fJ z;Z@mFZ3Sg(P7$9-5a2rUg<yF6({xVR?0j7Y=^Bw3#5$Ah3bVfl+hB9hze8r;MtzFY zVQZwDCua=gQeyHNYNWOarI`=${2?Ly0S@gVCW%cBwz04u9;|DpXmU<DSLESFoc7e= z{+-6`Q|-MsCa0Ih5{Fy8&dzjWx!2vHOt^*IEZxpVb$BpQU+%WICa2|vPmTQ^RbySB z>$EmVUx_Z!?d<YcefpxEXL^UaEW0U)a0aEK$FJlUn<60((g;(;ey6=Y=xi&GzcwZW zTTwqPctMI0dW(Q2-eM!R#F5E<ETFt|X;8aZ8r~H&?=0$S2D}l9pZTEoKz@X~7|NF` z3&Yg9cX#jpJ+@$&pL2^Vj5wxO!f$Z@6HCY%1VPwi>~{}0ItLrt$DPCiLX<5!42dbB z68=2IANxX6?|1em>YU8QehH3?m=Y#h2WxFI+b9%Q^kokR)oai@fU34Vh|f=F$ca=F zIOtbfd-o9(-1PmQZWnjN1`bY&tClFLxwDPV0VqC?jpm^bucHHRZ*RdRKmUurdW!Sf z@+S@cb=>HgIX3Xx?l{X2)DWPz%+zO852ANtxBu3CTmU$ZruvItZjjSeJFKT%WA$J8 zQ$Nm1je8-0zQ_Q3?n8e@gZf=xYzo{{a9@V$>8}9=#^M0q`ZRY^MFwGm$N2`k7klL- zR=1znd@NFiF+TwP;1TTHGJ6vOD2GLvR{^XN&`O{#DWSynmfY8JOUpVgh+|S5P$=ga z!#cLnU1VZL!1BAFAw^@boa#U!qF1%sDt%ydRIO52fWh38q434mnyuY@32cY;$|#~6 zZofB2Te3LoMe~B_1LMiFPFhT*O;9?y8uoaIfoT>ZfSzeK5cB?nb#@yruP(_DJ27!# zb%i!z30_@UrV3tRV?iE17$!T1TU*<2;3+->oWOr)sx_>yk^ZMoV!k2PYmU28FwMd& z{^gv(1d)-cbQ3hAU`hk3tR)8ch7RSpqws+m2M`{BjIXUO9QG>2wyx<|fGR#oWYs(z z)OHRrd9vV7t{o0nmuBDCB0FLQqx;h<O-^D0H@>;4-4878q+Emux3^lDx`~DO%Bwdo zFV0?AXuk4b_wqa@bvc)Fgwyg&9oy;V-u~)r<4fOuYXxKcVSAx5`P9lRfExHbQ?D*H zYS)%$!LT2F`FUB{*=dGwlXWmI4*GJG(iu7vgKB+tnsa|D`0Hb3R{%6f1vqOcTtSVz zt5`RkZbpCEG{D$}Zw!f2uz6x)pPj<sM&fQ<EaW2#vV$YgI*EDUfG~Vu78mE`ZJ<-P zhWGB>-PzhA=_lb3fXl-c5rOhS(z*BKX|o(GfGQL)#`pC%-dMe`%2tNC$%-eX0Zx#4 zNq`%#oB5@Sv_r>+Dsrv?1CWdqqrQCQrzV${7U4SEUy@&qr7Dthmz)8_b?%H|CkM$o z$Sm+Eb6Muy4<enLKD)CO$YFhk=EJBTzn=EG^>9&oq)sp#;4p>*$PO~Qb?fH*{2VC% z;~)P7+8UDN#*G^nFJ1)P6O;mj7x98UJ3>fjta6$JIYzNqD|h6`E3nv$;EpBI@ohRh z<2eviMlvNqvcsp%8BgcPK)AI#ci1c3*(B%8L2Y{G^?Ms{-MWpQ$>xv6%CjS|L3XZ# zEzWbrNu8KcV#S-l;`;PLd;dOZ9#I*{1|YM2z1i#F>%NIuy*{-d;C^tYId^?;`z=_h z4(kznDg^_qwE%Mf)76poeq&~_R!5@{WbYo_B|#46f3P*@)YYahFdgg|DcgHg+RX0c zG&uvX?ZW&rETS!t6sOl|P0cI|`g5=pp`yF@>2-ZtcodywI5?~fc3KC!N_8`T4HJY6 z{5aD~0l;;qM+-sA&PW!5452VR$QKbMBv7U$<2ShT?y^qGSkz1#n3%NFW04U*${WK* zjYYO-W1-d3Cd1;={o6MQY9><vJ=<@$vBD6agWSMW0C0yd!05_WMDF6|YT;-hA<B%y z4@&D-%&)`twhYsZQ5VP2L+DHnhncxmWd&9^mbRaJ-Bx{Swtet`Utv@fFury>Ery(* zre{bks&Pb3GSF^5V)mgUZl3qet0%@JEP`zLZf<T&P0#$oFaJ7n^7IC3h?D7``rPED zWx3Joq;@u-P8s;-{XTO*&l-2HyRpmaS$XY#?RQ>5=~KF=(<7RcWyIIN_Gf+qimj}y zkOSZx&_6MIpTAg8z?bk8+4DmN^kcmbs`)FaP)i|#PAmea2$T#sXGfwRsb&r{_|;3~ zTihzr3V^GS(ZPV}f(!!_%i^eHZP+WZzk*|QP?UMsW0+LZD7i(NtwOqipUz_P&zp^B zxhMYc@IfAs8K&99<3;(}YBfZ*%<5VOwU%2HZE-HF`z!m>CFx1_Njvw7J092Tli6|w zYK21$;IBFED?$-ONJQ+t2kV6Jf)$7jrG<!LGR2Y2W@&yNyFFev57sx97iP(j@W!n> z<il|XXh1v;*W}Ywewb?Y%EeU_12E0(^u)}}Ty=T|qw*xCK1<cY@ue7;aZ0&7uLA{N z-DveH6NFa+6P3+<hh+CXTxn=IHf(am;MtCc$<|?ir!(jbt6#pohf*~))#wZ--rB?u zzS0^@V5gs{4Q_3a0d#^KEcbWY0CY%19OvSUBE4>J?vYI8;@r&L9YFaMRbQN!)A{|~ z7PXMO9ZUSz-g@wnr&bqdlwE|=#do&1UwrBk(Wupam(yX{5Rnm5>e1lJ>ii|rboP7r zyUXf1HHq7ad*Uijo(_}8S%R=;oihf0qW9|u9b$Qxnv>+&A?XbT3ZbK)Ox4MOtiXeo z+<{pCc%A(apogP;i-eYk0Ioy~Ail!rik|)gT@U{lR3JrSSV$L3GO8H9{=7&cOV|Uq z_+E!yb;fZP#C7fR1tkj-sx}91vyrc^u7b8<W{x`m!%@C+G<CFn1Ygh3&T*{SY@^9W zJYb98Vc`9pE&2)QBi@lgr*=E6K$|nN(2H*c$DJYFhm8xl<#Yb=L={aB%PhJX?B@|C zG$Y038AeY*y#JI<;dE-B;-d8^ayHsyQ%^n;Ab5=NkoV=6U!Iw1Vp#;l%YxqN5HhQb zibTe5ZE{oo&~jRkfxm}^`QV-e$i#H3LsmNwtE5BT9a-olAK(*(339*?u)A6%##A9F z7P*cYcXnZMZfU8txhVx;y1^FW)z#(I<psoxyvod}+@hfejk(K}{&szO(L_+ceX!M> zyM(0{U=BmV@4drY0JXV=>$S;Q*~>fIW^_NCnZE*h*9ix(OOFHi_D~F!%69$hwJIvL zTs!dUQJMSqK$ddF5ppB|f7zU?@TI#&EIsoGWZyp6koU&aEO?Y+>Gxr4t#h~w`ouPj zssKEtsHtgApH*u42_1TheMH*mbYn#++Pj=&r}K;~U3(jQzt~Wj@^t{Jd#KZT`Pq}? zW)d^Ai0>bF1rb?1p7@OMT*g;kBg2Pb+qENQ1y$s(0##8wygl6H3-f$$d*jN}&oTAc zb0ox{%u#!-Lq_)M3dv`6bT4WQyPMj|=<c)Q;R)qCEp#D<-omnr&;rhYWz-NYbJEgl z7(trd_5-{!wQx;x#<{!JKtE1NKj?RNC#M%QSuxW04lO=o66bc?K$WwQ#g8c>!u^7j zl6AUJ9{eWu`zJ_6uXRwng`{}iL*e<A-}r4ZF364V9e*_TmC9bL_q{LHKJk3vMh_`Y z*Vnw<OnTyT{~h;Wd;y4C{B1Z=iWu_WeP!ykHJuM1Tc)Q{DO|L&vizri@{cnaS5{Ur z(#t0qG;(gCKNb3Z01NT?@DNL0w)XqO85D@GabdQ@fes;(6E^v0K*l8Em6<`OqFDMA zUsL%Bv4;aXOENOgKz|k4DwDZ6B}+8pj!aHEwyu>$aRAmg)4M>tndD_jH8(|5OSB1W z5oFrF@8Ut>QG@1wBQF?&R{0gwASFRN_I@m-MM^2%vI0rvNoi(L_rUSkS#6$^+aBL~ zB`i}e6!Xf}Mg(yD!P@4f3oB&C<Q0NqX%9p&U^>9|Bky_)BuZ4z`lt+a2dxgNGcH}c zfDRy64eZtJ&d$D0#+8Ykq!|`+iXL?B((3gK3mXqeHhu5nBAzA<HghZOT@F0@#=RXD z0#f*6TiQJ6;irB$nAq)4ytduj>I~OggS|dk+b3Vy>~434IOpu*pVMbWs@>e`aF!E^ z+p(!*Tn9B@03Y|-G=_|gxS=x|Q2YK4#O{9U&ensSgCBh9@|}&HZ{J=2LoZ#yL1<-e zh8#7@<g>T`Juh7Q%D3Nqu(9>b#RY}eO-v9tf&0qB><m!#>ZMf<q^c{wp3LgpoSSd< ztM$9PWMOOIn&Sb-1P2Sd;(~hE!4_@~S7HyHl*wULEOoW&0+GBxUUH1r@GCuJJnU3j zjWx7VR*p$>#bDOQ*sZjKej*ixqBJsI8Z0|8RQX}-ErBhb!5Ru<DV;y=OC6LhhJgFR zS-ma|zO=f+iC?(cU|T1)m=goo`CzGDBCBS1aM(V8oq&UQc5QBKUb}h;exgP@Axqx# z1UV=PlJ?nUAI8XzYgV(#aa}^}wA@t=DZS()BDtzg{!)%0?J!v27o<}d32+3AAYV1@ z!fO+Nj)UFI9}Er)zu0V@^NE>4_L%jCp$kWyc<bzz$+0pvq)?Fyyw@XPHYza)=B>Bh zxOC|f2`d3HY?WZdlJ2DRG>6x(U*Fo=n!zEe-7;T3g)vA;8<OR7iR~hK#)ERZH~r9D z!}SpmA0<VR>$=56a&vcQ=kDFRG=@w!(?p}zC&`{O(b{X0tZ;swvD0#kCm|_x2_KhC z;aJrf83S;Zkb@o$SG$eolE$vfCYwZvA>FA?dw+KRdiRk1x-J%Xl)BczI@N;k>XV$v zW{Grg+`?suUAKO3cHx>15}I1jD+Euggx!gnGA$B2Bw5wbLCf7vd#ZT_002S6MKiMN zciTJI>FFRk3EYKh!He)6W?;F_xJlwr+3Srmijd*0UboF7lhdGBPyD3=6Qr}$2+dTs zAG~wi0584QXy`?`&pOpvWPvMJr|y>U_A9e<I86Yp`eGn25Vc5gr4BCrJHtVUMsp7E zB>Rp<a48UWzS+3CJda3`5y$p<MGE;jBK#W+fue`CS)ne{W0F*2hi0a;9ui1p9hZ-# zG$>+iW;k_3eli?O;OUjv`si^c0Qr|HGBnT@h~I5vGN_|18mwoFS|2B=oq9&z<Re#m zhxnf5?CmL1dV(sMQyA$f^AEoK^_!=3Sgg-0Y;u<uD?k2y?nW<d=d82QW1&AgKo5cU z+k;nc>)<(N%`bj+dPm;Ar_9)l@(a&D`}rUFL533xJ#j(419J}OpMbs3Ul9e4+s2OV z*FR+G4G`eZNJl@87?fW{Yb&YT$h{@GrbAn;LRJD#>Z~v^1LZmh-PT(S*oKoafee9_ z7)rq?o{@&oB~@fe%9V8to4p;Wtphd9Ms6v|{Ln{0mz-p{NoWxvhDrxvt`}CF?EQX7 zDl=8s-Q4c2{W?viOQPjj9qwRyf?OuFXjw7@t{oM5=q<efFIsBqA=Y&CmV0YkOAB*v z-M)L};zbrc@*ZM8CbRXu^-ZuPhFFUw#j>~qVBN+xxT|xK78e)Rl?`576WVGuqH$mi zwUgfl5q#kyXHqRLW4)iAda%Au@1D7Sne>QT8|#DC?v<qlva^$^orWp7N_B!GPC>6T zQ&3=tU;7?mpnIG;St0-WlFaROlCQ5eYp>ngnZu@E9o&4d{nF(*<*%q!I{Q15HB!Dz zVMO2B-sZ@d7cMVfXx4T&*RHHA5b`!#BVPxnbnP)@Sh9#6oS!BE^Wnv%*(<9nMt>#A zvHc3nlggoi8bddCIu&+C7{gl|2loyLZ>^G=hNHwd%xPtgY#~G`2!ac!UAbt9?_mS6 z78Y)>J0pfc9@i*9vxR|L^qRK)rNR{nOKTH%@7;gx^*3?R!B0aA7%6i4GGKcGQV0xi z2d4l3+568JS@-O`53STy)m_!0I>(*PKKV=@a%RX0%)AVyt|^PQl_f~BtSebEB+G<s zON1cUfN?Ki;M#zJ`@w)Me~<-BvS?omggC<qBqwkV=gf&ac8-;E>}vm>wW{7-)BD7| zd+)J$cF)Y7>gu=N`oI79thJu?EO<OlR?&H^`s|9aC_aN9ivk7lI7QGH>$+?Vd5a-< zFeT8Up+Ug?Z-4t+w{G5~t`IlP=TC$$TP@R3oq!X9mBI|A@k~PG60t#Xh9xLDL`{at zNqUC%Ann6sP$@L2sbWK_{8_nDM#5em8fZ2)Et!xs8w>}$5SM_OWoGB#_vKgm*;I1| zkX$o=2+hw$*hbg#{aD{`5LoqrS^ikJNCVpr6X|erVbQk%e7yMLM@U@&wad$zNU|J^ z;1p#<a=9$5Qwhc+hI<BWNg9rrR~SB6Pm-kpDI59NT$`p*V>mu|UZE<ZF^K()R#i)6 z41@*EKq55-jNOV)O-GZYwWvs$iq@%6F&UHQa}{WA;hhCvLre#4i@Ze}I-T(}dihXy zu(jf<{TUq>LqCoTPNZJ1ig7i@YyAGC{4(dsw~2#JfcWvG9KGBj6j7xff(!{ODHR9v z89+1(0RYOK<zGh**Q^HULrvG+2hB4bSs*4#qfN3}DS{nQtH;5?JIo)xJvlxJQdPZJ zO7Oz`Xptrh&s%zpw46k9dXE=axFQdZkuI#*7cHSn<&I$~@$58J>8J8sDzs%XJKji3 ztbKelXn2t6+kwK&8T_3JkXm>7oVOV+q9&Ou%nsF*GU){xDrbX5V*OOIL|T=alET#( z!8-Jai6moj;bBQKeCAP7JqXDe1NN1QAX+Bx%MilFt{8{%4VbnJvB0_}A^rs1Tk0+u zQ4%0B;?t1M<P(+XlcjNsPwGABQOBS+T^8wscCMx?nOZffo}F&*9K8PKTMt9v`N3~D z2iO@jdXCxwB4EOQ&=!86>mMng=P6E#r)XAkZdM`Czn;Xoci{wjCeM$2>Jy*%=<^IT z0ZBGJAMq!E{sYZ~Cl|kc5BNqL9Ot80e~1}=fF5}cJp{jUv8(^08Nx=Y8kiJ7t)X5l zQjIoTrOe7b?<955i5wP`vO~=H49_doLgmnw_W2N_$a$fpRZ;WZ0dIMq(2M0RVhgq- z*+>*<6sUfr(3?Bn{AmZuArcS}UzTeCTR^10_(p}EQ8L#D<;Rs+KCP+OfK+fQ*ra%$ z9lzYdl^Z5%fVT`ZZ+WqX|Lk%22V90jeTf1?AWqU@%>XEtajHd+viW6d#FC9VJyor@ zrqU^VWhY3<lxkvnaNkfEk1(yDPN!!k(?9|cC+r<SClDUzHI{&6%VN>Y%nYX~U#Y~| zu`!f$rpDvjJKG?Lmo^s3Jf@D)R3eHqIvqzIwE5<4ZbI33UEurNc!d0cQoZ@cHk6r0 zv0Bd;%Zt<F7!QCF5>Joz_efxU`tthH>@>$Xy!P4j#QMTC*_@fl6twbAKZL|2W`!gS z;z?*c5^JAI(|6b>s>~Y4$s_`(^FTxzQML0Zwiz%Qsdx}7M0sRL86?aGT8oAcx-kO2 z9ny>CtH!wl(v=;h1V_tvj6_phWEPjJ9_iFH&o<Z7OTokgf8*O;Ut7l2Awdc|Ut!5x z3Zz?ogUUYQYl%T17rscYW=rvnaBRd@mIOD5pJTX3;}tvV>p`qa06Ku3H{N&y7c#^u z#^sIIzt2!U`^<Hr8A+p}sghuRnOLiSXeCc!$pB;63E)u|MTMt?y}|WdDXpimn1o(C zZD6ZW#>|apF$6A_g17*atVhYP7@A;yI^o{v{>t|Cq}bqR1jp#T0Ls4;rhlgk9{G-G z;4f$`D@c`<EEnbE<XD;UGO;k0+NjYZ(;=k}l@RU_r#3mPKG$Q6Q+pTD_h<;=5k<m4 z!2F-AWY`gg<lOn--g;ZP>M!P=fR}Aq&`2;0=y(O|dVSSJVC&G5C)U@*B2|$GIv))b ztMlNc)`YE%k;3Q@<065@(w7wxv<5`ch5|)#AJdyZGu3mfIT6rlycKw2SCsA~g{9fG zC_RDdh18HHCU|@VZKVf~!DB%`!<#DW!8fuJF&Akh{lmwd3*-o!hop~q9Ik<1r(TF6 z{G!4guGpyOkbov8L5O$})N0GZRJZVg-j;3{^c4YfC1mraJL#SKB%S)GCgE^usc-!P zn{AJL*4#hU{i|sMz31(8G(Ujy<|)@cVDb!fhZmGJPYuH--kMRUlzAngFsn@L*|d^3 zu+$E#+$VY)@0gYjQ_Cr!>bK#)@>1C(5Xz@X!7;>}TIBF%w8<-ppH>L#8_h<E(H49I z!E+fcP%=rSN;yStBKnr3kOpj=58A)9#D#9i2_X#l&2PVaA<C6D`dU!cM(>wD6Q7^b ziOH{zmPW6nSSUAEm-i9;aMR5r0_Gyn-#LzccT)s<8^nwJI;Pgo{NxulR+mV`0?@l4 ztS0ai%FQDf(+|rn-+f7p!gSxb{pTEL7=;V+1mJD5jglXbB_J554%-K?UK(CjT1X0& z-5%f%Z#0fK9G|$>5$!{e8~=p6-Z2K8b-=%Htl2JI(SkpzMwJJ84R*74y704aQj&9n zL1E>}r7<^*u;U6>8Bs}Pn%>T^?3Cjj>WfTFPbGnaxL(+!Ic57H_~|p_k=;_a-i^$q zIT00Ib!Ly;_6V`JdlYe{!AH3gI+c7gqzLN5a&jP838j7sZ5DGq;^Bjh!^0v=&*Lx5 zVw6wp92{|k(?B`(XC^&Rz(e7dhVh7#GM<?5Iw!o3*WYsTr2Hf1H0;+@ihzEv-JtB~ zQMqyJ2w99~__VWqcoJ$imQvB&@$s#@Td-*3{my!3Vl^FWl}nlN$VV^DFQk*H=;?eS z0;4@MF_zEe*;()~LHFko=n@I};dNA&UcA{AHig4;QtRO;o}NG&LS+H0=r0nKI=MJ7 z_y{(FQir9NkEUlIJ`$ZaGZ7Cf(@y!TXv6EY>>FG*6AN6cNVj>eG+1V#$@`AAX4@!^ zdDk7HYnXhDK29~}6$pmwA>#0_9k`sbnixXlmPA1>RfqzJtfGoM0a;7?Ca}zoZBUhe zJJ%c@XOX?cnB*J9v4W-CY*8u&)XaS_4=NQMB)faN49&v)JPeRrE)V@9lbPX5_YRLU z)6?Q(Sn>u>VR_PGRjCFt^<vs8YQ_n#)7sqa13ow4!fFOt)*a8K2ea%EsNPl^R>7MP zfRBen^VEIzGG*nkSBJZtQLsD%eEhZx*3ETawvIW1*N^Coe7F5{xSg02QK((kez&{6 zzV4Acxbmhi38BL4XbRFgfu13D=CL*d=IU9rn9q-4d?k^3G?76$%?HmHJSK1Q71~B5 z+akfrO0^1s2g5*fzS}7iE~!*m2&_<&+N+hSG*48RK^5yv@C1Mkhmb8R#d2m<vW-En zV!kl}1`m5CH@P-KBj~FLR6{`kYKQSu`J(E@vi5xlye1Tv>CL2T;4*3B_|Cy|%m<!= zUV$#prUlw|AH1M^l2TS}CT%WXlw>;16P-o`Lb|S0u6jK_dV@_^6|%<&h=J)PzpL1S zT+t!SehX)5)?t%a8?>Ap-}A4Rp!V0i;7=|JDRF{<)5L3Z48oYBC&FVmN_{^2fj}FW z7^<NKi%EJ0gC%B7(i2$CR*~`ayhgicG?is;IW}~ix$>2-VilkVHF0@zPvx@lbR4T_ zfGAfcKV|m2VvLM9U+Up#??8UcNYIxmRHKYCI6P{zh);fIF{w!5wJN;4@5NS-E|A$_ zoI2gXA}Vr4JrI!fyja2)>B*@tfAt%|Ch*V$q}HHD|JmoF&tDnP=rN}rAdK*STVg6V zj|kB7EGRwQ+GDLC^LqBJTk)N|DwJLL<1ll6?T`O4%zT)H0D4cBcmn9(?;Ln?-Tgff z9OuCX5ghZ51N^YRfBP7{KDaV~4s4FjXvggYHUzQ*$Dte`4I%=4rwhm0>*G)}lw$^_ z0mrAQE}k9b3a4GtSP5bZjj?%gh|>m7ft8(L`>DtZiceXMCrhn&`ypts9YO}#(Uxg6 zA+oy`B<G(;g$;2IRFmC(3x(N_F73Z|H#|9rDyoG^`C3p%ahnFm4(Hv#4{Zg2P^STL zV#q5A7+-RnC~XJeRV|mnwTJl%4X&c1NM0jpTk<r=iq!^WZHyd_4LXD}r1%~2-r?y- zlAKdAJx;Y6y!cW&moFcJtOVx4I#Srgt*b0y6f{8JD6XUuv*Xd!S#ttsU$dS`M4w$> zm>C~inn}HQb!BA^zIPH|J7{uoc4lRMPWhT9#xsxJj_P4*yx{*heVl{KxD7Is8r{?5 z+Ua~s2!1k-hGcg#Db^_g7ntJsEWsXDo)%a7IK|=VJdz)Hd@1T!?X88(lykv}V_?M% zm{-wQp<IKZ&TJtgSk@7R1(awpn0P$3VkQQQRa?h6?)1Ej8<AI0gplQfyN#*k{?TkM z4-+7jCYjGpUvVI0H_BT^`7I!eh&rbPfoPQ<{~AprcbT_R7NB(!iZ@96wMnN2>o~EB zGr3$UZr;6ncXM+#llj<3Kl19UuhlAr%U7SmYdk$O1MFkDz>hMlAlnk#hWuKRn+akt zix_1i{D@xx1Oy)P?W%WXMvFU}fspRk7q$>1V6XydfC%*C<20JOOER~l%BLDSm@$rA z?}z52EBD+wecR*QZ}MPp;X*c8Fef8?aCBq{Qm%JN&ev;{S@n=KD-*oy-YkAqH7P)q zm{F?4j4^=c8w^H&B5&eRav++6xzRn%!4}Z~EPNfM7>(!`fuMn^P%<L0`;zQV0<Y%f z1*j<#R2A_=EMXzCWpP{NkC>TE7?3yQd$SLT<B>-Wq*Fa38peQvw%HAMpE+jsLye`) zXliFeidOLiIo(gPIpBM~P{fdc@WXQPqO)FP+GKp9^?HQ`N}z_IpXu``>jof*c&l5~ zY`v&1vLNuUGtJm@aQSm{V`wXlo4Id>gg_)Nc95%*G*uH<8A0p}TsI2ed3;BuUY*0D zsf3c`uxI+YliSq6Z2NTw{R1J+hnYg^_@NGrE$vetNyK+c67b>X!Rb_w`S6VV>ze>S z*iZ5+!&BGODqUXGCJ?p^d$}qkf82zLB(r}om+Y8uD?!&-io7C4@)F4YaZZcL#>>WV zq|Q5xtlL-S@>k6-qZcad!;qEAssZfxWKbx$!65p6<(EBh_iErw@|Au5>%aFM+(j2P zOw2Lj)+@82pZ)|f4VwUF#XQV_zT0OxO6pa1=8J0o=y&0wsx(eF4^?IX(DCKhlJ(BT z6X@B`$%y^6fBTn7)0&%`2h#`B<B5m<QB9i<$$foQ_-S`;vv}KgMxldu(dbEOk?1ZM z3tZ%BYKEc3tN``l1#-<wju%&ahxNe*iiaMo1CHmM;DzB8MTR+D%rBxGRXbON>CKVp z?l;kF#HTmeK9zd4z&ii6Shfxtyz&5LU@PcKp=bru2Zdm*;kt>cqm%zytx1$58Yvfw zFehp)+%xdT@&D;Y<743(sin<Re9gu;74&fiNU@}&9iwG;|8Qevk)0iU?_d#^^x;W9 zH7+^J*_jNGnq;-Zlk9WXuR_8&DU{Zhm!R!(K#J_40|pQMDFue`<)eYf$64(>AU#8W z@}(RwbSk|8fZ?lEz;$d4&%J7(PNty52)ah2$Z@pJqNP?JJOmA7tI!C=#*3{!<lAa5 zx?k(3!3oA8wxT@IyLY$X^0s;*kU!7s&`^F~V#*YzjjA(EuARhXDQI}LFL1osSBj$W z31A9<el~-Pnl{RTOltx0oJGJ1g~Aaeg?Em1WqHFg#?F+J-~)}SDbq$Qe9la9O{kqN zc8%iNgt;v%17n8ob^NL<Sf`|zo1b4`Xh6tVTv*^wd^Opqq@~hDs;*@zsPsAWiZjt^ zU3>-bn)hY8ScGA7dv|JT68aNCBu9bJqhQw*3i++A?Js}zYn-#!u3f!(^A_Lu+;i7+ zCr3|Re|C9EVN)7SJPMfQr!V)EL2`PEN7fW+5Cu{?f%!p=>0yt+gv3r`7$m}D(|cqw zlGqJ9KgsQQA9o$PnV7_c1tjxAeWgh<YXu)im+d)FK5CPXg7x6C;7|<K^`kf@-(xQw zP_B*SM(Vlp7F1-dR4nwvXVX)N`bnY$*eakI!W8e?{9*OM-0O)z9}ZD@jVb}NnVDLd ztd-LSRRm1+h=~Ve_bv*0!(N2-zLtLnLm%fQ&Uj1+>;=5LSOt79?coJq?H`maX@DNy zc`Bt0b&<+urWsTJ3gup&Vj)mDSO5_s2g?9^6{DML1o&jJkPeZw6`>^vlm|Fs$sp3i z$ZD2a!7Lt%&5&PlA#0)!(pAY(QN>DwQ25A!;JVl(8ih`+B2_pRpMc3jFEy3Ft5qV# zHVP~gkhbOPwGb$#j>1sTb?9o%G26|I*P$)e>{302>QYhFSSVlGU!sK&0kgUXut#k9 z+{@n}eEIn2j~zgRT<2gdC}3v|b9~PWW(%|ykLNfcil_5h1R^zAon2#L$-?nfjHzZP zmkb@-@+F*QJtN4jQ)hT+N}^KU0jdzNlgnNj+;AA>@Ge#J<cPutuZkS1=VcKm-Ur)h zqmVd{nrgJJfkv~Ru!E03sIkP|Tp@}+c;l_x+q--Iy%+Lhc_^oU;`4N-K?12UJ+ksr z67R2BX|s#uz<58<{)61<NeLHEC|?bK^-Z!S6qLKz@8TGH{<&v<@{6BiOv#A#G%f#% zCxHG!Cgg|lChv6EdtU^{|2c>dY+=63i~@q-$OM3L2i3o<NfDx4tKq%{V*vq!J1eUX zKlDUOj7*3G6Y@jI(JB}h#s!6E-FF<-OV@@g$z?x@9l;N|0-~w#)f`ABTB23q?zmF5 z2JnKX!m_~?syrvF5~VHG%mbcMv<(s{iJMO&0v)N9N|V#myr6abS$nt9Jh;Bz=|ff# zhg*aS%L6iJs`$0kSS?a8vJXq1zmgpb4@brW4r3%=(vziXeRX-EP%NvqXz%nmTP#*8 z>nkfLTDli)d102e(O~Y2@A=Zo0)<HN0xqwt%uL~Tgb84@5aXG^3Guis-$kM=4V9Z& z?SyaLRpuoQ^2k^-GEwcGQBCQng4$VZk|*l-%PsL_QenzMiLTAoi!lI)q}ga(zjlRT zQoS5RLx^ugO}s<o7S+@7it)}dRi!P}!W8|TH(eavxK%wzIgALgdyYMf4M;Z&v(t1J zfJ`P<sdDwwDkuT^3e9$=xSW5Xh>R8v0^JrGssJ}bY20yvctyeuDDyVK0e?*cbfuEX zB!0qlVsjL6h5EtN$Bl#`KG8Fn3hq-xO^65akOIJ(NP@;uV&wgu!y}xiKsH{(qo|fK z1?v<GV6MIP>i53>jo+<SD^Fj)j*um0l2TeN{)68?lbHn&V9!hwY)Zo;QUZWb6aYfV zNpsc{KMYAoH`8g{tOz>IOT-g{;RV&Km}+{YVYuJPA&zu;6G!#o;XY57nw-iP3J^TR zUK$o(3)ZGD-nU)C=l&FI0{+5(F81_#uf5gXx}qPrznme!dI6d<wsW&{46F4UP)Yv* z^e`rLi}^T(v}|65u>m+5@kW!3nk12yNKGp38;Cn-?`>A1<Vp1iZzXG((G+x}&YGoH z^AQ<QCJX7JBAW0C3R!@(Io(x8RxsC~uC&;t?t(K_i;=mCJs=;gxKdX45nUV0pm1ut zZ9C%h^Z#7N<9Jz9yzkhALFaR&@VSkMDf-IAJBpi~25&A41#@gnr8#4b6`jT*tWqq5 z7X=x4IxFR&ea~8AM!Sjka~t=wJ7iQ-g^x}6TrLkK$jU^w-Wbdc+Y`kl8v+qcRKvK# z;T~9N?=|`t^LO8h4YP{15<pes$K!4nxHS5Wegb6dYs5Ooc`_P7&n2+UR%|8P9+Y3q zisnzg9u2(@XO!4b8mwUTNpWEq9ir3pC+qWJKC9|T_!(;vI3|<@I%3kg@q`V{Kvi7P zkB`ekE=hk<W|0inP8%NJcVB+RV+a@W!yJT0|0|!3&rUjx9v93bQ=`X2|HuG6Ex)th zp^!a^UN;V6-``O!lnakGU~K=)Pkrf`r!F(c*tLR;SS`s58ILD7`4IMiZ%Dz(;XM%i z>VFElC3qd|T%&*TPub2jI2A-F>_DfP;1;k^+5b(lMjC~pH5=EN^BXUk-t3=B>V>*X zxss&=YIlbGAQ)#Gu74NX=Ag~uH)~_%KJ2Y*$RHq-jki1`+iuI1I)@OMrl4&**rbZ% zpo&lNFB`o!cX;sCN@_NvqlhgJp6l?z3aHQV6`gLq-GB3#q9F)qh^Qmpi@B@0&}!dC zPjW@<0#+&YU%Ai0aSm-7ByMmLat7o}CE|no$9Z7i&AU6r8b=QF_sPAZ?BtZ3>zEwb zygmrW1AI?(esk}T9>Xre6Gjdbo-jSBju}0L{5Pk)<9rEzy2w99spq@_+?!@j9dgNJ zA`0{@7Yh-JnDiPa(7r3B<Gt-j_4ur`7gy{7;SMGE${8+Mn+hn|T#`^b667*?x~g@Q z)IxF5@x11$H*qrSB|KQ}Bj<yM$GQ2rjN5E9l6?@v1MUjYmlz0&0eG)P{towF`TlEo zLqm8m`~BOuZW$jJBS8*Vo=Yj7Lh!=1%2_r)y_I>Ar_gLUeI;&pgg&K2VWaO8LquSs zr&sDNwYk$J`hkpPY8=vz1e7@I`4;S}a+TUxczNaBSNp@^B@^mlt}-0hAsg!}^Yimk z>`%riK>N{;d<5FZ8*jaZ>vV2*7W(|=-CLCQ5*bFhxgn@!g%a}Tew>APaP7`EUIGw0 zO+~;RGH^x9p^KRF7_NpJwDhE8Z$^&KE_y}=T9<;C^>VogX`g&tEXv8L8D#z^lB(2e zS+@7YTi$jb^Tj*5($C=ozrg$OvG0T)Rg;;{gA;`SI4{i4G3D`CXS0&K!QD>BvYsrm z*N&Np4M5rBJVCUYx;bDkFVSLs9&&z;Z)HBO+#TQ`m@7F-c|p_;wOqw*Z2ribZj?M` zqyE}yt5{o1@|O~D5p-68ClwF?FDf-zX+q2)<{KZ<vzV{maR7sex(LaLi~zd<OMuDG z6!i`_Z!Qy9l2E)OZAvzauI1{OOVvCG3KVF&>nLz!JD8@0iI>YGp=WXjvc%>EKn>`t z7@6Nn<dCxvJ?V=`0xt?7VkE2QopvJTi6U1<8ZiiKP7i~U%6^pzWS(PKMFRzT--P`R z`oH1i89g{2!*ud9!e_4pYOFDiU(Erbuvjp|y*<1G{bs<2>2@1v0oyrZIW@8su@YSv z(Ii|3z9e4B`ZCMXSCc9Tkm2JTcbhGa^@pq**#`b*-M+%U5r$Z&*{oaAmkuSOG^T8< zyjW#oK>wng8TqnS-qn{R`+)WH;6WasS6LCJ7L{NceC(wcuudP~CU5%@3zbJIjnJDr zkjK>8ffaO7U+}o@!-L@AsWhaq#?N*x3ZMyQ^#!(qE$gE%K1Y5(!!g*bhIfDBp})X> z{&3w&8_n>?pFB9xN6+=qYk~{T?T>!FpOYMFhMR@J_%Ek1u+PQ6byW7x5C~DETaIKT z+H?lu+631EWr#BqDi@hJoi=bL{<Jxd20Tv3I@)3F9ix1h6UoZ*Ik*?@S8L>ZuGZ^Z zjIF@8dr=;)0;<}cYvO?2UL%(yi;At3Qwu-6Lo05OL@>iLEOEvzq@&1O&{nn5k`bM| z3|NErj~WcXkz2tXLM#O!%9c!~8V^jnP^squRcf?Y;%>7usiRz8)t;v&508#jvld~w zF}ZlTH+BfY3if)~+KonYVR4BvNglWmv&Aqp&q8k!dgm!r`BjcI<rCng=6uI}e|(ZH z7V@b+*#k#~d^R0BOPn@3wK4^yjt=(r_x9&9RJEGo0q{xFA-n@KBr%bq`so1dShZR? zvZbRUBt#P!9b=%50W<ATR0!Vjk;tZJf?P`3G($^$B~r2+RH}2s2gI<d1F@DC7vZ~O zy5P{BGZ<YVBN>9YxxVy35UUjaHo;SKG>U6;dIpV)UwK7%N4{;bT?L@UahLDEcyyeD z&d#BTt6QRS;ShueXg}PN%!I?^JT_LXg%uPhyBHRhx%-vZ%YCx>BBZI6rA2}&Jxn4B z?R0y^VxH-`y|sO7bCV-Bm(L-<!eM{w&fU4W%;Lh*(b37q#yT2A4A#svY@G>sL82lU zwc3g&2o~tv9+Q@+ec^!4#4{m|h?vQ6dJh(niK~v$eidO5p;qrtPtPz008n5ktA^vB zOkBFiX-A_w*S*C!T+!#=@rCc8C-~F3cOLUrXe&;@5l6c>tXM39r03@sn1a~3au8TC zSLT$GMC}K_&8O%MfIGVj|Kgc9ZkU8ehL5KE`SnA4N)UMf+-)mhj9AwcF`zS<X?X5) z*(^#LOnvqkGGq<ggY~2_;*~4-QgW2B7F4`q;Bg@BwSk$z_64_V2#>o6nOby9_?Yh^ z6vn5x5`VeGRR&xU?QxQ_HJ-hB%cCknH#5zZJlBBz0^n%F4P;O26Mvw8cqq6u-eXoc zNs>EmRA`!+dmglEX*=>;YvzdBp=@J$ul>0!o5;N(7VN^(?}$XC%~pcwSPmEliX)+= z!~8Zvh=P-ix-;lU&xqlqdaRbAW9UkStZ})Gcy?YJ%9o4XP_-J*BZ#}z#4_XonKPo5 z%Y|=ysr89^gUM(McF?h~-aP`~UUqJ-BW8Fc(X;f4gmR2eMTo$C>W=SyY13VNN}H*X zdAJ6qlfTy82!O~=7&vDM8TnT`1m^`A+xA>~1b!Vooj=ezr9JFjI0YbZfAc#p<HT|Q z!bAV)E|5Ui=0ZRD@kdXim$-8s=<vY(@J`Rm2ox&)-4g||k;M4QYsrRak`Ji;|4!e+ zI4&+O{Cj`=SC}yPEXarrToM}ehaQY4H~8@OfFsuco!<}B-NE2Lqpy8i@$3C(@K@;X zW3f`DZm3H<8DO6_CNK(zu^1zQdRz|zhAcp_LLduJ8&@TKdK}VoR6&-C@M$WU0NQdo z4jt;^d^>qv4kzUi8nhpNzcHcZeRuCBn<v_lWErZcJ7IJQK_bm2h66y2Te-Xdu9DeH z8#61*ihZhlm7stFA=wGQ#HMy|RUH!S6G6wdFLD3lwdPOcLE`Dgtq9ZR=p<Xg^(%fz z7_5xk&F21z(KL-c5~V)Q@$Johc=O0+Af~Y}KYQ)cI`kd{F8P!MD54RHG(on(*x@|l z^u<!(F`=W-e)4FAR>-3z#hAQU9M9&X#m=9gyQATgT=w`R2X<6ZL-7zMVS)etcV51` zdr+>m-n?}ee?Mo|*7gqRxt8!Jz6Z9)@yW5w4=WBJ*kR>MvA8(gIUmi@CF4g&lrfH! zb!VgL`LBu()avl{HQd_X0pGMu_lffqc+jKK>`7LNp!T!2vT}Hm+uGT`d3*E5&D)$< zu*112^MpGzrBWeWCLT0Id=qOY3D~n2z+M1u06O<KPp9U9d~uY`G`g$L2y<_Dq3i?5 zND#=L(Dw(sySq2uy74<-{ran~-{4sw+4C**B=_V2O%7G=C7s-28k|vki}?ynWQaKh z`N-<(N<kr)PPeUcJR~<X>m*U&$EB}G&vkoHem!nQyn@cO0FmfDPDV06v3^t{SM@{$ z6nq&Dau+QI;`S|`IsVF_;zHoK6%Y3ryBZN5|0YieKDUL9BKTl|kFMEZ<p%3IxWnk8 zK6l$k_p3M9a=yDjd96M@wdl@(OUxb~(ludtVL2A!g%4K0v+TrLP$a~73i77AkzmHK z1?}#!L2NNfM_g+VLz<b-Y{A~<Hzwiy9I=@NBc|&nv(hrk*2u#fIJUL(;J{v8UgqOW zX6M$Uoex?9AbKdo-Xp1fj2s^0RZ|^LKcsPJKT+(CwV<3=jlRJuy(9O*07_!%*(AY$ zSBkJDgiDX#64qnDGLSUaVtyPQAM=gQ<M%hUgj*ChsPJ2Qk}M92*(o7X{cOGw7YU&S zCjP5VGxVvoFQaj4iWaeKE%Q@qi7Lqy6S$O*mmH%chHH;?AqLTK6TWwRoS%=6ZsH8? zOj9v$W@a*$h}`BWcuhN<ZZtf(Bw{1;4-;A<`n(q3iKoGVLdO90jRGU{n=A3D>#T{z zU~loj+Mnenmu<i%;j|gePs!=1(`~j$LX>v`VSbN3;frO|C|<@3ezm$$%mL+u(Erwl z+7sCJ+3<qSvZ#)JD7k>C<^i7vUY@oQv87NYFU6Mg@sGZwA}|;Aqnk%wzC{2{`<~i4 zw7M_q8y>@bXn3I_Edo|#t`f;r#cI3o?`0c#>4oPxa2N=N<D9|p#6y4K9sVJ@VPNBq zqVwR*VDA{cjNWm7jKA>C3SMw}0>98#w8K?dQ=V7E?r)x5Jc~**<wS(oz-E?=B~XX6 z0Jn>NBor_<hpQhjoW~aW9jq%qa)j&+Cz&KXhpVI{If(~ph2}Hnkj7Ih*BX9J_^CsE z0PYW6*-kzIXmGJR*mPUFga66dCc>sFLdn9G$e`mVHB!<#!U{a*&OsJt5%!7cql~Gn ztaf=Kv0bTchK2ZfpAQrYB}6J<o^X(GujR#g^TNWGiJ>lEtkiJuBVLJx19(N{ox_D= zfSgMn+Hv+!pfd#9M8qU`DOMmQO&|jwf2~g8s$8Lj&@l-0=FJ-~fA{6>?XAn}Yh%e2 zV3+fIbN`5MX%o_oC!uh-hvp=ELN8spv>_c#P`mjud1Rs{I`u926n44si|85jMkO@E zGtzR^_qCu0{%O#sQUVM>*_9nOc*dR5n;@7wo15TgtSrvU!{ZZb>(UiG*7D*a5e!L8 z)*F0Wk$of9yM;!lay^q`P`H3|+tR5mQXz8!kD(4tAs$5i^`nU);*ErKaJ7~T+1Flw zy^PHei|p_3Q;@SpwH<N<Qz`_e0%7=5&y=l;0Xa82BebLnzSMohn^nd2wtngI)6YH& zUcY+f@~f}C{=#$5>05ge0tekJEUvh;Tt5_H=DVH>lb&wF2&DBYeQc$L&GUy}b5L;2 z2{WQLwYfwMHXt<M59o$w!7>|xi3G}d2g_%9WmVHP5-AqT4taU{V1Wedadh$eg1v{g zesJXmnBFf7*7D=r2Ys=d(^u3K&N-|4X--NfjGKRyz!#RRVIbplo0i`Ij}D=Zm#6SW zZT?iFj2r7o(0&lUyBDA^HB8x=U|d!n`v|^yCn%*<1p*PtUa3?@_8#-tJBQH(nz4#m z0u*H6O<r4fp<1glSS$q3IdNmm7;|zo*mFd)xt!&W+72fAirU8z%ik}SjJ)GG=An2A z@Yx&?S4Z}q03{z~*0Xjz6p0zYv<C><G|+90bD}E3#LdW_XH8j1jj~x3CDo3~HAaY+ zTg1!<tPYi<@>EgV<+K}{^TZq--iKr*l`DL|bFZ-wY*!THi))>rGMHIfj}B!Y$Bz$+ zg{>gc;QSsZ)}iC3-LmN{XSrD>N=1+!sOj6_eehF86Ult%9%>kvScE(&TV|3z{LwOk z5Dtoqa%I=hPnd6|ViA#4_oIWkS)Tlf2DtZqxRe+;C9lIALx_p@Nr1+Ru(L^WI&`!W zWUYB}pdhB%R9MFS^udplxE^wO(nTz>a+#F+$=~_f@1EN?9%i(dEVX9uk9{tlNk3vW zda2yh9)*XVQ{eVqx78Ja{*ArpYkN+hzi0*ee*aJXyT1x4fy8<|^z0a;qwoaKKg=Zj zP=EH^*5JR69{i&RyuTjB1UkNk)Z3sR6^}NrnC<^Ubx;vh+|@ul`x;6t!n-KbTk%V_ zQshne6IjZt!}4EYL}48rEiRSgho~L!=Kl4F=aA!RasgJ>#M;l5AW0N4ak}!=U@kb* z^?DQHji4%rkjXW0rL@Mpp>}^Av5-A%Z{>yddKkKRRZZrCmY^ud9bBl#i5yfyg=L8+ zUSS7SBN9)8_7Qn6RDsteKm-!?R(e*Hph~GkEbr3BD!`whgzf$*^OQ@-47~1?m7TrA z+qduV)mN`x<7jumO)lVi9?DWkQQekgyV5vGTE&n6;gzeq`$t#^00O*mw{G25CTJvz z@L#Er+u7b(T$l$~L$<j}Sb$P8Mi58-v5?E753{mDRVHfLC`;H_4Ga_2aK#nI)66ib zTa4wzV@f6627>Rk6yea$?%u+}oO|mTJGvFN6{K+b7Kb{nDI8rmK~pLGVOUC<Ys6ys zHe(c=Qk#|`9iQMV)DRfvQ0Mco+}-UfothRL2gv9&H2jMl#a}4bb>rqOMj3f{us&_x zIXFR@t(ZGeS^F{C-(jM`@&}ja3uWvp@(ti>)3XdHE>K*a$l@$6&S?&aF4jkmoXI0B z1=A@x!REVvaNvO*te2;rx_0~aZNB;=FTH5A8Hx!|IZLz+u4e`+OIuCUykdMj7Dl51 zkbofu9p5ln6FfVTHFSl@6_Np!o#t~=fWsW6`~rFq>joENS4rgjl`KuSmK~P_YcN>I z!Ezp5x#!?}@N0lS{GG?YGkPN#eXPo%OI|czKke{0Gb_Nj42<!@g}Zp)e4}C`DC5v@ zr{KO5@a&?XH}tD*VzU3Oa3&sk%PoyDEkQZ3)WFX~z+Lbgx2On#fOgfiN=sEn6H-0T zd}p1C=4Sdu3YtOghsu?dOW0<qvM1di%*p~3g1KE8h9Bv{dpTiixouezVBt#c&o!P6 z2{z@6yx6uDQBOjLykOd3WU_(qt31<PC5q59PWiB>R6IiM^q~|5oSJCL9k*qr`bsiv zJSt+1m-An>;W|tso}C>}O;UR3fGMOz0(0@|VmWBKo)cv#)4O&sQiI9!cxMm;3hxD! ztQf38Y6WLB6BHaXcrD|^cv)mE6XY4Qc&s!}t#1eUS3YSJAY`-kj2+`YX>TXHU}!7a zkSQaA>}xNm=LV!ZTz&1BlBVoQ?#PDB#%t>S>Rb1B&>jz}h;m~UrdZHeUv6FwEi{cI zGmzWzB|cjocy0O;!*qn5$Zr3QZ~j5R(SP83`Uic(sy0qP_k8r(4GbZ@i7o5%@PdCH z4WQ=%pa|SKP_6<S>et^)oKzIJz1T-!NkX#ubARejK)oXl$Zq5L^g$Or0rVF<TRv2` zd)vd?PQAel8@<3^`=;P)I9SX9o?x3pZiFqKq(G7^abv<S2h}J&6wWBV2QgRhd7A@+ zRG}tL6di0JC?s*%LR~Dy{IiC$2kZsup}8o4pGnR$;0kk7$;ZWy@-+?bLx@lkr=dpv z<PaQ!IKNBu&2n>PIT$)La>qc-o?p?T!L(qH-rd{h81~JYU?_NNX<?qgGv)_-JxGsp zlxFZ3ZxV3acV4PZkyOgjG7i;Shm6SggaUBQE-qx~6rQwDu5vdCuuzgFIhHMyX`X!c zy&e(-?CBI>BBqZOj~z6XO7R?i>ahEB#skFp!FT|<a^gsCBBE+FaA~0Wuvw5<H9I>k z^cg;bY~8HYXC#px8;?i3EgT$Gz&%)qwy|N6a0xwsb#29U`uP_8*3MH>s-Ka$@ic1! z5HCLML-n!KQQUef=_T<N+Jo`Np=B;EeM;i-4QgX0Z`{7ah)fW80BX0|3v;TY5l^D! zM;d4vFFO_sj*6KX0{xm*mZ}S*N$`RP<pE9HQgg!D{C<D=#Vuz;^GB{Xo#=QjNya5j znTSWN$}DUg9vv`*G!(W#u~6LE-BD^~vvK?O4W2hOG1=_&5dGv}=1EpG1W+7waH_0h zopGmD{1|l#5SA$wvUl!o(nWL*;^K?TYtKFV3=;&MbQ;Ffab)9-W%7G#X(v;bGl6e6 zg-@k5TUj*4KsdZTc@7*PENkhrjtI@ksvjOp$Vq5qa9O=xwO~|)d{1`_y9qkF7=4lY z3LQNyf_FwQ2zI>tm-b`Z4Ebuhf-V!W+n}TzmL^)okD_V-AfqoEU{cXvvF6M}Z1e_` zH8o@mHgeyxn^M7UHnMB!PmD5h?^wz<Gf^ECzufeTB(tLtLQ_?7uQ4DX?=U}I|3p-O zOFWfdK<i891DBzy!xqp-ex68+`MKr#wja4FfRcmapi1X8!Fah3B$8u$79(#-GGxU7 z^5pX1&RQ>B?VP^vdQPNJqZONV1IBEU2-JAsAZ=FlJt~hHJ4mc8r4HkaQ0;n;0tv4S zTo{@*id}do4}9%rCK**_=x_IK)T;KFqy%$}qGNt-ZPhk>N;tkikM9SXdo;%U?o#Gq zZeX5)rwQg*1?7R?-LW-e&wi%HE9+Dl1V)#~#qO~PFUzH}deQ(gVI?=E=y1AGmVgyz zmM6&OoF_Fh4}GmM8!-sYupB5ixV>%KJD5ORr4$bJn(bzOmRUq`;E(rIY;!pcZ6wJS zxb5^%9(rHkSQI!lc$lM;{2OoH2rQ5f)ZzDEOy9vvghu}pKR~0uFd?0L-$=?<qv00j zL$-PJ<LtX9#nXcv!5kR2QlRhl<ECeNk>5h+|JY}L<i|hzDP{$L9_QM*ILs43e}QBA zp}W<&$$I~<=g#=xg3&Ae_3+>{?cP|FlaM19zdKk^u4tvJN<w~eLV-^0YN|XX?+(;( zZIQxuq(usp52aMJpR#32kkPFOq!P`&q-sH?w8mHHeDWLWp7QJSK5dYzL!o4<Dylw+ zEDD{z##)j5x?~ph|9!C_RE_2I42>F(kK+!sBSGG3MWroCkzlB5&=~tgS!2SHNEDCp ztvmwTFP=Cy_X5oLxy=4a0h%?HV$FxDl92FAzyNQ)bpshkzK}FZJaBd@_Z#i*+R_~2 zKj3(aw_+1DaSc=(?M4f&k6Apiyob+5>2xZsD~5(eJVXcLoRAwiJ_cPL!vGopC>_i| zLg(Jzj)4{JO89`cwzqKnpB(QW9v)&*a37>;RA9B!f~d2wu!y>gCkpUfgg87%BA21g zcPt9^t)M3o)HvxaEmhoeJDGSEl!{yw9IK5v0bH&jxr4z(%_fs^MCF^RobZG2<>Q>D zGkH{=Kun>clGqd{v9ELH6<w_wmMHSr(o}IMc=i^KkQl!)muLV@Lf!x9=orWO%JQPp zCvf;zad-n{`dF5np!7fFY>r!^4R`L`0TxS=8I|$=87^VcbNBZTpy;fxEi+`8ULeFi zyxeYYnjBdj!7-GgnUU%A6eIG9kALEsXP=o!AzMEo4i)LGSa)L3QZY)|z|0CBhq1R= zDL#q7{gBJ#(37_m>o5-uL?WHm7_nC5c!*r})I1|tldazf1HGBdEM*BSjn5PY?PnB} z2gu%6*~r=)T;;1NSlajRdKY_!z0Y0MW|}~fp+<3O9ME|FC4VsItLh=hmx(XjaFQjE z42mooT|_Fky3dF)W7d!YWD;u`a6xQuv3>*IadYA`=B3tHutBiB@GpJu)!dj0A?i$Z z+vLUaHh<{08=+Pmk19t#z5#B|o^jfyFm_UgoB3;T0pJNIq5v)kqe<^oW=-Zs^7E%s z>@i5E<;fz6oGNY!Zo}M6CMKBW?Ro{9HDVGsJb_LAIQPe7>C`HGjgPOUfqeCCW|+MG z-YupndD?9=Z@B|otQnXZ4ZUg8f-AWj?V&NciFvZwR`{Q_D%9@MLd+_`PZJ-L_T}jG zkaNW7L_QVY=U6|A%go;~kQsH5$~Xjxtu|F;>JX}s!AG}`Ss4wEp;m*HPH`=sg@q;+ zBOb(}zIL!FK~@9QG2JS&AzhHc=aQ!&`;4<SW!bmlLn?OU3CF$${a;IR@QelZs%D@< zuX^7S8+0c}`F0p7>f-sg{K+mDgkK)G54p1yvM8dr`<1W%o?CYp@nc-s(CHulaZX8_ zUlRL#B!Hd-unPzDbi?Lhr(DM)5IQPFe(z?I#s@peMf8vEK^OhGKmBVHiLuG4DFD6K z$Q!-+6F`4aUHxIa&!`)3^aylx?teW8;sb~f{B`slKRQjU5Uz_{7v|={*ClNVJhU7k z@*!Dq6RzQy1*C~bNX5`juh!~Kr3R^Qd{7=NDS<!_RZQ1v$4Yi)ki2NysDP2VkDQ#K zKbdg>xa0+Cg<LJOAthYvJZ$r;$xS8Cikx1OgD~kB9ZmSYD7(m&ON$G5O+Z)vfL8rV zRpVf8U@Qn~NXADIOxuLzLEqjx!coV$iyrw=HirirUkHkLtXr5i7!7<opc$ez&87wu zyFacU7}VzT6Y|4Upz%ok?C$J<S|DvBtHK}XOfI4B4V}h+aY9?wRUFu;SByzGC=|ZC zwTt?Sp~-%&R@vOz628%~qbEH)I-&+AT8A$_|2)aNS1(^7>I%FDaeVs^zI*M;)vH%F zfZA|H+_emX5Ca6yq5=07@6&G<CE>Z9)*_=w2t}ETbgwhuc@D+*$t6&sUoz0fahz{% z@8Azjjwcr8W?jCW9x$aEAiI<qSC>=}N(Y;<3$pnfIv(!kR>G_Ci{u6~?!F7`SV;jI zCVGI1MhT5Y%#%8Xl#Mt)HHu5sHaG8}euGu1(^{^w$j<II^?*>P!HC+}*x21arlb_Z z2eMyZS)#MBLm)E2h^5UGh~){wQA%pj&*LOCGcjOJ<Jo1>@pU$zm8fZ1*Vd#KF$cWw zlDD^W-jS+iiS~52k;I>tapF#TiPnoyp@d60_3dGKM!_`+V9R?4CzzAW$`7MwSEaSi z%yy@~!-dfmJ-R~gU&!~r6YPMGAJ99RrvbQ@9Wwe+>dByBZoOj(+@hzO3C9KWgYdg; zQ+~bwJGzy5xA>1uPNhFOK}mP(bO7w^Fj&bLb*>r?y@@Yl>2h;{vu=l+7^<^sTw-HH zx5!-u3wLw*XoB-N+O8q_+JaJz;om1pb+8+so^h)~e*9L4jY)a0(P*ty9G^&ct5v=m zar?&c(Zuu&D?zq;JlW3W64RMpt(r`eX48hgEn_sB9ZOH~3}iwRMg-+IvPWIY67vQ1 z>e$qbxkfsT!vmG4#nNuK65|s*XS-4Y-vi~DJ$Ri-n`xKwl;z^VnLTWRT|H>~v{c0F z8%I@)Bn>HeiaN-q)JK@bDtE{U@4$3Oa{^_Wxy`pp8q)OmhXU;vh7Lc#acujuu(idt ztYx+uoKo-hp<6ica(dMYE)$R@Q5Bw!{2m4lMj%l*qIUQaSjnAAnLL|zy#}(D3PP&| zuaTiN1`b^zWlxn5GyFY7=Y(gKQ|pQ)^py>Z+(~8#VP$!#LG1u2Bk|W^WWy^4nB(8f zs$ll=f@_!wCSj>vj@~vQqX#F&`4&MWnSAcm<)xQjc^x;<g;-)18b@ZJ_bc~k^p8f3 zUTfjv0X_Tftvz-WVk2j-?~J{9z>(r|1s7%T2%l`Mum9<P?^l^Bpm`MN&+%=T8&3fJ z2Uz(}F1^18Mi0MpU_C$yekhLqItn1p{Z(l_ifBtRg@1*omGUKVH&Bal;-j1;tQF*2 z_^sLF6d_SH3|PYziu;JeZ;)kZQDc)@R=INSgNN1tszu=y=#)~q%Z7L!r^1|eT#MMs zNlD31JA5F}D_lC1D;{7(OO>*OBpvn;Kg<j0#bpvI=P8wI0_cO<G#&=!8(8;F{1AAx z^Me;;SQ4VQlv#b9R5HV%r3H%JP%TKFEsACF!HJ2)VYXoPp)fb3Y)D=Kyd5AixuKjm z2wbwOlNU>$&(6&oE9ndmygM&x5_bj!D;+H?`5>IN9)G`i=dMYf^l#p}i@*i+5-(eG z>&~5n!y~vOFxoF)-Z;q@ptCP8uK+mm<ubb#5^reOlYKii3AaZXT6B~HWgP$}2C6`S z^+upcO5+_@8F@)!^Qzw@BTY<qUK46S0fs#b694k@(pxw2i#Mv3GH!32+#>IGJGDlG z;UYNW`LzTdIxUXdDBe_tgW)kTLo4PbU#ZCVUMEN49XlZDQdE_I;3(Me7?(HJG2#wS zh(I*ZwSgGTf4B^`B2xkb#)@(hu8r*NA4-p+)yd^gvf1q6;Sms-&R32sMRQQPEEmZ# zpjC}_FO`<c=UZ>S@rSRx!cl&7boA;gFaN>IubgCaOH0dVk=ViEG1<?|pK^sVYDsF; zstE3&0D|Z?MkKQ!yMazilpSc{*|9-@sEq7^1v~~ufMokkYS2`G;z$@V4HlP{t&C{W zDzC|n>VQ62$fKCvXQuz@ZE-*Vf8S}1Kb}3)afYLAZ><v#9AUe|-qTD?hiRy>Xd?8? z5YH_h^uU17tA_iAW?RA_QsGdZE5S6pU<t?%ss*K>97r89db?0)9G|qP4TqPZl5Z9B zJpeRmpeH9lU^(4cGx);C5{<q6>Ydv_;eJH&Cas;_`riK3Q%^(4qn$XqX=?S>?d05C z_4eK5!a}!F8cR(yHn+x?R|+q`Jh8N_^mK+3aKCkTV*OHMXS=?$tL!40k;{%RF154y z#N2GVTo|93?S)R`n6VS7`1CZDECBl2j=<OD(!|P|;sWI3HfxZvj0h8J93Hmwh2(68 z92&X+c3H1h7ey!@1K?veNKuC>wnV|0VAInIIMN%`ve@0l3;_O0?9xPF99cTo$apqJ zax+zRL-TG}8WYmS(P<>34o-jH-}FiKFu?TOv@{!7!43C_yY`OfKC#AW8y1@sv<Rc2 zQwim+R*Mn8OOE&OXjmM!vU!JsWaF7x_6pudR{)5goSX)QF(*3};vp7dlg4Enwv{qz zZ7OOyncs@Ovar&<c(wF~tT3&PCt0B~krZbhR<TtlSdCaFp)9dP60EN(SMI{_ED;Nv zFvBGRY*`cTC3~=iIaplu0B$7l)<WO@?jK$Z>&70O@=~9BF81stIJA1WM?#~21c08N zuGITmhe~h2rSy%r5+~J!`xzgspWpUVIIjM!U;6nMp1DR)5kOCp{rx@v1khh#hkv+k zb?)E~9^TJ*--i6~3w|Bltw!GrE*6!AsIy6llSU~=GRdi;tcZbQR8d0NVdA)Kj_|oT zy%D!WA061Ah(%JklSF3i@>yJ%V&K?OZSGz<uwC2RocCUCGvrKGuEDny$OW+L0XH2* zLAK#~?eP|^)P~9#Z^sYlnZ2BEbZ@tq%~7hc5HV0>-{?KsNgbBK0}=g0??_$Idq#|) zUT<sfSiFdK3x3OSo=i&lYqb}gogJOzNM<ioYEbEM(buch+dD@H#U#dbdg7UZsH3C; zG3qjQ&q%gd27{1{hi_YPVd%Nk*y2fhr^v@EykH|E$2N8EIhIV0hIdYIYv+p4JP^<% zJ(Pn1a=fbNU_&GmSPSeU(CZ<b@XpHW%HH8IJwV;1<>f^b)L|V!Z6Oe$W(dT~TP#L_ zhCm)Bm$WqVNh!j^i6MnhnzFOIOCF&j@0QHKl#s_do<N+QJKWjahAvMI7DKhLupsxm zBsFyYaT#$5(szXhLg9nMLqI=r^1Hh`Q&zQ?fj24w?m%&GgcU^H4{;)Cc2S!>5#QR` zC2jQS>sKkBN-N1y;CoRh+TGnwrKaXg&ODdPZEtPfzPmX!JrjwJDZUd5H>@lz(Fx<s zoT7EJxwA*(k^iR;`BJ(?)qgN&&QAZyKm8|n@4{I+dHwabVxcZ}5!9&{UwDxo!=1x< ztb>8jkeId79~=M|#bz{Tm?ZA8^O>V;Mdyw5WFZhRp)JfnbvUz47Y*vym_%T5dTJV; zw4d~J0yo0CVsg5fHwupe1n;xd!Bg<s-#PcE(Y-IY;Bjt<{uGY+Xsu-08D~pwu>hKv zGn06WUt^w2gj~o?7g5disniKL*F7oEp3-Nj0Vg@;ty7)TjDbyQA=Rc;UMNzq=`_=; z-|K{$&FIurVs;j*GCnz-URvqFInHEQ0EsD3Zwx)%=H4Ensx3Hmi%YD`nafu?Cr9Zk z*ZBIx+*~`G#YF+sZRT>**RC<Z6C3NTgM;MsG;NqzS*~vFjxWq(Ifx=NnX>R=KbB5| z<`XkB_#sYX{ls`0wqk5*ax4WqU%dgyhNoP4{S8`=Ezv$X>9RrAtE@?KV->PseI+Nz zu<29_t(|=eVDnifS+`zGPS1o-&pOo#3Y{=Zn6IZ{(l$iPp=Utt{I`o2zg$2YGr6#c zz#&&+UGo&4QDADAY$}-ULiRSv1$q=rP*SfP5Z=|agrt0orQtjGCflPx^W2?@W3(S> z?XxaWaiQ&OeM)2^UZJullE%XFgFs2*5zM(}Hk+84?v=^}M&fhx>Gh2Sa>?ZHGXYG4 zRsoz6_5Q-~)MN}-O_JSsjGklziqkp6={mZU2Kau^4+D$E3=9)(8%CM@S3h6rS+5#K z<LOD_!(e(*LzP!HFn+9<x?&)Hs|QB&K~wp1oGt8!*REat>Nmbg9OI&vJaWhP(dY+t zAunt*ku?qjRSYOMo*w?rY#s->)8i5qk;(Uq{Pt^!p17O?=fcC^-?t{51%K_Y{5foR zeDeT$*Frsa^Cy7*LVEkdc#~iaI}{jt$nG8gqg&Mwz1>6kqxQfkL;xHEzI8xKeng2= zc(c)jQE^A}>9SA3A;ZbV{Q=aq&KXf#m<qH)DQ>5tbEy2M<ZfWL2!)$mqXLe+$!5zY zD{h1R7!}s_F3f8y2DX0q6FzB3An>;JbfG>jTk|f<;pcg=+B8iGn6>M{1X$X}k{<}r z3Wpgd)hjznw!jz;&f6A<?*d7!?$YTg{Pm@UIf(dDM&X?6qH*7bU4u3bK4UoC$gTtR zVa;4#TLQ~vGSkp$<}y>$lc?jxkHO*yD;jl2>72Eyib4|#@AjaE<E{pYNbk}F5N#*J zgpk|^uZbscV(si6P*Mul^w#Db^y>k*%d2agXLs*x()0WYq=fJs$TAU6;153B-=kC$ zd84G0nn^%DU!25Tporlo(=AR4Edk|uSccLPf)&B=+ERQwL>49U_4^P}{Jc@hrd9nU zjNxiFj4b5xxp}<ueQM<pj(~U0V_F8SXsPrGS-fW)rG~m1^$LJ~Zf>Cl;eH~;)ZjY| z?kiVJ`uFDF)@wBz4Z#LZR{Z^Z7m-Y^L)HiyJwE&0-90Iln50R*P@pH*S69L43=kxu zvoJ75rFj8`q~yXcx^d$+wiB*>l<#Vk5Kc`{YM771l;BDK@DE>Jm_ux|i^R=D3jgV9 za(rTHYFfgI0Bc)E+)c)$f<Ar#bU=&0)ac}9nmI%_2fQLzPN#8nPG|CMw9V{E6olLl zr(_QcvI9yGU_C{uiHX%}LI<MSniQOT**Yd0U4x@*IoR5QHGXcT-;cU3>U4kqyXt6@ z2Ixo8Gc9Cp!qB@bi=OvfSXv0<ohw~w(Xwj>8^VC$WcJd?Z3k=|ZxSD5(#pIfp<EPv z)TP8<5-E$KKQq(G$tir>wY?qO3}dNu`|t<~%JlmB8ANLGGUCb8YIW+$wN@byI-h*% zTD@KvUtFziZ%$pi*2(AN^Yg?SyQ~UgL9JHtl~-w~combAFz_3jo4sb6MLxc=gnu1P z7Em%)I~!bTb(I3kd@d4?wvMw1#q$g_u~o>%Cuf-AIG8)=K}DkJE0^PQvs6C|N5{xU zN={8TkB`{|C*~IjZp0EPpgiz9xwyb2gi*tOSKhuG4MkIHYYF_&Hph%9&g$y2U*l6@ zDaIyJ)MsjJZOb(?KM$<8>{!haD}VtFT^w*%ft2T184gM+rR#VfsrAFd156|EA}dRD z#32t#!*?qBVt{%_P0;s0Ro?bW;bW_lWeNPG%i|X(x;sYHg&(}p6Bss3B$6qQj(B$2 zIm97T6Z9>1N&6(L^8ocEkpQDe(3@i-3W!hASFAFq80IynL;7+eadXm|<#BiP?k<dh zMQY9`hnYr|(fgh$YeavuNG-qF_6YrWW(Wonr-s!nvCMdqAMBv<$?x$HTbtq+Jxq`J zH_|QmgV08M?TxoC#!0V?5gw}l$3M@SQUi@f{{!Ni57X@6v*;izS<6g!FZK2CTh^WZ zE-E*i^E<idH*YC$M{i$<wcyR>?EdMW_`(-|>_-?}(7aol_c!|qpudnA@?pHm&_{3{ z3i$E}ejIiLXuzl7=tK<O@oQWgUTTAuPbO+33chhk+_;}i-g+a+IN(XbW@KeT5$-A5 zmD9uBv4bzQm0<LhfoPh^MtCgj9+gnQ+BP}1PfIIQ={}$pAdE6i?z~5mnKMSb@SfbI zo_ebo^FYl_UeDmL=i70Y(p-~4&^C%k-1cjgW*m6@R4KX(S)cAenr3n$!LtJ>RdlF> z(9MML@B5@$Qm6&MF+G(&IL?tqX^Fy3e97vlP7fC`_Xp$B%{&{eWh+mPMW~&0dKN{m z9jXjKMiB<_L}gvbs4&Gn=lcM`LCL@Wtv`S`0AdCWZ}09xw`PN_!a})xd3$FEcjMK| zm#}b@@Y-y!p+Gb7=xs5dtG8Nwj$1<Vp^sEMQ+1<cz=+*sTqB;v8emDuW{<)9p+{%} ze?B}sCcp}o_3Js*L`({unHr#e@_C3xJ^sb{&9@7rieJ;<B1yTOodS;OVFDee9g#^m z*e27H(%Z2FP`U^^%8P=z$tH)louj<BySInu1J;n-<l*pJ6s+3b<&dVfE4`H(PZ=+z zk2KBR?g4iuFPKtX<h1g2n}RRuDC*bZCNC6<Op{!pc<avA?K^i*awn<jOd*&3+Sk5H zOQ_&`{i$nP+uJWZ{~X92X3@2$o?`dk-aELow#>Aozsw774!Hrl2FK4p0L1GpxNqLL zTatF6Gi9dY+%-ubTYCDdEdixMIyy0}bgZCpy36wIAeHIkBIOU=RKBRst=9V&Y=EVL zD@Q-|L)i_5jfQL)hdu#9@*Rd=wKXmtj<;~IgQ@V@K&sL#?tws%{%VspxNYzeJ+(2C z-Bd85ojeCjnB+u?+~mf|@oBdeP9?+R0)i7uWLDUGQ+&}J2NJ`HkIhVBQ$kJYkV``( zXKEVXE&CTtb%hqg%CP4?XUQ>GG>GV{F2_U~MNIHIiQyVoMm!d$JVm>Z6WJq?EbeSl zA>u5WX!l9N)+B-fLgobE9-e)---CfemOb9$cC`{4Px0lG%d0TLBdPILqdJzJlw4-3 zi519~!V8a2O^N<O$-mjT)Z${NQRgG7P90BT57es_6nyj|e}a8WNN^10jkyeDzGkJ2 zi#|dbYdjrR+|3ExE?RF8(5kCihij4Y70ILu`i{ZhnW0Myg#uQS_Iy)nXHjVEL?r)# z7}3MeH;ci_R#vQFEJ1xQuNe%9j>XQu?qZ-8$5}F-URfm(RvYN}1pU)27wIc(o(Q?- zw37wIvq=0WM2%w4Z#E55m48;?lG22OQrUu&?7|#S%qSHlv?cGkI_}-zvoiHX2GUaH z$5LPk-s&*qweyr{zms!30L70nh1mMyR$dD69K?u|_-HJh=3&viuX@HYpU+>ubm_}q z{f4tEAATTss`E7Zhi>rwt)i){K72hyzlmumt;-mC=Qg_c`8Yf`2lefJ<cS!pvzPCV z-9ABFEv7keaX(ChzxG%D0>>O@AAp{w`}8>X^90aeT$g`X?-U^N(PKX7jL~&6dZjNO ze<!$xUqK|IW}*ONj7(EGQ*l<78;*CjLi|Ro9F9=q!Rrn<o%t)28}SY7OlB?N%yuUw zpO<320T(t*tu&p}3IfP2Bd(+%k0_0XBOM+|hdvf1Sq<E?kePw8AgjQBxWDru<wrNp zrE+16d!v2d$njFuFt;n9$>9Z0!&7j$aUUt|NMc0>Jk85fU+(l2`ZZf{sZ=f18hEj& zgv!ni(8tAFLkBAoZJ;w9C1bda7a!6KH-}Us*O5u}q4biPAcU<VTr`9;2}c*_uKLns zJw-V(H#zy8c$YC+=y~PHLcX7*oXr@R5;=B&GSGn@Mpgaht(%-<uzk`~llfw0fB%R( zLl)1>%(5XGj8>W#h<|Qw9!5ucdS+>Hp6}8TPC;D4&A?%E$?>GaA<$sC)Qp2CKs><^ zKFDhgS%?HeB>&AbjfI0BvDYEmKnlU(;R!kj`0ZqiNP3we3}>b$Eq)y%nGe&AaKY?6 z39|TK2T~6P1xQ&&;!_zBOgJDg(}s336z)W+*Xj_>!4qrBYK@|fic??n`LuhI&(q0_ z7Y;nKjn~(fR420A-QK>N&z{g%4xOvjGNk!(sesoXGR9jsZ}N!QY;I>~w^=WvVcKdp z4h{~e+Kp9k{i)04;xQDAOXL<WE;5Z(@c==g$Qd%>FtgCXbe2EOrL6-8vne=vEJ!Ha zsvOvq(}|9gSZhH^#)J83Xh21^7;)}Tn`xM&T@%XFu&Ty_5aJRHt?pn+o;#lX2p>K0 z?q9j1cKZ)yFZ2^mP63m!bdZ5#(h!w$X0#wh`5-jaHa;_oEc&Y?3kRfaO;_G=HnZES zdUhj?c;{FrYnyS#h_)=%c2JQwu9l!xA{m=ZLsB1~nHx_{wv+&Q*5o^3M2tgdp;{bG z8N(KhCnrD_3?!P{)0tWFT+Os#c42o-&<3PV$$pLE_70t;F_qI(8cJLOsY%u?02yOK zE^wZlP+}@A?NyDG#9<?(*iz>;GYjUPURX4juo7B;$b6QfW;6x|XsfGiB?4T)yz!X~ z6{c}58_y&{!)Ohu)ar;x44GXvPK?0u^ptD~8OCGE#UY<(a+)TgeJR8VCkNn)aY+y= zHR&W4ma2CY0GJI4i<gf(VI8C04OhAycR1Q9U{H+$PLO7uln>|LNdCMmC98q*%!t`} zZnDY$Z0x8HFbVxcFu@r*pEZKrYg5Ub3)(tW96*G08l!bJ7J|*lP=WEMX4r_~)M1HR z?9po15ehc(B4&uJbF;N1)nzVrJ}3&Jitd^F+0v}<B{&+Pe;8a61)m?M&<KeR$%;Pf zxR1?hHIgn0@?zQcCHQ8_NZ@!Ct8TY=C@Yfnut3uX%k(Rol;$9;d*kLEkvSjk$FV@Q ze)_o=qR(C;1f*Z-<BMgYkG7GnWi3zuj&qb_(zlKeitOpme6_!OECnIP@~dwoN)3^Q z&uyU((>KhiFMj^Ve(~qNM4!Vry<dJlxcL)6|1kahq5f=eyp5s(?~!0C2M|Aaa}>J| zJY>U<X!}&TxVEd8=*+Z?QA2&wA@TjueYzkqgkRzkJ67Ej-l?{=hvKa_8nN<OdDAy9 zBODw5UP0bLR*)R|hEdG>DSjg1RueR&ieU?kh1d?76Q*&Vgo(oD0=e8mX|g)_AltU~ zS`z}(cUh`pQ0*CFw*=8;l2{7kKs-ShnoUCzlV(qB?;di(L8<|D9v4b%!3%RUe1<YH z91JG>BIoc#Dv6h-P^xnN%}h<|Bu0Hw{#t13DJsPxdSjJUCCW}ARebHBTZ@6?o|oMM z*`4H3ItQ&4Q$Ep`3Q8i94gXbM>H|(9!UI)=S&%kNBd0T)o=jKDWkewX1Z;L>qdxQO zv$&#>&6=BA1jln94qD;^6jj~0e06Rv!_8GV#_B^E0PO+pEh-XHR<ZDt05OQ!wRen% zV*{bi)c<HL(Fq<3mn2U?#wxvtiU{7jm8As`)Asfbp$u|Si6>w(RVlbt$kV0eVgb6p zqXRILm2oxw2P@4BA_pIPZCbhiO-GMW2Ix}|H<vwLT3&_uL$6}JKrT8yI#g=(S)^R8 zk~T{lD2@vyX=iV5e|MWPBB(+bXJK*a_~`gJo5dDdUAuJS##?zfH+wrLCkNNAUM&@h zbokf4_Emf;FoSs(Dt$iv)KgKixbbJk6RT^h3@dP4g@MH}=HwRoq>(hWB_mMbDVeEe z;dlau3)HxkmdoWq>Q-iJP*IB&<6JUFB-m_RT&~u@e+UPG%$Q~p08&5P%Q6g5`?*!@ z@B5-2eLZ^FxwZV5cShff93TpCo9L5cAk$ouR-nNqWje~$s=CKcm>wiw4l{!Xu?mwJ zQSW*mp4-0kbk-qeFAb1BtZPrWm9V`Wv2X=7L_53tO5H(ClKOY)Nek&IQ<=}x2FP6u zmTFO}_?HAp9I-)X!NWjnNiL_;Cnrg&Rw60W8z%rs*eX^<)l#_8lF-Em5+jx<w?aH2 zYr!bs6ewj;;4^S=tK`m3hm}hsP3=eNB?{;P3ZWk1V2_bAD@k>a@DxeVt~a6W;f$v< zU;r{b4e44AlA?|h5L2#>yGx8t<1(P^Md}M}<C>_7!ufNF^eEwfA0YQV`=~K|s(L2D z7L+iXM9he}nZBx~A9xqtDixkHsHB?=@v&PA!Iaa|_(6vHd(K8P(zI989`a1QGVdTP zATExwdwEBqH&*S7=TvFxa>c9raojXJE!+Y2yk`hviG^iF3HU3yG%P)<HXt99XA=b_ z#_$LT-w#W@HX88atbVh86gOZCau>TBsQv>{p5CMXNxKRn!&Wv}TKCrDniYPudi^Qu zW9<p=*&FY9fwzH1x|9C;wQIk9F;04guFuiv<s7pp$0PmGyiIcCr9I4R2K)P^;s5}4 zj(dfw2=uj9_$#j`Pj%2;AfQ)Z>TmwFzeKrnB3A%<x$54bPo4n!M><db=-)gz?Sd11 zbZ-rg|IrttuY;2^*s3HZXw{m4S(HR6RcfLc*ly@$M1jfe(@;82*!iA!U)*;z*Tgna zNh6MHc1fKg25S_f9SYKO^s(DX?gj^mnFp2;1vgdIXYBZw+>PPCQ{*FAnEt)m-_09p zbRN%1@|;)v^m3hYi0V{;5!8iWs9atr$AfEyT+L0$_ws^v8qozbDY<sS?}+dqcp{Am zqp6@-$>p<ClbAOqCeUA9oJZq@))p)EYa1(4y@^F>o>Mb9Lbwbuc;2pXeiRDXlM_5! z<Xm!wkPFLG(gsdhr@<gfqvE?=bu#ahuE5CzAOOM=KmfVE`s(+a^_o~iVJo)U>!FTM z<y0aA)v79_k{vsqh~3%TqGW8i-v#>P;a*u=TVGw`Qx>@v6@hP&w#<<2jpy4%*5y?q z^bCc7LSX9N2&8k;Uj1Bl0ZMK{uPRs*9b-?&v$(vpsJlg?G=Q!slq!IpLJ{*LNiUFW z%EfHTXicK<-4Eln(zJ5=DZ@}IRm4$|*GgYu<Q5T-N|g$!w5ZukXXY+#tkJX^cehCq zjz#(>D3c&LIyJesuT)oMz_y98<B2ct?QOw*-90?1HzWtn@ri5pGoSlBw?)kc^irln zR#$=AiE-2_Dbr0R(;VG<<;s=$xtZmawcB@hW;2;<SFg}b<yu{FB;0A11x~B1g;vAZ zFr{0BZt*xwSJD+Iu+v5Al!2DV)DCU_I`Dm37%DizfsYt_>J2+=Y-M<Q$q&fb`T8AQ z#Q|^+R&KDb`DLSa``do@@$7@%Gu|XW@C+#qfQ)Yl%oEm{b{G^VRsDdNnINNkOg+t- zn*=!Cd(TTU1$&gf0-7AsebuV_M|sDHY|^wf$<`2baF8J86BQwl$-_0k1=#1-;h|Eg zY$^DbYJ$P;BNYvEL#rJtMR}W42`p@aHmYtrj3i*L(<-t`#NKdrHJLMVm#S6{2+siA z8CIx(zNtU4fMpGy_OKbKYb$oI<p-PMYj-L=$@{{8Jh+02VAi%A#zxLiK_lC3m^^a8 zTaj1wm?@=NH3@Z*OP*VRNN!Hvv|J7#rXZOLaiDRju!aH!A_AF1R|)G%memAlG#hj& zLavZQRD>FyTP$V;K(tdi=r;)`{fL=k=}Gc^)R6?0`Q?Eu2V{QT`=59^Ai6!XXVgG+ zd-ZLm7SAL3&B$tUB+VuC5;F&$A<l$`Hbz{$3ORBC9nO+eL`K=D3PsXK^psbma<9Cz zW#}}MOVT*nil)9VnbxAm(0=z8^B3k1W(G=1d={s;5<hG<S`jfKco+#P8fE3BWvIJ( z;17aP$0L|=OCMe&GFFdS5iXoK$JxToTNmJ@cZMwo@~?hAF|a(;HIG1z{_SRlNNcz} z2*{=<nSflPAuxyHyUZo#@a;VaxpZ=9I~)D>9m*|=bM=9y-@8my7U@rX;m3aQXMf^7 z-Se6ZzwsNt@%|_MlPjO}K+prh2{(G)zf=GCF6@7OTW6mC)m*cZ02e8QW3AUC>625* zbNkq;lvjmk7Z<O*n3lMvPsxi9hrV+fnoUc~9Hb~`mBbS}9Hp-3t>c!^q%jDMX+yMK zu~{zW8}+AQ%Q!#er*E~$^^_Yv9HDNgJa8r(?7|>&8i9!ojG6~ZKkVK(b1PD*JDW_U zc!qIA9z@YG(Q7-(Xq7u$`D*@`%a@>70Q+|L5BL?_%=x{swgSr9KRV(XxG1>g_~_m~ zdg%FujL<p$W7av=&O|zeBnv)ZddXZeI`eQTaWKrz;X7W!8A;yK?93#8l9vCt=oTOl z=mIJyNomRP1g?4>Cz~(wjI=OUtl$Rdwp&|UTeK6zzq7MN9GuPW<oGx-7TMn3r7kS& zb^{g@>Gb%*0$%Eq>rX$uI6to>2QzszUOhgp0~_2l;5ZrC!_OGiJvBZ(n>e7^TuosW ze>zpEOFUa9F{F2J7N#ds)MTaGuwIsz7I@IPxw$FQ1m#90tSpx#esr4-;j!_Qm0$$7 z>3%-zI2fS!ut#HVVaXUoAazV0*8Tl`43dpY8!JmoeDCi55sUziTkIn4Lpmvn-aHOO zf1nt~52?WDB&@7mVOp{0FD@>XD`ij-F4)&z{eHPzSX`LH|Bk&jJu^EwF}}IENyvL= zcMrsXzkGgnW_#;yu~dKYh37N#3wT2HPzxE&5DWFVAiWM4%frUZqXWey7-nRehggOZ zPEAZ5j&|UH0ueTenapw%4uc^~bt9W;2+V2iN_G}a8d;gX2K|ju`~2L=6#Vtvi{MTd zb&@^6X6sP$TmyWy>U}RAJv7PPbLkFFr)68`S=y!N#ENI*5xfDq@E+nS=RL~>i@amA z0T5^Yz;omF{7XVK?sLWmK<_<I^o9&c79(?&$%A3c_5w0PqY2c`%wahotR(O!wNeP> za{q(3`4%f}CW%a%UM!VZ;8cmG8BVlt`;FJ^Aq%8*8~S9@G6x9z@Cd3vXACs1WQHJD zr4?o#Xle7Go<hL`b7O3n(}8Rv7eP|uCRyEHzyZKQnvKfssiLa-5a<p<RhbJVT*__1 zBU)%;km70n5u<cl--2C*SPgS~UWZvg++0%h(k5;-Gcy@?-jmlZG~aBR2(Z?vv}h&O zrL0xn@|12Crt!zvWF!s7ox#vb6tOphQG1t(q*KhF+F~-8c^=haA&Vg+Wp~_4+8(vx zlTB`~4S%a<1uw8XG-5oOh+Bi0uo9-NARyf<o5$@CSD#dE4>w~3UfDmr;Gk!?(&xr^ z63fd>Zgn6HW14~T=_@W68krhI{;E`CGMmj*FiVrj2|TZXq8Br85Jxhz!57E_tgLe% z2^KpB2~PTFpLzN#U;ABe&qLo_H2Ob=8vP`Oic$rn&h&7+{}0+E4MaS_!8SoL6OZw} z1IeDpB^UP2fvS=tWcCMl#x}F8whOD0##b{v{`TMetDSZO6}WeI&-0j10R0CY>nGO_ zdSLW8e<uVmf)>vA+d14|XQ~p{@a4ecWN*UFt75I@M3=M2&KPlEg{RNR_w=%b=B8vV z8EFG31IHRykZ@$8-bB(-gk!eU0YlDo-`P1y(n38QItS>=RP99Xu~McwV<_hY=Hsm0 zKgyQGw`igf4jwSY8>P(3@g*L!nxsR~e96X9Coqk?M0NquIx|1CnHr4H_HDj>4zr1b zoc;V2z>3H^r~zjlA6#2q<~*94orZ&vD^=#E(zQkhNgqCo#tz;hf)dn)<@f~1qOAg0 zB`m;)X&V<1`{qDWL9Wml!Y}iR&7n2PcTrqP6}9NkK~7aDJOF$N_%?}DGJ)^>;3%6d z7VqBO#2DaMfFg2oatt&<PUoqouFuac;Evkc+XFYV!*cYZRX;P6q0|M369-s&a_Y*Z zOOpt(<G@oyMF|PCoF0`(ksOn9TQFXXAdL~%->M_AYg3)X^)C4V8Aw&8Tm?{zjD(9* zNfhEbQ>X^!aiv_Gq;w8-Sgd2+amXPFc4xoCw>LF2s|jgx_%hg3cUIQ|M`~5%Yf5rG zD#-y#Yab|$K#<4`O5GrAo+J{2O?8A6eYv!?wOK5bkhqcK6ObK2Z->gn%u@Vqq!~2O zsKK@&5tg7q4W3S^07D7815(8N-24kKya)yP&ek?ygP|e08DAP~rr9afz2_#U=eQeD z4epFi5#UK!M|FZA9=Mi;W|*0p1Mj<gj)zD{XR|t|jV^Xw*lSq*)VX9Ddc)_2&dqP_ z$U+f(iY03>oI0XEkAQeBM*Hy>!O{)h2^R0@3t^*o@a{jhP1C`OTO-~Whhp9~0EhcW z0m_D!#5r+0(}^y@$Ms?;QfVm|GBs@pD-dr^L$T$#p?utyfJ-f2=eA1tD9t)RT1pwQ zIBFSF)o+stE6}Mb#jQ3=*f|)y!w9l3@D0lOi43X>fhPU0T*U{O14;xx?YZfzd{edG z6wOWi5q2E!8whq<zjjet2&A(fk$4o-n5SS9V3%-wNfs+#%Ib4iFSoaecw%Pou<V0; zIhL)lu`!P+exyumCo=KFGfLjvvYmJ`mNPC}+CwMUf*pvr7}OIz-NB`<A5>%YK9^IU z9~kyL5&B-K^fbO}lHQ5hK|Zuy)M2#tfAj3?nfzNs^$8dVR+&{wzVD;Rs80-;LsSc~ zIbcsBc};GMxnlE2{YKlYfU8Hwv^G@*Owe2~d@y+oF<T?WJMwvA-gM<v51jq7A9P;$ zqH-FNua40dwyXlXROQM1uWrKmo%ylOw6as`XB3YJ?m?ZGlq%O)H4kb2+BA^KC&OT1 zSzN%1^tI2|VKE}uKpgjbue|2N`oKT-n4-~t{-x;C8v%{}ZRA`Y_$xlp2N_F_1eP<r zThEzRG02g@V%DD&PY-fZ<KVda%Ik?rOT`*Tx6Kdqjpr`L#rFUFm0$S6XFe%s-vY4W zZHh^ae&h+Df0*9>P=9vx{PtZY*qDL?)vpPDM*HjB*&qBmJbKY@(9vS<8J)x+PE$D$ zCxMt2;x@sW0j;tFbKn4d<&Kr-OlovMLokifGEGWS)B<yPvPr|Q5ItR?YEq!IOX30L zn{el11F#kHSsbwdLHskg)*!^Qa~V&>)YeRdg!gzNF~vn|9_-7z`-kXALSJb#S~z0G z)plpRJqwUpzgX@pze@T>Cx<vH0LFY#C>Bu~HgoQHl+A<QX$+UGuPp5BA0n`b_XXri z1}$7*@?~if@Rw#xQSOzz+m0f+C@PSe#_RRf73JHTioZ@2(=&nEVcWet^z2T2knX}Z zc=gSj2M5Pgq6L_e`HClx3{J2L%ohCEx?QJ-01oFYXBJsjq^q*MA%qVvrO~KzZaw|X zGr)Z(EJ;7nYQ$nW@GtGA=U@XEDw6ASkeO-%pu(?%Gf%7%+6JVyLqfiM&NfV-{e%6j z%}vG!TLOouh~PRrWF{C3-wrvs)5zA9NE{GZN3yIz%@wnn&a$}^q75=C(1zzJ#uE%H z%!$`tdzE75pZ?^>pSgC4$+Wq1fLbUa2#I(k*w9n*-gP_haPDqy^F5^NHR~1VH<d;e zO(InJk@cjt=yLGw8ylC<u4%Nom;!qThhO;om!5m}`f>Jz&Zk?rGv0kHGT7Ct>zCo# zb0QLK!Dy7O4_U%iNSICn=v%>g;T89)GG{!M+qpN619&xbxXM)FjNy#8)D8upq{W1y zIcxzbTE>~j?k@Duys>`oadXeDP`krDLe41W7+vFoX8iEbe9%bsjr};n6I?SW<Aw}9 zMlXWk<+gO`SQT>>M01OWcf40+sB7C0<Jou}em95pTD)S&*uEw>&(1JLMTjap4&i#) z{FW+hs8@y@lnLTzR%bx&V9UT!c~|4VX;-n8GGMm&$l?>n7po*0abqG_*TW~UtWAMP z%?k`bqlBm;l8jV--2LIYrK&tS0O(>42=jGFXJ?gYOB4{4bJr$|>JyoLCug}$i9tVT z3nd5CKrQ!_@1I{?XK4`d5f8@&DBZeHUzymVIr2TdSg-k@gYsbN28V_@-Q)PY#Z#J? z<Rfe;lamyDP!=p}lW2n+^)^O+pajQ_-_8Hzd~`?iqf_^7k7|dHm_`=9^)i3*?GPIl zDQHkeP?82-iq$8E<>SaNE@Rk2#2SJ#4TOKA1v;!)g#9oBEpbcJ%nWdAt;%7GO6o?1 zjhmi`OZ7s*p}`P%fYC--F$eMEZE6jTZl!(Od>AC2De`PuYJAA^8F=Aj8@ut~wr|@Z zALvaV1%5bch-7~BBQO5`x4%ooCK!$nbhpuq;jUg<2z~LRL{s&)I`Yxe=-<7yIPjp? zE1x7eF0!1;P7bIzn@62;oe>EYYvJE{WBg16tBV2jd<9YHzw;mc2RI*r@{5a$+6UgX zE1m%Q2cC6LKIn_>UYP#eJ{zF?VDk;O;GpkD_hmV#%r3y8i_h4ZGj?~SpR$EnsU2OS zd{)E?IaYziwi#O?aiJM=Lbx!F=;-)pJ-10QbonuK(tAxuygTkr(}^BYb|Cu(hZp!S zD}_XqMsQw>Ai>?l^GPOD#?`)vI;<Rz#=W62^2F0Bz&`&XU&wKe`;8moG-XX%^;4L; zB0K=lxhH42YyjKJclM4r2k{E~MvM!Mv+*!jIy%XUUOyI<Xd03Q-QLmh$;#3^{0;J> z@}&|-58#YO@_lSElGr!79?n11SL*dDsxMmq=Igb{z8($B1baZtB|9hh6Yb$|CFC>P z9g5G<C-|77RNS?MJor3B47N76-?(uDNO*X#520XwZVo-iZ++)mAbti5G;;0QwS~F4 zXP<tW?=*skC`=#)JF%p$NcB@5*2hs<iQo+Jpa#Kx9^VK~9<oQ#qOFpMXMl21oC%!( z&FOq%j&Sz@Mj&kR2N-a84(xRFDjv#{T!D09o|j3YL&ds+15#q9!cbwT5%@0`7ZwOC zNd4OUUJw-uh0^ii9!Ag=l6vQ7v0S$Ijv)Dz3MbU4($I!NdwU0z%LRGkiRS=2*xzGb zAl8R#JQ`;T#p&0Xnd#@Ae_?HP6*U_yDiVdEQosuM{O5l3b3gtCT=m6betB`>%H_-0 zMF+=u7*Q`h|LpSeG9o|p)znm)c}VBb0Olqr%fPpv+~yTF`n5B9nS`taEImdO{)VFe zgOl6B56+}FrWx~<n|P3lJGk%P(FXrI_Vs0W&ioF39er_b$@{PVb)z?V%$wujtCjLD zAFyFrEqCn%viGDI=$MlCRY}U0p2>F(bO0TJArh%8-HBk{WithW1X-am$7$Ya{D>uQ z<*2zVX~7~sMM4PKjdI)?xg3-uJq?o_5meI<qYT+336$(yA4+C2pE8|9v2<8HG?p(i zE%u0jxGP(0dz65cySk+{ZXrrmh^8XKNl@@RY%sD1poamlxyT1ePL08><b>9zN%T}S zvO}L3*<F?fMbkuVRIx1mpV8lmhOyn5cBK5x0+&8{g5Iz=rx}};vf?SotTLY)+=w?V z-BUJ<j~73VihR6SDKwi6*B$m2l@e=*U>EyL02700<_|SG)BINq*TDV%?(@)Qfdty& z(y+8$Pt*IK=$uvUkXEu~6u2is8NED^vU==fVroI4ck9S{PjAvxZJsSidYUjEo;AmW zejJxuw$@+@+4s5!-4%Xii<{G3-OaUb6I#RU0g3rowLX5O@m4fSd`^0gcbEVg=s`?a zZhL${E{5Yq+PO}9n5F7Zq>Y`7l+)hI%F5Ti@y&NfobTi782vNy5q|Z@O^u!&!2aau zzvnZ2ANP1Pm+-LULI~FrUQ>l*I9k11Dpi8xFLe7T_J>;%X|=if12gl%nnSPt)xY%T zu57IEUAX5t{_aU3y~7<ZfKByaZGG~oKLR~)Zfmgp@duV&u;3jo-2cb{R?r0lc6E44 zy6O6%QY@!XxuPQK?sQ?Z;QUlpEB>B{MCgrjgX`T+Xt^&G5q3%_zGpU9xt5V2)HaGM zO2T1+KbFj{T+DI_EgJ<%5ud>it@5c74V+F-=!|K!Zf)-HVh+V<u&Ht7@n`cjkhXOo zS!EFMc}%T^ll$7`HFQf->D1C98IZ~WRin_OM1hhba<(H6ic^Xyq|&y)P>c40Eu_VP zc%)1X@MbhJGc!r<DXf!xsluwJoD(^1_{eAvp8_T0#ph|)m*K;tacLXfRL3oR7>;$$ zen2e9fJ|An78kFIYQYT^pr>u1dHJTys|1l7cRRl4$XK$`?vrYEck^y8pMB%?*UrLy zfQt}Nw`~ga*`uT5YgeCwKM!1<o24FB1%ETQb%7B(*W}W}pwd93@M?$~gIPiQ_(r<f zs6$d5;z{kum!F=`Ie~%qq2%hXG5D-09u`9V;c<2>K5=(*>*YUu<&{@oW8(+epaQ83 z=xCI(T;d5>EJBVkvv9x=m@Ckk5U?k=f&K>bkbnV*U}BgchWPqqK_Nmf$YX~w*lBrw zR<*T=3t4mpyN<8`oCj<V%b?BUdWWhHw*s3`SraN~RgWbmum*Q`wr;%jdiH1^(+DiW z*}S&8@*|)A^rel<W0BL<<%MfkpI+a%yt2HQnWb8m(l9{qhTTQzVrW!oMuw|ds!@d? z%r!V*;P{m;?qO6h^%z}hhb!GK|FK-23QfpEuc0?4kH6qDhfsdHJG%9iIJ$)IA*cJ+ z?c1*OAMS=G>?McvpbU*6Li4A}!!0Mg(PNNC5g!AHBh+ZnlZ7X0obxCs0Bo6XyynUg zU*kaf+-Y^TnQ1JTSHjL6VJ76Hm_Dqxqr(HoZD4f1J~^IVU0dfJW{zQ5bvpDnjKG;p z24+3|PXY#O1K+t1f$x?CqxjeKZSX-L<SNUALBz3uOTr@$n5BfIxE1q+N#Y8RNb#|g zPzP;#W?J_#?vOB|$&!>RRdxl?vtm}zKg?)B&c^g)xF1qWfWjoxDPJtAGLiXrnMKTh zSpK{=qKN{Y`hMrci^wQHDy_0Dhdsxpl}u}0W#lpUG2?O9V@fe*XiWN?#F*i;tW!c` zx!eg|#J4cFmspsFMBO<ZoFngqm^@YVolcx{vsCj$PI`m}(bJz`$mkhbOazj~Fac1W zg-^(3B1!goNCK3K#TGjBrauD%kUuH^)pA>Dr`tk&3#ScjRj!5UAFvg>Myk_en0xdS zSL)4S?1Dgq=#B>2&CRdu0$yudFxy>c99hy`SrPs%enT4|$tJoxpC<Wt(JJ>_x#48X zmfhgOps|+B7=;HY$vw??{rG1-_2WPG8P>zYYz53zAo0!p{!zi=t{i@o@etBVu&eF` z!XM@vF5t6l&+T5g)r<8)@k=X6NNd@W5li6Nw#^Gc^W9H>>JvZxr5}TGM)&gbo@ky2 zd*Y$LfYE(&3-19(01o0u`y@D}f;WRJf1vBwF-@Rdo=Ebd@DHoNo`mG(Vg&a2&F!nS zW6BMr*KB(xnbOB$4{=2(2S{YpSa}X~@W^4$`&`ERqGZ^qOf65&C}eY7%h~V73vqiQ z5kzASPqMHSkS63!+{ViKGTJxo6m>_3ix8}#qCSvawWwO?tu@FKVrNGSg+FmZq3_N< zj0+Y7;PwDul6%6;K@k$Jg-Ienq?yJkJ2RO^krGKn+}3#AMA{BT7UyP~wJPXgdM1NE z8XST{dU;_EOb;~(5QsNUWT6Cg<;S6d;GmvGOGVW~B?-@)JXumXc}6}NB+|)@vC6Mw zm1+Zn<Fwm;<$EvRxOE%G_~Fq>w~hBVdF9GgoNM@%=^Y`MR_9|M`}pd{m5+V=<4emB z=%cr9-&$Y4{KYSQab<Z4Yk@OYHF~Y94Ih)pC4vB5jLl&AbKq?FKZ>+44ji8xYk11> z?i+;V6zqCf15gF&1<=FS!ZxCFsHws8GBaTPa=c@ZkZekLoGjsb6DlV;vf?yhw}`DI zT0#UcM9J8rlM`}$*=`%1p6J4ID4t1s1nIz9<<^b2aLF&NtgbCDB2oIrtu1KroYt^k zI6I5wvP71;U4$|@-B(wZ`BJ`Rd3hDDW2K_=o`HtX1LYU@JblbVa+IouaU}YMFMVlc zWtGfVg0?Tb^zqA=knNwHU0C|qM_vR@Vk(fK%h=6KrAUu<0+JF~t%3ozii=SSg1ch( z&^G2d-6V5gyCr<9keN+lO=a1!DtDwF<{DS<bSOWvNHy{O$DxwH@O2hk8N74<%02hN zU>|tQyP}|;aq65q<DO0r)R;x2GR*_ex-D~EFeE(>fxGS@@2Ns<15_RKiPpHGNqb(l z7tJDrn36jr8;4*Gh!9xgBxX{pu{K#=*(|f>#0$!zxM~Pk@idG;<Gdl>n&9h5g~ZLE z?zLxd->`3Ze1)`|T5WQ8c*Dsy?gzDLESPJxkEPn=yDxpgI_2}E=5vupet4JJ4j~Xo z&9*=VRMraXnH#b-VZ55+p?tmE*|RG7I7rl!F)SlU+QB@F(7X`sATJa6NY5w)VY-$+ zMRl1iMt*o|wm1;I`=LFPN4u_F$xFowC{Bk8tr2@>XXn7vT!!uq8=(B$qz5#Fo}I8h zdg6@EG#|FnIs7j3P%WWK7TYPQjeK24)qk~=Vo|=At`O<2Ugt5vQlhIFwk8fk+ju(m zVcL%N7fH+vp6m87B69T$-|I0&LyAN=X6SR`jplBUq3F>MHhmf1meJ1lvej^4@vHTX zs>zwqjz~vL0Bi~RpN7zk8OjSt;F1Jox!&nyt2bf=&cb1)76u6o@FWVHG=>F@c%#m_ zNUa<HMt*2HZjMiU{9|AJ#y34y@PIpjx#gkJ|MbVlu0AtC5t+euhE2!P;lDo=FSMD& ztTKFFxqLaFm!hkgPvPm*7;@I7YVWtc7q4{^?izT&XCHoy#msK-pZ(pxNg4@`d2Cv& zrqP-IPWOKT=pVA@KfE6gFu?#04AJ~34jAp75e#wf?Q@?MPh$*m0~Ble_{hP9s?%Zx zrZ^ecIo$07PT|CYJ7C+lPA@^3KDDK^l<*KZ1_DB{-t7ESWZc*ax&b?BrBVUdLytz- z6%U3-OU*m4;{+%#qB=M@HIbQ_tkqlPn$8lyFGsL=;mtO8g2I7>9F7*g3kr2EpQkOj zu~_QlbIoRE78is*VSmEHN88Kg=T&vZb_X6yZkKkifg1-w-(qQbVV2XKZ$^iaX7gGE zm}*@%Mktgol<;u#S3W519XLovj)xH!3-bT~?u$u8K~$Iy9+cyU!$u`zV*3Y&axX<i zI05*=`853#h0D=37X%TR7}uRrkfq2uHb!OBgTrHvF&f-$)*@%Uav{6DwMENmKTI3c zTIjlo<QNQ``NfrA{^ei!)F(cA`SKN*B>THNPd)qmrS&z=V?VRqAw;SJ&>O6y+ykSV z)<HeBDrN@l*Rz-!oj?)LUy%x{uRhddREJA1PZ57Ql~E?{K}sv289EGy7P^pxKIuya zg7)L^X1q8974AP3HD7rS2C&3nfCWq7qFSfNGSgG|8pR?|b@$f(!O8CSCKlKF>MF3R zRON2?2y@3rM-AjkNE+yNkB?7`Y@l=wxJ%p+=Q<6*AOyjnE`qBR^YGx{2)M86oykP0 zTqk1~di@oQp-UTJ_>J{dg0)lAQ=kFL0sy#OZjxC?;sl%`4HG4zFv;}n(zI4;ffGoE zFvb0A9)|Ko;k;XCbu+pi=-|0M|HPBXZJ`jN(Fw%2_&qUs)k~gN{&wUUe=}IF0Zt0= zeekJK2=(yi*$3TK9d-jT&7Lt33}?$4ZYha+b^w{MqfL(iZVnSE8qhQRgAO-M!crT8 zgB9x<yOm|Ydpw;E1hr{<VhWLL6Nx~ha!w!<UMbP@luS-i!D@CkBk%ZWpLOICG299m z2{ywWE7S{Xd>ltWi`;7_un~kbpyKBkrv>N-Ar1bYk*wOqVo7v+r9fx^E%DUmLnzE* zXI22MXde5I=L>~2zi<Jl(uE^q<}*+n1Dlao)G{KTJ%I2`F#+98@{1jeYGF_jevG6? zllYY6WFUKJGnLz&|0%nOZWQt)K%wLT&rdMcjrL(j@N`t*Vs!M+?6pEzgCB#c^5(Ec zfYF#kGKtMPqS>UK;KJvFW{JIx+sNmP#jynF8Cj1#zWZEKho~U6oY_Pp*@)WBYOmFp z(1HZGw>SmZnjk#r%7NH1bWN3=V#q|MBDOF=i7uCvwWTNJ*)fKjet?0&P53L<@GPo* z;rSR=WCc_Yh-ZA6oHUdU0=Fq>V7bvY)ATJ4_c3g=SHK~}5<BbDOZ2aWp0JJ-C*c~x zs&0G8<}~dic1|`rp2cx@U(O)qIDOD1_Ab}kT-CgiE`BnO7{fPy?^|x(JlGG7!xvHO zoL#>*K0kvZn^vre1KCP+WY6u@Jr@{nc)P~hNzGj5#4i@BS)?kekYn9xBGeF%vF(If zz38`YMZfVTYe~Gg_ndX_*)3q0zx)^e^haK}&Xt}E>#N{BKllXDzh@Ucx!^r|z_)C_ zD0m&rX@BAWj$Zb*7x;p8wn+dQe2@0s8T?UK*;qW6IxkG(PiHS+mWw#26n5maFdztH z$H~*IJahbLM+48HupSGmoGK0yc35^y<Vti@n20Z%sS3e#`(VWV!((=5us9#Yh0F%c z;muZzTU{Y$VWJ)Y4X!*VF64^M%`J!}NEU9aukm%bjX9F7xU{lDy>mn>H-UVG>|1S2 zg4LyYfacPC=I}UA12D~LBz}GN;zGGbW-Sj=s>$tx?jfa2d49_xP#sq4NwIOmr007% zJTlX8%O_|RiK<Z2FJIo^XyNpRs;gr2@{_5+I9oini?Z@a;~P(=#uM3M<@f}Xp)@@; z)9jwLhz(RKR9PZmn>{(k>r8eIM>(})clP(MU4NDej+yBhw(r+oeHBO3^6J_=$YnaM z0;@P3p@18l6#O;)el|o5o!y;niO-N&1cAo{MwEXnMQ8Z^cnz%rju&|`l<E0i5RI^W z@K4}1hv=Wr<)6KNl`RkGOfD&6GMk&*9E~$Gv)~V(ha8=vDa%oG2A3VB0t$DsCqivj z+0I7w?(I8p;%DjG^dyy@cwP$bJpaP;PhGvtWII02VWI8r?(po;XB9Xi4j?ZSiu)PR zKASdVrM~zDZK`Vl&Zu=|DYp0&E7O@7kN^{;)9xaY^pTf7`qb4cue|cgx4!v%U;EnE zj}G^@w(j1!d*|EV{)0=GH!`!C!=s!kc~OnHi{F<hxvCaeGPiPm%{r25km%i-%fj)R z?dBfl9l8Yvp_4**I*UySFOVe7Tc+XdeqXIQ%{{A#Yy~X!ri1&@6*{_#M_trI|MdAZ z+2ESs#SdlEq}dkC8_<emz&hL8QV;Dhh3~~M_A;f0l^wO)2h|Vmn|F)UVT!56o8!Q4 z<yhZ#9l4f;gYBEFLXfGrPNpgH#U8>orhIzEdC2;p7EB<<qB2P|jp+{Tvzacd3<%D^ zVHJ?+P_LG7=`vDOh~s<F&vTv?f3u_@me_c&i=d5$7>PZWHvcoposMWcW>+)+MXB#9 z9)*o*ERn8(MY+$3lJVfIBQS{Udgc|`pq(~k=ww2wPRu~rIV|UKa#bbvGL=F|M`1VS zIe|zyl8xMqAA#lRX1UTah2~)uOK8>UH2f9Ip2u|Ov}Zc`YdX-ern&0H;qmL$`FIda zmPhXxnaX2Ljz>qW%3!{Eii3=bp^DDCPepCvr>9u&RH$8;hqyRZEF9zI;SOwjilFqV z!K^W5n(%Ov&}obB#FnDsWRg%L-&vK)21rgbj($)`(u)((6;^6MVG1{$&w9{}5Dr2F zGX|v!CjuS_oI1|bHzpM^p9Z}}<2aSf<hD6%94F=&^H%1iJorQo!S`a_=&MYcS?E`) zql(BGrCuqs+>klI^x)r%U7kKbbUSkxuhvIid>(=2J9jo8M)8Kz`Hk(~KmD!B*S_1V zR!=kO2-V3o*#iVmPx8b}ihzf6VN9X{lwq2&;g`$xT)t8)RS9`{KD1^digRP3W+(Lh zyZ!&^%f0{RU-ZBFDg&;-*ZYCp@818MT%Y~XPygjV|L-#`@e7a(%l7UOx%d2e0_fkf zi=JHY-aX)GAix3sI{4Q=?<-;SUibg%=P26{{0a*riuo#ck;Go)Mj}3HPD_~d+9DhL zruw6llnT|m{h4uX_uSSAoJLr;SaVqL$j+hDdad4V)z9pZD^<{<!IK@^-#_&F*lf)r zg7;yNtNb{N$SBTZ<$6ONn<R%EB|<2-nV3qY-g@f>@m7)=A=j6SxjUOXFm0f&f&{n) z9^~Ku{cq{iQkjV;@{98S8-qw%H==F>DMWqd2t;B6iZ{}e&}=xnXgSpI#kmZhwhRDV z<MGYAo72;i-F_IVB`1nF`YK8lr>v>y`C?e=%mDYJp2%Zn5Tak0$FHMMtVJrU&Z3uZ zG`vEw_wl6kFHx1L)V6jgfqICb9`5v9_5=k+zL#^9=jPPM(t(qY`VHUpOTYLF&?Ym} z(;%5wUin_VTE2YcDyqF0HaJG@q>1s2Y_OO^ehgzOVe<fMW@j>Vxap3lCIF{1*Wl`I z;@z1Lf0s{b&_$XO<e~sA<R3~cLQ|o&oMe<H;7PBnuQzHHdXy5YI7d15z(eNFBuGMx zr$r_PXRXN*NM(;x_VD1~t=C_Jpo<nwp;(~0E8LdFrA1u*+nbwI6S?*jsl79#A7l#^ z46Rd6?p`-nC<{>~k-SvMn=QUtDS~?n*`xWH@ot||xN`5|Yn+{5n4OzvS`vo9d>|&y zIIgd)ef$%jxPJA@*MIlx|MNfo$2=6VocY;lYzeUYM?Uf~zyK%=XCwmwN@Pq8RKmMe zAIX}v>Q_Fc4Ud{~B_Ir|)m)(h0an0RGv8D!tf<+bO0H0sQJZKv|Eh=0Ueb@5cD`iZ z79j;|Hdv~oYc}}Q=z2f5sNZ|<xQHu)FE!hLz_$r{!=Kd(>qNRz4Kg;4VJz@j3mygC zV$N*G^J32%a<_aCsTo?=>L%XXT0X|8c7g{acKK-CwJ$`e+3i}O{N3=kie|8D@i{U( zd^?oC9CEp}$1-naY%uBh9;K=fNuy9ejNqXtF4QMA#Y{yQ@N~1DacThZV04rFF2fEO z4p9xdOT_LO)*56{NX1LvEEYABR-74qHy1<5QCg5hZ*2C+z&4IMg0M#S0YFGc(@A<R zODQpU!)>B|4}%-V4jBz-==*RoD^}3%keyG1oeg5WH&D58H1ASE&dhO??}vz^BA<Tu zPqW}ad8fHEI0Z~&el);jmWJEIe$a?n1dPW0ucTzOcT;J$qlwgHyHT54S|!MNbbN@* z!2F|FZau;sv<IS`XiXw<@me4o<CvvQ(=nM$Wl}57C`?@oB+F7U*SJ04DUKwj9Gk1g z1;4$WRuPu2i7v1KcDTLvNtt0P(_uJP680{fYLn4mI*IQ(1NmM}V^8#_4vFDE<suu? z##56u-<T2?vEa_%!_70kg;|lyWk36wANl6DUslf2`*14X-yV&)5?WYjk*&ki-}+|b zpMAOZ>RYXT_iS!DIx)r8ICR+CY#tzcN4yUS>+P%Q?|Kd1Y=y)tYLHk(cKt{>S|yT0 zn}=t=`K{Cc@4xK*<FA~(x*h5EC5`PV;19V0vMBJK{pbJb-)htmjLv{A2-;wqz0cb| z0rZbzdVeVHIqJF#9@wXyZ_2^H!JFsy=+QZ<i_M*5SWe_%v8drqwv=pyi`q#e1`WxR z(P7NSmjIr+qdwFhS0GWFwV^kKeN9kh5Ejse*hhh}w7a{_vA4LgespjsupNh@r=l&A zSGUd1aKEyV1e1-Y=&@k3PE!;CNh+fYXDW^*{MK+iaZK0pJGDvy?lpW8B_y@$#r#Pw zSKypjTU#R+l>HYUGyWc$;i7~N1&&E+H8o<9O7)I(cwhpHy4`3}f)s&vlxHTVCQX#N zH8VX~hN(}zPjf7R1(k=_YB@0}GljGcRc5IZn<X%dA%QPPO1g;6Q#A(J=6IYtThgQg z1@sjsEg7raXJ`LlYYT%U2R4P-vb(d12t5g5&Phm3V!upa_5f1x?BQ~TZH^}h$KfIU zcyJJ(n0n@^D<T1NZdh$63988NF0Ucy3S=9)k-o**pzTR&ZUX`?4LjIBzzaxlfir<4 z%5bUz()`LGFgn~rOeQJ}blUJ(*49?#8q@^hv-`k(e4=0uaeIhO<EzwZr#xeT3zGpl z)b8FML<q5&$HHsN3wJiR8D*U7m;;ALM>lTX07qZH_SE|7;?DlbD{tIV5^XUj1`+zx zR?dvmkWOGeP?w%}rqW4i5=Ue&F<W@J+4<!cUi#S4{_bg~d1v!BPT&_`e35hgxo4lF z+rRep-=!BJHR0P^r*Ie+UFY=UAO9F*#H^?5Xf|e<x#0C<DFgyM&YT&%YyW3Je8{j? z6(L7y`f+!@LshP1Eum{<)GSF}ssyi{IHPORU*8Xsg5`Pcg3<Sb6>Zb`{c@Ktcz-nH zY-Xf>yh%b^_(ug=qpn@!w!M*#go<P+4GY34Yj8jjkue~QWvK{Gb#Q;D*+K)$CqVWJ ze_2il!=yAsAud&pWB!-hy+WOW7>bwFPtQ81;a2w)DxUP_&-!o*8`y!TXRTBDeMRd! z4O3gA*z9tdq}++-$L0I)^utVN>Qs>oL=FtkA=X?tR&9z>j}=-hWMyZbhVu=m7vWs3 zDWMtM;gM*z+QQ?3Cz<9`VGr-@S$M2Y=6xiVZ+6*8EzS@U|2-6`wY%JtO%BM-v_7dc z(a)cpm|)LhAC#Xt5^F#kS8ca5c0#$*;W#mkF+D7K!D`lq5g)5!B#|Q&k^_bNvwjV} zs~26_#W?r!KFC|GD4fsmLH7pd#km7w^w;;CLOheoa#^80HP9!xVKvkFRTe%ELK~DB z4-GGqK@^P3l8Qp8Fi1XoXnv(L1c`jtV)QCq4P2vhO84l2L(z6W((Ikp;N~!d(hogl z2dgpGmJdS^lp_oF2-8j)3}i={2&QBjC<fB)*V?BHsJS*G3_bcaFo2pJOa&ZRra=t1 zv)yAPaVBvSVlW-dG1S#mG2pC%+qg&B3M>bO1-OlZGY0ErC3rx<0G2>$zn<Odt!mr& zK;8JB{XBZ~yGz~_Z@MqO_`>ge?e~07c>gyUy_*>=Y*{1}kp>oi{ci6!zh3|6U#Z>R z>P*DL3p3HN6tpBe{{81+NcK*x!2{Lm5E_RiPfixT72iyln26E=<@1%ZuYSM(|NB>` z|NZ}Y`nA`>C2B1yi%C@#B&hX1C|>X06}}Ju`rrN=%kwkLH+=K&pKRlIegfzpV6r{= zi0_T(-R;3feD1GyDBerCvn|FB*pWNfxjAqavW-F*^}kvLCmn2LLUN{nNO;p-8g>&= zheeuH?w{P2#zm1o!+{Im#J+0mMoES2?(E=e+1S`<H(RKW!?nPn4uzDEF)DHZBcr?Y zj!yD?f@2kT_2T?2lz92kMT?xkoyFJkMao3&v?<*RWiWrZb)3yDuU^4B4vt_QmI}vf zYa6r!XRTcL62u(C44}cPFN@b-d|yPSr98+1fM*_DuA+1zxJMzD2;zrBu+nJ^8$LJ$ z(*+JsKTH8gN#T<5+UfNvG|Q$xKbzsWq>$G7$`Z#0*q;tuT3+!gcOnOgna#;A%Y>sx zAq!OYEIGkyyu|2@TX(nk*TmYh9i)E{QV^3{0@~cXT7$!yMu39&GtZUJW%qV>IYM@~ zcS_~*^7_Wg@^WTo%J($_DGHZs5Cw*)FKfqG6y!~Im+E4Y^r`Jq(*T5km?P{@WP5ln zuIE!;c8bQ|xOp3Lzo$y$$mgBK#d#sNet&XO;(eYprkbayg_M=aO0WW(%~2OK1NcM6 zTPc5>KR%er%!6j=>O?Yy1P$s88<($aZtvW@`4)_w7hifYGcyhGiI6c`7I*L5g2J-8 zx(1yI_5$y~+?UE<8}4icp;39qh`mgtIKc4tudT16E_b-U&mlyL;S0|{&&iFw2b%wv z|MFjuI?QB%4k7Xnp{M>CvX$4LdJ5BO?>GnT${&h@o~a9a2bobHIQJa8+fwxe+|y}^ zm7YFshp0%*j*7T|V2IP1SPFbQ*Er}5@UFCREXM%z(d~y(6csGY`(OC74X!^2;zxIY z$G1zG#Fc-YJ*j6D7?);{{3__Bc!t&Dk)iMLYhx}syMt?$cw;mhos0Uc^J)w#j9^Xw zF8Y%N!b@5ED49dOVuqB8!Zgt_l7Nm&jiX9K;#%SGNwt-$K**sPqVqwoI4QSYKdP){ z(m-Uk6xKzv*DtkCk1H*JASJ2N<MB|p7Eh**s}yhugXePfb}Fvq8PMNmuDUQaQES4M zK|+_jn)Y_Fm2GrE;o$zM@ff9yV~O#DN;8v60QHKsRvK#n^CJ|_RpFsU%FW(fDsh<2 zBNs+&v)1nI7VEN2!%RSOkV3t1wAxlofDht`U<<6Y`zN(F+!}Poh-cyukbVwx4>xMQ zYK~2naV@t_F=P<uqChuuY*Io3Dhn0N2WBWc0Au9*84rB~J?wLP#IOFr=8^3luGuP~ zCueel;Axmn6RSSULnY#}F-$yHf-rn1f9mwQv=XKwh<R#iCY_#Ql|XsmgLE=${IJ|C zx8X#M0qDyOVvlFMvr}x88Y*`^J+3_s{|{awY{gQ&Rcv&uwq2jXt=jX$p-QvIh)2%| zp`2xF-CV6*ZFVvf2?Eb-8XBW$<e*pw)61ETAXqq5ZnjX^$yS<37?aSCpfkM=rIBG} zoM!kej7r<*i5u{5Q2WeY%L@h>Ow21;Fz_KsD0(DL`oZR7=Pw%_yi>A_e*fElz<T>& zLpXAEu+_*J5tkxdtr7a}Tb+OY<=X%L_4?jHcRCfB&%`3hw<FoVPb!X}JjV@5>h)}{ z44OA;%|JGQHJgZqFo9pW)Bm4;r}y9f=IQ_T&G7aKaVqjCJONF+w7Xj#_%VYIVhjDn zKl>-Y_+y`j$_aIzpZ8C;@tZsW^bbD@AL=^<N4uZ&ex~|sKkP>*dhn)q*(i+gi~Zw3 zbQ3uVfopNg3bmNnycJ17dtMrI123ky2h#T#+)cTj=6A6Wwv&V{M@o=hWxeGMit+;I zda+ss&rKw8`HSF=k_mVhCk<;Gh6%Fl^(KC)Gl(Q?gureE4e)ghu>*${Txvp`^9ys4 zSZe1mZ>7s;Zr{DjLML(a)z@A_4d&LJyC6b}J7)7G9uVdXh!6z~Fe0ZNX}i>+t+4f% zN@(4{w<fJkQYSF)O(7cx0GkFPl>p;hHivZ~<v94MqRt5K($q_9OB_y!v{0!UCOX(< z^X?s7(I0u~rKH$0UBZC~apFiY+ecn`0T*feinAdi(OB#xTi8E1Qo*KL6`wcMA?Q80 zw^8UoQx9?rXm({~31&T9k%Rq1KsGJAb9bv+EplGI^x})@DFO*(wW2!jv<KlV{sdM* zyIo$<voj2+*-VDx)zi6T-hfe{7j!#(oja9rVKH!$)KFd+@^;AIpOO|NQITGEWpxz* zuK}u7RpSQHv}ums6bPP#-C`~)9*$%vQ*ezmqsX7etpx^WG!gE{QfYOvIpQAE;9n+7 zYHC(F(Df=eSzKI(6htn;jT<+KvoM2@qpr!+A|r~F#R_{rfD98ek(dCP<J7lcD59kj zngkP6i}V{fKs9uxW-=tMaiSg`?tSZ<-@JTj9di)`PoGmy04fAIxXa5c3<J%aotczk zx}{u86T@m&(tc)wV;u*Y3QQUF<Sn1}&Z4ouC>9KGG4hQIrQa(pDc9U^J<2#R#N>u< zu=GaP@BPd9+==z>>-vYXC;HN4QnSE~6dvoL&#jWoMmvGi476&iz^a`0hT5^=jnw2~ z{DU1#ffoan4vEZte9s>d3<@z721$B?^36+6kO|2m*e$n;H2`p%CCq|MCC3iSjp^~& zWITq;9KOY5JeqBEs_i~y7iK0P(}&XI%6MZyD~<LN<u9ORk4567^Ms;r9b-gxfqHwz z`qC7kDjtpMV5;pv!&IMP3^1B(^!k_tn$py)O(Lcf0cYdx9j6|>(j=l&6C{|nfuVC+ zq_XFME$k{Cz<O6ZB>J$|mZlq>&NyM5Xe>=?O*}@BVSJ4H^k*ki*=n=Y=uVHv<z5I! zCX+E-{^4kRiu`U64w0f*80H+Yf`xRFug0%Dt%#<y=SAPQo!K)1co`(f^57O$@)N-h zj)(IiGYPn%%N!3+oQRg~pv)@SFRDGK2@r+Qh^(Z(7prW_%7)acHDFw`T5fk+MRKJq zwhMY=xa)*HY&DX~Gey6L!Z?`<b)_IrPr!dySS*oD$VGG7UzmiC7phQRaB`f^C(?-E zfHM0NaYCuAZ)~cWR5CLjt2CH7QTiYBpCc(Koose`)$VDA6#qV_K|eE@BGWpP9-kWL z=A1+^Y`Hw?Ra0q#JeGqgayL(8eiL?71d9|&W>ym#B|FIHKj_o^0uPR`-+f)XVaC_c z41%Gb{P;^)w%>pC^@kzT2ROmPIJ&thEyr@@v)_BA_0N90`jziAN@e;Am4aAUsl`K| zy;E^q7{|f(J)?3k)tHlrBINUO$%8cRQEP~gNzW;?pFjJT-#q<qf3x>LefjKrn`q^c z{{;+ilA79c4&gk^zK5sim;N6=`{)1EpCC4lPmmukH}Qc?g(raiVTRzzX9q{1&$-cK zF8~CN(Sr-l0sV6xKK4^8HAsHM%BDa&5t#%SjW^M1KZ&s_v~G2vjM~B0$-2UCW#~;b zPz!k*^8-N-;~cYbv&G^z0G1)K%sEsk7eI&D;>fPExdSQjg~QTz0cNnfO2&4(NW6(K zs`DMHOad7ewg4rcS^d|e!@ar89FI*qZ{EDMySG!T)=7=U@sm#Luuo4;a}2Dmt`cge zk?=t{OVBAt3wV4y4s0!!tDphU8`~~0LX=Gi)|dt4W|c}%RY0z6#hJ`B4_>R+z_O&- z;||1%$rVfFWl3Z>5hHW}U&YBn+q;L9dX-6#1R3BkQqC4NW$7^~*{P695AhkHXkk$H zN3I#WyS01!_9pBedJYmKb_E0%fn>Pdlatr4Uq_mTa)4;;SL;pC^U}%+^-wuxCK6-l zYK>1$15TynfG^65XR_nLNyR<P<G=^vl*av!@Fa&##neJ^LVF4k*KclZVPW8LXAn(l zNO^M-DmAh)&CX<IVEbIXa+yKJBTk1arB8fc)mY(Mtki6*f#Z<+yMXsbV>UC#&3T7; zf%S!O{@zixSgv(iHA75EaR0>QWHLRC+S>lk7O>~jpZXMe3+(I!Ubc63{_y3O83HC? zK9|$Pi$=+arG-dv<O?|_6<?|`O(f}g6)~W4eY-t7J)NGKUR&QFFFAz>Pe||MXu*2C zv~lV1@Q^W`pI@+@I`Yy>FIoy*6c-@x(B}*XiOt*xB9!kh0w_bdNr&}zFbybbyc)1^ z>|$PvCXD-3&ba}bT;4m8kwk&;<SIi>ijA06J=n*BSAI$b%l2)Tc3`)UZh{whynWEU zRY=7=zS6g`poTIBtePATh%s)PgY;@WNybo}#1n(Z9Q5sIR~u1!1Q!lG4*D+Z9}?C1 z6q&E&T}YQOp1|SSJ&WKMzcdf7j-`=RHPdu)I=!8%;Hd@YjmKdJYB&JOErM*7dP1yV z92QhW9vg>|Z-uVKr4C0yZ0oa=<)$>q=Tpl0zIj}IX?^yn+(;+KngDu20^!))<OHtw zXP2jo_4YD2nmW)#rmP<D&7<<AxwKLQ`tWz4)8Oy#=IgEXOiI*tvpQ%nz>$Z7B9czT zYLuz!o=t06MLOb}^+EY;#rzdNv3x6dOvzlrL!ttIB9qX)aE<3Dd1$H5rxRnmQUFBo zQGF<9<{%?>ByGcv2g$#fOlL5E9@t6mbC?GiJ%Bur<$rRYy#;D4f`{(_FOQ}{pM)qP zZ_QeT0w#r%0|K5C>FJ}RLsE2rR_v0MR`;mVE;qY-B?J;e>lin&7+tqCJ%P0&Cw&U@ z>=bW0?s+Uq#%?A(J~<v|upm9I&Q9^IwpVEdv-XIb5a^wso{+28oV-|c^;QSX;?-$o zOIuF77Id{q2o9r5QH?T=|CquHko0o(4%2{X&M`os#tQX%#3?YGG-vdrW}QAF4t=m% z9njMTwq-WJFZ}ptwssCSx3(V=)BF8>dKj=*1`)^}ZrJW||F^&0{AXXTe)sieuPu^& z3X(lOD_LUxu@RE}5ZQC4l*+YS4rOViLY3&H8ymF-y^V6??Dya3|M&lYQER^PYB*mN zwMJ>=_oy`&Q#vZ>Hx7kQe*9y9_iz1&Cntv_!V=YgpThI!_Q@xJ{(~MIPp%*IK(Ixg z^YD$rdO!7pr8s)!IY8i_f_cfN13pu29V-okdKjW<EGIvnAy#N39xOjE!YAMFz}ILZ z<i>!9rpdp?C)SS(REO{ogR_&#iE24Nk)WDS68cO$G0tYqU)d7{=zBeUv5;`c>7f>k z=^H9O0COGi?A}mX%NMokH5jEkJ3CkiRw#s`syLuC+gqE9^K*O{<79hhZ~f9`{KcfM zf{s-$Di%d9-Om-PHPa_J$+v(!NEHBb&CSkWR2&?gh%sMl@_jguQEb`V-d61-T0fou z5YNnz8;XaRLOJp;3Lr}D2dKgJ4c#I}*&6mJE=IA(g3kkbF-8uN`bw<<wTVChxtLfK zw>P)2G|<I|uH%(KxZ(c60g1xO(jy#Es)C6@rR;1RF(3WNOMJ?N`D0s~TPS-Xi9?uG zv5sPi6A|Ob`$`q&ao4q4cW&Q4IXOZP5~kC18tkq_F-#JCPL*;A<`VrQ@C~t8J1m+T zGSVnB!`RU#I9KR7;CCnYmPvw%0#=|0aMky_t^DEkbY`JisqF9E1x$CLy{0GGgFRqW zP_d`GljG6#OIMC_rIRevKvv@P>_S+0UG$;Z+4)a=;$tg|bK3{Uxnh+#(ZRkfH0BP* zgR$ph)mjzxA%Y2&axtGfAuSl#1b&cUcBRDkGF9^V;_AjFCK7fF)pKb-0yynXlZl~9 zLuMGvPD>31n$<JUKF7e2(u_UE6vvq1H6A`Dj2Q`X&vPvCzWL^fGD)&VR2gID&{6J; z)P%HDS32C1Q1s*P+e<H&BzlScCS5}Jin=l2Q#x3Z=a%jLe;Nhu!N>hYu*M(rM(K`r z;|r@RJn>bY;4ws&6cjfjkv;*7nxemX0k{BTk9BSQZ$o&)0OPRhhFP#yp2@t-Rz6m; zl^|HD$Fdl$NKlt#m)V&q=qrFWuosjYfb}F)igA_<X{xd1DHe>>Q24IdRFW4-{u}Pk zq_n1rH5Ge;=T7!a><o^X((C|{^T^qgz8wiqseW*1d@PFFc4KZ*e4c(UVzq3rBQDKN z5ei^bf!de^M@0%aB#tYMxru}lV`6NKZJ>PjEINq;-?Hs#3^(M7LF#36nNX!92UlwO zaaI?bTAqkqt2>iKumx6$L|RJCE~>0EuzD2048i6HnBxB68>f=&MdW*e{>LDeKtpF| zk)Og;hBPy+e24or9mHEQtmo2*4aHxyRiCGGez2)DfPEwX=hOS#zlQYmHikXx=5T)( zJDh1yEEN^Q39G0!=K)Y2iv|q<W8<roI6aU`MCVfRxrrFTRpKY}Qxgl55)~!ySYZ_? z@}?n0H;<X*EVy5~{{23dmi$mq5~=VSi_Ec$B@+;7aO9_m$VI{^nvv85hn}&3$geB~ zt>;i1!wH4rcvMS1bVg*ED3B@-PEa+Elpfh6(g?Er*U=~C>%9yu@8e97Sdij#LnHo! zb?tj!ZLnBF$-fLS>H|Od#m~R?`dh~*C+}0I<-NaS2<(mO0^gE28xt@5=63J@fMoyW z+Kszymeu@pG@jO8`2!?-3FCxw*~-yTQ5jjI)S9tSrx$v2r~gmBdivk|i_?Gpd!fx^ zDl3a3ue@<}U_h<8;NIi-xOVmOfAQ=8G4c}3G*suI&KuZxZ=K3>-Sq^}zmNIz<dS#j z0pC0P=iKZ2H_%Z8{|+D2+juD5ZN`2I>D;aiv;QedE>D|yBPKy%BHRY`Bot0q-A)M3 zN=_Gmvk_$lSB$Ezts6f942skQnNNLu#Ly;1q=|*ld}NaZ%&Owu%rxs<8jJX$EgaAG zha@B*5~SsRcfL#EwzD(T*}225Teop7-@0=L2F1-=w{Tiha}=|J^OA5L?OI*mz;y?h zFIMUt%+zXu$tb2oII_KW0F#6Jqi4*{gKXsGOKY3E2k8k4j^-WMkyFdLmo1jCEpU@@ z-m%JgHbh;r`63Q}**_*<L)4J77;eq({yv8RkHaa6e_hfF5x62q)O#T()fnPmx0<A` z7mMA#yZOc&Z=v)E83}$0M+hGA%a<-;N?}^y^G3V<(xpox9iN@e%z{Reu<XhFB?|$G z%fq8X4!`S9UBg1aFj!oeWeWs?;|Il?j?DuB9b8K!fkM{2i7T2p!$)xHH`{<+3d-~? z$3W&8tzs8uM{}djXzLy1oH-}>7Y7D|&6{j@c;Xpk9*uEQ#nzHI^cYoyUs6*uW~Yf2 zLozfCpqwA2x=3l|ez{_WF(l4_l07t>gM)pXFjPfB_w(-d{^rhMqh2fKj+j)cMQ?;@ z@}z)nhOn7GWyV2$3($&0@zK%~&%W^D?940!_ESIebI645@9#3%m{ElL3H9vl?=y$5 zUAqR3Tw7+#UYwg>c>3w<cu6tmB;7Me{0J+{*;H$o*i0BxFcJw^5=^AS8Q(^_L-?qS znd9|+hBP$I4}k`&GvKrwr_1BOGc0A=e`2H!O11^)++Uot&mE(mL;S&#A2kL>Kl}K% zOtr)`VTHy-p>Yuv$z*{<&2*9KJU@)7E6I2&A;A;J<@VqvRcVl&Ukxx=Z<;lwRqxa% zQ)K5q+6_F}LmBE)GGxs{iH0RlY=^)NnvSGF6H<d|)9<!p{TAeM<=`T}Td%>mXc23Q z^x3UQtmw<#9$COc-fhJC9ZYI=p_%bGCLRzRtxdeVM7Z$pDpMROEL1-_&2X<BPfap6 znF-10*~&B-9gt#rsLIbzrzYc(xnvYT-fLE4i8SkXF3t0Hr;{X5p27K%a~EhCI$Hsf zHj22Ip@6gep#th5Ivp4_ux?mZFzJy|g!Yq3qCp@K%*K&KGBXwd&0DX?@j)Us_fI8a zXKe)3wOZ&^MM2xh_QL}~%N6dNwoqyKTS^1cG3s2oBs7eV3~ipDmFE3v1HtPjd$eR~ zb^#l^T&+N$7o88*+?1Rq6pgU_3+3`6Rj@XbTAfO!VyYP@jekfx6x)i1Gf6awRCrdW z4@VVFbo#5;rJM>Q!lr5m3P`<cF)|qlIItK3K8trrr3q}-Nx2J2Tr%%T=nqk&nn-4Z z@q*FBzRg5}w4-hU#S;j{rQAf}betnn-Y6CQ(5!ZQ-NL^xqfEFK^Pt~la36L52AEzZ z1i9Gt+E4w&7ysbpS2$rW4%3hBKw6hpl?8Agt+zsdc%w`1?En6?+V);|dLq1#AqZtu zoPm;kxCBkAi3!AX6}5(c_wr}|>O1}a?*Hih55INx@|_47<5D73$px#{Fo=O(Fpl?U zU}*pt{?R}9Pnk;yn8LI{<%YBD!TRb6pnv>F&mWO*^t0TL|93+60XP^%2>}Qg{a|np zRppRBgN;n26y8_KdR0p~B~eg-&b64a3-2!1m5HD#5xDVd>2oUH_vI}y;a3MpRs zr3YMXG}!g5X3!qThf>)HF4sADpkhx=PEV=UBYR>Ls)pnUIGU6YY4wlr&EQVKxgous zkTmA2<pKx-ZVo6DmJG_}&{%NNb7b%B+`fA4I+alHDC4;nJ=XGQG52Y+WaiA1nlDwj z6^I&7Fb-WBkIw*yfHn~HAE=(#?p|77<rt<g9pLpKTSSi%LOl46KZ$)SvQ66U8T{gt zlPO%tsHbzpW-@cQkLfN83&f_UkWw}oL;*B)tOsyu5<Y$sLvP={LlolLwX1Xs2Q(i6 zPat;<ti+A9v4*S-c)Bi?<*|5`^wU<IAOHx1Zh<lR<3IMf=bwL`$Kk0t%tYU;sm3Je zxmB<1+`X~5v_yeJ4n>6aym02^OokF#q?$4!#I?aIrsgRWYwGDZq@|D}3H*2zn}_|5 zn)NiFgAL(l{=|4O*1)c%)l0}qZr{C$r=Q0n=M|Q8A}KLJx*Z%3x9ZOJ0a*&98?G*| z@g|Z)t816W664?b&Uex1gjV#_wX1NAj<BT)#iN7WLheMjN=VU&hjJ}Q1`8h^?Ih)E zetwRSIa@y+ij>Og${NYdRFUfTBftN<U&o6tUPp(T07uuZT*hpB_L*mhCv2>(!drlC zb?wU4jg56?DX*#OEAFZJ))Cxv-F>Eku(*UzrIgChVH?oHmdZ?Ko8nO>=OWR4Iz-4* zr4f|MEC^zA%q$R`_tMB4_~Tu}&Ljgz9qQ*y?!Zq!x?!C|?f&u6n~ZJ+k8P*pOO^J@ zzG0jqvemuF6sIu*L=Ql>b9ymLiA4%-W7A+jr2uJ;dH+{LCi`(@Z$^R)Z~2V}d|8jq zv8%wG)>cCgb7yQY*zHPeuvlTUUZLwrLuW9^z24c`W{ZFWJrnIkm16?!B}P09-yiOF zB`#CLsMQ>YpNlY8r;$oeMEmtfB8_Sx+12bk<x+)JX2yo32{GE4&!GP#1wnhzaUvN0 ze7o#h&<m<iJt^Lp%w(wBD3d4>J?lo2f~V|i3O|+!qfN3HO=F(S>BK2I<*l3oV}yDV zDKLJakca)H6nrIT3r#{c(_K52ek~g%uQV}DXo9%}_7zPI2Z5D65+_IU@)kK%zNWfQ z%2(V+_N4Tu_%HK$a0K*mAuE%_v8MO`Fu3{%Cy{xt(fsQ6%Y})>btr`#2eg^QCiXzO zf*csOroBDFcdG0YKI@K!`q(b4Umlem3CPz&<+Inx5RgOxh&d2T(0XDS?5<#Lc2`UI zsW8fPJ1+LK>WOIHW8&%IyRtbZ!<!AB`Kh8&EZa^K!sOVvvK=(jR40r4T1ix)oF)=H zUJThBGKRuuJ+#``$GDhNiQS$v(MCfhR`>{h4V%x(YQn|y2s?CmYngTyH1_rr!T!=0 zKmYO{e!oCXw1>!%edm_@Jd(Z5&S&BLXrU7N=Bus$^~<$?{mptl-<wTSemLqR`+Bhf zF_d1ZG)1lXAO7{}fA^cGzx_)1q^y}Km%OE@JyIMWpn0lK{-fXcb&<DXG0;5jst=k7 zJK8Nz0R3Z_-hX7j;+*R)aN~_)eczzp783*?4={nLkITCt-}%@W`G`7c>`l%vmKX>I z@XCT^zrszWOsr(Wu+ABoM!dkO#9|~mX>#mk(ob=30(sbZC2?gOO89fC_7Xdz3M@xD zVL{2*bQLj2gN0jJ;;H@v{Nmf^p~R>qaoov*N#>@L)1_ID!WjY2i9Ay~Imyc2ARu6& zIX+18C0VxX>l@M-Ml~{lS{XHBR0WnZoyUQ4qpVkwDQh)^=gBL@2fVzvm{&3u!ZLN0 zdsH=b&Jwg5P*-ol!{KNFXPo4U7#o(l2O~eRx;O_$Ims2o1n7_yH8u@=mNdJlMA$+~ zDYjfy7Xalo?+`A)C(Ym9y1hwHk<dwoC~f8`F(Am1<>0047I+93Cn7U%yzv@<9>*04 zxR@5~epG2qrKh?5#`@*ul{G44(dF}*sh+Ar5o4JE{lKy5HcNo)t*xy~moKB1Lj)GG z4acO32%b^6cYc0WS`G9hVGVOBfw|dJxuLtR>3LJGh#emvGgxz(3>03x(Ez5s-7T)n z9vv{FmX}v~UMl*4=D{<VY_t>4eWP0JcWO+Jqm!bXkc3eq;mq7ZKNPur>sBG3TUeqx z);eH_eBb@O{XU0kgTw~Sy{bwMpSGH9KczUL7Ut)H{un%nW{@OXt5+EUym3;(DOCYy z(Dt!L7~1Ead-mC9p9VIlL;>_61-{$xBe(bVpSpJC+SO~+#sWqxkR~C?qb^pBYa&^J zWXaE2i6S{K`Hz`oID4JgtzZkC!wlgR5A0+bDJBEHA1v4w_<#bvO>WCVRJ6*l67x`S z%DKiP$MEP9K4+-=pGGejMf3L?_K$Pd^PPm1Nz};gd?n#fTsfcPeO4K?1Pn`fP3kUL z*Q_bRD&wTCs)Vq5Mx-YG6PQ3e?Qr8VwvEZ9TN1Jmzqk#AP+*JI$f1mq^uoBX=*Wqz zg9ou6$hT%QIn~?-!6SyKYE!3;aHG)b_A4;!saA1%O11}PDnOi(C38c?p+UmkYPb*e z25d4;fe5xElDyrDpge+SUl29KO&;!n`^V2BGLM-9>^TyLwI3!T=mz#qY8<vssNb%J z;s8W#Yv#W-NhMW)J!Oe8J;(wFRF6$x;%S+ODwQpRnbI8Efi2rY`zlXL0F`@~FfF<` z3J@u3B>h}XHs-d3T;=&_ok<*B9B`Nso|Mc4(h8D<msmF<+n`QHh64(a+BxA>>gVy9 zg-Wm?H;ZphMB)kbaHml)m`sDK*iyvXBp^96!<Hp`+v?nTbqJgq(vvYbuEJqpb2hSA zoa`5P@Txe=+)@H7WGW1{6i88)`Dv4p73hy8Y=Vi@Zq!gKE@5ETLV|7XZ@yuKL4o_| z8W4n}lT>&`4KV%~8%4ieVH7ahLQ(0$v1xOZk?$lk-pZCS_vvKJ))2IuF_rUsJOL0I zz~itYw5_#TeEm;;>5DIa@B5FyPyYiu*bvx@W6Dy1^0}YwfB8Gj|Me@iZ+)Lg^BGi} zaIf>q&G!HDwLYpf|MVN7n+NYit$DP27^fJCXaD6t{Cfocnew1{WNq*qJxspA6F~oH z$Lx>r-A7^iIbZvzt8Wwsyyt6i;*I_;Uz%;}CZSE9t5_oTR}nEqlLfNlxwil<*8puf zrX@UQweD>bk(dln7_Nx%??ark7KM)~SlMZXqho+-iiW^4$H|Mxqc(BizDeugCk7k< zWYMGL41;k_+9H5J&J}{NI>vBrO|sA8b$IKoo4#}LgL%MSas*;MKE8JC`kgylSFSw; zg64^!PT;%;n6l>r?m+-(>2Nn1538HwlNX$boG0vtG=n1nhax8{zEx@0?CfzG$Ei9F zal9c8j8az{O;3d4Vp%n)<xh;Gxem+)&-3_X<?>e^!QD}cdsrvSk%@3}B#fK||L*J_ z07LPA@9*uw4yrY~*^_KiesQFeJChLhr>4OZJRrA)N<_c$;P`&9j!?z9d}#v)IsRr0 z296($1ir1+fzLy@xeH>hApzRyQMs081F|`k@IxSrW1^WT?TmvDNZ}O>#dT_hTFlo1 zHo)~f28{=(M9<KNe2a=8TBwAh0;ooL9pd=VYC!Yw=JB_tXEGdusE*pH86uOId}z!N z=nB1djZL#kScYIX83NI<{r!E4da<8=^raVgqMLWNu*4*3n#++#!DK_d2XP$YJisAN zXt26;7F5)|N$DR>Ey(?#XBhlMBd~=krLyX@W5OkqOUp|?^;18I=ZNzj2d9REPV02( z&*hcXjr9%1j(VqXuU!K~+01gV%P5qPwrR-+4oiNe87dK_@&(GH1B9A0PNtf`rg`Os zif}DQF$`3-iY|6xyRHg^Nsij^u3*2h(gr{0ko~z;?0+4_^yilIDAs?>`<{8{ln%@P z1LARKg1|ssxK|lQeCSuNUZpF{FDzoZ)k&2J<opECyjMN~VmecgA6Ky)WM>-IAEXw# z4(w19ke(Nf$3zm17Kknri7{v5*a^(_2?DIItxFviuWi2`&#awB5T=3JVuTdRuTD+@ z{kUG9S5SPUA4{e~5%3)PwnUj!C_@z<yy8+g!m_901-{<X%05b%Dq|NBSB(~#E|$`P zXb*T?^{pZiDzBY&>LFmCS%hpgbOio>T7*B?Iz&`mO47!{JhI?7>>8uMjhj}LW|}6C z3C3e`geiM;N>m_z7A1%(7p(8Pc#sVNt9XdGYJ8|ujm9S<agmzXM$CHj0LZ|Diw)qf zRkO#wdN|EAn;yd~lIwab&S;?~%SKAK2}IlSLn2IDS%xh48Cs(0L0puGToMg_N&!+p zS59&JXbOgmERzIuN(Dw{rj#QjliT`*i6{08Q{k)?8HbKfC<#`_1mo_{>C`WEvNVM$ zWk3urAsdWDcB>D~&9KfD?ifnh=t`?4t0l?BwgglsQ4~ZObxyZ)i;D^0Z<QGczRC%x zkD+fJ(_3LRDup)*4*kqe{lxcPeLb7a`x*Vneg+$wMaxua7uFI!qFcMY|MPe2|J(1> zzx;CdfBe^{-@X~CcjPybYK?kpklpckj7e4vLGOR~_x~>15R4;GK9IF}m~MFj=pUx{ zo_uz2#s}a&@U@>i-TnP@Z=Un;=^Wx1fEb_>ahxA2M<{ZNg~B-xg<EtYxYLJxS><c8 z|MHt^o?G=FKOS5aM44m&Xi*hKn8Q_ee0ZoTPQ4z5pFmh_f27ZGdMW=5(341}NmXnj z!&2vasOSkeM&g}1oNR%L08FT+dZ}DxKVoyo@rJLOqY;e7{tg0PURuOsO?@JKbR5lO zK7v^nmsW7$D0{WrgRhS}R$NKbz9st-{~HgIFBT=SFXxM@hp@GvuV>+Z>6T&A5KFa_ zMwp{msmVv48fT;DEI~#FaE27m()=6;F)ls)%^cGUi_1JXowu|&k3~T*agei>b6VN) zESDtP8KfN?a)&2b1k{xQ+&|5ooPgt3mzU@nZi{OZ2#b#p3<^AAgN9ZF6d^}eDxcD5 zYtx?fjZ0UqTmhKE2$Ji_RF9#>L-apwRmclOod(qiqz{Pl!$+q>5PP9LI8aSqKzl30 zM`IXo9h`Owk`>LV&w+HDEzk!3E2J7Dvw5803?PjcSSccpLJ1(LXl52SDO3c`NZ`H^ zW}=6C+u#4*cM*YR%=lk2MS=H1=&U<FHOukbZ8i9Heqr&8pa0zC<oNa;(*GrL3GUpM zohD~zu|&i0V)6_21NpDm4={WtQWy>y)z)csiiJD?Ju@>K2Z0G%k#RAJyN((7i$DMK zgd+|P_n_31Iy^f!2c(>zoBiY`J_c6c*|Exytu!%8_qbcyw`^CkM4W*zC@<v<W4D52 z!5T$}^`amK6_ku-W+W~IMg%bp+3NzP3e%6q;0*S_w4qkh%o#3BU!K9g_wR1!R<~an zygB;U$GkIYp-93Nra^yZCgX~qv;pi3UxL$GM0vB0EGcuq>o6#<9fN(wz1jg!z;lkd z1BSGrsR6CX$huM%=U>n;9U!RGM`sD_E59k@1VCp_$`rL&0OKOs8&i@Lk;XAQ8G{1r zohdBIU9fUUI^tM*+?req$u>5!*u$~Z921>;!g|46hrM^!@8Nu<RqQ8lSYS?v#~{p{ zp2d>PG`@=60JB{3O9Xk)wo+NBKGO32(pEUNfVL{JDTngT7ZQzL#bw2)QT?fA@vNB- z$5V027V{k<5j!iyOq)>1WUP9sNJW+VxG<|y6l^X+H=*0PmLU+go*fUpbAz<vc~~fu z>y;Iw0;}p4p=8h2x4aat8kv5N1995qS1l-jIzvJHlL1piu3l%~U^=m98g5qXh27F3 zFyn6INl;ih08(M&sWE)4hkSFAV}jj`AD=&vPMA6LC{In9SVYXD@d+(tyV4@Q2HH8Z z%+@4ggyZ3?kz-`TaO^b~u{=21D9MM^FYj35DQ{D`7H7ZiF(^a9BUnv3rN47e$Y8Pt zIa=Zqe6{77JPy{4?*M_HUK=|}sJ+h5{Pa)UyuG=9aQHBO==Z(7`2Hj+j^atwsDfnQ z4j&d6B@PblqeE)V1*_J)dkfh*o_qG0fB5(R6BKor5{~BGH~*04#1laOzURi13xBW& z23GLU)(`gL;9MU?`N2m61TcED;UpfYOjaABjfxus9yJW_s@i;&T#@D*1FS2h$@ndJ z>uobMo54Kj78h6YpGtN|1s2%^L14K;0cZs$o14!}&!i@Jvj8fTj3a*NscGmtY{67( znwp#-P7eVZvW=46_<USEX7+xV6UaH@u%#V%TVc<`XDtEqD;2Qs)ytQ+cXm-Uzk2No z!F0ZvVzD4L^OvBPB7X_4Xd<SP+UyhWuHor{0tCTEUa{0T2$`c4hBrGn{%oD!6XPA# z5Is9M%0U62Oi#k3w2ewq6&xJ$ESj$|n=cc6fU-&1De^D*s}2${hn!#ZgE~zp-!zy7 z4k_I_t`t3d(swp@2)<MN91Z(cLozQ=@aN`d;nNe`AY}lrfA)Bv;06q(t<Ad-(;<aI z0YXf@R4zSz{b>X`k$u45Cl?Xzi}E6YXYTIZJLLS4LQ35wFcg7%9H-!5eC=dO;L*f( zB0PdgLk|GxdExwiq0{~u)(#G>TBSnqCb}+{E4o#tDq!L{pdzZ0HY5-%EUlhJ#;~F= zfjC~3TpJ>Pv`PB%X}dL*N**8Wmurx!RYVqx?((&#$!fiI^R0TV^1=%*AQBI<xOsaU zBjiXwhjK}di|tB|Ae~7CA<I#NEr7cbB@F1Qs;;9$Iu`rrCw~;y78*y##|Nn30R1_z zKlaj#FTC&~lLyrucI_{G{>MJ~$xlA>EdO~1a0YV;hdXnfAb><9?MES(VGSwuqLJWv zA$)Hz6Tl=PS2##U1jklmOqm84wOs7Q*UZ}|cd6(N8fYo{1D{C3rfd1s=#o6Q7##}u zo9EWGzcXr_2k(ravB$bsI-yVfV~%zLYmmPYCjpb49G@@;c#Rc`CF4a&-HfrohzQ>f zx<!(6-nKd7J&#t*3d5bA9B)>ZZ9|G~hzP+<=54kI)$i<dRmfsuLS~iMZZoEYeeO)c z)zF<gl~Ai1iI4XPN8!ImRYqkdS%YaTQjnbLhhm9QuWWoqeq4RFPjfAvU_EcaNm{G@ zF;1|q2k|BrPYYTit|B+^z~gR8z6KNf9TI25$;og`EPOqYc22s2$I!+wh%Jb~(~Ksj zA_?{!b&fb%<|46vQSe8=NV(R`J#utaa@PAqLN3bJbi$H$T`R8JkDRsyL}OwE`J9x- zk3f`ILyEW>WrfFq>!kbG@$lGY5A7jSoQG(%D`Qb*l%l}Jkg|>lxZ!j-K0aczwd!E> zIDQZ{&Dbnn$N_~M>6<Yap>93YX@rx6a7`@TbR8s*qEiWbPu7t%f#|<(L;eosOPh}5 zfXO33snrTWRKuM(YZk-F=}=5T06+b#tcp%Lmu-=#j-}Ybw?Tp-6ctsE$%Ge!IiL{J zsk}L6aGLrPcjz|Q9epGpTPM>JMF_>?XDeniZv4W}|MbC8_RgJ6f3C;Sk|9>PhwK@n zz>a#Hy}`pWK%f20kNo{#|681-jFd~xUkIAl<a`Xh`Q$79sP=%L>*s*`xi|gU9U}PZ z9eq8D1~^Hj4FO#qy1HB!f-<;Z%@s}rS%uoo)hLdQ0-#nkQ;0_avw?@haG>Y6IR+9R zK^q}rYUATei;D=VKq%zgq}1nlO7ekd(&w`$d=b)wW-1Vom#cVITpja>hC?{ORH701 z7>nW&=L><b06tDISG>pbiuaf*rMPg`*4FXlWTrD<bne5!#z`+KyaasQ?MEh)0;zCq zjkN+d1j0;zHZx6mDZn4irs^tW7|KPVZSEQO<Udge7PV{ATfzN{bF&UbK!h9^s%r~N zI0Zm7E%TXa$hTro#?h6NY_`!kbcT?mWJ$CHhgF_XCCDQoo;`!Zd=BqsbY<;QGBpFS zg9N#9F^78zY9>1cc>;Ky$-Y`zSa|Na=iu0^uB;#o1ce6oI!<~{Emz=CkOYns%zG%{ zV=?^SceeLW@@3jUi~{q3-ew*EkvZ_t$swPZPS63Vf~GqBX&8^}lK)c^$ZSM1(`jUC zHt*a)O)`W4U%906?TG8QJBLTdNIpy82UU+`5-t#;G=ehXyDNAyk(x};EFdu{$6>gG zd<`DMel(#ZzYw)Wn&{UUQ91-KsM2U0on%3WYfDsa(fNmCQnHdtiajGS12s=>y|lar z_f?)$iN0%AUs+#Mnzd=v!0`ZFt}HDnDvpH6$|AD;&p!POaE6%1@%|23iF`Z$KRSV- zHdhudUK8@OB{cw<CM6DdGuOM88`l{HT48#jdAk~RgrQHNC0}tC&C<Bz`W1OVk{xpH zl7ofWNx%6`M%QDoJVzIGutI}nJNn|>&K6+($F}2HV+K}7Jf1|%h-FCck!XR@2>%W1 z-Blw9E&=hu`oxInI*=SI-O@G`&7-djl()s(8RiO`VPz^eVuJ`#Sx&ileV#-sUv*f5 zF#JoT3#yM#0P-cEUD*vG&b3LE#vDZtma@VWIaACeq$C`suYH>-5p}y1ny}lWdx)I5 z@lqtJsG%}1hH@vQ_oS?StQXQdn*G`?6UCu65L}75lyFiV2yIrXZ^U=u<xR~QAsajJ z44Q|??)m|jtLTnQ9fdFO>Zb@90ONgA1$j8j&K{zT&w~cYNM?aX<2dQ@YD)%GTdo|~ zd>N*qjB7q+-U1_dm{B5@V^<Sic7g&*e7$EK3fyB$nA_OFU2vd0>RDuu86$E_c5$(k z*O>w}sM(xX@jD(|3{Nn<c77WUo*q^roGuF;E6<1SHA9j5Wv+%K83%?4f}Vwc7(0a{ z7zfgA=t3<2Xq--_w5irIAC!QV?#4NyScfV4v#)hR<1>+X+RQ>1=dJkSVvqsFmb4(Z zJ05!IPYki0bSjs|S-@?akmFi6`YHy2@@g?S^p6$I`v}q=3|;)t2r`mbQYsey-rxRz z{i%Qd-*I8OM?K1;_csh8SRbH~$NB9nVMhDk`PE<f2fzNea3P71xdbG6kOETg)a)l7 z`o}q-f26+4_qcON{r&^qQNrj+AH4QO<=eMkhNF=g4<0gLCt(>V>|$+(_1X?0Indb4 zB-Sney^2qfnP}{JZK)Dcu+!ID;;eefR0v<9qz;l3TxQ$MOsB|t%$Ja6K3iN^2JVvq z2KH$|r;uQdwowYX5(LK+%+ZFY30f>$a}Cl$Bm!I}%aJ@5N`~T{M{;g@b`FDNBAx!x zAN`T_b(IB$xlV-$yzFeU!$d}H?wqY~^x3;T9SzDU(q^ing&RYlmLlG<ESm7;DmdGO z9ihX9A?M%@=RP=oW@o0cFyM1btIjGADO?amq%s9t2IdK{FFiGdCt927c#>zJ8#p?= z_`Co&Ut^RTX#H%eq}XyY(WLyz@$SwJM+M1kK*8O;eON<?remed&Sm%@;yF0c=`MJ$ ziScp#STF(52*MM6<<bTT2_)Kb!b3x<*BZ1RzkaoFxV$(AafQ@Cm@^m-um~8|rNt%2 z{x}OkXbhl<Jph~mz@YkPJXY|GIS9`rWeotb+E{J#^fx%aaI-VC%ob|d^3;4UmXDE` zn+mBQ4%nAW5XZ*x;a=`|k782!65`pE7mC2D0*EiKUP9@AhiF5+HaEXSO<zXm^|x;A z?rg)Wtk=;NLdZh3Jb_9~IHm*-PQO8B(6QZUiETgy8KE8OO6EzQC8Lgcg>&}G)vM#F z2@;(?{i#phy}SMOZ+zpofBUzprTkkrZv5Wwe}kvKeEBko%M$lwAQA1s--dI}C<q2? zG=V*k;;_|tHG_IFB7GS-o{!LGWyk8IHcP<d(uEBS3TXN(mG+eJ6+P;dX(LHKqxjx) zkDXhUz8*(cZUFa#Re$cJ99_tdZKoTyQ#%77hSEUTEuaT_;O5Pn9F`zak{YFjC1SmT z+DsLWQo>JiB!?mDh)3?Q!&QT{W9Z58l?zFmlU{{3eZS%dXbld-%B9Ph=SuAq%o5Z# zKLW|P1^S#FfNn1q(1U6s<wUoWz%R1O#7wC{y(V!zxE`h--{NS}V0ITnBh;;gVu;nS zOnFln*CjY@K&7CsK*MRBl#oyyb=tV)=CVPJi#`PTszWi2((KF(7D>0wY-DdlVMYNx zPy97aKGA~csA8c+&p?C|^dlcPk>M*KJ+pM^C>}xHY4$9$kXh`MRgIi=rIL<S3@4EI zCiZ|4rukPOmh4bPB&4K{f1b`Gj3u>D-|%g>r;#GXL97>_sptM@n_9uYk7E+~8X>#2 zR4mIbQ7jjm1mxYNd*<dAZr!@Y1*}t^2+c~+zik5W-Nn^08cB~|f#H&o5n`smIZ3g7 zoG!XXQ%L#!?9Zy+%CHi(pg*G=C7MMhfTJ1_cH+SPQpOYx3wh{cu&@Tq8BqkC`4f^1 z0E1{gZ&EFip-w%VNI{R3n1p2w$u(eK=Q{=mhv@z!D2o@QipY=IC(ZXc_r}7T@<)(i z_T!(`DM^~FWRV_;^v&a#KkxrLESehs>wonx{Mx_$ONR#ssJemXF>+kfCfIM^{|(>v z$|oNBhwQ))@5ciKaKA&vH}0To20(oHdvN{e2mQ597-LRTj+8sF86rf(J5aINuec*l zFK|4x0eo)<M@I*TN9?e7Hn-qxaLCCC%^qt0QuF=j)U#TE@<+0ApvT}8Ktl$__foY% z*$Cvu=B6p{A;@l04gylD05vwYe{{Tma17rgn?sxgekwUqh$wgP=CTDtO<_wFL_R%T zUS53ZBQKFHx_)VcRq9+^{DRA?>v-;YE)klI3&Gj%1)iK64Yh<FUll8%&(2JN>cH{N zJRy%09xGlw_HLC>6-i(qNzT?#uGHY_@N`yqUXm0#2aQT0)tW?HwC_RkD^fNSkXUJ` z$7<;riF;Zs!?#*Ghd6+Ard2r-Y3)|MT4JB&G+tU+#a2NFGn>uP20W0cVE}1Pj*rS^ zP8pc!Jy1JBfdmsuwML1NYjK`I0uh<Pg+~`xFVD`epc`{?xVN#g@aCI005KF=qRA3! z?4N<fMJBdU6P?zHr_{hPJ_E#_{llZJ-TkfY-L>^K7!<t777CE>fkX@~>A{@1DBExv zb2rd7#kaUGeNGkxcjicg;~wcXx-Ig|P$;2*R}WtijC@Q5{v@`2a-7$Q)sUXR{QzoA zGc)91f}NqtPqVPlfH=GZeM{-cBx;*ymj+`s-M)Lb-mEiZFTV7#h2>SgonnOI^G~E+ zd+oJ1Ui;qG_Ri+c{{A6M9zk!p*hO~l6NL~>195JvK5JA2%Y?IXQ4E@qZS;l#eIXy2 zg=TXGi%1@QBaT=Y#?*uChd2qIQA@uQF9Hl<TA#)Qw)t@XY7JIyu*QQI=Ro|qUoYxd z`k=e2qd*=F=*jcqn`cC@rLFR@gkR_bYEa;52DxIXa(`*U$Q>?0Pkumh+(BKaXBfCP zt<Rn4qR#YPO@rcchtx(@IR*GvT~>!OYfXxg{2A~Q;|}>p(+nZ0%p9f#Je+#*gu1~* z8$r{qiO;voBYS#UC=^-XRx$zw_d>tdl5rvXRziwW_Y%=x6kDr@WyMgV35XWVXA8lJ zo({`PUQaPeIy|*P1SY!ABIjZm116qp{t?VwT}JGYRl`=mq7R|Ll9-0QP0vW<rUQ02 zS{{sJDaE3}s(1nP5*ZR>lWfKqF&K(&+t4;P4VfhpHh|Yh@rz8Dq*yY7CDoOrD<uBN zytRlH=u@fu?m0Gkx628+Df@VSq!U1P>i7h>oX6bX+r_k~SMhFCP}^k|QGA0=@XQm8 zHDaYC4$*GnD#L8x82*J$qYU>6yAIk?GM;31xR0Cx^)hdEC~yW$o`JKW$WvIlt%P8i zk;V*Uyf8J%-RHI<`6MP0Bt7k+nT*ORE+mNpk)Wl75JJJ2TcmJU7=$^3jb{8VG=ddO z;SOvpa*lPn^s%(+`2vVf%oYRnkEd_XeG5;@ISaLNg?Q!SB1*@f{q#rvKmXNlJoEH* zw%_|v#1EyBkLXL8>Q^pb`mg`dfBuu7{|sJ5DD!lJqxpyD&5ySEiHH6Xjo^pkwhjeG zaK-=}m>cPyhi?=y1h4&qb6`RM9Jp!K?0}dOrnHJk__M+DoMZU9ux?FmIR>KQaxO-K zMuZt*IPFzzn?l(-s--O<jYd;z<D{oN3cG3{pT{Xq<XF=6=C6`VJ{r%=WpJefnF^%} z0Lu<1<ea0HiYZSyFrUp4VhoOaeA{sDrR)%k0WtA>K!n*?UjruEL+CUHk~*i~Qsd-T z<F&JcT%-k!NE})q&cnlF68PZggA?ax@vF)I%681Pl%rahpJPvl!_E`wpq1evrVpnh z>NDsbF3->M4XOh}#m909K~21pY#Q)qp#8`j2RB2UP8F82lqnT|<znI<ST8*3&cWgS z;W3mU=uJ4B@Eg5(<3>JT2B#kE?}0W5T!8;;l@fKPII$XaYNnQXMyT`jE=Xei@|8>L z>-5ls3eU$H?Iwads<@QR?(c08xlT+>A@{Mfc@wS+{%<8OCUIe&0lyf;%uL3Gj4W9y zjD-N^!0O<FgM-6tu_D+(=!Wyn)b7OK$Dry^z)Q~aQl&!A^Mzh^KngZy7ikpQ?c<|E zA~E3j%a_)X?!lqX;Wslo7awP^!iNXD^=kb`e)LB^^XZR)+}^mov$KDkJ2?be1O6-| z%wz?qRRDgBOFnxHVFsK|N~^P!IcV9MuU@$--F=GGA`cRa@?5Yl<`$Mv4?Wu7`R>c# zV^8PfsPz+cCh_2-AN?3Zqe&HwlINgdHP@!WcKPK+@Ad*}wobIHEPgIAO_7@i<XV?= zb)YG?y<rC~wgf~WLVk#)j3*^F!j!hZlR<0gp6^hM&=;nkvcXb)TQonq(nqg<%sZfC zBOuZK{vNGnQe4{DASh>Ij;BU*@3LMnt{4}Cm2w$+ijL?kR<P6pgUVrL=P**AXy|eZ zDCnn!Y#edLO!$<sN2EW)@*&GbY93%%QC3tZ!A6J7R4M8*SD7ck*+{DrZk12Rl4BE7 zKy8qh3-8F-mS8J0hsp`PXs;$Bdlb#9Fgp@U-G`L{A#EM>$$sdnrpj~0IUqw`HP`qN z?afSd3}%9t;=CnO?5S7?>`?@)ST(ArAqxR7fHZ2{F%jx_#v;9Nd<NJ@NAM@544F`) z3`n!FX(XM*ULwX(SR%YWe|-BD^CYCSnL(cGDS%aO2%ibEh%97k4h2~NqCj20Cc>Jm zQ)H=5`F66QP!_ht9{umam?5Kwkr++Gz_Q#2NXHOoqslMiD%Xtikw}QK1WI)yuz6*5 zO(UcPs-!gvmW$>L$X*Mi-v?XMlapy&;5Z;Sb;!=at)PISEgrYbCBY;GusEhmQ{AZ3 zDaKyS2Eh5kT;xqJZeU5m7(nS>^_YyH4$cu&gD5*iUG3xqe`CCuOIW9R7AAnY4sVX> zV?wYSPh!B+ld@If3Dgw0znV(gj~RrId0~!zo%`t(JT*!^Co<H^U;2fgWgCC%<}C*2 zowlPNVw)fGt3`x5J^jUB_?f@=cm4)UUKScSUUB<O#^V(adH-`Ce*)+)wm&~acMDAF z0n~Wsog%p49Q1dra1R6!mIbIO(o501F<yXL06So4_DA6rIg*=1>v(@|ZkBDIj3wTY z?qMRqQsG21M6Msnu5;XpSYm8c5$pT-Kj4J0&sNK2aGtc;!qSEVw;^&e2}i|t6l7%B zVxYb24yO=uW@(sY=m?r8RT-46$J7ScSRr7X>7=!UC#P9+f11sqEB;Kc%L8!@d|uT~ zx6D*eOJ$wo%u|KuXcX;p5(l_5xu<N&^d+p;Qmw}K*y*b>pD-&iB;Zi<L5v59S|VX# zsvUUUXrT~>3Nbby5MNr~;7sOw$wuWXBm@JQ9>nOW1t#{wu}TmCIZmYC4^MK~3`ovX zF$xVwzCxM|@L^6)5MH34F)GLp=6z0uXP$W$H2l=lPqQ&qAVoD>U-<kNe)Q9ynxD^b z@?rPL@UT2%j<dtVgWSnJmFLeu3aQCbr2!7cvf?D0otsxIqEw=n*49=yN9lH+UA0K$ zk5uv;L71#b>yXWCO3diNHz{`m6y|-LgTQ%a2nQJ!ktsh=!I3;*WwK(NKr%s(kAhS1 zbQxuizIqc!7wMs>)x|;E^!cruH*<yjCqDV<r>|WF72Vz1V_X{5($T>Iz0I8)wW>@+ zlaB<zLDXhA2+N4ZjPkc)8lA<Z#ZP?dN0F8*<cqy-Yy0k<ek6Y7%4ITN-+JTKT<!!v zIbIn$pDcpZL>xK%mtJ}aZyy?|7$PQZ5vny>(xD%^fsJe<z&T6{Q7Wf`>83<ZCtFqH zreh}IPIKNH{YD=H0&+3^Lk%qciiigY63EMp8lX>4=@=o-IgTI2=;s&d&<GEf?dU!* z`q{_16?%h#?DPhR7HgL2P5g+sHrk_PssNNlsWU1L4aP}^^`~GUn}Bi&^rL7Jm1k5Z z)t8QpUtuxh@_9O}6LPF-l}O>zA*6;~w*wHwO{)s5(=(QmC_lO+n8em=F$92Fef@X} zcLn*Wty3w+fS6^!nFBz-B$HrVkUB}R;dq8Sb1S70qF1O9SDP3(B{W<5sMKt!DQgAp zg_FkMl&SQd3}X|;H>=O>51vtzgv|o0*c{C2Goxi8UrWJ+F{UCpN|dnRN|k?-B_KAo z9068s)HhNk)k<>{4!y-R?1!CAF(v!K3gQ|*0zNkXzC?liN}r|9C=<k2a?zO56VK$L zrg(tS?)~S%ai^QI{w=B!7?d|6I%+{J%O25;@yu4BIRQ_AJDzVkkkq2g{4&GWYSwV+ z&?K^h6gpELi}D^ke&~EZ3Q%BHq2HC9ka~gA5)yLgFx&hYOpw!@^Ck#tx}36TXn+#) zwc~XlJMk7xWlj<fMSg*Ri28t`BM1`?6KEpao;`<^YeYM2RB^5}B2-VCm`2s!QoKYP z<H1~#70XIvZ<Z0mVe?nvPwU+W@7{-8*IGV?>Ae^#k57Q~OJDfh3(r4$<Mv&+YP=cj zKM(m`KirQqI-G!OE6e}!-}n!H_22sWT=pbLBw$8KuHzk?DG$@^CxHH8dhf|+@AW`% zmY)LzIw?o|eD~vkkz3%mP|ZB~%e24iP=wXa-edGuxpqLMl37&kPy8Y<xs&oi%9}f; z3aQyFxKrK^<q|=^5n|_GXTKutJ2?#{ev*xl0ze#-uwr1yNWOh`c5Y$b(~sC#S!ryx z5VM_u!!8UUCO=YJt!YHKPB<+m=5BNdiuk}efn8rm>qb@6IT#y=w-lg$Q`m^iF)~3_ z%Vs>mrjBz|hbyIIq{ur4VTL?T*d0``;;`YQ2mF;PWndS_AQhDOlro`|EYJc~FV1D~ zW*I6~(jG_v)D9Hjtfb%*?mT2_=suo_eoG@F845$bH#sw%IlhmmTW}16BI08>3va;% zIXD&sNyK-y?j9W;%%Y^IayH6dz?}dbIygLJS6bh=^0Pnp^FQ&^KmEloehIJUZ~xZ6 znqOM`<R?F|v9ZPh1(!(zprkT)Pb<|1<D$YkV#b6DrQ-790+t2)xr$HC&%=PChsh)a z{o}X5I1#7TU=u^e5HqHG`v(|W`v*syf6EK=KxmR^(S(8LLocdayipULx&9QY{G3z3 zYvBpWu5<D-ov7Z`+}hr5R0}u}Df$CVfb`r#p^U;b%APQV?%cYCo$%5}K6>@aCHnv1 z_!yTMBAzEl2VgvD6h;Z}DC!M3<DNh_`jG~UX>b;zdKb@2rgCy(ni5v%+jQG7F+#}l z%M9qYw>Ix^ZUHF4J!n?8>gBcdOW3ItoWfEf0b^#0nw@kJ>~_*Dl^yG6F5_h^Sa}9D z5$&M!qnMW-MB<qD(q^m<Bb(`Z`qN<|YXo&7USRIR00sim4Ek=k49_3!ew2<b($T}! zUkCpNOFLM?Kdh738_WXX$fW;>;N8A`YbJvvC|iMggH>kmH2TIHZ(!9kdFJNkg+7he z1(FtpMho4IDLp1L0dTM0Fza3H9E*+k{w8LN$kXFm^YyyOepX5h_qkh}E?&vq2=8HF z!0uAKB{2^C>H(@X#)6cRA~e|L5+&w_r@|^hGlGy39j7f4*|H+pELeB>TavxJtx-fv zOqfT+dUN8kC*T`4H?JXhRk(wM1Fn`D5{n41YX+h5@+A#KYV{af4Y$B;Lex$QHdZ&o zX3#(b#|#D;D*9gPBPmB)Y$dPT%`;dB4)zvNzkr+C!V$&6<~3wL1d%pa8ZVC{31*V5 z>l5oDfF}3EET@aK_(WW0FB1F2l;DY<U^X|jwHil@i|I1alURSsMTr5lakvm$l)cxX zCW&fCu$NfvHVJ*wT(p%L9iEzTVL`E{NzIeWz6gnG#&}d#%KD}*D^iUL9YC+rn0wB# z)~vi$ICKWOI6C<7O(2YJnq&+v5}6`|d4UBtuFN1J-9r2;`W=Y^O&Agzq!l3?FQdY= z7=2Zm{E_M#&}`1b;XwS*0KJd1ov<#^sZbb8a&bQM%fIk*>}j`d-*p+;f1}YA`#BH! z%fIlmzy5dr`r`adxm*Tpcp+FTIzFfac;V0ZghPMfUHaj=p&xI-(H`u`{$>CUMmy#H zYkZNjTLF&Qm4MEiLn?;X59RR}SB0hgKPGFa^hEG00XuRQDdB`h3O|UiLxcd+umy?* zD~UA8JhSf(_E@<t;_UVKt5#Q#jGxCIz*mRv&C2R34NxkfJTa!?Z1tl70sK|8kWv{i z%>xNR+3^4iMOHzxiO@AAR3Y(i-Mw?Te?Sx!Za0lr^%k7&QCT4DT$eW1RaA&-L8?or zhsC2di+z!nJ_!xxGWox8)pUC>>DjO0zVlxaXQithI)hcOvQrk~=Ts22oT3yGqo7e; zOb*k<86!t+epV%=MCw(+$TB`9kLi0lESsjB-{#;EDTNe25lQ7JgA5D9N6-e`d~$>| zMdYkanN_Z5&&8tQ{+BLYPNvgPeZVW5+dFvYOqNHA={m<Gx~KoA7jZlT?KxTMl{}1p zlz-t1)vBT&T)%czv|x*$aJYhjWNBCxPjmG}$zi0r7w&oPnlBVAk1EShW3l|`r$0GA zKL>kvZe|LS&vYikaR;Roi-@vQs*LCoF2jmTnhEh_t<`_+#$8D5IA!tLk|%&4kKw@l zA_`#wA#EzTqClUcid7-c9K+<3y`<De&T;HXS($KqXdf0J^<;QDDtRf9x7$VO^36A2 z!+zu<@|h>n@Qc=9XOX4}_^TWFVejAoZ?S}QD)qV9jKMOo_Vs_nWJuElG)Uz_HJ^L| z$#66#{QzysN3VfX?m;LtJw@bX-jNxfQlv<WNU0!PW)UhSmY7?SjDj)nE?z(p3>11A z@Fhmq<0zUxw~>tkGI_7<=Z6mEg9d2oNx`WDxr_Dk6bhuqI$%;>zkXeEMh0=fUIh0n zTTye5vFoYB<hEDGO0rO^Tfkk33c5yo8#wEl0uorX0g{gZiWh$a98=nvU4^s|gpAly z_!j5l3#D6O0q!n|86`M6^Mp-F>&<KoYy-;1YRU?T8(kkhx60vIDzjzT4h%fLT|hxU zy1&e1%+pqbrg}t+;dgcx@X-*nB9qR{v1}8Ak`|SbTitR8u;_`EsdH>65T{?_SK9r! zOo_Y7+|~Z<(FvNTkIOvZ=adIDxqYi2WI~G08PlQ@^w;AnTXZA}q>l}$F9OiEZJ3PU zJ(M{*wLZ{+>f`7-0aCW5zMDNf$Qy1UUySp@6ogFy*}N*MAxvOIl1Ic>`%Hp<k34nR zGq`(jg%t7yK(;C3z$Z*&gu^7{!OZ|r0ND$?(N#*WuyVrE;#8iim^S83w?qV1rK}*< zxDdJ1nGAWWOXvWFqs^7hn+O`&QkGPXb*voo+?Q`;TH<(d8{QVIjmRLQMqlSWW(z{| zM-9`c1q=3viRQg+Hbo_U1HeVrnb0NeFBS8D>CgVV|L_0mAAJ0yAK{oa(cypdei$9j z<Ck81{=fc5|HWVX%YTN5H_w2eGmq(L{$fe<=Q`+#hyLHZ8S{Ui76;q3FHv{5_`jnk z{V2G9+Y9{T+GJIpslz777RC_=C7QJX${Et=`(+h}Is(b#wdDiHhUVE%ab9yJ^aeuS zUY6AnkJBWqHRgMxh!4ElYL!!rn{c4wGv{d2zdD&rb6WHmz;m5UTuyfc-IWs-i%~KO z!y5Ymw=wsIiHjPHCrI%tP!&|iJ!!!8r>;`#Tl$+5V#weU1!!7wn>Kd!k4|1uZuSpP zph1*L&pqvd>>-M9x~On>n2My@_bnzMatP-F8K_n=R{3hQS*fn3DS>1@HUO3gARdk^ zlu(Qzsu$uqB2~askyM4s4sv<32`sb`*${l><fCRSS;B9=bsK*c4MT9g-)+MMz+eIU z?jP(^aEp}F&8=-l0gQX)>NVt9;AH|`-+c8IeEiQn_u}I6>ND3agIVALrJ<9W44>=F zlnRAvxiC99j+?&={OI=aZKI8Yat<3Drz$v|(d6KC&$Rje&fqg}PU55ofidXx|Kh?N zf+5d8_bhqFA}>sgBTZxRoKtwBfD&LF<ao|Ao>K*J?JzWO+|QpJp0=yhsA_ckjdoWq z&oN|t$W>fM-SE!sTX30Pdg&vVH`el{%8grh;71`6Lej$W@)FR7Ib-ApSx(%Xj%2JE zT*e$o%_AHgD?htf$W5lFmX?-rJuwi|k{3-wE~4>VK+D(H*U(J7c6ohrDpjdApLzNj zaxpw@zyW*Uvt%lI^)x@W&B(E2Sz9S4VF|NBxo&77p_7Bl*-@Sl31l$KLJ{s4@k7LM ztR@uqG?7R~9P$v1qJK}Q%2%$hM1Mb6nCE^C-XGnI{DbF~|Kr)Lf(^%$1?k32W(F#k zRZ}Mfrzxiq>~s)T!lVI)nW)P^#|F3tij^SzfI{N=#qu9>O;DqU&T{&VyHph+>9m22 za>1H`#OiXM7^F4ga%OrVG)Xy&F3dECkA&KUiLnl3Lz2Ua{Xj(vm4>7Lx=qYoJg-W= zbZsR`sWfXAIS?a}7kq*_501y=q>+SZ*q<Pm5fUWt#y#s~!|DR`4dI0+kz~QrWL*g8 zo3tg{V99ea*hxC=rbz~?;D#_LaV-l?m<$gMkTcjAXPAX-Vv2qFrYgW_a39c!h3u2l z%_I+Cf{gi>=AD}xhH(c7UUq>Ay~_w6iT^y<%+bB91>W0k)*9nQsac|PsN|DY0q<Bm zBqWJj6DrN+vP>8HuwE<Ef6aPra(b3Mklm7f7zc`CFfE)l+GOZPG<}G_aUql5Tu2^S zrYDsuY+f6UAUt;kaOeulUox+U2A?tXP#!3rIUvPZ^$8_=Tf8q0r_Dx*HAe|L5n3c! z78ib;8O3edP2Oq2rtI}7!pa_^n1ici@<DkPEOp*jv>GN~00*2~Wj}mOuZb~~sOKCO z^)wPeuMD5jFZ|q3lWqhJ6+fM}wMRfrd9c~_?w_K!@deQGzw#IV%wPPozeWuLLWQ%l zv+kIO8sIdWQFL_S&3FRnFT6`XL^m8g`-9i-^!$UJWeEDuK>>I8>0Io}i2?xiaycv# zl^K$hn9}=d5D4I+j8C8{jn}PM;#fkXw~C*YxHdQsE(hd$z}5f&4LGFi-3DC1i1p^( z%`J{6V(#!(!B|e67yVrxYt?)<2M6sBvq#8mJVbe~k^5l%*SXP7&O2bdDa8|#+< zn!8)Km6~=IdgHA(Az+||vbDASt#5y4cW)2H6}j~cDeyR)B_c+eGBNw=(MirYFEMB& z@}`6%EPF);$n>q&l=`Mbs6?&VDS)#(B=Ra~igO1g7CGj-vUaGD#VzQ(Y_U8$H3fwo zXEQukRb~}~9vmKrxy0i;cVGTI6Q5D|A{IkG5(DP-w{A#tLv>?%@aW<5NQJuFwE{f} zGHa!ijff}2l6VqOvbnXzBkgQ$a_p_IZ%mQmDuX9Rbi#xjRZ&$SqT9pof^!|oe|mK? zl_VMT@c0<kEJanRS_MQVDT2d{ep46G2&;|+nx}2M2ZwSvp`kf71*)do@r&bw5?P33 zh&WZlQ0Sv>4iz-v6e+617@@PNvX?`AK$A|SN`6ACfY?}#q~}7LSzBLSyL1&}Aa`=i zkdYMo{L|NfgE#K(l8t?Qu!rR*@f?Q0@@w(^)7uP_oGxemxy%eqds^ysYN1$MzH%9= z>%zhuhZAO%`>%^dawj5;1l#egqmr4liqt6zNa1z>`xG*)C3mlV&XK>omQr_@6y zeK`?C(I+p8WWbUiW_~tDO|H2h!tStM5X&q9;2mp+PKF)Cq5!c8${2<aiW=PQ9(Et~ zjGkMtqgX#!y#8iz<=X=NN4_CCP8u?WcrFpRmD`=dUdP~Z!m%KZs0@0+Ug0@5VnxHs z!16RVr}3QxG_A0d2GAis@0bR?ZBjD%71ZLRVoeyI-kwo@S*{{%h_z3p;X<*%<OC2> zbq=eQ_#t3hdDY!crIb}T5=op23bTw+vQ{n9l9~i($@~^%$7(Qa&A&b3JcGntfOD%s zQRQX>9qV!ONhpeJbdD&P+FbbPVqq?vmP>iECfLUKAh3^S6Q`j$%{rSKmk|R)hblqI zIBW|k*l=~Tf$h(_!59ERy54z<>~l!o28Fxr2KW-U0=F^A9huX#r;tCAEMsDv98)f1 zR(lLVaWLyPk&B$^rywM8PWXX?q+}suE4mlhlMiDP@}&bg0oy<vHTsXwLmy55SHo(B zVrc+dz09paIbj*tj1Mc0zV*CemN`~XA$OF|9ia^Xv{$mSDi3f*VBSy4vSQ|-vs5h< z^T%`}9mN+(ou*2dGmDX6HMK;V;&c3$J0y}Rocts&DHKAtV!TBn(%2nCzsSp=Xzf=@ zdFCV|V#NeBjLef#?l?U)Yo3ciFWcmo%|`Q}w5Z;;jfIDdOo3Fo2#*v~exUVEOBCf$ z?H4vD&OOot`UFTXt*^pYL8Kj6pU>mu{=ap;tjJy6?&|8wpZSx2;;;YJKfkg#tAKVo z?b7?~Hu%&YsbfCq^Cy7*15Ljt7vJjv+5JOjyubG2JV5rNFGep2E;|nq2I9nGE3)xH zZNXj2>55~O(-)ivG6Tf28<JB3g2yMSkh+C9t<1VAhT`xBMXC;{^yYP71BpzzLQ!w@ zw;@BriUD-v{>O$Ut<B=aa+C@%>HKr@x3pn!B(vLs0)Wo6iaX4}H9=S2D%2E<<!7FG zIt0)y9^-YVj?KZrJ^&2c;l_<OX%SxD<anAT4K~1&P4gjtd$^e$)(d9M%}#S$ptiXC zsy!(#DiDzUoo|6L&t?oHFO@21=$EzHIDKLAQ1ptEm3&rZ6tp`86lfkc$6RKLC;@3k zz{lD7xyclne^C`hGTBP{(8o^#nuKA)2w8yl;{emm?QM$2Q^xP;5Z=)K_VyOOXFHW6 z`CJx*fnKVVi}?NM7#!!@J3CnlqVDa%fn3|T0`UV1yHpXoU0pneHhfLhOe2w_y{%rS zO3xo=PZs8uvxOqW9=Ir(%skF~9IDu6xSi(aGBN|iCKAsC#tWN!3HfgFhR4v*m^jWJ zOJ<u>mQuJPH7SRY`<S5bBF};yQpz5YdoVjY?;_1|oApEFu;M$1I7@j#K%Me!p;=I` z3Z2o#Rq_qUdBusiwsGmHE9)rFZ||K*u(DP$8&8~6PfWBFZNe1^xK_X$f(nplFgf`a zY|Br7=Cd0cmyuvXjh?(@%$Rg)^4VvuL(xIxWPNRw4IPw3v;jSz!=oJ00E%;o83cKQ z%2}}}1(G3~3Fz3uu*Efqs=IGqaKxQ$gOHO{0!_k*-jx}^Sx6t6G^+05iHs}|Y+zhp zNP8Mu9e^95)%)_#0(3qK&4YCsfac(@zQzMH;D-ei46NV?5LJem?|IVn6X&Q6oV>_h z0?8qrJ7`&mBo*@-tR^PRu=Nhi#adQOO+b)4aGA_q%Q57c-S^2%vO7mHfVqHR7Z&XP z{yx?$<IX*;1YQ&dEulPC4K9GW`9)0hLhg`s2GAIInl^){k*H_UVQDK@Qu~$4h04H- zQ}amL=cS^Ie_93X9*ZkgK&hV?|AOF*_*guF(oPa!A@M|I=*OW2@*H46v1%sL%HM6b zvL{C=X$iEaXXXSYTUg+6)}Rp@t=t^X)nQcvNl{IKRwVWjyAXR6yDopiGf(<I&10{k zfAUaL2p-CERL&3G!{eiAOD}4I8Ry#x{no)=NJyYs%zI-Ss*J9|?9u7>z-O)8)#4}) zu=~5*$LFos^)jXK7ffS@(GrD!!%|NsX-OQUkY)&EDyvdR3QY@QJsr+)2+5s>^SQi) za8xW$WTaw&vUC))o1#lZgR+`WYQ|X@?>iR==!+sBPo*>XDQtGhx@$J8l|q&QWj~aK zqmSr+Tu{hnr!(_1#%xOP4#n<hJ|dcQnrsORt=J5g)v1kJff~(EhLxxAqQ9P?{KHzO z?=%)PHNf=lt!Gdu;Pw2oPyNEr{R{=gb9oZva;DY$Xg%B?Xx7osra9Mt>gtt0`zL?x zKm1F7=K7U&(#-Gx;*#gw$35?5svldkp8)y~G=fhqzSjfioO!-U2VR!om=B=5e=@ix zxY6jRAXPV1=v4KU@U??&xuw--(aPbRP$iBU>VdE`!&51-9r!PahHMBxbI}>4ks>}d zhhn>f-a-_x<FXI-?efpDH3I=7lq(WplmlBQifd-cw<pFiy5mjuVvfwk`B~oz!Qvoe z%Rf`abod_Pfh;YIkA(^DAEWR{5v586EC`hyoDBve4H40?E0?c8q2{Xrx-Pk3jzHz= zLF|!;dFTx17{9KrEYbsb(|K6FrABI()ak}3lFAdo&g2}$p$`6oU?c2nd1*uv1U%d$ zB`vTj`X2Ng9B!qxPN)!)$Uf%n@tULlLfK%-Oo}5w`R2{rM0&Xj_<rNoO`s>Ikkl$U z@QEAF&7$9epFW$<!*`sVo|&JU!|6mEneQD>XP$fZ*{he<xb5_0ih~URihmzVjFTFY z2^Gy}CR33Rx;o**lRV%8dcx%^S9ly)D<~U4d7`kCcQ}xfPthBuns-XBE`)nFO<XuI z*I_sq4*}79Ro&AgNJLy^l?u5mPDTi`OhN~*+?@9%@!n}p#Lpsq6-e)gWGlk%SzcaE zO=aGE>&ER{H<$*`Kl|)+*RLGsOSd++%f(`=QIR*Z(V_=cg_jzl=6toWvqJ?SI6e*p z;sin-Xm#x}V4sRqdplduY&f)6R}t}yU)or^eCaaA5-|-vM!&JeTWx{q>rX$;sY_oe zexlhKBIqD|V^yLAaE2vIeT@vzysaFMw=i~apRhkM%<PaBycTbMK!BFx4ikd@guCf{ z9%o+h!yGp5@4yNV*5>ey^KScKAv+ofV8JMwe;D8DgYT_w-dKw$7vKUfECKP0kd+)C z$5f`H7$z~!47i)4eLy=f@TX6kL)S0RF2VXR-hxpiT&Ly#YVXaSB+IUH&zL<X_ZU6G zV~)tkp)yM~tE$k1D4_{x8M?;34BdSV+Pcl!&@%=YJPR}U12Eu;H{gv&skv>m8QiA1 zSCk~KRCDDR^XxIt(Z6r4<2!a9_sGhstc)DwE-B^Ve*Bz0?{BUBt#6rp5T>}|6pxRw z;usZ*Sg;q?rcph_5NE((_+P$sN$heOzg_xEA`>3hkX23ACLYK7Mow2S2<5-f`JtAf zTt_#w4jR~UGy%d$Z`8!7W5nXc;68ZJIiw^Kqa)WjGj${1H)y_DMRP7M&CC5Ox4q~Y zon3jteh^VT+}}YrAlunP6`;)k-?<O;l3X^6hZ)13X+AqM%^}jj;Fv)}N~4sh0M52H z&YU`FU>@NqYgLiGo%U>pQ^I&UR!v7o4=9WVgkcVR1d1^esXMwcK2pL+c5u&4biRQE zf>~MC=3#$$P&NqdEKF~S1wI0~8YhiFc`8Xf3)=<_h!IG6SRP^ZDUb8Pp)grS5!E7s z9vp6=rPh`k7#MEP=BS)pOEWWgpn7_H*_9yA93t&6g~=>aZEt5&(L~u!PV#gTr<;g! z$=Bv?INDfS!^zJg-j>BjBmV)0nIdi(z7Tz2UcvI;MsS(ilJt7NE!#<@WLsh`qUD9Z z$>a^R_gO{-AKI9Aij0CLB<WQSmDm;~f{fcr(YmGP{^XPH)BdFmk_6UEdeicc;IP0s zb#Y?!n_vIRv)8V&I}odeVa&tBk;|uDko&qHCD9Jm(o8_t|Ms7M^SA$(|2R6>kKc$s zV}d)!#!{zCC+a-Srz)Voul}oE^pPzPkJ=cc2hV*#4CN3%tmUj|fOZg*Vu^Gjeyo&9 zc&v@x?!;)8T~=Xs1(sR>6Mkqst%T43eK}ReuZ(Ep?CdO#Tf&zh;o!kkjFD)^a#zY5 zq~l{^+LRm-K&z}PIC~A<IFnxI!u7R~$N^Zaj!M^xh&Q0gqNZd3)YajX;xr%6>q%YH zyJQorZQx)XTR@KOnq%VR2(RSCb8ujwztB&_DvE@Jz$)hlYIm0Kk8F<MMaw{WGBrKN znE@aG4m}Vbog4`D3rj0deMr?r!5|0YiHAXhH;J_lhP>QkwRPy$gWCD68U$T=De<X& z*oNV7yYF8mt`&1sZXtqb_x5pk;1k1AVjIIlPnyZM-g%$H4fbbQHSFZD|CLbb2re?v z69=RnoQs9o*4hpc8LI$41Odx*5Y!jeFKipxLI=|KB%qJFL#AhsSy`MXJ0^z!(i=M5 z?jIPg15zL}0y=MNqZ2V1Kp}agd!*eaqr&kh1_$|@xQ|HiE3332Dw*I{R(bN%;N2J5 z2Kvy>`u5g3;Q+8)IA{jj)05pjeadd5kWiHPH>YQ2Ap_`8H&ah@L0#e?qL-Z8xh|rj z7ZwPkL}GHH(BHqfxccq~AFzYYP2aix;fF|+(CHX`TN@kV$dX~o$XzZc!jkR5Tb^M+ zA`&`<=M<%lDsvem(67Al3*Y$K*WP*O9fl?5Q%`pfzS~jKW3{!96B(>y5+n=d!YR>d zOk&m2&YwbOn;`*-y75V;V9ZF9MDl+E^v=vt)0yj?3B<7Bg3iuv#yR#F-vyv!ZddtJ zE28ii45g-an5|(=@QdS_{*lYYr+a}OZGjCPxejH{Y9YDuE;f}Y5J<QnkY_lO!N%y~ zgofsl7NkK*6GXBwP^G2wP|4CuNJ#&Qmn?5vRw3Hf7~3cZ9^$fPd0|QM%)u->#Cc;+ z@;Fv4_-G2?-`*0zFWU}d4J%!D*xhAK>XagNGoEiInzSZ4<7$?wy(dc+oravNM@LLB z&7dR#M<Mm}yC~GG1I(A><Hdy;fTNBhj*s!IqXfo%RB@!Anp?0ojVPo%!Pp@T?Cs4} zU?A%WwdK@^b1eq4%o`(Zfe2-yn6)5_*%Hy2yD@`}L8~gLQ*?Y(9Xlo5L1e8CGc``7 z_iqLy2+ajs%tJ4`!129J7BiF#eY!#7!JVa1{|N^OHwT0BXggf_D9w+A3#4N!j^j*0 zNEu#fQre$R)H#G+ERy1?QGSekOFN+8a;PpYe971$)(H}z$>6Bzu#0db@gI*d*xkYU z+vH*#4RYj5BULPYtykuY5wpLw%}Dq)EQXt#MNB5+$ymfN@@1sF&=K4r3@f-&{Foyb zm^}2XtfgcYCprg;A4n90MDg+%4_jVjLAm+*3ETG}|4g=u(j#il(*6o^YnFQp*$Ixa zzw+hJ|NIv}kC2^o;pA+>rFH6Ac*sRlM=*bEbTwR>yzs4G`TGC)zyIf7`r4P_kutlP zEf8#Yu@!RE<Mg5Pgz{efDxiPZ!{DjCzwhGVMLiuE#G9WF=+bhNUPMwjfS<eiiqdmh zLPW4QL2lafa#<EV&vVI4X4__?nVOvgjCOQ(;NP8_ooBJbjg9llbiUYJvkts06O;C7 z6-Gy*$(fx5lJR6%q?C4h+xkqD!1gdHvK`@eLX#eXwcx&~oN%%7r-)!P2XzFfPf8|W zC|TCueeXT^^Wb%OAPARmf7m&fFJI=F(vDWuWT+^6h}`N@AjV;)1?%7d`FWr-C8Vr7 z`-kX~Ly*^kX2Do2*|@P;{c)$khlWrNmgRO3QM7O$osb<CGe8fiuVd}o+TO%TFwma| zY$`U_2=wl!alb6gCERV;4B~6l*U!!`y!FmIu;JNd@c;Qip(yyRZI}^#P=?eUM?-@H zlK-!70OQY0&)~L)@=jrh%H@CkgM&)XgLmA{F_bjKl;dvS{Ghmao6x?NZ1=+QW?f@5 zOEY=MvrukYTR{vTT))9#0%r-dud*P)Krjy|FE^;(e)m0S;xsJg2Vg?SDUb?k&^y}0 zi*GuZ_3U#SkP;T>C=aKdz!%zw%2V>ig;~k~`q<h#TqT+94rf0~oC8M5c66b|N!HuK z;NZ2Z&mbELxBk|h8AjdW;yjS6Ffc&Z?CvSQfdG!35715QLwFG>Ia&lvyN!LH<h z8qlv~Kq8LR%ZP*4^~Ep!{DsL2|NcLILP0N#k6{5`zH%AS>ye=Xx(8Tqv=#BoI)VUz zDlFLHPJ(Tm8R9dAaVd;qVZLrvnn1_C1J(p1*<Q|%X-8KXHxoz#O}OeAf$pd_M`?2B ziYrvS6@~Zyrc}7(cd08Yng<Vi5fs+3)SJ|b0nem?mtq9DPRYNR+>J6q>`2fZuQiZ{ z39d}7@)Jvl(A7l*JdGS8mV#k(90Bg9*Jdd!FT|#KssK3H>IA(YmI}#)GZ@jpn1f9j zvZQr-lmft-6F8i$+=>r9F(j)8@R$4a^%V$!fyK=y4VhL6lpO3a>DqFfFG=Nw0#Q6z z+FjkfrV}7>6o?#5Pu%3V^RWaRy>U0oN!*Ta9xX$qn<d~?><;<tTiZz2Dl!I1rZD(1 zCzSA*oES}HZ$-<uqrE*RApso>3XbE&=MGr8NySY!OqpZxp)lRd4NTeWTe*j=Ax&Jx zMhHLj5zCcklURaVO&m8k^_4BT^|Y;lZ`ZF(+^!FTHqEp{QJ}=3y63%A7?bn29@i;> zAHKQ6#pZ~o%>wA-Ju#J=w)R{{hdF)3Z!yPEdv`agzM{gj=Hp+-cceUS_6c^mz_c11 zGZXbT2~~1W3uT6xsN5qQ9%WkFnbKlgTDzf<MM*dwaJ~{uDxMALhwi2ftQCZDyIEB- zgj6^zMwVRuWnJ~OQ~cIxQHpR#D)l(J=Tqy0Mot9l-C@r)>?v&W&wu91H-7Pr&;8u1 zoOZG{azf(qTFJnAkkM1NPRZyrl_Zu^%5dr8<k!FY<^SWi|L0%-55IEx!YD^8e1SC! zj%UL~n3AdFboq}qCLhk4SOxSCr(J&r?t1TiJ%!_ADB$n;Hy8l^o|l7f#hoc75MqA{ zl7#c1BuZeEBWaN1eHSKfY+#n-7=z-Xyr;^!D9fIoV<Uq_S@@trD!GQ)5vC%n&7PYx z*(}~%NS<ZX<>x7s9Pp+e!Y`DQ{8)3?99ryG;!oQaTMKap<T^Wj3ok0Om#m*4LMZj5 z7BYtdJ01tVD3@;`R)u?<m6sb3=Bv$;mDpt700b19tgFftV;dWwpOqT;B_ZOb##sVM zn_;W(4i6UK4k7!<IX=f1Bf|wsNPwxyJVUP+iJEFjlgDylB83mjr8nP?yqX2oS$u(M zr09@bu6j|@*^?-PNmm?wc>NZNJ?83b#9e*!<_-4N78p%BV#Z(C)ZNv+vRX7v>jPxn zr|#TlVI3YByLIc9d6??)@ICk3HO><_Ly%%70S~+4Ik4VMO-<JvBI?(Il>+KT{GA<< z(~OD9OB4qQ31UwrTtmVyJK8rrYq_fUhkGfNIZSbdnaZPycnIJgR}*cL&9)i6wV4)P zn46oub1UE5EpZ>5TN(>Gk)YDcOABkuORdd~gh$YfY;`MZ2!Pg(kB#*W48nwY_no&p zy1GCA`fC%zh2`SrjXQH#hJ^CMNub!0k=fp&FO*x?G?!M_R$!%PThZ@_haeM>&)Mm9 zKF(HTuJ3_?0*x>+HgfgavoPcN_QmI)|Lm*$=anm0t_%$i1Lkz5WMP-InAt)u_9w_L zcbW-_xC=9e)IM39_<@f~b}!ZoU1Oq(_LWAwk7S!QV*Uc`IFK=Lpof}|-zhqYwGd`y z`Sc9)R5vVz%9O8gaUsun{nOfEY!LpRU7u3o5S0aH)-tpc1_f4`H>oV-8c9adIDmUv zi(%`*HV!lmZ`!KCT4BWQL~*F(u&}hLYD17Q?a3m*Xu}E1nTchuQbu0f0vf$iG9>s# z<S52~`+G&Q6R%7etQhRd;A;W0pnvoL1hv)0%JS>*4sjabnrXemvOuI<qNOtQHQp58 zO!0&Z@xg1MlMT#`F%dwI;B1Pdyr;(FGK6=GdmeuQP@Yjo_2AP>nO<W9);{`R%AD;h z9)UOFC8F`aO9ZEA?+z0w6{{h&w*w6m{SoU!M<OmtDe{Lo7&O-Gbd*`F^w{X!yESP+ z-YSxYtNZD#wh!z(4kul{%iLoq`le$Rh}qJLDN>?9is$gxsaB4O6;6#GL93mGn!}lq z5~;Qop>3@~BGvFKP&<;s{KO7$WP0OqwsT+?-8Yh_j$T0X{EH#4xK&fTB6l{~PORfJ z#<Yr=MVW|EaxsI#dcVbT$GW@S!$OpAfL@^QT*gOhy`|&zTmi|tp{EDB**Q<skMTHf zC>unHx85E03{fBfVgMW(z4-jquYToAzwo6mAS;KptdJNcxngFd(i;xi?te)6c+j3` z2%a^CC*p#6{nb~#^-Ev-?f>=HfAyEYcJ=ZFb|#)e(a>#kmpm>o)GPv&zyBwGj25}S zORIqX{@ST}Rapy!)z{znuJ2c+z(EWG;%od@@v@6=-hGqiS8hR$-SS}9?d~i1j|sNE zzIpTZZGOmBO1vZ}7etE|IGY<1SFCZo2W+u~vF74J28T)7Li}}{;?i|7{R-{XlvUAC zTCAnjAfKlt@d4l}Pv{osnNkpk(Zl)xY~l=^pf_XaHV_R-(SfSS;*nU!_b><>7#OT9 z_=!1Whab<{%AC*UI@mrbgk)JvuE&;XJbVW{h_ZS9EKnVP%2{R3AsoZp!4xX%P>|k$ zu)DJji3lqH;?f%4cO|P*%vL=DFW5awh9WBV33L&t{Dpx*`E{hRApfHAbQMJhu|QNN zi=N~$7z3>S9D1y-uCXs4p45^7YH?wK0|x5CZ_%!S8ej?h8qm!E>*N1Mn1`rhPy~5q z@lFvXjBE?CjCQ)N<X>#t#4n@xi9xcnvAn#z(AeCL27FhpWd~JK+*++|s7A6A0)=sk zqZa3>UQFDx9&3slnd+rP7`sVgzq`xHK9vC9gKRkWH1A(MVtt#N>zD+q%ZqY(=JU3{ zH4s2%j4h4H;>HGn0b9FA+yN3Q`$A);jm@>MQ0VB&-?(|BxUz_XI2_IXeDA{Y>Ww=y zNGZ+FPAR)C5x|?9!Y-n}))O*|O#!WwQKY0oJBK*!S<^W@85ksy)Cgk(Aq;FbJj6y% zYJK^o7f21pSEN3`nWy7;ai9d>Wg+YzLJCXveu4VLM`(vd@_lMr85AhF>@~%-TS>S6 zkoz-`JaH`lkqf`%;8#R1ipT^;5CM`95F{3^;O~-{-Mzt+Pt`E5OGQW)0-yEqbPgAs z|9-|3ePWu^R08BoH9XxWOQR~_*>1^5W|Sdk$)}*AaZsk&L7ON@#!@CF;z1=jOKxi! zniA#)LraW1*8sE*;ZH?q5Y(Z#n-hF>3>fAuz3;vQOKG&rU}nJUR84#`C2Ga_%D)sB zvtJ|2as^NxOakl>kF+r!m$0Vn*zIkC0hp59isK`34o$+yG78mkE5n_~oY<(pY-Mvv z086yZs%45s1ZAo`M4l+a5%UKCMDV%`?3y1}|M4F-H-Rz@R2eZz(Ml#8Aiq8ic;m_N zL<-4dl$@(_U@H@o0o-KVmLiVCzxU6Dw#{NvmswFA;FgBjgN~grEaSm>kKNm?3#*=J zKiYas^oFI(PEK&aXnLAh0wL6DXOEx|BT>vxy=Vsx!E_`j{Y}Zq(_gHC9u29~C8FZf zWsnV_yvrKomRw*Vs?wwv^-FR(koeUaI=IkTkrWyL_jodJL+GSVwv)QaVxq*U(={fA zX>NP@{`EVvIlLEm(dU+Z+--?ui+)lNjpm?L$4NL!D5$K@;-oRTkQ~MJH$FP}xz}F) z#b5Zs&wt@_ue|ia*yso+$tY8MPkG#`&ggUkW?237WoP#Z`d3nRemF8b^ulw`{`?ny z?%Ut`rT_TtU-|a`^z~O?e!jo2hrNT}aZk>q0r4#Rxa5^H&V=Cn80tZX?*sQr70^F$ z6aK8;z?b0E2=+h2=P?LKeOM6+=o}Mr@a`Umi~OsEm-3%w*h86YQbF0;0<EGrspHy1 z$<N^$F)3w)zqV2PCV&iNuk{g^Fj-PtT8c<6T6!JG>L4`m<J|Pk&5bpDaCn{JPWY<r zP=IX-Pp~#B5pCt9VV%{QU0aJ{qm;sR6s<)U6sQy<*&Gp3_<EV!sMO(K2k9;?&W?{w z;8$BI7N5Iz6|WDQyR=6v4wY>Tz^C2bJa4$DF!%A_gFY#b#jr{yg5Xy?yW0{ZuFdy! z64%ME0R8v@+uPd&Z6UuJ%IoUL0a9r!owsi70L_W9<D8wO(=6^zy+9AgvXclOyJ|j| z5Pt{!Kg@uY)%Att<+=GqBH{Y;eIuh|g!#fE5OY8h$h$MM3&?V!`G8*v9eSul#ulx+ zbZL^p!}y=LFn)3Jf}>8@gHnLUwcpYVZ~I_(BU698wXxFKGg#Z$A|+CZqc@@gPpt`5 z01_ZoBQLdtO0?!mMqNoXwa=@Limua(ZX(zLy9lWwNe_`+thg~fJ7e6QL);{shc`CE zUnhf7o1%;jzyYup=5Ft9trG%^Gjd^RjRPFgig7Gn-_%MTqS@&?eSQ6}y!=vccL&<X zH*QVAcjq`2Pt3kSFLqP*5okp~D{LDnoi{ep^?)TF%ILtNfW5<5%C$8^kbt1i7K{`d zWq#qMS9*JTw^bTxic=fDf(&h31%|r1mHKLvHd2HFB;78y8KR-*f5nb^h0_t}s13#) z{0@(FxX*rXC|m%-Ui=obR$(NbJIQDf4r2U4Va}%B#}hd$ase<^T=pK}mPYNVlt?4y zDi+J7p@9+WA;RLaTPqop-hx=nmrO%psCzhydv*;F!>9qwB@7U0dmFq;mI%`?S0)Fc zIzcPA($c0n#$uFbfx&?HP9dkl^qk<FAZZGyqWytf-tuxH8p^QrtLi~ZcqezOOY4|b zU(cE*k3KZK-5uxpyIHP8Y~oG1#brrtIY^XSUAz~{=?I?XE+X=3fEg)BOm_-kP>&GY zeQ6>AGYzb}(LzH=DVUU3qWh~kX*wzS)SR#~`zZ#6)dd`XU`3#ZW4t~N5e@t5W#ieh zN+spgenDGFWy*3e86%7$VND6esygIhHCFm3_9Dx}nj~<zD;>&N!_|A-hPsjlxOKtk zaYDa)e@rDt$yU8m=KD@&mRmKx4QhDse|8MQVU3bi!MwEaUxtU&Z<&VtT&{PGMB2e4 zS<MRK=ZeZ@$k;Hm2Pk*dp~(X2LvX)3!h}?vDQX&^mhVjcW+%?()%F>!zB3!wJKZm~ zuO9diq+)A6%nxnms%ngL&^+rZFxv4wfAW=dIypo-K7`Nt?A1#@_v%Yu{e>@n^^Grm z<;!1u<LAHd`PV-S(0}En7hing*_U5<{*{+sv_GGJ_2n18@VVE%^o7rT^J~BGtzZ7y zum1AazxB&s{rXqF1cINO7$!4}^k1#NcnZEbc6opCo&q>gKI!*|S^fLJcNNgze_K_r ztk43!cEsRbOH7&AeEEm|Nqk2wrf7Gt%$awA)f4YK*8oTGjLK=$+=OcQ{M<bIq$rB5 z%~00(m8C%1<>1R`)(U14u{+nnw996dJ_deHveGHB;^yMa2cRKxj^c6O+}?x!p_Rg@ z*mBjFXOsnk<v0ufSV5oiNP!Sol)c1IVwV<Xa~)lr8=yIjV;I2-qYE7oxQR|Vj29dV z!l0Svd{4JrZrTUrL`;s)<(Sc_I?e~c0dD^GR>ikLCFcdR2oNu3EwUAvOfLyX@lo%i zcHE5TzCYg$$To&*156cj>}sW^xd1CX2vJK`98>vF>lrZijOF@?_ENz|Z5eDhe17xJ z^!4l40U|74)C(mxtQOjq2+rbKQTfF)&E#65FtU-_+PRDeVhJG8_@f{H81(=7pZnaE zE0+KPq5ugB9Fdy~&L<oE2k*bfsVN*7*gC-I-h9DRbQT7O9NbV~9j97yM?i^~zNUd! z+ShAl7M5r?5D#HzRDhnv&&|`7oBdFm8Qcbr5oBgi)V3Vw-Q2_uH<Uq^oIadd?Cox0 zW7Hh&U<_>Siia>UaiO`bodD{0-~K6Q*;lV#r5HbX=Yx0Odmrhs*{R!*sl=Kf@()~M zff<q&7Zunbqxr))a3x?Do)VA4ug{Ui;u2>C?6?^YE`|mNA=M(ZfBViIJ~0xl205b? z{t{I-KXE;M<X}|3C_kbp0cRdjqQ|I@g}O?JTzfodf&^hUP5f8D4&KUavqKp3Q4z@} zIcf*@hB*@17N5MyhxS!!=7tO6%Sr&~^mwfV6h4CC@bDH;FE*fAMzT@k45SLSVwbY- z3L;A=NlaYY(D0e-Gpha7IQqG=G#I88(?&cNJNIznP22(&4+^?6#VUL0pr2DCp6;xg zhI*0xEWR9MPd{K=GBXTpSxQzL156Xk2qq)Tl(>{;RXEPTCD_(@L>7*!i%yunVjyIc z1R6(!SHui60S~c%fES!bW@I*KcFVgjwHc;^IPTP|6oN?&43=|rpp;~4E{h*9z#0e( zt{$u0v3@84B-QvdzLv`t@LS3!nw<;}`L<0l*2jk1sDi&X=(GYlg^8EIu@i4fMu@I- zb2E8;a@^_n55w}_1J7rK%??F98mxD#Pq5xjc=$w-@tU5{;tjH6Mv2j9dmkGEn}Y*u zpEBCQ9Fhx$%J;!~Yj%;(Hh!wL-Q!uUmDD<Z^x@y>e887=i84#_MrlJRk_Et63n!VU zyurAeXd;Amkblao5$;&BW>u6!1ddL{Lm%E;e28~e!x>XHAbU@J?Jx8B=!i^n+!B(o zDKPHwo)d#N*xxfYT)22)RR5hAvHy-<7#|)U=qvO>m}ynIZcFQ{fqKGDtw<F@#d$f1 z=Z!_12*+D@Boy3-SmBR<>nfoC_-$7GMHvVPO;TFQOG|QTf%9c9{2RXspn*4_BD{|9 zPl_aJHP*76thMO39Eu;(h*-)N$dc6-i<$joV||nL4q(JQhholV(_iT0Jw8!n5MhIu zt4<-Qrd3kAwZ070LH-5M2}c|i97Kfy<q+U(BiDLix(*78Ws~AVabcw$DMl!hSot7p zYe3?-nUId=w+l<l_^zlPGaOitr;0#Hz&8S0NVBsJu+%t?rvPjKB8o^)w-!(B>^x9a zjyIwzoi0hBEI1gxJeXj1VF@M<F{T{2PNCDXzYp@`lcI<^5O|s?Kabnk-eLU$>su<5 zdUBQvz_r3Rs8OV8ErcbV^>eU*1P%L@dDq<WO_R#OfLr>*4{vZZ0aIvWbAylo$RM4a zJ@|O0?%ZUbhPG~sibtG*&=&2jO%PF_d%pj{2ff{$oKaqwygWWWCPp%(c2f4#)WTWn z$hHIMmly8{Y1PZQF0yiM{o>*>=asCJ6bG+1D&44vvh32-Y)N>v98m$Kpak$CGBwEE z%+D{f=PGJVk%)Nfxt{n0h>QwECIb{=nn+Sg?#+Ff%A*d_+NU}w!S5f{(<2yiU0vN2 zj|{`TeFKaDzJ)@A#N^dyuEHK#URj%8Tv8r@gB@BMI}cJ2%0(D0G@6nLDA*U+WMcWS zXOK5CYjAIGo3ye6efh=ZRcePS#mLYQ9a>yj{<k-OFg-OrK7oo(pLyWu3u%nPf43xP zAT$MUNVQ1{7{ZiE{HskPXC_!^tiqauuU)*RZP?*0LTNUO_{S(@nswA&-b#@HBt*!U z?z|V!NdQ_R)a?_nB24$seNu<Z9JK^%JiL$JobwtPio_c#D7UCFk2y_u7aHRqr>U9| zUM!L_<oel$69sF$2~wEmf(iaOm8BH+s`n;BB^I@?l7Txt0#6_>h1&|hV#qm31}uf@ z2<CzO@p#`k6d<0Glw`X*OjKZ>rNBx^h7RTu;3w9f6iB#_Bwy@b$1Y$DcL5qP+WCQ6 zf&?>5Ux_PXo(4seTV4*{a|9sNZWIykM?=&kUz7Ws2u(gS#aEp$D5lo9C4LQmY6Mz< zES7`T!w}~u%feg&HpReC4(=V8I%~xtmkk&pUX~yS$`*!XXQibC2!@P}Nn(#SXswEb zP2uAXBp;f=cD<kb_((PotidCml2E&fO{a%SsrT&ybGqw5M%oFAYL)fnRW*jaM`W1_ zs)8@HmH5tLk?VSp<v2@ZtdvjCj#;R?dWuEXzcr)I8dJcLzO=C|4waIQxkY3e`8N0+ z;zJ4|*i5HJeD3@@4~I2EmxLW2plLsDS3Jb)RpAKPGfIQoo~_(pAaA+#5PNMiu{-16 zn`V@|P4r(;DoyLaFGg<))Q&HVmmztiE|h&<5)p}lM6#IN&$xPs^*{U8RY3npn*C{b zXg~nIo5pxOUXjDMUgz@dKYVWIv@A&n?yO}eU0hiQ&^uo5=~4nFtZw&w*gg&C6^Y+0 z(-rf2eqjNN9Lx>m<tdt=*{mnU6M?+0ZgpvHYaK|pMLLhRT#s0c`@5`!nYJu=npy7J zWC|cPN-JawNzxz7r3dQbwip{MuFf3Av&+4C2zwWn21WwEh27WQ+BQ8qhtHm*NIZRb zXc)Z4V(a8cbGissP*X9AOks`uRtVJ_6XTe~RnAp~K+m>8Zd6M#(@5qQju4Px!KKHQ z_~3!^?8KmO1;<H7qaHR3f-@8xAs2QUg04{7<Vn<C_Jj%f*xn^a9Z%6IuxWadaf$zO zQbEg3PF|$`#nlzG?QY+`$z`x?v2D=Zzj5Qb3+e%7R*OYq1IXL@+-E+6++J629t|9h zKNR7W=%`?FWB}r|#|N3l+LeVVDg_CJ2eF1?A|ak*+u{)vdzMdEdI4{OjH!^^r8*-P zuZCy_<aYpLK%BoQ{`Az0#YiAhiPOvS4Aj<=h8Bm`{!uMr5r7Yj3inO!(@P=}pR6n| z)twx|zCx^XVPz8qiN<<)Kl=toFwbt>_>c@)m#;kY`e$G6?#!|y!jlL31H`EckAMyf zuYhn3mUNvwtSlontsc*zZqdt;1wF@jAo~fO&Y8x*@E9p@C1G@Ugkfg#D*NzrCMPd3 zTIhX>M=LQHM4GBSLFALW0qy~era~##vWG7_1zZT;L%e+7wir#mWz3lKRy`YLmd`{7 zG!$N`W}Q20uF=GsYpJ`O!jr=5@g$9>YDJ7yzN@7s`#CRjX172+KTxtv^FTXf7rL?- zM<$eGP1?Z$JxxbXfu9(14wCFJP5-e5OC0mwN@_;yKJ%cfM+}&vbfj!(Mvv#jtc8UM z3p8P6*!4_aoi}n&pc@J(11u;&vY^S!PAu;R3<5#7Bk>H)2$8c~r6Lw$PX@m=xC&{d z6@0W}C>e#E1?I9<>Ql2mxW8+IB)6);Bc6b1H3bUyEDBQGPu%=`XcmITiiP690@o>o zao;5k1R+H6#8xDY2Q8CgeJGINKrC<@Qr0}l%g*0yG};@Hp~9Gv?PQWfPW0F3r^-2> z9MEgn6P!?@o!lqzqAuoSQI9*Fh~oJXoJK+otwb(5#VFH6oFaN(&}%Z1ZK~?{6+^-f zOvL+gqsWe8Jfd3Eqhy!VQ`~(-lakQN-peA8M6aFFxUpxmSWW5ER$=aTIADeYNo{qQ zY0Z}Oh}zRkI0by$h-G=eW1=Zw+^4W*pYz0gc#rde7QnsEuk7V)9DulkdqBC4?C*X7 z*5emnI(+B)n5nPxwvsdcK8Mr8tM5nN`J;qdKk^3E3w~Bxz~_=Xeth}R@@KCA3;a!d zLEKuU1unS{>y*>hk!**)wz0VjEMt1Hkcp6CylUPsU74E9G02;vqsadaf)AO}*yOBS z05WOS$)zSm0$cA?BB`_Q1NY%Mv|$zO?{2TIE|NYIH}iUN1I#KT!RV`^V4Cg$JD696 z^;C3h`!C_6xJ5bpmbi?ayY=)E@;C$<CZS_THpe~+tQ#F2#niXhI6xInE&1lTyABFC zUgu{V$}2r&6Ctg9MTuB8@aU76i8_KlY1%>`gg}71$n<?+`OZ#6IWYrpmJjszvd#cK zsc2V@BMnrmNt>Fbg!2I0+Byy>XcM5nN!-}61M9x_ts}(es27;hdr(j#li_4zd~5{1 z&HL}YcT`h9Ff@#{1bpxB8$iKkd9?^yX>IQy^z*`nNkkXBd;3A491##Ibo17&t{f5s z5bVj0k`*Yiq^h>n;kd&IN=QR%TXSPe?QU^(*;-U=Z#tElO8&x~WHRUW2?KC~FR5&4 zCOQrb!3s-g1UAg=+qXCwU0zz!k+cmhB7--#@TSXX6TUT6XZDz24I=<`5wvI^#t<-& z?{4QY#0)T0NEycA33!f{?CI_@M_3)nytenq5V=i9gJhrx75ejxZn<!>Irefm3_P8Z zpuA7@oLtS|eEy|Zaq|<#jrb3y1#rKss{@%cuE8p#BJ;D;|Ia`E-^H~R>kw_}3<kj+ zrzOa}Y6N$ylyBh%aWn$$?EWtB&9@vE;D$=gIJx2MHy8-KqZgz#WVvGv3n~E20hiy< z+c5mAlK3O-72b#0UH*A|eO#FHTo-w+WNNG~^sMHudAq%AbSu`Wg`JbgB3Ydzoi3rq z1Nx3{G*9i2Ey17$<;~lzMhHGV5EU^Mx~EJf-XADjRbrGHJf0|nMATS)Sb%78P%01= zL8BzP+O>o@&WYm1F`9C|qTOzN&RLW4u%b%YAOe-)WC3NMKX33PT9*N!wYFKBGh7eu z`qlVR!U0k)Y;3Z8nfFm<Arpd|i;1BiONWW77e`(!BXXSEgQ%rQL7Xc1G9iD0Ml4Gl z-zqhgr&(Z7SsFZ()bzGRkDp&j?MEQhO(-)az5I@171?RdX$l#-DY>$A;-MX+L<xHk z*yP?2U$pP@KDLXgA?-{@0x9ljH%r3^NIDqNN4}LfUKcM$y8D`>g#CE?c<np{(`<59 z2iR6etS59O_g6IyzWYgq0H`FA#Ff&X&`|Hm4dBgtN4s?-9*7N2pQ=t$GJ>Z<u@uf^ zqtt|+Gc2KW3gu@o@Hs|iY2?VSf1b1QoS$XY)Qg6qJ!uL@_KxWt(1Q(v_nkM6;LY`? zmka4gKB~m1@%BIGiaf~Us(}7MTCe(BLu{oH@5@a&AP8un93R+XnryLvUT`xg2fSO{ zz)dR;lCY}rRmjVN<{(54)L-N<mVC$I{L=F6sVO35S=<nrVa{@g#U+AE*KtpZt6-i; zy{WAs*-%eUe^<`{nM${}H>CD}s5ud7jYvf2ASi-#9cTir$ZQH@gh%LDnPpe>bM2G9 zPD@aw50<<P33hAHJlW3&3VkdDtPT?s6Bq+v`a*v}Dsr|>@*6qi6c#DJj`m}bB5JrZ z7=CPI5Yjv-khXvp4`d%I^sx`mFRd6km3&o5+8uLtNL(GCBgUd6uV@iAH{-ZL-jf}H zcEVdM4R|Of<dV#`Q44_>8>iY+&0CKl;RDx?fGG*K5FEk&LIDw-AN}yn+qXU>ShJy} zeQaWq&4a3s4iB=jfst|4Ei5j+^Uho1thcpotgpWJ{(Bq6HG0XmFiCUJ;`9ysiW0S2 zdy;i^_u!;|_;Pc5_oYi0PmWMsfSaz3PlBWbE!eWD9ZI7?$*_b-Xs!eNtRkPT6t~n? znatGm3<Kci&D)S8aof|*$o|m9tjqZLX&F}<6>^1MuU%Mt0Azd?m)9^VNKcEbPhCSx zS9cEt2@O|mz$grgS4AnXtf(ffHc;sA?vjGRAidb%$H9n`hB<+uXE9w!nu~(!^z1B6 zp<SUvI|a!j<!DETN5b4k?AGiWLj(QX<o);Fg_*y!yiC>jRx%?B)j)ShK!JYIC{eJi z`#GHoZ)fMF=<_g-{986HWlAbdKu4mmm?(fJx-$2wHaQPiG=OE^M+NffY4L3Ji5yQ} z$DKYy!^NrXEqvu8>d|g~jz`_1b69CS2zgB1=}wJZm4%kal`fdBXbp%?3F%xk32Sh^ z@;9MPjAE1U&fPXPy0g@Be8cBr!ruWC#G{kR3vj^b1k@9Cjgc=Ng{P^KGZ*(NSteR# zaN3Ch<Ca8Y;^&Bfp&MJnTFzQvrA!XxXtPSyGQ0h#Mx1pc#q)G946Bf_3*m#=X`I~N zLV^6s!gHDF9NHY<kD!@E9W>PIvLB|<Z(iqwLoC*}**+E_sz`URkq!_TPi7Sw1I0Aj z#UK-PL3{?rJZFZs-l|pHG4FuVj|Y8Z@`;;Uu43tK=2Cz8Q2K-~o~k9+$L;;y!^gHy z4KFJHI(LZGkA1;Pn268NRwZ3gn;jm#YJoA%p5ku-a}+;W1NZlsYnD|*bao$vw&du} zQa}=SRDqR7e<!gk`Nat9*yj=(foeL7cF;K-k7H3G4IfWI$qhrxit3Tv=o;ylI`5SX zvW5pe!iV0`J~y4-^Rx2`Ynqv3_j);SPc48?VnbCaH&0@(Jr-s5MKct|-~0CO?|q>R ztBHRVuJJeVpC-ei42b4X)M+fsCH!wl<jh4j3D!$iF``1zdSl-*kM)+8(j(|AQZq!0 z99#zBn>7@Jn_zTXrTw9Dki##5{Vtw$bC!fE<|$XM5KH!?h%>HqM=uJJ%Ht@3MO?@S zcthDMS%N)Slj*;>w5+gNcsRQ#Cqi*)92y!Vn3Wt!I03k=%>OR(0)n1JJEiboMgJ}D z&DVtiv%ihvn}V@m^|Y`LtgdfR61>#VXaJ^c%aAdQgLHCxdbY2p3+fNLb(Dr0nHNeh zmlB$Gp_J6{`vLTo%_`HRKwIbp*aWV=m#F)hj*1S5*?UyknfWDdE*qeugKZm?Nt7?e z8f<D<wJh#35;lrB*OejiKoJDoptmQFKMArpcX;ONwQOe>+p{RQg!h5AMQ^BETwI!- zx|37N#d=hLfc5CmvxgDOg!Ki=m|IxFaH7Q&(F=3mLZZFCJc1^I`h06@mMg*TN`>2$ zA*z)oqQ`;h^zy>Ok^)Ry#4Z4@(3LuW$S5O$fc4%!G1IM?hL(m}TvjwX<{T={Y=lrI zc^pBq<bDT>kB*LDf)Jsxvb=(dIkH07j{qT5gXjnb9vmuixiGjn&F$;WGY;ucWQYg* z``M4-O)U}{yMK&p6rvF!S_Cj)=0R2_(U|2ptMBjY!x$jt8QVTR!oWcM2BV9r@(E9u z7?EwhM$qyNT`$Mq=GrrQy?qD<Ff8Hc^SVaf_aq!vp?Hq_J&S?`TPE_AvY9H;X~T35 zKsHS0c=CoB9SRuca{SeKE>hk~w2X%ot2Ip11K+Cbd1F&BW+dBcTIpN?jY^i)!9Hhx zs<^TgBU~dvct@W$U$lt1V^#Rt7Bz!?qU149@%r;GzzpX)UwZT{2n_V=3CMIn)Y^t` zkTxfdUu<>Zd00AnF19BlkcEW{nMyo@<;x3in9R~$l`@5SBU1%NI37jW=N_GD))qi{ zZx^*F$?3Q&7q_ua9ylx0e54)JFuXyk8&ezz&Tqwn6ZBU=w&7Hcudu*P*UOd*MgG`J zM_;yF<JB;j?h%=a=9FTiLUa_Q%LUHxc4mADE1U48?F-I&^07fhjAG861x$T}Yo&gG zmx>xZ{r7zzucJ>rKc(?A3gfgSPEVyqF|kosNz&laQX|WTwaD5t3AgZ0VGT5|yBM7O zX<JPaS5Pu|YFT->iTzOR#wNo0r6bd3!un5HI$8#|Hk~$RcAbbcBAQy*gKu!&)H+uw z3EE(~x`YvXmXBY%IMnpMTc>*AlhXoKK>y_Q)niuDc#l8pec0dwln<c6_ovt@V3`Bv z@;QQ)IIVqU*TFH#4p}ZyZ@`DDO++gi!K^q?*}wph>znIR{xYFMP$&w@oS}hY5Q}A@ z6ZOyzC_!#=Q%Y%Vi`X^DHX@p5nh9y;IikO?-*V`=ryUU-sa!Au*%Fm=!+<q&dxsNt z(uL|I0k5rGVTe3rGN_&KH3e%W{kyV7>WCa1?T`zYz?~_Q9I+HZSq4#<smB2i<`yY` zZ(s77WDK!HfE@k7|5na+2-fI19vy)ga9QJ=Q%d>$10o76p3lQ%Gv@z;O_YHUf~bqh zYIRAA+RzO<9F`2_lp_a0Xd?_roKC`ajiB)Bw`TydTg5dpDA9EM0%S>(E-Wr96)BlY z6za!GMgtk~;3d*}9o>0=Df>#HFnIOawU=Lf0ro$~DHKLW&qDS(N#5Gnn3=lO+?s<P z+E`aJ(BB7>ibD);g0;hyckWD&3=b+bj};Fq%2Ed$gKr?mqYuM53q1liW^s9?t+l<o zGk5dOo#(DSLwK|&``p-ACn}c<1Y0dFr4Du2{A{zOAEC(Ofb8n&r8fw;<qQ@lJlV?N z!_XQyP-*0W!r=Jmh_V?h7m1Q&TfKAp7Ci_|nVOyknoER)$YWr7HmehDTCl#3G@n9g z84`6hudi`T(Tq-FR|i2@Z73A?c6V9o$C}nm6DLcP7shCC==Jcj5EM7xX9HF1XqONZ zt~82mM-zgR+Mz8uR0+G|DRgM18DS1mbGN&+qEVY9vVoy!jzE>xpr=hBCvDTbU{;+$ z8M3!%3WqRvLnsF~VZx@a3DBqFuOeV{uB(*;Zl2Bog~J;!iKKp@tQg6dmZ42Jp3;Og zSFyrKjJ<7FilL;K8AUoKAM!cJKz3@EM0slN*vlCm?y`_qUVeV%MW$h4JlImUkEjte zUS==~dw67BtlE6h2*yjt)WT<V7{%udc;nURZrs_*m_#ir9>drddX~w^7@CwQp<5Y@ z2L!p9xqQxZnRt@Mm#mF4+S<(0XyH<p7lxM$s7qgqbIyG+&dsRM5E8LOk~nhZx;dd3 zSd&F}HFetAtR0;Uc+&~1o9h{_xgzg*t|?%;)0(RI*^!%DhGjLvOG8C}+Is`0_D*e@ zII=(CC`t{^d*8(`76Lc3hk8+9We;$n(vp3_W$xpZ^->BE)*54>$$q}!^Nrsz2Dp_g zDth&0NgDVzMw94LesiaFS-d6*!mt^vJ4{#2O;awWH=S+8Wu|i_K_^A-COSgyK~pMU z&#Yq9QCSg;1o;~5NY>21gq-sUo3;A0$G!!sfc~-XqQ|v>zU9aJeQ9MpJ*N(EA+^FL zYhTGj?~6OPL!1%JA!du#NpLO6q;NF}2ebOI2a~=YILt=4u&@k@#n-D?!jl?wsSH~; zqAEjJEv{4WA|GmZ5j9_=9h~muqC$dZ3*S5Ep*y&qmB>TsoQNN7X_XGL9if{17l+_2 zi0$wv=+>OsNk|#Ejin#v9iM=iS>`bzSf5$4;jV~BYi@q(E>FD4z?+7k&K$sSrVpXz zmCM%GaqY_?-I+sJS}6b#RN;x7Jh1X>$*x5wyA7phDBXDu9PISm=)pRs_Y5O|ZCE;T z=vh(GlBb~%Tw$Bl#$yK#;7^L->1mZ%mtyJLdO$jDb^XpPO+iEf+yI<-H?Ds;H9e)x zLn_^Jrklj?F}nLL?H!k{e&+e-p1*SSDlWa<t&QD-qZeLy;h8I!l$*<V9ZISyKyeJN z-r6X##nb+CbBjHN5e$O`*)TZc3IFY)goGo*LKz+$ppZt_F;FFM^AXG`n8zn|4g5(* z)9h?m3K~{`1pd)Ra(mpkd26u0fW8fsBv1bYQilM^ePlRUFe(1>*|`PkOYJ(ldK#Ns zu|wEf$Hpfh-y^%p4X<9kMhF3rnoO}9JA1I?w>LIO^y^7OFnfqy!`Og7Lp;OW><mBe z&*%AsR>GD5PQkJe5;{8S>n|`EAWSnDI8%TrP11wWk+HFf3q6#$w+Ep>ajpoVHl9*z zOA{_&$<LeN$Ft}i$MlZZZMX<2#Mr`+C4f@Mk6&rN7^j3EI&AWUV(NLvpzdh2#8n0X zPbKzz_Qg{&HnZceD&nN@!;}qhp6iyEL2X4lS>__%i``)@z$B73h^#BqXqQO8$TOB% zSyAJZocCT+AiiPNQc6@Y<%q!c91aG~IO{VHJrJDhJz)?w;o90NXiQP#2HZV-oHtH% zcEo1bwFZNnuQ)pr*~fVNekLG_+KJq>>MnZ`|Lp~H_bqQwTf(ZOvdn=JKGT_i85B~j z<tZGsaiE0Fj4jT@;a3JF6-y296b(apxWzZKcztDXvnLv&Hn`6ZeS~n0JEZaV^FudU z9M1ABpU?>2(FSdgw|BSA(vZnvhoYwxCMS(h07`BlwnDCMGg#kwA@#Cl_(3tf7pdZi zO^wXbMy5xeQfTb?J`5}dz#TDI-LR@;w1_}&W`Hx`!#=1Xq2$E7E??&D<L43%=w%C; zk)y%Zs1?AEP-rWQvXus?F0*qCt%EuXf)Sp8aw(QJHnQM&$LS;_Vci%{%!F?Iq{u@l zSnE8iRCt}|#H>E+oLivEp+Dyaf2tl=zDD>O8nAx6o(5##OKoTf_pa%O2BzCvo8@c< zXi621-4wlZkuf}fhkULQIuvOe!Nisf?DmGPTstc)BztsM3IhY<7sf|Nhw)M?Jz?Tb z6DA^l9hyf&b8Ef;x#9%z^$q0TclJ=U$EE6yPj_g6-FTKU=HYmdp&jWJF=c_{;6-2} z0iZ0k++SOdg<;A2&dH{`2F)F!b=+hSyb-7lcUI0iYa(f=?;mt^X2Ig@ZMf<Qfn_Vj zqs*O2h)abrKX4-&TZRZo)@Yidg&Gka%O0|^r9whU0`7YxoT+O9K9ojR?37G~!vq+b z6doB(>>PR3lvyzGe;EtIJk7Z_DnXDhfE%av^3psiH*C90^V8GQQz+qdb!17u^wwK% zt#57<`uV~O&%gTFSI~43W)`T_u?D`Owc-Xa#cAIlU>PvVP7hz@U}&g-HX}3xKrN0i z<Nf1z1lDJ19VdEvvnZ!8P_<S%q~yfJo*`O^Qx*D}bbY-&J*1@N7zAt$p@mT09cf3Z z3#h)}f>b{I1*ny>2XG%pJ3jK|wasawE|ymKD%;U*8X&d!(TO)Uy1Be(N<~KRieQDx z=N<qa^&alIw!Th~D@G@0-=I4>!ZZ=kLs0(Tq0#YIUw;kHn)E$eTNfAS*}DnkfNUc* z!1~5<dl6j0K?i+7si5gINT{-oO6u(}NAlB(b8xutC`X&R({pY9_=&lnt_Zu<fgU8c z4?V)D6NDp+AkW3}%S!Php?&La_F>6AubJUfGM=r;Oe`Ip`Ox(beZqzd0)mOB{Qcmk zhqMBE!7M6Tc;1}K@}%lRi{KQXlmv`kCaYpt9{_}je?XX{u)fkfDRZ+T5&VXUQ#K*B zC!`T$sz~;m`!!`6SJ&2bj71tz6LQf{_=gZ@!?=t+n%YSkV(ggYj(p^Fx}kXod~i0n zfVh~@hJZr*1cJ2!Px;)EV`Q)#h^D1N8smxg*UkqFrZdH{ra|*Msxl;J7K=}>n&sss z0HR`8ZLx*o&kd2?wEM_&?&cpqbWn(4AfIuPU0Y2gp&Pp=cjQmCrm>Hx$gaHFbsS4r zjE0y?&Q`L^;O=k3{C1|3sl+fi;WQ@sn7r1>9^p>$l56~94HzB=o@O;lDtsS54v$s` z84-x0ihE<VmQig)c0Ws@L5Ou0Tawa~d_WGPyS6hvbb5?WFUn(wGjN}D3p<XmRoAQ+ zi-GpQry5Qgbrxh6j+>5JkxnGqQ}XdQ(e;*4R<@9ZVr$Xx@&|j#Q<ZtaXmCyx!^}+; z^*-9BddU;k0#!i&gmu_sRb1cZ{ofQaNR=~O=}UG13h}bbhj2EWF1)pSfU}uh#}XAO z)C;W4{)aMbZ;t}bkR@R!*77Yb^$N=?n)QA89z0?A#z1@8%aw{njv^2qWdw_(O^=Th zXKx=m_4(fRYzMkl$|If8`fK~10tx|j+!>(U)0u<iLLqUA%j>BVXE36!bkc&eBqb+i zgi(h9s=K^^N#LV{AmElMS<40MHvxa)tmSH!bqLu@E6Q(0BY-AIfk6ekI+Xf~XifxM zaL?mT29POV5^|Y}*=-}k6mM{|(P(XLrn%Wr4-rXWSU8g;W+{|U8}c~qyhMuHUhAOQ zqopjc5|Rv21ft*r%q4E0$=tYp6JZ(XM$>aMa|`oOl3H5Z2m88*2J$A)(?rhHci(#t zxkgmMaK=Luf@gxtjVQ(nI#jM1y5QE0_qTTsHg}G4?YZr(BDyiekM{Q~q}Y1DZeXB4 z*^`VJ;t`>kZumhVO(AmxR|>5gn&ZOw7y+s<(edcBP2RkDlP+P4g(-yI{N@gZja>4W z2bfPh8mO_lR^-el-;Zq1Fxr&E!^7AIqod=OE?wc_STdd2b|Mxi0Byq0`ImgLZ0wS* z-`^!D0`VdS6?O$Br-PQT2Vl!&n%9a&C<tJB4uas`boTV4gOh2c%Q6t6AWE&T73m9V zbLGlq!amq>8PamrHr5jlEa#bW5}T!}bBQDV^fEY_v^H@Eu)gIo3m~@h9jTfSxk04E zhI!wG=J`J*9H`g7Ya1Ixjmtc!Iaw(pX(H4Zu(<GqQSiegO$M#~9ROuKyW{EXGu>x# zJg>te9?2TzE>8!q;947l2JQ`4Ic3E`4<86;OM|^}Z+B0>LekMLrk%l&uE-viDZwdA ziR3`vi6LCh$&6A(HZ)?`Y3*unmq`z~#nOU_f`S<!zKWA`T!%+}>WEg(R6~S_Xrl=$ z7-s^Jp)bJYKsOWXkhVSEdR{!y3eOEp65G79_$8PHTbo-RuZfsPc&HauJ#H_~A*IP} z0wA1RG1+M@{*)<rq<pm8$HXN`0kLbnT!#_P1Y=_I8%pb_Hvn9+r&%U!Meh1ZAlGxH zFJ<2H@@*^LgKz?<M;diJ5m7+}EZ8gF4jy>$m?TjtxcUC?mXw55(Y)!lMY-LQc<oIT zL8?Kt7_9;Kk}DjkE9lvRiCuq&wq;M@CbS!$SYIfFUFQ{AX%C$8WMz|k-h*O23xPXZ zJfgq{EjP0hfW+XjQ;kNpEi<BYb3bBo^OBO_#9>8*`)BRk?7k)Xi~m|EMfLSGw?LJ0 z^ECJFL#<ob@cb#^&#>S71|Pl(@57Ge>$v|=%V+6t0kVDcbd|@4Ma`vexDjBDJ#KD( z0Wt%Sol{%lBY6nvoPd=8U_aM3Z@v(-yX&+vB4%e4ZAdBxtdSqdz?qRFDkILfKixJ| zIYlkyqNEB;3?6r^`1Ovf*wUL!ZbGgs_qEt>h13ZcMQYLh<bMtwEVfN$0N-;LFcxlS zN`<u`HjE0{K)`^>5gZK{`dHNg83f1z%S<Tdu&1+A*tns7Z5@ayoC>`}J{Y_^CcPtF zOY%(`yFk&sq5%lN5tj*Q#$!tmtx`@Vbm1CF>1(5sKbU$^o*(}EPua++>GJX#Tf@di z5xj29BH{au&7FKt59Sl0c!mC6sPoe^b67_|{pnBNeDen{yzpXQVSs#lIEzF|wjetS zPNUI`Q`57HGuJO%7}K^>(@@)hj>ic{B4q3U7ts+g{(;5dVG6T%Ag`)iVMf)RpPy%A zoSmD;`-sz=l0Y_qlSOO5t)k>K6#OEhkik0`0(0~803{Lz(EbMO(KjJ*VgrXdj&^E9 zFzevpkSWsSNcx8fNJ^>MnQ1i5hKEPUG)&QTs?g8?As#*}wcyMl(?lL3W$-1MkR}4g zp<hYYcXW0S3=R<q4bH}%fjES@v|bd5r_)JF!YMgh``FlMPrlz1l?dk5*5K1uR70cm z?08`aG1M${m9$q1zg8e)Lp_HfDvX@HMsL7GF&8`Uxl|M{OVh)BXj+b^ETyrAE#?5H z799OB{DGgm$L4c{>N8bDUWL!<lK{<qwwA6*W@T!sh6_>%%<mJ{frq;6oON>wphGj` zoNx_idl;u?Ib#D$oSTW71WX$>#TgO6R$Xs0{d(g~Bw~`K<uV5|P$|LpqNQk+GQcNG z*ykgis5ySDzz@MK0@f3jlbvt)P)rV0lBH7jm(CTzHq8uCObGEPP^Pa}P^P<hd5~o| zl8Iv9ik`<0$$ZZnz`e?B%BNh(oCPA|G^S^<9;LA(%DYH1xPHZs+k*t6b<OMI6_f!( zCOE+T<_2)nweX$h;p2oK@(AU3V^rxFO~BMaq)|kUu_8(hqCvs<vm+3JOS3bREK3Hm zm19+B8cj`PXR|5L#DI50>(d)NLgs7@CUcyQ52-kKY*ZU=Hz^yYo41lY0$NBD!jd0H zumQ1*xCh<tuS5sBI3c{b;*cz&(yjEZGjP~Fcou7yBDs!OnxsH4y1Z%r_z8e^4a550 zO>S4x*L=daYPzjWV7e9o8|t>!xq^Nz20q<~M_(4g5t)f~=Hpf7R~QCHNYfa8Br~-7 z&~s>kDxg1yMt(XU5%2Etj-FbY!``ozDHf@8a8Wwb*9s*82M08Vx%L+0y$d74711wA z#3McBV;6w8Y(7UUYQ~4wR*l=MtGkN}@jlCIZk`MMX?vavty$hj_k@|an5}ngRldr} zzhtf~R$HWW*v42BafIs*CL!nd(ap^^P<)b|it?eNX%(W%>Wrv7+W_JZ92<zF%ks_L z_${mt@D`pLXzTKt+wzTQj0KzNKo)4u)45=EZNpC_P=J91Vn5mE=R*U1=u~3QtZ#1l zdJPc7CXusFfd@x0b})XBf1!pr&S_v;fyYs10yj-gP2wsRl`AX=1YBL;#6}WTrnUw} z{^O$qv=^`z6o<OFgsuZ3$^!!h3Nt@Hv$nRrytF)Z=N5ayd+)vt5#{BVUm@pfU4sNb z1y3__)tk6G<vE$1U7(R5rr;K&E=tU_&Vh9e=$UWn9k@M2J6Q0shlrghSWwZ=wdAg% zP3RX412+Dn6F}_|#}1$kU_DO0zCLtFyZH}^qSjYe$UlY9hqBNcF?yXt0RqCroFQ|N zsIGK7W&=G1wVgOch`yX-OixYG=3^5R6pu>DwU4@=0xXo@YM@YH4<v@Qzb}swg6p@t zvjY%z@tJF1`N~&bfA!Ult{!?2Sl`@4uN8-gt{o_#0gCt!<RX3!4U9<I!NJ1P(vs3$ z5$h}}mz-)KdlNoV>Uc&c<SUWB;0__IX_Lh?TZAwa@^GTy1V#}f-_1*y9=Z1H+{zkV zqujOZ==&H#HBj?i&rbH|A+@PxGI<g%tOl1|<>^=h4%-Df11G~~WjQ+cnH&C%f8uxW z*?pf7>ftPis+eJG8Oatcnglp{u{}~y?&nf~rh_NGrK2g50ry0s(|;mgc%AHSck^4g zZ4$KVHP)%f-X8JU&eZ`(;hr`>t}tQ(@=OZGUF6<AJP0a0;LL(z_c-bSi<{?FD^hW7 z4aDYdW?tZU{PYYAtXa>HjrY}2pg^;&U;uaA{6>Zm(B!`UL<go8Q;YErjuhCn9|{6; zbGUf8)7|CojDNRt#Gg}UB{`(Qg0zH7D#<V?QA)Vpb>%54cd(~Op2d#>f_RHPPAzE$ z&o+hhWto!m5y+lT++_0hDQP?27ZyKjAaQ?R+kH&l-%Ernx=ahHOC(t<xp=7e8eR|g zm-_^fh!8>fn@+G%l|2a6+tUu;WWDeS*HcZZuUy&|T427WWDj!lK>70INpkZ*fw0N; z!~$;5^>YJQGz#~!am#yWM)_c1MVC}1gGAl5V?kx|J=tN4R#Ct5{#v7Y)f3qQRY3nl zcH3i8=<?Mee3C){@#pdTQ)FQ8SaBe=Lj(6T>!4M0zRHuWw3?>9-G+*#9jD`X#zo!R z1<(?62In|wp3R+UE+~+(QIEqBfbSV{-^=4Aln>%ziS>n5SzE<uRMti<#IUY6w{SCy z!Xb~9)_Q+&d-I{napk@`+=1K&k2G+wSllqzRGm>y6afZVoa+T=6~`u+1)5)3K~;ZK zx->gGKyBz2oEESE<Ll)^t^rcRs#jY<l;7P)g$B31&hgm@YfcDNbs7ffnLJzoTq?@* zmRHumudq|NjD%2vA{Hu2Y^yVdy}<>h#TOF3Ctv^tYaHPwlXm>!hu87*(Xcmf-DZOU z$hK!&V6!hREkKAuXPqqD-5s6RZ`^>5K6zohCqD=^e4wuvYedZQb~YP!7qt?>cQ<d` z077o=kdT}lu3K>Qk+@k}TtcT3j8EC-=NAfvKBS4LDCQbXXX#yJHJKX{riuhW=>cV; zJ(RE`2N&#-3=ABOz-0^=@b2u)3_oEPM7#*%zGr7tj~?OzN1t9QawM`9g+OYYO|$?H zfXs8_`gI5}7bYf1;-z4T0~tuuGqdF9qJ>ch@9H91*cP_I{Ok-0`haB4C|-E^RfsgG z{cLP((R~x+<6XUd@OdUCE{u$f^!61H$K)KKwH;ZW4rmU_pJkztP^6?>gqcTBY)b}( zB?gjjw{(r2*$Bt;XaJ#z{PlG!YjClkcQ=t57AtOcX;nu(xa!RZxK!Nk$TsgEaRdax zOy&v(D)9zRhL+X{6kfcQri*7|HQ^8_-&tA2OR&-%45j{zmz|0;J((bn0yG%0fuZhV z?H(UYGl~M?>hjJvNc{IDC#bNL6oWJ`WMCUZM)S8MV{&k$!!Czb_6Rkfd1IX#F8hJM z=|`VvioUg@Iff|apZd|{9r>Shbu3U@39Y4G)dG|UlX2h!ECb@}Y)d&`^`e}Pl0kSb zk7Kc_IN*=@m2+1hbA#{k$l?vaHA@L``ch4cRo#X>U9>9=ZgQR@wIB0nSlLW+kq-mI zoAUwZ$8%>MWa696xJwMe>a5AJDW4bvB;g&oX<@CAAaaD#%`j-9U=|YUS-tCF>f3pO z0HwSd22YJ<;_@#^{I~2RdwsG!&VT!{T>kznv+j~)uCaaVAXo<!A~YuS7<$bQ5?#{Q zX+`RbeOP}o29#2eJi7!oSb(gkS;R7Fzo?_%9l_IdG?BWD^dP1+X)>dS^qTW?ye?A8 z+~2cBRbCj1;cAusl23==4eb%^AkxcX_4ZQ~#tk>8Pw82?16o=?ajSl^zNr4{{9B+3 z=+D2+pPna%rO@B_%I<H%zwzf`zmKm^mTyzJadr(3NY*1oMDl-Php@$punySO8K-e+ z6rbAKf}a(%hkpx|6THAm;OeK4c22ES8``=om5C|OfCUvYSVwY}9X4XNZSF6Zo@tE8 zFJ<wsiddy2P54ulh6b-H2#mdlJNr2@0GhhUrBz?QytV<a(smKxl#Z40p(+p5o-`#{ zbEOZ{CM-@;Ng4+5%Ju;%96t&eoqdq{@}BE)!fBu0k{1Ua4i973<LMwjo=#!VsRR-7 z2tX$$1TdW|0hC<KH7Wz1_!jY$SjU|<M3s$FB<n>7yN5@Rd0d2tcHkP!l9`z~5DBIf z_5z0tSR#}Jw<UWp(l^;GEes58=<n+XFX4m6BwATs5)FtT=4^IwXmEUZ&?`ba8F|F0 z#)c=Y??ezH^Afq9u+KKOw#LWCbOzs0Pok)v?rswk6qAHIvUQprQVX$|o0BvV1Vep^ zL8Xh$aj4)$#syT-<9#?+HazsiL-k^94c>7Ol%1a_ohp_RNSVgRoyK8;yqJbRXcnb| zJvqUZP7oo0p0*P8NocJGlLNgP8i_U+LqM7m4f6{Np!2S-o(mT)U^&oq?A*v}(nJJY zb6kMn94=2ba?m_{A#fC_0~BRznIOU0bQ#ZpAtU7?Vu<&(8MAv6K}*#ZR@U-eoghCM ztcE0}7FIgoYU8svmKU)lM2))(U!FoKgdV_&*5$Rr@pi=Iq9|@^D%98AfqZUpv#v#b zI!O}%RW^BJmwY_a{rWJ|W6&SZ`g33A<dc>s*oi~NdS@cIFs0hT@&`NdOsLC{rAHj9 zwOKbj5t8ZI%e<8QpGeOJEd{fkWg&+>FpDU2_$?<Kr^t@gDH%*27#cdSBeYR|0Sl9n z0dEXx$;;S5T0Qn5OBSP-4@GHjWgrQJSxO+;u@)_=b;h|j$~9|x`K(<mX>i7zq2XvA z6bQ0shPrNy2=OLf$$Ow74|m!<-|`iWgD2SS0cvE(PXN>l7VH+T<Xhu}i1y>B4MM1P zy;Fc(Oj9d#;-r^~l-0sc4p9+MZX*F%e>(JhuW2|3FuO&}BFCm-cX+^&6OY^bzm;|k zV_4Dh&SuflT{^>Yqt4sMN4}YJoPX&Yl^QsSOG~aXk&@FPoopc5*1%H0{TT_SOOsfe zd}1Uk#TnB+I*4OAFwIkX*6B1Jv|w$h6v(`{(Zm`k(HrGPv~u!^bd%gj!+tBNth$+$ z{OUkY_wxI6uD+hW7N`RHr>{>RO^qt95#`9<p+LAe{OKP$ryO6V3%2lyQnZ#tKYV{> zk96G+yFd_yHA+#QiP~As@>+2Rr-fh{xf_LUeVLXJiiK$kx5;vl>^vY6PrNO)${WS{ zsP~d26X_f@FD|&in9gBgvEzqETa%A46>#;E2MQlKt1wI$xy+>>2Rhe7SxMQLSvf5~ zl+XZovHVo>Z%K#IREm8?Ryr-Yk%?^uv%=VJ#iv3!p>A_eh%UC-LzgEAua1~q;;Q7N zFU2*sq3>B!3nvF}(XHE4G$5{PFov`^j<hAvu+rGKAVFXU9!cOSOFb3A$9(hl9ohnt z6RH=@Ep6NijT!(4u4@?Th{;UPOt-b?)<{pda|j2Ng5j$|5x<RusS67fbz)*%6ar-4 zjf?~fg*L`>#eO2(d34lY=%XE0i%^Mb5FvszPYYu|iBN9!as(riuB;Bl>QP|82X!Iw zFUbYi{BY7MhFBmb18qip@dG3{YRC}=%G%k6i`)pB=T-{fgZ~4<#Rtiz+lY$x0Vg^9 zmmW8|xwN-M>{(p}!wnA&&=H*ZD3lpfO~f8K`Fry{ndY|I`o_-gjsX;u28J$Oer9-V zyin)|t#SB3EaLIuL7`AUDu<DR(~f?@l@1tUM6Ox5_Tu6KJ~nKw#kJx)H)rNo*18EL zY{}5Rj0gBgca}&}b+B`ILZY&jjh&uc8zX;xOO$;s0KhM;ZSt@8BVD$#wk|Cn^CdF~ zg*Cx#8AZ;S7x{Dr2xuvuo&n8=>%ugQk$M1Fj$q31RtnY&_C6w@5SA3ZF=<yIwP3gD zia5###4{9ak}`&qY_bk&X;`lD%LJsns>Z(X8fgi#gF8Rg5YAIBByn{#Y?vy$dkO|M zSGs;>CbV%glAN_nZNV~g-a8Y6N4rPdeZY>Y1L*g#NH3d7#wVV8r&#z?d}R~4NTH~n z_<}GV)0k%})z%V4V@xwM<Lu=K)qiexPK1E?+<oob)63vDNve~u4Rx^T>g<l`y;S^Z zGWKdNp~=$I{O4{6X^AsRk78#_ryt(7e9L_I7SIqXnNXj28%u3E_j4cni80JgS<<B> z9Sw)O`DnKWl#%163;&}!_`<zC9m=~WMa>Pvp7&<b_#?bkxrq-g?FiPPrC;edMxzuZ z(^{x93SF>vOHzH=57l>0QnHbm^eu0oZ%Ht;6pqZd+`m){1?@=J!EDR>X_M+TPhtz4 z1~Wa0rLUIx(YAo^qv7AwmLKo3aXG_Jl6^DH->ng+LI9-+8Tj5Vh~SDpWA9StM(5#3 z>T#dF4repoDUhVEr1-ALJj(UBFu_SCDIj$P%dD>4d-&sV6j?@C9h)1c8S1`Z6E9zO zEnZMti|uWPJWFeFEnHG^ZgX;tp8aM{bZ|LEz|as;*a}2<Hqxzc%mVaD0vBz0f<y*2 z<mrk`ngEq}0>1^IgUkr{lxH0^Jv)TuCuEgkV}T9gNws(cwGik(7K4Ii8deX;m_{Op z5s6Q6_EQMdIK|3<O>1mvqX9?=-w~|`Tq&A!W$g!V{tz`6yoQSlvz(F>MhSHokg^8a zU0cEn#ev55);2sG6lS(Iw|jfLmX_BBhX-e;r#N(e?bX-+)35)hLVq602QU~}MxqFS zBA5qCqPez)wbMT^K&OIkv*Mh9w+StfWd-V8-PjuF>#^`<QoYK*Pvgt_sI4K=6sSbk zLS+8QPv0sG6#DuH#OhJS(Bu&-K-=5F{_NCE7zr)yS=a&X9X<3D_rd%@WP%e9V?hJy z)cUl5SPF_FXxJ#O&Cbnnu0c>W$*#n|GKK($74YWi9cA@8J}GW&%h;;}A+>V6z~?yo zsUV*7fBo<O)`b2bl!TTHHXcE=j95;Mumh(SmS&gMPnufB`ns|>?3-I=mx^PB?#<nU zmoJZO?;k4Ops8_YsYrML#mludGq#~ub+ls|P<~Jai3OAamx+LB;<`YTgd&MRWs-<K zo5FFtfT)4C6bdh&q^ao{(0Q1u4rSuY;!nzd9$$RU>yiUy9?HDnJVY*b9rr1tg?yg| z?u8?jPmPltp(19e0@E90-*V)`is4wtK^ucgs;SW7$OdgBZ+F2a7udOz9!Gjt%tcEb zpfqsi*!Ff1HnqjX+}jQWPdRS^DLUBI(qv1AqWR6N<+cIidSiN}?4HK$*5M3ln_3dZ zAuORZSsf*_D%{!M+@piyVtA?}C+8&3iYz+6k2@^97^-P<@6$&l@Yj^x{U)hpKa3C` zz3~NMXr0d}^3L+qwl=?j#hPfAmCS=mRYDq>HOjiRRO3>UCJk$Sq^9#8G&Lmusx%(7 z{3pY}%&=%eo!-+-OJ(x16e}_<!e#dK#0v7^5x12em82Risa<LK`8YhEhOIv3{9B;f zwdddFPxBLl8zWw?!!i_aQNGN@u%q-R@k5ehFy46^4ksM6T3AnxSBgbeGjo4#Ew8S* z>K~z~YsGb3@~pTp$nlPYwpp`4m9{a<Uj!(}X~#myA99W3^|VAqEPwoq7u;NBi9^m< z_(naK`@~HJ^inV|l)s6R!1Li-Kb1Bu5s~%nCk7fyjuRGd`?DnA;7Qs`n|)c`#bB2+ z#=JXx3&Jo$j_5#$wBWf{QQKNbY!sY-7T&AcSwJcQe08q2zN<t<BDBcceL$qFbag19 z>;<J$g&Wg^s~`WhxB(``t;61fqk*9@wv4xb`jh?Lox<QCRsnbysr6T0dWn##g_$Wp z4h^`8p7h=h2pFI<Ha1RHTHvPkLa?~WG8%h9$0H|)`_Mq}i<3Hl8X+T3iSeUznYb-z zu<Rxwo>bY`^GbbX-tijF2av5q9;T4bQ}~Gs6F9j!mBv5KwnksW4quv|qvT7Ab2<bV z9O>%GXIk2JmF`n=)YG%eKy!9IR6*gltZr=Z2>H9z%8gl$R`z$vAtmmFD5p*E^5vGV zt0g^vvK%yLuu1lJw%amwhkIMw8^xLFThx7bdvj)Xny7<+`O!~5oL{>IVQG5{UeE_O zr;h3xmbVXQ*S2b!S{qtBCMPev{=(I+-aIDEN^$GrNIxAqQRtbPU7VX;*xguXRClyx zY7ciBj`q61@eQ>@eO)kfbwX7SJ4?WV7v6U_`5bG~l5&5V6VYdok2;@Uju=vK&~ZTg zVT=+IL}Fiu*&44?e!~(jIaRBSr};VKu()_$ww*m9!p*VjK+0gE(IAWnVYv>NF)S?D z<O~l}o#KEGl#lWtv8Reo7mDSGi8CU!#*s5WA-WxtGV!e{R+LB>&(h^Sc$hq3Kt!TS z@|2+gJwL1Wh<jxHeQ3$J#r$(KWA*Y=6o8#SNH{Ekk|nOWog0Wo#Xu0@{!}>Mp?1J+ z;Xc0nSi_{{3;kk8dy;3gKwckLVJvz1-Kg;DxLZX3^&*#5(4!6f;_`=j)woN5p=S-h zxUWC;_sK-i35?Pa;Be;=1eM}oDLqU5=4js9FoEew`IB0!!`xqP^Hg8@-r=2Y{p$$c zx`5La^+GuN@@`Ms(L*V?nG<hxE0e|a_uenbC@R@nmi;PWg~j`7=#+5tPrU&@ts5>c zFaOz}{n@LpzUpO07VMkf{N`W&<zHUEem#B!A0|VswwCwdtFu0jfBVn>{LkUH<!|D< zrGE9D?|dgN*l+&kZ&EM{9A9>y<^QyrtKxmC9{PvcyifDZ!|v{tj5qsai7dIP0%{NI zQN`c-+UK|8|G;zXoj^}q#TGink)q`M<VLk^k*yU!J*W#2=5`|;@~6TFn+PzHZ$pcy zCv!0(dw6<WjPO2Hg|Pg^P{vCb7S{Mps;86HHd>=o_X*dh3Xu9?yb4n({sd9jPY5|U zA-9y7A9ANj5Oa4A9?i`B(mrtk`0{Ix#|H8);HVf-J9ki1m}(*JO7<6;*F5z9KC>`S z4jIxm;a{Jfx^=j}gIfIc8^pfe9337i6b63qZ~yJX_uuOs7#<%T>F(@8oxKHVj`~_y z<j-8a_8)%rTM%#*xQw4tRs>xq638wJ)|eb^ZIZWdZDE7M!>!<f7BX1Lsd;B=8rf_T zFwyO7i5MhUafBu4Y+psKrJVHX_Vyk&8>bM(b)-snbmGk+!pYIiTQ_=pdQpnR62gm$ z%)?2&iHFu4Qw#-69Kj`Mzy|O@1^(vIwAk*x`1&_*-db2(Bou?8IyOuKsS~V6_I0!` z*Rd224mY>=Fyc_}JVJD$fuQHZ#kGyq^{qXWk?I@rJ>4}&2h$(E+tAuZ;#<g9_*F5E zCWi;G2V|8sHDWM;zx(q&?_a+?HkikzB7-Ozf}^7&V%AH0<QRUx*czryPOZheRWL?^ zp~F6%at)?NWBD|UCsg^+jXw!9H1(74XP6z~SMgWLoW0v$c+P8|4!Dls(IuH*{gg~d zF#%wwZgMfdeL5Je+4(MVirOh3EE-w^8xOh{q&QLqJH5exsVIM%Ja@S{m7YRLj+spo zbhqQUXyTXpMHoHt1(%?+@z)be%+^rz6W_hU*f8*ey}N8Je@bZ~bu6wVub!F6J<hsc zvSdk0UqP{!EXh-!h5?hTx)whWR$%OFN3JCpnp7z~H`oBDi?+i}Yj6jxNg$2as1%~$ zKq@I@kWehu{hWtQcwC7UV<8YFp&Ku1ytP#v|EE2!e$pl3C-L$g%~0zX&Mr#gX_a;X zlfW+>kp;6VZlACLx#i$J5)NA)RZD)d=l=M|KmN5}`?U{0{IKHB|K@N01`O?A0lUBd z{qOtxZ+zn$-}~P8?)`auLje7kzVxNDN*LeGuc1_b@CSbo9+&#zKmF4`eesK53|HP~ z`9E3v+~=>V9{T%isOn|u7Kqm6Q#7x2s^moo3%!5nE2F={W%2vFu&gP#n+Hm9jUu!_ zFEKx~n5rmzqtj;2cwi!oWTU1xC~c=G#h!4~$eN{6`u|7Um5LFH>ZMAR+$&tZB8Q5^ zYkg>)P}BH{{%v?f{Ghl^;wCP?#@UkmYq`_6MBq%M=<wi*QyOFy&=^}nqRM#1#l z0<K;Y@>3YG+`d8EL_4*nzsTiX9ixMTh#SsM->R!Q8XXxS$`i?uo}S)o&s;^4l2C#6 zZ0DEX`0A@KzuK1{K$a09OIYJX=z>krr*~;TQFATkl7^>ugjd8;%FNErE-lQHq7~fJ znaf!$ofKDyM!@bOxY^=0(V<s1u@%s~Ma8nM0(nUVu)MnN7c8$9t<x0(EP=en4Eph| zuZ)-PxK{tAC9;@z__mdGSP~!h3ED`Km!Xq669DN@S-43sYI^edle(sp#@5C4y~XvN z&7+!@_S^?6JMS*;Zq{V#+dH>wGsVNE?fUG(ZvAdu>tRFdUTxFl=<v%|FVr3HHyv#c z_R)I%ISd83H-|gVPYkrw9&E2IH5~13F3+zm&UW(T+T*U4dXz5<y~z7yFp)A1I^@x) zKvuH7-QT+}(<9z|00b9l@bJa+E{v=AO=`r(Q!I6TYP`j>qkQz1PlqscV+b3+KaWMz z!L#9A!XkW%IkHLozNfCw#2OdXJDj8?u2Y?@>3Ga2H{3yMOtTcIOnxz$ck-H-q70+< zL8=9*R>*D{1!vzCap-_7X$Ax3=~I;Ql`u4*-Xuny;@88%;v|mJzu|@^VSdWEh|#=3 zY&DCnu@WY!h)+AnK8zPM`!jJWhebQA<aVW~A?{<otJ4##Zp&$DFA#;uebuL*=mW2# z*(;~sobwnqWzX<2<8^UNA3lkN+t1!3Y;#EtFiztl&Zvu8!WtxOP^TCABT}>2UGk?6 zeY-r~iDLWeyyxHpcNo6yd!S)%|JrM>J@7+5_6`2_Z~yj<H{Li4&BwQUe9B)1^dGyM zt3L<}U-`ljFa3A#ZKsQV3O9uPz^{){Z*qVx7^?-%vaTdMFqc`-RTA7L$Mfk{YL<iV zcx4g&@p9=Ggj$3Gl&_~1KZ$=BMumSEFUMh<OznKBB|Eh0S#Ny1F~$YTEv+2%lU*K* z27(fcJ#>EnJ#K7Lt3G>Sq`g@QEc<%8otDjh=|mz*1|MCtmW1IV*AB)K<f8T*V7v4B zd++@CM?c)&NByUs5G^S0BSQlaT^ts#ZxpvSi%9g4qZDZx1Sshvzznr^rE25;DkcGI zgFlr*9&-Qw0je$_B#a75$d@?3ZHp(h4IXr9EaLo@7{7QpvQPZ@WpQN{1aHtEaJ4Jt z9}B$WMqqtzSl2*q*6dLY%I>vI&23UF;-MxyqRo$E86LrT!GU5e<m^|hVC}-%#+&cm zy0fyivURY#y-obU;_lH7M5NYskp1k&5$R)JoE*w`WLsdzH#UwJdK!-pvJJ<(>&ru( znJa}{zNNN)cl~&Mp}F?(+QrFdM*4eO>Y8izU%EPZw7b>b+yEgSf)<&HKl{o{1BHHk zy%#4ZAY>yZNCq^bb0JE2NBdT-@mxC7kB3ldIQgI9!!W#4Gck2R*!WW;Fuq%S+jxfh z=l-DZd1`ov5gV>K??p1n=2oJ8lu%<_j0l1!AKQdDMO2mzN(L2`<sE909QwPoh(r3) z9Zqq%-@$JZNHsqFt%;I#$Uad+hQ@THZtnR=8O)$?Xv0uoTil|{lCDUYf%c%tYDu1x zUV`H4`}=s1*qQ;h8%gAK*TR*;nyDe-mWkEdA%xv9sc)!7(lTL?+wovh)KCC#&CpZv z&^qT)<jqoI6D75<|4SM(l&!pwUW3qg{=Q=QQ~i5(9g`kQpuAsKcFVY1LjfLP8-B7b z`-gw{huAm&M}PE33{F1z-QWFPZpgo=ihZ&>-}_g%*aHUOO>p+}D}4FC^;^Fs$%OlO zJ*x7T7p)5D@1wh_msDzjurS4&eQHH3$J5*?Tpu=xcmeW-K0uAT5RBHd#0L`Y6W=Wb zYeK30n)usP8N2{~O}uKS5Kp`dCJSuohv5#Xov&h%D&nw;Z52Ny-t$aNLg-v-bWNaC zwF@FGU~UjP$!_p9;$uWT)5LA+2_W_;KzoX415!gU>JqA#pm}txk?H8p_dox_ix(!w z>Q46CTN>wPr{8|}U9=jJN<7@(ednFG@Ssaj$ifW3(-7RBd+s@$-(UgQ3%E0-J|sI! zu4eupQoUr+L9)3HyqJU{P#maJJXa?MO-=dU9tHL8N=cJ~SUz2efk4W~6zR@oDI30T z3XOQXbVjYzN*s#_G%o#v10seoB6MVfC}e9hE85(`;*Z~cZ+&ZvnCUz7OCL<l?H-;K zcZk$IS}5*p5D;5a2dTXQ#eYnqqx~ym{ge4@)A2rc+~3?d*jVarI__($ui0GMTfSAh zIbXY59PDfw%r$g19<|l(Hy>@aHlFaT;r`ywTz!V-L-2>d*Q-}95f<5-&v*6oa>`NY zClZ){`g17nU|n@}Tj(`h{UkS}1IMuM$GABRC-3ys(2YkzJjhcpA|Cds@mUdh_=jQk zmBWHi!qiv|sN$>%_z+jn%Bbm{50oK!uM4P7AYd@0%i5s?p#46jyOq~H{4hZ0)6Ocr zb7WlJ%gOh?yx6LD+BKyr$7@>p=~lt=MK3(a?s<x>?aDLTBwqJQztRoNx9(<uJ<b4a zYPi~;vR_I|Su&nOn>>OsbI;KcPmPB-ZmYMBTHx>h{_o@V`0jVV%b$SwKmYST2hIQ9 z@BQ96w-z4v-}#;2i61&SISK8D<bVuUER8??(?2D0EL`yTl)nn-&v~dkg^w#=#Lrrz zW0(?fL-_`fT2jN(AATMK;;_%%8xW^3eY{D>+g@r5Ou-=EBfY?>T9-qv6b^{%?srJF zQaOG~eUhr6yXrmTte61eCLwI!iee0<n_nqHQeWNJUfJ9OHY#Gz;JZ%AxvxGkGO)>Z zE1r0Dm8??8({yzAT$r4MfwQx<Jv=z{`PW}ZqLEv%yuR|%EAXBgn_CfG0igm_CGAHh zLNUw_OmbT(%>mgf#Z4p{5rM?$u%xr?uyi)I(e0KT2kaSSTsSv?JG7?6v6c$Jd8;sj zjP#GEK1T*I(`%!+-5u>+xi+*Q5BK+w(Nu)p!5$(u^K*0P@2spYzx)1&i%Uyy{^afd zL1^mI+T{2!hZrBs7kj$8Mg|Kw$g^$jYuhB$Y=QufF)*6%D&(3PY7cvQy0Qdd>}}L; zuN-eI^|jVq8|^#V*;rnf#mnAYUo(*Jt~)u*wY8E0_Tt3Y<iy0Y*RCO9IXX7_+0TA9 z-`AHXa<{8%cyyw_uaNKQ866qsTLhOZr;iR#_^<Q_%@-^lND{l20I2eT5yQK94EO*D zvm=b3_`@(b<4F{Qr!W!X;S`2_Jg~!+smT&%L6`z@NzQqJ^GB!W(!C2&=Fu*{+})xk zJf&d7%J=j8l<s!gN(S+Lg2zi%3DG9J8w0j?nHJ#={y@J&{B-r{-A>x@lhZNag^fUe z#UXV1^wUS2+7+QyL&eKiC#zjBGfD-vIDpjJc$W)4A=jKXg2rB@_3)erQuT3<um#Af z7C#;4diWDe|B&4C_o#2m<IXz&umAe5koeif_!Z^({onunfBeUP<ha#u^7xd$3g{o< zFn+Qh9rl~EHoUMaq;|Ei)m7XiQX80~hX6QI$Rqrj+IV7+6r-82r^cIQ3}XCo6>AhW z*VJwoS0~<p<LmvNaj8ys_ezY(Q04ed`EZd!waH~#q$~lih%=zMh8X-&KG$04YDaG- z*P1cq8L4Y~Hd(t~%ocz(8$VEUc(5M;3c^3!*<4*(*xft8josPZbLrA#Z+A~?OItRJ zkGX4oYX^_>*2X5mpwJNR+`i>}1ia?E2cDirx}58q+x$QB_5`HzH75p&Z^rcwwFdOR zN91k;*=;E&kbS7oN4-!Rfm8#CLXuLsSu8y&vMy*%y!HN#jqR=XZ`^+G#%*F-3H;sI z-uagw|Mcec{N~m!x<y^xJ<A)rTSs+sYdcLXoEEgf7g}81TwE?*9PA~6mTUlpo{o;T zrq!kS<=N?`qurji#^(CtgYEUUriRg>VYGMp@_E4eP$5qwF%1PNMxyfr1J|xyn;4(C zeEBl@U%6(OEU>-3gF{0DgM;M5!m1&kRChj4`db=^%mSo_1;<M#(Zs`DZrp)VilZDb zmk*3EN&}Khedr_8$3PgL@tbg;6r75OO+1zSKH=hcGNv9Bp5jG{=Z@d-5iVq5PJN1n zP=KtZOk(uXn;*M^2Ju77RQP!)Yq@FRd~$bqmtLpMt4aG&jeWMclJ2a;8cBLEbmP5B ze%Hep40eD}8Up(Nk|+Mmg)|f|s)!#KeC&4qsFtXH|D?143u#=`H{N*TkN^0OV_1LA z6-jyA|L*Vp&Y^t#dcj`)$>UT0Dxg2-q4M-RF16ppn|;6{F$xJ=Q~)Ib#Dt|h0FD4P zV)#<tb}<Z!aZC(BLcvncP2KGtfX1&3Web&xH=&dr5`PsiM<_sebT9@|Mnb4{TtWY^ z;?Cy@Xu$U_S`1AEX~oTA5upk8SOP$upN%^nUpsHW_jrt@zNZK<WkP|7-vxmt-wUIC zd2s=iG%i8<eST>kc(c8^K0iN~ZEw!Cw_Lq4*$2!Qob7;fUo39)bmovwmtg$SadBf) zDW#522K#$K(r{^bFo{voegPq&C2C54sA`IrLrSkZ(=#CMEmEi)AK#i@m|a={uk&qB zR|kof-k)E;G(Nn(ceHv?zjM+E%V%n3v$3W9@`dr1Y>uK{d**UqZ_nh&z_XL1c-k{W zS)3fc^33?yVBhFKcm45xwyEY|d-Kk%o21RkH8&Dk(ArdgawJW0yy*~P2uI-6+uPIG z(b3o6f9c|6p}%i%V2~BOBbUwR^FTU0F><#zWv~`J?JNIvViEiq61CFc#vsz?5@eFt zT#e}r8cVxO6~271rO-^6L1Bc%V<wEo@`)CY_SF1}fp{3w_jprrq=i|ZDsZ`t@#L;_ z;>(wkE``X*2dvKhqSd?j<YmwNNHqU|rTjQQznl7A`sLl`#QoO#<2<)|?bFu+-~RTu z<4VC?|C2xYlNVon@#4jc2wA4oAwR|Hqj(c9Xgter{(~R<AUp;4{6`)UJgV}SH$@fD ze~QE7XX{o0g9Z$dg7_)?8ebo<Ldx40!{QXwsMxsihLOU)F(h&T6yNZyohAm>Dfegm z^WY6lA?y?e3QtM-HN&lf5#psSZ@`LXMrhcS-6AJ2?qKrcW(ddZ$>rLG#dmf|K1!-l z=;_k*G!8mHln2ttEz<XBY{W^AJGrBy3uPPV=!1Q|&5bpeCMV#j!=caRvYnl|wYB2n z;u0SB8@HwbuSiLbkByE`jFCu5?q^O2I4&^5XM1lSk9$`~jz0mw1Nol5-cE=vMD7-g z>zEmo3etRs)Ms)#hc)XvM~fT#!-f3LQQhXj$=lOwYdeQ~hbLD@`_{G(JKI|?4fZ}W zTG-m&Clk};a6bmh{^okFwdKPP-Y54Jw4R-f;{4Pt!25;KAyP=q&D_DF!Oe>40tcqA zua8oZ&i2x!ivvT01Utf3g4j=ts!W{|<prbgpnM=Z0zm+Dmo@Z}QyN+l{dAD-v5?+h z9#K#VoeX;Lx-y;usWI<=hVd3G*!c6*C=K8~44ZKO@JVb5r)EbeK>2OCkKep}&c;K! z;*9Vn3inLi{0UtXIr8EdeQRsWSvOB;Evm(?w!jn70<c*;{x$W2t&VEsrAwF2*;^k+ z=$8BD%gg!rl)nn-pNIkfSQjz{YEyneM=de*Ore|@5Cn)5DjWk8haD-H60VHlQR?UZ zRSY{)C?qx{;`ga%#Wq7INvK^6&QkR)M>(lxi3=QVSdQDygz^rm>}#*4WhT#L5t}p} z92ho`=OKb9^<aZ2^}uU%yGfG^>m8pu*q7Y8ydkXf$}`W@H#M(qZr{2y4bKFpHQJMq z=bydynU`Pr?CAK#U;OG<UwP%Tgw~=TGcq=j@6E%BM@eRTbE^l^jQH`ppya)MVsmS6 zP0tdX`op)c6P%jw?l`V%I5@8D%(dTGDE|A0QynnlcSs}9G?LE|55NxxyRzBFx@@Mt zqoom0-rb&AoSlZtzP7x0p}*sBYi;Jv?S;9S&s@Dk0KtU|6VT$xM+=LcqK=P_Zj;IN z_#~h26EJUU>*?vHDUjMxA_J7<X%x%Z?)aOAG7owppJ$zNCi~eN{}j2NF)3qc8^4cd zK?*>}Ga_|a7_?#R#p5$BQam_QBPYIpJYT#Rsd~jjF;%d5dX_(;ykL*@vUPUhT-BRn z8IEpJ-SLFhs9Nl53q0m609PK(8DKr(r>Uaiut(JLJj)-K;Xcm?9+UD{0sVQ7lc(xg zzN3eIJw^sGBu(M__^SYS{6l|LL@@q&K+JJFrfh)t4sr2P06N~M{fVg`#^^lUCk8R8 zpQOGjuUd@lVj$%=uUNH!v{Ee-T0U<4RE<Kj16+a2&{1&5FBLb7o7+Hn{MLvnCTVw+ z<{bl|zNNJp5)HDJM<=!8<D<_!bM^Jte-6PGXfxfNxvpIMK%sANX!y#ND`TUhw{PER zZ)<@Yb8@i%&O2}azyJM5H*QbOEH2F~EZtr#7IzL-ws-HWY`!(Mva*A=W*fwqk->iC zWyl*fzq+}(yFb*Ey)@EKih<3gx!tV|X!P%Y_(84_K7HNN>}@o5U=6`VC!1$~Zx56f z3=>k@Ub%b`m&t{R34|#DUeJW_wc~1s<uX1#hR0nAcVQ4IRe`km)kG4L;UFUMxVz&# zBymjo-7~FPi>EMd7?9zDR9D6qgrA4;mijiHHQ_#~fg1OF45`C!W9%L-h)1ATD)rmc zqvJsp22c1fzC$Qan0Ijtgywo`RyS-sPx;IsA;LTErl+Qk)rwSG;BjjKk~9H}KltE- zAN}Y@DTh5Sb95v>^#Z44D+zV=M?kX)&w_rFN>zJSG0wmI<t3>C`cHk3{A}H@9IwaQ ze?ZA8xEXNIJ@9u$NR+~|DX0-+nu<uspBp2afTUBujjxGITaKk-loQZf$vmmRq6z4& z9M6>_r;4AP1=mu5FZr$gA8;9n0wg}EsYCh(A2xh<g~^({HpCcOrLC=<h)>uxh5kGO z>Z8L2$STNLLLVm<)`B}vHrAGZ^6x+Vzy8aA+27v*KrgK<Z%f#(ac#e5YJG3(xM8Na zw|iLIkZIwEMBR?`bV83=THgXJ_vG5S#lpf8DVAW@@9k_$n{sdO*=H`F934V$fa(L9 z$4P(nnJXyK;7o_GPT?Wz1JDUPCE}H9usSFbpHn1A`lv<%@d*#0`XDeeNO@8!(cI;R zhXtf2k9_M1wLPAw>edn|ICNqRTg%5x_<20G;}6S$V6fbL48&tEz~V5#QZ`=2v7NF# z;xQkFS*o1n`1{^NI#sYR7b-4u6`SG-T@Yz-7m`X6R6U{9s20200#8~C5NryvM~(hb z6+Fd>|Bc`HjdDLdETFT9K##EeRY3o!#>`Xl+<-G;SdenyrM^l*iWHu3w0aL@Q1ROo zREmN7Ssug~sl;e0ypL;<0@m?w%YB(K#E&snMTF-?4Teozk?`Aq?LxD}NUpr@cY!(K zQzd&xlaiQJ2r)e!Sun2tI3Ps!5ZRgf+7o2v=jUeDR+d*+7T$dG&9~or`@j8v|MD;Y z^`B>^Zf$LCqG|ukwQKWh8?#HRGm9(p8@sK!E>b;htgl1pS>4)0bN<rE0CeNJqr?7O z(_m*yYeUU&cUya=cCd@Ysk<ZjuKnHZjrHQlKp!GJWP8HJ4kA}PX(ogABlL!$L9yEb z=+eb+X@Sj-kDa>UE~O5Vpm&UJ=~QU};5(x3{LAM!<6WDduXq#Bu8^4}^i&L*<4#F| z*YaMD$5P7V3uZuQ{EE=I9GAyMjSWJ-PmKFxh##tunhtR>;?WWhu=4Sls!KfH%4b15 zq{D0tr7a)iPwq<Rjrlay=*jJiYRRAO7J!DH!p8`&J*p~y?Q36)SvNT8Uw{2|6305M z$6-(SEK)oqD-0!kOv+yc^p9%HJPpr{VRwvFVkD757{2ib91tK&j10<~rXqk&eHbwJ zeIoc2bdJ$p`7R!B>fzfM2E`aC#?xmNCWXTs)`u$G<8d)w^mdLP5w}U`5pIm58ho5> zX+{WgWqp%))5DXR<@KH0^Gi^1=2kb?b`Eg1PcIkmEUdJ5b{*F@boUK*<og@jau+5q zc6awKt*qs{yZiIKmnKGsy4xFTPsp9rmCOCxzrERdvfHq;Tz|0D-FVpDe3EUd-(Fuk z+S}RN-l#b~f~$j*AN3bxWbm@{28A46IL|39R2lvaSvCRf6&s-<Ui1u}4!ER`d3<b| zB#AJ2428ppihDT>x$t4!vnh-lN)_KKZv2WJ9eO$7@9?ZtjiS!FOT0WD6)_NxCr%g= zsUaN?<MPoSaC!N!;s*swAXFi=Ox$ihfX^E3Ps3tYtwXg1sx9zvS^%t!G$aripzQn> z2sVH9SAP|rMu-%ImWT833U}qm_pkr@uj4P^{E#@76KqyLus)%>aT3|br~Fkwe{O^1 z>3mRtp7C}bJ}k!y<(I`6D+O6%^dF;^xG7_V<ftO$Q43Hh1;hhV2?j=tm1BSspiBzP z1xVx<q$*O5d*Yu5JQu$SjT3Gd<GHgS<5}iMs)EK0t_NLrv^A4JYHj;q@1*{?p=EjJ zX!Ed^>{DYygJd&3Y-pQZ-D+%V-ajOH)Bf?^R!d|3?VH#4wl_PoZQ0hQq5k~DP@(2X zX`x<!?d6wVcz(3d``o38zOK&CT)jLwF^;VJ;NW0C;*W(wcXt=+?9g~9q_V>re0Nzu zrL?*`WlxX@)aUkX+-2o>kz2-?lAq(XFXf^SIV?pbFCP{0NDCMEBf@|QpT~nd)p35G z)R2omjC;p#9%>zWIdzlNa4H|bUa-_Gh(}ksF%!2y+_2@16GnT*d34rO!mlch(x-Fn ztJbR80@W6H;1<B`{hjZ8huZ*=0m{H-RvrW;W2u=x{KG%|SkL+X_rLE8Z+KOt;HP9O zzxmB?hNoaZkQz2l2YXfl9!B{;R%PRhtAPF!H(m9INehHI<H#npwU=Xy08moMCLmx3 z88I^OKLgN-zl!0w7bw0m{OOm)a4jxI_%?Ot7^|heijkRLmii<vb0}D-V+zcLJH%Km z+%q(3xKHZ(P_|H!R8s`p#s!GU<l0*D?M*EtN<BEtwKR?Av-?|{o9o5CT=TP|c~Yfj zYL7Ct2jfEn*REXd>dX>QIx;kPc(Av&x{A0BoES78yE-A(v|XB<ym;~Q_=OAkz8*wm z+H=`V6RI+3$uug_l)sGKUe<u8a)%XK!=h9}u`3Rh)CjTWN-t=srt^EoBQ^|)@-Fbp zLK#xM9CvrPNjwZv10dWjo+j}kk}64DcP~b&B;mL5oy%{Ys%$)j;wP53O!%aHELD6; zT)enm)%VpFsJ1}01<q=LVzKzzYp>m-eIV0^aMkl{Mp!hYgZ;)gzH#q|K33(g0{ZhD zAy3t_VvH4FQ;e8n=#T;~;m;UvrSN(=L=I>;MlcnTag0U6eNy;1;QoM?!fgXq3r|cT zm>5d>S1CM{f=VeoT8@Xx;aY&^<zOy;V%(DD)<~*s;VHQ4f!w)F-B@p1UuSEk?qs05 zt<c-mh5x=a)0u4@8yOlO9VrwLe{4n8@#5rU7SZ<h?C|g~>8BvikVO?;zrMbHf@Y-z z3BSEb+U-cfhdh^vyN70R@B3ZDqm<u1Ze+h8Rpoe)1cdEXO9AfC8gW-vye9O1C{_3* z9?U75As$z$QpH_daYV(_;jG`ry%}y29vV-O^3j_b^Ik9iH@xB*R6a!GD^oMH9Qud$ z_peej;;CBcs+Fm>K(z%PS__c2>3iS%9)dFf_ZU4RHNz+P>A(Bk?>@ALf5eRmZ}qap zdYZWHDd%7O#a~>#dX?WlR^_iQ#E)vIJXOz4;rJ9530r=}jX%a)sr$ru^nSjI!C8#$ z0=Owhie99+V5#!Na4KA!!lv=(@mDd1E3bQOHk1RV7*@uGEN`xgI6gc&eoBPWRLqcN zUUw+n1<@L(#1JgIzq?1Y>7ikCF4^DP!zEweP!AEmIn#1<M5ZdGMa7!2@<Zuy4h;Y5 z{sBIw>Qb@w;`wk^JEz7&s*6*%jR9^L0I3h-0aNjzXBG862TAz=D7P-+;g=eR<zpbO za>Z#?UW?RaXU$D-+p{i?OA>k^zBq2-)FYm%m9AQuY710bpxOeDYYS8X{o~p*PeQpW z;`oXHC51EYjm+ZPmV=D5fLee`6+ut<Re&ZHAxJqmuIPHahXIhX8Dd0u4|tdA?G*aI z_dR1{pd5JJqdUSw{hIJl*JvmC6#tTo3NAe|mq_Adnwq3^*-%dwDlR@YK+kVIq&3to z#&Z=vFE8*tpm{}@9?)kDL*ouj!P9um+{1PX&pNBq;}(m%EM=RehIh)|OEr6VRy@>G z<uA9&QY9?61X4pN)llWDOT}WubLy-|q^@}q)~#w8t1VD%focmpg)LA8^iN@@o==rh z$habENkQ|tVC4X!{M&Lfpd2byyk`vfQs6HJZLzzwA}lUPlQBY#VQ2~_mfIw8$>ZCW zW5kM<iC<RHf=b=3qT{x_sHt0p`^Q)EUi$8);*LL_uvQbyQS2$ac$02VaD3`lu@zBq zG^R#NxgF(|O8quv-QD||RCAp*mf~St-WQ?QVoNDC1}dWM^68Ko@cyiO&ze;AQ)MV` z<Z_dsyb;PrORA1>smkrcdlV@(1}gS@^}}ilR9m3h0@W6HNG(tW^be_FpZ?oc^s~kY zuN>p1U}Xx>l%xNYcex@K32>w$ybG`?{x-((sn5$1^F3f?3jd|xRI0KmFnZQ)W1JTk z-rt|)+b##zsj|hO?S5c!{PT)8FSj}>j`)heJ@wmrc$X`};_@+8ZV!~Z;X~_HG>THz zX&9O1-BGby<LfKJ{Zt#qMpwlVSP`s;F%UQPJ?@+uW90>_IHJmL7&k)2o1_YMkJ0$_ oFN@V0R$HLj0@W6HL@n_D0|3lZjCHr7CjbBd07*qoM6N<$f@$o}g#Z8m literal 0 HcmV?d00001 diff --git a/silecs-diagnostic-cpp/src/silecs-diagnostic/resources/images/stop.png b/silecs-diagnostic-cpp/src/silecs-diagnostic/resources/images/stop.png new file mode 100755 index 0000000000000000000000000000000000000000..03a9a672daea270f0e35b47ef02fbe4b8124cccf GIT binary patch literal 6061 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 literal 0 HcmV?d00001 diff --git a/silecs-diagnostic-cpp/src/silecs-diagnostic/silecsmodule.cpp b/silecs-diagnostic-cpp/src/silecs-diagnostic/silecsmodule.cpp new file mode 100755 index 0000000..5567b14 --- /dev/null +++ b/silecs-diagnostic-cpp/src/silecs-diagnostic/silecsmodule.cpp @@ -0,0 +1,989 @@ +// Copyright 2016 CERN and GSI +// +// 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 3 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, see <http://www.gnu.org/licenses/>. + +#include <silecs-diagnostic/silecsmodule.h> +#include <silecs-communication/interface/utility/XMLParser.h> + +extern std::string UserName; + +//--------------------------------------------------------------------------------- +// TODO: to move this to utility +// remove then from diagnostictoolmainview as well! + +template <class T>bool from_string(T& t, const std::string& s, std::ios_base& (*f)(std::ios_base&)) +{ + std::istringstream iss(s); + return !(iss >> f >> t).fail(); +} +//--------------------------------------------------------------------------------- + +silecsModule::silecsModule(std::string logTopics, QTextBrowser *messageConsole): + messageConsole_(messageConsole), debugLoggingEnabled_(false) +{ + silecsService = NULL; + silecsCluster = NULL; + counterConnectedPLC = 0; + + if(logTopics.length() == 0) + { + Utils::logInfo(messageConsole_,"no log topics defined"); + silecsService = Silecs::Service::getInstance(0, NULL); + } + else + { + Utils::logInfo(messageConsole_,"the following log topics will be used: " + QString::fromStdString(logTopics)); + char *a = new char[logTopics.size()+1]; + a[logTopics.size()]=0; + memcpy(a,logTopics.c_str(),logTopics.size()); + char *argv[2] = { (char *)"-plcLog", a }; + silecsService = Silecs::Service::getInstance(2,argv); + } +} + +silecsModule::~silecsModule() +{ + silecsService->deleteInstance(); + silecsService = NULL; + silecsCluster = NULL; + Utils::logInfo(messageConsole_,"silecsModule destructor executed"); +} + +void silecsModule::setLogTopics(std::string logTopics) +{ + if(silecsService != NULL) + { + if(!silecsService->setLogTopics(logTopics)) + Utils::logError(messageConsole_,"Error while setting log topics "); + } +} + +bool silecsModule::isDebugLogEnabled() +{ + return debugLoggingEnabled_; +} + +void silecsModule::enableDebugLog() +{ + debugLoggingEnabled_ = true; +} + +Item *silecsModule::generateTree(string className, string deployFile) +{ + Item *root = NULL; + try{ + + Utils::logInfo(messageConsole_,"Loading deploy file: " + QString::fromStdString(deployFile)); + XMLParser parserDeploy(deployFile,true); + + ElementXML silecsDesign = parserDeploy.getFirstElementFromXPath("/SILECS-Deploy/Controller/SilecsDesign[@silecs-design-name='" + className + "']"); + string classVersion = silecsDesign.getAttribute("silecs-design-version"); + ElementXML deployUnitNode = parserDeploy.getFirstElementFromXPath("/SILECS-Deploy/Deploy-Unit"); + string deployName = deployUnitNode.getAttribute("name"); + + silecsCluster = silecsService->getCluster(className,classVersion); + root = new Item(silecsCluster); + root->setText(0,QString::fromStdString(className+" v"+classVersion)); + root->setWhatsThis(0,QString::fromStdString(CLUSTER_TYPE)); + root->setLinkedObject(silecsCluster); + + boost::ptr_vector<ElementXML> controllerNodes = parserDeploy.getElementsFromXPath_throwIfEmpty("/SILECS-Deploy/Controller"); + if(controllerNodes.size() == 0) + { + Utils::logError(messageConsole_,"No controller defined"); + return root; + } + boost::ptr_vector<ElementXML>::const_iterator controllerIter; + for(controllerIter = controllerNodes.begin(); controllerIter != controllerNodes.end(); controllerIter++) + { + std::string plcName = controllerIter->getAttribute("host-name"); + if(plcName.compare("")==true) + { + Utils::logError(messageConsole_,"PLC name empty - will be skipped"); + break; + } + Silecs::PLC *plc; + try + { + std::size_t deployFolderPos = deployFile.find(deployName); + string deployProject = deployFile.substr(0,deployFolderPos) + deployName; + string parameterFile = deployProject + "/generated/client/" + plcName + ".silecsparam"; + + Utils::logInfo(messageConsole_,"Loading parameter file: " + QString::fromStdString(parameterFile)); + plc = silecsCluster->getPLC(plcName,parameterFile); + } + catch(const Silecs::SilecsException& ex2) + { + Utils::logError(messageConsole_,"Error while loading "+QString::fromStdString(plcName)+". "+QString::fromStdString(ex2.what())); + continue; + } + + // add plc on the tree + Item *plcItem = Utils::addTreeItem(root,QString::fromStdString(plcName), + "",QString::fromStdString(PLC_TYPE),plc,":/Images/PLC.png"); + + // get devices for the current PLC + deviceVectorType deviceMap = plc->getDeviceMap(); + + deviceVectorType::iterator pDeviceIter; + for(pDeviceIter = deviceMap.begin(); pDeviceIter != deviceMap.end(); ++pDeviceIter) + { + std::string deviceName = pDeviceIter->first; + + Silecs::Device *device = pDeviceIter->second; + Utils::logInfo(messageConsole_,"found device: '" + QString::fromStdString(deviceName) + "' in parameter-file"); + + // add device on the tree + Item *deviceItem = Utils::addTreeItem(plcItem,QString::fromStdString(deviceName),"",QString::fromStdString(DEVICE_TYPE),device,":/Images/DEV.png"); + + // get register List for the current device + std::string registerList = device->getRegisterList(); + istringstream registerListSplitted(registerList); + + do + { + std::string registerName; + registerListSplitted >> registerName; + Utils::logInfo(messageConsole_,"found Register: '" + QString::fromStdString(registerName) + "' in parameter file"); + //avoid last empty register + if(registerName.compare("")==0) break; + + Silecs::Register *reg = device->getRegister(registerName); + + Item *registerItem = Utils::addTreeItem(deviceItem,QString::fromStdString(registerName),"",QString::fromStdString(REGISTER_TYPE),reg,":/Images/REG.png" ); + + // Set the block name + registerItem->setText(1 , QString::fromStdString(reg->getBlockName())); + + // Color background of input and output buffer + registerItem->setBackgroundColor(2,QColor(255,255,204));//light yellow + registerItem->setBackgroundColor(3,QColor(204,255,255));//light blue + + }while(registerListSplitted); + } + } // END OF PLC LOOP + } + catch (const Silecs::SilecsException& ex) + { + Utils::logError(messageConsole_,"getTreeroot - '" + QString::fromStdString(ex.what())); + return NULL; + } + catch(...) + { + Utils::logError(messageConsole_,"getTreeroot - Unknown Error '"); + return NULL; + } + + // Reset the number of connected PLC + this->counterConnectedPLC =0; + return root; +} + + +void silecsModule::setScalarDataInDeviceFromItem(Item *currentItem, std::string blockName) throw (std::string*) +{ + Silecs::Device* device = (Silecs::Device*)(currentItem->getLinkedObject()); + + // PLC and device name just for error messages + std::string plcName = ((Silecs::PLC*)dynamic_cast<Item*>(currentItem->parent())->getLinkedObject())->getName(); + std::string deviceName = device->getLabel(); + + std::string registerList = device->getRegisterList(); + istringstream registerListSplitted(registerList); + + int registerIndex = -1; + do + { + registerIndex++; + std::string registerName; + registerListSplitted >> registerName; + + qDebug() << "get Register"<<QString::fromStdString(registerName); + //avoid last empty register + + if(registerName.compare("")==0) break; + + Silecs::Register *reg = device->getRegister(registerName); + + // analyse just the register within the selected block + if(reg->getBlockName().compare(blockName)!=0) + { + qDebug() << "Continue"; + continue; + } + + std::string stringValue = currentItem->child(registerIndex)->text(3).toStdString(); + + Silecs::FormatType format = reg->getFormat(); + + switch(format) + { + case uInt8: + { + if(reg->isScalar()) + { + qDebug() << "uInt8"; + //Casting to uint16 and later to uint 8 to avoid it being converted for his ASCII character + uint16_t val; + if(!from_string<uint16_t>(val, stringValue, std::dec)) + { + qDebug()<< "Conversion from string to unsigned uInt8 failed"; + throw new std::string("Output buffer value of "+plcName+" / "+deviceName+" / "+registerName+ " must be a uInt8"); + } + reg->setValUInt8((uint16_t)val); + } + break; + } + + case Int8: + { + if(reg->isScalar()) + { + qDebug() << "Int8"; + int8_t val; + if(stringValue.length()!=1) + { + qDebug()<< "Conversion from string to Int8 failed"; + throw new std::string("Output buffer value of "+plcName+" / "+deviceName+" / "+registerName+ " must be a Int8 "); + } + else + { + val = (int8_t)stringValue[0]; + } + reg->setValInt8(val); + } + break; + } + + case uInt16: + { + if(reg->isScalar()) + { + qDebug() << "uInt16"; + uint16_t val; + if(!from_string<uint16_t>(val, stringValue, std::dec)) + { + qDebug()<< "Conversion from string to uInt16 failed"; + throw new std::string("Output buffer value of "+plcName+" / "+deviceName+" / "+registerName+ " must be a uInt16"); + } + reg->setValUInt16(val); + } + break; + } + + case Int16: + { + if(reg->isScalar()) + { + qDebug() << "Int16"; + int16_t val; + if(!from_string<int16_t>(val, stringValue, std::dec)) + { + qDebug()<< "Conversion from string to Int16 failed"; + throw new std::string("Output buffer value of "+plcName+" / "+deviceName+" / "+registerName+ " must be a Int16"); + } + reg->setValInt16(val); + } + break; + } + + case uInt32: + { + if(reg->isScalar()) + { + qDebug() << "uInt32"; + uint32_t val; + if(!from_string<uint32_t>(val, stringValue, std::dec)) + { + qDebug()<< "Conversion from string to uInt32 failed"; + throw new std::string("Output buffer value of "+plcName+" / "+deviceName+" / "+registerName+ " must be a uInt32"); + } + reg->setValUInt32(val); + } + break; + } + + case Int32: + { + if(reg->isScalar()) + { + qDebug() << "Int32"; + int32_t val; + if(!from_string<int32_t>(val, stringValue, std::dec)) + { + qDebug()<< "Conversion from string to Int32 failed"; + throw new std::string("Output buffer value of "+plcName+" / "+deviceName+" / "+registerName+ " must be a Int32"); + } + reg->setValInt32(val); + } + break; + } + + case uInt64: + { + if(reg->isScalar()) + { + qDebug() << "uInt64"; + uint64_t val; + if(!from_string<uint64_t>(val, stringValue, std::dec)) + { + qDebug()<< "Conversion from string to uInt64 failed"; + throw new std::string("Output buffer value of "+plcName+" / "+deviceName+" / "+registerName+ " must be a uInt64"); + } + reg->setValUInt64(val); + } + break; + } + + case Int64: + { + if(reg->isScalar()) + { + qDebug() << "Int64"; + int64_t val; + if(!from_string<int64_t>(val, stringValue, std::dec)) + { + qDebug()<< "Conversion from string to Int64 failed"; + throw new std::string("Output buffer value of "+plcName+" / "+deviceName+" / "+registerName+ " must be a Int64"); + } + reg->setValInt64(val); + } + break; + } + + case Float32: + { + if(reg->isScalar()) + { + qDebug() << "Float32"; + float val; + if(!from_string<float>(val, stringValue, std::dec)) + { + qDebug()<< "Conversion from string to Float32 failed"; + throw new std::string("Output buffer value of "+plcName+" / "+deviceName+" / "+registerName+ " must be a Float32"); + } + reg->setValFloat32(val); + } + break; + } + + case Float64: + { + if(reg->isScalar()) + { + qDebug() << "Float64"; + double val; + if(!from_string<double>(val, stringValue, std::dec)) + { + qDebug()<< "Conversion from string to Float64 failed"; + throw new std::string("Output buffer value of "+plcName+" / "+deviceName+" / "+registerName+ " must be a Float64"); + } + reg->setValFloat64(val); + } + break; + } + case String: + { + if(reg->isScalar()) + { + qDebug() << "String"; + reg->setValString(stringValue); + } + break; + } + case Date: + { + qDebug() << "Date"; + break; + } + } + }while(registerListSplitted); +} + + +void silecsModule::setArrayRegValue(Item *currentItem, std::vector<QString> *dataVector) +{ + Silecs::Register* reg = (Silecs::Register*)currentItem->getLinkedObject(); + Silecs::FormatType format = reg->getFormat(); + + //get device an plc name for message errors + std::string deviceName = ((Silecs::Device*)dynamic_cast<Item*>(currentItem->parent())->getLinkedObject())->getLabel(); + std::string plcName = ((Silecs::PLC*)dynamic_cast<Item*>(currentItem->parent()->parent())->getLinkedObject())->getName(); + std::string registerName = reg->getName(); + + // convert to the proper format + switch(format) + { + case uInt8: + { + Utils::logError(messageConsole_,"format = uInt8"); + if(reg->isDoubleArray()) // is 2DArray + { + uint8_t vector[reg->getDimension1()][reg->getDimension2()]; + uint16_t val; + for(unsigned long i=0;i<reg->getDimension1();i++) + { + for(unsigned long j=0; j<reg->getDimension2(); j++) + { + qDebug() << QString((*dataVector)[i*reg->getDimension2()+j]); + if(!from_string<uint16_t>(val, QString((*dataVector)[i*reg->getDimension2()+j]).toStdString(), std::dec)) + throw new std::string("Output buffer value of "+plcName+" / "+deviceName+" / "+registerName+ " must be a uInt8"); + else + vector[i][j] = (uint8_t)val; + } + } + reg->setValUInt8Array2D((const uint8_t*)vector,reg->getDimension1(),reg->getDimension2()); + qDebug() << "uInt8 2D array set"; + } + else + { + uint8_t vector[reg->getDimension1()]; + // Cast first to uint16_t to avoid conversion to ASCII character + uint16_t val; + for(unsigned long i=0;i<reg->getDimension1();i++) + { + qDebug() << QString((*dataVector)[i]); + if(!from_string<uint16_t>(val, QString((*dataVector)[i]).toStdString(), std::dec)) + throw new std::string("Output buffer value of "+plcName+" / "+deviceName+" / "+registerName+ " must be a uInt8"); + else + vector[i] = (uint8_t)val; + } + reg->setValUInt8Array(vector,reg->getDimension1()); + qDebug() << "uInt8 array set"; + } + break; + } + case Int8: + { + qDebug() << "format = Char"; + if(reg->isDoubleArray()) + { + int8_t vector[reg->getDimension1()][reg->getDimension2()]; + for(unsigned long i=0;i<reg->getDimension1();i++) + { + for(unsigned long j=0; j<reg->getDimension2(); j++) + { + qDebug() << QString((*dataVector)[i*reg->getDimension2()+j]); + if(QString((*dataVector)[i*reg->getDimension2()+j]).toStdString().length()!=1) + throw new std::string("Output buffer value of "+plcName+" / "+deviceName+" / "+registerName+ " must be a Int8"); + else + vector[i][j] = QString((*dataVector)[i*reg->getDimension2()+j]).toStdString()[0]; + } + } + reg->setValInt8Array2D((const int8_t*)vector,reg->getDimension1(),reg->getDimension2()); + qDebug() << "Int8 2D array set"; + } + else + { + int8_t vector[reg->getDimension1()]; + for(unsigned long i=0;i<reg->getDimension1();i++) + { + qDebug() << QString((*dataVector)[i]); + if(QString((*dataVector)[i]).toStdString().length()!=1) + throw new std::string("Output buffer value of "+plcName+" / "+deviceName+" / "+registerName+ " must be a Int8"); + else + vector[i] = QString((*dataVector)[i]).toStdString()[0]; + } + reg->setValInt8Array(vector,reg->getDimension1()); + qDebug() << "Int8 array set"; + } + break; + } + case uInt16: + { + qDebug() << "format = uInt16"; + if(reg->isDoubleArray()) + { + uint16_t vector[reg->getDimension1()][reg->getDimension2()]; + uint16_t val; + for(unsigned long i=0;i<reg->getDimension1();i++) + { + for(unsigned long j=0; j<reg->getDimension2(); j++) + { + qDebug() << QString((*dataVector)[i*reg->getDimension2()+j]); + if(!from_string<uint16_t>(val, QString((*dataVector)[i*reg->getDimension2()+j]).toStdString(), std::dec)) + throw new std::string("Output buffer value of "+plcName+" / "+deviceName+" / "+registerName+ " must be a uInt16"); + else + vector[i][j] = val; + } + } + reg->setValUInt16Array2D((const uint16_t*)vector,reg->getDimension1(),reg->getDimension2()); + qDebug() << "uInt16 2D array set"; + } + else + { + uint16_t vector[reg->getDimension1()]; + uint16_t val; + for(unsigned long i=0;i<reg->getDimension1();i++) + { + qDebug() << QString((*dataVector)[i]); + if(!from_string<uint16_t>(val, QString((*dataVector)[i]).toStdString(), std::dec)) + throw new std::string("Output buffer value of "+plcName+" / "+deviceName+" / "+registerName+ " must be a uInt16"); + else + vector[i] = val; + } + reg->setValUInt16Array(vector,reg->getDimension1()); + qDebug() << "uInt16 array set"; + } + break; + } + case Int16: + { + qDebug() << "format = Int16"; + if(reg->isDoubleArray()) + { + int16_t vector[reg->getDimension1()][reg->getDimension2()]; + int16_t val; + for(unsigned long i=0;i<reg->getDimension1();i++) + { + for(unsigned long j=0; j<reg->getDimension2(); j++) + { + qDebug() << QString((*dataVector)[i*reg->getDimension2()+j]); + if(!from_string<short>(val, QString((*dataVector)[i*reg->getDimension2()+j]).toStdString(), std::dec)) + throw new std::string("Output buffer value of "+plcName+" / "+deviceName+" / "+registerName+ " must be a Int16"); + else + vector[i][j] = val; + } + } + reg->setValInt16Array2D((const int16_t*)vector,reg->getDimension1(),reg->getDimension2()); + qDebug() << "Int16 2D array set"; + } + else + { + int16_t vector[reg->getDimension1()]; + int16_t val; + for(unsigned long i=0;i<reg->getDimension1();i++) + { + qDebug() << QString((*dataVector)[i]); + if(!from_string<short>(val, QString((*dataVector)[i]).toStdString(), std::dec)) + throw new std::string("Output buffer value of "+plcName+" / "+deviceName+" / "+registerName+ " must be a Int16"); + else + vector[i] = val; + } + reg->setValInt16Array(vector,reg->getDimension1()); + qDebug() << "Int16 array set"; + } + break; + } + case uInt32: + { + qDebug() << "format = uInt32"; + if(reg->isDoubleArray()) + { + uint32_t vector[reg->getDimension1()][reg->getDimension2()]; + uint32_t val; + for(unsigned long i=0;i<reg->getDimension1();i++) + { + for(unsigned long j=0; j<reg->getDimension2(); j++) + { + qDebug() << QString((*dataVector)[i*reg->getDimension2()+j]); + if(!from_string<uint32_t>(val, QString((*dataVector)[i*reg->getDimension2()+j]).toStdString(), std::dec)) + throw new std::string("Output buffer value of "+plcName+" / "+deviceName+" / "+registerName+ " must be a uInt32"); + else + vector[i][j] = val; + } + } + reg->setValUInt32Array2D((const uint32_t*)vector,reg->getDimension1(),reg->getDimension2()); + qDebug() << "uInt32 2D array set"; + } + else + { + uint32_t vector[reg->getDimension1()]; + uint32_t val; + for(unsigned long i=0;i<reg->getDimension1();i++) + { + qDebug() << QString((*dataVector)[i]); + if(!from_string<uint32_t>(val, QString((*dataVector)[i]).toStdString(), std::dec)) + throw new std::string("Output buffer value of "+plcName+" / "+deviceName+" / "+registerName+ " must be a uInt32"); + else + vector[i] = val; + } + reg->setValUInt32Array(vector,reg->getDimension1()); + qDebug() << "uInt32 array set"; + } + break; + } + case Int32: + { + qDebug() << "format = Int32"; + if(reg->isDoubleArray()) + { + int32_t vector[reg->getDimension1()][reg->getDimension2()]; + int32_t val; + for(unsigned long i=0;i<reg->getDimension1();i++) + { + for(unsigned long j=0; j<reg->getDimension2(); j++) + { + qDebug() << QString((*dataVector)[i*reg->getDimension2()+j]); + if(!from_string<int32_t>(val, QString((*dataVector)[i*reg->getDimension2()+j]).toStdString(), std::dec)) + throw new std::string("Output buffer value of "+plcName+" / "+deviceName+" / "+registerName+ " must be a Int32"); + else + vector[i][j] = val; + } + } + reg->setValInt32Array2D((const int32_t*)vector,reg->getDimension1(),reg->getDimension2()); + qDebug() << "Int32 2D array set"; + } + else + { + int32_t vector[reg->getDimension1()]; + int32_t val; + for(unsigned long i=0;i<reg->getDimension1();i++) + { + qDebug() << QString((*dataVector)[i]); + if(!from_string<int32_t>(val, QString((*dataVector)[i]).toStdString(), std::dec)) + throw new std::string("Output buffer value of "+plcName+" / "+deviceName+" / "+registerName+ " must be a Int32"); + else + vector[i] = val; + } + reg->setValInt32Array(vector,reg->getDimension1()); + qDebug() << "Int32 array set"; + } + break; + } + case uInt64: + { + qDebug() << "format = uInt64"; + if(reg->isDoubleArray()) + { + uint64_t vector[reg->getDimension1()][reg->getDimension2()]; + uint64_t val; + for(unsigned long i=0;i<reg->getDimension1();i++) + { + for(unsigned long j=0; j<reg->getDimension2(); j++) + { + qDebug() << QString((*dataVector)[i*reg->getDimension2()+j]); + if(!from_string<uint64_t>(val, QString((*dataVector)[i*reg->getDimension2()+j]).toStdString(), std::dec)) + throw new std::string("Output buffer value of "+plcName+" / "+deviceName+" / "+registerName+ " must be a uInt64"); + else + vector[i][j] = val; + } + } + reg->setValUInt64Array2D((const uint64_t*)vector,reg->getDimension1(),reg->getDimension2()); + qDebug() << "uInt64 2D array set"; + } + else + { + uint64_t vector[reg->getDimension1()]; + uint64_t val; + for(unsigned long i=0;i<reg->getDimension1();i++) + { + qDebug() << QString((*dataVector)[i]); + if(!from_string<uint64_t>(val, QString((*dataVector)[i]).toStdString(), std::dec)) + throw new std::string("Output buffer value of "+plcName+" / "+deviceName+" / "+registerName+ " must be a uInt64"); + else + vector[i] = val; + } + reg->setValUInt64Array(vector,reg->getDimension1()); + qDebug() << "uInt64 array set"; + } + break; + } + case Int64: + { + qDebug() << "format = Int64"; + if(reg->isDoubleArray()) + { + int64_t vector[reg->getDimension1()][reg->getDimension2()]; + int64_t val; + for(unsigned long i=0;i<reg->getDimension1();i++) + { + for(unsigned long j=0; j<reg->getDimension2(); j++) + { + qDebug() << QString((*dataVector)[i*reg->getDimension2()+j]); + if(!from_string<int64_t>(val, QString((*dataVector)[i*reg->getDimension2()+j]).toStdString(), std::dec)) + throw new std::string("Output buffer value of "+plcName+" / "+deviceName+" / "+registerName+ " must be a Int64"); + else + vector[i][j] = val; + } + } + reg->setValInt64Array2D((const int64_t*)vector,reg->getDimension1(),reg->getDimension2()); + qDebug() << "Int64 2D array set"; + } + else + { + int64_t vector[reg->getDimension1()]; + int64_t val; + for(unsigned long i=0;i<reg->getDimension1();i++) + { + qDebug() << QString((*dataVector)[i]); + if(!from_string<int64_t>(val, QString((*dataVector)[i]).toStdString(), std::dec)) + throw new std::string("Output buffer value of "+plcName+" / "+deviceName+" / "+registerName+ " must be a Int64"); + else + vector[i] = val; + } + reg->setValInt64Array(vector,reg->getDimension1()); + qDebug() << "Int64 array set"; + } + break; + } + case Float32: + { + qDebug() << "format = Float32"; + if(reg->isDoubleArray()) + { + float vector[reg->getDimension1()][reg->getDimension2()]; + float val; + for(unsigned long i=0;i<reg->getDimension1();i++) + { + for(unsigned long j=0; j<reg->getDimension2(); j++) + { + qDebug() << QString((*dataVector)[i*reg->getDimension2()+j]); + if(!from_string<float>(val, QString((*dataVector)[i*reg->getDimension2()+j]).toStdString(), std::dec)) + throw new std::string("Output buffer value of "+plcName+" / "+deviceName+" / "+registerName+ " must be a Float32"); + else + vector[i][j] = val; + } + } + reg->setValFloat32Array2D((const float*)vector,reg->getDimension1(),reg->getDimension2()); + qDebug() << "Float32 2D array set"; + } + else + { + float vector[reg->getDimension1()]; + float val; + for(unsigned long i=0;i<reg->getDimension1();i++) + { + qDebug() << QString((*dataVector)[i]); + if(!from_string<float>(val, QString((*dataVector)[i]).toStdString(), std::dec)) + throw new std::string("Output buffer value of "+plcName+" / "+deviceName+" / "+registerName+ " must be a Float32"); + else + vector[i] = val; + } + reg->setValFloat32Array(vector,reg->getDimension1()); + qDebug() << "Float32 array set"; + } + break; + } + case Float64: + { + qDebug() << "format = Float64"; + if(reg->isDoubleArray()) + { + double vector[reg->getDimension1()][reg->getDimension2()]; + double val; + for(unsigned long i=0;i<reg->getDimension1();i++) + { + for(unsigned long j=0; j<reg->getDimension2(); j++) + { + qDebug() << QString((*dataVector)[i*reg->getDimension2()+j]); + if(!from_string<double>(val, QString((*dataVector)[i*reg->getDimension2()+j]).toStdString(), std::dec)) + throw new std::string("Output buffer value of "+plcName+" / "+deviceName+" / "+registerName+ " must be a Float64"); + else + vector[i][j] = val; + } + } + reg->setValFloat64Array2D((const double*)vector,reg->getDimension1(),reg->getDimension2()); + qDebug() << "Float64 2D array set"; + } + else + { + double vector[reg->getDimension1()]; + double val; + for(unsigned long i=0;i<reg->getDimension1();i++) + { + qDebug() << QString((*dataVector)[i]); + if(!from_string<double>(val, QString((*dataVector)[i]).toStdString(), std::dec)) + throw new std::string("Output buffer value of "+plcName+" / "+deviceName+" / "+registerName+ " must be a Float64"); + else + vector[i] = val; + } + reg->setValFloat64Array(vector,reg->getDimension1()); + qDebug() << "Float64 array set"; + } + break; + } + case String: + { + qDebug() << "format = String"; + if(reg->isDoubleArray()) + { + void *vector = calloc(reg->getDimension1()*reg->getDimension2(), sizeof(void*)); + std::string** stringVector = static_cast<std::string**>(vector); + for(unsigned long i=0; i<(reg->getDimension1()); i++) + { + for(unsigned long j=0; j<reg->getDimension2(); j++) + { + stringVector[(i*reg->getDimension2())+j] = new std::string(((*dataVector)[(i*reg->getDimension2())+j]).toStdString()); + } + } + reg->setValStringArray2D((const std::string*)stringVector, reg->getDimension1(), reg->getDimension2()); + qDebug() << "String 2D array set"; + // cleanup + for (unsigned int i=0; i<(reg->getDimension1()*reg->getDimension2()); i++) + { + delete stringVector[i]; + } + free(vector); + } + else + { + std::string vector[reg->getDimension1()]; + for(unsigned long i=0;i<reg->getDimension1();i++) + { + vector[i] = ((*dataVector)[i]).toStdString(); + } + reg->setValStringArray(vector, reg->getDimension1()); + qDebug() << "String array set"; + } + break; + } + default: + Utils::logError(messageConsole_,"Error: no converter available for that format"); + } +} + + +HeaderInformations* silecsModule::getHeaderInformations(std::string plcName, string parameterFile) +{ + HeaderInformations* headerInfos = new HeaderInformations(); + + std::cout << "getHeaderInformations " << __LINE__ << std::endl; + Silecs::Cluster *headerCluster = silecsService->getCluster(HEADER_NAME,HEADER_VERSION); + std::cout << "getHeaderInformations " << __LINE__ << std::endl; + Silecs::PLC *plc = headerCluster->getPLC(plcName, parameterFile); + std::cout << "getHeaderInformations " << __LINE__ << std::endl; + Silecs::Device *device = plc->getDevice(HEADER_DEVICE); + std::cout << "getHeaderInformations " << __LINE__ << std::endl; + plc->connect(Silecs::MASTER_SYNCHRO,true); //connection will cause automatic Header registers uploading + std::cout << "getHeaderInformations " << __LINE__ << std::endl; + Silecs::Register *reg; + std::cout << "getHeaderInformations " << __LINE__ << std::endl; + // get/set release + reg = device->getRegister(HEADER_RELEASE_REG); + std::cout << "getHeaderInformations " << __LINE__ << std::endl; + headerInfos->setheaderRelease(reg->getValString()); + std::cout << "getHeaderInformations " << __LINE__ << std::endl; + // get/set release + reg = device->getRegister(HEADER_OWNER_REG); + std::cout << "getHeaderInformations " << __LINE__ << std::endl; + headerInfos->setheaderOwner(reg->getValString()); + std::cout << "getHeaderInformations " << __LINE__ << std::endl; + // get/set release + reg = device->getRegister(HEADER_DATE_REG); + std::cout << "getHeaderInformations " << __LINE__ << std::endl; + headerInfos->setheaderDate(reg->getInputValAsString()); + std::cout << "getHeaderInformations " << __LINE__ << std::endl; + // get/set release + // TODO: Fix checksum stuff for GSI + //reg = device->getRegister(HEADER_CHECKSUM_REG); + //headerInfos->setHeaderChecksum(reg->getInputValAsString()); + std::cout << "getHeaderInformations " << __LINE__ << std::endl; + // disconnect plc + if(plc->isConnected()) + plc->disconnect(); + std::cout << "getHeaderInformations " << __LINE__ << std::endl; + return headerInfos; +} + + +void silecsModule::updateClusterItem(Item *Cluster,bool updateInputBufferOnly) +{ + int numberOfPLC = Cluster->childCount(); + for(int PLCIndex=0; PLCIndex < numberOfPLC;PLCIndex++) + { + this->updatePLCItem(dynamic_cast<Item*>(Cluster->child(PLCIndex)),updateInputBufferOnly); + } +} + + +void silecsModule::updatePLCItem(Item *PLCItem,bool updateInputBufferOnly) +{ + int numberOfdevice = PLCItem->childCount(); + for(int deviceIndex=0; deviceIndex<numberOfdevice;deviceIndex++) + { + this->updateDeviceItem(dynamic_cast<Item*>(PLCItem->child(deviceIndex)),updateInputBufferOnly); + } +} + + +void silecsModule::updateDeviceItem(Item *deviceItem,bool updateInputBufferOnly) +{ + Silecs::Device *device = (Silecs::Device*)deviceItem->getLinkedObject(); + + int numberOfRegisters = deviceItem->childCount(); + for(int regIndex=0;regIndex<numberOfRegisters;regIndex++) + { + // Get the register Item in the tree view + Item *regItem = dynamic_cast<Item*>(deviceItem->child(regIndex)); + Silecs::Register *reg = device->getRegister(regItem->text(0).toStdString()); + + // PLC values + try + { + if(reg->hasInputAccess()) // is READ or READ+WRITE for silecs + { + if(reg->isScalar()) + { + // Display the value for scalar + regItem->setText(2 , QString::fromStdString(reg->getInputValAsString())); + } + else + { + // Display [...] for arrays + regItem->setText(2 , "[...]"); + } + } + else // is WRITE only for silecs + { + regItem->setText(2 , "WRITE-ONLY block"); + } + } + catch (std::exception& ex) + { + regItem->setText(2 , "?"); + std::ostringstream message; + message << "Impossible to read the input buffer value of - '" << regItem->text(0).toStdString() << "'"; + Utils::logError(messageConsole_,QString::fromStdString(message.str())); + } + + if(!updateInputBufferOnly) + { + // local values + try{ + if(reg->hasOutputAccess()) // = is WRITE or READ+WRITE for silecs + { + if(reg->isScalar()) + { + // Display the value for scalar + regItem->setText(3 , QString::fromStdString(reg->getOutputValAsString())); + } + else + { + // Display [...] for arrays + regItem->setText(3 , "[...]"); + } + // Output for type date not supported + if(reg->getFormat()==Date) + { + regItem->setText(3 , "Date format not supported."); + } + } + else // = is READ only for silecs + { + regItem->setText(3 , "READ-ONLY block"); + } + + } + catch (std::exception& ex) + { + regItem->setText(3 , "?"); + std::ostringstream message; + message << "Impossible to read the output buffer value of - '" << regItem->text(0).toStdString() << "'"; + Utils::logError(messageConsole_,QString::fromStdString(message.str())); + } + } + } +} + diff --git a/silecs-diagnostic-cpp/src/silecs-diagnostic/silecsmodule.h b/silecs-diagnostic-cpp/src/silecs-diagnostic/silecsmodule.h new file mode 100755 index 0000000..d89b473 --- /dev/null +++ b/silecs-diagnostic-cpp/src/silecs-diagnostic/silecsmodule.h @@ -0,0 +1,131 @@ +// Copyright 2016 CERN and GSI +// +// 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 3 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, see <http://www.gnu.org/licenses/>. + +#ifndef SILECSMODULE_H +#define SILECSMODULE_H + +#ifndef _Pow_PLC_SilecsModule_H_ // header encapsulation +#define _Pow_PLC_SilecsModule_H_ + +#include <QtGui> +#include <QtCore> + +#include <silecs-communication/interface/core/SilecsService.h> + +#include <silecs-diagnostic/constants.h> +#include <silecs-diagnostic/diagnostictoolmainview.h> +#include <silecs-diagnostic/headerinformations.h> +#include <silecs-diagnostic/item.h> +#include <silecs-diagnostic/utils.h> + +#include <string> +#include <cstdlib> +#include <iostream> +#include <sstream> +#include <algorithm> + +using namespace Silecs; + +enum LogTopic{ERROR, DEBUG, SETUP, ALLOC, LOCK, COMM, SEND, RECV, DATA, DIAG }; + +class silecsModule +{ +private: + Silecs::Service* silecsService; + Silecs::Cluster* silecsCluster; + + /** + * Add an element to the tree + */ + QTreeWidgetItem* addTreeItem(QTreeWidgetItem *parent,QString name ,QString description); + +public: + + /** + * Constructor. Get the SILECS service from the library + */ + silecsModule(std::string logParam, QTextBrowser *messageConsole); + + /** + * setLogTopics from the service + */ + void setLogTopics(std::string logParam); + + bool isDebugLogEnabled(); + void enableDebugLog(); + + /** + * Denstructor. Remove the SILECS service from the library + */ + ~silecsModule(); + + /** + *Generate the empty entire tree + */ + Item *generateTree(string className, string deployFile); + + /** + * Set the device with the proper scalar data converting + * from the string present in the GUI + * in case of error returns a string exception with the message + */ + void setScalarDataInDeviceFromItem(Item *currentItem, std::string blockName) throw (std::string*); + + /** + * Set the register with the proper data converting + * from the string present in the GUI + * in case of error returns a string exception with the message + */ + void setArrayRegValue(Item *currentItem,std::vector<QString> *dataVector); + + /** + * Updates the input and output values of all the register + * for the given device Item without any other impact on the GUI + */ + void updateDeviceItem(Item *deviceItem,bool updateInputBufferOnly); + + /** + * Updates the input and output values of all the register + * for the given PLC Item without any other impact on the GUI + */ + void updatePLCItem(Item *PLCItem,bool updateInputBufferOnly); + + /** + * Updates the input and output values of all the register + * for the given cluster Item without any other impact on the GUI + */ + void updateClusterItem(Item *Cluster,bool updateInputBufferOnly); + + /** + * Get Header for the given plc name + * return a heade info with all the data set + */ + HeaderInformations* getHeaderInformations(std::string plcName, string parameterFile); + + /** + * Count the number of PLC connected + */ + int counterConnectedPLC; + + QTextBrowser *messageConsole_; + +private: + + bool debugLoggingEnabled_; + +}; + +#endif // end of header encapsulation _Pow_PLC_SilecsModule_H_ +#endif // SILECSMODULE_H diff --git a/silecs-diagnostic-cpp/src/silecs-diagnostic/stderrredirect.cpp b/silecs-diagnostic-cpp/src/silecs-diagnostic/stderrredirect.cpp new file mode 100644 index 0000000..9699904 --- /dev/null +++ b/silecs-diagnostic-cpp/src/silecs-diagnostic/stderrredirect.cpp @@ -0,0 +1,84 @@ +// Copyright 2016 CERN and GSI +// +// 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 3 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, see <http://www.gnu.org/licenses/>. + +#include <silecs-diagnostic/stderrredirect.h> + +#include <QtCore> +#include <QtGui> +#include <QMessageBox> + + +StdErrRedirect::StdErrRedirect(QTextEdit *errorLog,QObject *parent): QObject(parent) +{ + // Store the pointer to the error log window + m_errorLog = errorLog; + + // Create a temporary filename: first find the path: + tmpFileNameQtFormat = QDir::tempPath(); + + // Make sure the closing slash is present: + if (!tmpFileNameQtFormat.endsWith(QChar('/'))) + tmpFileNameQtFormat.append(QChar('/')); + + // Add the file name itself: + tmpFileNameQtFormat.append("QtDiagDump_"+QString::number(QCoreApplication::applicationPid())); + + qDebug()<< "file ->" << tmpFileNameQtFormat; + + // Obtain a version of the filename in the operating system's native format: + tmpFileNameNativeFormat = QDir::toNativeSeparators(tmpFileNameQtFormat); + + // if file exists because previous section crashed i rename the file ***.old + QFile fileToRename(tmpFileNameQtFormat); + if(fileToRename.exists()) + fileToRename.rename(tmpFileNameQtFormat+".old"); + + // Set up redirection to this file: + FILE* fdesc = freopen(tmpFileNameNativeFormat.toAscii().constData(), "a+", stderr); + fdesc = NULL; //just defined to avoid L866 warning + + // Initialise the QFileSystemWatcher: + connect(&watcher, SIGNAL(fileChanged(const QString &)), + this, SLOT(fileChanged(const QString &))); + watcher.addPath(tmpFileNameQtFormat); + + tmp.setFileName(tmpFileNameQtFormat); +} + +StdErrRedirect::~StdErrRedirect() +{ + // Ensure the temporary file is properly deleted: + fclose(stderr); + tmp.close(); + tmp.open(QIODevice::ReadWrite); + tmp.remove(); +} + +void StdErrRedirect::fileChanged(const QString &filename) +{ + (void)filename; + tmp.open(QIODevice::ReadOnly); + QTextStream stream(&tmp); + QString content = stream.readAll(); + tmp.close(); + + // Identify what's new, and just send this to the window: + int newchars = content.size() - oldContent.size(); + if (newchars) + { + m_errorLog -> append(content.right(newchars)); + oldContent = content; + } +} diff --git a/silecs-diagnostic-cpp/src/silecs-diagnostic/stderrredirect.h b/silecs-diagnostic-cpp/src/silecs-diagnostic/stderrredirect.h new file mode 100644 index 0000000..59fc0ab --- /dev/null +++ b/silecs-diagnostic-cpp/src/silecs-diagnostic/stderrredirect.h @@ -0,0 +1,49 @@ +// Copyright 2016 CERN and GSI +// +// 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 3 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, see <http://www.gnu.org/licenses/>. + +#ifndef STDERRREDIRECT_H +#define STDERRREDIRECT_H + +#include <QObject> +#include <QTextEdit> +#include <QtCore> + + +class StdErrRedirect : public QObject +{ + Q_OBJECT + +public: + // Constructor + StdErrRedirect(); + StdErrRedirect(QTextEdit *errorLog, QObject *parent = NULL); + + // Destructor + ~StdErrRedirect(); + +private slots: + void fileChanged(const QString &filename); + +private: + QFile tmp; + QFileSystemWatcher watcher; + QString tmpFileNameQtFormat; + QString tmpFileNameNativeFormat; + + QTextEdit *m_errorLog; + QString oldContent; +}; + +#endif // STDERRREDIRECT_H diff --git a/silecs-diagnostic-cpp/src/silecs-diagnostic/utils.cpp b/silecs-diagnostic-cpp/src/silecs-diagnostic/utils.cpp new file mode 100755 index 0000000..2e73648 --- /dev/null +++ b/silecs-diagnostic-cpp/src/silecs-diagnostic/utils.cpp @@ -0,0 +1,336 @@ +// Copyright 2016 CERN and GSI +// +// 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 3 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, see <http://www.gnu.org/licenses/>. + +#include <silecs-diagnostic/utils.h> +#include <silecs-diagnostic/silecsmodule.h> + +extern silecsModule *mysilecs; + +void Utils::logError(QTextBrowser* errorConsole, QString message) +{ + errorConsole->insertHtml("<font color='red'>DIAG-TOOL [ERROR] " + message + "</font><br>"); + errorConsole->verticalScrollBar()->setValue(errorConsole->verticalScrollBar()->maximum()); +} + +void Utils::logInfo(QTextBrowser* errorConsole, QString message) +{ + errorConsole->insertHtml("<font color='black'>DIAG-TOOL [INFO] " + message + "</font><br>"); + errorConsole->verticalScrollBar()->setValue(errorConsole->verticalScrollBar()->maximum()); +} + +void Utils::logDebugIf(QTextBrowser* errorConsole, QString message) +{ + if( mysilecs->isDebugLogEnabled()) + { + errorConsole->insertHtml("<font color='black'>DIAG-TOOL [DEBUG] " + message + "</font><br>"); + errorConsole->verticalScrollBar()->setValue(errorConsole->verticalScrollBar()->maximum()); + } +} + +//convert integer to string +std::string Utils::convertInt(int number) +{ + char tmp[32]; + sprintf(tmp, "%d", number); + return tmp; +} + +//convert long to string +std::string Utils::convertLong(long number) +{ + char tmp[32]; + sprintf(tmp, "%ld", number); + return tmp; +} + +Item* Utils::addTreeItem(Item *parent,QString name ,QString description, QString type, void* linkedObject,QString icon) +{ + Item *itm = new Item(linkedObject); + itm->setFlags(Qt::ItemIsSelectable | Qt::ItemIsUserCheckable | Qt::ItemIsEnabled | Qt::ItemIsDragEnabled ); + itm->setText(0,name); + itm->setText(2,description); + itm->setWhatsThis(0,type); + + if(icon.compare("")!=0) + itm->setIcon(0,QIcon(QPixmap(icon))); + + parent->addChild(itm); + return itm; +} + +char* Utils::chop(char *string) +{ + size_t i, len; + len = strlen(string); + char *newstring; + newstring = (char *)malloc(len); + for(i = 0; i < strlen(string)-1; i++) + { + newstring[i] = string[i]; + } + newstring[len] = '\0'; + + return newstring; +} + +template <class T>bool from_string(T& t,const std::string& s, std::ios_base& (*f)(std::ios_base&)) +{ + std::istringstream iss(s); + return !(iss >> f >> t).fail(); +} + +void Utils::displayClusterInformation(Silecs::Cluster *cluster,QTextEdit *console) +{ + std::string text = ""; + + text.append("<h3>Cluster general information</h3>"); + text.append("<ul>"); + text.append("<li>Class name: "+cluster->getClassName()+"</li>"); + text.append("<li>Class version: "+cluster->getClassVersion()+"</li>"); + text.append("<li>Host name: "+cluster->getHostName()+"</li>"); + text.append("</ul>"); + + console->setText(QString::fromStdString(text)); + +} + +void Utils::displayPLCInformation(Silecs::PLC *plc,QTextEdit *console) +{ + std::string text = ""; + + //TODO: GSI Add Header Info + if(plc->isConnected()) + { +// text.append("<h3><font color ='green'>This PLC is currently connected</font></h3><hr/>"); +// +// HeaderInformations *headerInfo = mysilecs->getHeaderInformations(plc->getName(),plc->getParamsFileName()); +// text.append("<h3><font color ='green'>PLC Runtime information</font></h3>"); +// text.append("<ul>"); +// text.append("<li>PLC HEADER DATA uploaded from: "+plc->getName()+"</li>"); +// text.append("<li>Software Release: "+headerInfo->getheaderRelease()+"</li>"); +// text.append("<li>Mapping Owner: "+headerInfo->getheaderOwner()+"</li>"); +// text.append("<li>Mapping Checksum: "+headerInfo->getHeaderChecksum()+"</li>"); +// text.append("<li>Generation Date: "+headerInfo->getheaderDate()+"</li>"); +// text.append("</ul><hr/>"); +// +// delete headerInfo; + } + else + text.append("<h3>This PLC is currently disconnected</h3><hr/>"); + + text.append("<h3>PLC general information</h3>"); + text.append("<ul>"); + text.append("<li>Name: "+plc->getName()+"</li>"); + text.append("<li>Address: "+plc->getIPAddress()+"</li>"); + text.append("<li>Brand: "+plc->getBrand()+"</li>"); + text.append("<li>Model: "+plc->getModel()+"</li>"); + text.append("<li>Owner: "+plc->getLocalOwner()+"</li>"); + text.append("</ul><hr/>"); + + text.append("<h3>PLC configuration information</h3>"); + text.append("<ul>"); + text.append("<li>Protocol type: "+plc->getProtocolType()+"</li>"); + text.append("<li>Protocol mode: "+plc->getProtocolMode()+"</li>"); + text.append("<li>Base address: "+convertLong(plc->getBaseAddress())+"</li>"); + text.append("</ul><hr/>"); + + text.append("<h3>PLC generation information</h3>"); + text.append("<ul>"); + text.append("<li>Release: "+plc->getLocalRelease()+"</li>"); + text.append("<li>Date: "+plc->getLocalDate()+"</li>"); + text.append("<li>Checksum: "+convertLong(plc->getLocalChecksum())+"</li>"); + text.append("</ul><hr/>"); + + console->setText(QString::fromStdString(text)); +} + +void Utils::displayDeviceInformation(Silecs::Device *device,QTextEdit *console) +{ + std::string text = ""; + + text.append("<h3>Device general information</h3>"); + text.append("<ul>"); + text.append("<li>Name: "+device->getLabel()+"</li>"); + text.append("</ul>"); + + console->setText(QString::fromStdString(text)); +} + +void Utils::displayRegisterInformation(Silecs::Register *reg,QTextEdit *console) +{ + std::string text = ""; + + text.append("<h3>Register general information</h3>"); + text.append("<ul>"); + text.append("<li>Name: "+reg->getName()+"</li>"); + text.append("<li>Format: "+reg->getFormatAsString()+"</li>"); + if(reg->getFormat() == String) + text.append("<li>String length: "+convertLong(reg->getLength())+"</li>"); + text.append("<li>Dimension1: "+convertLong(reg->getDimension1())+"</li>"); + text.append("<li>Dimension2: "+convertLong(reg->getDimension2())+"</li>"); + text.append("<li>Block name: "+reg->getBlockName()+"</li>"); + text.append("<li>Last update: "+reg->getTimeStampAsString()+"</li>"); + + // Access method + if(reg->hasInputAccess() && reg->hasOutputAccess()) + text.append("<li>Access method: Read / Write </li>"); + else + { + if(reg->hasInputAccess()) text.append("<li>Access method: Read only </li>"); + else text.append("<li>Access method: Write only </li>"); + } + + text.append("<li>Synchronization method: "+reg->getSynchroTypeAsString()+"</li>"); + + // Retentive volatile + if(reg->isRetentive()) + text.append("<li>Storage method: Retentive</li>"); + else + text.append("<li>Storage method: Volatile</li>"); + + text.append("</ul>"); + + console->setText(QString::fromStdString(text)); + +} + +void Utils::displayRegisterValue(Silecs::Register *reg, + QLabel *binValueLabel, + QLabel *hexValueLabel, + QLabel *decValueLabel, + QLabel *asciiValueLabel + ) +{ + + if(!reg->hasInputAccess()){ + binValueLabel->setText("--Write only register--"); + hexValueLabel->setText("--Write only register--"); + decValueLabel->setText("--Write only register--"); + asciiValueLabel->setText("--Write only register--"); + } + else + { + // The register has input access + if(reg->getDimension1()>1 || reg->getDimension2()>1) + { + binValueLabel->setText("--Vector--"); + hexValueLabel->setText("--Vector--"); + decValueLabel->setText("--Vector--"); + asciiValueLabel->setText("--Vector--"); + } + else{ + //Scalar with input access + switch(reg->getFormat()) + { + case uInt8: + { + + binValueLabel->setText(QObject::tr("%1").arg(reg->getValUInt8(), 0, 2)); + hexValueLabel->setText(QObject::tr("%1").arg(reg->getValUInt8(), 0, 16)); + decValueLabel->setText(QObject::tr("%1").arg(reg->getValUInt8(), 0, 10)); + //QString temp; + //asciiValueLabel->setText(temp.sprintf("%c",reg->getValUInt8())); + QChar c = reg->getValUInt8(); + //if(!c.isPrint()) + // c='?'; + //asciiValueLabel->setText(QObject::tr("%1").arg(c)); + asciiValueLabel->setText(c.isPrint() ? QObject::tr("%1").arg(c):"--Not printable--"); + + break; + } + case Int8: + { + binValueLabel->setText(QObject::tr("%1").arg(reg->getValInt8(), 0, 2)); + hexValueLabel->setText(QObject::tr("%1").arg(reg->getValInt8(), 0, 16)); + decValueLabel->setText(QObject::tr("%1").arg(reg->getValInt8(), 0, 10)); + QChar c = reg->getValInt8(); + asciiValueLabel->setText(c.isPrint() ? QObject::tr("%1").arg(c):"--Not printable--"); + break; + } + case uInt16: + { + binValueLabel->setText(QObject::tr("%1").arg(reg->getValUInt16(), 0, 2)); + hexValueLabel->setText(QObject::tr("%1").arg(reg->getValUInt16(), 0, 16)); + decValueLabel->setText(QObject::tr("%1").arg(reg->getValUInt16(), 0, 10)); + asciiValueLabel->setText("--Not relevant--"); + break; + } + + case Int16: + { + binValueLabel->setText(QObject::tr("%1").arg(reg->getValInt16(), 0, 2)); + hexValueLabel->setText(QObject::tr("%1").arg(reg->getValInt16(), 0, 16)); + decValueLabel->setText(QObject::tr("%1").arg(reg->getValInt16(), 0, 10)); + asciiValueLabel->setText("--Not relevant--"); + break; + } + + case uInt32: + { + binValueLabel->setText(QObject::tr("%1").arg(reg->getValUInt32(), 0, 2)); + hexValueLabel->setText(QObject::tr("%1").arg(reg->getValUInt32(), 0, 16)); + decValueLabel->setText(QObject::tr("%1").arg(reg->getValUInt32(), 0, 10)); + asciiValueLabel->setText("--Not relevant--"); + break; + } + + case Int32: + { + binValueLabel->setText(QObject::tr("%1").arg(reg->getValInt32(), 0, 2)); + hexValueLabel->setText(QObject::tr("%1").arg(reg->getValInt32(), 0, 16)); + decValueLabel->setText(QObject::tr("%1").arg(reg->getValInt32(), 0, 10)); + asciiValueLabel->setText("--Not relevant--"); + break; + } + + case uInt64: + { + binValueLabel->setText(QObject::tr("%1").arg(reg->getValUInt64(), 0, 2)); + hexValueLabel->setText(QObject::tr("%1").arg(reg->getValUInt64(), 0, 16)); + decValueLabel->setText(QObject::tr("%1").arg(reg->getValUInt64(), 0, 10)); + asciiValueLabel->setText("--Not relevant--"); + break; + } + + case Int64: + { + binValueLabel->setText(QObject::tr("%1").arg(reg->getValInt64(), 0, 2)); + hexValueLabel->setText(QObject::tr("%1").arg(reg->getValInt64(), 0, 16)); + decValueLabel->setText(QObject::tr("%1").arg(reg->getValInt64(), 0, 10)); + asciiValueLabel->setText("--Not relevant--"); + break; + } + + case String: + { + binValueLabel->setText("--Not relevant--"); + hexValueLabel->setText("--Not relevant--"); + decValueLabel->setText("--Not relevant--"); + asciiValueLabel->setText("--Not relevant--"); + break; + } + + default:// Float32,Float64,Date + { + binValueLabel->setText("--Not relevant--"); + hexValueLabel->setText("--Not relevant--"); + decValueLabel->setText("--Not relevant--"); + asciiValueLabel->setText("--Not relevant--"); + break; + } + } + } + } +} diff --git a/silecs-diagnostic-cpp/src/silecs-diagnostic/utils.h b/silecs-diagnostic-cpp/src/silecs-diagnostic/utils.h new file mode 100755 index 0000000..45eee94 --- /dev/null +++ b/silecs-diagnostic-cpp/src/silecs-diagnostic/utils.h @@ -0,0 +1,110 @@ +// Copyright 2016 CERN and GSI +// +// 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 3 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, see <http://www.gnu.org/licenses/>. + +#ifndef UTILS_H +#define UTILS_H + +#include <string> +#include <map> +#include <vector> +#include <sstream> +#include <iostream> + +#include <QtCore> +#include <QtGui> +#include <QObject> +#include <QTextEdit> + +#include <silecs-diagnostic/item.h> + +namespace Silecs +{ + class Cluster; + class Register; + class Device; + class PLC; +} + +namespace Utils { + + void logError(QTextBrowser* errorConsole, QString message); + + void logInfo(QTextBrowser* errorConsole, QString message); + + void logDebugIf(QTextBrowser* errorConsole, QString message); + + /** + * Convert a integer number in the equivalent string + */ + std::string convertInt(int number); + + /** + * Convert a long number in the equivalent string + */ + std::string convertLong(long number); + + /** + * Add an element to the tree + */ + Item* addTreeItem(Item *parent,QString name ,QString description, QString type, void* linkedObject,QString icon); + + /** + * Remove the last element from a string + */ + char* chop(char *string); + + /** + * Convert from string to a generic numeric type + */ + template <class T>bool from_string(T& t,const std::string& s, std::ios_base& (*f)(std::ios_base&)); + + /** + * Display information about the cluster in the given console + */ + void displayClusterInformation(Silecs::Cluster *cluster,QTextEdit *console); + + /** + * Display information about the plc in the given console + */ + void displayPLCInformation(Silecs::PLC *plc,QTextEdit *console); + + /** + * Display information about the device in the given console + */ + void displayDeviceInformation(Silecs::Device *device,QTextEdit *console); + + /** + * Display information about the register in the given console + */ + void displayRegisterInformation(Silecs::Register *reg,QTextEdit *console); + + /** + * Display register value in multiple formats + */ + void displayRegisterValue(Silecs::Register *reg, + QLabel *binValueLabel, + QLabel *hexValueLabel, + QLabel *decValueLabel, + QLabel *asciiValueLabel + ); + + /** + * Return a map of the list of cluster the user can access + * < ClassName, ClassVersionList > + */ + std::map<std::string, std::vector<std::string>* >getUserAccessibleCluster(std::string userName); + +} +#endif // UTILS_H diff --git a/silecs-eclipse-plugin-feature/.project b/silecs-eclipse-plugin-feature/.project new file mode 100644 index 0000000..a49d71b --- /dev/null +++ b/silecs-eclipse-plugin-feature/.project @@ -0,0 +1,17 @@ +<?xml version="1.0" encoding="UTF-8"?> +<projectDescription> + <name>silecs-eclipse-plugin-feature</name> + <comment></comment> + <projects> + </projects> + <buildSpec> + <buildCommand> + <name>org.eclipse.pde.FeatureBuilder</name> + <arguments> + </arguments> + </buildCommand> + </buildSpec> + <natures> + <nature>org.eclipse.pde.FeatureNature</nature> + </natures> +</projectDescription> diff --git a/silecs-eclipse-plugin-feature/build.properties b/silecs-eclipse-plugin-feature/build.properties new file mode 100644 index 0000000..64f93a9 --- /dev/null +++ b/silecs-eclipse-plugin-feature/build.properties @@ -0,0 +1 @@ +bin.includes = feature.xml diff --git a/silecs-eclipse-plugin-feature/feature.xml b/silecs-eclipse-plugin-feature/feature.xml new file mode 100644 index 0000000..14d3b07 --- /dev/null +++ b/silecs-eclipse-plugin-feature/feature.xml @@ -0,0 +1,746 @@ +<?xml version="1.0" encoding="UTF-8"?> +<feature + id="silecsEclipsePluginFeature" + label="Silecs-eclipse-plugin-feature" + version="1.0.0.qualifier"> + + <description url="http://www.example.com/description"> + SILECS Eclipse Plugin + </description> + + <copyright url="http://www.example.com/copyright"> + Copyright 2016 CERN and GSI + +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 3 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, see <http://www.gnu.org/licenses/>. + </copyright> + + <license url="http://www.gnu.org/licenses"> + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/> + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + <one line to give the program's name and a brief idea of what it does.> + Copyright (C) <year> <name of author> + + 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 3 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, see <http://www.gnu.org/licenses/>. + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + <program> Copyright (C) <year> <name of author> + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +<http://www.gnu.org/licenses/>. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +<http://www.gnu.org/philosophy/why-not-lgpl.html>. + </license> + + <requires> + <import plugin="org.eclipse.ui"/> + <import plugin="org.eclipse.core.runtime"/> + <import plugin="org.eclipse.ui.workbench"/> + <import plugin="org.eclipse.core.resources"/> + <import plugin="org.eclipse.ui.ide"/> + <import plugin="org.eclipse.ui.editors"/> + <import plugin="org.eclipse.wst.xml.core"/> + <import plugin="org.eclipse.wst.xml.ui"/> + <import plugin="org.eclipse.ui.navigator.resources"/> + <import plugin="org.eclipse.core.filesystem"/> + <import plugin="org.eclipse.ui.console"/> + <import plugin="org.eclipse.ui.views"/> + <import plugin="org.eclipse.wst.validation"/> + <import plugin="org.eclipse.wst.validation.infopop"/> + <import plugin="org.eclipse.wst.validation.ui"/> + <import plugin="org.eclipse.jface.text"/> + <import plugin="org.eclipse.wst.sse.ui"/> + <import plugin="org.eclipse.ui.workbench.texteditor"/> + <import plugin="org.eclipse.text"/> + <import plugin="org.eclipse.wst.sse.core"/> + <import plugin="org.eclipse.ui.navigator"/> + <import plugin="org.eclipse.xsd"/> + <import plugin="org.eclipse.wst.xsd.core"/> + <import plugin="org.eclipse.core.expressions"/> + <import plugin="org.eclipse.cdt"/> + <import plugin="org.eclipse.cdt.core"/> + <import plugin="org.eclipse.cdt.ui"/> + <import plugin="org.eclipse.cdt.managedbuilder.ui"/> + <import plugin="org.eclipse.ltk.core.refactoring"/> + <import plugin="org.eclipse.ltk.ui.refactoring"/> + <import plugin="org.eclipse.equinox.launcher"/> + </requires> + + <plugin + id="silecs.eclipse.plugin" + download-size="0" + install-size="0" + version="0.0.0" + unpack="false"/> + +</feature> diff --git a/silecs-eclipse-plugin-update-site/.project b/silecs-eclipse-plugin-update-site/.project new file mode 100644 index 0000000..e9558b3 --- /dev/null +++ b/silecs-eclipse-plugin-update-site/.project @@ -0,0 +1,17 @@ +<?xml version="1.0" encoding="UTF-8"?> +<projectDescription> + <name>silecs-eclipse-plugin-update-site</name> + <comment></comment> + <projects> + </projects> + <buildSpec> + <buildCommand> + <name>org.eclipse.pde.UpdateSiteBuilder</name> + <arguments> + </arguments> + </buildCommand> + </buildSpec> + <natures> + <nature>org.eclipse.pde.UpdateSiteNature</nature> + </natures> +</projectDescription> diff --git a/silecs-eclipse-plugin-update-site/artifacts.jar b/silecs-eclipse-plugin-update-site/artifacts.jar new file mode 100644 index 0000000000000000000000000000000000000000..a4dc065cb54624162ab31ba014ff081382308c53 GIT binary patch literal 643 zcmWIWW@Zs#;Nak3sBHe_!GHvK8CVz+i%K%n5|c}c^(u06{+(iAI2-C)eAz%`&-3sX z6CB?%{xs&3eDlQRJkOTreOdccj+~e@Athth$$IxfrQ3~a7Xs2OUfI6AeKjlfdH3;I zi}M%oPF{3CkkgPU@Kjf4Xyg05{CoQjcmLFg56HbaY1%hojm#NSt887~7VOU5^`0xL zdG-RWEXLY2F@sInPrZWHb4;0|$;`6P%;$vrqNGQh9`?-=VcLAQs&+xIES@X36fIrK z)Xvt-Q(eSU82#Qlt|xip8n)!jwRbd5Nr(4b$}#htTp^`)l7(G;;?gx!*^(E$S`cQw z!TpJ&{-W6HA)4t6!>3fZ?t0iTtta{d>%OYTEqmO<RhJ*zpjvF28P;QCvglDkZSTaK zHCZ{0$7j#gE}xapd~~*`u$n}E#MZs?`FwpjC&gD;|J=X0GNI|!SI)ND&*Dw?a&~(j zEZbYZi6u+A_LWEbyPd{Q8_T!E{@hSeAN+oO{(?q18v{}0Fwq+Zd`n-tywg2;ys^(i z#x2sKce6(K;lqE5GpqH?V^@?%@4mC-q0Z+#yY^L2$`7ip?F;lY;$ED2i@Bcf?z%^u z=Wi8$s%v{!bL0Jw8&$=Re;<FJpK<YvQ}?dJ(}E%dzFn(T*=4-j`uUnA*8<u6efHkj zqQQCjgQ(8$*DSGF=U=O5eA=(};*$HfeBmj3k8G%WdaLrn|5MKv%LjO~bIka2pW{6v q149-&14Do}Ba;XNBE2BXfzk^qz(_p--mGjOC5%9552W>&Ks*2eYZKo9 literal 0 HcmV?d00001 diff --git a/silecs-eclipse-plugin-update-site/content.jar b/silecs-eclipse-plugin-update-site/content.jar new file mode 100644 index 0000000000000000000000000000000000000000..8ea08081a8759cb54e8da3d4954de65a0d2c5541 GIT binary patch literal 28454 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 literal 0 HcmV?d00001 diff --git a/silecs-eclipse-plugin-update-site/deliverToWebDav.sh b/silecs-eclipse-plugin-update-site/deliverToWebDav.sh new file mode 100755 index 0000000..c5ff0fe --- /dev/null +++ b/silecs-eclipse-plugin-update-site/deliverToWebDav.sh @@ -0,0 +1,29 @@ +#! /bin/bash + +kinit + +function copyFileToWebDav +{ + +cadaver -t <<EOF +open https://www.acc.gsi.de/dav/eclipse-luna/silecs +mput $1 +quit +EOF + +} + +for file in features/* +do + copyFileToWebDav $file +done + +for file in plugins/* +do + copyFileToWebDav $file +done + +copyFileToWebDav artifacts.jar +copyFileToWebDav content.jar +copyFileToWebDav index.html +copyFileToWebDav site.xml \ No newline at end of file diff --git a/silecs-eclipse-plugin-update-site/index.html b/silecs-eclipse-plugin-update-site/index.html new file mode 100644 index 0000000..c6627db --- /dev/null +++ b/silecs-eclipse-plugin-update-site/index.html @@ -0,0 +1,60 @@ +<html> +<head> +<title>silecs-eclipse-plugin-update-site</title> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> +<style>@import url("web/site.css");</style> +<script type="text/javascript"> + var returnval = 0; + var stylesheet, xmlFile, cache, doc; + function init(){ + // NSCP 7.1+ / Mozilla 1.4.1+ / Safari + // Use the standard DOM Level 2 technique, if it is supported + if (document.implementation && document.implementation.createDocument) { + xmlFile = document.implementation.createDocument("", "", null); + stylesheet = document.implementation.createDocument("", "", null); + if (xmlFile.load){ + xmlFile.load("site.xml"); + stylesheet.load("web/site.xsl"); + } else { + alert("Document could not be loaded by browser."); + } + xmlFile.addEventListener("load", transform, false); + stylesheet.addEventListener("load", transform, false); + } + //IE 6.0+ solution + else if (window.ActiveXObject) { + xmlFile = new ActiveXObject("msxml2.DOMDocument.3.0"); + xmlFile.async = false; + xmlFile.load("site.xml"); + stylesheet = new ActiveXObject("msxml2.FreeThreadedDOMDocument.3.0"); + stylesheet.async = false; + stylesheet.load("web/site.xsl"); + cache = new ActiveXObject("msxml2.XSLTemplate.3.0"); + cache.stylesheet = stylesheet; + transformData(); + } + } + // separate transformation function for IE 6.0+ + function transformData(){ + var processor = cache.createProcessor(); + processor.input = xmlFile; + processor.transform(); + data.innerHTML = processor.output; + } + // separate transformation function for NSCP 7.1+ and Mozilla 1.4.1+ + function transform(){ + returnval+=1; + if (returnval==2){ + var processor = new XSLTProcessor(); + processor.importStylesheet(stylesheet); + doc = processor.transformToDocument(xmlFile); + document.getElementById("data").innerHTML = doc.documentElement.innerHTML; + } + } +</script> +</head> +<body onload="init();"> +<!--[insert static HTML here]--> +<div id="data"><!-- this is where the transformed data goes --></div> +</body> +</html> diff --git a/silecs-eclipse-plugin-update-site/install.sh b/silecs-eclipse-plugin-update-site/install.sh new file mode 100755 index 0000000..b4af978 --- /dev/null +++ b/silecs-eclipse-plugin-update-site/install.sh @@ -0,0 +1,10 @@ +#!/bin/sh +set -e + +INSTALL_DIR=$1 + +SCRIPT=$(readlink -f "$0") +SCRIPTPATH=$(dirname "$SCRIPT") # path where this script is located in + +mkdir -p ${INSTALL_DIR} +cp -r ${SCRIPTPATH}/* ${INSTALL_DIR} \ No newline at end of file diff --git a/silecs-eclipse-plugin-update-site/site.xml b/silecs-eclipse-plugin-update-site/site.xml new file mode 100644 index 0000000..9800b60 --- /dev/null +++ b/silecs-eclipse-plugin-update-site/site.xml @@ -0,0 +1,15 @@ +<?xml version="1.0" encoding="UTF-8"?> +<site> + <feature url="features/silecsEclipsePluginFeature_1.0.0.201602241715.jar" id="silecsEclipsePluginFeature" version="1.0.0.201602241715"> + <category name="0.9.0"/> + </feature> + <feature url="features/silecsEclipsePluginFeature_1.0.0.201604071714.jar" id="silecsEclipsePluginFeature" version="1.0.0.201604071714"> + <category name="0.10.0"/> + </feature> + <feature url="features/silecsEclipsePluginFeature_1.0.0.201607261627.jar" id="silecsEclipsePluginFeature" version="1.0.0.201607261627"> + <category name="1.0.0"/> + </feature> + <category-def name="0.9.0" label="0.9.0"/> + <category-def name="0.10.0" label="0.10.0"/> + <category-def name="1.0.0" label="1.0.0"/> +</site> diff --git a/silecs-eclipse-plugin-update-site/test.txt b/silecs-eclipse-plugin-update-site/test.txt new file mode 100644 index 0000000..5e40c08 --- /dev/null +++ b/silecs-eclipse-plugin-update-site/test.txt @@ -0,0 +1 @@ +asdf \ No newline at end of file diff --git a/silecs-eclipse-plugin-update-site/web/site.css b/silecs-eclipse-plugin-update-site/web/site.css new file mode 100644 index 0000000..62c6f9f --- /dev/null +++ b/silecs-eclipse-plugin-update-site/web/site.css @@ -0,0 +1,12 @@ +<STYLE type="text/css"> +td.spacer {padding-bottom: 10px; padding-top: 10px;} +.title { font-family: sans-serif; color: #99AACC;} +.bodyText { font-family: sans-serif; font-size: 9pt; color:#000000; } +.sub-header { font-family: sans-serif; font-style: normal; font-weight: bold; font-size: 9pt; color: white;} +.log-text {font-family: sans-serif; font-style: normal; font-weight: lighter; font-size: 8pt; color:black;} +.big-header { font-family: sans-serif; font-style: normal; font-weight: bold; font-size: 9pt; color: white; border-top:10px solid white;} +.light-row {background:#FFFFFF} +.dark-row {background:#EEEEFF} +.header {background:#99AADD} +#indent {word-wrap : break-word;width :300px;text-indent:10px;} +</STYLE> diff --git a/silecs-eclipse-plugin-update-site/web/site.xsl b/silecs-eclipse-plugin-update-site/web/site.xsl new file mode 100644 index 0000000..ccb882e --- /dev/null +++ b/silecs-eclipse-plugin-update-site/web/site.xsl @@ -0,0 +1,214 @@ +<xsl:stylesheet version = '1.0' xmlns:xsl='http://www.w3.org/1999/XSL/Transform' xmlns:msxsl="urn:schemas-microsoft-com:xslt"> +<xsl:output method="html" encoding="UTF-8"/> +<xsl:key name="cat" match="category" use="@name"/> +<xsl:template match="/"> +<xsl:for-each select="site"> + <html> + <head> + <title>silecs-eclipse-plugin-update-site</title> + <style>@import url("web/site.css");</style> + </head> + <body> + <h1 class="title">silecs-eclipse-plugin-update-site</h1> + <p class="bodyText"><xsl:value-of select="description"/></p> + <table width="100%" border="0" cellspacing="1" cellpadding="2"> + <xsl:for-each select="category-def"> + <xsl:sort select="@label" order="ascending" case-order="upper-first"/> + <xsl:sort select="@name" order="ascending" case-order="upper-first"/> + <xsl:if test="count(key('cat',@name)) != 0"> + <tr class="header"> + <td class="sub-header" width="30%"> + <xsl:value-of select="@name"/> + </td> + <td class="sub-header" width="70%"> + <xsl:value-of select="@label"/> + </td> + </tr> + <xsl:for-each select="key('cat',@name)"> + <xsl:sort select="ancestor::feature//@version" order="ascending"/> + <xsl:sort select="ancestor::feature//@id" order="ascending" case-order="upper-first"/> + <tr> + <xsl:choose> + <xsl:when test="(position() mod 2 = 1)"> + <xsl:attribute name="class">dark-row</xsl:attribute> + </xsl:when> + <xsl:otherwise> + <xsl:attribute name="class">light-row</xsl:attribute> + </xsl:otherwise> + </xsl:choose> + <td class="log-text" id="indent"> + <xsl:choose> + <xsl:when test="ancestor::feature//@label"> + <a href="{ancestor::feature//@url}"><xsl:value-of select="ancestor::feature//@label"/></a> + <br/> + <div id="indent"> + (<xsl:value-of select="ancestor::feature//@id"/> - <xsl:value-of select="ancestor::feature//@version"/>) + </div> + </xsl:when> + <xsl:otherwise> + <a href="{ancestor::feature//@url}"><xsl:value-of select="ancestor::feature//@id"/> - <xsl:value-of select="ancestor::feature//@version"/></a> + </xsl:otherwise> + </xsl:choose> + <br /> + </td> + <td> + <table> + <xsl:if test="ancestor::feature//@os"> + <tr><td class="log-text" id="indent">Operating Systems:</td> + <td class="log-text" id="indent"><xsl:value-of select="ancestor::feature//@os"/></td> + </tr> + </xsl:if> + <xsl:if test="ancestor::feature//@ws"> + <tr><td class="log-text" id="indent">Windows Systems:</td> + <td class="log-text" id="indent"><xsl:value-of select="ancestor::feature//@ws"/></td> + </tr> + </xsl:if> + <xsl:if test="ancestor::feature//@nl"> + <tr><td class="log-text" id="indent">Languages:</td> + <td class="log-text" id="indent"><xsl:value-of select="ancestor::feature//@nl"/></td> + </tr> + </xsl:if> + <xsl:if test="ancestor::feature//@arch"> + <tr><td class="log-text" id="indent">Architecture:</td> + <td class="log-text" id="indent"><xsl:value-of select="ancestor::feature//@arch"/></td> + </tr> + </xsl:if> + </table> + </td> + </tr> + </xsl:for-each> + <tr><td class="spacer"><br/></td><td class="spacer"><br/></td></tr> + </xsl:if> + </xsl:for-each> + <xsl:if test="count(feature) > count(feature/category)"> + <tr class="header"> + <td class="sub-header" colspan="2"> + Uncategorized + </td> + </tr> + </xsl:if> + <xsl:choose> + <xsl:when test="function-available('msxsl:node-set')"> + <xsl:variable name="rtf-nodes"> + <xsl:for-each select="feature[not(category)]"> + <xsl:sort select="@id" order="ascending" case-order="upper-first"/> + <xsl:sort select="@version" order="ascending" /> + <xsl:value-of select="."/> + <xsl:copy-of select="." /> + </xsl:for-each> + </xsl:variable> + <xsl:variable name="myNodeSet" select="msxsl:node-set($rtf-nodes)/*"/> + <xsl:for-each select="$myNodeSet"> + <tr> + <xsl:choose> + <xsl:when test="position() mod 2 = 1"> + <xsl:attribute name="class">dark-row</xsl:attribute> + </xsl:when> + <xsl:otherwise> + <xsl:attribute name="class">light-row</xsl:attribute> + </xsl:otherwise> + </xsl:choose> + <td class="log-text" id="indent"> + <xsl:choose> + <xsl:when test="@label"> + <a href="{@url}"><xsl:value-of select="@label"/></a> + <br /> + <div id="indent"> + (<xsl:value-of select="@id"/> - <xsl:value-of select="@version"/>) + </div> + </xsl:when> + <xsl:otherwise> + <a href="{@url}"><xsl:value-of select="@id"/> - <xsl:value-of select="@version"/></a> + </xsl:otherwise> + </xsl:choose> + <br /><br /> + </td> + <td> + <table> + <xsl:if test="@os"> + <tr><td class="log-text" id="indent">Operating Systems:</td> + <td class="log-text" id="indent"><xsl:value-of select="@os"/></td> + </tr> + </xsl:if> + <xsl:if test="@ws"> + <tr><td class="log-text" id="indent">Windows Systems:</td> + <td class="log-text" id="indent"><xsl:value-of select="@ws"/></td> + </tr> + </xsl:if> + <xsl:if test="@nl"> + <tr><td class="log-text" id="indent">Languages:</td> + <td class="log-text" id="indent"><xsl:value-of select="@nl"/></td> + </tr> + </xsl:if> + <xsl:if test="@arch"> + <tr><td class="log-text" id="indent">Architecture:</td> + <td class="log-text" id="indent"><xsl:value-of select="@arch"/></td> + </tr> + </xsl:if> + </table> + </td> + </tr> + </xsl:for-each> + </xsl:when> + <xsl:otherwise> + <xsl:for-each select="feature[not(category)]"> + <xsl:sort select="@id" order="ascending" case-order="upper-first"/> + <xsl:sort select="@version" order="ascending" /> + <tr> + <xsl:choose> + <xsl:when test="count(preceding-sibling::feature[not(category)]) mod 2 = 1"> + <xsl:attribute name="class">dark-row</xsl:attribute> + </xsl:when> + <xsl:otherwise> + <xsl:attribute name="class">light-row</xsl:attribute> + </xsl:otherwise> + </xsl:choose> + <td class="log-text" id="indent"> + <xsl:choose> + <xsl:when test="@label"> + <a href="{@url}"><xsl:value-of select="@label"/></a> + <br /> + <div id="indent"> + (<xsl:value-of select="@id"/> - <xsl:value-of select="@version"/>) + </div> + </xsl:when> + <xsl:otherwise> + <a href="{@url}"><xsl:value-of select="@id"/> - <xsl:value-of select="@version"/></a> + </xsl:otherwise> + </xsl:choose> + <br /><br /> + </td> + <td> + <table> + <xsl:if test="@os"> + <tr><td class="log-text" id="indent">Operating Systems:</td> + <td class="log-text" id="indent"><xsl:value-of select="@os"/></td> + </tr> + </xsl:if> + <xsl:if test="@ws"> + <tr><td class="log-text" id="indent">Windows Systems:</td> + <td class="log-text" id="indent"><xsl:value-of select="@ws"/></td> + </tr> + </xsl:if> + <xsl:if test="@nl"> + <tr><td class="log-text" id="indent">Languages:</td> + <td class="log-text" id="indent"><xsl:value-of select="@nl"/></td> + </tr> + </xsl:if> + <xsl:if test="@arch"> + <tr><td class="log-text" id="indent">Architecture:</td> + <td class="log-text" id="indent"><xsl:value-of select="@arch"/></td> + </tr> + </xsl:if> + </table> + </td> + </tr> + </xsl:for-each> + </xsl:otherwise> + </xsl:choose> + </table> + </body> + </html> +</xsl:for-each> +</xsl:template> +</xsl:stylesheet> diff --git a/silecs-eclipse-plugin/.classpath b/silecs-eclipse-plugin/.classpath new file mode 100644 index 0000000..8cd7889 --- /dev/null +++ b/silecs-eclipse-plugin/.classpath @@ -0,0 +1,9 @@ +<?xml version="1.0" encoding="UTF-8"?> +<classpath> + <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8"/> + <classpathentry exported="true" kind="con" path="org.eclipse.pde.core.requiredPlugins"/> + <classpathentry kind="src" path="src/java"/> + <classpathentry exported="true" kind="lib" path="target/lib/xalan-2.7.2.jar"/> + <classpathentry exported="true" kind="lib" path="target/lib/jaxen-1.1.6.jar"/> + <classpathentry kind="output" path="target/classes"/> +</classpath> diff --git a/silecs-eclipse-plugin/.project b/silecs-eclipse-plugin/.project new file mode 100644 index 0000000..24f2a5d --- /dev/null +++ b/silecs-eclipse-plugin/.project @@ -0,0 +1,41 @@ +<?xml version="1.0" encoding="UTF-8"?> +<projectDescription> + <name>silecs-eclipse-plugin</name> + <comment></comment> + <projects> + </projects> + <buildSpec> + <buildCommand> + <name>org.python.pydev.PyDevBuilder</name> + <arguments> + </arguments> + </buildCommand> + <buildCommand> + <name>org.eclipse.jdt.core.javabuilder</name> + <arguments> + </arguments> + </buildCommand> + <buildCommand> + <name>org.eclipse.pde.ManifestBuilder</name> + <arguments> + </arguments> + </buildCommand> + <buildCommand> + <name>org.eclipse.pde.SchemaBuilder</name> + <arguments> + </arguments> + </buildCommand> + <buildCommand> + <name>org.eclipse.m2e.core.maven2Builder</name> + <arguments> + </arguments> + </buildCommand> + </buildSpec> + <natures> + <nature>org.eclipse.m2e.core.maven2Nature</nature> + <nature>org.eclipse.jdt.core.javanature</nature> + <nature>org.springsource.ide.eclipse.gradle.core.nature</nature> + <nature>org.eclipse.pde.PluginNature</nature> + <nature>org.python.pydev.pythonNature</nature> + </natures> +</projectDescription> diff --git a/silecs-eclipse-plugin/.pydevproject b/silecs-eclipse-plugin/.pydevproject new file mode 100644 index 0000000..3328e17 --- /dev/null +++ b/silecs-eclipse-plugin/.pydevproject @@ -0,0 +1,8 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<?eclipse-pydev version="1.0"?><pydev_project> +<pydev_property name="org.python.pydev.PYTHON_PROJECT_INTERPRETER">Default</pydev_property> +<pydev_property name="org.python.pydev.PYTHON_PROJECT_VERSION">jython 2.7</pydev_property> +<pydev_pathproperty name="org.python.pydev.PROJECT_SOURCE_PATH"> +<path>/${PROJECT_DIR_NAME}/src/scripts</path> +</pydev_pathproperty> +</pydev_project> diff --git a/silecs-eclipse-plugin/.settings/org.eclipse.core.resources.prefs b/silecs-eclipse-plugin/.settings/org.eclipse.core.resources.prefs new file mode 100644 index 0000000..8dd9b1d --- /dev/null +++ b/silecs-eclipse-plugin/.settings/org.eclipse.core.resources.prefs @@ -0,0 +1,3 @@ +eclipse.preferences.version=1 +encoding//src/test/java=UTF-8 +encoding/<project>=UTF-8 diff --git a/silecs-eclipse-plugin/.settings/org.eclipse.jdt.core.prefs b/silecs-eclipse-plugin/.settings/org.eclipse.jdt.core.prefs new file mode 100644 index 0000000..672496e --- /dev/null +++ b/silecs-eclipse-plugin/.settings/org.eclipse.jdt.core.prefs @@ -0,0 +1,12 @@ +eclipse.preferences.version=1 +org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled +org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8 +org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve +org.eclipse.jdt.core.compiler.compliance=1.8 +org.eclipse.jdt.core.compiler.debug.lineNumber=generate +org.eclipse.jdt.core.compiler.debug.localVariable=generate +org.eclipse.jdt.core.compiler.debug.sourceFile=generate +org.eclipse.jdt.core.compiler.problem.assertIdentifier=error +org.eclipse.jdt.core.compiler.problem.enumIdentifier=error +org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning +org.eclipse.jdt.core.compiler.source=1.8 diff --git a/silecs-eclipse-plugin/.settings/org.eclipse.ltk.core.refactoring.prefs b/silecs-eclipse-plugin/.settings/org.eclipse.ltk.core.refactoring.prefs new file mode 100644 index 0000000..b196c64 --- /dev/null +++ b/silecs-eclipse-plugin/.settings/org.eclipse.ltk.core.refactoring.prefs @@ -0,0 +1,2 @@ +eclipse.preferences.version=1 +org.eclipse.ltk.core.refactoring.enable.project.refactoring.history=false diff --git a/silecs-eclipse-plugin/.settings/org.eclipse.m2e.core.prefs b/silecs-eclipse-plugin/.settings/org.eclipse.m2e.core.prefs new file mode 100644 index 0000000..f897a7f --- /dev/null +++ b/silecs-eclipse-plugin/.settings/org.eclipse.m2e.core.prefs @@ -0,0 +1,4 @@ +activeProfiles= +eclipse.preferences.version=1 +resolveWorkspaceProjects=true +version=1 diff --git a/silecs-eclipse-plugin/JNLP-INF/APPLICATION_TEMPLATE.JNLP b/silecs-eclipse-plugin/JNLP-INF/APPLICATION_TEMPLATE.JNLP new file mode 100644 index 0000000..cf8e499 --- /dev/null +++ b/silecs-eclipse-plugin/JNLP-INF/APPLICATION_TEMPLATE.JNLP @@ -0,0 +1,69 @@ +<?xml version="1.0" encoding="UTF-8"?> +<jnlp spec="1.0+" codebase="*" href="silecs_launcher.jnlp"> <!-- URL to the site containing the jnlp application. It should match the + value used on export. Href, the name of this file --> + <information> + <!-- user readable name of the application --> + <title> Silecs-Eclipse-Plugin</title> + <!-- vendor name --> + <vendor>CERN</vendor> + <!-- vendor homepage --> + <homepage href="https://wikis/display/SIL/SILECs+Home"/> + <!-- product description --> + <description>Silecs Configuration tool</description> + </information> + + <!--request all permissions from the application. This does not change --> + <security> + <all-permissions /> + </security> + <update check="always" policy="always"></update> + + <!-- The name of the main class to execute. This does not change --> + <application-desc main-class="cern.silecs.activator.WebStartLauncher"> + <argument>-nosplash</argument> + <argument>-consoleLog</argument> + <argument>-data</argument> + <argument>@noDefault</argument> + </application-desc> + + <resources> + <!-- Reference to the launcher jar.--> + <jar href="*" /> + + <property name="app.name" value="Silecs-Eclipse-Plugin"></property> + <property name="app.version" value="1.m.p"></property> + + <!-- The id of the product to run, like found in the overview page of the + product editor --> + <property name="eclipse.application" value="silecs.eclipse.plugin.application" /> + <property name="osgi.parentClassloader" value="current" /> + <property name="osgi.framework" value="org.eclipse.osgi" /> + <property name="osgi.bundles" + value="org.eclipse.core.runtime@start,org.eclipse.equinox.common@2:start,org.eclipse.equinox.ds@1:start,org.eclipse.equinox.simpleconfigurator@1:start,org.eclipse.osgi@-1:start,org.eclipse.equinox.event@3:start" /> + </resources> + + <resources os="Windows"> + <j2se version="1.8+" + java-vm-args="-Xms128m -Xmx1024m -Dpython.cachedir.skip=true -Dpython.cachedir=/tmp -Dpython.home=. -Dpython.console.encoding=UTF-8" /> + + <property name="osgi.instance.area" value="@user.home/Silecs-Eclipse-Plugin/1.m.p/"/> + <property name="osgi.configuration.area" value="@user.home/Silecs-Eclipse-Plugin/1.m.p/"/> + + <extension name="Wrapper feature" + href="*" /> + </resources> + + <resources os="Linux"> + <j2se version="1.8+" + java-vm-args="-Xms128m -Xmx1024m -Dpython.cachedir.skip=true -Dpython.cachedir=/tmp -Dpython.home=. -Dpython.console.encoding=UTF-8" /> + + <property name="jnlp.osgi.instance.area" value="@user.home/Silecs-Eclipse-Plugin/1.m.p/" /> + <property name="jnlp.osgi.configuration.area" value="@user.home/Silecs-Eclipse-Plugin/1.m.p/" /> + <property name="jnlp.Dosgi.user.area" value="@user.home"/> + <property name="osgi.ws" value="gtk"/> + + <extension name="Wrapper feature" + href="*" /> + + </resources> +</jnlp> \ No newline at end of file diff --git a/silecs-eclipse-plugin/LICENSE b/silecs-eclipse-plugin/LICENSE new file mode 100644 index 0000000..20d40b6 --- /dev/null +++ b/silecs-eclipse-plugin/LICENSE @@ -0,0 +1,674 @@ + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/> + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + <one line to give the program's name and a brief idea of what it does.> + Copyright (C) <year> <name of author> + + 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 3 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, see <http://www.gnu.org/licenses/>. + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + <program> Copyright (C) <year> <name of author> + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +<http://www.gnu.org/licenses/>. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +<http://www.gnu.org/philosophy/why-not-lgpl.html>. \ No newline at end of file diff --git a/silecs-eclipse-plugin/META-INF/MANIFEST.MF b/silecs-eclipse-plugin/META-INF/MANIFEST.MF new file mode 100644 index 0000000..cd8d7fa --- /dev/null +++ b/silecs-eclipse-plugin/META-INF/MANIFEST.MF @@ -0,0 +1,134 @@ +Manifest-Version: 1.0 +Bundle-ManifestVersion: 2 +Bundle-Name: %Bundle-Name +Bundle-SymbolicName: silecs.eclipse.plugin;singleton:=true +Bundle-Version: 1.1.1.qualifier +Bundle-Activator: cern.silecs.activator.Activator +Require-Bundle: org.eclipse.ui, + org.eclipse.core.runtime, + org.eclipse.ui.workbench, + org.eclipse.core.resources, + org.eclipse.ui.ide, + org.eclipse.ui.editors, + org.eclipse.wst.xml.core, + org.eclipse.wst.xml.ui, + org.eclipse.ui.navigator.resources, + org.eclipse.core.filesystem, + org.eclipse.ui.console, + org.eclipse.ui.views, + org.eclipse.wst.validation, + org.eclipse.wst.validation.infopop, + org.eclipse.wst.validation.ui, + org.eclipse.jface.text, + org.eclipse.wst.sse.ui, + org.eclipse.ui.workbench.texteditor, + org.eclipse.text, + org.eclipse.wst.sse.core, + org.eclipse.ui.navigator, + org.eclipse.xsd, + org.eclipse.wst.xsd.core, + org.eclipse.core.expressions, + org.eclipse.cdt, + org.eclipse.cdt.core, + org.eclipse.cdt.ui, + org.eclipse.cdt.managedbuilder.ui, + org.eclipse.ltk.core.refactoring, + org.eclipse.ltk.ui.refactoring, + org.eclipse.equinox.launcher, + org.eclipse.cdt.make.core;bundle-version="7.3.0", + org.eclipse.cdt.make.ui;bundle-version="7.2.0", + org.eclipse.cdt.managedbuilder.core;bundle-version="8.3.0" +Bundle-RequiredExecutionEnvironment: JavaSE-1.8 +Bundle-ActivationPolicy: lazy +Bundle-ClassPath: ., + target/lib/xalan-2.7.2.jar, + target/lib/jaxen-1.1.6.jar +Permissions: all-permissions +Codebase: http://abwww.cern.ch/ap/dist/silecs/1.m.p/configuration/ +Application-Name: Silecs-Eclipse-Plugin +Export-Package: cern.silecs.activator, + cern.silecs.control.core, + cern.silecs.control.handlers, + cern.silecs.control.validation, + cern.silecs.control.validation.internal;x-internal:=true, + cern.silecs.model.document, + cern.silecs.model.exception, + cern.silecs.utils, + cern.silecs.view, + cern.silecs.view.console, + cern.silecs.view.dialogs, + cern.silecs.view.editor, + cern.silecs.view.editor.internal;x-internal:=true, + cern.silecs.view.explorer, + cern.silecs.view.job, + cern.silecs.view.marker, + cern.silecs.view.preferences, + cern.silecs.view.wizards, + cern.silecs.view.wizards.page, + java_cup.runtime, + org.apache.bcel, + org.apache.bcel.classfile, + org.apache.bcel.generic, + org.apache.bcel.util, + org.apache.bcel.verifier, + org.apache.bcel.verifier.exc, + org.apache.bcel.verifier.statics, + org.apache.bcel.verifier.structurals, + org.apache.regexp, + org.apache.xalan, + org.apache.xalan.client, + org.apache.xalan.extensions, + org.apache.xalan.lib, + org.apache.xalan.lib.sql, + org.apache.xalan.processor, + org.apache.xalan.res, + org.apache.xalan.serialize, + org.apache.xalan.templates, + org.apache.xalan.trace, + org.apache.xalan.transformer, + org.apache.xalan.xslt, + org.apache.xalan.xsltc, + org.apache.xalan.xsltc.cmdline, + org.apache.xalan.xsltc.cmdline.getopt, + org.apache.xalan.xsltc.compiler, + org.apache.xalan.xsltc.compiler.util, + org.apache.xalan.xsltc.dom, + org.apache.xalan.xsltc.runtime, + org.apache.xalan.xsltc.runtime.output, + org.apache.xalan.xsltc.trax, + org.apache.xalan.xsltc.util, + org.apache.xml.dtm, + org.apache.xml.dtm.ref, + org.apache.xml.dtm.ref.dom2dtm, + org.apache.xml.dtm.ref.sax2dtm, + org.apache.xml.res, + org.apache.xml.utils, + org.apache.xml.utils.res, + org.apache.xpath, + org.apache.xpath.axes, + org.apache.xpath.compiler, + org.apache.xpath.domapi, + org.apache.xpath.functions, + org.apache.xpath.jaxp, + org.apache.xpath.objects, + org.apache.xpath.operations, + org.apache.xpath.patterns, + org.apache.xpath.res, + org.jaxen, + org.jaxen.dom, + org.jaxen.dom4j, + org.jaxen.expr, + org.jaxen.expr.iter, + org.jaxen.function, + org.jaxen.function.ext, + org.jaxen.function.xslt, + org.jaxen.javabean, + org.jaxen.jdom, + org.jaxen.pattern, + org.jaxen.saxpath, + org.jaxen.saxpath.base, + org.jaxen.saxpath.helpers, + org.jaxen.util, + org.jaxen.xom, + org.w3c.dom, + trax diff --git a/silecs-eclipse-plugin/OSGI-INF/l10n/bundle.properties b/silecs-eclipse-plugin/OSGI-INF/l10n/bundle.properties new file mode 100644 index 0000000..3ed82f2 --- /dev/null +++ b/silecs-eclipse-plugin/OSGI-INF/l10n/bundle.properties @@ -0,0 +1,2 @@ +#Properties file for silecs.eclipse.plugin +Bundle-Name = Silecs-config \ No newline at end of file diff --git a/silecs-eclipse-plugin/README.md b/silecs-eclipse-plugin/README.md new file mode 100644 index 0000000..04caae1 --- /dev/null +++ b/silecs-eclipse-plugin/README.md @@ -0,0 +1,40 @@ +# silecs-codegen + +This component of the SILECS PLC-framework is used in order to generate and manage silecs-project. + +## Getting Started + +Please check the lab-specific SILECS-Wikis for more information: + +[CERN SILECS Wiki Page][CERN_Wiki] + +[GSI SILECS Wiki Page][GSI_Wiki] + +## License + +Licensed under the GNU GENERAL PUBLIC LICENSE Version 3. See the [LICENSE file][license] for details. + +[license]: LICENSE +[CERN_Wiki]: https://wikis.cern.ch/display/SIL/SILECs+Home +[GSI_Wiki]: https://www-acc.gsi.de/wiki/Frontend/SILECS + +## Dependencies + +### Eclipse Plugins +Install Eclipse plug-in development environment – repo: Official Eclipse repo +install eclipse-core-tool – http://eclipse.org/eclipse/platform-core/updates + +### Maven +Configure the Eclipe-Maven: +https://www-acc.gsi.de/wiki/bin/viewauth/IN/Maven + +Goto project-folder in console and run: +“mvn install†+Right click on project in eclipse configure → Convert to Maven Project +Goto eclipse and run project-->Build + +## Execution + +Goto eclipse-perspective +double-click plugin.xml +Launch an Eclipse Application \ No newline at end of file diff --git a/silecs-eclipse-plugin/build.properties b/silecs-eclipse-plugin/build.properties new file mode 100644 index 0000000..a172b18 --- /dev/null +++ b/silecs-eclipse-plugin/build.properties @@ -0,0 +1,16 @@ +source.. = src/java/ +output.. = bin/java/,\ + bin/ +bin.includes = plugin.xml,\ + META-INF/,\ + .,\ + icons/,\ + src/scripts/,\ + JNLP-INF/,\ + src/java/,\ + target/lib/jaxen-1.1.6.jar,\ + target/lib/xalan-2.7.2.jar,\ + OSGI-INF/ +src.includes = src/ +jars.compile.order = . +qualifier = context diff --git a/silecs-eclipse-plugin/icons/class-document.png b/silecs-eclipse-plugin/icons/class-document.png new file mode 100644 index 0000000000000000000000000000000000000000..80984b14d8f98dba890f8e9e56b08f7c642ba50c GIT binary patch literal 1035 zcmWksO^6m$6g@L0qt;-Wpoab6K#shE<fMyAnB*J2nSKTteTgkBTHHkuBr^~M$<qup zh@eeetECiA5JrfIX3-B(*;R(>fwXFq5V;Yeh>+8p#eJ81FT8v1Ip^%bx#9SRyEgzB zpPd=Z_k8DStXtFH$%i%`>S<(Qes};EukQE*82#(u(}$;f6ChxK0|5vLNJKIuM+zh% z1DVK%?8t#E6rd2rP#h&tgbGxm8mglPs?dN&G(&T=KvVx4B4m(50rjHqCSimV(PvCx zB9k#WQ!t4c%w#rZXAWkufQ2l^;w-@;R<M%QSe-Rk#RfLA8Jn{On<!AEjB+Zdj-#JV zgBjcq9hN0nq9wEBmco)O!!j+KWw#ubWd&Af#jLoMup+ClN~>not%g-ugEd++Yi=#9 z$pjNkW^z-QIt86^I?UmY=!|%RCwekZ?kPOUGd$C?d3Mj?Szh3UUd)So2`};ruk>nO z-D`N2H+Z8r^XA^dn_O_wWiEGxtFzz5X21d-h%QDXL}Db1<dGthA|o;*TV#(Mkrf3| z7{#J^l!&6Jh{~uI)uTpKMME@3vuGYIqA7$BLl*K-gtTgeu12S%<Lbk1g#;xknUX7o zl9ZuLWm9(LP?ic*sA4Lv5-L)KDpgI@RYO&3P@|fuxmu{LF6&0?YIn-}-Mv2h==UFY z*N-gD&mF?l^=sV+7<uuj;Q(jW-ZRsS^{>txT>x&sYc)o2?!#@pIkq_a%=FlAqj#(y z-E!rNmA8BA&Dp^dhqwLw&bv#SzL{EgTPqV=Cw2`7dj`YD9(et;iJhO{yZO)OFP&d` z|2QA~@sV5GH-EjbxU&89eGB(LXZwaX);@k=*Y595TzF~em;ZkFYSYV~zW3x$i(AfI z9(#DrsbiDN&z@YKe`RX&#+RR5`e@IU%g5hZeq;aX54P^U$-U=)-9Pv5_-nU*KezG7 Xx6?cR`FrP5hlAPaxxvK)FP!=x3@y|_ literal 0 HcmV?d00001 diff --git a/silecs-eclipse-plugin/icons/deploy-document.png b/silecs-eclipse-plugin/icons/deploy-document.png new file mode 100644 index 0000000000000000000000000000000000000000..894abc409c39559e46105f195802d42f64241321 GIT binary patch literal 1028 zcmWksO^6m$6g}SzgN-^g7||f6n~3lc{oEk2MPK#}GgCPZ<M)Dg5^}`VNX{;!mm)cB zBtq&|&`?422p8={qMudJRfKpDL{J+mYAGeQIK5fice(e%yXT&BHddAwX14F%4q#?! zakSd=>{i@0+24mAzWZoTgVU=Ehj97&o<D(!TPrV&=X(<{fPe!52nk4rL?lNFBq0OY zkcsTbfh-iD7z$AwB~XM4R6`}IqXw$bfM#e!bF@HH{~I!hkV66WqVF~X4Q_}&vjj_K ziI&__SdwK}Hp{f^mcz2Fz=~O+6}J*rWEED;Dy_QJuqtb?X4YuUt%Wt2U@{X;ZVFS! z(a$!5gcH$WF@edL$mC4HBxW!hGnt(^n8gAXV<C&P1dCX~YOG{+)?gJI*o=*A&K7K< zKp92Ksh~OqopE!};g0Bxc!DSML{IK1JjpXWn`e4<&*52K;KjVqi+c$#@(Qo!m0sOz zc$GJJGjH_f-ol$)aG8rPcZI97-^I2710IMjMkGYCNQ~r>B9bB_vPEWOj~tN|1yL*t zqj;2vqNs>!Q5n^vMpQ*ZG>gV)9xb9Ngph?8@=%1dWrVIqr=;WR!)}EHB~zl3D}|Dj zp=`=jcI8l(3RFymDy|YLQiZCiQq@&MRccT(HLAH<sBJClM(b*K%KP2D-Z=REXWjLK z_0{F07~cG;`v8NNpI;c^!qokXy_i0=_|j=$$30sy!22K0_2#zqrNi^vex2AkJ^AP# zpG@uUtusrbXU20szINow%;aM`uU`9f|J6MooZ9>1-Um;fx%B3hw+{b(d-lL^_VZoe z9{Ks7S4S&9Ouuq|{hjgn!j8c&(;r`Yck|BXvHMQ$I{xGn|Ghmo+&r+n@3*sa!+#(D zZt(QEwToX||7z_-yf=Jy?Tv%?p8N9Rc;X{&JoU}({rmoU<n`aD(&BSB*1mq=e8+*M M`Q_2&L&whk59;>LIsgCw literal 0 HcmV?d00001 diff --git a/silecs-eclipse-plugin/icons/diag-tool.gif b/silecs-eclipse-plugin/icons/diag-tool.gif new file mode 100644 index 0000000000000000000000000000000000000000..3748db1fddb2fe61380bac4dc029d6a617236453 GIT binary patch literal 197 zcmZ?wbhEHb6krfwXc1%h&j3Ua0!07+&rr_*L=XZ*HvyRp43d(P#>U1zK0aw_Y4!E> zGiT1+v}x0sGiRPYefl3SQ2fcl$iN`apaU`mWG4fw(*t!Q70r1sj;rXLUh@3bHhrD& z;@(r7^OkSFmw)`w&zJ+JE=F8Dn&$Lecvb>Og4T-Af~`}x-O>9d@~kf~_2bSOx7p4N F)&S-kU`_x4 literal 0 HcmV?d00001 diff --git a/silecs-eclipse-plugin/icons/generated-code.gif b/silecs-eclipse-plugin/icons/generated-code.gif new file mode 100644 index 0000000000000000000000000000000000000000..18ffabe77f499a954f2ef0d2077da4ff4365e391 GIT binary patch literal 591 zcmZ?wbhEHb6krfwc*el+|IGh?|2O{ozxm()3;+LZ{{Mf=@2@NW{yhEf>xzG0SN;9E z>fg^Ze}BLJ|M%Uum$SaToc-(5;eUTVyuZ=$;dal*TRk6c_I`V@`^&8fUvBhmSl0Xg z?Ta@js=nOc`1WM&`Xznu-@aV8xPR@E$&WXszS^DpYFFOz{hLl4*!*O3`s0lmuXp9W z+Evh9=+j*s`0m1zovWw+{`lzF{;e+_-{~$4=qe1}xoSpFVQ_ar@YxwDy#+z1_isM2 zZ_A5EcfNf3@b%M&Q+qa-C4`nHMwBFkuWc*c&{np-wRBy3MR`I*X<}4KLga?FijD1+ zYul^VE|{}s!JLh)6`R^BH?>u7Y^^F!h$@SZEQybLeE(i~T;$q$v)9a@Qyw2(78mvZ z|9=KL0>z&!j0_CX3_2h?L2<&szNR6%smUqGueqbyIm*C~#ns9!u(Qd5$;_SA$AsB; zO0<DC_hNQlLmP%pKj%mR`A~VD*7goZAqlb2?%w{1lcPPoB4nhd&0q~OW^`{>)zjBs z$i>CU#$ja89HeW#I+9<(L6I-mC7{VW+;*FUsDogTu(*hQ2gAV-Svhw}X?IUojj0I> vn~rdZYG(cTp~A|_r=q^(hJfIc%R<_gU3UtSm`+aiZ=Upr*|R7>fx#L8Moafv literal 0 HcmV?d00001 diff --git a/silecs-eclipse-plugin/icons/silecs-logo.ico b/silecs-eclipse-plugin/icons/silecs-logo.ico new file mode 100644 index 0000000000000000000000000000000000000000..2b22b71097787713417cae9933d9604b169ea962 GIT binary patch literal 15086 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 aNMJ$&6B77tBrtp)i2oBsnz(=8a`=C-`vvd- literal 0 HcmV?d00001 diff --git a/silecs-eclipse-plugin/icons/validate-document.gif b/silecs-eclipse-plugin/icons/validate-document.gif new file mode 100644 index 0000000000000000000000000000000000000000..23c97f09e677bb8812b26d4415fd97997e5c95a4 GIT binary patch literal 76 zcmZ?wbhEHb6krfwn8?f!yfVYEKB{JS)&Kwh6@RiYGB7YR=r8~QNS=X7c257w({Jy) dG&pl*gzr#W|He>ggQJQAZ^o%@>w*~=tO0mX7=r)+ literal 0 HcmV?d00001 diff --git a/silecs-eclipse-plugin/plugin.xml b/silecs-eclipse-plugin/plugin.xml new file mode 100644 index 0000000..8784193 --- /dev/null +++ b/silecs-eclipse-plugin/plugin.xml @@ -0,0 +1,874 @@ +<?xml version="1.0" encoding="UTF-8"?> +<?eclipse version="4.5"?> +<plugin> + <extension + id="application" + point="org.eclipse.core.runtime.applications"> + <application> + <run + class="cern.silecs.view.Application"> + </run> + </application> + </extension> + <extension + point="org.eclipse.core.resources.natures" + id="cern.fesa.plugin.core.fesaClassProjectNature" + name="cern.fesa.plugin.core.fesaClassProjectNature"> + </extension> + + <extension + point="org.eclipse.ui.perspectives"> + <perspective + class="cern.silecs.view.Perspective" + fixed="false" + id="silecs.eclipse.plugin.perspective" + name="Silecs"> + </perspective> + </extension> + <extension + point="org.eclipse.ui.perspectiveExtensions"> + <perspectiveExtension + targetID="silecs.eclipse.plugin.perspective"> + <view + closeable="false" + id="cern.silecs.view.explorer" + minimized="false" + moveable="false" + ratio="0.25" + relationship="left" + relative="org.eclipse.ui.editorss" + visible="true"> + </view> + <view + closeable="false" + id="org.eclipse.ui.views.ProblemView" + minimized="false" + ratio="0.8f" + relationship="bottom" + relative="org.eclipse.ui.editorss" + visible="true"> + </view> + <view + closeable="false" + id="org.eclipse.ui.console.ConsoleView" + minimized="false" + relationship="stack" + relative="org.eclipse.ui.views.ProblemView"> + </view> + <view + closeable="false" + id="org.eclipse.wst.xml.ui.views.annotations.XMLAnnotationsView" + minimized="false" + relationship="stack" + relative="org.eclipse.ui.views.ProblemView" + visible="true"> + </view> + </perspectiveExtension> + </extension> + <extension + point="org.eclipse.ui.ide.projectNatureImages"> + <image + icon="icons/deploy-document.png" + id="cern.silecs.control.core.DeployProjectNature.img" + natureId="cern.silecs.control.core.deployprojectnature"> + </image> + <image + icon="icons/class-document.png" + id="cern.silecs.control.core.DesignProjectNature.img" + natureId="cern.silecs.control.core.designprojectnature"> + </image> + </extension> + <extension + id="deployprojectnature" + point="org.eclipse.core.resources.natures"> + <runtime> + <run + class="cern.silecs.control.core.DeployProjectNature"> + </run> + </runtime> + </extension> + <extension + point="org.eclipse.ui.commands"> + <category + id="cern.silecs.view.category" + name="Cat"> + </category> + <command + categoryId="cern.silecs.view.category" + defaultHandler="cern.silecs.control.handlers.ValidateHandler" + id="cern.silecs.control.handlers.validate" + name="SILECS Validate"> + <commandParameter + id="silecs-eclipse-plugin.commandParameter" + name="silecs-eclipse-plugin.commandParameter" + optional="false"> + </commandParameter> + </command> + <command + categoryId="cern.silecs.view.category" + defaultHandler="cern.silecs.control.handlers.GenerateCodeHandler" + id="cern.silecs.control.handlers.generatecodehandler" + name="SILECS Generate Code"> + <commandParameter + id="silecs-eclipse-plugin.commandParameter" + name="silecs-eclipse-plugin.commandParameter" + optional="false"> + </commandParameter> + </command> + <command + categoryId="cern.silecs.view.category" + defaultHandler="cern.silecs.control.handlers.AboutSilecsHandler" + id="cern.silecs.control.handlers.aboutsilecs" + name="About Silecs"> + </command> + <command + categoryId="cern.silecs.view.category" + defaultHandler="cern.silecs.control.handlers.SilecsWikis" + id="cern.silecs.control.handlers.silecswikis" + name="Silecs Wikis"> + </command> + <command + categoryId="cern.silecs.view.category" + defaultHandler="cern.silecs.control.handlers.ExpandAllHandler" + id="cern.silecs.control.handlers.expandallhandler" + name="Expand All"> + </command> + <command + categoryId="cern.silecs.view.category" + defaultHandler="cern.silecs.control.handlers.DiagnosticToolHandler" + id="cern.silecs.control.handlers.launchdiagnostitoolhandler" + name="SILECS Diagnostic Tool"> + <commandParameter + id="silecs-eclipse-plugin.commandParameter" + name="silecs-eclipse-plugin.commandParameter" + optional="false"> + </commandParameter> + </command> + <command + categoryId="cern.silecs.view.category" + defaultHandler="cern.silecs.control.handlers.UpdateSilecsProjectHandler" + id="cern.silecs.control.handlers.updatesilecsprojecthandler" + name="SILECS Update Project"> + <commandParameter + id="silecs-eclipse-plugin.commandParameter" + name="silecs-eclipse-plugin.commandParameter" + optional="false"> + </commandParameter> + </command> + </extension> + <extension + point="org.eclipse.ui.menus"> + <menuContribution + locationURI="menu:org.eclipse.ui.main.menu"> + <menu + label="Silecs"> + <command + commandId="cern.silecs.control.handlers.silecswikis" + label="Silecs wikis" + style="push"> + </command> + <command + commandId="cern.silecs.control.handlers.aboutsilecs" + label="About Silecs" + style="push"> + </command> + + <visibleWhen + checkEnabled="false"> + <reference + definitionId="cern.silecs.view.perspectivedefinition"> + </reference> + </visibleWhen> + </menu> + + </menuContribution> + <menuContribution + locationURI="toolbar:org.eclipse.ui.main.toolbar"> + <toolbar + id="cern.silecs.view.toolbars.projectFunctions" + label="SILECS Toolbar"> + <command + commandId="cern.silecs.control.handlers.validate" + icon="icons/validate-document.gif" + label="SILECS Validate" + style="push"> + <visibleWhen + checkEnabled="false"> + <or> + <reference + definitionId="cern.silecs.view.editors.design.activeEditor"> + </reference> + <reference + definitionId="cern.silecs.view.editors.deploy.activeEditor"> + </reference> + </or> + </visibleWhen> + <parameter + name="silecs-eclipse-plugin.commandParameter" + value="toolbar"> + </parameter> + </command> + <command + commandId="cern.silecs.control.handlers.generatecodehandler" + icon="icons/generated-code.gif" + label="SILECS Generate Code" + style="push"> + <visibleWhen + checkEnabled="false"> + <or> + <reference + definitionId="cern.silecs.view.editors.design.activeEditor"> + </reference> + <reference + definitionId="cern.silecs.view.editors.deploy.activeEditor"> + </reference> + </or> + </visibleWhen> + <parameter + name="silecs-eclipse-plugin.commandParameter" + value="toolbar"> + </parameter> + </command> + <command + commandId="cern.silecs.control.handlers.launchdiagnostitoolhandler" + icon="icons/diag-tool.gif" + label="SILECS Diagnostic Tool" + style="push"> + <visibleWhen + checkEnabled="false"> + <reference + definitionId="cern.silecs.view.editors.deploy.activeEditor"> + </reference> + </visibleWhen> + <parameter + name="silecs-eclipse-plugin.commandParameter" + value="toolbar"> + </parameter> + </command> + </toolbar> + </menuContribution> + <menuContribution + allPopups="false" + locationURI="popup:org.eclipse.ui.navigator.ProjectExplorer#PopupMenu?after=additions"> + <menu + id="silecs_submenu" + label="SILECS"> + <command + commandId="cern.silecs.control.handlers.validate" + label="SILECS Validate" + style="push"> + <visibleWhen + checkEnabled="false"> + <or> + <reference + definitionId="cern.silecs.control.core.designprojectdefinition"> + </reference> + <reference + definitionId="cern.silecs.control.core.deployprojectdefinition"> + </reference> + <reference + definitionId="cern.silecs.menu.designFile"> + </reference> + <reference + definitionId="cern.silecs.menu.deployFile"> + </reference> + </or> + </visibleWhen> + <parameter + name="silecs-eclipse-plugin.commandParameter" + value="menubar"> + </parameter> + </command> + <command + commandId="cern.silecs.control.handlers.generatecodehandler" + label="SILECS Generate Code" + style="push"> + <visibleWhen + checkEnabled="false"> + <or> + <reference + definitionId="cern.silecs.control.core.designprojectdefinition"> + </reference> + <reference + definitionId="cern.silecs.control.core.deployprojectdefinition"> + </reference> + <reference + definitionId="cern.silecs.menu.designFile"> + </reference> + <reference + definitionId="cern.silecs.menu.deployFile"> + </reference> + </or> + </visibleWhen> + <parameter + name="silecs-eclipse-plugin.commandParameter" + value="menubar"> + </parameter> + </command> + <command + commandId="cern.silecs.control.handlers.launchdiagnostitoolhandler" + label="SILECS Diagnostic Tool" + style="push"> + <visibleWhen + checkEnabled="false"> + <or> + <reference + definitionId="cern.silecs.control.core.deployprojectdefinition"> + </reference> + <reference + definitionId="cern.silecs.menu.deployFile"> + </reference> + </or> + </visibleWhen> + <parameter + name="silecs-eclipse-plugin.commandParameter" + value="menubar"> + </parameter> + </command> + <command + commandId="cern.silecs.control.handlers.updatesilecsprojecthandler" + label="Update SILECS version" + style="push"> + <visibleWhen + checkEnabled="false"> + <or> + <reference + definitionId="cern.silecs.control.core.designprojectdefinition"> + </reference> + <reference + definitionId="cern.silecs.control.core.deployprojectdefinition"> + </reference> + <reference + definitionId="cern.silecs.menu.designFile"> + </reference> + <reference + definitionId="cern.silecs.menu.deployFile"> + </reference> + </or> + </visibleWhen> + <parameter + name="silecs-eclipse-plugin.commandParameter" + value="menubar"> + </parameter> + </command> + </menu> + </menuContribution> + <menuContribution + allPopups="false" + locationURI="popup:cern.silecs.view.explorer#PopupMenu?after=additions"> + <menu + id="silecs_submenu" + label="SILECS"> + </menu> + </menuContribution> + </extension> + <extension + point="org.eclipse.ui.editors"> + <editor + class="cern.silecs.view.editor.DesignMultiPageEditor" + contributorClass="org.eclipse.wst.xml.ui.internal.tabletree.XMLMultiPageEditorActionBarContributor" + default="true" + icon="icons/class-document.png" + extensions="xml" + filenames="silecsdesign" + id="cern.silecs.view.editors.design" + name="XML Editor"> + <contentTypeBinding + contentTypeId="cern.silecs.model.contenttype.design"> + </contentTypeBinding> + </editor> + <editor + class="cern.silecs.view.editor.DeployMultiPageEditor" + contributorClass="org.eclipse.wst.xml.ui.internal.tabletree.XMLMultiPageEditorActionBarContributor" + default="true" + icon="icons/deploy-document.png" + extensions="xml" + filenames="silecsdeploy" + id="cern.silecs.view.editors.deploy" + name="XML Editor"> + <contentTypeBinding + contentTypeId="cern.silecs.model.contenttype.deploy"> + </contentTypeBinding> + </editor> + </extension> + <extension + id="designprojectnature" + point="org.eclipse.core.resources.natures"> + <runtime> + <run + class="cern.silecs.control.core.DesignProjectNature"> + </run> + </runtime> + </extension> + <extension + id="cern.silecs.view.marker" + name="%silecs.marker.problem" + point="org.eclipse.core.resources.markers"> + <super + type="org.eclipse.core.resources.problemmarker"> + </super> + <persistent + value="false"> + </persistent> + <attribute + name="xPath"> + </attribute> + </extension> + <extension + point="org.eclipse.ui.editors.markerUpdaters"> + <updater + class="cern.silecs.view.marker.SilecsMarkerUpdater" + id="cern.silecs.view.marker.updater" + markerType="cern.silecs.view.marker"> + </updater> + </extension> + <extension + point="org.eclipse.ui.newWizards"> + <category + id="cern.silecs.view.category.wizards" + name="Silecs"> + </category> + <wizard + category="cern.silecs.view.category.wizards" + class="cern.silecs.view.wizards.NewSilecsDesignWizard" + finalPerspective="silecs.eclipse.plugin.perspective" + icon="icons/class-document.png" + id="cern.silecs.view.wizards.newdesignclass" + name="Design" + project="true"> + </wizard> + <wizard + category="cern.silecs.view.category.wizards" + class="cern.silecs.view.wizards.NewSilecsDeployWizard" + finalPerspective="silecs.eclipse.plugin.perspective" + icon="icons/deploy-document.png" + id="cern.silecs.view.wizards.newdeployclass" + name="Deploy" + project="true"> + </wizard> + </extension> + <extension + id="product" + point="org.eclipse.core.runtime.products"> + <product + application="silecs.eclipse.plugin.application" + name="Silecs-Eclipse-Plugin 1.1.1"> + <property + name="appName" + value="Silecs-Eclipse-Plugin 1.1.1"> + </property> + </product> + </extension> + <extension + point="org.eclipse.ui.importWizards"> + <category + id="cern.silecs.view.category.wizards" + name="Silecs"> + </category> + <wizard + category="cern.silecs.view.category.wizards" + class="cern.silecs.view.wizards.ImportDeployFileWizard" + icon="icons/deploy-document.png" + id="cern.silecs.view.wizards.importdeploywizard" + name="Import Silecs-1 Deploy-Unit File"> + </wizard> + <wizard + category="cern.silecs.view.category.wizards" + class="cern.silecs.view.wizards.ImportDesignFileWizard" + icon="icons/class-document.png" + id="cern.silecs.view.wizards.importdesignfilewizard" + name="Import Silecs-1 Design File"> + </wizard> + </extension> + <extension + point="org.eclipse.team.core.fileTypes"> + <fileTypes + extension="*.silecsdesign" + type="text"> + </fileTypes> + <fileTypes + extension="*.silecsdeploy" + type="text"> + </fileTypes> + </extension> + <extension + point="org.eclipse.core.contenttype.contentTypes"> + <content-type + base-type="org.eclipse.core.runtime.xml" + file-extensions="silecsdesign" + id="cern.silecs.model.contenttype.design" + name="Design"> + </content-type> + <content-type + base-type="org.eclipse.core.runtime.xml" + file-extensions="silecsdeploy" + id="cern.silecs.model.contenttype.deploy" + name="Deploy"> + </content-type> + </extension> + <extension + point="org.eclipse.core.expressions.definitions"> + <definition id="cern.silecs.designFile"> + <iterate ifEmpty="false"> + <adapt + type="org.eclipse.core.resources.IFile"> + <test + property="org.eclipse.core.resources.extension" + value="silecsdesign"> + </test> + </adapt> + </iterate> + </definition> + + <definition id="cern.silecs.deployFile"> + <iterate ifEmpty="false"> + <adapt + type="org.eclipse.core.resources.IFile"> + <test + property="org.eclipse.core.resources.extension" + value="silecsdeploy"> + </test> + </adapt> + </iterate> + </definition> + + <definition + id="cern.silecs.menu.designFile"> + <with + variable="activeMenuSelection"> + <reference + definitionId="cern.silecs.designFile"> + </reference> + </with> + </definition> + + <definition + id="cern.silecs.menu.deployFile"> + <with + variable="activeMenuSelection"> + <reference + definitionId="cern.silecs.deployFile"> + </reference> + </with> + </definition> + + <definition + id="cern.silecs.control.core.deployprojectdefinition"> + <iterate + ifEmpty="false"> + <adapt + type="org.eclipse.core.resources.IProject"> + <test + property="org.eclipse.core.resources.projectNature" + value="cern.silecs.control.core.deployprojectnature"> + </test> + </adapt> + </iterate> + </definition> + <definition + id="cern.silecs.control.core.designprojectdefinition"> + <iterate + ifEmpty="false"> + <adapt + type="org.eclipse.core.resources.IProject"> + <test + property="org.eclipse.core.resources.projectNature" + value="cern.silecs.control.core.designprojectnature"> + </test> + </adapt> + </iterate> + </definition> + <definition + id="cern.silecs.view.editors.design.activeEditor"> + <with variable="activeEditorId"> + <equals + value="cern.silecs.view.editors.design"> + </equals> + </with> + </definition> + <definition + id="cern.silecs.view.editors.deploy.activeEditor"> + <with variable="activeEditorId"> + <equals + value="cern.silecs.view.editors.deploy"> + </equals> + </with> + </definition> + <definition + id="cern.silecs.view.perspectivedefinition"> + <with + variable="activeWorkbenchWindow.activePerspective"> + <equals + value="silecs.eclipse.plugin.perspective"> + </equals> + </with> + </definition> + </extension> + <extension + point="org.eclipse.ui.decorators"> + <decorator + adaptable="true" + class="org.eclipse.cdt.internal.ui.navigator.CNavigatorProblemsLabelDecorator" + id="cern.silecs.view.decorators.ErrorDecorator" + label="Project error decorator" + lightweight="true" + location="BOTTOM_LEFT" + objectClass="org.eclipse.core.resources.IResource" + state="true"> + <enablement> + <and> + <objectClass + name="org.eclipse.core.resources.IResource"> + </objectClass> + <or> + <objectClass + name="org.eclipse.core.resources.IFolder"> + </objectClass> + <objectClass + name="org.eclipse.core.resources.IFile"> + </objectClass> + </or> + </and> + </enablement> + </decorator> + </extension> + <extension + point="org.eclipse.ui.bindings"> + <scheme + id="cern.silecs.control.bindingscheme" + name="Binding scheme"> + </scheme> + <key + commandId="cern.silecs.control.handlers.expandallhandler" + contextId="org.eclipse.ui.contexts.window" + schemeId="org.eclipse.ui.defaultAcceleratorConfiguration" + sequence="M1+M2+A"> + </key> + </extension> + <extension + point="org.eclipse.ui.views"> + <category + id="cern.silecs.view.ui" + name="Silecs"> + </category> + <view + category="cern.silecs.view.ui" + class="cern.silecs.view.explorer.SilecsProjectExplorer" + icon="icons/silecs-logo.ico" + id="cern.silecs.view.explorer" + name="Silecs Explorer" + restorable="true"> + </view> + </extension> + <extension + point="org.eclipse.ui.navigator.navigatorContent"> + <commonFilter + activeByDefault="true" + id="cern.silecs.view.explorer.filter.hiddenfiles" + name=".* resources" + visibleInUI="true"> + <filterExpression> + <and> + <adapt + type="org.eclipse.core.resources.IResource"> + <test + property="org.eclipse.core.resources.name" + value=".*"> + </test> + </adapt> + </and> + </filterExpression> + </commonFilter> + <navigatorContent + activeByDefault="true" + contentProvider="cern.silecs.view.explorer.ProjectContent" + id="cern.silecs.view.explorer.content" + labelProvider="org.eclipse.ui.model.WorkbenchLabelProvider" + name="Silecs Project Content" + priority="normal"> + <triggerPoints> + <or> + <adapt + type="org.eclipse.core.resources.IWorkspaceRoot"> + </adapt> + <adapt + type="org.eclipse.core.resources.IFolder"> + </adapt> + <adapt + type="org.eclipse.core.resources.IProject"> + <or> + <test + property="org.eclipse.core.resources.projectNature" + value="cern.silecs.control.core.DesignProjectNature"> + </test> + <test + property="org.eclipse.core.resources.projectNature" + value="cern.silecs.control.core.DeployProjectNature"> + </test> + </or> + </adapt> + </or> + </triggerPoints> + <possibleChildren> + <or> + <adapt + type="org.eclipse.core.resources.IProject"> + </adapt> + <adapt + type="org.eclipse.core.resources.IFolder"> + </adapt> + <adapt + type="org.eclipse.core.resources.IFile"> + </adapt> + </or> + </possibleChildren> + <commonSorter + class="cern.silecs.view.explorer.ContentSorter" + id="cern.silecs.view.explorer.sorter.ContentSorter"> + </commonSorter> + <dropAssistant + class="org.eclipse.cdt.internal.ui.navigator.CNavigatorDropAdapterAssistant" + id="cern.silecs.view.explorer.resourceDropAdapter"> + <possibleDropTargets> + <or> + <adapt + type="org.eclipse.core.resources.IProject"> + </adapt> + <adapt + type="org.eclipse.core.resources.IFolder"> + </adapt> + <adapt + type="org.eclipse.core.resources.IFile"> + </adapt> + </or></possibleDropTargets> + </dropAssistant> + <actionProvider + class="org.eclipse.cdt.internal.ui.navigator.CNavigatorEditActionProvider" + id="cern.silecs.view.explorer.actions.EditActions"> + </actionProvider> + <actionProvider + class="org.eclipse.cdt.internal.ui.navigator.CNavigatorRefactorActionProvider" + id="cern.silecs.view.explorer.actions.RefactorActions"> + </actionProvider> + </navigatorContent> + </extension> + <extension + point="org.eclipse.ui.navigator.viewer"> + <viewer + viewerId="cern.silecs.view.explorer"> + <popupMenu + allowsPlatformContributions="true" + id="cern.silecs.view.explorer#PopupMenu"> + <insertionPoint + name="group.new" + separator="true"> + </insertionPoint> + <insertionPoint + name="group.goto"> + </insertionPoint> + <insertionPoint + name="group.open" + separator="true"> + </insertionPoint> + <insertionPoint + name="group.openwith"> + </insertionPoint> + <insertionPoint + name="silecs" + separator="true"> + </insertionPoint> + <insertionPoint + name="group.edit" + separator="true"> + </insertionPoint> + <insertionPoint + name="group.reorganize" + separator="true"> + </insertionPoint> + <insertionPoint + name="group.port" + separator="true"> + </insertionPoint> + <insertionPoint + name="group.generate" + separator="true"> + </insertionPoint> + <insertionPoint + name="group.search" + separator="true"> + </insertionPoint> + <insertionPoint + name="group.build" + separator="true"> + </insertionPoint> + <insertionPoint + name="additions" + separator="true"> + </insertionPoint> + <insertionPoint + name="group.properties" + separator="true"> + </insertionPoint> + </popupMenu> + </viewer> + <viewerContentBinding + viewerId="cern.silecs.view.explorer"> + <includes> + <contentExtension + isRoot="true" + pattern="cern.silecs.view.explorer.content"> + </contentExtension> + <contentExtension + pattern="cern.silecs.view.explorer.filter.*"> + </contentExtension> + <contentExtension + pattern="org.eclipse.ui.navigator.resources.linkHelper"> + </contentExtension> + <contentExtension + pattern="org.eclipse.ui.navigator.resources.filters.workingSet"> + </contentExtension> + </includes> + </viewerContentBinding> + <viewerActionBinding + viewerId="cern.silecs.view.explorer"> + <includes> + <actionExtension + pattern="org.eclipse.ui.navigator.resources.*"> + </actionExtension> + <actionExtension + pattern="cern.silecs.view.explorer.*"> + </actionExtension> + </includes> + </viewerActionBinding> + <dragAssistant + class="org.eclipse.cdt.internal.ui.navigator.CNavigatorDragAdapterAssistant" + viewerId="cern.silecs.view.explorer"> + </dragAssistant> + </extension> + <extension + point="org.eclipse.core.runtime.preferences"> + <initializer + class="cern.silecs.view.preferences.PreferenceInitializer"> + </initializer> + </extension> + <extension + point="org.eclipse.ui.preferencePages"> + <page + class="cern.silecs.view.preferences.MainPreferencePage" + id="Silecs" + name="Silecs"> + </page> + <page + category="Silecs" + class="cern.silecs.view.preferences.EditorPreferencePage" + id="cern.silecs.plugin.preferences.editor" + name="XML-Editor"> + </page> + <page + category="Silecs" + class="cern.silecs.view.preferences.LoggingPreferencePage" + id="cern.silecs.plugin.preferences.logging" + name="Logging"> + </page> + </extension> +</plugin> diff --git a/silecs-eclipse-plugin/pom.xml b/silecs-eclipse-plugin/pom.xml new file mode 100644 index 0000000..85bf5fa --- /dev/null +++ b/silecs-eclipse-plugin/pom.xml @@ -0,0 +1,100 @@ +<?xml version="1.0" encoding="UTF-8"?> +<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> + <modelVersion>4.0.0</modelVersion> + <parent> + <groupId>de.gsi.cs.co</groupId> + <artifactId>csco-parent</artifactId> + <version>1.0.7</version> + </parent> + + <groupId>silecs-eclipse-plugin</groupId> + <artifactId>silecs-eclipse-plugin</artifactId> + <version>0.10.0</version> + <name>silecs-eclipse-plugin</name> + <packaging>jar</packaging> + <description>adfsfasfa.</description> + <url>sdasdasdasdasd</url> + + <developers> + <developer> + <id></id> + <name></name> + <email></email> + <url></url> + </developer> + </developers> + + <dependencies> + <dependency> + <groupId>org.slf4j</groupId> + <artifactId>slf4j-log4j12</artifactId> + <version>1.7.12</version> + </dependency> + <dependency> + <groupId>org.slf4j</groupId> + <artifactId>slf4j-api</artifactId> + <version>1.7.12</version> + </dependency> + <dependency> + <groupId>log4j</groupId> + <artifactId>log4j</artifactId> + <version>1.2.17</version> + </dependency> + <dependency> + <groupId>xalan</groupId> + <artifactId>xalan</artifactId> + <version>2.7.2</version> + </dependency> + <dependency> + <groupId>jaxen</groupId> + <artifactId>jaxen</artifactId> + <version>1.1.6</version> + </dependency> + </dependencies> + <build> + <plugins> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-dependency-plugin</artifactId> + <executions> + <execution> + <id>copy</id> + <phase>package</phase> + <goals> + <goal>copy</goal> + </goals> + <configuration> + <artifactItems> + <artifactItem> + <groupId>org.slf4j</groupId> + <artifactId>slf4j-log4j12</artifactId> + </artifactItem> + <artifactItem> + <groupId>org.slf4j</groupId> + <artifactId>slf4j-api</artifactId> + </artifactItem> + <artifactItem> + <groupId>log4j</groupId> + <artifactId>log4j</artifactId> + </artifactItem> + <artifactItem> + <groupId>xalan</groupId> + <artifactId>xalan</artifactId> + </artifactItem> + <artifactItem> + <groupId>jaxen</groupId> + <artifactId>jaxen</artifactId> + </artifactItem> + </artifactItems> + <outputDirectory>${project.build.directory}/lib</outputDirectory> + <overWriteReleases>false</overWriteReleases> + <overWriteSnapshots>true</overWriteSnapshots> + </configuration> + </execution> + </executions> + </plugin> + </plugins> + </build> + +</project> diff --git a/silecs-eclipse-plugin/project.properties b/silecs-eclipse-plugin/project.properties new file mode 100644 index 0000000..2dbdd52 --- /dev/null +++ b/silecs-eclipse-plugin/project.properties @@ -0,0 +1,3 @@ +eclipseLocalOverride=true +javadoc.enabled=false +junit.enabled=false \ No newline at end of file diff --git a/silecs-eclipse-plugin/src/java/cern/silecs/activator/Activator.java b/silecs-eclipse-plugin/src/java/cern/silecs/activator/Activator.java new file mode 100644 index 0000000..3eea8ab --- /dev/null +++ b/silecs-eclipse-plugin/src/java/cern/silecs/activator/Activator.java @@ -0,0 +1,70 @@ +// Copyright 2016 CERN and GSI +// +// 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 3 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, see <http://www.gnu.org/licenses/>. + +package cern.silecs.activator; + +import org.eclipse.jface.resource.ImageDescriptor; +import org.eclipse.ui.plugin.AbstractUIPlugin; +import org.osgi.framework.BundleContext; + +/** + * The activator class controls the plug-in life cycle + */ +public class Activator extends AbstractUIPlugin { + + // The plug-in ID + public static final String PLUGIN_ID = "silecs.eclipse.plugin"; //$NON-NLS-1$ + + // The shared instance + private static Activator plugin; + + public Activator() { + } + + /* + * (non-Javadoc) + * @see org.eclipse.ui.plugin.AbstractUIPlugin#start(org.osgi.framework.BundleContext) + */ + @Override + public void start(BundleContext context) throws Exception { + super.start(context); + plugin = this; + } + + /* + * (non-Javadoc) + * @see org.eclipse.ui.plugin.AbstractUIPlugin#stop(org.osgi.framework.BundleContext) + */ + @Override + public void stop(BundleContext context) throws Exception { + plugin = null; + super.stop(context); + } + + public static Activator getDefault() { + return plugin; + } + + /** + * Returns an image descriptor for the image file at the given + * plug-in relative path + * + * @param path the path + * @return the image descriptor + */ + public static ImageDescriptor getImageDescriptor(String path) { + return imageDescriptorFromPlugin(PLUGIN_ID, path); + } +} diff --git a/silecs-eclipse-plugin/src/java/cern/silecs/activator/WebStartLauncher.java b/silecs-eclipse-plugin/src/java/cern/silecs/activator/WebStartLauncher.java new file mode 100644 index 0000000..e3ee96e --- /dev/null +++ b/silecs-eclipse-plugin/src/java/cern/silecs/activator/WebStartLauncher.java @@ -0,0 +1,52 @@ +// Copyright 2016 CERN and GSI +// +// 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 3 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, see <http://www.gnu.org/licenses/>. + +package cern.silecs.activator; + +import java.util.Properties; +import java.util.Set; + +import org.eclipse.equinox.launcher.WebStartMain; + +/** + * This class is only used by jnlp launcher. + * It is not used locally. + */ +@SuppressWarnings("restriction") +public class WebStartLauncher { + + public static void main(String[] args) { + Properties properties = System.getProperties(); + // copy properties to avoid ConcurrentModificationException + Properties copiedProperties = new Properties(); + copiedProperties.putAll(properties); + Set<Object> keys = copiedProperties.keySet(); + for (Object key : keys) { + if (key instanceof String) { + String keyString = (String) key; + if (keyString.startsWith("jnlp.")) { + // re set all properties starting with the jnlp-prefix + // and set them without the prefix + String property = System.getProperty(keyString); + String replacedKeyString = keyString.replaceFirst("jnlp.", ""); + + System.setProperty(replacedKeyString, property); + } + } + } + + WebStartMain.main(args); + } +} \ No newline at end of file diff --git a/silecs-eclipse-plugin/src/java/cern/silecs/control/core/DeployProjectNature.java b/silecs-eclipse-plugin/src/java/cern/silecs/control/core/DeployProjectNature.java new file mode 100644 index 0000000..8442589 --- /dev/null +++ b/silecs-eclipse-plugin/src/java/cern/silecs/control/core/DeployProjectNature.java @@ -0,0 +1,103 @@ +// Copyright 2016 CERN and GSI +// +// 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 3 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, see <http://www.gnu.org/licenses/>. + +package cern.silecs.control.core; + +import org.eclipse.core.resources.IProject; +import org.eclipse.core.resources.IProjectNature; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.NullProgressMonitor; +import org.eclipse.core.runtime.SubProgressMonitor; + +public class DeployProjectNature extends SilecsProjectNature implements IProjectNature { + + private static final String CERN_FESA_PLUGIN_CORE_FESA_DEPLOY_PROJECT_NATURE = "cern.fesa.plugin.core.fesaDeployProjectNature"; + public static final String NATURE_ID = "cern.silecs.control.core.deployprojectnature"; + + public static void addDeployNature(IProject project, IProgressMonitor mon) throws CoreException { + IProgressMonitor monitor = mon; + if (monitor == null) { + monitor = new NullProgressMonitor(); + } + + try { + monitor.beginTask("Add silecs deploy nature", 2); + addNature(project, NATURE_ID, new SubProgressMonitor(monitor, 1)); + addCppNature(project, new SubProgressMonitor(monitor, 1)); + } finally { + monitor.done(); + } + } + + public static void removeDeployNature(IProject project, IProgressMonitor mon) throws CoreException { + IProgressMonitor monitor = mon; + if (monitor == null) { + monitor = new NullProgressMonitor(); + } + + try { + monitor.beginTask("Remove silecs deploy nature", 2); + removeNature(project, NATURE_ID, new SubProgressMonitor(monitor, 1)); + removeCppNature(project, new SubProgressMonitor(monitor, 1)); + } finally { + monitor.done(); + } + } + + public static void convertToDeployNature(IProject project, IProgressMonitor mon) throws CoreException { + IProgressMonitor monitor = mon; + if (monitor == null) { + monitor = new NullProgressMonitor(); + } + + try { + monitor.beginTask("Converting project to silecs deploy nature", 2); + removeAllNatures(project, new SubProgressMonitor(monitor, 1)); + addDeployNature(project, new SubProgressMonitor(monitor, 1)); + } finally { + monitor.done(); + } + } + + public static void addFESADeployUnitNature(IProject project, IProgressMonitor mon) throws CoreException { + IProgressMonitor monitor = mon; + if (mon == null) { + monitor = new NullProgressMonitor(); + } + monitor.beginTask("Adding FESA Class Nature to project", 2); + try { + addNature(project, CERN_FESA_PLUGIN_CORE_FESA_DEPLOY_PROJECT_NATURE, new SubProgressMonitor(monitor, 1)); + addManageBuilderNature(project,mon); + } finally { + monitor.done(); + } + } + + public static void removeFESADeployUnitNature(IProject project, IProgressMonitor mon) throws CoreException { + IProgressMonitor monitor = mon; + if (mon == null) { + monitor = new NullProgressMonitor(); + } + monitor.beginTask("Removing FESA Nature from project", 2); + try { + removeNature(project, CERN_FESA_PLUGIN_CORE_FESA_DEPLOY_PROJECT_NATURE, new SubProgressMonitor(monitor, 1)); + removeManageBuilderNature(project,mon); + } finally { + monitor.done(); + } + } + +} diff --git a/silecs-eclipse-plugin/src/java/cern/silecs/control/core/DesignProjectNature.java b/silecs-eclipse-plugin/src/java/cern/silecs/control/core/DesignProjectNature.java new file mode 100644 index 0000000..be974ee --- /dev/null +++ b/silecs-eclipse-plugin/src/java/cern/silecs/control/core/DesignProjectNature.java @@ -0,0 +1,110 @@ +// Copyright 2016 CERN and GSI +// +// 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 3 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, see <http://www.gnu.org/licenses/>. + +package cern.silecs.control.core; + +import org.eclipse.core.resources.IProject; +import org.eclipse.core.resources.IProjectNature; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.NullProgressMonitor; +import org.eclipse.core.runtime.SubProgressMonitor; + +import cern.silecs.view.console.ConsoleHandler; + +public class DesignProjectNature extends SilecsProjectNature implements IProjectNature { + + public static final String NATURE_ID = "cern.silecs.control.core.designprojectnature"; + + private static final String CERN_FESA_PLUGIN_CORE_FESA_CLASS_PROJECT_NATURE = "cern.fesa.plugin.core.fesaClassProjectNature"; + + public static void addClassNature(IProject project, IProgressMonitor mon) throws CoreException { + ConsoleHandler.printMessage("Debug0", true); + IProgressMonitor monitor = mon; + if (monitor == null) { + monitor = new NullProgressMonitor(); + } + + try { + monitor.beginTask("Add silecs class nature", 2); + ConsoleHandler.printMessage("Debug1", true); + addNature(project, NATURE_ID, new SubProgressMonitor(monitor, 1)); + ConsoleHandler.printMessage("Debug2", true); + addCppNature(project, new SubProgressMonitor(monitor, 1)); + ConsoleHandler.printMessage("Debug3", true); + } finally { + monitor.done(); + } + } + + public static void removeClassNature(IProject project, IProgressMonitor mon) throws CoreException { + IProgressMonitor monitor = mon; + if (monitor == null) { + monitor = new NullProgressMonitor(); + } + + try { + monitor.beginTask("Remove silecs class nature", 2); + removeNature(project, NATURE_ID, new SubProgressMonitor(monitor, 1)); + removeCppNature(project, new SubProgressMonitor(monitor, 1)); + } finally { + monitor.done(); + } + } + + public static void convertToClassNature(IProject project, IProgressMonitor mon) throws CoreException { + IProgressMonitor monitor = mon; + if (monitor == null) { + monitor = new NullProgressMonitor(); + } + + try { + monitor.beginTask("Converting project to silecs class nature", 2); + removeAllNatures(project, new SubProgressMonitor(monitor, 1)); + addClassNature(project, new SubProgressMonitor(monitor, 1)); + } finally { + monitor.done(); + } + } + + public static void addFESAClassNature(IProject project, IProgressMonitor mon) throws CoreException { + IProgressMonitor monitor = mon; + if (mon == null) { + monitor = new NullProgressMonitor(); + } + monitor.beginTask("Adding FESA Class Nature to project", 2); + try { + addNature(project, CERN_FESA_PLUGIN_CORE_FESA_CLASS_PROJECT_NATURE, new SubProgressMonitor(monitor, 1)); + addManageBuilderNature(project,mon); + } finally { + monitor.done(); + } + } + + public static void removeFESAClassNature(IProject project, IProgressMonitor mon) throws CoreException { + IProgressMonitor monitor = mon; + if (mon == null) { + monitor = new NullProgressMonitor(); + } + monitor.beginTask("Removing FESA Nature from project", 2); + try { + removeNature(project, CERN_FESA_PLUGIN_CORE_FESA_CLASS_PROJECT_NATURE, new SubProgressMonitor(monitor, 1)); + removeManageBuilderNature(project,mon); + } finally { + monitor.done(); + } + } + +} diff --git a/silecs-eclipse-plugin/src/java/cern/silecs/control/core/SilecsProjectNature.java b/silecs-eclipse-plugin/src/java/cern/silecs/control/core/SilecsProjectNature.java new file mode 100644 index 0000000..c7ea191 --- /dev/null +++ b/silecs-eclipse-plugin/src/java/cern/silecs/control/core/SilecsProjectNature.java @@ -0,0 +1,162 @@ +// Copyright 2016 CERN and GSI +// +// 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 3 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, see <http://www.gnu.org/licenses/>. + +package cern.silecs.control.core; + + +import org.eclipse.cdt.core.CCProjectNature; +import org.eclipse.core.resources.ICommand; +import org.eclipse.core.resources.IProject; +import org.eclipse.core.resources.IProjectDescription; +import org.eclipse.core.resources.IncrementalProjectBuilder; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.NullProgressMonitor; + +import org.eclipse.core.runtime.SubProgressMonitor; + +import cern.silecs.model.exception.SilecsException; +import cern.silecs.utils.SilecsConstants; +import cern.silecs.view.console.ConsoleHandler; + + +public abstract class SilecsProjectNature extends CCProjectNature { + + public static final String PROJECT_FILE = ".project"; + public static final String CDT_PROJECT_FILE = ".cproject"; + + private static final String ORG_ECLIPSE_CDT_MANAGEDBUILDER_CORE_SCANNER_CONFIG_NATURE = "org.eclipse.cdt.managedbuilder.core.ScannerConfigNature"; + private static final String ORG_ECLIPSE_CDT_MANAGEDBUILDER_CORE_MANAGED_BUILD_NATURE = "org.eclipse.cdt.managedbuilder.core.managedBuildNature"; + + private static final String FESA_BUILD_COMMAND_1 = "org.eclipse.cdt.managedbuilder.core.genmakebuilder"; + private static final String FESA_BUILD_COMMAND_2 = "org.eclipse.cdt.managedbuilder.core.ScannerConfigBuilder"; + + protected static void removeAllNatures(IProject project, IProgressMonitor mon) throws CoreException { + IProgressMonitor monitor = mon; + if (mon == null) { + monitor = new NullProgressMonitor(); + } + try { + IProjectDescription desc = project.getDescription(); + desc.setNatureIds(new String[0]); + project.setDescription(desc, null); + } finally { + monitor.done(); + } + } + + protected static void addCppNature(IProject project, IProgressMonitor mon) throws CoreException { + IProgressMonitor monitor = mon; + if (mon == null) { + monitor = new NullProgressMonitor(); + } + monitor.beginTask("Adding C++ Nature to project", 2); + + try { + addNature(project, C_NATURE_ID, new SubProgressMonitor(monitor, 1)); + addNature(project, CC_NATURE_ID, new SubProgressMonitor(monitor, 1)); + } finally { + monitor.done(); + } + } + + protected static void removeCppNature(IProject project, IProgressMonitor mon) throws CoreException { + IProgressMonitor monitor = mon; + if (mon == null) { + monitor = new NullProgressMonitor(); + } + + monitor.beginTask("Removing C++ Nature from project", 2); + + try { + removeNature(project, C_NATURE_ID, new SubProgressMonitor(monitor, 1)); + removeNature(project, CC_NATURE_ID, new SubProgressMonitor(monitor, 1)); + } finally { + monitor.done(); + } + } + + @Override + public void configure() throws CoreException { + // Do nothing. this allow to put fesa nature first + } + + public static SilecsConstants.ProjectType getProjectType(IProject project) throws CoreException, SilecsException { + if (project.hasNature(DesignProjectNature.NATURE_ID)) { + return SilecsConstants.ProjectType.DESIGN_PROJECT; + } else if (project.hasNature(DeployProjectNature.NATURE_ID)) { + return SilecsConstants.ProjectType.DEPLOY_PROJECT; + } else { + throw new SilecsException("Project " + project.getName() + " has no fesa nature"); + } + } + + protected static void addManageBuilderNature(IProject project, IProgressMonitor mon) throws CoreException { + IProgressMonitor monitor = mon; + if (mon == null) { + monitor = new NullProgressMonitor(); + } + monitor.beginTask("Adding Managebuilder Nature to project", 2); + + try { + addCppNature(project,mon); + addNature(project, ORG_ECLIPSE_CDT_MANAGEDBUILDER_CORE_MANAGED_BUILD_NATURE, new SubProgressMonitor(monitor, 1)); + addNature(project, ORG_ECLIPSE_CDT_MANAGEDBUILDER_CORE_SCANNER_CONFIG_NATURE, new SubProgressMonitor(monitor, 1)); + } finally { + monitor.done(); + } + } + + protected static void removeManageBuilderNature(IProject project, IProgressMonitor mon) throws CoreException { + IProgressMonitor monitor = mon; + if (mon == null) { + monitor = new NullProgressMonitor(); + } + + monitor.beginTask("Removing Managebuilder Nature from project", 2); + + try { + removeCppNature(project,mon); + removeNature(project, ORG_ECLIPSE_CDT_MANAGEDBUILDER_CORE_MANAGED_BUILD_NATURE, new SubProgressMonitor(monitor, 1)); + removeNature(project, ORG_ECLIPSE_CDT_MANAGEDBUILDER_CORE_SCANNER_CONFIG_NATURE, new SubProgressMonitor(monitor, 1)); + } finally { + monitor.done(); + } + } + + public static void addBuildSpecs(IProject project) + { + try { + IProjectDescription desc = project.getDescription(); + ICommand[] commands = new ICommand[2]; + final ICommand command0 = desc.newCommand(); + final ICommand command1 = desc.newCommand(); + command0.setBuilderName(FESA_BUILD_COMMAND_1); + command1.setBuilderName(FESA_BUILD_COMMAND_2); + commands[0] = command0; + commands[1] = command1; + + //remove auto-build options + commands[0].setBuilding(IncrementalProjectBuilder.AUTO_BUILD, false); + commands[1].setBuilding(IncrementalProjectBuilder.AUTO_BUILD, false); + commands[1].setBuilding(IncrementalProjectBuilder.CLEAN_BUILD, false); + desc.setBuildSpec(commands); + project.setDescription(desc, null); + } catch (CoreException e) { + e.printStackTrace(); + ConsoleHandler.printStackTrace(e); + } + } +} diff --git a/silecs-eclipse-plugin/src/java/cern/silecs/control/handlers/AboutSilecsHandler.java b/silecs-eclipse-plugin/src/java/cern/silecs/control/handlers/AboutSilecsHandler.java new file mode 100644 index 0000000..f639039 --- /dev/null +++ b/silecs-eclipse-plugin/src/java/cern/silecs/control/handlers/AboutSilecsHandler.java @@ -0,0 +1,68 @@ +// Copyright 2016 CERN and GSI +// +// 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 3 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, see <http://www.gnu.org/licenses/>. + +package cern.silecs.control.handlers; + +import org.eclipse.core.commands.AbstractHandler; +import org.eclipse.core.commands.ExecutionEvent; +import org.eclipse.core.commands.ExecutionException; +import org.eclipse.core.commands.IHandler; +import org.eclipse.jface.dialogs.MessageDialog; +import org.eclipse.swt.widgets.Shell; +import org.eclipse.ui.PlatformUI; + +import cern.silecs.utils.SilecsConstants; +import cern.silecs.view.dialogs.SilecsMessageDialog; + +/** + * This handler displays basic information about the Silecs tool. + */ +public class AboutSilecsHandler extends AbstractHandler implements IHandler { + + @Override + public Object execute(ExecutionEvent event) throws ExecutionException { + Shell shell = PlatformUI.getWorkbench().getDisplay().getActiveShell(); + + //GSI-Hack .. use GSI-Support + String dialogMessage = "About SILECS\n\n" + + "A 'Design project' defines the data to be exchanged with the controller (blocks and the registers) in a hardware independent manners while a 'Deploy project' binds several design instances on a physical controller. \n" + + "Purpose of this tool is to provide an easy-to-use graphical interface to guide the user in the definition of his design/deploy projects and to generate the client and controller resources necessary for the communication via the Silecs communication library.\n\n" + + + "If you are using this tool you may also be interests in: \n" + + "\u2022 Silecs communication library \n" + + "\u2022 Silecs diagnostic tool \n\n" + + "Support contact: silecs-support@gsi.de \n" + + "Silecs wiki: "+ SilecsConstants.SILECS_WIKIS_PATH + "\n\n\n" + + + "Copyright 2016 CERN and GSI\n" + + "This program is free software: you can redistribute it and/or modify\n" + + "it under the terms of the GNU General Public License as published by\n" + + "the Free Software Foundation, either version 3 of the License, or\n" + + "(at your option) any later version.\n\n" + + + "This program is distributed in the hope that it will be useful,\n" + + "but WITHOUT ANY WARRANTY; without even the implied warranty of\n" + + "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n" + + "GNU General Public License for more details.\n\n" + + "You should have received a copy of the GNU General Public License\n" + + "along with this program. If not, see <http://www.gnu.org/licenses/>.\n\n"; + + + MessageDialog dialog = new SilecsMessageDialog(shell, "About Silecs", null, dialogMessage, + MessageDialog.INFORMATION, new String[] { "OK" }, 0); + dialog.open(); + return null; + } +} diff --git a/silecs-eclipse-plugin/src/java/cern/silecs/control/handlers/BaseHandler.java b/silecs-eclipse-plugin/src/java/cern/silecs/control/handlers/BaseHandler.java new file mode 100644 index 0000000..5167a21 --- /dev/null +++ b/silecs-eclipse-plugin/src/java/cern/silecs/control/handlers/BaseHandler.java @@ -0,0 +1,175 @@ +// Copyright 2016 CERN and GSI +// +// 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 3 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, see <http://www.gnu.org/licenses/>. + +package cern.silecs.control.handlers; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import org.eclipse.core.commands.AbstractHandler; +import org.eclipse.core.commands.ExecutionEvent; +import org.eclipse.core.resources.IFile; +import org.eclipse.core.resources.IProject; +import org.eclipse.core.resources.IResource; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.jface.viewers.IStructuredSelection; +import org.eclipse.swt.widgets.Event; +import org.eclipse.swt.widgets.MenuItem; +import org.eclipse.ui.IEditorPart; +import org.eclipse.ui.IFileEditorInput; +import org.eclipse.ui.handlers.HandlerUtil; +import org.eclipse.ui.ide.IDE; + +import cern.silecs.control.core.DeployProjectNature; +import cern.silecs.control.core.DesignProjectNature; +import cern.silecs.utils.SilecsUtils; + +public abstract class BaseHandler extends AbstractHandler { + + + + /** + * Gives the list of selected documents + * Asks the user to save the file if dirty in an editor + * + * @param event + * @return + */ + protected List<IFile> retrieveIeplcFiles(ExecutionEvent event) { + List<IFile> files = retrieveIeplcFilesNonCheck(event); + return ensureFileSaved(files); + } + + /** + * Gives the Ieplc file form file selection or project selection + * @param event + * @return + */ + private List<IFile> retrieveIeplcFilesNonCheck(ExecutionEvent event) { + List<IFile> files = new ArrayList<IFile>(); + + // get from where the command was fired + Object trigger = event.getTrigger(); + if (trigger instanceof Event) { + Event ev = (Event) trigger; + + if (ev.widget instanceof MenuItem) { + // if fired by a popup + IStructuredSelection selection = (IStructuredSelection) HandlerUtil.getActiveMenuSelection(event); + + for (Object o : selection.toList()) { + if (o instanceof IFile) { + files.add((IFile) o); + } else if (o instanceof IProject) { + // if project selected return the design or du file + IProject project = (IProject) o; + try { + files.add(retriveIeplcFileFromProject(project)); + } catch (CoreException e) { + // if project nature can't be retrieve, log but do nothing + //LOGGER.error("Could not retrieve project nature for {}", project.getName()); + } catch (Exception e) { + //LOGGER.error("Project nature not supported for {}", project.getName()); + } + + } + } + + } else { + // the command was fired by a shortcut or a toolbar button + IEditorPart editor = HandlerUtil.getActiveEditor(event); + IFileEditorInput input = (IFileEditorInput) editor.getEditorInput(); + files.add(input.getFile()); + } + } + + return files; + } + + /** + * Gives the list of selected project + * + * @param event + * @return + */ + protected List<IProject> retrieveProjects(ExecutionEvent event) { + List<IProject> projects = new ArrayList<IProject>(); + + // get from where the command was fired + Object trigger = event.getTrigger(); + if (trigger instanceof Event) { + Event ev = (Event) trigger; + + if (ev.widget instanceof MenuItem) { + IStructuredSelection selection = (IStructuredSelection) HandlerUtil.getActiveMenuSelection(event); + List<?> resources = IDE.computeSelectedResources(selection); + for (Object o : resources) { + if (o instanceof IProject) { + projects.add((IProject) o); + } else if (o instanceof IFile) { + IProject project = ((IFile) o).getProject(); + + if (project != null) { + projects.add(project); + } + } + } + } else { + IEditorPart editor = HandlerUtil.getActiveEditor(event); + if (editor == null) return projects; + IFileEditorInput input = (IFileEditorInput) editor.getEditorInput(); + projects.add(input.getFile().getProject()); + } + } + + if (projects.isEmpty()) { + //LOGGER.info("No projects could be retrieved"); + } + + return projects; + } + + /** + * Finds the Ieplc file from the project root + * @param project + * @return + * @throws Exception + * @throws Exception + */ + private IFile retriveIeplcFileFromProject(IProject project) throws Exception { + if (project.hasNature(DeployProjectNature.NATURE_ID)) { + return SilecsUtils.getSilecsDeployFile(project); + } else if (project.hasNature(DesignProjectNature.NATURE_ID)) { + return SilecsUtils.getSilecsDesignFile(project); + } else { + throw new Exception(); + } + } + + /** + * Ensure the documents are not dirty in an open editor + * @param files + * @return + */ + private List<IFile> ensureFileSaved(List<IFile> files) { + if (IDE.saveAllEditors(files.toArray(new IResource[files.size()]), true)) { + return files; + } else { + return Collections.<IFile> emptyList(); + } + } + +} diff --git a/silecs-eclipse-plugin/src/java/cern/silecs/control/handlers/DiagnosticToolHandler.java b/silecs-eclipse-plugin/src/java/cern/silecs/control/handlers/DiagnosticToolHandler.java new file mode 100644 index 0000000..362d5d1 --- /dev/null +++ b/silecs-eclipse-plugin/src/java/cern/silecs/control/handlers/DiagnosticToolHandler.java @@ -0,0 +1,76 @@ +// Copyright 2016 CERN and GSI +// +// 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 3 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, see <http://www.gnu.org/licenses/>. + +package cern.silecs.control.handlers; + +import java.util.HashMap; +import java.util.Map; + +import org.eclipse.core.commands.AbstractHandler; +import org.eclipse.core.commands.ExecutionEvent; +import org.eclipse.core.commands.ExecutionException; +import org.eclipse.core.commands.IHandler; +import org.eclipse.core.resources.IFile; +import org.eclipse.core.resources.IProject; + +import cern.silecs.control.core.DeployProjectNature; +import cern.silecs.utils.OSExecute; +import cern.silecs.utils.SilecsUtils; +import cern.silecs.view.console.ConsoleHandler; +import cern.silecs.view.preferences.MainPreferencePage; + +public class DiagnosticToolHandler extends AbstractHandler implements IHandler { + + @Override + public Object execute(ExecutionEvent event) throws ExecutionException { + + try + { + ConsoleHandler.clear(); + + IProject project = SilecsUtils.extractSilecsFileFromEvent(event).getProject(); + + if( project.hasNature(DeployProjectNature.NATURE_ID) == false ) + throw new Exception("The project: " + project.getName() + " is not a silecs-deploy-project"); + + SilecsUtils.checkSilecsVersion(project); + IFile deployFile = SilecsUtils.getSilecsDeployFile(project); + + String binary = MainPreferencePage.getDiagToolBasePath(SilecsUtils.getSilecsVersion(project)) + "/bin/x86_64/silecs-diagnostic"; + String snap7lib = MainPreferencePage.getSNAP7LibraryBasePath(SilecsUtils.getSilecsVersion(project)) + "/bin/x86_64-linux"; + + ConsoleHandler.printMessage("Starting Silecs Diagnostic Tool from:" + binary, true); + + String[] command = new String[3]; + command[0] = binary; + command[1] = "-d"; + command[2] = deployFile.getRawLocation().makeAbsolute().toOSString(); + String envVarName = "LD_LIBRARY_PATH"; + Map<String, String> env = new HashMap<String, String>(); + env.put(envVarName, snap7lib); + ConsoleHandler.printMessage("Setting environment variable: '" + envVarName + "' to '" + snap7lib + "'", true); + ConsoleHandler.printMessage("Executing command: " + command[0] + " " + command[1] + " " + command[2], true); + OSExecute.executeCommand(env, command); + } + catch (Exception e) + { + ConsoleHandler.printError("Could not launch Silecs Diagnostic Tool", true); + e.printStackTrace(); + } + + return null; + } + +} diff --git a/silecs-eclipse-plugin/src/java/cern/silecs/control/handlers/ExpandAllHandler.java b/silecs-eclipse-plugin/src/java/cern/silecs/control/handlers/ExpandAllHandler.java new file mode 100644 index 0000000..e9e4559 --- /dev/null +++ b/silecs-eclipse-plugin/src/java/cern/silecs/control/handlers/ExpandAllHandler.java @@ -0,0 +1,60 @@ +// Copyright 2016 CERN and GSI +// +// 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 3 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, see <http://www.gnu.org/licenses/>. + +package cern.silecs.control.handlers; + +import java.util.ArrayList; + +import org.eclipse.core.commands.AbstractHandler; +import org.eclipse.core.commands.ExecutionEvent; +import org.eclipse.core.commands.ExecutionException; +import org.eclipse.core.commands.IHandler; +import org.eclipse.core.resources.IProject; +import org.eclipse.core.resources.IWorkspaceRoot; +import org.eclipse.core.resources.ResourcesPlugin; +import org.eclipse.jface.viewers.IStructuredSelection; +import org.eclipse.ui.ISelectionService; +import org.eclipse.ui.PlatformUI; +import cern.silecs.view.explorer.SilecsProjectExplorer; + +/** + * This handler is responsible for expanding selected projects in the silecs explorer.<br> + * It calls SilecsProjectExplorer's expandHelper to expand projects to src-file level. + */ +public class ExpandAllHandler extends AbstractHandler implements IHandler { + + @Override + public Object execute(ExecutionEvent event) throws ExecutionException { + IWorkspaceRoot root = ResourcesPlugin.getWorkspace().getRoot(); + ArrayList<IProject> projects = new ArrayList<>(); + + ISelectionService selectionService = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getSelectionService(); + + IStructuredSelection selections = (IStructuredSelection) selectionService + .getSelection(SilecsProjectExplorer.VIEW_ID); + + for(Object selection : selections.toArray()) { + if(selection instanceof IProject) + projects.add((IProject)selection); + } + + SilecsProjectExplorer explorer = (SilecsProjectExplorer) PlatformUI.getWorkbench().getActiveWorkbenchWindow() + .getActivePage().findView(SilecsProjectExplorer.VIEW_ID); + + explorer.expandHelper(root, projects); + + return null; + } +} diff --git a/silecs-eclipse-plugin/src/java/cern/silecs/control/handlers/GenerateCodeHandler.java b/silecs-eclipse-plugin/src/java/cern/silecs/control/handlers/GenerateCodeHandler.java new file mode 100644 index 0000000..94b33bc --- /dev/null +++ b/silecs-eclipse-plugin/src/java/cern/silecs/control/handlers/GenerateCodeHandler.java @@ -0,0 +1,154 @@ +// Copyright 2016 CERN and GSI +// +// 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 3 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, see <http://www.gnu.org/licenses/>. + +package cern.silecs.control.handlers; + +import java.io.File; +import java.io.FileInputStream; +import java.io.InputStream; + +import org.eclipse.core.commands.ExecutionEvent; +import org.eclipse.core.commands.ExecutionException; +import org.eclipse.core.commands.IHandler; +import org.eclipse.core.resources.IFile; +import org.eclipse.core.resources.IFolder; +import org.eclipse.core.resources.IProject; +import org.eclipse.core.resources.IResource; +import org.eclipse.jface.wizard.IWizard; +import org.eclipse.jface.wizard.WizardDialog; +import org.eclipse.swt.widgets.Shell; +import org.eclipse.ui.handlers.HandlerUtil; + + +import cern.silecs.control.core.DeployProjectNature; +import cern.silecs.control.core.DesignProjectNature; +import cern.silecs.model.exception.SilecsException; +import cern.silecs.utils.SilecsUtils; +import cern.silecs.view.console.ConsoleHandler; +import cern.silecs.view.job.BaseProjectJob; +import cern.silecs.view.job.GenerateClassJob; +import cern.silecs.view.job.GenerateDeployJob; +import cern.silecs.view.preferences.MainPreferencePage; +import cern.silecs.view.wizards.GenerateCodeWizard; + +public class GenerateCodeHandler extends BaseHandler implements IHandler { + + @Override + public Object execute(ExecutionEvent event) throws ExecutionException { + + ConsoleHandler.clear(); + + BaseProjectJob job = null; + try { + IFile silecsFile = SilecsUtils.extractSilecsFileFromEvent(event); + IProject project = silecsFile.getProject(); + SilecsUtils.checkSilecsVersion(project); + + IFolder src = project.getFolder("src"); + if(project.hasNature(DesignProjectNature.NATURE_ID) ) + { + IFile fesaDesignDoc = src.getFile(project.getName() + ".design"); + boolean designDocExists = fesaDesignDoc.exists(); + if(designDocExists) + { + IFile backup = src.getFile(fesaDesignDoc.getName() + ".backup"); + ConsoleHandler.printMessage("Existing FESA Design document detected - new data will be inserted", true); + ConsoleHandler.printWarning("Please note that old, obsolete xml-elements are not deleted automatically! Sometimes this can lead to an invalid FESA Design document!", true); + ConsoleHandler.printWarning("If this is the case, please remove the obsolete elements by hand.", true); + ConsoleHandler.printMessage("A backup of your old document will be saved at: " + backup.getRawLocation().makeAbsolute(), true); + if(backup.exists()) + backup.delete(true, null); + fesaDesignDoc.copy(backup.getFullPath(), true, null); + } + else + { + File[] templates = MainPreferencePage.getFESADesignTemplates(); + File template = pickTemplate(event,templates); + if( template == null) // cancel pressed + return null; + ConsoleHandler.printMessage("The following template will be used:" + template.getAbsolutePath(), true); + InputStream source = new FileInputStream(template); + fesaDesignDoc.create(source, IResource.NONE, null); + } + job = new GenerateClassJob(project, fesaDesignDoc); + } + else if(project.hasNature(DeployProjectNature.NATURE_ID) ) + { + IFile fesaDeployDoc = src.getFile(project.getName() + ".deploy"); + boolean deployDocExists = fesaDeployDoc.exists(); + if(deployDocExists) + { + IFile backup = src.getFile(fesaDeployDoc.getName() + ".backup"); + ConsoleHandler.printMessage("Existing FESA Deploy-Unit document detected - new data will be inserted", true); + ConsoleHandler.printWarning("Please note that old, obsolete xml-elements are not deleted automatically! Sometimes this can lead to an invalid FESA Deploy-Unit document !", true); + ConsoleHandler.printWarning("If this is the case, please remove the obsolete elements by hand.", true); + ConsoleHandler.printMessage("A backup of your old document will be saved at: " + backup.getRawLocation().makeAbsolute(), true); + if(backup.exists()) + backup.delete(true, null); + fesaDeployDoc.copy(backup.getFullPath(), true, null); + } + else + { + File[] templates = MainPreferencePage.getFESADeployUnitTemplates(); + File template = pickTemplate(event,templates); + if( template == null) // cancel pressed + return null; + ConsoleHandler.printMessage("The following template will be used:" + template.getAbsolutePath(), true); + InputStream source = new FileInputStream(template); + fesaDeployDoc.create(source, IResource.NONE, null); + } + + job = new GenerateDeployJob(project, fesaDeployDoc,!deployDocExists); + } + else + { + ConsoleHandler.printError("Failed to find SILECS Project Nature", true); + return null; + } + } catch (Exception e) + { + ConsoleHandler.printError("Failed to generate code: ", true); + ConsoleHandler.printStackTrace(e); + return null; + } + + job.setUser(true); + job.schedule(); + + return null; + } + + private File pickTemplate(ExecutionEvent event, File[] templates) throws SilecsException + { + if(templates.length < 1) + { + String error = "Failed to generate FESA Class. No templates found. please fix your FESA-PATH in the preferences!"; + ConsoleHandler.printError(error, true); + throw new SilecsException(error); + } + if( templates.length == 1 ) + { + return templates[0]; + } + //TODO: Would be nice to add the possibility to pick a foreign template from the file system + Shell activeShell = HandlerUtil.getActiveShell(event); + IWizard wizard = new GenerateCodeWizard(templates); + WizardDialog dialog = new WizardDialog(activeShell, wizard); + dialog.open(); + return ((GenerateCodeWizard)wizard).getChoice(); + } + + +} diff --git a/silecs-eclipse-plugin/src/java/cern/silecs/control/handlers/SilecsWikis.java b/silecs-eclipse-plugin/src/java/cern/silecs/control/handlers/SilecsWikis.java new file mode 100644 index 0000000..0973f98 --- /dev/null +++ b/silecs-eclipse-plugin/src/java/cern/silecs/control/handlers/SilecsWikis.java @@ -0,0 +1,54 @@ +// Copyright 2016 CERN and GSI +// +// 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 3 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, see <http://www.gnu.org/licenses/>. + +package cern.silecs.control.handlers; + +import org.eclipse.core.commands.AbstractHandler; +import org.eclipse.core.commands.ExecutionEvent; +import org.eclipse.core.commands.ExecutionException; +import org.eclipse.core.commands.IHandler; + +import cern.silecs.utils.SilecsUtils; +import cern.silecs.utils.SilecsConstants; + +import java.awt.Desktop; +import java.io.IOException; +import java.net.URI; +import java.net.URISyntaxException; + +/** + * This handler opens silecs-wiki in the browser. + */ +public class SilecsWikis extends AbstractHandler implements IHandler { + + @Override + public Object execute(ExecutionEvent event) throws ExecutionException { + + // Open windows default browser (or firefox under linux) and load Silecs Wikis pages + try { + if (SilecsUtils.isWindows) { + Desktop.getDesktop().browse(new URI(SilecsConstants.SILECS_WIKIS_PATH)); + } else { + Runtime runtime = Runtime.getRuntime(); + runtime.exec("/usr/bin/firefox -new-window " + SilecsConstants.SILECS_WIKIS_PATH); + } + } catch (IOException e) { + e.printStackTrace(); + } catch (URISyntaxException e) { + e.printStackTrace(); + } + return null; + } +} diff --git a/silecs-eclipse-plugin/src/java/cern/silecs/control/handlers/UpdateSilecsProjectHandler.java b/silecs-eclipse-plugin/src/java/cern/silecs/control/handlers/UpdateSilecsProjectHandler.java new file mode 100644 index 0000000..6966b77 --- /dev/null +++ b/silecs-eclipse-plugin/src/java/cern/silecs/control/handlers/UpdateSilecsProjectHandler.java @@ -0,0 +1,77 @@ +// Copyright 2016 CERN and GSI +// +// 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 3 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, see <http://www.gnu.org/licenses/>. + +package cern.silecs.control.handlers; + + +import org.eclipse.core.commands.AbstractHandler; +import org.eclipse.core.commands.ExecutionEvent; +import org.eclipse.core.commands.ExecutionException; +import org.eclipse.core.commands.IHandler; +import org.eclipse.core.resources.IFile; +import org.eclipse.core.resources.IProject; +import org.eclipse.jface.wizard.IWizard; +import org.eclipse.jface.wizard.WizardDialog; +import org.eclipse.swt.widgets.Shell; +import org.eclipse.ui.handlers.HandlerUtil; + +import cern.silecs.model.exception.SilecsException; +import cern.silecs.utils.SilecsUtils; +import cern.silecs.view.console.ConsoleHandler; +import cern.silecs.view.job.BaseProjectJob; + +import cern.silecs.view.job.UpdateVersionJob; +import cern.silecs.view.wizards.UpdateSilecsProjectWizard; + + +public class UpdateSilecsProjectHandler extends AbstractHandler implements IHandler { + + @Override + public Object execute(ExecutionEvent event) throws ExecutionException + { + + ConsoleHandler.clear(); + + BaseProjectJob job = null; + + try + { + String newVersion = pickVersion(event); + IFile silecsFile = SilecsUtils.extractSilecsFileFromEvent(event); + IProject project = silecsFile.getProject(); + job = new UpdateVersionJob(project, newVersion); + + } catch (Exception e) + { + ConsoleHandler.printError("Failed to update SILECS version: " , true); + ConsoleHandler.printStackTrace(e); + return null; + } + + job.setUser(true); + job.schedule(); + + return null; + } + + private String pickVersion(ExecutionEvent event) throws SilecsException + { + Shell activeShell = HandlerUtil.getActiveShell(event); + IWizard wizard = new UpdateSilecsProjectWizard(); + WizardDialog dialog = new WizardDialog(activeShell, wizard); + dialog.open(); + return ((UpdateSilecsProjectWizard)wizard).getSelectedVersion(); + } +} diff --git a/silecs-eclipse-plugin/src/java/cern/silecs/control/handlers/ValidateHandler.java b/silecs-eclipse-plugin/src/java/cern/silecs/control/handlers/ValidateHandler.java new file mode 100644 index 0000000..37e7e05 --- /dev/null +++ b/silecs-eclipse-plugin/src/java/cern/silecs/control/handlers/ValidateHandler.java @@ -0,0 +1,52 @@ +// Copyright 2016 CERN and GSI +// +// 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 3 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, see <http://www.gnu.org/licenses/>. + +package cern.silecs.control.handlers; + +import org.eclipse.core.commands.ExecutionEvent; +import org.eclipse.core.commands.ExecutionException; +import org.eclipse.core.commands.IHandler; +import org.eclipse.core.resources.IFile; + +import cern.silecs.view.console.ConsoleHandler; +import cern.silecs.view.job.ValidationJob; +import cern.silecs.utils.SilecsUtils; + + +public class ValidateHandler extends BaseHandler implements IHandler { + + @Override + public Object execute(ExecutionEvent event) throws ExecutionException { + + ConsoleHandler.clear(); + ConsoleHandler.printMessage("Validating XML ...", true); + ValidationJob job; + try + { + IFile file = SilecsUtils.extractSilecsFileFromEvent(event); + SilecsUtils.checkSilecsVersion(file.getProject()); + job = new ValidationJob(file); + } + catch (Exception e) + { + ConsoleHandler.printError("Failed to validate file:", true); + ConsoleHandler.printStackTrace(e); + return null; + } + + job.schedule(); + return null; + } +} diff --git a/silecs-eclipse-plugin/src/java/cern/silecs/control/validation/Validator.java b/silecs-eclipse-plugin/src/java/cern/silecs/control/validation/Validator.java new file mode 100644 index 0000000..e9e0197 --- /dev/null +++ b/silecs-eclipse-plugin/src/java/cern/silecs/control/validation/Validator.java @@ -0,0 +1,103 @@ +// Copyright 2016 CERN and GSI +// +// 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 3 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, see <http://www.gnu.org/licenses/>. + +package cern.silecs.control.validation; + +import java.io.File; +import java.io.FileInputStream; +import java.io.InputStream; +import java.util.List; + +import org.apache.xerces.parsers.DOMParser; +import org.apache.xerces.xni.parser.XMLInputSource; +import org.eclipse.core.resources.IFile; + +import cern.silecs.control.validation.internal.Handler; +import cern.silecs.model.document.SilecsDocumentError; +import cern.silecs.view.console.ConsoleHandler; + +/** + * Class used for validating single xmlFile + */ +public class Validator +{ + /** + * This method takes as an argument xml file.<br> + * If the document is not xml file or is somehow broken list with "Document is not parsed correctly" error is returned."<br> + * + * External python validation is called in this method! + * + * @param xmlFile + * @return list of errors + */ + public static List<SilecsDocumentError> validate(File xmlFile) + { + List<SilecsDocumentError> errors = null; + try { + // create DOM parser which validates, use a grammar pool, + // support xincludes and allow the access to the nodes + // during the parsing + DOMParser parser = new DOMParser(); + + parser.setFeature("http://xml.org/sax/features/validation", true); + parser.setFeature("http://apache.org/xml/features/validation/schema", true); + parser.setFeature("http://apache.org/xml/features/honour-all-schemaLocations", true); + parser.setFeature("http://apache.org/xml/features/xinclude", true); + parser.setFeature("http://apache.org/xml/features/xinclude/fixup-base-uris", false); + parser.setFeature("http://apache.org/xml/features/xinclude/fixup-language", false); + parser.setFeature("http://apache.org/xml/features/dom/defer-node-expansion", false); + + // Set the error handler + Handler handler = new Handler(xmlFile, parser); + parser.setErrorHandler(handler); + + // create the input + String uri = xmlFile.toURI().toString().replace("%20", " "); + + InputStream inputStream = new FileInputStream(xmlFile); + XMLInputSource inputSource = new XMLInputSource("", uri, uri, inputStream, "UTF-8"); + parser.parse(inputSource); + + // get the errors and the model + errors = handler.getErrors(); + errors.addAll(internalRules.validate(xmlFile)); + + } + catch (Exception e) + { + ConsoleHandler.printError("Document " + xmlFile.getName() + " has not been parsed correctly: " + e.getMessage(), true); + ConsoleHandler.printStackTrace(e); + } + + return errors; + } + + public static boolean isDocumentValid(IFile silecsDocument) + { + try + { + File xmlFile = new File(silecsDocument.getLocationURI()); + if (validate(xmlFile).isEmpty()) + return true; + return false; + } + catch (Exception e) + { + e.printStackTrace(); + ConsoleHandler.printStackTrace(e); + return false; + } + } +} diff --git a/silecs-eclipse-plugin/src/java/cern/silecs/control/validation/internal/Handler.java b/silecs-eclipse-plugin/src/java/cern/silecs/control/validation/internal/Handler.java new file mode 100644 index 0000000..56f49f7 --- /dev/null +++ b/silecs-eclipse-plugin/src/java/cern/silecs/control/validation/internal/Handler.java @@ -0,0 +1,91 @@ +// Copyright 2016 CERN and GSI +// +// 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 3 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, see <http://www.gnu.org/licenses/>. + +package cern.silecs.control.validation.internal; + +import java.io.File; +import java.util.ArrayList; +import java.util.List; + +import org.apache.xerces.parsers.DOMParser; +import org.w3c.dom.Element; +import org.xml.sax.ErrorHandler; +import org.xml.sax.SAXException; +import org.xml.sax.SAXNotRecognizedException; +import org.xml.sax.SAXNotSupportedException; +import org.xml.sax.SAXParseException; + +import cern.silecs.model.document.SilecsDocumentError; +import cern.silecs.model.document.SilecsDocumentError.ErrorLevel; +import cern.silecs.view.console.ConsoleHandler; + +public class Handler implements ErrorHandler +{ + private static final String CURRENT_NODE = "http://apache.org/xml/properties/dom/current-element-node"; + + private final DOMParser parser; + private final String fileName; + private List<SilecsDocumentError> errors; + + public Handler(File xmlFile, DOMParser parser) { + this.parser = parser; + this.fileName = xmlFile.getName(); + this.errors = new ArrayList<SilecsDocumentError>(); + } + + @Override + public void warning(SAXParseException e) throws SAXException { + addError(ErrorLevel.WARNING, e); + } + + @Override + public void error(SAXParseException e) throws SAXException { + addError(ErrorLevel.ERROR, e); + } + + @Override + public void fatalError(SAXParseException e) throws SAXException { + addError(ErrorLevel.FATAL, e); + } + + public final List<SilecsDocumentError> getErrors() { + return errors; + } + + private void addError(ErrorLevel level, SAXParseException e) { + Element element = null; + try + { + element = (Element) parser.getProperty(CURRENT_NODE); + } + catch (SAXNotRecognizedException | SAXNotSupportedException e1) + { + ConsoleHandler.printStackTrace(e1); + return; + } + SilecsDocumentError error = null; + String file = e.getSystemId(); + if (!file.endsWith(fileName)) { + // if the error is in the included xml or in the schema, we want to report the problem + // on the validated file but with a specific message + error = new SilecsDocumentError(level, "Error in included file: " + file + " at " + e.getLineNumber() + ":" + + e.getColumnNumber() + " => " + e.getMessage(), -1, -1, null); + } else { + error = new SilecsDocumentError(level, e, element); + } + + errors.add(error); + } +} diff --git a/silecs-eclipse-plugin/src/java/cern/silecs/control/validation/internalRules.java b/silecs-eclipse-plugin/src/java/cern/silecs/control/validation/internalRules.java new file mode 100644 index 0000000..0b2524b --- /dev/null +++ b/silecs-eclipse-plugin/src/java/cern/silecs/control/validation/internalRules.java @@ -0,0 +1,201 @@ +// Copyright 2016 CERN and GSI +// +// 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 3 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, see <http://www.gnu.org/licenses/>. + +package cern.silecs.control.validation; + +import java.io.File; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.parsers.ParserConfigurationException; + +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; +import org.xml.sax.SAXException; + +import cern.silecs.model.document.SilecsDocumentError; +import cern.silecs.utils.SilecsUtils; + +public class internalRules { + + public static List<SilecsDocumentError> validate(File file) throws ParserConfigurationException, SAXException, IOException + { + // Some of the XSD-checks are version-specific. This is painful and will vanish some day when using XSD1.1 for all checks + //String silecs_version = + + List<SilecsDocumentError> errors = new ArrayList<SilecsDocumentError>(); + + DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance(); + DocumentBuilder dBuilder = dbFactory.newDocumentBuilder(); + Document doc = dBuilder.parse(file); + + if( SilecsUtils.isSilecsDesign(file.getAbsolutePath()) ) + { + errors.addAll(classRule_RegisterDim2(doc)); + errors.addAll(classRule_RO_Slave(doc)); + errors.addAll(classRule_WO_Master(doc)); + errors.addAll(classRule_StringLength(doc)); + } + if( SilecsUtils.isSilecsDeploy(file.getAbsolutePath()) ) + { + errors.addAll(deployRule_addressing_SchneiderM340(doc)); + errors.addAll(deployRule_addressing_BeckhoffCX90xx(doc)); + } + return errors; + } + + private static String getXPath(Node node) + { + Node parent = node.getParentNode(); + if (parent == null) + { + return "/"; + } + + if(!((Element)node).getAttribute("name").isEmpty()) + return getXPath(parent) + "/" + node.getNodeName() + "[@name='"+ ((Element)node).getAttribute("name") + "']"; + + return getXPath(parent) + "/" + node.getNodeName(); + } + + private static List<SilecsDocumentError> classRule_RegisterDim2(Document doc) + { + List<SilecsDocumentError> errors = new ArrayList<SilecsDocumentError>(); + NodeList regNodes = doc.getElementsByTagName("Register"); + for( int i = 0; i< regNodes.getLength() ; i++) + { + Element register = (Element)regNodes.item(i); + if( register.hasAttribute("array-dim2") && !register.hasAttribute("array-dim1") ) + { + SilecsDocumentError newError = new SilecsDocumentError( SilecsDocumentError.ErrorLevel.ERROR, "array-dim1 is required if array-dim2 is defined", -1, -1,getXPath(register)); + errors.add(newError); + } + } + return errors; + } + + private static List<SilecsDocumentError> classRule_RO_Slave(Document doc) + { + List<SilecsDocumentError> errors = new ArrayList<SilecsDocumentError>(); + NodeList blockNodes = doc.getElementsByTagName("Block"); + for( int i = 0; i< blockNodes.getLength() ; i++) + { + Element block = (Element)blockNodes.item(i); + if( block.getAttribute("mode").equals("READ-ONLY") ) + { + NodeList registerNodes = block.getElementsByTagName("Register"); + for( int j = 0; j< registerNodes.getLength() ; j++) + { + Element register = (Element)registerNodes.item(j); + if( register.getAttribute("synchro").equals("SLAVE") ) + { + SilecsDocumentError newError = new SilecsDocumentError( SilecsDocumentError.ErrorLevel.ERROR, "Register cannot have SLAVE synchro attribute within READ-ONLY block", -1, -1,getXPath(register)); + errors.add(newError); + } + } + } + } + return errors; + } + + private static List<SilecsDocumentError> classRule_WO_Master(Document doc) + { + List<SilecsDocumentError> errors = new ArrayList<SilecsDocumentError>(); + NodeList blockNodes = doc.getElementsByTagName("Block"); + for( int i = 0; i< blockNodes.getLength() ; i++) + { + Element block = (Element)blockNodes.item(i); + if( block.getAttribute("mode").equals("WRITE-ONLY")) + { + NodeList registerNodes = block.getElementsByTagName("Register"); + for( int j = 0; j< registerNodes.getLength() ; j++) + { + Element register = (Element)registerNodes.item(j); + if( register.getAttribute("synchro").equals("MASTER") ) + { + SilecsDocumentError newError = new SilecsDocumentError( SilecsDocumentError.ErrorLevel.ERROR, "Register cannot have MASTER synchro attribute within WRITE-ONLY block", -1, -1,getXPath(register)); + errors.add(newError); + } + } + } + } + return errors; + } + + private static List<SilecsDocumentError> classRule_StringLength(Document doc) + { + List<SilecsDocumentError> errors = new ArrayList<SilecsDocumentError>(); + NodeList registerNodes = doc.getElementsByTagName("Register"); + for( int j = 0; j< registerNodes.getLength() ; j++) + { + Element register = (Element)registerNodes.item(j); + if( register.getAttribute("format").equals("string") == false ) + { + if( register.hasAttribute("string-len")) + { + SilecsDocumentError newError = new SilecsDocumentError( SilecsDocumentError.ErrorLevel.ERROR, "string-len attribute only allowed for @format='string'.", -1, -1,getXPath(register)); + errors.add(newError); + } + } + } + return errors; + } + + private static List<SilecsDocumentError> deployRule_addressing_SchneiderM340(Document doc) + { + List<SilecsDocumentError> errors = new ArrayList<SilecsDocumentError>(); + NodeList schneiderPLCNode = doc.getElementsByTagName("Schneider-PLC"); + for( int i = 0; i< schneiderPLCNode.getLength() ; i++) + { + Element plc = (Element)schneiderPLCNode.item(i); + if( plc.getAttribute("model").equals("M340")) + { + int basAddress = Integer.parseInt( plc.getAttribute("base-address")); + if( basAddress%2 != 0 ) + { + SilecsDocumentError newError = new SilecsDocumentError( SilecsDocumentError.ErrorLevel.ERROR, "Only even addressing is allowed for UNITY_M340. Please change the base address value to an even number.", -1, -1,getXPath(plc)); + errors.add(newError); + } + } + } + return errors; + } + + private static List<SilecsDocumentError> deployRule_addressing_BeckhoffCX90xx(Document doc) + { + List<SilecsDocumentError> errors = new ArrayList<SilecsDocumentError>(); + NodeList schneiderPLCNode = doc.getElementsByTagName("Beckhoff-PLC"); + for( int i = 0; i< schneiderPLCNode.getLength() ; i++) + { + Element plc = (Element)schneiderPLCNode.item(i); + if( plc.getAttribute("model").equals("CX9020")) + { + int basAddress = Integer.parseInt( plc.getAttribute("base-address")); + if( basAddress%2 != 0 ) + { + SilecsDocumentError newError = new SilecsDocumentError( SilecsDocumentError.ErrorLevel.ERROR, "Only even addressing is allowed for TWINCAT_CX9020. Please change the base address value to an even number.", -1, -1,getXPath(plc)); + errors.add(newError); + } + } + } + return errors; + } + +} diff --git a/silecs-eclipse-plugin/src/java/cern/silecs/model/document/SilecsDocumentError.java b/silecs-eclipse-plugin/src/java/cern/silecs/model/document/SilecsDocumentError.java new file mode 100644 index 0000000..1e0f25d --- /dev/null +++ b/silecs-eclipse-plugin/src/java/cern/silecs/model/document/SilecsDocumentError.java @@ -0,0 +1,106 @@ +// Copyright 2016 CERN and GSI +// +// 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 3 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, see <http://www.gnu.org/licenses/>. + +package cern.silecs.model.document; + +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import org.w3c.dom.Node; +import org.xml.sax.SAXParseException; + +import cern.silecs.utils.XmlUtils; + + +public class SilecsDocumentError { + + public enum ErrorLevel { + INFO, + WARNING, + ERROR, + FATAL + } + + /** + * error level + */ + public final ErrorLevel level; + + /** + * text with the description of the error + */ + public final String message; + + /** + * line of the error + */ + public final int lineNumber; + + /** + * column of the error + */ + public final int columnNumber; + + /** + * Element which cause the error + */ + public final String xPath; + + /** + * If an identity constraint has been violated, this contains the name of the violated key + */ + public final String violatedKey; + + /** + * If an identity constraint has been violated, this contains the incorrect value which is the cause of the error + */ + public final String incorrectValue; + + private static final String CONSTRAINT_MESSAGE_PATTERN = "cvc-identity-constraint.4.3: Key '(.*)' with value '(.*)' not found for identity constraint of element '(.*)'\\."; + + public SilecsDocumentError(ErrorLevel level, String message, int lineNumber, int columnNumber, String xPath) { + this.level = level; + this.message = message; + this.lineNumber = lineNumber; + this.columnNumber = columnNumber; + this.xPath = xPath; + + String key = ""; + String value = ""; + Pattern constraintPattern = Pattern.compile(CONSTRAINT_MESSAGE_PATTERN); + Matcher m = constraintPattern.matcher(message); + if (m.find()) { + key = m.group(1); + value = m.group(2); + } + + this.violatedKey = key; + this.incorrectValue = value; + } + + public SilecsDocumentError(ErrorLevel level, SAXParseException e, Node node) { + this(level, e.getMessage(), e.getLineNumber(), e.getColumnNumber(), XmlUtils.xPathFromNode(node)); + } + + public boolean isIdentityConstraintError() { + return !violatedKey.isEmpty(); + } + + @Override + public String toString() { + return lineNumber + ":" + columnNumber + " => " + message; + } +} + diff --git a/silecs-eclipse-plugin/src/java/cern/silecs/model/document/XmlBasedDocument.java b/silecs-eclipse-plugin/src/java/cern/silecs/model/document/XmlBasedDocument.java new file mode 100644 index 0000000..e48c06a --- /dev/null +++ b/silecs-eclipse-plugin/src/java/cern/silecs/model/document/XmlBasedDocument.java @@ -0,0 +1,234 @@ +// Copyright 2016 CERN and GSI +// +// 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 3 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, see <http://www.gnu.org/licenses/>. + +package cern.silecs.model.document; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import javax.xml.transform.TransformerException; +import javax.xml.transform.TransformerFactoryConfigurationError; + +import org.apache.xpath.XPathAPI; +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; + +import cern.silecs.model.exception.SilecsException; +import cern.silecs.utils.XmlUtils; +import cern.silecs.view.console.ConsoleHandler; + +public class XmlBasedDocument { + + public static final String XML_EXTENSION = ".xml"; + public static final String XSD_EXTENSION = ".xsd"; + + protected Document xmlDocument; + + /** + * Abstract class for data access object based on xml DOM + */ + public XmlBasedDocument(Document xmlDocument) { + this.xmlDocument = xmlDocument; + } + + /** + * Give the DOM + * + * @return + */ + public Document getXmlDocument() { + return xmlDocument; + } + + /** + * Helper that gives the list of element from an xPath query + * + * @param xPathQuery + * @return + * @throws SilecsException + */ + public List<Element> getElements(String xPathQuery) throws SilecsException { + return getElements(xmlDocument, xPathQuery); + } + + /** + * Helper that gives the list of element from an xPath query + * + * @param node node from where the query is executed + * @param xPathQuery + * @return + * @throws SilecsException + */ + public List<Element> getElements(Node node, String xPathQuery) throws SilecsException { + List<Node> nodes = getNodes(node, xPathQuery); + List<Element> elements = new ArrayList<Element>(nodes.size()); + + for (Node n : nodes) { + if (n instanceof Element) { + elements.add((Element) n); + } + } + + return elements; + } + + /** + * Helper that gives the first element from an xPath query + * + * @param xPathQuery + * @return + * @throws SilecsException + */ + public Element getSingleElement(String xPathQuery) throws SilecsException { + Node foundNode = getSingleNode(xPathQuery); + if (foundNode instanceof Element) { + return (Element) foundNode; + } else { + return null; + } + } + + /** + * Helper that gives the first element from an xPath query + * + * @param node node from where the query is executed + * @param xPathQuery + * @return + * @throws SilecsException + */ + public Element getSingleElement(Node node, String xPathQuery) throws SilecsException { + Node foundNode = getSingleNode(node, xPathQuery); + if (foundNode instanceof Element) { + return (Element) foundNode; + } else { + return null; + } + } + + public List<Node> getNodes(String xPathQuery) throws SilecsException { + return getNodes(xmlDocument, xPathQuery); + } + + public List<Node> getNodes(Node node, String xPathQuery) throws SilecsException { + if (xPathQuery == null || xPathQuery.isEmpty()) { + return Collections.emptyList(); + } + + // check the node is from the document + if (node != xmlDocument && node.getOwnerDocument() != xmlDocument) { + throw new SilecsException("The given node is not part of the document being queried"); + } + + try { + NodeList foundNodes = XPathAPI.selectNodeList(node, xPathQuery); + List<Node> nodes = new ArrayList<Node>(foundNodes.getLength()); + + for (int i = 0; i < foundNodes.getLength(); i++) { + nodes.add(foundNodes.item(i)); + } + + return nodes; + } catch (TransformerException e) { + throw new SilecsException("Could not get entity's node using xpath " + xPathQuery, e); + } + } + + /** + * Helper that gives the first node from an xPath query + * + * @param xPathQuery + * @return + * @throws SilecsException + */ + public Node getSingleNode(String xPathQuery) throws SilecsException { + if (xPathQuery == null || xPathQuery.isEmpty()) { + return null; + } + + try { + return XPathAPI.selectSingleNode(xmlDocument, xPathQuery); + } catch (TransformerException e) { + throw new SilecsException("Could not get entity's node using xpath " + xPathQuery, e); + } + } + + /** + * Helper that gives the first node from an xPath query + * + * @param node node from where the query is executed + * @param xPathQuery + * @return + * @throws SilecsException + */ + public Node getSingleNode(Node node, String xPathQuery) throws SilecsException { + if (xPathQuery == null || xPathQuery.isEmpty()) { + return null; + } + + // check the node is from the document + if (node.getOwnerDocument() != xmlDocument) { + throw new SilecsException("The given node is not part of the document being queried"); + } + + try { + return XPathAPI.selectSingleNode(node, xPathQuery); + } catch (TransformerException e) { + throw new SilecsException("Could not get entity's node using xpath " + xPathQuery, e); + } + } + + /** + * Helper that gives the tag name of the elements matched by the xpath + * + * @param xPathQuery + * @return + * @throws SilecsException + */ + public List<String> getTagNames(String xPathQuery) throws SilecsException { + List<Element> elements = getElements(xPathQuery); + List<String> nodeNames = new ArrayList<String>(elements.size()); + + for (Element e : elements) { + nodeNames.add(e.getTagName()); + } + + return nodeNames; + } + + /** + * Give the string representation of the DOM + */ + @Override + public String toString() + { + try + { + return XmlUtils.nodeToString(xmlDocument); + } + catch( TransformerException e) + { + ConsoleHandler.printStackTrace(e); + return super.toString(); + } + catch(TransformerFactoryConfigurationError e) + { + ConsoleHandler.printStackTrace(e.getException()); + return super.toString(); + } + } +} \ No newline at end of file diff --git a/silecs-eclipse-plugin/src/java/cern/silecs/model/exception/SilecsException.java b/silecs-eclipse-plugin/src/java/cern/silecs/model/exception/SilecsException.java new file mode 100644 index 0000000..0e8ff65 --- /dev/null +++ b/silecs-eclipse-plugin/src/java/cern/silecs/model/exception/SilecsException.java @@ -0,0 +1,95 @@ +// Copyright 2016 CERN and GSI +// +// 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 3 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, see <http://www.gnu.org/licenses/>. + +package cern.silecs.model.exception; + + +public class SilecsException extends Exception { + + private static final long serialVersionUID = 5282474727123991544L; + + /** + * The error code which can be used to localize the error messages + */ + private final int errorCode; + + /** Empty constructor **/ + public SilecsException() { + this.errorCode = -1; + } + + /** + * Constructor with the Silecs error code + * + * @param errorCode + */ + public SilecsException(int errorCode) { + this.errorCode = errorCode; + } + + /** + * Constructor + * + * @param message + */ + public SilecsException(String message) { + super(message); + this.errorCode = -1; + } + + /** + * Constructor with the Silecs error code + * + * @param errorCode + * @param message + */ + public SilecsException(int errorCode, String message) { + super(message); + this.errorCode = errorCode; + } + + /** + * Constructor + * + * @param message + * @param cause previous cause of the error (exception chaining) + */ + public SilecsException(String message, Throwable cause) { + super(message, cause); + this.errorCode = -1; + } + + /** + * Constructor + * + * @param errorCode + * @param message + * @param cause + */ + public SilecsException(int errorCode, String message, Throwable cause) { + super(message, cause); + this.errorCode = errorCode; + } + + /** + * Returns the Silecs error code + * -1 is the default value if no error code is set + * @return + */ + public int getErrorCode() { + return errorCode; + } +} + diff --git a/silecs-eclipse-plugin/src/java/cern/silecs/utils/OSExecute.java b/silecs-eclipse-plugin/src/java/cern/silecs/utils/OSExecute.java new file mode 100644 index 0000000..929f7d2 --- /dev/null +++ b/silecs-eclipse-plugin/src/java/cern/silecs/utils/OSExecute.java @@ -0,0 +1,142 @@ +// Copyright 2016 CERN and GSI +// +// 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 3 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, see <http://www.gnu.org/licenses/>. + +package cern.silecs.utils; + +import java.io.BufferedReader; +import java.io.File; +import java.io.IOException; +import java.io.InputStreamReader; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import cern.silecs.model.exception.SilecsException; +import cern.silecs.view.console.ConsoleHandler; +import cern.silecs.view.preferences.MainPreferencePage; + +public class OSExecute +{ + + public static String getlatestSilecsFesaCodegen(String codegenBaseDirectory, String silecsVersion) throws SilecsException + { + String fesaBaseDirectory = codegenBaseDirectory + "/fesa"; + if(!new File(fesaBaseDirectory).exists()) + { + throw new SilecsException("The directory: '" + fesaBaseDirectory + "' does not exist. Please check your Eclipse-Silecs preferences!"); + } + List<String> availableFesaVersions = MainPreferencePage.getAllFesaVersions(); + String selectedFesaVersion = MainPreferencePage.getFESAVersion(); + String tempFesaVersion = selectedFesaVersion; + int fesaVersionIndex = availableFesaVersions.lastIndexOf(selectedFesaVersion); + String fesaDirectory = ""; + while(true) + { + String fesaVersionUnderscored = tempFesaVersion.replaceAll("\\.", "_"); + fesaDirectory = fesaBaseDirectory + "/fesa_" + fesaVersionUnderscored; + if(new File(fesaDirectory).exists()) + { + return fesaDirectory; + } + fesaVersionIndex ++ ; + if( fesaVersionIndex >= availableFesaVersions.size() ) + { + throw new SilecsException("No matching silecs code-generation found for FESA-version '" + selectedFesaVersion + "'. Please select a more recent FESA-version in the Eclipse-Silecs preferences!"); + } + ConsoleHandler.printError("No silecs code-generation for the FESA-version '" + tempFesaVersion + "' found. Attempt to use silecs-codegen for the older FESA-version: '" + availableFesaVersions.get(fesaVersionIndex) + "'", true); + tempFesaVersion = availableFesaVersions.get(fesaVersionIndex); + } + } + + + public static void executePython(String file, String method, String silecsVersion, String[] parameters) throws IOException, InterruptedException, SilecsException + { + String[] command = new String[3]; + command[0] = "python"; + command[1] = "-c"; + + String codegenBaseDirectory = MainPreferencePage.getCodeGenBasePath(silecsVersion); + String fesaDirectory = getlatestSilecsFesaCodegen(codegenBaseDirectory, silecsVersion); + + // Add required root directories + command[2] = "import sys; "; + command[2] += "sys.path.append('" + codegenBaseDirectory + "'); "; + command[2] += "sys.path.append('" + codegenBaseDirectory + "/migration'); "; + command[2] += "sys.path.append('" + fesaDirectory + "'); "; + + // import file + command[2] += "import " + file + "; "; + + // execute method + command[2] += file +"." + method + "("; + + for(int i=0;i<parameters.length;i++) + { + command[2] += "'" + parameters[i] + "'"; + if( i < parameters.length - 1) + { + command[2] += ","; + } + } + command[2] += ")"; + int exitCode = executeCommand(command); + if (exitCode != 0) + { + throw new SilecsException("Executing python-command '" + command[2] + "' failed. Error code: " + exitCode); + } + } + + class Environment + { + String environmentVariableName; + + + }; + + public static int executeCommand(String... command) throws IOException, InterruptedException, SilecsException + { + Map<String, String> env = new HashMap<String, String>(); + return executeCommand(env, command); + } + + public static int executeCommand(Map<String, String> environmentVariables, String... command) throws IOException, InterruptedException, SilecsException + { + ProcessBuilder pb = new ProcessBuilder(command); + Map<String, String> env = pb.environment(); + env.putAll(environmentVariables); + + Process process = pb.start(); + process.waitFor(); + int exitCode = process.exitValue(); + + BufferedReader input = new BufferedReader(new InputStreamReader(process.getInputStream())); + String line; + while ((line = input.readLine()) != null) + { + ConsoleHandler.printMessage(line, true); + } + input.close(); + + BufferedReader error = new BufferedReader(new InputStreamReader(process.getErrorStream())); + + while ((line = error.readLine()) != null) + { + ConsoleHandler.printError(line, true); + } + error.close(); + + return exitCode; + } +} \ No newline at end of file diff --git a/silecs-eclipse-plugin/src/java/cern/silecs/utils/SilecsConstants.java b/silecs-eclipse-plugin/src/java/cern/silecs/utils/SilecsConstants.java new file mode 100644 index 0000000..da2ea02 --- /dev/null +++ b/silecs-eclipse-plugin/src/java/cern/silecs/utils/SilecsConstants.java @@ -0,0 +1,103 @@ +// Copyright 2016 CERN and GSI +// +// 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 3 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, see <http://www.gnu.org/licenses/>. + +package cern.silecs.utils; + +import java.util.Arrays; +import java.util.List; + +public class SilecsConstants { + + public enum ProjectType { + DESIGN_PROJECT, + DEPLOY_PROJECT + } + + public static final String SILECS_NAME = "Silecs-Eclipse-Plugin"; + + //consistency check + public static final String DESIGN_CLASS_NODE = "SILECS-Class"; + + public static final String DEPLOY_UNIT_NODE = "Deploy-Unit"; + + public static final String NAME = "name"; + + public static final String HOST_NAME = "host-name"; + + // schema files + public static final String DESIGN_SCHEMA_XSD = "DesignSchema.xsd"; + + public static final String DEPLOY_SCHEMA_XSD = "DeploySchema.xsd"; + + //file extensions + public static final String IEDESIGN_FILE = "silecsdesign"; + + public static final String IEDEPLOY_FILE = "silecsdeploy"; + + //name patterns + public static final String DESIGN_PATTERN = "[A-Z][A-Za-z0-9_]*"; + + public static final String DEPLOY_PATTERN = "[A-Z][A-Za-z0-9_]*"; + + public static final int MAX_DESIGN_LENGTH = 12; + + public static final int MAX_DEPLOY_LENGTH = 20; + + public static final String CLASS_VERSION_PATTERN = "[0-9]*\\.[0-9]*\\.[0-9]*"; + + public static final String IEPLC_3_VERSION_PATTERN = "[0-9]*"; + + public static final String FULL_DESIGN_PATTERN = "[A-Z][A-Za-z0-9_]*[_][0-9]\\.[0-9]\\.[0-9]"; + + // SILECS versions which are supported by this plugin + public static final String[] SUPPORTED_SILECS_MAJOR_VERSIONS = { "1","DEV"}; + public static final List<String> ADDITIONAL_SILECS_TARGET_MIGRATION_VERSIONS = Arrays.asList("0.10.0"); //e.g. in order to allow migration from 0.9.0 to 0.10.0 + public static final int DEFAULT_SILECS_VERSION_INDEX = 0; + + // SILECS Versions which are NOT supported by this plugin + // All other versions foudn in the silecs-search path are supported + public static final String[] SILECS_VERSION_BLACKLIST = { "0.9.0" }; + + //Wizards + //New Design Wizard + public static final String NEW_DESIGN_WIZARD_TITLE = "New Design Wizard"; + public static final String NEW_DESIGN_PAGE_TITLE = "New Design Project"; + + //New Deploy Wizard + public static final String NEW_DEPLOY_WIZARD_TITLE = "New Deploy Wizard"; + public static final String NEW_DEPLOY_PAGE_TITLE = "New Deploy Project"; + + //New Class Wizard Page + + public static final String INVAILD_PROJECT_NAME= "Invaild project name. Project name must follow pattern:"; + + public static final String INITIAL_PROJECT_VERSION = "1.0.0"; + + //Generate Fesa Class Wizard + public static final String GENERATE_FESA_CLASS_WIZARD_TITLE = "Generate Fesa Class Wizard"; + public static final String GENERATE_FESA_CLASS_PAGE_TITLE = "Generate Fesa Class"; + + //Generate Client Resources Wizard + public static final String GENERATE_CLIENT_RESOURCES_WIZARD_TITLE = "Generate Client Resources Wizard"; + public static final String GENERATE_CLIENT_RESOURCES_PAGE_TITLE = "Generate Client Resources"; + + //Deliver Client Resources Wizard + public static final String DELIVER_CLIENT_RESOURCES_WIZARD_TITLE = "Deliver Client Resources Wizard"; + public static final String DELIVER_CLIENT_RESOURCES_PAGE_TITLE = "Deliver Client Resources"; + + //GSI-Hack Use GSI SILECS Wiki + //public static final String SILECS_WIKIS_PATH = "https://wikis.cern.ch/display/SIL"; + public static final String SILECS_WIKIS_PATH = "https://www-acc.gsi.de/wiki/Frontend/SILECS"; +} diff --git a/silecs-eclipse-plugin/src/java/cern/silecs/utils/SilecsUtils.java b/silecs-eclipse-plugin/src/java/cern/silecs/utils/SilecsUtils.java new file mode 100644 index 0000000..12d0376 --- /dev/null +++ b/silecs-eclipse-plugin/src/java/cern/silecs/utils/SilecsUtils.java @@ -0,0 +1,311 @@ +// Copyright 2016 CERN and GSI +// +// 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 3 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, see <http://www.gnu.org/licenses/>. + +package cern.silecs.utils; + +import java.io.File; +import java.net.URL; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; + +import org.eclipse.core.commands.ExecutionEvent; +import org.eclipse.core.commands.ExecutionException; +import org.eclipse.core.resources.IFile; +import org.eclipse.core.resources.IProject; +import org.eclipse.core.runtime.FileLocator; +import org.eclipse.core.runtime.IAdaptable; +import org.eclipse.core.runtime.Path; +import org.eclipse.core.runtime.Platform; +import org.eclipse.jface.viewers.ISelection; +import org.eclipse.jface.viewers.ITreeSelection; +import org.eclipse.jface.viewers.TreePath; +import org.eclipse.jface.viewers.TreeSelection; +import org.eclipse.swt.widgets.Display; +import org.eclipse.ui.IEditorDescriptor; +import org.eclipse.ui.IEditorPart; +import org.eclipse.ui.IFileEditorInput; +import org.eclipse.ui.IWorkbenchPage; +import org.eclipse.ui.IWorkbenchWindow; +import org.eclipse.ui.PlatformUI; +import org.eclipse.ui.handlers.HandlerUtil; +import org.eclipse.ui.part.FileEditorInput; +import org.w3c.dom.Document; +import org.w3c.dom.Node; + +import cern.silecs.activator.Activator; +import cern.silecs.control.core.DeployProjectNature; +import cern.silecs.control.core.DesignProjectNature; +import cern.silecs.model.exception.SilecsException; +import cern.silecs.view.console.ConsoleHandler; +import cern.silecs.view.preferences.MainPreferencePage; + +public class SilecsUtils { + + public static final String CLASS_VERSION_MATCHER = "version"; + + static public String userName; + static public boolean isWindows = false; + static { + String system = System.getProperty("os.name"); + isWindows = system.toLowerCase().contains("win"); + userName = System.getProperty("user.name"); + } + + public static String findInBundle(String resourceToLocate) { + try { + URL fileURL = FileLocator.find(Platform.getBundle(Activator.PLUGIN_ID), new Path(resourceToLocate), null); + fileURL = FileLocator.toFileURL(fileURL); + if(isWindows) + return fileURL.getPath().toString().substring(1); + + return fileURL.getPath().toString(); + } catch (Exception e1) { + e1.printStackTrace(); + } + return null; + } + + public static String getSilecsDesignFilePath(String workspacePath, String projectName) { + return workspacePath + "/" + projectName + "/" + getSilecsDesignFilePathRelative(projectName); + } + + public static String getSilecsDeployFilePath(String workspacePath, String projectName) { + return workspacePath + "/" + projectName + "/" + getSilecsDeployFilePathRelative(projectName); + } + + public static String getSilecsDesignFilePathRelative(String projectName) { + return "/src/" + projectName + "." + SilecsConstants.IEDESIGN_FILE; + } + + public static String getSilecsDeployFilePathRelative(String projectName){ + return "/src/" + projectName + "." + SilecsConstants.IEDEPLOY_FILE; + } + + public static Boolean isSilecsDesign(String filePath) + { + String extension = ""; + int i = filePath.lastIndexOf('.'); + if (i > 0) + extension = filePath.substring(i+1); + if(extension.equals(SilecsConstants.IEDESIGN_FILE) ) + return true; + return false; + } + + public static Boolean isSilecsDeploy(String filePath) + { + String extension = ""; + int i = filePath.lastIndexOf('.'); + if (i > 0) + extension = filePath.substring(i+1); + if(extension.equals(SilecsConstants.IEDEPLOY_FILE) ) + return true; + return false; + } + + public static IFile getSilecsDesignFile(IProject project) { + return project.getFile(getSilecsDesignFilePathRelative(project.getName())); + } + + public static IFile getSilecsDeployFile(IProject project) { + return project.getFile(getSilecsDeployFilePathRelative(project.getName())); + } + + public static IFile getSilecsDocument(IProject project) throws Exception + { + if ( project.hasNature(DesignProjectNature.NATURE_ID) ) + { + return SilecsUtils.getSilecsDesignFile(project); + } + else if( project.hasNature(DeployProjectNature.NATURE_ID) ) + { + return SilecsUtils.getSilecsDeployFile(project); + } + else + throw new Exception("The project: " + project.getName() + " is not a silecs-project"); + } + + public static String getSilecsVersion(IProject project) throws SilecsException { + String filePath = ""; + try + { + if( project.hasNature(DeployProjectNature.NATURE_ID) ) + { + filePath = getSilecsDeployFile(project).getRawLocation().makeAbsolute().toOSString(); + } + else if( project.hasNature(DesignProjectNature.NATURE_ID) ) + { + filePath = getSilecsDesignFile(project).getRawLocation().makeAbsolute().toOSString(); + } + else + { + throw new SilecsException("Faild to extract project nature from: " + project.getName()); + } + + DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance(); + DocumentBuilder dBuilder = dbFactory.newDocumentBuilder(); + Document doc = dBuilder.parse(filePath); + Node root; + if( project.hasNature(DesignProjectNature.NATURE_ID) ) + root = doc.getElementsByTagName("SILECS-Design").item(0); + else + root = doc.getElementsByTagName("SILECS-Deploy").item(0); + return root.getAttributes().getNamedItem("silecs-version").getTextContent(); + } + catch(Exception ex) + { + ConsoleHandler.printError("Faild to extract silecs-version from: " + filePath, true); + + throw new SilecsException("Faild to extract silecs-version from: " + filePath, ex); + } + } + + public static String getSilecsDesignVersion(String filePath) throws SilecsException { + try + { + DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance(); + DocumentBuilder dBuilder = dbFactory.newDocumentBuilder(); + Document doc = dBuilder.parse(filePath); + Node classNode = doc.getElementsByTagName("SILECS-Class").item(0); + return classNode.getAttributes().getNamedItem(CLASS_VERSION_MATCHER).getNodeValue(); + } + catch(Exception ex) + { + ConsoleHandler.printError("Faild to extract class-version from: " + filePath, true); + throw new SilecsException("Faild to extract class-version from: " + filePath, ex); + } + } + + public static String getDeployVersion(String filePath) throws SilecsException { + try + { + DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance(); + DocumentBuilder dBuilder = dbFactory.newDocumentBuilder(); + Document doc = dBuilder.parse(filePath); + Node deployNode = doc.getElementsByTagName("Deploy-Unit").item(0); + return deployNode.getAttributes().getNamedItem(CLASS_VERSION_MATCHER).getNodeValue(); + } + catch(Exception ex) + { + ConsoleHandler.printError("Faild to extract deploy-version from: " + filePath, true); + throw new SilecsException("Faild to extract deploy-version from: " + filePath, ex); + } + } + + public static void openInEditor(IFile file) + { + Display.getDefault().asyncExec(new Runnable() { + @Override + public void run() { + IEditorDescriptor desc = PlatformUI.getWorkbench().getEditorRegistry().getDefaultEditor(file.getName()); + IWorkbenchPage page = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage(); + try { + page.openEditor(new FileEditorInput(file), desc.getId()); + } catch (Exception e) { + ConsoleHandler.printError("Failed to open file:" + file, true); + e.printStackTrace(); + } + } + }); + } + + + public static void checkSilecsVersion(IProject project) throws SilecsException + { + String version = getSilecsVersion(project); + if( isSilecsVersionSupported(version) == false ) + { + throw new SilecsException("The old silecs version: '" + version + "' is not supported by this silecs-plugin. Please update your SILECS project to a more recent version (right-click --> SILECS Update Project)"); + } + } + + + public static Boolean isSilecsVersionSupported(String version) + { + for(String supportedVersion: SilecsConstants.SUPPORTED_SILECS_MAJOR_VERSIONS) + { + if(version.startsWith(supportedVersion)) + return true; + } + return false; + } + + public static List<String> readOutAvailableSilecsVersions() + { + List<String> silecsVersions = new ArrayList<String>(); + if (MainPreferencePage.isLocalDirectoryUsed()) + { + silecsVersions.add("DEV"); + return silecsVersions; + } + + // We just pick any sub-project + File silecsBaseFolder = new File(MainPreferencePage.getGlobalSilecsDirectory() + "/silecs-model"); + for (final File fileEntry : silecsBaseFolder.listFiles()) + { + silecsVersions.add(fileEntry.getName()); + } + Collections.sort(silecsVersions); + Collections.reverse(silecsVersions); + return silecsVersions; + } + + public static IFile extractSilecsFileFromEvent(ExecutionEvent event) throws Exception + { + String parameter = event.getParameter("silecs-eclipse-plugin.commandParameter"); + if ( parameter.equals("menubar")) + { + IWorkbenchWindow window = HandlerUtil.getActiveWorkbenchWindow(event); + IWorkbenchPage activePage = window.getActivePage(); + + // Get the Selection from the active WorkbenchPage page + ISelection selection = activePage.getSelection(); + if(selection instanceof ITreeSelection) // Event was triggered by right-click on project + { + TreeSelection treeSelection = (TreeSelection) selection; + TreePath[] treePaths = treeSelection.getPaths(); + TreePath treePath = treePaths[0]; + + // The first segment should be a IProject + Object firstSegmentObj = treePath.getFirstSegment(); + IProject theProject = (IProject) ((IAdaptable)firstSegmentObj).getAdapter(IProject.class); + if( theProject == null ) + { + ConsoleHandler.printError("Failed to find the right project", true); + throw new ExecutionException("Failed to find the right project"); + } + return getSilecsDocument(theProject); + } + } + if (parameter.equals("toolbar")) + { + // The default: the toolbar button was pressed + IEditorPart editor = HandlerUtil.getActiveEditor(event); + if (editor == null) + { + ConsoleHandler.printError("Failed to find active SILECS editor", true); + throw new Exception("Failed to find active SILECS editor"); + } + return ((IFileEditorInput) editor.getEditorInput()).getFile(); + } + String message = new String("Failed to find correct silecs-project/file - command: '" + event.getCommand().getName() + "' send with parameter: '" + parameter + "'."); + ConsoleHandler.printError(message, true); + throw new Exception(message); + } +} diff --git a/silecs-eclipse-plugin/src/java/cern/silecs/utils/XmlUtils.java b/silecs-eclipse-plugin/src/java/cern/silecs/utils/XmlUtils.java new file mode 100644 index 0000000..218810b --- /dev/null +++ b/silecs-eclipse-plugin/src/java/cern/silecs/utils/XmlUtils.java @@ -0,0 +1,188 @@ +// Copyright 2016 CERN and GSI +// +// 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 3 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, see <http://www.gnu.org/licenses/>. + +package cern.silecs.utils; + +import java.io.StringWriter; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +import javax.xml.transform.OutputKeys; +import javax.xml.transform.Transformer; +import javax.xml.transform.TransformerConfigurationException; +import javax.xml.transform.TransformerException; +import javax.xml.transform.TransformerFactory; +import javax.xml.transform.TransformerFactoryConfigurationError; +import javax.xml.transform.dom.DOMSource; +import javax.xml.transform.stream.StreamResult; + +import org.eclipse.jface.text.IDocument; +import org.eclipse.ui.IEditorPart; +import org.eclipse.ui.IEditorReference; +import org.eclipse.ui.IWorkbenchPage; +import org.eclipse.ui.IWorkbenchWindow; +import org.eclipse.ui.PlatformUI; +import org.eclipse.ui.texteditor.ITextEditor; +import org.eclipse.wst.sse.core.StructuredModelManager; +import org.eclipse.wst.sse.core.internal.provisional.IStructuredModel; +import org.eclipse.wst.xml.core.internal.contentmodel.modelquery.ModelQuery; +import org.eclipse.wst.xml.core.internal.contentmodel.modelqueryimpl.CMDocumentLoader; +import org.eclipse.wst.xml.core.internal.contentmodel.modelqueryimpl.InferredGrammarBuildingCMDocumentLoader; +import org.eclipse.wst.xml.core.internal.modelquery.ModelQueryUtil; + +import org.eclipse.wst.xml.core.internal.provisional.document.IDOMModel; +import org.w3c.dom.Attr; +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; + +@SuppressWarnings("restriction") +public class XmlUtils { + + private static TransformerFactory TRANSFORMER_FACTORY; + + public static String nodeToString(Node node) throws TransformerFactoryConfigurationError, TransformerException { + Transformer transformer = createPrettyTransformer(); + + // if given node is not a complete document, we do not + // put the xml declaration. we also omit if the document already has + // a type + if (!(node instanceof Document) || ((Document) node).getDoctype() != null) { + transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes"); + } + + // write node to string + DOMSource source = new DOMSource(node); + StringWriter writer = new StringWriter(); + StreamResult result = new StreamResult(writer); + transformer.transform(source, result); + + return writer.toString(); + } + + + private static Transformer createPrettyTransformer() throws TransformerConfigurationException, + TransformerFactoryConfigurationError { + if (TRANSFORMER_FACTORY == null) { + TRANSFORMER_FACTORY = TransformerFactory.newInstance(); + } + Transformer t = TRANSFORMER_FACTORY.newTransformer(); + t.setOutputProperty(OutputKeys.INDENT, "yes"); + t.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "4"); + + return t; + } + + public static String xPathFromNode(Node node) { + if (node == null) { + return ""; + } + + switch (node.getNodeType()) { + case Node.DOCUMENT_NODE: + return ""; + + case Node.ATTRIBUTE_NODE: + Attr attr = (Attr) node; + return xPathFromNode(attr.getOwnerElement()) + "/@" + attr.getName(); + + case Node.ELEMENT_NODE: + Element elem = (Element) node; + Node parent = elem.getParentNode(); + String name = elem.getTagName(); + NodeList childs = parent.getChildNodes(); + + int index = 1; + for (int i = 0; i < childs.getLength(); i++) { + Node n = childs.item(i); + if (n.equals(elem)) { + // first element in xPath is 1, not 0 + return xPathFromNode(parent) + "/" + node.getNodeName() + "[" + index + "]"; + } else if (n instanceof Element && n.getNodeName().equals(name)) { + // there is another element with the same name before in the list + index++; + } + } + + default: + throw new IllegalStateException("Unexpected Node type: " + node.getNodeType()); + } + } + + /** + * Return the string contained in the string builder. Remove the ending if equals to the parameter (use for joining + * strings in loops) + * + * @param stringBuilder + * @param endingToRemove + * @return + */ + public static String finalize(StringBuilder stringBuilder, String endingToRemove) { + if (stringBuilder == null) { + throw new IllegalArgumentException("stringBuilder cannot be null"); + } else if (endingToRemove == null) { + throw new IllegalArgumentException("endingToRemove cannot be null"); + } + + int length = stringBuilder.length(); + int endingLength = endingToRemove.length(); + if (length > endingLength && stringBuilder.substring(length - endingLength).equals(endingToRemove)) { + return stringBuilder.substring(0, length - endingLength); + } else { + return stringBuilder.toString(); + } + } + + public static void reloadDependencies() { + List<IEditorReference> editors = new ArrayList<>(); + for (IWorkbenchWindow window : PlatformUI.getWorkbench().getWorkbenchWindows()) { + for (IWorkbenchPage page : window.getPages()) { + editors.addAll(Arrays.asList(page.getEditorReferences())); + } + } + + for (IEditorReference er : editors) { + IEditorPart editor = er.getEditor(false); + ITextEditor textEditor = null; + if (editor instanceof ITextEditor) + textEditor = (ITextEditor) editor; + else if (editor != null) { + Object o = editor.getAdapter(ITextEditor.class); + if (o != null) + textEditor = (ITextEditor) o; + } + if (textEditor != null) { + IDocument document = textEditor.getDocumentProvider().getDocument(textEditor.getEditorInput()); + IStructuredModel model = StructuredModelManager.getModelManager().getExistingModelForRead(document); + if (model != null) { + ModelQuery modelQuery = null; + try { + modelQuery = ModelQueryUtil.getModelQuery(model); + } finally { + model.releaseFromRead(); + } + Document domDocument = ((IDOMModel) model).getDocument(); + if ((modelQuery != null) && (modelQuery.getCMDocumentManager() != null)) { + modelQuery.getCMDocumentManager().getCMDocumentCache().clear(); + CMDocumentLoader loader = new InferredGrammarBuildingCMDocumentLoader(domDocument, modelQuery); + loader.loadCMDocuments(); + } + } + } + } + } +} diff --git a/silecs-eclipse-plugin/src/java/cern/silecs/view/Application.java b/silecs-eclipse-plugin/src/java/cern/silecs/view/Application.java new file mode 100644 index 0000000..b74bc99 --- /dev/null +++ b/silecs-eclipse-plugin/src/java/cern/silecs/view/Application.java @@ -0,0 +1,68 @@ +// Copyright 2016 CERN and GSI +// +// 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 3 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, see <http://www.gnu.org/licenses/>. + +package cern.silecs.view; + +import org.eclipse.equinox.app.IApplication; +import org.eclipse.equinox.app.IApplicationContext; +import org.eclipse.swt.widgets.Display; +import org.eclipse.ui.IWorkbench; +import org.eclipse.ui.PlatformUI; + +/** + * This class controls all aspects of the application's execution + */ +public class Application implements IApplication { + + /* (non-Javadoc) + * @see org.eclipse.equinox.app.IApplication#start(org.eclipse.equinox.app.IApplicationContext) + */ + @Override + public Object start(IApplicationContext context) throws Exception { + Display display = PlatformUI.createDisplay(); + + // Displaying ChooseWorkspace Dialog and then assigning new workspace to the application + // Add "-data @noDefault" to PROGRAM ARGUMENTS to make workspace choosing working + + try { + int returnCode = PlatformUI.createAndRunWorkbench(display, new ApplicationWorkbenchAdvisor()); + if (returnCode == PlatformUI.RETURN_RESTART) + return IApplication.EXIT_RESTART; + else + return IApplication.EXIT_OK; + } finally { + display.dispose(); + } + + } + + /* (non-Javadoc) + * @see org.eclipse.equinox.app.IApplication#stop() + */ + @Override + public void stop() { + if (!PlatformUI.isWorkbenchRunning()) + return; + final IWorkbench workbench = PlatformUI.getWorkbench(); + final Display display = workbench.getDisplay(); + display.syncExec(new Runnable() { + @Override + public void run() { + if (!display.isDisposed()) + workbench.close(); + } + }); + } +} diff --git a/silecs-eclipse-plugin/src/java/cern/silecs/view/ApplicationActionBarAdvisor.java b/silecs-eclipse-plugin/src/java/cern/silecs/view/ApplicationActionBarAdvisor.java new file mode 100644 index 0000000..8ff8da6 --- /dev/null +++ b/silecs-eclipse-plugin/src/java/cern/silecs/view/ApplicationActionBarAdvisor.java @@ -0,0 +1,27 @@ +// Copyright 2016 CERN and GSI +// +// 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 3 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, see <http://www.gnu.org/licenses/>. + +package cern.silecs.view; + + +import org.eclipse.ui.application.ActionBarAdvisor; +import org.eclipse.ui.application.IActionBarConfigurer; + +public class ApplicationActionBarAdvisor extends ActionBarAdvisor { + + public ApplicationActionBarAdvisor(IActionBarConfigurer configurer) { + super(configurer); + } +} diff --git a/silecs-eclipse-plugin/src/java/cern/silecs/view/ApplicationWorkbenchAdvisor.java b/silecs-eclipse-plugin/src/java/cern/silecs/view/ApplicationWorkbenchAdvisor.java new file mode 100644 index 0000000..ed4ba23 --- /dev/null +++ b/silecs-eclipse-plugin/src/java/cern/silecs/view/ApplicationWorkbenchAdvisor.java @@ -0,0 +1,120 @@ +// Copyright 2016 CERN and GSI +// +// 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 3 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, see <http://www.gnu.org/licenses/>. + +package cern.silecs.view; + +import java.net.URL; +import java.net.URLClassLoader; + +import org.eclipse.core.resources.IProject; +import org.eclipse.core.resources.IResource; +import org.eclipse.core.resources.IResourceChangeEvent; +import org.eclipse.core.resources.IResourceChangeListener; +import org.eclipse.core.resources.IResourceDelta; +import org.eclipse.core.resources.ResourcesPlugin; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IAdaptable; +import org.eclipse.ui.IWorkbenchPreferenceConstants; +import org.eclipse.ui.PlatformUI; +import org.eclipse.ui.application.IWorkbenchConfigurer; +import org.eclipse.ui.application.IWorkbenchWindowConfigurer; +import org.eclipse.ui.application.WorkbenchAdvisor; +import org.eclipse.ui.application.WorkbenchWindowAdvisor; +import org.eclipse.ui.ide.IDE; + +import cern.silecs.utils.OSExecute; +import cern.silecs.utils.SilecsConstants; +import cern.silecs.utils.XmlUtils; +import cern.silecs.view.console.ConsoleHandler; + +/** + * In this class a lot of initialization takes place because this is the point when workbench is already created. + */ +public class ApplicationWorkbenchAdvisor extends WorkbenchAdvisor { + + private static final String PERSPECTIVE_ID = "silecs.eclipse.plugin.perspective"; //$NON-NLS-1$ + + @Override + public WorkbenchWindowAdvisor createWorkbenchWindowAdvisor(IWorkbenchWindowConfigurer configurer) { + return new ApplicationWorkbenchWindowAdvisor(configurer); + } + + @Override + public String getInitialWindowPerspectiveId() { + return PERSPECTIVE_ID; + } + + @Override + public void initialize(IWorkbenchConfigurer configurer) { + super.initialize(configurer); + + configurer.setSaveAndRestore(true); + PlatformUI.getPreferenceStore().setValue(IWorkbenchPreferenceConstants.SHOW_TRADITIONAL_STYLE_TABS, false); + + IDE.registerAdapters(); + + addGenerateClassEnumListener(); + } + + @Override + public IAdaptable getDefaultPageInput() { + return ResourcesPlugin.getWorkspace().getRoot(); + } + + public void printClassPath() { + ClassLoader cl = ClassLoader.getSystemClassLoader(); + + URL[] urls = ((URLClassLoader)cl).getURLs(); + + for(URL url: urls){ + System.out.println(url.getFile()); + } + } + + /** + * This methods adds a listener that should regenerate class enum whenever design project is deleted + */ + private void addGenerateClassEnumListener() { + + ResourcesPlugin.getWorkspace().addResourceChangeListener(new IResourceChangeListener() { + @Override + public void resourceChanged(IResourceChangeEvent event) { + IResourceDelta rootDelta = event.getDelta(); + try { + rootDelta.accept(delta -> { + IResource resource = delta.getResource(); + + // make sure that the project has been removed and it was a design project + if (resource instanceof IProject + && (delta.getKind() == IResourceDelta.REMOVED || delta.getKind() == IResourceDelta.ADDED) + && resource.getName().matches(SilecsConstants.FULL_DESIGN_PATTERN)) { + try { + XmlUtils.reloadDependencies(); + } catch (Exception e) { + e.printStackTrace(); + } + + return false; + + } + return true; + }); + } catch (CoreException e) { + e.printStackTrace(); + } + } + }, IResourceChangeEvent.POST_CHANGE); + } +} diff --git a/silecs-eclipse-plugin/src/java/cern/silecs/view/ApplicationWorkbenchWindowAdvisor.java b/silecs-eclipse-plugin/src/java/cern/silecs/view/ApplicationWorkbenchWindowAdvisor.java new file mode 100644 index 0000000..c41468e --- /dev/null +++ b/silecs-eclipse-plugin/src/java/cern/silecs/view/ApplicationWorkbenchWindowAdvisor.java @@ -0,0 +1,179 @@ +// Copyright 2016 CERN and GSI +// +// 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 3 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, see <http://www.gnu.org/licenses/>. + +package cern.silecs.view; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +import org.eclipse.core.resources.IFile; +import org.eclipse.core.resources.ResourcesPlugin; +import org.eclipse.swt.graphics.Point; +import org.eclipse.ui.IEditorPart; +import org.eclipse.ui.IFileEditorInput; +import org.eclipse.ui.IPartListener; +import org.eclipse.ui.IWorkbench; +import org.eclipse.ui.IWorkbenchPage; +import org.eclipse.ui.IWorkbenchPart; +import org.eclipse.ui.PlatformUI; +import org.eclipse.ui.application.ActionBarAdvisor; +import org.eclipse.ui.application.IActionBarConfigurer; +import org.eclipse.ui.application.IWorkbenchWindowConfigurer; +import org.eclipse.ui.application.WorkbenchWindowAdvisor; +import org.eclipse.ui.internal.dialogs.WorkbenchWizardElement; +import org.eclipse.ui.internal.wizards.AbstractExtensionWizardRegistry; +import org.eclipse.ui.wizards.IWizardCategory; +import org.eclipse.ui.wizards.IWizardDescriptor; + +import cern.silecs.utils.SilecsConstants; + +@SuppressWarnings("restriction") +public class ApplicationWorkbenchWindowAdvisor extends WorkbenchWindowAdvisor { + + public ApplicationWorkbenchWindowAdvisor(IWorkbenchWindowConfigurer configurer) { + super(configurer); + } + + @Override + public ActionBarAdvisor createActionBarAdvisor(IActionBarConfigurer configurer) { + return new ApplicationActionBarAdvisor(configurer); + } + + @Override + public void preWindowOpen() { + IWorkbenchWindowConfigurer configurer = getWindowConfigurer(); + configurer.setInitialSize(new Point(700, 500)); + configurer.setShowCoolBar(true); + configurer.setShowStatusLine(true); + configurer.setTitle(SilecsConstants.SILECS_NAME); //$NON-NLS-1$ + configurer.setShowProgressIndicator(true); + } + + @Override + public void postWindowOpen() { + super.postWindowOpen(); + + addChangedEditorListener(); + + // removing unnecessary wizards from new and import menu. + AbstractExtensionWizardRegistry wizardRegistry = (AbstractExtensionWizardRegistry) PlatformUI.getWorkbench() + .getNewWizardRegistry(); + IWizardCategory[] categories = PlatformUI.getWorkbench().getNewWizardRegistry().getRootCategory() + .getCategories(); + + for (IWizardDescriptor wizard : getAllWizards(categories)) { + if (wizard.getCategory().getId().matches("org.eclipse.ui.Basic")) { + WorkbenchWizardElement wizardElement = (WorkbenchWizardElement) wizard; + wizardRegistry.removeExtension(wizardElement.getConfigurationElement().getDeclaringExtension(), + new Object[] { wizardElement }); + } else if (wizard.getCategory().getId().matches("org.eclipse.wst.xml.examples")) { + WorkbenchWizardElement wizardElement = (WorkbenchWizardElement) wizard; + wizardRegistry.removeExtension(wizardElement.getConfigurationElement().getDeclaringExtension(), + new Object[] { wizardElement }); + } else if (wizard.getCategory().getId().matches("org.eclipse.wst.XMLCategory")) { + WorkbenchWizardElement wizardElement = (WorkbenchWizardElement) wizard; + wizardRegistry.removeExtension(wizardElement.getConfigurationElement().getDeclaringExtension(), + new Object[] { wizardElement }); + } else if (wizard.getCategory().getId().matches("org.eclipse.cdt.ui.newCWizards")) { + WorkbenchWizardElement wizardElement = (WorkbenchWizardElement) wizard; + wizardRegistry.removeExtension(wizardElement.getConfigurationElement().getDeclaringExtension(), + new Object[] { wizardElement }); + } + + } + + wizardRegistry = (AbstractExtensionWizardRegistry) PlatformUI.getWorkbench().getImportWizardRegistry(); + + categories = PlatformUI.getWorkbench().getImportWizardRegistry().getRootCategory().getCategories(); + + for (IWizardDescriptor wizard : getAllWizards(categories)) { + if (wizard.getCategory().getId().matches("org.eclipse.cdt.ui.importWizardCategory")) { + WorkbenchWizardElement wizardElement = (WorkbenchWizardElement) wizard; + wizardRegistry.removeExtension(wizardElement.getConfigurationElement().getDeclaringExtension(), + new Object[] { wizardElement }); + } else if (wizard.getCategory().getId().matches("org.eclipse.debug.ui")) { + WorkbenchWizardElement wizardElement = (WorkbenchWizardElement) wizard; + wizardRegistry.removeExtension(wizardElement.getConfigurationElement().getDeclaringExtension(), + new Object[] { wizardElement }); + } else if (wizard.getCategory().getId().matches("org.eclipse.wst.XMLCategory")) { + WorkbenchWizardElement wizardElement = (WorkbenchWizardElement) wizard; + wizardRegistry.removeExtension(wizardElement.getConfigurationElement().getDeclaringExtension(), + new Object[] { wizardElement }); + } else if (wizard.getCategory().getId().matches("org.eclipse.team.ui.importWizards")) { + WorkbenchWizardElement wizardElement = (WorkbenchWizardElement) wizard; + wizardRegistry.removeExtension(wizardElement.getConfigurationElement().getDeclaringExtension(), + new Object[] { wizardElement }); + } + } + } + + private IWizardDescriptor[] getAllWizards(IWizardCategory[] categories) { + List<IWizardDescriptor> results = new ArrayList<IWizardDescriptor>(); + for (IWizardCategory wizardCategory : categories) { + results.addAll(Arrays.asList(wizardCategory.getWizards())); + results.addAll(Arrays.asList(getAllWizards(wizardCategory.getCategories()))); + } + return results.toArray(new IWizardDescriptor[0]); + } + + private void addChangedEditorListener() { + IWorkbench workbench = PlatformUI.getWorkbench(); + IWorkbenchPage page = workbench.getActiveWorkbenchWindow().getActivePage(); + page.addPartListener(new IPartListener() { + + @Override + public void partOpened(IWorkbenchPart part) { + setApplicationTitle(); + } + + @Override + public void partDeactivated(IWorkbenchPart part) { + setApplicationTitle(); + } + + @Override + public void partClosed(IWorkbenchPart part) { + setApplicationTitle(); + } + + @Override + public void partBroughtToTop(IWorkbenchPart part) { + setApplicationTitle(); + } + + @Override + public void partActivated(IWorkbenchPart part) { + setApplicationTitle(); + } + + private void setApplicationTitle() { + IEditorPart editorPart = page.getActiveEditor(); + IWorkbenchWindowConfigurer configurer = getWindowConfigurer(); + + if (editorPart != null) { + IFileEditorInput editorInput = (IFileEditorInput) editorPart.getEditorInput(); + IFile file = editorInput.getFile(); + + configurer.setTitle(file.getFullPath() + " - " + SilecsConstants.SILECS_NAME + " - " + + ResourcesPlugin.getWorkspace()); + } else { + configurer.setTitle(SilecsConstants.SILECS_NAME + " - " + ResourcesPlugin.getWorkspace() ); + } + } + }); + + } +} diff --git a/silecs-eclipse-plugin/src/java/cern/silecs/view/Perspective.java b/silecs-eclipse-plugin/src/java/cern/silecs/view/Perspective.java new file mode 100644 index 0000000..2404834 --- /dev/null +++ b/silecs-eclipse-plugin/src/java/cern/silecs/view/Perspective.java @@ -0,0 +1,28 @@ +// Copyright 2016 CERN and GSI +// +// 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 3 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, see <http://www.gnu.org/licenses/>. + +package cern.silecs.view; + +import org.eclipse.ui.IPageLayout; +import org.eclipse.ui.IPerspectiveFactory; + +public class Perspective implements IPerspectiveFactory { + + @Override + public void createInitialLayout(IPageLayout layout) { + // TODO Auto-generated method stub + + } +} diff --git a/silecs-eclipse-plugin/src/java/cern/silecs/view/console/ConsoleHandler.java b/silecs-eclipse-plugin/src/java/cern/silecs/view/console/ConsoleHandler.java new file mode 100644 index 0000000..454b9d5 --- /dev/null +++ b/silecs-eclipse-plugin/src/java/cern/silecs/view/console/ConsoleHandler.java @@ -0,0 +1,109 @@ +// Copyright 2016 CERN and GSI +// +// 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 3 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, see <http://www.gnu.org/licenses/>. + +package cern.silecs.view.console; + +import org.eclipse.swt.SWT; +import org.eclipse.swt.widgets.Display; +import org.eclipse.ui.console.ConsolePlugin; +import org.eclipse.ui.console.IConsole; +import org.eclipse.ui.console.MessageConsole; +import org.eclipse.ui.console.MessageConsoleStream; + +public class ConsoleHandler { + + private static MessageConsole console; + private static MessageConsoleStream messageStream; + private static MessageConsoleStream errorStream; + private static MessageConsoleStream warningStream; + + static { + console = new MessageConsole("Console", null); + ConsolePlugin.getDefault().getConsoleManager().addConsoles(new IConsole[] { console }); + + messageStream = console.newMessageStream(); + errorStream = console.newMessageStream(); + warningStream = console.newMessageStream(); + + final Display display = Display.getDefault(); + Display.getDefault().asyncExec(new Runnable() + { + public void run() + { + errorStream.setColor(display.getSystemColor(SWT.COLOR_RED)); + warningStream.setColor(display.getSystemColor(SWT.COLOR_DARK_YELLOW)); + } + }); + } + + public static void clear() { + console.clearConsole(); + } + + /** + * Prints message in the silecs console. + * + * @param message Message to appear in the console + * @param activateOnWrite determines whether to activate the console + */ + public static void printMessage(String message, boolean activateOnWrite) { + messageStream.setActivateOnWrite(activateOnWrite); + messageStream.println(message); + } + + /** + * Prints error message in the silecs console. + * + * @param Error message to appear in the console + * @param activateOnWrite determines whether to activate the console + */ + public static void printError(String message, boolean activateOnWrite) { + errorStream.setActivateOnWrite(activateOnWrite); + errorStream.println(message); + } + + + private static void printTrace(Throwable ex) { + if( ex == null) + return; + StackTraceElement[] stacktrace = ex.getStackTrace(); + + for(int i=1; i<stacktrace.length; i++){ + errorStream.println(stacktrace[i].toString()); + } + } + + public static void printStackTrace(Exception ex) { + errorStream.println(ex.getLocalizedMessage()); + errorStream.println("Stacktrace: "); + printTrace(ex); + errorStream.println("Caused by: "); + printTrace(ex.getCause()); + errorStream.setActivateOnWrite(true); + } + + + /** + * Prints error message in the silecs console. + * + * @param Warning message to appear in the console + * @param activateOnWrite determines whether to activate the console + */ + public static void printWarning(String message, boolean activateOnWrite) { + warningStream.setActivateOnWrite(activateOnWrite); + warningStream.println(message); + } + +} diff --git a/silecs-eclipse-plugin/src/java/cern/silecs/view/dialogs/SilecsMessageDialog.java b/silecs-eclipse-plugin/src/java/cern/silecs/view/dialogs/SilecsMessageDialog.java new file mode 100644 index 0000000..d9ea685 --- /dev/null +++ b/silecs-eclipse-plugin/src/java/cern/silecs/view/dialogs/SilecsMessageDialog.java @@ -0,0 +1,48 @@ +// Copyright 2016 CERN and GSI +// +// 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 3 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, see <http://www.gnu.org/licenses/>. + +package cern.silecs.view.dialogs; + +import org.eclipse.jface.dialogs.MessageDialog; +import org.eclipse.swt.graphics.Image; +import org.eclipse.swt.widgets.Shell; +import org.eclipse.ui.PlatformUI; + +import cern.silecs.utils.SilecsUtils; + +/** + * This class adds Silecs logo to jface Message Dialog. + * @see MessageDialog + */ +public class SilecsMessageDialog extends MessageDialog{ + + private Image image = null; + + /** + * @see MessageDialog#MessageDialog(Shell, String, Image, String, int, String[], int) + */ + public SilecsMessageDialog(Shell parentShell, String dialogTitle, Image dialogTitleImage, String dialogMessage, + int dialogImageType, String[] dialogButtonLabels, int defaultIndex) { + super(parentShell, dialogTitle, dialogTitleImage, dialogMessage, dialogImageType, dialogButtonLabels, defaultIndex); + + String imagePath = SilecsUtils.findInBundle("icons/silecs-logo.ico"); + image = new Image(PlatformUI.getWorkbench().getDisplay(), imagePath); + } + + @Override + public Image getImage() { + return image; + } +} \ No newline at end of file diff --git a/silecs-eclipse-plugin/src/java/cern/silecs/view/editor/DeployMultiPageEditor.java b/silecs-eclipse-plugin/src/java/cern/silecs/view/editor/DeployMultiPageEditor.java new file mode 100644 index 0000000..e1d4967 --- /dev/null +++ b/silecs-eclipse-plugin/src/java/cern/silecs/view/editor/DeployMultiPageEditor.java @@ -0,0 +1,25 @@ +// Copyright 2016 CERN and GSI +// +// 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 3 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, see <http://www.gnu.org/licenses/>. + +package cern.silecs.view.editor; + +public class DeployMultiPageEditor extends XMLMultiPageEditor { + + public static String ID = "cern.silecs.view.editors.deploy"; + public DeployMultiPageEditor() { + super(); + } + +} diff --git a/silecs-eclipse-plugin/src/java/cern/silecs/view/editor/DesignMultiPageEditor.java b/silecs-eclipse-plugin/src/java/cern/silecs/view/editor/DesignMultiPageEditor.java new file mode 100644 index 0000000..f8f5711 --- /dev/null +++ b/silecs-eclipse-plugin/src/java/cern/silecs/view/editor/DesignMultiPageEditor.java @@ -0,0 +1,25 @@ +// Copyright 2016 CERN and GSI +// +// 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 3 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, see <http://www.gnu.org/licenses/>. + +package cern.silecs.view.editor; + +public class DesignMultiPageEditor extends XMLMultiPageEditor { + + public static String ID = "cern.silecs.view.editors.design"; + public DesignMultiPageEditor() { + super(); + } + +} diff --git a/silecs-eclipse-plugin/src/java/cern/silecs/view/editor/XMLMultiPageEditor.java b/silecs-eclipse-plugin/src/java/cern/silecs/view/editor/XMLMultiPageEditor.java new file mode 100644 index 0000000..1ca464a --- /dev/null +++ b/silecs-eclipse-plugin/src/java/cern/silecs/view/editor/XMLMultiPageEditor.java @@ -0,0 +1,169 @@ +// Copyright 2016 CERN and GSI +// +// 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 3 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, see <http://www.gnu.org/licenses/>. + +package cern.silecs.view.editor; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +import org.eclipse.core.resources.IFile; +import org.eclipse.core.resources.IResourceChangeEvent; +import org.eclipse.core.resources.ResourcesPlugin; + +import org.eclipse.jface.text.BadLocationException; +import org.eclipse.jface.text.IDocument; +import org.eclipse.jface.text.IRegion; +import org.eclipse.jface.text.ITextViewer; +import org.eclipse.swt.layout.GridData; +import org.eclipse.ui.IEditorInput; +import org.eclipse.ui.IEditorPart; +import org.eclipse.ui.IEditorReference; +import org.eclipse.ui.IEditorSite; +import org.eclipse.ui.IFileEditorInput; +import org.eclipse.ui.IWorkbenchPage; +import org.eclipse.ui.IWorkbenchWindow; +import org.eclipse.ui.PartInitException; +import org.eclipse.ui.PlatformUI; +import org.eclipse.wst.sse.ui.StructuredTextEditor; +import org.eclipse.wst.sse.ui.internal.contentassist.ContentAssistUtils; +import org.eclipse.wst.xml.core.internal.document.NodeImpl; +import org.eclipse.wst.xml.ui.internal.XMLUIPlugin; +import org.eclipse.wst.xml.ui.internal.tabletree.IDesignViewer; +import org.eclipse.wst.xml.ui.internal.tabletree.XMLMultiPageEditorPart; +import org.eclipse.wst.xml.ui.internal.tabletree.XMLTableTreeHelpContextIds; +import org.eclipse.core.runtime.IProgressMonitor; + +import cern.silecs.view.console.ConsoleHandler; +import cern.silecs.view.editor.internal.SilecsXMLTableTreeViewer; +import cern.silecs.view.job.ValidationJob; + +@SuppressWarnings("restriction") +public class XMLMultiPageEditor extends XMLMultiPageEditorPart { + + SilecsXMLTableTreeViewer xmlTableTreeViewer; + + public XMLMultiPageEditor() { + super(); + } + + @Override + public void init(IEditorSite site, IEditorInput input) throws PartInitException { + super.init(site, input); + + // useless to instantiate toolbar since not used + noToolbar(); + } + + @Override + public void dispose() { + ResourcesPlugin.getWorkspace().removeResourceChangeListener(xmlTableTreeViewer); + super.dispose(); + } + + @Override + protected void createPages() { + super.createPages(); + + // add itself as resource change listener + ResourcesPlugin.getWorkspace().addResourceChangeListener(xmlTableTreeViewer, IResourceChangeEvent.POST_CHANGE); + } + + @Override + protected IDesignViewer createDesignPage() { + xmlTableTreeViewer = new SilecsXMLTableTreeViewer(getContainer(), this); + xmlTableTreeViewer.getControl().setLayoutData(new GridData(GridData.FILL_BOTH)); + + // Set the default info-pop for XML design viewer. + XMLUIPlugin.getInstance().getWorkbench().getHelpSystem() + .setHelp(xmlTableTreeViewer.getControl(), XMLTableTreeHelpContextIds.XML_DESIGN_VIEW_HELPID); + + return xmlTableTreeViewer; + } + + public IDocument getDocument() { + IDocument document = null; + StructuredTextEditor textEditor = (StructuredTextEditor) getAdapter(StructuredTextEditor.class); + if (textEditor != null) { + document = textEditor.getDocumentProvider().getDocument(textEditor.getEditorInput()); + } + + return document; + } + + public static XMLMultiPageEditor getOpenedEditor(IFile file) { + + // get all the opened editors + List<IEditorReference> editors = new ArrayList<>(); + for (IWorkbenchWindow window : PlatformUI.getWorkbench().getWorkbenchWindows()) { + for (IWorkbenchPage page : window.getPages()) { + editors.addAll(Arrays.asList(page.getEditorReferences())); + } + } + + for (IEditorReference er : editors) { + IEditorPart editor = er.getEditor(false); + try { + IEditorInput editorInput = er.getEditorInput(); + if (editor instanceof XMLMultiPageEditor && editorInput instanceof IFileEditorInput) { + IFileEditorInput input = (IFileEditorInput) editorInput; + + if (input.getFile().equals(file)) { + return (XMLMultiPageEditor) editor; + } + } + } catch (PartInitException e) { + e.printStackTrace(); + } + } + return null; + } + + + public NodeImpl getNodeAtPosition(int line, int column) { + try { + // line 1 is considered as line 0 by eclipse + // same for columns + if (line > 0) { + IRegion region = getDocument().getLineInformation(line - 1); + ITextViewer viewer = ((StructuredTextEditor) getAdapter(StructuredTextEditor.class)).getTextViewer(); + return (NodeImpl) ContentAssistUtils.getNodeAt(viewer, region.getOffset() + column - 2); + } + } catch (BadLocationException e) { + e.printStackTrace(); + } + + return null; + } + + @Override + public void doSave(IProgressMonitor monitor) + { + IEditorInput editorInput = getEditorInput(); + if (editorInput instanceof IFileEditorInput) + { + IFile fesaFile = ((IFileEditorInput) editorInput).getFile(); + + super.doSave(monitor); + + ConsoleHandler.printMessage("Validating XML ...", true); + ValidationJob job; + job = new ValidationJob(fesaFile); + job.schedule(); + } + } + + +} diff --git a/silecs-eclipse-plugin/src/java/cern/silecs/view/editor/internal/SchemaHelper.java b/silecs-eclipse-plugin/src/java/cern/silecs/view/editor/internal/SchemaHelper.java new file mode 100644 index 0000000..0754660 --- /dev/null +++ b/silecs-eclipse-plugin/src/java/cern/silecs/view/editor/internal/SchemaHelper.java @@ -0,0 +1,58 @@ +// Copyright 2016 CERN and GSI +// +// 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 3 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, see <http://www.gnu.org/licenses/>. + +package cern.silecs.view.editor.internal; + +import java.util.Collections; +import java.util.List; + +import org.eclipse.wst.xml.core.internal.contentmodel.CMElementDeclaration; +import org.eclipse.wst.xml.core.internal.document.CMNodeUtil; +import org.eclipse.wst.xsd.contentmodel.internal.XSDImpl.XSDElementDeclarationAdapter; +import org.eclipse.xsd.XSDElementDeclaration; +import org.eclipse.xsd.XSDIdentityConstraintDefinition; +import org.w3c.dom.Element; + +@SuppressWarnings("restriction") +public abstract class SchemaHelper { + + public static List<XSDIdentityConstraintDefinition> findIdentityConstraints(Element element) { + CMElementDeclaration elemDecl = CMNodeUtil.getElementDeclaration(element); + if (elemDecl instanceof XSDElementDeclarationAdapter) { + XSDElementDeclarationAdapter xsdElemAdapt = (XSDElementDeclarationAdapter) elemDecl; + XSDElementDeclaration xsdElementDecl = (XSDElementDeclaration) xsdElemAdapt.getKey(); + + // get all the key constraints definitions + List<XSDIdentityConstraintDefinition> constraints = xsdElementDecl.getResolvedElementDeclaration() + .getIdentityConstraintDefinitions(); + constraints.addAll(xsdElementDecl.getResolvedElementDeclaration().getIdentityConstraintDefinitions()); + + return constraints; + } else { + return Collections.emptyList(); + } + } + + public static XSDIdentityConstraintDefinition findIdentityConstraint(Element element, String constraintName) { + List<XSDIdentityConstraintDefinition> constraints = findIdentityConstraints(element); + for (XSDIdentityConstraintDefinition c : constraints) { + if (c.getName().equals(constraintName)) { + return c; + } + } + + return null; + } +} diff --git a/silecs-eclipse-plugin/src/java/cern/silecs/view/editor/internal/SilecsTableColumnViewerLabelProvider.java b/silecs-eclipse-plugin/src/java/cern/silecs/view/editor/internal/SilecsTableColumnViewerLabelProvider.java new file mode 100644 index 0000000..75fd12b --- /dev/null +++ b/silecs-eclipse-plugin/src/java/cern/silecs/view/editor/internal/SilecsTableColumnViewerLabelProvider.java @@ -0,0 +1,181 @@ +// Copyright 2016 CERN and GSI +// +// 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 3 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, see <http://www.gnu.org/licenses/>. + +package cern.silecs.view.editor.internal; + +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; + +import org.eclipse.core.resources.IMarker; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.jface.viewers.CellLabelProvider; +import org.eclipse.jface.viewers.LabelProviderChangedEvent; +import org.eclipse.jface.viewers.ViewerCell; +import org.eclipse.swt.SWT; +import org.eclipse.swt.graphics.Color; +import org.eclipse.swt.graphics.Point; +import org.eclipse.swt.widgets.Display; +import org.eclipse.wst.xml.ui.internal.tabletree.XMLTableTreeContentProvider; +import org.w3c.dom.Node; + +import cern.silecs.utils.XmlUtils; + + +/** + * Label provider for the design view of the FesaEditor + */ +@SuppressWarnings("restriction") +public class SilecsTableColumnViewerLabelProvider extends CellLabelProvider { + + private static final int TOOLTIP_DELAY_MS = 500; + + // since we could not have multiple inheritance in java, + // we inject the base label provider in this CellLabelProvider + // which adds support for tool-tips in the registered treeViewer + private final XMLTableTreeContentProvider baseLabelProvider; + + // These 2 maps behave like a bidirectional map + // marker -> node + // node -> Set<marker> + private final Map<IMarker, Node> markerToNode = new HashMap<>(); + private final Map<Node, Set<IMarker>> nodeToMarkers = new HashMap<>(); + + public SilecsTableColumnViewerLabelProvider(XMLTableTreeContentProvider baseLabelProvider) { + this.baseLabelProvider = baseLabelProvider; + } + + /** + * Register an error/warning with its associated node + * Fire a label provider changed event + * + * @param marker + * @param node + */ + public void addFault(IMarker marker, Node node) { + markerToNode.put(marker, node); + if (nodeToMarkers.containsKey(node)) { + nodeToMarkers.get(node).add(marker); + } else { + Set<IMarker> markers = new HashSet<>(); + markers.add(marker); + nodeToMarkers.put(node, markers); + } + + fireLabelProviderChanged(new LabelProviderChangedEvent(this, node)); + } + + /** + * Remove the marker and its associated node from the faulty list + * Fire a label provider changed event + * + * @param marker + */ + public void removeFault(IMarker marker) { + Node node = markerToNode.remove(marker); + if (node != null) { + Set<IMarker> markers = nodeToMarkers.get(node); + markers.remove(marker); + if (markers.isEmpty()) { + nodeToMarkers.remove(node); + } + fireLabelProviderChanged(new LabelProviderChangedEvent(this, node)); + } + } + + /** + * Clears all the registered marker/nodes + */ + public void clearFaults() { + markerToNode.clear(); + nodeToMarkers.clear(); + } + + /** + * Provide a tool-tip for the faulty node with the error message of the associated markers + */ + @Override + public String getToolTipText(Object element) { + if (nodeToMarkers.containsKey(element)) { + Set<IMarker> markers = nodeToMarkers.get(element); + StringBuilder sb = new StringBuilder(); + for (IMarker marker : markers) { + try { + sb.append(marker.getAttribute(IMarker.MESSAGE) + "\n"); + } catch (CoreException e) { + // don't do anything + } + } + + return XmlUtils.finalize(sb, "\n"); + } + + return null; + } + + @Override + public Point getToolTipShift(Object object) { + return new Point(5, 5); + } + + @Override + public int getToolTipDisplayDelayTime(Object object) { + return TOOLTIP_DELAY_MS; + } + + @Override + public int getToolTipTimeDisplayed(Object object) { + return -1; + } + + /** + * Use the base label provider for the content If the element is fault, compute the background color + */ + @Override + public void update(ViewerCell cell) { + Object element = cell.getElement(); + int index = cell.getColumnIndex(); + + cell.setText(baseLabelProvider.getColumnText(element, index)); + cell.setImage(baseLabelProvider.getColumnImage(element, index)); + + cell.setForeground(baseLabelProvider.getForeground(element, index)); + if (nodeToMarkers.containsKey(element)) { + // background of the faulty cell + cell.setBackground(computeCellBackground((Node) element)); + } else { + cell.setBackground(baseLabelProvider.getBackground(element, index)); + } + } + + /** + * Helper to compute the background color of a faulty cell + * + * @param node + * @return + */ + private Color computeCellBackground(Node node) { + Set<IMarker> markers = nodeToMarkers.get(node); + int color = SWT.COLOR_YELLOW; + for (IMarker marker : markers) { + if (marker.getAttribute(IMarker.SEVERITY, IMarker.SEVERITY_ERROR) == IMarker.SEVERITY_ERROR) { + color = SWT.COLOR_RED; + break; + } + } + return Display.getCurrent().getSystemColor(color); + } +} diff --git a/silecs-eclipse-plugin/src/java/cern/silecs/view/editor/internal/SilecsXMLTableTreeContentProvider.java b/silecs-eclipse-plugin/src/java/cern/silecs/view/editor/internal/SilecsXMLTableTreeContentProvider.java new file mode 100644 index 0000000..1fce623 --- /dev/null +++ b/silecs-eclipse-plugin/src/java/cern/silecs/view/editor/internal/SilecsXMLTableTreeContentProvider.java @@ -0,0 +1,111 @@ +// Copyright 2016 CERN and GSI +// +// 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 3 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, see <http://www.gnu.org/licenses/>. + +package cern.silecs.view.editor.internal; + +import org.eclipse.osgi.util.TextProcessor; +import org.eclipse.wst.xml.ui.internal.tabletree.XMLTableTreeContentProvider; +import org.w3c.dom.Attr; +import org.w3c.dom.Element; +import org.w3c.dom.NamedNodeMap; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; + +import cern.silecs.utils.SilecsConstants; + +@SuppressWarnings("restriction") +public class SilecsXMLTableTreeContentProvider extends XMLTableTreeContentProvider{ + + @Override + public String getColumnText(Object object, int column) { + String result = super.getColumnText(object, column); + + if ((result.isEmpty() || result.startsWith("(")) && object instanceof Element && column == 1) { + result = getElementValueHelper((Element) object); + } + + result = TextProcessor.process(result); + return result != null ? result : ""; + } + + private String getElementValueHelper(Element element) { + + StringBuilder sb = new StringBuilder(); + if (element.hasAttributes()) { + NamedNodeMap map = element.getAttributes(); + + sb.append("("); + // put name first + Attr name = (Attr) map.getNamedItem(SilecsConstants.NAME); + if (name != null) { + sb.append(name.getValue() + ": "); + } + + // put other attributes + for (int i = 0; i < map.getLength(); i++) { + Attr a = (Attr) map.item(i); + String attrName = a.getName(); + + // name has already been added + // do not propagate id + if (!(attrName.equals(SilecsConstants.NAME))) { + sb.append(attrName + "=" + a.getValue() + ", "); + } + } + + } + + if (sb.length() < 2) { + // if we didn't find smth interesting + // the node behaves like a container + return getContainerElementValueHelper(element); + } else if (sb.charAt(0) == '(') { + // remove the last comma/colon and close the parenthesis + sb.setLength(sb.length() - 2); + sb.append(")"); + } + + return sb.toString(); + } + + private String getContainerElementValueHelper(Element element) { + if (element.hasAttribute(SilecsConstants.NAME)) { + return element.getAttribute(SilecsConstants.NAME); + } else if (element.hasChildNodes()) { + NodeList nodeList = element.getChildNodes(); + + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < nodeList.getLength(); i++) { + Node n = nodeList.item(i); + if (n instanceof Element) { + String val = getContainerElementValueHelper((Element) n); + if (!val.isEmpty()) { + if (sb.length() != 0) { + sb.append(", "); + } + + sb.append(val); + } + + } + } + + return sb.toString(); + } else { + return ""; + } + } + +} diff --git a/silecs-eclipse-plugin/src/java/cern/silecs/view/editor/internal/SilecsXMLTableTreePropertyDescriptionFactory.java b/silecs-eclipse-plugin/src/java/cern/silecs/view/editor/internal/SilecsXMLTableTreePropertyDescriptionFactory.java new file mode 100644 index 0000000..e0a32b4 --- /dev/null +++ b/silecs-eclipse-plugin/src/java/cern/silecs/view/editor/internal/SilecsXMLTableTreePropertyDescriptionFactory.java @@ -0,0 +1,194 @@ +// Copyright 2016 CERN and GSI +// +// 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 3 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, see <http://www.gnu.org/licenses/>. + +package cern.silecs.view.editor.internal; + +import java.io.File; +import java.io.FileFilter; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import java.util.TreeSet; + +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; + +import org.eclipse.core.resources.IWorkspaceRoot; +import org.eclipse.core.resources.ResourcesPlugin; +import org.eclipse.ui.views.properties.IPropertyDescriptor; +import org.eclipse.wst.xml.core.internal.contentmodel.CMNode; +import org.eclipse.wst.xml.ui.internal.properties.EnumeratedStringPropertyDescriptor; +import org.eclipse.wst.xml.ui.internal.tabletree.XMLTableTreePropertyDescriptorFactory; +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.Node; + +import cern.silecs.model.exception.SilecsException; +import cern.silecs.utils.SilecsConstants; +import cern.silecs.view.console.ConsoleHandler; + +@SuppressWarnings("restriction") +class SilecsXMLTableTreePropertyDescriptorFactory extends XMLTableTreePropertyDescriptorFactory { + + public static final String DESIGN_NAME_MATCHER = "silecs-design-name"; + public static final String DESIGN_VERSION_MATCHER = "silecs-design-version"; + + + @Override + protected IPropertyDescriptor createPropertyDescriptorHelper(String name, Element element, CMNode cmNode) + { + Collection<String> values = null; + try + { + if (isSilecsDesignName(element,name)) + { + + values = getPossibleClassNames(); + } + if (isSilecsDesignVersion(element,name) ) + { + if( !element.getAttribute(DESIGN_NAME_MATCHER).isEmpty() ) + { + values = getPossibleClassVersions(element.getAttribute(DESIGN_NAME_MATCHER)); + } + } + } + catch (SilecsException e) + { + ConsoleHandler.printStackTrace(e); + } + + if (values != null && !values.isEmpty()) + { + return new EnumeratedStringPropertyDescriptor(name, name, values.toArray(new String[values.size()])); + } + else + { + return super.createPropertyDescriptorHelper(name, element, cmNode); + } + } + + private static boolean isSilecsDesignName(Element element, String attribute) + { + if (element.getTagName().matches("SilecsDesign") && attribute.matches(DESIGN_NAME_MATCHER)) + return true; + return false; + } + + private static boolean isSilecsDesignVersion(Element element, String attribute) + { + if (element.getTagName().matches("SilecsDesign") && attribute.matches(DESIGN_VERSION_MATCHER)) + return true; + return false; + } + + private static List<String> getPossibleClassNames() throws SilecsException + { + Set<File> classes = getClassFiles(); + String searchTerm = "." + SilecsConstants.IEDESIGN_FILE; + List<String> classNames = new ArrayList<>(); + + for (File classFile : classes) + { + String className = classFile.getName().replace(searchTerm,""); + classNames.add(className); + } + return classNames; + } + + private static List<String> getPossibleClassVersions(String className) throws SilecsException + { + Set<File> classes = getClassFiles(); + List<String> classVersions = new ArrayList<>(); + String searchTerm = "." + SilecsConstants.IEDESIGN_FILE; + + for (File classFile : classes) + { + String classNameFile = classFile.getName().replace(searchTerm,""); + //ConsoleHandler.printMessage("getPossibleClassVersions - classNameFile: " + classNameFile, true); + //ConsoleHandler.printMessage("getPossibleClassVersions - className: " + className, true); + if (classNameFile.equals(className) ) + { + try + { + DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance(); + DocumentBuilder dBuilder = dbFactory.newDocumentBuilder(); + Document doc = dBuilder.parse(classFile); + Node classNode = doc.getElementsByTagName("SILECS-Class").item(0); + if( classNode != null ) + { + classVersions.add( classNode.getAttributes().getNamedItem("version").getNodeValue() ); + } + } + catch(Exception e) + { + e.printStackTrace(); + ConsoleHandler.printError("No version found in class: " + classNameFile, true); + } + } + } + return classVersions; + } + + private static Set<File> getClassFiles() throws SilecsException + { + IWorkspaceRoot workspaceRoot = ResourcesPlugin.getWorkspace().getRoot(); + Set<File> projects = listDirectories(workspaceRoot.getLocation().toFile()); + Set<File> classes = new HashSet<File>(); + + String searchTerm = "." + SilecsConstants.IEDESIGN_FILE; + for (File p : projects) + { + File designFolder = new File(p.getAbsolutePath()+"/src"); + if( !designFolder.exists() ) + continue; + + File[] listOfFiles = designFolder.listFiles(); + for (int i = 0; i < listOfFiles.length; i++) + { + if (listOfFiles[i].getName().endsWith(searchTerm)) + { + classes.add(listOfFiles[i]); + } + } + } + return classes; + } + + private static Set<File> listDirectories(File directory) + { + File[] directories = directory.listFiles(new FileFilter() + { + @Override + public boolean accept(File pathname) + { + return pathname.isDirectory(); + } + }); + + if (directories != null) + { + return new TreeSet<File>(Arrays.asList(directories)); + } + else + { + return Collections.emptySet(); + } + } +} diff --git a/silecs-eclipse-plugin/src/java/cern/silecs/view/editor/internal/SilecsXMLTableTreeViewer.java b/silecs-eclipse-plugin/src/java/cern/silecs/view/editor/internal/SilecsXMLTableTreeViewer.java new file mode 100644 index 0000000..e70cdcc --- /dev/null +++ b/silecs-eclipse-plugin/src/java/cern/silecs/view/editor/internal/SilecsXMLTableTreeViewer.java @@ -0,0 +1,176 @@ +// Copyright 2016 CERN and GSI +// +// 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 3 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, see <http://www.gnu.org/licenses/>. + +package cern.silecs.view.editor.internal; + +import java.util.Arrays; +import java.util.Comparator; + +import org.eclipse.core.resources.IFile; +import org.eclipse.core.resources.IMarker; +import org.eclipse.core.resources.IMarkerDelta; +import org.eclipse.core.resources.IResource; +import org.eclipse.core.resources.IResourceChangeEvent; +import org.eclipse.core.resources.IResourceChangeListener; +import org.eclipse.core.resources.IResourceDelta; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.jface.viewers.ColumnViewerToolTipSupport; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.TreeItem; +import org.eclipse.ui.IEditorInput; +import org.eclipse.ui.IEditorPart; +import org.eclipse.ui.IFileEditorInput; +import org.eclipse.wst.xml.core.internal.document.NodeImpl; +import org.eclipse.wst.xml.ui.internal.tabletree.XMLTableTreeContentProvider; +import org.eclipse.wst.xml.ui.internal.tabletree.XMLTableTreeViewer; +import org.w3c.dom.Element; +import org.w3c.dom.Node; + +import cern.silecs.view.marker.SilecsMarker; + +@SuppressWarnings("restriction") +public class SilecsXMLTableTreeViewer extends XMLTableTreeViewer implements IResourceChangeListener{ + + + + private final IEditorPart parentEditor; + private final SilecsTableColumnViewerLabelProvider labelProvider; + + + /** + * @param parent + */ + public SilecsXMLTableTreeViewer(Composite parent, IEditorPart parentEditor) { + super(parent); + this.parentEditor = parentEditor; + + this.propertyDescriptorFactory = new SilecsXMLTableTreePropertyDescriptorFactory(); + XMLTableTreeContentProvider provider = new SilecsXMLTableTreeContentProvider(); + setContentProvider(provider); + this.labelProvider = new SilecsTableColumnViewerLabelProvider(provider); + setLabelProvider(labelProvider); + ColumnViewerToolTipSupport.enableFor(this); + } + + @Override + protected void inputChanged(Object input, Object oldInput) { + super.inputChanged(input, oldInput); + + labelProvider.clearFaults(); + IEditorInput editorInput = parentEditor.getEditorInput(); + if (editorInput instanceof IFileEditorInput) { + try { + IFile inputFile = ((IFileEditorInput) editorInput).getFile(); + IMarker[] markers = inputFile.findMarkers(SilecsMarker.TYPE, false, IResource.DEPTH_ZERO); + + for (IMarker m : markers) { + displayMarker(m); + } + } catch (CoreException e) { +// LOGGER.error(e.getMessage()); + } + } + refresh(); + } + + + @Override + public void refresh(Object element, boolean updateLabels) { + super.refresh(element, updateLabels); + + // we also want to refresh label of parents elements + if (element instanceof Element) { + Node parent = ((Element) element).getParentNode(); + while (parent != null) { + super.refresh(parent, updateLabels); + parent = parent.getParentNode(); + } + } + } + + + @Override + public void resourceChanged(IResourceChangeEvent event) { + IEditorInput editorInput = parentEditor.getEditorInput(); + if (editorInput instanceof IFileEditorInput) { + // only apply changes if input is a file + final IFile inputFile = ((IFileEditorInput) editorInput).getFile(); + + // sort the markers so that we handle first the deletion and the the creation + final IMarkerDelta makerDelta[] = event.findMarkerDeltas(SilecsMarker.TYPE, false); + Arrays.sort(makerDelta, new Comparator<IMarkerDelta>() { + @Override + public int compare(IMarkerDelta md1, IMarkerDelta md2) { + if (md1.getKind() == IResourceDelta.ADDED) { + return md2.getKind() == IResourceDelta.ADDED ? 0 : 1; + } else if (md1.getKind() == IResourceDelta.REMOVED) { + return md2.getKind() == IResourceDelta.REMOVED ? 0 : -1; + } else if (md2.getKind() == IResourceDelta.ADDED) { + return -1; + } else if (md2.getKind() == IResourceDelta.REMOVED) { + return 1; + } else { + return 0; + } + } + }); + + getControl().getDisplay().syncExec(new Runnable() { + @Override + public void run() { + // this is a hack to avoid automatic scrolling to + // one of the faulty nodes + TreeItem item = getTree().getTopItem(); + for (IMarkerDelta md : makerDelta) { + if (md.getResource().equals(inputFile)) { + if (md.getKind() == IResourceDelta.ADDED) { + displayMarker(md.getMarker()); + } else if (md.getKind() == IResourceDelta.REMOVED) { + removeMarker(md.getMarker()); + } + } + } + + if (item != null) { + getTree().setTopItem(item); + } + } + }); + } + } + + public void displayMarker(final IMarker marker) { + NodeImpl node = null; + try { + node = (NodeImpl) marker.getAttribute(SilecsMarker.NODE_ATTR); + if (node != null) { + labelProvider.addFault(marker, node); + reveal(node); + } + } catch (CoreException e) { + //LOGGER.error("Could not highlight node: {}", e.getMessage()); + } + } + + public void removeMarker(final IMarker marker) { + labelProvider.removeFault(marker); + } + + @Override + public String getTitle() { + return "Tree View"; + } + +} diff --git a/silecs-eclipse-plugin/src/java/cern/silecs/view/explorer/ContentSorter.java b/silecs-eclipse-plugin/src/java/cern/silecs/view/explorer/ContentSorter.java new file mode 100644 index 0000000..091b1a6 --- /dev/null +++ b/silecs-eclipse-plugin/src/java/cern/silecs/view/explorer/ContentSorter.java @@ -0,0 +1,64 @@ +// Copyright 2016 CERN and GSI +// +// 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 3 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, see <http://www.gnu.org/licenses/>. + +package cern.silecs.view.explorer; + +import org.eclipse.core.resources.IProject; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.jface.viewers.Viewer; +import org.eclipse.jface.viewers.ViewerSorter; +import org.eclipse.ui.views.navigator.ResourceComparator; + +import cern.silecs.control.core.DesignProjectNature; + +public class ContentSorter extends ViewerSorter { + + private ResourceComparator resourceComparator; + + public ContentSorter() { + resourceComparator = new ResourceComparator(ResourceComparator.NAME); + } + + @Override + public int compare(Viewer viewer, Object e1, Object e2) { + if (e1 instanceof IProject && e2 instanceof IProject) { + + IProject f1 = (IProject) e1; + IProject f2 = (IProject) e2; + + if (!f1.isOpen() || !f2.isOpen()) + return resourceComparator.compare(viewer, e1, e2); + + boolean f1b = false; + boolean f2b = false; + try { + f1b = f1.hasNature(DesignProjectNature.NATURE_ID); + f2b = f2.hasNature(DesignProjectNature.NATURE_ID); + } catch (CoreException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + if (f1b ^ f2b) + if (f1b == true) { + return -1; + } else { + return 1; + } + } + + // else let the resource comparator do the ordering + return resourceComparator.compare(viewer, e1, e2); + } +} diff --git a/silecs-eclipse-plugin/src/java/cern/silecs/view/explorer/ProjectContent.java b/silecs-eclipse-plugin/src/java/cern/silecs/view/explorer/ProjectContent.java new file mode 100644 index 0000000..77bf856 --- /dev/null +++ b/silecs-eclipse-plugin/src/java/cern/silecs/view/explorer/ProjectContent.java @@ -0,0 +1,137 @@ +// Copyright 2016 CERN and GSI +// +// 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 3 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, see <http://www.gnu.org/licenses/>. + +package cern.silecs.view.explorer; + +import org.eclipse.core.resources.IFile; +import org.eclipse.core.resources.IFolder; +import org.eclipse.core.resources.IProject; +import org.eclipse.core.resources.IResource; +import org.eclipse.core.resources.IResourceChangeEvent; +import org.eclipse.core.resources.IResourceChangeListener; +import org.eclipse.core.resources.IWorkspaceRoot; +import org.eclipse.core.resources.ResourcesPlugin; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.jface.viewers.ITreeContentProvider; +import org.eclipse.jface.viewers.Viewer; +import org.eclipse.swt.widgets.Display; + +public class ProjectContent implements ITreeContentProvider, IResourceChangeListener { + + private Viewer attachedViewer; + + private static final Object[] NO_OBJECTS = new Object[0]; + + public ProjectContent() { + ResourcesPlugin.getWorkspace().addResourceChangeListener(this); + } + + @Override + public void dispose() { + ResourcesPlugin.getWorkspace().removeResourceChangeListener(this); + } + + @Override + public void inputChanged(Viewer viewer, Object oldInput, Object newInput) { + attachedViewer = viewer; + } + + @Override + public Object[] getElements(Object inputElement) { + if (inputElement instanceof IWorkspaceRoot) { + // if root return the projects + return ((IWorkspaceRoot) inputElement).getProjects(); + } else if (inputElement instanceof IProject || inputElement instanceof IFolder) { + // if folder or project, return the content + return getChildren(inputElement); + } else { + return NO_OBJECTS; + } + } + + @Override + public Object[] getChildren(Object parentElement) { + if (parentElement instanceof IProject) { + IProject p = (IProject) parentElement; + try { + return p.members(); + } catch (CoreException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + + } else if (parentElement instanceof IFolder) { + try { + return ((IFolder) parentElement).members(); + } catch (CoreException e) { + // The resource is not found + return NO_OBJECTS; + } + } + return NO_OBJECTS; + } + + @Override + public Object getParent(Object element) { + if (element instanceof IProject) { + return ((IProject) element).getWorkspace().getRoot(); + } else if (element instanceof IFolder) { + IFolder folder = (IFolder) element; + if (folder.getParent() instanceof IProject) { + // parent of folder is the project + return folder.getProject(); + } else { + return folder.getParent(); + } + } else if (element instanceof IFile) { + IFile file = (IFile) element; + return file.getParent(); + } else { + return null; + } + } + + @Override + public boolean hasChildren(Object element) { + IResource[] members = null; + + try { + if (element instanceof IFolder) { + members = ((IFolder) element).members(); + } + } catch (CoreException e) { + // error while accessing members + } + + // has children if element is project or not empty folder + return element instanceof IProject || (members != null && members.length > 0); + } + + @Override + public void resourceChanged(IResourceChangeEvent event) { + if (attachedViewer != null && !attachedViewer.getControl().isDisposed()) { + + // make the UI thread update the viewer + Display.getDefault().asyncExec(new Runnable() { + + @Override + public void run() { + attachedViewer.refresh(); + } + }); + } + } + +} diff --git a/silecs-eclipse-plugin/src/java/cern/silecs/view/explorer/SilecsProjectExplorer.java b/silecs-eclipse-plugin/src/java/cern/silecs/view/explorer/SilecsProjectExplorer.java new file mode 100644 index 0000000..b5811da --- /dev/null +++ b/silecs-eclipse-plugin/src/java/cern/silecs/view/explorer/SilecsProjectExplorer.java @@ -0,0 +1,198 @@ +// Copyright 2016 CERN and GSI +// +// 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 3 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, see <http://www.gnu.org/licenses/>. + +package cern.silecs.view.explorer; + +import java.time.LocalDateTime; +import java.time.ZoneOffset; +import java.time.format.DateTimeFormatter; +import java.util.ArrayList; +import java.util.List; + +import org.eclipse.core.resources.IContainer; +import org.eclipse.core.resources.IFile; +import org.eclipse.core.resources.IProject; +import org.eclipse.core.resources.IResource; +import org.eclipse.core.resources.IWorkspaceRoot; +import org.eclipse.core.resources.ResourcesPlugin; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.NullProgressMonitor; +import org.eclipse.jface.action.IAction; +import org.eclipse.jface.action.IStatusLineManager; +import org.eclipse.jface.viewers.DoubleClickEvent; +import org.eclipse.jface.viewers.ILabelProvider; +import org.eclipse.jface.viewers.ISelection; +import org.eclipse.jface.viewers.ISelectionChangedListener; +import org.eclipse.jface.viewers.IStructuredSelection; +import org.eclipse.jface.viewers.SelectionChangedEvent; +import org.eclipse.jface.viewers.TreeViewer; +import org.eclipse.swt.graphics.Image; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.ui.IActionBars; +import org.eclipse.ui.navigator.CommonNavigator; +import org.eclipse.ui.navigator.CommonViewer; +import org.eclipse.ui.navigator.ICommonActionConstants; + +import cern.silecs.control.core.DeployProjectNature; +import cern.silecs.control.core.DesignProjectNature; +import cern.silecs.utils.SilecsUtils; + +/** + * This class is a subclass of CommonNavigator that provide changes concerning expanding tree. + * + * @see CommonNavigator + */ +public class SilecsProjectExplorer extends CommonNavigator { + + public static final String VIEW_ID = "cern.silecs.view.explorer"; + + @Override + public void createPartControl(Composite aParent) { + super.createPartControl(aParent); + CommonViewer viewer = getCommonViewer(); + + IActionBars bars = getViewSite().getActionBars(); + IStatusLineManager lineManager = bars.getStatusLineManager(); + + ILabelProvider labelProvider = (ILabelProvider) viewer.getLabelProvider(); + + viewer.addPostSelectionChangedListener(new ISelectionChangedListener() { + + @Override + public void selectionChanged(SelectionChangedEvent event) { + + ISelection aSelection = event.getSelection(); + if (aSelection != null && !aSelection.isEmpty() && aSelection instanceof IStructuredSelection) { + IStructuredSelection selection = (IStructuredSelection) aSelection; + IResource file = null; + + if (selection.size() == 1 && selection.getFirstElement() instanceof IProject) { + IProject project = (IProject) selection.getFirstElement(); + try { + if (project.hasNature(DesignProjectNature.NATURE_ID)) { + file = SilecsUtils.getSilecsDesignFile(project); + } else if (project.hasNature(DeployProjectNature.NATURE_ID)) { + file = SilecsUtils.getSilecsDeployFile(project); + } + } catch (Exception e) { + e.printStackTrace(); + } + + } else if(selection.size() == 1 && selection.getFirstElement() instanceof IFile) { + file = (IFile) selection.getFirstElement(); + } + + if(file != null) { + Image img = null; + img = labelProvider.getImage(((IStructuredSelection) aSelection).getFirstElement()); + long modificationTime = file.getLocalTimeStamp() / 1000; + + DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd-MM-YYYY HH:mm:ss"); + LocalDateTime dateAndTime = LocalDateTime.ofEpochSecond(modificationTime, 0, ZoneOffset.ofHours(2)); + + lineManager.setMessage(img,"Last modfication: " + formatter.format(dateAndTime) + " : " + file.getFullPath()); + } + } + + } + }); + + } + + /** + * This method is responsible for expanding the project tree from the root to the silecs file(*.silecsdesign or + * *.silecsdeploy) + */ + @Override + protected void handleDoubleClick(DoubleClickEvent anEvent) { + + IStructuredSelection selection = (IStructuredSelection) anEvent.getSelection(); + Object element = selection.getFirstElement(); + if (element instanceof IProject && !((IProject) element).isOpen()) { + try { + ((IProject) element).open(new NullProgressMonitor()); + } catch (CoreException e) { + e.printStackTrace(); + } + return; + + } else if (element instanceof IProject && ((IProject) element).isOpen()) { + List<IProject> projectList = new ArrayList<IProject>(); + projectList.add((IProject) element); + + IWorkspaceRoot root = ResourcesPlugin.getWorkspace().getRoot(); + + expandHelper(root, projectList); + return; + } + super.handleDoubleClick(anEvent); + } + + /** + * This method expands elements in the tree. Since the tool does not have knowledge about project structure it must + * be done recursively. + * + * @param root {@link WorkspaceRoot} + * @param projects List of projects that need to be expanded + */ + public void expandHelper(IWorkspaceRoot root, List<IProject> projects) { + for (IProject project : projects) { + if (project.isOpen()) { + try { + IFile file = null; + if (project.hasNature(DeployProjectNature.NATURE_ID)) { + file = SilecsUtils.getSilecsDeployFile(project); + } else if (project.hasNature(DesignProjectNature.NATURE_ID)) { + file = SilecsUtils.getSilecsDesignFile(project); + } + if (file == null) + continue; + + IContainer parent = file.getParent(); + List<Object> toExpand = new ArrayList<>(); + + do { + toExpand.add(0, parent); + } while ((parent = parent.getParent()) != root); + boolean expand = !getCommonViewer().getExpandedState(project); + toExpand.forEach(o -> expand(o, expand)); + } catch (Exception e) { + e.printStackTrace(); + } + } + } + } + + /** + * Expands single element in the viewer + * + * @param element + * @return true if expanded + */ + private boolean expand(Object element, boolean expand) { + IAction openHandler = getViewSite().getActionBars().getGlobalActionHandler(ICommonActionConstants.OPEN); + + if (openHandler == null) { + + TreeViewer viewer = getCommonViewer(); + if (viewer.isExpandable(element)) { + viewer.setExpandedState(element, expand); + return true; + } + } + return false; + } + +} diff --git a/silecs-eclipse-plugin/src/java/cern/silecs/view/job/BaseFileJob.java b/silecs-eclipse-plugin/src/java/cern/silecs/view/job/BaseFileJob.java new file mode 100644 index 0000000..563bb7b --- /dev/null +++ b/silecs-eclipse-plugin/src/java/cern/silecs/view/job/BaseFileJob.java @@ -0,0 +1,79 @@ +// Copyright 2016 CERN and GSI +// +// 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 3 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, see <http://www.gnu.org/licenses/>. + +package cern.silecs.view.job; + +import java.util.HashMap; +import java.util.Map; + +import org.eclipse.core.resources.IFile; +import org.eclipse.core.resources.IResource; +import org.eclipse.core.resources.ResourcesPlugin; +import org.eclipse.core.resources.WorkspaceJob; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Status; +import org.eclipse.core.runtime.jobs.ISchedulingRule; + +import cern.silecs.activator.Activator; + +public abstract class BaseFileJob extends WorkspaceJob { + + protected final IFile file; + protected final Map<IResource, Exception> failures; + + + /** + * @param name + */ + public BaseFileJob(String name, IFile file) { + super(name); + this.file = file; + this.failures = new HashMap<IResource, Exception>(); + + // set the job rule + setRule(createJobRule()); + } + + public Map<IResource, Exception> getFailures(){ + return failures; + } + + protected IStatus computeReturnStatus() { + if (failures.isEmpty()) { + return Status.OK_STATUS; + } else { + // return INFO status so that eclipse does not open the default error pop up + // we handle manually the error reporting + return new Status(IStatus.INFO, Activator.PLUGIN_ID, ""); + } + } + + + /** + * Create the job rule to avoid concurrency on the used resources + * + * @return rule used for the job + */ + protected ISchedulingRule createJobRule() { + return null; + } + + protected final ISchedulingRule workspaceRule() { + return ResourcesPlugin.getWorkspace().getRoot(); + } + + + +} diff --git a/silecs-eclipse-plugin/src/java/cern/silecs/view/job/BaseProjectJob.java b/silecs-eclipse-plugin/src/java/cern/silecs/view/job/BaseProjectJob.java new file mode 100644 index 0000000..ba40902 --- /dev/null +++ b/silecs-eclipse-plugin/src/java/cern/silecs/view/job/BaseProjectJob.java @@ -0,0 +1,76 @@ +// Copyright 2016 CERN and GSI +// +// 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 3 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, see <http://www.gnu.org/licenses/>. + +package cern.silecs.view.job; + +import java.util.HashMap; +import java.util.Map; + + +import org.eclipse.core.resources.IProject; +import org.eclipse.core.resources.IResource; +import org.eclipse.core.resources.ResourcesPlugin; +import org.eclipse.core.resources.WorkspaceJob; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Status; +import org.eclipse.core.runtime.jobs.ISchedulingRule; + +import cern.silecs.activator.Activator; + +public abstract class BaseProjectJob extends WorkspaceJob { + + protected final IProject project; + protected final Map<IResource, Exception> failures; + + /** + * @param name + */ + public BaseProjectJob(String name, IProject project) { + super(name); + this.failures = new HashMap<IResource, Exception>(); + this.project = project; + + // set the job rule + setRule(createJobRule()); + } + + public Map<IResource, Exception> getFailures() { + return failures; + } + + protected IStatus computeReturnStatus() { + if (failures.isEmpty()) { + return Status.OK_STATUS; + } else { + // return INFO status so that eclipse does not open the default error pop up + // we handle manually the error reporting + return new Status(IStatus.INFO, Activator.PLUGIN_ID, ""); + } + } + + /** + * Create the job rule to avoid concurrency on the used resources + * + * @return rule used for the job + */ + protected ISchedulingRule createJobRule() { + return null; + } + + protected final ISchedulingRule workspaceRule() { + return ResourcesPlugin.getWorkspace().getRoot(); + } + +} diff --git a/silecs-eclipse-plugin/src/java/cern/silecs/view/job/GenerateClassJob.java b/silecs-eclipse-plugin/src/java/cern/silecs/view/job/GenerateClassJob.java new file mode 100644 index 0000000..263b22d --- /dev/null +++ b/silecs-eclipse-plugin/src/java/cern/silecs/view/job/GenerateClassJob.java @@ -0,0 +1,99 @@ +// Copyright 2016 CERN and GSI +// +// 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 3 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, see <http://www.gnu.org/licenses/>. + +package cern.silecs.view.job; + +import org.eclipse.core.resources.IFile; +import org.eclipse.core.resources.IProject; +import org.eclipse.core.resources.IResource; +import org.eclipse.core.resources.IWorkspaceRoot; +import org.eclipse.core.resources.ResourcesPlugin; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.SubProgressMonitor; + +import cern.silecs.control.core.DesignProjectNature; +import cern.silecs.control.validation.Validator; +import cern.silecs.utils.OSExecute; +import cern.silecs.utils.SilecsUtils; +import cern.silecs.view.console.ConsoleHandler; +import cern.silecs.view.preferences.MainPreferencePage; + +public class GenerateClassJob extends BaseProjectJob { + + private static final String JOB_NAME = "Generate SILECS Class Job"; + + IFile fesaDesignXML; + + public GenerateClassJob(IProject project, IFile fesaDesignDoc) { + super(JOB_NAME, project); + fesaDesignXML = fesaDesignDoc; + } + + @Override + public IStatus runInWorkspace(IProgressMonitor monitor) throws CoreException { + + IWorkspaceRoot workspaceRoot = ResourcesPlugin.getWorkspace().getRoot(); + String workspacePath = workspaceRoot.getLocation().toFile().getPath(); + + monitor.beginTask("Generate Fesa Classes", 1); + + generateFesaClass(workspacePath, new SubProgressMonitor(monitor, 1)); + DesignProjectNature.addFESAClassNature(project,monitor); + DesignProjectNature.addBuildSpecs(project); + monitor.done(); + + return computeReturnStatus(); + } + + boolean generateFesaClass(String workspacePath, IProgressMonitor monitor) + { + String projectName = project.getName(); + String projectPath = workspacePath + "/" + projectName; + try { + String silecsDesignFilePath = SilecsUtils.getSilecsDesignFilePath(workspacePath, projectName); + String silecsVersion = SilecsUtils.getSilecsVersion(project); + String silecsLibraryBasePath = MainPreferencePage.getSilecsLibraryBasePath(silecsVersion); + + ConsoleHandler.printMessage("Generating FESA class: " + projectName, false); + + if (!Validator.isDocumentValid(SilecsUtils.getSilecsDesignFile(project))) + { + ConsoleHandler.printError( "Failed to generated FESA class: '" + projectName + "'. Please fix all design errors first!", true); + return false; + } + + monitor.beginTask("Generating " + projectName, 2); + OSExecute.executePython("generateFesaDesign","fillDesignFile",silecsVersion,new String[]{MainPreferencePage.getFESAVersion(),projectName,workspacePath,MainPreferencePage.getFESADesignSchemaPath()}); + OSExecute.executePython("generateSourceCode","genCppFiles",silecsVersion,new String[]{projectName, workspacePath,silecsDesignFilePath}); // attention - Cpp Codegen has to happen AFTER design file codegen + OSExecute.executePython("generateBuildEnvironment","genMakefileClass",silecsVersion,new String[]{projectPath,silecsLibraryBasePath}); + OSExecute.executePython("generateBuildEnvironment","genCProjectFile",silecsVersion,new String[]{projectPath.toString()}); + project.refreshLocal(IResource.DEPTH_INFINITE, null); + SilecsUtils.openInEditor(fesaDesignXML); + monitor.worked(1); + } catch (Exception e) { + e.printStackTrace(); + ConsoleHandler.printError("Failed to generate FESA class: " + projectName, true); + ConsoleHandler.printStackTrace(e); + return false; + } + + monitor.done(); + ConsoleHandler.printMessage( "Successfully generated FESA class: " + projectName, true); + return true; + + } +} diff --git a/silecs-eclipse-plugin/src/java/cern/silecs/view/job/GenerateDeployJob.java b/silecs-eclipse-plugin/src/java/cern/silecs/view/job/GenerateDeployJob.java new file mode 100644 index 0000000..2fb5f6c --- /dev/null +++ b/silecs-eclipse-plugin/src/java/cern/silecs/view/job/GenerateDeployJob.java @@ -0,0 +1,107 @@ +// Copyright 2016 CERN and GSI +// +// 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 3 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, see <http://www.gnu.org/licenses/>. + +package cern.silecs.view.job; + +import org.eclipse.core.resources.IFile; +import org.eclipse.core.resources.IProject; +import org.eclipse.core.resources.IResource; +import org.eclipse.core.resources.IWorkspaceRoot; +import org.eclipse.core.resources.ResourcesPlugin; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.SubProgressMonitor; + +import cern.silecs.control.core.DeployProjectNature; +import cern.silecs.control.validation.Validator; +import cern.silecs.utils.OSExecute; +import cern.silecs.utils.SilecsUtils; +import cern.silecs.view.console.ConsoleHandler; +import cern.silecs.view.preferences.MainPreferencePage; + +public class GenerateDeployJob extends BaseProjectJob { + + private static final String JOB_NAME = "Generate SILECS Deploy Job"; + + IFile fesaDeployDoc_; + boolean createdNewDeployDoc_; + + public GenerateDeployJob(IProject project, IFile fesaDeployDoc, boolean createdNewDeployDoc) { + super(JOB_NAME, project); + fesaDeployDoc_ = fesaDeployDoc; + createdNewDeployDoc_ = createdNewDeployDoc; + } + + @Override + public IStatus runInWorkspace(IProgressMonitor monitor) throws CoreException { + + IWorkspaceRoot workspaceRoot = ResourcesPlugin.getWorkspace().getRoot(); + String workspacePath = workspaceRoot.getLocation().toFile().getPath(); + + monitor.beginTask("Generating Code", 1); + generateDeploy(workspacePath, new SubProgressMonitor(monitor, 1)); + monitor.done(); + + return computeReturnStatus(); + } + + private void generateDeploy(String workspacePath, IProgressMonitor monitor ) + { + String projectName = project.getName(); + + try { + String deployPath = SilecsUtils.getSilecsDeployFilePath(workspacePath,projectName); + String deployVersion = SilecsUtils.getDeployVersion(deployPath); + String silecsVersion = SilecsUtils.getSilecsVersion(project); + + monitor.beginTask("Generating: " + projectName, 2); + + ConsoleHandler.printMessage("Generating Code for: " + projectName, false); + if (!Validator.isDocumentValid(SilecsUtils.getSilecsDeployFile(project))) + { + ConsoleHandler.printError( "Failed to generated code for: '" + projectName + "'. Please fix all xml errors first!", true); + return; + } + + OSExecute.executePython("genparam","genParam",silecsVersion,new String[]{workspacePath, projectName, deployVersion,silecsVersion}); + OSExecute.executePython("genplcsrc","genPlcSrc",silecsVersion,new String[]{workspacePath, projectName,silecsVersion}); + OSExecute.executePython("genduwrapper","genDuWrapper",silecsVersion,new String[]{workspacePath, projectName, deployVersion}); + OSExecute.executePython("generateBuildEnvironment","genCProjectFile",silecsVersion,new String[]{project.getLocation().toString()}); + + String silecsLibraryBasePath = MainPreferencePage.getSilecsLibraryBasePath(SilecsUtils.getSilecsVersion(project)); + String snap7LibraryBasePath = MainPreferencePage.getSNAP7LibraryBasePath(SilecsUtils.getSilecsVersion(project)); + OSExecute.executePython("generateBuildEnvironment","genMakefileDU",silecsVersion,new String[]{ workspacePath + "/" + projectName, silecsLibraryBasePath,snap7LibraryBasePath}); + OSExecute.executePython("fillFESADeployUnit","fillDeployUnit",silecsVersion,new String[]{ workspacePath, projectName, MainPreferencePage.getFESADeployUnitSchemaPath(), MainPreferencePage.getFESAVersion() }); + + DeployProjectNature.addFESADeployUnitNature(project,monitor); + DeployProjectNature.addBuildSpecs(project); + + project.refreshLocal(IResource.DEPTH_INFINITE, null); + + ConsoleHandler.printMessage("Succeeded in generated code for " + projectName, true); + + if(createdNewDeployDoc_) + SilecsUtils.openInEditor(fesaDeployDoc_); + + monitor.worked(1); + + } catch (Exception e) { + e.printStackTrace(); + ConsoleHandler.printError("Failed to generate code for " + projectName, true); + ConsoleHandler.printStackTrace(e); + } + } +} \ No newline at end of file diff --git a/silecs-eclipse-plugin/src/java/cern/silecs/view/job/UpdateVersionJob.java b/silecs-eclipse-plugin/src/java/cern/silecs/view/job/UpdateVersionJob.java new file mode 100644 index 0000000..d12e3f6 --- /dev/null +++ b/silecs-eclipse-plugin/src/java/cern/silecs/view/job/UpdateVersionJob.java @@ -0,0 +1,115 @@ +// Copyright 2016 CERN and GSI +// +// 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 3 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, see <http://www.gnu.org/licenses/>. + +package cern.silecs.view.job; + +import java.io.File; + +import org.eclipse.core.resources.IProject; +import org.eclipse.core.resources.IResource; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.IStatus; + +import cern.silecs.control.core.DeployProjectNature; +import cern.silecs.control.core.DesignProjectNature; +import cern.silecs.model.exception.SilecsException; +import cern.silecs.utils.OSExecute; +import cern.silecs.utils.SilecsUtils; +import cern.silecs.utils.SilecsConstants; +import cern.silecs.view.console.ConsoleHandler; +import cern.silecs.view.preferences.MainPreferencePage; + +public class UpdateVersionJob extends BaseProjectJob { + + private static final String JOB_NAME = "Update SILECS Version Job"; + + String newVersion_; + String oldVersion_; + + public UpdateVersionJob(IProject project, String newVersion ) { + super(JOB_NAME, project); + newVersion_ = newVersion; + } + + @Override + public IStatus runInWorkspace(IProgressMonitor monitor) throws CoreException + { + monitor.beginTask("Updating Silecs Version", 1); + updateVersion(monitor); + monitor.done(); + return computeReturnStatus(); + } + + boolean updateVersion(IProgressMonitor monitor) + { + try { + oldVersion_ = SilecsUtils.getSilecsVersion(project); + + int result = oldVersion_.compareTo(newVersion_); + if( result >= 0) + { + throw new SilecsException("Migration from "+ oldVersion_ +" to "+ newVersion_ +" not possible. The target-version always needto newer than the current version"); + } + + String codeGenBasePath = MainPreferencePage.getCodeGenBasePath(newVersion_); + String silecsDocumentPath = SilecsUtils.getSilecsDocument(project).getRawLocation().makeAbsolute().toOSString(); + String oldVersionUnderscored = oldVersion_.replace(".", "_"); + String newVersionUnderscored = newVersion_.replace(".", "_"); + String migrationScript = codeGenBasePath + "/migration/" + oldVersionUnderscored + "to" + newVersionUnderscored + ".py"; + + if(! new File(migrationScript).exists()) + { + ConsoleHandler.printWarning("There is no Migration Script for an update from: '" + oldVersion_ + "' to '" + newVersion_ + "'. Using generic migration-script. Only basic xml-version strings will be changed.", true); + migrationScript = codeGenBasePath + "/migration/migrationBase.py"; + if(! new File(migrationScript).exists()) + { + throw new SilecsException("The Migration Script: '" + migrationScript + "' does not exist. Please check your Eclipse-Silecs preferences!"); + } + } + + String newXMLSchema = MainPreferencePage.getModelBasePath(newVersion_) + "/"; + if ( project.hasNature(DesignProjectNature.NATURE_ID) ) + { + newXMLSchema += SilecsConstants.DESIGN_SCHEMA_XSD; + } + else if( project.hasNature(DeployProjectNature.NATURE_ID) ) + { + newXMLSchema += SilecsConstants.DEPLOY_SCHEMA_XSD; + } + else + throw new Exception("The project: " + project.getName() + " is not a silecs-project"); + + OSExecute.executeCommand("python", migrationScript, silecsDocumentPath, newXMLSchema, oldVersion_, newVersion_); + ConsoleHandler.printMessage("Updating Silecs Version from '" + oldVersion_ + "'to '" + newVersion_ + "'", false); + + monitor.beginTask("Updating Silecs Version " + project.getName(), 2); + + project.refreshLocal(IResource.DEPTH_INFINITE, null); + + monitor.worked(1); + } catch (Exception e) { + e.printStackTrace(); + ConsoleHandler.printError("Failed to update SILECS version of: " + project.getName(), true); + ConsoleHandler.printStackTrace(e); + return false; + } + + monitor.done(); + ConsoleHandler.printMessage( "Successfully updated SILECS version of: " + project.getName(), true); + return true; + + } +} diff --git a/silecs-eclipse-plugin/src/java/cern/silecs/view/job/ValidationJob.java b/silecs-eclipse-plugin/src/java/cern/silecs/view/job/ValidationJob.java new file mode 100644 index 0000000..35af12f --- /dev/null +++ b/silecs-eclipse-plugin/src/java/cern/silecs/view/job/ValidationJob.java @@ -0,0 +1,223 @@ +// Copyright 2016 CERN and GSI +// +// 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 3 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, see <http://www.gnu.org/licenses/>. + +package cern.silecs.view.job; + +import java.io.File; +import java.util.List; + +import org.eclipse.core.resources.IFile; +import org.eclipse.core.resources.IMarker; +import org.eclipse.core.resources.IResource; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.NullProgressMonitor; +import org.eclipse.core.runtime.SubProgressMonitor; +import org.eclipse.swt.widgets.Display; +import org.eclipse.ui.IViewPart; +import org.eclipse.ui.IWorkbenchPage; +import org.eclipse.ui.PlatformUI; +import org.eclipse.wst.sse.core.StructuredModelManager; +import org.eclipse.wst.sse.core.internal.provisional.IStructuredModel; +import org.eclipse.wst.xml.core.internal.document.AttrImpl; +import org.eclipse.wst.xml.core.internal.document.ElementImpl; +import org.eclipse.wst.xml.core.internal.document.NodeImpl; +import org.eclipse.wst.xml.core.internal.provisional.document.IDOMModel; +import org.eclipse.xsd.XSDIdentityConstraintDefinition; +import org.eclipse.xsd.XSDXPathDefinition; +import org.w3c.dom.Element; +import org.w3c.dom.Node; + +import cern.silecs.control.validation.Validator; +import cern.silecs.model.document.SilecsDocumentError; +import cern.silecs.model.document.XmlBasedDocument; +import cern.silecs.model.exception.SilecsException; +import cern.silecs.view.console.ConsoleHandler; +import cern.silecs.view.editor.XMLMultiPageEditor; +import cern.silecs.view.editor.internal.SchemaHelper; +import cern.silecs.view.marker.SilecsMarker; + +@SuppressWarnings("restriction") +public class ValidationJob extends BaseFileJob +{ + private static final String JOB_NAME = "silecs validation job"; + + public ValidationJob(IFile file) { + this(JOB_NAME, file); + + } + + public ValidationJob(String name, IFile file) { + super(name, file); + } + + @Override + public IStatus runInWorkspace(IProgressMonitor monitor) throws CoreException { + boolean hasErros = false; + try + { + // monitor.beginTask(Messages.get(Message.VALIDATION_PROCESS) + " ...", silecsFiles.size() * 2); + monitor.beginTask("Validation Job", 1); + try + { + hasErros = !isValid(file, new SubProgressMonitor(monitor, 1)); + file.refreshLocal(IResource.DEPTH_ZERO, null); + } + catch (Exception e) + { + failures.put(file, e); + } + + return computeReturnStatus(); + } + finally + { + // Open problem view if there are some errors + if (hasErros) { + Display.getDefault().syncExec(new Runnable() { + + @Override + public void run() { + IWorkbenchPage activepage = PlatformUI.getWorkbench().getActiveWorkbenchWindow() + .getActivePage(); + IViewPart pbv = activepage.findView("org.eclipse.ui.views.ProblemView"); + if (pbv != null) { + activepage.bringToTop(pbv); + } + } + }); + } + + monitor.done(); + } + } + + protected boolean isValid(IFile silecsFile, IProgressMonitor monitor) { + IProgressMonitor mon = monitor; + if (mon == null) { + mon = new NullProgressMonitor(); + } + + try { + mon.beginTask("Validation", 1); + + List<SilecsDocumentError> errors = null; + + File file = new File(silecsFile.getLocationURI()); + + errors = Validator.validate(file); + + final XMLMultiPageEditor editor = XMLMultiPageEditor.getOpenedEditor(silecsFile); + + updateMarkers(silecsFile, errors, editor); + + // return true if document is valid + if (errors.isEmpty()) { + ConsoleHandler.printMessage("Document " + silecsFile.getName() + " is valid", true); + return true; + } + ConsoleHandler.printError("Document " + silecsFile.getName() + " is not valid", true); + return false; + } finally { + mon.done(); + } + } + + private void updateMarkers(IFile silecsFile, List<SilecsDocumentError> errors, XMLMultiPageEditor editor) { + // remove old markers + try + { + silecsFile.deleteMarkers(SilecsMarker.TYPE, false, IResource.DEPTH_ZERO); + } + catch (CoreException e) + { + ConsoleHandler.printStackTrace(e); + } + + for (SilecsDocumentError error : errors) + { + try + { + createMarker(silecsFile, error, editor); + } + catch (Exception e) + { + ConsoleHandler.printMessage("Could not create marker for " + error, true); + } + } + + } + + private IMarker createMarker(IFile file, SilecsDocumentError error, XMLMultiPageEditor editor) throws CoreException, SilecsException { + IStructuredModel model = StructuredModelManager.getModelManager().getExistingModelForRead(file); + if (model instanceof IDOMModel) + { + try { + NodeImpl hintNode = null; + XmlBasedDocument xmlDocument = new XmlBasedDocument(((IDOMModel) model).getDocument()); + + if (error.xPath != null) + { + hintNode = (NodeImpl) xmlDocument.getSingleNode(error.xPath); + } + + // first try to get accurate not thanks to the schema + if (error.isIdentityConstraintError() && hintNode instanceof Element) { + XSDIdentityConstraintDefinition def = SchemaHelper.findIdentityConstraint((Element) hintNode, + error.violatedKey); + + // def = null can happen when eclipse has not finished to build the schema + if (def != null) { + List<Node> candidates = xmlDocument.getNodes(hintNode, def.getSelector().getValue()); + for (Node candidate : candidates) { + for (XSDXPathDefinition field : def.getFields()) { + List<Node> values = xmlDocument.getNodes(candidate, field.getValue()); + for (Node v : values) { + if ((v instanceof AttrImpl && ((AttrImpl) v).getValue() + .equals(error.incorrectValue)) + || (v instanceof Element) + && ((ElementImpl) v).getTextContent().equals(error.incorrectValue)) { + return SilecsMarker.create(file, error, (NodeImpl) v); + } + } + } + } + } + } + + // try to get the node thanks to the document position + if (editor != null) { + NodeImpl node = editor.getNodeAtPosition(error.lineNumber, error.columnNumber); + if (node != null) { + hintNode = node; + } + } + + // if fail, use the hint node found with the xpath provided by the validator + if (hintNode != null) { + return SilecsMarker.create(file, error, hintNode); + } + } + catch (SilecsException e) + { + ConsoleHandler.printMessage("Could not get precise location for marker: " + e.getMessage(), true); + throw e; + } + } + return SilecsMarker.create(file, error); + } + +} diff --git a/silecs-eclipse-plugin/src/java/cern/silecs/view/marker/SilecsMarker.java b/silecs-eclipse-plugin/src/java/cern/silecs/view/marker/SilecsMarker.java new file mode 100644 index 0000000..ea12b39 --- /dev/null +++ b/silecs-eclipse-plugin/src/java/cern/silecs/view/marker/SilecsMarker.java @@ -0,0 +1,64 @@ +// Copyright 2016 CERN and GSI +// +// 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 3 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, see <http://www.gnu.org/licenses/>. + +package cern.silecs.view.marker; + +import org.eclipse.core.resources.IFile; +import org.eclipse.core.resources.IMarker; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.wst.xml.core.internal.document.NodeImpl; + +import cern.silecs.model.document.SilecsDocumentError; + +@SuppressWarnings("restriction") +public abstract class SilecsMarker { + +// private static final Logger LOGGER = LoggerFactory.getLogger(SilecsMarker.class); + + public static final String TYPE = "cern.silecs.view.marker"; + + public static final String NODE_ATTR = "node"; + + public static IMarker create(IFile file, SilecsDocumentError error, NodeImpl node) throws CoreException { + IMarker marker = create(file, error); + if (node != null) { + marker.setAttribute(IMarker.CHAR_START, node.getStartOffset()); + marker.setAttribute(IMarker.CHAR_END, node.getEndOffset()); + marker.setAttribute(NODE_ATTR, node); + } + + return marker; + } + + public static IMarker create(IFile file, SilecsDocumentError error) throws CoreException { + IMarker marker = file.createMarker(SilecsMarker.TYPE); + + marker.setAttribute(IMarker.MESSAGE, error.message); + marker.setAttribute(IMarker.LINE_NUMBER, error.lineNumber); + switch (error.level) { + case INFO: + marker.setAttribute(IMarker.SEVERITY, IMarker.SEVERITY_INFO); + break; + case WARNING: + marker.setAttribute(IMarker.SEVERITY, IMarker.SEVERITY_WARNING); + break; + default: + marker.setAttribute(IMarker.SEVERITY, IMarker.SEVERITY_ERROR); + break; + } + + return marker; + } +} diff --git a/silecs-eclipse-plugin/src/java/cern/silecs/view/marker/SilecsMarkerUpdater.java b/silecs-eclipse-plugin/src/java/cern/silecs/view/marker/SilecsMarkerUpdater.java new file mode 100644 index 0000000..ed8193f --- /dev/null +++ b/silecs-eclipse-plugin/src/java/cern/silecs/view/marker/SilecsMarkerUpdater.java @@ -0,0 +1,48 @@ +// Copyright 2016 CERN and GSI +// +// 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 3 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, see <http://www.gnu.org/licenses/>. + +package cern.silecs.view.marker; + +import org.eclipse.core.resources.IMarker; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.jface.text.IDocument; +import org.eclipse.jface.text.Position; +import org.eclipse.ui.texteditor.IMarkerUpdater; + +public class SilecsMarkerUpdater implements IMarkerUpdater { + + @Override + public String getMarkerType() { + return SilecsMarker.TYPE; + } + + @Override + public String[] getAttribute() { + return null; + } + + @Override + public boolean updateMarker(IMarker marker, IDocument document, Position position) { + try { + int start = position.getOffset(); + int end = position.getOffset() + position.getLength(); + marker.setAttribute(IMarker.CHAR_START, start); + marker.setAttribute(IMarker.CHAR_END, end); + return true; + } catch (CoreException e) { + return false; + } + } +} diff --git a/silecs-eclipse-plugin/src/java/cern/silecs/view/preferences/EditorPreferencePage.java b/silecs-eclipse-plugin/src/java/cern/silecs/view/preferences/EditorPreferencePage.java new file mode 100644 index 0000000..8ed40f1 --- /dev/null +++ b/silecs-eclipse-plugin/src/java/cern/silecs/view/preferences/EditorPreferencePage.java @@ -0,0 +1,232 @@ +// Copyright 2016 CERN and GSI +// +// 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 3 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, see <http://www.gnu.org/licenses/>. + +package cern.silecs.view.preferences; + +import org.eclipse.jface.preference.ColorSelector; +import org.eclipse.jface.preference.IPreferenceStore; +import org.eclipse.jface.preference.PreferencePage; +import org.eclipse.swt.SWT; +import org.eclipse.swt.graphics.RGB; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.layout.GridLayout; +import org.eclipse.swt.layout.RowLayout; +import org.eclipse.swt.widgets.Button; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Control; +import org.eclipse.swt.widgets.Event; +import org.eclipse.swt.widgets.Group; +import org.eclipse.swt.widgets.Label; +import org.eclipse.swt.widgets.Listener; +import org.eclipse.ui.IWorkbench; +import org.eclipse.ui.IWorkbenchPreferencePage; + +import cern.silecs.activator.Activator; + +public class EditorPreferencePage extends PreferencePage implements IWorkbenchPreferencePage { + +// // validate on save +// public static final String VALIDATE_ON_SAVE = "VALIDATE_ON_SAVE"; +// +// // colors +// public static final String EDITABLE_COLOR_R = "XML_EDITOR_COLOR_EDITABLE_R"; +// public static final String EDITABLE_COLOR_G = "XML_EDITOR_COLOR_EDITABLE_G"; +// public static final String EDITABLE_COLOR_B = "XML_EDITOR_COLOR_EDITABLE_B"; +// +// public static final String CONTENT_COLOR_R = "XML_EDITOR_COLOR_CONTENT_R"; +// public static final String CONTENT_COLOR_G = "XML_EDITOR_COLOR_CONTENT_G"; +// public static final String CONTENT_COLOR_B = "XML_EDITOR_COLOR_CONTENT_B"; +// +// // link documentation to the editor +// public static final String LINK_DOCUMENTATION = "DISPLAY_DOCUMENTATION"; +// public static final String BRING_DOCUMENTATION_TO_FRONT = "DOCUMENTATION_TO_FRONT"; +// +// public static final String SHOW_GENERATED = "SHOW_GENERATED"; +// +// // default theme +// public static final RGB DEFAULT_EDITABLE = new RGB(0, 0, 0); +// public static final RGB DEFAULT_CONTENT = new RGB(130, 170, 150); +// +// // ocean theme +// public static final RGB OCEAN_EDITABLE = new RGB(0, 0, 128); +// public static final RGB OCEAN_CONTENT = new RGB(0, 206, 209); +// +// // fire theme +// public static final RGB FIRE_EDITABLE = new RGB(205, 79, 57); +// public static final RGB FIRE_CONTENT = new RGB(205, 205, 0); +// +// private Button validationOnSave; +// +// private ColorSelector editableColorSelector; +// private ColorSelector contentColorSelector; +// +// private Button linkDocumentation; +// private Button bringDocumentationToFront; +// private Button showGeneratedContent; + + @Override + public void init(IWorkbench workbench) { + setPreferenceStore(Activator.getDefault().getPreferenceStore()); + setDescription("Not yet available"); + } + + @Override + protected Control createContents(Composite parent) { + Composite container = new Composite(parent, SWT.NONE); +// +// IPreferenceStore prefs = getPreferenceStore(); +// + GridLayout layout = new GridLayout(1, false); + container.setLayout(layout); +// +// // validation options +// Group validationGroup = new Group(container, SWT.NONE); +// validationGroup.setText("Validation"); +// validationGroup.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, false)); +// layout = new GridLayout(1, false); +// validationGroup.setLayout(layout); +// validationOnSave = new Button(validationGroup, SWT.CHECK); +// validationOnSave.setText("Validate after Safe"); +// validationOnSave.setSelection(prefs.getBoolean(VALIDATE_ON_SAVE)); +// +// // color options +// Group colorGroup = new Group(container, SWT.NONE); +// colorGroup.setText("Colors"); +// colorGroup.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, false)); +// layout = new GridLayout(2, false); +// colorGroup.setLayout(layout); +// +// Label editableColorLabel = new Label(colorGroup, SWT.NONE); +// editableColorLabel.setText("Editable Text color"); +// +// contentColorSelector = new ColorSelector(colorGroup); +// RGB contentColor = new RGB(prefs.getInt(CONTENT_COLOR_R), prefs.getInt(CONTENT_COLOR_G), +// prefs.getInt(CONTENT_COLOR_B)); +// contentColorSelector.setColorValue(contentColor); +// +// Label contentColorLabel = new Label(colorGroup, SWT.NONE); +// contentColorLabel.setText("Content Text Color"); +// +// editableColorSelector = new ColorSelector(colorGroup); +// RGB editableColor = new RGB(prefs.getInt(EDITABLE_COLOR_R), prefs.getInt(EDITABLE_COLOR_G), +// prefs.getInt(EDITABLE_COLOR_B)); +// editableColorSelector.setColorValue(editableColor); +// +// Group buttonGroup = new Group(colorGroup, SWT.NONE); +// buttonGroup.setText("Color Scheme"); +// RowLayout buttonLayout = new RowLayout(SWT.HORIZONTAL); +// buttonLayout.marginLeft = 5; +// buttonLayout.marginRight = 5; +// buttonLayout.marginTop = 5; +// buttonLayout.marginBottom = 5; +// buttonLayout.spacing = 5; +// buttonLayout.pack = false; +// buttonLayout.justify = true; +// buttonGroup.setLayout(buttonLayout); +// GridData buttonGridData = new GridData(SWT.FILL, SWT.FILL, true, false); +// buttonGridData.horizontalSpan = 2; +// buttonGroup.setLayoutData(buttonGridData); +// +// +// Button defaultScheme = new Button(buttonGroup, SWT.PUSH); +// defaultScheme.setText("default"); +// +// Button oceanScheme = new Button(buttonGroup, SWT.PUSH); +// oceanScheme.setText("ocean"); +// +// Button fireScheme = new Button(buttonGroup, SWT.PUSH); +// fireScheme.setText("fire"); +// +// defaultScheme.addListener(SWT.Selection, new Listener() { +// +// @Override +// public void handleEvent(Event event) { +// contentColorSelector.setColorValue(DEFAULT_CONTENT); +// editableColorSelector.setColorValue(DEFAULT_EDITABLE); +// } +// }); +// +// oceanScheme.addListener(SWT.Selection, new Listener() { +// +// @Override +// public void handleEvent(Event event) { +// contentColorSelector.setColorValue(OCEAN_CONTENT); +// editableColorSelector.setColorValue(OCEAN_EDITABLE); +// } +// }); +// +// fireScheme.addListener(SWT.Selection, new Listener() { +// +// @Override +// public void handleEvent(Event event) { +// contentColorSelector.setColorValue(FIRE_CONTENT); +// editableColorSelector.setColorValue(FIRE_EDITABLE); +// } +// }); +// +// Group others = new Group(container, SWT.NONE); +// others.setText("Others"); +// others.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, false)); +// layout = new GridLayout(1, false); +// others.setLayout(layout); +// linkDocumentation = new Button(others, SWT.CHECK); +// linkDocumentation.setText("Link Documentation"); +// linkDocumentation.setSelection(prefs.getBoolean(LINK_DOCUMENTATION)); +// bringDocumentationToFront = new Button(others, SWT.CHECK); +// bringDocumentationToFront.setText("Bring Documentation to Front"); +// bringDocumentationToFront.setSelection(prefs.getBoolean(BRING_DOCUMENTATION_TO_FRONT)); +// +// showGeneratedContent = new Button(others, SWT.CHECK); +// showGeneratedContent.setText("Show generated content"); +// showGeneratedContent.setSelection(prefs.getBoolean(SHOW_GENERATED)); +// + return container; + } +// + @Override + public boolean performOk() { +// IPreferenceStore prefs = getPreferenceStore(); +// +// RGB content = contentColorSelector.getColorValue(); +// RGB editable = editableColorSelector.getColorValue(); +// +// prefs.setValue(VALIDATE_ON_SAVE, validationOnSave.getSelection()); +// +// prefs.setValue(CONTENT_COLOR_R, content.red); +// prefs.setValue(CONTENT_COLOR_G, content.green); +// prefs.setValue(CONTENT_COLOR_B, content.blue); +// prefs.setValue(EDITABLE_COLOR_R, editable.red); +// prefs.setValue(EDITABLE_COLOR_G, editable.green); +// prefs.setValue(EDITABLE_COLOR_B, editable.blue); +// +// prefs.setValue(LINK_DOCUMENTATION, linkDocumentation.getSelection()); +// prefs.setValue(BRING_DOCUMENTATION_TO_FRONT, bringDocumentationToFront.getSelection()); +// prefs.setValue(SHOW_GENERATED, showGeneratedContent.getSelection()); +// + return true; + } + + @Override + protected void performDefaults() { +// validationOnSave.setSelection(true); +// +// contentColorSelector.setColorValue(DEFAULT_CONTENT); +// editableColorSelector.setColorValue(DEFAULT_EDITABLE); +// +// linkDocumentation.setSelection(true); +// bringDocumentationToFront.setSelection(false); +// showGeneratedContent.setSelection(false); + } +} diff --git a/silecs-eclipse-plugin/src/java/cern/silecs/view/preferences/LoggingPreferencePage.java b/silecs-eclipse-plugin/src/java/cern/silecs/view/preferences/LoggingPreferencePage.java new file mode 100644 index 0000000..b10a026 --- /dev/null +++ b/silecs-eclipse-plugin/src/java/cern/silecs/view/preferences/LoggingPreferencePage.java @@ -0,0 +1,121 @@ +// Copyright 2016 CERN and GSI +// +// 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 3 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, see <http://www.gnu.org/licenses/>. + +package cern.silecs.view.preferences; + +import java.io.File; +import org.eclipse.jface.preference.IPreferenceStore; +import org.eclipse.jface.preference.PreferencePage; +import org.eclipse.swt.SWT; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.layout.GridLayout; +import org.eclipse.swt.widgets.Button; +import org.eclipse.swt.widgets.Combo; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Control; +import org.eclipse.swt.widgets.DirectoryDialog; +import org.eclipse.swt.widgets.Event; +import org.eclipse.swt.widgets.Label; +import org.eclipse.swt.widgets.Listener; +import org.eclipse.swt.widgets.Text; +import org.eclipse.ui.IWorkbench; +import org.eclipse.ui.IWorkbenchPreferencePage; + +import cern.silecs.activator.Activator; + +public class LoggingPreferencePage extends PreferencePage implements IWorkbenchPreferencePage { + + + public static final String[] LOG_LEVELS = { "FATAL", "ERROR", "WARN", "INFO", "DEBUG", "TRACE", "OFF" }; + public static final int DEFAULT_LOG_LEVEL_INDEX = 3; + public static final String DEFAULT_LOG_DIRECTORY = System.getProperty("user.home") + "/.logs/fesa-plugin"; + + public static final String LOG_LEVEL = "fesaLog.level"; + public static final String LOG_DIRECTORY = "fesaLog.directory"; + public static final String BRING_CONSOLE_TO_FRONT = "CONSOLE_TO_FRONT"; + + private Combo logLevel; + private Text logDirectory; + + @Override + public void init(IWorkbench workbench) { + setPreferenceStore(Activator.getDefault().getPreferenceStore()); + setDescription("SILECS Logging"); + } + + @Override + protected Control createContents(Composite parent) { + IPreferenceStore prefs = getPreferenceStore(); + + Composite container = new Composite(parent, SWT.NONE); + GridLayout layout = new GridLayout(3, false); + container.setLayout(layout); + + Label level = new Label(container, SWT.NONE); + level.setText("Log Level"); + logLevel = new Combo(container, SWT.BORDER | SWT.V_SCROLL | SWT.READ_ONLY); + logLevel.setItems(LOG_LEVELS); + logLevel.select(prefs.getInt(LOG_LEVEL)); + GridData dataLayout = new GridData(); + dataLayout.horizontalSpan = 2; + logLevel.setLayoutData(dataLayout); + + Label directory = new Label(container, SWT.NONE); + directory.setText("Log Directory"); + logDirectory = new Text(container, SWT.BORDER); + logDirectory.setText(prefs.getString(LOG_DIRECTORY)); + dataLayout = new GridData(SWT.FILL, SWT.TOP, true, false); + logDirectory.setLayoutData(dataLayout); + + Button browse = new Button(container, SWT.PUSH); + browse.setText("browse"); + browse.addListener(SWT.Selection, new Listener() { + + @Override + public void handleEvent(Event event) { + DirectoryDialog dirDialog = new DirectoryDialog(getShell()); + logDirectory.setText(dirDialog.open()); + } + }); + + return container; + } + + @Override + public boolean performOk() { + IPreferenceStore prefs = getPreferenceStore(); + + int levelIndex = logLevel.getSelectionIndex(); + File logDir = new File(logDirectory.getText()); + + if (!logDir.isDirectory()) { + setErrorMessage("Invalid Path !" + logDir.getAbsolutePath()); + return false; + } + + prefs.setValue(LOG_LEVEL, levelIndex); + prefs.setValue(LOG_DIRECTORY, logDir.getAbsolutePath()); + + + return true; + } + + @Override + protected void performDefaults() { + logLevel.select(DEFAULT_LOG_LEVEL_INDEX); + logDirectory.setText(DEFAULT_LOG_DIRECTORY); + } + +} diff --git a/silecs-eclipse-plugin/src/java/cern/silecs/view/preferences/MainPreferencePage.java b/silecs-eclipse-plugin/src/java/cern/silecs/view/preferences/MainPreferencePage.java new file mode 100644 index 0000000..20a9e8c --- /dev/null +++ b/silecs-eclipse-plugin/src/java/cern/silecs/view/preferences/MainPreferencePage.java @@ -0,0 +1,344 @@ +// Copyright 2016 CERN and GSI +// +// 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 3 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, see <http://www.gnu.org/licenses/>. + +package cern.silecs.view.preferences; + +import java.io.File; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import org.eclipse.jface.preference.FieldEditorPreferencePage; +import org.eclipse.jface.preference.IPreferenceStore; +import org.eclipse.swt.SWT; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.layout.GridLayout; +import org.eclipse.swt.widgets.Button; +import org.eclipse.swt.widgets.Combo; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Control; +import org.eclipse.swt.widgets.DirectoryDialog; +import org.eclipse.swt.widgets.Event; +import org.eclipse.swt.widgets.Label; +import org.eclipse.swt.widgets.Listener; +import org.eclipse.swt.widgets.Text; +import org.eclipse.ui.IWorkbench; +import org.eclipse.ui.IWorkbenchPreferencePage; + +import cern.silecs.activator.Activator; +import cern.silecs.model.exception.SilecsException; +import cern.silecs.view.console.ConsoleHandler; + +public class MainPreferencePage extends FieldEditorPreferencePage implements IWorkbenchPreferencePage { + + public static final String SILECS_DIRECTORY_TAG = "SILECS_DIRECTORY"; + public static final String FESA_DIRECTORY_TAG = "FESA_DIRECTORY"; + public static final String LOCAL_DIRECTORY_TAG = "LOCAL_DIRECTORY"; + public static final String USE_LOCAL_DIRECTORY_TAG = "USE_LOCAL_DIRECTORY"; + public static final String FESSA_VERSION_TAG = "FESA_VERSION"; + + public static final String SILECS_DIRECTORY_DEFAULT = "/common/usr/cscofe/silecs"; + public static final String FESA_DIRECTORY_DEFAULT = "/opt/fesa"; + public static final Boolean USE_LOCAL_DIRECTORY_DEFAULT = false; + + private static List<String> fesaVersions_ = readOutAvailableFesaVersions(); + + private static Text silecsDirectory; + private static Text fesaDirectory; + private static Button useLocalWorkspace; + private static Text localWorkspaceDirectory; + private static Combo fesaVersion; + + public static boolean isLocalDirectoryUsed() + { + IPreferenceStore prefs = Activator.getDefault().getPreferenceStore(); + return prefs.getBoolean(USE_LOCAL_DIRECTORY_TAG); + } + + public static String getGlobalSilecsDirectory() + { + IPreferenceStore prefs = Activator.getDefault().getPreferenceStore(); + return prefs.getString(SILECS_DIRECTORY_TAG); + } + + public static String getModelBasePath(String modelVersion) + { + IPreferenceStore prefs = Activator.getDefault().getPreferenceStore(); + if(prefs.getBoolean(USE_LOCAL_DIRECTORY_TAG)) + return prefs.getString(LOCAL_DIRECTORY_TAG) + "/silecs-model/src/xml"; + else + return prefs.getString(SILECS_DIRECTORY_TAG) + "/silecs-model/" + modelVersion + "/" + "xml"; + } + + public static String getCodeGenBasePath(String codegenVersion) + { + IPreferenceStore prefs = Activator.getDefault().getPreferenceStore(); + if(prefs.getBoolean(USE_LOCAL_DIRECTORY_TAG)) + return prefs.getString(LOCAL_DIRECTORY_TAG) + "/silecs-codegen/src/xml"; + else + return prefs.getString(SILECS_DIRECTORY_TAG) + "/silecs-codegen/" + codegenVersion + "/" + "xml"; + } + + public static String getDiagToolBasePath(String diagToolVersion) + { + IPreferenceStore prefs = Activator.getDefault().getPreferenceStore(); + if(prefs.getBoolean(USE_LOCAL_DIRECTORY_TAG)) + return prefs.getString(LOCAL_DIRECTORY_TAG) + "/silecs-diagnostic-cpp/build"; + else + return prefs.getString(SILECS_DIRECTORY_TAG) + "/silecs-diagnostic-cpp/" + diagToolVersion; + } + + public static String getSilecsLibraryBasePath(String silecsLibraryVersion) + { + IPreferenceStore prefs = Activator.getDefault().getPreferenceStore(); + if(prefs.getBoolean(USE_LOCAL_DIRECTORY_TAG)) + return prefs.getString(LOCAL_DIRECTORY_TAG) + "/silecs-communication-cpp/build"; + else + return prefs.getString(SILECS_DIRECTORY_TAG) + "/silecs-communication-cpp/" + silecsLibraryVersion; + } + + public static String getSNAP7LibraryBasePath(String silecsLibraryVersion) + { + IPreferenceStore prefs = Activator.getDefault().getPreferenceStore(); + if(prefs.getBoolean(USE_LOCAL_DIRECTORY_TAG)) + return prefs.getString(LOCAL_DIRECTORY_TAG) + "/snap7/snap7-full/build"; + else + return prefs.getString(SILECS_DIRECTORY_TAG) + "/snap7/" + silecsLibraryVersion; + } + + public static String getFESAVersion() throws SilecsException + { + int index = Activator.getDefault().getPreferenceStore().getInt(FESSA_VERSION_TAG); + return fesaVersions_.get(index); + } + + public static File[] getFESADesignTemplates() throws SilecsException + { + return getFESATemplates("design"); + } + + public static File[] getFESADeployUnitTemplates() throws SilecsException + { + return getFESATemplates("deployment"); + } + + public static String getFESADeployUnitSchemaPath() throws SilecsException + { + String fesaBaseDirectory = Activator.getDefault().getPreferenceStore().getString(FESA_DIRECTORY_TAG); + return new String(fesaBaseDirectory + "/fesa-model-gsi/" + getFESAVersion() + "/xml/deployment/deployment-gsi.xsd"); + } + + public static String getFESADesignSchemaPath() throws SilecsException + { + String fesaBaseDirectory = Activator.getDefault().getPreferenceStore().getString(FESA_DIRECTORY_TAG); + return new String(fesaBaseDirectory + "/fesa-model-gsi/" + getFESAVersion() + "/xml/design/design-gsi.xsd"); + } + + protected static File[] getFESATemplates(String type) throws SilecsException + { + String fesaBaseDirectory = Activator.getDefault().getPreferenceStore().getString(FESA_DIRECTORY_TAG); + File folderModel = new File(fesaBaseDirectory + "/fesa-model/" + getFESAVersion() + "/xml/" + type + "/templates"); + File folderModelGSI = new File(fesaBaseDirectory + "/fesa-model-gsi/" + getFESAVersion() + "/xml/" + type + "/templates"); + + File[] templatesModel = folderModel.listFiles(); + if( templatesModel == null) + templatesModel = new File[0]; + + File[] templatesModelGSI = folderModelGSI.listFiles(); + if( templatesModelGSI == null) + templatesModelGSI = new File[0]; + + if ( (templatesModel.length + templatesModelGSI.length) == 0 ) + { + ConsoleHandler.printMessage("Template search folder 1: " + folderModel.getPath(), true); + ConsoleHandler.printMessage("Template search folder 2: " + folderModelGSI.getPath(), true); + throw new SilecsException("No templates found there! Please fix the 'FESA Base Path' in the Preferences!"); + } + File[] templates= new File[templatesModel.length+templatesModelGSI.length]; + System.arraycopy(templatesModel, 0, templates, 0, templatesModel.length); + System.arraycopy(templatesModelGSI, 0, templates, templatesModel.length, templatesModelGSI.length); + return templates; + } + + public static String getLocalDirectoryDefault() + { + return System.getProperty("user.home") + "/workspace"; + } + + @Override + protected void createFieldEditors() + { + // TODO Auto-generated method stub + } + + @Override + public void init(IWorkbench workbench) + { + setDescription("SILECS Preferences"); + setPreferenceStore(Activator.getDefault().getPreferenceStore()); + } + + protected void switchEnableLocalWorkspace(Boolean localEnabled) + { + fesaDirectory.setEnabled(true);//to stay backward -compartible + silecsDirectory.setEnabled(!localEnabled); + localWorkspaceDirectory.setEnabled(localEnabled); + } + + public static List<String> getAllFesaVersions() + { + return fesaVersions_; + } + + protected static List<String> readOutAvailableFesaVersions() + { + String fesaModelDirectory = Activator.getDefault().getPreferenceStore().getString(FESA_DIRECTORY_TAG) + "/fesa-model-gsi"; + File fesaBaseFolder = new File(fesaModelDirectory); + + List<String> fesaVersions = new ArrayList<String>(); + for (final File fileEntry : fesaBaseFolder.listFiles()) + { + fesaVersions.add(fileEntry.getName()); + } + Collections.sort(fesaVersions); + Collections.reverse(fesaVersions); + return fesaVersions; + } + + @Override + protected Control createContents(Composite parent) + { + IPreferenceStore prefs = getPreferenceStore(); + + Composite container = new Composite(parent, SWT.NONE); + GridLayout layout = new GridLayout(3, false); + container.setLayout(layout); + + GridData dataLayout = new GridData(); + dataLayout.horizontalSpan = 2; + + { // fesa base + Label directory = new Label(container, SWT.NONE); + directory.setText("FESA Base Path"); + fesaDirectory = new Text(container, SWT.BORDER); + fesaDirectory.setText(prefs.getString(FESA_DIRECTORY_TAG)); + dataLayout = new GridData(SWT.FILL, SWT.TOP, true, false); + fesaDirectory.setLayoutData(dataLayout); + + Button browse = new Button(container, SWT.PUSH); + browse.setText("browse"); + browse.addListener(SWT.Selection, new Listener() { + + @Override + public void handleEvent(Event event) { + DirectoryDialog dirDialog = new DirectoryDialog(getShell()); + fesaDirectory.setText(dirDialog.open()); + } + }); + } + + { // FESA version + Label level = new Label(container, SWT.NONE); + level.setText("FESA Version to use"); + fesaVersion = new Combo(container, SWT.BORDER | SWT.V_SCROLL | SWT.READ_ONLY); + fesaVersion.setItems(fesaVersions_.toArray(new String[fesaVersions_.size()])); + fesaVersion.select(prefs.getInt(FESSA_VERSION_TAG)); + dataLayout = new GridData(); + dataLayout.horizontalSpan = 2; + fesaVersion.setLayoutData(dataLayout); + } + + { // silecs base + Label directory = new Label(container, SWT.NONE); + directory.setText("SILECS Base Path"); + silecsDirectory = new Text(container, SWT.BORDER); + silecsDirectory.setText(prefs.getString(SILECS_DIRECTORY_TAG)); + dataLayout = new GridData(SWT.FILL, SWT.TOP, true, false); + silecsDirectory.setLayoutData(dataLayout); + + Button browse = new Button(container, SWT.PUSH); + browse.setText("browse"); + browse.addListener(SWT.Selection, new Listener() { + + @Override + public void handleEvent(Event event) { + DirectoryDialog dirDialog = new DirectoryDialog(getShell()); + silecsDirectory.setText(dirDialog.open()); + } + }); + } + + useLocalWorkspace = new Button(container, SWT.CHECK); + useLocalWorkspace.setText("Use local workspace"); + dataLayout = new GridData(SWT.FILL, SWT.TOP, true, false); + dataLayout.horizontalSpan = 3; + useLocalWorkspace.setLayoutData(dataLayout); + useLocalWorkspace.setSelection(prefs.getBoolean(USE_LOCAL_DIRECTORY_TAG)); + useLocalWorkspace.addListener(SWT.Selection, new Listener() { + @Override + public void handleEvent(Event event) { + switchEnableLocalWorkspace(useLocalWorkspace.getSelection()); + } + }); + + { // Local SILECS Workspace + Label directory = new Label(container, SWT.NONE); + directory.setText("Local SILECS Workspace"); + localWorkspaceDirectory = new Text(container, SWT.BORDER); + localWorkspaceDirectory.setText(prefs.getString(LOCAL_DIRECTORY_TAG)); + dataLayout = new GridData(SWT.FILL, SWT.TOP, true, false); + localWorkspaceDirectory.setLayoutData(dataLayout); + + Button browse = new Button(container, SWT.PUSH); + browse.setText("browse"); + browse.addListener(SWT.Selection, new Listener() { + + @Override + public void handleEvent(Event event) { + DirectoryDialog dirDialog = new DirectoryDialog(getShell()); + localWorkspaceDirectory.setText(dirDialog.open()); + } + }); + } + + switchEnableLocalWorkspace(useLocalWorkspace.getSelection()); + return container; + } + + @Override + public boolean performOk() + { + IPreferenceStore prefs = getPreferenceStore(); + prefs.setValue(SILECS_DIRECTORY_TAG, silecsDirectory.getText()); + prefs.setValue(FESA_DIRECTORY_TAG, fesaDirectory.getText()); + prefs.setValue(USE_LOCAL_DIRECTORY_TAG, useLocalWorkspace.getSelection()); + prefs.setValue(LOCAL_DIRECTORY_TAG, localWorkspaceDirectory.getText()); + prefs.setValue(FESSA_VERSION_TAG, fesaVersion.getSelectionIndex()); + return true; + } + + @Override + protected void performDefaults() + { + silecsDirectory.setText(SILECS_DIRECTORY_DEFAULT); + fesaDirectory.setText(FESA_DIRECTORY_DEFAULT); + useLocalWorkspace.setSelection(USE_LOCAL_DIRECTORY_DEFAULT); + localWorkspaceDirectory.setText(MainPreferencePage.getLocalDirectoryDefault()); + localWorkspaceDirectory.setEnabled(false); + fesaVersion.select(0); + switchEnableLocalWorkspace(useLocalWorkspace.getSelection()); + } + +} diff --git a/silecs-eclipse-plugin/src/java/cern/silecs/view/preferences/PreferenceInitializer.java b/silecs-eclipse-plugin/src/java/cern/silecs/view/preferences/PreferenceInitializer.java new file mode 100644 index 0000000..f82a6d2 --- /dev/null +++ b/silecs-eclipse-plugin/src/java/cern/silecs/view/preferences/PreferenceInitializer.java @@ -0,0 +1,59 @@ +// Copyright 2016 CERN and GSI +// +// 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 3 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, see <http://www.gnu.org/licenses/>. + +package cern.silecs.view.preferences; + + +import org.eclipse.core.runtime.preferences.AbstractPreferenceInitializer; +import org.eclipse.jface.preference.IPreferenceStore; +import org.eclipse.swt.graphics.RGB; + +import cern.silecs.activator.Activator; + + +public class PreferenceInitializer extends AbstractPreferenceInitializer { + + @Override + public void initializeDefaultPreferences() { + IPreferenceStore prefs = Activator.getDefault().getPreferenceStore(); + + prefs.setDefault(MainPreferencePage.SILECS_DIRECTORY_TAG, MainPreferencePage.SILECS_DIRECTORY_DEFAULT); + prefs.setDefault(MainPreferencePage.FESA_DIRECTORY_TAG, MainPreferencePage.FESA_DIRECTORY_DEFAULT); + prefs.setDefault(MainPreferencePage.LOCAL_DIRECTORY_TAG, MainPreferencePage.getLocalDirectoryDefault()); + prefs.setDefault(MainPreferencePage.USE_LOCAL_DIRECTORY_TAG, MainPreferencePage.USE_LOCAL_DIRECTORY_DEFAULT); + + // init the xml editor preferences +// prefs.setDefault(EditorPreferencePage.VALIDATE_ON_SAVE, true); +// +// RGB dflt = EditorPreferencePage.DEFAULT_EDITABLE; +// prefs.setDefault(EditorPreferencePage.EDITABLE_COLOR_R, dflt.red); +// prefs.setDefault(EditorPreferencePage.EDITABLE_COLOR_G, dflt.green); +// prefs.setDefault(EditorPreferencePage.EDITABLE_COLOR_B, dflt.blue); +// +// dflt = EditorPreferencePage.DEFAULT_CONTENT; +// prefs.setDefault(EditorPreferencePage.CONTENT_COLOR_R, dflt.red); +// prefs.setDefault(EditorPreferencePage.CONTENT_COLOR_G, dflt.green); +// prefs.setDefault(EditorPreferencePage.CONTENT_COLOR_B, dflt.blue); +// +// prefs.setDefault(EditorPreferencePage.LINK_DOCUMENTATION, true); +// prefs.setDefault(EditorPreferencePage.BRING_DOCUMENTATION_TO_FRONT, false); +// prefs.setDefault(EditorPreferencePage.SHOW_GENERATED, false); + + // logging preferences + prefs.setDefault(LoggingPreferencePage.LOG_LEVEL, LoggingPreferencePage.DEFAULT_LOG_LEVEL_INDEX); + prefs.setDefault(LoggingPreferencePage.LOG_DIRECTORY, LoggingPreferencePage.DEFAULT_LOG_DIRECTORY); + prefs.setDefault(LoggingPreferencePage.BRING_CONSOLE_TO_FRONT, true); + } +} diff --git a/silecs-eclipse-plugin/src/java/cern/silecs/view/wizards/GenerateCodeWizard.java b/silecs-eclipse-plugin/src/java/cern/silecs/view/wizards/GenerateCodeWizard.java new file mode 100644 index 0000000..05ab3ed --- /dev/null +++ b/silecs-eclipse-plugin/src/java/cern/silecs/view/wizards/GenerateCodeWizard.java @@ -0,0 +1,70 @@ +// Copyright 2016 CERN and GSI +// +// 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 3 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, see <http://www.gnu.org/licenses/>. + +package cern.silecs.view.wizards; +import java.io.File; +import java.util.ArrayList; +import java.util.List; + +import org.eclipse.jface.wizard.Wizard; + +import cern.silecs.view.console.ConsoleHandler; +import cern.silecs.view.wizards.page.PickTemplatePage; + +public class GenerateCodeWizard extends Wizard +{ + private File[] templates; + File choice = null; + PickTemplatePage page; + + public GenerateCodeWizard(File[] templateFiles) { + super(); + setWindowTitle("Pick a template"); + templates = templateFiles; + } + + @Override + public void addPages() { + super.addPages(); + + List<String> templateNames = new ArrayList<String>(); + for( File file : templates) + { + templateNames.add(file.getName()); + } + String[] simpleArray = new String[ templateNames.size() ]; + page = new PickTemplatePage("Pick a template",templateNames.toArray(simpleArray)); + addPage(page); + } + + public File getChoice() + { + return choice; + } + + @Override + public boolean performFinish() { + String template = page.getTemplate(); + //ConsoleHandler.printMessage("template selected: " + template , true); + for( File file : templates) + { + //ConsoleHandler.printMessage("file available: " + file.getName() , true); + if( file.getName().equals(template)) + choice = file; + } + //ConsoleHandler.printMessage("choice full path: " + choice.getAbsolutePath() , true); + return true; + } +} diff --git a/silecs-eclipse-plugin/src/java/cern/silecs/view/wizards/ImportDeployFileWizard.java b/silecs-eclipse-plugin/src/java/cern/silecs/view/wizards/ImportDeployFileWizard.java new file mode 100644 index 0000000..496d5b7 --- /dev/null +++ b/silecs-eclipse-plugin/src/java/cern/silecs/view/wizards/ImportDeployFileWizard.java @@ -0,0 +1,79 @@ +// Copyright 2016 CERN and GSI +// +// 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 3 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, see <http://www.gnu.org/licenses/>. + +package cern.silecs.view.wizards; + +import org.eclipse.core.resources.IProject; +import org.eclipse.core.resources.IWorkspaceRoot; +import org.eclipse.core.resources.ResourcesPlugin; +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.NullProgressMonitor; +import org.eclipse.jface.wizard.Wizard; + +import cern.silecs.control.core.DeployProjectNature; +import cern.silecs.utils.SilecsConstants; +import cern.silecs.utils.SilecsUtils; +import cern.silecs.utils.XmlUtils; +import cern.silecs.view.console.ConsoleHandler; +import cern.silecs.view.wizards.page.ChooseFilePage; +import cern.silecs.view.wizards.page.SilecsProjectPage; + +public class ImportDeployFileWizard extends Wizard { + + private ChooseFilePage firstPage; + private SilecsProjectPage secondPage; + + public ImportDeployFileWizard() { + setWindowTitle("Import Deploy-Unit File Wizard"); + } + + @Override + public void addPages() { + super.addPages(); + + firstPage = new ChooseFilePage("Import Deploy-Unit file to workspace", SilecsConstants.ProjectType.DEPLOY_PROJECT); + secondPage = new SilecsProjectPage("Import Deploy-Unit file to workspace", + SilecsConstants.ProjectType.DEPLOY_PROJECT, + "Enter new deploy-unit name", + "Enter new deploy-unit version"); + + addPage(firstPage); + addPage(secondPage); + } + + @Override + public boolean performFinish() { + try { + ConsoleHandler.clear(); + IWorkspaceRoot workspaceRoot = ResourcesPlugin.getWorkspace().getRoot(); + + String newDeployName = secondPage.getprojectNameText(); + IProject project = workspaceRoot.getProject(newDeployName); + + XmlUtils.reloadDependencies(); + + IProgressMonitor monitor = new NullProgressMonitor(); + DeployProjectNature.addDeployNature(project, monitor); + + SilecsUtils.openInEditor(SilecsUtils.getSilecsDeployFile(project)); + } catch (Exception e) { + e.printStackTrace(); + ConsoleHandler.printStackTrace(e); + } + + return true; + } + +} diff --git a/silecs-eclipse-plugin/src/java/cern/silecs/view/wizards/ImportDesignFileWizard.java b/silecs-eclipse-plugin/src/java/cern/silecs/view/wizards/ImportDesignFileWizard.java new file mode 100644 index 0000000..76afc40 --- /dev/null +++ b/silecs-eclipse-plugin/src/java/cern/silecs/view/wizards/ImportDesignFileWizard.java @@ -0,0 +1,76 @@ +// Copyright 2016 CERN and GSI +// +// 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 3 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, see <http://www.gnu.org/licenses/>. + +package cern.silecs.view.wizards; + +import org.eclipse.core.resources.IProject; +import org.eclipse.core.resources.IWorkspaceRoot; +import org.eclipse.core.resources.ResourcesPlugin; +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.NullProgressMonitor; +import org.eclipse.jface.wizard.Wizard; + +import cern.silecs.control.core.DesignProjectNature; +import cern.silecs.utils.SilecsConstants; +import cern.silecs.utils.SilecsUtils; +import cern.silecs.view.console.ConsoleHandler; +import cern.silecs.view.wizards.page.ChooseFilePage; +import cern.silecs.view.wizards.page.SilecsProjectPage; + +public class ImportDesignFileWizard extends Wizard { + + private ChooseFilePage firstPage; + private SilecsProjectPage secondPage; + + public ImportDesignFileWizard() { + setWindowTitle("Import Design File Wizard"); + } + + @Override + public void addPages() { + super.addPages(); + + firstPage = new ChooseFilePage("Import Design file to workspace", SilecsConstants.ProjectType.DESIGN_PROJECT); + secondPage = new SilecsProjectPage("Set Design properties", + SilecsConstants.ProjectType.DESIGN_PROJECT, + "Enter new deploy-unit name", + "Enter new deploy-unit version"); + + addPage(firstPage); + addPage(secondPage); + } + + @Override + public boolean performFinish() { + try { + ConsoleHandler.clear(); + IWorkspaceRoot workspaceRoot = ResourcesPlugin.getWorkspace().getRoot(); + + String designName = secondPage.getprojectNameText(); + IProject project = workspaceRoot.getProject(designName); + + IProgressMonitor monitor = new NullProgressMonitor(); + DesignProjectNature.addClassNature(project, monitor); + + SilecsUtils.openInEditor(SilecsUtils.getSilecsDesignFile(project)); + + } catch (Exception e) { + e.printStackTrace(); + ConsoleHandler.printStackTrace(e); + } + return true; + } + +} diff --git a/silecs-eclipse-plugin/src/java/cern/silecs/view/wizards/NewSilecsDeployWizard.java b/silecs-eclipse-plugin/src/java/cern/silecs/view/wizards/NewSilecsDeployWizard.java new file mode 100644 index 0000000..4cde66a --- /dev/null +++ b/silecs-eclipse-plugin/src/java/cern/silecs/view/wizards/NewSilecsDeployWizard.java @@ -0,0 +1,113 @@ +// Copyright 2016 CERN and GSI +// +// 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 3 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, see <http://www.gnu.org/licenses/>. + +package cern.silecs.view.wizards; + +import java.io.File; + +import org.eclipse.core.resources.IFile; +import org.eclipse.core.resources.IProject; +import org.eclipse.core.resources.IProjectDescription; +import org.eclipse.core.resources.IResource; +import org.eclipse.core.resources.IWorkspaceRoot; +import org.eclipse.core.resources.ResourcesPlugin; +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.NullProgressMonitor; +import org.eclipse.jface.viewers.IStructuredSelection; +import org.eclipse.jface.wizard.Wizard; +import org.eclipse.ui.INewWizard; +import org.eclipse.ui.IWorkbench; + +import cern.silecs.control.core.DeployProjectNature; +import cern.silecs.model.exception.SilecsException; +import cern.silecs.utils.SilecsConstants; +import cern.silecs.utils.OSExecute; +import cern.silecs.utils.SilecsUtils; +import cern.silecs.utils.XmlUtils; +import cern.silecs.view.console.ConsoleHandler; +import cern.silecs.view.preferences.MainPreferencePage; +import cern.silecs.view.wizards.page.SilecsProjectPage; + +public class NewSilecsDeployWizard extends Wizard implements INewWizard +{ + + SilecsProjectPage page; + + public NewSilecsDeployWizard() { + super(); + setWindowTitle(SilecsConstants.NEW_DEPLOY_WIZARD_TITLE); + } + + @Override + public void addPages() { + super.addPages(); + page = new SilecsProjectPage(SilecsConstants.NEW_DEPLOY_PAGE_TITLE, + SilecsConstants.ProjectType.DEPLOY_PROJECT, + "Enter deploy-unit name", + "Enter silecs version"); + addPage(page); + } + + @Override + public boolean performFinish() + { + try + { + ConsoleHandler.clear(); + String deployName = page.getprojectNameText(); + String silecsVersion = page.getsilecsVersionText(); + String deploySchema = MainPreferencePage.getModelBasePath(silecsVersion) + "/" + SilecsConstants.DEPLOY_SCHEMA_XSD; + if(! new File(deploySchema).exists()) + { + throw new SilecsException("The Deploy Schema: '" + deploySchema + "' does not exist. Please check your Eclipse-Silecs preferences!"); + } + IWorkspaceRoot workspaceRoot = ResourcesPlugin.getWorkspace().getRoot(); + String workspacePath = workspaceRoot.getLocation().toFile().getPath(); + + IProject project = workspaceRoot.getProject(deployName); + OSExecute.executePython("iefiles","newDeployProject",silecsVersion,new String[]{workspacePath, deployName,deploySchema,silecsVersion}); + XmlUtils.reloadDependencies(); + + IFile deployFile = SilecsUtils.getSilecsDeployFile(project); + + IProgressMonitor monitor = new NullProgressMonitor(); + //project.create(monitor); + //DeployProjectNature.addDeployNature(project, monitor); TODO: No idea why this does not work + + IProjectDescription description = project.getWorkspace().newProjectDescription(project.getName()); + String[] newNatures = new String[1]; + newNatures[0] = DeployProjectNature.NATURE_ID; + description.setNatureIds(newNatures); + + project.create(description, null); + + project.open(IResource.FORCE, monitor); + + SilecsUtils.openInEditor(deployFile); + } + catch (Exception e) + { + e.printStackTrace(); + ConsoleHandler.printStackTrace(e); + } + return true; + } + + @Override + public void init(IWorkbench arg0, IStructuredSelection arg1) { + // TODO Auto-generated method stub + + } +} diff --git a/silecs-eclipse-plugin/src/java/cern/silecs/view/wizards/NewSilecsDesignWizard.java b/silecs-eclipse-plugin/src/java/cern/silecs/view/wizards/NewSilecsDesignWizard.java new file mode 100644 index 0000000..7d915f5 --- /dev/null +++ b/silecs-eclipse-plugin/src/java/cern/silecs/view/wizards/NewSilecsDesignWizard.java @@ -0,0 +1,115 @@ +// Copyright 2016 CERN and GSI +// +// 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 3 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, see <http://www.gnu.org/licenses/>. + +package cern.silecs.view.wizards; + +import java.io.File; + +import org.eclipse.core.resources.IFile; +import org.eclipse.core.resources.IProject; +import org.eclipse.core.resources.IProjectDescription; +import org.eclipse.core.resources.IResource; +import org.eclipse.core.resources.IWorkspaceRoot; +import org.eclipse.core.resources.ResourcesPlugin; +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.NullProgressMonitor; +import org.eclipse.jface.viewers.IStructuredSelection; +import org.eclipse.jface.wizard.Wizard; +import org.eclipse.ui.INewWizard; +import org.eclipse.ui.IWorkbench; + +import cern.silecs.control.core.DesignProjectNature; +import cern.silecs.model.exception.SilecsException; +import cern.silecs.utils.OSExecute; +import cern.silecs.utils.SilecsUtils; +import cern.silecs.utils.SilecsConstants; +import cern.silecs.view.console.ConsoleHandler; +import cern.silecs.view.preferences.MainPreferencePage; +import cern.silecs.view.wizards.page.SilecsProjectPage; + +public class NewSilecsDesignWizard extends Wizard implements INewWizard{ + + SilecsProjectPage page; + + public NewSilecsDesignWizard() { + super(); + setWindowTitle(SilecsConstants.NEW_DESIGN_WIZARD_TITLE); + } + + @Override + public void addPages() { + super.addPages(); + + page = new SilecsProjectPage(SilecsConstants.NEW_DESIGN_PAGE_TITLE, + SilecsConstants.ProjectType.DESIGN_PROJECT, + "Enter design name", + "Enter silecs version"); + + addPage(page); + } + + @Override + public boolean performFinish() + { + try + { + ConsoleHandler.clear(); + String designName = page.getprojectNameText(); + String silecsVersion = page.getsilecsVersionText(); + String designSchema = MainPreferencePage.getModelBasePath(silecsVersion) + "/" +SilecsConstants.DESIGN_SCHEMA_XSD; + + if(! new File(designSchema).exists()) + { + throw new SilecsException("The Design Schema: '" + designSchema + "' does not exist. Please check your Eclipse-Silecs preferences!"); + } + + IWorkspaceRoot workspaceRoot = ResourcesPlugin.getWorkspace().getRoot(); + String workspacePath = workspaceRoot.getLocation().toFile().getPath(); + + IProject project = workspaceRoot.getProject(designName); + OSExecute.executePython("iefiles","newDesignProject",silecsVersion, new String[]{workspacePath, designName, designSchema, silecsVersion}); + + IFile designFile = SilecsUtils.getSilecsDesignFile(project); + + + IProgressMonitor monitor = new NullProgressMonitor(); + //project.create(monitor); + + IProjectDescription description = project.getWorkspace().newProjectDescription(project.getName()); + String[] newNatures = new String[1]; + newNatures[0] = DesignProjectNature.NATURE_ID; + description.setNatureIds(newNatures); + + project.create(description, null); + + project.open(IResource.FORCE, monitor); + //DesignProjectNature.addClassNature(project, monitor); TODO: No idea why this does not work + SilecsUtils.openInEditor(designFile); + } + catch (Exception e) + { + e.printStackTrace(); + ConsoleHandler.printStackTrace(e); + } + return true; + } + + @Override + public void init(IWorkbench arg0, IStructuredSelection arg1) { + // TODO Auto-generated method stub + + } + +} diff --git a/silecs-eclipse-plugin/src/java/cern/silecs/view/wizards/UpdateSilecsProjectWizard.java b/silecs-eclipse-plugin/src/java/cern/silecs/view/wizards/UpdateSilecsProjectWizard.java new file mode 100644 index 0000000..2de9a3e --- /dev/null +++ b/silecs-eclipse-plugin/src/java/cern/silecs/view/wizards/UpdateSilecsProjectWizard.java @@ -0,0 +1,52 @@ +// Copyright 2016 CERN and GSI +// +// 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 3 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, see <http://www.gnu.org/licenses/>. + +package cern.silecs.view.wizards; + +import org.eclipse.jface.wizard.Wizard; + +import cern.silecs.view.console.ConsoleHandler; +import cern.silecs.view.wizards.page.PickVersionPage; + +public class UpdateSilecsProjectWizard extends Wizard +{ + String selectedVersion; + PickVersionPage page; + + public UpdateSilecsProjectWizard() { + super(); + setWindowTitle("Pick a version"); + } + + @Override + public void addPages() { + super.addPages(); + page = new PickVersionPage("Select the new SILECS version"); + addPage(page); + } + + public String getSelectedVersion() + { + return selectedVersion; + } + + @Override + public boolean performFinish() { + ConsoleHandler.clear(); + selectedVersion = page.getsilecsVersionText(); + ConsoleHandler.printMessage("selected version: " + selectedVersion , true); + return true; + } +} diff --git a/silecs-eclipse-plugin/src/java/cern/silecs/view/wizards/page/ChooseFilePage.java b/silecs-eclipse-plugin/src/java/cern/silecs/view/wizards/page/ChooseFilePage.java new file mode 100644 index 0000000..0f26be8 --- /dev/null +++ b/silecs-eclipse-plugin/src/java/cern/silecs/view/wizards/page/ChooseFilePage.java @@ -0,0 +1,136 @@ +// Copyright 2016 CERN and GSI +// +// 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 3 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, see <http://www.gnu.org/licenses/>. + +package cern.silecs.view.wizards.page; + + +import org.eclipse.core.resources.ResourcesPlugin; +import org.eclipse.jface.dialogs.IMessageProvider; +import org.eclipse.jface.wizard.WizardPage; +import org.eclipse.swt.SWT; +import org.eclipse.swt.events.ModifyEvent; +import org.eclipse.swt.events.ModifyListener; +import org.eclipse.swt.events.SelectionEvent; +import org.eclipse.swt.events.SelectionListener; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.layout.GridLayout; +import org.eclipse.swt.widgets.Button; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.FileDialog; +import org.eclipse.swt.widgets.Label; +import org.eclipse.swt.widgets.Shell; +import org.eclipse.swt.widgets.Text; +import org.eclipse.ui.PlatformUI; + +import cern.silecs.utils.SilecsConstants; + +public class ChooseFilePage extends WizardPage{ + + private Composite container; + + private Text filePathText; + + private SilecsConstants.ProjectType projectType; + + /** + * @param pageName + */ + public ChooseFilePage(String pageName, SilecsConstants.ProjectType type) { + super(pageName); + setTitle(pageName); + + projectType = type; + } + + @Override + public void createControl(Composite parent) { + container = new Composite(parent, SWT.NONE); + GridLayout layout = new GridLayout(); + container.setLayout(layout); + layout.numColumns = 3; + + Label classNameLabel = new Label(container, SWT.NONE); + classNameLabel.setText("Enter file path"); + + filePathText = new Text(container, SWT.BORDER | SWT.SINGLE); + filePathText.setText(""); + filePathText.addModifyListener(new ModifyListener() { + + @Override + public void modifyText(ModifyEvent e) { + setErrorMessage(null); + setMessage(null, IMessageProvider.WARNING); + setPageComplete(true); + + saveProjectData(); + } + }); + + Button locateFileButton = new Button(container, SWT.NONE); + locateFileButton.setText("Select file"); + locateFileButton.addSelectionListener(new SelectionListener() { + + @Override + public void widgetSelected(SelectionEvent e) { + Shell shell = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getShell(); + + FileDialog dialog = new FileDialog(shell, SWT.OPEN); + dialog.setFilterPath(ResourcesPlugin.getWorkspace().getRoot().getLocationURI().getPath()); + filePathText.setText(dialog.open()); + } + + @Override + public void widgetDefaultSelected(SelectionEvent e) { + // do nothing + } + }); + + GridData gd = new GridData(GridData.FILL_HORIZONTAL); + filePathText.setLayoutData(gd); + + setControl(container); + setPageComplete(false); + } + + public String getFilePath() { + return filePathText.getText(); + } + + protected void saveProjectData() { + try { + String originalFilePath = filePathText.getText(); + + switch(projectType) { + case DESIGN_PROJECT: + int dotAfterDesignName = originalFilePath.lastIndexOf('.'); + String designName = originalFilePath.substring(0, dotAfterDesignName); + int dotBeforeDesignName = designName.lastIndexOf('.'); + designName = designName.substring(dotBeforeDesignName); + ((SilecsProjectPage) getNextPage()).setprojectNameText(designName); + break; + + case DEPLOY_PROJECT: + int dotAfterDUName = originalFilePath.lastIndexOf('.'); + String deployName = originalFilePath.substring(0, dotAfterDUName); + int dotBeforeDUName = deployName.lastIndexOf('.'); + deployName = deployName.substring(dotBeforeDUName); + ((SilecsProjectPage) getNextPage()).setprojectNameText(deployName); + break; + } + } catch (Exception e) { + e.printStackTrace(); + } + } +} diff --git a/silecs-eclipse-plugin/src/java/cern/silecs/view/wizards/page/PickTemplatePage.java b/silecs-eclipse-plugin/src/java/cern/silecs/view/wizards/page/PickTemplatePage.java new file mode 100644 index 0000000..aa99505 --- /dev/null +++ b/silecs-eclipse-plugin/src/java/cern/silecs/view/wizards/page/PickTemplatePage.java @@ -0,0 +1,58 @@ +// Copyright 2016 CERN and GSI +// +// 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 3 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, see <http://www.gnu.org/licenses/>. + +package cern.silecs.view.wizards.page; +import org.eclipse.jface.wizard.WizardPage; +import org.eclipse.swt.SWT; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.layout.GridLayout; +import org.eclipse.swt.widgets.Combo; +import org.eclipse.swt.widgets.Composite; + +public class PickTemplatePage extends WizardPage{ + + private String[] templates; + private Composite container; + private Combo templatePicker; + + /** + * @param pageName + */ + public PickTemplatePage(String pageName, String[] templateNames) { + super(pageName); + setTitle(pageName); + templates = templateNames; + } + + @Override + public void createControl(Composite parent) { + container = new Composite(parent, SWT.NONE); + GridLayout layout = new GridLayout(); + container.setLayout(layout); + layout.numColumns = 1; + + templatePicker = new Combo(container, SWT.BORDER | SWT.V_SCROLL | SWT.READ_ONLY); + templatePicker.setItems(templates); + templatePicker.select(0); + GridData dataLayout = new GridData(); + dataLayout.horizontalSpan = 1; + templatePicker.setLayoutData(dataLayout); + setControl(container); + } + + public String getTemplate() { + return templatePicker.getText(); + } +} diff --git a/silecs-eclipse-plugin/src/java/cern/silecs/view/wizards/page/PickVersionPage.java b/silecs-eclipse-plugin/src/java/cern/silecs/view/wizards/page/PickVersionPage.java new file mode 100644 index 0000000..0326bee --- /dev/null +++ b/silecs-eclipse-plugin/src/java/cern/silecs/view/wizards/page/PickVersionPage.java @@ -0,0 +1,72 @@ +// Copyright 2016 CERN and GSI +// +// 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 3 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, see <http://www.gnu.org/licenses/>. + +package cern.silecs.view.wizards.page; + +import java.util.List; + +import org.eclipse.jface.wizard.WizardPage; +import org.eclipse.swt.SWT; + +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.layout.GridLayout; +import org.eclipse.swt.widgets.Combo; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Label; + +import cern.silecs.utils.SilecsConstants; +import cern.silecs.utils.SilecsUtils; + +public class PickVersionPage extends WizardPage { + + private Combo silecsVersionText; + private String silecsVersionDescription; + + public PickVersionPage(String pageName) + { + super(pageName); + setTitle(pageName); + silecsVersionDescription = "New silecs version"; + } + + @Override + public void createControl(Composite parent) + { + Composite container = new Composite(parent, SWT.NONE); + GridLayout layout = new GridLayout(); + container.setLayout(layout); + layout.numColumns = 2; + + Label classVersionLabel = new Label(container, SWT.NONE); + classVersionLabel.setText(silecsVersionDescription); + + silecsVersionText = new Combo(container, SWT.BORDER | SWT.V_SCROLL | SWT.READ_ONLY); + List<String> availableSilecsVersions = SilecsUtils.readOutAvailableSilecsVersions(); + availableSilecsVersions.addAll(SilecsConstants.ADDITIONAL_SILECS_TARGET_MIGRATION_VERSIONS); + silecsVersionText.setItems(availableSilecsVersions.toArray(new String[availableSilecsVersions.size()])); + silecsVersionText.select(SilecsConstants.DEFAULT_SILECS_VERSION_INDEX); + GridData dataLayout = new GridData(); + dataLayout.horizontalSpan = 2; + silecsVersionText.setLayoutData(dataLayout); + + // required to avoid an error in the system + setControl(container); + setPageComplete(true); + } + + public String getsilecsVersionText() { + return silecsVersionText.getText(); + } +} diff --git a/silecs-eclipse-plugin/src/java/cern/silecs/view/wizards/page/SilecsProjectPage.java b/silecs-eclipse-plugin/src/java/cern/silecs/view/wizards/page/SilecsProjectPage.java new file mode 100644 index 0000000..61a31e3 --- /dev/null +++ b/silecs-eclipse-plugin/src/java/cern/silecs/view/wizards/page/SilecsProjectPage.java @@ -0,0 +1,152 @@ +// Copyright 2016 CERN and GSI +// +// 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 3 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, see <http://www.gnu.org/licenses/>. + +package cern.silecs.view.wizards.page; + +import java.util.List; + +import org.eclipse.core.resources.IProject; +import org.eclipse.core.resources.IWorkspaceRoot; +import org.eclipse.core.resources.ResourcesPlugin; +import org.eclipse.jface.dialogs.IMessageProvider; +import org.eclipse.jface.wizard.WizardPage; +import org.eclipse.swt.SWT; +import org.eclipse.swt.events.ModifyEvent; +import org.eclipse.swt.events.ModifyListener; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.layout.GridLayout; +import org.eclipse.swt.widgets.Combo; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Label; +import org.eclipse.swt.widgets.Text; + +import cern.silecs.utils.SilecsConstants; +import cern.silecs.utils.SilecsUtils; +import cern.silecs.view.preferences.MainPreferencePage; + +public class SilecsProjectPage extends WizardPage { + + private Text projectNameText; + private String projectNameDescription; + + private Combo silecsVersionText; + private String silecsVersionDescription; + + private String projectNamePattern; + private int maxNameLength; + + + private class PatternMatcherListener implements ModifyListener{ + + @Override + public void modifyText(ModifyEvent e) { + String name = projectNameText.getText(); + setErrorMessage(null); + setMessage(null, IMessageProvider.WARNING); + setPageComplete(true); + + if (!name.matches(projectNamePattern)) { + setErrorMessage(SilecsConstants.INVAILD_PROJECT_NAME + "\n" + projectNamePattern); + setPageComplete(false); + } else if(name.length() > maxNameLength) { + setErrorMessage("Name cannot be longer than " + maxNameLength + " characters"); + setPageComplete(false); + } else if (workspaceContainsProject(projectNameText.getText())) { + setErrorMessage("Project with this name already exists in the workspace"); + setPageComplete(false); + } + } + + } + + /** + * @param pageName + * @param projectNameLabelDescryption For example "Enter project name:" + * @param projectVersionLabelDescryption + * @param type + */ + public SilecsProjectPage(String pageName, SilecsConstants.ProjectType type, String projectNameLabelDescryption, + String silecsVersionLabelDescryption) { + super("New Silecs Project Page"); + setTitle(pageName); + + projectNameDescription = projectNameLabelDescryption; + silecsVersionDescription = silecsVersionLabelDescryption; + + if (type == SilecsConstants.ProjectType.DEPLOY_PROJECT) { + projectNamePattern = SilecsConstants.DEPLOY_PATTERN; + maxNameLength = SilecsConstants.MAX_DEPLOY_LENGTH; + } + else if (type == SilecsConstants.ProjectType.DESIGN_PROJECT) { + projectNamePattern = SilecsConstants.DESIGN_PATTERN; + maxNameLength = SilecsConstants.MAX_DESIGN_LENGTH; + } + } + + + @Override + public void createControl(Composite parent) { + Composite container = new Composite(parent, SWT.NONE); + GridLayout layout = new GridLayout(); + container.setLayout(layout); + layout.numColumns = 2; + + Label classNameLabel = new Label(container, SWT.NONE); + classNameLabel.setText(projectNameDescription); + + projectNameText = new Text(container, SWT.BORDER | SWT.SINGLE); + projectNameText.setText(""); + projectNameText.addModifyListener(new PatternMatcherListener()); + GridData gd = new GridData(GridData.FILL_HORIZONTAL); + projectNameText.setLayoutData(gd); + + Label classVersionLabel = new Label(container, SWT.NONE); + classVersionLabel.setText(silecsVersionDescription); + + silecsVersionText = new Combo(container, SWT.BORDER | SWT.V_SCROLL | SWT.READ_ONLY); + List<String> availableSilecsVersions = SilecsUtils.readOutAvailableSilecsVersions(); + silecsVersionText.setItems(availableSilecsVersions.toArray(new String[availableSilecsVersions.size()])); + silecsVersionText.select(SilecsConstants.DEFAULT_SILECS_VERSION_INDEX); + GridData dataLayout = new GridData(); + dataLayout.horizontalSpan = 2; + silecsVersionText.setLayoutData(dataLayout); + + // required to avoid an error in the system + setControl(container); + setPageComplete(false); + } + + public String getprojectNameText() { + return projectNameText.getText(); + } + + public String getsilecsVersionText() { + return silecsVersionText.getText(); + } + + public void setprojectNameText(String text) { + projectNameText.setText(text); + } + + public void setsilecsVersionText(String text) { + silecsVersionText.setText(text); + } + + private boolean workspaceContainsProject(String name) { + IWorkspaceRoot workspaceRoot = ResourcesPlugin.getWorkspace().getRoot(); + IProject project = workspaceRoot.getProject(name); + return project.exists(); + } +} diff --git a/silecs-model/.project b/silecs-model/.project new file mode 100644 index 0000000..f2e3f95 --- /dev/null +++ b/silecs-model/.project @@ -0,0 +1,11 @@ +<?xml version="1.0" encoding="UTF-8"?> +<projectDescription> + <name>silecs-model</name> + <comment></comment> + <projects> + </projects> + <buildSpec> + </buildSpec> + <natures> + </natures> +</projectDescription> diff --git a/silecs-model/.settings/org.eclipse.core.resources.prefs b/silecs-model/.settings/org.eclipse.core.resources.prefs new file mode 100644 index 0000000..0c18201 --- /dev/null +++ b/silecs-model/.settings/org.eclipse.core.resources.prefs @@ -0,0 +1,2 @@ +eclipse.preferences.version=1 +encoding//src/xml/DeploySchema.xsd=UTF8 diff --git a/silecs-model/LICENSE b/silecs-model/LICENSE new file mode 100644 index 0000000..20d40b6 --- /dev/null +++ b/silecs-model/LICENSE @@ -0,0 +1,674 @@ + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/> + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + <one line to give the program's name and a brief idea of what it does.> + Copyright (C) <year> <name of author> + + 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 3 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, see <http://www.gnu.org/licenses/>. + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + <program> Copyright (C) <year> <name of author> + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +<http://www.gnu.org/licenses/>. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +<http://www.gnu.org/philosophy/why-not-lgpl.html>. \ No newline at end of file diff --git a/silecs-model/README.md b/silecs-model/README.md new file mode 100644 index 0000000..e81edfe --- /dev/null +++ b/silecs-model/README.md @@ -0,0 +1,19 @@ +# silecs-codegen + +This component of the SILECS PLC-framework is used in order to validate silecs-project-specific XML files. + +## Getting Started + +Please check the lab-specific SILECS-Wikis for more information: + +[CERN SILECS Wiki Page][CERN_Wiki] + +[GSI SILECS Wiki Page][GSI_Wiki] + +## License + +Licensed under the GNU GENERAL PUBLIC LICENSE Version 3. See the [LICENSE file][license] for details. + +[license]: LICENSE +[CERN_Wiki]: https://wikis.cern.ch/display/SIL/SILECs+Home +[GSI_Wiki]: https://www-acc.gsi.de/wiki/Frontend/SILECS \ No newline at end of file diff --git a/silecs-model/install.sh b/silecs-model/install.sh new file mode 100755 index 0000000..e8e33e9 --- /dev/null +++ b/silecs-model/install.sh @@ -0,0 +1,10 @@ +#!/bin/sh +set -e + +INSTALL_DIR=$1 + +SCRIPT=$(readlink -f "$0") +SCRIPTPATH=$(dirname "$SCRIPT") # path where this script is located in + +mkdir -p ${INSTALL_DIR} +cp -r ${SCRIPTPATH}/src/xml ${INSTALL_DIR} \ No newline at end of file diff --git a/silecs-model/src/xml/DeploySchema.xsd b/silecs-model/src/xml/DeploySchema.xsd new file mode 100644 index 0000000..ffc6ec6 --- /dev/null +++ b/silecs-model/src/xml/DeploySchema.xsd @@ -0,0 +1,518 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- Copyright 2016 CERN and GSI +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 3 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, see http://www.gnu.org/licenses/.--> + +<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified" attributeFormDefault="unqualified"> + <xs:include schemaLocation="shared.xsd" /> + + <xs:element name="SILECS-Deploy"> + <xs:annotation> + <xs:documentation>A SILECS configuration contains the class designs, the memory mapping and the hardware distribution for a given set of PLCs.</xs:documentation> + <xs:appinfo> + <doc> + The SILECS configuration defines the data structure and the communication parameters required for the interconnection of the PLCs and the Front-End clients. It consists of 3 parts: + <ol> + <li> Design: to define the structure of the exchanged data + <li> Mapping: to define the PLC memory mapping and the protocol parameters + <li> Generation: to define the hardware on which we will deployed the different Mapping + </ol> + Generally under the responsability of a unique expert entity, an SILECS configuration is done for a set of classes and PLCs in the scope of a particular project or set of equipment. + </doc> + </xs:appinfo> + </xs:annotation> + <xs:complexType> + <xs:sequence> + <xs:element name="Information"> + <xs:complexType> + <xs:sequence> + <xs:element name="Owner"> + <xs:complexType> + <xs:attribute name="user-login" type="xs:string" use="required"/> + </xs:complexType> + </xs:element> + <xs:element name="Editor" maxOccurs="unbounded"> + <xs:complexType> + <xs:attribute name="user-login" type="xs:string" use="required"/> + </xs:complexType> + </xs:element> + </xs:sequence> + </xs:complexType> + </xs:element> + <xs:element name="Deploy-Unit"> + <xs:complexType> + <xs:attribute name="name" type="DeployNameType" use="required"/> + <xs:attribute name="version" type="VersionType" use="required"/> + </xs:complexType> + </xs:element> + <xs:element name="Controller" type="ControllerType" maxOccurs="unbounded" minOccurs="1"> + <xs:unique name="Device-name-unique-per-controller"> + <xs:selector xpath="SilecsDesign/Device"/> + <xs:field xpath="@device-name"/> + </xs:unique> + <xs:unique name="Class-name-unique-per-controller"> + <xs:selector xpath="SilecsDesign"/> + <xs:field xpath="@silecs-design-name"/> + </xs:unique> + </xs:element> + </xs:sequence> + <xs:attribute name="silecs-version" type="xs:string" use="required"> + <xs:annotation> + <xs:appinfo> + <doc>Silecs framework version</doc> + </xs:appinfo> + </xs:annotation> + </xs:attribute> + <xs:attribute name="created" type="xs:string" use="required"> + <xs:annotation> + <xs:appinfo> + <doc>Creation date</doc> + </xs:appinfo> + </xs:annotation> + </xs:attribute> + <xs:attribute name="updated" type="xs:string" use="required"> + <xs:annotation> + <xs:appinfo> + <doc>Last update Date</doc> + </xs:appinfo> + </xs:annotation> + </xs:attribute> + </xs:complexType> + <xs:unique name="Host-name-unique-per-silecsdeploy"> + <xs:selector xpath="Controller"/> + <xs:field xpath="@host-name"/> + </xs:unique> + </xs:element> + + <xs:complexType name="ControllerType"> + <xs:sequence> + <xs:choice> + <xs:element name="Siemens-PLC" type="SiemensPLCType"> + <xs:annotation> + <xs:documentation>A Siemens-Mapping defines a particular Mapping of classes intended to SIMATIC PLCs</xs:documentation> + </xs:annotation> + </xs:element> + <xs:element name="Schneider-PLC" type="SchneiderPLCType"> + <xs:annotation> + <xs:documentation>A Schneider-Mapping defines a particular Mapping of classes intended to PL7/UNITY PLCs</xs:documentation> + </xs:annotation> + </xs:element> + <xs:element name="Beckhoff-PLC" type="BeckhoffPLCType"> + <xs:annotation> + <xs:documentation>A Beckhoff-Mapping defines a particular Mapping of classes intended to TwinCat PLCs</xs:documentation> + </xs:annotation> + </xs:element> + <!-- No support for this type in CERN codegen so far<xs:element name="Beckhoff-RIO" type="BeckhoffRIOType"> + <xs:annotation> + <xs:documentation>A Beckhoff-RIO deployment defines the physical Mapping of TwinCAT Remote IO modules.</xs:documentation> + </xs:annotation> + </xs:element>--> + <xs:element name="Rabbit-uC" type="RabbituCType"> + <xs:annotation> + <xs:documentation>A Rabbit-Mapping defines a particular Mapping of classes intended for Rabbit microcontrollers</xs:documentation> + </xs:annotation> + </xs:element> + <xs:element name="Virtual-Controller" type="VirtualControllerType"> + <xs:annotation> + <xs:documentation>Defines a particular C++ code mapping of classes intended for Software controller</xs:documentation> + </xs:annotation> + </xs:element> + <xs:element name="NI-Controller" type="NIControllerType"> + <xs:annotation> + <xs:documentation>A NI-Mapping defines a particular Mapping of classes intended to National Instrument Controllers</xs:documentation> + </xs:annotation> + </xs:element> + </xs:choice> + <xs:element name="SilecsDesign" type="SilecsDesignType" maxOccurs="unbounded"/> + </xs:sequence> + <xs:attribute name="host-name" type="HostNameType" use="required"/> + </xs:complexType> + + <xs:complexType name="SilecsDesignType"> + <xs:sequence> + <xs:element name="Device" type="DeviceType" maxOccurs="unbounded"/> + </xs:sequence> + <xs:attribute name="silecs-design-name" type="SilecsClassNameType" use="required"/> + <xs:attribute name="silecs-design-version" type="VersionType" use="required"/> + </xs:complexType> + + <xs:complexType name="DeviceType"> + <xs:sequence> + <xs:annotation> + <xs:documentation>The device is an instance of the related silecs-design.</xs:documentation> + <xs:appinfo> + <doc> + The device is an instance of the related SILECS design class. + The label is dedicated to the PLC process and the SILECS client software to identify the device in the scope of that class in that particular Mapping. + It does not identify a unique device instance of the control system at the supervision level. + The device sequence will occupy contiguous segment of PLC memory respecting their exact ordering. + The SILECS tool assists the expert in ordering devices as required. + </doc> + </xs:appinfo> + </xs:annotation> + </xs:sequence> + <xs:attribute name="device-name" type="DeviceNameType" use="required"/> + </xs:complexType> + + <xs:simpleType name="HostNameType"> + <xs:restriction base="xs:string"> + <xs:minLength value="1"/> + <xs:pattern value="[_A-Za-z0-9]*"/> + </xs:restriction> + </xs:simpleType> + <xs:simpleType name="DeployNameType"> + <xs:restriction base="xs:string"> + <xs:minLength value="1"/> + <xs:maxLength value="20"/> + <xs:pattern value="[_A-Za-z]+[_A-Za-z0-9]*"/> + </xs:restriction> + </xs:simpleType> + + <xs:simpleType name="DeviceNameType"> + <xs:restriction base="xs:string"> + <xs:minLength value="1"/> + <xs:maxLength value="30"/> + <!-- In FESA the deviceName is restricted to max. 30 characters --> + <xs:pattern value="[_A-Za-z][_A-Za-z0-9]*"/> + </xs:restriction> + </xs:simpleType> + + <xs:simpleType name="SiemensSystemType"> + <xs:restriction base="xs:string"> + <xs:enumeration value="STEP-7"/> + <xs:enumeration value="TIA-PORTAL"/> + </xs:restriction> + </xs:simpleType> + <xs:simpleType name="SchneiderSystemType"> + <xs:restriction base="xs:string"> + <xs:enumeration value="UNITY Pro"/> + </xs:restriction> + </xs:simpleType> + <xs:simpleType name="BeckhoffSystemType"> + <xs:restriction base="xs:string"> + <xs:enumeration value="TWINCat"/> + </xs:restriction> + </xs:simpleType> + <xs:simpleType name="RabbitSystemType"> + <xs:restriction base="xs:string"> + <xs:enumeration value="Standard-C"/> + </xs:restriction> + </xs:simpleType> + <xs:simpleType name="NISystemType"> + <xs:restriction base="xs:string"> + <xs:enumeration value="Labview"/> + </xs:restriction> + </xs:simpleType> + <xs:simpleType name="BothProtocolType"> + <xs:restriction base="xs:string"> + <xs:enumeration value="DEVICE_MODE"/> + <xs:enumeration value="BLOCK_MODE"/> + </xs:restriction> + </xs:simpleType> + <xs:simpleType name="DeviceProtocolType"> + <xs:restriction base="xs:string"> + <xs:enumeration value="DEVICE_MODE"/> + </xs:restriction> + </xs:simpleType> + <xs:simpleType name="BlockProtocolType"> + <xs:restriction base="xs:string"> + <xs:enumeration value="BLOCK_MODE"/> + </xs:restriction> + </xs:simpleType> + <xs:simpleType name="PCSystemType"> + <xs:restriction base="xs:string"> + <xs:enumeration value="SNAP7 linux32"/> + <xs:enumeration value="SNAP7 linux64"/> + </xs:restriction> + </xs:simpleType> + + <xs:complexType name="SiemensPLCType"> + <xs:attribute name="system" type="SiemensSystemType" use="required"> + <xs:annotation> + <xs:documentation>System infrastructure used to develop and/or configure the controller software.</xs:documentation> + <xs:appinfo> + <doc> + System infrastructure used to develop and/or configure the controller software. + </doc> + </xs:appinfo> + </xs:annotation> + </xs:attribute> + <xs:attribute name="model" use="required"> + <xs:simpleType> + <xs:restriction base="xs:string"> + <xs:enumeration value="SIMATIC_S7-300"/> + <xs:enumeration value="SIMATIC_S7-400"/> + <xs:enumeration value="SIMATIC_S7-1200"/> + <xs:enumeration value="SIMATIC_S7-1500"/> + <xs:enumeration value="SIMATIC_ET-200S"/> + </xs:restriction> + </xs:simpleType> + </xs:attribute> + <xs:attribute name="protocol" type="BothProtocolType" use="required"> + <xs:annotation> + <xs:documentation>Data access mode is defined at PLC level for all the classes</xs:documentation> + <xs:appinfo> + <doc> + DEVICE_MODE: One S7-DB per class/device ([class-name]_[device-label|id]), <br>containing the corresponding ordered list of Blocks + <br>BLOCK_MODE: One S7-DB per class/block ([class-name]_[block-name]), <br>containing array of corresponding Block, one element per device + </doc> + </xs:appinfo> + </xs:annotation> + </xs:attribute> + <xs:attribute name="base-DB-number" type="xs:unsignedInt" use="required"> + <xs:annotation> + <xs:documentation>Number of the diagnostic DB that is the first one of the global configuration (corresponds to the common SilecsHeader data-block).</xs:documentation> + <xs:appinfo> + <doc> + Number of the diagnostic DB that is the first one of the global configuration ( >=1) + </doc> + </xs:appinfo> + </xs:annotation> + </xs:attribute> + </xs:complexType> + <xs:complexType name="SchneiderPLCType"> + <xs:attribute name="system" type="SchneiderSystemType" use="required"> + <xs:annotation> + <xs:documentation>System infrastructure used to develop and/or configure the controller software.</xs:documentation> + <xs:appinfo> + <doc> + System infrastructure used to develop and/or configure the controller software. + </doc> + </xs:appinfo> + </xs:annotation> + </xs:attribute> + <xs:attribute name="model" use="required"> + <xs:simpleType> + <xs:restriction base="xs:string"> + <xs:enumeration value="Premium"/> + <xs:enumeration value="Quantum"/> + <xs:enumeration value="M340"/> + </xs:restriction> + </xs:simpleType> + </xs:attribute> + <xs:attribute name="protocol" type="BlockProtocolType" use="required"> + <xs:annotation> + <xs:documentation>Data access mode is defined at PLC level for all the classes</xs:documentation> + <xs:appinfo> + <doc> + BLOCK_MODE: One data-segment per class/block ([class-name]_[block-name]), <br>containing array of corresponding Block, one element per device + </doc> + </xs:appinfo> + </xs:annotation> + </xs:attribute> + <xs:attribute name="base-address" type="xs:unsignedInt" use="required"> + <xs:annotation> + <xs:documentation>Start address of the SILECS configuration (corresponds to the common SilecsHeader block address). Attention: 16bit address value is expected independently from the HW model (16 or 32 bit).</xs:documentation> + <xs:appinfo> + <doc> + Start address of the SILECS configuration (corresponds to the common SilecsHeader block address). + <br>Attention: 16bit address value is expected independently from the HW model (16 or 32 bit) + </doc> + </xs:appinfo> + </xs:annotation> + </xs:attribute> +</xs:complexType> + +<xs:complexType name="BeckhoffPLCType"> + <xs:attribute name="system" type="BeckhoffSystemType" use="required"> + <xs:annotation> + <xs:documentation>System infrastructure used to develop and/or configure the controller software.</xs:documentation> + <xs:appinfo> + <doc> + System infrastructure used to develop and/or configure the Controller software. + </doc> + </xs:appinfo> + </xs:annotation> + </xs:attribute> + <xs:attribute name="model" use="required"> + <xs:simpleType> + <xs:restriction base="xs:string"> + <xs:enumeration value="BC9020"/> + <xs:enumeration value="CX9020"/> + </xs:restriction> + </xs:simpleType> + </xs:attribute> + <xs:attribute name="protocol" type="BlockProtocolType" use="required"> + <xs:annotation> + <xs:documentation>Data access mode is defined at PLC level for all the classes</xs:documentation> + <xs:appinfo> + <doc> + BLOCK_MODE: One data-segment per class/block ([class-name]_[block-name]), <br>containing array of corresponding Block, one element per device + </doc> + </xs:appinfo> + </xs:annotation> + </xs:attribute> + <xs:attribute name="base-address" type="xs:unsignedInt" use="required"> + <xs:annotation> + <xs:documentation>Start address of the SILECS configuration (corresponds to the common SilecsHeader block address). Attention: 16bit address value is expected independently from the HW model (16 or 32 bit).</xs:documentation> + <xs:appinfo> + <doc> + Start address of the SILECS configuration (corresponds to the common SilecsHeader block address). + <br>Attention: 16bit address value is expected independently from the HW model (16 or 32 bit) + </doc> + </xs:appinfo> + </xs:annotation> + </xs:attribute> +</xs:complexType> + +<!-- No support for this type in CERN codegen so far <xs:complexType name="BeckhoffRIOType"> + <xs:attribute name="system" type="BeckhoffSystemType" use="required"> + <xs:annotation> + <xs:documentation>System infrastructure used to develop and/or configure the controller software.</xs:documentation> + <xs:appinfo> + <doc> + System infrastructure used to develop and/or configure the Controller software. + </doc> + </xs:appinfo> + </xs:annotation> + </xs:attribute> + <xs:attribute name="model" use="required"> + <xs:simpleType> + <xs:restriction base="xs:string"> + <xs:enumeration value="BK9000"/> + <xs:enumeration value="BK9050"/> + <xs:enumeration value="BK9100"/> + </xs:restriction> + </xs:simpleType> + </xs:attribute> + <xs:attribute name="io-base-address" type="xs:unsignedInt" use="required"> + <xs:annotation> + <xs:documentation>Start address of the Remote IO modules (can be 0 if not required). Attention: 16bit address value is expected independently from the HW model (16 or 32 bit).</xs:documentation> + <xs:appinfo> + <doc> + Start address of the Remote IO modules (can be 0 if not required). + <br>Attention: 16bit address value is expected independently from the HW model (16 or 32 bit). + </doc> + </xs:appinfo> + </xs:annotation> + </xs:attribute> +</xs:complexType>--> + +<xs:complexType name="RabbituCType"> + <xs:attribute name="system" type="RabbitSystemType" use="required"> + <xs:annotation> + <xs:documentation>System infrastructure used to develop and/or configure the controller software.</xs:documentation> + <xs:appinfo> + <doc> + System infrastructure used to develop and/or configure the Controller software. + </doc> + </xs:appinfo> + </xs:annotation> + </xs:attribute> + <xs:attribute name="model" use="required"> + <xs:simpleType> + <xs:restriction base="xs:string"> + <xs:enumeration value="Rabbit_RCM_4010"/> + <xs:enumeration value="Rabbit_RCM_2000"/> + </xs:restriction> + </xs:simpleType> + </xs:attribute> + <xs:attribute name="protocol" type="BothProtocolType" use="required"> + <xs:annotation> + <xs:documentation>Data access mode is defined at PLC level for all the classes</xs:documentation> + <xs:appinfo> + <doc> + DEVICE_MODE: One C struct field per class/device ([class-name]_[device-label|id]), <br>containing the corresponding ordered list of Blocks + <br>BLOCK_MODE: One C struct field per class/block ([class-name]_[block-name]), <br>containing array of corresponding Block, one element per device + </doc> + </xs:appinfo> + </xs:annotation> + </xs:attribute> + <xs:attribute name="base-address" type="xs:unsignedInt" use="required"> + <xs:annotation> + <xs:documentation>Start address of the entire SILECS configuration interpreted as 16bit address.</xs:documentation> + <xs:appinfo> + <doc> + Start address of the entire SILECS configuration interpreted as 16bit address. + </doc> + </xs:appinfo> + </xs:annotation> + </xs:attribute> +</xs:complexType> + +<xs:complexType name="VirtualControllerType"> + <xs:attribute name="system" type="PCSystemType" use="required"> + <xs:annotation> + <xs:documentation>System infrastructure used to develop and/or configure the controller software.</xs:documentation> + <xs:appinfo> + <doc> + System infrastructure used to develop and/or configure the Controller software. + </doc> + </xs:appinfo> + </xs:annotation> + </xs:attribute> + <xs:attribute name="model" use="required"> + <xs:simpleType> + <xs:restriction base="xs:string"> + <xs:enumeration value="SIMATIC_S7-VIRTUAL"/> + </xs:restriction> + </xs:simpleType> + </xs:attribute> + <xs:attribute name="protocol" type="BothProtocolType" use="required"> + <xs:annotation> + <xs:documentation>Data access mode is defined at PLC level for all the classes</xs:documentation> + <xs:appinfo> + <doc> + DEVICE_MODE: One C struct field per class/device ([class-name]_[device-label|id]), <br>containing the corresponding ordered list of Blocks + <br>BLOCK_MODE: One C struct field per class/block ([class-name]_[block-name]), <br>containing array of corresponding Block, one element per device + </doc> + </xs:appinfo> + </xs:annotation> + </xs:attribute> + <xs:attribute name="base-DB-number" type="xs:unsignedInt" use="required"> + <xs:annotation> + <xs:documentation>Number of the diagnostic DB that is the first one of the global configuration (corresponds to the common SilecsHeader data-block).</xs:documentation> + <xs:appinfo> + <doc> + Number of the diagnostic DB that is the first one of the global configuration ( >=1) + </doc> + </xs:appinfo> + </xs:annotation> + </xs:attribute> +</xs:complexType> + +<xs:complexType name="NIControllerType"> + <xs:attribute name="model" use="required"> + <xs:simpleType> + <xs:restriction base="xs:string"> + <xs:enumeration value="Compact_RIO"/> + <xs:enumeration value="PXI_RT"/> + <xs:enumeration value="PXI_Windows"/> + <xs:enumeration value="PC_Windows"/> + <xs:enumeration value="Other_Support_CNV"/> + </xs:restriction> + </xs:simpleType> + </xs:attribute> + <xs:attribute name="system" type="NISystemType" use="required"> + <xs:annotation> + <xs:documentation>System infrastructure used to develop and/or configure the controller software.</xs:documentation> + <xs:appinfo> + <doc> + System infrastructure used to develop and/or configure the Controller software. + </doc> + </xs:appinfo> + </xs:annotation> + </xs:attribute> + <xs:attribute name="protocol" type="DeviceProtocolType" use="required"> + <xs:annotation> + <xs:documentation>Data access mode is defined at PLC level for all the classes</xs:documentation> + <xs:appinfo> + <doc> + DEVICE_MODE: One shared variable per class/device (//class-name//controllerName//device-label), <br>containing the corresponding ordered list of Blocks. + </doc> + </xs:appinfo> + </xs:annotation> + </xs:attribute> +</xs:complexType> + +</xs:schema> diff --git a/silecs-model/src/xml/DesignSchema.xsd b/silecs-model/src/xml/DesignSchema.xsd new file mode 100644 index 0000000..aa754bc --- /dev/null +++ b/silecs-model/src/xml/DesignSchema.xsd @@ -0,0 +1,355 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- Copyright 2016 CERN and GSI +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 3 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, see http://www.gnu.org/licenses/.--> + +<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified" attributeFormDefault="unqualified"> + <xs:include schemaLocation="shared.xsd" /> + + <xs:element name="SILECS-Design"> + <xs:annotation> + <xs:documentation>A SILECS configuration contains the class designs, the memory mapping and the hardware distribution for a given set of PLCs.</xs:documentation> + <xs:appinfo> + <doc> + The SILECS configuration defines the data structure and the communication parameters required for the interconnection of the PLCs and the Front-End clients. It consists of 3 parts: + <ol> + <li> Design: to define the structure of the exchanged data + <li> Mapping: to define the PLC memory mapping and the protocol parameters + <li> Generation: to define a the hardware on which we will deployed the different Mapping + </ol> + Generally under the responsability of a unique expert entity, an SILECS configuration is done for a set of classes and PLCs in the scope of a particular project or set of equipments. + </doc> + </xs:appinfo> + </xs:annotation> + <xs:complexType> + <xs:sequence> + <xs:element name="Information"> + <xs:complexType> + <xs:sequence> + <xs:element name="Owner"> + <xs:annotation> + <xs:documentation>Owner is the one who created the class. He has write-access on the Design document and can deploy the corresponding class course. Owner can add Editors and Users on his class.</xs:documentation> + <xs:appinfo> + <doc>Owner is the one who created the class. He has write-access on the Design document and can deploy the corresponding class course. Owner can add Editors and Users on his class.</doc> + </xs:appinfo> + </xs:annotation> + <xs:complexType> + <xs:attribute name="user-login" type="xs:string" use="required"/> + </xs:complexType> + </xs:element> + <xs:choice maxOccurs="unbounded"> + <xs:element name="Editor" minOccurs="0" maxOccurs="unbounded"> + <xs:annotation> + <xs:documentation>Editor has write-access on the Design document and can deploy the corresponding class. He cannot add Editors or Users on the class.</xs:documentation> + <xs:appinfo> + <doc>Editor has write-access on the Design document and can deploy the corresponding class. He cannot add Editors or Users on the class.</doc> + </xs:appinfo> + </xs:annotation> + <xs:complexType> + <xs:attribute name="user-login" type="xs:string" use="required"/> + </xs:complexType> + </xs:element> + <xs:element name="User" minOccurs="0" maxOccurs="unbounded"> + <xs:annotation> + <xs:documentation>User has read-only access on the Design document but can deploy the corresponding class. He cannot add Editors or Users on the class.</xs:documentation> + <xs:appinfo> + <doc>User has read-only access on the Design document but can deploy the corresponding class. He cannot add Editors or Users on the class.</doc> + </xs:appinfo> + </xs:annotation> + <xs:complexType> + <xs:attribute name="user-login" type="xs:string" use="required"/> + </xs:complexType> + </xs:element> + </xs:choice> + </xs:sequence> + </xs:complexType> + </xs:element> + <xs:element name="SILECS-Class"> + <xs:annotation> + <xs:documentation>The Class node contains the definition of a particular class</xs:documentation> + <xs:appinfo> + <doc> + The Class node contains the definition of a particular class. Designing a class means: + <ol> + <li> Defining a unique class name in the scope of the all configuration + <li> Providing list of variables which will be exchanged with the target PLC + <li> Identifying coherent groups of variables according to their nature and access mode + </ol> + The SILECS tool assists the expert in specifying the data blocks from this abstract point of view. + </doc> + </xs:appinfo> + </xs:annotation> + <xs:complexType> + <xs:sequence> + <xs:element name="Description" type="xs:string" minOccurs="0"/> + <xs:element name="Block" maxOccurs="unbounded"> + <xs:complexType> + <xs:sequence> + <xs:element name="Description" type="xs:string" minOccurs="0"/> + <xs:element name="Register" type="RegisterType" maxOccurs="unbounded"> + <xs:annotation> + <xs:appinfo> + <doc> + The Register is the elementary component of the SILECS data model. + <br>Each variable has a unique name in the scope of the class (including all blocks). + </doc> + </xs:appinfo> + </xs:annotation> + </xs:element> + </xs:sequence> + <xs:attribute name="name" type="BlockNameType" use="required"> + <xs:annotation> + <xs:appinfo> + Defines the name of the block that must be unique in all the class. + Must not exceed 12 characters. + </xs:appinfo> + </xs:annotation> + </xs:attribute> + <xs:attribute name="mode" use="required"> + <xs:annotation> + <xs:documentation>Defines the access-mode of the block and finally of its related variables.</xs:documentation> + </xs:annotation> + <xs:simpleType> + <xs:restriction base="xs:string"> + <xs:enumeration value="READ-ONLY"/> + <xs:enumeration value="WRITE-ONLY"/> + <xs:enumeration value="READ-WRITE"/> + </xs:restriction> + </xs:simpleType> + </xs:attribute> + <xs:attribute name="generateFesaProperty" type="xs:boolean" use="required"> + <xs:annotation> + <xs:appinfo> + Defines if the code-generation will generate a FESA-Property and the related Actions/Events/etc for this block + </xs:appinfo> + </xs:annotation> + </xs:attribute> + </xs:complexType> + </xs:element> + </xs:sequence> + <xs:attribute name="name" type="SilecsClassNameType" use="required"/> + <xs:attribute name="version" type="VersionType" use="required"/> + <xs:attribute name="domain" use="required"> + <xs:annotation> + <xs:documentation>Defines the domain of use of the class: Operation or Test</xs:documentation> + </xs:annotation> + <xs:simpleType> + <xs:restriction base="xs:string"> + <xs:enumeration value="TEST"/> + <xs:enumeration value="OPERATIONAL"/> + </xs:restriction> + </xs:simpleType> + </xs:attribute> + </xs:complexType> + <xs:unique name="Register-name-per-class"> + <xs:selector xpath="Block/Register"/> + <xs:field xpath="@name"/> + </xs:unique> + <xs:unique name="Block-name-per-class"> + <xs:selector xpath="Block"/> + <xs:field xpath="@name"/> + </xs:unique> + </xs:element> + </xs:sequence> + <xs:attribute name="silecs-version" type="VersionType" use="required"/> + <xs:attribute name="created" type="xs:string" use="required"/> + <xs:attribute name="updated" type="xs:string" use="required"/> + </xs:complexType> + </xs:element> + +<xs:complexType name="RegisterType"> + <xs:sequence> + <xs:element name="Description" type="xs:string" minOccurs="0"/> + </xs:sequence> + <xs:attribute name="name" type="RegisterNameType" use="required"> + <xs:annotation> + <xs:appinfo> + <doc>Name must be unique and must respect the following standard: [_A-Za-z]+[_A-Za-z0-9]*</doc> + </xs:appinfo> + </xs:annotation> + </xs:attribute> + <xs:attribute name="format" type="FormatType" use="required"> + <xs:annotation> + <xs:appinfo> + <doc> + <table border = "1"> + <tr> + <th align="center"> Hardware types </th> + <th align="center"> Client process types </th> + </tr> + <tr> + <td align="center"> uint8 / byte </td> + <td align="center"> uint8_t </td> + </tr> + <tr> + <td align="center"> int8 / char </td> + <td align="center"> int8_t </td> + </tr> + <tr> + <td align="center"> uint16 / word </td> + <td align="center"> uint16_t </td> + </tr> + <tr> + <td align="center"> int16 / int </td> + <td align="center"> int16_t </td> + </tr> + <tr> + <td align="center"> uint32 / dword </td> + <td align="center"> uint32_t </td> + </tr> + <tr> + <td align="center"> int32 / dint </td> + <td align="center"> int32_t </td> + </tr> + <tr> + <td align="center"> uint64 </td> + <td align="center"> uint64_t </td> + </tr> + <tr> + <td align="center"> int64 </td> + <td align="center"> int64_t </td> + </tr> + <tr> + <td align="center"> float32 / real </td> + <td align="center"> float </td> + </tr> + <tr> + <td align="center"> float64 </td> + <td align="center"> double </td> + </tr> + <tr> + <td align="center"> date / dt </td> + <td align="center"> double </td> + </tr> + <tr> + <td align="center"> string / char[] </td> + <td align="center"> string </td> + </tr> + </table> + </doc> + </xs:appinfo> + </xs:annotation> + </xs:attribute> + <xs:attribute name="synchro" use="required"> + <xs:annotation> + <xs:appinfo> + <doc> + initial value or processing value of persistent data must be up-to-date each time a connection is established. + <br/>SILECS library supports automatic synchronization. + <ul> + <li>MASTER: PLC overwrites FEC register values. </li> + <li>SLAVE: FEC overwrites PLC register values. </li> + <li>NONE: no automatic synchronization performed. (volatile data) </li> + </ul> + </doc> + </xs:appinfo> + </xs:annotation> + <xs:simpleType> + <xs:restriction base="xs:string"> + <xs:enumeration value="MASTER"/> + <xs:enumeration value="SLAVE"/> + <xs:enumeration value="NONE"/> + </xs:restriction> + </xs:simpleType> + </xs:attribute> + <xs:attribute name="array-dim1" type="DimensionType" use="optional" default="1"> + <xs:annotation> + <xs:appinfo> + <doc> + specify register dimension. + <br/> if array-dim1 = 1 the register is a scalar. If array-dim1 > 1 the register is an array. + </doc> + </xs:appinfo> + </xs:annotation> + </xs:attribute> + <xs:attribute name="array-dim2" type="DimensionType" use="optional" default="1"> + <xs:annotation> + <xs:appinfo> + <doc> + specify second register dimension. + <br/> if array-dim2 = 1 the register is monodimensional. If array-dim2 > 1 the register is bidimensional. + </doc> + </xs:appinfo> + </xs:annotation> + </xs:attribute> + <xs:attribute name="string-len" type="LengthType" use="optional"> + <xs:annotation> + <xs:appinfo> + <doc>specify length of string. If not specified, default value is 64.</doc> + </xs:appinfo> + </xs:annotation> + </xs:attribute> + <xs:attribute name="generateFesaValueItem" type="xs:boolean" use="required"> + <xs:annotation> + <xs:appinfo> + Defines if the code-generation will generate a FESA-Value-Item for this Register + </xs:appinfo> + </xs:annotation> + </xs:attribute> +</xs:complexType> + + + <xs:simpleType name="BlockNameType"> + <xs:restriction base="xs:string"> + <xs:minLength value="1"/> + <xs:maxLength value="30"/> + <!-- Siemens Support bezüglich der maximalen Zeichenlänge für PLC- Tags : S7-300/1200/1500er bei 128 Zeichen --> + <!-- FESA PropertyNames have max. 30 characters. Since For each Block a prop is generated, we have to use this limit --> + <xs:pattern value="[_A-Za-z]+[_A-Za-z0-9]*"/> + </xs:restriction> + </xs:simpleType> + <xs:simpleType name="RegisterNameType"> + <xs:restriction base="xs:string"> + <xs:minLength value="1"/> + <xs:maxLength value="60"/> + <!-- FESA Fields have max. 60 characters. Since For each Register a field is generated, we have to use this limit --> + <xs:pattern value="[_A-Za-z]+[_A-Za-z0-9]*"/> + </xs:restriction> + </xs:simpleType> + <xs:simpleType name="FormatType"> + <xs:restriction base="xs:string"> + <xs:enumeration value="uint8"/> + <xs:enumeration value="int8"/> + <xs:enumeration value="uint16"/> + <xs:enumeration value="int16"/> + <xs:enumeration value="uint32"/> + <xs:enumeration value="int32"/> + <xs:enumeration value="uint64"/> + <xs:enumeration value="int64"/> + <xs:enumeration value="float32"/> + <xs:enumeration value="float64"/> + <xs:enumeration value="string"/> + <xs:enumeration value="date"/> + <xs:enumeration value="char"/> + <xs:enumeration value="byte"/> + <xs:enumeration value="word"/> + <xs:enumeration value="dword"/> + <xs:enumeration value="int"/> + <xs:enumeration value="dint"/> + <xs:enumeration value="real"/> + <xs:enumeration value="dt"/> + </xs:restriction> + </xs:simpleType> + + <xs:simpleType name="DimensionType"> + <xs:restriction base="xs:unsignedInt"> + <xs:minInclusive value="1"/> + </xs:restriction> + </xs:simpleType> + <xs:simpleType name="LengthType"> + <xs:restriction base="xs:unsignedInt"> + <xs:minInclusive value="2"/> + <xs:maxInclusive value="254"/> + </xs:restriction> + </xs:simpleType> +</xs:schema> diff --git a/silecs-model/src/xml/shared.xsd b/silecs-model/src/xml/shared.xsd new file mode 100644 index 0000000..ee68b9c --- /dev/null +++ b/silecs-model/src/xml/shared.xsd @@ -0,0 +1,33 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- Copyright 2016 CERN and GSI +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 3 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, see http://www.gnu.org/licenses/.--> + +<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified" attributeFormDefault="unqualified"> + + <xs:simpleType name="SilecsClassNameType"> <!-- Same restrictions as for FESA class name --> + <xs:restriction base="xs:string"> + <xs:minLength value="1"/> + <xs:maxLength value="20"/> + <xs:pattern value="[_A-Za-z]+[_A-Za-z0-9]*"/> + </xs:restriction> + </xs:simpleType> + + <xs:simpleType name="VersionType"> + <xs:restriction base="xs:string"> + <xs:minLength value="1"/> + <xs:maxLength value="20"/> + </xs:restriction> + </xs:simpleType> + + </xs:schema> diff --git a/snap7/.project b/snap7/.project new file mode 100644 index 0000000..4171e78 --- /dev/null +++ b/snap7/.project @@ -0,0 +1,11 @@ +<?xml version="1.0" encoding="UTF-8"?> +<projectDescription> + <name>snap7</name> + <comment></comment> + <projects> + </projects> + <buildSpec> + </buildSpec> + <natures> + </natures> +</projectDescription> diff --git a/snap7/build.sh b/snap7/build.sh new file mode 100755 index 0000000..fe8ea20 --- /dev/null +++ b/snap7/build.sh @@ -0,0 +1,12 @@ +#!/bin/sh +set -e + +SNAP7_VERSION=1.4.0 +SNAP7_FOLDER=snap7-full-${SNAP7_VERSION} + +rm -rf snap7-full* +wget http://downloads.sourceforge.net/project/snap7/${SNAP7_VERSION}/${SNAP7_FOLDER}.tar.gz +tar -vxzf ${SNAP7_FOLDER}.tar.gz +mv ${SNAP7_FOLDER} snap7-full +cd snap7-full/build/unix +make -f x86_64_linux.mk diff --git a/snap7/install.sh b/snap7/install.sh new file mode 100755 index 0000000..b4c97cb --- /dev/null +++ b/snap7/install.sh @@ -0,0 +1,10 @@ +#!/bin/sh +set -e + +INSTALL_DIR=$1 + +SCRIPT=$(readlink -f "$0") +SCRIPTPATH=$(dirname "$SCRIPT") # path where this script is located in + +mkdir -p ${INSTALL_DIR} +cp -r ${SCRIPTPATH}/snap7-full/build/bin ${INSTALL_DIR} \ No newline at end of file -- GitLab