From d5b35e5ba3b0309807f7c6473d23e047d50b0446 Mon Sep 17 00:00:00 2001 From: Lars Pastewka Date: Fri, 30 Oct 2026 23:53:57 +0100 Subject: [PATCH 1/2] DOC: The CG work fields stay in the collection The docstrings and the Python reference still said the solver's work fields are removed again on return, which has not been true since the work fields were pooled. Say that they stay, how they are named, and that register_field_collection without field_names would write them to a file. Co-Authored-By: Claude Fable 5.1 --- CMakeCache.txt | 38 +++++++++++++++++++ CMakeFiles/cmake.check_cache | 1 + docs/python.md | 6 ++- language_bindings/python/muGrid/Solvers.py | 9 +++-- python_binding_io_field-tests.nc | Bin 0 -> 2520 bytes python_binding_io_frame-lifetime-tests.nc | Bin 0 -> 1240 bytes python_binding_io_global-attributes-tests.nc | Bin 0 -> 1052 bytes python_binding_io_state-field-tests.nc | Bin 0 -> 4584 bytes test_io_output.nc | Bin 0 -> 1224 bytes 9 files changed, 50 insertions(+), 4 deletions(-) create mode 100644 CMakeCache.txt create mode 100644 CMakeFiles/cmake.check_cache create mode 100644 python_binding_io_field-tests.nc create mode 100644 python_binding_io_frame-lifetime-tests.nc create mode 100644 python_binding_io_global-attributes-tests.nc create mode 100644 python_binding_io_state-field-tests.nc create mode 100644 test_io_output.nc diff --git a/CMakeCache.txt b/CMakeCache.txt new file mode 100644 index 00000000..f91f6e33 --- /dev/null +++ b/CMakeCache.txt @@ -0,0 +1,38 @@ +# This is the CMakeCache file. +# For build in directory: /home/pastewka/muSpectre/muGrid +# It was generated by CMake: /usr/bin/cmake +# You can edit this file to change values found and used by cmake. +# If you do not want to change any of the values, simply exit the editor. +# If you do want to change a value, simply edit, save, and exit the editor. +# The syntax for the file is as follows: +# KEY:TYPE=VALUE +# KEY is the name of a variable in the cache. +# TYPE is a hint to GUIs for the type of VALUE, DO NOT EDIT TYPE!. +# VALUE is the current value for the KEY. + +######################## +# EXTERNAL cache entries +######################## + + +######################## +# INTERNAL cache entries +######################## + +//This is the directory where this CMakeCache.txt was created +CMAKE_CACHEFILE_DIR:INTERNAL=/home/pastewka/muSpectre/muGrid +//Major version of cmake used to create the current loaded cache +CMAKE_CACHE_MAJOR_VERSION:INTERNAL=4 +//Minor version of cmake used to create the current loaded cache +CMAKE_CACHE_MINOR_VERSION:INTERNAL=2 +//Patch version of cmake used to create the current loaded cache +CMAKE_CACHE_PATCH_VERSION:INTERNAL=3 +//Path to CMake executable. +CMAKE_COMMAND:INTERNAL=/usr/bin/cmake +//Path to cpack program executable. +CMAKE_CPACK_COMMAND:INTERNAL=/usr/bin/cpack +//Path to ctest program executable. +CMAKE_CTEST_COMMAND:INTERNAL=/usr/bin/ctest +//Path to CMake installation. +CMAKE_ROOT:INTERNAL=/usr/share/cmake-4.2 + diff --git a/CMakeFiles/cmake.check_cache b/CMakeFiles/cmake.check_cache new file mode 100644 index 00000000..3dccd731 --- /dev/null +++ b/CMakeFiles/cmake.check_cache @@ -0,0 +1 @@ +# This file is generated by cmake for dependency checking of the CMakeCache.txt file diff --git a/docs/python.md b/docs/python.md index d702fed9..6c126ea8 100644 --- a/docs/python.md +++ b/docs/python.md @@ -629,7 +629,7 @@ $\|\mathbf{r}\|_2 \le \max(\mathrm{rtol}\,\|\mathbf{b}\|_2, \mathrm{atol})$. | Parameter | Description | |-----------|-------------| | `comm` | `Communicator` used for the global reductions. | -| `fc` | Collection (`GlobalFieldCollection`, `LocalFieldCollection` or `CartesianDecomposition`) on which temporary work fields are created and removed again. | +| `fc` | Collection (`GlobalFieldCollection`, `LocalFieldCollection` or `CartesianDecomposition`) holding the solver's work fields. They stay registered after the solve, so the next solve on the same collection reuses them instead of allocating anew; their names start with `cg-work`. | | `b` | Right-hand side field. Its dtype sets the working precision. | | `x` | Initial guess; overwritten with the solution. | | `hessp` | Callable `hessp(x, Ax)` writing $\mathbf{A}\mathbf{x}$ into `Ax`. | @@ -649,6 +649,10 @@ preconditioner is found not to be positive definite, or if a residual becomes NaN or infinite. With a `float32` right-hand side, an `rtol` below `muGrid.Solvers.FLOAT32_RTOL_FLOOR` (`1e-6`) triggers a `RuntimeWarning`. +Since the work fields remain in `fc`, a `register_field_collection` of that +collection without `field_names` would write them to the file as well; name +the fields you want written. + ### conjugate_gradients_pipelined ```python diff --git a/language_bindings/python/muGrid/Solvers.py b/language_bindings/python/muGrid/Solvers.py index a6d51d70..1d6cc680 100644 --- a/language_bindings/python/muGrid/Solvers.py +++ b/language_bindings/python/muGrid/Solvers.py @@ -224,8 +224,11 @@ def conjugate_gradients( Communicator for parallel processing. fc : muGrid.GlobalFieldCollection, muGrid.LocalFieldCollection, or muGrid.CartesianDecomposition - Collection for creating temporary fields used by the CG algorithm. - They are named ``cg#-`` and removed again on return. + Collection holding the work fields of the CG algorithm. They are + named ``cg-work--...`` and stay registered in the + collection after the solve for the next one to reuse; pass + ``field_names`` to ``FileIONetCDF.register_field_collection`` to + leave them out of a file. b : muGrid.Field Right-hand side vector. x : muGrid.Field @@ -641,7 +644,7 @@ def conjugate_gradients_pipelined( ---------- comm, fc, b, x, hessp, prec, tol, maxiter, timer, rtol, atol As for :func:`conjugate_gradients`. Work fields are named - ``pcg#-``. + ``pcg-work--...`` and stay in the collection as well. callback : callable, optional Called as ``callback(iteration, state_dict)`` at the start of every iteration, after the reduction completes, with keys "x", "r", "p", diff --git a/python_binding_io_field-tests.nc b/python_binding_io_field-tests.nc new file mode 100644 index 0000000000000000000000000000000000000000..d056764379524f3ad6381bbcca6db7b975aa8459 GIT binary patch literal 2520 zcmd^9eNYr-7+>!A8c*Rm#he=Sn#1WtmTnL3;F$8URCG)n3#6Q!*_PWqSY7V$ZXu{d zqnsGWkHXSPO9f_h&@mv253MxBbe!?V!a*#c0fD>YGaJh$v%0-|--9{SZ2GU>KlXW_ z=Y4*^-}65E>@HcF9!B_=+-s(xeI&AB7CV#AA!m}ACvsMY%}%p?K27Hewj4$vMb06T z7M>GWQioGR&_-r0#vww|k(SI_;@^0m6R}sP#NsAvWt6P4nHeEnl38LC1kNn-Hful- z>&=~v5hTQ2%Oh}pOo8a2>EOgbDTLIc>Bz;snPIkbjHFJpjEH(9LpdtFo}_f7UZ*#z zwJe!Wu3Hcwo4|=Y?k&bC^;BAtF-@1O)~-m)NXx`1mB2VeI^V|f-UhQ1f*5x{y&!Br z6l3qDIWxa-xt(X}BF^rRZpm9MHt7-=r)m96I#;9fG&PlINTf*0MCK-&3@LgY$Kr7! zq7hdvFVcC8BX2T~7H1nRdX{2R3@nwTGcuMOoykB^DP|*+lBzcv*d)|J72;w!huO{- zNN>P*g6mREtpgzm;*m*pCt? zJR&e(m=|+|dXw-x;Ta4qwDO`ij&qe(n_3E~3+%Qcp5<8YSvVr^^xJS`iP?AmE>Jc> zNP5ze=2%)-4(Il@@dfpd@(0DXx|UW zM~`{#*Bh*_^&yCeI=}t@JpV)s-B=dnhhjh2qWqBH_=EZgFAvVgoez%xQy)f8Z-Cuz zHNh3w^0cCEDV*Pa0|Y^NVp!=aJK!K5g6;v*m+HEfd0Yu zqxJ3$;JT%lQ93|D|Bzz+!TPn}8eM+i-PWBjb~gOQN3Ct}2HCgr(BM`$1wXE8E$f8# z*k2M0GcUkE$n)W4^X1_2{4TF-Qo^viyU29L2xC2L_4=6?!KJk(BsIiB|8DI@)BA^E z@Mq@Pmd8&+_h?*>r#u_3bTF}RM}G=k8qH&o9V&3G`*1kx_?Iy5ymeyPAKRd@HCn!@ zvKcy@vhb+e3Gj`@wPQ~6Uhr&p-md6d4P(!VwTi3W{8HF4Ui1<4e}Cg;^1UCRw<7Dn z$^Bj679wA3$ZLne&DCqNFHMK8!_!`B?2Cu13)`9_j%eZ7P5riW?yXRlrK~$tJO|E2 z4cgVel|xVY>b=WK1^D{Bvc^=K3Z8wouIlCz82KtelU_Ry22N$e^-T+4sBH1LD}4lx z_2k{@`9cZ3E90A}SvTNv%a&caeXY>GD5SB5uY%#HB2pDj4-B}P_mIZ5(5q~4_p~^n zX5*rtTAoycd*LewkDu8Lp792H_P!YS{OAie-;@#XiCPm^pZpG7Xj=1nTVox3n_1cM m@CW8ygGn2@=@&d*uAXN7N+{&Ti5(SNVMv3~(Ny|Fa_ literal 0 HcmV?d00001 diff --git a/python_binding_io_frame-lifetime-tests.nc b/python_binding_io_frame-lifetime-tests.nc new file mode 100644 index 0000000000000000000000000000000000000000..a8134a15f2dcfb479d08d4b962336d71d186d05b GIT binary patch literal 1240 zcmdr~y-ve05Duk5h#yfECZ-6MGPsIUlF%#+AYfr)Vv5|@X)PrVa?%QTFJ6GB;87Tf zYhPNR@BsCYJAZfIcjw$)UEkQ2J{z^!F+N~+DoM@^xMWT$Cdxv_l;?3g&p{baS;cdP zQqD4p+$LM;s?!qB+Nr;r#%qa}71--HY|q@bjonWqBNZ=1Oi5*WYnfQr^AL8C=X!zD zqbNs@XN}f^r`pso@H!rj20`TdPVX+dj~;;4%}80rc|m#oD!M2Ly#MO`;5J2p`&Z4w ze0nQ6jb}`j>Xlrih3Xb~r|)kn?wEMw;J)9-2oKTteCUUs%P5S|Ixt#eUd0nqPL_3g zkR7BR#U%789=HKXNAA$aI7|W(UU-2|2l`i8U86-=nMnSmCNPgcU)|q*7^Y<%FZD5! zL?n}#m-Y6@O3xoO?384sna!?Y!~Ptt+B1`5Hb!*M;nXD%My>B{%VR;3L^zI; zILX2Ri>m0`yT)s`(OCg|0^NRs^HG+^hvDEfKhM8_Dv-3cq|!{3g0poX=>C0Az z3z_Lg=Bw)RqY;c;aZ|fp3RP;i3DCXy^~2$z$MX;m(;<%VB$^#g(s2@V2FHl@yw^-v zGN<*t?K1#&RwfM7amw&0&S*J}Cn?6`BBSH?NtUva|AT?|V!SSlxNs-1M4+$W&px~o zq1UZGriQ9wPDH)9J;tuiA3VAxm38aBy_`usrIJuq7g96bG= tJZrI$4LmeKmm~kDF-fCf48c}oH#9xcb%-{*pcm439rGk z@B%yqkHH(ju04}jo3<(v5^9u{*0VFS-^}dnOtPo%&g!HXRY{Iu{Rn71NW3`*rbHSu zk!EqSq9S5^NofysHK0buqclz^6LU(ZVLb6dGtIn=n}OgVGcDM60JIVX8#v7N27P9CE!PVs*068e1K;%q zCyv`^UC3Y)Y%!ktiCCx`$Tb*Ob2|<|67r%H$0YG0e?~}Jb2L%2bw3xH@DO}77Py0{{RH4&#>n(7k9~xf;V%&bRm{JOlkg` zlv_nRx8(_Q^f5<}qmzQ(&+l&-5Pe1CYsl*q_8;i-yYhgq>iaQ^y8LhXaig%ba}@qv z#=A!0;>SBi-~K8Nv}+WuX;1bU*k|B=WI(-}^r_yL`c!W|eX6&YKBZ_s_8IuU85n;% Z&jZ*sDi5Xis^axtRlMG-l5chN`3HyD=gj~B literal 0 HcmV?d00001 diff --git a/test_io_output.nc b/test_io_output.nc new file mode 100644 index 0000000000000000000000000000000000000000..6684116620e61c4783b31ccbb75cb252420d2d6b GIT binary patch literal 1224 zcmeHF!A^rf5XIUWQ#Cf|$rDiz)r5xK77#9yXw-`*PoBt@g?5ty256%n<_~!CbNmEZ zcZODt#t(20JZ9d!H@iD~ae39z)LN^d3;*kYoupuC48aPtvd1PueJgwVl-q`A6L2Rg zVpfSf3puO6vjv<^sYxu8TGTQ6+)T~;lg4YQs|4-^bv;V_q2pU4qkrSy`gf?(XRNHk zH0L4_F<&-B-EaNAXq%>}{i)|(I=?Oi4;OJ!%2SFg$>kwXcl7csc>{RgAOm|qOyZf7 zk!QQqiaB1twhLYpQH4`hPFH>USnVW~6Xx2S3@wKxW6QG%aU+MhXVkIz5N=QhFCLds zAs*xeJ{a7W{(T>y)U<<@eT)m1Mbl7}As0oZW{n=5gw0Br=@zKvdy=bL#q})eIn209 z)L(pGn7~@;hwlb+?Rh4uI*+}2S#HRb@lfOo!DH#V0YOUM{sH=<9{E7ky#t`2fvx}m literal 0 HcmV?d00001 From d5b2da6751a943ff67d032f7cc4b611a8474fd0c Mon Sep 17 00:00:00 2001 From: Lars Pastewka Date: Sat, 31 Oct 2026 08:19:20 +0100 Subject: [PATCH 2/2] MAINT: Remove test output and CMake cache swept into the previous commit The Python IO tests write their NetCDF files into the source tree, and an in-source CMake run had left a CMakeCache.txt; none of it belongs in the repository. Co-Authored-By: Claude Fable 5.1 --- CMakeCache.txt | 38 ------------------- CMakeFiles/cmake.check_cache | 1 - python_binding_io_field-tests.nc | Bin 2520 -> 0 bytes python_binding_io_frame-lifetime-tests.nc | Bin 1240 -> 0 bytes python_binding_io_global-attributes-tests.nc | Bin 1052 -> 0 bytes python_binding_io_state-field-tests.nc | Bin 4584 -> 0 bytes test_io_output.nc | Bin 1224 -> 0 bytes 7 files changed, 39 deletions(-) delete mode 100644 CMakeCache.txt delete mode 100644 CMakeFiles/cmake.check_cache delete mode 100644 python_binding_io_field-tests.nc delete mode 100644 python_binding_io_frame-lifetime-tests.nc delete mode 100644 python_binding_io_global-attributes-tests.nc delete mode 100644 python_binding_io_state-field-tests.nc delete mode 100644 test_io_output.nc diff --git a/CMakeCache.txt b/CMakeCache.txt deleted file mode 100644 index f91f6e33..00000000 --- a/CMakeCache.txt +++ /dev/null @@ -1,38 +0,0 @@ -# This is the CMakeCache file. -# For build in directory: /home/pastewka/muSpectre/muGrid -# It was generated by CMake: /usr/bin/cmake -# You can edit this file to change values found and used by cmake. -# If you do not want to change any of the values, simply exit the editor. -# If you do want to change a value, simply edit, save, and exit the editor. -# The syntax for the file is as follows: -# KEY:TYPE=VALUE -# KEY is the name of a variable in the cache. -# TYPE is a hint to GUIs for the type of VALUE, DO NOT EDIT TYPE!. -# VALUE is the current value for the KEY. - -######################## -# EXTERNAL cache entries -######################## - - -######################## -# INTERNAL cache entries -######################## - -//This is the directory where this CMakeCache.txt was created -CMAKE_CACHEFILE_DIR:INTERNAL=/home/pastewka/muSpectre/muGrid -//Major version of cmake used to create the current loaded cache -CMAKE_CACHE_MAJOR_VERSION:INTERNAL=4 -//Minor version of cmake used to create the current loaded cache -CMAKE_CACHE_MINOR_VERSION:INTERNAL=2 -//Patch version of cmake used to create the current loaded cache -CMAKE_CACHE_PATCH_VERSION:INTERNAL=3 -//Path to CMake executable. -CMAKE_COMMAND:INTERNAL=/usr/bin/cmake -//Path to cpack program executable. -CMAKE_CPACK_COMMAND:INTERNAL=/usr/bin/cpack -//Path to ctest program executable. -CMAKE_CTEST_COMMAND:INTERNAL=/usr/bin/ctest -//Path to CMake installation. -CMAKE_ROOT:INTERNAL=/usr/share/cmake-4.2 - diff --git a/CMakeFiles/cmake.check_cache b/CMakeFiles/cmake.check_cache deleted file mode 100644 index 3dccd731..00000000 --- a/CMakeFiles/cmake.check_cache +++ /dev/null @@ -1 +0,0 @@ -# This file is generated by cmake for dependency checking of the CMakeCache.txt file diff --git a/python_binding_io_field-tests.nc b/python_binding_io_field-tests.nc deleted file mode 100644 index d056764379524f3ad6381bbcca6db7b975aa8459..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2520 zcmd^9eNYr-7+>!A8c*Rm#he=Sn#1WtmTnL3;F$8URCG)n3#6Q!*_PWqSY7V$ZXu{d zqnsGWkHXSPO9f_h&@mv253MxBbe!?V!a*#c0fD>YGaJh$v%0-|--9{SZ2GU>KlXW_ z=Y4*^-}65E>@HcF9!B_=+-s(xeI&AB7CV#AA!m}ACvsMY%}%p?K27Hewj4$vMb06T z7M>GWQioGR&_-r0#vww|k(SI_;@^0m6R}sP#NsAvWt6P4nHeEnl38LC1kNn-Hful- z>&=~v5hTQ2%Oh}pOo8a2>EOgbDTLIc>Bz;snPIkbjHFJpjEH(9LpdtFo}_f7UZ*#z zwJe!Wu3Hcwo4|=Y?k&bC^;BAtF-@1O)~-m)NXx`1mB2VeI^V|f-UhQ1f*5x{y&!Br z6l3qDIWxa-xt(X}BF^rRZpm9MHt7-=r)m96I#;9fG&PlINTf*0MCK-&3@LgY$Kr7! zq7hdvFVcC8BX2T~7H1nRdX{2R3@nwTGcuMOoykB^DP|*+lBzcv*d)|J72;w!huO{- zNN>P*g6mREtpgzm;*m*pCt? zJR&e(m=|+|dXw-x;Ta4qwDO`ij&qe(n_3E~3+%Qcp5<8YSvVr^^xJS`iP?AmE>Jc> zNP5ze=2%)-4(Il@@dfpd@(0DXx|UW zM~`{#*Bh*_^&yCeI=}t@JpV)s-B=dnhhjh2qWqBH_=EZgFAvVgoez%xQy)f8Z-Cuz zHNh3w^0cCEDV*Pa0|Y^NVp!=aJK!K5g6;v*m+HEfd0Yu zqxJ3$;JT%lQ93|D|Bzz+!TPn}8eM+i-PWBjb~gOQN3Ct}2HCgr(BM`$1wXE8E$f8# z*k2M0GcUkE$n)W4^X1_2{4TF-Qo^viyU29L2xC2L_4=6?!KJk(BsIiB|8DI@)BA^E z@Mq@Pmd8&+_h?*>r#u_3bTF}RM}G=k8qH&o9V&3G`*1kx_?Iy5ymeyPAKRd@HCn!@ zvKcy@vhb+e3Gj`@wPQ~6Uhr&p-md6d4P(!VwTi3W{8HF4Ui1<4e}Cg;^1UCRw<7Dn z$^Bj679wA3$ZLne&DCqNFHMK8!_!`B?2Cu13)`9_j%eZ7P5riW?yXRlrK~$tJO|E2 z4cgVel|xVY>b=WK1^D{Bvc^=K3Z8wouIlCz82KtelU_Ry22N$e^-T+4sBH1LD}4lx z_2k{@`9cZ3E90A}SvTNv%a&caeXY>GD5SB5uY%#HB2pDj4-B}P_mIZ5(5q~4_p~^n zX5*rtTAoycd*LewkDu8Lp792H_P!YS{OAie-;@#XiCPm^pZpG7Xj=1nTVox3n_1cM m@CW8ygGn2@=@&d*uAXN7N+{&Ti5(SNVMv3~(Ny|Fa_ diff --git a/python_binding_io_frame-lifetime-tests.nc b/python_binding_io_frame-lifetime-tests.nc deleted file mode 100644 index a8134a15f2dcfb479d08d4b962336d71d186d05b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1240 zcmdr~y-ve05Duk5h#yfECZ-6MGPsIUlF%#+AYfr)Vv5|@X)PrVa?%QTFJ6GB;87Tf zYhPNR@BsCYJAZfIcjw$)UEkQ2J{z^!F+N~+DoM@^xMWT$Cdxv_l;?3g&p{baS;cdP zQqD4p+$LM;s?!qB+Nr;r#%qa}71--HY|q@bjonWqBNZ=1Oi5*WYnfQr^AL8C=X!zD zqbNs@XN}f^r`pso@H!rj20`TdPVX+dj~;;4%}80rc|m#oD!M2Ly#MO`;5J2p`&Z4w ze0nQ6jb}`j>Xlrih3Xb~r|)kn?wEMw;J)9-2oKTteCUUs%P5S|Ixt#eUd0nqPL_3g zkR7BR#U%789=HKXNAA$aI7|W(UU-2|2l`i8U86-=nMnSmCNPgcU)|q*7^Y<%FZD5! zL?n}#m-Y6@O3xoO?384sna!?Y!~Ptt+B1`5Hb!*M;nXD%My>B{%VR;3L^zI; zILX2Ri>m0`yT)s`(OCg|0^NRs^HG+^hvDEfKhM8_Dv-3cq|!{3g0poX=>C0Az z3z_Lg=Bw)RqY;c;aZ|fp3RP;i3DCXy^~2$z$MX;m(;<%VB$^#g(s2@V2FHl@yw^-v zGN<*t?K1#&RwfM7amw&0&S*J}Cn?6`BBSH?NtUva|AT?|V!SSlxNs-1M4+$W&px~o zq1UZGriQ9wPDH)9J;tuiA3VAxm38aBy_`usrIJuq7g96bG= tJZrI$4LmeKmm~kDF-fCf48c}oH#9xcb%-{*pcm439rGk z@B%yqkHH(ju04}jo3<(v5^9u{*0VFS-^}dnOtPo%&g!HXRY{Iu{Rn71NW3`*rbHSu zk!EqSq9S5^NofysHK0buqclz^6LU(ZVLb6dGtIn=n}OgVGcDM60JIVX8#v7N27P9CE!PVs*068e1K;%q zCyv`^UC3Y)Y%!ktiCCx`$Tb*Ob2|<|67r%H$0YG0e?~}Jb2L%2bw3xH@DO}77Py0{{RH4&#>n(7k9~xf;V%&bRm{JOlkg` zlv_nRx8(_Q^f5<}qmzQ(&+l&-5Pe1CYsl*q_8;i-yYhgq>iaQ^y8LhXaig%ba}@qv z#=A!0;>SBi-~K8Nv}+WuX;1bU*k|B=WI(-}^r_yL`c!W|eX6&YKBZ_s_8IuU85n;% Z&jZ*sDi5Xis^axtRlMG-l5chN`3HyD=gj~B diff --git a/test_io_output.nc b/test_io_output.nc deleted file mode 100644 index 6684116620e61c4783b31ccbb75cb252420d2d6b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1224 zcmeHF!A^rf5XIUWQ#Cf|$rDiz)r5xK77#9yXw-`*PoBt@g?5ty256%n<_~!CbNmEZ zcZODt#t(20JZ9d!H@iD~ae39z)LN^d3;*kYoupuC48aPtvd1PueJgwVl-q`A6L2Rg zVpfSf3puO6vjv<^sYxu8TGTQ6+)T~;lg4YQs|4-^bv;V_q2pU4qkrSy`gf?(XRNHk zH0L4_F<&-B-EaNAXq%>}{i)|(I=?Oi4;OJ!%2SFg$>kwXcl7csc>{RgAOm|qOyZf7 zk!QQqiaB1twhLYpQH4`hPFH>USnVW~6Xx2S3@wKxW6QG%aU+MhXVkIz5N=QhFCLds zAs*xeJ{a7W{(T>y)U<<@eT)m1Mbl7}As0oZW{n=5gw0Br=@zKvdy=bL#q})eIn209 z)L(pGn7~@;hwlb+?Rh4uI*+}2S#HRb@lfOo!DH#V0YOUM{sH=<9{E7ky#t`2fvx}m