From 4d9f5c35693b5508f58fa4f78c6ca4384fcbf416 Mon Sep 17 00:00:00 2001 From: Henrik Andersson Date: Thu, 5 Jun 2025 10:04:51 +0200 Subject: [PATCH 1/3] Undo reshaping of spectra on write etc. --- mikeio/dfsu/_dfsu.py | 28 ++++++++++++++++++++----- mikeio/spatial/_FM_geometry_spectral.py | 4 ++++ tests/test_dfsu_spectral.py | 7 +++++++ 3 files changed, 34 insertions(+), 5 deletions(-) diff --git a/mikeio/dfsu/_dfsu.py b/mikeio/dfsu/_dfsu.py index c499abc18..4fd34c06b 100644 --- a/mikeio/dfsu/_dfsu.py +++ b/mikeio/dfsu/_dfsu.py @@ -51,7 +51,7 @@ def write_dfsu(filename: str | Path, data: Dataset) -> None: geometry = data.geometry dfsu_filetype = DfsuFileType.Dfsu2D - if geometry.is_layered: + if geometry.is_layered or geometry.is_spectral: dfsu_filetype = geometry._type.value xn = geometry.node_coordinates[:, 0] @@ -61,9 +61,24 @@ def write_dfsu(filename: str | Path, data: Dataset) -> None: elem_table = [np.array(e) + 1 for e in geometry.element_table] builder = DfsuBuilder.Create(dfsu_filetype) - if dfsu_filetype != DfsuFileType.Dfsu2D: + if dfsu_filetype in ( + DfsuFileType.Dfsu3DSigma, + DfsuFileType.Dfsu3DSigmaZ, + DfsuFileType.DfsuVerticalColumn, + DfsuFileType.DfsuVerticalProfileSigma, + DfsuFileType.DfsuVerticalProfileSigmaZ, + ): builder.SetNumberOfSigmaLayers(geometry.n_sigma_layers) + if dfsu_filetype in ( + DfsuFileType.DfsuSpectral0D, + DfsuFileType.DfsuSpectral1D, + DfsuFileType.DfsuSpectral2D, + ): + builder.SetFrequencies(geometry.frequencies) + # TODO should directions always be converted to radians + builder.SetDirections(np.deg2rad(geometry.directions)) + builder.SetNodes(xn, yn, zn, geometry.codes) builder.SetElements(elem_table) @@ -82,9 +97,6 @@ def write_dfsu(filename: str | Path, data: Dataset) -> None: builder.SetTemporalAxis(temporal_axis) builder.SetZUnit(eumUnit.eumUmeter) - if dfsu_filetype != DfsuFileType.Dfsu2D: - builder.SetNumberOfSigmaLayers(geometry.n_sigma_layers) - for item in data.items: builder.AddDynamicItem(item.name, eumQuantity.Create(item.type, item.unit)) @@ -117,7 +129,13 @@ def write_dfsu_data(dfs: DfsuFile, ds: Dataset, is_layered: bool) -> None: d = da.to_numpy()[i, :] else: d = da.to_numpy() + d = d.copy() # to avoid modifying the input d[np.isnan(d)] = data.deletevalue + + if d.ndim != 1: + d = np.moveaxis(d, 0, -1) + d = d.reshape(-1) + dfs.WriteItemTimeStepNext(t_rel[i], d.astype(np.float32)) dfs.Close() diff --git a/mikeio/spatial/_FM_geometry_spectral.py b/mikeio/spatial/_FM_geometry_spectral.py index 2e58085f7..ca5c5e3b4 100644 --- a/mikeio/spatial/_FM_geometry_spectral.py +++ b/mikeio/spatial/_FM_geometry_spectral.py @@ -105,6 +105,10 @@ def n_frequencies(self) -> int: """Number of frequencies.""" return 0 if self.frequencies is None else len(self.frequencies) + @property + def is_layered(self) -> bool: + return False + @property def frequencies(self) -> np.ndarray | None: """Frequency axis.""" diff --git a/tests/test_dfsu_spectral.py b/tests/test_dfsu_spectral.py index 8b90fbf8a..c1c9dd2e7 100644 --- a/tests/test_dfsu_spectral.py +++ b/tests/test_dfsu_spectral.py @@ -439,3 +439,10 @@ def test_plot_da_spectrum(dfsu_pt: DfsuSpectral) -> None: # dfs.plot_spectrum(spec, title="pt", plot_type="shaded") # dfs.plot_spectrum(spec, r_as_periods=False, plot_type="contour") plt.close("all") + + +def test_write_line_spectra(dfsu_line: DfsuSpectral) -> None: + ds = dfsu_line.read() + ds.to_dfs("line.dfsu") + + ds2 = mikeio.read("line.dfsu") From 7389ce66b47970a10b181167379f8b7bc7b58fe8 Mon Sep 17 00:00:00 2001 From: Henrik Andersson Date: Wed, 11 Jun 2025 13:36:14 +0200 Subject: [PATCH 2/3] Test with alpha release of mikecore --- .github/workflows/full_test.yml | 2 + .github/workflows/legacy_test.yml | 2 + .github/workflows/notebooks_test.yml | 2 + mikeio/spatial/_FM_geometry_spectral.py | 25 +++++++ pyproject.toml | 4 +- tests/test_dfsu_spectral.py | 67 ++++++++++++++++-- .../spectra/North_BC_2024_subset.dfsu | Bin 0 -> 96475 bytes 7 files changed, 96 insertions(+), 6 deletions(-) create mode 100755 tests/testdata/spectra/North_BC_2024_subset.dfsu diff --git a/.github/workflows/full_test.yml b/.github/workflows/full_test.yml index 54669db7e..4483ffd0c 100644 --- a/.github/workflows/full_test.yml +++ b/.github/workflows/full_test.yml @@ -34,6 +34,8 @@ jobs: - name: Install mikeio run: | + # TODO remove after release of mikecore + pip install https://github.com/DHI/mikecore-python/releases/download/v0.3.a0/mikecore-0.3.0a0-py3-none-any.whl pip install .[test] - name: Test with pytest run: | diff --git a/.github/workflows/legacy_test.yml b/.github/workflows/legacy_test.yml index 39c6fcc52..debbb72db 100644 --- a/.github/workflows/legacy_test.yml +++ b/.github/workflows/legacy_test.yml @@ -22,6 +22,8 @@ jobs: - name: Install MIKE IO run: | python -m pip install --upgrade pip + # TODO remove after release of mikecore + pip install https://github.com/DHI/mikecore-python/releases/download/v0.3.a0/mikecore-0.3.0a0-py3-none-any.whl pip install .[test] pip install -r requirements_min.txt - name: Test with pytest diff --git a/.github/workflows/notebooks_test.yml b/.github/workflows/notebooks_test.yml index 9b09a5e62..a48e05ac5 100644 --- a/.github/workflows/notebooks_test.yml +++ b/.github/workflows/notebooks_test.yml @@ -21,6 +21,8 @@ jobs: python-version: "3.13" - name: Install mikeio run: | + # TODO remove after release of mikecore + pip install https://github.com/DHI/mikecore-python/releases/download/v0.3.a0/mikecore-0.3.0a0-py3-none-any.whl pip install .[test,notebooks] - name: Test notebooks run: | diff --git a/mikeio/spatial/_FM_geometry_spectral.py b/mikeio/spatial/_FM_geometry_spectral.py index ca5c5e3b4..b64797644 100644 --- a/mikeio/spatial/_FM_geometry_spectral.py +++ b/mikeio/spatial/_FM_geometry_spectral.py @@ -186,6 +186,31 @@ def elements_to_geometry( # type: ignore class GeometryFMLineSpectrum(_GeometryFMSpectrum): """Flexible mesh line spectrum geometry.""" + @staticmethod + def create_dummy_coordinates( + n_nodes: int, frequencies: np.ndarray, directions: np.ndarray + ) -> GeometryFMLineSpectrum: + # boogus x, y, z 1..n, 1..n, -10 + node_coordinates = np.zeros((n_nodes, 3), dtype=float) + node_coordinates[:, 0] = np.arange(1, n_nodes + 1) # x + node_coordinates[:, 1] = np.arange(1, n_nodes + 1) # y + node_coordinates[:, 2] = -10.0 # z + + # element table with nodes [0,1], [1,2], ..., [n-2,n-1] + element_table = np.zeros((n_nodes - 1, 2), dtype=int) + for i in range(n_nodes - 1): + element_table[i, 0] = i + element_table[i, 1] = i + 1 + return GeometryFMLineSpectrum( + node_coordinates=node_coordinates, + element_table=element_table, + codes=np.zeros(n_nodes, dtype=int), + dfsu_type=DfsuFileType.DfsuSpectral1D, + projection="LONG/LAT", + frequencies=frequencies, + directions=directions, + ) + def isel( # type: ignore self, idx: Sequence[int], axis: str = "node" ) -> GeometryFMPointSpectrum | GeometryFMLineSpectrum: diff --git a/pyproject.toml b/pyproject.toml index ab1ef0699..2a368de0a 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -20,9 +20,9 @@ exclude = [ [project] name = "mikeio" -version = "2.7.0" +version = "3.0.0a0" dependencies = [ - "mikecore>=0.2.1", + "mikecore>=0.3.0a0", "numpy>=1.22.0", "pandas>=1.3", "matplotlib>=3.6.0", diff --git a/tests/test_dfsu_spectral.py b/tests/test_dfsu_spectral.py index c1c9dd2e7..3ff296b02 100644 --- a/tests/test_dfsu_spectral.py +++ b/tests/test_dfsu_spectral.py @@ -1,12 +1,14 @@ +from pathlib import Path import pytest import numpy as np import matplotlib.pyplot as plt import mikeio from mikecore.DfsuFile import DfsuFileType -from mikeio import DfsuSpectral +from mikeio import DfsuSpectral, EUMType, EUMUnit from mikeio.spatial import GeometryFMPointSpectrum, GeometryFMAreaSpectrum import mikeio._spectral as _spectral +from mikeio.spatial._FM_geometry_spectral import GeometryFMLineSpectrum @pytest.fixture @@ -441,8 +443,65 @@ def test_plot_da_spectrum(dfsu_pt: DfsuSpectral) -> None: plt.close("all") -def test_write_line_spectra(dfsu_line: DfsuSpectral) -> None: +def test_write_line_spectra(dfsu_line: DfsuSpectral, tmp_path: Path) -> None: ds = dfsu_line.read() - ds.to_dfs("line.dfsu") - ds2 = mikeio.read("line.dfsu") + fp = tmp_path / "line.dfsu" + + ds.to_dfs(fp) + + ds2 = mikeio.read(fp) + + +def test_write_line_spectra_energy(tmp_path: Path) -> None: + ds = mikeio.read("tests/testdata/spectra/North_BC_2024_subset.dfsu") + assert ds["Energy density"].type == EUMType.Wave_energy_density + assert ds["Energy density"].unit == EUMUnit.meter_pow_2_sec_per_deg + assert ds.geometry.directions[-1] == pytest.approx(350) + assert ds.geometry.frequencies[0] == pytest.approx(0.035) + assert ds.geometry.frequencies[-1] == pytest.approx(0.983586) + assert ds["Energy density"].isel(time=-1).isel(node=0).isel(frequency=35).isel( + direction=28 + ).to_numpy() == pytest.approx(2.6239042e-05) + + fp = tmp_path / "line_energy.dfsu" + ds.to_dfs(fp) + + ds2 = mikeio.read(fp) + assert ds2["Energy density"].type == EUMType.Wave_energy_density + assert ds2["Energy density"].unit == EUMUnit.meter_pow_2_sec_per_deg + assert ds2.geometry.directions[-1] == pytest.approx(350) + assert ds2.geometry.frequencies[0] == pytest.approx(0.035) + assert ds2.geometry.frequencies[-1] == pytest.approx(0.983586) + assert ds2["Energy density"].isel(time=-1).isel(node=0).isel(frequency=35).isel( + direction=28 + ).to_numpy() == pytest.approx(2.6239042e-05) + assert np.all(ds2.to_numpy() == ds.to_numpy()) + + +def test_write_area_spectra(dfsu_area: DfsuSpectral, tmp_path: Path) -> None: + ds = dfsu_area.read() + fp = tmp_path / "area.dfsu" + ds.to_dfs(fp) + + dfs = mikeio.DfsuSpectral(fp) + assert dfs.geometry.is_spectral + assert dfs._type == DfsuFileType.DfsuSpectral2D + assert dfs.geometry.n_frequencies == 25 + assert dfs.frequencies is not None + assert len(dfs.frequencies) == 25 + assert dfs.geometry.n_directions == 16 + assert dfs.directions is not None + assert len(dfs.directions) == 16 + + ds2 = dfs.read() + assert np.all(ds2.to_numpy() == ds.to_numpy()) + + +def test_create_line_spectrum_dummy_coordinates() -> None: + freq = np.array([0.035, 0.983586]) + dirs = np.arange(5.0, 360.0, step=10.0) + geometry = GeometryFMLineSpectrum.create_dummy_coordinates( + n_nodes=10, frequencies=freq, directions=dirs + ) + assert geometry.n_nodes == 10 diff --git a/tests/testdata/spectra/North_BC_2024_subset.dfsu b/tests/testdata/spectra/North_BC_2024_subset.dfsu new file mode 100755 index 0000000000000000000000000000000000000000..0c9f7cfde8c0f4c9c85f4d41c74d0f6160724074 GIT binary patch literal 96475 zcmeF(d0b8H-Z=if+w;_(=Xtm1d8&jaWyshh5)p+$QJJTbN|T|1qB4|9sZ?YLp-dGK znPpZ8p~zIfxX*n*=RWRpey{Hz-{*Ut^Q^^wt!rKTbFFoK-fOMvTG?B!qui#uj_{f; z80R)-xL`_9c$h#Vh@2Z7A($OJKS(euEHpA8I5a{qGdMILe7PVnATmHL2n-X1hD8d3 z0)rz3f)NuI28E6o2zCh%3WyA1y+FW0=z%|UkQ_7@1OiPt~K=se1k09&sqsZXk zfh{nozmF(`hz5#biz5Y-yj%u)V{{cv3Rn^(h*%gjD>8iXf`O{B!J$C|p(GguF%Y^S zcwSI&*uXYf2K}*@djqfjKF)6&Edvq#ecazR2HqIhp#HY;BecJdCIkN{%ow&OrN56Z zv-q(=NxHeZ6495~-^Y+aepC#^F@I~+-`~HszmFw@{cQbngDr!g213S87(Y@s*4Z0m z0r}D5pDg`-g7N)*6URd^0|7?8(WEgLHAX$?=Pva6!9V|kex|Vu1_D`F{NsKE`<a+fB<3TAH1i=r44i60qpEGdof=fA1*>6y@08 zH{&G)IS}^aa+^M490&>@*!aQsqw**9z*_vbSAU;VcK`3`kTwjY^CN0}SYVJKIPkab zpIrz3tpFW(=l47YioY(ubo-Zzf1byW4*o+P&e_nPwFB?`Nbm>Jk1hM$+N)gBApZM*cSs3qQxKKM!vM!@}<) z*}obV{+t2s?=py7zVN^GO#Jg4ez^Xt*PnC14n&U+6NJqkcr*wMiumumnErVRKS$Jo zj{URspHuj88eGCcLkAu+f|vX;Q~vkNFoc0)|2o6`to^(G|Ck(ppJ{%dZGN9|exG%I zpLu?${Au?27&kEcpa*J4ga<8J927e1Z;t}Xfx7?uBi4^O{g(v6KWY_I@%EZZuDx-o z#{N~agMIZ=5Bsl=X4_}9kqYEuE~DE$A|XI7k{$1VIdvD zs;Lg-a0raMaMZ72V@Uy zS32IsUmU1=;D|ZdGf)qA;@J?LiUT-KHYqZvfq19!Pwk!V;@zC)4DogvXzR2#HN**X za2mk_r03ZMe z00MvjAOHve0)PM@00;mAfB+x>2mk_r03ZMe00MvjAOHve0)PM@00;mAfB+x>2mk_r z03ZMe00MvjAOHve0)PM@00;mAfB+x>2mk_r03ZMe00MvjAOHve0)PM@00;mAfB+x> z2mk_r03ZMe00MvjAOHve0)PM@00;mAfB+x>2mk_r03ZMe00MvjAOHve0)PM@00;mA zfB+x>2mk_r03ZMe00MvjAOHve0)PM@00;mAfB+x>2mk_r03ZMe00MvjAOHve0)PM@ z00;mAfB+x>2mk_r03ZMe00MvjAOHve0)PM@00;mAfB+x>2mk_r03ZMe00MvjAOHve z0)PM@00;mAfB+x>2mk{AsRDf-b^YMYn*Y@F{D>!=X-}iRf*u zBT;#vgRs)0cM&NS5$LOSCd)UQy9r-xBhl-7-dh%a6jLhpNywy^Od>n&5@|R^01g({IBgbNMURvovBio5N3W8L zd7jF^{7Qx7;4Hb<9vkVSi~A(FJ+%@^)M{Dk`z4Zx60CB%bB^j#6IHc&+kQptA(L!& zdV&=6at_PGBtuT1!`)OMCEmDn0&7>LRMT8BFi``QG7lhC}W(OqV7(M*JOCoH5`Xcs)OQ0 zIocs#hO^l&OItZd@wI)YY}?0jb%g1>rs7?IMjLlYHPpFC{%+wJ*~y2MvJ9`yitTx) zWoy#ktD|{f?dAA%P2oAP+CT4zJZ5x@Oq6+2)|pnIkS1K0IR?@+6|#QxHu0wH`NvZ-eRQ?LPOE#!;> znf^dV*<`OtyJM?OwY{ks->6i#m%NZ$FYuM;H4T$D47sb=`k5_%uws-3fpOBVB0kbA zSYS|>2VGX&F&$96cHE^X^Yv2><){^iC!U&A*9ltdHSaWms+nqE??BaZ-&rbju)B&M zQl*O6(xA-Py-YLx^j2+xyFzQRiK0p3-c)z2xu+J;8r9A=G7V+0le*c4$b!}CvDiR$(j$tS7@z!nEHN0j;{CsOqaOcLU+6#sk^)F zyY}r#FWrSj!CFY6wHEREn$Bs0uWl8gO8bdfsy$9Rq$R&7)W(j(>IOHnw4$YOtp_Si z_cW2NyC)0N23OD2UV9p-oi6dvPMck>-Fxk#X8Gd=&9)^jy4H}(T6I2MD;xhv6S=5R zvv_Bc#5+KL z57w3^Gs$>|Kp%V!>nh$zLRns+N0DH15FNXnK=k`|gHU$tIPr?-bu-!y0Ik%HOY8RP4(NIpi z()xuKT*0NUTV_XB-P}uGEZR{gAcku1pwdWpluU&WI-EGX`WYfyVgPZCs?!iGru0>E&Ez0c;3MkO`B37^o^zpK{2TUR)M`>xl$#F zB5fBesCvx5xr-!P6uQmIO2oH1{dR?@|J4g&$@~;y^2HTGZ@;I)$Pz1|@8l$_z6PP> z=!OEZIPaTP^11m|HJuh#-S`WlAxG`3KFHRJ+CGvcK2zPC@>N}DIg+IPrUR|T>~5!jP}k;XQop*DP`loarQKLCjGB>uhHlH6!HkW0%6Ru!#F!VhmhPW{rgxm6 z(6h_R=pM&T)AEdym>)B)u(lDWu|_=3V9I8lVSs6ljL3%JjAaSW7jIpvZR@FW_ zXZW$b?B#JcS#Dh)n49$e%+myaCSx^-r7D&)11Gh!-^Dv~k&|0FsYx)7pa#uu8oY=V zRXCTm+z!Dm8)3t8`Hbe?ikZh->ki`O_OQ4&+G!kv>l$`MLl`^63&YVobzpbr33xWD zt^5sPG`?t!nzw(7kb8Sb97jBIDTj21zzv{{;6&fE;X7uu3J`Xlg0aDl{M-mRZ(LUj zmmL$st!-rUE<}5BzfW5&h{{%otk&%i*2l&Qj@cXd$iNKVnXW|Mfg2KjP4_e&X2Wrz z{lWuQ*(RoyA^3(cX}FKz!=PRKMSIfuU*6dW8W)G~2M5|&?U*%OayPb6EL=a!>M*86 zIQdeG;HCJWU|&R{@M-Ki0U`ga7=7xYv~k5?>E$Io;;Uf}R?QTd=!q>x6te%O=|Jh}#2^e4e;kb$CsUA;A<6fw{O%&;Q55sKu&)C%!Ragn5vwLz?egv#uEa~1nUpXGb= zGi2dgUP(fHYQzg2riyQ_@{oj;>BT(<*)mgwt3p+pBd<9=SmyOKL?TW`i$R^~RyMVp z#NTi4wE_m0|4aeuK@haIeXYf^ty{pC&!H?n?Rg2FRlCk2Ndbn=J&ps%SAk%cVM{f|08^;;}-bL=e@AqRw3~3+pi%aCk4W6d{R-(pHE=vg|{%Yr?=5=l{7T&tQwX4 za5Kt9{1F{f--t}qigDNWcHs#JWcV>daFz~RzhXOTuVTti@UW4$*Wl7Rw_%)@QV9DW zCXv?NY9-Dx77^6;!|*lvy|{~PwWYKv1|RXV6*nepIce#ZU6ds*Fp4+7p48*RBSyCt z;9K)=;4@e9iBs5l_?$CSDJuR%+P7mh)WEaRlm`tvNsKvU;Q_B#c)cIqTfRY(>QX!Oj ztJ#yhddxhssJEC>p1g$IqnpiWC}*%-PNp#3H44VZL@3QZYaHdXg+Ik<$R6rTbOhyK z{R-wJYdL!`V+ZRyTEmQ7{gGA_J%qY+f-5yVdJ`>t&ot_2%k`{rohHtQLwRhA3=ONu z;Sn8_rlj37scC*wR?`un;k4z);@J~bPTYseQqH^wYBuWZCC2+LJbL~zK7HGrFh=5R zYq~8cg)?%t8;`F$$lXBGa$H}ZW_r8O8JW-N47WAGOuuRsW9*_W+(d>qU-bMa@5MO{ zw?})NHH<=K#z#__pEGB(C@ba6Ij_@s@*~lLRB#=CiI0YdN;=G*Uc+Er{77ddoS)DB z#8a>oUFrO3j`c$KqrHNF^9p`VWF@Cq!e{es`0RISOF4~WG;DUhui(-oj1``Q6fIu( zme0PpkgM#z%^o-H9-E-iatlh|vu9613!R~Garv$}Nao#1p5g4a;Fno~!Q;SBoL!WCfCIG^ff2p=5E6Gw=4 zSydJ66gYmY;HH&JIeQkVIoWp-xd%@=bMAg23qgUC#4k>GTGg-h5P-MN=AN8*m94IA zWiO~ub7$TC!v4fKEqIdx6O-65t1KrAL8osJS9E6y*xa#M#=066rzS1D&aZ!j*gLfh>*_A>5@%T2=T;`RD(xOI!@#4!~@!gZt+ z_oR-8cy%WLn)JvC+I8Fx2_)+QWNn7u3B32~ETYk>5MaF(w3X6u0h7}&H zfe*0@h7}vG6FP#+$#FMoNjdDjc;Yd*F8=(nk2eKxlvj-2b>%sNR#l2{ zO%tFljDCrj$NoUR)L%iv4mv^IYrBw?B$6TQ#BfTV^5`KEFfBaV?|| z$}6Rr^M;f6kzrU7VKj;$C!>1XmYLj_L`!i7VTQ!umZf!_fEM#C}*BgW)%o(vQ_; zv0fe6!o-$zQ|D3V;k)J&E&aCU<5r*8XPH4nc;5@y%#!XIum;OWbU5YFE{ zXSoHvkhvz&mji$4#{RM}l0N_KHiBQb8=l~C&oci@2cDlFWjR62VLHx%bCBRZ*7ZCZ zJtB}!_*l2qGGHgovOQ0T-@NNR?ys(KpzeQ4wI6sRFcMrosH(=WTh+8jz{4>%E4uXfhZARUV zsYI3wHo+nH0-*(>?H1PrY>RByK*+a?m%!l(5+rJg3F}fvz+8V^gxrQ+4R11*Kxr~H z)P@}m6Z<`djLH(Av!9K%%zbTzV=d1>bF)VyeVP*BS7Xue@DNW#<%z?v$&#Vy&j;cx z_a;oj1(C|pO%FyO=S|)KA2$L8x4!0%C?y|;1=m`l>vG0edVdh%PP@dQ;~$ZcPUlC% zuM{-Gg0Hg>JKZ@DYU$jF`8LRdfQ@skw9!>6ZVt!~3$7i-es%N|+4E@lrxjk>=McW$T$_KLg^#n%r) z?3x?_>s!_Z?V4i?$8h&S#Y4N0?(c;-9kQ4Oz3}P4U&h2PumH!8-vDd+s({Xpjrq$MP|a!3kY}S{nU6pJ<w_vYxFD_u#I?))<-Ol4t~bsE2RXk5JvW{Cz3NYEv#tm<=Wr2t{y_s6 zWQqUF{(KTxfD1an7T0&igI8bs>%0Vq72xyt6&9(!<=}&dHvQ#(R`-a&-HlcjG@C-O zRes`M#+wg2E!a%|HZ{Gx8y2TQH@a3|< z{EWM}&H^r4vkZ~@wHJ-9kw96 z#Gb#zXhv3o;)wiy%2y>=>hx1U; zaQ)`MUt;)QQXmm)AHhnezlYb_tb%W9^Zq5~K_d#f$XN-8z7`|44=sf+x|jT?m@nt* zKxyIYpwWrx@DHE_gyNMYBKh<4KgB$^u>!w;^cEU46ow%8zeRjowgi!8cKcKAE6)ai zVQbB>3mqd6b~*zxlUapO3`_r0OoCt*xa^e!Y;LOuVpsbRSkxqphudRGdnN!$aya;pM9xuhDgFo1)|sDb?{=EpTa0>Poz z>Tz(&J_4dGH4^^S*Y8hx{fOC$Q$VKE;4pu`@30c64{XBbb$@vs{)h#Z|9t|UzDvO< z)KUmlR%$WbbLU^q%dpeiU;)9C5K&L-;M+3_f4P2m6T#qc=?J8s_Zt+oD*!c@k%;_9 zNzXIaEymhH(Px&VVEW%=p#L!@Ns5GaUq@pi+T*aE_Yqk5#AM7r##Ao42=&8l z$Mo2ua6y++uyexH*uRg#iqgP?c1FPTUH332B!h7-+fQL{xWr@SfhT{4k+5Z;A>DBn zd2AYdio+|+!8P`{`?Kn>rK7iELu2-UFK@pCVm7S%bCoV*ZW+nbB&YR{uG8)Y?*-l;DLiEHd$GiN1U|? z`?L)jW+EX|4==)0E-A!Ttx{k~Wi;$w)K17t#{(9l-6lfXFG*p({9@!@*kp|B=5^Rd z1}Jv)?H8CCS7p%Sax*0L+a1U|V>zton=^_^O~T}rBw}AQV6l-|Z!u-g`=A!-6_D!C z$Hh-XiMXIY-;gD zobu^4?B?(?Y(YvEY&awvIs)wotAZ&IZHv&D#&dXF2lOGXVuvp-+u9oUru`+%DftzY zzhN^><{yigTDBB(_tI+Iq=U|u?y94>Y*sezetth}%ENEa{NNq1!qhaxx~6nYqt{kk z=;GCEVn`7L;b+8ma#iws|$+|Upw|=N~%k65APnZ>{#>(SCMlSH_Cq| zEScm7z3Pd8$(kvMvkpQ`iCTc$azI|7hi`J@4AdSBg?>4jZMKmd2kBT^7z#+ z*Vx}*PeA!UOJG6%NDD_+8AynH_D5o~Q~vAw6yP!r{Cgk)`KEC=!pF@0V?G^ox8>(| zGnn=U$fO11(cualmYlc>)4X@&ALH1=Bb=Y#VJOU0!WBD7IPIV^%kg@V<&2skI3Muv zKfc>x^IBvv+n0$fkl(NrP7Wj_g*?XlPBr5TPTa5{AKL^rbEOt3XcE*u(-YO6`4OL) z6Gr^0r6mI0A~Ce zG;z-8>7>B;cB1-e88N2qE8MzD3-?dF0=H|~i<}!o!hUUq61}&NBURR3BfewqCocA@ zLnOKN!ebyAh%eFeQIj{F#d0=1Ciu>jkt!Y)6DhM&iEH1)BIn-Tg=oVJL-KrB==Yhi zxCNU|60X@0EXQI^2Iv>(Nzs6%`RV0Jl{2w$ZDU5#xSE%(APY4dpHtn zsZPh|E!aW4Fk=bHyY4M<=KXWT;2Ica=^_I9WoRXOc|;C&{2NEYgyF+T37hd`VPpa+ z@Y+mLwl)pp@GuA6JlX~Gwb6j9|M;E2^!-8_akG*f{8&zwSYXL3Q5M)?SJ4<@aS3KZ z{VrVM(^z7)DVm(|&P>4Wg1P9|goy>$nG72@H0-K#pZmx_X*G=JJ26c$hW9K!YkIV+)k|QmMllHcg9#Ec; z=Ot0d?rT8g+N4E@ zjz$i&XSp|W#m%pl^f$SL1-ns%s}AQaIpuQbnh$TlxYw@`4<9(fZpH*)61JWqR^(10 zV^ix%WZo^}Y9bS{F=YdEMm`7jc>G=j1nM{|EYoo?}}oz}Fol(s8IgEiT%z(9^su+zKV;JRIn#4~y- z&3W)ly7*uRZT{pMTJ?=<<@-}TL~AaF7P`-k9yI?F?Q&%~?V0Q` z4kow6)lo}uUavObNp1&8KCR!W^9z*pxy>cC{t1~h$A>#DYXqlp-yk8D=prY={$^(4}cp{C$*Z`N48$m8ILT!Ru9#SW#6?(wI=bKK}1?R7LO?;@Jl zT@qotS&kobtr`Ehx{^5UB8vKOFr0oQ>@t1SBUd_%Dx%*aohGEJ@8FZx#1meX&L`cH zU7!-%PSZo8lNb*L5JsrQb-H`TQsQh#G9hodhS+6hl3yI%LF>v-W#lxEXDV}Q8SZ&m zjHdK2#M2d)#5V`aiAx-_$s41b=^?B1OmpK0W={1?X7Xz@)5wyM7R+)YUOfGh=kYYtJKdW_sTbThqX>tg0y&J5ON!cL~+_@zt_$Q`W15~M9g$^gENoTz9jhW_>NC`pF{Za_uc8Pmq#zb}9i+rC;6oQCYTyq(?)c6;gui5DKnBzBe{y(eej9yM$s zC#!|j_iZthiD)gkduA&_lbH|qHOFGVxmlw*h5HHbp3bKYy46F!Il_aUT<1s2L+dc# z@NOvYga@d~VV^Lr!G}o~g<}};9;cb9jW*2VCGm`V4QbeM4S|@83H=z@oNu_oC=w-Y zS0XcI-v`#9+yyKT)gxxp{lz$WE&+EHk&jzyy#wz)`4gpWv>PjGXFj`Uu8h6jrjEsl zZL@Tdhg#mgfy8HuzY^TQY1CEcPOwbPWRBwCHn!9Iacut{DPj2O&G?XR8R4v+PTJrv zrcIa!W9R5ba-zMO*bDtL*&&HTh@xE^2}2G@iOqAU(gx>~B-1aoz?!VkZSw zv)MECq~6jc#2z`3lt_e7wn&TV)R$K5;UA}PMjpA#mSvn^6CA1JM=Y{%kP6b|JXU?i&=d682uG>r_uZ*uEf6m=cjpuJdSj6lTdJ)HIb(_VDJN1~C z_(H}bchPwVXVd9}m1f%Ml6$ncH7KTQPCWP2l-c~_g2(*BZ^it4ErmaIav7a1xlZe) zN6{xdD`4JEa^MX!2n4+9?SkX=5BM+g8u_>u3r71vF&*`|t58R8UlfGEdTno<9Hs;$f3k0XR>DoQ~(a)y{*rk?yc$7W=kDCW5 z{Erk^wUP-CGLl$F8r$RN~Ph&F_CsCeCfu+0hJ$X<;5EWh;O(DK%Atlg~5V1iUk^UPj2{NxC zI6mnK>EmWKBcN(K(_YxY=v|piFFC&-qe;JoaT`P;ehD+-$FXpz1~F-P1EFSp=-*G&GaX0n;bg|k1?+Zj;ojD30??$Rf-$*mjJ$3p zW3lWwG!Cks4uo2Y?lCtkJyGN3k;Dl+A)a;q+L7TwI@Ltztzr?TOqXv8exnfp57xvDmH z!!8UP?^?ljnSX`5u=$Z-NZ29K>ua7?udEA1JhY#vqppqfnU3ZpuPNueZoSIWHd~7@ zPsWIQGdje`vnKI_swYSyA(_Sw6>NjeHw&7jJA;J@;U8ByYjp zEyBa6S4yq-ZI@T~YZSV<(eg!i#PYol$MYtz7IKNJ89cXGYhm4sFOm&jPh|(j&y&|u zDrIdA+hzYF2LYhde+b~Zx*>DczDMd`HlWixhat15-iRlpO`w*#m5?b92cyP5Wg;+1 zTYLX_jn0$nJo0xgoNFeuh!H=!&Mczt{CUo7Z!I3hf$he)wjJlJTnWT+P40t1$ z{?%_kM#UxK{1h&f4E!FV(_lLWcTNYVU?`J!&1W=s+tTOk+QTvUi{~a1>{f1}zO^YL zPxp;rkJ*2ozu+TUIP2VK0a!SaA5M)ULB1i#)s_zAFZ|n-37aywoyE06?`V+Kk+>Ur+L0`t#@#2; zevwL6657QX!}6F*blJ?}-95~?{${qP16;UV`9h4ZM@sE3#!FZ&<0bVs?yxFzPO`V-0-<3fv&RQ=ci%$n(wptcl{v3si1>akhK*O z3238K9Ey_;!*@$))0PU50ZM_zpNI6_j7T|n>mEg}O_8|&v%gro_m$X3*D5Wld8at%zFGBwj#4j~lCBa;`hu zXEFg|I||=nGa7fW0fT-|m<3@@@qxoqJg{hT2pZE2B3Jl&F>*D|3@@)*8uobzWms}P zYWjpmOsL^Axp?jtVy&u|39DuCFrQ<2!#Q)f;bXS2)6VR$ocHY+p0#rkqR7H%mK9++y72_B>bvO8)YTi{BgeY$ z?gu2d?hli%u~#c%Pi&Uo9r#h%cj*k~)?3xgiJ#k;Yoc$mq9z}aN&_^C;B!nRra4*R zm8DhWQ#x7fP6PYV5`T7zbUY`0T%=5fyQGj{4=G0+R4V-|KPYyN8^*c$E|x=bFX71V z@8A}{>69IHvQ_%&1*%(lnaUg27bzFFC2;3=S8$so9o)>jH+fHY*vXf16M^j#|6p|oISGk{--j<8-e1jYp%+^4Wa3l&YQwtCgdh zQHpZoFojcBiZUUIrfHoSqs?YL)Vk!PX#F_fH1l@UDtJ8@B?dlRNtl?S3incJt*mzF z+Qm@){o1{{5*LE5EclqRY$-|=v&LB^$=aqKMI5YiB9`etZ>AVV>_4K1edFnm=Pp&g z9AB**8U#`;^>kCO`1nyPE}yO6c(Gm|z9do)ecqzGzu8JTcJ4xDN%%hHv3F3l_r2ZP zJ8y{kQ2k>4-BN~L8k3;=WP3y5;z3pBr}-$KTNkLD>IGT~b)xR#i9Fq|vQ zJI_-Mt{`R;4P?8`b$XI2gjddV&(J)pyz$FEZ%Hf0*x8?9Zlwu25R^{JF10Y z4W(F?iZ8pFio6$-hAtk9#9yjp6CsnIFm~8a=4w60b6>iraMpJ&WX_DUBG*JzkaODS z)1@8VObGoM{~`};<>U2Hgk#!?SgWlCEwn^dlP!c5xW9&T)*UXG9$YTIkp5Vz)jX6| zg*i)ita&4LyIaT~wR05j`0%xYGgeYDQU;c9pT13DMrA9K#4+B=_MIzMTN)^+Y~?VH4r z%BTYv*!BF+wY;PuL;oka!ER54NEtk zdsTTso+J}O3KUJ-TGXn(+uCEhXXw&jgz0*jY+Wc?raKn$T-l&_A-jS;tnhm9K>gJ9 znU+)>tjjVj({-o>I=+)ucOcQ3BSuS>+Mb@gG^ zIzb3ub!1+)@wJdO;kEww|qj4?zy}}hYiox-LMGLS@xe+eO^RRfB&pfr(NEl z**mE~r>{MzZ}Ep4jOS|f-mi^%LfB4q(JQ`Y{dPOefpib;Y@g4@`@Eu0op^runQL*vL1%z=-aTLuJ zLhb4T@%)$?F}7@?*!Mn0)Z#LOKgXOUOlQn9!+69iK0IusK_v6Sr61n|DqT zyT?*p|B0g+VvuU?pMIc@b+=M?s*%c@!_t&fn)WM2%A+dn{&dY6|GC;+{bFsWvs!yg zS*8ivn5V+ny;3=lDe7xZB+YG2u6CKlaNWrMak|GunhqCuQkzhATD{@$6}6g)*1TN+ z(q8cP)>({yqFd$jT6gAHxo&J_v~HVUk|u7=Qq9QqMVj-kw`yNqY}SQ;9;KJXdFb0Q z9R0UTeY$yG2g=dgq)u`Yeu{{v$6$8+t;bt)CaH zCF~igyYbdvKkH$w{(0;<{gCNf_3tij(67$U)3zi|*7ohq(z1%8b;oaQ(Ax-}>c3gM z(l4JhFRU`^i}dx`i0upTIsXR z+7M2&*1xqx2U%RKA9e?6Af3Y)7F@WlPtCrfFO^&9T7q|IRsL;Sr`3mbJ~OKH8LkFi|JzNY~j8DbQVbx>{c`YMya$M!X3%sNQs-ag%BKj9%kz z&I=un6RWq$P0&}HJq-7UtT6S4?l1?;Za2#^_M7=4g!xWYxvtP)t6%@zQSY)rVQ9bU zW*Qn5X|_qNG7mDWGmm+C&(v@!UKcQ}Pbbbs=s#@08tm;|OeHsGnzhC~=8%2<=6A#H zn8x}{(p}rLPZxdlxQ<#+Fyua+ZQA0y#BBP$*Zj5A)9kt!Z2q?!1b`0xAH{C(X0CG7@f6H2JiG%($=Rm z;^M+0O6AdMWM_w&)R=^3w)F{|;Mh3_LHjGP;88&UM{beGGJRdmEh{eIxSx^m!U8Xd z@|P4y;&qLZfVMcvgvSi4NfTX!J3Qm9+?}yjDyT*rem_mN>G4Lz?I(E({~P{_n%E<< zlQjfs^5+6s!0p+xL4!TyosqYcvXg_=^yTB#(k_y^KmDU}vUlqq+FH^gNFV(jCebj`mmT7vIma5(au2k302~pe8Xc}SoF6{{aS-J_I7wYW&>~#9) z<=TGyD9tR*dCkqH^BRk)`P%0;#kv-VlYZz_H+{XFuYcowQpc;At({(6uIRk!<_3Hwk=?Uzk`tkFk_4~`jy2}9*bUnmbx(1JKou}Oc{YnoP!y%QM;n`5J zVfmCkeQHIKt_O5XmkzqB^P4_J&+gY5p4DzLSf!;Im?_}~YonV1I~b*x=+OH7-CTXz z(cSv^;bDfptYd~;{V4-6IL9!(d4r)P#X;ZcZ`Kzx-1T)m#3)4OW;hR1dSW5l!!qf`7r zqv}qg(UuWtTzV!~zeyXfhmOhBU)(d=AnTfHwCnm{oGc-kMi)IWX1+XVJaYGdzB_xP zp0VhFKDHp)u#Qz@41MWqf`HeX&egh^>hhVU4b@-tXR{vb6Fsm7%M%@jaCdu?MLNig zX%(60(7u~4?9DZuka`+iBC8$Sc;b+KD!s0z0gue4MOV{Z>Zr6F$Zb<&j2G@^I7b)Mw_` zNms40NqC!wbMIS^wf4039}!~=NscjQCFC1VmZzGY5Jc7}Z?w(uFSa(*rXX!j4bQOd zPir@}N1ru5TLCfceEHer;TUI~?CfpBx*cbe)a7LJs;S%hkDCuD{M!kTG!&?F_zCP< zj|sRH=}O$lc^H_>f)Q}Tw4tc1$$4?`BI$FmHf%UJUAnRiK% zJKj+#Pliw|kItYyI-kp#e&?Xzg=fFu?BG*^+5|ec!~X;O(Ad4aOB1$p*RG)O*K{RX zjevMdy@heog{NGl+YU5XS>1{e4L!G4obVYgp0|S{F}SMwY*RpR(?mryHTaipl#H&y_lx~o%pQrs-CE`d0?rBCo=S(j`!*W zezSC3M>p-Yt8Lo(F%8^yncRtnxSWVx50hiH^aG; zw+vZh_ZTJ|*`xQHa!LOp=9=Es-DsHA-(h%R9%NjBbTuy1%8gSlL5#H55JS5+!vMR$ zHx$#?8&;f=8z+s8G0t4Q$(Yl!#CYhki_yriHH@enVUQTT41%kbhSxXd8eh#mVce;_ zYE+!6GJYxDVs!i*WT-i_(9j@TZx~$MX^_9mGoE9?P2ZBqCaTkS<2qEcF+rDZV1;BF z;!^e-hzG2U#&?g6CtICOO*;Zi{&Sp6g&S$62fLdLX@yq|{byephClN+E}Ww@CAsIC zb_RBEhoc7&zz)oP*fY)!uL=G-Jx+$y;F?IMnu&w-fF<)1gHPk0;A zvH+u3;5wrd5oTKD{?61qbFn#U{w6akJk%V~qBRd&UvBi?TyK=*v>AC*XPfdXLd-9y zQ0p=%&wBeRi1nQ{`^}->nWiOQhnbwCyi7Gu?wh8fk=C5$Ro0*K9$FVlj$6}w$64Q` zWSXu&>@l55?lqAP#+Y4fZ(6@uS7y`kq1|R){u!GozABrJ<6lgpH_FYmS!T2En2YAJ zBXpZW=yMzFc&hDD;s+bXfe0HcX_k3PRFe6v*LHJ5n8`Y_dc6&Hp0n+vn#H!G99?Wn zC)}`+%kP+z4It~c_5^E~Z>jbC_-{7Qxuv%El1pt+E=|LP>@NjoXSCD^;SyE@=?$V@Q~%UTShdB7u1`U^R2{JuhZ!N+UT( zj-}wQpQW)*U#IM8l+xq74cu!ot#JROwZg-L#tC1|OXUu4>*magT+Ltq(T)ymE)+vz$|bv^o8%YImnyT?UsaY(DNweg z^~fW%-Ljr%Neb6Wyy6?ZL2=BUq%Qgvpt%(pt!Yj0)U>HY>d3P)RR(dgx&>mX&d%GR zZciJnW!c*4Mjjul+Zn0Uov4_k{dy@(qa5v`ort4pr@l|tau;6LO&PL5|Lt_D{;>55 z{qs$2y8BlwbUkOc>1>Bb>*5~W)2aF&=$ee z{rs#``fEEg3~nf>aqUNxan8sO25ZzV!{FBqdfG#lp>QMFkbgeFuv$Yh7NUcVLoY5f z@^4Qy9!}>OK^w;!K8{K>tlk=Ln0&3l&~-J^SbFf7G2`Spqh(2j(d|IIan`qdLk9h- zA?N;e!y%>6XmjzfG2=PbwEi;7Bs`Bc+0D6OoI2*C0dg7NZv!VK0#;)CUjK zc8?%a$(eDc^Kn8`Kf+*KWteDGBBmR+OG=F5wXUY;s!Y>Yez6G&&NOYg9c)4iR~twA zWf&93Wg96s-x{}vq?wYY^qM@iIP=2#FDB25huowP~SEnyI45-Tct&gn4@UO>^?j$dGEC#v^qP#^<5kFkEkG+0~VzL;O1I&Hel{ATL0hnO`J1|EQ; zZLJf^j#`f%bi=x;`KWcysU_A{b9Lrbw-%enSgtTLr`$3pmo!>WL(aBwKEJ`{x_zjP z*9we{0b6c9rYBn4Ji=N}^;vFBPROvSwH{{+ITmgEfjG-n`K8rn)fR!Z;Kd^AeQDv= zXR_L?uegJ48=n>1f)`%5t&KfoJ89$)+iwSQtdH40v({i=SXcG<*<2hQWqUhRI!LtB zX;4s`YS8l+$Ns-|&hwwk_x+QX+ah}(bk<79ZNm7Z5Cea?Ux2#A;q7q3V zqbLgP6cv$%GMY+hDblYypYP-MCwy*vZd{M!xbD3k$BpNCT-WhB54w87fV$)rOtrq; zL=93S6uSNsz4w_E^IV0+*ibUek>gYU@$i52`S&Ga`sU(s4wNB_-z`v%id>`Fp38u)J>8B;1(dB26`uhf>jqNw;vup19u($66 z?E3*_#w-3B`^Bt8O^>(fnj}9mG}X{RIQ=n_yuO!aJn1*Gyb$~OoL!y?W(R~+xQ;qW zoZ@}vT+YHUenxbyK(_Xtpk+>tV4rCmpa1wQuS4ktUw3CB|9hFNAoNKYa?2(Qtw=hC z4o#(@#OZ28(|SVir~3x-fSZZzhSNxTA`deR=*8?L-e6g_cd-^{h{@39sB{@wx1+C&_Wb$)|sU*zI5)1UC&J??-&eL+yD z1K2%0gA;>xxJYavZdI6$%RAo0`~AZ~tHwnDZEu1iqw~OZK{U`_auwGsWr1hDlAu=J z8jw+Uf&MCWSQTgl@AB1PYr`{;KE?(s8Ug`*W(9b^EFXNVFoYK}LSe3I3><$H3P&PH zs8tjVGJjS9*?=k_m-zuKe!3mL+SdSsJ+8uDkp}qfN(ywT>j3-Oe}lr^zrmmg0tagA z;7bP?;(6I@;_@{)qIlaw_$P%02Ud}=@gNDi&qcuy7Zqa0Hk5dJHJ&hAx{VO#0AlQ^ z5Bzu}8@l{urFG^5IP^4vNC@a5p5OgINJ;e*QHceF>PRhIGVm3~O#Xc?;lx(0A>!f@ zd(tv}Ik~{xiA>!jLtd{_Ct5x%CSF#05hYuT2z@;-GDGn)`Kjj-`CYn=G`Jf}Mj(kq zR(uC>F8vBIOG1&HobDz|?l@2>Tl}fpbLUf!--}X`4l_jf-Ff8f9t-lNY$oY~tfmTj zUQu+07;R(mk(y(hMQQX!leGQ|@^SNhva8gHIcFp^H6mG^ZOgg99<$$@3ve|BUk-t$A=ea-*I7P*LzJy0oP-K4YZl?i&D(Lj{^TG z`lkX-VFlu!v)WmK_cqJDE?gzIW1gp?PqRjq!;K3x_gW}u z`IU%hZQQk5W!2qi)rt?_)VGBuss5SbYxtTB=u8JS8DyMMFf_RQ+d%HOiSAf7raPe@ zuWyknqUWP=P~UfBqjA9-A9mHx9QKHMG@Ir5%DCgtF5`sV>rK_y?J((y-D@hkVkf5{ zj^+^$f_bS4&OD19shs)D2eX{S2yR?i4@XTRje8G2&G-KGK~OKrLOvb&B?z=X&u=)V z%y*q@DcHKChcCLpOOV2Sg~VTIM}L+)MeDMzqt<7>A(b&s$hI~UROI*&(jH=oUR|&e zYj`S$#|&%Zcecpm)7HDNzTOAuVe<&gleEVww`O5qly~A;-JkGoM`7^VVH`i>6@%9$ z4`ISjeen`E8dogehu4i5gO=4PK-)YU%*sgu;DrEuCJXURRljj=)e!#UzB;JLJq1Q5 zW`H)3gxkR%;P|!{*3j4VPcuu zU*6e@67td4V0#%GzQNW)`OnLt+2u6&sY9BeWEK&!JA#N_*QLb1N^K%ruoDjKsDYkM zm2gC45Wa}oL@50@Pn1jEA&x1u5?AaK33co?>={rd!WYO9673d5;mt1MSsI&UyPA{E zBYbkI^Aq9ukVhDQk0j>a+eT<-94D*|tjP!9D0wTchD5bbkm0mHSs$H82(w-jQ6W!= zcQ;f>KTacQ>ZwbulfkGMEhDNmzMt$Zks-}B{K%AGchXTJoy-WLsoQJIsQ9D{)P@6< z)S6w(DXV3PWRlA>aslfedAnSm+J500^>}Cw?Lm6d+Yi~&`kJ4p^sTZKwPr7Mh_!}l zjVz&_d+nqRU4)p6Iw}lTOok~>%cIk?vnYeD!nD7{7cxW7d66VMbsE^SUOT zQ5`d8oP>1f&v+VLd?%9D-PJ@l#8XVg_eIR=mL*Kgy~T{Ev^7J4vvi#3FnzT03BA30 zgnm9P#~f@FFmHwkM%V{u7CCAB$HRZ%^Dm4i-EWCEDUGsjhGxiV+8&VG(lS@#OKp`@ zXp0=H`jPys)ypr*{?w9JX-jI*bfpk2rEkVswrNQ!*R9{HR#+!!tjj1@RYjvTc8`kb za-9bZLN*|VYs&Qv%WRx=Jsfj%Bd9_BDiK7_Wy>vn)pt*f-G%qFr6m&Fr2i2cd6qgGIduLx|A>Vr|LbUiVBRV@!Ah+p!6_Xnl>KBF&1wq2@Mex;8hp>6=ikQ>K8tjEs9EP|y zW06m?@sS!?u+UEfm?|rRl9NTalGSYd?7F$sxZ-NCAw(alcWFXj#~z?o;tK-joB}Ofhr!y3W?;A) zhm*)IDBK$l-IJr>gC7jU)?ES}5_0fHo+#99)q}%*S+FqZHrzJc51rn0!^rl0xVlIS z_TvFik>v^9?e{_B>KCy5pf)jyvWabT4TxdhIQ+JDGyFRQh1|emnC9C8&jteGXkIjt zyZ8WMb1IQ=FPuj#)2fI0l~P3VSs|iHLx*U=3W#op*TiJeG|^{1K~TY`2pvle;-lLp z!u_xxku;be`1jRM_@qR9q{IidPOGk=ZRI zH|;c8@VlR!dnAH-{9%B~0~6G~hp(tU^=vAm@j3ZxcpkN02ce!jt)!MLl%$(pY^4hd z66r%O(RA`5T{=W)J!SKEqeIV*R%*cED~0Kl(4v;=%=3+0#=pXdiHo^NAKgDmJu+WU z|Fn0b)1>3+^%9UdR+7P_oy=nT=VdVkmdu?^%b0{> ze?~`lC6jG!&s_KHrFEIlbfEVeT7BCDy)8+LsnW4xBGeq1WN%w0E7j;f9{vkC_>ZJ3 zZ+gYAO@3fW1Rs|Bz4wTmh_0K&2UMGy{2HI1u zdM4iQ^^YBRWxRMOmTg$x!gfB>$gUkzG0BshGCs0q%+&P96_d2n&8Cmk3OP2S{ybT? zY+iC`8c(^tj#Ktv8ONMG#=Ufh%`Fwv-(m8o1N9y??2*LGIAU1v5-s$LWd)+MJOkAo0ciNwMAXqG8{6r~$4~gq z!{5BLz@bVp_OMle@h2Z)#~ll?z)#(nTXQ}Rq!huqY+c|#r3D&wPT;jQG;S<@9{-b( zg+s{(T=t_Ih)+EU#;%$iqGvj>5YE(-UX>B2Q) z6g-t%0KMY7VaB!RQ0esmv>YggYYfeyMoKEw)7}rELne&B@DYj>8~p7L`2>GAhZxNM z0k71g!wn%1p~vqlFfZ*f)G3`y*eE0rb6;f=6M}T&>>npW+UglhfH;wIN}s6S#1OBS zog}cyapK))VbYTOhnOm>Ce$UZh&0;*;>?>A!t&NpqE%6q)Ze_4WS51JhnH+7XFKYV zDJmz4NmCiJw_uXcOP428HB(6ujXqL3^&M%t`4yQKe~2``qE7b9#*!;^){*1Q3FPhX zv#8#^zLctR2-Wg!J+-1+g{;N%qz5`O`bSOv`4`5OZ=1wFln=1Rkqo)FOrhN7<8~6`-6qnbmcDYw zUEj>I-}Y5@baIx8zWo`^ax+BB^bVy}a3Dpcq|8oD*^tpJF!`ujJX)-wcJQ}O9;e%2 z9S1S&^8|*xl`gtVU%%2-=yoif0q%D6hV!z~#Teu|XI zs*RFtT;#5afAIy=d2`Y^dxBhf?iESA=JQFs6BFee=&+G9h>G$SxntaQb~m|y9$e*f zAB!TUpN)_&wMNL+#RGh?14(?;sZp@S78M+7%oF@@7DENGkI;RAztLWy-{>3*c~oko z2B~_SkN#A)Km%G6Pz#MjOv*?H_um2VLp19~!) z7=YqRK&@B_ENIEY-OpL$2kYAL)Q~)UO0^FEX=@GC>+`^wB`3hskTQ_Yn-BgFLLl?n zT5!u|F5rAy2CBDR2g&nfVBc+3Xk@JhP5p0zy?8uWS}*_%t1p2k>$*W+79TF$y&95x zwnF=pTj8-QJm{YA3Sb-NK<7|n$ex1GbMOFMJi7^=X}b!^iEGfT{Qz8Z)f$GJ&VfU2 zaWFh99gd_8K#8}1zh}eMiA((&L?ZPRK9V~KZ`Hko>-=uPz#orbbdi84d>Bk@uiZ&p zo4cFPiu?P%W(00HWldPkHzV%IP{e~9xkTCIU7{oNDG|HrIdLQ;kN99|M|hN2TAH99|skj{ zc;h-LCKg4aembPxU^?k@dpmjKSRDDm=o8uIL{ZNu2TH4FJ{1-=MRt}QA{}B_)GGLy z9B>z*6#chRE012LRxaA`o0G{zpR-|hIbNanF{X^^2|ebTpCL2jZpqY4cr#YJeHmM1 z8FT274fAgHQ(E-C5OYiG8@*xIFM527CSx~4FvXwEnLcR2v;^t=$HRXi2mg`u`sF(D z>ZTf2-0&tjrOOF&RXh`kRY#I!@)C~AxrU}lPQL4qP3`McuKAs+Su=T1i)+=1ixo+B|NeM&6gJI>~5-L9myC;ab6L!`3veZr!2}x@PK23{=Kf>3z9; zN53)oq_N>PJ2p%0ARE75z+P+k)_6mks7a}*B)h`ms>z>ArKXNMR&&y?8uMNo1@Ioc z+Q1WDoXRn;_Tv~2%y9MI8FRI7RB@d*7xPcwc_>JWlt9kf$snqrp1(46A79w_tUy@G zQ1C}5PSB?F2toX-Q2Q_U(2TTR6cK)pR4zP*BzI?_-r;anPhVBE3hA%44P3}4^z6=!YSiQB~paM_+l{IpXl zo>x$W*Phn`txvIe|lCA4_#ZsYdEV^K9lzOT7mTI28o__bF zpH}dkq9#?Tf~)n+v_5?rtypTsyiC8G53$l!L_Z@ zd(>lPzqdvxkILI?x(jz{+Qog=^zP@WkUC{*PL4jBz1u9+)=JoE#2k#$nNHhi(EGZ} zpiJVuf!mp1I?%LBw<5{PU~m?qr}Q~bA5mUq?Aa#Cj#=l$-e2HYcJ`oP zd--JnXW2agM?8jK88V;WX_F<`R4OW{>~IpiAI(LSDnilPQ`u$bqFqi130$D48$xn2W%H7kZB z-!2W3-pGN?XO{!rtvLW>mVl=FRUpB2B~WU%06~9FfEni`ka9Q?_|;zoXT&~&oXBb5 znl=mi3|;^a-<5#f4U+Jz&MQ!FJOsR7sKO+MfFCR^;r7i7AaYw4_I3-wJ=H!?DvO4` zqBxw`8wlM_B|_092Vmp%Ja|uR33OxZVg8v?SU8pp^@3xem30~1OWuIqnO$&I*B~6B zjz9xW7BmkNCeC&|h7Ak5U~r2h@%DiUVI9dMcJwfWMcYppDKrk>`K}-WBN$?ILO?8d zyNFM||apk=km~WL2LUNorjo zJp3Dp4RR!D8KC@^k&KY>l}D+k2{lx;ax2A4ccG3* z38={ao74iABUDK6K}sl$MVp%@($R&*w8j21ntMfs&Og{dNv8PFiScYYl-8o_EK=y2 ztzT)MQW-{dt{M|)bbubcN(|1^&$re{+9=ugzjyw_mkB9#<4yvxX`9DR!U3Q4YNh-0* zH+8YLY!UstbSqz6#!Fw;w&0muw5+Dg*I$ydV^3$4VohFaY;oSJNyrsxa=-N{?{!X9 zduVB=S!%jlO}c+X-FS(#j_^5YgL4)84Av#*8AQ1q(MkH4rmN7YWRRi6(#v{psjqJ` zWi&&1akt@;J&Xs)qocs0E zFSFA*ug%`>FXZN5YUWIQ=W?qPh4^)v0>R?VK?0S*Xu1g|!mnkm1;JV7!1){>Nbgz-IwNAi;FDCahAskD+dY8t8E@e6`aJm7kO#(QQow>U zCqNB)2@GGq4vPLf18Hyb!D^ioAUIDRT3d|+znnf`xa=Ev_D~8=qH?gSQ5WLqGoZ5K z2ROKYF?6WG;kh9lSkQ?6on1S?J9@4#;Po2VVW9_0oFGKcABC*dv2gpUb#T{{IH;p~ z5IU{QfwS^YK*jt(c&sZK?$H$|&SH;Ym{$vooO}$wH++Xh!oT3#Wh|mjs~JjNABAVk z*Agi&8RD>>9!Snt=*u2Rk@>bLlXToert#}Qxr&fsUG&LYielI3xIs(bCgeX$wvH}_2&m||P zI>@QDd1UYGNYX5zj=WJTP3;}hqPjeIR7p(*Y1mXvrmyy=j&+(*SC=SKO{wveaEmbg zBVU6?0*vVuMe)?I2~P1!hpBtlDyd#hIwfcElCrm+OXC-p(rv9<=@Iou)avPGDtmkz z?UzH*-Q6m5?2I4n{oxE<-F1cjVlqf?JLyX6JanPo?|VU)t-DFj#Fx-o$TRxrSy5(T zni#X8RGc}c-ua*Z@PG9AcO--JjsLgDCNj5Nv^FzYwm`*|<=dIcn!8O~oO9-u%!l=& z@&U=tG6Ub2%RET8SK71DS7UencMavI#+pUZE0w`5UA0a`OY^)ztlEt|Ug|YR)@w&v z#OQBie&|z$dIp+F209_96?N09F6rlJP3Q_)wd&0-^f#(FsAf8=W4CG9`65%tqCTV1 zDn;X=-bJST$I2$9&BsmDv`oxSG)!~OowMY2Gr`<#NA{X+e74K%cZMam&@Gr#@wkyQ zj~B)puPEg&Tlkdk<0vke+EdIET=~22#pX9ZckfDm%%(KH23aBS>Wo4Bo68XIvKxrZ z^i9D;MZ3T#`#y4TbRDu_`#!|}5Q-LWZ$&E}kDyiJQrO5V2XstqKDsbP3%lKZ1D!7D zKy@z7!OD&t#U^x`urk3@OmUVAHeKS4sbC`bSxz(79#V-Z?4806rBe9TQg?h)*fxCF zNeuV>rhr$^&&6-0uEF_JPI$(Go%q_45`5LAb2vNd0Ulw!9}mdPz^enqfOF{sym9y( zo-^EmZ~6Kje_k&PdIB}TN|EchU;S&m;o2hbGk^>FI#?hmLk>K7qXX(!n*qAW5zHwT z2ko(Zuy=VO=u?USej6A5^)@~=?M<+#=PuAR{045Mm4Uv6 zKS9c|J#fx@CrGc;f%Y4fVd;J)X#PhY`W)s%Y-Q7L|9i(IB3Ob**-#3vG|Lfh z=A0nXo%a&h4J*P$*@+0s+ey4viY3^K3JI6ZMuazrC7O2`l22N`5I-C)5M%5&M8ZQz zjxAe2-dh|@>f7HTIyJ?}W8Rm@`IAW`^?fm!0-MR2?F1#f)RS_k*+iL?oFOMf_K;B} zC^hkPhWz@dnM8j6CbyKjQ8OEYDF0uH6gm8qjEceFfjoJMyJyKjV^>-H+j9K-1u3Nh{?yn znaxF9xE^6yHxVaE5Ad#m9DM%L z^|-6z7M$M^kDqO-z`Lgc@I&D(xc+Gfh!GaxZ0f*OgVS&w^JM(HUM?;d(T?wV6@}M? zP2qPp?g31IBX~nffN`G&+$r!R?x4_si(0(LdmIYzyDjxT0~0A7#;te)%y4V-wOA&CMhd^Q-&F#yIkOM%}yaj+nu2{7!H zP7o7$!Q}&>Ag%-5bzY3S-WkD?kbLi%y22(sRcz*jF z*mhwP6r24RSQR8e4coay_(EyIX2UsnI^Ze{2+|<7v~UQ&z3#-G{6hG=MS_^~Y>4nS zJVG?tcoSOuYU0=$6S929lJrUrAca=s5V>~i2%$v`88b(Sydrg!IFFqt-hWph%{2|k zPL28G?#>J%sP!>1^W`)dCJ{oWxXX~Ybtj3z%lhPxPdswPa3E>=w4TsjW()snR|6kuq=3jLN76 zEfL)?J|@*U*~e14dR}IHi=9+X%Mba^tA1+Xx*F%OnP?1q?{ z%BNV>Yi%}KSN6x~a`RR6)^$Yb?HKo)J<>yJ*M8ch*A*%*?KCOW;JA6muuPO>mcQv*m5}@8CRKsKzxJt>oQ!s>R#)LX3A*w~crC zM+9HDZJ5U3QgQ(S^eAKq^5*jgE2CMsc0Im9C zf+;oEV;jnoF!wkFYpHpI@}9gvFMOJX9o^-G8J>88Cftj|xYxw+G@pA|(}HNM(?b_? z^i#wF`vq91<$f%9yD}ye+lUGO;o+GpB=Md#71)aTwpeHwA4_X=#lVVO>~$u@hOWQF z9{alDU9>U2IrApA`{xR5rpX5LIkg(w_qq(L3v$KQKM=-~YPRF=Yc28W#245@moV&e zraRVVzZH8ZsKqw@T7iWOD&QwMNANjyYws85g5zY2fJ?+fmtoOfDNx)kNK4% zxX9;Tyu-H$cTs2IMGImvKhFS+FpR_2w_V1X{)A!mLz{7%pBg}#?#J(N9B}@ReC$fm zVXRZV1}lCdiDNfXFxwjyc&=gsU>&1C+vB77oi-bMUU4E$d*hrFp!-MytY4lBuz)l0V!$%Ec*9rVw%#7jzFGsH zrgp$L52xSbhC!yX@JqWoEZVgX_Qs?@d_e=0FCGBB&6e=pU7EOF z@E&e{Hy>`ABMB3Td2q)$4|wBh2K>-o2S(^Bc;IarvHY4Bam273?om;K_0jrJ--`n^ z=0w1?!&TtlM}hwo{r?KQ>Y5|DY-^m<@+eaJYhsx23U4t<)9ggqMvI@)@f#Cn_0(Ko zz3Wj_srArOl?lGDs&(yzG3IG zJj2UwY~$c9M@=+k>`Y6+cT@Y6V&mA^F($LmJ3K*6KNX{4qB7{f9!+GU#A!k6r&&mG-C-oJYDUm6vRYOsU`(`m)9wor?EDUQWLd zd|Qqogwb_mkq3&*Y_37WEiC^siG{tN9fHa|Ta7T`p9CRO7RYSxhlsRz8>TcibMJ*IzEjCJXQSM0{;0iJB6==08{HZ?jBcLNK%H1D?ALNre5-pacC?Jb+^;RcJbeyf z$+kt!(Ve);%jwgygLUXS-DRpRHns&NnB-}o|NMLcU~6c%v! z2Y$yk8b5Kc7yFZ}jdR8W@#D@L@Q;g5;V1w8N1oMs0CSF(25lG8aF6L)?2LRjR_&{R z3&|+sUv!q>iIUM+ia|YA?QRQ<_O|1z-sfRr&7N3UxED5k-5$$#%*NJaeMA2b#3&fD literal 0 HcmV?d00001 From afdba230327e2f0dc6a2ad1107020a9dc8001609 Mon Sep 17 00:00:00 2001 From: Henrik Andersson Date: Tue, 24 Jun 2025 14:38:00 +0200 Subject: [PATCH 3/3] Use mikecore alpha version from PyPI --- .github/workflows/full_test.yml | 2 -- .github/workflows/legacy_test.yml | 2 -- .github/workflows/notebooks_test.yml | 2 -- 3 files changed, 6 deletions(-) diff --git a/.github/workflows/full_test.yml b/.github/workflows/full_test.yml index 4483ffd0c..54669db7e 100644 --- a/.github/workflows/full_test.yml +++ b/.github/workflows/full_test.yml @@ -34,8 +34,6 @@ jobs: - name: Install mikeio run: | - # TODO remove after release of mikecore - pip install https://github.com/DHI/mikecore-python/releases/download/v0.3.a0/mikecore-0.3.0a0-py3-none-any.whl pip install .[test] - name: Test with pytest run: | diff --git a/.github/workflows/legacy_test.yml b/.github/workflows/legacy_test.yml index debbb72db..39c6fcc52 100644 --- a/.github/workflows/legacy_test.yml +++ b/.github/workflows/legacy_test.yml @@ -22,8 +22,6 @@ jobs: - name: Install MIKE IO run: | python -m pip install --upgrade pip - # TODO remove after release of mikecore - pip install https://github.com/DHI/mikecore-python/releases/download/v0.3.a0/mikecore-0.3.0a0-py3-none-any.whl pip install .[test] pip install -r requirements_min.txt - name: Test with pytest diff --git a/.github/workflows/notebooks_test.yml b/.github/workflows/notebooks_test.yml index a48e05ac5..9b09a5e62 100644 --- a/.github/workflows/notebooks_test.yml +++ b/.github/workflows/notebooks_test.yml @@ -21,8 +21,6 @@ jobs: python-version: "3.13" - name: Install mikeio run: | - # TODO remove after release of mikecore - pip install https://github.com/DHI/mikecore-python/releases/download/v0.3.a0/mikecore-0.3.0a0-py3-none-any.whl pip install .[test,notebooks] - name: Test notebooks run: |