From 97ecd617d039b794b82ccce293a9257255f7c4df Mon Sep 17 00:00:00 2001 From: Dave Kleinschmidt Date: Fri, 31 Oct 2025 17:28:03 -0400 Subject: [PATCH 1/5] First pass implementation of fixed scale offset decoder --- .../zarrita/src/codecs/fixedoffsetscale.ts | 49 +++++++++++++++++++ 1 file changed, 49 insertions(+) create mode 100644 packages/zarrita/src/codecs/fixedoffsetscale.ts diff --git a/packages/zarrita/src/codecs/fixedoffsetscale.ts b/packages/zarrita/src/codecs/fixedoffsetscale.ts new file mode 100644 index 00000000..1b6f3707 --- /dev/null +++ b/packages/zarrita/src/codecs/fixedoffsetscale.ts @@ -0,0 +1,49 @@ +import type { Chunk, NumberDataType, TypedArrayConstructor } from "../metadata.js" +import { coerce_dtype, get_ctr } from "../utils.js" + +type FixedScaleOffsetConfig = { + offset: number; + scale: number; + dtype: string; + astype?: string; +} + +export class FixedScaleOffsetCodec { + readonly kind = "array_to_array"; + + #offset: number; + #scale: number; + #dtype: D; + #TypedArray: TypedArrayConstructor + #astype: A; + + constructor(configuration: FixedScaleOffsetConfig) { + this.#dtype = coerce_dtype(configuration.dtype); + this.#TypedArray = get_ctr(this.#dtype); + this.#astype = coerce_dtype(configuration.astype ?? configuration.dtype); + this.#offset = configuration.offset; + this.#scale = configuration.scale; + } + + static fromConfig(configuration: FixedScaleOffsetConfig) { + return new FixedScaleOffsetCodec(configuration); + } + + encode(arr: Chunk): Chunk { + throw new Error( + "`FixedScaleOffsetCodec.encode` is not implemented. Please open an issue at https://github.com/manzt/zarrita.js/issues." + ); + } + + decode(arr: Chunk): Chunk { + const out_data = new this.#TypedArray(arr.data.length); + arr.data.forEach((value, i) => { + out_data[i] = (value / this.#scale) + this.#offset; + }); + return { + data: out_data, + shape: arr.shape, + stride: arr.stride, + }; + } +} From 53a0e3b3f14bbee5f1e0febde3916ba1ca22db4b Mon Sep 17 00:00:00 2001 From: Dave Kleinschmidt Date: Fri, 31 Oct 2025 17:34:19 -0400 Subject: [PATCH 2/5] rename, add to default registry --- packages/zarrita/src/codecs.ts | 4 +++- .../src/codecs/{fixedoffsetscale.ts => fixedscaleoffset.ts} | 0 2 files changed, 3 insertions(+), 1 deletion(-) rename packages/zarrita/src/codecs/{fixedoffsetscale.ts => fixedscaleoffset.ts} (100%) diff --git a/packages/zarrita/src/codecs.ts b/packages/zarrita/src/codecs.ts index 82e35a10..7d6ecc1b 100644 --- a/packages/zarrita/src/codecs.ts +++ b/packages/zarrita/src/codecs.ts @@ -2,6 +2,7 @@ import type { Codec as _Codec } from "numcodecs"; import { BitroundCodec } from "./codecs/bitround.js"; import { BytesCodec } from "./codecs/bytes.js"; import { Crc32cCodec } from "./codecs/crc32c.js"; +import { FixedScaleOffsetCodec } from "./codecs/fixedscaleoffset.js"; import { GzipCodec } from "./codecs/gzip.js"; import { JsonCodec } from "./codecs/json2.js"; import { TransposeCodec } from "./codecs/transpose.js"; @@ -35,7 +36,8 @@ function create_default_registry(): Map Promise> { .set("crc32c", () => Crc32cCodec) .set("vlen-utf8", () => VLenUTF8) .set("json2", () => JsonCodec) - .set("bitround", () => BitroundCodec); + .set("bitround", () => BitroundCodec) + .set("fixedscaleoffset", () => FixedScaleOffsetCodec); } export const registry: Map Promise> = diff --git a/packages/zarrita/src/codecs/fixedoffsetscale.ts b/packages/zarrita/src/codecs/fixedscaleoffset.ts similarity index 100% rename from packages/zarrita/src/codecs/fixedoffsetscale.ts rename to packages/zarrita/src/codecs/fixedscaleoffset.ts From 2d3b27da2fb0c0d6f2423d8d61088413e9c5cdd7 Mon Sep 17 00:00:00 2001 From: Dave Kleinschmidt Date: Sat, 1 Nov 2025 14:35:03 -0400 Subject: [PATCH 3/5] fixes --- packages/zarrita/src/codecs/fixedscaleoffset.ts | 16 ++++++++-------- packages/zarrita/src/util.ts | 2 +- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/packages/zarrita/src/codecs/fixedscaleoffset.ts b/packages/zarrita/src/codecs/fixedscaleoffset.ts index 1b6f3707..be4e4ae1 100644 --- a/packages/zarrita/src/codecs/fixedscaleoffset.ts +++ b/packages/zarrita/src/codecs/fixedscaleoffset.ts @@ -1,5 +1,5 @@ import type { Chunk, NumberDataType, TypedArrayConstructor } from "../metadata.js" -import { coerce_dtype, get_ctr } from "../utils.js" +import { coerce_dtype, get_ctr } from "../util.js" type FixedScaleOffsetConfig = { offset: number; @@ -13,14 +13,14 @@ export class FixedScaleOffsetCodec - #astype: A; + // #astype: A; constructor(configuration: FixedScaleOffsetConfig) { - this.#dtype = coerce_dtype(configuration.dtype); - this.#TypedArray = get_ctr(this.#dtype); - this.#astype = coerce_dtype(configuration.astype ?? configuration.dtype); + const { data_type } = coerce_dtype(configuration.dtype); + this.#TypedArray = get_ctr(data_type as NumberDataType); + // this.#astype = coerce_dtype(configuration.astype ?? configuration.dtype); + this.#offset = configuration.offset; this.#scale = configuration.scale; } @@ -29,7 +29,7 @@ export class FixedScaleOffsetCodec): Chunk { + encode(_arr: Chunk): Chunk { throw new Error( "`FixedScaleOffsetCodec.encode` is not implemented. Please open an issue at https://github.com/manzt/zarrita.js/issues." ); @@ -37,7 +37,7 @@ export class FixedScaleOffsetCodec): Chunk { const out_data = new this.#TypedArray(arr.data.length); - arr.data.forEach((value, i) => { + arr.data.forEach((value: number, i: number) => { out_data[i] = (value / this.#scale) + this.#offset; }); return { diff --git a/packages/zarrita/src/util.ts b/packages/zarrita/src/util.ts index 3146cccc..c28912d5 100644 --- a/packages/zarrita/src/util.ts +++ b/packages/zarrita/src/util.ts @@ -119,7 +119,7 @@ export function create_chunk_key_encoder({ throw new Error(`Unknown chunk key encoding: ${name}`); } -function coerce_dtype( +export function coerce_dtype( dtype: string, ): { data_type: DataType } | { data_type: DataType; endian: "little" | "big" } { if (dtype === "|O") { From 757a90e14a0fd810078ea88f59b81219a7643ab0 Mon Sep 17 00:00:00 2001 From: Dave Kleinschmidt Date: Sat, 1 Nov 2025 14:41:34 -0400 Subject: [PATCH 4/5] eff it lets encode, too --- .../zarrita/src/codecs/fixedscaleoffset.ts | 25 ++++++++++++------- 1 file changed, 16 insertions(+), 9 deletions(-) diff --git a/packages/zarrita/src/codecs/fixedscaleoffset.ts b/packages/zarrita/src/codecs/fixedscaleoffset.ts index be4e4ae1..49b61df8 100644 --- a/packages/zarrita/src/codecs/fixedscaleoffset.ts +++ b/packages/zarrita/src/codecs/fixedscaleoffset.ts @@ -13,13 +13,14 @@ export class FixedScaleOffsetCodec - // #astype: A; + #TypedArrayIn: TypedArrayConstructor + #TypedArrayOut: TypedArrayConstructor constructor(configuration: FixedScaleOffsetConfig) { const { data_type } = coerce_dtype(configuration.dtype); - this.#TypedArray = get_ctr(data_type as NumberDataType); - // this.#astype = coerce_dtype(configuration.astype ?? configuration.dtype); + this.#TypedArrayIn = get_ctr(data_type as NumberDataType); + const { data_type: as_data_type } = coerce_dtype(configuration.astype ?? configuration.dtype); + this.#TypedArrayOut = get_ctr(as_data_type as NumberDataType); this.#offset = configuration.offset; this.#scale = configuration.scale; @@ -29,14 +30,20 @@ export class FixedScaleOffsetCodec): Chunk { - throw new Error( - "`FixedScaleOffsetCodec.encode` is not implemented. Please open an issue at https://github.com/manzt/zarrita.js/issues." - ); + encode(arr: Chunk): Chunk { + const data = new this.#TypedArrayOut(arr.data.length); + arr.data.forEach((value: number, i: number) => { + data[i] = (value - this.#offset) * this.#scale; + }); + return { + data, + shape: arr.shape, + stride: arr.stride + } } decode(arr: Chunk): Chunk { - const out_data = new this.#TypedArray(arr.data.length); + const out_data = new this.#TypedArrayIn(arr.data.length); arr.data.forEach((value: number, i: number) => { out_data[i] = (value / this.#scale) + this.#offset; }); From 6e0129b76b89e515dccc67c9e90c6e1ab83143bf Mon Sep 17 00:00:00 2001 From: Dave Kleinschmidt Date: Sat, 1 Nov 2025 15:22:34 -0400 Subject: [PATCH 5/5] basic test and fixtures --- fixtures/v2/data.zarr/.zmetadata | 64 ++++++++++++++++++ .../.zarray | 32 +++++++++ .../0.0.0 | Bin 0 -> 34 bytes .../0.0.1 | Bin 0 -> 34 bytes .../0.0.2 | Bin 0 -> 34 bytes fixtures/v2/data.zipped_from_parent.zarr.zip | Bin 31108 -> 34121 bytes fixtures/v2/data.zipped_from_within.zarr.zip | Bin 28380 -> 31193 bytes .../@zarrita-ndarray/__tests__/index.test.ts | 10 +++ scripts/generate-v2.py | 21 +++++- 9 files changed, 126 insertions(+), 1 deletion(-) create mode 100644 fixtures/v2/data.zarr/3d.chunked.mixed.i2.C.fixedscaleoffset/.zarray create mode 100644 fixtures/v2/data.zarr/3d.chunked.mixed.i2.C.fixedscaleoffset/0.0.0 create mode 100644 fixtures/v2/data.zarr/3d.chunked.mixed.i2.C.fixedscaleoffset/0.0.1 create mode 100644 fixtures/v2/data.zarr/3d.chunked.mixed.i2.C.fixedscaleoffset/0.0.2 diff --git a/fixtures/v2/data.zarr/.zmetadata b/fixtures/v2/data.zarr/.zmetadata index 9e21c3af..82fbc2fa 100644 --- a/fixtures/v2/data.zarr/.zmetadata +++ b/fixtures/v2/data.zarr/.zmetadata @@ -472,6 +472,38 @@ ], "zarr_format": 2 }, + "3d.chunked.mixed.i2.C.fixedscaleoffset/.zarray": { + "chunks": [ + 3, + 3, + 1 + ], + "compressor": { + "blocksize": 0, + "clevel": 5, + "cname": "lz4", + "id": "blosc", + "shuffle": 1 + }, + "dtype": "4GB#JVH2BCpU zkxEpOG(JuI&N1DyUC!ON-~0aYzW4c@o~O^}`Rwmm-?jD{_E~$GubRTj#f1K1gGd{P z{$u11E+#Q1N0Ki|DTw6ly})W6C)1RG&Frp$$m18l&BV<5otcS=RS5aN%_m($5?I4M zkm&5~>E}iCclC84`goBXoP4MYql@D%OksJ`uZh5+j~xAlk@xoX_4XNi@d?)7$wfqd z(vD6(4&JU_zOJ4g(pp4mUD~%Kx_S_OU7Uy>BzGriuHB%(;#d3!3CKI457c`NkpS^t zDDhh;p5E>xU*x@1$KxV!V?P4Ghnl03gNvVso0FrGt14ZFQ5A9wsXs~hlhJwPZzM#s zpz6RChfIPLh$n)3d?jC~GEZdRQnq&~VOe&u8j{rn)jDBeE*WtdfvVEdd-K#XPk+BV zIOwX~r@Fqv?b#xBrKdXeH~4;1M6Vf1xL@lvCY-!&+kKoPBRA0D(QL8y3zUwzh9P_z zYo8Rfa5JBtK6{gu#I?EAYqxEkFB??toGkm%lJ~;Wo13fzz7c1T7pq>rEiJ(p`lle> zAl7`X>>mNI-$ADLR*GJDz;dgAE7}IdBkyu zRaH_^QXL~=O{0$n=rzloI$Imi$<9Cw`PWX5W=7q0IM2h_HnX^mpZt^ z$-;nQglY88Cg|`T21c0?{dd`q*Uaj?%sFr{3}}WzBMtN8X@_B8P!|BJ8DbY{yfm$f z($X+6sNaOPGhrG}({ML=1`G`9H=(7W(0Ce=J<~X0U{GnGVT5Vi^YSjC7#J8-H_)VY z(ZFzSZrK0>gOUafL!mK&m}MOiz;1_li_(7H*Y@d9`Fes70?L46uD424FTxL>h6Fkt|VX|TFc<{cLX zYIV)pU}Ql<8Y~F0i^d16W6CUpfk8C`ZO%zFVPI2qfG-RTYG=@z5gvh=xVi(=dljT$ z@bvI?b@uc0^HH)=QBxv2F;F)!_vb5~LL$EgQa6AV(1Z&^ln;J!1xWe8AL*YF`n;YP z9TOJQ*x|^Nm%|$#c1+tuI^4h5J%304sqa1hdw*T9{mAao zhso-l+27_@PC4-5>c+(C(pPn|`L>y1bwUTppQJl1b*oBi^=8(n);!;E?*4*AW{>^_ z_r3;29{p0Z=a` zO1rK$7duc-$c*;)6nyahRH2E4=h839v;C%Ay0ZJOm#O5-zSA5RoQ2sQ@@609UF`bP z_|poRjUJRYUK#G2vW^L91+-V&`P#9jaX;xl^|{HQ;JL&3b1iRY9%Me>pR{$?G^wsr z3+_*CBPJy*7v)>rDJn7JC;7TTY?FD;F5Z&8#aD%;`nUYHYh_g#dz0X#E77G=;(db1RFti9HwVsdDq z96{{B>ev&n+EO`NDGzOB<1~){bW4h2e)``HKd-yT`y1ERK0fn=?HO-&TA>i?0YuMj zOSfHDaT@gi#-!lKLf^9-1ia=+y*x!BWTmYxa4T!M#of(O{5L5mEsEfyVZ`GSW@E~- z+nb}>Lg4XxomYH{&C#nWUO(|WurF}%8nXW%Bx$Lz_Z)VY1a0KkgPeHu42Xz4cs7EF zPtQgu0z)>!Mx?Nk<%kq^vM_PD5TY6g0y6ef0Sp9lR^#p(Fmwi_q^Cqd|I^2Tw9Uzr zLh*6(Wk9dH|8{#dAz)Kk(8D+EsURd2gtj9NnW7Fq;zvfP@4Xee8nx+l%8`#$d3nQR z#fe-mKVF&f^Wn|&trz<4mARIh+RvPBySs6}cv#G`(iu_ZSG3DZBg0H*<}gdUpDhwK z_z=0FGke3u0PU2Ny&osMrv8_;KeO}lVq5X?bolO!>mc`3WO@T-%V z{H(95y(_Jkk}}L>QDt9`%1=5b6Lx zaOkK>mN@X^ctl8yZm@2wF8i&=_DwYD^OpzL6UG0xuR}Kx8F?LcetU-w=FhVUorHCS z%LE?6xKyq{=J@xkD34dE^*l;*AA{@d>S+fqkSK zbjIf#A}M;jI)}a$z&Oc>_)4y-p<~vXTY*#CzDl?6;yGkdnsmge$K`Q|=uZFC4Mm~$ zX19$7jxV!SPg&4$pl2g@-3LKRzUpA}#})qfPOkP36KL7`I_K_APLJF`w`PSU?R#!k zSgdBzS(1IxSzM8&Vdu({e9oZxch_zcog;g=BgN@}?fd?vtf>j|ua>TiurcM?EEwJ~ zmq+}W_DznWJT`IW?&KDAh5!EkUitIep%js|#_n3`LGA^%(()0AR- zn|I|i3eSLv+dCmfPC?Avk)Oox9FJ?_^kawN|0Z@UVY3s1j~x?0{Y&g9O8);Sc6bo? zSHs7S2^eH#;~=qP3)9L%<$WqH%3dnBl;5h1-#O=Uu2zk1Tl%4FlGlOVO6=^)t0F=U z=!WXXghc5ctPExzw~wF5s;P`_qToc(#}6K0iLFZgCg)9Z zc4qX`oTRTE=`7+cS0S+jEU_nC7-H900bl4sX}{1ZKD?LFx?u3dpWYpFH!=5pcp_RN z9H;y{|IVYxkG6*AB;*8ZUA%ww&Iz5lwOzD`D=O|bk64X#Q{^f?BlQ5Oj-bfcGc9_> zcRq=wHkj;h_u}%3vu*vU6R}9c%0Opj#1jP`cj24Ww(;d&NQu35Ys4~^k6SLhvw4!- zZhl(m+Y3=^!$&Jkr=+H5YJC_NIT|ZxN}}K9&}18|GbZE$;&}GeP`b@Yq)aU&jL%Qv zEgHH67(t_J+@ok+j=|%1*OGnTqlMwYkgZMc5Oov`2})!nEYTbchYLDcPGKx)qw(1%NCYD_&qWT@#N?=`<-9`f2~Rt)ZDnnfX$cLecj zRYaukU}tnrx47^7nt(4Vv9|HLhAjsossxKaw6TTWsf^J%vS9G><+BFwxC6RtGdec4 zztVn``Ri%zM>|>5X$b=QtpR?2!#hHb{m2%6+5d6=6eAVxub&dD5AjNIl!!^a&gX54 zlg@B>pO#1n-yOcOHK(X?-odN6T5ojaZ&E04FB!00t_pWBiaL5i{Tzo;#kXF|x>sd` zdmKr%3oTPaZ2MYjzO#V(yDv%%LC*~hk%zYE0GOp4&Sz9daRwt9??sy*?O%8+r~et8 ztrE}Q_Of#DTMTP~zI?*`MEN4aGY>^$>BxfZX`vOFkRC->l~t9Hrv;-Gv$_l*$ zpBHs}zF#r}J+3t1Z*FZO$~pHI_VR+}w5CbFYz|^dsx;;_Aq(_e!pKpyA$k;TxqQhY zm3fOJm|1N^!Vf%3}IuU}>6 zQS{6+CUv%*+ixg}r{dJm1Iv--SQY`{dnoXC@T#J^ene zG3i6%@s?Q#0Sd^2=j9Pr>8X^GJmlrYiDr&WVY4}or16}xBrd_xBG_SuNwlmOQK5ry zn>5;Cwi;0(xbMLgA@nzvzb-*L%mfeY@9$CzP>rlFU|T`Tc9^{)z`uBL+lRd0-+wf| zIB)C09pDgYR=v3Vck!9s0vliGM4zzwyK;q_fpz(S{wMt!?KY*VSDVGy50ZslUaCY) z=}G7JTD-jKS*xyFPGGd3L$PjDmUQ$PeAyth37JKYi!%r9#`pGI4#gPW(dOH7aI23qU$RjA! z(1(yU_M=q{5QoPS?+F@9L2pbX1UH;UmPKnfFvCH$4J-;__XkGnwqd)!PVihBsX{rZ zs32shWr%zk_1}EzgUg!UEw>^a&;%!?-68hsF|BvH zqBpx0nw(>l(}emX!i-ioS)Tllqh$B>^D|WX;xrUO-{vWPBXdPwd$JUy;AV&x-)LPU z0UY+xP(a^IC_qg^u_q1N{lr=Xy$l*CMml5vr3%+#=VeE;3-k*YZFWJkFoZU(;_eQA z4BZn^-)b=55BbXFjD8GN)|_=)FZWfs#`Fir8srzJU9E46R^|EBz9uZf?dQI|$Fy!_ zSP6dB6eXQg*KOS+SZ4mEGT(}IS3X~Zg#yczZQhy%hx9AHv52e}ujF?MJm}t+qrXAZ zsO0oUtsfZ<^`_0Yr{?iLi^y!`lX@GTxgo)5wRx(UIcLdUfA>am`~B-bdv2&YY{S=T&QM)M=I4Ff#Xo@iYNMMU|}3JHoZ7qrlxqk^HLsdje6uDAUZwbMxUh+@Pa5 zs(4`s>S&0_L%a2fx~4hu9hRNn!Y`b8MQQL{992%5Au&`AKet=E^DOf6Xs`eU zz@!GqiV*6vir3*oJ`N$@RI@%mXO_0%7p+^K%jKG7=$9(L?1)QqX+rq&&^f;!?rbS6 z&i~GK*8ib>hvkdcV(*`Hs_%%Cb8Xgi^N4+5SN<1Gkl1C`f9#h^4UyWS85E%OQooMK zx@nEM*HgB)>qV@|54EL~2}^CiC*~AhSbYAf$>FcW+2m4lUxRoi#m6tJZcEAK`qots zwcxLLed7=N;kEJQ8fVw_SkKk5?BUIBeF16_+u}(ZhN)K@=;udc{r9vDp4gU1d=UCx zg^V7VND*lpBC#F5cpwl_Z}cVsZGSJe^bhqH-Kuolj zZ;dbS07}rFM!Jrx(;2nMKq7^OY)CX?Q8|2gT(~p*(^CThhCne2#;PJXecbWnv#7^A zL=eejkOwSW$4LgUp@k@@WKO7L6r!1l2|2{vc${nx{A`Xxz(F;LgK(=?JBFC=#|Z+o z`4Bbc1Z{IAGj<`XgSX!{8sV%LdBBbVFrtsH46$4M4vw8}FHyUkJNt zLep6Dh#$?wa-8z#4EA+LY@@uy1Do0P(e_yd2+Vu+nnAx1v3dM@pd_N zr{8z5bV^rNui~4tl>Ja;>&4g}rR9rtfZ4={nWZsg}ds8WDDv zkF&{yr$}yU{E14lNWl*SZ8;frWhZxjdA$40zH_RY-aY58Jy`}uYivCrLZdn=pSUU; zx+@1+2;hOxk8qOS@+`7^eSMGEBKdm`phi9EDrBhA7PR&u7xl8Gg! zGxkB*2eRz^2p45Z*3}hfZNzg!|2z-Pdi3hmAL$cWWe?KCasy0^opj~RSKgL;xRO&o zDJdmk`j(`lYq<_9FXu?g7M^kPeZvA1V>Xf8PM(Jw(++W{PfOO$7mSI1_3(3y_w-f4 z`LQKihrBtJCt;zK!yJex=!56)MtH(iJ2TS3JcWrB$D`tDVq4Hc#x&8faa!m>xQ}8l^)-%~~nexx-5X_#~Fu;+KgZjz!O(*@5Y9C+rblT|ht zZy-hY-MH-QllmW&%~{(6IdLBy7ObC<0SRI*!`2p%hS8+fGi57v9X+7mD+JK8|gT?#A%uN{QCC9E4J_F z1qKa#eo^>5&OAMpUGVWAiGd|n0XorhpKLcYb-cgo_j*BIn?>g3u5oK>;^sG?`DbLTDh!zqu>uqKODdELK-@ zHP$|y+kbzsoTJxX{xMbm?135!rFJdnI#Dp=`=#*AWAv;PtmkMr#Z?`e^o_Qg3``3j zSH`Jr`*n|Z3KLVNHhTVxy?3A#CSxs981kI9)H z3F^&kbv-6Ob@j!q#7m}^nz~A-Y2RL$mOPYpR((`c67achGub!isrULp?kXwtWQa_84$|P zGadA1uSnZFZ4di z-|0Kc8uTLT&+~Ql5i|Ne_!K5yJ=S9n!s2WKjG zeA&VgmmvN&GbZ@k-rxka{|3xlvokjOTmN}J>&UX=9ejbY_sdcU#d_7x8fAQfmp(GO zbM(@k1#AmmlXoiH#vMAoms{r2hx@Xd74-bI3BE1;ejYVF?P=oeW&6mdv$lTGs7P88 z`+0qj^PQ|$CK4qI#}4v5wyud7{Hs~)ZzARw?I0aTwv5rVT+e4h5ErVo%Bt-oEXr_u zX2O0hA+9@G^-#BUM)bP4^#t}U(p?R{^B!OEz0&ib{m2`e*Y^$6ceGx~-0Tpy%C*j@ zJR&sKsQS&aJYHp<&B-gQjn^F)4HdLXx8Q4fRlD?IX8n^wt+{uu|LC$i7{ilwaJqoR z*@27C-afFHZxHcfcdyl=uh~@>J{23SlmD~S&+%REkq7Oco>}s4-c`NU$oa^wYb85> zi<<6o&OaycW#Khe^=yp@$#Yuqt*nYa_R8EZzw5L}$fZ8)ScjikO!uB%EtBTbyGInJ z%p!L(v8Ou-_+0)w&H*E?YwU;TfXUlDeH<7|u@|L8{mn)eM_uDwVAq1aVQgtA2RYWO zf!q$_^oZ4tBgG=OL3xK-H8}i>AFk`IwJloUxu?t1K*TV&Ax>w%Phia647nR0tpuMd zXUcgKvU}(6pQG8Fu-UI7>V4gew+4E_r^OC>+gnt$?u&hvMA|2P#NmCJN(FZv#}D6C z+U2JRJ_UZCBMO+}3_=_ENSbb)8%|DL*+e>XHN0fcj=ThwzAZnjq?g84>o!#8$NU}F zfrI_v34ZgPgax{Ol97*|;DIWLhyIZqns%%8n_{)%?%KUarEl0hl|Sl1tl4&J)t5D) z8nd2ytIdo1vaMUNIk&00N8o!Fw{*w4iVzK};HA-T1blig*Ix8G=w<7f_rZCeivRVR zU=RMg7AIn&(msoCG|05+<6rNRYnjQuZg`@;Te zLw;65$fc{x(d&InE!m_+2%AnU#HoMrau$YqZwi(h)T4@|*FJ?T3a3S|eQJBR$R-iJ zt*%o@CmbUWb0AmtOq)H@tbYIcrMCB;w+2yE+n1;NkHp74cf5jxER_GQjD8xQ&~kxw z&B9BscUbWCMN1~y)@tr+j|pDI$?54fZL`o_As>e#!$Fc{hp>O%>Bj`JQt{fa zy2bmN6`CTW!p)+0U8s~cbjh{8!M17HEDdSaf%)YeStg?IYdX*BUAaC^i}zXU*~JhB zf{_O=Z9y2Ir^2LpXv_FZcBFr*g7@&JTe5m8>hYmQl87RiStO=VQ(XjV?8i0KvX1_h zpQ#r~SebwUYiz><)@Wv+O}?Hau%14!-Xz1;;6T7pYiOT6nq4z7Wrw6Ae^RHyO$dS* z&+yd4SsTPz zeQdA6fq=uwhCxt~vP0OBRGCT_C;~d92C0YPAi%+7SO|9<2=r?TGz2)53=8oH2Lhde z0}TNVB*Q{zv*Hnj$N@_fIE)Mnk%a>>^8F4@7vLZ=ECeSTo)kmVuizlSA!JwxFC2)G z!zDNfZ~_??q6G&6B??*>;Pf#pgbq6%QA3|M;iLd(k6|IQa3Ij3Ezm{_&K<)-a88|E z3Up!*Gz7LIL43>yq7K9h7lHv@fb+(%Qar|iKzBD1cHwjZ&Kko)EJaSL@!TM^MPZvz zK%#PRAW%05Ed@AZ3@Zf>C%zQW5a4_=XzIuK|nz*%Bgh#fc(==>^ZU4V1M zun=uH5U4JoA+QZiphfBPOimOUlAzrnI6(|6MIH_W8j_$P!0BOF2!7;?++;?J>H=Eb z;N&nYgg*`hYEg7_F>wI{798yW1b7-SHbV?NHpnaI)nWMUuy4AKRTzQWQaf_%Qg z!GWd&Pno1xfEQ5v(4rRj9YBS>> z&>1R-zzIxP?CyWXrsL45#}weeB`mfta>U6n>kv_QVy{R942>0OMx}#|G>*X86*y=K zYgcvZ#46KoWlZl2U98Nhbkvq2d5>5cipw)m=eX#r{B6B7gMrX*3z!5%JY#HQq{GYI) z?Ft;&gT*fRSL}Z>G%%CZMcS&Ua$_#qU@r;6`5tgk57w-X(FbABh`>QOSTau`Bbw+4 z#K18HI06TYBZN$*qKgA<9N_dDEKUf09Apc?Zhdg(4HoAM3=SQ6CiZM#21+Jkc>^=h zq0u*R#s&_)85U&NhZW-kFlcDtco{5VSEX9A#+s2^?kM2f2cG_Gl0wx9zH95fX1dbQM@3#T;@$K0t4X|9NU2f zXv77e6PKtJAULrD3$RFjatRm+u;8!`EI=wQ038Xa{ttU#0Y+Bl`Qs({r*J_8W_Aoq zFzjHh@c|e#CTyRW#8^R$evPwLz!ik9HYO$u^y+m02I>SyZfh}~_kyD_u!Ip6v4Ttp z!XRnb3un|*1e7#6CAwI2TorYffTJg{Mtqn)3LQ(PqJU#3uqc1%qx@6pLp3w>G@7zt zJY&@TGCF_)&iR7lC$JW9gDwVx1^`ZZz>-#_Oivs-`k#2)fT2o71q*@+RSe{#;G736 zTVXh>GsqM66E@XNq8nwO>f|CY5UQ}BenEgKwr0zfLr$!K< z7#Dz!1QVOl%rOs-ZoOFxu@YboxzRZaaC;7%qJXs`x5*c0(1^gX1lY~CXVIhrpdU)< z>@=zlz*z)Xgr3O}koDmazySnU1RHf685r0J;LHImLfzyD5X~YJ8xl3@p@yWcft3NQ zWkyE>z*-bIa$s1F;lw8%0tL#ns3L)v{;{O()TA#G9s8ofV6#QglXua;P_L`QG6r7$ z$1~)bwNQ zo;{o|1aH}6^{^hfKt?@60{6!V2$VXg76o2`AI3th49P&3(8Z#o6)FnWZb91i;h>CN ziie{Oyb_P4?InE>25AE?q+@Ao)R~+%>h*Lyi6*9PoTFTdMZrYev9HXrfT zrek@Fhd_ZMjtT}|{l*fPv5dY*424SYrZ*O9)^a!~I&Og~6?m%~3zY&1^-l#5XcGio ztW=ceZ6J#{)c!UEpbekG( zBY}6Rv82t@n_Ld;&1yIt@X|7tuetiTICQ9@+B0}z87s*_00Db_8SmYxy2eHVsj={n zD&d{cFoC$_Ib~JzVDCk+-G-h&vT#mx7V=O^scomSFo~iGoe3bUv=Bz{}}y) zn@OC>$-&=2CDg&!cb@fHE+$q7^IBID@&p9)Ffp@zXJ%qz6GHxP%Sq3W0?zOZA-ec_ z2lx z?CtC6;E%kQIyEi=H~td=_@UvX;^-RS<>Bn4;-*fQ!>9;3hsB>J{MqCj@;3)WvY_a| z6Ngp8Aq0;E&*Vz}2vy#gz9sA*4@c(MB`lJv7E!+=EX+MiVwONvS=mE*jqFoD9t;h+ z>GY|uukd)efJ5cEZtV^JUu3asCX$}lKADM}xM%bJ7-!b$5XYyp#oNx4+vggG^JlGT zE^6dqJ~eIjCTq!SbF0^Ebyt)Pt#(P5?On}xe#xy()&k#&(@9$Dm+#3)@<;qFI%*Ot(HXfPqnE1cvNP4HH?cbsPppjS-kmM{1a3 z&#kw>z^JPr^guI>Obuf=E4U8^Mh$^cg@x&KqK0WCrSF4*QCC6!frUvUQN!>Zy0&C0 zgr*_1KvTnkyf>)Nu|C$fV2D9^1}&OS8e-Z$SQzs|5QAy}tY}m@sA!QWbM%Cxg#p0` z)5xD)(D4Thj4C7Y@3g0ujCp?c95@&TBtxd5hPi3#0T>w61i(s$*y%t`%?o8285kJU zZbIvsFpZ_DdyqaI1_rg8(A1D=ERE={sa!BHC^gV9!ZhYtuTv-<1_qT4G}Ah1V7N9n zZiInBnFb9*rcr_TrR}b8Fo+d^wVPxb71*#!hyVkFni^>HEKEa9Rg}zC7#JiBfTyOD zCJ>meb}bJE26Z;jvPq+{0{8jYC5-T-Dm6CMnaJ_IBcA?X7lCMYYSrIr{M9~ocY z?!=p)#}^fOL}$57R8Wa$LEx8@Ke~f<|2}Wi%i-j4C+l_UtE$#j(=7&MxXHl>NDDi1 zzbjU4XkIF_*Oz$@zlFve z>Mve=i@iaDq|0;pwQP2Z%$BW}_Xx~%Pd(3^o^<;x=iZ?g^CC_+#&D=WcbX z4Kpg3Sa7m$F`SnmYce3;l}BZlkI7dC|4=B|>T^e`5{w42mXVcfgn9D(n;cVR+{`V- z6Kh4Xcs?mRi~(UewV zT8f?+zgCBsqZF;mU%n)N_UrB6_)<8<&O>F;0wz+#x6$>d}jq^EB;_hw-_Q< zRpb%J=Kwvqc3Rq_86hi&$WMo<**4Mf4E>0O9Kz4qkpi z&b~ofnKW_y1JUI5He$DNs!e;iDe7TvIgis40c6RGgo3$0E zPzzw@5Y{C0Bgav|M_&5%NwP>zrg@P^dE;H4_nakzX`z|1B7TcZcwHkmtYq2g%UNwD z(A1^-hF|$v+=_~~%>jvfLWZs(-~Zz@Z8eVW1D;Z#j{JU{myFhch{%JdBMABQbc8H0 ztRw71G8;*bNai336Gsvuih>{@<3G^aU}`ms=P~@Pv6#q(Gzl+q?(cxx7w?csx^D+_vjhg_Svr?&91FE)vQt zb=yr#3%EiRAFSCbHb?eA`(fuqo31ZQ*fLTS-YhYV-msE)vtU&FTwaNnI=48B^Vubs z-={Y&RQfsi$Mo0t{f9-@n0ab14D~Fsp^~bxiq20-gc~x*BMZR|s8n5WxF{scL9i#= zJGMKuJG4)U+pBJhSQk*G-mfc&BQgk1H$WH#Cz74)9qe7&N$t)Adjgr@m`oEf@^9Wz zz$iT3XlopvWbfQ=-%f6KBsdWq2rkK^1%-)K9E?}gDFsen2NxGc>zq>lb`EC{wyr=l z9E?{cJQza3t$}i91Z}xf`N_kq7xRW*{rwa;cN248PqSF5aFXhug8NTndTor)O3De| zcJ=-JX->op_cpO&?%1Szyy7)74V5eSO%?`Aw}-|g6gC=^-2W_|QMY_=n-8~7lFf@> zy3q?3SsUq^MmH<*dJ5mFwn@I}gTyQD?$JwGdbgbaxS=_{&GMAc_g7-;jGvmWWX(95 zt=&VV-}RLwu_5Mo^nY5_xro-fhV%&RcjTJ*DK_y?@N0)!iJvIRZ_`(AW#lks}&TrP&|pshapcRO zBX!ixQnE3IZgBG75|s0i*G7Fe_%+iU3L(6Mh*hg1B9}PZS^tF z`UCI==8Mr%A>4Ppj{|DIeP9WpxkzQ&p#ETH@zi4num zB+M9jXhS1_vvj@n^y*lyFvKrk*f7x6&sRC^@6c?uWJ2rf%AxP^Y(<6&DT=8I#m0qC z#1iB#)wo~M$y6D(uM{VSy&a?uPdpl@+fY+a?9m;HKaYIU7zMvMpTjJ6gR$`Cr~) zyLy7(jkMTOrfUXgT*4QY&-P#45uYfmw#*>$>w@;Lk4mSbxt|f?*^36EoXe+6pZGv^ zTGe1!J_k`HbsBY=kPGxo!f0M^jOO*L^%gHslh=x7X4@bdb>O+^&%+{}Q^I~hTMF<6 z)+}Pc%pYu!w8%p!T1aClXby#vt3Fzs67%rGhwf7Qu||()hom}S!Fd+4U@}W zF0?M&w(e7Rcm3aCx%M=uW%eU-m9IwS`fZjx*}!7sO~J(tclW(C(kfTng(UUUwS&!H z6GP{*sL0MPKdb9+rL?9t@!8D5*qvdvEqPg4j(b8juR@Y~nRS=+#3Ti^<-cC%h!@Gu z-uO${=a*~C9>UM_e`WS4c%Gh-a*6->52{<0hzP;&9y}33e&g}$V)VLRFmdmf zPK{vonA#%tWe&NHvzG-2m1wp0P{iYqPZIw z;h@q64u#PB#Id|>MDMSQcrS@jBkxmI5;E2{M#{`Vn@{$*uKJWdH1s4;`MxF5cBwzV z$~)bX#O=YjAIS^t!-0C585CFOI$L>qOeMVk1A;aF%8g-=1_p z>P)po9@iW1#yFw@&fzx4gsVriKkAF!dau;r60e#m^d&md#JpkkiJzRMJFlOcuGW{d zNGak&zVdexcg(fsB_IoKg=_PV4bNKB9di%UbZ8rkKOoh59dc36@*-R~A^a?I_@{vr=MV z-Ri4ZwBNAeJB#RgiAsWV$Ue`$Jj0EeCZ(rrwFj~sYgazIHzl9&GCI4SU;0B-_Qn(w zbIS}1ORm!0L7w%bwnx{0b>C2T+?fCH?xqV}q#>$|c;?=&->CIMlMOIfoshkBT@h(4 z;XqPUY7;i2^D5dM0*giO+b54>aa^RLs(!}}69$mz7LCS{*hx5U75o^$IEFl5g`wD& zZB>gZ8Xuu|T43F8qH`gXGaw1L_9&BY{VtMcI&+$k$t;b%mNjLIxHh)>uef|zK(s0X1doR=CTTWEk7e`Xj?}(p1@4;A*wSSN2e}ut z7kTq1w=6~ zD+`;8Bg#o5B!<%A7P~du&mb?4It!2hOlW|d2q8Y}WLf}Ys7uYUDbysNomVPKM++cQlMuY|{T zHwV!GiDTCK-Y?P_;nG_)LxWXb8{Q$ZZCYjN^PK&|deL>HCpyxqB1>$3q~={ZuXXO~ z@&n(9vq@!^{zl16%1y7U?n%p?_Py5Q#(l$$B`xo#* zU?~~xUYIyAngKX)%ni#b29i1LsJD$}h@Kxr^c*yTz=05I?wPa_b)krwFC%+qFXzd7 zDS3R#+>zVa4wKW3h?!b9OSAA^dWd(Mxz$!4SLbWSmAborl@!j`a@TnE?w-sv&v}Pe zFWdO>GJmBQyXRV6_4xV>k+~Pcv!j~`fw=*ZVQ<-4?9%x+DjFG_QK;6^*6(^eeFP?~6?w!n04v1Kw+b9)0X& zh_5AJ-*|O)C6;I@4`F7L92dmxs*f{(ScIa7-Pc_)-or z@`*#JQ-}+%;q%L9toBuZD(enC`1Rjl`P|Mcmln^J%D>heh?;zgfk~*Ey&es}&_^0D zFcXuC`vn9uJEGSe!>Iw%05KdRP@oWm@gL~4Q7DRcfzR-|d%HN%$P3L2K&K6!2q7Qq zBz^u!BHC(Fbs_N4%rZBmhv3L<%P3Rvn%Xe41#Q>$T=OnPq%T_9Uy}2!+OY3rcysZN zTe}YpCj_;cCuXaE$on*>XoiSdvR&StQ(f&W9Ws^GEBNOu;n-jK;zB~Vik_5_%$=t? zc|@hmSuIbLkM68j>pa=rp^?Y@B0BN`KUc$Y-eS2a$;T@#Vg!5swdQ5rDL=8jziH>Y zJ!jQ5eY?+IYhDU^YivFsN+UW7KXFAiJa_<^2;hOx_i$q%qZz=&dO<5i%6IJR5X9JL zELx<{<&CIECGyawjWh>CXh~t`Y9^Mvj)ceMJtSGhXjfG!HuH)z8zfFg{B4QIdHUwf zUzy`M<&QJPPX{kIbJka|G`%PH#FR@RE$wj1v@L0e)^HzC)#FUd6`p>gt8U(MGj`F_ z9lTF$Gxu{YoSLpvAQ&I_=E>K1-)Sqt3KB})hpjnA!MoA2=Ql3m8~ z`pw*G);&a>Xt|D89%3bj3(P`;w7m+uG>_k|S)#kCYx|8S{vq4v*R-Fsxx0PNqsxQl zVao+l>{aWG-?fMzcqG7dUc%{0`fQ0d4cT|@8|Q9StsUeEF{}C*7C!snMIOI!i}`un zK7aoG7VvAk*{K-!Ei#46z`yv}NI*dm)GNEgxA+iB(FadZqtxOG3Ke!3eQAL(81Fvb z*JI2;kjNAvClvqsu_9PM2Q_Oxw1`uc}T8HJ}?p&5rK zwUY@*YXs8PeT(!#gs+@PcTmx6mjA3+GuQL`v$bb=uoWa;w^}OXz@B>C;=|pyiMy2v-!nWfo(+v} zJ~z{Vw`*GH@zRgt1Py;DVsBpWF*`~BBLjVzE2kA-KVi1L=*XMk;oek=VcH>L7>*Y6 z(FZr!8>Jf8GR-ZXH%R2vN5+Ba`VufX24xq(NXJRWBk@Nkke8>|H;NnzC9(0CT%FQ! zG8^eQxyZFTyXE?})GIb!@*$!BzP`HDl4N-_gF~?CujIeQ*1@`QbDOsruXK8};?H_P zz6}d3Z@ML|s!398DCC$rPd>BbZcf-)L9RaAm?d#*Ny5&H+wS-&m`7ZskCXk+z|sKzTZkOy~b*# zU_M8~Q(V!ZLEl)r$-k*lRB2r6pv!`XEKE#_3()#6cC=e1)YIAD0Uh>n;ze0^OBs-i2|k<1@T5o5%CUp9?7}TpZrgPF(H%A0oZq z50vaIz0P;0rAI`az{Js0-b9KMoF#v(aJq)x z-4%xph+Jr~v3t%ZzVyvKMPBiaR?Qsl4f!kYdE9E=C7#OD&%b;ZKhN|h!4||kd8?TR z|H)enu8&hcROTI9@am2a^S0h{ML#*B@O012#7}}txuZ1tB7Qr2&HSQzD~EZY;;Krm zw0+^#o=%>x+@G4ItA08&tIj(d=A%A$znu8n2o2frT=%6yFLMQw2lI<0Jsfw=_GTe# zMDBEHiXS{D(BoFskZ>wfyMCZJx%*j@d`DmXz{ZZiy#q7TfA9Mh6x3m!{aWShfj>=) z%_Z29_bXmMh^ROJrcucd$G6Uv?9RitwGTRpuSLdu%1E|3~X%lzDH zCS+S&X!non!YK=bA@@O3o2Q%Z>897@1;zLkzPaVSbf3gg0h5$BBKem@7Rc}+X@Y^0g8p^

?o9t+WDs^re4nqqRmF=v2`|$e_Q)J`>?&8Q;JL#& z;J-rW=1CF1qJXc_MNCOX5%v5InjRe+PfRgwa45VQRk|xMKSix?%Ye1al7wpgy2^t1 zL8=ZK?1d$GXFCZO=-N3(E-k@=D2RyMTrf20bXAMHa;zhY&aDt~E}Ss2!!TtZb221P z2$?xXym57s6DSBCkkc>Bs8a|j|5bY|<>}PBFTN{REAPC$`;g2HyXOjryofbh@2==y z6|rdMb6*Ylr2eh%1)rU6sO}c{k;5a?zP2KKk#*RTxOW16pDy3N;Iq%i#yh{qWsh3W z^_nm*!UL=0@v)g-C2WndH}nzKyPjU1&9V53=Q$(uzfHRY4f7U046-NP6v0$f0mj1lymsy%*gi zYT)k1>TujC<^bnww6D!8)B4Zv-x|9g`Ys}h>G<=$|0~(M>%LE@kd^A7Y25SVl*aRH ztL9&P8)(Jf7blf|njFn9xkhtOTYT6GE-r76shfo!2>Ce{8xJ{1wF?L3pK1~zsg$hw zreCt>nNmYcY?MXZj`Ni=#;&K=-C*Cebmk%%wttE@Idhhab=7p7F}QM_N{WxzYB|Ia z4ul~OUf6+ffSw4`KZ^WGS&=g#2%5C9qi z+|Gi9&|$-46ha3qqrlB9Scn`Ph|&8uI9Y&OS+EdX?08fRuL6OC05`H=A$)KkMvFsm z5a2o%EJPy?1j;CAS%9lpun@W&c#Impo`jx6t;;3 zWK;FK0zu7ZV_$}>3?r~!ed0$i+ug$TrfK$m$y%K}`g zf`w?sfk0&e4S{V)0yWBzcXCFdE(zKUg6mYUROI78pe_j-0$inng&-g|YLh7~Dhp_F zgKJc<5J5N)s7BF|#l#5=m~gZK5MY&Ie4z^5mjSL*8KGk&30Q zmS?)iVmdllbR;t|+r-A*ESmRK;h+rfD1l=cxS<5gvKdHeeKIl-00!9w?g7EFOBA_& z!NGxM6}b2VOGzAnz+hrImgu4X1|{$jI2P2Y;q@PI5&)NfVBdQQ(%wE9XRxb4;Bde# z8(0bGPQ%54mH?JjL_k>!0R&7mHGUtD?%9B&1KhHKsek@6%x7D714i47QN_xAx%n6`54NDQ1xfNLqR zD)F8^2!k2{u6@Art{-V+rSNV-f*1(u!G#Z490%ktba9|{0o?U~#i^r@!$8^#Zg{}r z=pjwAbm*a*HBPK>puIj1;DGjec+mr#vVm(JMhF=RGT4x*SPCID01PS`xJ&`dFb-s) z77osTvezK1wgL#KC8e|nGEm9{mnvXcRf!M4AgjQ=1z1+yMhf*5R?!dwVW26Rg)K1) zjJmfG!LLF3p(rRSq5rv>3|h!5z_Fk{p^@?MSQebpf(r?-l9-C@XrjFPgdhw`104Iu zN@KbdU9A5F|mG?CK#-&aRQ+dOS)fii?fQ!260# z(pUtH%No8C#5T}Td#fg0S=*#ySpUT_c`%P>#+APh1MJ6=Ia?og)r&7n&W z9ji_;Cg7koR*7HHN1>z16cljC8jE5!mo6=I3U?E$07cEv+RY^z6w3E9Hf{}Pe8FLB ztOoGNQ&U2X!Jq1S{ zR-?cH+YvfO0-sh06e!iAkOYpnVwrYV4a>BNNunbg3e4n5hX%3_j$)-S0T2V092|AU zax5C>bSO?yJ`rrlBRXzHP)i=EF*ylzI7B%f8|#3_f517OPLMOP0Kf=z#eC|wr-TOM zQ>AdW5S%H+$|09N2$VP|1c3veSjF{2Ml(Q-q9KTmR46D|y#?9!3K-~cF= zZ7K^VCxv<(6c39+5IBB`Wt;dSx>)~-ZB&L5K*2by@w*>%788#a$|nO(Vq*E$3V{Np zZxk?a&=JeHZcQxXCMJm?R|(EFVxe5L;GpQ31qxN*3?mk*6B6n_B|xA~IBR36qVhE3 z(~EFA0nRRt5H#XEZ$h9z=>+9t0!Ie1+$+|hPtt$-nkWG>8g@u8o*ZU)b`Xwf;N&2d zX@U3vQ2e538#tne1Q4*pdU!md$QtVjq{rPqDuf?;lfV1; zKoYD?11FuZ1X$@qz%VEfZ0$>CoG3J=S-%VdjgD9*W*%7lxQBx?HdTZtAd2Y0nIbIb zqzxvgWdwskwt{>*G~5RK_G3EFa|Y)*y}$R5_dWOX+)wv@?)~nyziaKa*WPQdWxA1>g_8mLMfu}) zP5fc%Z}S;M8C(xy9X;KBJg~mb-cDFA51gHY*9wbm91P5U)@;tu=i|r4z{v80k%56l z5d4p(2si@Mhha7FZ=p|=8k~YZ&fDA5Yc|wFoLKOaw0H2b^K|y`c6N7@)WAw=lgoy6 zcEfr*Ibhvzt`3r%N08Ep-Si#D07;;47HK9Xj6xcJoTuj=g1e_H&KpRhOgb7EWah^U z##6CZuygWpb8)a&a8{BMgcGR>GNWt}_ z{D!E5D*PN$TLx@oj+&MpGH?#-)}7SBAzDy_6UY=AxvtA; zHgK>)(RwWcnL>AL5#*x|4lRDvE>Va~^6C)DThzh9_K9Bd9fn$wN6mRM z*$REg`)5COaLBiy1}Bh79{W3ro4Uh=b_%qdEAo&y+&XQO4(f748wFZuY!BJ`+{Tbu zP8}R#9JL`PlR4bo5q{p(!692g&A8AMIQ5f-5(tOg-MpP0ecXM#6fBff6z~poM8%B5 z1@afbj;RWwVknlU2!|p#_K7V7!7*Q$Z${AT25dxRaAZ@LJ$HT%Pe|}-O=HOr-xAk? z1H%`7^!Xn9ebs7^&EBOx<89)b>W(e*O@2yp68ui$S9fQBUtYx=-G6IWVolk*dYJ;N z%;0*#82lH>E_3bbvO3)bwaT@xcV2$7B9YN;c*Wyy{$Zy^ir3s@Z5G38aou<;lbIm7 zXWxzE{0sLcUS&*)t-H*AV!VAtP+n^oo07WASyy*tC=!d!99<6Pt^z(GYICP$2PD86kd)SPIn#!ho%?m0Sm`DzEV8odpKiSX(H99o7 z`HYP5v<5MhpipT~n=@FEPyc6z4ne+Fh%3kYg{lIySfBA^pW;z>{$=z+Y=6f*O9EH8$Qh zEa_Zr!xz3b>lePZyK=ep(}EbrE5pfq56_k8xv=8NoDOVq!g>*2^==XI`M>aY^rM21yXg`G$1^9tGb6Pp`e;v|2p~}rd;*l_O-pkkx5TK(D^vwaopg(2f+`N1pJi(E6<*a8~a`ii}q(l8% z`LCIt2ePdK3z%H}0E$la4`j(7*m}E9$vA%HVvK0?rl@o8I?_1W3D2x#VpY%na!C$n zeEHv9ACE_8hnu$6y|~!M`idtzy+{yRyCRqOow3?hnG3C5BV51>!5>+6{2t3B-d-SJ zveGvdx|Fxx=laNAGMen49**%+HRN^*-m#hKh$nlE8UKr3t#`cgEfE_l-?#ZhA3r#L z8?4-?$r?&*eJ5QPA$9-zX-*t;`+x->x$eQFY3ZK8KcRb8EP(~T7)xNo3t=Y%exl+5 z^vrJwP(19uz}4Ar;`Tv7SAhWi(aR3E&%vEQ@N)2`Lvu$)KYBESA?7eKFesoO0EIq7 z<2OUjIP_;mkoRL9ZPmIn^@?H7m3erAWyG+YZwGJA|Ml$NmG-MckIS9QHrp^dW|5`_p z@b>)Rn}R3QFI-9%IP>;Q&Z6ttEk)lPOk@{++a!B0`|XaVAhjKVR=k=HKLt$Q)Yd&( z6m6NBwX)fVoQ%K_eMLlmSY9lq|RTsy% z3zmQF_`LwBe8uh2Ns9n)lHij=&l{>^tH8u1hYWV?=h@J}NbLaaC~da;FKnC1g3Xbq zcM`?^O$eHs|CA7He71I7j9;ZO-I#5d8yId3Nq|%+b#_1Y-$bApIZg9Gz<1ep+414x z@TRt=cFj1&sUtV#Wdd!Y6qgAdt3uoVqSs|GE9ja|j4B?QMG#lTSv_%GS9|~9oQ`jj zork&O&B~IK9QvGI1d1H;P1{)b zR{OgaT9LRn0|m|h#HTbXLX`u03>w%H0a%lL7p`kg#0ljMVADh{s*jch5!1#r`;chO z7fZ0W#o0P`;kz98Z21U$c5!4!6JG1X1?UE)!(eS4fXNbo(c1Ij_#ESAHCSqX-QfSk zudiXX5vAqVDGY$dq)GjHamxQke%%dwqK1}Vr@$LM%K-TGJq#O)6pt%8DS9Z~SNx4q)(IcZ z)UL}m4&RLHvNN@v-LXUY5@llE#S`b~NN@UOk+%)*67Xporw*DF;ZUpr3q%$sh&&4; z|Lk!_`-<^5e+LdM-OV`E-zHKj6s!2B;NkPIK`VpH;)@09oIHOIED2h$w^O8;Gd%VI zw`i?obJa#(!_|HgUH)NF7h82p9)1x`YcxL5>A~p{Yt{ZsD|D5rg}&B?&^9@4SD||~ zR&f;`;Gns8Z|FLv!97<$?`TWuG|d(K{zk;o;Q5Bl%xPybHTp@sdQ;VcMNs}_GId6U zP!tz~?;Ulb{>+Yy_KSMvzMZ%=~vhZ(ek60(J#{hFWWXFd;ScL&qSgY7uD`9(o9#F@O{Kn z0{qFqQP6)zJWHC^sl>0|KwMHw$ZEN-eTSmmVV=?jNiF*A{4p~{u=V>zidO?+N=lfz3HZtGrh z3|w6%)1eEaPV9>9dWtdMD8kMxqmrl>SN3YPMcIDKfxf<`zZ074 zZ&pel0h(J@18MG?)G~su$<7LaHO=>9Ug@isFFy+ILg#DvZF-CKU%{jxBVB%3%iBzD zYeRI)!qM;}0lQx3WMtSKKWM!L+=WV77OfW%7tmPt^$uGkCNp#AFCmX#POp#i{de`R z7}l+Jy@9J^)~ zJwfkqU;&&3Jxa0@>X3xq;cNm*B8e*j4hjv;M1X6ccQ^vkCx&}e{FK8Q3R!h<*>=)8 ze!eB@9sT)#e*A2DbH&Py%g-*%q(;5sPszn2{JY+0MVzx3-Js*5Z&@*>_eHN(vqPc! zowX=i3|`3Ttx_m+-x)p+_4U=S+O=JB4o3LcW$USad2l^c?)$fecOHK@!08_+k6)#- za!e{S0bBCUmXCScHm(xZ-4)6mitd;p(>lzDH)28t+l=(J()!n@lBOIC9~b&VF(9NW zDBeJlNIUpTj-S?47=9mVWHyp;X$%VfsDaZ8m5AWDO44lH>C=tBsAJO(_lVf`WY~Ak z@co$$8@=54DQx1#1L&CfO%smT`(_JMk^T{j324j(V9*H$iXb4}A)rv$ZuIo&Wzu%< zVBFV+DG_4ivLmS%lm-~Rsh$EC3Q&d~{KsWDQh3dSgryFI}({D9&L@0BA>D&?=>hkOOvC|rN zGb{wYsfpk&uhwoqDo}1ZQdMBVa=3uE(M*nsd7r0RVZ2`DcP8QOVpV(&2V-1^a`bkp z8J6bm()gKS*RZ+e!JK@)SD~3ryb_;6GIu5zZZb_XG36*d=Ih#o?|gFSSKnP_yPf%u z@9)0WiytSsK3I67_c!EYpn!Zjtw}a_np*;XIw%LnGg3#hpyw9!uxs`aXsuep%m{4P zNoLS=_^u&Me41AsGx)6dS++9BpphX5VWk3HF(b>C*NRZo0j1EPt5Zs7C``>K7LkK3 zTh{R%le1yrJV8S#l@q45WvU!IJG?C)ynpOCmY#ided`r>VYkmJV>N=q-yd35c{78! z!{+ocf$}H!lhce2raNk;F5LkYm7tZ+g)ZJ>n#fG!1Pk6UWA9<`crGQx>pv7G;sd9dsQ4U)yXwbO{Iwxo?uV z1K^-gkVTvpFGwhWtXkIB*Nl=o_(ba0=W#k`8Th2hu1j)iDN6`hAGGApvqP;#B?UiN zFZn*R?J|G!UbMHZd-Z|X#m+5iE^bjzZ7N2gu!Bu%`{1xdTA;)pHGe;aw|ezhmfc%S zJzlbY+AeH~f2Jv+h*@j(BQdAws``~%#wWjFrSWB^-uiJ2@-N<2Kag0Q=Urbj@%(qo z`@4VHPHv5>P`$LR&vL1jc^^-9`x~U5;7{GAH$mbPYT8l9%-dh`hi>raVw9k1djULj z_?N(vKNf?(TO@}@vFA*`SSEk92!FOj2^y``Q;(J?Z(}^b7r?S%Tj)5*XoS3PEd#ci z1Z)*@PzV?lrs^8I8QQjhsp=41GmW`&UWuQZvvl%7N4H^KD{v;3Qfe0;q#Shb++?2;Q-BofHg5T#s``jk<8<%&yKTH2SN3m6*X;SLB(ATY!!`L1g{D_yM*_gX{ z@tnAGRVHBq{bL!lg$reS-GSPxz&CwRB7;Mr{fj;33`{xQQBTYJ@iNOp zofH?bY^uDpLo6@o@9Utf=kMPAl{}YK{xn@Q&(GM%L0i^z!-K`oHgL!$C#NRN+mn21 zE9XhY_3X*nLi5k}Hm)!>VinHo=6<#-J)V8_+!W0Mfyjt=&%Q=_&f6GJ5LLQ&!oLzZ z5fV&2$qps}edJzgij!H@$p~I(GBdEu;_b+}-siuPKCZiV%?*kHB92hxdI}B&*FG_Y zoHdHvdOr{AH>YRvq#BnTHCU$I#;Ih{kJSua-2KKyq$IV#$lq7P?P9Omxw_i5TDyA> z-F@bL@X*TIt_xQ84=s6eV{}u1F@J)sVxz%_*PCpAr>eZdcQaOh&0{g%riCn zE<7LDAi+~3J6lISTk@wy+S;c|(G5!TUSVcXd>4TaB(A|zBgZaVKKt398j&vse=l!3 zOIUqa_edlG*4V)wO(9yE!b9UhVynRU04ik-{noE-pIi7!+>U$MYP`};qn)^jp}RM{ zy;43rKRTWg*RQ`U=e9(H)J2zH8^(8}eDk-o@_43G*}oxsbh(j~w^X>1)7AJ)4Jj9v zg6KPD>jZJEiRVl{-G3i_OrGz1n(Ot;{*i507V2{M&htN4`dO4u#oHb`m@|0RM%?@K z&!P0q^NR1BH#$^!`kmjz^KPOeIgHT@gf4}lk3!%yHP=}^$M5j4WLlzWF~@DCg%R7LGJ%Lhk54fJNpxFTJSe6KnNP(L9)oP6M5qeRb#ho88fF+ab^k|J8|@#H>;pZGFsExkDQ|LHeh zqT5+9n5K6ry4FmgQ^T=d1Q|X3mV4zkeM?84b^?>0RXI=qHJ$h$n;SxMm{HmH`!NqQ z14E`J0|O_}je@_cgE!6|=Z%{!q8&)v?4G8GsUP|!c-+f?%cv#q^y1A){sWoq&ZlMP zY`V4=dwuiu=AN>-nh$gouZ6`8_k0xmHT-92sJ<@bXMFOhL0vY{%7C$RcOnJj_udOo z(%B*q%FN=;V{~$D@tDTV_uf^k9OrX(E3$=@-lw^Gm}{{5c@^$CZ0K-;&0%HI592 zZA|Njw>1q*g=;1(&O7t*f=&1BQ`>Db)Jjs7)b*+@HTFbzE^tov7?!HRr8k8!zOCcNH>K6urZ|(fuO(aOe_?|C_A8 zueUXX&L8UcDoVV?r5JjqrZG3S*XZc_FCyz6yx{3PQ=r>X6*1Sx?Pe;s&-uvLEvatq zwHNP%zjoxjeNEs~(OqrBt*q8N9^4&^P3m0L{h)l6S32`e9wq63OvSE|J?yawVxKZ2 z1HK;%NKpB2%)~i6W0$Yx-`5M1)|DLKJs9<*JQY)-Tl1<($}3>)bHj(Hu0LGCy5c?l zkfK#={Mln%QrG*R$XLti`f6glTZetzYWq6V#X8H6<8!n2j;K~9uZjA)z0dJs);nYI zQn}MH+%GI^L&rzeN_>q)eIo26WAWyZYUbN{jWJ?^brxB5-I!GwF0YK)E+@o(j8KmM zXqgeQEp|JGZI5J6qxZ5GH@$E6J?%{Tu;cv`gEI%(Z)RHC#cp)2H>?N^iZZPEur8lR zk=r^&$I@uqS&<+Ci!)}t&F|{gKFe%qE7Dl{@XpU3o0v%MteAQH;+Mv*z54XjY`K2u znIxJ~x&S|9t*c}Y(@zq~T%u|8b0)zC5N@a@t=e?&GPb}YEeKeF;R z%j#^^&_$Ou;@Vl{e;$*1Qt`-Pm7r5Y@aZlelgN)p2Q-XZ${r=jF)ze-Gq9bpQEG_>cZh2+|(8tulag2+*lmlE)V7dEC%NwsBCb@tc3Le#*HBkYkPE%XcB|~e?StW%ryU(qh z<+Mm1Ptf&7qHw)_1Eea-4_VMXlK}Z7+W@C#+|bdJIM~pfHt?drCa>@ z{afYOV^3AAh^9C9$G_r(M<06l3z{j8Zisjpm(Y5ZWy{Lz?+=*q4n-_V$s>gFif>gr z-WeINk%PnCWv;d0BS9~_VuNwqqAnrd{M;89yh6#=Z`vitTjZL{-Sly|vw!bZ_1v(bE%_1~ySJ?*QjQ)<8i=Ouv*bH)#$gGRQunS_Sq&kl@ZA{7^Ez5vd6=zx)}ZQ#HI zWWdlJJ8EELTN^mAF$jB+1VbGiPy-`d+Q5Nx$$+7r2;hv3jtXQu8#piv3%SG-X%lq7 z$W}IRU>q4RRGE*O3S=7_IPhIE;He7^bP^+b*ua4ovQnY~HOI*QHE>{GGGIt~z#XEK z7}>oB4*Zl17-~>}nqy?=8aVI@Hc~2}UK6N+;o0ALGad+9(oqzE>9AvD#~QfApUHrs zm4}*RWVaePu)!QsDj+9>+A84bdn6U-$$%jzgj!-`mm0Xl&{aCp2|*I021a(MfdgBU z0Ye<4rUL%l07=DdGGK@b)WFEjG;oO*aF9{~*)eJ=kX>ouz}{rQ(2_>IK#(12;J{DF zfT1OgT4H238aS{5h@VKUVxpM|IwyqeL<0woBm;&xMy)*fa}K0ce4+qM2gk@BG;oP^ zxk#x1%LBdgko{-iz~{(-p*;_^@{qk};J~9~z>rnY;22H7ypx-OMmZRr z#39>yz=_*E5A~RIh4IK99`F(0(l;UvCrUg5BU^UBN3;k35lUX6Insy{D0?R%gxT~` z8xbVX(OC(yRR`QkH0D#84e^2z-4Mu57;wVYg8Mv*giYtF(G7s?djTJyaMl4(s~p+m z0zSZE@amBI4E{;ONXL*yWdI8O3(%?@+1moH^1tW@qth`U`$E7OTnXMgQeu$81nF`N z$R-f*5pU5qB5Er^wtRq(s0Awf=$PX_nGNy+v<8d_t4o8I-=JGl$W{+ zP~J_D5m_EUM+P?&%@fcW46=2?q|lQGfDuZtbQ%k?K>?hSKG5lfOz3}#$dF`!e8a?= zB|fC2Tp6_r6~ygPh=qTRL=k|%-v0-U(qpvEKr9tAtFPHNhb}+@^3f|n8l>f zbZl72!f!aN4+U7%I~B6#8xH$~43>^93R&(Ahm{BICy+Y(U)h^ZOu_z>JH{faz9*%f zbZXBj!P03E@RuZlGsiP1%kg;WBo_#wX|hao#_;!$TG@!}Zxu1({BDBI|_VwDic4djFZK;n`%TZ05)fV52<3na~k|AuEO9 zd?b)z(#Zrol}C&jA;XSQAQhL64FH}NL&AQh0E^n3;W=0&tlkPzX=%D9;tGVPYml&K zDZtW@ma-}E%=l7hf&2$xVP|Nl5_dN1B1(#^!-ZSIIz9?*a}|~8Cu~ zHBzxjODty_fhat(q!CWcFKQ#uFhe3XoEW5=vQ$U7)tRgwRNpw8+(c%O)s1jwE>Oir zWi!Mfki~;=Y6>){iBH$IgRB*V4VPriZT*H=Bu~BK5XrRb4JUBl(TGYh8s2Cwy46^JE&PexKQbs0=;Lu5pEO~=Vy?z~ZdrB;Tn+=bsIk;uliMBvL`9lNe+*3)})@^(l+~PplwUw)-1kQ)5 bAqDhV$Y5oIR!t=MOB$RK&Vv7&f#H7uc>kZ| literal 28380 zcmdU2c{o+w_cvz_NoJQ&#taQoip(WZsifrI%Qa=lkfF(}3=yItMPzDHiJ~$j4MGzt zq>{>5sWi!NAJaYOo_pPM-{<%H<9FZZyia|f=l$%pKWpu^*Is+A{k2-d%ErwE{g{2U z?8g2u@vqrTl1v^!IAu0{7 zS5KUuixbWh@8KlJy$>mk)U|+7Q6LHQO(V_NgfU1HjQ8=`LGtqP!21Ddv?xadgG~MS z!Fbw^>O>cRPj@FrbyqFA970@jj;SP7YZJy1e|6l6F?!kB6h9uFD3sHdng8TEwCLLa+W7 z|1Xln4O3~48~x^@XYSj6IK`QnA4Gg6FWGUC)H&ZIls|JrYjHCVbKWfZZ8p+3=GSc4 z>87F(T;rUkFtDEQ;)*-lYy`jKW)qfbUA-?S%^&u+_@r^1)dq#Xg5H0E*FIX+@%sqz z){B4p90^9b&z@bb3W{z2$^og2Jo$9VrOO1s84I3EF=*K4h~Fs zS)7RTxOI}j&2~OAqz$gY2sp`!51o>Fnv8&V6Dh$@y|CFq8(d2r$c~v75+%6N z+`vKF;FfQ(2>jP|y< zLtAi&70i@(qXh5xXlcSvQ*cP1SSi=wppaXtoaix~+zb#dg3>0t5b+0Xa1BPZ+3i5d zxJ5zMyy?IhV4Q@KoVjIY5^Zp3d17T8*Nvx?{H2W*L=lwa)e&;nX@i696T9Tys1025Shr2B%(2q7aWGk2%7nuO3eX`I5;jovdpR2RKm%p#Nji$Cb!HI#WnE6Yg z+F7t;E&)+76w6bE!w?+%ClrI=SRg7OGpwy17ZV#E+t}&ITae2a5q@IXYPpDjQjfyj zU(WvM4LI=oqU`{OqkCQEo0Qkp?dxV+4$E7esdIu=2G`l9$v^$BmtK-q5|fw4L%WCbEjtq3$IsJ zRx(xJ)mLS?^F&{@q4Hkhkz*+t)s?tAxXk*R%EmiQb1IowC=PUB#HpVkYG{%U0~%a= zQepL^21ThsVbY!fcesXt@o?rUl3J|@Pp)4JF-6YR!b&o}UNkEvz)R>!&)F-hrM*@R zrOErVUcR>Pq4!#uH-mYc7oA1epYr7#<6G+b%lz}IxptnU_uiQv+pjrkz*!$VD zW$?6qIs3KAxVVjY;e7MQIft1qd`WfNJ5#p%?1INL+HtAL`V#z0yCkG%|03Kpj%%{Y z-OE>Yp!B+k?3W#XYz2rO5zsIOcC)Jk3q=m&1le!1RZstZw43!`zagm=^NnW1CF!{r#;i6)$h8H0rhVX zykvC-$hHV9V6^%H6ocyT&sN*L;YP3K>LUvkMJ3}c;!eM9Pv?3`dTOhXu;kP)_ta?S z7e8S}WICV9vpb^rTGZX%R@z=02~doXEwx+e*a>7E@&Vk0QxNE`$a+<3rGRy=^7 z`a#|SmM`#d4IIlps2eh%D1+c4-}3+w%0Eca#KWMi$iyn{>ajdT?Y*EG?cd}&_VOOF zE>At`)a%j`DzPUZeQQaWgXMkGf2UU3E;+kRH!xjd|*|;qcau(;eyR> z?{XjR;quH6a(}M6ykq~JN^1)iz2!NVoTb!Q8upl#6>xu=+_IK;yHG^ud|s(n%kFTN6tGJ%e@JUyton20kJ+#9M~;haF!#`19PCkS zOQAOt^<_V$0S9v6lc31~rURzXSUN(1L%@OLK6nI0%pgh>56}i+}sxLTrQ5jbWw+B{(>BI&_jci2{xScme0c ziNh~-gM|`YTI58T58m0C(R`VVpFRE@Aa2b>WIz=TgSpxu(q>`kw3*t|N0~1djK2Qc zzkB{R=E1&Ji87G{jX#ACo<$AVnw*zb6uRr;^Sggu*c`VGi4yMUg!{abwQ@~WYxqqU z2g-H^N5vI28zPHis`7e>+^MlmyzLDl12?zG zl`I20E`Hk5n$}^JC;a`j#3qwxW@}l~PiE=%QCMqZ)f^cpVK$!Yq(LZ#lib@eU&DnX z&A1{eN@1Rf)(zc)^v9rUo0DU7JBCoMfaM2&#E8%v0z+nGatL7l1h4>5C&vgOr}eYw zkArzCz$-7F)+?iTPJ$)_4!QAIfeaKlEv3410w@f|?Vq5@AFjb`9AFu$rJWL^zI{(z z;VM}j7CdJRmyp#!ht6uAHF^q-jj5xlIkzI*+M14(+n4B`Se?@AF>}AnDKaa@M(*X&mY{C} zO$lBZ+cO)J0mudjPs zF}mLoe|O>f^ibQu=Gq@DNDV!fz=cAG5)<%Eh8_qO>F$uTYofVAz+QN1%W%gKU)8L? zqw<=G0_|_AM!(0h6&oohtE4EGm=rygh*P{$>vm;XhWeQABX1_~JD%~d_y6EJ2im33 z2hN?0oL?)V_qI)*eyE>c0UQQPp*+9t8WPKhlP$R#>TTs~Y98@<;M&^f>K)Jaj|{9E zUG%U$WM_Y?cE(q`vOfjYpX`mQc-O73kIJ~ZUm@`H5xsy|pTNz3%ZwJO__vuzQJNO~dm^SEgDjF4Y+);Mz54NDks!AF~bO`0EJ0&22kd~csL`h z{zRmB+#$P!&L^Vl*GO=(Drlz|C6>QhY*W5#Q-5!7Ze}L& zV9@q;;P5K9>59IDw2-dS*P9%%qFGs6e~Ebia%np#@bltdxr53c`E!!5@W1#$aU0i{ za;jMzOj{LvXb%jgO;2g0v@s7Xg|l>I3YX_Rn!$T^J#P6ldV(%aVF8>CBT6EQw97#k zrxrj-6mccM!Jwh32yi)caVivl=u5YDpjK3UG5acf4pDwpU_j~8_P&BYKZYA$U$FJ$ z2_!~Y)-1jKr?hCFpxtY|nA0{RW~xRm}9i$^Zm<_s^7nf-+c6bH+OKN8ex(4!hdtKl5wSP9Ryf6ZsaLt z-*#K8UBgRs(CV(}``1z;CL7I-_0s$Fk5lG|Odk~oLopzvDk$DSl1M-JOFc5FsVKru z%E)Xe`P@G!_@f0*FH|Cf<0~oCrzcJ{{GyFbKinf@JEE{}o)q{q9X58k2@}}ljR(*% z^_wIdvG+}PL4fp+IMI-XJOBorV4w&B(j5W{gYCvoo?gan_ok@ViYQIeVKr4@6I~OK z)(qHww$EiosiiFDWhFv(eoB&yf`0)Uf>{hdLuS?QT$2 z?yT|TIOMiTv~y{6_(xmLvJBk2vv`mlsV{cF*?cdG2n7(wJBV@DPw0L!kht?fwaGbF zBSZL0WVoqC)A}<%Im`Clyf9mHFky*m*vA63?*#6s8?7sl6TcIx%Rd?M3sajoef5(N z(LTumPnj2+QWE&XD9M5F#kF0-btl|$+ zSCWInkiJG~;@GdyE$E=Z-jJw{e#^D#f-_43Baz>MZu~RU^E;{UaHtT#{wE#cO-gdmf}?IHq=SH{=*_;G0~u zWREz`BV9wANS$&BSo=pXuPP6jKaH{|;tqxmfNl00_M8KPLhhR)?f^I#6l9aA#}5*v zk;9qUU)z}Fwg^bn>F0C1W}En@E3Z82^1M7bLO*QYpQn48uap-4U_Te|)S+|z>vxhp ztzC>oFaZ6Z8f zCaWR3!uCf>?v;y6FI-=p^bIFZD7W%6PGnMRc~gB~Rx#hNu4b%WYu&qBe>sviB;H4&03H5iap>E9c%caz z8pED5Sz?ARGlAbTQ-j7T^~5bR^>Bj^_ySm#e;oq{8Qq9?&E>#Wj{;kT925cugQ=dM?xzKLby!&M@4-^Z5^i5*H|pL1E^rP~!3%H&dZ*F2LsfCw4zK}Q<|5zwVQUH8)E z4B1x@j>JMR!CA6sCM8j9HYR_2YiSMv24HjuHcg>f6e+S-(Ji~hzzpV6p9O{mC`^K8 z;RMZsgtJ_|nh4|5*VwZ?d1Dn z8v|JB2Oo5ch1@$Q@i17t|KX|3>2mF>`LlYOi5q9HmYAC@9+tsYfE%!s%ylZ9H#+#i z>!Pt3kNrN;*Ze2GW?p@!;Gdw(y8D>u$t#js-)DqAwys&#&Gr0^P=nbnZ_DOX?W>~} z^M5{nc08&KDREfr<0{iuBv7Y|GX6(N2*?4 zitAO^mob*Bd$ueWr zBCkLnd;nt$P^?(F#|x;v3Vf3XB@`S6?H6^gXJX0iihEMgM^I3SbkUGuv#30`MJhk+ zZ(CUQv$t>m%AL-xc#|*&{yie^ij&LrXnYOG@C^qKp)332Uv(|(Z#+A8^`ByS0BErX$IKc#<5ABsE zIGI+R%%G%(m5FT{Z-?f3XYfMCxbC!@8FmE%8s2N%l##`E ze0Ax56D5OIZcUp$+_Ff;uGj7orN;}+g9CIui+XfU->qGtx2=|^RWUKgX;lF!F@(N8 zAaGbTFjYfg!a$hC6ec7?uZF?|%h3Q;Ly@_U>;Fj&#i!XzpGpDBr>mhbS%4`HnyR7b zWV?J^EKt-)tX1@%!!poD_x;4I*PE}<|mI97&j zP`Y`AsX+;yBmr=74N54SI~@cZr!S#EFNR=WKL&e_{MmQN9tF&Cf<2l_v^0T-#e*bN zf%5^>dldPt&%iOS_?0w~S7|XpbF2AQe9YjjtA4&|@1N}-O-t-ER?590TR*qR{g>J3 zmb7odn{2(GuBz-a%NbEIpX)a_+T7*hku2T0?reqeH?3C+wDL(NwaI7AW>`3;C z8ihhhVd$e0I8DrTT2C^+WWflI(*U&4(e>`oArKjR`ZIF(pZ-|#@fjc}^{P1lg-It< z5v&&Z?q43<{a@xlxba+^TCnE9={Ox8L+ zUh`+O5Z{(XR<~Uf*3~AcG!=2oT%eTEbuT;Qyb#x*UDS%0jWGqjcbP!JtMr%D-9Zhq z-R~cKi~oN!BPb3t?IX^M9r@Y6-K z{pogI=^DayuZNTb8pYJ)ZO*u!SZLGZE>oztcEkG+u1$PKx8!*|ZvDBGtj@*ZCF{u5 zIrK5y>%(yAzOtKq=i2&2wFHc$yV`ZKxwjOoz3+afb-!c^&k+CW{ro($p9Wgu za+R#bkN#7#9N8SBb*$Vgy6|Bh_=%bse&680WTiRT7*3j5_6( z@&!qkKFsm09F~n@(@0U2`*-v++lx%a?QE)}tQkr71D52pwUv6F`+e(Z@1UJs^zs^) z;NyCp;U?d9m~^uS@9%lMMH^{%LkozKd#O?vtzwMgP|JV$g6|#QNOdYOwVNXK5u&G@Ak24Tlt|X@n2VW z@x*LS{rj$NtDK0fAOBu6FXaO=+_>*tC%krieDV6(4UyHVA_i-|>YlA5jxH1LD=ELO zyn|z5?R+L)j&kJzhmo`<&F}2Dl{v3>Ntn} z)-1byR@ArH|7&D1Q-X0=BR^ipy=&{48D>rRqU#Z5`*#;4YYy%hwvk&AS7XpnRTw)$ zQRx7`&_WkEPtBdK|6=4)i|RcCL%kK(mvUE4)}~OsX8>r})CDijFaMOCE`3JWoEY}j z#ZghPFmPDWpeVgTIjG`S{i)<}~5+(C2(mGvH=zh^N3q z>(jB(8DFLBjI*{33T$@CU!TRX{F=uFV~f8n`-O~h7eC|bJ-_DiUWx?TVED+gX)hYU z)ahz#vPOHwdUiQ6(QT&}PIKBr#{&%2I27v}*F&nJUWkIN%mLg7Aq!DdU@Y+oZJw0Zt=a2;R4gnuJ zBmncKr=(ORsJQhF2dG4;{Be>i)rq!tVbvTXez++(8k zJ_7sr`v|DF5s=Wx*Abv@Rt#@|Z7HUhjFPI5x{@e$f-k1$a% zhiwD^Gxg&~&;wn6!OqQNS7_5=Lbu4&UOa&Fl8nNf@FW{qktifF;f9A7eG>R0|g9Gff*S26aZY}Ib4)fKz59o3gj~Ya9}?aFtnsG zFA(Gt0C3>PC}3zwW0n}%{tpLM2k{f7Rg86yV{<~t)_*u~ED9Ln7_;)=rnY;TTK6yp@-UBKJAf z_K(djkWK&NGLMI|1+<_Uj1Q5m^>9{l!9^1?aXTSA9mc5>BRI8DK_>|uc!~mvJ=RH& zjTB@bJ)9JGYOo9vg6vj@6G8+pEunA+&j39f#;f%}z zg}~IY8Kec-Y7M7l&MaC(Fcgy`8>`_1#7sK?9S2B0z9O5b;RB3LI{=+Mfx06>rX>7; z6tGSYctJZh1tXiM;R>#y1yM^^%AJ*w0&5c?rJlHura zw9pwidLjFe;ppFJqtmfU>PCa~k+z^H5$SHm+L5st46+${T0)DqEJQZg{dB^>r z#0@eCgwS+ZrcMXaf4&9C(2AR=mu5V^L$)izDbbuu1DZiv;HA#w;|D~GnmmmW=(r5B zRU_L0;pUe>3!9D&lChDkfN<dn*!gIFNGFJ0f2?&6`ULm-rf;j)RkF_3o<$QTX*Tx7sG*|>$(Dv)hp<1&wj1TSb}V=@o2 z_{c^qI4w8SXo*jUb22zQQbPJn3H5Psaw`>9PLK^*a88IQOiWymO&T5y%$!=+kk8z_ zfKpsK9FRfbQ2-M3G76NAzobqqGUnpZpw!w_?-MppgzS8R^ShN6G$xwK!Xw*~;3g-d zNke!#Y?HC!7KbDz0EIo(sDzCeWSbJ4n7g!~86*bTBm^g>5IjDGbS31Lq3NWjP7Kmb z&Co`;zo|Ss)G;(2Hrd3H{X%eNHq*q$L=AZeWIGO=8oPzG#Aj&RL3ZE32Y58?0Cbit zc?QT%8~6aLKrugT|A8q0n!$ex+mRYB1p^?hhumX>O~c3z8@PsNET)BxNyB6VMK-p; z`5B@)#D8)NK! { expect(res.shape).toStrictEqual([3, 3, 3]); expect(res.stride).toStrictEqual([1, 3, 9]); }); + + it("3d.chunked.mixed.i2.C.fixedscaleoffset", async () => { + let arr = await zarr.open.v2(store.resolve("/3d.chunked.mixed.i2.C.fixedscaleoffset"), { + kind: "array", + }); + let res = await get(arr); + expect(res.data).toStrictEqual(new Int16Array(range(27))); + expect(res.shape).toStrictEqual([3, 3, 3]); + expect(res.stride).toStrictEqual([9, 3, 1]); + }); }); diff --git a/scripts/generate-v2.py b/scripts/generate-v2.py index 7045a370..cebb6571 100644 --- a/scripts/generate-v2.py +++ b/scripts/generate-v2.py @@ -12,7 +12,7 @@ import zarr import numpy as np -from numcodecs import Zlib, Blosc, LZ4, Zstd, VLenUTF8 +from numcodecs import Zlib, Blosc, LZ4, Zstd, VLenUTF8, FixedScaleOffset SELF_DIR = pathlib.Path(__file__).parent @@ -170,6 +170,25 @@ chunks=(3, 3, 1), ) +# 3d.chunked.mixed.i2.C.fixedscaleoffset +root.create_dataset( + "3d.chunked.mixed.i2.F.fixedscaleoffset", + data=np.arange(27).reshape(3, 3, 3), + order="F", + dtype="i2", + chunks=(3, 3, 1), + filters=[FixedScaleOffset(offset=1, scale=2, dtype="i2")], +) + +# 3d.chunked.mixed.i2.C.fixedscaleoffset +root.create_dataset( + "3d.chunked.mixed.i2.C.fixedscaleoffset", + data=np.arange(27).reshape(3, 3, 3), + order="C", + dtype="i2", + chunks=(3, 3, 1), + filters=[FixedScaleOffset(offset=1, scale=2, dtype="i2")], +) # 3d.chunked.o data = np.array(