From 534e331df92af41c27b2b34177d9ad9c6a471fe8 Mon Sep 17 00:00:00 2001 From: AnsMelanie Date: Thu, 20 Mar 2025 15:41:13 +0100 Subject: [PATCH] upd thermal desktop 2025 r2 --- .../.gitignore | 9 + .../thermal-desktop-opentd-for-demo/.vale.ini | 10 + .../api/.gitignore | 5 + .../api/index.md | 2 + .../articles/changelog.md | 62 + .../articles/docfx.json | 13 + .../appendix-A-using-opentd-with-MATLAB.md | 126 ++ .../appendix-B-using-opentd-with-python.md | 114 ++ ...appendix-C-using-opentd-with-powershell.md | 15 + ...dix-D-using-opentd-with-csharp-compiler.md | 21 + .../communicating-with-sinda-fluint.md | 9 + .../basetrans-and-localtrans.md | 59 + .../creating-td-model/bivariate-arrays.md | 99 ++ .../connections-handles-markers-domains.md | 82 ++ .../finite-difference-surfaces-and-solids.md | 63 + .../creating-td-model/finite-elements.md | 87 ++ .../creating-td-model/fluid-entities.md | 62 + .../creating-td-model/hello-world.md | 39 + .../creating-td-model/nodes-and-conductor.md | 43 + .../creating-td-model/optical-properties.md | 53 + .../creating-td-model/overview.md | 3 + .../units-symbols-expressions.md | 91 ++ .../creating-td-model/use-a-loop.md | 76 ++ .../articles/getting-started/extras.md | 240 ++++ .../getting-started/further-reading.md | 11 + .../interacting-with-end-users.md | 239 ++++ ...ching-programs-td-process-using-add-ins.md | 3 + .../16ae466d28b3584b1dcbdf90484ad0bd.png | Bin 0 -> 40063 bytes .../19913b5a9a51f4926a07426227c010fa.png | Bin 0 -> 20848 bytes .../1fe5ddd44d6df8c7835612e8287ecb11.png | Bin 0 -> 124984 bytes .../24e388913334338e77b9c87f790b9e76.png | Bin 0 -> 5618 bytes .../2f2bcdeb872649910f747dfa5b80c4fa.png | Bin 0 -> 9011 bytes .../3c770a52859919ecb6e3a152a4c38b0d.png | Bin 0 -> 13917 bytes .../4e8146a507a20e79c517c1fe15f18d47.png | Bin 0 -> 11107 bytes .../b81c03156e87978bef43d64eefb85d01.png | Bin 0 -> 4942 bytes .../d47e44c0a654c0607631af3cacc32f6a.png | Bin 0 -> 3975 bytes .../getting-started/modifying-td-models.md | 225 ++++ .../articles/getting-started/prerequisites.md | 8 + .../getting-started/reading-results.md | 1065 +++++++++++++++++ .../articles/getting-started/test-demo.md | 90 ++ .../getting-started/troubleshooting.md | 21 + .../getting-started/working-with-case-sets.md | 160 +++ .../articles/index.md | 19 + .../articles/toc.yml | 63 + .../docfx.json | 68 ++ .../thermal-desktop-opentd-for-demo/index.md | 4 + .../styles/Google/AMPM.yml | 9 + .../styles/Google/Acronyms.yml | 64 + .../styles/Google/Colons.yml | 8 + .../styles/Google/Contractions.yml | 30 + .../styles/Google/DateFormat.yml | 9 + .../styles/Google/Ellipses.yml | 9 + .../styles/Google/EmDash.yml | 13 + .../styles/Google/Exclamation.yml | 12 + .../styles/Google/FirstPerson.yml | 13 + .../styles/Google/Gender.yml | 9 + .../styles/Google/GenderBias.yml | 43 + .../styles/Google/HeadingPunctuation.yml | 13 + .../styles/Google/Headings.yml | 29 + .../styles/Google/Latin.yml | 11 + .../styles/Google/LyHyphens.yml | 14 + .../styles/Google/OptionalPlurals.yml | 12 + .../styles/Google/Ordinal.yml | 7 + .../styles/Google/OxfordComma.yml | 7 + .../styles/Google/Parens.yml | 7 + .../styles/Google/Passive.yml | 184 +++ .../styles/Google/Periods.yml | 7 + .../styles/Google/Quotes.yml | 7 + .../styles/Google/Ranges.yml | 7 + .../styles/Google/Semicolons.yml | 8 + .../styles/Google/Slang.yml | 11 + .../styles/Google/Spacing.yml | 10 + .../styles/Google/Spelling.yml | 10 + .../styles/Google/Units.yml | 8 + .../styles/Google/We.yml | 11 + .../styles/Google/Will.yml | 7 + .../styles/Google/WordList.yml | 80 ++ .../styles/Google/meta.json | 4 + .../styles/Google/vocab.txt | 0 .../config/vocabularies/ansys/accept.txt | 47 + .../thermal-desktop-opentd-for-demo/toc.yml | 5 + 81 files changed, 4084 insertions(+) create mode 100644 2025R2/thermal-desktop-opentd-for-demo/.gitignore create mode 100644 2025R2/thermal-desktop-opentd-for-demo/.vale.ini create mode 100644 2025R2/thermal-desktop-opentd-for-demo/api/.gitignore create mode 100644 2025R2/thermal-desktop-opentd-for-demo/api/index.md create mode 100644 2025R2/thermal-desktop-opentd-for-demo/articles/changelog.md create mode 100644 2025R2/thermal-desktop-opentd-for-demo/articles/docfx.json create mode 100644 2025R2/thermal-desktop-opentd-for-demo/articles/getting-started/appendix-A-using-opentd-with-MATLAB.md create mode 100644 2025R2/thermal-desktop-opentd-for-demo/articles/getting-started/appendix-B-using-opentd-with-python.md create mode 100644 2025R2/thermal-desktop-opentd-for-demo/articles/getting-started/appendix-C-using-opentd-with-powershell.md create mode 100644 2025R2/thermal-desktop-opentd-for-demo/articles/getting-started/appendix-D-using-opentd-with-csharp-compiler.md create mode 100644 2025R2/thermal-desktop-opentd-for-demo/articles/getting-started/communicating-with-sinda-fluint.md create mode 100644 2025R2/thermal-desktop-opentd-for-demo/articles/getting-started/creating-td-model/basetrans-and-localtrans.md create mode 100644 2025R2/thermal-desktop-opentd-for-demo/articles/getting-started/creating-td-model/bivariate-arrays.md create mode 100644 2025R2/thermal-desktop-opentd-for-demo/articles/getting-started/creating-td-model/connections-handles-markers-domains.md create mode 100644 2025R2/thermal-desktop-opentd-for-demo/articles/getting-started/creating-td-model/finite-difference-surfaces-and-solids.md create mode 100644 2025R2/thermal-desktop-opentd-for-demo/articles/getting-started/creating-td-model/finite-elements.md create mode 100644 2025R2/thermal-desktop-opentd-for-demo/articles/getting-started/creating-td-model/fluid-entities.md create mode 100644 2025R2/thermal-desktop-opentd-for-demo/articles/getting-started/creating-td-model/hello-world.md create mode 100644 2025R2/thermal-desktop-opentd-for-demo/articles/getting-started/creating-td-model/nodes-and-conductor.md create mode 100644 2025R2/thermal-desktop-opentd-for-demo/articles/getting-started/creating-td-model/optical-properties.md create mode 100644 2025R2/thermal-desktop-opentd-for-demo/articles/getting-started/creating-td-model/overview.md create mode 100644 2025R2/thermal-desktop-opentd-for-demo/articles/getting-started/creating-td-model/units-symbols-expressions.md create mode 100644 2025R2/thermal-desktop-opentd-for-demo/articles/getting-started/creating-td-model/use-a-loop.md create mode 100644 2025R2/thermal-desktop-opentd-for-demo/articles/getting-started/extras.md create mode 100644 2025R2/thermal-desktop-opentd-for-demo/articles/getting-started/further-reading.md create mode 100644 2025R2/thermal-desktop-opentd-for-demo/articles/getting-started/interacting-with-end-users.md create mode 100644 2025R2/thermal-desktop-opentd-for-demo/articles/getting-started/launching-programs-td-process-using-add-ins.md create mode 100644 2025R2/thermal-desktop-opentd-for-demo/articles/getting-started/media/16ae466d28b3584b1dcbdf90484ad0bd.png create mode 100644 2025R2/thermal-desktop-opentd-for-demo/articles/getting-started/media/19913b5a9a51f4926a07426227c010fa.png create mode 100644 2025R2/thermal-desktop-opentd-for-demo/articles/getting-started/media/1fe5ddd44d6df8c7835612e8287ecb11.png create mode 100644 2025R2/thermal-desktop-opentd-for-demo/articles/getting-started/media/24e388913334338e77b9c87f790b9e76.png create mode 100644 2025R2/thermal-desktop-opentd-for-demo/articles/getting-started/media/2f2bcdeb872649910f747dfa5b80c4fa.png create mode 100644 2025R2/thermal-desktop-opentd-for-demo/articles/getting-started/media/3c770a52859919ecb6e3a152a4c38b0d.png create mode 100644 2025R2/thermal-desktop-opentd-for-demo/articles/getting-started/media/4e8146a507a20e79c517c1fe15f18d47.png create mode 100644 2025R2/thermal-desktop-opentd-for-demo/articles/getting-started/media/b81c03156e87978bef43d64eefb85d01.png create mode 100644 2025R2/thermal-desktop-opentd-for-demo/articles/getting-started/media/d47e44c0a654c0607631af3cacc32f6a.png create mode 100644 2025R2/thermal-desktop-opentd-for-demo/articles/getting-started/modifying-td-models.md create mode 100644 2025R2/thermal-desktop-opentd-for-demo/articles/getting-started/prerequisites.md create mode 100644 2025R2/thermal-desktop-opentd-for-demo/articles/getting-started/reading-results.md create mode 100644 2025R2/thermal-desktop-opentd-for-demo/articles/getting-started/test-demo.md create mode 100644 2025R2/thermal-desktop-opentd-for-demo/articles/getting-started/troubleshooting.md create mode 100644 2025R2/thermal-desktop-opentd-for-demo/articles/getting-started/working-with-case-sets.md create mode 100644 2025R2/thermal-desktop-opentd-for-demo/articles/index.md create mode 100644 2025R2/thermal-desktop-opentd-for-demo/articles/toc.yml create mode 100644 2025R2/thermal-desktop-opentd-for-demo/docfx.json create mode 100644 2025R2/thermal-desktop-opentd-for-demo/index.md create mode 100644 2025R2/thermal-desktop-opentd-for-demo/styles/Google/AMPM.yml create mode 100644 2025R2/thermal-desktop-opentd-for-demo/styles/Google/Acronyms.yml create mode 100644 2025R2/thermal-desktop-opentd-for-demo/styles/Google/Colons.yml create mode 100644 2025R2/thermal-desktop-opentd-for-demo/styles/Google/Contractions.yml create mode 100644 2025R2/thermal-desktop-opentd-for-demo/styles/Google/DateFormat.yml create mode 100644 2025R2/thermal-desktop-opentd-for-demo/styles/Google/Ellipses.yml create mode 100644 2025R2/thermal-desktop-opentd-for-demo/styles/Google/EmDash.yml create mode 100644 2025R2/thermal-desktop-opentd-for-demo/styles/Google/Exclamation.yml create mode 100644 2025R2/thermal-desktop-opentd-for-demo/styles/Google/FirstPerson.yml create mode 100644 2025R2/thermal-desktop-opentd-for-demo/styles/Google/Gender.yml create mode 100644 2025R2/thermal-desktop-opentd-for-demo/styles/Google/GenderBias.yml create mode 100644 2025R2/thermal-desktop-opentd-for-demo/styles/Google/HeadingPunctuation.yml create mode 100644 2025R2/thermal-desktop-opentd-for-demo/styles/Google/Headings.yml create mode 100644 2025R2/thermal-desktop-opentd-for-demo/styles/Google/Latin.yml create mode 100644 2025R2/thermal-desktop-opentd-for-demo/styles/Google/LyHyphens.yml create mode 100644 2025R2/thermal-desktop-opentd-for-demo/styles/Google/OptionalPlurals.yml create mode 100644 2025R2/thermal-desktop-opentd-for-demo/styles/Google/Ordinal.yml create mode 100644 2025R2/thermal-desktop-opentd-for-demo/styles/Google/OxfordComma.yml create mode 100644 2025R2/thermal-desktop-opentd-for-demo/styles/Google/Parens.yml create mode 100644 2025R2/thermal-desktop-opentd-for-demo/styles/Google/Passive.yml create mode 100644 2025R2/thermal-desktop-opentd-for-demo/styles/Google/Periods.yml create mode 100644 2025R2/thermal-desktop-opentd-for-demo/styles/Google/Quotes.yml create mode 100644 2025R2/thermal-desktop-opentd-for-demo/styles/Google/Ranges.yml create mode 100644 2025R2/thermal-desktop-opentd-for-demo/styles/Google/Semicolons.yml create mode 100644 2025R2/thermal-desktop-opentd-for-demo/styles/Google/Slang.yml create mode 100644 2025R2/thermal-desktop-opentd-for-demo/styles/Google/Spacing.yml create mode 100644 2025R2/thermal-desktop-opentd-for-demo/styles/Google/Spelling.yml create mode 100644 2025R2/thermal-desktop-opentd-for-demo/styles/Google/Units.yml create mode 100644 2025R2/thermal-desktop-opentd-for-demo/styles/Google/We.yml create mode 100644 2025R2/thermal-desktop-opentd-for-demo/styles/Google/Will.yml create mode 100644 2025R2/thermal-desktop-opentd-for-demo/styles/Google/WordList.yml create mode 100644 2025R2/thermal-desktop-opentd-for-demo/styles/Google/meta.json create mode 100644 2025R2/thermal-desktop-opentd-for-demo/styles/Google/vocab.txt create mode 100644 2025R2/thermal-desktop-opentd-for-demo/styles/config/vocabularies/ansys/accept.txt create mode 100644 2025R2/thermal-desktop-opentd-for-demo/toc.yml diff --git a/2025R2/thermal-desktop-opentd-for-demo/.gitignore b/2025R2/thermal-desktop-opentd-for-demo/.gitignore new file mode 100644 index 0000000000..4378419e7f --- /dev/null +++ b/2025R2/thermal-desktop-opentd-for-demo/.gitignore @@ -0,0 +1,9 @@ +############### +# folder # +############### +/**/DROP/ +/**/TEMP/ +/**/packages/ +/**/bin/ +/**/obj/ +_site diff --git a/2025R2/thermal-desktop-opentd-for-demo/.vale.ini b/2025R2/thermal-desktop-opentd-for-demo/.vale.ini new file mode 100644 index 0000000000..4e3997ac45 --- /dev/null +++ b/2025R2/thermal-desktop-opentd-for-demo/.vale.ini @@ -0,0 +1,10 @@ +StylesPath = styles + +Vocab = ansys + +MinAlertLevel = suggestion + +Packages = Google + +[*.md] +BasedOnStyles = Vale, Google \ No newline at end of file diff --git a/2025R2/thermal-desktop-opentd-for-demo/api/.gitignore b/2025R2/thermal-desktop-opentd-for-demo/api/.gitignore new file mode 100644 index 0000000000..e8079a3bef --- /dev/null +++ b/2025R2/thermal-desktop-opentd-for-demo/api/.gitignore @@ -0,0 +1,5 @@ +############### +# temp file # +############### +*.yml +.manifest diff --git a/2025R2/thermal-desktop-opentd-for-demo/api/index.md b/2025R2/thermal-desktop-opentd-for-demo/api/index.md new file mode 100644 index 0000000000..78dc9c0057 --- /dev/null +++ b/2025R2/thermal-desktop-opentd-for-demo/api/index.md @@ -0,0 +1,2 @@ +# PLACEHOLDER +TODO: Add .NET projects to the *src* folder and run `docfx` to generate **REAL** *API Documentation*! diff --git a/2025R2/thermal-desktop-opentd-for-demo/articles/changelog.md b/2025R2/thermal-desktop-opentd-for-demo/articles/changelog.md new file mode 100644 index 0000000000..537bff24fa --- /dev/null +++ b/2025R2/thermal-desktop-opentd-for-demo/articles/changelog.md @@ -0,0 +1,62 @@ +# Changelog + +## Version 2024 R2 + +### New features + +- added `case set group name` parameter to `TDSF_CoSolver` constructors +- added `Message` member to `CompareSuite`; just returns `Log` member +- twin lump ids are now automatically sequenced if `lump.TwinId == 0` +- added auto start of OpenTD servers on `_SAVEAS` for all versions of OpenTD + +## Version 2024 R1 + +### Note + +This was an administrative release. There is only one new feature: added `Comparer.ToString()` method. + +## Version 2023 R2 + +### Major new features + +- added support for controlling item visibility via the `ThermalDesktop.VisibilityManager` +- added `ReadMeshDataFile` method to read various mesh data formats into TD +- added support for stack aliases +- added `DynamicSindaStatus` class for interacting with messages generated by `Dynamic Sinda` +- added limited support for new beta `SaveX` file format + +### Other new features + +- added `MeshDisplayer.BaseTrans` property -- now you can move FEM's +- added experimental `CaseSetManager.IsCaseRunning()` method for asynchronous cases +- added `Contactor.Comment` property +- use lightweight SubmodelNameData's to identify submodels for FloCAD objects +- added `GetNumberOfDbObjects(...)` method +- implemented `ConvertFDtoFE` method +- `Matrix3d.SetOrigin` now returns the new matrix instead of `void` +- `Dataset.Factory.Load` method to load `sav`, `savx`, or `CSR` +- `Comparer` ctor overload to accept `IDatasets` instead of `Datasets` +- added `Close` and `ReOpen` methods to `IDataset` +- added `CloseDatasets` and `ReOpenDatasets` methods to `Comparer` +- added ability to rename and delete aliases +- added `CaseSetManagerOptions.ShowTextScreenDuringRun` member +- added `Conductor.UseGlobalAccelm` member +- added `RcEntityData.GlobalContactArray` member +- added `RcSolidElement.AnalysisGroupsVolumetric` member +- added `RcFdSolidData.AnalysisGroupsVolumetric` member +- added `FkLocator.Anchor` member +- added `Pipe.LengthDivisions` and `RadialDivisions` members +- added `Tie.LengthDivisions`, `RadialDivisions`, and `UseGlobalAccelm` members + +### Performance improvements + +- `CreateCone` returns correct node names +- `Polygon.Update()` no longer duplicates vertices +- `CoSolver.Continue()` returns -1 if `SF` disconnected, instead of an exception +- New `scr` filename and pipe name conventions to avoid Windows Defender mistaking `scr` files for viruses +- avoid issues with duplicate handles in Assembly +- fix parsing mixed-case subtypes like "DeltaP" +- fix `GetMeshFD(s)` so it populates returned object(s) correctly +- `GetPipe` no longer returns pipes with blank signatures +- pipe ties now handle domains correctly +- `CaseSet.Run` and `CaseSetManager.Run` now handle casesets with drive symbols from Excel diff --git a/2025R2/thermal-desktop-opentd-for-demo/articles/docfx.json b/2025R2/thermal-desktop-opentd-for-demo/articles/docfx.json new file mode 100644 index 0000000000..8b11bf0e2b --- /dev/null +++ b/2025R2/thermal-desktop-opentd-for-demo/articles/docfx.json @@ -0,0 +1,13 @@ +{ + "build": { + "globalMetadata": { + "title": "Thermal Desktop OpenTD 2025 R2", + "summary": "", + "version": "2025 R2", + "product": "Thermal Desktop", + "programming language": "C#", + "product collection": "Fluids", + "physics": "Fluids" + } + } +} \ No newline at end of file diff --git a/2025R2/thermal-desktop-opentd-for-demo/articles/getting-started/appendix-A-using-opentd-with-MATLAB.md b/2025R2/thermal-desktop-opentd-for-demo/articles/getting-started/appendix-A-using-opentd-with-MATLAB.md new file mode 100644 index 0000000000..5628fa6a80 --- /dev/null +++ b/2025R2/thermal-desktop-opentd-for-demo/articles/getting-started/appendix-A-using-opentd-with-MATLAB.md @@ -0,0 +1,126 @@ +# Appendix A: Using OpenTD with MATLAB + +While it is not feasible for us to maintain separate "Getting Started with OpenTD" guides for every programming language, we would still like to help you get started with OpenTD, even if you are not using C\#. The following .m script is a MATLAB port of the program in the [Create and run a case](working-with-case-sets.md#create-and-run-a-case) section. This can be used as a sort of "Rosetta Stone" to help you translate other C\# examples to MATLAB. + +```MATLAB +%% Using OpenTDv242 with MATLAB +% CRTech +% Tested with MATLAB R2023b +% OpenTD is an Application Programming Interface (API) for Thermal Desktop +% (TD) that allows you to automate many of the tasks currently performed +% interactively using TD’s Graphical User Interface (GUI). OpenTD gives you +% the tools to programmatically create, query, edit, delete, and run +% models. You can use any .NET language to interact with OpenTD (C\#, +% VB.NET, F\#, etc.) or any system that can load .NET assemblies such as +% MATLAB or Python. +% Regardless of how you interact with OpenTD, you’ll need to have at least +% an intermediate understanding of .NET object-oriented programming. If you +% are starting from scratch, we recommend learning C\#, since it is the +% language that we support. However, we understand that there might be +% compelling reasons for you to connect to OpenTD via MATLAB. It is +% possible, although the way MATLAB handles .NET enums is awkward and +% MATLAB does not support implicit constructors. +% To get started with OpenTD, read "Getting Started with OpenTDv242.pdf", +% which can be found in your TD v241 installation directory under "Manual". +% The Getting Started guide explains the fundamental concepts of OpenTD, +% using several C\# examples. We've ported one of those examples to MATLAB +% below. +%% The "Create and Run a Case" example ported to MATLAB +% See "Getting Started with OpenTDv242.pdf" in your TD v241 installation +% directory under "Manual" for an explanation of this script. +% Note: Please contact us at crtech.support@ansys.com if you think there are +% better ways to use OpenTD with MATLAB, especially with regard to .NET +% enums and implicit constructors. For examples of awkward code, see how a +% node is set to be a boundary node and how the InitialTemp of a node is +% set -- in the script below vs. in the original C\#. +openTD = NET.addAssembly('OpenTDv242'); +import OpenTDv242.\*; +td = ThermalDesktop; +td.Connect(); +% \*\*\* Create a simple model of a heated bar \*\*\* +barNodes = NET.createArray('OpenTDv242.Node', 10); +for i = 1:10 +n = td.CreateNode(); +n.Submodel = SubmodelNameData('bar'); +n.Id = i; +n.MassVol = 10; +n.Origin = Point3d(0.01 \* (i - 1), 1, 0); +n.InitialTemp = Dimensional(n.InitialTemp, 300); +n.Update(); +barNodes(i) = n; +end +for i = 1:9 +c = td.CreateConductor(... +Connection(barNodes(i).Handle), Connection(barNodes(i+1).Handle)); +c.Submodel = SubmodelNameData('bar'); +c.Value = 0.1; +c.Update(); +end +roomAir = td.CreateNode(); +roomAir.Submodel = SubmodelNameData('room'); +roomAir.NodeType = OpenTDv242.('RcNodeData+NodeTypes').BOUNDARY; +roomAir.Origin = Point3d(0.055, 1.1, 0); +roomAir.InitialTemp = Dimensional(roomAir.InitialTemp, 300); +roomAir.Update(); +barConnections = NET.createGeneric(... +'System.Collections.Generic.List', {'OpenTDv242.Connection'},10); +for i = 1:10 +barConnections.Add(Connection(barNodes(i).Handle)); +end +convection = td.CreateConductor(... +Connection(roomAir.Handle), barConnections); +convection.Value = 1; +convection.Submodel = SubmodelNameData('room'); +convection.Update(); +qTorch = td.CreateSymbol('qTorch', '80'); +heatLoadConnections = NET.createGeneric(... +'System.Collections.Generic.List', {'OpenTDv242.Connection'},1); +heatLoadConnections.Add(Connection(barNodes(1).Handle)); +torch = td.CreateHeatLoad(heatLoadConnections); +torch.ValueExp.Value = qTorch.Name; +torch.Submodel = SubmodelNameData('torch'); +torch.Update(); +td.ZoomExtents(); +% \*\*\* End simple model creation \*\*\* +% Create a transient case and run it: +nominal = td.CreateCaseSet(... +'transient with nominal torch', '', 'torchNom'); +nominal.SteadyState = 0; +nominal.Transient = 1; +nominal.SindaControl.timend... += Dimensional(nominal.SindaControl.timend, 600); +nominal.Update(); +nominal.Run(); +% Create a cold case by overriding a symbol, and run it: +cold = td.CreateCaseSet(... +'transient with cold torch', '', 'torchCold'); +cold.SteadyState = 0; +cold.Transient = 1; +cold.SindaControl.timend... += Dimensional(nominal.SindaControl.timend, 1200); +cold.SymbolNames.Add(qTorch.Name); +cold.SymbolValues.Add('50'); +cold.SymbolComments.Add('cold torch heat input'); +cold.SaveAll = 1; +cold.Update(); +cold.Run(); +%% Working with Dimensionals +% All dimensional quanitities in the API are stored using a custom .NET +% generic type called a Dimensional. For example, a Dimensional\ +% stores temperatures. Using C\#, Dimensionals are implicitly cast to and +% from doubles as required, but this does not appear to work in MATLAB. +% Instead, we've overloaded the double function and created a Dimensional +% function to explicitly cast doubles to Dimensionals. +function x = double(Dimensional) +% Cast a .NET generic Dimensional type to a double +x = Dimensional.op_Implicit(Dimensional); +end +function x = Dimensional(Dimensional, double) +% Cast a double to a .NET generic Dimensional type +x = Dimensional.op_Implicit(double); +end +%% Acknowledgements +% Thank you to Dan Hensley and Daniel Reasa with ATA Engineering for +% performing some of the early work to determine how to use OpenTD with +% MATLAB. +``` diff --git a/2025R2/thermal-desktop-opentd-for-demo/articles/getting-started/appendix-B-using-opentd-with-python.md b/2025R2/thermal-desktop-opentd-for-demo/articles/getting-started/appendix-B-using-opentd-with-python.md new file mode 100644 index 0000000000..fa28d7080c --- /dev/null +++ b/2025R2/thermal-desktop-opentd-for-demo/articles/getting-started/appendix-B-using-opentd-with-python.md @@ -0,0 +1,114 @@ +# Appendix B: Using OpenTD with Python + +While it is not feasible for us to maintain separate "Getting Started with OpenTD" guides for every programming language, we would still like to help you get started with OpenTD, even if you are not using C\#. The following .py script is a MATLAB port of the program in the [Create and run a case](working-with-case-sets.md#create-and-run-a-case) section. This can be used as a sort of "Rosetta Stone" to help you translate other C\# examples to Python. It uses the pythonnet module, found at: [http://pythonnet.github.io/](http://pythonnet.github.io/). + +```python +\#\#\#\# Using OpenTDv242 with Python \#\#\#\# +\# CRTech +\# Feb, 2022 +\# Created with Python 2.7.15 and pythonnet 2.3.0 +\# OpenTD is an Application Programming Interface (API) for Thermal Desktop +\# (TD) that allows you to automate many of the tasks currently performed +\# interactively using TD's Graphical User Interface (GUI). OpenTD gives you +\# the tools to programmatically create, query, edit, delete, and run +\# models. You can use any .NET language to interact with OpenTD (C\#, +\# VB.NET, F\#, etc.) or any system that can load .NET assemblies such as +\# MATLAB or Python. +\# Regardless of how you interact with OpenTD, you'll need to have at least +\# an intermediate understanding of .NET object-oriented programming. If you +\# are starting from scratch, we recommend learning C\#, since it is the +\# language that we support. However, we understand that there might be +\# compelling reasons for you to connect to OpenTD via Python. It is +\# possible using the pythonnet module: +\# http://pythonnet.github.io/ +\# To get started with OpenTD, read "Getting Started with OpenTDv242.pdf", +\# which can be found in your TD v241 installation directory under "Manual". +\# The Getting Started guide explains the fundamental concepts of OpenTD, +\# using several C\# examples. We've ported one of those examples to Python +\# below. +\#\#\#\# The "Create and Run a Case" example ported to Python \#\#\#\# +\# See "Getting Started with OpenTDv242.pdf" in your TD v241 installation +\# directory under "Manual" for an explanation of this script. +\# Note: Please contact us at crtech.support@ansys.com if you think there are +\# better ways to use OpenTD with Python, especially with regard to setting +\# dimensional values. +\# REQUIREMENT: You must install the pythonnet module to use this script. +import sys +import clr +\# Need to add explicit GAC path to sys.path so clr.AddReference +\# can find OpenTDv242.dll. Note the use of forward slashes in the path: +sys.path.append("C:/Windows/Microsoft.NET/assembly/GAC_MSIL/OpenTDv242/ReplaceMe") +clr.AddReference("OpenTDv242") +from OpenTDv242 import \* +\# We'll want to use .NET System types and generic Lists: +from System import \* +from System.Collections.Generic import List +\# To access dimensional quantities in OpenTD, we need to use Dimensionals. +\# These are cast to/from doubles implicitly in C\#, but here we'll need to +\# refer to them explicitly. (See setting InitialTemp, below.) +from OpenTDv242 import Dimension +from OpenTDv242.Dimension import \* +td = ThermalDesktop() +td.Connect() +\# \*\*\* Create a simple model of a heated bar \*\*\* +barNodes = List[Node]() +for i in range(10): + n = td.CreateNode() + n.Submodel = SubmodelNameData("bar") + n.Id = i + 1 + n.MassVol = 10.0 + n.Origin = Point3d(0.01 \* i, 1.0, 0.0) + n.InitialTemp = Dimensional[Dimension.Temp](300.0) + n.Update() + barNodes.Add(n) +for i in range(9): + c = td.CreateConductor(Connection(barNodes[i]), Connection(barNodes[i+1])) + c.Submodel = SubmodelNameData("bar") + c.Value = 0.1 + c.Update() +roomAir = td.CreateNode() +roomAir.Submodel = SubmodelNameData('room') +roomAir.NodeType = RcNodeData.NodeTypes.BOUNDARY +roomAir.Origin = Point3d(0.055, 1.1, 0.0) +roomAir.InitialTemp = Dimensional[Dimension.Temp](300.0) +roomAir.Update() +barConnections = List[Connection]() +for n in barNodes: + barConnections.Add(Connection(n)) +convection = td.CreateConductor(Connection(roomAir), barConnections) +convection.Value = 1.0 +convection.Submodel = SubmodelNameData("room") +convection.Update() +qTorch = td.CreateSymbol("qTorch", "80") +heatLoadConnections = List[Connection]() +heatLoadConnections.Add(Connection(barNodes[0])) +torch = td.CreateHeatLoad(heatLoadConnections) +torch.ValueExp.Value = qTorch.Name +torch.Submodel = SubmodelNameData("torch") +torch.Update() +td.ZoomExtents() +\# \*\*\* End simple model creation \*\*\* +\# Create a transient case and run it: +nominal = td.CreateCaseSet("transient with nominal torch", "", "torchNom") +nominal.SteadyState = 0 +nominal.Transient = 1 +nominal.SindaControl.timend = Dimensional[Dimension.Time](600.0) +nominal.Update() +nominal.Run() +\# Create a cold case by overriding a symbol, and run it: +cold = td.CreateCaseSet("transient with cold torch", "", "torchCold") +cold.SteadyState = 0 +cold.Transient = 1 +cold.SindaControl.timend = Dimensional[Dimension.Time](1200.0) +cold.SaveQ = 1 +cold.SymbolNames.Add(qTorch.Name) +cold.SymbolValues.Add("50") +cold.SymbolComments.Add("cold torch heat input"); +cold.SaveAll = 1; +cold.Update() +cold.Run() +\#\#\#\# Acknowledgements +\# Thank you to James Etchells with the European Space Agency (ESA) for +\# performing some of the early work to determine how to use OpenTD with +\# Python. +``` diff --git a/2025R2/thermal-desktop-opentd-for-demo/articles/getting-started/appendix-C-using-opentd-with-powershell.md b/2025R2/thermal-desktop-opentd-for-demo/articles/getting-started/appendix-C-using-opentd-with-powershell.md new file mode 100644 index 0000000000..7043a122b7 --- /dev/null +++ b/2025R2/thermal-desktop-opentd-for-demo/articles/getting-started/appendix-C-using-opentd-with-powershell.md @@ -0,0 +1,15 @@ +# Appendix C: Using OpenTD with PowerShell + +Windows PowerShell can be used to interact with OpenTD, which is useful since it is included with Windows, that is, you don't need to install Visual Studio, MATLAB, or anything extra to use OpenTD. And unlike Python or MATLAB, PowerShell was designed to support .NET objects, so its .NET syntax isn't too bad. + +PowerShell is likely already installed on your Windows machine. If not, or you'd like help finding it, check out the official documentation: + +[https://docs.microsoft.com/en-us/powershell/](https://docs.microsoft.com/en-us/powershell/) + +Here’s a simple PowerShell script that loads OpenTD, creates a ThermalDesktop instance and opens it: + +```powershell +Add-Type -Path "C:\\Windows\\Microsoft.NET\\assembly\\GAC_MSIL\\OpenTDv242\\v4.0_23.2.0.0__65e6d95ed5c2e178\\OpenTDv242.dll" +\$td = New-Object -TypeName 'OpenTDv232.ThermalDesktop' +\$td.Connect() +``` diff --git a/2025R2/thermal-desktop-opentd-for-demo/articles/getting-started/appendix-D-using-opentd-with-csharp-compiler.md b/2025R2/thermal-desktop-opentd-for-demo/articles/getting-started/appendix-D-using-opentd-with-csharp-compiler.md new file mode 100644 index 0000000000..4bb5470ce8 --- /dev/null +++ b/2025R2/thermal-desktop-opentd-for-demo/articles/getting-started/appendix-D-using-opentd-with-csharp-compiler.md @@ -0,0 +1,21 @@ + +# Appendix D: Using OpenTD Interactively with the C# Interactive Compiler + +Normally C\# is compiled before running, but you can open an interactive C\# Read-eval-print loop (REPL) in Visual Studio using the following command: View-\>Other Windows-\>C\# Interactive + +Once open, you can use it to interactively execute C\# code, including OpenTD. For example: + +```csharp +\> \#r "OpenTDv242" // loads the dll as a reference +\> using OpenTDv242; +\> var td = new ThermalDesktop(); +\> td.Connect(); +\> var n = td.CreateNode(new Point3d(1, 1, 3)); +\> td.ZoomExtents(); +\> n.Comment = "Hello World!"; +\> n.Update(); +\> var nTest = td.GetNodes().First(); +\> Console.WriteLine(nTest); +RcNode.MAIN.1::236 "Hello World!" +\> td.Quit(); +``` diff --git a/2025R2/thermal-desktop-opentd-for-demo/articles/getting-started/communicating-with-sinda-fluint.md b/2025R2/thermal-desktop-opentd-for-demo/articles/getting-started/communicating-with-sinda-fluint.md new file mode 100644 index 0000000000..3dc546c6ab --- /dev/null +++ b/2025R2/thermal-desktop-opentd-for-demo/articles/getting-started/communicating-with-sinda-fluint.md @@ -0,0 +1,9 @@ +# Communicating with SINDA/FLUINT + +OpenTD can be used to communicate with and control running SINDA/FLUINT (S/F) solutions using the classes in the OpenTDv242.*CoSolver* namespace: + +- *SF_Launcher* is used to load and run a S/F model directly from an input file, such as an *inp* file created by the TD Case Set Manager. Once launched, the solution proceeds normally with no interaction from the SF_Launcher object. +- *SF_CoSolver* is like an SF_Launcher in that it launches a S/F model from an input file, but once launched it attempts to connect to and control it. +- *TDSF_CoSolver* launches a S/F model from within the TD Case Set Manager, then attempts to connect to and control it. + +There is a demo of CoSolver usage available in the OpenTD 2023 R2 demos package. (See [Further reading section](further-reading.md)) diff --git a/2025R2/thermal-desktop-opentd-for-demo/articles/getting-started/creating-td-model/basetrans-and-localtrans.md b/2025R2/thermal-desktop-opentd-for-demo/articles/getting-started/creating-td-model/basetrans-and-localtrans.md new file mode 100644 index 0000000000..a5c5685648 --- /dev/null +++ b/2025R2/thermal-desktop-opentd-for-demo/articles/getting-started/creating-td-model/basetrans-and-localtrans.md @@ -0,0 +1,59 @@ +# Additional information on positioning entities using BaseTrans and LocalTrans + +As discussed in [Create and position finite-difference surfaces and solids](finite-difference-surfaces-and-solids.md), many OpenTD classes contain the members BaseTrans and LocalTrans, which both can be used to position entities. BaseTrans is equivalent to using AutoCAD commands like MOVE or ROTATE3D to position the entity, while LocalTrans is equivalent to using the Trans/Rot tab that can be found when editing an entity: + +![A screenshot of a computer Description automatically generated with medium confidence](../media/3c770a52859919ecb6e3a152a4c38b0d.png) + +These particular Trans/Rot parameters would result in the following transformations: + +1. Translate 2 m along the entity's base Y axis +2. Rotate -30 deg about the entity's Y axis +3. Rotate 45 deg about the entity's new X axis, that is, rotations are intrinsic (they are about the entity's current axes, not some fixed axes). + +LocalTrans is an instance of the *Transformation* class. To use it to perform the operations listed above, you'd use something like this: + +```c# +a.LocalTrans.Ty = 2; +a.LocalTrans.Axis1 = 1; // Y +a.LocalTrans.Rot1 = -30; +a.LocalTrans.Axis2 = 0; // X +a.LocalTrans.Rot2 = 45; +a.Update(); +``` + +BaseTrans is an instance of the *Matrix3d* class, that is, it is a 4x4 matrix representing a geometric transformation: + +![A picture containing screenshot, text, number, font Description automatically generated](../media/24e388913334338e77b9c87f790b9e76.png) + +The upper-left 3x3 submatrix represents a rotation. (In general it could represent many other operations, but when positioning entities using OpenTD, you should stick to rotations.) The 3x1 column vector on the right represents a translation. The bottom row should always be 0 0 0 1. + +OpenTD positions entities at the WCS origin, then transforms them by BaseTrans, followed by LocalTrans. Some of the methods available to BaseTrans are frequently misunderstood. There is a family of methods that sets the rotation matrix: + +- SetToRotation +- SetToRotX +- SetToRotY +- SetToRotZ + +These cannot be used sequentially to perform sequential rotations. Each one clears the rotation matrix and sets it to a single rotation. For example, SetToRotX(45) creates a rotation matrix that rotates 45 deg about the X axis. + +To perform sequential rotations, use matrix multiplication. For example, to perform a 10 deg rotation about an entity's Z axis, followed by a 50 deg rotation about its new X axis (that is, intrinsic rotations), you could use something like: + +```c# +var A = new Matrix3d().SetToRotZ(10); +var B = new Matrix3d().SetToRotX(50); +a.BaseTrans = A \* B; +a.Update(); +``` + +For intrinsic rotations, multiply matrices in order from left to right. + +Translations can also be included using matrix multiplication. For example, to perform a 10 deg rotation about an entity's Z axis, followed by a 2 m translation along its X axis, followed by a 50 deg rotation about its X axis, you could use something like: + +```c# +var A = new Matrix3d().SetToRotZ(10); +var T = new Matrix3d(); +T.SetOrigin(new Point3d(2, 0, 0)); +var B = new Matrix3d().SetToRotX(50); +a.BaseTrans = A * T * B; +a.Update(); +``` diff --git a/2025R2/thermal-desktop-opentd-for-demo/articles/getting-started/creating-td-model/bivariate-arrays.md b/2025R2/thermal-desktop-opentd-for-demo/articles/getting-started/creating-td-model/bivariate-arrays.md new file mode 100644 index 0000000000..42917332a2 --- /dev/null +++ b/2025R2/thermal-desktop-opentd-for-demo/articles/getting-started/creating-td-model/bivariate-arrays.md @@ -0,0 +1,99 @@ +# Create thermophysical properties using bivariate arrays + +The following program demonstrates how to create or open a thermophysical property database, and how to create materials in it. One of the material definitions uses bivariate arrays, which are used in many places within SINDA/FLUINT, TD, and OpenTD. + +```c# +using System.Collections.Generic; +using OpenTDv242; + +namespace OpenTDv242GettingStarted +{ + class CreateThermophysicalProps + { + public static void Main(string[] args) + { + var td = new ThermalDesktop(); + td.Connect(); + + // Let's make sure we're working with an empty database. + // Note: relative pathnames in OpenTD are relative to the current + // working directory, which usually starts at the location of your + // exe file. + string dbPath = "TemporaryThermoPropDatabase.tdp"; + System.IO.File.Delete(dbPath); + td.OpenThermoPropDB(dbPath); + + // We'll create a thermophysical property representing Al 6061-T6, + // with data taken from the Spacecraft Thermal Control Handbook. + // The handbook uses the following units: + // density: kg/cm3 + // k: W/(cm.degC) + // Cp: W-hr/(kg.degC) + // We'll set WorkingUnits to SI with cm before setting density and k. + // For Cp, we'll need to set energy units to W-hr. + // Since we're working with inconsistent units, we'll save and restore + // whatever working unit system was in use before now. + Units.SaveWorkingUnits(); + Units.WorkingUnits.SetToSI(); + Units.WorkingUnits.modelLength = UnitsData.ModelLength.CM; + var Al6061 = td.CreateThermoProps("Al6061-T6"); + Al6061.Comment = "Al 6061-T6 from Spacecraft Thermal Control Handbook\\n" + "The Aerospace Corp., 2002"; + Al6061.Density = 0.00277; + Al6061.Conductivity = 1.679; + Units.WorkingUnits.energy = UnitsData.Energy.WATT_HOUR; + Al6061.SpecificHeat = 0.267; + Al6061.Update(); + Units.RestoreWorkingUnits(); + + // To rename a thermophysical property, you need to use Rename, + // since thermophysical properties are stored in TD using names as + // identifiers, unlike other entities that use AutoCAD handles. + Al6061.Rename("Aluminum 6061-T6"); + + // What if you've got a material with anisotropic, + // temperature- and pressure-dependent conductivity? + // For example, here's the conductivity of "Material A": + + // conductivity in x and y directions: + // 100 K: 21 W/(m.K) + // 200 K: 25 W/(m.K) + // 300 K: 27 W/(m.K) + + // conductivity in z-dir: (W/(m.K)) + // 150 K 250 K 350 K + // 50 kPa 3 5 8 + // 100 kPa 6 9 10 + + // Here's how to create a material with temperature- + // and pressure-dependent conductivity. + Units.WorkingUnits.SetToSI(); + var materialA = td.CreateThermoProps("Material A"); + materialA.Comment = "Aniso k demo"; + materialA.Anisotropic = 1; + materialA.VarConductivity = 1; + materialA.VarConductivityY = 1; + var kxyTemp = new List { 100, 200, 300, }; + var kxyValue = new List { 21, 25, 27, }; + materialA.ConductivityTemp = kxyTemp; + materialA.ConductivityValue = kxyValue; + materialA.ConductivityYTemp = kxyTemp; + materialA.ConductivityYValue = kxyValue; + materialA.VarCondTempPresZ = 1; + materialA.bivarTemperatureZ = new List { 150, 250, 350 }; + materialA.bivarPressureZ = new List { 50, 100 }; + materialA.bivarConductivityZ = new List + { + 3, 5, 8, + 6, 9, 10, + }; + materialA.Update(); + } + } +} +``` + +After running the program, the kz conductivity for Material A will show that the three lists of doubles we input are now expressed as a bivariate array: + +![Bivariate array](../media/b81c03156e87978bef43d64eefb85d01.png) + +The dwg units default to SI so the pressures are shown in Pa, even though we set the OpenTD WorkingUnits to kPa. Remember that WorkingUnits are independent of dwg units (See the [Work with units, symbols, and expressions](units-symbols-expressions.md) section). diff --git a/2025R2/thermal-desktop-opentd-for-demo/articles/getting-started/creating-td-model/connections-handles-markers-domains.md b/2025R2/thermal-desktop-opentd-for-demo/articles/getting-started/creating-td-model/connections-handles-markers-domains.md new file mode 100644 index 0000000000..81b8829c71 --- /dev/null +++ b/2025R2/thermal-desktop-opentd-for-demo/articles/getting-started/creating-td-model/connections-handles-markers-domains.md @@ -0,0 +1,82 @@ +# Work with connections, handles, markers, and domains + +To connect objects in TD, you will use a Connection. A Connection contains a handle and a marker. As discussed in [Create nodes and a conductor](nodes-and-conductor.md) section, a handle is a string that TD uses to uniquely identify each object in a drawing. You have probably seen them listed in the Model Browser: + +![C:\\Users\\matt\\AppData\\Local\\Temp\\SNAGHTML29a2a79e.PNG](../media/2f2bcdeb872649910f747dfa5b80c4fa.png) + +In addition to Connections, OpenTD uses handles to find objects when, for example, you call the Update() method on an object. Internally, OpenTD keeps track of which dwg contains the object, and finds it in the dwg using the Handle property of the object. + +The other part of a Connection is a marker. This is an integer that specifies how the associated object is connected. For example, marker = 1 connects to the XMIN surface of an FD brick. Marker = 42 connects to XMAX, YMAX, and ZMAX. And Marker = 63 connects to all six surfaces of a brick. You might be wondering if those are random numbers! Converted to binary they make more sense: + +| Decimal | Binary | Applied Surfaces | | | | | | +|---------|----------|------------------|------|------|------|------|------| +| 1 | 0b000001 | | | | | | XMIN | +| 42 | 0b101010 | ZMAX | | YMAX | | XMAX | | +| 63 | 0b111111 | ZMAX | ZMIN | YMAX | YMIN | XMAX | XMIN | + +There is a special value for markers: if Marker is set to -999, then the Connection connects to a TD domain. In this special case, the Handle member no longer specifies the handle of a single TD object, but rather the name of the domain. + +The following program demonstrates these concepts: + +```c# +using System.Collections.Generic; +using OpenTDv242; + +namespace OpenTDv242GettingStarted +{ + class WorkWithConnections + { + public static void Main(string[] args) + { + var td = new ThermalDesktop(); + td.Connect(); + + // create a rectangle: + var brick = td.CreateSolidBrick(); + + // create a heatload with default connection: + // equiv. to td.CreateHeatLoad(new Connection(brick.Handle, 1)); + var heatLoad = td.CreateHeatLoad(brick); + heatLoad.AppliedType = RcHeatLoadData.AppliedTypeBoundaryConds.SURFACE; + heatLoad.Update(); + + // with marker = 1 = 0b000001, heatload applied to XMIN + // let's apply it to XMIN and YMIN: + heatLoad.ApplyConnections[0].Marker = 0b000101; + heatLoad.Name = "q applied to brick"; + heatLoad.Update(); + + // create a rectangle: + var rect = td.CreateRectangle(); + rect.BaseTrans.SetToRotX(90); + rect.BaseTrans.SetOrigin(new Point3d(0, 0, 2)); + rect.XMax = 2; + rect.YMax = 3; + rect.BreakdownU.Num = 10; + rect.BreakdownV.Num = 15; + rect.Update(); + + // create a domain that includes some of the rect nodes: + var domainConnections = new List(); + foreach (Node n in td.GetNodes()) + { + if (rect.AttachedNodeHandles.Contains(n.Handle)) + { + if (n.Origin.Z < 4 && n.Origin.X < 1) + domainConnections.Add(new Connection(n)); + } + } + td.GetDomainManager().CreateDomain("HEATED", DomainType.NODESET, domainConnections); + + // apply a heat load to the domain: + var rectHeatLoad = td.CreateHeatLoad(new Connection("HEATED", -999)); + rectHeatLoad.Name = "q applied to rectangle domain"; + rectHeatLoad.Update(); + + td.SetVisualStyle(VisualStyles.THERMAL); + td.RestoreIsoView(IsoViews.SW); + td.ZoomExtents(); + } + } +} +``` diff --git a/2025R2/thermal-desktop-opentd-for-demo/articles/getting-started/creating-td-model/finite-difference-surfaces-and-solids.md b/2025R2/thermal-desktop-opentd-for-demo/articles/getting-started/creating-td-model/finite-difference-surfaces-and-solids.md new file mode 100644 index 0000000000..2be73ed22b --- /dev/null +++ b/2025R2/thermal-desktop-opentd-for-demo/articles/getting-started/creating-td-model/finite-difference-surfaces-and-solids.md @@ -0,0 +1,63 @@ +# Create and position finite-difference surfaces and solids + +You can use OpenTD to create Finite Difference (FD) surfaces and solids, and other geometric entities. When working with geometric entities in OpenTD, you will use two class members to position and orient objects: + +**BaseTrans**: This Matrix3d represents the position and orientation of the entity’s local coordinate system relative to the AutoCAD World Coordinate System (WCS). Modifying this member is equivalent to using AutoCAD commands such as MOVE or ROTATE3D to position and orient the entity. + +**LocalTrans**: This *Transformation* represents the position and orientation of the entity relative to its local coordinate system. Modifying this member is equivalent to editing the “Trans/Rot” tab in the GUI: + +![Trans/Rot tab in the GUI](../media/4e8146a507a20e79c517c1fe15f18d47.png) + + Here is a program that demonstrates creating FD entities and positioning them using BaseTrans and LocalTrans: + +```c# +using OpenTDv242; +namespace OpenTDv242GettingStarted +{ + class PositionFiniteDifference + { + public static void Main(string[] args) + { + var td = new ThermalDesktop(); + td.Connect(); + + // create a rectangle and position it using BaseTrans, + // which is equivalent to moving and rotating it using + // AutoCAD commands + var rect = td.CreateRectangle(); + rect.TopStartSubmodel = "plate"; + rect.TopStartId = 1; + rect.XMax = 1.1; + rect.YMax = 2.1; + rect.BreakdownU.Num = 10; + rect.BreakdownV.Num = 20; + rect.BaseTrans.SetToRotX(30); + rect.BaseTrans.SetOrigin(new Point3d(0, 0, 1)); + rect.Update(); + + // create an FD solid brick and position it using LocalTrans, + // which is equivalent to moving and rotating it using + // the TD Trans/Rot tab + var fdBrick = td.CreateSolidBrick(); + fdBrick.StartSubmodel = "brick"; + fdBrick.StartId = 1; + fdBrick.XMax = 0.19; + fdBrick.YMax = 0.31; + fdBrick.ZMax = 0.50; + fdBrick.BreakdownU.Num = 2; + fdBrick.BreakdownV.Num = 3; + fdBrick.BreakdownW.Num = 5; + fdBrick.LocalTrans.Tx = 0.5; + fdBrick.LocalTrans.Ty = 1.0; + fdBrick.LocalTrans.Tz = 0.5; + fdBrick.LocalTrans.Axis1 = 2; // rotate about z + fdBrick.LocalTrans.Rot1 = 30; // rotate 30 deg about z + fdBrick.Update(); + + // control view + td.SetVisualStyle(VisualStyles.THERMAL_PP); + td.RestoreIsoView(IsoViews.NE); + } + } +} +``` diff --git a/2025R2/thermal-desktop-opentd-for-demo/articles/getting-started/creating-td-model/finite-elements.md b/2025R2/thermal-desktop-opentd-for-demo/articles/getting-started/creating-td-model/finite-elements.md new file mode 100644 index 0000000000..84646cb5cc --- /dev/null +++ b/2025R2/thermal-desktop-opentd-for-demo/articles/getting-started/creating-td-model/finite-elements.md @@ -0,0 +1,87 @@ +# Create finite elements + +In TD, finite elements can be created directly by attaching them to existing nodes, but the preferred approach is to use an FE Mesh Importer. OpenTD allows you to use either method. + +Creating a finite element mesh using the *FEMeshImporter* class is demonstrated in the following program: + +```c# +using System; +using OpenTDv242; + +namespace OpenTDv242GettingStarted +{ + class CreateFiniteElements + { + public static void Main(string[] args) + { + var td = new ThermalDesktop(); + td.Connect(); + + // In TD and OpenTD, you can create a FEM with nodes and elements + // directly, but the preferred approach is to use an FE Mesh Importer. + + // We'll demonstrate how to use a mesh importer. We'll start + // by creating an empty one: + bool useUCS = false; + var meshImporter = td.CreateFEMeshImporter("a mesh importer", useUCS); + + // We're going to call the FEMeshImporter.SetMesh command, but + // first we'll need to construct an FEMesh to pass to it. We'll + // use linear quads, but a full complement of linear and quadratic + // surface and solid element types are available. + // The FEMesh object is a lightweight description of the mesh, with + // lightweight nodes and elements that are only used as input to + // the SetMesh command. + var feMesh = new OpenTDv242.RadCAD.FEModel.FEMesh(); + int uDiv = 10; + int vDiv = 10; + double height = 0.5; + double xPeriods = 2.0; + double yPeriods = 1.0; + double xLen = 5.0; + double yLen = 3.0; + int id = 0; + int elemId = 0; + for (int j = 0; j < vDiv + 1; ++j) + { + double y = j * yLen / vDiv; + for (int i = 0; i < uDiv + 1; ++i) + { + double x = i * xLen / uDiv; + double z = height * Math.Cos(x / xLen * xPeriods * 2.0 * Math.PI) * Math.Cos(y / yLen * yPeriods * 2.0 * Math.PI); + // lightweight node description: + var node = new OpenTDv242.RadCAD.FEModel.Node(); + node.x = x; + node.y = y; + node.z = z; + node.Nx = 0.0; + node.Ny = 0.0; + node.Nz = 1.0; + node.id = ++id; + feMesh.nodes.Add(node); + if (i < uDiv && j < vDiv) + { + // lightweight surface description: + var face = new OpenTDv242.RadCAD.FEModel.SurfaceElement(); + face.id = ++elemId; + face.order = 1; + face.numNodes = 4; + int baseIndex = j * (uDiv + 1) + i + 1; + face.nodeIds.Add(baseIndex); + face.nodeIds.Add(baseIndex + 1); + face.nodeIds.Add(baseIndex + 1 + uDiv + 1); + face.nodeIds.Add(baseIndex + uDiv + 1); + feMesh.surfaceElements.Add(face); + } + } + } + meshImporter.SetMesh(feMesh); + td.SetVisualStyle(VisualStyles.THERMAL_PP); + td.RestoreIsoView(IsoViews.SE); + td.ZoomExtents(); + } + } +} +``` + +If you create a mesh using the FEMeshImporter class (the preferred approach), it is important to note that the *FEMesh* definition provided during creation is only used at that time. After creation, the client-side FEMesh object is not connected to the TD model and if you want to edit the mesh, you will have to get the editable objects to modify. This is discussed in section [Query and edit finite elements](../modifying-td-models.md#query-and-edit-finite-elements). diff --git a/2025R2/thermal-desktop-opentd-for-demo/articles/getting-started/creating-td-model/fluid-entities.md b/2025R2/thermal-desktop-opentd-for-demo/articles/getting-started/creating-td-model/fluid-entities.md new file mode 100644 index 0000000000..de477bccd4 --- /dev/null +++ b/2025R2/thermal-desktop-opentd-for-demo/articles/getting-started/creating-td-model/fluid-entities.md @@ -0,0 +1,62 @@ +# Create fluid entities + +With a FloCAD license, you can use OpenTD to work with FloCAD entities, using methods like those we’ve already discussed for thermal entities. Here is a program that demonstrates working with FloCAD: + +```c# +using System.Collections.Generic; +using OpenTDv242; +using OpenTDv242.FloCAD; + +namespace OpenTDv242GettingStarted +{ + class CreateFluidEntities + { + public static void Main(string[] args) + { + var td = new ThermalDesktop(); + td.Connect(); + + // create a fluid submodel + var primary = td.CreateFluidSubmodel("PRIMARY"); + primary.ClearFluidLists(); + primary.FluidIds.Add(6070); + primary.FluidLetters.Add(0); // 0 = A, 1 = B, etc. + primary.FluidFilenames.Add(""); // will be set to "Water", b/c ID 6070 + primary.Update(); + + // create some lumps + var lumps = new List(); + for (int i = 0; i < 10; ++i) + { + var lump = td.CreateLump(); + lump.Submodel = "PRIMARY"; + lump.Origin = new Point3d(0.1 * i, 1, 0); + lump.Volume = 1e-4; + lump.Update(); + lumps.Add(lump); + } + + // make end lumps into plenums + lumps[0].LumpType = RcLumpData.LumpTypes.PLENUM; + lumps[0].InitialPres = 2e5; + lumps[0].Update(); + lumps[lumps.Count - 1].LumpType = RcLumpData.LumpTypes.PLENUM; + lumps[lumps.Count - 1].InitialPres = 1e5; + lumps[lumps.Count - 1].Update(); + + // connect the lumps with stubes + for (int i = 0; i < lumps.Count - 1; ++i) + { + var stube = td.CreatePath(lumps[i], lumps[i + 1]); + stube.FlowArea = 0.003; + stube.Update(); + } + + // control view + td.SetVisualStyle(VisualStyles.THERMAL_PP); + td.RestoreIsoView(IsoViews.SW); + td.ZoomExtents(); + } + } +} +``` diff --git a/2025R2/thermal-desktop-opentd-for-demo/articles/getting-started/creating-td-model/hello-world.md b/2025R2/thermal-desktop-opentd-for-demo/articles/getting-started/creating-td-model/hello-world.md new file mode 100644 index 0000000000..973d3e3362 --- /dev/null +++ b/2025R2/thermal-desktop-opentd-for-demo/articles/getting-started/creating-td-model/hello-world.md @@ -0,0 +1,39 @@ +# Hello World (Start TD and create a node) + +Let’s create a simple OpenTD program. Start by creating a `C\#` console application in Visual Studio. Look for the template called “Console App (.NET Framework)”, not “.NET Core” or “.NET Standard”. It should look something like this: + +![A screenshot of a computer screen Description automatically generated with low confidence](../media/d47e44c0a654c0607631af3cacc32f6a.png) + +Next, add a reference to the `OpenTDv242.dll` assembly, which you can find in the GAC. (Try looking under C:\\Windows\\Microsoft.NET\\assembly\\GAC_MSIL\\OpenTDv242.) If there are multiple directories, use the one with the highest Assembly Version, which you will see in the directory name, for example “…_24.2.0.0__...”. + +Add the following code, then compile and run the program: + +```csharp +using OpenTDv242; +namespace OpenTDv242GettingStarted +{ + class HelloWorld + { + public static void Main(string[] args) + { + var td = new ThermalDesktop(); + td.Connect(); + var n = td.CreateNode(); + n.Comment = "Hello World!"; + n.Update(); + } + } +} +``` + +When you run the program, an instance of TD should open and a node should be created at (0, 0, 0). When you edit the node, the comment should be “Hello World!”. If any of these things are not true, check the [Troubleshooting](../troubleshooting.md) section at the end of this guide. + +Assuming it worked, let’s examine how. First, we created a `_ThermalDesktop_` object called `td`. This object represents one instance of TD. It has hundreds of methods for interacting with TD models. A single OpenTD client program can create an arbitrary number of ThermalDesktop instances, allowing you to manipulate several models and communicate between them. + +Next, we called the `ThermalDesktop._Connect()_` method. By default, this will start a new instance of TD using the latest version of AutoCAD installed. You can control how it works using the `ThermalDesktop*.ConnectConfig*` property ([Control how OpenTD connects to Thermal Desktop section](../extras.md#control-how-opentd-connects-to-thermal-desktop)). + +`Connect()`, like most ThermalDesktop commands, is called synchronously, so it will only return control to your program once it finishes. If there is a problem, it will throw an exception. All OpenTD methods throw exceptions if there is a problem; you do not need to check return values for success. + +Once `Connect()` returned, we called `ThermalDesktop._CreateNode()_` to create a node in TD with default settings. We put the return value in a variable called n. This variable is of type `_Node_` and represents the TD node in our client program. + +Next, we updated the `_Comment_` member of n. This only updated the comment for the client-program Node. To send that update to TD, we called the `Node._Update()_` method. This is an important concept to understand; when you work with objects in your client program that represent objects in TD, they do not automatically propagate their changes to TD. To do that, you need to call the `Update()` method. (Some objects also have`_UpdateFromTD()_` methods to get the latest changes from TD.) diff --git a/2025R2/thermal-desktop-opentd-for-demo/articles/getting-started/creating-td-model/nodes-and-conductor.md b/2025R2/thermal-desktop-opentd-for-demo/articles/getting-started/creating-td-model/nodes-and-conductor.md new file mode 100644 index 0000000000..9a9f300d4a --- /dev/null +++ b/2025R2/thermal-desktop-opentd-for-demo/articles/getting-started/creating-td-model/nodes-and-conductor.md @@ -0,0 +1,43 @@ +# Create nodes and a conductor + +This program demonstrates how to create two nodes and connect them with a conductor. To try it, create a .NET Framework C\# console application that references OpenTD, add the following code, then compile and run it. + +```c# +using OpenTDv242; +namespace OpenTDv242GettingStarted +{ + class CreateNodesAndConductors + { + public static void Main(string[] args) + { + var td = new ThermalDesktop(); + td.Connect(); + var n1 = td.CreateNode(); + n1.Submodel = "bar"; + n1.Id = 100; + n1.Update(); + var n2 = td.CreateNode(); + n2.Submodel = "bar"; + n2.Id = 110; + n2.Origin = new Point3d(1, 1, 0); + n2.Update(); + var c = td.CreateConductor(n1, n2); + c.Submodel = "bar"; + c.Value = 10; + c.Update(); + } + } +} +``` + +How did this program work? After starting a new instance of TD, we created two `Node` objects, `n1` and `n2`, using the`CreateNode()` method. + +When TD created each node, it set the `Node.*Handle*` property to a unique identifier, the same string you may have noticed in the TD Model Browser: + +![C:\\Users\\matt\\AppData\\Local\\Temp\\SNAGHTML29a2a79e.PNG](../media/2f2bcdeb872649910f747dfa5b80c4fa.png) + +Since TD allows duplicate SINDA names for some entities, OpenTD uses AutoCAD *handles* to identify most entities uniquely. (See the [Work with connections, handles, markers, and domains section](./connections-handles-markers-domains.md) for a detailed discussion of handles and related concepts.) + +Next, we called the `*CreateConductor*` method. This method accepts two `*Connections*` representing the nodes connected to the conductor. Each Connection consists of a handle and a `*marker*`. As mentioned above, a handle is a unique identifier for a TD entity. A marker is an integer that determines how something is connected such as Top or XMAX. (See the [Work with connections, handles, markers, and domains](./connections-handles-markers-domains.md) section) + +When we called CreateConductor, we simply passed it our two nodes, n1 and n2. OpenTD knows how to implicitly create new Connections from Nodes by reading the `Node.Handle` property and assuming a default value for the`Connection.Marker` property, which is fine because node connections do not use markers. (See the [Execute TD COM commands](../extras.md#execute-td-com-commands) section for a discussion of implicit casting.) diff --git a/2025R2/thermal-desktop-opentd-for-demo/articles/getting-started/creating-td-model/optical-properties.md b/2025R2/thermal-desktop-opentd-for-demo/articles/getting-started/creating-td-model/optical-properties.md new file mode 100644 index 0000000000..83138f1d9e --- /dev/null +++ b/2025R2/thermal-desktop-opentd-for-demo/articles/getting-started/creating-td-model/optical-properties.md @@ -0,0 +1,53 @@ +# Create optical properties + +If you have a RadCAD license, you can create optical properties with OpenTD. The following program creates a simple optical property, and a more complicated wavelength-dependent property: + +```c# +using System.Collections.Generic; +using OpenTDv242; + +namespace OpenTDv242GettingStarted +{ + class CreateOpticalProperties + { + public static void Main(string[] args) + { + var td = new ThermalDesktop(); + td.Connect(); + + // Let's make sure we're working with an empty optical database. + // Note: relative pathnames in OpenTD are relative to the current + // working directory, which usually starts at the location of your + // exe file. + string dbPath = "TemporaryOpticalPropDatabase.rco"; + System.IO.File.Delete(dbPath); + td.OpenOpticalPropDB(dbPath); + + // create simple optical property + var black = td.CreateOpticalProps("black"); + black.Comment = "ideal black surface"; + black.Alph = 1; + black.Emis = 1; + black.Update(); + + // create wavelength-dependent optical property + var catalac = td.CreateOpticalProps("Cat-A-Lac Black"); + catalac.Comment = "Cat-A-Lac Black from TwoPlates.dwg"; + catalac.UseWaveLengthDepProps = 1; + catalac.UseVarWaveLengthEmiss = 1; + + // wavelength always in micrometers, regardless of WorkingUnits: + catalac.emissVarWaveLengthum = new List\< double\> { + + 0.100, 8.000, 10.000, 13.000, 19.000, 20.000, + 30.000, 40.000, 60.000, 110.000, 1000.000, + }; + catalac.emissVarWaveLengthValue = new List { + 0.92, 0.92, 0.85, 0.91, 0.94, 0.82, + 0.95, 0.95, 0.78, 0.6, 0.1, + }; + catalac.Update(); + } + } +} +``` diff --git a/2025R2/thermal-desktop-opentd-for-demo/articles/getting-started/creating-td-model/overview.md b/2025R2/thermal-desktop-opentd-for-demo/articles/getting-started/creating-td-model/overview.md new file mode 100644 index 0000000000..5b0c748a17 --- /dev/null +++ b/2025R2/thermal-desktop-opentd-for-demo/articles/getting-started/creating-td-model/overview.md @@ -0,0 +1,3 @@ +# Creating TD models + +We will start our tour of OpenTD by learning how to connect to TD and create new entities like nodes and conductors. diff --git a/2025R2/thermal-desktop-opentd-for-demo/articles/getting-started/creating-td-model/units-symbols-expressions.md b/2025R2/thermal-desktop-opentd-for-demo/articles/getting-started/creating-td-model/units-symbols-expressions.md new file mode 100644 index 0000000000..9ffcea7aa5 --- /dev/null +++ b/2025R2/thermal-desktop-opentd-for-demo/articles/getting-started/creating-td-model/units-symbols-expressions.md @@ -0,0 +1,91 @@ +# Work with units, symbols, and expressions + +OpenTD offers full support for units, symbols, and expressions. The most important concept to understand is that-except for a few exceptions discussed below–all dimensional values in OpenTD are expressed in the units defined in a thread static variable called `*Units.WorkingUnits*`, which is completely independent of the drawing units set in any connected TD instance. + +You can use expressions in OpenTD anywhere you can use them in the GUI. Look for members named "SomethingExp" to set the expression corresponding to the member "Something." Just like in the GUI, expressions have their own unit system, independent of the dwg units and the WorkingUnits. This is the main exception to the rule that all dimensional values in OpenTD are expressed in `Units.WorkingUnits`. The other exceptions are rare properties that must be entered in a specific unit, for example km for *PlanetParameters.radiusKm*. In all cases these will be indicated by the unit name in the name of the property. Any other exceptions will be class members with fixed units in their names. + +The following program shows how to use WorkingUnits, symbols, and expressions: + +```c# +using System; +using System.Collections.Generic; +using System.Linq; // for the Select method, below +using OpenTDv242; + +namespace OpenTDv242GettingStarted +{ + class WorkWithUnitsSymbolsExpressions + { + public static void Main(string[] args) + { + var td = new ThermalDesktop(); + td.Connect(); + + // To set the units used in the GUI, use SetDwgUnits. + // This is equivalent to setting Preferences->Units. + // Here we'll set the dwg units to English with inches + // instead of feet for model length: + var dwgUnits = new UnitsData(); + dwgUnits.SetToEng(); + dwgUnits.modelLength = UnitsData.ModelLength.INCH; + td.SetDwgUnits(dwgUnits); + + // OpenTD uses its own unit system called WorkingUnits + // to control input and output of all dimensional + // values. In this example we'll set WorkingUnits to SI, + // then set and get the density of a material in kg/m3. + // Then we'll set WorkingUnits.modelLength to cm and get + // the same property, showing that it will now return as + // kg/cm3. Note that since the dwg units were set to inches + // and lbm, the value shown in the GUI is 0.289018 lbm/in^3: + // it's completely independent of the WorkingUnits. + string materialName = "steel"; + if (td.GetThermoPropss().Select(x => x.Name).Contains(materialName)) + td.DeleteThermoProps(materialName); + var material = td.CreateThermoProps(materialName); + Units.WorkingUnits.SetToSI(); // this is the default anyway + material.Density = 8000; // kg/m3 + material.Update(); + Console.WriteLine(material.Density); // "8000" + Console.WriteLine(material.Density.ToString()); // "8000 kg/m^3" + Units.WorkingUnits.modelLength = UnitsData.ModelLength.CM; + Console.WriteLine(material.Density); // "0.008" + Console.WriteLine(material.Density.ToString()); // "0.008 kg/cm^3" + + // You can set both the dwg units and WorkingUnits with the + // SetUnits method. Also, you don't always have to create + // a new UnitsData. The Units.SI and Units.Eng UnitsData + // objects are convenient static readonly objects that + // correspond to standard SI and English units systems. + td.SetUnits(Units.SI); + + // Create symbols using the CreateSymbol method. Here we'll + // create a symbol representing a heat load value in Btu/hr: + string symbolName = "heatload"; + var heatload = td.CreateSymbol(symbolName, "34.12 * 2"); + heatload.Description = "heat load in Btu/hr"; + heatload.Update(); + + // Get evaluated symbol values using GetSymbolValue. These + // represent the basic symbol values, unmodified by Case Sets + // or other means. + var heatloadValue = td.GetSymbolValue(symbolName); + Console.WriteLine($"{symbolName} value = {heatloadValue}"); + + // You can use expressions in OpenTD anywhere you can use + // them in the GUI. Here we'll create a heatload, set its + // value expression ("ValueExp") to our symbol created above, + // then set the units of the expression to BTU/hr to match + // the symbol: + var n = td.CreateNode(); + var q = td.CreateHeatLoad(new List { n }); + q.ValueExp.Value = symbolName; + q.ValueExp.units.energy = UnitsData.Energy.BTU; + q.ValueExp.units.time = UnitsData.Time.HR; + q.Update(); + + td.ZoomExtents(); + } + } +} +``` diff --git a/2025R2/thermal-desktop-opentd-for-demo/articles/getting-started/creating-td-model/use-a-loop.md b/2025R2/thermal-desktop-opentd-for-demo/articles/getting-started/creating-td-model/use-a-loop.md new file mode 100644 index 0000000000..25deef6c8b --- /dev/null +++ b/2025R2/thermal-desktop-opentd-for-demo/articles/getting-started/creating-td-model/use-a-loop.md @@ -0,0 +1,76 @@ +# Use a loop to create many layers, nodes, and conductors + +It is easy to create two nodes and a conductor using the GUI. The real usefulness of an API like OpenTD is in automating things that are tedious and/or time-consuming. For example, the following program creates 101 nodes in a sinusoid pattern connected by conductors and puts them on 101 randomly colored layers. This program only uses a few new OpenTD concepts, but it demonstrates how OpenTD types can be combined with C\# statements to quickly accomplish things that would take much longer using the GUI. + +```c# +using System; +using System.Collections.Generic; +using OpenTDv242; + +namespace OpenTDv242GettingStarted +{ + class UseLoop + { + public static void Main(string[] args) + { + // parameters + const int numNodes = 101; + const string submodel = "wavybeam"; + const int startingNodeNum = 200; + const string layerPrefix = "Random Layer"; + const double Length = 10.0; + const double amplitude = 2.0; + const double freq = 4; + var startingPoint = new Point3d(0, 1, 0); + + // start TD + var td = new ThermalDesktop(); + td.Connect(); + + // create nodes and put them in a list for later use + var r = new Random(); + var nodes = new List(); + + for (int i = 0; i < numNodes; ++i) + { + var layer = td.CreateLayer(layerPrefix + " " + i); + layer.ColorIndex = r.Next(254) + 1; + layer.Update(); + + double x = Length / (numNodes - 1) * i; + double y = amplitude * Math.Sin(freq * x / Length * 2 * Math.PI); + var nodeDisplacementFromStartingPoint = new Vector3d(x, y, 0); + + var n = td.CreateNode(); + n.Layer = layer.Name; + n.Submodel = submodel; + n.Id = startingNodeNum + i; + n.Origin = startingPoint + nodeDisplacementFromStartingPoint; + n.Update(); + + nodes.Add(n); + } + + // create conductors + for (int i = 0; i < nodes.Count - 1; ++i) + { + var c = td.CreateConductor(nodes[i], nodes[i + 1]); + c.Layer = nodes[i].Layer; + c.Submodel = submodel; + c.Update(); + } + + // control view + td.ZoomExtents(); + } + } +} +``` + +In the above program, note that we performed vector addition using the + operator: + +```csharp +n.Origin = startingPoint + nodeDisplacementFromStartingPoint; +``` + +OpenTD knows how to perform limited arithmetic with its *Point2d*, *Point3d*, *Vector3d*, and *Matrix3d* objects. diff --git a/2025R2/thermal-desktop-opentd-for-demo/articles/getting-started/extras.md b/2025R2/thermal-desktop-opentd-for-demo/articles/getting-started/extras.md new file mode 100644 index 0000000000..09a14e2d88 --- /dev/null +++ b/2025R2/thermal-desktop-opentd-for-demo/articles/getting-started/extras.md @@ -0,0 +1,240 @@ +# Extras + +The Extras section covers advanced topics and additional functionalities in OpenTD, including connection management, server control, command execution, implicit casting, and versioning considerations. + +## Control how OpenTD connects to Thermal Desktop + +In this guide, we mostly call ThermalDesktop.Connect() with default options, which means it starts a new instance of TD with the latest version of AutoCAD available, then creates a new, blank drawing. To change this behavior, set the ThermalDesktop.*ConnectConfig* member before calling Connect(), as shown in the following program, which hides the AutoCAD window while it’s running: + +```c# +using OpenTDv242; +namespace OpenTDv242GettingStarted +{ + class ControlHowOpenTDConnects + { + public static void Main(string[] args) + { + var td = new ThermalDesktop(); + td.ConnectConfig.AcadVisible = false; + td.Connect(); + // useful code goes here... + td.Quit(); + } + } +} +``` + +This program also demonstrates the ThermalDesktop.*Quit()* method, which tells AutoCAD to close, regardless of whether there are unsaved changes. (To save a dwg, use ThermalDesktop.*SaveAs*.) To *really* force AutoCAD to quit – by killing the acad.exe process – use ThermalDesktop.Quit(true). This should be considered a last resort. It may leave lock files in the dwg directory and/or have other unintended consequences. + +Here are some useful members of ConnectConfig: + +- **AcadExePathname**: By default, Connect() starts the latest version of AutoCAD found on your machine. Set AcadExePathname to the full path of any acad.exe to use it instead. + +- **AcadVisible**: Set to false to hide the AutoCAD window. This only works when starting new TD instances, not attaching to already-running instances. + +- **DwgPathname**: If this is set, Connect() will try to attach to or start a TD instance with this dwg. It will throw an exception if the dwg does not exist. Instead of editing ConnectConfig, this can also be set using an overloaded ThermalDesktop constructor: + +```c# +var td = new ThermalDesktop(@”path\\to\\dwg”); +``` + +- **PipeEndpointName**: Use this after issuing one of the TD commands for starting servers (See the [Control OpenTD servers from AutoCAD](#control-opentd-servers-from-autocad) section) to connect to an already-running instance of TD. + +- **Type**: This determines whether Connect() will try to attach to an already-running instance of TD or start a new one. The default is AUTO, which means it will try both – first it will try to attach, but if that fails, it will start a new instance. + +A complete list of ConnectConfig members (along with all OpenTD types) can be found in the “OpenTD Class Reference” document. (See the [Further reading](further-reading.md) section) + +## Control OpenTD servers from AutoCAD + +A client program communicates with TD via an OpenTD server launched within the acad.exe process, identified with a string called a *Pipe Endpoint Name*. When you load a dwg containing TD entities, an OpenTD server is started using the dwg pathname to generate the pipe endpoint name. That’s how the Connect() method finds the correct acad process when DwgPathname is set (See the [Control how OpenTD connects to Thermal Desktop](#control-how-opentd-connects-to-thermal-desktop) section). An OpenTD server is also automatically started when you start a new instance of TD via OpenTD. + +There are commands you can use at the AutoCAD command line to query and start OpenTD servers: + +- **RCOPENTDV242**: This command will ask you for a pipe endpoint name and start a server with that name. +- **RCOPENTDV242RANDOM**: This command will start a server with a random name. +- **RCOPENTDV242DWG**: This command will start a server with a name based on the dwg pathname. It is included for completeness, but there should never be a reason to call it, since it is called automatically by TD. +- **RCOPENTDV242LISTSERVERS**: This command will list the pipe endpoint names of the active OpenTDv242 servers. + +To connect a client program to a server based on endpoint name, set ThermalDesktop.ConnectConfig.PipeEndpointName before calling Connect() – (See the [Control how OpenTD connects to Thermal Desktop](#control-how-opentd-connects-to-thermal-desktop) section). + +## Execute AutoCAD commands + +When an OpenTD method is not available to perform a task, you might be able to use the ThermalDesktop.*SendCommand* method to send an AutoCAD command to TD. SendCommand has the following signature: + +```c# +void SendCommand(string command, bool echo = true, int delay = 1000) +``` + +In addition to the string containing the command, there are two optional parameters: *echo* and *delay*. Echo determines whether your command will be echoed to the AutoCAD command line and defaults to true. Delay is the time in milliseconds that your program will wait after issuing the command before continuing. SendCommand executes asynchronously, and currently there is no way for OpenTD to check when it is done. The workaround is to wait a fixed amount of time before continuing. The default delay is 1000 ms. You may wish to experiment with shorter delays to speed up execution. + +The following program demonstrates using SendCommand: + +```c# +using OpenTDv242; +namespace OpenTDv242GettingStarted +{ + class ExecuteAutocadCommands + { + public static void Main(string[] args) + { + var td = new ThermalDesktop(); + td.Connect(); + + // draw an AutoCAD rectangle: + td.SendCommand("rectang 3,3 4,5 "); + + // draw AutoCAD text: (Using a dash in front + // of the command to make it command-line only. + // This works for some AutoCAD commands.) + td.SendCommand("-text 3,2.6 0.25 0 A Door\\n"); + + // zoom extents using OpenTD method: + td.ZoomExtents(); + + // zoom view to scale factor 1.5: (using + // abbreviated command names) + td.SendCommand("z s 1.5 "); + } + } +} +``` + +## Execute TD COM commands + +Before OpenTD, there was a Windows Component Object Model (COM) interface to TD. It could be used to perform a subset of OpenTD functions. To use it, commands were entered as text strings and parsed by the TD COM server. + +In OpenTD, the ThermalDesktop.*SendLegacyComCommand* method emulates the TD COM parser without actually using a COM connection. + +Most TD COM functionality can be accomplished using native OpenTD methods. The SendLegacyComCommand method is included for completeness, and to ease the process of migrating an existing TD COM application to OpenTD. SendLegacyComCommand is not recommended to be used by new OpenTD applications. + +Since the underlying RadCAD functions used by the COM server report success/failure via the AutoCAD console and not via a return value, SendLegacyComCommand may appear to succeed when it did not. It will only throw exceptions if it doesn't recognize a command or if the command crashes AutoCAD, and not if the command fails in some non-catastrophic way. + +SendLegacyComCommand usually returns an empty string. The only exception to this is the "get" command, which attempts to return a string representing the value of a symbol. + +The following commands are supported: + +- **acadcommand "command" ["optional parameter" "optional parameter" ...]** + Executes an AutoCAD console command. The command and any parameters are individually enclosed in double quotes. New applications should use ThermalDesktop.SendCommand instead. Examples: + + - SendLegacyComCommand("acadcommand \\"zoom\\" \\"extents\\"") + - SendLegacyComCommand("acadcommand \\"line\\" \\"1,1\\" \\"2,2\\" \\"\\"") + +- **case [optional parameters]** +Calculates radiation and Cond/Cap data for the current case set. New applications should use OpenTD CaseSetManager and/or CaseSet instead. Examples: + - SendLegacyComCommand("case") // Calculates all radiation and cond/cap data. + - SendLegacyComCommand("case rad0 rad3 cc") // Calculates 1st and 4th radiation tasks and cond/cap data. + +- **caseset parameters** +Provides access to the Case Set Manager. New applications should use OpenTD CaseSetManager and/or CaseSet instead. + +- **copyradkfiles fromFilename toFilename** +Copies radk files. + +- **createmapset** +Undocumented interactive command. + +- **disableuserbreaks** +Disables the ability to press ESC to end tasks. + +- **displaycurrentdataset** + Displays the current post-processing dataset. New applications should use OpenTD.PostProcessing instead. + +- **dumpppmap outputFilename** +Undocumented post-processing command. New applications should use OpenTD.Results instead. + +- **exitautocad** +Attempts to exit Thermal Desktop without saving the dwg. New applications should use ThermalDesktop.Quit instead. + +- **exportnodeinfo** +Calls the RcExportNodeInfo command. New applications should use ThermalDesktop.ExportNodeInfo instead. + +- **get symbolName** +Returns a string representing the evaluated value of a symbol. New applications should use ThermalDesktop.GetSymbolValue instead. + +- **importcomet filename** +Undocumented. + +- **mapnastran inputFilename outputFilename [optional tolerance]** +Maps the current post-processing data to the Nastran mesh defined in inputFilename, writing the results in Nastran format in outputFilename. New applications should use PostProcessing.*DataMapper* instead. + +- **object** +This command is used by Dynamic SINDA/FLUINT to display the value of OBJECT in the TD Dynamic SINDA/FLUINT status window. + +- **opticalias alias opticalProp** +Changes what optical property an alias refers to. The names cannot include spaces. New applications should use ThermalDesktop.OpticalPropAliasManager instead. + +- **orbit parameters** +Provides access to the Heating Rate Case Manager. New applications should use OpenTD Orbit instead. + +- **output message** +Writes message to the TD Dynamic SINDA/FLUINT status window. + +- **postprocess filename [optional delay in ms]** +Creates or updates a TEXT-type dataset from a file. New applications should use PostProcessing.DatasetManager instead. + +- **ppnexttime** +Steps forward to the next record in the current dataset. New applications should use PostProcessing.DatasetManager instead. + +- **ppsavefile savOrCsrPathname** +Creates or updates a SF-type dataset from a save file or CSR directory. New applications should use PostProcessing.DatasetManager instead. + +- **ppsettime index** +Sets the record for the current post-processing dataset. Uses 0-indexed record array index (0, 1, 2, etc) not record number. New applications should use PostProcessing.DatasetManager instead. + +- **sendf4** +Sends the F4 keycode. Useful for capturing the screen using hypersnap/cam. + +- **set symbolName expressionIncludingSpaces** +Updates an existing symbol's expression. New applications should use OpenTD Symbol instead. + +- **setmapconstanttol toleranceInDwgUnits** +Sets the constant tolerance to be used by the mapnastran command, in dwg units. New applications should use PostProcessing.DataMapper instead. + +- **setmapcurrentorall parameter** +If parameter is ALL, the mapnastran command will perform the mapping for all records in the dataset. If parameter is any other value, it will perform the mapping at the current record. New applications should use PostProcessing.DataMapper instead. + +- **setmapset mapsetName** +Instructs the mapnastran command to only use the specified object mapset. + +- **setmapvariabletol TolerancesSeperatedBySpaces** +Sets the progressive tolerance to be used by the mapnastran command, in dwg units. + +- **startcase [optional name]** +Runs the current case set, or the one specified by the optional name. New applications should use OpenTD CaseSetManager and/or CaseSet instead. + +- **tdmapallmappers appendToFilename** +Executes all mappers. Inserts the appendToFilename string at the end of each output file, before any extension. New applications should use PostProcessing.DataMapper instead. + +- **thermoalias alias thermoProp** +Changes what thermophysical property an alias refers to. The names cannot include spaces. New applications should use ThermalDesktop.ThermoPropAliasManager instead. + +- **update** +Updates all entity values based on symbol expressions. + +## The magic of implicit casting + +In the [Create nodes and a conductor](creating-td-model/nodes-and-conductor.md) section, we created a conductor with the following code: + +```c# +var c = td.CreateConductor(n1, n2); +``` + +where n1 and n2 were existing Node objects. CreateConductor has several overloads. The one we used is: + +```c# +Conductor CreateConductor(Connection from, Connection to) +``` + +We took advantage of the fact that OpenTD will implicitly cast a *DbObject* (like a Node) to a new Connection. Explicitly, the C\# compiler constructed Connections from our Nodes like this: + +```c# +var c = td.CreateConductor(new Connection(n1, 1), new Connection(n2, 1)); +``` + +OpenTD uses implicit casting in many places. For example, to cast StandardDataSubtypes to DataSubtypes. (See the [A note on DataSubtypes](reading-results.md#a-note-on-datasubtypes) section) Some languages do not support .NET implicit casting. If you’re using one of those languages to interface with OpenTD, you can always explicitly cast to the required type. (See [Appendix A: Using OpenTD with MATLAB](appendix-A-using-opentd-with-MATLAB.md) and [Appendix B: Using OpenTD with Python](appendix-B-using-opentd-with-python.md)) + +## A note on OpenTD versioning + +OpenTDv242 is included with TD as the OpenTDv242.dll, OpenTDv242.CoSolver.dll, and OpenTDv242.Results.dll assemblies installed in the Global Assembly Cache (GAC). All OpenTDv242 types are contained within the "OpenTDv242" namespace. Any changes we make to this interface will be additive. That is, we will not remove classes or methods. Therefore, you can write software referencing OpenTDv242 knowing that it will not be broken by updates or new releases of TD. + +Each subsequent release of OpenTD will be contained in its own family of dll’s (OpenTDv64.dll, OpenTDv64.Results.dll, etc.) and use its own namespace. When we develop each subsequent release, we will start with a complete copy of the previous release, then make changes only as required. Most commands should remain unchanged from release to release, and you should be able to take advantage of new features in new versions of OpenTD with a minimum of changes to your old programs. diff --git a/2025R2/thermal-desktop-opentd-for-demo/articles/getting-started/further-reading.md b/2025R2/thermal-desktop-opentd-for-demo/articles/getting-started/further-reading.md new file mode 100644 index 0000000000..7fc06080c9 --- /dev/null +++ b/2025R2/thermal-desktop-opentd-for-demo/articles/getting-started/further-reading.md @@ -0,0 +1,11 @@ +# Further reading + +- Also installed with TD is a file called “OpenTDv242 Class Reference.chm”. This contains a complete list of all public types, members, and methods in OpenTDv242. You can find it in the TD installation directory, usually in the same location as this guide. + +- The TD user forum ([http://www.crtech.com/forum](http://www.crtech.com/forum)) contains more OpenTD demos, written in C#, MATLAB, and Python. Two boards are especially useful: + +- Software Usage->Tutorials->OpenTD contains a post called OpenTDv242 Demos that contains a Visual Studio project that demonstrates many more features of OpenTD: + +![Graphical user interface, text, application, email Description automatically generated](media/1fe5ddd44d6df8c7835612e8287ecb11.png) + +- Software Usage->Product-specific Discussions->OpenTD is a place to ask and answer questions about OpenTD. There are dozens of discussions, covering many aspects of OpenTD usage. diff --git a/2025R2/thermal-desktop-opentd-for-demo/articles/getting-started/interacting-with-end-users.md b/2025R2/thermal-desktop-opentd-for-demo/articles/getting-started/interacting-with-end-users.md new file mode 100644 index 0000000000..19f307fca6 --- /dev/null +++ b/2025R2/thermal-desktop-opentd-for-demo/articles/getting-started/interacting-with-end-users.md @@ -0,0 +1,239 @@ +# Interacting with end users + +## Control the view + +There are several techniques you can use to control how the model is displayed in the main Thermal Desktop window: + +- Use the ThermalDesktop.VisibilityManager to get and set item and item label visibility. + +- Use an object’s *Layer* member to change what layer it is on, perhaps moving it to or from a frozen layer. + +- Use ThermalDesktop.*GetLayers* or .*GetLayer* to get an existing layer, then change its color, frozen status, and so on. + +- Use an object’s *ColorIndex* member to directly change its color. + +- Use ThermalDesktop.*RestoreIsoView* to set the view to one of the standard isometric views. + +- Use ThermalDesktop.*RestoreOrthoView* to set the view to one of the standard orthographic views. + +- Use ThermalDesktop.*RestoreView* to set the view to a pre-defined, custom named view. These can also contain layer settings. Create named views in the GUI using the AutoCAD “view” command. + +- Use ThermalDesktop.*SetView* and either an *IsoViews* enum, an *OrthoViews* enum, or a string representing a named view to set the view. + +- Use ThermalDesktop.*SetVisualStyle* to select wireframe, hidden, shaded, and more. + +- Use ThermalDesktop.*ResetGraphics* to redraw everything in the main window. + +- Display contour plots using the ThermalDesktop.*DatasetManager*. See the [Reading result](reading-results.md#create-contour-plots) section. + +## Capture graphics area + +Once you have set up the main TD view using the techniques discussed above, you may wish to capture the graphics area as a bitmap for use elsewhere. To do this, use the ThermalDesktop.*CaptureGraphicsArea* method, with the following signature: + +System.Drawing.Bitmap ThermalDesktop.CaptureGraphicsArea() + +The Bitmap object it returns can be saved to a file, or further processed within your program. + +Caution: Internally, this method uses the Windows clipboard to get the bitmap out of TD. Unfortunately, it deletes anything that was on the clipboard before. + +## Working with the selection set + +OpenTD allows you to ask the end user to select entities on screen, just like a TD command. It also allows you to do the opposite: set the selection set programmatically. These two operations are performed with the ThermalDesktop.*GetSelection* and *SetSelection* methods, respectively. There is also a *ClearSelection* method. + +GetSelection returns a list of *EntityDescriptors*, each containing a Connection for a selected entity and a string called *RawType* from AutoCAD describing what it is. For example, if the user selected a node, the RawType would be “RcNode”. + +EntityDescriptors are also returned by the ThermalDesktop.*GetEntityType* and *GetEntityTypes* methods, which can be used to determine entity types from handles. + +The following program demonstrates working with selection sets. It also uses the LINQ *query syntax* (for example: ‘from node in td.GetNodes() where node.Submodel == “MAIN”…’), which is a declarative syntax that can be easier to read than the *method syntax* we have used previously. + +```c# +using System; +using System.Linq; +using OpenTDv242; + +namespace OpenTDv242GettingStarted +{ + class Selections + { + public static void Main(string[] args) + { + var td = new ThermalDesktop(); + td.Connect(); + + // Create some randomly-placed nodes and lumps: + var rand = new Random(); + const int numberOfItems = 200; + for (int i = 0; i < numberOfItems / 2; ++i) + { + td.CreateNode(new Point3d( + rand.NextDouble(), rand.NextDouble(), rand.NextDouble())); + var lump = td.CreateLump(); + lump.Origin = new Point3d( + rand.NextDouble(), rand.NextDouble(), rand.NextDouble()); + lump.Update(); + } + td.SetView(IsoViews.SE); + + Console.WriteLine("Using SetSelection to select entities for which" + + " X < 0.5, Y < 0.5, and Z > 0.5"); + var NodeHandles = from node in td.GetNodes() + where node.Origin.X < 0.5 + && node.Origin.Y < 0.5 + && node.Origin.Z > 0.5 + select node.Handle; + var LumpHandles = from lump in td.GetLumps() + where lump.Origin.X < 0.5 + && lump.Origin.Y < 0.5 + && lump.Origin.Z > 0.5 + select lump.Handle; + var Region1Handles = NodeHandles.Concat(LumpHandles); + td.SetSelection(Region1Handles); + Console.WriteLine($"Selected {NodeHandles.Count()} nodes" + + $" and {LumpHandles.Count()} lumps. You may" + + $" have to move your mouse into the AutoCAD window" + + $" to see the selection."); + Console.WriteLine("Press [ENTER] to continue..."); + Console.ReadLine(); + + Console.WriteLine("Now asking user to select entites."); + td.ClearSelection(); + var selectedEntities = td.GetSelection(); + var selectedNodeHandles = from entity in selectedEntities + where entity.RawType == "RcNode" + select entity.Connection.Handle; + var selectedLumpHandles = from entity in selectedEntities + where entity.RawType == "RcLump" + select entity.Connection.Handle; + Console.WriteLine($"User selected {selectedNodeHandles.Count()}" + + $" nodes and {LumpHandles.Count()} lumps."); + } + } +} +``` + +## Using loggers + +Using log files to record program operations and errors can be a helpful technique, especially when debugging problems. OpenTD offers access to a powerful logging framework, the same one used by us within TD. + +To use the logging framework, you will create an OpenTDv242.*Logging.Logger* object, then call various methods on it to send messages to log files. The messages have one of the following levels assigned to them, from most to least important: Error, Warning, Information, and Verbose. + +Loggers are created using the *LoggerFactory* class, usually as a static member of a class. For example, here is the one we use internally for the ThermalDesktop class: + +```c# +private static readonly Logger log = +LoggerFactory.GetLogger(typeof(ThermalDesktop).ToString()); +``` + +The LoggerFactory.*GetLogger* method accepts a string representing the name of the logger. This name will be used to route messages from the logger to files. Conventionally, this is the full name of the class that it is defined in, to make it obvious where messages originated. In the above line, we used “typeof(ThermalDesktop).ToString()” instead of the literal string “OpenTDv242.ThermalDesktop” to ensure that the name is correct with no typos. Did you notice the typo in that literal string? + +After calling GetLogger, your log is ready to use. Interestingly, you don’t define a log file location within your program. Instead, this is controlled at runtime using the configuration file located at %localappdata%\\ThermalDesktop\\OpenTDLogConfig.xml. This makes logging more flexible. During debugging on an end-user’s computer, you can adjust this configuration file to concentrate on the problem areas in your program. + +This is a recent configuration file installed with TD: + +```lua +\ +\ +\br}4~4HoIokuG-r6Znb`Hqsd|sA^pN- z@>YiG$>A$YKg7L71aWv8lw0_42|l`IAKyIX&AfV9^}$6#1zp~)BRK<6a|T%w1hlel zLAMmGD*?J7f$cfyUqfERUm;iPBY{IB7hg z;%rbJ*odI0NYU$l5+1)4Z_qDS&k|Zttg;%@ttBV`?=!FQZuMz#bi8$-sU04WIY&Bf zcvaObmwUROhjZ#LYv0yP-WHdW7*GJS(MqEFIUY3vnDhmj+zF)#mgCpxl5w;-|o zPHeF#D!vut#|L7X6hXPA6Q=l4YQ|9~W?sv(lKO_n(?Rz2GhRfNLJ6Z>VD0Cl=NTk* zPB&mV>BZ>KFZ#t4Is0Oyvckb@9v@9So!r?I%&z3ol*1B##oe2V4`Ho<=D6=J+TG}a zq49!opuLWuq>tA#;0^Y^=MUY>-4VEw{?`GMnn6n|H)N8Lt&tvn_vA-whW#<)$>vp{ zj@SDDi1vKhC-nKiSu@Z4X|Z7QM$NDh0(P$x+~#Y{?8#P8hvfW6W1hQ9@5Q4z9n1-- zh2t*G(Y5W~-s9{0Be@&dgl=~SAF@62d%6t$jq^hikNYDN*Uuz8We_7q#m-H)d8fP~ z@H6IC!g*R-W1%G)UEXyQBTH-!vk9LCDQYM8%Zgkk5{bK~?&`BRHOfM(dYDDloRF|wJLu8B9mPBYmN?!R#FB9u|-69B*Uu3lkiPdV(1;Mla zXlwN=dyKedpDl-usO~&eLYJ6mB(?WSs5e>>a&#{%S`7WJ;+oO(Cbh{t!?3Y=;7fMh z#-rsMXY`2+$6m;xZO8)g)gZ?M;PBoL?%Y+o#P)*6+31XS|L~4X=>E8Tj0bA?II${f41}#%chLY_eOhBlqbjP#%5hAe8sW+%_?(Rn7qw%O#^Kzit({~Yp zVgD(99^cSwSYDMt)LzisQEZ@=W?5YH2b7bRNi~^L6Z)0ij&h z+QOUNpUy8of0D9*<%7#m*N+b$vz|*YQy#4VxMuJ$9()InGM~$t+Lnh$QCfhbTl*wy zf)=Ic6D}(m!pXpgXiA8^>^(KLG^<-SjVgDb0!zZ}xxY|SyfghEU2VL#xFritl?9Kn z;`0!1uq3}m0%KTdUla+u{>c>QT)OH9Chd zD;Q?R7<`fZf)-)Y<&db(EI{atH&6$nVmvl`k3O$!pn)F`UY=UH^AvEB(bp_!9F6Np zZ<2_*FcQ{KCL)cdnXE>9<)P8f@VP1_)gvr83-!mkiQv z`kdDDPCj#z=cy$UDKX07;A`CI=CZcd5QCeQib_bNcP2Jx?K3SwESUn%2y>hKW?e4#MPiotaw!xxw`5>7SfUushP`qa?|* z?28NOEvn@6gKKCZyZKH&;;Zq2=$`(yEPK_9%t)e>soMU@CL}y zuNvUhKp4&9$Vhi+9n7z+f-sz@k&6q?($bRI&nS&C*dMT2XlYoFgbQ*CRnGXGQZVXA zKD)SBTk=>58s@fyU!Xk=34U1BC<~>4Mp59pLm+88NG|;3&$M!)M&R9PIg>=mhtDYR zk>6dTnPn58mP(R8FzM$biu3IG^MHTiLmI3U7y?t2;rBRy=J=<9rTLJqP=7Q26P^9T zJZJ-10h(j5l8pQBzK3=|Jyn}HYgtOz$iMh!1?9LXXEws$4DWjKkVTo+b4~cYs)p zL+sPxzX*&Gc6Nr3-;$Aadq#P8catxP|O z-7YjzkGU9{RP0zA2@i44j{JLiqhw)4M1nq1dW`&m@TJq!y_>NyLw_v!UMRxLVhqr8EpoP;KQ9Vb`$kwY@A(gH)54|yv zUxz}-I0BJr-DcT5Tnt3E=q#-lk(bx^kmoF`d!8t-@xn$K-hLBQ4DBKeehC;`;qw>y zOu@VuIFu&;xu5K`7U7QIFA-tlfg5BRj~zmEh!eOfkE-6Wouj{sb}T|%sF09GHZk^5Bki?2g?ib1?AJbB z)u0owZH0_m2=lcVcss(Vp!x~(tc{cY#Qc7(AeuZ(Y!Q6iU)koiw>X5v#2wvX1jQHz1;lR)`ChVSU3Kx@EGa5}bCAm%=@_yGw;z7{o}VGSe0)!G z2y_t%w*NRl3fkknJ~wt ze(79y{>Wj;PQq4$tmvGqBVpoTuF`@_RxUnD7jW@nsbnJOkxcFDjE0Y_ECvA=mlAkh z6BV?qh=sWD+m5!9oi(-v%3Q@4CSqW*xes!@-p*w=l96X2T)zISuYvCjGp*a_hd^@; z)To#Z0Oy?}8NK^$d%d&s)y{Bm{bF$g!NlVzZJqb!%~6yB0VzWjtz_xwnogJN=+Jb_ zqvde7%N+1x#jXac?5J-jNuP+a!($CgkG082$ALOj6hczQo@Fsz>a~{4tpR|Q%3L1R|fts?1lw>Z&`@zF6sZW8d!v7g)vQKWh_EC_J;;;Zs4~V zYi8LOZTd+cUX1GS-$~t5V+d4|d4I4(s4dy+4CwV9XE0^#on{+|cBtt=X?*$0IlC5~ zfOYEIOy>rnPl@~^!ABpHDL+1mA$)ohd$>xwBDCsw=Z=?eYwjGUeHBp3SF!Xmh;erB z*jP8kHBaDOgd+Z0_v-7<2K(YJ-k5;vvQ_t9;xlOnufskjsgVTW<>ZMz$Nps4k2XP^ z(tIUv0M=oqy|}$9YZ^H4=mu40i1^xRD?;Z*j<`dCsND+2&B4mD$i5f?hqV;dvHi_cMUY|?(S}l zHkUbP=Gc7qXFt`u_o`m@E~}cz?Y(FtT5PGq6a*#YWoUs)gaLBXF{vZ=0t&&GO8;eB z(#U=&9IAaU3H$PME2E&G0AzNNs3dfSz_iPvNacmH8l&z=C5NIHiV({FtL1?*j6ir` zE;0NH15ejeH>M)%dMGHx_wW=?P2n~mB^^BVWtraVXSH!Q1Nuy6cu+ke9xmKlyrS#k zDRQ$jd_2`2Zqn%0ZzZRPAc&I4DCNsVdJoW)D^GO~w5Ay2`gd7Pi<2@#A%~J^^jDjg znM}h?9BPYjLq$a6(Umxh^tNzLeB-fP2ndM7cwC=OI7|Vx2s>usScM#yT?=*cFEcwH zo+}q05?YRI#NCxx!(QNusjy|PKc^g^7Y%f4$^Mt;GDe+5UQnA;6DtX`G3fGpHTd2% z*~gQ9C^%_U_DOzJEMw+5S3&B!L%c7CIHUl$V)}@|#PQ zg_jm#JUY(Q+8SSmiF*3ROi8c}NhTI^afU4+l_|pfbNH#SR#a@|81B`Ix}aBG%_k*d z97EQ?5tIL5cOaIM$lWqjn9Waht~r*m&*>;B-`Uvjl_)*I@N$*-;;}d1u^RaCtX0>k zI;hbfd~ZUS0L;yoU_8KC#Udrt-46|Q{%jdWN6XX2~WW!fn*y-x>#;d@CQFh%l+%|k` zD^V77f^Ujb+74l;Hc2^LvZaeq_#VOqwi8@?Cnhc2E|i|gEkxcC@_LAy@q6=urnne} zg^AwlY4lp_rrP7byTmj&0=pd*l6M8Keq;Dy(;caHcw38NH=rMg5zF89=AEGGK`nh6 zlMj~*6GV1vF!rz_B}76QjJ@M5IIketxu??Y3%7R~sxjTIbNV@JR9Y61%ac1?F7`lB6dmgC@Q3iIKx3LqQ z{{&PYoA6(c=L{?rD7G)Dg~h(Wxfl?4pB=e=s`@!#s*Av~s2g`vho2QnNwXLq5&qeJ zyLXNLP~d9g%G!a64Z5n}&VsQO#*82O&4ku^&>Z@+Ano_&n7;M-kKD6AJ_gZVdR((` z&4==9`o|c847o40Kl4-JJ8Ul#p+vf!_T=Co8v%aWXC;!A|09C0 zN1&~YCSxGIt`S;t8RkRZJtq_XIZ;;5D z7_ql{m>QLRI?`xV^v?0gwm0tImOd8(?fZ60*O#NKQkp32^0BiIY_6n8cWQA=W}uf; zIv8-E((|c%!XTxgYvE;;8_NhxX;RJ*r?-->e~UbZiAIkNmlVq=t)5>PJD|i*-XI+D zC3-sLzkS=_)o?-T;aZ#b!+)c*QL-QCf_E6F)#MoEex){WGcz-Oc>kEGEycfS zCax~h{4=f|-X^WJ6U7DK)JAyvnzDC#UV85Cn`O>s#Y;-IAKIM9ziyi;>U_o*kZk#+ zH1*LtvEaQKNy5?wrF};xP0@|a!4>;+qB#>ml9K7A+kJjjfhHGWDwNJ`3Oc2s;uYyi zc5K$@$3?0R+{0sOr6$cr8h0`ZZVck3C{pcV81;naBlFFhWV%a6Z$nCaNDr zV|@8uTC|6q{v}PA z)_+HL|5PEPuvT1II~qJZuctYo4s69iLf1J1l=R$-_^s?k*Kkpws$?UoDxvxYV@@br7wnL zXXadfmRe(TvQc2SxJ;j(kuYkR$yf+Oc3~@&NMvD-p!w+$sa}R>IYusE&hfymJ4bv) zIU_S{(HaZkl=ffEkCz_;LyxCa!$up6y}RKO!Ku7}-KA?+UQ?hw?JVC{g{=6x&LOlV zLkEfbg`1v)@~sX^5a~T30Uzs4bJ4lxm-__ zH>H!Phk4a9*3?6Vn0wReeYb}@)NdrBv3&EGC z5|Vs%P+W1toAgfdAnkFtL>Y$CDGgxYJ)B(npet6dljHSo=57kTN83QHQp`&5735b` zn|mLGjg-2f9{hTPj*zZLB_f)KW2RG3k107>+wmhe`Na2_!5NbRZii0y`uCnd!I(II zH-g-p+O4CmCwwmT{U08kUKC}*tKSrjK?}kvqa?jM!mEOP0_gfuuGl(V2?{BUOo63q z6Yre)UaS%_(;P~-TVW82^LBi)sFluWUMD>wx!UPN{PrmP#%Z1F560|!VdJsLXjpzp z+ujU>srYNs9-gdQGuj);uA0?r19uvRe=`NAc{K|?$zeGJi9EM))gE~cf{ir*)W}pn zyUfDE6%kPssdCqhbhl}52V+Ylj*BK-oPRVTb`n=yHH(G!Crwmd<`4Bq5uZXSmO{6O zUA5Y1Ns0n#B30wF6TThTY)FkMQ^aOD^t1x5;}dE=`W__Im^1z*{(;S8?+Kmh;*4uB zQ{Q)}ATd#m!h|^Nlf@yw_&MQ#FmQoCs8jR|k?3wZEhyR+g$+Wykt&RZ>saz80C6LO zP-=RX1zNg@+KCSCzL3Ks^6QqY6KQ|(=WJF)*V`XmbxI5o(JvpD6XUmOg8<1v^1(dC zW=u)$r8pIW1-QU3Gn5seFN*+}Dfc#{4#BfS5;-wvJO26IB8mmZCTYXE->hMs-Wb@H z1|~OVS~?j+mx`P)HXMceSgG?zOSo;`lb+8^&;$HaQ%kg+F2>1=y%H!?Pet-Uxyn7_ z>TW|>B@E5Z*=+63h<%YtKvZZ|fx+wMcnao8uA{Z1i(~OBNS5QTWJPUAYtT=L@+K;U z)YQ;Z8(s(sJ728u{HuvrtvL-4&Ug^aeM%wvim%p5#`*RL5?8A61T(ns%N=^oVvVDf z(nsMQQ`cZmqtU>LIZlD2AXxB?E zNtduYfqyM0hUBpjk}6jJzf(=5nD6?K2b->+`Vqy|Ve7I)-{VY-ri z=)^pW_mwg>%W8U7F}Z8Obi>_XAS#edx7I`UreWf;U`NDjLox~3@OQ+?cU`1ZQim}L zk4J!iq+n)Lbq^<%>xtvzrH#iyiL}K&imZ(FI)1tTBf!IR!osIwS5&&AcC$a`J-SIW zGz4}%YzWss6*bkKA+A3SF<*jkkRCh+W1@t?&p~a%-Fc}u0Zo1(+`^^(2~mN|bJMC< zh<>Df{O;+97itK0dPrY1`-|>8xdzxkU zkdx$xmTVy%JP&<1m(s$kOnv;8k1wZ~isk-zhW?%?oj^U-RS;R(d+yRm}$o+*8}W691dGEpB%hr=p`CH~DJ9s!+GA&}q*{mhrR!Z-1U&ve(Cj zF$OdBQ-z~}1Pa3_RVgE=M2zrfabF>`H2m#^DC-f?~6Lwd$Nn{9e!}AD(wS zfH>5o{ew$DB7y5|;AIKheD$XReEcP-=nEuYhM7c+OHcl(4ps!HiB%voVfKJZ*|g$q zgA~w@s|gE)mAMAyt_U_wg|TIGA$Acm(RDbJ#I!8Brxx?8)sf|*(o8?lwEi5P#LOSWH zh1xrJL)7btbU!a2n9X2oSL0o=Tofkr4qfe8A<^qOy!7&MwaL5P8NIE7y5(nBQs@s; zSayY(t2mSbEz8>ae1*~I5d091m|Wq6htcKpB{$oySZ<+Gktt2HJ@u$7oiBjtEV|t$|L8cI zwyV4^?e-B(h>v~TQ*LLfFMWH6w+8}&2L^PPP5nl%G92|>`4ed6(p4nl?$#>LTQsM? z*sCA&95&PGm@`707w)((Q7(i+z;&UBpQQMHwj(t&3KliRWl8U}0^$#`)}Y;}m!DX6 zJEAu_n`F;p6g=!JRBI(8_C6yBS#5;ec@J0jC6M3oPkG9qFO^?;i-*jCvo$&R#QMiS z+c7M@YUDvnLGw>j8;4p6y8FQ8!7XgA1BqXv$&+Q1k*PNcc z5B_ZU_#;&-QvcrUpUJFJRX)he)K_)?@?pZxFm$ZWaLi$KIe9lP$cQk?b%DX@2eL2jY zNHB9ZSr`y2pROQGBX^TyT$cAvC}Y;Cv7S&}1XeBd-hkdBDY)w# zeXQT!Cf2=0hFtY6TmAR+vVS>`!^S|P!J$f!_A?|lLh5|S8mRpu=aVAMp5GzRXyMsD z;H5M{F_wwgf!ABbIW&AI@*M0(u+su4 zGNLbh;Ws|<_USWGqE*eb)_sE! zj`rX8o0#TDJYR%5fy*p@b^K6_VlGZy4=EQ9S&H;&Sjz&{g)60Brh-)PVeY!c} zPH(U7TT1>VIiJ(#7n?vN?Kk@qj(mm9=}gKr9Fx4rJ4F1-k4qc9mh4oMS1(OhPtI+Z ziR>qrE4i&Cxvv#II+7bbHyfZ2Rb5X)t#8#}d>gFtqf?btM+-cU=f586G!=V{75g&s zZ3BYN&6J48Ed&GKuIBEn7;0}$%`tTRJTVjeh>#~-CRV%=i7vXL{dH|SR3NdPboQBD zXvZ_W1>-tz@b9T>WY2G?K#qAKMlHsbN!H^L5mRQaXz|Fq&;oDr!_;CTu&`icq>v%q z4QTNP(Kb6UyI4KV?TDO@RJ&AZ_@7-hgA?+LD#2nS$!9NV^?CD)8j8s%=uvcpVCf}) znWMr;6Y0UM0|;R5cM2t=T;pEB8ik%HPhaklcP|C9moNj&ABKBI_mEQ~ZE^ve->&Z6 zQP-W(+uR6hCVu8t>eYy`iOI$}LxpLo6(nC#*Dg5_JGGVT*|iN(z=pr#lGukGXyJG% zb_SIguvIe(F-&A75IUub7~)EubR(Z9g#rjJBBBKL ze6(Kz-gBX$;pcVIeh*C^JB~OOf_8G4-2L7py%-wHI^Xv-A^6$mFGP0uVOX8cIiQ!$ zm5KEoAfnooi`nA7A^vb+Xt+A2f=0W$+pJ_n($d$&#_^04saZ_Z2|khJx0N68e6-0V zT5KfR`*ni*s?w+YhF4vzt*l|%({XoFaxyFNV`xw+BeeIUJpF|Pthj2h^4L^mOFK5D zBFg#Wv*IpND+_w#G)_I9B-CDWiG`r-X-YFE6I)#lqkT{&ZCO>**L%|~9&3ydy@ITaC8g zVcQGJ5T#2aO&8_BOaKlXaS_TpcBp<0_vE|Z3F!aYGOv6ihv=8bjc>GVOT&d5BP9+L zgHZc<1gVSfOvR=l80&3nV_ZS7hedoiOM$y~1M#B!5rvar{znZf&Ylc*$IyKTu22We zg!>+O(k3zvu7EfzYouoMjgtRI!VuXKNv9n*Gxp7qVS)Z}R^24ProgOyxhP&kh!8DG z+O++NdSj*lQH>U6-VdBFP*_^&jd<=;cAR5rR%OE>jK2tN-iOV%A+1c3OlnxD^mcgW z=A!HiP{tYMd3Y@my@_VbcJm#_f)}$`Bej)QMwiuTm^pe*&G}_+e&r`kFVlXTbu)Vc zXZd$8wqMgK3t>q5&eoD3+?Z+nEQ`=N`P5lF4{M|~2v>{BTuBBmJZ~o@!4SL?zxMTQc7Rx0kYOHtAYe<~Oxcw*)*&!w_Ye-_;(rx$!>8{!dXt<)I zyrF28Oyz#ic(R%`c-}A4h?3u=mY6HnM;o!b2f_d91z;K~qpWC>3`=egOInb9ox*$? zU1W!)ekPw#-%{_yfeYU>7a_$_+It*Y%%5Aur`4(a9`2*?r;Y}oHakJ?`%iZ{*{x4= zhI@cY-@4g(cv``z;ol&IALSX3i7X%i{45VoxMDcAMyJV?m^#TEI=`o_r<#2k@re}+ z%!fl8H(p>JUPmS_m7dQ^zrLcW6`_!EA63VZH)o)L2&)c3{C*cXZC9!MkvnIxB(JQ< zBpy)VVF$T>F)6(>1_4>4(pM2@nV0=-H``2h$E1v222$`vcavE?;a;sjsbocpKsH~v z@uJB!Fje9;+L0R`{R60l)MJkcDMAP2XJ@WpseJKyBFm$}Wy#oh1BVJ251sp2bhJW( zrkLdK?zayQ*=*&wKSFz&sY2t<&?&zS<{H_3?aLwCgrI|u%t%YUlQO;HK&gQ(aP*?u zj6K@S-(wI|2zQ(?$TCcFw!ZN&oR>-}Qzf|YNCn%mhM+20b@YCPbr!(Sd4Pv{xoqk9 zCbchIkSefR)IM+ZurpwOhF=1e6_=opj&It#8LW*ZwK&l-lYs^+#mc%BB5V?oD;*^j ze3}c>^8w;)RI5kTz`=qWF;Yj*MCDkiXo4(b(S)ORBfhs|Czr5yY2LUw|7fskP&_Pf z%F^MJ>F2V4YUI0(b!@|Ej@%em~B`l$`< zt=cJ>06_{1h^6wxA?@i3#lUplBfWsIsjcmTjV!=u42*~RKmF3nroixQlv{e+w*Pu6 zr{(!GyM*T4-@=Y;+3!_ooY2NpUXHQ{A_|?><)Y5x*k)q;NWX-sBUf!=t}%0!sDDkx zN!+EO+3C0i=xDzh(;R+mJ3CX7+rN*}Xy)dPV_u??z@4A)D_F7^44S8vk^5SdjbNM|w_W?FsN; z9Ye7}$twvrl^B+OuU%I_YCNd;$}l>rj|+%^$+7|lWn{1-JxpM)d@Byu=1ZVrJ?QeS z9|+VsJjM$W-jxi$Q{+gRHDxsQNRwu&;^?TxmNZBDwDQJ=%+(Qmu31b%_nvLXb)h84 z(RP>W_f0xzU>Hy-#mc*_2a7pjOCtrT2rRqe_f<^nyuCCD8evSb9$PH_l0JWr6BtK2 zJeU}2_L5ezqrfH@tnK*Bekv8%FAKVZ7dv%g*yeMERNsCB zgFPGKrjU5Ejd7r;%eSST)G{R_T<&9Zg~ez!_7nJ~CvkJqTLigv`@ zN$-PgCr-BMe6igYWkyh_l%@i5+=ZS1CBmftm7Hz_(>&W2G6v>PY4O%TxZLm-?`J&+KEaM+1O*^cXlk z8>;JHxPh$U2bYUuQB=x%#?whi(u$DkXgQXj$HT9ji3*Ug*RN=X6+2;1S{5$vd4J!S zrH@(6&dv3880FlK)pZbhqoD0oV8yHWY!70d^zv)xPLrPcbM3feXe7? z*`JcLY%?#b=U3e^e`8%X9vl}{u=}uPSHW}V25rqP9LRqz)Auu)YaenonBpocKz4T8 zE*f?N)4F|2>vtuYS73NiLMDDt~8ika-cA3lf?Ld(w$Wjzb_GBpK z4p_4_Y^(&kgyXS(?4~CgoC}zQe%EQf%{@P+6$ksi>%u(#3#g3qY z)u>bzm~P{u0b|RnK3IciA@QwtoAwhSucMlzRbc)nCR-7iM!c?tXK25c1IQbOaW0lR zE}-FT6C& z1mW%f0APPw8BSCq{E{QBJ+4f!6 zt_X~|@iwdJys}z0r942k9^}NMlzxQFAd!(v&}nAhsKHdW)9>s_5?5FiVST}8z?L!1 zYx*hJ<7<{7?VLI|AeJVG$i@z%EG-r2hFpR^5gLvT!g`?6yl9p0)G% zVThCcyUZ;#eYu16U>On*s0@G??Fijw2$yatMQz_XBmq+3YJ8(BwEa{fGE(@1J-#Js zl)B_oR*&g)xm00hQhH>!Fem)N$Ae(E(t3`Z8FtAn#h)A2vntiJ%9g{YFN)190tsoh zLV0UTck$OAs%e1q!{V#KQbZc|0}tj(@mA~U*ZIC%RMqHh9)3y9@r&fFojY&+!;(ok zc6uA5C;YwWvW=06=zbPFn)_RL8}qZ4t#m}ukrtMOWHRh;)C#$dP>yg)*UQTGwCpbc zz#&K$XrjS=U|{r7oif2IkL(`x^PJ8PY#x`Oo+NFK!GC`1{RtgFvatP9V+rsht@8wQ{=?5Bzi*Hn(q1JmmFHM~v3B0*`JgK{d?9%ox&Iqro9|Ap{Vh|5&|WYyk&zm0 z)tlNarGzY1?4n>sHB$bxWYQar88mj|0T;9Q;!1>wgfz$=IjL*LI0E<=`ubBSMo~XK zep;@O8nsmrm(n1v*U`DmA`XF(W<`T%cFeiZpdj7(UuoIYpmZeAy4}xdRh~r2U5K&b zfXBU6)*W++Q4@DsjeeloI$MncD!Oedk9dedMQ&IUTVuHo-}TcRXzoxRg12rAFI8Sw|#(nfY~-hF;W8fw&fl z4>#D}Lu%Ra{>*R_XCk+o8CkwtMLw_Sn&KEK&$1acQ|JcDXZegIVLdzTANl(1ZI`cP$|%3u)Bl-{|Ou!ya>!@IeHENH>535Zl@!l_TV=?$T!%QficTT{7j|UB?%*;fW^zHx$**}R4(=yg@YrPBO|YDt=`8rFr8BI$2juM3BnbaQ z1u5h{nIl27Jyo0@>n|+wsz%(AM&9@(;n?|{_Zj+aLgmMxYwLM)Z%yT|`AjHOo2bv`8`pgK&JJeVSQ6X1(`%@P$=hd?)S`2SnP0{{LYr zM8TW#CNuZ9N_C?4GD!eGQ*(mrilB)5ba}43*$SBrL%+Lv`P?7~dh9>$JnRKpUX7|U zZ&6zdo8+Y5!sm9N=bju1$30wSB~mP;c3y~=kzX+wjEgnXlqJ@s1VEbnSDX6% zRvf_Y9=_e^?unpzKH>VY8Q0i*Vu_7~&S0g=s@~#Wr~_4@zhjKw5DM!- zltdcR6kLLju4ah8Skl#F8?aIje#{hU7F@<=Ka4Jn)cC1Ip;mois3u>t4V==8!CDax zpD?$T=wFL~o4GS9`Y3N0HJ~mzXpGG|2lq#GmZ_w^A?m=YFoWz8Toqu0f(`&(H5 zv0g$HVF6AnC(0Iv|Mv()jbpQ-{aeD>q?LqUW+tiR|Kl42P_;q==&+;unQNA8XZ*Ey z5f-kmY;}iRXJ==PHadO3Nfiu{Fg`q8P9-)^E(I$I-jjZI(rv(1q;i(ML zyU1TS!8@SPoU(Fc9et}ZctD~Xj;t}(Hyu`3bL-LiOhthM|2LVl|NI9AnvO`c|3BoB zf>g{wi0!)bZ_Z+qit-(xQDyTSHU4eQNa+0+_bDhY{{DmSFKe>$3O!*b5CyWdt5V>) zf#nSr@r~gjFTPK@+kdDhPgV^hx>D%9a4rzGm2T}1$;u>q_MVLSfUyANX{cTv9aLl& z>qGnXnb;K`N2+ghj5WfTn+0pSfHa&|$R)#rzv-*Ysv%$7X<5rYA2uA>HeQdFG7NV) z&AtM_v2E2QrIz_SuuK5~2{=1w*I2TzBYvIp&kd}0z9TzE79d55`_|#P<>jcs4~OgN z(3m*E2yfw=kHlq=wF(Goq$K)M-7765mP#GrT}11F;R{TFL~ikWV8YBHuREer$6j}~ zdqr<5Ntvah1pLbhZ<7zHhda8xr z+9N20e=D_KJ1W=VZEPu&9J{p~F_;^EyqNL+8t+7KUe+=n-~K1SYGMvNd208vF}m&J zUJ4(7ZL4Xz16K^=GA1IyKUX{AX-9pFCgpG?&KCB?e|A5Y5O+nUn-Tt*mSSZ?7hMs7UgaR6#*N1bb78LxPZw&+&H5ct5K6N$8<5d3qAU(&*FHCvhA^>@ zl}m@+5%2sVxB$QYiw~?sN{Y>GB)mg0_d5^7>f8Clr{+r}9}7{)D&T6O@foV($aUhO z!nI-ckeU9n{M}~~A|VFXwlLJ2!~(&-%&*`MN9Q5#Yq{IBphyFvH>_;(_a=?Yt~WG? zw`=WojaqEhD5Rnz?(S^n7Q?!#0>AFLkeRA%fQ^II<>9<+ngehI}_%=q^MJ2CBh8^w%P6c&AtYX21V zz!TATve^0)xT2f5w_3V`wHo&oUx+0Q0>9!i8zjAHn9R+OefyICFt9|$18=ujdkWor zLkW~K_`5=U{zxju441UQ8yPVrgt$0w99)1(Z#AU4dRH8U?%5A1w?tGrWw{lF>4|l_ z!oh|b5NRoK-`M6S;W1a$GFE5N8G!a-r)iTMb#mzU;!$V+-bzpYN|j- z?u^;cqbP_QCxS_}0@u!MUDeiN9s-Y`t?1^FPqVxI z@5Tm!seblQ>P#ueTFd*B{z1oCQ~EXjk^P#dM^$TXq(^Hh&QHWUJi$rP^xNDh4Fn56 zoSY$sc{%!D72)d9goBeOb3ZT^z3vp?jwlft_9{Ovc=&ti)~u+9oR%SD%GU>c+N_-? zZ!5<}Sp$pCvFlk9XWU$=p0}5f+_A7V?hA`>re)FF*3vt}J-_I!v>>4S6Oj)l(+IbVgxrgTXd(cj5J3;$z2MpfSPEg1nDPU(qLPcC7E|1LA@Fu_9>o`%8Ycx#u8CVfvdvo@vrOePX#i@eleB(3m?)) z8vs4e2HS!Ft`TebI21jp@@&2^A*m+otI^SgukCA?zK>s213C%3AkYgtp^_+$kr1}77Q>gv$e0D9l;=I%MO~EDS^C1!%qaF&+7#| zb-<4o`&rB&){pmgZe&zV^i`pM1~5L+?=h-e24a;rxTBa9BO5#cD^tG17B?BTn?jIg&N$3Yne_o-{>{mUqe0E zkt}Ow++msb+jE*3Q=EjF!B^;4H6$(clbULw(qmE#&UXcOM3Rs$KSmM*BNirpG?POV zg<>PNKhvM`FNOohC$gmAG|1Yl5cBqU7pJtM!+6Q1!aiFsMEhhO470|1OwLw_FD8a2 z%eu5pTbrd4{6OH_I(_>fz5YUJz{?i!N;Kec`8^)JKZ!|wygoE^Jye`|`*{qh^d=i% zvGMFt#29U`CTpf%VZ7QSFHg)D*2ml#)mRO~$JK7~GYO1tc&i!AlvT0ObT`=jax@C+ z;rA;(huTl$=!rYL7k`Ia<3wk~Kr2{r0Wi!17OWmKKfGxhhEt_!cUlq5?EG&_2-1dq zz-N+v%L^{mLw&p{>ITmi&WsAVBcs+de>AGYJCl|7)n<_JWFxwr@Ei`B=8Nzv*Zavl zxtG1X2m^xnrMF*TckfIYu0Nc5Vl&L}P5GS@wRa45)>G*?M(c?bltDJQWu0t?v@RiztJ?iV!c zM2$U(bKwczQCpSB+ud?in|eyjVRkKp$MoP1ZlwkVk#9cW>q_7hf>ykP&(_<5)J|3U zS)u7&Ar|MF7ZR6I>(;ZCqvEaWaaQoY2F6zu0-l(b8=iP?pq*D9%c))nVV6e2`?0`5 zip+;TZ8QcwjEoa}KWLc3%c1~;%HoBoRTp$6?uLT+TnC*FnJz_Jtr#I=zrjB_37nl z&A9c;$5J454WSL?}p93hD*Vtwri` z)%$EQM-^^o&`&6-Ble=f0WkcGe~H3htgjo6ED%#5?Y5KN-z(Ef;{wcqK3@vluJVD{ zU{&~GGr>gYbHXd|`m(cF<4O&hndm~C`HgnEwAVXyurB_5PpI{NUrZ_eK2!a0S~ljy z#sl+WI|E8l4IZ*S(Zl17boDj;39W2ZXCW8!g1=yN)_T-F&_HCt*FWU>*t({G4_cAM zU}G+{K-iyHTEh=&xt=nX{>xa>&+IEcLy!~BI)CX7{(6Kf5--hy^ws0UGnx!6&)3JN zCgVhHtT?fj=R%aK_=|UuM*4TlsiL zbM>M}MQEv#RvkV91z)8>#kUcEmQ&ioSw)`>cTOp~rCw}(ctQ5OC-?B$;@q4ekuJSs^oavzDIlymf91|B zfk0@u1wSZ@1if^bTE?Im5<3hezj=lHbW2O`(GUwHo23(yzs zhO;l;YFQ3ZnczHF{>W#oS<#oVH^UUwg3;g@mlZlymW#2`&y7^?oxDKWWzUO$qWNR= zG_>K2Q+~H)GQ}|F`*Cuqp>g2SiRg-r^psGylOp6M)0otGK4L0YiYLGISYXXyVC%r1 zmQ0?e7>u67la$Y;Ey`0|mdJ&}40yrA7Xx#Z5)Ni=BSDF|Z_OQ64oh)Y>lP2K&dP1} zjKhtyd8JI>@_nQ{D0?Ns`z6EE>Me#jG4$RbcoOz@&hNHnTw#1&%U@Z*Bd`@3L*+diE63HA~JCjIFe4?BMWi&)kR9b@QX zkafJl{3jQqCLiUPmS*fzES*-rgQYroG5=n&YFV#4iqz8xetO!|8h6c`nkI{%m(aBN z_Ur|6GFC%bd9*$~8&A_bWGoWSz}#P0ER(t*w-H%b3N%=EZuOjqV04@~vMmi3ha=0( zMo6@l^m(DTv8|2<%kjbSdeu0jBT!MD@T}Knm0Hp6JfR_{pulx;s-oXe=seKdGq}0# zwBhP?h!ERi5&34R1=Jb5t@m*H8-c(Wt63!Z8z;*TPR-4zP8dOvqmy2{dOG=0E^~8#-MI77=7BQoPU6A0;e+`D^ z2AU|vVYiO>_;S!N-;tw!>*Zxd+~Ltj2VV5rghMm68V)2z6HIT)YI?D`UwH#Oi;MBX z?5UTR$BlM9g1+yx6cSR-edU0qj+2u7-VT}U%w?)CXT|*`I^$akQ)M~}?w8lBseW01 zu|Q*va*Oe*?=Mm3RZ`AWwnvnc9yn-TR6=mvl~M-kaE!FWTDC0Oh=cT8CS%7>M|_-^ zBaIwdh-ihJ}IZee#Jm3LpkS) z8zFyDc3OUS)et{Yl;7MJq|w-`pp+l)e}|ae2O|KRI^3zc@)_6R`()I3vub0`da%2} zbH8M&EhUzimW+L;E$21H8pEB72m`H%lpk`W6`q<#*SJLNJ%bg;jJIp2Qz!?f7ak=` ztOXTC+k+SFtBkqd)~^8n1Wpz=p$6}9%nM%a$Y3!i)@Xqhy$QGxZv3sO<@l5`(FQ@3 zmbx1&4pBMgNck~LazB(TruC|%3#tw0%CA+ApWBtZ^06_o?E+po1j)ubBDu#yr_Q_x z2}rDd@7uM|FbzuJUle%l4L1HOw@G3OuK7&(#7aEf;5zo60Eb3dvyslely4DT=}U&I zO-#J8pNKYOHyqM^W)ZsDyx2iGI#G2@uZqhNzQ5@So98;XBH7#w)PFEcjN7z_R!Vp6 za^dWVuCt8W)a`uOIc@JxQweAVyuqJ%rW_HX!&~3LV!JivEfrrx%BzmxRrAuKG!HGwp+P^R?k*>uc&1t%uY^!BObN z_MHFB4on!*`%yqjMkfsqh2!Glco$1HxEFeJ#kCisi()5Ng zDmL&$dNb@5!{@d2VQao{=%=V66vR)nj>wu$SU(?90z;iWksQfKZGS5Km8oE!%j>qZ zYCmY}Y^U{)%lIIChl8rCEk%rhV(`f~MPB%*vroA(uabZoG6Vcx8*^1Om zDJgu4*)0yE@0_4*27T|&#<|&L{p+6yvxL@SZFQc{8JsV?;3PuwU`YNb#(l#KnHk9(0IOU^mdu>RmQ{LT(Q!@5X8&{|HpB-*cRB4}Em9S0B z3((GA+gMAhq)K-crEVEbNwaCKd{qxmy-8RPbX=wi*GjWilKe%hAQ>82CZ~rSmBcn|&$f`J_~${oQZD&Gw_{SW*R(b_ zRJuTv!-Q|z@C8sO|g(Xc%nw@&mNQ~&5FxwBZOpC@$*JW$j%1YFU@(knsDZNl)Z%|`WD9kq)wH-Kn_;-khc z@W!i9R0TE;1==q0tBcjU_pJhARf2F@50WbBe)luLl?9}oWWcSnk9$wuigK3sFzk*u zEIh1C-4Z!h!WVC-u4>d_pE)DO;?qmTz2RT9rJ7a`!bYJ-_vavZ?_igkRpXNQs&Ga= z*VLL9{#D+7z{Nn#;|A>FPDiOc4!T!6zr}5NoH1XyZ=}gYeb_Um4LBal?SCrC>4i9f zSI!Yn9X?zYbKt^XFQIsg4dMn72|vusJ&;YD9a&D(+k#GCAD(jUdb0bEs&yB72VQ)` zy1en*Kue({>BYVbH+AwXdviVM+&is9;qR5`naC*^g$aTOK#5oN)(y%I==lvIr&o9< z8R!?%^|JPch9Xyq%(^BDk`lN+aDma+#mDi#a@>RKS82dbF00SH?Fco<7`YHJUyPd| zddl^1UYNK72!EcY4@tj<2rYJagy_ z(e$vlB{kW4EZFt z-N|rhALbjCHEyr-J|;WZ=$pLJf7xV4pP^rkkQTc8@P4epNxFeC-d8pQ1G5cn&-x3p zBnGba!pUFIHdJ)n!m(K-XFVsv52gbBm(OH59h}FW`ze;Vx;J0ERFM&w@~jwK-VENp ztgbyyI1+=Ha{PwDar#5FOQf7qh&n=V(ry-|tY1~^@7{%Mfv2mXRNJ!GHz0|%Lg|C6Q6+UPB)8yCwm=)!&O8hyW5A}2jSYiV8YSnNn=le_LWejR8hS}G! z!URZF&BhpwX^4*R8NOM(O=?-50elX7-3V9prT07Ee7!iY35fe0d}C#nJ%t>(79}mH zAkugu9W8Z;&dt8Ml|H!SF-nfb!d#`bV&2^z(5+XayCxS6HV7fIhwF3B<^6Qwetyyzc)fl6y#>Rz3Zg}!= zRBFGGkC^-M+4N2j6L3VD9@%;!nbTq*No8{D_PQHkr&6~ZRq7;9b3Yies*1e64TA4& zmqQ?2x{p{I$`gpJz^)#w&AAd=k&D_~B!|l9j&25qhr1I%G-eJ61!Tu#4c=hxjjSa1sf;LNtqGcDH_L;1 z?S>a`7_-kJB(y3vm^IGL=ts&xiny5vrGXbFqAcgC-*sfE^GR6xKl<==1J2b>U4dgG zzt6a_e4t7mBAsP?m1xqtCD6C9%zKPa?$mJ#48L0}5k;U;k5c)hJW+H|*O{>0;KO=n zG0L&hngdvLT$Mq0r}FuK1FiQY=k~-|VZ8;<@>U$nh%TbZ*0gRL?Ck6d4You%lhVJp ze^ewN-E8Jk+WVm*3EV9B4-BgA{JcEG;x2=$+GVB=(h=qs&sKi5d`4IhIarA#uo}N8#ET2~oI`QcLaxvwcZ%;U%S~TV_SjxET@We6IXQO0?Pgngglx-<<4+R-^;H% z_d($CT_YDLwYuo{C;!h;5xp>03^QFICZ11ET#h8ZSV$ovvH#5@cc`E=iUnq19blmo zt|opdb4O`0?0eisId z7zWe9QsV&YM{WMsVM}oLQ~ZAveEpH;QT(M=k-)>(W=oGHxdu(a@26Or)KN*FpJ_e0 z=SOl!a!z4Rn$2W0$cMKK!j9OmTU;U*WreVf&K^UY<wQmp9PKE zJb`rpsPVWK1Y(A5NYId|ToAZcgVVV~1>&I7T+}*vn%#vpXKETVb{eCl+R6jvTC6@4 zqyXkaH7#xxyF7Ef$&xIkvV=*hRn_;lqJjA6>)UsGG(tW=9UrJ`DKW|1piaRCHJxz_ zF5Z{KCDj9;I77IJ5}aB478srWp{;6{K4BgimnrIcl@5En#RQYczAfuOzfJDu916;C zMTA(PKsK*SXy*GC)W*d&14TsIUvFi6M6$uawx4MAdD`?%CgnVre3b=Eo z<_aj;xR(nY#aW`32XztLj-O6t49X>m>^p z2kYUX`jy`W>ZGu6W1CAhelNKuxQy6)&mLZ0H$=ZdI=H=g_&X*>T0M6VzHRAjs41GZ zxoJ78;?C@x@n!}MBq6or@zDs*Agj`XOIPTA8b%mK_?Q1#va}9s;%j9l=4wMP5g2|Y zv`!0+)B@=^(~~Z++119(Mwg%DyVT0y>p}YOu<(a0_beXoHM20 z)az>iA6M7niJ9wtxF}aa3yAL&wOraoXSyp@en1f(HUs|Dw%Nh48lYv%DIbcIR|Khe zIJ;&oghQ-)`T(@~5x;Q;M~h1@_6k>l2RIB&W3U2^#eq-aEqrKsdinWd zGL}Y>gz*%JEf^&ksFXp@Fs^jsWja{?{7Qko)IokV_^BenEnnu0tF{L>cQ``~AoWz;zdVk(B1t|4QK>@nvPH@R|Ey52wdX13oi#YFktTP->2= zm2NCb|1)#B*`G>MJy7G5|2#(N#o!kL{0HKP4-i~yhkct_geAh5b8+CRoC%P#JN*2W z5QsTKEK2?6%U5NGi2u~QbXbdSaGE1g}8st_(ZPH*29xmdcCCDW8$!FCZGTATdmYeCAfo z%f+HE-26416o%*LIC5v2H(Xf6y0d!S#Z~acQH%)YeGeIjXQU~V(7bx@$xKliY@Tsd zMi-;*U?-Eq!Q&<8KMm;3qlaI^7mKb!RimkjSfDai@a|*j8I9XFOMX-0(!dG%s4XT< z^fSnMjA_kKFM(Ye7XOC^QNgDZ!*fjR!05nEMLNI;3;hqaFoy4;e(Ez;oUF0s>Ak9+ z?#VcJTn33+r0hIq+vTZ%8J6`(J%Sh}$mV-PI~Gqf80hL8H!`8#XZG)KhmzRi)In~d zjC~(3aK)|kWl~(5UCBE=hIc5;q?QoDHEc%kcNCYWq(+mu`pcz$!-4aYpC8_P54?c*JLdc43J=_W&XPr3`vy| zK6KDiqhR7#EQpU=VkPEif*Zz1{~;*HldJ^irbkMD7tmw&Iq%UdfzT5C!>uR^t4#)7 zRW*OpWvG@a!fkT$q^}&30iR7HTCuS6n+CC?&47ghX+%j@p|iZmZm~Wa?x(=C&jeyg zotomS7};w$&FsK}ABOjDF(esU6*JEr!QbiJlv9^yEfe;$z? z^x_*qyi4l_paiBg6whp`lpq5tLxng4YrqMwA;(spxorB>W(#?3zE;UXYpuGbRoB=o z$lE+pKg3TNrr%Iq_w(H(8u}?xpk0VfVj@KUIjvLO^{;L-Rb|X+vYAPhFQ5JG48u~e z#ObH`iu4L;3&_{M-{4rp9mMBd=>vWNXLi4Q#BVga!82L!LS>NsMVQ?3av_s)qKw-d zpVgQHPw{ve;rxqTYN{W+6{rqXj-0*n=NM55#@zGs2j=Lu8DG% zo-F8-2~%MS)>*(as{I_+BDy}YQ=xsq6VDIDbda}hh#H9QUul&cJ%#kk{@C-~qqs7V z-PAxk;l1%LhvzK=dn9tv=JBmz(GZADoMe=t@~tJ1vG9VCpj!qEj{CQ*Aoczkrc^}r zIvz-77%v=C_9YBA_RwN)sc5zPN+OB(<63 zKey=kH~J0ei~B>GC2iw9pP=Gj+}n@f^afA{Ac(v#0*2N^p%VAI!u)J9hB%|}9!C>P zj*sD#fUKO{!p0BR3pou<{N=zzjTqKyFJ!|C0(;7J@5a1TDY2Lep0mRPj;lb5rLJk2|hKjA7%BOuv1cel*HBL{my!C!S zIndw{_8BgqK)y}a?*KBXe5Vcg6r>C)Mib^F3(Po!)3cR{sH%kHjt4E|jEJ@5GT*05 zUCXQSMy*NzkYKcrA6)-u@ZTW@(NHvjpr2&0oxIBb6hJnk1uExWAEDG4zcRYg=D6|> zG41EYaPAh;xEW)rSc4WXHxfmi=bhvdqSf_r0j|3bV#+5GDnX=H`jihZeYGH>0#f7J zclNJ%VtkQe!nm~r2}x_kP~8&Z^@UE;s2}i`zxr0!S@Uuy8 zi#!$F{9O;f!^6PDCwmF(+-$7m5mCyQWECXcvQkM291&P13u{*3$>4=hX|o|XjNaRV zSTs;BvkR943nQ7SM#b`FJNt+krdxPj1Am_*W#)_hc)n)3cv6lw1gCeEE5bLE4Kn1{ ztV8!vOaAW;A^$7r9@Xgoq5>h^>W%dg8V`DA$H26QD(gEh_I$D(*2z$D;}E|Ba8!jt zTZjqyDL!znX9gac6q@>KP**2T>wB0Al7SLeUwrIl2F-3L97&0CEYS_r~2j@qmlP^5Ne@|^OI z#_!)JDy$#!U%MI^?%H}*Ca1LI2W=EqM@DkqNdx8woU;G)w|`}0Z*rx_kdF1K(Sn^4 zcWLzK&VMSp{i5RDiI__MchSXPoQmdO|DtKmVNCaDzy06gi1wCe?-*yzlhA5M1((jA zBSP7~2*0Cm2|CzhNH8csDzXPEV4iQxm;r z1s;GxSMk*J77jNHT1EcJ^V+||JDt#45eU4~4glGKgJWu#c$H0pkdDM5j;rtSkKpv9 z*AZz>ioQZtEH+NCJ6@X(+I~f}GdieZr3~}S-q`h$EIT&vsa5X{@U=Eg%1cL8^+;IB z@)UyAg7oY0VjkBC4V7sBW*i53 zBrIR}vIb;|lVP|I#;@d6Y#TP%9jnqQp`9o$P<^d>&GY=D1wclFG--bDt2tysPfx9^ z8v8DwZ5R;A{r*|)qpw0SUyBu^0EOu7J73%N!-Sx1wE#L%2GeAPJwX)=$eTUI3r{zt$?c45rhIMc zSly)rLiaXU*%J0y^TmpKhCu-ST3T+5*!_zX#gYMuT=9gjflhn1F4S%$O)zM8gX|3# zimK=OOftrv*z?)WYpqx&8nJL9?{X~=`&5QnEnl7y0+=}Zh*ZWtFy+j3VyvHiD`Wkz zX+kJ7Dwx#7Onq(Q{cB3|nu@x96PZJ^D#aRf*SN8rk+vnePSen;Tp(2b$NKD8(ca3r zSjUzSPihQ85jJMNG9uw$>M`n)?`?-OeJ{w|DqH8Zu1ZaD*q%70J~s4ji%q<-15D>%)pSY>nlV{!f$3uOnn=OFq22Y;q*ZpL6IPM)76fq-Iw9Wfm~7pFntB;oYbwd%}t=y>XJF8|zSTA5gqs7z~8p z)Vg%8sfa(?CjYJwaMR4j1g&9hL;43G`j*nljKEB%#wy0uaLo~?zt^^hU=mJ|!!bxb`Y_S&G6YGk#h%Y>N}2VT7wJIo;nL zrvPTykLWlF*Gn7M*VoVhxFd#9_b5A6gr7(Gr7M;igowW3GF?f4-VXddBB5+eb;*cR ze!eLK+&G1W{5zOzWDC8VWpJ1brg9AI7-EoKuB#+nvAvRz1h#@i3Jg{k`Ic*_CP{Kt zYvz^RAha@ccrtR`BFxN>D1qd0e5dQ36rm(;3k@+gngA*ouGNX29N0-ImaY7k-F=Q& z9`Aehlm&*0^bBlFj8(kdG@AJ$t~Qlsb!;)ciL! z4A;iZQt#Xvrt^1a@y$Hq%q+YjT^#J?Npm*)v1E!c=ddgMe8loiI+mcXA86;PQ!}U& z%OuC3S3a>DS!}z+vwL6sa#}|W97sTz>#i%4(poO_s<)LpWh7{~)XZ8H9D0;Qr0rLc z4B9KzPpbWvQ0pUbz0Mg2BLd7&*0)d(M0??i{)86f7UChED?$?Ji3zm#(e9gV7iEezvb59rge-Fqo$S^*k1~8%@Z`YtfxXYM`cUTKH7n!%*e&tu?vFh zCCBnC4D-r*T!b3mRK7eI$=mFHP=3>z5_E?@leF+{r^G8P24AX)*|DeJWwFtQ9rK3K z5sYsrdV)`QX3ScENmCp5N$|tqxn%V(+XcDzOq-?1`TAZ7Fwm@+jSuNu%X>WyDQ>Dv zFBzl>bwxjA`>~~e3(E5c8S(oKr$n_64A*oh+Vm1>KqgfmPD)_U+&q=@?MS?a5WTuW z6ftl*ct_aZDd`&g;yqK-GT3cVa5XmDG_Azj#r;W|vzL?@*O$sWU-t9I5sB3tu~f!z z8BLK|NsR4&O19;$LOtSQ_|I0_L**JdyCus>kad7NQBYqy2pZxRZ*z(1t^Y(C_ve3=*CLf+ z9!bj&hX^ ze1>U?bFOX(We9S2VPHNacq~jS#v!=b3Q2h{6ekGJ+ADaZNC?@Dk#|s4Clj?g`edwA zHJ}inyjz-WQkgWVBXFxAox%#BssvYN&-hZnXu2-5X5uA~ey2jBJ$41%{%~*0$qo}k zjo0tVHDhTELkm@op;k@N;jo6nKc(VF^|37wT_~Ck_VN?fPpxfQm~cW z!c+ReMkDJ96p*}kxf!PvJ}t!O$(n%J8>TAk7Z1-#NhDJ`MBgZa*`uzDaVA@(ol97H z;$Bu(we_M;c}t^{C*_MUmK^4()vD9Nk4*%V{+U5aR|fP&T`8|`A+BpKq9MmZdB;LA z!?trwAzFw=nCs^KxIoov{5Sf;QW^F2O`(tcj67oqxp5C%{eVlyxIJbO-2K4!1{^af zOg-M$*XOTs7YT<|tAxU@fy8n!=A&Wbb$(k5PUh(!$DJFHJ)RV06gQR~&5TRGkPUpe zPp~Pk)525TanQlm^iZ2QFisc3-^CeGgh-wv0j&UGH_cp_UdV)nG%&39pMd~N{R*Zn z2EwPQhbOL;PXsEnDW7Rk#V#UMgaTYwT@7kyaR!o;#pxL9H<-QWGtO7FUU0ue+w`8z zD0Mtsn|;=LQ#X5AMjb@!miLo=J;vU5Qac-2DqtTHmcG!Ym4&T)+@#Rk&v}&W_reg` zS4WZHYBM$h>dXo2JQ_r6 z7I3UZ1lo%%h?2UtzJ6GxpN{p7lneC9x*sY++|I|X-`7&V#PUk_`ZL|r5JeM>Ds2LC z*CHrITa}uz^APl08qjmQaa$5M+)WGAOTuxhSku4fNFq-M;yC(VmPugO52C^s8phsJ z(|bMqaI*SYw{466)axCfnuvq29p9Z<|81AY%*~*uRYQmAd4bp3tpzB?`XUyF?N7)) zi(xpZ$cb}F;Pi@{pS2<#V^=kSiR`(6e{F#pqL5T|7FN1$7Kz2ouZ8?Y<(uUVwl*E& zj#4k>NJJC0-SBiS2&+!`3`))g`W#*0SH>{+$xi0yB#T~C63+DV%k@Lmpb`7fe=TY}E;)s(n1I$MZ6KG| zta`5#gFFmFEbNMS>?151@w>}M-RL+$6k;K%YIAcUMmk*VyR@3|vosIqyVb|z=V2+% zpClk<*Fr-1U2%P{86eN1X?w*woD(~j9r*mZWx=4Tjta&{2^fLtR8h9?E#V?ZH%H+f zvkUBdizLVb7NN^!=Hg%=Ka>4w{MC z&>fUNsXkoi6&ben?$M?#$xPecx0VW=k;1= zBR&`KeAdIC&1TSeT;YN1VTn+9`NKfmza?;DXD}misfuUKjRJ$QUBR5x7 z4i6eJg&Ti-E1?Ew!8f{xsGjh8k^;G`y(_nHB<9*BHVN6BpNru(8jQc4-0I8*D3ilf zxK`vO92gT*AAePEof|)luPqBi23@tfCYI-{^Ao(M>=%fGHPS*R5^JMHN;@Ph{L$Z< zsDm6dSYH?A`AgicJQ#U+=fsFg@dN$0ZkNBr;rJrX_83mJ$K?@M zS*afDah`#*+9T7F2X6cE4r5{mTE8m~V4SH+L~}fUrhRRHEA=U!s0*Al z(IXnV1Gb$rIoKK@&?oUD@fI8(99>4(#~IFa*O+ABW+73R;Ja<$qS+PExKz7vl+bf;wnzmIZ}H9#PC$ zF#fFl;qGW~uO+L7^ur&7hRzfs2Mj%iM6}fE30tk?rbPHf1T)i=bli~zHX!_Q><};b zJVhjehd+-tOcw19G9R;N%aOM*hQZnE_H)m<&>X82w3QLScDl93mPc?{naFDRK!^-o zow@zKjAa)W*Z;(6U-N9=y-@vEoR^^`j-(Mq`R;5O#)KH{GAz*wrix|SHcq}l@zd** zn45wYvBldEqZEBn2xXqsx}gG$KDlOo9`l3n5zZW6-0;xPX~>9jS?PusYS(d2);ur= zu)&(Nm<9Hx0yC>IA^Dg1z3w=k=ek7WtrCz%n)1Eo;tBbeiaq=O)#;~ktNgUs{>9Nh zyWHa(Pc|+lKU?U-yU=(NBKhX{HWd^~>9zCf!sTsmG|r|GG5%!1ol91L*gxmuGbp6f z9eScZakO@=t;KRYQwJW+}Rs&Dx=%uykjW>XH^Ru#JTm5etNf*$y8Bya509*?jpB5 z^d81JC&wk*5kIgA_hSKGmEu`%ztbe2K*#zuyhQKJo7VOp8=ldw;9lXd;M>f>OlJq> zwJ5qj3YBep{0HY<^C-pp959c`My$s;%6hdUYx1Sw8UDAek#nfAO7CE$KzidUS5FZ- zetDM>9T9;smdvlMmrU$i!V<4c-d-zWmU!zq@_a&FxR`!ivmdWC?THk9=k+k+`y619 z7IC+QhdNN&9Gw8zt{I^ozve2khYOt1Xd(NnM%wSDo99-?0}d{jsq{!qR5B3~i)L%5 zqdR!l)xr&c%5<3sj@zLc$ZXqA>$#eS?cvC;lkU7#^zT0*urG9ad6=3RII<2%triXj z!6)Vp(r6x!hLlWfCant-s%i~ln0ynP`C+HsTOuYnVv zH-aodSW;RIN>P^6gVguFQ&=?cl>x_J++UW(W)D;hTian!vz$st(!iZ+=&dBAjPr`SGqn&6fY-mPt z5&c_t7*BXKFuKRVH=o85G3i&L7J9Sf(LeL-AR%q{6n)sg=jb#|`j4`7&jQ$x98S~b zIAZFUq9(N9lZ)7aubh#5E0#`Ti}IZ5A9==cKVyHwmUEHMaU}lH)Z@e-XfV1%)nYB> zB*7@BUCVlh!QSDq6^(;BxH2`u*&i&6e5GuhgxHw)*r??>_0z}~Ij`41Efiipsr5>n z0zbdb-dC#VQm-_w^wfyw7X72tPFgm7AtXrh5Z^AxW{a(=j-Q&xtxRpKKC|eaeI)B@tPmt* zy5+P{{S80Nak9k*MWy@TqtLNofNs^p;Tjs-%CVCQ`C^-6H=wzq-4@jP9f$UroM^RUZ2AJL0_?; zAz(C1r1pE8b2HICCC-~ha!Qk{z<&GKkIJTM)G2(mP%{MYu7^1~v^88x3}#g;xs9Yy zH--c)&_0$4FsWVd^4;qqx_$6Gc1JuMD~XlK-yDmuO>MuXOPrN7pFQQYd0)alMUk+S z`*p*$#!1mBGrW^5HL1(5U%WBlM=Z{uvmQXgqERB6k&p)mnwdQ5iFbWCi|`gsyljNo zAXP1*hKvlHh2=HU+_AKMD?4%+9P>xo391 z516hvW@OVMAdCN5V6U~ojt<6JUHueP(kF?}I#zDE`!X6wh0FuoC>kCV!!SCHYc6CI z+q!$8GMZGmYhNqvCpdPAQ{>DoB9^a@%ntRg$95&~n^)A}nxDL30ubL0>a-8Z(x}g@ z;AEQ_?@D83;<3i>eRVQ#Nm`?P8 z!Y!1F4!+>4I)Dek@S+ZX&nVZDoK@3N2}2ul9JEjua%k%YWK#l13;d}THFwQd1dEH*RVOz(D0uA3QVxk(D^R84@0bC zP{t=k9`v#r#aK7zIpj*Mv8kC;@0MhG$cNvFkME9(1L~*Or4}i7ubRI^UcIl# zh#`oFIu$}7Gl--O!`uchC%0(FkcGTAE-48vCSEXog!MO@u&54|h##-Zx$aDJdoly( ze3k7jAD8QGwEf|++_(<}pW2`8C z+zmIl)|vop9Zu4>&Ha_{xBW-i=fh(!XC}6+jF!UUjz8D3_-yqnkH|G+se7z^NW?B1 zP1YZMQlX2&*QF%;J{KiQ%=sw{ZaR2E2zpC<51?gg$iTCQo<=k6c3sfFfVP0ues||6 zbN%RDv zAosMIUN|%~G?(4RyG$jl2GpJVK`AX8i{9-hK9EmwTF>j9-;aZ%K1_1k6u(D*y5?eH z^ft*KarPk|w-51xbjOD&Juysp;J!iFm}`DzfRCs4*i|8!{5N@8HOHmvR;A2HlR-X< zwpKAek)$;|;CQQi=;R9PzuYD8nP{Amb!Voeg?GL4pZ8*<>#a^Kw~0Odhu^Gsbqc!Koc6> zh&V1yZ|4mysNFs{120<0Em6m))N150wI@=wEn$jHKM)DtKWqk zKQoFvL0EDn_H+4254iA}^MF|7Sy%qb131=u@MxSrn>|$G?QUL6HmwN03;f!2Cmcc& z{3q3c_1hI9w%eb%jF!qnfoQ;eFXji|PkyP2*8uuQN52gv5@M`YdFWqG?#rlpDDkSn z2;&@bzX;F-^#p$`M}`9a@GJk~NH+>l-;(Hp?D(KSUm`!TCQ*3qzXOARH4(J)g6eU; zdbt1mpB>cy--x`Unv6JXtvVGARr2o`{cl;I7nJDaFMjVYn*Z}v{q5)e%@MCS{B@_h1x9(F1L$;aPVm9AF_)=;#lXwI^f@eFBC37)rXNpab zP$A4XY`bg!#XH2 z;sLTz>=JFFpNwQJphulAPCEk?kjdupOeG;3@++o{qSbfauTy8Nw*#0KM`Duz*rfX| z$o+f>MW6<>UIVdvvMvD(sT}@OIBR42CS}N(7a>3UxaN8b-J-i5Ii$d9B?nED(Z{M8 z;YwFPDDbjY%C%ZmHbFh+& zKBU~ngmi`BopgMW7&M`)$)^lY6IKT|Rb};O?>Tw+4J>Q&49fEv^yTx}^xlx|^BGtp z%e_f>-fv`I6$iWD?QdbHh0il&C9v@FO9$C;eHc1WqXaj0nO&KbZKh6|07YVy{y2-b zWwHB&-YAC2$JtUYbUinpUF8m>hvQan*p|asFo-$Mv|vm@K8OBF^?AAzCBJtm*oCy5 z6AL{7!l)N){;Xj%IRT%fjFy)!1ajicwz%`2xfV5`in+8}5Az&~&CxX?Qj z9rjvyU>`@AUU-kX;g=l=(xPzaEIWlcgQPW4`M;sJ^K`V+ZXP7HF9>|Y%{{ykhz{Riqhe}^bMPeWd0oD zX7BN96*%HLtLBB2VYX>Qh!I9xXI=fDYK;~AzZQBQnU=61psw*z+9#CYh_yYg%lla{`aD^K} zq7WC>uv?mi%`mqU`)cTt4YI?u@`O`EPDMGIXRMrJS}8*Mxyi-AfdxCxQ}&*$%2LF!Lz)@q$W5t%(UM`uB+~f*)PQtM z!L7hxwK8pRePUkF2^O(U7dFhqiJddBTCRitTA;siX#eTKpDkWT$8YNfQ@!`64vekd zr$8%8?u@mmtkF)pC~}#WJyqc^d{q1ePE9Md zSi71-(XxqM&_9`lb~HywOieL^J>YHA4}~+e?UB={FG4O{I3w`0_w_JuGh4prvO`MB z6_k>VpJieRw6@?MeEr(-@@z(++{dduHLOps6Qvzs%xtznfY)O-O@d#ZW_p}@852P< zLr~gNY=~XF;G6x$BoW*wiea-H8L){C*_f*|Y9zb?fPGx=o9&z3o&DaEau3oPOXH7oTCrX>X`ZAK?XY1bdb zfRwVW7T+w{vLE>{){CKg2rmiDMcZG8KwC{WaMK_v!6X{Zk7NItS#sQN(@G89BJ#LD zBeP^PTiUL8G^nTLSJk#=%)mipM;15qk%7kK%O*+MJr_pzLE8^LNxOS(gwVx>`qhBV zX7`!k4S@)gvCPs-rEg7>Bb{U){_|{5dRxD7U62eHzwhZDj}}LS?|b&ba4d_T?=LtI zWXk2^l*Qm?R8%MSW;PNZ9h7f5UtPJpT8Nc9Lj+&dJFUnf-FBcUgg zmeCe0f&!=uV`Ns8SfA-{8a?+u9^xaN%7txs=VK`o@%Z64yO|V5k!A%RNaK66GCa_0QS9XnJ#O9~ zFJI9SiaO<{&bo0u7;NVz&CDoA_``m1LQihl(2t3HR^pkA0F% zj}<4G7RENOe^qSk3q1KVR*nTM!pCwWnE-Np?0_~(G&B?}m1ACnFb-|NfhHC!6UA_OKYn%sa&%?!$6t0$)o9kpAGe3{X}Q#LgKZq)&{TegY})b@%$;4b>^waT*|4n|a)6w;YWNtU<8$ zDtvf=lBvi)^)}Wi*j;A}Rl)GsYz>}HEO`2(t@&4W(rEM63^u1f_&W0L{P2$UB0p2Sc1AU;@O*y;D4Nh;22r+M(I1cCi5fiHc-{#_Zth6Fx4IJmoq1YAswOSz z3;4ha{C*))c;3@#nK2cfLUu7w@-Cvv%I+I@8_>kaFG;JA6*A;P<7VaxY1`U5U%2C} zE)Y!l>Pp*osX(&@#JNn*Yz=&U8fAXkeEgODjX!LsV&@^piRK$aVGUMYom|<}`drc-WpWT(W9PTRPxi^tg_eW;mkY{nepzT|? zzO`MUDHi~M&*3MA@^P0}6u+ND<%f2+XRoK_7oFpEwcr*3hQ7H9zLV{zHi3O>@`VmR zygjof^AL{s?6MrRSZC`ZelL9I57P>>3!$u_q3VJ%0BUS3xFn-~|0Ydrf6(xr*_fX* zYDB;`kNiITSKqv!@Xd;PA;H&9dh&-vhP57T_BZxgl$9*Q zpr7Qds6z2qrgO82F-eXePRrN)U$2h*T`x|Wj#{3oOzqaUbvwp@0=`e{+<^7No)_#} z;_28x@TeAAjeO?KsM_6N;RP(Vkg#6STor$LKA-E0@n2TLNl8kE2#CGllu&cqAzakxQ+Qw|_RYHTUSN?f z{eB4vz?y!bkG|!1y3Oo;V`9>5SAyseFk7=ajf5j&RxQoDWElEN05#(&`H~pwEjHN4 z+Rk7z+k84tg-ovCW^{&Qd!{h38CeMi;uc;5~@Q+Ci^}1Nukjg^OO!JfJQee{Mj0uw`}1!4&>og(=#jW-MtO$ z;}5+`JnKW*9*`;ChIT^GjzH9uu5`FYqlr=@on4M#*vq*p%GD#?zkfG|6^_F!q}Gh& zPSYi}YiVy>geYMlxAk*fTT~(#m*E+=jILS_9Cli=y!Ym=-ItaoD}6^&q{+-0<3M}m za8Aff5na2nMFm@rHYM=>mPGya9=ZC%>^a2aAevs$1CLP@3$5vs^zPn|DsjE;eNgT*)LT6jPh>=i($&S>RUb?$J)s{h%9h?Q zF2A#HvPZCB{jmYKj#4Rkm~XAYpvBo_En)0fO;nZd{dp(sNYv6o0rP?CwTOAdET>KG zp9P33?;wPTd~5}O4Htzn<=9MR&9-Fq986dY#h8bS3p=opYHUYmf7zUJ-XXV(UM*UtXJZCxa9_$JZ=79js5{hQj*vpyy@ySHG80iq1Fc}7Uzqu0=~q(oWzO5 ze9*Cg>{e!xpDuB=r_gS}EttaBU5H9DqZ9}C518H;=TQB?aUo+bMA^lW*`0_M+TBLG z8I~l}@k{H{GBU$i`6vw||*?m*F?{xTDEiz!i$*79Y zS{{GvW^!O-Qty${AK*Mj@^j6%HfL0_^`21q_L-|O$}qfKa4d|TYKSGL=};q{`4XpK zWG!%S_}C;RNb4hcu|i6Blk1T9wnl$j8IAa-Kjk$ZaZyvaBxPgqkWwtZkX7 zz8uZzo=$uCvojEXOr$^lBk04Zm!0g`h!H0#wTR{H2d?uu+W8ePSr8yO-{{cWV=?F_6zfgl5CHGH`JoGGZ6a;Ya-wj9va3ba;nO=_)DrU>P;*~ z4BZ@twv!UH;1R--IpXWu``giJ7Ded6QdV@oO#nQ1 zTm?){r*((@;I!N7zwbTjznFrf+4F;2&#gg?t$KgAV%cFlZ|rnyHo4jm3V)SW@PtHl zyGGgrjMX<@>X?H*1!S1xd^=kUC-T|YKlP})G`eK94hrbw`71=;exGVVq8F9T%I zFi0t9@{K@>DdzS@WlRNkC4sES;mzF8K=U|XMGmA796PJ7(wvW0D|Lf+opeNFKvZb) zQP*i7BN4dlW9;RoVk=El`0p~)bGJ|G-YN_H{wBMn zXh*D%S;C@uFiT+AqS|>u)TV!664`!36sb`kP&FESUg~4Og!K#Y zp$=KF!32>mK>==VKeU;fJ{9e74cm)3q-&=JNZ}Zz-Uq$YJ55mW0G!6jGq7!g!Lx(- zpzDqI`g_RDX}Nw&$C{K*?6V}|)Yy06liWn_M-t{%VBlB$$0oPFHU~(jgQl!IeIPm4 zemThO`cPOjH1CR3Z=0jfvusH*40Fbrp7zR4w+fMhua3X{?e+gW7?G7oPQMyB9vtXg znzC?WV{@#~!0@jEZQvpQ>{o*)>R9qTb=)y&DmaBIBGm%ivgj_vZiuKJL@;663b}oS zBphjkH9e9r<4OpckFAa#C}OP-kp}BAWgd_rmd(rqrs(FP5~~>1G5^^DV`8koJ?N3>iS*^xd?WGK zopyLi(Tyv(*{nTfQRkZu{0Yb&~>k%Ecuxu2%~uwyK@S<`^J6utJ-9kNsr_4i_fb=MwQQv z5U&w;uvf5I9X#`cWiaO0Qd3&y(;4_>+O#rOkrW*=S5!`|zHA9vbB`m=Gj!8Y#z}s6 zPNb%KbfjH{rd7K7gTcWUKV!=6_r8>3oDpTw?W*!-hY6Fk5pPVSb7=b?!* zuT(>ir+D>eonTpG>Ja0xPZ(!C{_+VO4r)-y`&o44Sc(9dFD+M^uGM+iniOxC|>YS$elQqUJtAa<`8dks~ z-f1Hi8Vf>|J$bZ5!%&{lkdHIN_XyfRKfAXAO!?5lj}_tHJAXv2jN*Ep`T%3(5tf`r zMh{T$D>5+_@avSeqY5m^@370YlLM_=C<=x~p7yed^#PN6pFJbzyWn><-ukL$7z&U1 z+k3*|oPZ@-PSTZWY*;Bp=Y)Vf>rCp`gIpM|OQOB4^;N+q&o{3=&&Z|M(U``!zwunU(TA zz8!>5&@U(XG|K#!F886x-2Xs?Q8@hmAM)P$J+mx(AFkMTQc0@fRBYR} zt%_~iHY#>fv2EM7ZS#G)duBe}GvEK<{qeby>zsY|;=cF2)|!}*CdT-VH7#p7$6?uxKNHCV00{+h&>|gLLmEab-<9b`*PthO((28VUA{LT~rsl%6 z$O=EZwOAa+@4NR8MEC!Ic9Woh0I=7vUz~`@V92F{_)-P1b}`Q zqbBr%{|KsoqQhO0-vF?9WHy=QKZ3=dKa!AuY}eC`=?6qw=-B7{tvI$Gv^l1eJvgZq zfiGOK6SDYGQm%Z&4yL$(VVmo#=-&Oj>|pT@$<%}AY149JhfvYQ@h(HA$|;}1Khw?h zt=3)B?^?EvxLY@D;e>SsTht&j*q_`p)Fd6Ir%vFiTIXp8spFoXAT?QBI?&UnbV)%q zB*wmU%ECYCN)1;pgOYGolxW5{VJwEglbExQf#bratp+DJTOdwUBRRO}vp$fiT0Ly} zmmktzMus;dtZ_4t5&qfUWK9+LMR zM@ucHWU#YV_=2}I6L5Xb>*fVwV>-3!SXs@sh>G z3*(Xp09KaHvD8?3yj4HD$fC^~A1dh?a z4iU~duR|;HteX!1otV@;{a`_sEhJi|kigs?3wq(1RKAlu?_~~KX=ASykgv@D=5IHH zrM8awn%JF!ivE2vDKh0d$_V|KE@tu-RdEneUtxI{2u`Z5R>|lCA$MdwJKycADvg_4 zTk&N?FXZ^O7x=S`rF7EVwOz|bMh50_aqqVCJmzd!cS|sfzLGL*9IOQPvT;M4vjrsK z`+4ytULk~^ol46v@se8f0c8G-a3R;&C^WVA6BxZOp1tw<*GpG#^U#j%*_{d z5Q28b5gy{9EdqhbS=ZrRXG;w*Bf)b4@rRm8SFHC3)I<9X^2WGou$Vto>cOcqIV>vS z-Xj#LZYAG*Yx32F`wz|*DvaqyzucnjS$%-po&rEU3@$trW}cNNd<&X=m zpbGofV`ymDs2@~9w+bOQVQ8v4u`m>!t{lIow4MLLkv%;M1wJB0B=zAJECIJ0t3;Ci z^~G+-TIuXgSW4^QO_?&?LlsiRs)M+qYYM7rv;HFssVB!Fwde*o>m0TGs_*G~_c-AR z=7?{GAPKy99bDQU?*kYFbjD_9%;2)2uukyLV{wtN%ZOOgTW>ag(Z4K}WpX+}6T3S- zXKAO@0|i<)dwdPX_XX`90!X!fq z(}Umk_b{1Yr?Su1+14<^M`N3p>PMi%Tfx?G;g+;UA4D`_eXJ@X43A#VtE5YjS}if4 zYbu&QUS2F&!{3*JZq_I*q_ML`nPXNNlXz1}(*-asIU^0g;jIRG4x(cgQoD5}FC+!T zlqsd_Q)Sgt4p_81>(?j0u)U8+L>r=7sfXWS1wDXAHKy(|eP@{rQCi@e+w7_@4e8v{ z3|2kdUSQJ75TT-8x>sd!fIg2HaG0iR2N#bdld9Ss(nH6vf?#5w z_)*7p{aV=@@z`Wam1 z&S_DxOdMsIP;QnrTOd+y7clG0qrM#Bb{g3*jta3pGeTt-W$O{}FP_=7E19!5bNB<8(JS`g?_BZu%h(W%&V$Jh`wH)nr#qi-ZlWIqA}hR zVGJ|tE%p0xN8@on$&n^V5JC&-0JTOFeaPMs&P=7<`6QP&wLR{-y8E3xE0nKL=SR&n zxP;HUtTl&Hij569s|f)C4~$nkf|*P}W=7Pd2>P4Ai|*+?Bi@#ROgn~LI-vJ79__}7 zh6cE3T>CGw6(dlSWQ2N|eb4^ZTL?TH0cQT#@T@s>YGl9AHZp$2)(e9OxOd&7U9@B* zjdS;S)=bddEpbh0W|vu!=2G}16{0IDH)yu2lD69~2L1G4ZFBGE#k_UrdZddtxM*kZ zbAuc%afb-$Wn?pv(l9JhxcZi8<&&UBl(g}u}GgB)rHqZ zI2nVE&*PK()Ai6{wUG+9SFPC!`hs@o!Atm4@M3iDaB%J2H#v&D-jl_E*0^R@>TELf zvT%{d9T7NZgMARAr$+ZeP1VZu7vc%!c0f^t7=Lg*hOh4I7E}GBREaR1Cl18 z^SAd47ahUz{v=uYF|*H)`KJ>tgl!6Mh`u*-kO$oPm{n?vm6Tw4C$kiRVTnM|tY-^;Uw7o~{SY!O7%@HZ-`!fZ0nqp=_H$IFtjZP zUsGRCrmKRdk)9`fUV7J%GvFkK1)ki#p_mg+IiSy>{lxgJ*D?_*tqqss@(x^oz-x1B z0&>=9;;~kSgVDDn@2Ed%<1?RUSuEnwj1jA<-_u=BqCFw849$dIv#W+{>bpYszUQg_ z%^O|$u(;D#iRp9f0F-&T>1*8a`ZaTgIj^$;ywj}%oU0_XNtN3d)QB2;{z=#Ov|Unf zzmvJc1EHf&qqna=u=0`0d2h-$9lh0bqoUhNxW@wsZiT?4hbG?bwqAKHoHKC0-H#)^zy-_ zbuTY|roTmR?(~iD^rk$(t|>l%TxLl$vjnv{gEb=r5dK<83EOcUz<6MfL;33@w533d z_{92H0$ux+ebFRRR-`}A+u|!>#gw&$|A<+H|HMxrX+FBJ+qhWzo}=_&ncUMd7>t#) z>jT|+#R+1T%^$OoCno+_QYW@^Ts6QAPloDAnjshNF!NqkF$`Ax$qFW>TLP`>=KT6U z>35E}(SIv^=c0iM@_j!len%`XG8s2-0d>U1|45{Fz-q_EEiO41N*ebYuh^p0M+ zlqzqelz{v<7eE{z2Ckgv_7R7(COxkb=^@js595s(TBUq&WrqAQNAkV5sxV&`ZA3_3 zh3PEAe$saE@w>XY$ie4@u%Q?JOUV({eltM=Z0)LZ*M|){eXYE%7-s50k~BpDmcvl1 zI_EC@9TR@AxK30A6N2u27$vG|?o;7fSi%rbpjBVcLx@WsHOX9g8nm81HgYYrtfp#& zJfLK^a{p_S>{G3BvAm_pdUjyWF>PsR^AB%|jx=*V@yS<{z4QhfY0|^g*_WBGm^71# zSncX5)cXeB5}GzbGD6M@0-P4UlCbYKbqWJrh+ZG&t*lsByFVk?<*zQl;99Vd<{3y! ziw=S+m5eGX1G@8VwK#J@dMu)X)EZ05Ae9TO^pSH3l(UYG(Hhv~Zp3$Zr}w!PNXHED4T_$$&C`}>sn2+f z0XKMJ`x)Nv!fq1+JYQdoqRj}9H)7=&H8}%58q_1|Rb`vJaBCXqW2B~8XXKCir{_XG zzCBJBtl=cOFUrQat5m)6veu*?vfF^_klHE!MLJ7j`XhTU9MqMMGcnF--|*FL1sRdB z5u!=EU&BekbQ@5j+yJ(8!ka;M$leCu$gy35P^X=q29vSG*|1g;U^s(P}24 z<(wLC*C?`io3d(iFS{*$Eudkmq(*nLKU%z=0L;XJC<&}E!o0sfoU$L-JS0g=LN6T4 z#2loBlhghr6^xQtCY)JpyYpJFuu3TZ8PyPx@H;GxE!p}d5n;Rr*5Zk#zsCuzyrL$QFG77Wq`H4Q!b@yr`)3mN0@09UY zt?3V|7DX#j`R4|k>6wc-Jps)yFw;51L=gcgacX(H!K(Wa?PB(L+nng{C(+&k!j9it zE>`@~Q3>y~-dQmQ(&4AT=GHg;cvIJZ{BX0yntBY{{nC0xi&)j5q|K!DYd6Qh&XID* zbLhToUT7X}h=dOPfQi1(oQSXFS0+5y;|{t#QvT7sO|eu+q{??55-c$Wa{+uXrt**L z((f)A@UXB^0;?Ds_ZNyuvQ_m+Mn2>uK;k#^HsR_LSoACeg>gx*C(c*e^$=7Kq*cc` zb`~X~{4J3*q`B!+)WXv+1RB|#;x~762lK6(_uTLuuQy7I4*g&&0xUfnar2_7PB`#? z>Jq%y9n|_@kLqNO;eyC*K>`~{>GV`s=J)Rqq2v@uj>XUzldIEm$zk^|`WDo~y(jhQ zm4+ZM)Pb&-(7PL$CmU#Ie*}IKfWjoVdSCzpqP_X?V-%ps{wZ+q2cu4vg}=-bCs`qjnl+Uvs~uI9W8NR_t{|~>ue0NsE{0W@`|;n zZ_f)~HL6qhHYPs}pF96)jb1(TW4_Nr@7(x7gMD7KYR(}{;7(XxaX8D?u6<}#Mp+PB zB2;m>z23~J2OCIlszPKD?)dg8D2v-S2{W2>TQH5^;>LRO1x9OATq<=oC)mYxk=ln^ zbm^z-OJJIr6gzQI#ZLqTR=tbY`#m)JhgsyW?hq*u4hY;I`^ndfkwU8Vr%;?Pq^B5% zEm%QB48yZJ=F&Y-JSs|)HW2NofXl3VqFqVM^QSE2iLYQ9I9V5-78l=)Tl)~Yr`@5L zDnGwmz7?U2*T(@H!_|f!l8RrqV^ME^a=-v}ovLFT8+=lX|XyrfX>PlU} z^QKfT{g|n6N(vmNM$HzAWvEUvk7W4xk%`E<0`M-f~u6$b;sTW`wBUCm^|H%pjr&p=l&W|cM!b(A`bM1H`tUZuM zMp*QE+aL9noIuMA2B()#yN(P~9xG@sB1cvfD4%XOA$pR_qg!GA1?qMgXLUJtw0@j{ zq%Z&r&qa);_Qe-eZY4_@Up;iVl%=P`=hA1;zMqw_rR+kUGEgfG z>);p_0P35o7W7GFuX_ynXu{#-p_7@V!Fs(haN@Rq>I_h+?zA6wuyFAjxw<& z^u6@zv|88!J1nXK=bU^pkYxw+y`)~DWLbJpOP%SJ19FC2rfGV=0|xhN+ivg(ZMcCO zd>3nd6n0AvTkmQhx)r^?7WLyD4VYO-1yP5^oWdNC_Do6Q(=I=uJeKeE#lT3((b?B? z-(6l8zm0ZzdfXu>Su~o}NL3~A^^%p{j+-8&NfH@W1isdQ+&jA4l0?&!+Ak_Ef+^0| z<(Lz2x}u}Hkdv-$)t8PrvP#}8;2a8Cz%^POl+LNWGGj1UBB-{29?v{NrNVKhs^l zUTd-5>fKeabZ#oOT+~TeUpF6yDp?b=GdIY5i+)98Wtt~F2+R9IcF}aJJ(nPY$vf}T zAm?ByCI&3N08xdTHT1+}|07A}G75-saW1DJ2V){amu3_7)1DO2H$#T=iWz<&bxKVc zQi*Pp(TL$l5sM3x_fc`4D582z$KC%T(#(=^-5H|=fsA{2dl>!rXMhp}VVM(cPwDa( zLP7zGZtuNuo8ozb!N0KJc;2RHoKc0BUqp!$=}~JLlX{CeS=}!en_KuDTp8#3c*xP%OXgEVU-@F@k zq8zw=uok=f-aK2pUGQ2z*Q2t8rA)cVq2xluse7vQZ{(rzD-e@IR0TK`%P+S{CmZy4 z0dvW^AwDTG`#X2XdwKdd--dal-}BCXF1;p5Ej_CMMja%xQOIw?vYT(P?*+|TBQAu& z$mWcMSl542J)FHWbvzS1QeJb)^gt6OaR*v+)_JkF^KYlylcX<)$SnH|ejH|W%purf zW}+bTh$h>^2gd1Hy-t9wW~El1_kKcaog!TA=)4xGG=Xs7dqZx%YqD9mQ7kZhd_8y9 z>ARi8)^#@Sl6-8wFHjEBL=YHN5Y90Oi(I2pH7@Bvxjrvmy>nDu*w@M+q*_kmH0<8A zmDb@#bd!d8uB+U*a$TFhyTs)F@Hcf$X^xC#nL*K?O2RJWv>)2=0by|||6z{{AFs(R zJ}H==jwSTu_}YY=tUMP6vp-O|ds_-Pg#}2fck~{UK=#7uyb^GK&SzwE2V*)iHpZaq z_bzq@ZhNo$FW`Hic$ep^$VzpM>T*QQ3|=u^B(JOK2ViMhA9}lao-WAz%%IDZc!JV= zI(}Vx-C?<=e08)(sL>v6A6)ZSPVT8cTwNLgQ2Eq=ZT2~g1hLr)cJhMS9g8>92^g>c?9XL!2;gGYdQ~36LFmg;Ur_2Z;Z$MZqgn@-e_^9lj9Q%@`))B7LH3spXHqZ!# zvc9J_0g5RDwLcp^xl#0vy^dj=(*;7h?U#t?!vSw|?28bp9^A3ofKPBkmONk@DyL9Cfy+e5L7OPdk7yw?wK84l@tZsvl<@DYG-qM`j6yX`1?YPFTpYAt@!h07hrj6C$<}T2fnSAWBn6*}{T8ybqZi(}$revbBDH}h zG&O=W%pDKx&SJ}(5}ruKFzS}Bd=|x}tk~Py-B*un^EFpWJ+(;@Y-U>oq8DMX2_u2c z1TVrs>gTxrM%C;ZyVztJsm%NgOW;U6Rw8QNK%*L%ik^yW;UydxnyyJitC&N#0dU-vX!VBonfj;Mk}uuVWQ$-Cs`D zw-u9%d78AUW~0Jj{X{``!pJSzdKsw}AZ2V6{h0>6bI*tybItDch7t2Bb93w8n=1-* zCNiv#&~VnpFy+raF7hLyrjF3JA0@=Ww2QUkSwot?PGzr;l6AG0!_j6N=TqHpv=|-@ zvp^YyQc;=i>J|!;gm*S*O!Q9in$l=-kN2xkD~%_FNF)zc*GqBits`;C1y0zA0*Ng#v9xXO;Es7bPkV1f;4E06qIf!b&5_>| zzZ4wUvBQP`cFUaD^st@C3nJ!Hzeo9Z+R4AFfm9m+2B*=WK z^}k@mZ=nAntos^C0RCje!9KgPz-_54NDP*E3?B_AH&e`Ja9K*S-Km2n5`ilFK5tCk@+> zE;RnJxihYw?e6duZ;=dKqm}L~%tynVw{09aUK^x+WbBq=t3fqJM2IGHQ*infwoDyK z?!QXad|jc|^usd4{38V(7H9~o9Y`;nfHOm#?&h=lGL3b*UhjW6EHQ6~UV6Z-Dlf@e z$WO3zTZG<|ySBK>4M+d4yeGkZH6*9Qzd179RS$PW_p?BNYw|%zA2Eg;SesdXElUL( zA|DYf(VzOCfee76xPC~$S~if42RXnS?Lq%6E_1iB)X-sMbhxiunX_3Hp`Bq7ACyJW zFaOy`e3Weum)p1*m8rMz@A@%ZMZiekrSMo^?z`8rFfTiyK|W)8!u7I&KG9Fk!@ldU z4>?ILY!c~8B_#jUIV%l7j}>wSo|S;iTZpUO%l5F{@pY5tmaikRY0W?~-iu)r5IjBG z$v@;qxjYd#YjI_~3cfVMS?fNIUhW1yvis!zyZr0f0S}jVHb-Zx>mvE8)H*AB^W}#( ztm`9J)S(kem*?HS>x66E;T{1E-ARL1I=#(*n_3dUmbe0c=}+Sv^BKPjX_lVy1}}&C zg=wj#)?=H~$H$@p4oelvjLM6-;Ll{|c->0@7$^qqb->KIErp>tZ*Egetl)=Bv_Zc% z2CwrVu1|)Y(!g&_-gR02aj(mUf)6L)!QH_5e7NLjjMSh8;gjjf%5&JZ1wo>v2uy?9-@G!q zv}lxFV2vx@P`EQahbO4=!0TLqufiUk_oB-{J;$`;5MmDwKAG3-jH>b#QHX}sjP1ui z1rfjt36R7%kb)1H7Fd|QlxS+$0sUdbGkozJb{{cGuWpDQawoX%C(P1&HMod^rD(@4 zj*E-J_lwbM-pvoZk4XtnRxRAO^w&{jy_!NoWwHDJ>6Z)iz3R_*_@YG)i88>-nVHnT z#Zo7PlOwfYn$T0&Ozw(>j9K0*;kI~uIhRr@E`R>=Dq=>Lgc02n$D~@#1>&uOyp#Um z0H`zyL{me@L}UAZFmrl{0R070vVmoOrCjNb(Lu7rSHC8QLNX0FDDPE<1s0f4%-*SO zHzNiIA*@{WZgz$tJT_nHdEos~X|cL!-BTgeJ-KX6)h#fsk!>jN`2YA2L_7fa z*R#ubNSQnv6_oZ4C>GnbUd%0M0@s+n8mN6bf4zV5RQORmy?wg+uR!azh0cTbB znBG0yn23*6PCVc@V@MHW$!BMQnhO^ivihc^cn5;?P6Jebf5a_tnu)+MIa%B_5Xo_6 ztV82-GG=XiFu!$Jw(*4NR3;%}3;p`Ho-h91%eht;P28cW zR%T~^fq?(o)z>GuC3EY=<5h#4{7e1%$pE1@E(LK%lZBHS0^qInoP~5X0p2}u8VFd(u!lZ)&-;`EWe{HT7*9xDfB1T zycmt9Kzr5WW6ma&%Uf^(6Q6lV;5a{+mBW|3?~`=5UqSA$(N_P*({|YrZaJ`T+cjII zsj_FlKOjM9yT4oR85S7qzT8y3wop;JnPmw@XUVFX)X!qxRqY2)6lK$?>MC>RtfV+< z!g*TMT%xoHDQ{f{1x`Ty=3x{2ub=`bVU6U?@A`M0^xyLVjc^|_x5fpJ5tD!Vm_ITC zL?Ib;-~UMyw$T5mz@}o(q5t|n+5vc04fy{)s1eh5_1nqM6ovy_gBE`hMO-UBt#%yK z)kcC@^l)9%v-Aul6YJ7m4NKD@nz6p58dSmBUouQ^Jx`D+vAC}|BsN~GK&y>Ed(nRn zQe_2NR{^c#jxTAM^IK`J+@yrlCTnh)`oq0WJ6Q2NEYhuu@qvXcs_3FAFk*W^;qtWh zJGa*{ZBe;@SN^#o8;hfTroI_so%8&DHjyn#{U2}VfesZSWc_o2WZkD07fxhja6{(} z9Dl(fZy7HI(62s(CCIlWuh{KY<*C2*(5A@?Q8F?3S7rdMjiVf$Bgf0MZ3zw+7korB zE}#t2?;QdGFvnvqThC^UbP!(~wsQXFsR;87xtG7%*Q7V zI&wktpxC}u|)(t_B#*`ZPa{n>uPOhA>Z z!%iHutfpN})bPiQ=SLng@8bB>5qI}_Ma?L^yIe;X$9(3VG&7poKMJ%L>J5r_k<|y_ zOz>4sj*#LJqnG+rt6bkc&)Ojzek~?mzLHLJ0Gc~OK5T?Tm;7{WF7CS_O4?z481G}r z?CXecPGyo_XiHsVVmKYR+#h$LPyNL?YCtM&i_DRPGFn5l8b=u)H&33LD_9-U9tym~ z=ko<9&e~fS3CfRvOrk;Z0zkC_V%;R~^qfex_IA%|7s^kJa#?3gM|W6VKXR1jmE|Xx z?Lz$>EKV|Tm#5cwlzh@V3nzmg8R$XE#T~8EJy61zA{I@X2koc#BVhumMa!w~&YhP1 zD9FWR=un#-m`8c{U^)kgBHg~8jn1L-6WrZW7ry7p^Z^@1(haJo5AUu)bvwxv2{|Fc z3ZBH~Re@Du^&5t!#;)U1i*@!S)pxaqZzP)Vy{N8{@bQMY%nlFiQ%3k{^s8Mr8DR!D z>HwM?9uh3kZ@xwhCmKudW}t0$ItO~1metnnuQxpuNi&P+n2dHudj>sEjGX89mL@gq zbbF~6dpH)qYC}>we*#PTK+yt`bb+RPL1_X5QoeiJCL_!Vp(mtyg}nb!FIyZBXj($E9FE_vw(p+OuC}8arsKQLY*y6@rD%d~o%0yEtSuwaozHv`QXubwz)Zc%k=!6vi3VzF15 zBh3o@d3UBhz1vHa9uyD@^H!{J<90RFqck-7th`*rVU(k8aT_|)_;_)yy7W^u_G40g z;${DH^GZ7Nz%P8ic4k@#y(h+3xXG<$%jqRcvtHlBhinoj6hpq@qXSmpMxH=>KyNRH zfvZICXEb;n69CB{*=Vvp`$Z#qcbfbLIiW4nzH*D@bz-M}=YYHxo^rE9m88;Ae#ajN z`|QF6MP&$Cb4@H(o8D=6xSWJDLAPIn#|;G|t?Y=ge|C|l@8X_qDVB{SLZ;V#X&xe3 zG5q1RFbf;5VO&jcOo!oL^3?r9xNCl2DBM151hI#h>=+~sO9;)=x$$DvaH<_eNZ4P&j7-X!I98@EEqbOYBBx9fha|r-Eb5Y4 z%-GGXa-%gKrJ-Z?Il`MTYcus*k?k+H*YBvGVdP)V95=~e5(&n7zi>y z!ZzvSz*vpx7y&KGLzbF1zG_`iZQ4b-HVLz`nDWGfg{$A$njW=bW2o{}XPoYOM=xXI zTXaIjsA$N!6K1AgAk{Asgby_jc{%4*IVFDk01U&6%k>#>AIe=^_Fb7BpDN9Zy_H2m z7L&oMLH_;W_LWN;o-Gw8&rU4IlG7I@dBw(|g86-qg>wnUJ!Vmu-F!;U7P*sRF_&hC zoAa)C8G~zHTgNZx0XyLi5`77j44EJ%DNjW0@e4I5ab7ha6rX4saNXtcQNK^#*H@kp z-``U{uMy;`H923(-}NwylL>dbm4+sx1sK~!Vj^BagJT?3@!DaZ&3kAur@7cpkrpMN z&FW_@tNnx~XT5Q8vsmTUb%QL&)rkh-`PP@CgUm(bTuGp~8VplZth)!=eyR^jYjU`O zMY2<=Bj@I{5OU&7Q()B|LDAbmTP`?l6Hc0;S~2S@K}M=oJuPbi^q+Dem5dgrYQ@7b(VCGS>bB&SkWp=+$VBIO`94B! ziaCieXRkMF3tRbCC=j+r675|&8qnBKS>st&Tjg;E94RqEqpVAh8Qkv`(nYNzfjrhKY2iS zYKH3&^SN`5*o5fZA+RWkn|MVFZlR z`3N>&9}K!S7m?xOMC^x1mlul{16ok;X8~5Wr%T? z&vA*R6kMph>^hg>`6`9TBLL}Sck`mhtcEs7+a1RUzccs}zbz!phARx2;5+qdc#ZDr zS5m?^W0xw3^<=+R=DJ$c@nr5Ux1uIRZn>B zK)jMUBuqr+;H^OzhB90AgB;w@knnVNso!_)_NTpyKO6YX8EC!`IU;#VH2)m$4K^hU zUSLtn*9@*-vU*g3MK@ecjUQhI_Q^YnllUNX?#y)Ihr0%`ZAHuV{GvF9f%Fy|D@8cadXo6jc6d&cTh*rXR5^g zTeVnRf=`kqXUhc+ytM49X{cXu$}yBGRYEVVM^>_1Waq`b>bZbHcA+tMrc|Ks-nEX+ z$l(?%I+E1|T*GE_<#<{_37Y}75H_TIR}Ipr5ipL+KKmiD32$fTlgdDQ9*Q8OfU3Alasmr+?fxL6#6W;h}Kj4R=3r@vwZPcIn| z92g;lKT`h_zjc9iK!F=w0zL^~KQAKa1k3!E6hrFzc=BqGiPYKg{c6h5Zx-kUX}qCB zO`&L!*nl!)_F4+x$TrNv0*u3O@>_T5S6bL@W7ar|&_W{;zA>TB$U?UeyzwW|3&HAB ziL2(Z+f?m<5{zgd>QwUG8Q50!#jYNB6do^niHef-A(Qh9?W&X4Go9h`hX_V2`9+3g zXX7*Gl`w)jnimP^S)LH+OnuRtPh1iw?6invCMJ%e<{0hDYgySUHGI zg0eSJQ_BOh3TwC`M{mFKwn3#!6g$59HBvH)#FD|PBggse?Lrp#a1iM-foWl-#^8G5 z|3HslBY%P+*XI9{_#K)bHGQb% zvD@hKb@bn|EL~s)NPx|lu!V^BP8$-iY54KIGJUl&6V$Qi+Bx!Ao`HxXW0gSdkN-;H zm#gCVg1}1ly!rHU;P@0QRo#K#GT9kcTLixo;Yi)*r=HIznC?5V9+-R6qZdLQ(ZkgS zI!Z~>ClsNP2poCK+=&t@Haw%Q%XrrJj-#^MS^LVYp)-3my+@CGw;PgtJ%?VNAA)wvVcNxz(JoB$#7WPl zD>QZ+>iqP_h$|1CP1Z_T>&|sdH2ObKM6s9$aqV z7-M*tJxPzgt1Kt~bhrNyPwc`}TRa|7^1AufhBas4vrh6RktEj2e+F^ zjyy{Ed=}{YOsCg=(-V&7qTS*4RfCZRT><-xoxO!QPG9igL{6$E za^O;4Z!*-j-N#)qQ;aVg(9yo^|@hEPD){krs+Rx#G-=*m0r{+qe*h;9(3@_ zN1KObOC$T?-H>E)308r1&(INNBp=7ndr&iZW8pH_b%;eZ(=Vb&tmEMXNYm|>=m*&l zT)W0q0sgg6q31P|$73@HnN^N1Ya^3cN63G65s)e9Qrpkwk`U4L%O<>|5-FVzCU(Or z9_|?=XZk5b;G3ds9p#ZXJM!Z>kiu^{?AtQpf35Wme9$IIZi8eE&;;j0ja>r<+~!G; zId94u5`Zrn^_C^ahp$s&%&M_e3-fpX7?IQ9U!WC&X&AWA=>@bTIUpNJF%nfj9#GL3 znby2T|Cr>#56o^AA8MaDO(3YDMIcv;?dT$6Xn8zsl+X%sOhxFiDCJe|r*OIL&toM* z%e8XbvN-Z1bR}oLq!z4^gM#B4)Cg>|Mba{%T#xqu^!WN(f&iGS?7*%xnjzRgifUC)9;P zujO=`7~93hy%{=gIjBd0v{F zaKG^rg(k6t4B4EFpKQ8ih&@ags{ZR4Unkqb;9M41rXKL5Z?h3yd{OAZX+UE+@;L|+ zCS$}kYGh;c!;4UpOjfsh<-%?PKXgX$Su6jXloA1;*e#Ed(60EX+?PfJ0^_d(-d_ox zuPYLyG)$^WJWO%T2CS4MdPA|qPy%wKFI8$t;jJWpP*Z4bGzBkkMs3*UBgup|(eKSC z1Y29%5K*;27eZn_mD%_<8)hjapm1#@p`7GJ%6P93lbP);ydYBNmK7!9e-$Yc`(CV*&)K)nBuUmMnRUV z6OM%B^YVl1hr!!cPj5>fPPbj9x0m)iIn0?w&dBsKZX$>CB2G87*_)$t&E)7xPjZxN zhh|L|{p6Wmk8~Wad${7_hTNnM>^_&yM~tVJ`|AS8cysr(@7BNaq=K>O%c01p4dv#i z-^kbtn1{^KUL*se;CDxjqjxiE_n)@vbh*cQmBT;|7zt64*%`<(2?|_CL_>zKMU3A& zHrzn1zrKUMMny5){i+;Tl~Hd%cVpP6mPF#CKzSzqU6hr`E=aQ;8c^e$UGekjD1kUE zek^jNUTxHxv*XlYEG76sQom%T0b%MAj2I)29*v|hVnLQvnED8xE9#*K8`+>8&4mXE zg3c@cZ%@7uR7*1l>DWrdS4a4aCGVHFzvl+walAuE#Wvz$(xIk|2A@sgm?SSZmjqN) zaKyyKs7?A&{^DL3nOr(SF9YZv`?2M;!U3-=?hxGZfurZVG`Q-u;YVkw13s$nE&*Mk z3&C2bax?H6?krygP}}t1+)EUpt0jRjxVnPl?M&onKv`m61m)o z)y+q)Z*^8;95(4|{K{_%m}ACY6giA6E)Zd-U1|OK_>K3DtPRCqQDR}W2=3rUNe5{J z%~6p}ogdhy=6UGMh>7UoB&*%X$mb4Fd-qY3yx!%#Sp54Tmu+Z-&y-ck2_SJh^9aa9 zv5z9z?aqmeBDe$P?ViJCqOazid#dczz&}nt40Wox6|_$>H4~KLcj!WXXJ!pUo@EA| zhQfDD40#lC>*NwO?lho{8GUmSE@^%#?A{0?&|$&|v@k|_li{cl;W+#``Ui~jFDsu6 z@EP6rTlHi}e#p2`B#EEC%>nUVdBlrD*00X3`gTOUl^i0Ua!>_;Po%w9}!0ou$h_YZpHt7x@x zQP6CQFkcBsIwbQPLcWNiiYztjnhDkRRJ5O;Kjjy^lt>1d&)xYtkkxNzeZ%}>!N|=B z;sO`q#Nn&#F}iDtayvDwGSv1soKH3V{}#!@e*plJtlBpbE>z#@a{_8DG6AtjRGdsP z{aBMx4x|My!Pq{Wk9^XesW+?rY>mplb@e?s&E8p@=vI=zxoU z!aNQNTdT;wJzjFlo&a!|J_Pm3)##Q-R=#8Gi2Y!7f)C;~2n)QR7F>BtFJfD0C&#Z& zLv4#;I{1l2yEJOdDr>Z(z9(e3TZBWZ2{Fi#Z1zp*cyP`9_&1=(NZw=&k8}V3i5iH+ z<`IxmIzKLf&)=N4%7V|owJROt+4sVXILdx=0W=VPMEAmj`^UL$=Q}Nf;O0&$$7I6a z7yBm|SoIBXsB8SzKN7G1cX;rRpihUQD`ZV4k##un_tyi^!!AD}z*qXAQpo&YuJtcP z?3eUGYwxG@%;fm{3jWYjm^i@J!^oF$lK(wE{efPgGXS7S^x8Yui+^O!fFG2iz-32N zqSZI~|55dS!Ck6jpsLdvV>5@%{{X-MfCk`$LNNBqXhADiLpRVV&a4p9a~P!nSSdIh zfrDL$$;|f;M~_W2#Gf;SW5s?E+|}r9v?>sj|Mex54!|&q)3vd2&Ug@+tNwZQmShTP zJ`w9Kc8_kH^@J#TL`rmTC%iJ7R$YXXR=oz36~gqM@{|t8w{QQm)EH27Kx5GEs#c7Q zdM1-%6T!ebkS3(yku^cavdI8>v9Qc`kcS`%R&`gfLGzVqKO1D5AJF9>nEBq3l%lq` z|NHH*pyrt%e>nD_;lcG@eVJST!sZf{m;=K?`x2Lhhp*=V@N%QJ_g*(ArNpOZ2-obd1VW@K6eS+w)Hx zav$UXEJH*Ni=z|AYhhVRWg3JFwpjL;-;sI%d7ZzRJAz@{w8JM>P6oUX)2->PEJaeT?uo8?{an7FL{gC zFCTVowiWp3VProLaC<_`K^vSOH z@sb-H}7`pI-C zg@xb*wvA?~emx$Xi?m=5f7$5< z>HV>bb>{6w(-)1Ur(@MSsm74pqnAo2Yz>z1#cIf^ z#S&T{`R0P0Ap6)-#QPBSQ8c>uaK^R11g5vQ_vrjMc%2RsL5rT9T)SI~0j?TKqRK-E z7#SNE^8PN{Sr&A3<+aLi{72d7g22A$!1e6B;v#cpAl;d5_lBJRLjyWvL;Mb#9TwB! zn#&@eB|DC+Z8;RK04}P_0qqE&-}EW0kdP-rOIsvnVph+!z@i-KW#I32@cRd9&C8B} zOmlWkQ`KltLUK3$B&h$fevcd|N?;*`m=UFrVb#c^6T&@xwTNAOpxzNU(GfNO2vDZ9 zk)lx>hb0i2|BtY_HZ$iov84AsPXjkZAO!{&G6{!Tw@wc~HZnBp2`;p4t6QDa0oV zG{a&4wNwSMa0W>g0F$Jps?v32ISdO@fuxr5`8-VUbx1mxvLz_$*&Kd-nEwd27+-Am zdmi-DohM}}!BRAjq>Z@UNIku|u;9x>cJJVwt{R3~YU)@Z4jFjhex`XxL2Tn)`)jEUpfCQ2sb zZ?Qa&#hY=9O0vR+|02Gt&tLe$kh<-U+873ndNzV#q%D}eT@8jd^CP!D@ zmlt|1rBwMXwk!bytT05#q!*u7SB-GDO?bxw6M1I*@`p2hqJ%X%)9LjC-yWYQWzJ;$ zdN^5FD+Rdy&GeO=Z@`(UuTK&{pAB^064hgho4AKt9i}`)9gi<2d0LHCl+a&yE5^06 z`pGLXYQTwHCJzX8;eC7ZdAK3aGH$FG{8JgFotqLh(1QO_mWI{o30HoSDhQcDe90BO z`xy?(tX7Zo1G_d?Nb9qjCzB_3qJN?KZ%sEM1&@)OAxMd23&3H#I!U^NB%Q%6n3+!E z+-b=%Li;7VL%$jtTy(c=ycMy#E42JP;s~gKy=rxXw?_LUAH%AJm$2FDuLK318E>NU zl}-NMKUjfe)~jt3`xd@+l}2rm0iz&Fp|5m;zMu2X!*EMZq+>y4gxl)bO7D$7MKHNf)khMN)WU#82Pggt%Fv1NAz zYc<^DfFkA5{`3#b#9y&IdvUP6isI}^plvfx`R4F-qPfIYGQ1gbD9ly6eUV#U$!o?6 za@D82y&@pJS=8iBVLsevQVouJB7{~&d0KDFzS*;7=FehENO!PEkA)tF;vWmuF>X-+iBB63P49&UUNrT*XfKanESehEO5> z?dI`$@+JriIfy9Z49b8i~M-2ggj-$n8ayY<#|&=O`K5^Q>`b7 zbS!kwIB}sB|G$Oo<1Xtb9~R%qAE9^y`C2BXU$rKdxQVMib5N<_6PX|(W&vX2zhCqK zj%qA*af6y1+UGBwQb_Y6bnS&0_-y|7@2Y4_hG7gbEB>8%>i=l4l-!5eEk);^%lY>^ zf0*4FpV}Rs6g)gpiI+$Z(r?5I%Ti&bvCK6r%cTW5jl;%PBK+B?^tDC{QUbWW;6nX# z{J4#jg%T3KiAi4ZaZ#sRWlJwqnzcd&_gMY54^(=8YW|fVCJXH{8Y) zEYhNh(Xm6$lI4vVV{4c7)*zKmg7-VKC|bHMhnS2mt?*IyewvS57$e09X!CHUFyvWJ zZLeQD58t3DT9annfH6Yki$X4;zml{Q zIOnkmzXktuIl;#I3wszmvkN^NrRun*U>ILZGn=UYm89r~seZgN3MwqTMUBt!k9@v% zsi8=5KK6r_0)k!&gi<|;tcq}%r)3}ra(nC7;IB??os#ntFR5?*m$@>@S@CkH=Cy`aT<+ZM5 z*&ruR9Q1oLrJr{mErCSXAT)c1p#^Qg@6=(~@Atz4!atQwTLbbTW5sAaSjsV}liutj@A0+~1aIbpQfLM5yA4$I5o}KPb%1yp0U9EOzFzT=V=@UE%()X_-Egt!$j89gQX&n_^B_CX@X(Ei22P;nBlGJ z1ZZzN7$xBjblywqAj6|ReqQ80@v7-uJDW124JwEKPNeeg=IR;^V89RcS$;>x1eWXh z%G?lHRrijd4B)0R4qjI>BG zC`Hcc?pS}Fe$|2d_JvNfTBR++XI>)Pj``L=AkOHugFvsjQmRQRf_CTkj!`Jrv|1R3 zk4nL6Y1m_dj99ZuXyVR12fO41;XvcHVMpY1EyEUO2h0HM#FrWj?lo4M>IjoSeU@;y z-i@L2mi5=e@w|VA>Wyd6K4u66(reWOjH;#>EBxs_@9{Y^$0#N;T#{83vg_%F_uo`Q1{6oD8*TQ<$?6c5woHzq+jT^FJI42TLsO9t;_7UPSoI97+XXr_R6gkK{DqB8FZyvsUqZGKbR zCFOvQ)y%+eSHbP=`}a$E?}iAREN}7uvJ86+NI%>V27%sXS(ra#VHv#fw}#;c(_~W3 z4uyYURFlJ7d#&)U7m9srL|}G=^ke9p+i>yuYmyK0$qS4%grU6XX{vPiaaVR}`h}>F zf>YZPd3*6Zzdle|pj@pEH3>6>Q|+2MUUzIBnzDK&ZXKS%0aL5+EXq!DcBT7M<@&Rt zXXroIjG7-GP81KB0hUn6nu4kaL1vt^f^cCtOGWcl*z`2V{yGhW>))>t-Y3yBo~^ip z8b6mjP{Urr661rB_-L~SrIG(;HLu{G24p#NMAPyGkjc7_qJpzV^Fy653aC@tP-yNg6>g3N6r5dC<4>6QRK! zEjM8TJJjMBEX&1=ByzgY<)CbRnTzUj;TslGcTo+dzvQh(fUQPSGScvrYmCuyc7CP} zID<&d{VCJ>8447mircak8O)iVj(lj9%>*k$!lobJ(E=!zM%)2>gZ@d!rk#RwQ1k_4 zNsH0LI5hg@XZ;e~a4QakrZdHcUaY(x%Wu_Q)-Q&05NCkbs!w}cjpzj5=lGON4Y|Yk zP!)p6*lTmw)iEsUb?+B@ede$i8x`cH>i) z{YY{=ma-RZjg(`?H(!qqAZ_aUphKT;KQRrv{($1*WIF_Gd&O1uU-`NIVHEa%MXhqb z+tVGPeKOK8!(rpR&y%^R@S*v>E?{qkeZPI=JwNR|jIk)uL@e(tSIMgrK6{PrT3kj^ zcLqOTsWN3H;ualy{$`kNP)boH%uB$$9UHCrjA`qh@8>th#l2&puNI8*{zAt5?1`Lz zNVC7#q7So{56i?&v*BkmEobWnF#5|;QE)0460gIT&^m)05bZN)fMAFv4-%1rWSpTk zAFwtSVQB%}_bbz9I&Gz6vnv#Z2r9-jY{ppmO~oxmNY}WCap1nmAfUPHj}vA=)THg1KfO%o|HHpZCSd1wEJhpY!D;=|qMA*xAXNCTxS zknqu-!T9|b4WIzMU#xbI5}%@PO%Zpq7XK<-cG#d8QIl{;=At_s;tRVg@^nxl8kdwc zgD63cFo6<>DU*;@sGQ^+iF|47S9W$iM;QEL<~{w5PZ~$Mb|bOj;gf~1hmTKd)w}Bv zj@#RhJ9J~TZ+T#y zmhxZka}rcf+(eTF0<*h3;W3k7)g3u1z72Z58)Icw@JP@hqSzEfjf)Yqs-6|YmgwBO z&l9r97$`wx5}E)%vgYA#JA)?)-cA#UB~g}&NY{gIOsS+@))Qq`E^j;-m+$joTUXFf zRr90Ut`nS2H;hb-!r(WM(Zq}STPDtc`2MiE_3%2oZ~45xHi}Q@iF<2B&ii$ucb7;* zwMx9KU7iy+2*N!5@YR%}M|fUQi}8(LYUNBKn`yu1q?2Uz`I@tWK`RJ^*OAwF$q`t9UAyJ6*XaNCCovzeBhIxA;LEmdal3W>pKd?XX=3BGw+pYs*HqU>K*+f zLw4+!1v{`xhdCvi{X$(LMEVG1^rjpAIO?*>(fpn)o^$(uYCnpuHq;je7kYSrg3&FC zQ0>@zymKQHGg3l;U!|s+tE;tk*M|c7p3Bypu2)+Gb^-9@rfu6J+@|Vcr?*_(@|Ir> z?5(@iv#GNC-sgx)lfX*auk32RYJt2S10cg3hods1*wiV*4*!n7Xht-3Hdo3KjV7!>hhYPY~I z5U)z=x3?BnrpdKZez*~1%6pyhWW(sv(|9D(HU+3V8u2y3`gSXYA@VJW4dEE3 z29L5kigD3pgcP4MY*6hdXA=DM3n80ey!W*K@i@S+c2L;%Y}l3*k@)~VD>tpTM+1I+%AMPH(cSrD9bLnq!3kvYHdl4#qU1iv0 zWhKiGeS6v%pChKrO^3_*^EWO(efPTo6GXER&3@$+x?Q6#vQr*^1+0*6ro9lo9S=## z@>r9dTZ?Zb9bSpe(Y_tTp}nLW;R<&YWTd!wnz0?LoJ-6>1cbq`&(_kp&EvdYTy9cl zzxV6$racoyF3hyxX)Hi?e);oobF0Pna^>S0mVT&YBCP#LRzAkEdm!S62s^yq;>0OvOLVjz<%L=3;LZ%qrXiqWhP#_wH!)g)taE8Vu14I z;3lpzGF--?uGWgqG^J;<-i2(NTZn_Q1lnbq9Y~mJ^VsJE`4*o(Dfos|xX*O^pxq($ zIBs6_&&E_2h;<--)E(z}=x!PyvyQ~fa>+5zefh-wpjNzV08J!#5&}DM04vNz`5P>gGB6 z22Z)=SpZtwFJc?D{2Edb-dKX`lk0;+!G48FbNg>Vx?np;SWDHK77Ie>ZXlVC81)Tj z#xTC*`457Qw(h;KFyD=^q5qpf$1IQJEBt*oqMffZkGpUqgsXr|WRFOXpWAQZEvri@ z=&sKh_9Rfr?UmVuiIXS9ZohILdH%J5u!H=FIKog8i!bty)W8~4Hntf1;EbNo?_-+x zCD#$52ra_Z#*C&$)SXMn?c{N(i+Pi-Azl zm@;NaNot0rz%Ro_7~uxeqf}IGCN-V-j=r=vtp;K4Ts;oI0?E#NWT#jL>Q31_hK6%p z5tpk(H${ffJ$3&SdI`;KS&w!;8Y8YBJ6sC`O`2r z!__{z0Mi_f_W}@6cvWRazk1kWL1)FuvgpT$HexoAo58ZF1`{mJLy0ptfc>sMrjur2 zLjjqcv$=}VHB!8ZRKO~oiSuw#0arM$*LXaVHwU#R{8?N5T8s(&GMx$}Ft4hLt9(GtHn7YD{=oeh;rCPLBm94)rD z;Rs$Ldre~*3l*uuPc&*^@$!uT-Hx!cv8K%QAr~1v|OpL2YIC#Pk0SRZ+ zi2GLHE4}#VaFPlmbPs}8C9873BfH+WkGuwT5Zh_Ga%%2XY9RpvC`g`kJ{%ACyma0! zoeEk1&<5J{PQqnD{;u(-O|hHhS{(@#ScaTyA9W-pptS4B&}*?F1~xT0@3_p0J0Uj9H3_NS1*5EN z>OP^N?~Ops3+-}*KKRCgVkQV-D-^8}tzqfvp7NZ6 z<)uIi($t^dmx$1pLm_?Qjm&nT^@jJBXVeCFktfut3oVo4uNIH`Hc{)$sF%#QSQ?qC z&c9cfj3gl zqnoCUh=?%0u$GqeOmbvQ;?y9ahS$XCeA3DL*7LOpTAa4OKu-M17R@AS;MHd zsFNB$>{_v6Qoc9&3#GaOp2$D=j^8(nzbejR3-Dnw&C9$eAt}ClOSzKg?GK zSrSXc;10L>e#Wpn8(@Ewzq2U)Q7e{}L$hfM5)<>9g<)giXYo*jWK zQHC9S;)4oq+(Dh`f@^|(y-!&WN%}cP5utA;_U8}G2>1;KN@Z&>NGcoN z?B&$7j^5Vfx^-|p4z0}2eL|%tR0?#J>?`Zp|$f8t%pz~i~ zAYMM`_409<^YTm5duLS8552gE0JDGi4THiI0^1af?( z?vi>F#Xi$`nPm%0+8q4_Aq@GL5LhAX4AnP#o#@&EMfdr3d$*87iQ|_a_0}@;nbg`r z=Y#bHaz#--G)C2z`%#D%=L5oA5=3V;537b=Crwi(9Tu8(rRQy6NBF4Udpzi!ad4~- zYx%XmtX4Q8HN4euX3Kdzcv1N~8^6zz93Emvu#whuyRv66heYLk(D&8!Zx)MPPuq8D zq}jwMN>S@p-RwghkW#1dX<25d@p;ff6Qo0Ev5I~^LrR&F22?h7OR9Ed9J-i%Gfng` zZn6|ZfL;qvkFkwaglkp=Dx`NA%$b!=qB-n?c^PDheS^ z+zFVi6LN9&_wkMQ(B-JkdnGvFOnYc|OUUdDc>7n3t7{qZeCNIWExRYWk8CM3v8fpR zEO*TFP=nx!aF5wS98+KvY)PL%>|lW^GOCzEb%&UrU`}!7^et3D>tq@=GcbLhO1sUQ z2wv-uOvxLs==IKuDow7H8hO(Ys?BC2@i!$of7ben+FnxSMaY>h#HPq>B=;fey1xol z-`Zi5`a8)z(PjjWwP4fLRjj8F?&$~E5J|9+YOGC;92U;#Vfqv8;K1#NeV1|&EUgL4 zt0RigZPOx`*|3lg>vt6i-^gJ37H?fNaZPr0edfBb))}K<9k7rFjKV~f_gf15W>;5t zq@CSC`E@6?eO3Hh4dHjUCJYDbdBW_IC>NZ}6Xl|gebP~Hb6jq7(rRO>Xl_Soe^Xe+ z5X-Nfb3s+4oR+=1{5gC&GFJLkClf8IT0scZ(G)hwAsMNtqb?%#h-g_Bb-wNbenAut zhCX3c3(0m|tfM8c90R=p=lvnBN(WN&YOGldaM)Ij4lVfS;~g(B`~>euW|0MKvIU(X zn$QJCOgb&WYXX=hHSJ(!hSd==sR>M5Z`fU(gHTBk6&wv7-qiPX@B8Q5hsL13fsWF# z)XA1)TWec;h_jU}ZY`5Ix_#_hjn?gZtNgOgZ`7x3*Fl`#x&YsOd}d9zUggz0*?cbS zffw)u8Q4osx3~?jM`*T&?eb~jd;%)v-11&MnxKvbPxIel&xX7Y6sku+MxxGQg3@RA ziKCnRlAw_iF)>xq#hWGqWexXVBmEMPObaO92~$_^ z@+aFd%G=7_uJ466`Bx`$WE>P`W2npxi+e94G1?N!K|=h_Pxu8(Z6S>T#0eZ%?}&pj_QNn+*49v(bF7*LJSti{tt zOJMz$ia7;|h&%Unum9!;V3x2?{V0wbO5XOw5_WRLm@%LyDe0RPn{ebe>S$Em%>abSnE^h+)jw*SX&n)JCYUp9EJTHhb$66% z)2V`WJ*uvl8CIADeK(8q=*BPn&QhUdFgY{|sz1@v6QFwVDmo;4wU1}AJCSwpzRFUL zZA%)bSlg?aE4XfoYWWe_(D(Uju8?gta+xhrhxbdK_mYB)-&+%)Mq46ns`31O-JqEv zhXGCLs@8+N9>+fRCUZkIslW3fzYKmNx@hm*b;(1f0vV{S0->aQ)OpqV(!>?dV?q|{ zPjljN2OOdc>+6V|jM^e82AQqSw}Q)ZF@s4vL$?g<`*tWSYjh1G0Vy#3^Ihg0uYYXM zA}JNxWR(vWUz9|e*+Ps#!P@1NX%}BE=jXhZGW%Q7#ZOigY5WDM3Onksh$t|xLz|ia zkT_jV>co_o3r)3(AqjM=aZ~&&{%}fZ%w`v0LeZ2q#eit+-klrw+tbHko^1U9`{v$1 zlltt~IgLw;p-<89dFY4rv+-LBBFra!VUwPM8AJ)eyrY#k`M^E+#LT6*M#pz}9(v`y zkOXx$anb(JaNo1k!orCdXeoSm8}rCynu4*^kn=sU(<{D3fRi(hubBa`#7E=67vvoH zc&+s>hb!-2sYs&d?0$>~8-8E`UXQeO%5T{3Zy+Qfka{gCm>5XcGup4GxpSiOg*=!1 zZsyrAQnr@f`>7omaAeT%^4xp{68DChfers0KJp_yVLwTs6l5((zlJiF^vXlg5m%}Q`=S&Y<1TudTufN{ALSo~KfZ^No&m$~NlOZkQ zJ`um4k&_4Jy}0hi$dfkwtIbGXZSYp#md1Ero*g|V+e zOzep0N5q}i1`maqs6a;vs&&nTgLfyF51=>jv8EiEWRvfmH_cGmB~`zVwmRY@o~sKz z7PgFso=UWd%mM{>RV&)B@K4K(dTy9hc6TE7YPbyHDH;QkS6Qs>22%D*+ppBykK!kI zmpe%dpCz=>;wrC}fFjQqo>zQWrwy2?#i1Xmq%-(JRR^l|!3ai+64Eai{&7nR{!sxB z$K8*H_@UmR^8^gFdocU#or0TXFHpW2sG+QXD7FANMkb5nrqe^cJ!mY}D;sLhd$fG;*#k1)rA< zz4NO#Jcq(J2w3IwJ|arQsD?Btm$NVLKB)l_{{w1cGkt_2!6SuJ3rXq8)llB7|#P?`fLE3$;v`6;NtI!oiz(h2g z9isNI3aMYUnq=*GI}=Ot_*9BhQe=&Ep`IWVNp`l}`3@LTxNqXgl4YO5iUQTEOHvWV z_eG;9!A(*}P5LKk@~6%uCtE;iLF9Ngifr0tV?E{jJ&vshs$R0p8oTZHi2DOu6-6qW zfvy>7x@3Up3tN*=Y)VIMn6I8BoO1l|z(jdfa*y4ep`xU@6%jn3S>e`ajMwn#xl~?a z>#U~TB!F`zd5V-BzYaHs+e5BSNJT^KCwAcr8X+pnN%TFPBxt!2OsXXGp)uO8zG`pO zADsNIM7|#(^+9sDe%&QqRHz{CWF2K>okZ=Ut(ta)Pzu}}n%*Zf3o7R9qQqyv9#n9;*z*T zG`?h)-?L1&@nq4O_S|*oiXUy@j4>KXgf{)TN4#x97p6>ELK79rwH3@5yc2`xfT&8N zDX6!q^i)(!cE3fn;U$x>ja&_rvV)f;ElEA*+;0ik(Q>(V7WulAWk(cPe?sJmq{_@_ z7B-M>HA-Y*pv0tNT94V-Y4ZeMb~#b1`pbxsz!$ty<+{YhZCFYR4|bA|8a={Oab!|s zc%fwG7egN4eIUbgi{XyUpc#Eyn#0uRaqS#BkXke&Jy7Ir&7+PfDf>EGx<9!c?$e1zAd&OpBT|S6OB~jAuYeCF|FNa6~;TE{LT22jZQAMzd_H~!eD7J zlT+;>NJl~e#O!#T`^5jjZ(u`i3=1joL3XY`|21CFmjR0Z#!3R=#$!HWMK^te-~N^t{tr76B>XW+o%`Wk z!T#TKH-EA2|9-TqnzoexVFCUR%DQzoZaOI`X%q)TA=d4WBO-6(! z2esV9jfR~=c-_v&v*dQ$w6Hx;pvD=ii~6K<=fiV2VE^Cjx6>55c7F6GYR5VAZBzDO zMzdl68cTOXOsRJ44|716_qN;e^iQTxZji|^5{ikRJ14r_3Pw`8_<8sb*_o4HBJm+2 z0dOSoj50tAyjhnC)^&TR8;9|*wf}x)+qpC~qF6#%DkB1y>ngPuw_j3IlACWca4rF= z@bC*~Kt2#chxZTg0KqE;K^5{kKR=AFzo7Bk3n=*gT%$-q(f|J9=Y&CFUeZ$wC?1vw zHsu5}Rtr6qxRJp&c?srn`nw@XbmYYT}bBc-n+-%Q=lpFtri-}i)lI6CIX%Ukbqe5 z(TBd@6vq46duHxS#0U4dOM{gp35}!!a~F*8V^|^6gr#D`ec8J#=Pj$lrmkzKxAn-YBZ+qVm9Jq38c6Os&qLbAAYAIdxBvH)*pC7G zlEE=5N~z$%Non9;*B!LXevZrhE_~`$1;w=GO_(6uh$Lk)GQ4%ixVscUq>>0;f`}4g zxEDC;j~wA&kK$v*AdM9@XXH00Q)Ud&8tA~F*lQ!f0`U0cVbZTnKv=qmwQ&gV$W>(Q@o>z_N+*98yYsa^#j2=dnBa#YUpuOL>#=vo5_ z9~J)lMul+q_R64Qib+V;WS&S{WLaEk)!Y^Lu69 zAHFN*y^Gab(VYgU2FdT@YSw^dK#e6uD9|$f>RYKBb0TC28O#^2l2ceJBWriUO^{b} zPy;2RTeg2x4_7~qNu5^HR>`xp^5EiU>55x21aG6avpNQlT0Hw{<70q9RPAo}?$O$# z6-gw;oq<#(0bVTn_DH;6FUgrtIeH`-=eLGs!gZitU(6>O|66OdDIu{-3uQFWXGxO-QF?cKreHP*K%BCyL1gz&G3Omk z!RyNIfuc>G%NV0Jr>Z98gFKC0T~+kclS0x2!??z9M$D=svA?pF44v-@PstTXrmgD> zS{9?(3;f%l6o$)r3V?1Ybs&5^u#!wF+3~ITGnD`sf`tQI;dcSSw`YERq6wKkc^e-+ zG-pox8Y4Qf=P34UKK0-xVJ>H$p?*~5=v?!p3bkD7|D0p~n!azyKUA`l4pH$jasxF1 zr!F@zYw{ei(vf^TXdYT(Id2WK7mF4xQ#<+GzyGTWVx-t_HU4`t~ z>6$;K8GTRD=-H(x^<4%g>?c3W# zxl{n11nP03I61l)FC7nBsjFuVj=S2maz{5wz}q(Yq^?@%$%dXz~S4lxRpF&@M%Z$$rDUj0+lul}9&)CQ z!1R$?=GDeAjQ?Ux6^*g~8vM=eVnL@JiT``vkScNAM?nksUesShZLS!m=Eb~pg=i*= z6l}c+I%YKM5)k>KX}GH6;&eSrA2`J_14>~_3vRcN6b_DXQ1^NxmdLV6aOsQIr&mM$ zHU1lU3Cz@5IPFqcvHm!P7TAKLN$KF|&H9E#BL-~HP;DP0Tr2<3C|@tr#xJluQuM41c06cGCqZ7+e7 z+Jw(QL}rq<_+6n3@;_tF72{m}4AfE$ZTQG5Y}r1vF_Swf@xTh6Eb9_z&}!XGMYaDCu-J z_~CsUD~=(IYMPC}QFVm1LEV?fT~C-@T64?HPX%3Mi1LjvGjvC?L~&BG9Z<&)| z{4Z0CmE^-96~9EG|1e0|TYG%*(^WR2x?ZZ~6ci-nqowIyDw-T1H&oNn#Oly z#g+S6baB=P5>js2hYk(QQ*DL&6BH$7S<0xFY3`1ysX@Wd7FiC=f(mjEc>bvP+B#`$13cRogICC0; zL-TVLk|=dbukdzH-hF38aj13$EhB7OHI&T^#vc}18Th(WxPb4ZfrQpob(xBJ%}f~e#J@w^o@YAW>pe$B^`(*?S5_+}@A&!WrUM)I$}`|h+jp_iKO zf@=0!$?JA0$S+gL8un9Ky#{;bfS`s>0lKjsAw0<8)K-(6h6jsaG`Yp#!s;Z9#p>(I zCo_ohHNO^{sG)cz9a&9NhS^URqFg64qpGFvzKndL=D*L)!*4-P%CZO10 z-IhLi)h=9SRV|c2R6hGPHI|Buf}6xE-W|6(XCN0P`Km|4H#Mn%ra-;BCOmfy8F4=U zsTju*bWo75figj|Hhsen=E6|L<#lxhfYz*347yL)2nTd(+vJ_~*W4NmCg~E{i9=~7 zZO$Smcyx{Pbb))QR41Fp@e?pW#aZ#*l5MWL5JFhjrlTV`^<%mmkdv)^@+ie5(6T7v z6(jNwkaHNH6;3znoUjsdA(Yt?h-c`xzy*hx|F)K}k4D12a01B4sNpqBK3)nf|U+;mznTn`Ve4z^Kho=dVGce_yY}t$q zq8K{@7lCkBnWw2gH;m}01L+E#pCR5szrVosJFkRpUaV}(;5fqI+j#AKKN@8 zoEB4UKy@LYBMk%Xw^qIn`4_=`XW<592k+4cW+tqJ&L`Svm%XoMJ|l15t~~k!C;<=r ztHhf@G`Sm53-fTFKjPie#5@)%XTN%9`YkAho)cO`jA96@;54320z$%niS(g}fV(?> z(Bw;H>-^@W&CQeX1|$C~^UXP;K(iV9?p~aF@$)1e#VzHVX6 z9v(kTiph|atQXjkENMQOokA|w5gie+hMYgL7>2@pUu2wvO#fN-p(FxaSf+i(8kBFC z9lkIIuc})iqq#jH1}{(6QCuH+XyRK#S2%^S^p4N!o+h z32WR(d@nLQC?WMdN0|fs*APUS&wYmaM^1q|g*4r%%RGKZc_hMHswh@98HAdgiA72} zYo;-k*-WKexGr6gZePyc;J`Ah9X5iZI1wlPV}%oYl|RdZ2)pAeTHi9blG_TRQ!If= z4Y)(J9mEn#6!aB76*_PVFct4;is+t&2SH7vPizE;kV1{zpQf}eNChn8=RG^1bBDm~ z{bmE)%@b64qkYapjO$KV?|%kAj4TDFvf)~_Za>7zs0_=*S|%fd`pk0%(kZ49lihvC{*L%<-#1Vk;Y!v6U<%Yd z4YKZmj2MHMs_0T_c5v`%*^}3G!H(g*Hr#~8%C)8e8RgM1Vr<3=w}jS+?OeoYi-K}o z0WF1Ki*h^;h2$z3nFuQT60$5z)H%qvy2C|fsbpewpYqZP>IEjZVU~Vhjf6S)*2mrkerOdxt5loh z?_72IKq^h>B_OW8CKWa1T(;TVSW>efbk;pVA}|{=BW-%R`{y*CDAL8 zo7d_s9ZzK@HpgkzPtU4O{(onBW4OPjT+>i|ZGpulv=CeSFxu~O`M2#)4%m~h97|pC zJX<0WJmo&YT{~(Gn5JVK?N`h7AoX+|fvR&Kf`y9(Gb_-Tr_&AlDdR4<~|?{CvXGJ;owF zVs_IFo{8pu=h-Lg6{U@Qas%(keLDPo%_8j@%ls%Uw zL`|0Xm**hRu6Q#TMcekjq(YMLv**hok>~Z`9gjpzF@!9+b9*!9|`m%#CY^wzac zojyGLt6zrYtaql#e_iqpaZ&J|F}DbJ$lMmfn_z0M#EidUt%Y!Ev-+cZ=_BlB7pHXP zPid_w++&~MyZchZuh1Yu9jCLnlIfvxoXg$#6>k9r(&i%wBT`BIU}9$$l-wP(^bO)} zRRIN4C~2Huu)aG+_CpFeO=0G_fZtD^;NC@KAgQNk zfJf2c7n?_2%Bl0r*4-{=SBJzNUsyL4JUTPhF`y@A^R6Yw7CccQERqPvPAKH^!Qk1K zF@yGiPH^x%mL??t@LXGP>3%lXM#UYRWUdGNJQww+xv7U3T5gD_LA}e%N%C0j7MR&1 zcD{L(m?8q1YIm{9WHOq5W$A@AD?AR97IOh^bxk#sSTKzJoDTn6%1kQXYu*yk8SZyJ zzOQ)0b#Xmbw}tks$lT5X{Ip(Styi3zb^sGW6N)C00+1z7V?2_H@2x?Hn{JSdCbp>$ z;Jz>Nm1=L;Gb2_+MPyZ)n)T>T4EGC(OUj6uE#AO16^t(b9jn7~Xf`JfCIz;up-6OT z{R%6AOTJMzlHRCyWLn6RKbCET0j+-{4H5dBDtE{;UzpqE>$a%@7w4iCxT zPB)-*E_QmKL-;yQdEBDUOW~E+yh@0|x8bVnnSIePA|8RHKvg|5G>+jaG`>UkUimfw zxoFQrW+w3k)zp()Q5Vtb1c%htE;w_05K}8a0cQ1hL;H2u0`mYiNeI89dCr@vj;BB% zn~`5R-z6W5W;~mRdtkv&!nQ?(JeH+f5&>Y?i1>|w^9^w=fM9zFq4$eQ@Oy+3XMH(J7zGQ$-SCR(o1&L&0pgV1@O8b z1glfMpTpX(2(9c_O{}$-*DumpgMaXIpN;||W_=$?L(HI}A?TH6)hzC!(%B zSeL4xfZgosEn1afZaubzTU1Gn4eOJyUoB3*sIo)1qH;hjucT09rR-_pT@ftW^JTZR%F8Jf7i zdCX#648j;1zAFI>QHLj3jGv=5Fui?@g&*ntr)~NR7(Qezfi$Mq>>Ytd#18}MJc|Xc zZ-e~$A@e@7wNZCJxnL*^FsbM1O7fEsz5oZ#)%0N`)<-HOIJ+Fvyh1-tY2W^R5N6*# zfM?s@LzTAC9S=H{Zn=w&q;C1rOw#74=;~ShWgmbdyyAnWXVsa{oezK0$dzQvRuDV{zAS^R{kVWb?2Fl%f(5- z#TUblQYFn_`M&2%%T{Zhx_|w-1Nf~^%(iXziDhPH<-2AJpmX|?BPbBv90+ex*&0Z} zRR&aQZP3)3tM473dAikkcx=Nqrc57%nqzIV1r))!nAn&2lFu}!X#YJyfo z>(O>LnfKTfcl+|!?(iB`&#&*jEAO`^0m{tfZ!aV@CPVbTpef(P*-Uvnd&MO-f~#8^ zKYB{4jA4~z@+7Bg8t|Q@*Hpvr&S+n$k{Mf`ZDilT`^8ITi?6skk(o7rQBzEv1@y8z z7I4)SPvh3LPm7msDx#Vf+deqMs~Efzc4=O6x(kzNi>w6@Z=?}ij!p^prn-TbZ+yKB z#iI~xjjq~=zD}vE;hJkgRz^A1FTMk(($$=aCDK(p-VzVS`p*qzA=$@dQj^+J_LEhI zr$1NVIX^3z_jc|n_c)w88xDTzW+s!+=a6oG_~4C_>Ww^>3Pl`U^H1yL(EwLA-%-zK zLgytjO~UU{je*fnG5^LRg%(NT>?9A$%qL48Bz1M+QH7mAS*#FVc2VAhr1w@;(o)K_ z);T@d={FnP+_Q3A+v@Ow9oo$^<xP$P-;41oA^#31utoaCPi25B8X`#&R!i0 zfEf=Mbcgjy<^2Pkx)i7;ezesraK#D>`aa7S>8tGJMP4T^=xr$fW9LSRT(dGzoVs(T z6K%HNhY`e5T)jT@Aqaz)v{A8$zHds^R7*pPv`?OU-1E@FBFOZ?vEQ>Tc!3gM(9r?kg6f5y*_v!&jg`zJ^C4Sje zGT+TyScM%TIQKn$xr?&t5>03UsP$Vw66}AQ|-^*7*I4EqL=nhz}PG}GS#YJ`jrOJpz z#9{3cQD!{nbV1tED2@!fY^qD~nR7W#h7+QL*Mt@0YU0?xOM1WD5=OSYt>oN@G^7M^ z99{R?l`^In@>N>Hk6IjkQ-zkpnH6j(W%%JF4YZ@@^<9~YB83!0*s zikv_U);8hEzB(X^zR&+7>zuO2@XHbgYhTyJOoccJgJP zbI;xT-0!dTto6*N)|^$ds>b-eW7G)lH^@>C3oNwXYGE`dR-_GZpeQIFiKvAZa4CZs z?i=>IfbSso-QGLsNmPS$y_ewAkCz(>v^Y;MLvF180Nvm=?e>(UuJ9y}jW753{o!nP z9v3~H6q0JX9pXJJt&0zwNgv|X*X7_E0ys7%u|zx@$B8jab1|Fw!MD^dO6R36ZuHF@ zpv}kX85EZX(vf0ZV~eKiD@Zj^Q_bXr=uNwQ&5{-xy*P8 zspN#%bR21lv$|R6qNNbW-R`K1dR;clEy4fo%WOG|8|G&!e<*kb_I}3*hqM{sx_l!nhej;OVU0Rs848bYPVszWLo`-a3#M8^1?vf#^8I#(V zIpgtQy3YGSYcz!=z(#G0umeiokLQ8_0jdcq%;fL+Oq?+pyqjO!Y6IZHFLwktAKCS* z8+$D@NUY~jm)_4Ww@)+ZsFd7t>x;gYeAsq61BBXGk*c*)yF~~k~)l4?`m#?z7Urv8G8^^Z0M={+_BoFlZX08_x`0c0;Q(>-H*w$`e zZ_HV+Ee{Lb!5Z=u99Y|Ltup!spXg6IL=^|$hXiqCHQsf{bVd;3TXdHx%#zwNs|!B3 zFEv`Dzq6(6i394`kpS2edLmP4w6H9JN1c7X`2CG(kCO{I(>(86Q-#)`t}j<_oP$h! zRRb6B+znNZRjzdE7P0k4oH898M~LS=abBR`%ff2miwCvOIx2)%J#SE4QI4n@xLhJV z&M~wL+~HCvY`An(Abg1$T=V?IhG^1jMRx;}odD4hAs17fe@lV^-YH*hj@G{~M-fIT z{v%I{$?W-=Ui&T%X;ny4y1o~-TW2>~U-KH^vjVHIbGceUk`L~mE^z*zSOBAuBC4Nn za7CE@5f29C1GU_~+Z(G=NEvYfdlh2ygr2aH)@WSShie)La8c0Pqh4PSi%MgKH|QzF zk2hrEijs*M`+tN3c8|D+M@W)Z$^%n>>tdl(cH^T8d)n`RKN?8QOM2#woNE}`a+zlO zCYF~#0Et-kAQ*WaRbIpWO-5SlVB-g+nn-#p_USJQrhV=pK#<_j#+(XXcG<8&43uY# zt;qhM&t558Y|5p?)6&_e1E7*>aY%K>P3!n^A+u*;rWEhn87s_?()h2)T({CzK`dTX! zs=GoXT%9a3h>b~0DEj>kQi+YA_iFIi^qNIxNm)}9jM>a>Ts~H09C4mU{Nrx6&%&5v zmWEDBD<>%a)`51i7?-B-SrtRoU+LpJi<=$GgV5{;@p-`_mp5UD&x)iyX;Y3iiiR59n&f*34$L)bB8#=@C;}ITFHYRl!=evC8Ul=#?MOGMmWl&bKHVf;@9S zX;vgJ9oyUU`nwkO9kylF62H3Q{%LsVUUtCpmd1jRSDxCOFBK^* zHW`m4?zyZ7TI0JfbV~elVyHR)O2WX{WKQ|px9I*QkYQ9Q z%%{Y!4K}F34MQfI$e*`~Vq3%vTJ*}i!U?3V7^PrbECjIyWO&i;DMMAea5#Vb;^R?( z<;t5Ij+4dTeWsPB6FEu5G~jVZABM(uflRf{Kz6@uB8VrdrGi{ouPMLj@%_y7w1ANJ zl+=wyWOLc*AJ#$%^zE3wX!2_hf15bfeAr_wnBc?=cOav zWr~{R;c87jMUPSGktIX%5QFLeiQbT-OSGFmBr@aH__+Sk!L`smwCjHd70$Yo7X{3e z!!3z3vMAwS%&!oH1Gme{@g4sHY8H}5e^TmbdMV5HGe(st;J4|PD%JMSs7SUZsF6MK zI3*C6oCFbONV%FhKeGUz5Tr1%#36AQO8(d(RTPx0KyP~{Y2wW9*S$(^^3Qt)R+7>@ zx%0xZxGIva(UBIaxRE`!L_w^BtjCC~>^hW22WO;JKNI()BeU!%vsiI)OJ?=Ch9nKy zqk6@9fsbMiQFq-+Zz$12YcT<5ms^Ac^Q5xpq%DkVl9g-#plTp?3KGYPzPChlr_gGq z4|+Sw=oc9oQX;$T5$KinOw)>7{uLApTdc)y=@q(FtKKi{!~5F}LA<5Gf~%%tzOb8^ z40)09@tUm`dTA+wa|Dd*iwX}#ch(IEju7Z(?*XZ^1JA2`;@%hFr?y-z&V1%9fjm!G z4>BNc`+rKfr6)nLN+MG*78@vMbU*By{mzjD=HKl3T02pu)B(#x#4A_m!c!$7lW&6O zGgRs#DH708{fWSX1I+D@>rMA6AJPR@^T^-?<)bCUvDkFhhy|A$JKHn5r7@tdx#ZuB zY%3bsfhQ|9v%O{N_PjGrlMayNB-{S*J~TWj*OxweU25M0*HNmx{*Ic}0PW#_W6tHV z1GlnHORTUNUF}buaPOQjDNW<}a@l!now>~P=Hg2^`Fm}xed8SQ+j+3tz8hWnGYi3J zqA+QcsTQNJLd1EVfxXVu?w03@&>D})y($}d$c(})Y*Z$`e}FtWw`LYvI*wVbyYV6G zKR_Mui2~@!ajSWBpf``td8lQ@9igc3o5*fm+h$b>EWFc1V#79m1g#R@<=&uwKi%2m z;c>!{f7qf{b=!_Fp%r2^Jh7oQGHCz_cxtQ4F2Fq!BSKYn*jp+pkSmj+1u1#b*as4mLhnOinhcfMzt{R3M5K!zf&*@NeoT%^|JuSMM4 zT#d8~GEsjpYlTC*@WXE7WbB(HAyMg+V{BmUF=^_ zOyCfSUV{1n5igAeM{Bp+M1GEq=28};y4j49k;W)~M2P+weR0@CZL6hG0L`@T+wUluv8d~DkaVmcy`=g|@xU9N z@@?{O8S8U+fdj-fZ2VsL%5qq3GfX=oIb>fQxm&14<%DD^(B|+lgyNNcjyJXe=l#ce z(~;SIR!H^+q=_h(9mDvV+4W0Kc^!WbppnTlzg0>KJ2YoC;sdJG&&mlxQ_O#e81+sg zZRJz(Yw6;_aM%MH%3-6QyyZ+@>L8uN*qpMN4xofEj<}^8y0!&CXe z{shc^IF#_C0iF3({Qh)`BR4lb^xmZ3!5?&^tdU5IHZ=G!aOyb7Q7Cj&@P&pTVU$R* zGZ6OXPA^TwS6VXUg=P=)bQ)!4vR5~;icvH?5iV0Fu5DEgaO2p{T>`Jw--Tzkzbhqo z*}Z`X5A=HcsR2z4Tw)f;4^;XF5R5yzvdF^@BRzCH+O=}Ijag5GKAtT!$#fYE&mZav ziQ;w3e;w6oaC49IJnbPvCbXy!kFtdNO+mY|0+?As`yA5R*}XWt@~uBsak2n{r;@Zh zPH(Y##eXi)YYAYLJ z&ii4j1;Q6*F}O|ydStyPcU}YfQn9{~TuJiQ{<#z&uErk5m8{~6;lj7>dZ!uH4JEeo z!ME>hffRjvnl3pX)G(m$-PIx1_LIBr|GscWb*YcQaZwX}hAT+<88K zk-WNugjDV@7i2*LK})KXP?%IW^KxY65JcbOPsajZdDv}iI(|J-RwJwyxBO1Wv42dh z#4h)y_zq4m5l1Aw9&}YTRa5PUh>-DwC8Zy;?*C$YCU+V7>jiZfoc@z5n|2vP0^g|+ z?cc8H(lei={I-l<&p9_9GO zdV!|_;n#~M^Q&#z7ox{|4!*ZDSdXH|@~xJj;AMlL->pG~tP2*F%tEmofOADZ{0yJ2 z(EVQIUmZxaG%L@pwtY(i$&Oe3Ob}Fn`B4{A)L?A%o}7 zlY$FV`$`a#{Z2U&Vd`wydkC5WW0JRiotbPDdC#6;J{VcH2lH9;84yLAY|=tQpk9l< zI`V_ZsSNWCzw!t-E0{c4mBh|pfLAx14mfxGdPiHcwh~o)MaHFwU_|5idAbWhcPqMd zjhn%M$0*n&oE~6gDZ(y%p0;b-YEN#)r_ijb`{b8XV*JcF9A~UdJ-@V+PM9o0zeat&FT#d+(~)rnR&CpBQ?xoGIlQML94dldp0}^ z@laQ^pyDwmgPh)lXnHKl5}bkhjkA|x<3ygSf_Ghhm3D|vZF&n?Do;)!;JX5^Ngj;F z6(Pxkr5NX`QY{5)nw}fW+Bg$jEb@6<;GY%gv!(?1#hI|d({(H-c%#x&rmBa70^0_Z zQwoNimBw6$%`1dRrKPIRIJ0yW%(q3*xM;o+t4WmiMnj)92x;wSkY{zc z2-e_*!QLNu_E2eWJ^!`6bwhpH5%kPRC?Pl}VEl<7#A4rZ+kHuy+W6k@968_x?v47- z0_E9k^B<9|V2CExWvq{f`&fPnTkG=h4`+bfC93jwe;(=4?1K4NOu&^%ky_b60hB19 zdXMb|-(9dA9#0ezE7liwgZW*km_INd&deh661wI9jKZ>fM59FL4DzS2Pe_8LR*R35 z$jgv`Stq-p4-^YJQT)0%GZ}jc%x1$qE3)C!1)Gp3z0?=f^_APxz zp=mDjyIMk9xr<NJ4D@~!TH%hfYdeEB3 zWNMq%qp26I$qG=J)nVU_?NNO%yAy`-HD-Ccz&Sm?5RLL1qv0ZH`Bg8^C=04eJLuuG z>l5YUl}?Gna^um~{#NG!+fOE|fuJ=cW^i zM6#5_LYsU6GbZ2X;WGO>5uJP7tGh|f)&R!{Sm~29+HD=Boh}6Mfiz@PdkvEjh*4?? z5i+0z20!AG{TlGQ0;@i2M-0VsmYmW=H_FGl(`&PioJr>*ewYyvsQ~eUFboCZ#z&HbU4FJ6CBE=q1H+rHnDRO<8fa(tXD?V zGBmE$H8Nr#eV!02U>M(CsMiNW9%`;$8_o1>MD37!t`)4Ky1d zr)p3_SfC*Mj+eH*LZ2}5Chg6oUi@?`FaDfNHOLi~_Fr`E(^D}d{;Tf_BGZ4(!`Qs2 zpttIVI-JkJK0dlrE5!wr971x)3HsrcL}yB*aADVd8=zWI52h;u^HL_MC`*iD*@uCP zTDN%LqY_x97$~ejM{Ug6R;tJBW2RLWArN8^Q&o)f5%$Eu-0A3k(0zUvzE1E`{{Go3 z2^S-xYsS14p=&xmo!)Sv4(BPEON3c^h!M%;sY?=H7ojvQx*e_eR+GgIKy6&^26D}> zmjDk0Rar2sS;&gYi5153YE~@Lar3f{St5TnCVHYEt;Mgw#uc6PI7p#BiZCa7X)~sM z0uUThFI;M!gJm?lNmOHYE63~en5#DTs@~Xk=<+`@aTz$0T6#~hDsJjA-e`U24QYTp zbdA;LtwPuQIV~0ABL)%R0N>6z=#=ze`=a~@SgeY=yz?R7bFw6H&$3ekr&wQjR^NXu zmJZdZn&|)n=_JNQ61zKRkKXb?^>+mQC!i?auuo;&T76_StOU*1_UOHpbd|RHh9sF#<=BA@2>~euycpqd1$I==o5V(L(p@V=IYNsU=#OJI z3#(wyatKD5tAp5gxZ?>Hd{%1UK@4w4YHoi&M^_ho0weIfC$?GC@3~U#9;vZ~6&P+* zWoyb(eAmG0ye4rwP^zY8ahY*4$P-ET#xfVZWGtrR)peWG6Dcfx3a}|BOL6WZ37SM$ zErkJLxqc63NfcO|!~QTiPY zQ}}}?rhW;B<}v&dL8gC-caA2g8Xm^UWw$N2SPhw2KIs;QPrTA9U5bx*MFThWu^an| zLbv(O_84zmQBZ$iGee*6q2devCz)J$Bq6YbPGnhBaYyS80)~BD68XGou#zo9ftDmF zGQN^-^9^6_TVyWD^m;=B8yT4r;atR4?3zf|sIySp_)NB+=X5fp{TV^O19wQ)?1pc- zyONutywYmvL~k00^<^K@otd~64+^`grtmo$SW|sF)>ERl1d3Eit3``5ZzQkG!SyyY zQKHJn%^%|qrGPG#ihv$GIWGwY7k`>yIi-{W<%uq&$nD>F ziJoQQccdV>lF-7$rcdu`mTj2QNRC#o)hwv5#%SV6dq=MZvz7?|=>hy@HX0Wf7caU{ zCynxUHd`O)=dIn`+&J#^Ltk6aF(?3a_4q>|?svvw1mSE&d@LFbBBxk!-9F~3uP*J` za^GjV`W~`>^==BLJ`Gq1T9f}Di_{?oJqSJpKzMEh6M~K}Js-ey*?bJy*Zns(If=9IRh*b{>YXuCMEi~#%|Y%udN=cVS%($DS;l_)8Yf_MZw$A zfeMsSunA`@{#!0S52l8l27g4`X;gjCp@Z#rZk7m*0xzjhNkZL1T>(axjxj!aWw%AQ>qr^Z~0$hPVTq-(p2Gj}=F+w)a= zRAX~HG3jJ;yu!FX?s?m{R4cq5R7;I(AHU!9C+3c`utF#1V>p6B+7UB-FqAWcuud=g z%7WBOWm#iIaYvkAN?3EYP>ek|2P629Pv*@$9HLN`k85*XWDV%-2`K%(nt?`-NlM2d zcJ6r`nf4wHiXWw}M>|Bp=0~O;Jiy zd1H1rA-Gqz80m+Klwe$e*flIrO2{=#sG$;Qg1j7Ddgbdi#1n{7F|suVONRSYD?`F( z%>cGXFbZe>xI@9GTcxiE`YUNc?OphKIUprNz0Oyn9Qr1vpc>HE$g ze<;}STBAiJA3bcG5lkOy@-S&S#eIuIXRo4p@E(u9sN}RFs<7O01*KtoMdUtuntwj7 ztPMiL?d8CZxWj9E7EK~3^{KKr!u79#2Kr2aH5vYh7V~CjP^ZflhR?IIK|RiLa)iaD zNm%-_a3^Y&(po2M2%-V2K8I^jwcG~Y7k}I%`_@UOF2+=yZ|w%V;B zPYWf*Mup>N#HR3p?`yK+Y;XnNnDb5>#+qC=k}bJaihl#I%+6yExs#Wef0)$G25{*i zbEtZlAMoi5G8hH;(~tQqst_I*{`8eA4o2nVifZg*nvU|FklEWSHWt;2?;5hJit##at&`boF74+2u`BQOF8nwV~EpZ zG0Vovzzy4Eclj>}k{ZYbv8W~GiZkPXk0;>$LR1x{?eNx*MpsQ;6QOBI?~0`(q#xJr zXL7!91kb#$7w=Pi7Ml(2R5wlv557_$%g_<}^|d_z3v?RzQY{Kr%SvFm zxsFh19+hUq*){x(KT&tB?`P)0E@HEIGT2>P!s`u*r$VwuDC-BU-<| zPe{8e)D+0mu7T@7-aY*~rO&6!j6lkW5Tp)GGdNX{Q-|HS1d1nvMithyv(s~PM9|n< zB}2r=TSLQ$Z6-a3!xn0UB_Prj4c<7k5TSlj*oVIE;Yq|L_W-baaacgPB&^RAfHilq zREt8;M{uKGRIVfBwSj=i+R%ui*v0w|NHzKT>p!so>E97Ph~600L?pcYXgvIwl zG)zBORVd7ca21rwwH>zfuu$mj78x8}MhM!*F^6Lw0q4tVQ}S%2rQ~J>HviT6j+m)p zZZwbf7u+zpg_zTJK}Wy$rtoJtxBN|E@PRaQB(AD*X4&AA0J#i|g}!#A?(4H4sVaE# z>EN^*=fQR^HvQvN$UZ~pH9#Q3;XHzc12ijA9WsBLseatZE(_T&#om>mn6NTrRdm;p zZQTADR6Fqybb)P?Cg@Nn0UZaCKXf`%>mY}fyTjeEW}8jBdd5E3i&cGJGMkX36p?rQ zbH|fS{iG-&!KXE8%mM;njv(X&O0>O{gi!FiwTPgg?4<%LF^dW@yNU@o%ruq3q}&*0 zEzH2i?EWXkjc&<1XxtEj-iVZwx4XA@-J&tHn9yYf z4k;G3jePKCMs**KfH<=)94kRzNJuM4$6u;Dia6UD!@(4uU#fP%*1AaW%|Lh`jh?yU zehvIeqMim|c@0`q)*c3#@&S&2Z+a;he+hs4NrL(GB6Y zn)cWOg;P;RFxj_DyUIKl1DYxn#y9&?KiF+}*LAJ_NQqo!CQrS-ed|3IMs(%>}y^ zGscv-9Px1}7`B8mAbopP`VXrD10#Re)*m`v1WipJ)QW0a_0?U$?NLlefP3>sY6uQy zZ>oIoMh!Q{6r=>7IK(qp%1&30bx+=T{`|(xR7+IOXG{(VhNInG=u<1f#j%GR-3?Wy zq!QEBV4Sa{KcWEG8CyJr#csC*s=D!8d9it9yW{cul0J^-2J?3k4%%AQ?6)Y@e|*95 zelb*{An6oDFI*d57!d7dw&4rgg}p+wjcGu2wY?=7XaIVQ&`pYfV|(GuB78_Wu9n;Z z|2HQOo>M(@7meKaOK4Te4wOOogsE;>$?#7*-awNsU&2EOxuZQB_MK`Pe8~|_ln}>5 z(kbDJz&pWENa>>`=9QUw)QW_;%n*jLb}ze9mASU!rO&iKe>y~tyySxbMUqKSJ~ADi z8K*r_ADiji>i$oW5s#LSboT32=*<{Sf@z$H`o4txflLdK7?0{MkN*7vYy ziN#y41)QdWyx=I|UNbY*h!;Iy*2s)9NMH8GpqY6;tuQ#ZgNfc7hI&=?)hR8>c2S;@ ziHc=+C(MiO_x%hXb%Cc!7?&c5ZV}DvW4)=5C*_1}L~Mk?hy5@cKD9N)j8EI)Hn^Fj zGgs8^^ms{U>0UNKWRr_7Q@{Yj@DkJ1Mj}(A@8}1>JVxYWPU#m>pwaD#+f?5UHLVTo zXyPF0TX9qHkqX7zAK7E@c}0s(dFX8W)wWnJ4q?WyI$)txm~jV;PxV*5#+;qu%joTd zQ8eJfO3h7Q6rt!nAONSx&qJ?m)){J`? zg^TFe2lr!{y7#K#1JVCY4uKyo&QVlwoTz%zepvHmeBwnl$-!pMO@>_pEdgnCCV7y@EgvOz}9nUo28`CO$Np6 z&dx4^bzAz!?U%!?LddHIrsWT=OO3I#zDMa7j6?xVfd3{BK7eQDmRcK!VaNQ^7a+aL zQ)oN$$O=hP7~`3~bUc3=v5n@%;Aw1%;q~)rEJV9B3e@2I@?bB%ai9!!|=MGGbLhGH8A6=K7Yv{bx*HN#l0Jp>=d{GQBt)TBH4NU zWmL*Tbx}HnVR5_Bq)|y4jLMS?a}->w5tUZkd9ZOvdc-b0H20SmQh8@5yg^g~k=-jy zB}uNq4NHqBZ43fN+&^ZjUpQXh?W)F#pbm(lL33$PI3b}$@ozm<3vHbV|C!WpE zZzfN@%&)-*0e8rU0W3bd0rDP?-|$f$x zQjRz{4@s&n^^jjWbDrN_>8ic3+V(hy<_``>YbT$P85%+xxHMCGM-{^E>QaFwRt@my zF9yAyG>B=?yY#u^si{3qWU%yC9!mEPepe%IzQc z@K~K7NMT1q26vNX_~cqmVP}irrO&t6HAL}vHfLprvmr*0ygi}tefyX+ej=IMi5p1L z0RRNOiv(0d#dXUoJnlbg{tE1KU_^#`8)-{+(F{gF+j11#CFEL+e`jx?sn%dlgDi z665m!9Lz-;O`GnICiB9TMdSeSib#pglf(<@DjV=A+@}z+s~Qx#VZP0#wAWvBh0+F9 zOy9-F!p0I(y@6s$Xgpfe1;Z9EfeO@zUX|oEV&@P^_|W?_Gy8wV3#Ar)M`MXY$Nn(> z!f201;nfXXRU!5rZ$+-g2G5Zyp=yXNJWFNI!+zj+uyn71^VgIWtqH z5PS3dmM7<6GXoRVHf7TnM2P1LSQrj(U7KWm*yv`qytQcFIMLe>WMo?bVq0MB{Iu0HVrJ@&Z* zGGEr=appq(Br;FSdsX3kI+I5gZgR<(Fpfwv)H)F@p>zm26{9vlE)6vNw`+5goN-a zdU2{a#(t|nO>lyH@P4j<&w>R{R5ZEPWeP0|a5EN!^Irj$Emul$FG`8AP?qB?Xy|cr zH%YNEv$D5jw9lC^P|l-q24X&mFp(;X2^FqD9O^_jHstJRXRMz9K}<9BHGm%1T-R_*U(`@`JqFrpp9~yZt)JKcA3?t`Wmy_+)@t$2+|>o57HpLI8nW8X2k)vkoE+G@v*>)TS$oz$m-|;q77TM5Qe@!^LdiP$u z2@l;IKzze;*D=o%(wQv@P~>pc!^>072nv@`FVu+-y|RzSf|0PBNf4p)E<-u4O1#+k zxru2FuP6Fb-|6m<{M3GkSyE_QCZ<_uHYHBwE8M1k_c(L%BCPYdQ)EgMgiz69mR%Xg z)`M<1VpbdwJVF4rEHC<$y}n>fdW~+8()I<6NE6b12PLC`8Q^V144p*SfaZyIb#RD@Y-i@6@?p>%9@~ZY?A@<&Rm4&HO#<0+EX^tM z?MeDrYMgpNW|wfpnE1>5kp`);>;_|i4ie8EvqP@ z8;?S1i1A(q~O*)dZGqiXIE@4`k8A3vT%MS>)a0(}NTK93`C zt>#5G35=5>CaP`$C|W~jxup*2nzBi7>SyYXo2A}E6*XW;qaz9kvUSrN%VOSz@Co2T zOBcmvTM3PQqlM5`RidWuecsWn&=mL01L~4{miFOz<#}D8#~!hnPO0t*ZDpwxUSa(@ z+{VFw%tkW zE`qIi&4=Z7XOvGq<|mmNemYBqRq*gYIhJ@C`24u)czM zxD`;0>nAU8c-S<)t20~DLi=fQn=?fo8z+QK7^(@gnZS7Rlv4lwXo7_QHVO$!(NxDd zJNb>+po|zviOV1p3C2sRrNxQaDQj&d>#q#+w)L=5c$kkHO$aKuGeID10Rbkd!Nms! zjwkg2<`9Vc&)YjL=3-O6@0=)Hwd--cT2fwArdCwOUNdi3vX6RGmG!Nt@{!?!*sA#M zI|s1y)EVf;{0J|@u52A2{=kt-vBxwIc(<-sJdQb(wYF~GAc!amwjRFWxBK2Wu$_l}lUG)o)J+2jk_3t2g!*V#cp5*l2t1p9Sry1X%9E^D zP9}t;PHBw%H|Yz6TB{uzVWcth^ATuRroAe;Vt2S*+`?pk!>Vj!F7qv|D&5;2GIo-@p392=!x}<@Q^AwqQYPtR}=_Zs~7d-)Y-*7N( zcg9~ax+ zjmLLGdPT7ro&csc;W&k~+AuB0L|C8V7KRqPH8F}@L@TnLLex*uyb2%N_48DA3OL@( z_f7|`#b@hx^h-iN!Vf1_WH~sod@U zuk#rLKr0w!^-hfP%PzvPdgI&-uFxK2nC-iv^$qPbUV^?;&*qha97tU@M28zqNCv_* zvG>Wt8tVtAv*Gh@;!$;-MFs1h=1GDIo1!mhesUqBB3f^X4Nead4Y2hY=+`@>G#qC_RGYe}@!x2s?8(ws{p3=j}Q9yLzD zVxfEa!^EnheE(vUvN_#^kAC*hAo-E$j?1bZb$j@)=8NJ!KDt4(WkM)P-GJkisiqyL z0$B2?!U87#fDQl92ll59S8VHCF41iddG^u{kyT>Nomdp9L8sePNXk&w*n2~PSyP%) z>PXr-lK}Tp*r=$6(y&n}NzB$z$t@HJxDKrJ;SdlgkA$CT4JJQO3`(ih zPm&%hB3I92NIoDK3SO?!&t9l7%0poGAk1;#en!I%sT?QwxLot4Co<^%%#j{+N{g>` z$t~FvK*KC1jmQjcAY*DJNu1%4YI(yb>v-rx5&HId0u%K}2_3S;p zz6KXXi_rJJM}|4GGt<{V0V>l1)%qy6)Buk4-hdFrQkCVoXIZpICSPe`M;O5B+p0id zAS4a#I?e0Jvo->L?mN$ANdQdLpjQ?sTY@z z&q-1XV@Qewv?eYMeK`Xy29khJ4MO2{_tpAcS3Xltr^GBBJqAnwk@<5Y^T)if9i#*B zFDCu0ZDsCRhL|}Si{xs)idWd(f9>5B$2}iM|K1KaAe$?l>!4wkBN(49>90f~n`8lX zGNKQ&Y6qC5_&PNmUVQ&G(u0aUIy=JC*|;Kfa3n0oktMpWJ{kRofmrRdR$@hIB;RJ@ zo5XkyNX+RAJqGu2i&JtoW^DEpt6ShjU(~*b9(HhI3+E1>(Di63S}(U!XsdHasr`(} z*oPMZcs{H{BVNx(MRi{qHK7d6PTbi&xJs?u!#bY)W{Jq1aD-R}u7cN9-4Y4Xh{d}u zxI1K}uq}UNL&xUcEpv_7W2!Db3{$oflBCV1eViq|d1U=L4+B}HwedJ1 z_Ic>C?`>uC8dg&il74ykJf$1w{%tfoN46v_5e-2*4w++)2s8Ryx5n1$ z+Xv%4;X8ci9ji8{_~LV>)-+k=;O&EN;;lhx$O>j| zxUVD~2yrl29fx&oJ8v@2@64szwwui6lB|o{v3AF)G|!<+mnrP2b^-q52bT4>vuv`g zhFvl@9R(7~WQ}Es_(ppRVcK{hI*~IqWhEuF_RX$bq(qpnC`7@XAI?&_w+0t)YdU6r zYu^5t)l%X7Ij75M|Z-nG+gs%w-+uXmXb!REYTs_YBF zyqa8(_L_p*B{E-541f{%AE5E}NZGL*QH!p`>J>B;ChYn~B5;EItzU3uGnC2G5X}@L zsqwAIO-`;;fDKkV53=LmmSv1s+!1g5xZla0+1UU+>?hwcARvS0^K^*9U(L~ zR+>591hRGcaYobuW7D*k)&AWntBO02=;c=@qYRz~)M=sBi~Qg7TPa7!12#@C%d(O} zJd6?uQra?A50s=u(7l)En!BD2wt0XLyA5NB_PqRe%rO1N(&r!ja zf{j>&Y#lln$B#+jt5$KUqzV_A>D)$oA(0shzNbu^S%y>4pb@-$a@NA-v`F+nd=*L@ z($TSqo~}4f9DLyuahAg=ck0w*n8b{<@Q%ep#Jo_X-;IDLXiIocb!ng4^w0=f>8zHK zJWcGe`4kCBEp%C*K2IT81{Rc(jAo0x}0BRqNc{sf8L%x z0L{fvF8!v4j&2w#r0iHO3e)hC1d98$_UDEHbH_YvyFU28MmNX55-&q&^U3 z6Yz(@WtTr5&603{zU~AtbAdXqAipbIhohXj^U1WJ+bfnRNUYc2l!jb-GpTXqWg{0U z-Y@{BWU}#D?9$qF$@OI1FG~JccB++vBE_hRvotiYlOa|rUSB)RMInNeLF*kOG8-lX|2UURaI@7xG|0QAJnjh$3-IL{}|(-7-i4D zm}OoM|7>UFgxRboGt2`)yLhY9ycbUBg0%>&&n)aHnltQ~jank(MWc`|alDgp>)URn zLzox84`(~cV>KJSJ(c1ER$zq5pOfMii*j7L4Iiv8D}c(q5t}8*b;cP95Q3Q<@uOpd zhvrgw_msKhz4;t=6sOU(Xot@d)tKYCO*`0QzJ%j@F8g2a^-+xaFURC)tt@H zvv_qN{n?Q_mSjniCxrbrs#4*7i(BK`pF0o>Ut%-duKbP^kMStS+Vg!P*fYOXc7{Zv ztAwoOn{Zf#_kDV8E92ubSIh5+*s@D2S&HjXg5&^`Q>nI6v#t?~OZDbkKWPvf0Eg~Q zmK3%n`(eS65hdJm+_0*|R-+bE^hKYl1!nNQ|FK5g-0NRclsacy;JAUs?M%UL60oQc}6Pfff^A;=?BO*7zqSq=mA9P z!~s(RSg)SbX*GBbx>qRP(}cs}WEK_{lr$xVm+|lvB*M3?cvCYUtDAy&0zsEZv%rX_ zDR+ILWsCP)oyQDC0LQQQl8<(RBFlKTgUOV$3kKo4l2X2Q*i9%KO@G4olc)G@0gtA( zv&##K7G4>`;kwm@Xu$8<7fTMjC-TXhcNlZncY7P%-&h$J0iN1D6LmT~rt1YS&+44~ zecr0s^#V`^Gda6crWPEQa`EMD1(jN(Vc<)UgE-&Vu?1{TXKyez(rPhQtYP zZsTYv5XR>%tGj42qpW$?xrm84Aex275Jp|8DaQxhb+eMY_it$q{T&FmvZ7` zkF=tzdVG!d68z3J#_;zdt_J(^N6BOv3u=Wd#hSv0hT4GXyUwin;C z*gKHzavMbAkc6TDi<||2fw|q!JsRD2B?6TgTF6COw$>x5upkUxK{90stVA?rk4RPG zn#0YUK<=fE2<`v1_f}DLE=~Vn zf;++4IKiFZ?(XgyHcoJN36kLM?(Xiv-QC^YeaQLFdEcCGZsuavnz{IM#p=~h@9ygA z>Z)ItWONL}S|9EXV_!j|W_$oAe<#H|bG$cmp(YF|vgW5WDi->?`R^WjJka#x z$+D#bO@DR%?{}ZxS9T2XuaQ20?_-6---OceQ9z6wZbF?xls zD{XbB!Qk*XqJ>@z$yM2ZR6!%@AW$tPZ37+qlZ@|+kLcinzkW9gmwtvVg3iCKYTmDe z^Zt@IhJgr?rx$q~e=lGdoQoPKEGvNV0yT?HOepBfO_K2=K`@ljTo`Z;a>~edF~E8M zAd8rtbw75l9SSXsyif7*ycFCO)Yg!$DQR(h;n-L66d3X&fO!@sds)swG;_~(!KifR zf#82O^Ea`5T&U?~L0fnEBJMh=cz@M-kl6_MwnW8y1&Iz;$(xz+J$0sU8sn>Mt~tKp zyh&r#KWJi~uaI5p$Di#{^yBXTYP}o|W~;pU=6>I6OfHHS*K!WW(s~az2)1bZ*YBP3 zDPBbWv71*i>tU}=+y+TH7_ORTHm_RDMajeaBkEzohQewJNj?IpC@XdFY#w>SdG>gH zjje&!WyIL=bGuyxSEw`fEbhz(%8hPTB_T;S8O4nsZ(@zD(dC0okG+Q=?;+3ZOLuJ- zPHW)PW&g{V^!Q-A#uDW3D5$#J*jw6c2qe!;=pyAcv*m!DC(br+3Ab0{pqseVHrn*_8G@pexGmE4HXYZ6% zHxRlCMN|WUf}CxrV3v=aYVaHzz|{2>>7zFOB3P3boc+BcqAAC#*ncU^=VOYLknWR4 zi17Fw2NiAKy66UHbk1=zRMkxW=`RI3d|N>XU7I5K7y z?o9Jq_h_jVf02LX%wouKE#g+-9mN!2=e+Kt@mkNV*YhXH)k(;_D$1b)k+tgKWoqGj z=+$M%4_2|d<=h~JnwJ%?{-TwykxJ{WUfpE6xY4G`I_lX@=z;ZC{zpl$_eb#+`V+tD zFW%$)V7NY>3DffC*&_!Ke09pPc;LyY_cxC}!a%ip_aMA054Z{*uX-UWLTDl3Z>jRM zR?<8g%ibFgblwTIRVs`l_;%ph^2j9ja)EJg64EY>SA}pihnSI(fp7+6KZUt}eu7sg z;2!xdm;WPb>nZ4YLAhfABF2Og?HBEW)$0URVQF2nsiN|2r5GpDft6k4*|ZGzzzWXD zX2)Quy_(L?MAi+CAZ~;2iKR3VH#+pG6yoACfQ=y^v{yp~`(!uP_35tLZGJT)lV7uB zmmT8JrdaX$jr>S)(5xW$fR>mOq$8!A}V47R&` zkKrW3^&2YN>E?tgb|lr=qeE;qY#C#=Q)V&xGo;Y1pJjP)hl} z7YqY%Vfd03W;jc0uf6m1bEa`ho6OA3BTyL|+U_0g#h=$4{ob%H;=Su0;8s^00fD(Iu$Hr@;Xr-}%1rw6|8D5} zoof#}JjN$0a$r9zwat5h(XU&Dkt>X!)g~$eJRHls+?pyl#!q@=E0FE*(1xwpnP6Bj z%fxOvv^`#_M{HkSLGSNvJp56<#YtyKxSIiQ)lQeK3b`n!>;ld#ZUpQD&zHi|3yCX* zYJ0$#ui`+w(=7kxwYhg+y1a+cY>20~>dK{3hc3$%1=bwW4bWT_y?HgbKP>$g6lt2_ zA_-5gh39$-939hjX$Q;gw4`U!rZ2vhw|G6Rzp#Jfygz7nwyBVa%E00DgEdUFM(Yu9 z(8rfaYyD1#P4a6*Gr-?Gs)C{r5b)DTNZVY{t&alGDkYfQEhEUzGJ<)QW^6D@NOZyU zdJ`=%T|>h^T1Df0`jlKbX^*b$=H6Q!6HX>S2B{ zU*8_U5D1o!yaDIfxKW6wW8S>7S%2mn}x~-vX)ES>#4!JBMRU*F` zk?xMdG0ZBm4Ka%!M(VUo@I&k;pUNcw&Eix9G5 z5E*J?c{ZH8Tn{dCUk^?5LpSi;FFf6kaH7q>^~&l4j{R@2h5H+4gHCDV!CZ{CxvOD< z;|z)BFku}QB=4h__s)gl!7!Ulx`lMS_nvb%;8NMgMF)a3;sDUd9rw*1CRTu^u>{kI z_6TMTWW6R0&T-PCnHGl33$rVj6s~%((SU(;uiecT@(2e#!9a#HyHqY#$cIL={l(NE zRt?}~&TtzJk6`X>2Oc(Jb_+tikjRde-q9EMTN0Abo;~TC6Hm4mdTlVfL6q(U7^yK1 zMy$>GeOm&W=Gi5@SA;t5=)sEoHP8r}EH&W8=fj)4A80W~?^v^HSIEqXL~Din>pdGq z$IU+5eKTM;^SXj~Rml_5kIbM7GeJQ?C2~--1zD21c_;2x_v&9x} z`ArT^w&58w&btWWVc8|R&tKp2?@!1?ZRpw1SjOP|q*j(`6j_st z0(#GTc?^}B#T1f`45x@}$3O2VOA7|f9KAxUWL&3G)MeYU|78yTbF&P4ceKD=yW?U^ z$W_9(Kc+WZf6fBCD6S{a$P-^pKN7Ny0keE0?(SWRh+GXXI7Gi5)Tp#92a}*IbuTom z=qLL@#<_8DnYBchtq`SOB|SiY03Eh3E+T9iV%-cTBqYR_{qDseB*6FhqSp4H|BSCY z6bqM*H^5a09J=lgN<$!B;9D*@6})Ss@Phfns*eN>QtrhY?-H0tnb< zz184i@RoOluX>o76ExvUPnY-s3|_w(_0q7gFSosy1S3gQK+Uer1=JV{_vTU~^bU|0H)x{MxK( zkc-VQo;;pT_J?J(ob;QhaDYZJ8qILX5VZYPd(0V8cW0})&j~f8#B>qoQhAnX+>QX< zxTAI3z0R*8qP~hm178C2*j$&2NG`VVQig;28aF?xXWyZ;lmZjD$g_Q1#@77 zOuuXPF*_D*D<@JukkAeVt#&>EQvt-9c_kxDk8xbOq-wPB@ZIU|Mig-xeu`9NJYG{* z#d0kC!(W=Ht_SzGdJuIw-8hTRJsqNk2i*a5rP_hUX_E0%I-PVpg}*RvUQ8^^eEIXV zWb84e(S`cD1!)uoju2JFALF?Tw9dS1%VD%*-Of*KSP@uvJJOh$QXS60#_30;MKwc> zUxUZ!Bt9&Js6f|bibv?rU}Bb#CXiq{LFV@dw6;s;#Un`LpA?nxzlkkOBBkPnW2zI+ z(@CO}aU_+eiLNBtUf=ek$^$BK&*ZquWFu3BI7fekZuJ$z>*oJg$~G*4?;2+0Pm+9Q zabw1NYkU6Hdc%0kW{Z{Yb!X6`p7=dm2Ku^*ZfiSDLrVc|tIdi#6cSG@;A>*CDNA|R zV661LiU(O8{%SC{mx-`!bdhX_cL~%-1$+7p9oPs6(cA8hcmu zrEq!fx!}AV$KU^W`rx?EKzkftk{pUf%-aT*=u#+Fr;#z1^86rPl_zNzeGrj}t5C|? znN|%lfHt?z<^Cy=8V~%jQj!h+ZHi?S@}P(} zD~_~v?Qu^&?~|AOH;dRk$e}uc!P^foTR9e$99mFurN8JTUx|;50ySslX1`_}C|bC^ zU>%=!?XyuFQKDU88?S|NITW3w5ev_TNOiVmp1b?}OI0PIrvv3STuGXc4~kt=WYF$s z>e~HAZpHD_Zg37N{@A?Eot@=vfwk<+7^4-rc(%3^Ya&1eU{@S@h3HQ2?$d;6D9O4h zn?{MfDtZPJRc%+v7Y*g*NNpisl&SQ91t68s_~C#EGEf(Ew7|m~9g^;&>F;%#Gd4F= zkh}(>=}yT2qcIUoOw1uwWhv_~HgbOSP}S%Z0D7UKZa_W&Jf_n9t^|wp%}P8DU7gcO zN#qX1F!K0I;ZX(f0D`Mc!%=@f3N9tz&C+wM2Be#&X0s>1*bpW^#MaXVT$vM_*eTZ* zb6t$GhXXo?rJY>d;P|9qOiFZR5nQd{cx^B4gxv8dQtAGa!WQv(HN5)Dw0jTb^8n)I z#M=Rak{BnJhq6iB@U+dXDXy5{&FaZuDlr@KB~7}R(y-s7Bk}qLl=el3*4cn zkn@U(rHNm@Y;foLk$hAHiF4cW)hv~Hvsp6nzCx8p7|up|@i8oG;T6%2jwd3ACI`t= zZq@7Xm_oRVc_#)B4YqKDt zO#EEWT5X#|&`d<XoWZ88tnx37Yr&kAV0W23VOvdo;P}s^-|Y@dT|GQV z*ZS}-&SgUoN^T}nNaPrb+FKzL1H%|aG)s~lZ52B7_&*s*5mhgPRhT}FClDMCV2#?d znTucAXJ>};d3Zvsk^+U&<&Qg0ZhaM5FT=^I_U^f?R3fTUiYeF86Sl(fA4TJLS12fJ z9c)gJKPUAYs3Ps)vr1zoFBbd*d3gU<4|r%KFF#RZ7P2Zqc<<5hrdp?D&1M+~YpW5= zoSW>RMJ;+WU>lPT$+EWf#Ri_u&K~mC{gs8MAV@$mp5dOohE>efb0;CrRe1X!O{@8h9;o@(55EwNtXC^Y+0RI^E+ zwBv!mfL8LgoxUXp*obCwyoq`PS`{9v@Z-06#88VDecOI?g2`fI4>hl{+uU<}-Rh?z zFxQcMr;X4%l#BH)N>uTT{O2$JKC8zppy?w2vvCQCAgn@aNJvONda@61)}kik=%*>o zPqmiNmogjcvN~O}b-)zKhqL=|Iw0Xlo<-9NkuHY(MKLbhO}6U!N6#SUq3TKoQ*?9c z^fBKkg@``SW+oC;~SaKqn9b7jDSyLu1q7$3ufmB9;J~?ZTi1F&E2tzj>w5 zy{7y9?Rmw4JPv+gD^~v#o&k7w(ZjUO^L8z1H*XtUaa%pIx^2K@wed|tv4^P&(mnlu z&{Fzp5F(#dXCLkTEiyNq^CoM4gZ-dYr89s=p6N^D77T|OWo0QTdh0=tv;B)%3@ZC4 ztI0tF_e&BleY#>$jm3)EO`PFM5o(E~o&)8g_y90OkGWcR3SWfI4|g6kd7*LnF=%i%rx44wLgOh z_fenLiDWfGC#1q}nEo$hHxUJsG0UlXqUC`%iuL=kRjco9($zh3@wv&UZ3}sq!!44R zp)U}*Nm%{>{+t>pk#5ndiZf^O#C9B} z^kz-w4>hCtRF?U`{4w}J4O%NzPOQb2{UiLBqk43+QlyC=2nh~;a(9g+pS}sXEiv2Q zn#pTAz?;gT;5eENhH2P0xQUjMG4Y`o1}Nq^Vf7`iQXJ*Fwpva%xnmw5#6I2elbT9= zpnq({+W-9M!-wlLx*n7!;ve*?AzF zvlN*POL@HDS2!M(`B_t+UGNN{gb1tl$VfqXB*X?Bw+m0o-zCgb4+;fkZ9Gqv&tgs#`84Bbf#3h)h8H~^uy%)7z3^1y+{h=J) zFr)IG@9QyuWt=r2kHm?&wsVS*FeBt=Qpj9B3FP5Uv}(v;sPR4#e+gfsy=yJn&6=Fvsbbxu>FUs86fgT&0^7XJ6AVS1+K2N`1;+98}I{eLnC_`=8+8R5My0ZdfP5EcJd5(1wZd78W-K*?%B8}{=+Ow zsQXdODmvvDEXnX&G>XZ??DdKv6^g8aR+yGbwAU$`4=#D9Zd8WQI#Vk%KO9wI9}Oh+ zDw06>SK*HgQi3DDj`kvA6zMY@=*NE$bGQJtSef#z4|mYRCH?^$m%*)%qT^8rcY9dM z_OyZRoQ+d(CYP4;+}nDkGD?KEgJ>zSL(P3$tVj=L6wVo8p6=x4*D)pZvmE=1$+dZgU*&-8bQ>C zFh{ec_cyXU-InT3yGyPRfknj^zG|g(F$~FpI59x-{IIibb7|pz3$7sFCR-@Rq_4Rt zl5<-#`96o??H!_4v5<#&*a|Ep5v`eFRp|67-%Ju?J2G`aDrfy!x~<^qf{__zU(@Ew zn=Uv>`ptRoQCb>LKCDu>!BZ zsLk?qPRN5|T7A`g<1v$GUk)YQqexkylp5GqH-L|sH+x6A_we0$@NvGw&A7b9>4Tyu z_+&Gc94&4^w%fJatt&6w2{uuvatmMqyPaKW7dx5ld@yuw^&XHVdKGiTIl6Vv@Xz&L zPa!8S?^A6&_VsFaBq%f#-mQKh1?Bdac$;(A^oTW)6C-!6ZQdELcyNa)o)b#bVsRv@ zfk4SZPz7O-NR(Q?YMtTzDBeS~rz~vJn6`kjKcZoHxv=L~!Vq+#Yv%NIK4q%gN0qGW zkB}-t{RJ7aBC<)X`xb@2%6TfbmZCZtM&kk+{Esg7Q65ZeDBA52aa%)gtR3d``U=g| zXnr^|kV3QH(TS)eL#xsPBJa*W0|)6=%M|m^^|fIjCK=A{>m2qsW$+=X(S#GRY3 z&Yc_JJO>MeB#DY{wS9VGzW)*(j3E3Xpc~CK=K#&=m>LmT2}O({^ebb!av{8^*wKDq z9C$Z_Vp6{Br<+!h!RW}0=fc4gK{&oLL7r`JwlU`>rDn(-JbYU&2S^Q^pCNHxWGC;B zmtS**kN0c_B}2v+5i(*z7NNO^H7Z*6Xu;zwLnE;I1|h*z1!$_5rTr#kzGCxyD9GKW zjqKOp3ldXmDm3DVaScvF?wJF|E(2R&|HDwnS&*Km9^pRm;#o1{{c z@5$n#*~ zAH|zC8{I#aYR@>o?K5we(Gyzov!Itz@K>psc7HqYV;8I256Ew%M~hyz58Eahr=zw73s?5*}8zX*Zh`M9DsPGOaC6T4G|M z!ukhO&g7y+TC9)U=6o`F&l}rD9@)C56AVhb<0>kvu$DU-4{#5*zGI)vhX}P2zj_F! z_oe^#Ao#7&Cg6QEtSQrgAQ&7PlGoA-IX*s)#HM=719KUSzx42GA6859*$QAYq6ODx zlv{(gIyk!On41dNH-R6PA8cx&z`+|ZnkQ34pKA*djUy)Na{`2>xA_q5eY^j<{_*)e z1%zQxq<2QXvIxnmH|uR$FXS6UNx#Eqj%uibFfDiEjd|0EQ%3yt=|aDID`f|ADar3& z$S|mMouT5fcH*7uVUl%LgN9E}8tRTfpELEj@w61YX*!ST;h*Fj4xw}&ta)q9xFs-1 z3Dgs9(K!^Wbn_l+6C!F32}|DYG%FNDs6Nv@BcSPed~aX$M2-EzQZg{YSJiEjjVQaK zuf_ff-FD6u7KpDC+Wze7sRwqwxH@Nez30(Fs3;Y>+7)!T5;$b~_AwV6w$d~c-DpJF z{l+Ta#$?Tf$)QX*5RN(&{(5nOwo_jC8<$K^%lEenTfom~n(^jC;Pqkpd3d^3XW!XE zrRRj8TAd@!CY(H*Q^v;u^RvFLH7_XGTsYQ}iKA#%IR|We66}bZ<7nsE)vzJ|GfTdI zd;!j0Xm~uFs8+eufAYE>>T^8-L5@$F&sW#ddh_w|J7dq#`KRpE25k*+-A2iI@Po%} z*x*&DrQ_PCzf)8f9l(vY+CjZSz$3tIIRq~mKKMV^qtwQO`DE^9w#w&L|4MlSW65FK zXnQJ`MMRJSaI1x;5223G$+B#X{lv&xZ`+Y8hNz@7x!I!fjXCt_Z;U78YJta!KWvqv1w~kr< zt|*ibOTYtRQinIn*!>eE|zAZN1|IGP&#f~y1ljujA*Fy-P1a`8kRm$jI z{PnYr`qgZOhB`O;>v;qAgrg0{qmz=}Q6R@L9C28rAiySKN2Rt*fC-JZTF#hqiy7&Ss&pm$AIfMNL3}vXMH61#2AA6cdvyUvIEzk%QKXpYf-xsL|=+2dj_C|3f zI_AG?T8;@NA~}1Qm0#K|3Z5x>m2TD4LOlzML!#=QtV^qrkn|5tpzfW!^RX^MEt&3; zfwcST-{Tg_X9;@~Ar0nkSTDAhjzq4osaUQh_NUt}@^;5pa8ZZbMXSHJF>)3ybpxeVaUf+XNKy5 z?6GYaEkilnU9C=1D)R=!d~xeK?7c^08;>F;G%@B&qz{0viYu<~(rxI!(v9b%;dWVe zHW7WOV&Z6F$R!2u*tO03-MtRlCB2by@N3xr30sOqt@L7_`^>kvT5_^zy%#=Mkd+xh zrgBP1oc^n?4mJg}2#{l8{lnu^lfLwD_va(Zk~sEAmDDI=B4?p4oM<0Iangdan62#x zT<3C9gf{u92Ul#_L8d-*i#dN0UnL2AUrAvWV~#2A=sB{$E1?@Yw(-Ytm-K?bFJ(``n&EO4-eOZV6No%o{0bw z^|Neg!`>g1jGKr!(K3}V>OJ7r{Yqo2hqfuaU;Nv!F593~<1QW*3aYn<_}^}PI;`ul zTt*^VP+@1^4q_fxV}A2Qj3=c7!e|&~Id9+*b|zZVps|?5wgOyHzRKG8-i7f$hH{=L zUt&?C>&;>0L1L$TORva7s+!1Uj3B#c;;bpdfOjVx&X&k~y##+orjL^QV~lcr6e|kG zKLl%t;0qa=W@nPVE7Ba0N5OfD7!uPaBvw32j21uFCVuT2uJVQ^C-hNtfTl2n-!BhBf*5N(^ z5RO;EUZl5J(3H%e$AK?tM6M`!TJ6YQ?q2SCu9`Vf^3|GEAS~ka!1xTIsOayhw=4ux zV@)J(*(J@25GOH!q}Mdd0gy%iTXIO`VU_Ow+C%xy1O=9z#>hx{WNU}a;w7rNLy(V& zbP<`A+6+u0g1iJicDrU4v|`^E=EH;PBo?yI+t*WNldK!ukd|R#GV0a)q*maXZf@Z- zT35i!*T|!vm4dE^jBah$%J>J83geG6Jp9hXWta+4&5{sfDcx})L3qAxPJ#LXiBIk% z`0`owEE043;I1?Chx~X3*swyx$X0X$XodU}0#(My%s*h?w)uF_4B1d0(4FtH+C|ct zqdqOhn0A$(YcmMi`b%w8h|}W)wB~mWQcE z{KXuyBA`2GWQ2jd-RcLOFPPJu`O9~CYl^RY4A1QJiET(4)dOAu`=1uJzRNP!-f8S# z-8259=uZ)4fY}TxNgHm4c5^@du~G+ zA-KQLxWC0B%IOs6l*Us;Gf>9wg^08e`#|IQn0hie6ze{~JEa(y{M3k&lIQe|4lE{i z%Hk4WR~>*+dqvlIc-3_FIJ!704_xh|;t!JYzwSpBGBis;K6X$|?}RcT;|A(e>l%0sv81&=h+y)XWaF~ zMmy@VnJ)YjpNmaP8|ooWf(FhaQm#{ogNmzl^LDR`-Jl1ZTHC=j+*-Qe5RQ&WBa24f z>*_NjFxfpotG9Eh!0JB#O8KATZz;+Ly&H3oB*Dk}hQfV!+}2-a7Pnkf`hIB)5jqFemROF}W>c*A?$uyO=rVV>)s z?tQhS*^~&5XtjR!Ml~x`wV*0Oe8XFMGs5tsn{y>820GOv`6JSaTvTmWbe72H_2$yV z-Dur31BEW3UT>Y<37~&Qy_eQX_|Y;0U;wxN^aFmS;Qn}SzH;t+*Tv8560hU&47x3T zt`s2u;yDWxe|Lta&65rj?gR9yhX*9jG^IMLA%5FX={YcV-N#rWa)-WO=Ih{!(W%@a zCXFmqX?7HRRr3-tkD;1I9PKyq6Xj>}%R|IWvoqQAQC^9}8>Dep&2gfSmaPY_LPb&( z!!6|)YX#gsRP~cO*+s=Onh^~q+&H?8)|XCiC~sPXi8_X^*5AiSlCu!AG#;<|vslz+ z^H|J3;ktk*a~js%razt+NTt$56jo)ujRv%_W(qbs}S zN`*$EXj$D`H!?IXW?X1I^e>!+-f=`6uQE4|A~gu3^% zmqy*vg=f+Oc2PHq;#GK0Uk|VyvY$ju61&!Lyn%mHYLoaM zYwF!03W}V_X>b;%lTTK?I3Es`f;T@ue{4QxL~jAG?{6w>7^*%wc(%dcf}pu_ia9au)^eIvCO%3Fmp)s;Eoy6n4_l z*@5RG=%)A0wGnDeVpp*7-C6gmiD9YgVx5!Cx(UiHd^{C1Gg{>WRm5(@NRKo!apAV4 z$mFI%R>WpYz-4Nnp2UjpGBfshU$43Inc#x#Nh?*CD&pDAt*UwNny4(hB9)J^8QmhC zw#ZH+snUQXcjwCx9yNlNd0fnGrUMf(YG>A$bxnu#ja1w|AY!{-=G*{}tL)Z{@}Q2J z|9+_i-->Zn`0AGhTK#)eRI8}guCyM71r0)THXr@-bYDyJ#d1DXI=A{*)vyIG>u3wQ zi{rUV!uDB#y;(sbb7+*Rrw!}=M==)~`vi^L`cBl;@5i1)5gX@zOr&JPVHRw|Rk?fw zRspuTc%=EDqZYhbJHna@ND2mB(_gy#@B3`kSOMv9+PRO`{y6=XjpB2-c+-A>?f z7nL5YlcaQ&U&)bn-xXREtjos+4~iOm%F!;vBPL}8&iujaK&28*RqCaf?O&MY$i{_= z6Ig{mE#J+1i8L&iu$~{s!~p+#30~B+4rH|*hicFT1iOs(!tND!!8Nhi6RFLLtoiR^ z!DtYrSdmD!4*lHO#KlFz14WeesppK{jSyiJvrY}-4_^N~T@7b+?3<>zxVSKKXxrH{ zfA$quot&JE@u!*c{7&isc&WZ@z04J=!S{NuEU9kPzZj7ovRjt}r&XTYEF1~{g;Xp> zo3bjXUcPl;A`ngN9kF9h6xg}z&Ate&-V~Ub>vlPmFV$xe=Um>EFPtTK%Yyw5eguOg zGOm0xF}cbr*DcJxJZb{4Jb-g9QnaHE%0_yY10!ROL*c)j_p5y9%r(|1ML#6xZovvJ ziH?rsjYdws`!%&37M3R?UX$rZD00hNJ;c~rEou&Xd55L+!7{8AV}lflKu02Ab?u-%KJ0hfw-nDyMXU<(S^PQzzVF zdl{_0L=hX{!8pGizhROC^_2j{G+|5R?P9s9N4l=A0*hD-`xeKc-P@}k8yG`3FOqB&>9Lrzjeu2sgbpp)Jq2HeTuTWoze{^}@t!;%J} zG<f|&EgW{7zOfL zs5dQjKlVxVD0I==_24*;q@1vKDF;_R2{+xd<(Ms+PCj4;{7&sW34AKzUu0f>`kLbE ze_i>o@W^a|4!;`{+V(d)WAVLRtM8 z@e%f}M_>FuaTf_K-c{NHR%bWd6@ASL3skb|<@wJ#Y_Z!^@|T=NnwQ+qMoXgoQnH=;u-Nlkna`tyl&hF#%sphGEYm0z>WC%7Ou4x=sje6 z43Bx8JQUs1%P~fz<2T4%!2FNWesxt@3180#xuHw+iT?9`Yt0D~4S#KU1E@#Yw>jJ` zEgFkI>P_}!(LL;Qm0L%Eg?l8vka&^DS#$ev<^f1iq48&6GkhB~J{P#OT^O2xTR4dP zuZLa&%kOX(5tsN?v8s@~gzAeff5E9S;=+ybGzTYB2Q>?rVdjsqB@eant>1YEJP>4` z7YbhZKJRR)VuWHE9-*|I?P^q4a{c|-)vV*~v#P!JyO_TattNV*p6H(+uu3g>S zkZ^I~Ym?fG#!{|VY>exdLQhXE;o#t;8as};6-l?i|2zN*>>uBYJOp-q*+EK4q(VA# z&j-W8!Wv&#aFGm8UlbbCbOodP!~6Pw9>*7c`>Z4{x}*PNo&GIH)IYtq!}hy_{jc`_ z@A|I?98`M`|3?P@KAL(eU=S~S?U1P_miG3}>(PM-AubgVl%aS5`01OzcP*or)jA~vNC6Qj! zMv^mU(!|Vr+~`(pK`mky0mVm%hx$Z-$048U6G_UVD_E_xNOzeF+=7UUN(|(SCqAu* z>xbD_;R<5IUlfLztk#O}+{R&jL#cNbbC#d2+@dR~h0_rcNzhar={~8lj+#${Bzujort~qZI*n#KuIBG%FWw>-|=g zLTN~?M=EPFxOe8Pus%U17R$&7>tfubN7+g5<_7FbgZ#+<*F1QjFjFq9^Nc=cJ|KTy zY96PIwe630B&D3AA#&2@Hj(M)H?jq(BI%!^m%6xsQ7VQI6NkllSxHqQ;%@}Sz| z!cEqX5}aH*i3n!mB4!5?+xZ$102~G!ZM#qamLK3p6VZ7sK;D4|+%+HNi&5ijfuMWu z`2YhmN)^J{WMeg(T^W|Go3n!rJt;6t@8UBsK!h4472jOQH&6C-f%=Y%@Q#bqUN&8Q z@HmEn&bze`1Xt8C>y}|0YbKbd7$LlLm@ldh_l4&D4gB6ztLd#|b9?j?X*lXrjOn3CisF_TA* zjYfOSy>L9fhfX^-I`fMrX$pE{v~2MmKA|d%3y?3E9p?soqfRTw&%d07`mQ_N4xnVt z==#E1MQsYTL(_DyuV+z#j`f5C4j_K9u?>#WQ8NWuUohiCt2WsZwBt8;l*9bo!m>8A zuxquE7Y2g1L7a%2n7#y!PIRuh;)Rm&cBNgyq!gTr1d9fP1p;PX*w1?;CZ{wlYYti? zd{(brFD?Id9Irr5@+a)i$#vSV@gPKVAMcis^(EK^?9ZS;t#vYJ&m0x*tEzd+Ml)=rbMJkmTXBz$CaKMV+X%p-gXYJ=(t#VYS z^Ec}piP@1e@!1h~qNpY;>+?IZah!TE;kQ$|ixg=3TWyi68LIo0vg`uNb3#f<=!=+a z?6fe5l&CAsUe2|22;+edMV@a|O7Gx*!v!;!Dh~XT9u-FsZPqg`;Mee^K(juq!gg4& z3SCccc{~AK9!71t%EoXS!v5JC;(aeGPXD+B`c#?Xyh9E+nP)qq|Jq2v*}cA!c*Gus zJ6^bzhPQB>r@i(A+!>C-R)xjKFRBO-u6DU3Y6$;8V80c2sd(?vj|K`~F8$P5A&J$l znBK!~SUI$5uM6PL3mtsG$Wcy3^P|w*rC-AOsLgJwn zZ=scz{Hs0VGL1xJ$E(b8CV z5tSoe3mJ4QQcS6Ouo1ZtboX`>EFggkI-z0FrT6*xkxi_c3n-VMU1%h#92Sb~xG*QR zLbIvv_%+ia!>54&cW6cQbs%i*wfAS!M0$HHr^PZ@RY6J`6~Yb_z`5|c~yqzXiLQc(@3!>~kgZe8d)R+K?=``MR zFd%Uo?m1aOJ}zp?6YZ&nI`sCX+cE8#&IzgE7jn^GPEr zZ1#RW-#+h3cr&XGBAH0w{drn4I^dwh_`uy*7|`cBuqS-(u!Nck)ovs<5&fEZ1Z=xibh0WWk44ZtF&lFYEC=wkYN6*!3{0#rf8? zuONdfKl;TadnSi7r3Ye%(`g5u)#(y>rCG=<9BCM~5C=sLqk6m3y_FJ;OylLufP!}B ztk<3Fc^ueT$3{6r5141q4dnA#-^3JSv+s)V^2dN()OXYU(<5cYRc+-hFrX}khk0mjmGbgQiF$1y3MWSR(!o{iC~af-)EIozIQBaI%|X>#*zmse5?McvZV0>xs13U& zkaQV4dB7(vJtaEWEw6TX{o4dGlIcK)O;ya(W5M&DP5lX>4YLV3mYLs%6&TKm1mK?A zmi_PnLiTrFfKs2fYNVSv;LjXcfNJv%O}7UwbAzKN22Ytphi@K8!4n1;i^y5zaJq8T zL$x@A*RCOuXn@_D#9v2izx8|YQy7u(?D&FGtq+ho{j4%mEUFS!i~-$nmo!EyO@;=2 z;6ZsSwVe{4N)lPV0Qh84+Fj{EQ9*f!V*yKSuyFIFNKaka)k6Id%cZor7P_{!%EtXG zLkd7-J6Bgwd51#F8zWB&I)Vf+2kZj4K`jJGq;SiBR1Swksc;&#ia}&FXJz3F%fbffhOsDfDRj<&y z>4E+MdP2fc@`W!}zb;(UGYnI8#C#S;IrlMV!N`%z}IDhL|#=oiHK5w z>w3g+%1d)wcNlK@W^HK|nlA}+MXSKT3wA{6GT4)tqZ~=Ju`5AzzE{hYp__lj-Er;E zEzCjxa>Yk%RZKaP#?RTlx_WE3634u*@N2F&gbVdnxPzaS8Xgxo=iACrcu%4&XsTKT zEEho4UblaCBymk`DkQj{ussIrZl>xwY^kz@reuja#iI={(6bRGkF5zPzUyn?OgaL8 zniuR8p9+b^2Shs+0HG2ygbSainEOztq5Qbvg_H3ESXtn)L~&Bg@wyiq+|`O=`$xkX z*kHeYl_DpPqlh}7T%gBwezqZyVNtH{2lxn4G&!q9$FIw~a64WfWvAsvO|Y5^AjOqo zeJ9-?OY8BhCDw8+8|FL&az1cM#zwJ9;9@nHh|6b5=PVHa_ycD#iN z&ogy0@RDiy`1#@#Fi)?Y7Z67qCA~Tm6kd~ke8Ho3cx^Ie^m)Z1$~5s{998)1OvXoO zRqbpRsWER+y{un{W?(*b=72#Tq-^Q3t6#vA?jf z)!gW5Xe^GiPCcKmzxdVT{sl_Lrlp02^S)w&g8F<^|Ci)yAOok>Zu;KaD*`k!5-7)) z5Vw^TsF?id6A%Dl@96k-B1@Pa%TRs;H7s*DSFyo6|3BWxe^b3<8U0%lSiM^0|_5B|Z* z{_Y^9{*K_p3^;%MU*j~=yoV83)+0)a{=pc(ZK^?#Lkita*nbV<13dwhDbYOH{}woDAe_;am#kKm7wk8+xt!Tn+~ZONW1%|~H8>4@)PAN5Km5U%yz zy}^GDO#cGn*zECWHORR-1M&{bVuczFI=mCgkU{59=*1@yNe+Y?!i~|ut$ZbRtMg7H zxVr66d7jbHg7N;@S#kne&cEn;%KT2=|NnPy*z(a466$UdH3I*~SMKla8_w&%MZ7ku zuKK@O=x+Rav!L8z>npG;KOO$ps&hI@AYGlRs@z%r*RH$quZKan;;b}dG+`e7nY!XV z#ZO&F2&60Au2Hl21J|GWo7}n%M#2Rj9S*%;yEUbI=)bIljE-xl*n2@5k)!?3tOfJ7@Pf&rGdJuv_PAcZQ)X+F$@4-!U*|1h>C z`qBXa)Xh-2H`<<=`&nN+m95qWq+FnEKv`{d-Nk~4kYo^dMAKfsuR%Tc`$EvG#zLLi z%WW0=cf3X=+O6(Jdu*i+eMM`aSB6wZI=fHGG~%XT#+k)KEjMrOXyg87rV+VVj?Q6D z#j}fCM$=AxmpwYRPL@09q4BJ^*nvET{v_mt(=mME(yRDpz`!ojZdU9-hEn_ZAp%J@ zg#x77%8Is3taL6%N=mFufmhsn1F*Pc5k1==s_d#W-*5IfO48>mxS;1iI$wJA!%p;V zRAk24na$_*@N+A1hyu!h^2p*3>$H{jXIo9bo0tg|nFGzz2TPtWG?XW3SEYrpGdpm~ zwYMv~=->k zH}Grt2vGxVe0o<*kpJWW+J_hH0i?{>ipI{ijLk5LmnQe5rMtPPh|dwi+x{Ee3}Xl zP>IsV1P?R9^v9}?B}~_>*A7-e@gD8}1_-C2Sqs^RyH(y*G5uWP;~8Z6rU-Vr^(gy+ z+a%$k4AxV=$bjr%bHdV1(bG!VV96OBE_Lo^F^Ox6e|5_eGw4i(v&?a7ARIO)^ffTa zWYt0iwjUM@c(hCITx?}I6Q*AF=NS{|NDvS2=-R5(Ka+R&R`s=Rkp=uk*V7J&e?njq z1Yw~P?{Y!T7n~h^(Dvbn?kmCs8(qr9R@{&63=85iLe)<9UdvGqdS)5JkzW{#Cp!We z?X8*brP;_A#X@EZ#H5{}Nh$(Qn$C}LC~&!pi0!VLGbK{w8IkqhN)?e`N!DlVWCqwg zPM>Vr^B9ka52TfWf6h0(9C4i$^{Dw4`i${M_UOt27bUHsj=|w;!|^Ht9=F=TbKiU| zs@K#SpOEVUzoBK(iC;p<7;|K~_+0lmV8AVB zK!DkeIVO1ew5p95H}p@}PYj|-I6T2K3-0R=)b+@u$RiRWRcEspT_La9YzhSt*}!Q zGPZvYVJmdBuvGPLrTLckh2*^6mLTYlbcu(k55yPjvIQA%Ir+9i;eU-VL!m?a0B7E4 znvO(NqUjV-d~yyhvzMik>-^Syn9^clWtmB?HED>q$5%3ykDJ4BJpl11vj-PL-z5d3 zrHZh6$KlQQMh$O4SsQ@dXgax0{K7tS%j<41pc)f{W@3 z=fWvieveG~`uq%kz&vm?zHg0)2|zyG%4Dxh;N>=t^_E9Zq;VT(t=N9uuo)ErQ>)(C zuj#FXl%xu8>uQx~3!Yt=|7wWxNOc)L#>_o#5N-I(xm!!p46|d8Tw6=?&$sKSm*5Vj zS;L=nTy1$g~{Wi6uKV0$ZFL2=~Eo!-VbM*2}Ns2nym z%obAzfpVVF?{M+BXL}6(jZEIPmyceiw{zdc{;K*k!8yqfw!h9Wr}J;)Y^T@ftnc;+ zIBv}3{?YD|XvQFXd|vda$XJQpc}uj@b|2_arI|hJ?xQ-I0NwkWHM#?(C>LG#c3)mv zwQ2urJne{#(M#)KN~fpVJF3BHEM*!>UB?&ez~0weZu=Mpyq=B}!qLBeQAc?%^E+t6 z=k~_@u`i7uvzas3SVKiLsEuMj9o*%Ymk-^29nQRSN5IK>QRy{gZcnE;`3=7dE4lrI zt1h;FgK7I+>Ox=5?bc75aznm=76^-qm{7qDD|S|&!g>^uI6Y(3(p)^&7`)%T2U>Ei zZ!62bVIb!4RISndEXW{|#hS@2M}|wH%A@%oDPm-`P^)wOiuQ88NZV`KboRygfw+!E zw^YIw0Rbp~2b-wT;8QBip|*OVh+W6SY}jz}>iB{!xbALW|f5@b)L z$N6U_H-?`IurHXQ#AIF&%75mbXHzar95Csjk&%b>%+ceU!R6TKlw53;_|bxtA$Ll# zYB9@PVqbr($=Z4SQ+yun(czgAOzC;XP(+$yS~X0-%RCuoESjYM>baehWhnmA@iH^+N4U=M=R50ip;P%#;e?Ol*4MQGd=o~br01hJs+ z&Sa96cZO-gheRuL)eh>H1yf$VI8~$c4EQ)qBZQ{1C7safWK?>g!?g8DSu>%M|9MH9 zjcNt1l@*_to4v5g-g-^RP2dQ5#Kc^{XpbUJ8WqO^LdVxNd5X1|k=b{L@FPk=fJ`X| z5@fPF%H`BZ4v{2uwSCCr=iPDg9|S?AgpY87f@b&))h2g;;^FQhLId$LV)z8iXtZXB zakV7xCBBayH}=piDh=l4ACwqpH{KY-N@NR;OoNnDCKMhsL#AiIm!T);wu1GW70+z+ zE7WCk1~xm?jz-qBHwQS*@7AB{RN|G7NDVBEtYEiZiJ({uPfx3!%_9gH?t{;NJ6wGF z_rTzsy~Oy2Y+RqnY{@c+j_LZG5dYnYV zkG1@g4m+m@V z6qKtv*m>eFoLmt|!T;EDY|wE)-alyCQfyt|V?62-KjnZwmcQ&OTS|?>=autV7I|FhtmK_Bh$J>y z5b$9c8i5$L`loDHo&H@!Z!HBQ%KschpRkHOfN3aD>JzI3N^&hVVcAj#-6lWr%i=6X zO{?vI8zq?FNl!Umrx9r9^QK0bH5hy>#Fne;fPbnc)w{X0ZTBu))p=*Ae3Xj~{Oaqi zY)YLY#{2GWK(+kc;vgQL>$0y``tP~#L%nCN7yEbYytRRer^{n^M+)u1sQ1o3Ymj<= z@4g+A$2n=es8j&WF&-@L(Q?n}!v)fh))GYyaJm=VH{@3pG$@MtgS|FVFgSVjzSXat zf|>EM$qzcjqkC1K^##K#iND6R(~@uB;!U<|9DW~5hd(~q6H9omc4ZuhxUA0UtxE-X z9OFfF7I@N9<~okwxc~M0E*c5nmVr$f*7GGcOeZe#QA}UINavnR@WE`95R|9UwMimL z8>b@SJnnqn*DYQch`-^v@Br`uY|=BR+oTbw)6w4QqZVpiQrBKwkrlX5hiNO>8VSN& zkT(1$6%jer=fvibzal4tu(gB_Mdr=sLBqvfF5yW($jqrfJKtsYmee8;NaZHprzLat{GLB|&HIsf$U!O&b% zM;x!mk2*20M@IybzOx?qSmTG+l93-2z{g&Zfln=t@#rmMo+2-KHbpzo48|atuI>T4 z5xS|m=zFf$V!C$DCYL6_z5?U(z^crCyMQoxGHeS;udP6n_mC<`}j@u8c(^i?t9`Vk$A1k z(xmKC;uP(x(*BzR&}lc=Hz36f_PH6~PoDD0oZs@=@XtWxy2cQN#>l97#4eC<`WI>A zKHg-Rg0?Mq4|4DWs-jjFEO_}n@Vp_f3Zk_oM^kH5Ju%#{K{iZgRKMnhZH&%o)n}cp#X(JkM);lrM z#EIWm?*QPawo)+)yg7*j2vVcnSm&`A?<&YCyhLJ(Xj%Wi#mZ$hHLlY zI$jImiw(}FuM4`-Urj6bFEcaQ6XxJzSu+XD`Ys#<4f4EAr5+FIke&zLoEytw&$%h2 zyIU(He&mvfHK~?&HM=-`7MW^OVHxC&Dfay-?>0el9=PC)@~mwrcvR6xQ6Jkv_MadW z?dmo}cbXcoH~@WFG`70KF)>*I%^u{L>1J=THXFz=(sEUtn16f?DL_*8kR9pbDGEEp zN0cJ(vA5x4oF@?DvLZB|p7+hO_SMrGqyHimG*pS8UrdI56@_sC%K4r}(v@rNf)P_z z=5Dj^nn5x{k2FJLejmiv9ArV2Y)%clTB_~*Pi>YBKfbgHJ((cMPAq;U5_F)(`)TmU zs83u|CJKJw(80AOR)LvBfAz8t<^&JfRU3ZjFVNkY% zT2-%~8K-QqFH$S3R4BYm2>`7sctT!Ik}S5!Zf(y7vP@~LTX(Uu=Zh64#-mo?ojY+E z9QBaX!%YJfL_d{t{kaRfAQ(NXr)}uIpCFMGPYFvEy|Zdo0#M$o{_Szk?W^2B`}sHL z0(p1be1O12z4atjfqNXBEFcW*y`{|(sHixu_OT0_r~aK< zv|q0oN2IS~#{O%o0ai8B%FI@x_4hc6qX~R;X0VcT?&opHQmL`0n*YN((7Tyt_kGgs zLz^T0KMX|5clO{N9d;mOe4*^|d~!}lD^3017;YZub9EB%+{Mc|cxFYdd_U_OAv@yq zO=e%cqfQyZ5kr7Vse3abwO86zt6E;3qwL*tby9CbFn&IR-h6&34JN12?>DOAwY3oZ zZsaymd8HB;Ng-1#pkI~wspquDdifsSS*R@sdmC8aK>&m*W;yBxWF|TTpYuC^buI1U zdB1d(jk+h`O#odffBh1odZ-1v663V+28T)dT(@$|-hrzgCm1h-&IyQsKPonBW5;;* zxUe*Tvlsgo^gNR(W~TD1Q!tG0&|A1L^w&w3qmDI7xj)xy1Sm797)RHR8AW?y1>`$( zmn>|qK7_X*+!hEb=?pJiaU{4hiqO(F1yT~sR$;9o6&G}kK}BY^Y&b^{+cD}Z6GOZZ z)k0^1n!)0b-##E)U^7nJm`<%KSVUv4g^xK(A_o&@VMJa`r*JY*i#s$kh!#XkqwY!9U>*7T+z!+0k5yQEo2vm*~tPF zJ%45&rUNrsT$iVe|M8Y|^|(new&I-|4FEXz5SqekfZQ1r3h*5WSNB_VM$U>o-M@wM zP8NjLvG_)gm+-jPnPW)=`L;WVr;hoMbfL1C%N!E-18$B5iN2q4c5G)!BvJ8VY0h;o z#Xt1jwqc<{|8%R4_3$L)Rv+GkW}=c5&)#8ip5V*LJkjWvO5X*Bb>N5$IS9)LLHIB3 z!ZJh&w_>>KTEZ5h|1h9;wR!SlPbMdG$t6U!D&Z=P>b=QUg+I}*kC0E%dbto2>j+xy z8BOBb-{q_5)xG==6iJ@ZN%O^*va-BOvx}y@!>9!n25(emPBtHX57^~ zJ39kZZRIqRcLGxBPI}fmy*qIH^}2d&r|5@rV3%5|5`$*sn+z+b`gMB<#6aq|8>N%n z2i=Z8gq+Tg8LBvbXgoh+SG*g{9T|r$F=f%?ildzmMSNKb23O%Ok{B<~2Fpn0 z>?Sxrg<6l9XWTL&Tnn>(YJOFJc(`p8CZ zsiKEJ8Pv^WkU-ws6ONypGi(lZ#BgKl*is$&wimzHxDAWF7~NW80UzoYORw^Rs{E1+ z?Ejo<4Kil?bk#kwnpNq-4wT+MeW*n4S^m31<(_PJPJ~szCl2}0%LPE?RplyWOoRRx DYyuMA literal 0 HcmV?d00001 diff --git a/2025R2/thermal-desktop-opentd-for-demo/articles/getting-started/media/2f2bcdeb872649910f747dfa5b80c4fa.png b/2025R2/thermal-desktop-opentd-for-demo/articles/getting-started/media/2f2bcdeb872649910f747dfa5b80c4fa.png new file mode 100644 index 0000000000000000000000000000000000000000..b9af82d469a571f8437b0c6dade609dd44bd1791 GIT binary patch literal 9011 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 literal 0 HcmV?d00001 diff --git a/2025R2/thermal-desktop-opentd-for-demo/articles/getting-started/media/4e8146a507a20e79c517c1fe15f18d47.png b/2025R2/thermal-desktop-opentd-for-demo/articles/getting-started/media/4e8146a507a20e79c517c1fe15f18d47.png new file mode 100644 index 0000000000000000000000000000000000000000..d5a63ee065c5aa8af6febfc93d953b5a226e0262 GIT binary patch literal 11107 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

e&*E-?KF{Uy&>yBy0 zTG>D9l%q`>#ZpSS-kw>3KDEXiAr>_1ja5A@7qv zcp5%i>v`kObKHUEPmQ2Pb-Y)oK=+ih-Ie-ZlLkVrz_!S1Q)?IHM3_uXVxLl_-CUuC zXY{Mm=7zaKRbAVrrSOyP+DdEXh6=B9FY3C&@|^+KN>&jMF1)UTjc)a9_5-DFvXw*> zwyQhl@!wCL#)Xp>%KF9@SuT1=+eS+%sbGw}wJysXL*xwMC*mwP=*e~DanxnZbQcYf zA;0PTCgA5cr^FWZ{I$zgUlRTN{CpGj81os-SF*^4eaT9>staJeD1FV;&boAM^ULPJ z9u@kU1`j`W#fC%dw=QnZX~KPgUxhoD+F1$Rv9LTPC!TNNyzW!_Q*kosl(o1;SFJm@ zVio7A$|u?E3B2B&mZ<&jc2i!1+s~t*4(3Alg{_`X5iygoY3OnwIt>Uo7dl}s|UTWH(u-$5aHolvwIt+ z;vJL>xo=`4CClPl=Fr#tX4bcRCP>W?0CKR+y~MvSbi;bM&UU@EeYntd#_Uzce#Qv zDAe}npvf=r4ihOnBhNP!W>TKn7i(_Zt-Tk>=JTF%I%Yw_{hQZ8n|2`<#WFbXfiEE* zH=Xva$|Cg++rurR2xL2Kgk0AEZ&;`Ve|~sGx%G6-gE64~l%01O;)4HCPYx$Tdq9+@)nSF!C^ zNnhi}+i=F|`@Imkn#5+9wcu@lOrEbj7q;jQ=idZJrCx%DQ4R1H?OYdQnu za9P#sXw~ht63uTO7|H!*wi74Dz}zmrkm?p#PfctOKN$ROxFYWHJN;c$w6NZ=ac(-( zC+oJ zwjcKNucn8ywpS8h3QrhW?i^aa#+fuFny;fKfAdf`qgucbE%d6ue1D=TM*G8xX%Jhh z@Jn*>G~1kMNx~|SR#ie3M-?^D$xMx%H`Y|?)&WH*W2~0V^C35{l`ufN4yEOKWAE)^ z60?BMyxUXNw-f zs%Q@UR&^}}V=qD?)NXZU2rqESvK6KMUPbk8x?!NQRMJG{pB$%2VVIgg`xlb0W?TLt zIh}~I(*caO^MqJRKRu`??{fVENl$d=f!nGO;oV-()lSBLq5S{IO>~99WDDA)e51u0 znb8v>OHFsjTAAX8IhR(<^+;>u=>i9X^PO{98yUUEwB0wp>0c|MZk)_@C#8<>vCL4X z8n_}v-KZvWe*72AN9I4euF=-AQ;W%MBAd=H$e3;ih=(pli>$fjl@*3atD^vGM&EQ@ zCake)DoqLdc?nr9u<26QMPvT2=*|bW9V{G=5v@NsEW=Q@_cmDHCMLaArmtZMGZvZ{ z9orD&sPnWxOUkE{S+`Kvt<(10Co*+KjbSp+Ydv_i_n=Px-!}=mh%4`3)*WmgKo?~iN{U7h zExuwBaW}8nefzKA_A@v!(em!=D5YO6%eN#|EmzuhYCMed__U{58Wl+|>oPtxP4=bKBD&gS&)6avYPRo-=eCx3 zmmu#QOH)jR43C<6lxP!}5{=%VWJu;P(CE`|@B&>84N zwF%gS%rx%SY06|n(|Y=^yNcfb0YMEA@jt26JNyyMpGRSG2A*DmfG;UAdC_uV!=V2K DDZ?tL literal 0 HcmV?d00001 diff --git a/2025R2/thermal-desktop-opentd-for-demo/articles/getting-started/media/b81c03156e87978bef43d64eefb85d01.png b/2025R2/thermal-desktop-opentd-for-demo/articles/getting-started/media/b81c03156e87978bef43d64eefb85d01.png new file mode 100644 index 0000000000000000000000000000000000000000..f03624626bfcd89112b9d616569a47b5bdc5fb9b GIT binary patch literal 4942 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 literal 0 HcmV?d00001 diff --git a/2025R2/thermal-desktop-opentd-for-demo/articles/getting-started/media/d47e44c0a654c0607631af3cacc32f6a.png b/2025R2/thermal-desktop-opentd-for-demo/articles/getting-started/media/d47e44c0a654c0607631af3cacc32f6a.png new file mode 100644 index 0000000000000000000000000000000000000000..59b81e77cfb8dc1c2fb489fcfe43663e6f425d0b GIT binary patch literal 3975 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 literal 0 HcmV?d00001 diff --git a/2025R2/thermal-desktop-opentd-for-demo/articles/getting-started/modifying-td-models.md b/2025R2/thermal-desktop-opentd-for-demo/articles/getting-started/modifying-td-models.md new file mode 100644 index 0000000000..6c263333c9 --- /dev/null +++ b/2025R2/thermal-desktop-opentd-for-demo/articles/getting-started/modifying-td-models.md @@ -0,0 +1,225 @@ +# Modifying TD models + +So far, you have seen how to create new entities in TD, but OpenTD can also be used to query existing models and modify their contents. For most entity types, there is a ThermalDesktop method to get all items of that type in the model, and a method to get a specific item. For example, *GetNodes()* returns a list of all Nodes, and *GetNode(string handle)* returns a specific node if you know its AutoCAD handle. (See the [Work with connections, handles, markers, and domains section](creating-td-model/connections-handles-markers-domains.md)) It is often convenient to use the *LINQ Single* or *Where* methods to search a returned list of entities to find the items that meet some criteria. For example, to find all the arithmetic nodes on layer “sheet”, you could do something like this: + +```c# +var arithmeticNodes = td.GetNodes().Where +(x =\> x.NodeType == RcNodeData.NodeTypes.ARITHMETIC +&& x.Layer == “sheet”); +``` + +The variable `arithmeticNodes` would now be an `*IEnumerable\*` containing all of the arithmetic nodes on layer “sheet”. + +**Note**: You can use foreach to iterate over the elements of an `IEnumerable`, just like a List. Or you can convert the `IEnumerable` to a List using the `ToList()` method. + +Another useful LINQ technique is to use the `*Select*` method to extract a related list from an input list. For example, the following line creates an `IEnumerable\` containing the handles of all of the nodes returned by `GetNodes()`: + +```c# +var nodeHandles = td.GetNodes().Select(x =\> x.Handle); +``` + +To delete any item with an AutoCAD handle, use the `*ThermalDesktop.DeleteEntity*` method. For items without handles, there are specialized delete methods such as `ThermalDesktop.DeleteSymbol*`, which accepts the name of the symbol to delete. + +The following examples demonstrate querying, modifying and deleting entities in a model. + +## Query and edit a model + +Here is a program that demonstrates how to query a model and make simple edits. For the purposes of this program, we will first create a model and then query it, but the model could have been created by any means, including the GUI. The query techniques are the same. + +```c# +using System; +using System.Collections.Generic; +using System.Linq; +using OpenTDv242; + +namespace OpenTDv242GettingStarted +{ + class QueryModel + { + public static void Main(string[] args) + { + var td = new ThermalDesktop(); + td.Connect(); + Console.WriteLine("Creating a simple model..."); + var barNodes = new List(); + for (int i = 0; i < 10; ++i) + { + var n = td.CreateNode(); + n.Submodel = "bar"; + n.Id = i + 1; + n.Origin = new Point3d(0.01 * i, 1, 0); + n.Update(); + barNodes.Add(n); + } + for (int i = 0; i < barNodes.Count - 1; ++i) + { + var c = td.CreateConductor(barNodes[i], barNodes[i + 1]); + c.Submodel = "bar"; + c.Id = 100 * (i + 1); + c.Update(); + } + var roomAir = td.CreateNode(); + roomAir.Submodel = "room"; + roomAir.NodeType = RcNodeData.NodeTypes.BOUNDARY; + roomAir.Origin = new Point3d(0.055, 1.1, 0); + roomAir.InitialTemp = 300; + roomAir.Update(); + var barConnections = new List(); + foreach (Node n in barNodes) + barConnections.Add(new Connection(n)); + var convection = td.CreateConductor(roomAir, barConnections); + convection.Value = 1; + convection.Submodel = "room"; + convection.Id = 33; + convection.Update(); + td.ZoomExtents(); + Console.WriteLine("Get all nodes in model..."); + var allNodes = td.GetNodes(); + foreach (Node n in allNodes) + Console.WriteLine(" " + n); + Console.WriteLine("Edit node BAR.3..."); + try + { + var bar3 = allNodes.Single(x => x.Submodel == "BAR" && x.Id == 3); + Console.WriteLine(" Found it. Editing..."); + bar3.Comment = "This node was edited by OpenTD."; + bar3.Update(); + } + catch (Exception ex) + { + Console.WriteLine("Problem getting or editing BAR.3: " + ex.Message); + } + Console.WriteLine("Find all boundary nodes..."); + var boundaryNodes = allNodes.Where(x => x.NodeType == RcNodeData.NodeTypes.BOUNDARY); + foreach (Node n in boundaryNodes) + Console.WriteLine(" " + n); + Console.WriteLine("Get the nodes connected to each conductor..."); + var nodesInConductor = new Dictionary>(); + foreach (Conductor c in td.GetConductors()) + { + try + { + var nodes = new List(); + foreach (Connection conn in c.From) + nodes.Add(allNodes.Single(n => n.Handle == conn.Handle)); + foreach (Connection conn in c.To) + nodes.Add(allNodes.Single(n => n.Handle == conn.Handle)); + nodesInConductor.Add(c, nodes); + } + catch (Exception ex) + { + Console.WriteLine("Problem getting nodes for {0}: {1}", c, ex.Message); + } + } + foreach (Conductor c in nodesInConductor.Keys) + { + Console.WriteLine(" " + c + " is connected to:"); + foreach (Node n in nodesInConductor[c]) + Console.WriteLine(" " + n); + } + Console.WriteLine("Try to get a symbol that doesn't exist..."); + var thicknessSymbol = td.GetSymbols().Where(x => x.Name == "thickness"); + int count = thicknessSymbol.Count(); + if (count == 0) + Console.WriteLine(" There was no symbol named 'thickness'."); + else + Console.WriteLine(" Found {0} symbol(s) named 'thickness'.", count); + } + } +} +``` + +## Query and edit finite elements + +As mentioned previously in the [Additional information on positioning entities using BaseTrans and LocalTrans](creating-td-model/basetrans-and-localtrans.md) section, if you want to edit a mesh created by an FEMeshImporter, you will first have to get the objects representing the actual nodes and elements. Editing the FEMeshImporter directly only offers limited functionality. This is demonstrated in the following program: + +```c# +using System; +using System.Linq; +using OpenTDv242; +using OpenTDv242.RadCAD.FEM; +namespace OpenTDv242GettingStarted +{ + class QueryAndEditFiniteElements + { + public static void Main(string[] args) + { + var td = new ThermalDesktop(); + td.Connect(); + // First we'll create a mesh using an FEMeshImporter: + var meshImporter = td.CreateFEMeshImporter("a mesh importer", false); + var feMesh = new OpenTDv242.RadCAD.FEModel.FEMesh(); + int uDiv = 3; + int vDiv = 3; + double height = 0.5; + double xPeriods = 2.0; + double yPeriods = 1.0; + double xLen = 5.0; + double yLen = 3.0; + int id = 0; + int elemId = 0; + for (int j = 0; j \< vDiv + 1; ++j) + { + double y = j \*yLen / vDiv; + for (int i = 0; i \< uDiv + 1; ++i) + { + double x = i \*xLen / uDiv; + double z = height \* + Math.Cos(x / xLen \*xPeriods \*2.0 \*Math.PI) \* + Math.Cos(y / yLen \*yPeriods \*2.0 \*Math.PI); + var node = new OpenTDv242.RadCAD.FEModel.Node(); + node.x = x; + node.y = y; + node.z = z; + node.Nx = 0.0; + node.Ny = 0.0; + node.Nz = 1.0; + node.id = ++id; + feMesh.nodes.Add(node); + if (i \< uDiv && j \< vDiv) + { + var face = new OpenTDv242.RadCAD.FEModel.SurfaceElement(); + face.id = ++elemId; + face.order = 1; + face.numNodes = 4; + int baseIndex = j \*(uDiv + 1) + i + 1; + face.nodeIds.Add(baseIndex); + face.nodeIds.Add(baseIndex + 1); + face.nodeIds.Add(baseIndex + 1 + uDiv + 1); + face.nodeIds.Add(baseIndex + uDiv + 1); + feMesh.surfaceElements.Add(face); + } + } + } + meshImporter.SetMesh(feMesh); + + // As mentioned previously, the FEMesh we passed to SetMesh + // is a lightweight description of the mesh, suitable for + // initial creation only. To work with the elements + // it created, we need to get them from TD: + var quads = td.GetLinearQuads(); + + // Let's edit all of the elements and their nodes: + string submodel = "new_submodel"; + var allNodes = td.GetNodes(); + foreach (LinearQuad q in quads) + { + q.CondSubmodel = submodel; + q.TopThickness = 0.01; + q.Update(); + var quadNodes + = allNodes.Where(n =\> q.AttachedNodeHandles.Contains(n.Handle)); + foreach (Node n in quadNodes) + { + n.Submodel = submodel; + n.Update(); + } + } + + td.SetVisualStyle(VisualStyles.THERMAL_PP); + td.RestoreIsoView(IsoViews.SE); + td.ZoomExtents(); + } + } +} +``` diff --git a/2025R2/thermal-desktop-opentd-for-demo/articles/getting-started/prerequisites.md b/2025R2/thermal-desktop-opentd-for-demo/articles/getting-started/prerequisites.md new file mode 100644 index 0000000000..622f7d1a7d --- /dev/null +++ b/2025R2/thermal-desktop-opentd-for-demo/articles/getting-started/prerequisites.md @@ -0,0 +1,8 @@ +# Prerequisites + +Before getting started with OpenTD, ensure that you meet the following prerequisites and technical requirements. + +## Technical requirements + +- .NET Framework version: OpenTD targets .NET Framework 4.8. It does not work with .NET Core or .NET Standard. You must target the .NET Framework. +- AutoCAD version: OpenTD requires AutoCAD 2018 or later. diff --git a/2025R2/thermal-desktop-opentd-for-demo/articles/getting-started/reading-results.md b/2025R2/thermal-desktop-opentd-for-demo/articles/getting-started/reading-results.md new file mode 100644 index 0000000000..9b5251d5fc --- /dev/null +++ b/2025R2/thermal-desktop-opentd-for-demo/articles/getting-started/reading-results.md @@ -0,0 +1,1065 @@ +# Reading results + +OpenTD offers two ways to work with solution results: + +1. You can work directly with save files, CSR’s and other data files. You can create XY plots and tables, or you can simply get the data into memory for further manipulation. +2. You can create and modify contour plots and other post-processing output within a TD instance. + + The following examples will show how to use both methods. + +## Work directly with results using OpenTDv242.Results + +The classes for working directly with save files, CSR’s or other solution results are found within the *OpenTDv242.Results* namespace, packaged within the OpenTDv242.Results.dll assembly. The following section describes how to set up a .NET project to access this assembly. + +### Before using OpenTDv242.Results + +To use OpenTD to explore results directly (rather than via an instance of TD), you will need to add a reference to the OpenTDv242.esults.dll assembly. You can find it in the GAC in the 64-bit directory. (Try looking under C:\\Windows\\Microsoft.ET\\assembly\\GAC_64\\OpenTDv242.Results.) You will also probably need to add a reference to OpenTDv242.dll, as usual. [See the Hello World](creating-td-model/hello-world.md) +Since OpenTDv242.Results is a 64-bit assembly, your project will also have to be 64-bit. In Visual Studio, use the Configuration manager to create a 64-bit solution and a 64-bit project. When set up correctly, your Configuration Manager dialog should look something like this: +![Configuration Manager dialog](media/19913b5a9a51f4926a07426227c010fa.png) + +### The basics + +OpenTD offers powerful tools for manipulating solution results, but it is a lot to learn all at once. This section shows how to imply get some data out of a save file or CSR. +First, reference the OpenTDv242.Results dll as discussed above. Next, add a using statement for convenience: + +using OpenTDv242.Results.Dataset; + +Now you can connect to a save file: + +```c# +var myData = new SaveFile(@”path\\to\\sav”); +``` + +Or connect to a CSR: + +```c# +var myData = new CSR(@”path\\to\\CSR”); +``` + +To get, for example, all temperatures from a couple of nodes, pass their SINDA/FLUINT names to the *IDataset*.*GetData* method and call *GetValues(UnitsData u)* on the result: + +```c# +var someNodeTs = myData.GetData(“WALL.T10”, “WALL.T11”).GetValues(Units.SI); +``` + +This will return a list containing two inner lists of node temperatures in SI units, one for each node. Note that if you request data for just one entity, it will still be returned as a list of lists. For example, the following returns a list containing a single list of flowrates for path “FLOW.60”: + +```c# +var onePathFRs = myData.GetData(“FLOW.FR60”).GetValues(Units.SI); +``` + +To get the data in other units, you can pass an appropriate *UnitsData* object to GetValues, for example: + +```c# +var someNodeTsEng = myData.GetData(“WALL.T10”, “WALL.T11”).GetValues(Units.Eng); +``` + +GetData will accept arbitrary-length lists of SINDA/FLUINT names of any type. They can even include registers: + +```c# +var disparateData = myData.GetData( +“WALL.T10”, “FLOW.PL100”, “VALVE_POS”, “ROOM.T1”).GetValues(Units.SI); +``` + +In this case, GetData will assume that “VALVE_POS” is a dimensionless register and return the raw values from the save/CSR. This behavior can be modified, as discussed in the [Work with groups in results data](#work-with-groups-in-results-data) section. + +You can construct an array of strings to pass to GetData. For example, to get temperatures for nodes “MAIN.1” through “MAIN.100”, inclusive: + +```c# +string[] someNames = new string[100]; +for (int i = 0; i \< 100; ++i) +someNames[i] = "MAIN.T" + (i + 1); +var someTs = myData.GetData(someNames).GetValues(Units.SI); +``` + +Please note that there are special classes that help to construct lists of entities representing SINDA/FLUINT and TD groups such as submodels and domains. These are introduced in the [Advanced results manipulation and XY plots](#advanced-results-manipulation-and-xy-plots) section and discussed in detail in the [Work with groups in results data](#work-with-groups-in-results-data) section. + +In the examples above, we have extracted ‘T’, ‘PL’, and ‘FR’ data. Please examine the values of the StandardDataSubtypes enum to see all strings recognized by GetData. It also recognizes names that require fluid constituent letters, such as ‘GTW’. StandardDataSubtypes are discussed in Sections [Work with groups in results data](#work-with-groups-in-results-data) and [A note on DataSubtypes](#a-note-on-datasubtypes). + +To get TIMEN from a dataset, use: + +```c# +var times = myData.GetTimes().GetValues(); +``` + +This returns a list of times in the current WorkingUnits. + +### Advanced Results Manipulation and XY Plots + +The previous section showed how to easily get data out of save files or CSR’s. In this and the following sections we will show how to manipulate that data, work with groups and multiple datasets, combine data in arbitrarily complex ways, and create simple XY plots. + +Compared to previous methods for extracting and plotting SINDA/FLUINT data, OpenTD offers several improvements: + +- The *IDataset* interface and abstract *Dataset* class provide a common syntax for extracting data from save files, CSR’s, and other sources. You can use several implementations of Dataset: + + - *SaveFile* + - *CSR* + - *SpreadsheetDataFile* + - *TextTransientFile* + +- Data is returned from Datasets via *DataArrays*. In addition to containing the data (T’s, Q’s, and more), DataArrays know their physical dimension, their units, and contain a reference back to their source Dataset. + +- If data is missing from a record, it is expressed in DataArrays as NaN. This happens, for example, when register values are only written to a transient dataset for the beginning and end records. + +- *ItemIdentifiers* are used to identify items, such as “MAIN.1” or “FLOW.100”. + +- *ItemIdentifierCollections* can be constructed based on submodels, domains, or arbitrary lists. + +- The *DataSubtype* class describes things like T, Q, TL, GTW, etc. Standard DataSubtypes can be created using the *StandardDataSubtypes* enum or the *FullStandardDataSubtype* struct. (The FullStandardDataSubtype struct is required to describe subtypes that contain a fluid constituent, like GTW.) Custom DataSubtypes can also be created. + +- *DataItemIdentifiers* combine ItemIdentifiers and DataSubtypes. They are used to identify data from items, such as “MAIN.T1”, “FLOW.TL100”, or “FLOW.GTW100”. + +- *DataItemIdentifierCollections* can be constructed by combining ItemIdentifierCollections with DataSubtypes, or from arbitrary lists. + +- *DerivedDatasets* are Datasets that contain references to multiple Datasets and operate on them to return data. Because DerivedDatasets are also Datasets, they can be used anywhere Datasets can be used -- even as input to other DerivedDatasets -- so you can chain them together in arbitrarily complex ways. You can extend the DerivedDataset class to create your own, or use the following pre-defined DerivedDatasets: + + - *ConcatenatedDataset* takes a list of input Datasets and stitches their data together. + - *DatasetSlice* takes a single Dataset and only returns data between given start and end times. + +- *DerivedDataArrays* are like DerivedDatasets but for DataArrays. They contain a list of input DataArrays and operate on them to return data. Just like DerivedDatasets, DerivedDataArrays can be chained together in arbitrarily complex ways, and you can create your own by extending the DerivedDataArray class or use the following pre-defined DerivedDataArrays: + + - *AverageDataArray* returns the arithmetic mean of its input arrays at each record. + - *ForumlaDataArray* operates on each record of its input arrays using a provided formula, in the units provided. + - *MaxDataArray* returns the maximum value of its input arrays at each record. + - *MinDataArray* returns the minimum value of its input arrays at each record. + - *SelectMaxDataArray* returns the input array with the maximum value. + - *SelectMinDataArray* returns the input array with the minimum value. + - *SumDataArray* returns the sum of its input arrays at each record. + - *WeightedAverageDataArray* returns a weighted average of its input arrays at each record. The weighting factors can be fixed or change with each record. There are helpful constructors to make it easy to, for example, determine mCp-weighted temperatures. + +- Plots are intelligent: + + - They automatically put series with different dimensions on different axes. + - They automatically name themselves and series. + - They automatically label axes with dimensions and units. (They default to the WorkingUnits at the time they are first created.) + - NaN’s are displayed as a discontinuity in the series. Series with discontinuities (or steady-state series with only one record) are automatically displayed with markers and lines. + - All the above can be customized. + +In this program, we will make use of the “torchNom.sav” and “torchCold.sav” files created in the [Create and run a case](working-with-case-sets.md#create-and-run-a-case) section, so please run that program and locate the two save files. + +Once Visual Studio is set up with a 64-bit solution and project ( Section [Before using OpenTDv242.Results](#before-using-opentdv242results)), and you have added references to OpenTDv242.dll and OpenTDv242.Results.dll, you will be ready to try the following program. + +```c# +using System; +using OpenTDv242; +using OpenTDv242.Results.Dataset; +using OpenTDv242.Results.Plot; + +Namespace OpenTDv242GettingStarted +{ + class ExploreAndPlotResults + { + static void Main(string[] args) + { + // A Dataset is an abstract class representing solution + // results. You can create a Dataset from a save file, + // a CSR, a text file, or from a combination of other + // Datasets. Let's open the torch save files created + // in the "Create and Run a Case" example. + // You may have to change the paths to your copies of + // torchNom.sav and torchCold.sav. + var torchNom = new SaveFile(@"c:\\temp\\OpenTDCreateAndRunCase\\torchNom.sav"); + var torchCold = new SaveFile(@"c:\\temp\\OpenTDCreateAndRunCase\\torchCold.sav"); + + // Data is returned as DataArrays or DataArrayCollections, + // which know their physical dimension, their source, and + // how to return their values in any unit system. + DataArrayCollection someTemps = torchNom.GetData("BAR.T1", "BAR.T2"); + + // DataArray.GetValues returns data in current WorkingUnits + Units.WorkingUnits.SetToSI(); + Console.WriteLine("BAR.T1 at first time in K: " + someTemps[0].GetValues()[0].ToString()); + + Units.WorkingUnits.temp = UnitsData.Temp.F; + Console.WriteLine("BAR.T1 at first time in deg F: " + someTemps[0].GetValues()[0].ToString()); + + // You can plot data using a SimplePlot: + var plotSomeTemps = new SimplePlot(); + plotSomeTemps.AddSeries(someTemps); + plotSomeTemps.Show(); + // Note that AddSeries accepted a DataArrayCollection. Since + // each DataArray has a reference to its Dataset, AddSeries is + // able to go and get the time array for X data. + + // Let's make a plot with different types of data: + var TandQ = torchNom.GetData("BAR.T1", "BAR.Q1"); + var TandQPlot = new SimplePlot(); + TandQPlot.AddSeries(TandQ); + TandQPlot.Show(); + // Note that since we only saved Q data to the sav + // file for the final record, it is shown as a point. + + // Let's plot temperatures for all BAR nodes from both datasets. + // To do this, we're going to use an ItemIdentifierCollection to + // identify all of the BAR nodes. + var barNodes = new ItemIdentifierCollection(DataTypes.NODE, "BAR", torchNom); + var barTsNom = torchNom.GetData(barNodes, StandardDataSubtypes.T); + var barTsCold = torchCold.GetData(barNodes, StandardDataSubtypes.T); + var allBarNodesPlot = new SimplePlot(); + allBarNodesPlot.AddSeries(barTsNom); + allBarNodesPlot.AddSeries(barTsCold); + allBarNodesPlot.Show(); + + // That was a lot of series on one plot. Let's plot the average + // bar temps from each case instead. For this we'll use an + // AverageDataArray, which is a type of DerivedDataArray. + // DerivedDataArrays take a collection of DataArrays and + // operate on it to produce a single DataArray. + var avgTNom = new AverageDataArray(barTsNom); + var avgTCold = new AverageDataArray(barTsCold); + var avgPlot = new SimplePlot("Average bar T's"); + avgPlot.AddSeries(avgTNom); + avgPlot.AddSeries(avgTCold); + avgPlot.Show(); + + // There are other types of DerivedDataArrays. Here we'll use + // a SelectMaxDataArray to find the hottest node across both + // datasets: + var allTs = new DataArrayCollection(); + allTs.AddRange(barTsNom); + allTs.AddRange(barTsCold); + var maxT = new SelectMaxDataArray(allTs); + var maxPlot = new SimplePlot("Hottest Node"); + maxPlot.AddSeries(maxT); + maxPlot.AutoHideLegend = false; + maxPlot.Show(); + // We set AutoHideLegend to false because SimplePlot will + // normally hide the legend if there's only one series, + // and use the series name as the title. Since we customized + // the title, that wouldn't work here. + + // What if we're only interested in the first 400 s of the + // cold case? We can use a DatasetSlice, which is a type of + // DerivedDataset. DerivedDatasets are to Datasets what + // DerivedDataArrays are to DataArrays. + Units.WorkingUnits.time = UnitsData.Time.SEC; + var coldCaseSlice = new DatasetSlice(torchCold, 0, 400); + var bar2TCold400 = coldCaseSlice.GetData("BAR.T2"); + var slicePlot = new SimplePlot(); + slicePlot.AddSeries(bar2TCold400); + slicePlot.Show(); + // Note that if there isn't a record at 400 s, DatasetSlice + // will choose the next record. + } + } +} +``` + +If it runs correctly, you should see several *SimplePlot*-generated dialogs like the following. Instead of displaying them to the screen with SimplePlot.*Show()*, we could have used .*GetAsImage* or .*GetAsTable* to return objects that could be further manipulated in our program, or .*SaveAsImage* or .*SaveAsTable* to write image or csv files containing the data. + +![img](media/16ae466d28b3584b1dcbdf90484ad0bd.png) + +### Work with Groups in Results Data + +The previous example provided an overview of using OpenTD to read and plot SINDA/FLUINT results. In the following example we will discuss ItemIdentifiers and DataItemIdentifiers, which allow you to specify groups of items, whether by submodel, domain, or arbitrary list. + +Once again, we are using the OpenTDv242.Results dll, so create a 64-bit project as discussed in [Work directly with results using OpenTDv242.Results](#work-directly-with-results-using-opentdv242results). + +```C# +using System; +using System.IO; +using System.Collections.Generic; +using OpenTDv242; +using OpenTDv242.Results.Dataset; +using OpenTDv242.Results.Plot; + +namespace OpenTDv242GettingStarted +{ + class WorkingWithGroups + { + public static void Main(string[] args) + { + // Let's open one of the torch save files from the + // "Create and Run a Case" example. + // You may need to change the workingDir string to the + // dir containing torchNom.sav. + string workingDir = @"c:\\temp\\OpenTDCreateAndRunCase"; + var data = new SaveFile(Path.Combine(workingDir, "torchNom.sav")); + + #region ItemIdentifiers + // Use ItemIdentifiers to identify SINDA/FLUINT entities + // like WALL.100, WATER.45, or MY_REGISTER. + + // You can create a collection of ItemIdentifiers from a submodel in a + // Dataset: + var allbarNodeNames = new ItemIdentifierCollection(DataTypes.NODE, "BAR", data); + Console.WriteLine("\\nItemIdentifierCollection: BAR submodel:"); + foreach (var item in allbarNodeNames) + { + Console.WriteLine("{0} => Submodel = '{1}', Id = {2}", + item, item.Submodel, item.Id); + } + + // You can create a collection of ItemIdentifiers representing the + // nodes in a domain, but you need to supply a ThermalDesktop instance + // to define the domain: (this example is commented out to avoid loading + // a TD instance.) + // var allSomeDomainNodes + // = new ItemIdentifierCollection("SOME_DOMAIN", aTdInstance); + + // You can create arbitrary collections of ItemIdentifiers by supplying + // a list of SINDA names: + var arbitraryItems = new ItemIdentifierCollection( + "MAIN.1", + "FLOW.10", + "MY_REGISTER"); + + Console.WriteLine("\\nItemIdentifiers: arbitrary list:"); + foreach (var item in arbitraryItems) + { + Console.WriteLine("{0} => Sub = '{1}', Id = {2}, RegName = '{3}'", + item, item.Submodel, item.Id, item.RegisterName); + } + #endregion + + #region DataSubtypes + // Use DataSubtypes to identify types of SINDA/FLUINT data, + // like T, TL, GTW, etc. + + // You can create a new DataSubtype with the StandardDataSubtypes enum: + var SubtypeT = new DataSubtype(StandardDataSubtypes.T); + + // For multispecies data, you can provide a StandardDataSubtypes + // and a FluidConstituents enum... + var SubtypeGTW = new DataSubtype( + StandardDataSubtypes.GT, FluidConstituents.W); + + // ...or you can provide a FullStandardDataSubtypes struct, + // which just contains a StandardDataSubtypes/FluidConstituents pair: + var SubtypeGTW_alternate = new DataSubtype(new FullStandardDataSubtype( + StandardDataSubtypes.GT, FluidConstituents.W)); + + // You can also create your own DataSubtype, maybe for custom data + // you're reading out of a text file: + var SubtypeBoundaryLayerThickness = new DataSubtype( + dimension: UnitsData.UnitsType.MODEL_LENGTH, + isDimensionalOnlyIfPositive: false, + description: "Boundary Layer Thickness for Phase B", + baseSindaDesignator: null, + dataType: DataTypes.PATH); + + // Through the magic of implicit casts, you can use a + // StandardDataSubtypes or FullStandardDataSubtype anywhere + // a DataSubtype is expected: + var listOfDataSubtypes = new List() { + StandardDataSubtypes.T, + new FullStandardDataSubtype(StandardDataSubtypes.GT, FluidConstituents.W) + }; + + Console.WriteLine("\\nDataSubtypes: implicit casts to DataSubtype:"); + foreach (var item in listOfDataSubtypes) + { + Console.WriteLine(item); + } + #endregion + + #region Get data with DataSubtypes and ItemIdentifiers + // Datasets can return data for multiple items if provided an + // ItemIdentifierCollection and a DataSubtype: + var allBarNodeTs = data.GetData(allbarNodeNames, StandardDataSubtypes.T); + + Console.WriteLine("\\nGet data with DataSubtypes and ItemIdentifiers:\\n" + + "DataArrayCollection.Name: {0}\\n.Count: {1}\\n.DataItemCount: {2}", + allBarNodeTs.Name, allBarNodeTs.Count, allBarNodeTs.DataItemCount); + #endregion + + #region DataItemIdentifiers + // Use DataItemIdentifiers to identify SINDA/FLUINT entities like + // WALL.T100, WATER.TL45, or "MY_REGISTER temperature". + // They combine ItemIdentifiers and DataSubtypes. + // You can create DataItemIdentifiers from ItemIdentifiers and a single + // DataSubtype: + var allBar_T_Names = new DataItemIdentifierCollection( + allbarNodeNames, StandardDataSubtypes.T); + + Console.WriteLine("\\nDataItemIdentifiers: all BAR T names:"); + foreach (var item in allBar_T_Names) + { + Console.WriteLine(item); + } + + // Or you can create a DataItemIdentifierCollection + // by parsing a list of SINDA/FLUINT names: + var parsedDataItems = new DataItemIdentifierCollection( + "MAIN.T100", + "FLOW.FR40", + "FLOW.GTW11", + "A_REGISTER"); + + Console.WriteLine("\\nDataItemIdentifiers: parsed SINDA/FLUINT names:"); + foreach (var item in parsedDataItems) + { + Console.WriteLine(item); + } + + // One issue with parsing SINDA/FLUINT names: it will assume any + // registers are dimensionless, so if you'd like to assign a + // dimension to a register, you should explicitly create the + // DataItemIdentifier for it: + var A_REGISTER_flowrate = new DataItemIdentifier( + new ItemIdentifier("A_REGISTER"), StandardDataSubtypes.FR); + + // If the register stores data in a unit system other than that + // of the Dataset, you can specify that too: + var A_REGISTER_flowrate_Eng = new DataItemIdentifier( + new ItemIdentifier("A_REGISTER"), StandardDataSubtypes.FR, + Units.Eng); + + // You can combine ItemIdentifiers and a list of DataSubtypes, + // creating all combinations of DataItemIdentifiers: + var TandQ = new List() { + StandardDataSubtypes.T, + StandardDataSubtypes.Q + }; + + var allBar_TandQ_Names = new DataItemIdentifierCollection(allbarNodeNames, TandQ); + + Console.WriteLine("\\nDataItemIdentifiers: combine ItemIdentifiers and DataSubtypes:"); + foreach (var item in allBar_TandQ_Names) + { + Console.WriteLine(item); + } + #endregion + + #region Get data with DataItemIdentifiers + // Datasets can return data for multiple items if provided a + // DataItemIdentifierCollection: + var allBar_TandQ = data.GetData(allBar_TandQ_Names); + + // And you can plot all the series in a DataArrayCollection + // with a single SimplePlot.AddSeries method: + { + var plot = new SimplePlot(); + plot.Name = "Get data with DataItemIdentifiers: plot DataArrayCollection"; + plot.AddSeries(allBar_TandQ); + plot.Show(); + } + + // Since the DataArrays in allBar_TandQ know their SourceDataset, + // AddSeries uses it to get time for the x data of each series. + // Skip some steps and let GetData parse a list of SINDA/FLUINT names. + + // One issue with this: it will assume any registers are dimensionless, + // so if you'd like to assign a dimension to a register, you should + // explicitly create the DataItemIdentifier for it. + var someData = data.GetData("BAR.T1", "BAR.Q1", "BAR.T3"); + + { + var plot = new SimplePlot(); + plot.Name = "Get data with DataItemIdentifiers: parsed names"; + plot.AddSeries(someData); + plot.Show(); + } + #endregion + } + } +} +``` + +### A Note on DataSubtypes + +As shown in the preceding sections, the DataSubtype class is used to describe types of data found in solution results such as “node temperature T” or “lump pressure PL”. There are several methods that require a DataSubtype as a parameter. When using those methods, you can create your own DataSubtype, but it is usually easier to allow OpenTD to do it for you by making use of the StandardDataSubtypes enum and/or the FullStandardDataSubtype struct. + +Through the magic of implicit casting (See the [Execute TD COM commands section](extras.md#execute-td-com-commands)) any method that accepts a DataSubtype will accept either a StandardDataSubtypes or FullStandardDataSubtype instead. For example, one of the GetData overloads has the following signature: + +```c# +DataArrayCollection GetData( +ItemIdentifierCollection itemIds, DataSubtype subtype, UnitsData units = null) +``` + +It expects a list of entity names (the ItemIdentifierCollection), the type of data to get (the DataSubtype), and you can optionally specify the units for any registers in the ItemIdentifierCollection. To get node temperatures for all the nodes in the “PANEL” domain from TD instance “td”, you could do this: + +```c# +var panelNodes = new ItemIdentifierCollection(“PANEL”, td); +var panelNodeTs = myData.GetData(panelNodes, StandardDataSubtypes.T); +``` + +We passed “StandardDataSubtypes.T” even though the method expected a DataSubtype. If you are using a language that does not support .NET implicit casting, you can explicitly construct the DataSubtype instead: + +```c# +var panelNodes = new ItemIdentifierCollection(“PANEL”, td); +var panelNodeTs = myData.GetData(panelNodes, new DataSubtype(StandardDataSubtypes.T)); +``` + +Implicit casting to a DataSubtype also works for FullStandardDataSubtypes, which are structs that combine StandardDataSubtypes with a fluid constituent. + +### Get Model Topology from Solution Results + +As demonstrated in [Modifying TD models](modifying-td-models.md), you can query a dwg file to determine the topology of a model. For example, you can use ThermalDesktop.*GetConductors()* to get all of the conductors, then for each you can use the *From* and *To* members and GetNode to find the attached nodes. + +That approach is suitable when you are working with the dwg file, but if you are just using solution results it is often more convenient to read topology data directly without involving TD. Also, model topology can change during the run due to BUILD statements or other techniques, so reverse-engineering the actual topology at a given record from the dwg file is error-prone. + +Fortunately, OpenTD allows you to read the actual as-solved model topology at each record using *PCS files* automatically created by SINDA/FLUINT. You may have seen these files before in your solution directory, often named “MyCase.savPCS” or similar. + +The following program will read model topology from a PCS file and print out all the conductors and the nodes they connect. It uses “torchNom.sav” and “torchNom.savPCS”, created in the [Create and run a case](working-with-case-sets.md#create-and-run-a-case) section, so please run that program and locate the two files. + +```c# +using System; +using System.Collections.Generic; +using System.IO; +using OpenTDv242.Results.Dataset; +using OpenTDv242.Results.Dataset.Topology; + +namespace OpenTDv242GettingStarted +{ + class GettingModelTopology + { + public static void Main(string[] args) + { + // Let's open one of the torch save files from the + // "Create and Run a Case" example. + // You may need to change the workingDir string to the + // dir containing torchNom.sav. + string workingDir = @"c:\\temp\\OpenTDCreateAndRunCase"; + var data = new SaveFile(Path.Combine(workingDir, "torchNom.sav")); + + // Now we'll read the PCS file, which contains topology and other + // extra information. Topology can change with each record, so we + // have to specify which record. We'll just use the first one: + List recordNums = data.GetRecordNumbers(); + string pcsPath = Path.Combine(workingDir, "torchNom.savPCS"); + IDatasetTopology topology + = DatasetTopology.Load(data, recordNums[0], pcsPath); + + // Find all conductors and their attached nodes: + foreach (IConductorInfo cond in topology.Conductors) + { + Console.WriteLine("{0} Conductor {1}:", cond.IsRad ? "Radiation" : "Linear", cond.SindaName); + Console.WriteLine(" From {0} Node {1}", cond.FromNode.NodeType, cond.FromNode.SindaName); + Console.WriteLine(" To {0} Node {1}", cond.ToNode.NodeType, cond.ToNode.SindaName); + } + } + } +} +``` + +You may notice that each of the conductors is listed twice, once from node A to B, and once from B to A. This is an indication that the conductor is a normal two-way conductor. One-way conductors will only show up once. + +### Calculate Heat Rates between Groups + +Model topology along with solution results can be used to determine heat rates between groups of entities. This is done using an *IBrowser*. + +The following program uses the solution results from section [Create and run a case](working-with-case-sets.md#create-and-run-a-case) . Make sure to run that program first before trying this one. As you may recall, that program creates a model of a bar heated on one end, convecting to a room along its length. We will be using results from a transient case, starting with a cold bar. + +We will create two IBrowsers, one early in the solution and one at the final record, using them to find the total heat rate from the bar to the room at the two times. We will also use a SumDataArray (section [Advanced results manipulation and XY plots](#advanced-results-manipulation-and-xy-plots)) to plot the constant total external heat into the bar over the whole solution. We expect the heat rate from the bar to the room to approach the external heat rate as the system approaches steady-state. + +```c# +using System; +using System.Collections.Generic; +using System.IO; +using OpenTDv242.Results.Dataset; +using OpenTDv242.Results.Dataset.Topology; +using OpenTDv242.Results.Plot; + +namespace OpenTDv242GettingStarted +{ + class CalculatingHeatRates + { + public static void Main(string[] args) + { + // Open torchCold.sav and torchCold.savPCS, getting topology at + // early record: (using torchCold because we set SaveAll = 1 to + // make sure all data req'd for Browser available) + string workingDir = @"c:\\temp\\OpenTDCreateAndRunCase"; + var data = new SaveFile(Path.Combine(workingDir, "torchCold.sav")); + List recordNums = data.GetRecordNumbers(); + List timesSec = data.GetTimes().GetValues(); + string pcsPath = Path.Combine(workingDir, "torchCold.savPCS"); + int earlyIndex = 1; + IDatasetTopology topologyEarly = DatasetTopology.Load(data, recordNums[earlyIndex], pcsPath); + IDatasetTopology topologyEarly + = DatasetTopology.Load(data, recordNums[earlyIndex], pcsPath); + + // Create Browser at early record and find heat rate from + // submodel BAR to ROOM: + IBrowser browserEarly + = Browser.Create(data, topologyEarly, recordNums[earlyIndex]); + HeatratesBetween heatratesEarly + = browserEarly.GetHeatBetweenSubmodels("BAR", "ROOM"); + Console.WriteLine("At time {0} s, heat rate from BAR to ROOM: {1} W", + timesSec[earlyIndex], heatratesEarly.TotalHeatrate); + + // Find heat rate between submodels at final record: + // (Using early-record topology because we know it + // doesn't change in this model.) + int finalIndex = recordNums.Count - 1; + IBrowser browserFinal + = Browser.Create(data, topologyEarly, recordNums[finalIndex]); + HeatratesBetween heatratesFinal + = browserFinal.GetHeatBetweenSubmodels("BAR", "ROOM"); + Console.WriteLine("At time {0} s, heat rate from BAR to ROOM: {1} W", + timesSec[finalIndex], heatratesFinal.TotalHeatrate); + + // Plot total external heat into bar: + var barNodes = new ItemIdentifierCollection(DataTypes.NODE, "BAR", data); + DataArrayCollection barQs + = data.GetData(barNodes, StandardDataSubtypes.Q); + var barQSum = new SumDataArray(barQs); + var plot = new SimplePlot(); + plot.AddSeries(barQSum); + plot.Show(); + } + } +} +``` + +For this program, we only looked at heat rates between submodels, using IBrowser.*GetHeatBewteenSubmodels*. But any arbitrary group of nodes or ties can be examined using the IBrowser.*GetHeatBetween* method. + +### Read Text Files + +In addition to SaveFile and CSR data sources, there are other types of Dataset classes available: + +SpreadsheetDataFile, for reading columns of comma-delimited data + +TextTransientFile, for reading the TD-specific Text Transient Dataset file, as defined in the TD manual. + +All of them implement the OpenTDv242.Dataset.IDataset interface, so they can be used interchangeably. The following program demonstrates treating a csv file as a Dataset using OpenTDv242.Results: + +```c# +using System; +using System.IO; +using OpenTDv242; +using OpenTDv242.Results.Dataset; +using OpenTDv242.Results.Plot; + +namespace OpenTDv242GettingStarted +{ + class ReadSpreadsheetFile + { + public static void Main(string[] args) + { + // you may wish to change the location of the working dir: + string workingDir = @"c:\\temp\\ReadTextFiles"; + if (Directory.Exists(workingDir)) + Directory.Delete(workingDir, true); + Directory.CreateDirectory(workingDir); + + // We'll create a spreadsheet file to read: + var pathname = Path.Combine(workingDir, "testData.csv"); + var spreadsheetData = "TIMEN,WALL.T100,WALL.T200,INCIDENT_FLUX,COOLANT.FR10\n" + + "hr,,,W/m^2,kg/min\n" + + "0,70,68,100,0.5\n" + + "1,75,69,102,0.41\n" + + "2,77,,101,0.43\n" + + "3,NaN,70,102,0.52\n" + + "4,78.5,70,103,0.5"; + File.WriteAllText(pathname, spreadsheetData); + // The file is comma-delimited. By default, it can be comma- or + // tab-delimited. Other delimiters can be chosen by adjusting the + // Delimiters array. Space cannot be used, because it can be used as part + // of certain units expressions. + + // The first row holds names. SINDA/FLUINT names like MAIN.T1 or + // FLOW.GTX10 are valid. Other strings will be assumed to be register + // names. + + // The second row holds optional units. For blank cells, + // SpreadsheetDataFile.Units will be assumed. All registers except TIMEN + // will be assumed to be dimensionless, and their units will be ignored. + + // For this example, the file represents observations of a heated and + // cooled wall, taken every hour. Time was measured in hours, + // temperatures in deg F, heating flux in W/m^2, and coolant flowrate + // in kg/min. The observer noted units on the second row for everything + // except the temperatures. The observer also missed taking two of the + // data readings, with one listed as NaN and one listed as an empty cell. + + // First, we'll create the Dataset from the spreadsheet file: + var data = new SpreadsheetDataFile(pathname); + + // We'll set the Dataset temperature units to F since the temperature + // units aren't listed in the file: + data.Units.temp = UnitsData.Temp.F; + + // We can use the Dataset methods to extract data from + // SpreadsheetDataFiles: + Console.WriteLine("Thermal submodels:"); + foreach (string submodel in data.GetThermalSubmodels()) + Console.WriteLine(" " + submodel); + Console.WriteLine("Paths in submodel COOLANT:"); + foreach (long id in data.GetPathIds("COOLANT")) + Console.WriteLine(" " + id); + + // Let's get heating and cooling data: + + // Most registers are assumed dimensionless, so we'll have to tell + // the dataset that INCIDENT_HEAT is a flux. First, let's create a + // custom DataSubtype representing heat flux: + var heatFlux = new DataSubtype( + dimension: UnitsData.UnitsType.FLUX, + description: "heat flux"); + + // Now let's get the INCIDENT_HEAT data: (We'll use GetRegisterData so we + // can assign it a DataSubtype and state what units the values are in.) + var incident_heat = data.GetRegisterData( + "INCIDENT_FLUX", heatFlux, Units.SI); + + // The coolant flowrate is easier, since the dataset already knows its + // DataSubtype and units: + var coolantFR10 = data.GetData("COOLANT.FR10"); + + // Now let's create some plots, in SI units: + Units.WorkingUnits.SetToSI(); + + var inputPlot = new SimplePlot("Heating and Cooling Applied to Wall"); + inputPlot.AddSeries(incident_heat); + inputPlot.AddSeries(coolantFR10); + inputPlot.Show(); + + var wallTempPlot = new SimplePlot(); + wallTempPlot.AddSeries(data.GetData("WALL.T100", "WALL.T200")); + wallTempPlot.Show(); + } + } +} +``` + +The following program treats a TD Text Transient Data file as a Dataset: + +```c# +using System; +using System.IO; +using OpenTDv242; +using OpenTDv242.Results.Dataset; +using OpenTDv242.Results.Plot; + +namespace OpenTDv242GettingStarted +{ + class ReadTextTransientFile + { + public static void Main(string[] args) + { + // you may wish to change the location of the working dir: + string workingDir = @"c:\\temp\\ReadTextFiles"; + if (Directory.Exists(workingDir)) + Directory.Delete(workingDir, true); + Directory.CreateDirectory(workingDir); + + // We'll create a text transient file to read: + var pathname = Path.Combine(workingDir, "testData.txt"); + var angleData = "\# Case 0 Motor Angle\\n" + + "\#\\n" + + "\#TIME_UNITS hr\\n" + + "\#\\n" + + "Label=Angle\\n" + + "3\\n" + + "MOTOR.69\\n" + + "MOTOR.70\\n" + + "MOTOR.71\\n" + + "1.\\n" + + "53.7093946669\\n" + + "53.7093946669\\n" + + "53.2207743327\\n" + + "2.\\n" + + "60.\\n" + + "65.\\n" + + "70."; + + File.WriteAllText(pathname, angleData); + + // File specification: + // ... + // 1. Optional arbitrary number of comment lines beginning with \# + // 2. Optional \#TIME_UNITS line + // \* Must be only one space between TIME_UNITS and value + // \* First character of value is compared against first + // character of Time enum values SEC, MIN or HR + // 3. Optional arbitrary number of comment lines beginning with \# + // 4. Optional Label = line + // \* Label= does not need to appear at start of line + // \* Value is 2048 characters max + // 5. Integer specifying number of items n + // \* 2048 characters max + // 6. n lines containing item names + // \* Throw away spaces, \\n, and \\r + // \* If no ‘.’, prepend ‘MAIN.’ to name + // \* 2048 characters max + // 7. Single line containing first time + // \* 2048 characters max + // 8. n lines containing data for that time + // \* 2048 characters max + + // We'll use a custom DataSubtype to describe the motor angle data + // stored in the text transient file. The description "motor crank + // angle" will be overwritten by the "Label =" line in the example + // text file. + var motorAngle = new DataSubtype(UnitsData.UnitsType.ANGLE, + false, "motor crank angle", null, + DataTypes.NODE); + + // If we didn't provide a DataSubtype to the TextTransientFile + // constructor, it would assume T (node temperature). If we didn't + // provide units, it would assume the data was in the current + // Units.WorkingUnits. (With the exception of time units, which can be + // overwritten by a \#TIME_UNITS statement in the file. + var data = new TextTransientFile(pathname, motorAngle, Units.SI); + + // You can use the Dataset methods to extract data from + // TextTransientFiles + Console.WriteLine("Thermal submodels:"); + foreach (string submodel in data.GetThermalSubmodels()) + Console.WriteLine(" " + submodel); + Console.WriteLine("Nodes in submodel MOTOR:"); + foreach (long id in data.GetNodeIds("MOTOR")) + Console.WriteLine(" " + id); + + // In addition to the Dataset methods TextTransientFiles also implement + // the ISimpleDataset interface, which includes the GetAllData() method. + // This returns a DataArrayCollection all of the data in the + // SimpleDataset. It defaults to returning time as the first array, but + // we'll override that behavior here with the includeXDataAsFirstArray + // parameter. + var allData = data.GetAllData(includeXDataAsFirstArray: false); + + // Find and plot max motor angle in radians + var maxMotorAngle = new MaxDataArray(allData); + + var plot = new SimplePlot(); + plot.AddSeries(maxMotorAngle); + plot.AutoSetAxes(); + plot.YAxes[0].Units.angle = UnitsData.Angle.RADIANS; + plot.Show(); + } + } +} +``` + +### Compare Datasets + +The *Comparer* class can be used to determine if two Datasets are the same. By default, it compares the following: + +- Number of records +- Max and min times +- Thermal submodel names +- Node names +- Fluid submodel names +- Lump names +- Path names +- All T data for node names that are common between datasets +- All TL data for common lumps +- All PL data for common lumps +- All FR data for common paths + +Any of the above can be excluded, and the following can be added to the comparison: + +- Conductor names +- Tie names +- FTie names +- IFace names +- Any of the hundreds of StandardDataSubtypes or FullStandardDataSubtypes (by adding them to the *DataToCompare* member) for the relevant common entities. + +All floating point data is compared in SI units with a default tolerance of 1%. The tolerance can be adjusted by changing the *PercentTol* member. Any items that exceed tolerance will be saved in the *Exceedances* member and can be plotted using the *PlotExceedances* method. + +*CompareAssertions* can be used to store a Comparer along with an assertion about whether the two Datasets should be identical. + +*CompareSuites* can hold a collection of CompareAssertions, run all comparisons, and report on the success or failure of all assertions. The following program demonstrates the use of a simple CompareSuite: + +```csharp +using System; +using System.IO; +using OpenTDv242.Results.Dataset; +namespace OpenTDv242GettingStarted +{ + class CompareDatasets + { + public static void Main(string[] args) + { + // you may wish to change the location of the working dir: + string workingDir = @"c:\temp\CompareDatasets"; + if (Directory.Exists(workingDir)) + Directory.Delete(workingDir, true); + Directory.CreateDirectory(workingDir); + + #region Create Files + + // for clarity, we'll just create a few csv files and read them + // in as SpreadsheetFiles, but of course Comparers can be used + // with any kind of Dataset, including sav files and CSR's + + // file 1: (baseline) + string pathBaseline = Path.Combine(workingDir, "baseline.csv"); + string dataBaseline + = "TIMEN,WALL.T100\n" + + "min,F\n" + + "0,70\n" + + "1,75\n" + + "2,77"; + File.WriteAllText(pathBaseline, dataBaseline); + + // file 2: (identical to baseline) + string pathCopy = Path.Combine(workingDir, "baselineCopy.csv"); + File.Copy(pathBaseline, pathCopy); + + // file 3: (add extra node) + string pathExtraNode = Path.Combine(workingDir, "extraNode.csv"); + string dataExtraNode + = "TIMEN,WALL.T100,MAIN.T4\n" + + "min,F,F\n" + + "0,70,32\n" + + "1,75,32\n" + + "2,77,32"; + File.WriteAllText(pathExtraNode, dataExtraNode); + + // file 4: (same as baseline, but different time units) + string pathDifferentUnits = Path.Combine( + workingDir, "differentUnits.csv"); + string dataDifferentUnits + = "TIMEN,WALL.T100\n" + + "s,F\n" + + "0,70\n" + + "60,75\n" + + "120,77"; + File.WriteAllText(pathDifferentUnits, dataDifferentUnits); + + // file 5: (different temperatures) + string pathDifferentT = Path.Combine(workingDir, "differentT.csv"); + string dataDifferentT + = "TIMEN,WALL.T100\n" + + "min,F\n" + + "0,50\n" + + "1,52\n" + + "2,53"; + File.WriteAllText(pathDifferentT, dataDifferentT); + + #endregion + + // Read all of the files as Datasets: + var baseline = new SpreadsheetDataFile(pathBaseline); + var copy = new SpreadsheetDataFile(pathCopy); + var extraNode = new SpreadsheetDataFile(pathExtraNode); + var differentUnits = new SpreadsheetDataFile(pathDifferentUnits); + var differentT = new SpreadsheetDataFile(pathDifferentT); + + // Create a CompareSuite with our assertions: (we'll get one + // wrong on purpose) + var suite = new CompareSuite() + { + new CompareAssertion(baseline, copy, assertDatasetsSame: true), + new CompareAssertion(baseline, extraNode, true), // wrong + new CompareAssertion(baseline, differentUnits, true), + new CompareAssertion(baseline, differentT, false), + }; + + Tuple<int, int> SuccessAndTotal = suite.Run(); + Console.WriteLine("{0} out of {1} assertions were true.", + SuccessAndTotal.Item1, SuccessAndTotal.Item2); + Console.WriteLine(); + Console.WriteLine("Full log output:"); + Console.WriteLine(); + Console.Write(suite.Log); + + // Let's use an exceedance plot to see how different baseline + // and differentT are: + var compareToDifferentT = new Comparer(baseline, differentT); + compareToDifferentT.Run(); + compareToDifferentT.PlotExceedances(); + Console.WriteLine(); + Console.WriteLine("Running baseline to differentT comparison again" + + " and plotting exceedance plot:"); + Console.WriteLine(); + Console.WriteLine(compareToDifferentT.Message); + } + } +} +``` + +## Work with datasets in TD using OpenTDv242.PostProcessing + +To work with solution results within Thermal Desktop, use the OpenTDv242.PostProcessing namespace, specifically the ThermalDesktop.*DatasetManager*. This gives you the same functionality as the “Postprocessing Datasets” dialog in the GUI. + +### Create contour plots + +The following program will create and run a simple model, use the OpenTDv242.Results namespace to find when the max mCp-weighted temperature of a component occurs, then use the DatasetManager to create a temperature contour at that time with TD. It will also display an XY plot of the mCp-weighted temperature, to confirm that the correct time was selected. This barely scratches the surface of what you can do with the DatasetManager! + +```c# +using System.IO; +using System.Linq; +using OpenTDv242; +using OpenTDv242.Dimension; +using OpenTDv242.Results.Dataset; +using OpenTDv242.Results.Plot; +namespace OpenTDv242GettingStarted +{ + class CreateContourPlots + { + public static void Main(string[] args) + { + + // you may wish to change the location of the working dir: + + string workingDir = @"c:\\temp\\CreateContourPlots"; + if (Directory.Exists(workingDir)) + Directory.Delete(workingDir, true); + Directory.CreateDirectory(workingDir); + + var td = new ThermalDesktop(); + td.ConnectConfig.StartDirectory = workingDir; + td.Connect(); + + #region Create and run model + + td.CreateThermoProps("dummy"); + + var disk = td.CreateDisk(); + disk.BreakdownU.Num = 10; + disk.BreakdownV.Num = 10; + disk.TopMaterial = "dummy"; + disk.TopStartSubmodel = "MYDISK"; + disk.Update(); + + var hotNode = td.GetNode(disk.AttachedNodeHandles[50]); + var coldNode = td.GetNode(disk.AttachedNodeHandles[75]); + hotNode.NodeType = RcNodeData.NodeTypes.BOUNDARY; + hotNode.UserOverride = true; + hotNode.UseVersusTime = 1; + hotNode.TimeArray = new DimensionalList