From b36ca7fc2e75f25abd752477e7766a47a3280968 Mon Sep 17 00:00:00 2001 From: Raph Levien Date: Sat, 6 Nov 2021 16:25:56 -0700 Subject: [PATCH] Add generated shaders --- tests/shader/gen/prefix_reduce.hlsl | 72 ++++++++++++++++ tests/shader/gen/prefix_reduce.msl | 68 +++++++++++++++ tests/shader/gen/prefix_reduce.spv | Bin 0 -> 3504 bytes tests/shader/gen/prefix_root.hlsl | 80 ++++++++++++++++++ tests/shader/gen/prefix_root.msl | 112 +++++++++++++++++++++++++ tests/shader/gen/prefix_root.spv | Bin 0 -> 4104 bytes tests/shader/gen/prefix_scan.hlsl | 92 +++++++++++++++++++++ tests/shader/gen/prefix_scan.msl | 123 ++++++++++++++++++++++++++++ tests/shader/gen/prefix_scan.spv | Bin 0 -> 4736 bytes 9 files changed, 547 insertions(+) create mode 100644 tests/shader/gen/prefix_reduce.hlsl create mode 100644 tests/shader/gen/prefix_reduce.msl create mode 100644 tests/shader/gen/prefix_reduce.spv create mode 100644 tests/shader/gen/prefix_root.hlsl create mode 100644 tests/shader/gen/prefix_root.msl create mode 100644 tests/shader/gen/prefix_root.spv create mode 100644 tests/shader/gen/prefix_scan.hlsl create mode 100644 tests/shader/gen/prefix_scan.msl create mode 100644 tests/shader/gen/prefix_scan.spv diff --git a/tests/shader/gen/prefix_reduce.hlsl b/tests/shader/gen/prefix_reduce.hlsl new file mode 100644 index 0000000..837a75a --- /dev/null +++ b/tests/shader/gen/prefix_reduce.hlsl @@ -0,0 +1,72 @@ +struct Monoid +{ + uint element; +}; + +static const uint3 gl_WorkGroupSize = uint3(512u, 1u, 1u); + +ByteAddressBuffer _40 : register(t0); +RWByteAddressBuffer _129 : register(u1); + +static uint3 gl_WorkGroupID; +static uint3 gl_LocalInvocationID; +static uint3 gl_GlobalInvocationID; +struct SPIRV_Cross_Input +{ + uint3 gl_WorkGroupID : SV_GroupID; + uint3 gl_LocalInvocationID : SV_GroupThreadID; + uint3 gl_GlobalInvocationID : SV_DispatchThreadID; +}; + +groupshared Monoid sh_scratch[512]; + +Monoid combine_monoid(Monoid a, Monoid b) +{ + Monoid _22 = { a.element + b.element }; + return _22; +} + +void comp_main() +{ + uint ix = gl_GlobalInvocationID.x * 8u; + Monoid _44; + _44.element = _40.Load(ix * 4 + 0); + Monoid agg; + agg.element = _44.element; + Monoid param_1; + for (uint i = 1u; i < 8u; i++) + { + Monoid param = agg; + Monoid _64; + _64.element = _40.Load((ix + i) * 4 + 0); + param_1.element = _64.element; + agg = combine_monoid(param, param_1); + } + sh_scratch[gl_LocalInvocationID.x] = agg; + for (uint i_1 = 0u; i_1 < 9u; i_1++) + { + GroupMemoryBarrierWithGroupSync(); + if ((gl_LocalInvocationID.x + uint(1 << int(i_1))) < 512u) + { + Monoid other = sh_scratch[gl_LocalInvocationID.x + uint(1 << int(i_1))]; + Monoid param_2 = agg; + Monoid param_3 = other; + agg = combine_monoid(param_2, param_3); + } + GroupMemoryBarrierWithGroupSync(); + sh_scratch[gl_LocalInvocationID.x] = agg; + } + if (gl_LocalInvocationID.x == 0u) + { + _129.Store(gl_WorkGroupID.x * 4 + 0, agg.element); + } +} + +[numthreads(512, 1, 1)] +void main(SPIRV_Cross_Input stage_input) +{ + gl_WorkGroupID = stage_input.gl_WorkGroupID; + gl_LocalInvocationID = stage_input.gl_LocalInvocationID; + gl_GlobalInvocationID = stage_input.gl_GlobalInvocationID; + comp_main(); +} diff --git a/tests/shader/gen/prefix_reduce.msl b/tests/shader/gen/prefix_reduce.msl new file mode 100644 index 0000000..e1ed0ce --- /dev/null +++ b/tests/shader/gen/prefix_reduce.msl @@ -0,0 +1,68 @@ +#pragma clang diagnostic ignored "-Wmissing-prototypes" + +#include +#include + +using namespace metal; + +struct Monoid +{ + uint element; +}; + +struct Monoid_1 +{ + uint element; +}; + +struct InBuf +{ + Monoid_1 inbuf[1]; +}; + +struct OutBuf +{ + Monoid_1 outbuf[1]; +}; + +constant uint3 gl_WorkGroupSize [[maybe_unused]] = uint3(512u, 1u, 1u); + +static inline __attribute__((always_inline)) +Monoid combine_monoid(thread const Monoid& a, thread const Monoid& b) +{ + return Monoid{ a.element + b.element }; +} + +kernel void main0(const device InBuf& _40 [[buffer(0)]], device OutBuf& _129 [[buffer(1)]], uint3 gl_GlobalInvocationID [[thread_position_in_grid]], uint3 gl_LocalInvocationID [[thread_position_in_threadgroup]], uint3 gl_WorkGroupID [[threadgroup_position_in_grid]]) +{ + threadgroup Monoid sh_scratch[512]; + uint ix = gl_GlobalInvocationID.x * 8u; + Monoid agg; + agg.element = _40.inbuf[ix].element; + Monoid param_1; + for (uint i = 1u; i < 8u; i++) + { + Monoid param = agg; + param_1.element = _40.inbuf[ix + i].element; + agg = combine_monoid(param, param_1); + } + sh_scratch[gl_LocalInvocationID.x] = agg; + for (uint i_1 = 0u; i_1 < 9u; i_1++) + { + threadgroup_barrier(mem_flags::mem_threadgroup); + if ((gl_LocalInvocationID.x + uint(1 << int(i_1))) < 512u) + { + Monoid other = sh_scratch[gl_LocalInvocationID.x + uint(1 << int(i_1))]; + Monoid param_2 = agg; + Monoid param_3 = other; + agg = combine_monoid(param_2, param_3); + } + threadgroup_barrier(mem_flags::mem_threadgroup); + sh_scratch[gl_LocalInvocationID.x] = agg; + } + if (gl_LocalInvocationID.x == 0u) + { + _129.outbuf[gl_WorkGroupID.x].element = agg.element; + } +} + diff --git a/tests/shader/gen/prefix_reduce.spv b/tests/shader/gen/prefix_reduce.spv new file mode 100644 index 0000000000000000000000000000000000000000..d1db3aab8ab019deb8a9f24a8d497a576e57c22e GIT binary patch literal 3504 zcmZ{ldsmco5XT?6iDCk&UDZI!D21fFMpBps6ozJHcU)kFP1vPn*Q_jstgPNifAtzV zy^vl-w{z=NRo6V9Vwrf zzBoO+R$CZ8dhCcEJCoMbQJ-$&+Tm@`N}*KNuorq6+JJhoX|X6$9X0b%V(cY#_iRjOAfs+IbxL!96qcg6Y3C-IEAIa`lDkH9;iHfWOnV{Z4Q z`sN%rV_H)mx72uNdI0i--rrDD-8osqgPHwv_~w0^z2)=UZ{)Yne13KFZ-KmT18)8Y zGX2|3ch`3DD`&f%(i8^xMciJcpqd9hcdkz z+0%#K1CN~dqFbB!twFo9Fjjmt(|x1Jr|&+rZs&}b@796 z-`5O#9=RY;4@&2g!SP6L})T?fr!e55Ea?lkX+ZB%-~GnRg1_*saFB z>i(X@qIY-1d-R{lZ03mkZzB5+p}&o6FQLDK+)09c^z42`|L&2xd2hju5%XU4bx17g z*gz&t>VGG*IoHEX*SB)F?8~`G$Jr0#?ZxB!{sz(xH>Z2x9@>k#?=_Iqwfh~)+x-^h z^|73;zu%R-z1XDtZOPkLGku(@+@psecg_7eO-=UK2Z`UtNBscQ2lYc^bY%}>;r|%2 z*f`$q%^}EL@;9JOKi}Xmr0qhMcPPVP#I~pN8Af&{#(I~!e#*|~2=qHM9f3Pr`7h*u z3VsywXg>zmE{{5oBb(y~?s9)mLSpvy2RYQAgv@2Ea>SlOw#U$)MmE>2td~(_eZ=)~ z=BFWhv3B24J!bSQa?HqBW1P`*khYl7c!t6Lnb8?!_aJ7ZuHPx<@4e4M{=N22{k-2g z#GQ?EvOjtBa~3(@&x`0{{iQ_V*XHuRSK-zx_pM)pzYck{zX8`SkA5y8n_UH~MdUzrR9Xhq@ts<6HDKvc4Yk z-+_Mv>94Q7s_SR3QIGsj{*s=A{2RFy-FNkDgH90F3E!TRyO8bWF1UB~z= uint(1 << int(i_1))) + { + Monoid other = sh_scratch[gl_LocalInvocationID.x - uint(1 << int(i_1))]; + Monoid param_2 = other; + Monoid param_3 = agg; + agg = combine_monoid(param_2, param_3); + } + GroupMemoryBarrierWithGroupSync(); + sh_scratch[gl_LocalInvocationID.x] = agg; + } + GroupMemoryBarrierWithGroupSync(); + Monoid row = _133; + if (gl_LocalInvocationID.x > 0u) + { + row = sh_scratch[gl_LocalInvocationID.x - 1u]; + } + for (uint i_2 = 0u; i_2 < 8u; i_2++) + { + Monoid param_4 = row; + Monoid param_5 = local[i_2]; + Monoid m = combine_monoid(param_4, param_5); + _42.Store((ix + i_2) * 4 + 0, m.element); + } +} + +[numthreads(512, 1, 1)] +void main(SPIRV_Cross_Input stage_input) +{ + gl_LocalInvocationID = stage_input.gl_LocalInvocationID; + gl_GlobalInvocationID = stage_input.gl_GlobalInvocationID; + comp_main(); +} diff --git a/tests/shader/gen/prefix_root.msl b/tests/shader/gen/prefix_root.msl new file mode 100644 index 0000000..ff02287 --- /dev/null +++ b/tests/shader/gen/prefix_root.msl @@ -0,0 +1,112 @@ +#pragma clang diagnostic ignored "-Wmissing-prototypes" +#pragma clang diagnostic ignored "-Wmissing-braces" + +#include +#include + +using namespace metal; + +template +struct spvUnsafeArray +{ + T elements[Num ? Num : 1]; + + thread T& operator [] (size_t pos) thread + { + return elements[pos]; + } + constexpr const thread T& operator [] (size_t pos) const thread + { + return elements[pos]; + } + + device T& operator [] (size_t pos) device + { + return elements[pos]; + } + constexpr const device T& operator [] (size_t pos) const device + { + return elements[pos]; + } + + constexpr const constant T& operator [] (size_t pos) const constant + { + return elements[pos]; + } + + threadgroup T& operator [] (size_t pos) threadgroup + { + return elements[pos]; + } + constexpr const threadgroup T& operator [] (size_t pos) const threadgroup + { + return elements[pos]; + } +}; + +struct Monoid +{ + uint element; +}; + +struct Monoid_1 +{ + uint element; +}; + +struct DataBuf +{ + Monoid_1 data[1]; +}; + +constant uint3 gl_WorkGroupSize [[maybe_unused]] = uint3(512u, 1u, 1u); + +static inline __attribute__((always_inline)) +Monoid combine_monoid(thread const Monoid& a, thread const Monoid& b) +{ + return Monoid{ a.element + b.element }; +} + +kernel void main0(device DataBuf& _42 [[buffer(0)]], uint3 gl_GlobalInvocationID [[thread_position_in_grid]], uint3 gl_LocalInvocationID [[thread_position_in_threadgroup]]) +{ + threadgroup Monoid sh_scratch[512]; + uint ix = gl_GlobalInvocationID.x * 8u; + spvUnsafeArray local; + local[0].element = _42.data[ix].element; + Monoid param_1; + for (uint i = 1u; i < 8u; i++) + { + Monoid param = local[i - 1u]; + param_1.element = _42.data[ix + i].element; + local[i] = combine_monoid(param, param_1); + } + Monoid agg = local[7]; + sh_scratch[gl_LocalInvocationID.x] = agg; + for (uint i_1 = 0u; i_1 < 9u; i_1++) + { + threadgroup_barrier(mem_flags::mem_threadgroup); + if (gl_LocalInvocationID.x >= uint(1 << int(i_1))) + { + Monoid other = sh_scratch[gl_LocalInvocationID.x - uint(1 << int(i_1))]; + Monoid param_2 = other; + Monoid param_3 = agg; + agg = combine_monoid(param_2, param_3); + } + threadgroup_barrier(mem_flags::mem_threadgroup); + sh_scratch[gl_LocalInvocationID.x] = agg; + } + threadgroup_barrier(mem_flags::mem_threadgroup); + Monoid row = Monoid{ 0u }; + if (gl_LocalInvocationID.x > 0u) + { + row = sh_scratch[gl_LocalInvocationID.x - 1u]; + } + for (uint i_2 = 0u; i_2 < 8u; i_2++) + { + Monoid param_4 = row; + Monoid param_5 = local[i_2]; + Monoid m = combine_monoid(param_4, param_5); + _42.data[ix + i_2].element = m.element; + } +} + diff --git a/tests/shader/gen/prefix_root.spv b/tests/shader/gen/prefix_root.spv new file mode 100644 index 0000000000000000000000000000000000000000..70ba31c92ccab887aaf9be7a7fc71ee83cc25c2a GIT binary patch literal 4104 zcmZ{miE>m`5QcA@B!oo*0$M0w0tm<^D2s?7AR5phAnse3EF`0oOiU&$ii#NA7u*q1 zal^GNpTY7$dC^WPg^LzUNRozRQqq!qm(-r=$we?p zGC65Zbw}sE&XuFp-j!?Ct}F$cL9nZ|ng=?E#)T&^kb z519M}Xd)uNR!l+3uF6oQ)SHl@DaBApU%79vZ>S2>noI%rR0g|CLw#L?Y3!2G>d076 zbwzFEim}zJH~yDlZGp2UNfFVWjPB0t+33HgIm3(4`I^N(=WA|EmVmbxtHo_&2hwwieR|>4*0WTDNBdfIDYYAuZRp|R zNO3U3w_Jb=$!>75zn^tY$vxPk16`v%BgJaZKk`itW<|o`#N`mw_(_o8KDrTdQm3H)hzL zMLuKaB0k2?L+g`wKXp4|J#)bJu2yd?eqn~?J>Md9EoUL^zgT_=dNJZ2SEKEZoHdE< zy`28#neE!B;W}*Vnn~0R8E-W15*n8Yohy6C>{eBw)yWV#_ud#%DY&c`^5-L2>l|R_y4%`P|F? zcOd$r*E=!}^>43tVmrgpYq4<~xLfDuHpJh5_cShQydB#b?TIysjkWLIfxT15xjV7* z=e`3h=Qk+sRW5(8-a+iQ7u)^zAm+5TI}v%;@6NFC&iQ?a-=F-P-=FcZ{sFM-T;uoY zA;fQ(apn{oqwRZaF6(;)?fKNs-F|ct@zLLn)~}B9_h6eN=B^K0t`~9c#9hdK#I@SL zz#l*>{Yac`0K5KdB{=!m?@?^``yeLo#<1n%eL9G39{ISVL)hMtzPQK3*z(@f zFj^eGC$Q!89YKr3cNE+E*XMUv9CQB^_7uc5`iwDF-aC#ysQ>Stp2k<-muKMQqlRPH z=8f|`i|zT0b5HRx#66ucd#`rAcX%AJukk&3F5~R2>-EXy=XO81zGh>`;ZGoOug_!G z*Z%^X{P)?+yofC~7jb4@M*BE3`d&ihtXn&Bzk*$#`&Bskxc}F%<^0}9e_qG7Kl-AF zZ(z&E8N{A9_EqaUiMCFCZ=$V9?K}K7`W?ha|GQ}Y>ge@**yf0L_= uint(1 << int(i_1))) + { + Monoid other = sh_scratch[gl_LocalInvocationID.x - uint(1 << int(i_1))]; + Monoid param_2 = other; + Monoid param_3 = agg; + agg = combine_monoid(param_2, param_3); + } + GroupMemoryBarrierWithGroupSync(); + sh_scratch[gl_LocalInvocationID.x] = agg; + } + GroupMemoryBarrierWithGroupSync(); + Monoid row = _133; + if (gl_WorkGroupID.x > 0u) + { + Monoid _148; + _148.element = _143.Load((gl_WorkGroupID.x - 1u) * 4 + 0); + row.element = _148.element; + } + if (gl_LocalInvocationID.x > 0u) + { + Monoid param_4 = row; + Monoid param_5 = sh_scratch[gl_LocalInvocationID.x - 1u]; + row = combine_monoid(param_4, param_5); + } + for (uint i_2 = 0u; i_2 < 8u; i_2++) + { + Monoid param_6 = row; + Monoid param_7 = local[i_2]; + Monoid m = combine_monoid(param_6, param_7); + _42.Store((ix + i_2) * 4 + 0, m.element); + } +} + +[numthreads(512, 1, 1)] +void main(SPIRV_Cross_Input stage_input) +{ + gl_WorkGroupID = stage_input.gl_WorkGroupID; + gl_LocalInvocationID = stage_input.gl_LocalInvocationID; + gl_GlobalInvocationID = stage_input.gl_GlobalInvocationID; + comp_main(); +} diff --git a/tests/shader/gen/prefix_scan.msl b/tests/shader/gen/prefix_scan.msl new file mode 100644 index 0000000..c1efb22 --- /dev/null +++ b/tests/shader/gen/prefix_scan.msl @@ -0,0 +1,123 @@ +#pragma clang diagnostic ignored "-Wmissing-prototypes" +#pragma clang diagnostic ignored "-Wmissing-braces" + +#include +#include + +using namespace metal; + +template +struct spvUnsafeArray +{ + T elements[Num ? Num : 1]; + + thread T& operator [] (size_t pos) thread + { + return elements[pos]; + } + constexpr const thread T& operator [] (size_t pos) const thread + { + return elements[pos]; + } + + device T& operator [] (size_t pos) device + { + return elements[pos]; + } + constexpr const device T& operator [] (size_t pos) const device + { + return elements[pos]; + } + + constexpr const constant T& operator [] (size_t pos) const constant + { + return elements[pos]; + } + + threadgroup T& operator [] (size_t pos) threadgroup + { + return elements[pos]; + } + constexpr const threadgroup T& operator [] (size_t pos) const threadgroup + { + return elements[pos]; + } +}; + +struct Monoid +{ + uint element; +}; + +struct Monoid_1 +{ + uint element; +}; + +struct DataBuf +{ + Monoid_1 data[1]; +}; + +struct ParentBuf +{ + Monoid_1 parent[1]; +}; + +constant uint3 gl_WorkGroupSize [[maybe_unused]] = uint3(512u, 1u, 1u); + +static inline __attribute__((always_inline)) +Monoid combine_monoid(thread const Monoid& a, thread const Monoid& b) +{ + return Monoid{ a.element + b.element }; +} + +kernel void main0(device DataBuf& _42 [[buffer(0)]], device ParentBuf& _143 [[buffer(1)]], uint3 gl_GlobalInvocationID [[thread_position_in_grid]], uint3 gl_LocalInvocationID [[thread_position_in_threadgroup]], uint3 gl_WorkGroupID [[threadgroup_position_in_grid]]) +{ + threadgroup Monoid sh_scratch[512]; + uint ix = gl_GlobalInvocationID.x * 8u; + spvUnsafeArray local; + local[0].element = _42.data[ix].element; + Monoid param_1; + for (uint i = 1u; i < 8u; i++) + { + Monoid param = local[i - 1u]; + param_1.element = _42.data[ix + i].element; + local[i] = combine_monoid(param, param_1); + } + Monoid agg = local[7]; + sh_scratch[gl_LocalInvocationID.x] = agg; + for (uint i_1 = 0u; i_1 < 9u; i_1++) + { + threadgroup_barrier(mem_flags::mem_threadgroup); + if (gl_LocalInvocationID.x >= uint(1 << int(i_1))) + { + Monoid other = sh_scratch[gl_LocalInvocationID.x - uint(1 << int(i_1))]; + Monoid param_2 = other; + Monoid param_3 = agg; + agg = combine_monoid(param_2, param_3); + } + threadgroup_barrier(mem_flags::mem_threadgroup); + sh_scratch[gl_LocalInvocationID.x] = agg; + } + threadgroup_barrier(mem_flags::mem_threadgroup); + Monoid row = Monoid{ 0u }; + if (gl_WorkGroupID.x > 0u) + { + row.element = _143.parent[gl_WorkGroupID.x - 1u].element; + } + if (gl_LocalInvocationID.x > 0u) + { + Monoid param_4 = row; + Monoid param_5 = sh_scratch[gl_LocalInvocationID.x - 1u]; + row = combine_monoid(param_4, param_5); + } + for (uint i_2 = 0u; i_2 < 8u; i_2++) + { + Monoid param_6 = row; + Monoid param_7 = local[i_2]; + Monoid m = combine_monoid(param_6, param_7); + _42.data[ix + i_2].element = m.element; + } +} + diff --git a/tests/shader/gen/prefix_scan.spv b/tests/shader/gen/prefix_scan.spv new file mode 100644 index 0000000000000000000000000000000000000000..d4216e95f91038753486e70cb2a8db3ac3beca00 GIT binary patch literal 4736 zcmZ{mhjUa_6vm%y5`!QC5giMfC?L`l6)ac)(TE0#Vn+>|LK01~akH@(#29<;6;ZL% z?22t1{}BHQ+l-FC-`jWeWgTzk%=y0WoO|!N=iaxI!lYyOPm=wT1Cqw%hom}YB$H5* zWJ=PI`qs7$ZA(Tf-AhhccA^>6l0uqjP80L$@paf>v46fbmHN9AR;W)oQqnWfGuSg!L1{{+!n;a?o&7^S9fN7^{Et@p_@xx#Y%r^ zXziLbw=S8BA3z+)_&j{RX1U|vn(LDJ@HNFsarNlt^jvaBH=5ph76=&Plkoj1u1i+q zhl}OnV8+jzzzfNGc(J#adG*N^;E}$Lk*;#F($!Zzk9Wd(+AO)|IO$&35s$rw!KF%H zPZ{rh+=kEZea8e|NXFph(kv-+Ma-a|Cax(v;hO_dFttk7xYwj6aIc?-#wv@23{~*{A$| za`)R0bN}!0?&q7H$=5as-@Ck##Cqn=#vJA!g*T?|e)<;7dX9wKt7^T~ z{5cs{_k8p4)in$0{mRwnyLw7e>OexeMY~0hjRCQ9PgTH&XfBVqhI?n+<;$1_q}W1rsuS8+H&5P z`JT<;`}hr|9`BmIBj2$#%IDzc=D2ZxDwFAaDM~y@jGhx zSPl2LE1$nT$K7v7j$7}}8os-R`y1wZtLTc~!O@uCiuZLEJ+Z&dnEDtw@?)@OtOYxp zuG&Mj$X^InTSd0-dNJl(_Zv25o_D?kGv?mbdIDzu&ATMq>qM}54)Z+YQp{ZQ++S{< z*!%MCf9IZ0!F%8OU)Xaw{#49i{4~6AebjzB*fsXBm*3n9OwF_Y!5Z>qm}@y#9CObE zJ2&`Q8Q+?nNzt(dXs^#z%R`={4y!M^e6wcNbZxm(}Oh1gWgJ#(?2wfwz$2eIEJVE1dsT+`Yv#nhd@KI7*5&acA!oy))Tt1~_3 zUjuiZb2j3y#r&-_&o$-di2cr8%lfXzdp^DIZWF$UIgEGWjqBt5U0~OUch>_}>&AR{ z@(yeh=3Md5=$r9cFBWI(1J|CdA5A^>y8-NeKXJBc_!}{Mt$ru#HsA*^^o-&$x)H4Fk*HeL8k9yQI3RaKr>1MF&sK*`M0``uK z#Xa(`ccSh+4ddkzyB(}%>^8hSVt0bQe`EeG%j4bO1)hpI$Cx?hs(Z)L2mSxu)7`{s z`*IJOdepE5?7DHjd%>R1Jol7u!Q9g~X7BaR_YSvW_BDP_?#ncL>wIHs`FFbsUR$%d zW9au|ajy@6$FbR1?Drs8{iE#7JOoxV$2ao`-r<`u_AsVq-QrmLNpS7jPob&D{XY#> z^Y=b}>z)BWfi+>qt!p0sSb$H_zTgjryqZ1#s>Cy@;kB z=YI*T7UzEj?C|`?UdGfszc|)@6y7Qedro8T;60Px-@y0q?_&<*AK;Da;}v2LnHoUY%b=U$p0kMJ;z?KJo@k{ z*gm+9F>`j})not9z=!4d=V0rJ@9qn*IqI?Jmtfb4xBC@%0p|NNKi=xsU~?UwVITe* z%=~z(a`Wu1eYQXPsP9{FzMk*kYVkW@Of7$R_W4i#Q$G#!f9d_<_Q5e3JC#1z&jWIJ z3fR35#9OQ1)eOuWYmIsi%Jj&Y33qNj=U}*c^l%o~dFt)F2kSWmQ~!%S#n$>avB;sb literal 0 HcmV?d00001