From 3e6b922a0aa14a07c2ff0f5236d6bcfa2092e034 Mon Sep 17 00:00:00 2001 From: German <28149841+germa89@users.noreply.github.com> Date: Thu, 19 Oct 2023 18:57:20 +0200 Subject: [PATCH 01/12] Renaming `mapdl.mode` to `mapdl.connection` (#2431) * Renaming `mapdl.mode` to `mapdl.connection` * Update the image cache * Empty comment to trigger CICD --------- Co-authored-by: germa89 --- src/ansys/mapdl/core/mapdl.py | 4 ++-- .../plot_incomplete_nodal_selection.png | Bin 24046 -> 36204 bytes tests/test_grpc.py | 2 +- tests/test_mapdl.py | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/ansys/mapdl/core/mapdl.py b/src/ansys/mapdl/core/mapdl.py index e6b310f312..5ea89026c6 100644 --- a/src/ansys/mapdl/core/mapdl.py +++ b/src/ansys/mapdl/core/mapdl.py @@ -325,8 +325,8 @@ def print_com(self, value): ) @property - def mode(self): - """Return the type of instance, namely: grpc, corba or console.""" + def connection(self): + """Return the type of connection to the instance, namely: grpc, corba or console.""" return self._mode @property diff --git a/tests/.image_cache/plot_incomplete_nodal_selection.png b/tests/.image_cache/plot_incomplete_nodal_selection.png index 31ba437e1a063a0cfd5a4148dbcb09cd4ca8f718..620a5edb2055cad822c7a85b9cc8043856ac3397 100644 GIT binary patch literal 36204 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 Ji(}R|{x8QCG+h7y literal 24046 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¥Ch8I8qS;x) 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 Date: Tue, 24 Oct 2023 18:34:07 +0800 Subject: [PATCH 02/12] Adding numpydoc hook (#2381) * Implementing numpy hook * typo * Update .pre-commit-config.yaml * Update .pre-commit-config.yaml * Update .pre-commit-config.yaml * Update .pre-commit-config.yaml * Fixing hook configuration * Adapting partially the docs to the hook * Changing header --- .pre-commit-config.yaml | 13 ++++ pyproject.toml | 69 ++++++++++++++++++- .../mapdl/core/_commands/preproc/elements.py | 2 +- src/ansys/mapdl/core/common_grpc.py | 4 +- src/ansys/mapdl/core/errors.py | 2 +- src/ansys/mapdl/core/launcher.py | 6 +- src/ansys/mapdl/core/logging.py | 4 +- src/ansys/mapdl/core/mapdl.py | 6 +- src/ansys/mapdl/core/mapdl_corba.py | 2 +- src/ansys/mapdl/core/mapdl_grpc.py | 4 +- src/ansys/mapdl/core/mesh_grpc.py | 4 +- src/ansys/mapdl/core/parameters.py | 6 +- src/ansys/mapdl/core/plotting.py | 14 ++-- src/ansys/mapdl/core/post.py | 5 +- src/ansys/mapdl/core/xpl.py | 3 +- 15 files changed, 113 insertions(+), 31 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 6036af92c2..eb59122236 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -7,6 +7,19 @@ repos: hooks: - id: isort +- repo: https://github.com/numpy/numpydoc + rev: v1.6.0 + hooks: + - id: numpydoc-validation + exclude: | + (?x)( + tests/| + examples| + doc/source/| + src/ansys/mapdl/core/_commands| + src/ansys/mapdl/core/commands + ) + - repo: https://github.com/psf/black rev: 23.9.1 # IF VERSION CHANGES --> MODIFY "blacken-docs" MANUALLY AS WELL!! hooks: diff --git a/pyproject.toml b/pyproject.toml index 900e10a19f..99eab51f26 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -155,4 +155,71 @@ show_missing = true skip = '*.pyc,*.txt,*.gif,*.png,*.jpg,*.js,*.html,*.doctree,*.ttf,*.woff,*.woff2,*.eot,*.mp4,*.inv,*.pickle,*.ipynb,flycheck*,./.git/*,./.hypothesis/*,*.yml,./doc/build/*,./doc/images/*,./dist/*,*~,.hypothesis*,./doc/source/examples/*,*cover,*.dat,*.mac,*.cdb,*.CDB,build,./docker/mapdl/v*,./factory/*,./ansys/mapdl/core/mapdl_functions.py,PKG-INFO,*.mypy_cache/*,./docker/mapdl/*,./_unused/*' ignore-words = "doc/styles/Vocab/ANSYS/accept.txt" quiet-level = 3 -ignore-regex=".*codespell-ignore$|NORML|POIN" \ No newline at end of file +ignore-regex=".*codespell-ignore$|NORML|POIN" + +[tool.numpydoc_validation] +checks = [ + #"all", # report on all checks, except the below + # "GL01", # "Docstring text (summary) should start in the line immediately " + # "after the opening quotes (not in the same line, or leaving a " + # "blank line in between)", + # "GL02", # "Closing quotes should be placed in the line after the last text " + # "in the docstring (do not close the quotes in the same line as " + # "the text, or leave a blank line between the last text and the " + # "quotes)", + # "GL03", # "Double line break found; please use only one blank line to " + # "separate sections or paragraphs, and do not leave blank lines " + # "at the end of docstrings", + "GL05", # 'Tabs found at the start of line "{line_with_tabs}", please use ' + # "whitespace only", + # "GL06", # 'Found unknown section "{section}". Allowed sections are: ' + # "{allowed_sections}", + "GL07", # "Sections are in the wrong order. Correct order is: {correct_sections}", + # "GL08", # "The object does not have a docstring", + # "GL09", # "Deprecation warning should precede extended summary", + "GL10", # "reST directives {directives} must be followed by two colons", + # "SS01", # "No summary found (a short summary in a single line should be " + # "present at the beginning of the docstring)", + "SS02", # "Summary does not start with a capital letter", + # "SS03", # "Summary does not end with a period", + "SS04", # "Summary contains heading whitespaces", + # "SS05", # "Summary must start with infinitive verb, not third person " + # '(e.g. use "Generate" instead of "Generates")', + # "SS06", # "Summary should fit in a single line", + # "ES01", # "No extended summary found", + # "PR01", # "Parameters {missing_params} not documented", + # "PR02", # "Unknown parameters {unknown_params}", + "PR03", # "Wrong parameters order. Actual: {actual_params}. " + # "Documented: {documented_params}", + # "PR04", # 'Parameter "{param_name}" has no type', + "PR05", # 'Parameter "{param_name}" type should not finish with "."', + "PR06", # 'Parameter "{param_name}" type should use "{right_type}" instead ' + # 'of "{wrong_type}"', + "PR07", # 'Parameter "{param_name}" has no description', + # "PR08", # 'Parameter "{param_name}" description should start with a ' + # "capital letter", + # "PR09", # 'Parameter "{param_name}" description should finish with "."', + # "PR10", # 'Parameter "{param_name}" requires a space before the colon ' + # "separating the parameter name and type", + # "RT01", # "No Returns section found", + # "RT02", # "The first line of the Returns section should contain only the " + # "type, unless multiple values are being returned", + # "RT03", # "Return value has no description", + # "RT04", # "Return value description should start with a capital letter", + # "RT05", # 'Return value description should finish with "."', + "YD01", # "No Yields section found", + # "SA01", # "See Also section not found", + "SA02", # "Missing period at end of description for See Also " + # '"{reference_name}" reference', + "SA03", # "Description should be capitalized for See Also " + # '"{reference_name}" reference', + "SA04", # 'Missing description for See Also "{reference_name}" reference', + # "EX01", # "No examples section found", +] + + +override_SS05 = [ # override SS05 to allow docstrings starting with these words + # '^Process ', + # '^Assess ', + # '^Access ', +] diff --git a/src/ansys/mapdl/core/_commands/preproc/elements.py b/src/ansys/mapdl/core/_commands/preproc/elements.py index d9645fc769..3fc1304ccf 100644 --- a/src/ansys/mapdl/core/_commands/preproc/elements.py +++ b/src/ansys/mapdl/core/_commands/preproc/elements.py @@ -1241,7 +1241,7 @@ def eplot(self, **kwargs): APDL Command: EPLOT Notes - ------ + ----- Produces an element display of the selected elements. In full graphics, only those elements faces with all of their corresponding nodes selected are plotted. In PowerGraphics, all element faces of the selected diff --git a/src/ansys/mapdl/core/common_grpc.py b/src/ansys/mapdl/core/common_grpc.py index 16c242f1e4..62408fc188 100644 --- a/src/ansys/mapdl/core/common_grpc.py +++ b/src/ansys/mapdl/core/common_grpc.py @@ -104,7 +104,7 @@ def check_vget_input(entity: str, item: str, itnum: str) -> str: Returns ------- - command : str + str MAPDL formatted vget command after the "VGET, " in the format of: "ENTITY, , ITEM, ITNUM" """ @@ -158,7 +158,7 @@ def parse_chunks(chunks, dtype=None): Returns ------- - array : np.ndarray + np.ndarray Deserialized numpy array. """ diff --git a/src/ansys/mapdl/core/errors.py b/src/ansys/mapdl/core/errors.py index e61fffbaad..023e99b455 100644 --- a/src/ansys/mapdl/core/errors.py +++ b/src/ansys/mapdl/core/errors.py @@ -1,4 +1,4 @@ -"""pymapdl specific errors""" +"""PyMAPDL specific errors""" from functools import wraps import signal diff --git a/src/ansys/mapdl/core/launcher.py b/src/ansys/mapdl/core/launcher.py index a50a4758d9..a11834df37 100644 --- a/src/ansys/mapdl/core/launcher.py +++ b/src/ansys/mapdl/core/launcher.py @@ -1079,15 +1079,15 @@ def launch_mapdl( ``log_apdl='pymapdl_log.txt'``). By default this is disabled. remove_temp_files : bool, optional - .. deprecated:: 0.64.0 - Use argument ``remove_temp_dir_on_exit`` instead. - When ``run_location`` is ``None``, this launcher creates a new MAPDL working directory within the user temporary directory, obtainable with ``tempfile.gettempdir()``. When this parameter is ``True``, this directory will be deleted when MAPDL is exited. Default ``False``. + .. deprecated:: 0.64.0 + Use argument ``remove_temp_dir_on_exit`` instead. + remove_temp_dir_on_exit : bool, optional When ``run_location`` is ``None``, this launcher creates a new MAPDL working directory within the user temporary directory, obtainable with diff --git a/src/ansys/mapdl/core/logging.py b/src/ansys/mapdl/core/logging.py index 2c9d38c3f9..e695181047 100644 --- a/src/ansys/mapdl/core/logging.py +++ b/src/ansys/mapdl/core/logging.py @@ -10,8 +10,8 @@ outputs and it is used to track the different MAPDL instances. -Usage ------ +How to use +========== Global logger ~~~~~~~~~~~~~ diff --git a/src/ansys/mapdl/core/mapdl.py b/src/ansys/mapdl/core/mapdl.py index 5ea89026c6..1ba922e538 100644 --- a/src/ansys/mapdl/core/mapdl.py +++ b/src/ansys/mapdl/core/mapdl.py @@ -3002,6 +3002,8 @@ def run_multiline(self, commands) -> str: This function is being deprecated. Please use `input_strings` instead. + Allows to run multiple mapdl commands in different lines in one go. + Parameters ---------- commands : str @@ -3642,7 +3644,7 @@ def directory(self, path: Union[str, pathlib.Path]) -> None: @property def _lockfile(self): - """lockfile path""" + """Lockfile path""" path = self.directory if path is not None: return os.path.join(path, self.jobname + ".lock").replace("\\", "/") @@ -3885,7 +3887,7 @@ def _screenshot_path(self): return filenames[-1] def _set_log_level(self, level): - """alias for set_log_level""" + """Alias for set_log_level""" self.set_log_level(level) def list(self, filename, ext=""): diff --git a/src/ansys/mapdl/core/mapdl_corba.py b/src/ansys/mapdl/core/mapdl_corba.py index 39f1bf3f0b..e596421797 100644 --- a/src/ansys/mapdl/core/mapdl_corba.py +++ b/src/ansys/mapdl/core/mapdl_corba.py @@ -414,7 +414,7 @@ def _run(self, command, **kwargs): return response def _close_output(self): - """closes the output file""" + """Closes the output file""" self._output = "" if self._outfile: self._outfile.close() diff --git a/src/ansys/mapdl/core/mapdl_grpc.py b/src/ansys/mapdl/core/mapdl_grpc.py index dce09f08b2..b13e3e5ed0 100644 --- a/src/ansys/mapdl/core/mapdl_grpc.py +++ b/src/ansys/mapdl/core/mapdl_grpc.py @@ -1,4 +1,4 @@ -"""gRPC specific class and methods for the MAPDL gRPC client """ +"""A gRPC specific class and methods for the MAPDL gRPC client """ import fnmatch from functools import wraps @@ -2473,7 +2473,7 @@ def _get_array( kloop="", **kwargs, ): - """gRPC VGET request. + """Do a gRPC VGET request. Send a vget request, receive a bytes stream, and return it as a numpy array. diff --git a/src/ansys/mapdl/core/mesh_grpc.py b/src/ansys/mapdl/core/mesh_grpc.py index 2568606fe0..f29849a62b 100644 --- a/src/ansys/mapdl/core/mesh_grpc.py +++ b/src/ansys/mapdl/core/mesh_grpc.py @@ -543,7 +543,7 @@ def _load_nodes(self, chunk_size=DEFAULT_CHUNKSIZE): Returns ------- - nodes : np.ndarray + np.ndarray Numpy array of nodes """ if self._chunk_size: @@ -655,7 +655,7 @@ def _load_element_types(self, chunk_size=DEFAULT_CHUNKSIZE): Parameters ---------- - chunk_size : int + int Size of the chunks to request from the server. """ request = anskernel.StreamRequest(chunk_size=chunk_size) diff --git a/src/ansys/mapdl/core/parameters.py b/src/ansys/mapdl/core/parameters.py index da1dda442c..3b7487184b 100644 --- a/src/ansys/mapdl/core/parameters.py +++ b/src/ansys/mapdl/core/parameters.py @@ -535,12 +535,12 @@ def _set_parameter_array(self, name, arr): Parameters ---------- - arr : np.ndarray or List - Array to send to MAPDL. Maximum of 3 dimensions. - name : str Name of the array to write to within MAPDL. + arr : np.ndarray or List + Array to send to MAPDL. Maximum of 3 dimensions. + Examples -------- Load a 1D numpy array into MAPDL diff --git a/src/ansys/mapdl/core/plotting.py b/src/ansys/mapdl/core/plotting.py index 27a7191ba1..490ecb9bbb 100644 --- a/src/ansys/mapdl/core/plotting.py +++ b/src/ansys/mapdl/core/plotting.py @@ -224,13 +224,13 @@ def _general_plotter( ``off_screen`` are evaluated to ``False`` and ``True`` respectively. - style : string, optional + style : str, optional Visualization style of the mesh. One of the following: ``style='surface'``, ``style='wireframe'``, ``style='points'``. Defaults to ``'surface'``. Note that ``'wireframe'`` only shows a wireframe of the outer geometry. - color : string or 3 item list, optional + color : str, list[int, int, int], optional Use to make the entire mesh have a single solid color. Either a string, RGB list, or hex color string. For example: ``color='white'``, ``color='w'``, ``color=[1, 1, 1]``, or @@ -241,9 +241,9 @@ def _general_plotter( Shows the edges of a mesh. Does not apply to a wireframe representation. - edge_color : string or 3 item list, optional, defaults to black + edge_color : str, list[int, int, int], optional The solid color to give the edges when ``show_edges=True``. - Either a string, RGB list, or hex color string. + Either a string, RGB list, or hex color string. Defaults to black. point_size : float, optional Point size of any nodes in the dataset plotted. Also applicable @@ -594,13 +594,13 @@ def general_plotter( savefig : str, optional Saves screenshot to a file path. - style : string, optional + style : str, optional Visualization style of the mesh. One of the following: ``style='surface'``, ``style='wireframe'``, ``style='points'``. Defaults to ``'surface'``. Note that ``'wireframe'`` only shows a wireframe of the outer geometry. - color : string or 3 item list, optional + color : str, list[int, int, int], optional Use to make the entire mesh have a single solid color. Either a string, RGB list, or hex color string. For example: ``color='white'``, ``color='w'``, ``color=[1, 1, 1]``, or @@ -611,7 +611,7 @@ def general_plotter( Shows the edges of a mesh. Does not apply to a wireframe representation. - edge_color : string or 3 item list, optional, + edge_color : str, list[int, int, int], optional The solid color to give the edges when ``show_edges=True``. Either a string, RGB list, or hex color string. Defaults to black. diff --git a/src/ansys/mapdl/core/post.py b/src/ansys/mapdl/core/post.py index 57022832d0..702a6c676a 100644 --- a/src/ansys/mapdl/core/post.py +++ b/src/ansys/mapdl/core/post.py @@ -113,11 +113,11 @@ def _mapdl(self): @property def _log(self): - """alias for mapdl log""" + """Alias for mapdl log""" return self._mapdl._log def _set_log_level(self, level): - """alias for mapdl._set_log_level""" + """Alias for mapdl._set_log_level""" return self._mapdl._set_log_level(level) @supress_logging @@ -1346,6 +1346,7 @@ def plot_element_stress( **kwargs : dict, optional Keyword arguments passed to :func:`general_plotter ` + Returns ------- pyvista.plotting.renderer.CameraPosition diff --git a/src/ansys/mapdl/core/xpl.py b/src/ansys/mapdl/core/xpl.py index 1d5b219877..5c305a0e15 100644 --- a/src/ansys/mapdl/core/xpl.py +++ b/src/ansys/mapdl/core/xpl.py @@ -362,8 +362,7 @@ def save(self): return response def extract(self, recordname, sets="ALL", asarray=False): - """ - Import a Matrix/Vector from a MAPDL result file. + """Import a Matrix/Vector from a MAPDL result file. At the moment, this only supports reading the displacement vectors from a result file. From 758d51b83f4b6c10f3e52bc9d1aa37227abd6c79 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Tue, 24 Oct 2023 13:44:14 +0000 Subject: [PATCH 03/12] [pre-commit.ci] pre-commit autoupdate (#2440) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * [pre-commit.ci] pre-commit autoupdate updates: - [github.com/psf/black: 23.9.1 → 23.10.0](https://github.com/psf/black/compare/23.9.1...23.10.0) * Update the image cache * Update .pre-commit-config.yaml --------- Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> Co-authored-by: pre-commit-ci[bot] Co-authored-by: Camille <78221213+clatapie@users.noreply.github.com> --- .pre-commit-config.yaml | 4 ++-- .../plot_incomplete_nodal_selection.png | Bin 36204 -> 24046 bytes 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index eb59122236..645b976e28 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -21,7 +21,7 @@ repos: ) - repo: https://github.com/psf/black - rev: 23.9.1 # IF VERSION CHANGES --> MODIFY "blacken-docs" MANUALLY AS WELL!! + rev: 23.10.0 # IF VERSION CHANGES --> MODIFY "blacken-docs" MANUALLY AS WELL!! hooks: - id: black args: @@ -31,7 +31,7 @@ repos: rev: 1.16.0 hooks: - id: blacken-docs - additional_dependencies: [black==23.9.1] + additional_dependencies: [black==23.10.0] - repo: https://github.com/PyCQA/flake8 rev: 6.1.0 diff --git a/tests/.image_cache/plot_incomplete_nodal_selection.png b/tests/.image_cache/plot_incomplete_nodal_selection.png index 620a5edb2055cad822c7a85b9cc8043856ac3397..31ba437e1a063a0cfd5a4148dbcb09cd4ca8f718 100644 GIT binary patch literal 24046 zcmeFZc|4Tu+dqB{vL##ggis+OTV&$$QYjl4;pXd2L-{zeaA&trYRkK?!sHaexdjah&hL6B|w zdfLVaLI;1OMHp$|L#gYw6@r{E(APdBnd<$%jpq>(`4xb3};VAXP^rGeUvRxYVbS<2ukeDkD;_j2 zCL0>caxh`_PhYQUH4a-B9uYr1%cWUDiF*1pD1K{@yXw5d@#FWKp5?nX^bMZm4tKwD zaa3dehvDeXuDG6~2>~m*9EY#u1d#5@Y<=iAVh~gt9v@z8Yd;iX4B!-e0z zy)84HG|QHZj4i{DF0~bqr<1B*`?9G`N_GjZjx1aoZS7^y(W+QqZfMZG_r}I`ZIG6- zVDh2kyuwTrU!|&sMs!@c$MnVXhwwF5x)g*DsH>|V2=HDxhBsWk`}%p$(l@`-8=g8Q znuqOlsZuIzKJmPNhB7$698amPJUir?W++&!am67nZLBJZS2STcER-eTP{)ml{G!SD zjnm}l+fkFRUR{bQoFbOhuFsG=BS!3X>bb}H`9%kto1>!_;K_qk)oYds+$?J|KZKe; zeAuyLhvfx5PtBUios^+KywlnoZJL6Dpk9X1;kO>c0)dq@b+?7k&Aj&fCV0cq=knYX zudwt&X!WFeC&L>qmoDS8opR0vpFWl;_4^Lkq`gdyQ<+^F6h2e@+DzN$&0F;q6Mf5q zkDm5_CVqGaTptKAk}xqYbe=W{@hr}(T;CV~p~@OkcKbODwLWZore&ewh(1l)-M@N7 z$$9Jgn?iS)p17EUpXTRY%4+HvG2*D}$BL{sq?*0tH|&vp#bI>+z(sw1{nzO~`a3-A#(cukaGrSg z(S>gpKEL$fDE3LsTKsV_fO5^s=e<~%MsaTX3GF`L^_i{8Pq|#BG}r4H`htCL5j16F z#N6AzlL{6GqVC^}b6&fUSn2F@*|=_?xmijw%PKsEvKlNF*6!c`OOmxREoO-+E?f*|5J@ zor{HDLE(H)Vdqnqtdbw?-@C7Nc;mGMS&Mvie*fzC*4*%RxN-K=+F&gAYoGl^Ck+i> zzI>V0*rI8%9Qfzc`p6E-#i|*$%K1|dR>2HI{gdj8 z-D-xj{uRNm^!vYG-*J&UJG{fa>v43n7wP-3j>h0p)}&~jsP|&?vvy}@`B=-|^P{5u zUd}6P--bw8Jwj0=(&>FNJu;%@<~?GvKIQf;7d7-x8uXO78r~Nho*J)QAq8;E_Aaw- zvnDOnYMwG&RpxnSYBJqqQ%>&qQ>E%o9t~GLIMS!a$5OFA;_h1_d%?lsxtnjw1!vP^ z$42V6CKSc03au8t&<*J9?t2JWA)&eBz8Z>ax5Soku(z{Jj-#l^)bd6|A;V)dWDY>e}!^|@XmD=H~v zWtNrPICHmCb%|U`X_?#^GG2J_-df3irEKdnIprP{5Q?s@Tg7^Z`(A%*j#u53=J@Ee zFAA~a{H^LrhV6nkd^-9O1=MO)Q2Q(&4IWVtE+~j)$!?FjI=b|T$XCc%dhYP@OqlG# zg#XM+)F;Z|l|#y0ZV$^UF3m5shQ2KIb{`!X3Cez35UZ!JFVkJ(?3C_(Nz>r?@#B{- zfA^m`8d%)nt1td`CU+E~kHx6uep8urhfKauFHrW1TfEwn(?c1^Pl>bPW^a&_>aqt$GfJC*SkZq(oXp= znf0F0JVPYU5s<$DiZgldCTcWn(EWqtizRLRhc*EwAEt1}NJU zzg`;a$!1;f9v#jib$rEh2h=Xbt@r!SS1RIHKUeP+NUn61;PRVO#VaZFD0ujeJz=AC z`7QmTWtaq)BI>Qz%W7XR3#kvRw0=>E2l-jlzLZh*Fn=>$@@>lh-8HX6#@gas%mRLu zwH%MzGM#zP8pa*=U+B`stN09gYxLJG#W6T$z3#5?OsE}rcV#;N&+~vv{7~z*PirTe z)=$Gv?`g4Zb9Csl;wbL&kmqB0v&iK?>PsP=Sd9q}FP<4_Ke^w$H9mT8+Dkuwb5+OQ z)scr4i(6vEUgJ5s&lwj>^()K||6Gi}9zWPPVWVAWsrt0(h?NoS_ zyt)e*#6CC#sce`t3uCx z>*IO?Ik!;b+`{Rzoqzhy;_-79zq~8fWgYjwu_`#Feb4<|$d78z{WEpyX$sCAI+gg6 z$|8l`yLXp;7x#!s%z66st?BAykh}F(`anrZ$=|LCL0U<1rEL30)BdcMRpaFL?Ngl_ zv@$$B@II?^t+a2W!5j?dhxvMM)GwMjv#c23ClBj~FP^Hz+ovD=p~>#$nQo{pn%yiR zALZc`jo3H6sJR1JU5$>{lzcB<{;Li_( zg`$>^&GCy?W-ooOUAs{+6a5f%hQzSu6Xx}y{x${v0mZK!Mv@i24qtQZE$gmqJlH2V zv6XJa({Sp0L7LkipHKcXU1Caxt)=~yL=!W0uc=@7DHqMN7547#hNY^io#iP@{ru*# zHeBHk>mBmn%=k~0s=gO4y+W@0xwvnpV$mj^+-G?H&6S;MzJr69Ap4FoT_Y_~P8Rx+ ziscw4h9LXt*ZJ@A&F?oxe93q=UvN%Sjjln>M&rkW1M~4??y5y`VoEap9kCy7_wQ(l zfvw}XhgC11o95XaM zrIeqZh5@75w{KMqw=%RehnGpRlpNINyq=``$5^5>Gn>~UXhf-uWhQB>^ z@92V~LY6-9=?af~bot|pE#GT)94#mL$A$A|TNm?LQ??gY;N~Az_mTU8JZjn&|^15=_81LTj zelYLm4!B$MFC7%Xm7wLxqv9}17l|^EF%&Tc>W!snUxm)kp$?tVYu=I7MsgZ^J zWJ`>J*IPwl%FkX(VZ{}LcLha|lvZ|w2NzTr6uDW?bGdkwn*XR!SG-o;LNQwk=*`^;BQR_4vj5UE$9Dalh|i!{zWo;G zwH`exO5OJRO@JMs50ANkp?ckA|BD9Wt&n_rE0pB?@@=%gd{JO#Hn_Z`S=z{fv1LfO zF&p=uG8*z^Mx*nO`5`hp*Y%i~n97-|{EL+Wfnd-=KRVDx9$JgqUA%^}-UTdBGb0xs_kiM`Cqe)-SZO5MpFqw~iCe!YCW(^ts<@?o*5DW{1E zCsw?jV??RndSA=#X9u?RaZweKKK7YpxSp0Kmi;zf9=AlElP3Vu}fn~#IGhM37arVo{d`e_9ElX$HiiBLg z*eo{w5+)5(Ca0XfpDXz~{4pweZcAYGHl0+I7BqF0_2rWLS~uFaTsI_1_&JPD2LfYi z041DlTE5^|k}T{u_nD3b9<|lURU`iKV=J?Yi_-=JVxJ&Z?4Pr9?Oi^a)YiU_S7+!w zE}NKXY0i~hyMX&ES$?=+jFS zlM{i48k^SRot5qB&==i&qO&a9OB?$XXy}+~3y{sfP8+v${->vjc6D<4E>r*lQ)pGen-Onds zsCJRm^V64^=r*327HloI1p-^V&)oaG%IN&fB2zU17W$r^Q*72VA1re(n^x#*drfO7 zs;d{IUc0zL3R5T70HEDDHdCQ0Kh^r76yQl_na|5LwjN`vcF*Fh(YbmDdZe~`uQ0WC zavaRVLnXh%hsSw<)ZtB@7|MN5?lT~jKd&(tWYzusOZE;$RgI1PmCwvqT2iln`E#@3 z?5%ih2v>dwy@-weGw(XrTRsMOFEMj)Fx5N%(LaXnpHOnljjeY%)IIx0%w8l+WSW*YzOrn4Yx18MzN z>Fb2Z>qWAfniC$QM7?*WB45m1(~c%R@*cE4WPj)6gMRLC7w_pW^a+ZwwCE{yPM%zy z{!uX?*`>C;JK6YhF?^i!&UIKCG;3VK_+Cxa?->z|WR?)Cmd41X=TS z*$sJH{R`XZqlPME z$L{6B20S_smXhjJR#L8(t^ASN2U4);+<{+v*nQOEjW9VM@4m#Y*sv)a7`&`qO{ijc$O-2LH8zLd;!i zsgiKaf`)FhS_xH3+#PhqM7Z*RTC!BsLI{6vV?^Y%5)Q#t92^J!ak|5g@KMhPMNjJ9 z6l;#)afxn2$gM&qyK&3@NXvhx=8y0s`GSh3P-?phY{aDzyEur{n&qwgh5bI z!P@`2n;zLz9w>|-zDFMBY?Jsaw;E0nzFp{dPO$s`UA${`s7(ITRQ|20s{L-P>U%_A zh&eY4HRf^g6cC9`{_Rt@5F>7eTh&l ze7FaP%1n>`en3d{xDZbbf{fip5RuaoYf1{<`*uA>5=A%7K_p&c?KffC7RgbBg$^+a ze>C{)e)Jj}?Z+f0KGX>!>Q!^ct@`&b{kf%mjZO0`S{YIW%6BBUFS{3b2)8s=; zp!(0gBLlB3Tjn`dT@qRlf5tIvOU}bhvjSOYhkOw>@Eo*QtybAZix5O%SIJt7VZ)3? zbUA{Idi1O`fv9KEf{b;;)GjSa;BF2KW2e}ek(Xi+U0B%295%XPZJdZWUnzpBy6Uz{ zPvs{e3Q^UIaSLb2rdiGZtk&er$Wp4zTC~X(WJFFJiD4vkr<2141^HOS@6_6^YU;^> zDffBv-sQYg<*PN1R}zU#sUO!xz9i`+OB$s2Ad4$RZU(C8ayP&XQ8q!nsC&S z4eJdHSxb;?xuqFs2y~!WWvxXvXWJknoTTCy21hSa&4>_WjMi$CyLNFQgQ1}9unA$a z2G%4j3*5jMt&a4Na zeDe>ROzu$$909i7VFRjW&A^ZSuFLh9soRsUi$TmFe|3(8As#*88VOUi8c3S3l*e{77N&rpK zP;8Y%%Lhf`Q260KmxnZn7vzHnfA-NhIb6E{c>;NSE7c9jxd6e_DoKh4DSbgTRf2{S zct7|d5v7y{qO&wrUm!<}1&UQ62!w5R2o4c%&U=;WlxW94o(CI42wgpPPQ|7)E1ccsZk6j4&~VK@_Wf#)eAw%ZqrNOfetI9(vndi$O%B zU<=Vd8FPl#U&T`1us9OSBqv*hwjzEHg%H#M;hNl;GTm`DtPiF{@$f z2*Uhj7jmarh%f@`V?{TwhJ_>%O@NJ3qgWe8mr#8VqC%5Yvk+aP$WBM(kp(qnPy>G= ztqR=Amg4m1#zEW?q6l3D=`dCtQgv`M5mn6{qG2fQZ@(ffTQw=X$rn&XZryJYfwIQ)nWMRit%h z%EaDW>^+E|oWCj7U-{}nL%eQ+RSkpXRt%D(EC9P_`<%pdV-Z&yhnLiqIlzbptsY30wY6cyb*n3Zh@W_Nq*_bgu2ctCiH-Zm4Z7 zEw!Jm6C$pCj=6S6=02+t21^dm8P4=t6>Xusvhu{0LwV=A!+CqVi$w?H_+l1EzJ2@F ze8Rggqk!%F34`q%3GQ0jZrj+1dTwrHXljWS1x0KeF{|SgshVgdsyT1$#~%GHnx@_L zhwesXg*viHS~TNo!{vV`L|?yZe|7c!;G89IwoU2Om6Uhq4vTttFGLU($>RqHm@rf> zQ?>|`&LUe^J=Cq~vzMFwER8H4$4|4| z9eLGsGzoW4!82)nVcDA5oMMQdNt3imd$Gw!hEh7+1>!kN3!PVj^47+Y_w8b<;J+|Q@v>RKvOEYmZ!c- zQ1~>7R@vOxYPTqyR`_P_coUmW%8hw1j@i|+xScI$&Q$y{=v-6%%AJ|i!Tkd-PqWm0nvE2zzgbj(BHF(Uo*IT`LfP%1<1H@9m*2k z#pW)r(<{COERBWtbGu8i-PMAw&x~)wKB;A3^g0)2+45Atpj`KRulYUyfV91L4W9?O zu`FyuM2-JPtZ)ANhqv|QBp1^b8ZuO_T6``6?Y(q~|NlWJ4D3iE`#j24zBD<8VXE>r zR@sVpZVX$>Bhu4_jhZrZbNP#s`@O%=(^}N-P&JEDzcaixP=A-~y=}G{($Rqt4DJ$r zyCz}vk~%HnT_O`-PT9wdo939ipSQDwTuxhKAkYEKZWEeEas&(4=^~Cicg2Pu0{fmr z?fZo68V@|_&V;aqPy`hxi<&`m%BEr?$-ACl5=B_owhRVA4qXVQRbI$w%;~mA9HqbnT%v5cJZlqQ@5ydHT zfh+{NfkYd`2=$yJUZ={)GEXq<-ms#_XId&c&wqqrmo3t1Jwu`;Tn3~zq9WySbcln4 z!_sxm0;hjoRCKPm@#zOzj0+K159COdE5%=b`8Te0w~=nfS&ZVM-8 zXVWzcvf|DvVrt=mRb@1yuSDmrvqUn{ies8N1G?}XL#F`@9)q-B?)Dg|IM&OSet&b> z==99v?#^+c{Uk?6WJGBn6QgaF(8&Hd3}V3sOL=JTxwTEyS)WG5c)^zPQ4JVOdhp+0 zT0}kH#o545u=uQ)DXcRYfKd z2$r)=F>}vE0FomH;3{}Z&|t&!rD@eQ={d|bU4Z%)$#%#izhI5p>n}|S;*SK?rWnwy zk0=g!q=7xBCS5v|RH7Krl@M2}brGk5vP}#^P;n9n4f!J~49`JEAk8O=MBjT((9uA& z@0= )K0RK&?P2^x~~8+Qz@Ui(s7_SFbJ5L~g=PBm(>Oia7e~2mpswR#QI|PxP{h zFmEp3*6^{6g`*_`k=gHY%P5KXW`|9Rg;%&?^1&xt5a})OeEJfdHErn1G$V^;V=#1?uw3lvk)yJatvI>_8DIy z+w&MDphZ=iJyijeW~^{ya@d`J4>)CghVUW)ZUF)TE>6XKsd@L6;s0~^;A?3uQY{L3 z?0H2{)3LGyP0711Nf7S5&P=Yu@SyMs#RvpoE~vfcFgnX%@;aO_A_vefw#y|xn-VlG z572UC10ix>-U9bhsV0C+M2{}ikrvSb;ObOA96ECt2?&4iu1_xM_5$3cj>y%qz~_G< z$gqWySE!ji?6ky5|GJlKHWH;ygSAA>_1{H`F-HgMdwON)smy9O4~4tRW3}Z%QqsRq z3wxvT-H!R8Ms@E~A9<$*^BHK;(a=E$@VWc&EXjN4&ucOgPG={_k~$71q-T)cra$0A z)F1}HEeK)JCBl}&vfpQ}A!~0irt0Y51MhgQ+B>x?^6nm7j1_uO*P6uk`{eqb_sxJ) zEvQP^DYpYrs{#*)5&)rowM7VFrv*t=u`3{ids45z^jIC<%Cc1Ng1G#Jwa9`t3*qEu zG{jx)n8A5p~i%=Eq0H2Xn=bz}b#;IIH{|HqhiAm3H@{2+Nq2jb>X6~^e zmIH{_UtLx0CjyX055Ud+@zrj;>;WX&9?Aik@7{0`ZcW9mIQlvlV35JuyZQB@;vEaZeGzwNdia0xou(8u7?$`|7ZI7Db+?LppkX`gx;msh8{6P*N zDk5N(uj>%xM&nw?6HSddDVZAN8cJr;K4vTwcHD^DGQ#_T_%#b@!YLzWI-nM?4eZ`2 zi_2RppAM-8~w>67WNMt`R#zd+85&n_uN*PT=g4;d*HcZUh@g2-*WvatN~>#wMy+;*~hj^e2B9cy@>ulr6xTgo-G);oscb(ZIjLuZYyGr`Zv>y+(J1% zl%iZ6Mj!o2N^6mKSz;dy>_(86i5j4%6L3o_x&%r+siuh#c@7{~k5cV~AaS*d=h2lq zqz(fW2FM;r`ffqmcB(eyg~h-S+qPYexUr61EIwx29&PMFsCC3t9KHU)I2Sh?(Jb;93e${5_#Y%aPapjA&3`2qr=4&oy@JQ;V}~=^@=vIoQnW*o*rQ>e^wHYg`b56EIY)W~?RsS$pNG>9Ngv z&e&-S+K3}8IkKCXyM=l(4<5dSSp(av1}sF3m-gR47cEBL1*Gek6Ais$k-ThZnzyBc zSYl!~En=ehRn%n(i$p#^3u-PG{3kz9zWL0ZIA7}=FPh(QyAB5xIL5iVN79ZEzgeeAES`!zL{?Z1smpzV2;?6xWkl~Hfk7aIZ-UO!7h*)zbGEXh7SdAu zW89H#*D8&u^2V!M!*)eRCxM9HF||XI8%kL7QIf0W^)bEsXxoowx1{wwhdj5nZAXi9 zIAup#=?7reP%Lb-ap0b`g^ZJrAw*E?w;{I5Rd#<3s;-XH6^Y;z#~o;JMwV2Q0Vrule;g?u$9@HFb00m6IFyS1K=VOK562f9oEor3`o?WnRQrmb#*eN$R(jT&*$V3#iIL* zfthzfSjb=)A5OsE8#CwA0Q76#ocEjh;)_4eU^FCPZ9uqmzmmI5|C6Zk=tc4?NgFx7 zA4Vo6mzqK&-MCrk?bbw^KKngp#Fkxs&qLq?{cRXRlckX9xKvQ>9G<7mcQ~0irT)id zs6LwXiKu7jJ^5p~pKppgTxoJ7I5DJOs)I_vaa*66dY#?ErRa+&H}q=?)wm_;JNT@| z=OA+bo%qfaO?Lbt5Qj!aVAf61!&hSMZ2j7ih+0k&1bK92iYHoaD{q_GL3Q=s!RU?VCW+9r0 zP(H$ixl=#3hr=w7Ymc)a%*^nfvMKkwI#;m_E$bGc=noJ!?CM!#kchi{k1R^uX$8tb zYA{mgD%s0Vp37~pSsDCR3cWCI-Kl`YLl^}4#+%}>b!`_t?&@;+FYB3uTcK65Pa7td zNIRj?6LUTFU%j*Bccv`D7Y;)X1Mp&prE&T~d!=Ih32-b08y>ERlr+_&NjE3vs6DRO z>sO(nKh>wV8d@IC`}NBgXhhEDhS$3fC&Y)612Z8)b!mB>5~SpwwPP~E*17Ev#_$|t zA&R*Qo%?kD6~(k?+(=?5?%k+Ic4YCP0|DmRdA-H?eSW`=^|v?i8Wc{S`m{2F`2GhI z)o~kUTX{hd*=KhOB7uah|D?V$%lQhUMo_x(|3XDII3%;vIj+X4_3^EaeA4u78o1&j z)m^cY#j;61U8;vit{y_1amu(Tnl+)WvF2;fo|$`lDV9@OVWu+Te&bK=5Um}!WM z+Rss}uGZG!Aqta~F!u>HpB||U*@6UhnDnZT`FJ$RXr_H>y>IsZNB^iOHxA1UvyjTm z*HMWk3fdtf|8pbB{CAmq-|0n*rTb+tQSh7h(;>mZYb8sa8sqC1r-|5KeRQtRXo~bK|$+y|rc`qEckVZOyCd2$9!W z-Iykk=CbpD4;z?Fn4IdW|0il8OQbAk-o==NHc)ZAr{6hx$m_KnWDw`6n*K8 zgicl=5mnT{m-1$%N%!#;FTNZ)h+tmfakZ7+h|gdfK~F%K?%oZ^<2fPUbA26w-Eb1S z5s~9+9CQoIPm(I4?H`KHResP6`zk{#`s!*4H+x{5{N*Kf=!4NBM*&@49Psq40g~Aj z6laexT&jjF+xE30IQL5~hwpRpk(ZK4Oui=z!gB;NuVVhl#R!{^b=h@s3j?^-8;K0k zalLj3@B#E!AGK2PWve>!oD@lf{h(I}rV5JngguW<*JufMyLZt;vV#X!%_Yl{ygx?f z&@mEz!?#F?2n=*M_MO3pM%_BB+?3OOl%P>_Ao1^52 zNam5$FT%(*o=^ttjY01(eSc^wJ}H*BTj=>&452T;Z^$&nZ95=-bm{A_NZ)Ko zyRj~&bT~`EO(miTB4u2DY3c7k+ZP%-0zb1oC*9$rQR{MXepG(X=&&dekU9kJ#FNhE6&#t>isEP`q&5Ikvab3n*4cH{hjXxB*MRT8YO|3c{ z6)}qpLDZ)&=1N6X9#iUXXn{FWS>0v<0cE`eFy%2{k946dMp|PHYt4 z9|#;TZfb5?*~pP`;R1qQ1{8b{Qm>o(xRlg> zZMM!7i{DQVpg{hc@)=TtcolskkY7S?_k|X=#9LGZP7vqkxk(z>S5c-k!m>pLxOoM7 zHsZ~OrkOlpea06HF-f(T$o~9;U1>(Q$!u{xp8uBD_H9bgwyR(Qve|nP@U{k zvO>Tfck*%aYM%QqAWOAQ1Rav`d)5yz&@<7?EN%)A&BaKdV7oMNAz@O9e=Yb%v(OgY z&*$<>3ajPlVj&C^y*)J0-5jrcbaZakd2VP<9*H?AGGP5^e|``m9$~vEOcF}ODl#H% zQQMZ6ADF7iBXS06s_cgP3I>#<-1_Gv>1|X=6XO4|J>6fA{G_is(F07H5cUZP=>DX4 z+R`qFCT16cJ({^1+%CB~aiH66NrF>cEbUB5aK$IS-u;y9g1NIIieR@tB{yj+Am5HGvOU~wTa;iVQ7w#20?wS1 zApNR8l@@s9ya}bP>q`d3q6h&ogPrmm8yEIAP}%ulHsG%$Hgt0RNu=HKTfIp zJbg{>lvEB2dL_b=v_98Sw-5jwdWrfe43fM0!AQ6rueI}Wn9Y-2V7sb=RkBW(RzHzv zMu+MzN>p_MI(}xfwwGaB^>OA2QsX@tN>ajw{p-QdOaOPU5|AK0k&d{BgRoM=K$mrz zbX4#8nrA_-E<-0cPO@t&{MiR`d}fWGbHph6s=QY%H1o#}BgJEb|=H5H!_Cp0@`2m~i~B$4MhzWs^{ zALkv|PShdT&f7aOgiWvdufZ_VRX;5d6JpzhAJe|;pou*JWs81@mfCk1C{hX_G@T{l zg&ZlUW2)$1TdagtHptp6bXH*d7cy6K=|U1%*u@hh?$TB!2HA$^2U{*F*fX6)FrOht zC_W{3*v+yara8l!3yE`i!kcO21a{p0^wxuP`E-n@(dX{E)K2+Q_*Yr_I^*uwV_EO* zw*PAAB*FxyEMvP>L_~lN5ob!R6jD^#$)XRvhi&O)Qw&5V48o*4p3NVPVc(a5cdB|i zf&cq#ky~B;XUsk22{z)j%@}@0VoHoU{W|E*;{4<1q-Kjb9;_f8Jw#4%y41=g)(;Ie z<2bpR2uhAh1PKeTDAfr&2e=GA^;_iIR&4===FHaQ_Dw6rs-0fzIj(&)r}{&7&R)>j z^=%<#V9dwve~egq2(v7(XdOdprTS;~SZ$v5glp(6mJ8LI?CLZ~M97!^kqV8SCx)}6 zA`|tL(QB{HkYsOe6`@8QLh6eJU4TL-!=DH2-q#|;`1DWoIr|=Ai*V+qfSO~I0&c$d z!IQ5YL#m98*6bq^J_uVs@^{w{{(c6dmuT~`H%{I|kBnQw5>kyut0{A@@nFbAgwT~! zxtGUS!e-+{#Y$A8(qlqP*&g#(>$aCvOev_36FWBH#&J9!^Ipszy0^>G=eRkJ<1M09 zQY*7Fyb_aD_7^2Hp!tf(>>R+puYM05(7czdSmAG^wtFh=ct7Ed?bNtQ3#BbIeS@!T z4T)uE=g5BoMbA`?w%|AImFx)n7Jv(}!aF{&uO@ZZ658+D6NovAjULudUdK438-+%x zvx{halO*|@7KrIM81zkh?t0;H@r3{6gj@UcA0CO<8Y&gNL^3!9c)-;g-CHTllV3R|3vlc8I&RE zb%^$;F!*IKda+uo$wou$&y=*Zz3{!fh4&2Ed6P^GUun^hnKCNR#^T=p{c`vJh zKW_Vk+RF1GGsico3a)GEs1wu(aeN}ziemwv;SM1JYTTXEY$Vja5K z*p+CIWcit6SkKR#NPbtLd1Q$&7*(YasTSY`@uL>Hg9s$D-fTOK^dd$(b)w(gRMptz zWerE=CVXJ}+{l_F_w4;BbAHTT_V;-ScOiR$H9E;uaI~G15!Et4PH=bc`yqDMk?rED zG3$o}C{!oXT^HI2v4h^uHh8|nJGgTofq};9wpjf}}kt zjsx=$84%F90~J3DWf0KSBMA0w@()HQ>xbwNiiJ?B(8lX?Bn1G!l2CY#;P?uMDj=4L zdWc!Sz#v^r@G#wGMC27Zy}|y(HoUV%sFuY*aJC6Xra+7=cD?_sMPy|oKi|Y$bvPze z0z0)J7(>?w#zLwDsgEOGZVKQ!Jb3UpR5l>}9I$9ThMm96#UT%MLK-&c4}t#Zo2c7+ z3k<8`*kYyMra6pkm1S5vEQ3LC_Q#)*lZQAev1Q;gG4EXH6lGyl2I(=*SSuO}r0{Rv zpBvoyucfCJl(E1olYvLWXWgD@*shKNFrZt;?UlPjR~~Xg z+I?!bgy0SYcfkR(iHdtip8!HlGg;KM>P$Sj$fgZ#uR7_g{#E&kc}FD(7mBMh?eio| z*Fr*@0yYAmXEV$JWz{=Nm``6sMd2`dYUG3y9ulUcv(rQy5o^d_=ilv4yw!UPsTzdT zrtHh2u;BYgGmr{}s{}T6){*ip5dXPkjTiKdMX=3}b2!?{P=iFI^$I2u!~!rhh+V|n zhlCNkAR{D)2Q0~rAP4SA4|dQb3^F1XCHjWp-;^R_FsLPb zs}96-Lw$|qGcCa(YJuzKBwLK?y<=812o_^PxzBi4n!*tL9w=nfOzUiiu-DS{FPsRn zq$urSmg=Bck@5Z3{mc2fwgSJmj=@W4Z$d|2NhT04I2Jb*&Geo#K0KqkgR&6wGd6+< z?`Y0Y#x4#}{wZFWAB1uJ`LQ#(0gr}3{|xuv(xKZF7iJ@yzVJp4{cq)~<(9B%{C7?D zoi|hAZOcpJ;|eyXPQqJhoxJYd8lDb|(YJT|QCB_qvWSk@xDT|3@||TKizjicVHh3UvI!Gg@hqI^JlF8(+*%H)vcppQ-$7(vN@)CYs@7iMl<6qD_k!XMN2 zDLK21;%F5UmX?wd@l5l^sT-RU9WkTcj#0uX@UANR#fiUXXJjMW-ltBfhYx=YEgNfX z<>r{F>l*A=Rad&czGP&3dc67B*;-oB$1ySR_VA;l;O_vDleyDoITOdn^@Hr=+xM~Rete6+JUip6jz1@EvZ&YF{H*jvk$Cdyu7N9D?%hJu zh&7C;&|r{Yd0VfuIWWbBTvd{uE9th6bjTs+bjI1kyc?!-O~rg9EBIW+Ox(M@qVU=^ zyi|I~*!a6_Y=zJ2;E?|eyps}huvvT;B64ewy3Vb&+Bag^(TDCG12-ky_*q?P>ZC@S zbK!ZZ6%7XOVCp(l|Np9v-D}~qH|BsjB&oM_Z;6Z$EOJ;(C_Kq0k#{pYmwhTNugtVs z?-CU?Se=CmX>4m|0UM>&MY>OU(zV?;L1=7ddb0fO5L+HI4Z?XUjv84p*auwamX0n~ z9&)9r`foEGEz7^|YE`pb9MM|lFIKVSEa>16-A&)$o3^^dbkzbeQ(?)NGGm1HF6{%kKFv-Ciq^c_#+k=m2^*2gH6&ps{_Yb=Ba{OzA{O0w`AH7GH zwi#BBSQbhBQ(U__3vX30 zG5xJ~n%~!7G}FU8>+AT$v`T0D)&1g04_Gc*-n>5i=KI|~{6ACTV¥Ch8I8qS;x) z7uM?)Sc4A5y&)BR;^vBw{vDWEKRak33+T7&sb~799}x&gcRf6X{Ro6s28uzBYg2zD z%yE=l8|HOnJK_n6Me#|z=qqQrgS2SOx%0|wZEHKl_)`8>cFv$ZxX4Ri&J1N~x=iy~ zXo7k8ZtQ3&Jz&t4KaE8n}M>w2cdL7fOgAkO`+c-tg3p>?T z7;@O59V*Xtcz0s>85%?)Y@)waYgZHHNHTP}_c0aG9a>j0J+zwuAVR{)Vkpz6DIlHv zB$!43uw_o<6$5Nm);#7LlSd7%Iv_o=B|xMA4biX=v6@g+R|1MB}`*i0+-viBE_O?Do+$ zW-|(G_#4nt);-@)A6Das%)mk=HzUbw=11h5V0K@P22nilAF`w3g1R$*s!>3hlKwy} zz!bY(4h11>*R5zEjbaBSEJ*V|Z6v8M9=i{686&7j4~Zb5umrFh_9(>o1>#2Ak0VIi z-P>$roePjNngU=h8CBJS;<)7F68f(SsAh>vVNfcOm%0-xl{Pa6;nlnStTkX?=_EEKx3Wub~wq^l++ z%_;9q_0(y-kVc!3A9B8Y2v_IJi9F#9JQgO5x^&*{u9`ZHS~Bi5v&IT<1j*vK#08i~ zRs`)H+nA2^l`Wrgb5Gul5Tdy<$%h9!JtPv*a!$|b461VPNLs9IWg}-vvdf`GWf<4c zg)^7I#t<0!`2bdP66_SqaoLO#xEKUT=6o(4<5H>#)tZ%49LGNe;<3K4lem9WirZ^K z(PO8wJESosO>aWLq!E!3-8RKa*Hz^!+Upo*yFUZ3P8aAHhJ1u6Y*A5&n^=--3^*TEhvcnDfKK{42tuQ1MR>_cUxF=yCxf12|7i5cDy1#cLaF1YU?PW zYP*A4SNbh}XdD8q(H`OkPnJnv{h8pPS@I=`p~`j%xdzk1a%|U6F*$MFq!vF}m0nXm zm(XY6s|um3IFfdXdMq9#X^)8BfJfI<77#hwM>skJcVrWq$s}vhLo}$e`sVjXRulwM z4#OC_x9DJ6mpW;U(K*Gu9gIEmXbT#{lp%nCo#0NqIz!{59pJPi2Sa2InsVnwa7&C4 zGI!S$tD!xc%<0C&2+pj|eu-n%8Gilr+nzb#j>vF$4#DZwS56TC@99Afnnri%dkAxW zDxX(&(A&Le)VGD8Opw2KcxWpj70RZOCw=a7eE?CrgP`QNn*tCERs#Ydm9c2cK9A$r zkj77kcf*`kbW^~gLEb6=l~tUe+OF=L#!1kLHMkh+d(t7sX(*<9BzPI@DFaU=@|>*F zQ}jUy!^TvTxutz3e{I>cowY;w9EuQ9~cEzz9wcFiTD1Enc zw&@ulIdb3yUR5l}BbI>(#M}3YC{;LeA$ip51B8`w4G#6qx~zDZu?z-O)ofI_Hd?J2 zfzIloYZ-%H_Dl*i3)R!YRbr#B2?cSv$B&3~{~K?qvxjFtrzN$)0P9PmrRvHnb+Qp) z$`FH)J^yk6DJtNc((guX3*m&8QDiNof_)vFZIC5$9xiK_06i>AC+GSFRKj%n+!zLF zP5~u|$zXDBDTmv@dKcdYx?=Ree-a1|lM%<+hMq~n-eTx_enSqs z(1zG5`upv2IR5S2?N6?6a||221?c#$z;_5ZBFCWRW|nLP#?|=g5)fuNmZK8k(uF>gZZ(<{b>wG%3L_D~Ijb_@J|__J2Y7u0X@c$& z&X&25P7xfL>4nGm%SWcM*V|JIOX*clIGjx}N5{c7V(m*Cjcgnml1d#g>UZ@h~{91?!z+E*n&;IXtM} z0xH07=7XkNiF+2GlOW`@u>cL(ihB76q_6>gEeCF&!=ZGR#tnvdBejMdG|?Jc9j=@>NU(JL54N@zWz0=&EzEKR$1ku(xemTRHt~sSLm(fjo zGf_ty6_=haAhgH#!0Qw-vIgXd#r4aTMb3tCL@us~XmvpmN2oJlO|#G++}){l{cn1Z z2;?U?Scb<`iXNoQZ`aN9G;`}O?w=Y!43co0@HTNPR3!9AmSa%hh~%7uneCuA%jjgt zHxshFt?gSnk!cX%FEFq4bY)*I1V?kZ!=V_DFDqDGfxpB8Uj04jD_!LQ0W9UskvJCc zw}|(F_$q1C;na}>lP(lC1xl~q$cs$rgCY3Dhkx{K0X+aR?$BOjizP96#c|US_|8rGstxW7yYvfrtW)r$=FU#7XDKUr!W{gW zn$3B_UAmhAA)4?4-jRWwE6)!H+xMIhWO<|r23G#u+AKrn-RYri`3(eq*UMDsB?xn<+6d9ivOarjh){XQvdLNJBM$A0&u;oVt5a}GiSRBU zpz59&6IB%WJvlZ@%_2}Dw4mXleZD^Ru}p&_X)UNlvWxQ%5WZm4S=wk7;LRwlf-@+d zI>n?XUN5}iStlz8#Wy}XdH@h$834~(gzAq%SxoT&1O?qm0eYzn0E!~VAu?L1RH`;W z7U=GL^*8^rYu<-=llOm$x$=0Z*ERkQGEp~6i@HaRMoCCYi%DgUMyaWYTeefi7KW%n zLs@>ua)gpKT1eR`k)akD2Ao4NtcZXb_ol&NdX|-C5SN_`gvQWs^`B_4zeyKlEZ~ zRL$c@Ik;?WeJT-AeN|iKD~G8C(j&OnMR@-G(oJ9|A{5{ov|8UTeGUi9$Xo?Lz@-ff zti<51Q#0VM0b<{Mz9R)M-o++wjxF2hWs;b`FH4TDF%6&rdkkcbs(<)GxY&5;$pfdr zkMbFzjUoAi#Kthb`#j&kXveuP`9;L#3JWAe9F>{L0c09wvFh3zJm#br}r2JLPCp*<_r_qZL1xOMyJSSbW5r%Ka& zAESCx^46u|D?o^7nrlD$=;F(ouC1ZUULBSbrG=!cSFa4W`89qyUJj)V>ux^WMEK{3 z>@E-uhd%g2?*r9ytM*A~$dXO{-+J82#TuhbXtrw73n>Mc$`D&%B<&*SW5BtF?TBt^ z&cjVavtn#3Fjk#`a@H~0w>927Ms4fo9BFBpWnKca*qw)BA%0dWcE-MNk^(9-i_TYR zQf=()QlZi8Rs3q7rlcfwa(h?-RV%+Xw@xv0<3fZEr@GRyHM+q|M7(e@pbSW4F1(qX z?5WdhG0=53?eKJ_7(qyWpyKbT0`OGpdLT|hZ3WlRIB8}&he=d};+_SF3ke(S`#cP_ zlyoW>WGRi~%uYNkb#_OJIka}7^}$wRzldx?#(9|>-2oUQw7kr>F0p*s-@>7z>+*!T zFD1@TfevSx^-tjAxy+ezpd;A&Cms2i0qF}BPj3s zF_*x1A18qnZYby-im13zM7SBU3ggbCD0%9y`zla>>-^0a-QUUnZOaEk9@a z$(Vv1#eYwau$Fani2c1KBf{`~eg9=n`@0fnQ{qCW2FklkK*r`l*=6F{)*vM5p{#Jk zV4N5i?o1$g9+6Pvgb}E3qX=X$By_FnJRxO-`8#iOyWV8A%%6F!pC*g~ps?~}-YxOa zWVViCVSA}@KgoH3($bwrT=eo<1vx7>^?O&yo7({betJg6ht=idg6Rh&oyl97jIXR= zDJSJKwug&x(JOuoEKo%G(Mz72LJEw!(lk5D?xV;#PmKmKw2VDEcoxkDs z#}-rnNsISSLA$np`mz2y-#z`qtrgLAC-Vw~4qho+{p#$jDs1RlD<5y)twio?@Ha6p ziXR{)cC!1tKg$qv-dQH`z}Jv>#*A8=S-~3$g|M~Eu}p;#s+{iGs(imM5{7Vo>NVys z<@;~kv&XKt**Z?*(Y=MsPlwXFC&%L=QX^&D-z2X}RR8>l?RY}M$GY}NYen_)pLrB@ zj}!NvP~HXbb$4vpJH@>-Wj=yF;c`_j8@IQZ$sQ_hDDYe`1FoA?)TPN;&H=tZsGk$u zJAKNef&)-QcJ7t?;>X+z1C{|TWAD20u{;rf*sey5rC9+zpkWXe{^zsiNqJ+98tzoI|%`;l<%Es9=)%;H%(k^ z?%E(Z`A|iBM7M8xFFJ$#U{PQdjCTa?C|vg-y@I0y?kZ@5~bl#enCiO=a#T9LHbUWVpW$ga;+l32c^M7F`%PYx@z{ZF|95qZe zX`vb0;zzEr^tT-Q_nVi-%7|44ztK(BeE8y1S?q>lN2a~+I^{R<&&aQ$uifZvIGdJ{ zar{AY;y*ohQeLlF&G1os1Tv*-q5e3iai}rIjnL7mK6BN5@#OH-RE?>FFUzp)qiN(8 zYijlQfl$j#m!6``OzZk5xBHLO2`(m01m#^W@=f5!uHeQlAB*fMQr~7lFi#ML7f3h< z;m!Pw@oogFin!kH1m)2$uEjZTIAAL9>p){UoEF}Wy0qE2Q+|t%_DX8pkI-qXh(FVs zZF)p#8wAwJxWW@Rhh!OndNF4(TpUUDu={|C5_6dKYih-r4FWh-48(E7t)&@^+n)^L zr5fYv4mbEb%=yY!wG`{U3w423P~d<%OIoxqQmY3Vs+)N*o`M;WKapg?6~v;3^EV1F-p08-dt|nix{Dh^BshL&(cucr~cW z4(k4FWgnP|Wh4YdJO~l-VRRQ(VO-T_`AWd|)O+}}l`UUI2;5E1!$|rkAV6S4)O+}@ zXe#sWBHtbww6JvTo-|wzt7O3)F)Uu3d4AAEDrJg@G?v1_F-l`N@|AE{*kdIGzPq~sy-5EDF(NN&H>s+)tve7MG&vQTbeSbdp{d~T$Mg}@8Ox#Q$ z5Qs(h-oKAPpmV@SI?#Dq;7xw&g%t>tAglZDU6bGs+vKpMw}kB75Lk}KQ)e@uzcj@D zIrq1~xxY28zVW)(4Glu?+^%&C8ah5aoL0(LVw3%Aj&0}l-0N&a!rZ}{_7H@}&!8?S zC@>V!&~|7+^(yy}OB@y23#aQP2FoHb0v-2k}_ZRwyA{Olf zc&BvCrO5k5RFRE6VZvM>sc=Jk{&Yl|xkqvy){{=!fzJlS5B5+;A(X-2P#!RRGyWTK z^xe;o&G)>Civ&u`Ck%B7u8Oxl^Q_36AmYe0>&@&Y=irVXhGE;|NMs1Lm1an+l320-%(S$6S_S@+T{;j5k{F~!U=SP zYi|-@DtAI7o;@2MBZOk{R~s)i5wGN|B_zPYSN4grMVMg1wj=8tb>=^N>#=e z8uO2SMErf{!>bS?>nqqnszx3sV@fuwYK{B&%uV>YcNas?CKQ@oN!l9K29XL?!w7ZTN0v3A+u-mGd+S>A$VE&R5gMrSRcGXV5aRl-*g;`djFf$N z(55V$)Ghvy9Xfx~Hs(F}#f1BmETsmuJo2`qJUs2KNxWIN!~XqyH=d8gt4UHY)#5~MtXYHI$&T$k1;+457m>5Bslv43KtXT_EJM7z-cRsFd5;E=4 z$xNIjwB@Y9DPY6w;O!kKYmM5$oNTLPn)zD>^PgD4lgy(dzC=Fd{qF^YA?AuE-05_x zT}$oaPiV?~#M;!aN!SW0XS<#?VrewUb4qOE6^2B>d10D?A5@_BQ~Re91b#!&wh^O} ziQCgxD@^=5tlOtQmJ1WQCon2zcQQkU)^@hG5;nJ*3~a> zxI^wZCXlkdsSr9$B9b^n{k_ZFaoRyWZABgmt0cn308{s7_8@0mtS0nYH>Kn4%Mjxp z>B*{=Ikkl;FeH4g2lRS zH`sr0unrjIJE8TU)rPdbKX#S1<2NIQhz4SVlaq7ScStj9cYdR>O969?PoB*2j+ps2 zbUN3EeHGWWpI*iaovHH6wNN`as&r{3uvFM3A{R*bUGf3-biSd^tODgsLg>_bMtnBn zR192>UV|Nht?k!F3cgKNL_C{Z<+H9+^?cWz+|e4oQUK;vI@KGfs`EnE?ETzM>+em3 z|86xG6Z8w69?1Ba9g6!s=rK9hgslYZgFUHXh5epuEi)BQ34|Oqyb6MM`&>j=2L}^e z0wI*?S_qBVS>Wuq)y^@3DPxOK5aqz-uHXuTQ6OXKZq8h@5o1Y6Of(?O?e(v>+f#d` z-=HTkb0^2yL33gIoq356RHN@o=5ey4j-9l=$H5${O{0Gxto7=soa6w1#RKjiVJ?`I zk2=WX?`N~R)4bTbxYn&*-ZjAIm=DGP$xp|6LP0Do8F{(@hwnA)Zjm~uwcB0xp_Ha^ z_myN}wN?tEY>;uNIby5E96o=#KiPU>=e*Uu(*prZ$#l-&p=@U9*oSVIW9CTjA?b&+ zLlno$!L6hQ2%lAm@##wvep$IF5d~Y%@NTA*lEC3&u;HXVlKtuA-s~xY@koW#;tj+^ zD1Or#w)TyB4fef-06B`W8?O#k}$B)0_+pS|1zO-U@2tSc0 zKjEh*fG5`7d&=I5o(q=pe2OvSr>=X%C%3ti!M#Vi`yUL} zlFHr3W;3L6lKlavO%=WraKgtqI270Ai&J2@ubILyAZ`WrpVeqSk|AaAiCn6U@XobB z!N~WEknVq=t~c>XWi=V40}tDp^hVwp3IA#&!NEia4u1xV0iQ06Gzk1InxDeAb%aTw z;7^-n_J?;2gH(3yM-bVDDue@S@cwZrdM9jo>pga*J#8hVhI+e&bd;5{GgV)+y$4_g znWT*j29WnAiu#ikMQVi|u~JNn*(ck#FJ8US;c87d&!NlI@p#iu_zEwx<7N>0Eu*>a zOtte`iGk!~>Z`~8$G*O@+6PMC;M2w1yy@H3W$z!5zI_Y%8`zo9u3A!HM!)!cFgaS_ zcNXhT=yFg*1*KmPvVJV+z==9tV&yIR4a~g=Mo2|c9Q%SPE|{DhzR54PYgZWNl_CzK z^wu`w#i#Rg3@(yw-Y(*i{nfAsqb|cL4>J#Rom8tmN{@@vH3w> zjTPIIj2T0T2s`9~x3yJc22}GbMfGM06JSbjzF(BoIRU`XH~zle{rZNYy(HamW=aHY@G6pTLdRR+^SN0(`@`N7A$TTZHfsfc5q$ z|D)4})G}a~erD}akW*0HPGk7q7V%rE?-^2u6Ohz3d-6V{%YMFcFDL%$yqmJZ#=6H) zYtW8Uv7Fnhp$`(j25O&N1d0dsdFD%H^VLL3kO3GP@jKQKwlQuF^WB-lV#r5S54?Vd z0;a0mjE}m$*_BuUceOkM*0;ARN+M<5#*o{H-@JiPT0$gPE8jkzZ^HgE7QO@^K^>;j z`3TEQOFf-tb6_Xhwa5fw`x$p_TLZhK-!KM|e>UQ?&^h6gt0aJYQG@{!=55_7>a{%= zPWX9j4FomeXA6FjahIi{>6?w64}P;iZx?xs*>QI_+<7x=XPQ(1fLIVCoV-=c_R6av zAj&NhAO|h5?Wp!V(|o~6?3xN?>?-{52L{M=I>Ls$jRC>=pTskU?3<3BW3S|#jDfp{ zh@JUJ@_I+SRO>N$Tw(4`IJ)~@=0~il9Q+}}NqGlYQ4r*a$W?y+wJNc=BAnVrT}!(P{~b-HCP3@# zzjD;k+LM2iSC!JfEr!&r{%CQ_Oy8cZ^g#ph$^3Rk+2%SFMQX47m52!;O#!Gafrc$C z8r}|ro0r=htYeXId>ZmY1RL^lLTXLK7i`Y#|UH<&wW86^iO`(UaiPLKden!R(nquevEa)JwO5i2&5 zP_4%q zc0+-9wY@2qh#`-N<#mtND!w9Ys=e}I{23eKwF&?j3u?C|XlHCdDx8|LjjZ=xW7}f` zGDxO;9dy>;`#|TZ;*tODOQ=&IYJ>+?ID$N9-8mJlOM@ElRrPe9JeKdRPf4u|B#izC(A>yL#i?`XItwXskE3) zygO%1o%fV4P-8!iYRw0Sb~a>sPz;N6#uPGRX@WVEs1W zhU+vstPt z%^Lj1TS`rqNU150vWI>7GjCjTD0y>S52xUddU||PBVOoSV@ooXNM{*sKKkXX3$|+z za9in@2ivwd-7B4BHjGG)lA<1ubjjMacyan(qzl3v{AR|V^!5gHNYC7q5N9oaYr@6z zeiWGKe|sEsh+ivkUDFIxh6Uxy1>-viXny7nX{L_$cGDC!6eZ7!+mEGVs(xesDdX4O zN%--c_c1JDTM~Dc*~8`mv`pj+SzL+^%2W=Y3AP)QzT;VNi+S__=f{1z|DWw~^U6WK zu!9k{ z6+EzM$CQOLG8@%Knj0c-4EJX(AzSPXQGO@uxL2_0qfEV9$18sTR=uz#V)NeRW97h| z_d6Hr=1^`cC0T|oc&i$#1{ad>cWD*a)=K;?lFQ0xRNo`!`W$t^IL91Qy+S!A8iw!d zRWu()0aybM-@YH>itm|(%r-*Jznvrk#QWd}y60yzd6kwi9aGTY0sn$h3e zBs*klep7z#lH;!;m7h_ztk;H69FQlR-8qIZQHqKkqiYQ=dB{!?elj~<=Vj&Rae4*F zXPbxLV?OQmyB5e)err{!*GOTPoLI=<`m-t10o$7e09kHP=FcL!6}qY6mF+Kd{Eiw} zE5SOxVx?^T)F-6%iwoH*!rhmxVk$gqyZnM3yeWd<5%folODBh|kDXU?y*kzU8* zXMu1Cd<*>X6|%qj+(GmYj|cwmPlycbOwj`UrX<1iw4?J$0e{8^MZDxV8;Ez2)5yQW z{x9HjZsLFJUyzqB&g+kBDrtb!6+CIq201w|4!nYtfcrK&(4T!=7yNIc=X)YQ@|^ud z9r2a^{M?^Ls_#os~wIwF?NE&=};O8{7)y2AfuUe~1k|D%h4 z)q?W=mkZBKA)s>}v>s#o;*4qOIY1lU53CZC7$hn4(K zO8`@u`)z(U*Z+NKXFqSf_UA7DoLvT3O;R0rQ~It7d~;^N|HEqk4~_eQ_T~R#ng2J8 zOJ0i7GrZRbgF@J&hBVgy=J8_g~ zyu`>Q^d( zKmvUJ3NRQXH;fY$%1r}myY^aYrC@zm)1Q^@z2<*&vqU%SNd&FY-4o81k|Z#-U%$? z$22gu;$aqaCB>|4Y&hxu_33o?01l>-@z*r>&g^+2Lv9Bp$pdcechFuSYzL`^j^9rk z5KEJ@FbgqCFLpPj&)|&IT}stN&W0_eFJ_GJUmRAD5a0ew00$W0DGqQB-tZ9XhEG{$ z!sFE8$NRC+(nk-=(mNyf#BPDu?1H_}sbN|SpvX4@Ake!srzLn=|8$~Vjyh%2S~T1G{Q zv3yqfoOd@(54c)}$CzULMEwz&jqb#*neR2528}=fupU|B!U$UhpXd8ysZzPzyu4UR z^@6JY>+e_pO~cGmHJRH?hSW6mKwmo*|8vs^xaB>m)*vta@L?B~J#Yo+?Etq#smTPe zB*{_NVtkMA5!FO2l~&z@`L!(QRxYcLhRE0Iv%~^Kb<{+Z8n%z(s~e>$#^U<*OZz{- z+&G8h@?tq6Yd5Hh400K?O!TIusU7NiaOqpQ7{KmGe~ zk%QZm!E6Xy*z@~rNIhTMaa?L4HH!yk6?E<|y5Y`1fycUMSsbwa4LQ~mPlHnh;C1KJ zZHHd0=8*1Q-#q^$RBBK8HbdvoMzGcTaqtYB$wJ$ckv8&-Zza7W<_@**|I79)oMM>5 zbf25|?byhIa=ClJ%-`_FQH`u2A6{aPSZ5@vJ-WT^8Wza*Ky2o+-c;S|*F(oJDDxg# zas$gs2N}6Ts6{4^iaGCzv42?&hZlT&;`2l_*OA#3$I9<*sldsX=2mQ$x>i8eiE=(0 z>q^D8-g45PYu@e6WE1e>>;mgRIt zPUJ&?wN%5DWJ;vpf_tl0?v#Xe0(b@txFqlgA%f67agj51#COtzzgPq?_zyStY^3-0Nc^ z(H|&OY-cVlpqo?FDA<#V`)p=BC&+L}Z$%rar4C@*IZ&=)7h}YwOMzK}ZS1C9Iuen_|=dhIGKkT4%Ad9T)fNgeshh5Mw)SEXT^F-sD178ww+Rjf- z;GPfC)5eZ#GSAjx`V82cGOp+s?pn6N_9@K9<>CWxp`{jM2|RJvL{l7krBhDk_m;<3 z6iddJgF7Q(ofq=jPFHd-DBcePg#ey#q8C2AHoPFm7*U(Ohq1WqYIkDoPnVET`u7ky zQJ8C?`?ZY@y*a)yP8W~tjC@jQ@ho1P>8ccuLdC;5 z+oVHF?J_2(sBCpKm+4L}qo0Ew$6f}g$B4?h>;^&ddedpvH<;_J$M^EGbG6J>7~R>pn2C*yRl@cLvL zu4LhU3huL2hPg09B%8+bkiNUDAaRi18-UY9$MT@e^mlOCKnUBc8}c%a)#K{qhSv#Y zZ-hyd9x-mP;RH?h(v1aO65NE>sI1WapI91A@i&d;yds%&h)?(8u0`j4GQm=p_*js=?{1c&sVsF$Ui z5OtYfi&I2_TcrYvTILddN$Zys#UClXO|#5L1M2<8b?L;j<%c*$#_M;&fqFQTQL#|| z%sK&jg7~;4^+&oRv zd>RlXrsJyPI9=wiP>$1`TLOK|osl;2*0fWX&iQ9VNvc~sIR_G`TZ*MV3i*f$`ubsu z7|VL{Mx3%b3rCBpYbgw`*8@)OMyWppbB!MdJD$L81oQjW(hD^17SuE5-rBR5DB2MOaEN{u|?Ig=$mC?$)rhXA7MF!o7bc)-SfmdfhJHNHOfzy;-?Wy6CpT% z32;#LtN(F<{S6=$Bg29Q<2bg_WNW=sMA-ACXxeY{BfDs;!$dPVwesYLrrq+l3-^2y z5N`et5cwMVHJSJ6`a0poLb~bK(J9b@Dw9%Sq;ic$-zC}*6carW^+LUF_M??8*e2a^ z-~jEY-u!v^3f&Dc*b{Zg;!C64i?pD#^rYm!f1ELtZE4Iu_SjNWlbicKcQ_-X@SO-{ zAj76{lTl?rE+$1-gSoi$CulOQBLQRi>cRv%lH9ttQE}J0@Tj$}@s@{W9NQYMnFtSd z4Zq=Ar@htjPa8Zt@hy&}W=KWa&s=mR^3(VuPNUN60gzj{hRwfcYln8jkO2Tjf@y)y zm+-ueF>lgtsaYy?z{d$)1r5mwhlC)YeLg%vwLZ&S~I@}dnV8fYDE>_5>Qfk%L&SbFXvw1Jd3MkedjHMj{MRj0 zk3J^#hA$!yo|5zLJ!;0~kqM+|G2)xTYl3cJDe}O}Fr#ApS*({1f#{35YL_ zK(Vp<3YfFeBQg)$t+wivrfM4H`nQkV?z=baL>R5vkZj+hc4b^7uVb6&joZsZ{ClNRsRf7>~;YD>tS-G(DxyLkOl zBR);@xiH4KtZ+EhK4aIA9d|dk6x`<_icyuaWcfUqDitNrVD>}K`F+&`CB!GEt0~U< zsQYg?K?0a{pnd@Y&3j&%pzeY9mQ(Zb)a^6lLZ{$d!)?;vzoiVO(F8?9uP~K_iCtMy zxV=L{sTk5}(cks8Gi=EXjaa&{_bAf&y7xqL=dJUp0iYq{vWE@krQ8+n%_Ws_wq-Nr zJluf-vT_obTFo9NW@WiA!&OneZ(ImHSS3p1ro5>~$z;k<5B5E!WHSKR8E(zIq%RkO ze}2-x>(w05`ws(v4*(YR=GC7lSd~zNcO#m~^KwG+PdoWcOZz4SdeWc+0VX#&gm0kZ z>FHsQ+JzIDg_=S)>4`8wj^h$DXX`$)U2R!onU7xKb#$_68nmy{8Qmw0C@Ya1c+{ST z%S1RfdR>0c^d|JNnDqDI!w8}SyS6r`==-1U1_#!<`OkU8m^d2akbfD5P1kxB`RG2g zW_FchWTOKuU-^%>FYC|JcvgGSxWA?N;Jx3aB%iW=Czwj~OZNJ#SR`|uTMS-je9jlc zBuJn4U7EfOHK%KTeL2QDIlQl0a&owy*mJA9%1OD;3;8tuneXMx zw*-R9?XANGp3Ovos$y?EKBG;(1!Z)>Pp&3i?|AEceSkLo`oM$25%1ZgwNk6`sdtr6 zqWLl(-Hj?`V4h6IeO?e^I|AT+2O&5x((77v)%CH!2Gj3wQ!(9zuM)aUnp}k+wf}Zi zVlWxcbPs4igxh=Nwq>yOfG~l!r3*6-%dhgTW(IOj*FG#Aka3>Y#oU!;=$vF8gH8ux zH9#&)V**WTm84dHo{|500x&v50Ge&M_$*z}?z=Q!?`+Y!le~T$$f@Q0D871;J|w64 zMVy`EP-2k=HreR}l7pA}JUn&Lq@r}^^TGft`#GjlC%k~C62n-v6Pk@qhI{V2!zbxS zoZN9+FWf9^H~J3PLwvtGQ4QJUVHfw*1oZ;*!wnnXXa58+E-O6wt1Ph*^aK<+`}j|l z5^2)_gO<4ok$w+~s)7b>)qP$?S`A&4;Z_LJMOEyTY~4j8nw|r*g89lBaS9a+s0n_y zcwn#?+w>A!j6Xhl9^56MX4M;*a`Ym24TW9L_YkYsB~)Vj1C|?oJsap7YI)7OUM$`z z$K9bXTHu8J`Z8`>QMzzL=S8jAZ(V(G9dW|?<~dgYkw{wKJ0o)fx7IVu(4+k4K!-Pg zTr57w5LwLErn`apOd0G}3H^5H9eBPI!=hPiWHdaxvU_8cN|$rmy+N6OYqoIwHD@&^ zVl*jlnf=$Xz^{6wqS}+s3&MQe&!r$qIFa)!Xy2%1CR&K}Y+E4TK!C)+yQytsL-#`< z>;Al&Gx-lgeYv~w&A+`8X!?}$Izb@Sg#UbL-|-P$+uKcuE`7qKg^42lvCXHxZ(-QK zEAPdaNQf~D7ZP#w4LM9X3~{=5!5G%daE~_g%OyK~_>=?9RQ@HSy8@!IS09RKF$og$ zeyA6Uj%Hxi^=~u3*G}R3Zglr?{d25hU>{=lLM?RMQwjEpb788aPG!nR{&6GcLSr8- z!!3|HtKc8L4cMbfZR4El2FPoh#x?yoCV7iK4sy$C_mV76);{)%9onF9oBVj`X=I}~ z#DI1$N^+8RY_so*fS*c3{6O{cgtNJ6Y4Jk8kE!d}Ty6e~R9>CUMql3Xi+yWeDq6d} zKFpIod_AJmJ{d380)Vpc0X*D(%Kyx9{4IOce&fsJNAks}bhR6`0s3iUhq@NlC ztim5Tv3q-x<;IKX53Y+Wv|4$ddgY}f>Q&xFJJ(04#ufChE4aQr(5;dby>AA3 zp&tDL_}je*xhv3P&MCBU%}WYFxY*V39cp7a` zZ_E5uf{56huLdAlz85LVAS8Zav?mf9`c)!3MJ<2Qm?(S+)MoP+DDu>`iS|nfzbnxA zb~$m`0h!4PiQHeMU^xXu&vR(&3Z2)`^|j^T0g6gGwlZ4$NoNhnY(ObrCZ&HqFvU2M zsoc|=-aJQqG7Ve2AjX^-4O`>9T=7pZYGZ1&3xv)T!4<{R)XMJ(@;SDBqI*%;8A+GM zsNa{e^I!uRjO5|7?71S48+Cl+%HvP~)`aia(M-(Kc>1q{(r1(-u{t*f$%Zxzv-STd zBF;H{zE`#VR4d2kqV#b6g?hUToX|GSUU{As_TSuKVO=6#$n{)oU}V86RAw zTM~>)5q`i%SLnI_o}13o8rqj9$#4#}iT|WjPaG&2kQ3S<$4L}RBt1 z6gds_dX#S6sVd(-1$Vgaf)HV#nLCk^9^ID~6zT4?_+Q|Zlt_KMfvf2)`y@&$GnpQYGp0=s@(l$rPdOy^lj)|SR3gXL}$kJ)-C zW1BL}qOp2Whf=Tg^MKuPq6|HTm7 zWJMXY6*T3!3-USw{g|csa1PX3Fp;RRu8=`H_BZQ`iM4Z&K4~~SkxBx8ew6Gu5U>&w z_wiW69zcSS92@VCUkK!*DwHGh@2J=o^*zDbamB9DTed~(cMy&My+4<-Jf8aDZzRpk zo_Wn)UvSNU-%@lOhq#<{uENDSBI-WByIclWw;tZWVR?t#2inZ z9Kiv1WjYfrb68Sy_BG3N-oDzDQ4K8qrAFQkS52isbXdfbeUzV%{qFC_=z}Puu8;jI zt4-HE&VOKk8;6^mn3wr*BoN8muL*iR!ms`laB3CT+aONKc+lVys;0fJjLyP+7i3^p zG)*H>^MkAtms#}U_O<74RruvH&nVOqo2-mvpQ$ zXoY~Khux>gG`uxbyTsn4lDEf{jIB+lq{RVLt29+@A`>~uokb~nOG&*!!m$;!x_wqG z*a34I<>fxf^U+SyWCki(W&n2>*~}vYW|uHkm!$m|pB*&yU4gqj*=bdp#;6g%`aj4D z*7Op_d(f6Wab{+J@s%Q~1@F6^raU+E(h}2|0rEuRc>3S1cji_pp=%?UTGN}Q7OoYP ztkxwmWH2i#mS$jU>X*EAU6JZ}fvA0;rBnc%6!>1dNtSGKwuATI%q>b+?0$skgJuDkv+oM`IZvb+9x9%QQS95EqH#!yl{KsT-+$!vkwGw9p?@U$jk~Xskua=Gzq;F zEubDBckZd}t>2(+TOMgOx_6tNC`n+bN4VD<#lMWD0X=%0IfqOQxI07Ft3(TkH=m+t zztpswXO7W$8ldRv8w8R7Z%;KOXE?p@E3nPP|LwPypz1@f`idV@-a~p2OYj$Y3i+mF#Vgn-2|3G!xuhEhU)XyWGng6n1U*o8mzs5_T zlau=U27^Qm&^|8MZ*ohd?dANhK2@#QX8JlINr9?@Mgu^?kS8Kdz|71u=Rb}K^frWn^>g0tNrDL3oA3X$eKIYMc zA%do6rn9R9pc?}T|K)@s<-OHR4TmMBuUw%Zt3*bq8sz+Ph-4G>x^CA;=pD(mVD~Fr zx%v$%l|wG+swh9D`J%GJ3X|1m&4xXxszu^t#yhH`wRf^lM_MEKc&-Ubx*q`8VHoydYU!>`#kTns(Ua#V=uNte#Ym!m0OEmf%^Hv zD@sxY+nH1T4zp859jMN`+%9N!z7f$2Js_vjw#ktw)@ZsH>b0u+mb;%9O3bom`K7Zs z7yhOLNyMng(HPrl-3s#=$mt_t2w)67Iiz0_fC~@O^-?@OyFHB|u@d zGwYB1xDJTCT2Hzl5I_XuZ5?EO`ZBbo@#!FxM_~?qnw&LRp4G#H=RI@4nHe}#xtIdA z28v~Xk=-TTU>kk6F<|kES(@kJrxEpx5lD_XGAz-Xz^C?2ZQ3tp1U?fye9Sk71F9C4 zkkPmJ!f}+8>(QA}ftC?Sz3IO5GN2On@Up8T$ijIczSJl~3ZOd=2Be5V-eL6?5;bbm z1oEh`Jr8h>zDuUGda4kMcgaOm;;=Ymn(&HR_9?W5J7#g4r*^hs0~Ou;PznIh7D*KC zkJ=ju!mT&UwdGc}GD40c37dX%+;@=7Kuoa`-NeZ{8MTMV!M+?m0=X`YvbPo^I*^VP zMiZ2~L1?oUL}ZLcuWSh6&;{%CXf-j`1`bzT+=Josy8CS=x3X4l?tUWSmO zzkj)L>_RM4a*1p>Jia-xr)CTfJbHDa&}z;5u34}cI~up&^671bAsd~$yk+`_)zMW> zx+QNG_7z69R#AU{^305N48ZmyS7c;-=cL~}A9;+60>pYLVvd4P!&-?_3kl$`I9-=@ zruLJ20H6y$`Q1;iD{fv+T;IH|Y1Q&{sr80mXujRQfE;J8J#_ov;aG?`Rb!K4_H7XK za7>2K`VNSYI7Yua)8B>__glj@?C&i-sG=6l1JxWBPvgCmJlzx7DA}VM%B*4tFwtaO ze}HM3@1tRpo`Q@No|_=Kl{&_@1NWF;i$N}&g==+E@8$so6CY1qjp{Ka%$p|$c=$l~ zLRx?nnn>P)sBIDI1r-he8iU z7N7E2Z0`LUu7m=9etUVdl|NpdI2HK4r7 z_H7b4%6sI5GoJvU)O6$9l`TqDy=Z(1k2KwY*cq2m<{9ZbF4*)0GDx5^c6$$;CRV1n zMf%+jDYpp+{s}a-MK8o5NxK6Cj&u8TL_6P$e!!tZxrQJEJ5y)ml+Q+2bq^>v;{%|i zOAu`3=C#8A-dTP-1Zai(4>kd{AQ(>U6mC5PfezQ`ezbiE z6MA=uEwl+bVV2fR-2H$cydT778ytNw-motgInRD>pS=8TELPP-`%yR}iq@V3V?L(` zBR*f$X7cP{W$qDU=k2)#wMIxnhSiImrG~ejMB>EGa~uN%5A|I=r$XdD!-Ne;w7z7* z!ZdRv-HL?@&!{luL~D2dvae6 zwAHJn#!tm{PQob|A4{mk$&~gnx8i!;D8Ru>-j`6@9EHldA`j+g5yWUAx8u822g2^* z{E(?eW|@a%LKt)I3FAo@An@_oBg+m-O_pJ{6r(>I_gJ$>d*vz4;XXh}W;SFvpm0r_ zzNd5bCz89t2a1kJtX3PXg?2~-`me#=gizpVs@_x=vU*J2H(~%zZrES>#RJEs6pW>I z^bzxAEwPMDj>9E@x`SUU)f|F(Ke%i_=K9scHXt*+_fK`n`)MC}^$>1TDQtZgn0u1= z`eL1|V>~d`-Ja+r%q@oFawfp19o~A9Vim|ewyk?taur!SC+qZW_8<3EIayZ$9h1K` zZ4@joY$S53<5_=b*qMO}ce<$mQy3$XW-bTjH zi^V%Udrq)9*=BXS&y5bjg&Y$?Xd?mOIXBI8_Iv3LLSXN3*RsZGUt15Lh7T)g+E*c> zRO}1$L>_U=Ov=oDwuCJKdZtFNhk$;@kpC2)$iTn=soQP!ETde90*_V9 z)xk-C21pIxL=8Cro*&q3igB22Alhkm|L`6IPL9v>W*j5 zx{rumo+Pj-zhFw>Jfn;9LFZQF7>vkt-_kKaHQY5a0c`>Z${}`_N^VrHz1JAL_@g%= z(aXNIz(_*3@&BYlY6aw4nC3&lfvVcw;KT34(Xt9ZK$Q-tX~SxFLvhEYXKH^y<#R>r z*K|-~qPaHkR7tgkgkB~wArv^>S%(%>jczQ)27vrBIiW%`@d@K$!M{mnecYQnf`$H7X7_FO9XGe1|JDCV|` zCdw@s@%@E^6_cc375hw#cmG!w%Qy)^nFJ%IYl7!LI8`J9Eeaq1Sf1DpZ9EuBbi9|I z{o$0&klJ(MpSYAu3&(Yqr2}Op7DhD_|1g-8mNXC%H0A}9#gyktz22atYV31WK-qLy zJZX>}Ecs};F}e&L2uPTQ#$14d*iY>A&*8@lLo=weCv-f~Er19#O56;ryuY-kz{(xN z6g}b?hWhG7UTr`+1jW-XdW7nTWRb|?3r|vhxph|KNZ2qZss&Q4J9s; z_H;T9mPs+Y!hjIbNC++GIq+3-I(^Zi3fgg-1%3NNup_F#D&nKoRDhGRujh22i0t_U zfj9P|eW1I!&!5L`LN>?=H~9Bd5)y+fAY2uJ$Egqa-_J^B$8$b2Ju#FGCmoP}JPMg+ zpgWB5#svBO(Pf4DHBu`ad;oFO^3*3-B;eqMSz;x(XK0^VD7elILK3kNn|5m>aF}pd zpwd{Y{QSGS`>?yVFqOC6KR*?NvF+1lzFUR|=X2{>gGOT24Mr>$j!PyvkgV?0h0rYE z1gQFfpd53LOh@l|jgDG*#i=UV%e@4Smwl3t_n6cHZ3s=tBu^=g*8l}sTM%hQa#s%s z{}}O+F`$@207(FPgW-d~Eq?@Gb~!3+;=n00dx(DXGycN3L0P*GI?};Cd~=ri z);_0hI91hp^5*Kp69xNr;C#IIe3a|#fvO?OB^b3Bwyz{QTUc;o%B}PAYB^g5d#7%~6pvBxt}$Uoj~b2K;sVDjZJVOl`W!cV zfX?~2HUF1dAr9Sg^wgB2;g6HLa)wSVc=&RX4ZmdfulVF`_Tw!5&A~kN1cP0Vy=&ZN+^6pYVwIa(o%M%asiP)X0 z;$FKvEr|>d7qkRRCoF487^h42nB_fYXBy-*68S819aLW)7m$!BtOY;a!zQM#FOsVG zqVt5f?tj-hUAy8^>u!o_wSc!@xi}8_`uM-o;gcQ(mE8?Ry3f}c{B4JnE0q8vj3&+ zN&nQF(ytCSbfycM|#wqX7r6THU>>o~}{Jy;{F(z993KFoX}Ca)iV zqw*OZeVI(rBr_KMJPcBv{sz@C${;m+Jt)Rw=hVK5l8dzId%Q%+eB~DIUVI z`j=URWA@1}Xb!!c8(*#u+p|GaPWP`L!b^!BBM`ozk1fF;H3i6LZzq$|>RyYEW2_6ouTB|OA_aydt z=UZ<8aw;szcTR{|&IJe6g9)I`=DfUikRoJkZ1|)Bt$OqM$JSL@7uqKpF3PaH_Zj{A z&wzo!6<<#dn{ix8O%Ldskq8TWyjGJV^XrT!o;o$|*dR+o%Bk{~5jivFs=w&!*RNWr z{14L_$kP3IX7q36=p*$iVi6Z;bN|l#qI|=!|A!F%O~`1!`oLOW9wm)va4^~OvjE;q z?U7qytde+-Wn*db!GpaIb#D_Db$z@ueR(YlJ@slw_nq@k6aa5czpmMMOU7-@P?nXQ zyMQ{zxe)TSU6O;z*fA2wL8-VBHR%oTecsQRMIe2^5jO9J-g-7h$6oq2h`bgGm!EA9Oq z_wpbFO%52MCeP3bv>ijp#j<3eWi43*s-eW$|C7MkW@_K|_ribbtrHVYHS9Q{3psQO zi4PVPIDey%T3Q3Nyk`L7lSuH%{&_&q72U1Xd2!R6Sj)dz!KFv7O)N``um*~(aY==N z;(i%Zc@Eu_Yoc)}qmT~uy8==s&dolEqEW^1o(D&#aznKDfeJjEap~s9@zcs+d!rAG zHg&3?>h4Hw&^j;O2e;a%4Z7iR3a3CfKQp6AQtvErM*0J0L*apHkDE(9WqL|}#z*wA z=NG?m3y+4Kpw(1WzB<1Rj89l1)DVuGJbwG0v~izmrH>B{*uLQr?fw3_+qsfAxQQBW z2@n4VjvQw?5R+c?Dmgh@9x-7!HLh75QItXCQIo&0a9OOdbJkAjw zSrwzM7ZIZ`utMA4b@{(Kp}G0e)(n|Id%&|-Wo7`RrlRTCT~dthzI!8#>d)ON0jLmr z$tWe&9sOGt@1|?s=GzIff<3>k3FwA_W1x_)jzxZ3>nb+`@5@9gVW|?#nrZ!=Ir|7d zYMF4D!OXlYIghfb5{qq;hzG%fR1LdwJ=0a7mt#tO-8u+~M$w*_o(Y?4+d zzQo4C0pe+wefXgZK?78okFNbEt6PKN7#~6HahikFpw4!I-@=zD-rbQ_`gXSC?is17 z=%0AxjuG`zR&=4=3RqxSBu_;%Ct&q^nf7Jw^aomnT$b9d=wxRt1lzR1vSKne zCR$^e-9+SHvs;e>Y=Bn1Sc!?e-LI*7K;F?UZtWS;EJ33VoaO0@G^g3OO$7L|_FfAK%N zNbix3kLW212>*Gl3seGs9Qzj_wFMNq-sHzo?#km;7e9}$OBfuW{}%VYnSNiaJ3 zFZug$V+5O0xs8I@mHdzSFZej(#nMs}wJifhtC~x+v#cZH#LVRG+!#o46G=H$M@SAC z#{4}==yQS(WUvLm9V2ob`Cr3j$K6vHttJ_l46j{hWa@Hjmr0F&ag++@2FK^9ND+Nw zfK((_ADAbt$^6a=V;C{xKV)ff7D4I!G-o2;NEM5knY7hP`p+Ad5Tg$?R+bZ=cIJ=G zTW$_~*l-#uUOO>V9mBY7*@?0U^|kw~+&NjGybB+bP$=L02OI0ph%o)!NYPLV*aViw*#E$;I%xoNny?1t`v z1iUglefi{Wnh*WmM{bOHy!N}zsh(l6LA}<6%zCw=fV17``s&tS#XMRqF(4z!^-xIa z-j%;n67&Aj(&prP=qgsl{w~f_wtBm__F7M@jj;cR-T=X#*yR|+25!BBxQ3op{c;bAf058C^DZ%( zfEwydJca8IOhJ2g7=gnD+&;cdRJO%N+#F0y5Nq|RDZf6TmlEk#1D}**8K}}X*On8d z``5uq#Dr73$|)xKFRiB{;&ET3tMhvi8saG&y|-81G0`?iT8F+cau68x44*#cthoIk zgYkc>?akw%eBb`zYYN%m|ZW?E2`t!$O0Y#~_^AxobY zdqk4GkTnTo8^%1xHTryi_kBOl@A*CdJpI)R*L9ueaUSdYJeD^T!*84Ytw(>}2(Y{$ zo-=cwm-Mjj*syim$&0t9o}IrOg|XUS&gR-qt?l?oQb8m_*6;35JA2m0qEk;l(TC&v zQvy=Yg|$BYyepRNh?&^Sc3gaOy24$aQwDao6ra{}h#!D$6sNbb z+J`-H4Kc<#Y3`G-3>PhS(hjFk6?0vH7CTxhzMmo*l^gdW4I3m)%o3=d+wNhkbYK&Uev*dle+Jsl-kL zi8`HqjC#4WW9=72h_<~tTfNLQ{DfMgK=qG?Ewd!wnfa>zE-&}DWL$-@alc`|Zv4Kd zXJduUZKCg5-a9DV8)I(xBrD)(=j-cFzXtRloAY#eevsKB&MF&>^>g6e#7Wb^8d>%8 zd5uf%rE(Xh?HKjv(>qiK_N-t1@$|HKcZXQ&G&leF$)=kP^2f6}m%mZ0=N*Lzhgv@> z-5Uw*8@V{_IDC-lK)0&9O5_C(xw5ny+`Ja$dgr~Fil2?B0Z3YI915 zvKn8XtcwkzaSQqE&|LHOPg`gjb;7lXIgMT~UAUgJ8sgw!de7^@Zev$Ev*_62CA!iQ5N|(w(Z0WkX-bKQ`pe1$AD|4V;_Q$)8!d z$3MFxN{LShaCeVWv1I3*YBJFhbNb^(W{3aTy=wibO3K-p9l==Kw{!PT&+lxiP)(U} z*JUWpSNMW2@_cRoCbKTazTVgFqnJ?ORbiQO)~;gvN8ECl2L0}ad6B@m9mmo^AMOvn z;dF*WyqX}R>M?jo*xc=HAL*f|>pO~`qu7n>G3}p_#lKgSoy4=rI*zt<} zT9KTncLU@4`?~?gp-Ii;G9y}P{tfXmg_tc5r;tr$_F1^#HlrusSx#2H=y~=g;M|h_ z-dT13g*%fqE7s~70y&aG%fUeP$r^azXLW+`w$+#!Lfk&xF`=6K)#Q8Tr0C;15Xs{iHUUmvw}BhxFSdyVo_B(CcO z2JZM-`7>ugn<2it`e?nUT~e;{Jbo(5yjVmvUf8%=d@x};5z_ohU3>0LG2T7PcD~HM zTkcH7y@?fU;sch4gi_xny?ZPNeqJyCLd`cjG%e9dyjFGWrA*o@ir-@gz1y;CNr?rg zoBNdWR!Vb&Y{kzuohHVzz4>&2%AKl=%SmQCrcVPTr%t508J<13GHYlcF&T`FK&#f!^cXty zVp(r#?fOs#5lN2M3$%)5a?#E5dFiSX>!fqpbW378cV8d&OHaS^E9&KLEKjP;<+5ve z{+G{s-He{ztzRft9x1E!Laxc^ZJdaHWaVByJ5#pffCDO6R6-*1woUhaXHL5=COeDX z=3H>!_M*D`w)~OEq2pn@G;Nxaa50e4D)C`3Jl4qKU81X2K{jQJ|Lmv7roVcVOxP|Z zO}O_DrCw{VFnl(9IQh^DT+48R>vT*apMkCPi%+HffUTLbc~)-A{dIHBB^L{CHP40w zxsGW2CPllR;=6Yak?x2onSbJNRTn7vX>@&5FXQ$3$fXAU@P-?;c!Lj5FKYtDm+bB} zmD<10j(Hew-=O5$8*gBN7rmX~^zirTgYgU;#})0IKH7CYHPEyYqb@Ow>7gQmo zbWd;e(4m|A{IQ7+UbF`*>zdq}SA^6NIgzRXlU2U8jLQXklB-)LiMHa=UH)0bP`UMc zXSbz}+%K;XLkjWW#zah&WJn#JUY(=LP3u@UdI$GSJYqr$<|W_G3fDL`mX4gMCOr3d zHtE9)4_5Oo4V?-f3Q~^UrTGLZHVzKUu*XKQn{DNd+u8e2#pO$}Eaaf{X6@{_ZFe%9 z!Su6rd9P|p#6P8uZ87rY?7=Z~ z0kJbz-s4CzE0%-23|)ha`gp;Eiys7LzpmN2_5bpQL^?P!{}ZzgNy}#qq`Pws3#7wG z{1qSWxqs+|obwCq_dYeQG8}f@Y%O-TX5&n<@})$RTu<#VjSq=`W-z3z7El%N665zY z-A}J>u}q`<;NJ6j-ed-PWhjuODJ}Ct+IqD8UN>Ha>=L$bUo-BlA1GmyFy2(QW_|5^ z)^x5(^b`~@6g|6+*`(Py*&uWJ3&m*Z$aj?v*I$I)E$Y;cBaS0&4L z)y`ko%){JX``+~FtjMNV;cUtCN)=&`FzMZ_Tr*oA4$e}&4r=T>xMPvyc&K#x>>Vem z&1Q?_E_1W1*{Y?3OXhB)x%y^&+VSj@xt$twjIfIGlTh$CaVH#8J7+$rW^v!>dO(nF z)n}!?H`7gSRst@*H3V5xw%bv{2kiwEC0Y|q6Ee(#Y#WJBXVVNtZ+Ef8Xa7#kRCui9 zKREksJ*RA?RAjVc9AkZ-6TzZ)cTdmzwu}C=R-(M+(P&GHhGj?MVsOz&d{I2GbXahF zV*{_XZ4RMB8KNL(FTqztkZ-3fTqjl|Rd%9xJ(V){gd_ODOre z-iFX1-JXZT^;oXouzu?F+P@~TJMly6@8JD)XAa+dhfm2C64yDVz|kGgqra$Zm8%rJ zIOB8Z?x(s%ef8H~a}BuJ-D0~}F-S601lygRqS_ufxJ6$H(|fNMt$TWArC&-`D%cWP z@YOZt-u}Z6CuiKh-bib*(P%Lx0@1WR*ytr;D@F9sd6%exVDsXq9?361g7;T?{&wtB za_K%Nas1o^mr+&*!IM`yjjxz{d_1(&+VFl~+M=&j9wpa{NzyTLlWxhM}Zgv81ATfARmh@^s>CJ#*OJUvEs#^H2myXISvI{oF2x$dU zPwTIDKnI{-pKqS6ERLItdyfRLZIm~Yu5HeE16lNm>>Jg{(PB4`uL<4LIJcLsuF%}F zE0|jEYYk@tIS`U68gl#I!K@hUeaQk(dB5E#*KT9Fi^5TnoToI^E-TfTCb#zglkr_GtQ5uidB#tz~W%@{_I-7OF^f#S5jHfr!{ot?v zmBs_(`EvNGgJy`y4isJER*06lc|3!%cBdVR{jtW+(1PVFw=Uv8)2qmJujh3`)w>A> z^4iZ^^#vl=8Z5u?Tb$de4u#nOfk2Te{QGaU(6ES>$mCB&=@CBs0==(e3^ug&%l}?` zjURY!Hhn7M6$3nd@bAVFO*y9-CZ9ZkaAU_tq57?jJZOZRqEDza5LF~db7rb@VFUlB z>9u@s8(I$(@u=ie98XE_Np0a9ABtTxLDE=IqSrGTF_M_j(*?RGCZ#UI zu~{EP==-jJBBGXjQLCJtgBsC^kPimX(FP=1|2;yM-auFrP2GLIj?T5U7b=%IhdOa$ zx7Cs40+)zhSC98x#Kdpfh~$OMAd-jb`_td3eb@WjkJ=&>%m#lW)EkgI2bvBE_#9BB zG?OaHj2%M-xaxHQ51t=FvPaW_d0U{uw!c;6d&yaZdIyfrfBR?=)bNB{yb-N$!4!&C zjaD@N{CpUHLxA+gW}_Zc_55BnCr-@x{`bfT%ioV_b1_D<08hNzw;$?E%csX9h;z-# zm$orS8v~=Ql+eZ1wtv&8?(bbyJZ%R|w%`k%LfJIb!{bvtY@GkK|#HxiDS? zn~Iv{4`vvIB9ez0m;8Ii+`gH_i{b@*`(0*p!eXF~6 zplq$(2Kqba8FcOL!hR~m^zcTrKIRMmf~qUD0|6=XpMD!e@iuI&4BeWB1qM+J>qKN_(3T6}EV(Sl zK3WtY4V>htReZ8R7liclT^1I}fdZvk7jm04e&?CmdJQAS!dvJmLMMVN&K|dKMO~}V zH3m&T1gwSM`-~HceDUvU4&-X_7-)h`g#}bV{~BW8qElcjBHV| zMMm$UGLM0MJ{M<3Oilm|TmPOQK77}mGgWOsrsvr>0n5*f^h)F_p~-tz%Bz?)mxAQ?k%^Vh3V<2=q`iuFo{I`r~DM z&EG=*X3>y?Z3k{+s1X}kjGv~zO$e(sT3Xjf)$lwrA0-L2MQ!K{1QLuHDeSPSHYSdd zzTD1;tAWM^!c06_>d@loq1-=CoJ{ye_y#m==!5mqCdMOJmVVPl|Ady*-N<~qKaJiP z0zcS|3hMU#$hbZj7KFmHADg;iR6Y@_s?^jIb?xg@M`jUk7V*j0PX)9jMozr6uOR}Z&u&r~OIloPr-M2~$ssLvkc zeOIlEbd9cWOD-Nv3;VobCPoG$lYfO_6vUo0BjxW=3zEp1hf#;V6Ld!RYUg%E)c0$r z)dBrRm}MXZBOmmxRZluVI?tKOh#uw`hzsJiUE8SVA`-1=i_bz~Q*#nn%#nSTI)R(D z3#B)Y8=x9MS>=7r1QO4dhoN^m_<=SaF?n|N;CFrbWL@YDQE}0VtM)Nn3LI`)ZNhG< zOjRp1Km6K{rW~dWjUqJSmv~9gWhMEr=WDBiQ+xl@XzKLRh}g9;_q@(iQ{w-2q&g&j zFk5+24%m=(%6=aMW8t;i7?Z;+gy2O;dHgvSu6D@nAji}{f!Tz>g)wMDHbeZ=5ZPML zmFN7muhg@nszuAqs?rVK(nWs@f)p;_#^f~2NaO#H&7m#_23J{adG}{=i#eot4nDTp z%W+e+%AmDjW!E;+hmRuW$f)&_7t4A!^yCrdE_u$8K1Mt<{7cRKQ~)&KEz@|tTGXm@ z7`h&P86#9*HEQoMS3A*`M7aFI{fieQ!4SR`y&Uw#gg9}gwa$)3>8Qwgn`T;7%bOws zg5_=kAMsAm0&(v9DV;byVx`8LD@WTKO@bc?n`10iszN=xJZgJU9^iW$ zQ1xJuOM&pOVv{^c>vB{Gw&W31`{sZ+V;lP{b?`#Am7yADySoVbyz-ic_hKg ze}V<_yVjS@Y6wz#phV~DQp-B;?{8Q2d&Mh7SAIdKx7Oq! zXFmCZVf4j8yMi6IwcG1;IBWk$PMOr?*#s?valUX@PH54Dwo`IlQg5fEx%P(IKr^35 zE1B0?A5k|lMfvG+xR~;dfk&I_`)6C*yW5xuDP`_1L%&Jd;yN(3A5HhlTO()(5Sx-&nKyW+D||>elN6Z7aoyw3)8{BF**> z?2aehu6eIgqyNX3~jEPxbEvy6HlcJs37p4r-zNd4;nZN^Ub zn=g+Co{b3*RwldJMHxvy|DZ`byQ*R(?TPE}V&~ejJFUq**Y53+Yp_%$=EUGS2IW7< zh&S!~-8YYO8;o0&3iwD|9$a^&r^>9z({@eo91&JW@HHR_1-_V{eyqadI3VgQkrGB+ z%1-!{sUAHLP1(AhIfbdUoyeD#L`?CnTmGj);Y%w6a~50#85sVMERXQr5a8YeL$mZ*)5m}$9_M?}WOsKSh|wb{|1T?_Dbv1_V-wZ4yfJYJfl(bc*iNd!-? z{>f-c>LFrIQ4M4jh20Ffc#Jc#CO85E{Ulz1x_EKgm?D3Oa3x{g60!bFHs?Sb@Zh4` zmY;&x+fca}!Son|P>;1#lWPd#&~SrP-Nm`_>T#Qi7K&F3N4sajiwt$95iMcH(qH|w zmLFT3qU`s3f@cHHrTU#MxR+eodZ_;Q*-+Vu=>pLD0)1#Kwee1{uYC5}U%S*H zicyS$IJ4umx~C7 z&IpnTIqk$MtAyW{8T?Jb5w3|V+ZgJzRhV76D`}733B|AEvm)crVoLVO&m)7}^;I=r zw0n*tqYl7fzPc<4%FN&s@L~{??cgN22$r9m;6$_~nUMonfSTkD1B0_Dy7#D^Lw%d# zfs9BrZxbKmKOQ;+QGehOKEsc?LJ)`R4x3c`J$~!;fEQ$fOZ7;WIa2x8eR&kRLMC}B(HjA7vcdIy--qI&&W zMpwW&hNs&wnY8DdV&fK}c#HNzG^nV=#yMmfk0#|<$7)DZY3D8yJLUbZ|2!!n2wTIm zz0fW=m7Qs7M1yz)o{wJc&>j0qsJsFZV27x-d&4>#ei0gnbsXMJJr;YuzuYk%2Mx|Z z60n?FtF4{X9owMCS+pxafO-sD@o1<)uGHwBXB?@utcYFYBH3Tjq0ls z4TDf4fSaO^itJgh3o~k+t5ap>0kXG6Nl{bVTWRMAzoRt1M~jlKEoXfy=+XtsnOvFg zU1V$qh=Ur^UNg~3POfPu7JW~cmGs+olCgPQ{@~n$>idgQq|Adpz4|g+kq^7T+b5i* z=r5eHq!@0=R%c6#sQFT#Ix*8Bx~Z@vak=iwE})JSHGBR+@cNmc02@KlyWNE&)ft8m z0-Bgv=Fz%SF>KAu7{vc;*jV7FPFp)9t;NG0`IMjUs!M={@1`%Ujx3f#LigtVd*~y0IMhHK2;ujT%#17dB%d>;_td8BpXa z{QI|lCF*f)mvqbB9@cR%#eP#%B$l=Vldi(_00<4p8mLku&1u$mP6d&mxFO)CW)xeJI=)}!AZp$NnLOwhdN3c^;)Q&mHWNKdD zz}8TXAOFaYv~p&4M3B#UsWWIlN38iaBlY`E(Y)n;`4*o3@%ZVlp*H=I(`LQFX23O| z2~1B+q;7lZ%=|r3q?x-Dcf~XS747CSDBY9XF* z2@MP&vrcX=U+8*)Mm8lZH+<(SL^u*zVeR_Gh0`pF+zd!NYI=2Shj2|5K)l_7C6mQ6 zcPGXCi@$Wzjzl7J)J%cRS3(fdgQBtQJ>=yUWao;6;p;!_D;}BwK2D`n=;yr|Ykg=l zqP-=P=sq#aL3;kZo;Y$mzKn_n(XfV157yN$Q$npv5gQ|wIkA;OmrmMRBp@89EXMO@ z5(|cX6`F;@f_JgR+w|(^`3rAstm#%ePV9=enm{}+Y#H0s8%$E&iC8xnP{ue~kVKhW z;s|~(eUS_ffOtv1UrF&lD9H$+$SA2|Gs=Brd0>PB^HEpanRyL{+t9=gXsLUn9k-Oy z-uhwMdOTE|_Ic{t;!TTPi1jRNQ2!0E@6qE5Sy~HGR$b|xIOsqTj*vc_m>4uR+i|0^ zZ!LTs7-QVhIKw?tJ=9sK^wSK>hHw|ENKse0x4dn7R=1w;3H=-O!?T>tkhsCFIWai4 zqwJ>r$}=`Tsdyp&;3t0e*_70!ZTJm+G#b?|R)p*D%P3fnGXki~?jPj^(Yp0CetRIt zFUkPb7>%UZMj*7FKROY0h?qrOjuoZ8IOG^8jp&ZcFU(Ra79XtdoW73C$0XmOg&5N| z6y<2>y!!s+g@B)}(tnx^ugWM%T3Z@TQ#oumTQ3_j18teG4>qU{!elC zjzffr3p79g!G0#jeTBa|jJ?A_`q^Gk^-qkQchGk8wa;b6hE!v}-{plt#t;r>X(F{x zRcm1hzAjrX+rme>c_%KEQjwP@k=p0pM>b#DYsL^AUp>v6^_!*mz^r^Ok-QlwZeIZ} ze=3PMP2_FDlv0q!a|?w2^0A)KeACxM38JXxt<I_iA5=oZ%f+(#L)*O@-`fIx8KV zKZ-XLi8-N*oa^k7xps1@L-f->N%|A1;95nq0+EbA{>z~+STJXJ%b0#Ss&TcKS`|F+ zk^y^JJ5+yuf#^BdVft;cBm5ERGb-4>(ep*D-+o(UL^IzVoa0$AKHkte3}ovFzb||F?mZ1MLD7wPDMSGkhHjk&Mui-b?K=^y2--g^QSWOh)ovtw&=kN@F#QTF z?5dler8CCXLxjwCdW}&R%5POoz8}Slh@?qE#DZU_@z~G??fmX66fZLdz@zMQ$;P`2 zmN)SMeC7303KjsZvyiqj#S7G>@%KdT4eeBJ`uy)PLueT~N%Z`y`^~p%JEFbjD95u- z5r00Vu%KG9+?0Hilm*9zP>yEh(o$Xz`NgB$3|0^yWf~4IqEvWa^&enG3V*?82!oY4 zp^ou(WT=P-aQvDH4efKpj#^F*8vawc0s_q4YPKy z$4yNVn2=@$*l{Vxza&p%vCpTBg%iLFRW&b#4WJYsmvdRgDBiw^-!Jy|le%=Z8gx^` zFN)k>e>f>tFJXizh`rik&fY#J%-r)CT{VfLsi!oxI(Pk@!rujR)*KmeAG}~vRr;sz zddWxNRV4Zh`qD_a^vT=e-Zns;a6r&Ue_0RV*a5>sanMaUTil=h3OwAuUl=_)Mbacr z{OPkXqD>C;3JsZSIvy9K&;Kbo1Ep~X??k7p>uS!1DlO59dDzF_1}MQ{AGDov9MqDz zS1!d=9-0|nZf2yBm47^l-`rGOvsOpsBd)`U64zH|PSoGYk7fdwxl@y%s7x3l-lHeY z80bv|#kgsv_h%4~KR+E?Q`JrP6}-MUZ1k>h-y1&)Oj6M}e1!@<&>vGq^p7l>4$hm2 zsZx3hTo|n50X9d!S==2|fK%WaKymZc;HJa=LtYl91)biKPq11YFP`Zt>tE7dv;VI+8pGhT zF$j}BfTSbjJ2LH@FVE9;&+8edT%wN6xA~f^|I%Q+kNRy)B3U)4WGc1!^E>Ev{mRE& zQUB`7kg1Nd`}7|_hwJVSf`Aoc?6W0NxwgKeFdKFL?p+IIj*DqZkcH&$k(tr>t-cvI z)j4HcU}aWgqdOnNSzr-e0wZi-kcnbOr*kO(&wByDUlHY^*hu}>tmrn%m1dPU+O$qc9%JN^kmoON#+R}6N z=WKR$;($T|`2D)i4!zm=ZOMBg$vs0Ql#$+q@cJE^Rm?Ci$seta#{Tj9)z?A!4h88y z{TI%d|BkA;Hgum50ONvSx(#L6*|=R`xOf+0?PUK%^80NGbWNCN>w(&C47FG7OU@;I z^B{;??9_SK>OS+gGx~knr#_fpQJOs+F!B;WJPp6aeE%AQ0@zmrP}mxWwswqEd_5gD zNpvV@MGC|yA3iL#D%Dt&1-~5Td8$`aCB@c%%(J4a+;^ez3+L?+Q73gV6fB0ZQHqOltI)Tq@B5GLBStpWH%j!zTXmtOGE#U2;G&6F4ei7 z`7Ec>PRf6U>MB}TWa2(cu^A6437>om{2S)MiNx!>UOnzQv+iBzfv1#utM(s7@bdL$ z3&fzA;9QzU+5f%&xbeCFbT$tzvnmMoUYPq+QQ2d4`9Gb_#nu)Is+|Qsf(TAiPF6)i zQB~e+IhBQYx>^vl%O~^q29NGimO%`8!!w~c4hm_;>jr77K7KAS-n0KC#Rx&Ud$8^k zlUVPC#t@jHWCGK=oZU^uX!Sw`)ZA%utI7WdKrh`&3#q-*bWE3o3Vv41tI3)QuU61+ zs#DxWBAmaZc}`{PSNTr9caGWBCFjy#>I|4)R^U36Z04JkXDO|mD)<(pmMUOTM1jWS zQ8oT;3g@LBi1yBh_)ICcLMd*t(fgBh>H?CRVMkJgfc8S^Z5nZU+Z|fzFrRFc!?Eh z(=RrnM1XzfV?yjSH*_C9HI34m2mO$l>W>5<(K}5qv2uYJQ}ADNX_KGS-H8j%Xi6t^ z9qW!wrneZb&wL)YZaYLQ+5o_?5x|S6!k-J9tP$HV=7O4_q-0-+oyzVIJudTN*>cxL z{OAjNVOmYur#^qrJ8ag+2?rY0!Pjpf;%Bt1{OLXkBh*z6Sta^+72jQ z(XGX}LH}(3^E9d~z|H*eJHXOQdg|hT^fk!#(U+|_9!|czSV}!hmEXg535{~2?wB(y zYP)AV!~o5rkDgvTzF|hyCq8hLY>J3S5YuA|Q38Nafeo{Y1FC>wi+%wr8OjBl(J$Bt zIe7deSmWaTEZb z0!=4%@oS5AkoWUFoSa`$r@-4u4hD39}`myD0b+&HnHSvBM;qPF(b>(kz z(>5IaM&24zJfze>q=+l-pl>c-k2#OHd;I`}o#4jS$K5SqLYqCyVoIrK)Pk->xKU5H zR&XM!U4)7BrvCf;nhfA9hhF`!8%McvUT7e#YSpk60Yz$UU{^?S9Kxa52*%(V_l3K& zK}ewEC!m#4pc~c!uSoIHq&Vjik%(|!WW?0hjA5%b_(-+F_8voo^ECVn#PBqf6(bZ) zs9qoBqd8qL#|Y2B518&xU6k@ZK~Zl1SrUf94oBMi^m2CMqB#L0ig+!Foi@-eVL}oO znD?xIC{0b-uBlFA*S#l)9~TeyAOC1vW26y$8wlS0;O%6pOmN`VO-d-3F=LlYw{Pzi zO(+p}XahV&}*&&cZAJ30Lg2Lhdf-xu4P%y!Vz78BMMH4i6@E2!X7BBow)eTXKI0p2-uvXflH1%8HHmOy$*A=u>?yc>jiQc z8c@fM3uLJ?*g^Ojoze3r)OxTZ)3G{c5fAF8z8rc{0}odDMyHrm3RUh99KywM;cfluCp6L1IkUa2XVqXaG`>X~p*K*oi41OnG$69bzeU zP?EFJ z68LnJJm*TUUtFfF9m?1Nx`+0xOM;+n*y6%lb6|ho!-Dw*%cV~PQ;;KFj6l^avC`oq zq~Crro^*g7nIauFy`1Oxf#lY2PfvD8LcW)R3%9>=7jb?P$Q4XBLu zN4E1Rn0Gs|a={L}-<68lo!AJOA*Zcwz5r*BXC0Psb0EBbf}Bl>W^>&azGqG=D~GpYuyM)ME1{e zqNqtBHmL$-kn2BVfPMzl#b3Aok;rDmMC^RoN&66_ zZ`^ns0`N0J;cTAlY(Db%yR#K6o)08?x~2(j?4S)U0HxMc|7 z>BNx$XF+s0wu|1D5Q(l%h6IX~;|rYF0!WCFeFCc#Mk7N7HF#_J5P$7c zz`b>4oaHd9sv?^c4IEJ2uwNI2IDm4x`_SbBUjt^tnI?wrGwiiw+O@T_C*4><)uf$q z&_zu`*CCgm&-I%{=`j-`n|k^c6Rf=LLHA_p9bz*hiWI=xnsN`lc~a^}>`B*#-(n}i zK+Gr{GGKcl9M}wu9xy88#ChVf3kxM3l^P! zAlyST-T{XSI&RDsqs9helvzPmPj4q8Q4w@ z@O;MIc*MFJ&^juK9#kXk39nGyt+{RyV`V=iM!inglK9>4^NPod3Z#|t z*lFGBXX}`Z5V(uc>)X!ttMC3IUSi@l*+&rxXxl$w?m}T9>48-7t^9maG+n6}i;)OQ z=05h>P_c4as~xxoy2EJm!>ymMeLl*tF+qMoAIH$-I8^ZxDh=rPGtlLFZciCej8Cc)^Y zxfR+Dd@P;GrEBQzETFi$JpkB5Mj@FeEx|4yd}Q)i2@_V`bYSuLLR87dodZ6q;k+&> zqo89uNy*N?m(zHSpRfCwmxmgriR|!*%zSh1T~tMbydxXry|`u=hG_g+1YCJHcW$;`9(ye!>KuXfe<$-A?TB zWV*EB^_#AsdUL(3hH?;2l)VY z)Dpq!XlrwA-xe)hSdJaCC!!{l^mr%WGP^+RS?ZCXC|4YPd_tR6arbr))oB|nFPxkB z1l{UkMtFh6h;SG=mAk4M-{T7HR5V%8i>_+!!R=?`>1=7)(;D)Yx^tMD2G18Om`o1WA$|!$*NbcQW;8L=(JmE;?^gut1+>G;v_8;w{B88jbaB6+itp3X4QE(vv zBR2xe0sc_?2_*5+(x;%4u}V@CYvpAU$;;D6br>^uG9YsjaLkXndbkspSx6~(B=KhB zxBj}w7x&5kctxp~FSQ${o(ja*o@;cVgGh~gfq>(@OeEE-Gktr^t9R(R3fEp~=s9CE zbgS)j<8rAO3hK6$ijku>LWGAT$2>*frJ{86M}+D>ed^L%nN1FDIAHNPrQbJX?O~*S zC8eg?kJd||!u<_WvI}Yc8aSpQ&1)`dLVcS#sN6sF*q0nxss-av-1mxO&H;8Eox_3E+kB>T|3m?JXs1tAUE71$iK!zmUtJvQ zyr^ZYA8dCd|1FXOXj0K#eblw0K%xZL69segGTH)VODb&BF;c{`?Bduebd|5PU&dvq zOTj!FIn2-Duwq|b2*LI}x@(MvPN4ce@TI9r#StuDQ65VGSX<6fin@%X%(_xBq@KkH zE^W2Gx}ivq8>`7F!PI2{*3uw{6xAan|J)65Yue!S70}lSCqL%VrUI7;->M-3Lmbdl z)A_N4Fp%+mkJXakt*B3Fazs#``k_?JnoaNXQMfQf*oP9r)}|}j^12)x)!MdAZ0^0z zcYHCA_+oie*2cXLNi+H_czJ+_vj3sufr%Jy8lnJgNf8s_Bv;n&-f89G`m0aCzPtga z!9?j_2P_G+uvZ+_6$h5N5D#OL3KKy!1AUWU-E~KuChJ2gaN7!o(|Q)T-fl8W!SmQ9 zW%VKeF+i1Wf}7m<6X2W_&P=qUcNJJ}m7U&)0rZ=D|8LrXb&lOUYGGaP!)GjJ*%7#u zM66kX+V;|Ff_UK5+V{9<-9Gy5KU`~@EcV>s)OO6koeC6?hM;c_;uF-S778m~)vX1G zk^GbOiE)OQLp7y_j(Z^{yTH#i*$r}jmX^!~3M)FW9LG%V_Zv8J?T_Q^*rU>4*I;0q z!_~P4?l8S%6^jC6NnV!5-rqqZFIvm@juR9jeQ7 zFUML_WD|^G_GO-p3IBi^wI>fJCQ=>@nOnY8w`$1gk}Yd4Wg1z&)h5%P*R3(F1+;X? zHj(WwpV07ONB$4Fastc;u9ca{$}P<7vV`N(KFaLQrnW0cJzEX~PVs+}A(E!||C*lo zFSzGDIDB_4>$rD*3BlgdKpt&VW^;x}?aA4A(l7nB|8?I% z3O)gs`PDstn87o6#o>|RSjK2y1M#7l$zeDI9(FA>+Y8tYMdH+>b+&3x=5W-4=#=lb z63jopyL32##h54Jr)u@b=H4e1zn74~fHzwH`9z37HCtJJ0@6l)@0<4bo253+C>V$* z9a(KOMsuKKBVm^4(9o*mL&6L5niZHCmq?9L)7v@ug>#$c6LTp_it;w&1h z#!N?ZQRjOcz=AF~W9)^zI7r3pn!2F#sO;AR?>|4q$~1obo51#It>0eA!^{Me_y}jg zUxnqxtwic&squPFD(7z(b5U3^XI1MQB_(%ak;jJic6p8w6Hyl)2{ z&5S1$rjrvg#s-yXVvHe_i;^@xtyt>yv1*H=NdKIzT=nJuWO^lCX1zVFzu=wr zD`6dYhV*cg%?OPRc&yap2PXyn?mm27T%exw3&D zs{`^xN>pZh8&LkU!rf9wJ!48)F7e6vKy0^E=^v4!*?Pjk^Y;kESs7ZgeYY5a_Gb*Y z{&iSC*yd`#CAC#^1 z5Su?g;@D%Y0vGtFl=~oVPy%nfu{!%^a(7R%Kix{%`xjhPztRJ475e3a7@^SepDAIH z)r)H|WOo&YTkBJQ8;jJr1~17U3VUR9Vv0pvr?tkt+P{B!qH{6sdJgmY;_zr>T4RDy zPgIMSR@?Ws+$X%sK^_xpSMBXw$P{k<=|@vC$jT@v{$KrQbgx?@BDKm*v+dDMhu)N}YEllT(*shjL#%+c-}2pk%5oS@8WHli2|DYK1$!G=E_ zT%(va6~lny@}e?A@NA3nZ_6Uxz17N>-*~+B;R%A7mV zpS&a*?6OUlW(19uR@xgKI0Tk^qa2q3XeP*QePCJknr9eu#Yy(Q>sywL1M{w|)_Y?At{i}~HL&RFv7LSv&>=1(!+ zXdy88D%c!z=J7jsP#=MGt=<*+mf4u?zT2fR(j4m(_5HK0yfsk8pvr*|J-zIwk|kA3j}R`tl0fcWkV%g$dD^QlFE(|W z+B1I8&!@q3zxB6xOJ8UK;n#n}NK9G`5)MV$=8OBbdz`Gu=Fde90XAWd4+-`Qp*5)8 zn5^scN{>J3oN!(=Ur4+Yzn7XGli&L)G*azTCFAgiaMclGwqcuwS6vU*Y}Bq^#Xi5w zA=27ryQ!@bjipWm;HLL`L(qr#$CV*zW`DE_w&>h9&U<+{)k;{Nr;fcMEADa%ja#SF zI#6fwilYL_6nsRu8Z~V~1nbakT~w`MK@eNhN=a*&9EnEYNOYj7DlZEX|9~J04ztX+ z@;%enC5p>G0!D*SA(b>O3Jqs_D{<2Xb^r{))nMNOR0iF>#F`imsdE%IaMLJyhuqn8 zp&b}P21I}qJdzORc5T5Kz&36A4|f7yGfqIo+yDH3vKf#J61b>A`G96{_TDI%>DPxZ z27&*UHn?C8foCw1)(X=qk=S_B-0bo0a%mT7^kIn9A=1aEg5Q9*RW)Zg(qI}|=JfVG z4#7e~8Il;?6%XBI5Ii>|8t-l(=+zb z*#DBt>Wh?ttq@5eX0>^Zcd8712 zF>s{KvTu9zEZq+QFb_81;H>J-_J|v#1wlbA$S{cT(Iu7rNw{>o3~mJ=-}4T9(CdB< z+L)hqb;h%UgsD4OWtWhelgf`;#iwW_x( zD|F34WI53{D*~B;T@3-vK+|;h0EMkr;PMKtr}`_ Ji(}R|{x8QCG+h7y From a9cc6d2b7d9d0cc13ab428810db13199aea590d3 Mon Sep 17 00:00:00 2001 From: German <28149841+germa89@users.noreply.github.com> Date: Wed, 25 Oct 2023 18:42:44 +0800 Subject: [PATCH 04/12] Setting navigation with keys to False (#2445) * Setting navigation with keys to False * Update the image cache * Revert "Update the image cache" This reverts commit 39e845f37d16503f0918e9680871da251f4982a4. --------- Co-authored-by: germa89 --- doc/source/conf.py | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/source/conf.py b/doc/source/conf.py index 02b9e8ce4b..ed937859b7 100755 --- a/doc/source/conf.py +++ b/doc/source/conf.py @@ -258,6 +258,7 @@ "show_breadcrumbs": True, "collapse_navigation": True, "use_edit_page_button": True, + "navigation_with_keys": False, "additional_breadcrumbs": [ ("PyAnsys", "https://docs.pyansys.com/"), ], From afe9b86acd48dc4fa088ffe36dd9c74bb85a652d Mon Sep 17 00:00:00 2001 From: German <28149841+germa89@users.noreply.github.com> Date: Wed, 25 Oct 2023 18:56:20 +0800 Subject: [PATCH 05/12] Fixing "Attaching modified files to PR" (#2439) * Adding more permissions to the workflow * Testing changes on checkout * testing workflow permissions * adding packages permission * Setting navigation with keys to False --- .github/workflows/ci.yml | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 53da909290..24a9352d3c 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -47,11 +47,14 @@ concurrency: group: ${{ github.workflow }}-${{ github.ref }} cancel-in-progress: true - defaults: run: shell: bash +permissions: + contents: write + packages: read + jobs: doc-style: @@ -479,6 +482,9 @@ jobs: with: repository: ${{ github.event.pull_request.head.repo.full_name }} ref: ${{ github.event.pull_request.head.ref }} + persist-credentials: false + fetch-depth: 0 + - name: "Setup Python" uses: actions/setup-python@v4 From 51c1db4d9022241a1d2027d9aa09f60c4ac774eb Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 25 Oct 2023 13:49:50 +0200 Subject: [PATCH 06/12] Bump pypandoc from 1.11 to 1.12 (#2437) * Bump pypandoc from 1.11 to 1.12 Bumps [pypandoc](https://github.com/JessicaTegner/pypandoc) from 1.11 to 1.12. - [Release notes](https://github.com/JessicaTegner/pypandoc/releases) - [Changelog](https://github.com/JessicaTegner/pypandoc/blob/master/release.md) - [Commits](https://github.com/JessicaTegner/pypandoc/compare/v1.11...v1.12) --- updated-dependencies: - dependency-name: pypandoc dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] * Adding more permissions to the workflow * Testing changes on checkout * testing workflow permissions * adding packages permission --------- Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: German Co-authored-by: Camille <78221213+clatapie@users.noreply.github.com> Co-authored-by: German <28149841+germa89@users.noreply.github.com> --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 99eab51f26..4447e511ad 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -86,7 +86,7 @@ doc = [ "pandas==2.1.1", "plotly==5.17.0", "pyiges[full]==0.3.1", - "pypandoc==1.11", + "pypandoc==1.12", "pytest-sphinx==0.5.0", "pythreejs==2.4.2", "pyvista[trame]==0.42.3", From ffa3d294e87b07df874936b51fc570751c2a4368 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 25 Oct 2023 11:53:46 +0000 Subject: [PATCH 07/12] Bump ansys-dpf-core from 0.9.0 to 0.10.0 (#2436) Bumps [ansys-dpf-core](https://github.com/ansys/pydpf-core) from 0.9.0 to 0.10.0. - [Release notes](https://github.com/ansys/pydpf-core/releases) - [Commits](https://github.com/ansys/pydpf-core/compare/v0.9.0...v0.10.0) --- updated-dependencies: - dependency-name: ansys-dpf-core dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- pyproject.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 4447e511ad..24e308c33d 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -56,7 +56,7 @@ classifiers = [ [project.optional-dependencies] tests = [ - "ansys-dpf-core==0.9.0", + "ansys-dpf-core==0.10.0", "autopep8==2.0.4", "matplotlib==3.8.0", "scipy==1.10.1; python_version < '3.9'", # to support python 3.8 @@ -73,7 +73,7 @@ tests = [ ] doc = [ "sphinx==7.2.6", - "ansys-dpf-core==0.9.0", + "ansys-dpf-core==0.10.0", "ansys-mapdl-reader==0.52.20", "ansys-sphinx-theme==0.12.3", "grpcio==1.51.1", From f1a9895263fb9764a3830be2b2afc81687dbd183 Mon Sep 17 00:00:00 2001 From: German <28149841+germa89@users.noreply.github.com> Date: Fri, 27 Oct 2023 00:20:01 +0800 Subject: [PATCH 08/12] Improving converter (#2433) * first approach * Being more exigent on the commands with empty arguments. Avoiding issue `/out,scratch`. * Adding tests to previous commit * Adding `use_vtk` argument * Adding clear_at_start argument * Commenting better /out,scratch * Avoiding cmplot conversion Improving arguments parsing * Supporting macros calls * Fixing expand arguments * Removing prep7 after /verify * reducing white space in bypassed commands Getting ready for empty-commands. * reducing white spacing Avoiding converting mode for the moment. * Adding arguments to ddoption * Fixing vm double argument * Fixing vm extra argument * Fixing vm extra argument * Fix double arg * Fixing launcher reference * Fixing wrong parameter name in parres * Exiting interactive (P) xsel function if in non_interactive. * Avoiding parsing some unexisting commands. Avoiding consider 'INF' as infinitive (float). * exiting early if in non_interactive when checking file path. * adding check_parameter_names argument to converter and mapdl Add other arguments to cli Avoiding `/type` conversion Passing MAPDL arguments from launcher_mapdl to MAPDL class * Removing extra /out in vm51 * Avoiding dict changing size and passing start arguments to cases where we are connecting to already existing instances. * Better parsing CLI arguments. Adding `ADD` to skipped arguments * Exiting early some functions when in `non_interactive` * Making sure we are passing vtk * Better CLI parsing * Avoiding some checks while in non_interactive. Cache Device at the beginning of the session. * Removing extra arguments in SUBOPT. * Adding more commands to ignores * Force output in png mode retrieval * adding missing argument to prcamp * Avoiding parameter name issue when extension is part of name and not supplied independently. * Updating converter golden tests * Avoiding too early exit in mapdl.input * Removing check * Update the image cache * removing coda codacy warnings * Adding missing arguments * Fixing argument order * Adding missing commands to ignored. Not scaping non_interactive after *VWRITE format. * Eliminating unused argument in TBDATA * Allowing arguments in macro calls. * Taking into account leading chars * Adding missing argument to HEMIOPT * Adding more command to empty spaces * removing extra argument * removing extra argument * Adding missing argument to PSDGRAPH * * Fixing no exit from interactive. * Using f string for `mapdl.run` with ARGXs. * * Adding FORCED_MAPPING for exceptions. * Improving entry/exit non-interactive commands * Reducing the trailing space. * * Fix issue when non finding pymapdl equivalent, it gets none. * Commenting out /exit in non_interactive * * Keeping empty lines * Making sure we account for commands with empty arguments with spaces in them. * Fix error that `find_match` returns always something and it is used to create the mapdl method (which might not exist) * Removing extra arguments. * Adding missing arguments * Adding golden tests * Adding /AXLAB specific behaviour. Fixing not finding commands in _valid_commands. * Fixing tests * Update the image cache * Empty comment to trigger CICD * Adding missing import * Improving parsing when using functions * Early exiting `*GET` when in `non_interactive`. * Improving coverage * Removing unreachable code. * Fixing vwrite command * Fixing kabs vs kswp in Xsel commands * Fixing not plotting when no show command was set. IMGREAD issue. --------- Co-authored-by: germa89 Co-authored-by: Camille <78221213+clatapie@users.noreply.github.com> --- doc/source/user_guide/launcher.rst | 4 +- .../_commands/apdl/parameter_definition.py | 14 +- .../core/_commands/aux12_/radiosity_solver.py | 5 +- .../mapdl/core/_commands/post1_/special.py | 29 +- .../mapdl/core/_commands/post26_/special.py | 2 +- .../core/_commands/preproc/special_purpose.py | 36 +- .../_commands/solution/analysis_options.py | 33 +- .../_commands/solution/spectrum_options.py | 12 +- src/ansys/mapdl/core/convert.py | 550 +++++++++++++----- src/ansys/mapdl/core/examples/verif/vm132.dat | 2 +- src/ansys/mapdl/core/examples/verif/vm139.dat | 4 +- src/ansys/mapdl/core/examples/verif/vm147.dat | 2 +- src/ansys/mapdl/core/examples/verif/vm221.dat | 2 +- src/ansys/mapdl/core/examples/verif/vm227.dat | 2 +- src/ansys/mapdl/core/examples/verif/vm273.dat | 2 +- src/ansys/mapdl/core/examples/verif/vm285.dat | 2 +- src/ansys/mapdl/core/examples/verif/vm287.dat | 2 +- src/ansys/mapdl/core/examples/verif/vm309.dat | 2 +- src/ansys/mapdl/core/examples/verif/vm51.dat | 1 - src/ansys/mapdl/core/launcher.py | 41 +- src/ansys/mapdl/core/mapdl.py | 65 ++- src/ansys/mapdl/core/mapdl_grpc.py | 27 +- src/ansys/mapdl/core/misc.py | 14 +- src/ansys/mapdl/core/post.py | 1 + tests/test_convert.py | 209 ++++++- tests/test_mapdl.py | 9 + 26 files changed, 815 insertions(+), 257 deletions(-) diff --git a/doc/source/user_guide/launcher.rst b/doc/source/user_guide/launcher.rst index d7b2028a79..cfc3c61941 100644 --- a/doc/source/user_guide/launcher.rst +++ b/doc/source/user_guide/launcher.rst @@ -6,7 +6,7 @@ the location of MAPDL must be provided for non-standard installations. When running for the first time, ``ansys-mapdl-core`` requests the location of the MAPDL executable if it cannot automatically find it. You can test your installation of PyMAPDL and set it up by running -the :func:`launch_mapdl() ` function: +the :func:`launch_mapdl() ` function: .. code:: python @@ -81,4 +81,4 @@ keyword argument: API reference ~~~~~~~~~~~~~ For more information on controlling how MAPDL launches locally, see the -description of the :func:`launch_mapdl() ` function. +description of the :func:`launch_mapdl() ` function. diff --git a/src/ansys/mapdl/core/_commands/apdl/parameter_definition.py b/src/ansys/mapdl/core/_commands/apdl/parameter_definition.py index f459e70486..0504307d11 100644 --- a/src/ansys/mapdl/core/_commands/apdl/parameter_definition.py +++ b/src/ansys/mapdl/core/_commands/apdl/parameter_definition.py @@ -518,13 +518,15 @@ def parres(self, lab="", fname="", ext="", **kwargs): >>> mapdl.parres('parm.PARM') """ - if ext: - fname = fname + "." + ext - elif not fname: - fname = "." + "PARM" + if not fname: + fname = self.jobname - if "Grpc" in self.__class__.__name__: # grpc mode - if self._local: + fname = self._get_file_name( + fname=fname, ext=ext, default_extension="parm" + ) # Although documentation says `PARM` + + if self._mode == "grpc": # grpc mode + if self.is_local: # It must be a file! if os.path.isfile(fname): # And it exist! diff --git a/src/ansys/mapdl/core/_commands/aux12_/radiosity_solver.py b/src/ansys/mapdl/core/_commands/aux12_/radiosity_solver.py index 7201c54824..0ac25dfa89 100644 --- a/src/ansys/mapdl/core/_commands/aux12_/radiosity_solver.py +++ b/src/ansys/mapdl/core/_commands/aux12_/radiosity_solver.py @@ -9,8 +9,11 @@ def hemiopt(self, hres="", **kwargs): hres Hemicube resolution. Increase value to increase the accuracy of the view factor calculation. Defaults to 10. + + tolerance + Tolerance value that controls whether or not facets are subdivided in view factor calculations to increase view factor accuracy. TOLERANCE is closely related to the spacing between facets. Defaults to 1e-6. """ - command = f"HEMIOPT,{hres}" + command = f"HEMIOPT,{hres},{tolerance}" return self.run(command, **kwargs) def radopt( diff --git a/src/ansys/mapdl/core/_commands/post1_/special.py b/src/ansys/mapdl/core/_commands/post1_/special.py index 74659aed3b..25e8831ea6 100644 --- a/src/ansys/mapdl/core/_commands/post1_/special.py +++ b/src/ansys/mapdl/core/_commands/post1_/special.py @@ -1748,6 +1748,7 @@ def prcamp( stabval="", keyallfreq="", keynegfreq="", + keywhirl="", **kwargs, ): """Prints Campbell diagram data for applications involving rotating @@ -1768,19 +1769,18 @@ def prcamp( slope The slope of the line to be printed. This value must be positive. - SLOPE > 0 - The line represents the number of excitations per revolution of the rotor. For - example, SLOPE = 1 represents one excitation per - revolution, usually resulting from unbalance. + SLOPE > 0 - The line represents the number of excitations per + revolution of the rotor. For example, SLOPE = 1 represents one + excitation per revolution, usually resulting from unbalance. - SLOPE = 0 - The line represents the stability threshold for stability values or logarithmic - decrements printout (STABVAL = 1 or 2) + SLOPE = 0 - The line represents the stability threshold for stability + values or logarithmic decrements printout (STABVAL = 1 or 2) unit Specifies the unit of measurement for rotational angular velocities: - RDS - Rotational angular velocities in radians per second (rad/s). This value is the - default. + RDS - Rotational angular velocities in radians per second (rad/s). This value is the default. RPM - Rotational angular velocities in revolutions per minute (RPMs). @@ -1794,8 +1794,8 @@ def prcamp( stabval Flag to print the stability values: - 0 (OFF or NO) - Print the frequencies (the imaginary parts of the eigenvalues in Hz). This - value is the default. + 0 (OFF or NO) - Print the frequencies (the imaginary parts of the + eigenvalues in Hz). This value is the default. 1 (ON or YES) - Print the stability values (the real parts of the eigenvalues in Hz). @@ -1804,9 +1804,8 @@ def prcamp( keyallfreq Key to specify if all frequencies above FREQB are printed out: - 0 (OFF or NO) - A maximum of 10 frequencies are printed out. They correspond to the frequencies - displayed via the PLCAMP command. This value is the - default. + 0 (OFF or NO) - A maximum of 10 frequencies are printed out. They + correspond to the frequencies displayed via the PLCAMP command. This value is the default. 1 (ON or YES) - All frequencies are printed out. @@ -1819,6 +1818,12 @@ def prcamp( 1 (ON or YES) - Negative and positive frequencies are printed out. + keywhirl + Flag to print the whirl and instability keys for each load step: + + 0 (OFF or NO) - Print the whirl for the last load step. This value is the default. + 1 (ON or YES) - Print the whirl and instability keys for each load step. + Notes ----- The following items are required when generating a Campbell diagram: diff --git a/src/ansys/mapdl/core/_commands/post26_/special.py b/src/ansys/mapdl/core/_commands/post26_/special.py index 37e75e9d3d..3a899bf393 100644 --- a/src/ansys/mapdl/core/_commands/post26_/special.py +++ b/src/ansys/mapdl/core/_commands/post26_/special.py @@ -330,7 +330,7 @@ def rpsd( See POST26 - Response Power Spectral Density in the Mechanical APDL Theory Reference for more information on these equations. """ - command = f"RPSD,{ir},{ia},{ib},{itype},{datum},{name},{signif}" + command = f"RPSD,{ir},{ia},{ib},{itype},{datum},{name},,{signif}" return self.run(command, **kwargs) def smooth( diff --git a/src/ansys/mapdl/core/_commands/preproc/special_purpose.py b/src/ansys/mapdl/core/_commands/preproc/special_purpose.py index 23c962db2d..7f80d5b4b4 100644 --- a/src/ansys/mapdl/core/_commands/preproc/special_purpose.py +++ b/src/ansys/mapdl/core/_commands/preproc/special_purpose.py @@ -969,7 +969,9 @@ def sstate( command = f"SSTATE,{action},{cm_name},{val1},{val2},{val3},{val4},{val5},{val6},{val7},{val8},{val9}" return self.run(command, **kwargs) - def xfdata(self, enrichmentid="", elemnum="", nodenum="", phi="", **kwargs): + def xfdata( + self, enrichmentid="", lsm="", elemnum="", nodenum="", phi="", psi="", **kwargs + ): """Defines a crack in the model by specifying nodal level set values APDL Command: XFDATA @@ -993,6 +995,10 @@ def xfdata(self, enrichmentid="", elemnum="", nodenum="", phi="", **kwargs): phi Signed normal distance of the node from the crack. + psi + Signed normal distance of the node from the crack tip (or crack front). + Used only in the singularity- based XFEM method. + Notes ----- Issue the XFDATA command multiple times as needed to specify nodal @@ -1000,10 +1006,19 @@ def xfdata(self, enrichmentid="", elemnum="", nodenum="", phi="", **kwargs): This command is valid in PREP7 (/PREP7) only. """ - command = f"XFDATA,{enrichmentid},{elemnum},{nodenum},{phi}" + command = f"XFDATA,{enrichmentid},{lsm},{elemnum},{nodenum},{phi},{psi}" return self.run(command, **kwargs) - def xfenrich(self, enrichmentid="", compname="", matid="", **kwargs): + def xfenrich( + self, + enrichmentid="", + compname="", + matid="", + method="", + radius="", + snaptoler="", + **kwargs, + ): """Defines parameters associated with crack propagation using XFEM APDL Command: XFENRICH @@ -1025,6 +1040,19 @@ def xfenrich(self, enrichmentid="", compname="", matid="", **kwargs): the initial crack. If 0 or not specified, the initial crack is assumed to be free of cohesive zone behavior. + method + PHAN -- Use phantom-node-based XFEM (default). + SING -- Use singularity-based XFEM. + + radius + Radius defining the region around the crack tip encompassing the + set of elements to be influenced by the crack-tip singularity effects. + Default = 0.0. Used only in singularity-based XFEM. + + snaptoler + Snap tolerance to snap the crack tip to the closest crack face along + the extension direction. Default = 1.0E-6. Used only in singularity-based XFEM. + Notes ----- If MatID is specified, the cohesive zone behavior is described by the @@ -1032,7 +1060,7 @@ def xfenrich(self, enrichmentid="", compname="", matid="", **kwargs): This command is valid in PREP7 (/PREP7) only. """ - command = f"XFENRICH,{enrichmentid},{compname},{matid}" + command = f"XFENRICH,{enrichmentid},{compname},{matid}, {method}, {radius}, {snaptoler}" return self.run(command, **kwargs) def xflist(self, enrichmentid="", **kwargs): diff --git a/src/ansys/mapdl/core/_commands/solution/analysis_options.py b/src/ansys/mapdl/core/_commands/solution/analysis_options.py index 585c9b42ea..deed5ba9e5 100644 --- a/src/ansys/mapdl/core/_commands/solution/analysis_options.py +++ b/src/ansys/mapdl/core/_commands/solution/analysis_options.py @@ -1105,25 +1105,27 @@ def cutcontrol(self, lab="", value="", option="", **kwargs): command = f"CUTCONTROL,{lab},{value},{option}" return self.run(command, **kwargs) - def ddoption(self, decomp="", **kwargs): + def ddoption(self, decomp="", nprocpersol="", numsolforlp="", **kwargs): """Sets domain decomposer option for Distributed ANSYS. APDL Command: DDOPTION Parameters ---------- - decomp + Decomp Controls which domain decomposition algorithm to use. - AUTO - Use the default domain decomposition algorithm when splitting the model into - domains for Distributed ANSYS (default). + * AUTO - Automatically selects the optimal domain decomposition method (default). + * MESH - Decompose the FEA mesh. + * FREQ - Decompose the frequency domain for harmonic analyses. + * CYCHI -Decompose the harmonic indices for cyclic symmetry modal analyses. - GREEDY - Use the "greedy" domain decomposition algorithm. + nprocpersol + Number of processes to be used for mesh-based decomposition in conjunction with each frequency solution (`Decomp = FREQ`) or harmonic index solution (`Decomp = CYCHI`). Defaults to 1. This field + is ignored when `Decomp = MESH`. - METIS - Use the METIS graph partitioning domain decomposition algorithm. + numsolforlp + Number of frequency or harmonic index solutions in a subsequent linear perturbation harmonic or linear perturbation cyclic modal analysis. This field is ignored when `Decomp = MESH` Notes ----- @@ -2016,7 +2018,7 @@ def essolv( command = f"ESSOLV,{electit},{strutit},{dimn},{morphopt},{mcomp},{xcomp},{electol},{strutol},{mxloop},,{ruseky},{restky},{eiscomp}" return self.run(command, **kwargs) - def expass(self, key="", **kwargs): + def expass(self, key="", keystat="", **kwargs): """Specifies an expansion pass of an analysis. APDL Command: EXPASS @@ -2025,10 +2027,13 @@ def expass(self, key="", **kwargs): ---------- key Expansion pass key: + * OFF - No expansion pass will be performed (default). + * ON - An expansion pass will be performed. - OFF - No expansion pass will be performed (default). - - ON - An expansion pass will be performed. + keystat + Static correction vectors key: + * ON - Include static correction vectors in the expanded displacements (default). + * OFF - Do not include static correction vectors in the expanded displacements. Notes ----- @@ -2040,7 +2045,7 @@ def expass(self, key="", **kwargs): This command is also valid in PREP7. """ - command = f"EXPASS,{key}" + command = f"EXPASS,{key},,,{keystat}" return self.run(command, **kwargs) def gauge(self, opt="", freq="", **kwargs): diff --git a/src/ansys/mapdl/core/_commands/solution/spectrum_options.py b/src/ansys/mapdl/core/_commands/solution/spectrum_options.py index ff65b77274..55ecbf445b 100644 --- a/src/ansys/mapdl/core/_commands/solution/spectrum_options.py +++ b/src/ansys/mapdl/core/_commands/solution/spectrum_options.py @@ -669,7 +669,7 @@ def psdfrq( command = f"PSDFRQ,{tblno1},{tblno2},{freq1},{freq2},{freq3},{freq4},{freq5},{freq6},{freq7}" return self.run(command, **kwargs) - def psdgraph(self, tblno1="", tblno2="", **kwargs): + def psdgraph(self, tblno1="", tblno2="", displaykey="", **kwargs): """Displays input PSD curves APDL Command: PSDGRAPH @@ -683,6 +683,14 @@ def psdgraph(self, tblno1="", tblno2="", **kwargs): Second PSD table number to display. TBLNO2 is used only in conjunction with the COVAL or the QDVAL commands. + displaykey + Key to display the points markers and numbering: + + 0 - Display points markers and numbering (default). + 1 - Display points numbering only. + 2 - Display points markers only. + 3 - No points markers or numbering. + Notes ----- The input PSD tables are displayed in log-log format as dotted lines. @@ -699,7 +707,7 @@ def psdgraph(self, tblno1="", tblno2="", **kwargs): This command is valid in any processor. """ - command = f"PSDGRAPH,{tblno1},{tblno2}" + command = f"PSDGRAPH,{tblno1},{tblno2},{displaykey}" return self.run(command, **kwargs) def psdres(self, lab="", relkey="", **kwargs): diff --git a/src/ansys/mapdl/core/convert.py b/src/ansys/mapdl/core/convert.py index 0c8530a468..1385256e41 100644 --- a/src/ansys/mapdl/core/convert.py +++ b/src/ansys/mapdl/core/convert.py @@ -15,58 +15,97 @@ "max-line-length": 100, } +LOGLEVEL_DEFAULT = "WARNING" +AUTO_EXIT_DEFAULT = True +LINE_ENDING_DEFAULT = None +EXEC_FILE_DEFAULT = None +MACROS_AS_FUNCTIONS_DEFAULT = True +USE_FUNCTION_NAMES_DEFAULT = True +SHOW_LOG_DEFAULT = False +ADD_IMPORTS_DEFAULT = True +COMMENT_SOLVE_DEFAULT = False +CLEANUP_OUTPUT_DEFAULT = True +HEADER_DEFAULT = True +PRINT_COM_DEFAULT = True +ONLY_COMMANDS_DEFAULT = False +USE_VTK_DEFAULT = None +CLEAR_AT_START_DEFAULT = False +CHECK_PARAMETER_NAMES_DEFAULT = True + + # This commands have "--" as one or some arguments -COMMANDS_WITH_EMPTY_ARGS = [ - "/CMA", # "/CMAP, - "/NER", # "/NERR, - "/PBF", # "/PBF, - "/PMO", # "/PMORE, - "ANTY", # ANTYPE, - "ASBL", # ASBL, - "ATAN", # ATAN, - "BCSO", # BCSOPTION, - "CLOG", # CLOG, - "CONJ", # CONJUG, - "DERI", # DERIV, - "DSPO", # DSPOPTION, - "ENER", # ENERSOL, - "ENSY", # ENSYM, - "ESYM", # ESYM, - "EXP", # EXP, - "EXPA", # EXPAND, - "FCLI", # FCLIST, - "FILE", # FILEAUX2, - "FLUR", # FLUREAD, - "GMAT", # GMATRIX, - "IMAG", # IMAGIN, - "INT1", # INT1, - "LARG", # LARGE, - "LATT", # LATT, - "MAP", # MAP, - "MORP", # MORPH, - "MPCO", # MPCOPY, - "NLOG", # NLOG, - "PLMA", # PLMAP, - "PRED", # PRED, - "PROD", # PROD, - "QRDO", # QRDOPT, - "QUOT", # QUOT, - "RACE", # RACE, - "REAL", # REALVAR, - "REME", # REMESH, - "SESY", # SESYMM, - "SETF", # SETFGAP, - "SETR", # SETRAN, - "SMAL", # SMALL, - "SNOP", # SNOPTION, - "SURE", # SURESU, - "THOP", # THOPT, - "TINT", # TINTP, -] +COMMANDS_WITH_EMPTY_ARGS = { + "/CMA": (), # "/CMAP, + "/NER": (), # "/NERR, + "/PBF": (), # "/PBF, + "/PMO": (), # "/PMORE, + "ADD": (), # "ADD" + "ANTY": (), # ANTYPE, + "ASBL": (), # ASBL, + "ATAN": (), # ATAN, + "BCSO": (), # BCSOPTION, + "CORI": (), # CORIOLIS + "CDRE": (), # CDREAD + "CLOG": (), # CLOG, + "CONJ": (), # CONJUG, + "DERI": (), # DERIV, + "DSPO": (), # DSPOPTION, + "ENER": (), # ENERSOL, + "ENSY": (), # ENSYM, + "ESYM": (), # ESYM, + "EXP": (), # EXP, + "EXPA": (), # EXPAND, + "FCLI": (), # FCLIST, + "FILE": (), # FILEAUX2, + "FLUR": (), # FLUREAD, + "GMAT": (), # GMATRIX, + "IMAG": (), # IMAGIN, + "INT1": (), # INT1, + "LARG": (), # LARGE, + "LATT": (), # LATT, + "MAP": (), # MAP, + "MORP": (), # MORPH, + "MPCO": (), # MPCOPY, + "NLOG": (), # NLOG, + "PLMA": (), # PLMAP, + "PRED": (), # PRED, + "PROD": (), # PROD, + "QRDO": (), # QRDOPT, + "QUOT": (), # QUOT, + "RACE": (), # RACE, + "RDEC": (), # RDEC + "REAL": (), # REALVAR, + "REME": (), # REMESH, + "RPSD": (), # RPSD + "SECR": (), # SECREAD + "SECW": (), # SECWRITE + "SESY": (), # SESYMM, + "SETF": (), # SETFGAP, + "SETR": (), # SETRAN, + "SMAL": (), # SMALL, + "SNOP": (), # SNOPTION, + "SQRT": (), # SQRT + "SURE": (), # SURESU, + "THOP": (), # THOPT, + "TINT": (), # TINTP, + "XFDA": (), # XFDATA +} -COMMANDS_TO_NOT_BE_CONVERTED = [] -COMMANDS_TO_NOT_BE_CONVERTED.extend(COMMANDS_WITH_EMPTY_ARGS) +COMMANDS_TO_NOT_BE_CONVERTED = [ + "CMPL", # CMPLOT default behaviour does not match the `mapdl.cmplot`'s at the moemnt + "MODE", # Until we merge #2431 + "/LIN", # Until we merge 2432 + "/LAR", # Until we merge 2432 + "/TYP", # Until we merge 2432 + "/DSC", # Until we merge 2432 + # CDREAD # commented above +] + +FORCED_MAPPING = { + # Forced mapping between MAPDL and PyMAPDL + "SECT": "sectype", # Because it is shadowed by `sectinqr` +} def convert_script( @@ -85,6 +124,9 @@ def convert_script( header=True, print_com=True, only_commands=False, + use_vtk=None, + clear_at_start=False, + check_parameter_names=True, ): """Converts an ANSYS input file to a python PyMAPDL script. @@ -156,6 +198,13 @@ def convert_script( and exit commands are NOT included (``auto_exit=False``). Overrides ``header``, ``add_imports`` and ``auto_exit``. + use_vtk : bool, optional + It sets the `mapdl.use_vtk` argument equals True or False depending on + this value. + + clear_at_start : bool, optional + Add a `mapdl.clear()` after the Mapdl object initialization. + Returns ------- list @@ -211,6 +260,9 @@ def convert_script( header=header, print_com=print_com, only_commands=only_commands, + use_vtk=use_vtk, + clear_at_start=clear_at_start, + check_parameter_names=check_parameter_names, ) translator.save(filename_out) @@ -232,6 +284,9 @@ def convert_apdl_block( header=True, print_com=True, only_commands=False, + use_vtk=None, + clear_at_start=False, + check_parameter_names=False, ): """Converts an ANSYS input string to a python PyMAPDL string. @@ -299,6 +354,17 @@ def convert_apdl_block( and exit commands are NOT included (``auto_exit=False``). Overrides ``header``, ``add_imports`` and ``auto_exit``. + use_vtk : bool, optional + It sets the `mapdl.use_vtk` argument equals True or False depending on + this value. Defaults to `None` which is Mapdl class default. + + clear_at_start : bool, optional + Add a `mapdl.clear()` after the Mapdl object initialization. Defaults to + `False`. + + check_parameter_names : bool, optional + Set MAPDL object to avoid parameter name checks (do not raise leading underscored parameter exceptions). Defaults to `False`. + Returns ------- list @@ -335,6 +401,9 @@ def convert_apdl_block( header=header, print_com=print_com, only_commands=only_commands, + use_vtk=use_vtk, + clear_at_start=clear_at_start, + check_parameter_names=check_parameter_names, ) if isinstance(apdl_strings, str): @@ -357,6 +426,9 @@ def _convert( header=True, print_com=True, only_commands=False, + use_vtk=None, + clear_at_start=False, + check_parameter_names=True, ): if only_commands: auto_exit = False @@ -375,6 +447,9 @@ def _convert( cleanup_output=cleanup_output, header=header, print_com=print_com, + use_vtk=use_vtk, + clear_at_start=clear_at_start, + check_parameter_names=check_parameter_names, ) if isinstance(apdl_strings, str): @@ -437,6 +512,9 @@ def __init__( cleanup_output=True, header=True, print_com=True, + use_vtk=None, + clear_at_start=False, + check_parameter_names=False, ): self._non_interactive_level = 0 self.lines = Lines(mute=not show_log) @@ -454,12 +532,17 @@ def __init__( self.cleanup_output = cleanup_output self._header = header self.print_com = print_com + self.verification_example = False + self.use_vtk = use_vtk + self.clear_at_start = clear_at_start + self.check_parameter_names = check_parameter_names + self.macros_names = [] self.write_header() if self._add_imports: self.initialize_mapdl_object(loglevel, exec_file) - self._valid_commands = dir(Commands) + self._valid_commands = self._get_valid_pymapdl_methods_short() self._block_commands = { "NBLO": "NBLOCK", "EBLO": "EBLOCK", @@ -474,7 +557,6 @@ def __init__( } # Commands where you need to count the number of lines. _NON_INTERACTIVE_COMMANDS = { - "*CRE": "*CREATE", "*VWR": "*VWRITE", "*VRE": "*VREAD", } @@ -553,17 +635,26 @@ def initialize_mapdl_object(self, loglevel, exec_file): core_module = "ansys.mapdl.core" # shouldn't change self.lines.append(f"from {core_module} import launch_mapdl") + mapdl_arguments = [f'loglevel="{loglevel}"'] + if exec_file: - exec_file_parameter = f'exec_file="{exec_file}", ' - else: - exec_file_parameter = "" + mapdl_arguments.append(f'exec_file="{exec_file}"') if self.print_com: - line = f'{self.obj_name} = launch_mapdl({exec_file_parameter}loglevel="{loglevel}", print_com=True)\n' - else: - line = f'{self.obj_name} = launch_mapdl({exec_file_parameter}loglevel="{loglevel}")\n' + mapdl_arguments.append("print_com=True") + + if self.use_vtk is not None: + mapdl_arguments.append(f"use_vtk={bool(self.use_vtk)}") + + if self.check_parameter_names is not None and not self.check_parameter_names: + mapdl_arguments.append("check_parameter_names=False") + + line = f'{self.obj_name} = launch_mapdl({", ".join(mapdl_arguments)})' self.lines.append(line) + if self.clear_at_start: + self.lines.append(f"{self.obj_name}.clear() # Clearing session") + @property def line_ending(self): return self._line_ending @@ -611,6 +702,8 @@ def translate_line(self, line): self.comment = self.comment.lstrip() if not line: + # Keeping empty lines + self.lines.append("") return # Cleaning ending empty arguments. @@ -623,6 +716,8 @@ def translate_line(self, line): line = ",".join(line_[ind:][::-1]) + line_with_trailing_commas = line + # remove trailing comma line = line[:-1] if line[-1] == "," else line line_upper = line.upper() @@ -630,7 +725,7 @@ def translate_line(self, line): cmd_caps = line.split(",")[0].upper() cmd_caps_short = cmd_caps[:4] - items = line.split(",") + items = self._get_items(line.strip()) if cmd_caps_short in ["SOLV", "LSSO"] and self._comment_solve: self.store_command( @@ -640,11 +735,19 @@ def translate_line(self, line): self.store_command("com", [line]) return + if cmd_caps_short == "/VER": + self.verification_example = True + if cmd_caps_short == "/COM": # It is a comment self.store_command("com", [line[5:]]) return + if cmd_caps_short == "C***": + # It is an old style comment + self.store_command("com", [line[5:]]) + return + if cmd_caps == "*DO": self.start_non_interactive() self.store_run_command(line) @@ -655,9 +758,16 @@ def translate_line(self, line): self.end_non_interactive() return + if "/EXI" in cmd_caps.upper() and self.non_interactive: + self.store_command("com", [f"Skipping: {line}"]) + return + if self.output_to_file(line): - self.start_non_interactive() - self.store_run_command(line) + if self.verification_example and "SCRATCH" in line.upper(): + self.store_command("com", [f"Skipping: {line}"]) + else: + self.start_non_interactive() + self.store_run_command(line) return if self.output_to_default(line): @@ -669,7 +779,6 @@ def translate_line(self, line): if cmd_caps == "/VERIFY": self.store_run_command("FINISH") self.store_run_command(line) - self.store_run_command("/PREP7") return if cmd_caps_short == "*REP": @@ -677,7 +786,7 @@ def translate_line(self, line): prev_cmd = self.lines.pop(-1) self.start_non_interactive() new_prev_cmd = ( - " " + prev_cmd + self.indent + prev_cmd ) # Since we are writing in self.lines we need to add the indentation by ourselves. self.lines.append(new_prev_cmd) self.store_run_command( @@ -686,13 +795,27 @@ def translate_line(self, line): self.end_non_interactive() return + # Skipping conversion if command has empty arguments and there is ",," in the call + if ( + cmd_caps_short in COMMANDS_WITH_EMPTY_ARGS + and ",," in line_with_trailing_commas.replace(" ", "") + ): + self.store_run_command(line.strip()) + return + + # Skipping commands to not be converted if cmd_caps_short in COMMANDS_TO_NOT_BE_CONVERTED: - self.store_run_command(line) + self.store_run_command(line.strip()) return if cmd_caps_short == "/TIT": # /TITLE parameters = line.split(",")[1:] - return self.store_command("title", ["".join(parameters).strip()]) + return self.store_command("title", [",".join(parameters).strip()]) + + if cmd_caps_short == "/AXL": # /AXLAB + parameters = line.split(",")[1:] + parameters_ = [parameters[0], ",".join(parameters[1:])] + return self.store_command("axlab", parameters_) if cmd_caps_short == "*GET": if self.non_interactive: # gives error @@ -710,12 +833,29 @@ def translate_line(self, line): return if cmd_caps_short == "*CRE": # creating a function + self.macros_names.append(items[1]) if self.macros_as_functions: self.start_function(items[1].strip()) return else: self.start_non_interactive() + ## Treating functions + if items[0] in self.macros_names and self.macros_as_functions: + # We are calling the function/macro created before. + func_name = items[0].strip() + + args = self._parse_arguments(items[1:]) + self.store_python_command(f"{func_name}({args})") + return + + if cmd_caps_short == "*USE" and self.macros_as_functions: + func_name = items[1].strip() + if func_name in self._functions: + args = self._parse_arguments(items[2:]) + self.store_python_command(f"{func_name}({args})") + return + if cmd_caps == "/PREP7": return self.store_command("prep7", []) @@ -749,17 +889,7 @@ def translate_line(self, line): + "The previous line is: \n%s\n\n" % self.lines[-1] ) self.store_run_command(line) - if ( - not self._in_block - ): # To escape cmds that require (XX) but they are not in block - self.end_non_interactive() return - elif cmd_caps_short == "*USE" and self.macros_as_functions: - func_name = items[1].strip() - if func_name in self._functions: - args = ", ".join(items[2:]) - self.lines.append(f"{func_name}({args})") - return # check if a line is setting a variable if "=" in items[0]: # line sets a variable: @@ -781,52 +911,65 @@ def translate_line(self, line): # check valid command if ( self._pymapdl_command(command) not in self._valid_commands - or cmd_caps_short in self._non_interactive_commands + and cmd_caps_short in self._non_interactive_commands ): - if cmd_caps_short in self._non_interactive_commands: - if cmd_caps_short in self._block_commands: - self._in_block = True - self._block_count = 0 - self._block_count_target = 0 - - elif cmd_caps_short in self._enum_block_commands: - self._in_block = True - self._block_count = 0 - if cmd_caps_short == "CMBL": # In cmblock - # CMBLOCK,Cname,Entity,NUMITEMS,,,,,KOPT - numitems = int(line.split(",")[3]) - _block_count_target = ( - numitems // 8 + 1 if numitems % 8 != 0 else numitems // 8 - ) - self._block_count_target = ( - _block_count_target + 2 - ) # because the cmd_caps_short line and option line. - - self._block_current_cmd = cmd_caps_short - self.start_non_interactive() + if cmd_caps_short in self._block_commands: + self._in_block = True + self._block_count = 0 + self._block_count_target = 0 + + elif cmd_caps_short in self._enum_block_commands: + self._in_block = True + self._block_count = 0 + if cmd_caps_short == "CMBL": # In cmblock + # CMBLOCK,Cname,Entity,NUMITEMS,,,,,KOPT + numitems = int(line.split(",")[3]) + _block_count_target = ( + numitems // 8 + 1 if numitems % 8 != 0 else numitems // 8 + ) + self._block_count_target = ( + _block_count_target + 2 + ) # because the cmd_caps_short line and option line. + + self._block_current_cmd = cmd_caps_short + self.start_non_interactive() + self.store_run_command(line.strip()) + + elif self.use_function_names: + # Takign into account the leading characters + if command.upper() in FORCED_MAPPING: + # Checking exceptions/forced mapping + command = FORCED_MAPPING[command.upper()] - if self._in_block and cmd_caps_short not in self._non_interactive_commands: - self.store_run_command(original_line) else: - self.store_run_command(line) + # Looking for a suitable candidate. + if command[0] == "/": + slash_command = f"slash{command[1:4]}" + if slash_command in self._valid_commands: + command = slash_command + else: + command = command[1:] + elif command[0] == "*": + star_command = f"star{command[1:4]}" + if star_command in self._valid_commands: + command = star_command + else: + command = command[1:] + + # Some commands are abbreviated (only 4 letters) + from ansys.mapdl.core import Mapdl + + if command not in dir(Mapdl): + command = self.find_match(command) + + # Storing + if command: + self.store_command(command, parameters) + else: # find_match can return None + self.store_run_command(line.strip()) - elif self.use_function_names: - if command[0] == "/": - slash_command = f"slash{command[1:]}" - if slash_command in dir(Commands): - command = slash_command - else: - command = command[1:] - elif command[0] == "*": - star_command = f"star{command[1:]}" - if star_command in dir(Commands): - command = star_command - else: - command = command[1:] - - self.store_command(command, parameters) else: - self.store_run_command(line) + self.store_run_command(line.strip()) def _pymapdl_command(self, command): if command[0] in ["/", "*"]: @@ -839,14 +982,16 @@ def start_function(self, func_name): self.store_empty_line() self._infunction = True spacing = " " * (len(func_name) + 5) - line = "def %s(%s," % ( + line = self.indent + "def %s(%s," % ( func_name, ", ".join(["ARG%d=''" % i for i in range(1, 7)]), ) + line += "\n" line += "%s%s," % ( spacing, ", ".join(["ARG%d=''" % i for i in range(7, 13)]), ) + line += "\n" line += "%s%s):" % ( spacing, ", ".join(["ARG%d=''" % i for i in range(13, 19)]), @@ -866,22 +1011,24 @@ def store_run_command(self, command, run_underscored=False): else: underscore = "" + # Removing trailing/leading spaces + command = command.strip() + if self._infunction and "ARG" in command: args = [] for i in range(1, 19): arg = "ARG%d" % i c = 0 if arg in command: - command = command.replace(arg, "{%d:s}" % c) + command = command.replace(arg, "{" + f"{arg}" + "}") args.append(arg) c += 1 - line = '%s%s.%srun("%s".format(%s))' % ( + line = '%s%s.%srun(f"%s")' % ( self.indent, self.obj_name, underscore, command, - ", ".join(args), ) elif self.comment: @@ -910,12 +1057,15 @@ def store_empty_line(self): """Stores an empty line""" self.lines.append("") - def store_command(self, function, parameters): - """Stores a valid pyansys function with parameters""" + def store_python_command(self, command): + line = f"{self.indent}{command}" + self.lines.append(line) + + def _parse_arguments(self, parameters): parsed_parameters = [] for parameter in parameters: parameter = parameter.strip() - if is_float(parameter): + if is_float(parameter) and parameter.upper() != "INF": parsed_parameters.append(parameter) elif "ARG" in parameter and self._infunction: parsed_parameters.append("%s" % parameter) @@ -927,7 +1077,12 @@ def store_command(self, function, parameters): parameter = parameter[1:-1] parsed_parameters.append(f'"{parameter}"') - parameter_str = ", ".join(parsed_parameters) + return ", ".join(parsed_parameters) + + def store_command(self, function, parameters): + """Stores a valid pyansys function with parameters""" + parameter_str = self._parse_arguments(parameters) + if self.comment: line = "%s%s.%s(%s) # %s" % ( self.indent, @@ -957,9 +1112,9 @@ def start_non_interactive(self): def end_non_interactive(self): self._non_interactive_level -= 1 - if self._non_interactive_level == 0: - self.non_interactive = False + if self._non_interactive_level <= 0: self.indent = self.indent[4:] + self.non_interactive = False def output_to_file(self, line): """Return if an APDL line is redirecting to a file.""" @@ -1001,6 +1156,52 @@ def output_to_default(self, line): return False + def _get_items(self, line_): + """Parse the line items (comma separated elements) but ignoring the ones inside parenthesis, or brackets""" + + parenthesis_count = 0 + + items = [] + begining_substring = 0 + + for ind, each_char in enumerate(line_): + if each_char in ["(", "[", "{"]: + parenthesis_count += 1 + + if each_char == "," and parenthesis_count == 0: + items.append(line_[begining_substring:ind]) + begining_substring = ind + 1 + + if ind == len(line_) - 1: # reaching ending of line + items.append(line_[begining_substring : ind + 1]) + + if each_char in [")", "]", "}"]: + parenthesis_count -= 1 + + return items + + def _get_valid_pymapdl_methods_short(self): + pymethods = dir(Commands) + + reduced_list = [] + for each_method in pymethods: + if not re.match(r"^[\*~/A-Za-z]\w*$", each_method): + continue + if each_method.startswith("slash"): + reduced_list.append(each_method[:8]) + elif each_method.startswith("star"): + reduced_list.append(each_method[:7]) + else: + reduced_list.append(each_method[:4]) + return reduced_list + + def find_match(self, cmd): + pymethods = sorted(dir(Commands)) + + for each in pymethods: + if each.startswith(cmd): + return each + import click @@ -1011,60 +1212,89 @@ def output_to_default(self, line): @click.option("--filename_out", default=None, help="Name of the output Python script.") @click.option( "--loglevel", - default="WARNING", + default=LOGLEVEL_DEFAULT, help="Logging level of the ansys object within the script.", ) @click.option( "--auto_exit", - default=True, + default=AUTO_EXIT_DEFAULT, help="Adds a line to the end of the script to exit MAPDL. Default ``True``", ) -@click.option("--line_ending", default=None, help="When None, automatically is ``\n.``") +@click.option( + "--line_ending", + default=LINE_ENDING_DEFAULT, + help="When None, automatically is ``\n.``", +) @click.option( "--exec_file", - default=None, + default=EXEC_FILE_DEFAULT, help="Specify the location of the ANSYS executable and include it in the converter output ``launch_mapdl`` call.", ) @click.option( "--macros_as_functions", - default=True, + default=MACROS_AS_FUNCTIONS_DEFAULT, help="Attempt to convert MAPDL macros to python functions.", ) @click.option( "--use_function_names", - default=True, + default=USE_FUNCTION_NAMES_DEFAULT, help="Convert MAPDL functions to ansys.mapdl.core.Mapdl class methods. When ``True``, the MAPDL command ``K`` will be converted to ``mapdl.k``. When ``False``, it will be converted to ``mapdl.run('k')``.", ) @click.option( "--show_log", - default=False, + default=SHOW_LOG_DEFAULT, help="Print the converted commands using a logger (from ``logging`` Python module).", ) @click.option( "--add_imports", - default=True, + default=ADD_IMPORTS_DEFAULT, help='If ``True``, add the lines ``from ansys.mapdl.core import launch_mapdl`` and ``mapdl = launch_mapdl(loglevel="WARNING")`` to the beginning of the output file. This option is useful if you are planning to use the output script from another mapdl session. See examples section. This option overrides ``auto_exit``.', ) @click.option( "--comment_solve", - default=False, + default=COMMENT_SOLVE_DEFAULT, help='If ``True``, it will pythonically comment the lines that contain ``"SOLVE"`` or ``"/EOF"``.', ) @click.option( "--cleanup_output", - default=True, + default=CLEANUP_OUTPUT_DEFAULT, help="If ``True`` the output is formatted using ``autopep8`` before writing the file or returning the string. This requires ``autopep8`` to be installed.", ) @click.option( "--header", - default=True, + default=HEADER_DEFAULT, help="If ``True``, the default header is written in the first line of the output. If a string is provided, this string will be used as header.", ) @click.option( "--print_com", - default=True, + default=PRINT_COM_DEFAULT, help="Print command ``/COM`` arguments to python console. Defaults to ``True``.", ) +@click.option( + "--only_commands", + default=ONLY_COMMANDS_DEFAULT, + help="""converts only the commands, meaning that header + (``header=False``), imports (``add_imports=False``), + and exit commands are NOT included (``auto_exit=False``). + Overrides ``header``, ``add_imports`` and ``auto_exit``.""", +) +@click.option( + "--use_vtk", + default=USE_VTK_DEFAULT, + help="""It sets the `mapdl.use_vtk` argument equals True or False depending on + this value.""", +) +@click.option( + "--clear_at_start", + default=CLEAR_AT_START_DEFAULT, + help="""Add a `mapdl.clear()` after the Mapdl object initialization. Defaults to + `False`.""", +) +@click.option( + "--check_parameter_names", + default=CHECK_PARAMETER_NAMES_DEFAULT, + help="""Set MAPDL object to avoid parameter name checks (do not raise leading underscored parameter exceptions). Defaults to `True`.""", +) def cli( filename_in, o, @@ -1081,6 +1311,10 @@ def cli( cleanup_output, header, print_com, + only_commands, + use_vtk, + clear_at_start, + check_parameter_names, ): """PyMAPDL CLI tool for converting MAPDL scripts to PyMAPDL scripts. @@ -1113,6 +1347,30 @@ def cli( if o: filename_out = o + # Parsing commands: + loglevel = _parse_cli_command(loglevel, LOGLEVEL_DEFAULT) + auto_exit = _parse_cli_command(auto_exit, AUTO_EXIT_DEFAULT) + line_ending = _parse_cli_command(line_ending, LINE_ENDING_DEFAULT) + exec_file = _parse_cli_command(exec_file, EXEC_FILE_DEFAULT) + macros_as_functions = _parse_cli_command( + macros_as_functions, MACROS_AS_FUNCTIONS_DEFAULT + ) + use_function_names = _parse_cli_command( + use_function_names, USE_FUNCTION_NAMES_DEFAULT + ) + show_log = _parse_cli_command(show_log, SHOW_LOG_DEFAULT) + add_imports = _parse_cli_command(add_imports, ADD_IMPORTS_DEFAULT) + comment_solve = _parse_cli_command(comment_solve, COMMENT_SOLVE_DEFAULT) + cleanup_output = _parse_cli_command(cleanup_output, CLEANUP_OUTPUT_DEFAULT) + header = _parse_cli_command(header, HEADER_DEFAULT) + print_com = _parse_cli_command(print_com, PRINT_COM_DEFAULT) + only_commands = _parse_cli_command(only_commands, ONLY_COMMANDS_DEFAULT) + use_vtk = _parse_cli_command(use_vtk, USE_VTK_DEFAULT) + clear_at_start = _parse_cli_command(clear_at_start, CLEAR_AT_START_DEFAULT) + check_parameter_names = _parse_cli_command( + check_parameter_names, CHECK_PARAMETER_NAMES_DEFAULT + ) + convert_script( filename_in, filename_out, @@ -1128,6 +1386,10 @@ def cli( cleanup_output, header, print_com, + only_commands, + use_vtk, + clear_at_start, + check_parameter_names, ) if filename_out: @@ -1136,3 +1398,17 @@ def cli( print( f"File {filename_in} successfully converted to {os.path.splitext(filename_in)[0] + '.py'}." ) + + +def _parse_cli_command(command, default=None): + if isinstance(command, bool): + return command + if command is None: + return + + if command.upper() == "TRUE": + return True + elif command.upper() == "FALSE": + return False + else: + return default diff --git a/src/ansys/mapdl/core/examples/verif/vm132.dat b/src/ansys/mapdl/core/examples/verif/vm132.dat index 85cc37dbcb..98c7483d6c 100755 --- a/src/ansys/mapdl/core/examples/verif/vm132.dat +++ b/src/ansys/mapdl/core/examples/verif/vm132.dat @@ -22,7 +22,7 @@ D,ALL,ALL ! FIX ALL DOFS FINISH /SOLU NSUBST,100,100,100 -RATE,ON,ON +RATE,ON OUTPR,BASIC,10 ! PRINT BASIC SOLUTION FOR EVERY 10TH SUBSTEP OUTRES,ESOL,1 ! STORE ELEMENT SOLUTION FOR EVERY SUBSTEP /OUT,SCRATCH diff --git a/src/ansys/mapdl/core/examples/verif/vm139.dat b/src/ansys/mapdl/core/examples/verif/vm139.dat index 863ef1c87c..cf126a7f0b 100755 --- a/src/ansys/mapdl/core/examples/verif/vm139.dat +++ b/src/ansys/mapdl/core/examples/verif/vm139.dat @@ -25,7 +25,7 @@ D,1,UX,,,,,UY,UZ D,11,UX,,,,,UZ D,ALL,ROTZ NSEL,S,LOC,X,22.5 -DSYM,SYMM,X,0,22.5 ! SYMMETRY B.C.'S AT CENTERLINE +DSYM,SYMM,X,0 ! SYMMETRY B.C.'S AT CENTERLINE NSEL,ALL FINISH /SOLU @@ -100,7 +100,7 @@ NSEL,R,LOC,Y,0 D,ALL,UY ALLSEL,ALL NSEL,S,LOC,X,22.5 -DSYM,SYMM,X,0,22.5 ! SYMMETRY B.C.'S AT CENTERLINE +DSYM,SYMM,X,0 ! SYMMETRY B.C.'S AT CENTERLINE NSEL,ALL FINISH /SOLU diff --git a/src/ansys/mapdl/core/examples/verif/vm147.dat b/src/ansys/mapdl/core/examples/verif/vm147.dat index 0b34f0f978..29676c2de1 100755 --- a/src/ansys/mapdl/core/examples/verif/vm147.dat +++ b/src/ansys/mapdl/core/examples/verif/vm147.dat @@ -26,7 +26,7 @@ VTYPE,1 ! NON-HIDDEN (FAST) METHOD GEOM,1,50 ! 2-D AXISYMMETRIC GEOM WITH 50 FACETS MPRINT,1 STEF,5.6696E-8 ! STEFAN-BOLTZMANN CONSTANT IN MKS UNITS -WRITE,CONE,SUB ! WRITE RADIATION SUBSTRUCTURE MATRIX +WRITE,CONE ! WRITE RADIATION SUBSTRUCTURE MATRIX FINISH /CLEAR,NOSTART ! CLEAR DATABASE; DO NOT READ START.ANS FILE /PREP7 diff --git a/src/ansys/mapdl/core/examples/verif/vm221.dat b/src/ansys/mapdl/core/examples/verif/vm221.dat index 523bbcbb5e..07f4b5ac29 100755 --- a/src/ansys/mapdl/core/examples/verif/vm221.dat +++ b/src/ansys/mapdl/core/examples/verif/vm221.dat @@ -24,7 +24,7 @@ C6=70E3 !MPA, [MARTENSITE MODULUS] C7=0 !M = 0, SYMMETRICAL BEHAVIOR TB,SMA,1,,7,MEFF -TBDATA,1,C1,C2,C3,C4,C5,C6,C7 +TBDATA,1,C1,C2,C3,C4,C5,C6 BLOCK,0.00,5.00,0.00,5.00,0.00,5.00 ESIZE,5 diff --git a/src/ansys/mapdl/core/examples/verif/vm227.dat b/src/ansys/mapdl/core/examples/verif/vm227.dat index eacfe91d18..7f8fec704c 100755 --- a/src/ansys/mapdl/core/examples/verif/vm227.dat +++ b/src/ansys/mapdl/core/examples/verif/vm227.dat @@ -28,7 +28,7 @@ SFL,8,RDSF,1, ,1, FINISH /AUX12 STEF,0.119E-10 !SET STEFAN-BOLTZMAN CONSTANT FOR MODEL -hemiopt,,,,,,,,,,,,,,,,,,,0 +hemiopt TOFFST,100 !SET TEMPERATURE OFFSET RADOPT,,0.1,2,1000,0.1,0.1 !SET RADIOSITY OPTIONS SPCTEMP,1,0.E+00 !SET TEMPERATURE FOR RADIATION TO SPACE diff --git a/src/ansys/mapdl/core/examples/verif/vm273.dat b/src/ansys/mapdl/core/examples/verif/vm273.dat index a4f5ed1dcf..f0145eed29 100755 --- a/src/ansys/mapdl/core/examples/verif/vm273.dat +++ b/src/ansys/mapdl/core/examples/verif/vm273.dat @@ -27,7 +27,7 @@ C6=70E3 !MPA, [MARTENSITE MODULUS] C7=0 ! M = 0, SYMMETRICAL BEHAVIOR TB,SMA,1,,7,MEFF -TBDATA,1,C1,C2,C3,C4,C5,C6,C7 +TBDATA,1,C1,C2,C3,C4,C5,C6 BLOCK,0.00,10.00,0.00,10.00,0.00,10.00 ESIZE,10 diff --git a/src/ansys/mapdl/core/examples/verif/vm285.dat b/src/ansys/mapdl/core/examples/verif/vm285.dat index 8c06bd0da1..c33f584b02 100644 --- a/src/ansys/mapdl/core/examples/verif/vm285.dat +++ b/src/ansys/mapdl/core/examples/verif/vm285.dat @@ -46,7 +46,7 @@ A,1,2,3,4,7 A,7,4,5,6 AGLUE,ALL -KSCON,2,A/20,0,12,,10 ! CRACK TIP ELEMENTS +KSCON,2,A/20,0,12,, ! CRACK TIP ELEMENTS ESIZE,0.3 AMESH,1 diff --git a/src/ansys/mapdl/core/examples/verif/vm287.dat b/src/ansys/mapdl/core/examples/verif/vm287.dat index 8fec708652..a3aec45a2d 100644 --- a/src/ansys/mapdl/core/examples/verif/vm287.dat +++ b/src/ansys/mapdl/core/examples/verif/vm287.dat @@ -70,7 +70,7 @@ ALLSEL XFENRICH,ENRICH1,TESTCMP,1 FLST,3,2,8 FITEM,3,0.0,5.0,0 -FITEM,3,5.0,5.0,0,0 +FITEM,3,5.0,5.0,0 XFDATA,ENRICH1,P51X ALLSEL /OUT diff --git a/src/ansys/mapdl/core/examples/verif/vm309.dat b/src/ansys/mapdl/core/examples/verif/vm309.dat index 0eae3c8044..ae5776c976 100644 --- a/src/ansys/mapdl/core/examples/verif/vm309.dat +++ b/src/ansys/mapdl/core/examples/verif/vm309.dat @@ -95,7 +95,7 @@ FINISH OUTRES,ALL,ALL ANTYPE,1 BUCOPT,LANB,3 -SUBOPT,0,0,0,0,0,ALL +SUBOPT,0,0 MXPAND,3,,,YES SOLVE FINISH diff --git a/src/ansys/mapdl/core/examples/verif/vm51.dat b/src/ansys/mapdl/core/examples/verif/vm51.dat index cc02967b5e..69cbeafcaa 100755 --- a/src/ansys/mapdl/core/examples/verif/vm51.dat +++ b/src/ansys/mapdl/core/examples/verif/vm51.dat @@ -1,5 +1,4 @@ /COM,ANSYS MEDIA REL. 2023R2 (05/12/2023) REF. VERIF. MANUAL: REL. 2023R2 -/OUT,SCRATCH /VERIFY,VM51 JPGPRF,500,100,1 ! MACRO TO SET PREFS FOR JPEG PLOTS /SHOW,JPEG diff --git a/src/ansys/mapdl/core/launcher.py b/src/ansys/mapdl/core/launcher.py index a11834df37..d68872e387 100644 --- a/src/ansys/mapdl/core/launcher.py +++ b/src/ansys/mapdl/core/launcher.py @@ -32,6 +32,7 @@ VersionError, ) from ansys.mapdl.core.licensing import ALLOWABLE_LICENSES, LicenseChecker +from ansys.mapdl.core.mapdl import _ALLOWED_START_PARM from ansys.mapdl.core.mapdl_grpc import MAX_MESSAGE_LENGTH, MapdlGrpc from ansys.mapdl.core.misc import ( check_valid_ip, @@ -1355,6 +1356,15 @@ def launch_mapdl( # Extract arguments: force_intel = kwargs.pop("force_intel", False) broadcast = kwargs.pop("log_broadcast", False) + use_vtk = kwargs.pop("use_vtk", None) + + # Transferring MAPDL arguments to start_parameters: + start_parm = {} + + kwargs_keys = list(kwargs.keys()) + for each_par in kwargs_keys: + if each_par in _ALLOWED_START_PARM: + start_parm[each_par] = kwargs.pop(each_par) # Raising error if using non-allowed arguments if kwargs: @@ -1449,6 +1459,7 @@ def launch_mapdl( cleanup_on_exit=False, loglevel=loglevel, set_no_abort=set_no_abort, + **start_parm, ) GALLERY_INSTANCE[0] = {"ip": mapdl._ip, "port": mapdl._port} return mapdl @@ -1461,6 +1472,8 @@ def launch_mapdl( cleanup_on_exit=False, loglevel=loglevel, set_no_abort=set_no_abort, + use_vtk=use_vtk, + **start_parm, ) if clear_on_connect: mapdl.clear() @@ -1474,6 +1487,8 @@ def launch_mapdl( cleanup_on_exit=False, loglevel=loglevel, set_no_abort=set_no_abort, + use_vtk=use_vtk, + **start_parm, ) if clear_on_connect: mapdl.clear() @@ -1489,6 +1504,8 @@ def launch_mapdl( loglevel=loglevel, set_no_abort=set_no_abort, log_apdl=log_apdl, + use_vtk=use_vtk, + **start_parm, ) if clear_on_connect: mapdl.clear() @@ -1556,14 +1573,16 @@ def launch_mapdl( additional_switches = _check_license_argument(license_type, additional_switches) LOG.debug(f"Using additional switches {additional_switches}.") - start_parm = { - "exec_file": exec_file, - "run_location": run_location, - "additional_switches": additional_switches, - "jobname": jobname, - "nproc": nproc, - "print_com": print_com, - } + start_parm.update( + { + "exec_file": exec_file, + "run_location": run_location, + "additional_switches": additional_switches, + "jobname": jobname, + "nproc": nproc, + "print_com": print_com, + } + ) if mode in ["console", "corba"]: start_parm["start_timeout"] = start_timeout @@ -1585,7 +1604,9 @@ def launch_mapdl( if mode == "console": from ansys.mapdl.core.mapdl_console import MapdlConsole - mapdl = MapdlConsole(loglevel=loglevel, log_apdl=log_apdl, **start_parm) + mapdl = MapdlConsole( + loglevel=loglevel, log_apdl=log_apdl, use_vtk=use_vtk, **start_parm + ) elif mode == "corba": try: # pending deprecation to ansys-mapdl-corba @@ -1601,6 +1622,7 @@ def launch_mapdl( log_apdl=log_apdl, log_broadcast=broadcast, verbose=verbose_mapdl, + use_vtk=use_vtk, **start_parm, ) elif mode == "grpc": @@ -1621,6 +1643,7 @@ def launch_mapdl( remove_temp_dir_on_exit=remove_temp_dir_on_exit, log_apdl=log_apdl, process=process, + use_vtk=use_vtk, **start_parm, ) if run_location is None: diff --git a/src/ansys/mapdl/core/mapdl.py b/src/ansys/mapdl/core/mapdl.py index 1ba922e538..a34959f80e 100644 --- a/src/ansys/mapdl/core/mapdl.py +++ b/src/ansys/mapdl/core/mapdl.py @@ -193,7 +193,9 @@ def setup_logger(loglevel="INFO", log_file=True, mapdl_instance=None): "process", "ram", "run_location", - "start_timeout" "timeout", + "start_timeout", + "timeout", + "check_parameter_names", ] @@ -267,6 +269,7 @@ def __init__( self._jobname: str = start_parm.get("jobname", "file") self._path: Union[str, pathlib.Path] = start_parm.get("run_location", None) self._print_com: bool = print_com # print the command /COM input. + self.check_parameter_names = start_parm.get("check_parameter_names", True) # Setting up loggers self._log: logging.Logger = logger.add_instance_logger( @@ -366,6 +369,9 @@ def check_status(self): @property def file_type_for_plots(self): """Returns the current file type for plotting.""" + if not self._file_type_for_plots: + self._run("/show, PNG") + self._file_type_for_plots = "PNG" return self._file_type_for_plots @file_type_for_plots.setter @@ -475,6 +481,10 @@ def wrap_xsel_function_output(method): @wraps(func) def inner_wrapper(*args, **kwargs): # in interactive mode (item='p'), the output is not suppressed + if self._store_commands: + # In non-interactive mode, we do not need to check anything. + return + is_interactive_arg = ( True if len(args) >= 2 @@ -2019,27 +2029,31 @@ def __enter__(self) -> None: "``vtk=True``" ) - if not self._parent()._png_mode: - self._parent().show("PNG", mute=True) - self._parent().gfile(self._pixel_res, mute=True) + if not self._parent()._store_commands: + if not self._parent()._png_mode: + self._parent().show("PNG", mute=True) + self._parent().gfile(self._pixel_res, mute=True) - self.previous_device = self._parent().file_type_for_plots + self.previous_device = self._parent().file_type_for_plots - if self._parent().file_type_for_plots not in ["PNG", "TIFF", "PNG", "VRML"]: - self._parent().show(self._parent().default_file_type_for_plots) + if self._parent().file_type_for_plots not in [ + "PNG", + "TIFF", + "PNG", + "VRML", + ]: + self._parent().show(self._parent().default_file_type_for_plots) def __exit__(self, *args) -> None: self._parent()._log.debug("Exiting in 'WithInterativePlotting' mode") self._parent().show("close", mute=True) - if not self._parent()._png_mode: - self._parent().show("PNG", mute=True) - self._parent().gfile(self._pixel_res, mute=True) - self._parent().file_type_for_plots = self.previous_device + if not self._parent()._store_commands: + if not self._parent()._png_mode: + self._parent().show("PNG", mute=True) + self._parent().gfile(self._pixel_res, mute=True) - def __exit__(self, *args) -> None: - self._parent()._log.debug("Exiting in 'WithInterativePlotting' mode") - self._parent().show("close", mute=True) + self._parent().file_type_for_plots = self.previous_device @property def _has_matplotlib(self): @@ -2053,7 +2067,8 @@ def _has_matplotlib(self): @property def _png_mode(self): """Returns True when MAPDL is set to write plots as png to file.""" - return "PNG" in self.show(mute=False) + with self.force_output: + return "PNG" in self.show(mute=False) def set_log_level(self, loglevel: DEBUG_LEVELS) -> None: """Sets log level @@ -2786,6 +2801,10 @@ def get( with self.force_output: response = self.run(command, **kwargs) + if self._store_commands: + # Return early in non_interactive + return + value = response.split("=")[-1].strip() if item3: self._log.info( @@ -3247,7 +3266,7 @@ def run( command = "/CLE,NOSTART" # Tracking output device - if command[:4].upper() == "/SHO": + if command[:4].upper() == "/SHO" and "," in command: self._file_type_for_plots = command.split(",")[1].upper() # Invalid commands silently ignored. @@ -3290,8 +3309,17 @@ def run( # Edge case. `\title, 'par=1234' ` self._check_parameter_name(param_name) + short_cmd = parse_to_short_cmd(command) text = self._run(command, verbose=verbose, mute=mute) + if ( + "Display device has not yet been specified with the /SHOW command" in text + and short_cmd in PLOT_COMMANDS + ): + # Reissuing the command to make sure we get output. + self.show(self.default_file_type_for_plots) + text = self._run(command, verbose=verbose, mute=mute) + if command[:4].upper() == "/CLE" and self.is_grpc: # We have reset the database, so we need to create a new session id self._create_session() @@ -3311,8 +3339,6 @@ def run( self._raise_errors(text) # special returns for certain geometry commands - short_cmd = parse_to_short_cmd(command) - if short_cmd in PLOT_COMMANDS: self._log.debug("It is a plot command.") plot_path = self._get_plot_name(text) @@ -3981,6 +4007,9 @@ def get_nodal_constrains(self, label=None): def _check_parameter_name(self, param_name): """Checks if a parameter name is allowed or not.""" + if not self.check_parameter_names: + return + param_name = param_name.strip() match_valid_parameter_name = r"^[a-zA-Z_][a-zA-Z\d_\(\),\s\%]{0,31}$" diff --git a/src/ansys/mapdl/core/mapdl_grpc.py b/src/ansys/mapdl/core/mapdl_grpc.py index b13e3e5ed0..c9c119d2de 100644 --- a/src/ansys/mapdl/core/mapdl_grpc.py +++ b/src/ansys/mapdl/core/mapdl_grpc.py @@ -873,6 +873,7 @@ def _run_at_connect(self): self.show(self._file_type_for_plots) self.version # Caching version + self.file_type_for_plots # Setting /show,png and caching it. def _reset_cache(self): """Reset cached items.""" @@ -1811,11 +1812,6 @@ def input( if not self._apdl_log.closed: self._apdl_log.write(tmp_dat) - # Escaping early if inside non_interactive context - if self._store_commands: - self._stored_commands.append(tmp_dat.splitlines()[1]) - return None - if self._local: local_path = self.directory tmp_name_path = os.path.join(local_path, tmp_name) @@ -1824,6 +1820,11 @@ def input( else: self._upload_raw(tmp_dat.encode(), tmp_name) + # Escaping early if inside non_interactive context + if self._store_commands: + self._stored_commands.append(tmp_dat.splitlines()[1]) + return None + request = pb_types.InputFileRequest(filename=tmp_name) # even though we don't care about the output, we still @@ -1896,9 +1897,13 @@ def _get_file_path(self, fname: str, progress_bar: bool = False) -> str: if os.path.isfile(fname): # And it exists filename = os.path.join(os.getcwd(), fname) - elif fname in self.list_files(): + elif not self._store_commands and fname in self.list_files(): # It exists in the Mapdl working directory filename = os.path.join(self.directory, fname) + elif self._store_commands: + # Assuming that in non_interactive we have uploaded the file + # manually. + filename = os.path.join(self.directory, fname) else: # Finally raise FileNotFoundError(f"Unable to locate filename '{fname}'") @@ -1909,10 +1914,15 @@ def _get_file_path(self, fname: str, progress_bar: bool = False) -> str: self.upload(ffullpath, progress_bar=progress_bar) filename = fname - elif fname in self.list_files(): + elif not self._store_commands and fname in self.list_files(): # It exists in the Mapdl working directory filename = fname + elif self._store_commands: + # Assuming that in non_interactive, the file exists already in + # the Mapdl working directory + filename = fname + else: raise FileNotFoundError(f"Unable to locate filename '{fname}'") @@ -3034,7 +3044,8 @@ def vget( ) -> NDArray[np.float64]: """Wraps VGET""" super().vget(par=par, ir=ir, tstrt=tstrt, kcplx=kcplx, **kwargs) - return self.parameters[par] + if not self._store_commands: + return self.parameters[par] def get_variable( self, diff --git a/src/ansys/mapdl/core/misc.py b/src/ansys/mapdl/core/misc.py index 4b526712e7..29aa153e7f 100644 --- a/src/ansys/mapdl/core/misc.py +++ b/src/ansys/mapdl/core/misc.py @@ -1249,13 +1249,13 @@ def wrapper(self, *args, **kwargs): else: return original_sel_func( self, - type_=type_, - item=item, - comp=comp, - vmin=vmin, - vmax=vmax, - vinc=vinc, - kabs=kabs, + type_, + item, + comp, + vmin, + vmax, + vinc, + kabs, # ksel, esel, nsel uses kabs, but lsel, asel, vsel uses kswp **kwargs, ) diff --git a/src/ansys/mapdl/core/post.py b/src/ansys/mapdl/core/post.py index 702a6c676a..1a4c95f295 100644 --- a/src/ansys/mapdl/core/post.py +++ b/src/ansys/mapdl/core/post.py @@ -3,6 +3,7 @@ import numpy as np +from ansys.mapdl.core.errors import MapdlRuntimeError from ansys.mapdl.core.misc import supress_logging from ansys.mapdl.core.plotting import general_plotter diff --git a/tests/test_convert.py b/tests/test_convert.py index bfaceae501..6f088cdeda 100644 --- a/tests/test_convert.py +++ b/tests/test_convert.py @@ -43,34 +43,34 @@ pynblock = """with mapdl.non_interactive: mapdl.run("nblock,3,,326253") mapdl.run("(1i9,3e20.9e3)") - mapdl.run(" 1 3.352881632E-03 1.110639271E-02 5.172433282E-03") - mapdl.run(" 2 3.485685736E-03 1.110981270E-02 4.999255638E-03") - mapdl.run(" 3 3.615164748E-03 1.111323677E-02 4.823719994E-03") - mapdl.run(" 4 3.673859471E-03 1.111439119E-02 4.740300611E-03") - mapdl.run(" 5 3.709417144E-03 1.111407057E-02 4.691582629E-03") + mapdl.run("1 3.352881632E-03 1.110639271E-02 5.172433282E-03") + mapdl.run("2 3.485685736E-03 1.110981270E-02 4.999255638E-03") + mapdl.run("3 3.615164748E-03 1.111323677E-02 4.823719994E-03") + mapdl.run("4 3.673859471E-03 1.111439119E-02 4.740300611E-03") + mapdl.run("5 3.709417144E-03 1.111407057E-02 4.691582629E-03") mapdl.run("-1")""" pyeblock = """with mapdl.non_interactive: mapdl.run("eblock,19,solid,,6240") mapdl.run("(19i9)") - mapdl.run(" 1 1 1 1 0 0 0 0 20 0 38161 186586 186589 192999 193065 191265 191262 193063 193064") - mapdl.run(" 194712 194731 213866 194716 210305 210306 213993 210310 194715 194730 213865 213995") - mapdl.run(" 1 1 1 1 0 0 0 0 20 0 38162 186586 193065 192999 186589 186781 193066 192935 186784") - mapdl.run(" 194716 213866 194731 194712 195560 213737 195572 195557 194714 213997 213736 194729") - mapdl.run(" 1 1 1 1 0 0 0 0 20 0 38163 186781 193066 192935 186784 186976 193067 192871 186979") - mapdl.run(" 195560 213737 195572 195557 196210 213608 196222 196207 195559 213998 213607 195571") - mapdl.run(" 1 1 1 1 0 0 0 0 20 0 38164 186976 193067 192871 186979 187171 193068 192807 187174") - mapdl.run(" 196210 213608 196222 196207 196860 213479 196872 196857 196209 213999 213478 196221")""" + mapdl.run("1 1 1 1 0 0 0 0 20 0 38161 186586 186589 192999 193065 191265 191262 193063 193064") + mapdl.run("194712 194731 213866 194716 210305 210306 213993 210310 194715 194730 213865 213995") + mapdl.run("1 1 1 1 0 0 0 0 20 0 38162 186586 193065 192999 186589 186781 193066 192935 186784") + mapdl.run("194716 213866 194731 194712 195560 213737 195572 195557 194714 213997 213736 194729") + mapdl.run("1 1 1 1 0 0 0 0 20 0 38163 186781 193066 192935 186784 186976 193067 192871 186979") + mapdl.run("195560 213737 195572 195557 196210 213608 196222 196207 195559 213998 213607 195571") + mapdl.run("1 1 1 1 0 0 0 0 20 0 38164 186976 193067 192871 186979 187171 193068 192807 187174") + mapdl.run("196210 213608 196222 196207 196860 213479 196872 196857 196209 213999 213478 196221")""" pycmblock = """with mapdl.non_interactive: mapdl.run("CMBLOCK,PRESSURE_AREAS,NODE, 48") mapdl.run("(8i10)") - mapdl.run(" 1688 1689 1690 1691 1700 1701 1702 1703") - mapdl.run(" 1704 1705 1706 1707 1708 1709 1710 1711") - mapdl.run(" 1712 1721 1723 1731 1736 1754 1755 1756") - mapdl.run(" 1757 1758 1759 1760 1761 1762 1763 1764") - mapdl.run(" 1765 1766 1767 1768 1769 1802 1803 1804") - mapdl.run(" 1805 1806 1807 1808 1809 1831 1832 1833")""" + mapdl.run("1688 1689 1690 1691 1700 1701 1702 1703") + mapdl.run("1704 1705 1706 1707 1708 1709 1710 1711") + mapdl.run("1712 1721 1723 1731 1736 1754 1755 1756") + mapdl.run("1757 1758 1759 1760 1761 1762 1763 1764") + mapdl.run("1765 1766 1767 1768 1769 1802 1803 1804") + mapdl.run("1805 1806 1807 1808 1809 1831 1832 1833")""" block_commands = ["nblock", "eblock", "cmblock"] @@ -142,6 +142,25 @@ *END *USE,SLV""" +DO_CONVERSION = """with mapdl.non_interactive: + mapdl.run("*DO,I,1,81") # REPEAT MACRO EXECUTION""" + +GOLDEN_TESTS = { + "/DELETE,TABLE_1": 'mapdl.slashdelete("TABLE_1")', + "PROD,4,3, , ,FORCE , , ,-1.0,1,1,": 'mapdl.run("PROD,4,3, , ,FORCE , , ,-1.0,1,1")', + "ALLSEL,ALL": 'mapdl.allsel("ALL")', + "/EXIT,NOSAVE": 'mapdl.exit("NOSAVE")', + "": "", + "*DO,I,1,81 ! REPEAT MACRO EXECUTION": DO_CONVERSION, + " *USE,LOAD ! EXECUTE MACRO": 'mapdl.use("LOAD") # EXECUTE MACRO', + "*ENDDO": 'mapdl.run("*ENDDO")', + "SECT,1,SHELL": 'mapdl.sectype(1, "SHELL")', + "SECD,.00005,1 ! PLATE THICKNESS": "mapdl.secdata(.00005, 1) # PLATE THICKNESS", + "/show, asdf": 'mapdl.show("asdf")', + "*STAT,UXFEA2 ": 'mapdl.starstatus("UXFEA2")', + "/AXLAB,X,NORMALIZED TIME,TAU=ALPHA**2*D*t": 'mapdl.axlab("X", "NORMALIZED TIME,TAU=ALPHA**2*D*t")', +} + def test_convert_no_use_function_names(tmpdir): vm_file = examples.vmfiles["vm1"] @@ -318,9 +337,16 @@ def test_header(): assert '"""My header"""' in convert_apdl_block("/com", header="My header") -def test_com(): - converted_output = convert_apdl_block( +@pytest.mark.parametrize( + "cmd", + [ "/com, this is a comment !inline comment!", + "C***, this is a comment !inline comment!", + ], +) +def test_com(cmd): + converted_output = convert_apdl_block( + cmd, header=False, add_imports=False, ) @@ -360,13 +386,45 @@ def test_repeat(): ) -@pytest.mark.parametrize("cmd", COMMANDS_TO_NOT_BE_CONVERTED) -def test_commands_to_not_be_converted(cmd): - assert f'mapdl.run("{cmd}")' in convert_apdl_block( +@pytest.mark.parametrize( + "cmd", + [ + "/PMORE", # "/PMORE, + "ANTYPE", # ANTYPE, + "ASBL", # ASBL, + "ATAN", # ATAN, + ], +) +def test_empty_arguments_2(cmd): + # Checking trailing commas does not avoid conversion + assert f'mapdl.run("{cmd}")' not in convert_apdl_block( + cmd + ",,", header=False, add_imports=False + ) + + # Checking empty arguments avoid conversion + assert f'mapdl.run("{cmd.upper()},,OTHER_ARG")' in convert_apdl_block( + cmd + ",,OTHER_ARG", header=False, add_imports=False + ) + + # Checking default conversion + assert f'mapdl.run("{cmd}")' not in convert_apdl_block( cmd, header=False, add_imports=False ) +def test_commands_with_empty_arguments(): + cmd = """ANTYPE,STATIC ! STATIC ANALYSIS +ANTYPE,STATIC,,NON_EMPTY_ARGUMENT + +ANTYPE,STATIC,,,""" + pycmd = """mapdl.antype("STATIC") # STATIC ANALYSIS +mapdl.run("ANTYPE,STATIC,,NON_EMPTY_ARGUMENT") + +mapdl.antype("STATIC")""" + + assert pycmd in convert_apdl_block(cmd, header=False, add_imports=False) + + @pytest.mark.parametrize("ending", ["\n", "\r\n"]) def test_detect_line_ending(ending): assert ending in convert_apdl_block( @@ -387,7 +445,7 @@ def test_no_macro_as_functions(): APDL_MACRO, macros_as_functions=False, add_imports=False, header=False ) assert "with mapdl.non_interactive" in output - assert ' mapdl.run("*CREATE,SLV")' in output + assert ' mapdl.create("SLV")' in output assert ' mapdl.run("*END")' in output @@ -427,6 +485,54 @@ def test_only_commands(): assert "mapdl.exit" not in output +@pytest.mark.parametrize("vtk", [None, True, False]) +def test_use_vtk(vtk): + output = convert_apdl_block( + "/view,1,1,1", + only_commands=False, + add_imports=True, + use_vtk=vtk, + ) + assert "mapdl.view(1, 1, 1)" in output + assert "launch_mapdl" in output + if vtk is None: + assert "use_vtk" not in output + else: + assert f"use_vtk={vtk}" in output + + +@pytest.mark.parametrize("check_parameter_names", [None, True, False]) +def test_check_parameter_names(check_parameter_names): + output = convert_apdl_block( + "/view,1,1,1", + only_commands=False, + add_imports=True, + check_parameter_names=check_parameter_names, + ) + assert "mapdl.view(1, 1, 1)" in output + assert "launch_mapdl" in output + if check_parameter_names is not None and not check_parameter_names: + assert "check_parameter_names=False" in output + else: + assert f"check_parameter_names" not in output + + +@pytest.mark.parametrize("clear_at_start", [None, True, False]) +def test_clear_at_start(clear_at_start): + output = convert_apdl_block( + "/view,1,1,1", + only_commands=False, + add_imports=True, + clear_at_start=clear_at_start, + ) + assert "mapdl.view(1, 1, 1)" in output + assert "launch_mapdl" in output + if clear_at_start: + assert "mapdl.clear()" in output + else: + assert "mapdl.clear()" not in output + + @pytest.mark.parametrize( "parameters", [ @@ -452,6 +558,30 @@ def test_convert_star_slash(parameters): assert convert_apdl_block(parameters[0], only_commands=True) == parameters[1] +def test_parsing_items(): + cmd = "VGET,VALUE7(2,2),2,7E-2" + conv_cmd = convert_apdl_block(cmd, only_commands=True) + assert 'mapdl.vget("VALUE7(2,2)", 2, 7E-2)' in conv_cmd + + +def test_macros_call(): + cmd = """ +*create,myfunc +/prep7 +*end +myfunc +""" + conv_cmd = convert_apdl_block(cmd, only_commands=True) + assert "mapdl.prep7()" in conv_cmd + assert "def myfunc(" in conv_cmd + assert "myfunc()" in conv_cmd + + +@pytest.mark.parametrize("mapdl_cmd", GOLDEN_TESTS.keys()) +def test_golden(mapdl_cmd): + assert GOLDEN_TESTS[mapdl_cmd] == convert_apdl_block(mapdl_cmd, only_commands=True) + + ## CLI testing @@ -510,3 +640,32 @@ def test_converter_cli(tmpdir, run_cli): assert "mapdl.prep7()" in newcontent assert "mapdl.exit()" not in newcontent assert "launch_mapdl" not in newcontent + + +def test_exit_in_non_interactive(): + cmd = """ +*do,i,1,10 +/exit +*enddo""" + output = convert_apdl_block(cmd, only_commands=True) + + assert 'mapdl.run("*do,i,1,10")' in output + assert 'mapdl.com("Skipping: /exit")' in output + assert 'mapdl.run("*enddo")' in output + assert "mapdl.exit" not in output + + +@pytest.mark.parametrize("cmd", COMMANDS_TO_NOT_BE_CONVERTED) +def test_commands_to_not_be_converted(cmd): + assert f'mapdl.run("{cmd}")' in convert_apdl_block(cmd, only_commands=True) + + +def test_vwrite(): + cmd = """*VWRITE ! WRITE OUTPUT IN TABULAR FORMAT +(///T14,'MODE',T24,'COEFF',T34,'ISYM',/)""" + + pycmd = """with mapdl.non_interactive: + mapdl.run("*VWRITE") # WRITE OUTPUT IN TABULAR FORMAT + mapdl.run("(///T14,'MODE',T24,'COEFF',T34,'ISYM',/)")""" + + assert pycmd in convert_apdl_block(cmd, only_commands=True) diff --git a/tests/test_mapdl.py b/tests/test_mapdl.py index 3291616f53..283fc70487 100644 --- a/tests/test_mapdl.py +++ b/tests/test_mapdl.py @@ -1995,3 +1995,12 @@ def test_non_valid_kwarg(mapdl): with pytest.warns(UserWarning): mapdl.cdwrite(options="DB", fname="test1", ext="cdb") + + +def test_check_parameter_names(mapdl): + with pytest.raises(ValueError): + mapdl.parameters["_dummy"] = 1 + + mapdl.check_parameter_names = False + mapdl.parameters["_dummy"] = 1 + mapdl.check_parameter_names = True # returning to default From 712ec3249318ecb35ab6e5a74c4da368bc97fac0 Mon Sep 17 00:00:00 2001 From: German <28149841+germa89@users.noreply.github.com> Date: Fri, 27 Oct 2023 01:14:31 +0800 Subject: [PATCH 09/12] Marking flaky tests as xfail (#2446) Marking as xfail flaky tests. --- tests/test_mesh_grpc.py | 1 + tests/test_pool.py | 1 + tests/test_post.py | 1 + 3 files changed, 3 insertions(+) diff --git a/tests/test_mesh_grpc.py b/tests/test_mesh_grpc.py index 4afc487f8c..7667c6ac97 100644 --- a/tests/test_mesh_grpc.py +++ b/tests/test_mesh_grpc.py @@ -58,6 +58,7 @@ def test_local(mapdl): assert mapdl._local == mapdl.mesh.local +@pytest.mark.xfail(strict=False, reason="Flaky test. See #2435") def test_empty_mesh(mapdl, cleared): assert mapdl.mesh.n_node == 0 assert mapdl.mesh.n_elem == 0 diff --git a/tests/test_pool.py b/tests/test_pool.py index ae8cd83250..302e3c66ed 100644 --- a/tests/test_pool.py +++ b/tests/test_pool.py @@ -77,6 +77,7 @@ def test_invalid_exec(): ) +@pytest.mark.xfail(strict=False, reason="Flaky test. See #2435") @skip_if_not_local def test_heal(pool): pool_sz = len(pool) diff --git a/tests/test_post.py b/tests/test_post.py index 2edd736220..4067707b5b 100644 --- a/tests/test_post.py +++ b/tests/test_post.py @@ -733,6 +733,7 @@ def test_plot_incomplete_element_selection(mapdl, contact_solve): assert mapdl.post_processing.plot_element_displacement() is None +@pytest.mark.xfail(strict=False, reason="The image regression is failing. See #2435") def test_plot_incomplete_nodal_selection(mapdl, contact_solve): mapdl.nsel("S", "NODE", "", 1, mapdl.mesh.n_node // 2) assert mapdl.post_processing.plot_nodal_displacement() is None From 1fe9f7919238e5309412e257005c2e691f34098d Mon Sep 17 00:00:00 2001 From: German <28149841+germa89@users.noreply.github.com> Date: Fri, 27 Oct 2023 01:48:27 +0800 Subject: [PATCH 10/12] Clarifying email usage (#2451) * Clarifying email usage * Using email in readme to avoid packaging issues * Empty to trigger CICD * Apply suggestions from code review Co-authored-by: Kathy Pippert <84872299+PipKat@users.noreply.github.com> * fixing typos --------- Co-authored-by: Kathy Pippert <84872299+PipKat@users.noreply.github.com> --- README.rst | 6 +++++- doc/source/examples/index.rst | 3 +-- doc/source/getting_started/contribution.rst | 9 +++++---- doc/source/getting_started/learning.rst | 4 ++-- doc/source/getting_started/versioning.rst | 3 +-- doc/source/index.rst | 7 ++++++- doc/source/links.rst | 2 ++ doc/source/user_guide/database.rst | 2 +- 8 files changed, 23 insertions(+), 13 deletions(-) diff --git a/README.rst b/README.rst index 7952f1a9d6..54948515d2 100644 --- a/README.rst +++ b/README.rst @@ -73,7 +73,11 @@ you can create issues to report bugs and request new features. On the `PyMAPDL D `_ page or the `Discussions `_ page on the Ansys Developer portal, you can post questions, share ideas, and get community feedback. -To reach the project support team, email `pyansys.core@ansys.com `_. +To reach the project support team, email `PyAnsys Core team `_. +Unfortunately, this team cannot answer specific library questions or issues. You must +use the `PyMAPDL Issues `_ +and `PyMAPDL Discussions `_ pages +for raising issues, request new features, and asking questions. Project transition - legacy support ----------------------------------- diff --git a/doc/source/examples/index.rst b/doc/source/examples/index.rst index 9fc3514f27..e33c25faf6 100644 --- a/doc/source/examples/index.rst +++ b/doc/source/examples/index.rst @@ -54,5 +54,4 @@ These links refers to the following GitHub repository where you can find all of `GitHub Example Data Repository `_ If you find a missing or broken link, open an issue in -GitHub (`PyMAPDL Issues `_) -or send an email to `PyAnsys Core team `_. +GitHub (`PyMAPDL Issues `_). diff --git a/doc/source/getting_started/contribution.rst b/doc/source/getting_started/contribution.rst index 2377fe7085..12f8e16438 100644 --- a/doc/source/getting_started/contribution.rst +++ b/doc/source/getting_started/contribution.rst @@ -33,12 +33,13 @@ Use the `PyMAPDL Issues `_ page to submit questions, report bugs, and request new features. When possible, use these issue templates: -* Bug report template -* Feature request template +* **🐞 Bug, problem, or error**: Fill a bug report here +* **📖 Documentation issue**: Modifications to the documentation only +* **🎓 Adding an example**: Proposing a new example for the library +* **💡 New feature**: Enhancements to the code -If your issue does not fit into one of these categories, create your own issue. +If your issue does not fit into one of these categories, click on `Open a black issue `_. -To reach the project support team, email `PyAnsys Core team `_. Viewing PyMAPDL documentation ============================= diff --git a/doc/source/getting_started/learning.rst b/doc/source/getting_started/learning.rst index d76de57073..a57a5e65ed 100644 --- a/doc/source/getting_started/learning.rst +++ b/doc/source/getting_started/learning.rst @@ -174,5 +174,5 @@ Recommended articles .. vale on -Feel free to email any educational or learning resource to -`PyAnsys Core team `_. \ No newline at end of file +Feel free to share any educational or learning resources by `opening an issue `_ +or `starting a discussion `_ on Github. \ No newline at end of file diff --git a/doc/source/getting_started/versioning.rst b/doc/source/getting_started/versioning.rst index 2a543bc93d..10e12e1325 100644 --- a/doc/source/getting_started/versioning.rst +++ b/doc/source/getting_started/versioning.rst @@ -86,8 +86,7 @@ it is recommended exploring alternative interfaces available in PyMAPDL. PyMAPDL maintainers greatly appreciate your support and understanding during this transition. If you have any questions or concerns regarding this change, -email `pyansys.core@ansys.com `_ or -post them on the `PyMAPDL Discussions `_ page. +post them on the `PyMAPDL Discussions `_ page. Console interface ----------------- diff --git a/doc/source/index.rst b/doc/source/index.rst index 187352b145..e6186ff38b 100644 --- a/doc/source/index.rst +++ b/doc/source/index.rst @@ -181,7 +181,12 @@ you can create issues to report bugs and request new features. On the `PyMAPDL D `_ page or the `Discussions `_ page on the Ansys Developer portal, you can post questions, share ideas, and get community feedback. -To reach the project support team, email `pyansys.core@ansys.com `_. +To reach the PyAnsys project support team, email `PyAnsys Core team `_. +Unfortunately no specific library questions or issues are answered through this email. +Please refer to `PyMAPDL Issues `_, +or `PyMAPDL Discussions `_ for raising issues, +request new features, or asking questions. + Project index ------------- diff --git a/doc/source/links.rst b/doc/source/links.rst index 5949e5276f..dee5c715b5 100644 --- a/doc/source/links.rst +++ b/doc/source/links.rst @@ -120,6 +120,8 @@ .. _pymapdl_releases: https://github.com/ansys/pymapdl/releases .. _pymapdl_run_ubuntu: https://mapdl.docs.pyansys.com/version/dev/user_guide/troubleshoot.html#ubuntu .. _pymapdl_issues: https://github.com/ansys/pymapdl/issues +.. _pymapdl_new_issue: https://github.com/ansys/pymapdl/issues/new/choose +.. _pymapdl_new_blank_issue: https://github.com/ansys/pymapdl/issues/new .. _pymapdl_repo: https://github.com/ansys/pymapdl .. _pymapdl_docs: https://mapdl.docs.pyansys.com/version/stable/ .. _pymapdl_dev_docs: https://mapdl.docs.pyansys.com/version/dev/ diff --git a/doc/source/user_guide/database.rst b/doc/source/user_guide/database.rst index f0e87b65c8..1eb4b1ea12 100644 --- a/doc/source/user_guide/database.rst +++ b/doc/source/user_guide/database.rst @@ -1,7 +1,7 @@ Access MAPDL database ===================== -.. warning:: This feature is still in beta. Report any errors or suggestions to `PyAnsys Core team `_. +.. warning:: This feature is still in beta. To report any errors or suggestions, `open an issue on GitHub `_. In PyMAPDL v0.61.2 and later, you can access elements and nodes data from the MAPDL database using the DB module. From 3b891a091bafe26eaa09156c016a285d2a9eb99a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 27 Oct 2023 09:36:45 +0200 Subject: [PATCH 11/12] Bump imageio from 2.31.5 to 2.31.6 (#2457) Bumps [imageio](https://github.com/imageio/imageio) from 2.31.5 to 2.31.6. - [Release notes](https://github.com/imageio/imageio/releases) - [Changelog](https://github.com/imageio/imageio/blob/master/CHANGELOG.md) - [Commits](https://github.com/imageio/imageio/compare/v2.31.5...v2.31.6) --- updated-dependencies: - dependency-name: imageio dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 24e308c33d..d6794f767c 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -78,7 +78,7 @@ doc = [ "ansys-sphinx-theme==0.12.3", "grpcio==1.51.1", "imageio-ffmpeg==0.4.9", - "imageio==2.31.5", + "imageio==2.31.6", "jupyter_sphinx==0.4.0", "jupyterlab>=3.2.8", "matplotlib==3.8.0", From 2c9bad9b018086ed6ef8b414b71bf5d3bcebef27 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 27 Oct 2023 09:37:14 +0200 Subject: [PATCH 12/12] Bump pandas from 2.1.1 to 2.1.2 (#2455) Bumps [pandas](https://github.com/pandas-dev/pandas) from 2.1.1 to 2.1.2. - [Release notes](https://github.com/pandas-dev/pandas/releases) - [Commits](https://github.com/pandas-dev/pandas/compare/v2.1.1...v2.1.2) --- updated-dependencies: - dependency-name: pandas dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- pyproject.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index d6794f767c..67ffd7c619 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -61,7 +61,7 @@ tests = [ "matplotlib==3.8.0", "scipy==1.10.1; python_version < '3.9'", # to support python 3.8 "scipy==1.11.3; python_version > '3.8'", - "pandas==2.1.1", + "pandas==2.1.2", "pyiges[full]==0.3.1", "pytest==7.4.2", "pytest-cov==4.1.0", @@ -83,7 +83,7 @@ doc = [ "jupyterlab>=3.2.8", "matplotlib==3.8.0", "numpydoc==1.6.0", - "pandas==2.1.1", + "pandas==2.1.2", "plotly==5.17.0", "pyiges[full]==0.3.1", "pypandoc==1.12",