From 175220a682bd826f1c122022c95e4c4aaee381b1 Mon Sep 17 00:00:00 2001 From: Jerry Ling Date: Sat, 28 Jan 2023 16:01:57 -0500 Subject: [PATCH] handle RNTupleCardinality field and add test file (#209) * handle RNTupleCardinality field and add test file --- Project.toml | 4 +- src/RNTuple/bootstrap.jl | 6 -- src/RNTuple/constants.jl | 9 ++- src/RNTuple/fieldcolumn_reading.jl | 68 +++++++++++++++--- src/RNTuple/fieldcolumn_schema.jl | 31 +++++++- src/UnROOT.jl | 1 + src/iteration.jl | 4 ++ test/rntuple_tests.jl | 12 +++- ...DoubleMuParked_Muons_rntuple_1000evts.root | Bin 0 -> 31135 bytes 9 files changed, 113 insertions(+), 22 deletions(-) create mode 100644 test/samples/RNTuple/Run2012BC_DoubleMuParked_Muons_rntuple_1000evts.root diff --git a/Project.toml b/Project.toml index f1caec7c..5b40a674 100644 --- a/Project.toml +++ b/Project.toml @@ -1,11 +1,12 @@ name = "UnROOT" uuid = "3cd96dde-e98d-4713-81e9-a4a1b0235ce9" authors = ["Tamas Gal", "Jerry Ling", "Johannes Schumann", "Nick Amin"] -version = "0.8.22" +version = "0.8.23" [deps] AbstractTrees = "1520ce14-60c1-5f80-bbc7-55ef81b5835c" ArraysOfArrays = "65a8f2f4-9b39-5baf-92e2-a9cc46fdf018" +BitIntegers = "c3b6d118-76ef-56ca-8cc7-ebb389d030a1" CodecLz4 = "5ba52731-8f18-5e0d-9241-30f10d1ec561" CodecXz = "ba30903b-d9e8-5048-a5ec-d1f5b0d4b47b" CodecZstd = "6b39b394-51ab-5f42-8807-6242bab2b4c2" @@ -28,6 +29,7 @@ xrootdgo_jll = "9d84c17e-11f2-50ef-8cc9-e9701362097f" [compat] AbstractTrees = "^0.3.0, 0.4" ArraysOfArrays = "^0.5.3, ^0.6" +BitIntegers = "^0.2.6" CodecLz4 = "^0.3.0, ^0.4.0" CodecXz = "^0.6.0, ^0.7.0" CodecZstd = "^0.6.0, ^0.7.0" diff --git a/src/RNTuple/bootstrap.jl b/src/RNTuple/bootstrap.jl index 39aa27cc..02ceb1d8 100644 --- a/src/RNTuple/bootstrap.jl +++ b/src/RNTuple/bootstrap.jl @@ -180,9 +180,3 @@ function _rntuple_read(io, ::Type{RNTupleListNoFrame{T}}) where T seek(io, end_pos) return res end - -primitive type Switch <: Integer 64 end -Base.show(io::IO, ::Type{Switch}) = print(io, "Switch") -Base.:&(x::Switch, y::Switch) = Switch(UInt64(x) & UInt64(y)) -Base.Int64(x::Switch) = reinterpret(Int64, x) -Base.UInt64(x::Switch) = reinterpret(UInt64, x) diff --git a/src/RNTuple/constants.jl b/src/RNTuple/constants.jl index 1728a15b..525d3422 100644 --- a/src/RNTuple/constants.jl +++ b/src/RNTuple/constants.jl @@ -1,7 +1,12 @@ +# the signed ones are not used +@define_integers 64 SignedSwitch Switch +@define_integers 32 SignedIndex32 Index32 +@define_integers 64 SignedIndex64 Index64 + #https://github.com/root-project/root/blob/master/tree/ntuple/v7/doc/specifications.md const rntuple_col_type_dict = ( - Int64, - Int32, + Index64, + Index32, Switch, # Switch UInt8, UInt8, # char diff --git a/src/RNTuple/fieldcolumn_reading.jl b/src/RNTuple/fieldcolumn_reading.jl index 55266dbf..efaf2be0 100644 --- a/src/RNTuple/fieldcolumn_reading.jl +++ b/src/RNTuple/fieldcolumn_reading.jl @@ -1,3 +1,28 @@ +""" + _field_output_type(::Type{F}) where F + +This is function is used in two ways: + +- provide a output type prediction for each "field" in RNTuple so we can +achieve type stability +- it's also used to enforce the type stability in [`read_field`](@ref): + +``` + # this is basically a type assertion for `res` + return res::_field_output_type(field) +``` +""" +function _field_output_type() end + +""" + read_field(io, field::F, page_list) where F + +Read a field from the `io` stream. The `page_list` is a list of PageLinks for the +current cluster group. The type stability is achieved by type asserting +based on type `F` via [`_field_output_type`](@ref) function. +""" +function read_field() end + _field_output_type(x::T) where T = _field_output_type(T) function _field_output_type(::Type{StdArrayField{N, T}}) where {N, T<:LeafField} @@ -30,7 +55,30 @@ function read_field(io, field::StringField{O, T}, page_list) where {O, T} return res::_field_output_type(field) end -_field_output_type(::Type{LeafField{T}}) where {T} = Base.ReinterpretArray{T, 1, UInt8, Vector{UInt8}, false} +const T_Reinter{T} = Base.ReinterpretArray{T, 1, UInt8, Vector{UInt8}, false} + +struct CardinalityVector{T} <: AbstractVector{T} + contents::T_Reinter{T} +end +Base.length(ary::CardinalityVector) = length(ary.contents) +Base.size(ary::CardinalityVector) = (length(ary.contents), ) +Base.IndexStyle(::CardinalityVector) = IndexLinear() +function Base.getindex(ary::CardinalityVector{T}, i::Int) where {T} + ary.contents[i] - get(ary.contents, i-1, zero(T)) +end + + +_field_output_type(::Type{RNTupleCardinality{T}}) where {T} = CardinalityVector{T} +function read_field(io, field::RNTupleCardinality{T}, page_list) where T + nbits = field.nbits + pages = page_list[field.content_col_idx] + bytes = read_pagedesc(io, pages, nbits) + contents = reinterpret(T, bytes) + res = CardinalityVector(contents) + return res::_field_output_type(field) +end + +_field_output_type(::Type{LeafField{T}}) where {T} = T_Reinter{T} function read_field(io, field::LeafField{T}, page_list) where T nbits = field.nbits pages = page_list[field.content_col_idx] @@ -55,7 +103,7 @@ function read_field(io, field::LeafField{Bool}, page_list) return res::_field_output_type(field) end -_field_output_type(::Type{VectorField{O, T}}) where {O, T} = VectorOfVectors{eltype(_field_output_type(T)), _field_output_type(T), Vector{Int32}, Vector{Tuple{}}} +_field_output_type(::Type{VectorField{O, T}}) where {O, T} = VectorOfVectors{eltype(_field_output_type(T)), _field_output_type(T), Vector{eltype(O)}, Vector{Tuple{}}} function read_field(io, field::VectorField{O, T}, page_list) where {O, T} offset = read_field(io, field.offset_col, page_list) content = read_field(io, field.content_col, page_list) @@ -71,9 +119,12 @@ function _field_output_type(::Type{StructField{N, T}}) where {N, T} types2 = Tuple{_field_output_type.(T.types)...} StructArray{NamedTuple{N, types}, 1, NamedTuple{N, types2}, Int64} end + """ - Since each field of the struct is stored in a separate field of the RNTuple, - this function returns a `StructArray` for efficiency / performance reason. + read_field(io, field::StructField{N, T}, page_list) where {N, T} + +Since each field of the struct is stored in a separate field of the RNTuple, +this function returns a `StructArray` to maximize efficiency. """ function read_field(io, field::StructField{N, T}, page_list) where {N, T} contents = (read_field(io, col, page_list) for col in field.content_cols) @@ -100,14 +151,13 @@ function Base.getindex(ary::UnionVector, i::Int) end function _split_switch_bits(content) - kindex = Int64.(content) .& 0x00000000000FFFFF .+ 1 - tags = Int8.(UInt64.(content) .>> 44) + kindex = content .& 0x00000000000FFFFF .+ 1 + tags = Int8.(content .>> 44) return kindex, tags end function _field_output_type(::Type{UnionField{S, T}}) where {S, T} - type = Union{eltype.(_field_output_type.(T.types))...} - type2 = Tuple{_field_output_type.(T.types)...} - return UnionVector{type, type2} + types = _field_output_type.(T.types) + return UnionVector{Union{eltype.(types)...}, Tuple{types...}} end function read_field(io, field::UnionField{S, T}, page_list) where {S, T} switch = read_field(io, field.switch_col, page_list) diff --git a/src/RNTuple/fieldcolumn_schema.jl b/src/RNTuple/fieldcolumn_schema.jl index c678bdfc..d3b54d2f 100644 --- a/src/RNTuple/fieldcolumn_schema.jl +++ b/src/RNTuple/fieldcolumn_schema.jl @@ -28,6 +28,7 @@ end """ struct LeafField{T} content_col_idx::Int + nbits::Int end Base case of field nesting, this links to a column in the RNTuple by 0-based index. @@ -39,15 +40,33 @@ struct LeafField{T} nbits::Int end +""" + struct RNTupleCardinality{T} + content_col_idx::Int + nbits::Int + end + +Special field. The cardinality is basically a counter, but the data column is +a leaf column of Index32 or Index64. To get a number from Cardinality, one needs to +compute `ary[i] - ary[i-1]`. +""" +struct RNTupleCardinality{T} + content_col_idx::Int + nbits::Int +end +RNTupleCardinality(l::LeafField{T}) where T = RNTupleCardinality{T}(l.content_col_idx, l.nbits) + +Base.eltype(::Type{LeafField{T}}) where T = T + function _search_col_type(field_id, column_records, col_id::Int...) if length(col_id) == 2 && - # String is the only known leaf field that splits in column records column_records[col_id[1]].type == 2 && column_records[col_id[2]].type == 5 return StringField(LeafField{Int32}(col_id[1], 32), LeafField{Char}(col_id[2], 8)) elseif length(col_id) == 1 record = column_records[only(col_id)] - return LeafField{rntuple_col_type_dict[record.type]}(only(col_id), record.nbits) + LeafType = rntuple_col_type_dict[record.type] + return LeafField{LeafType}(only(col_id), record.nbits) else error("un-handled base case, report issue to authors") end @@ -82,7 +101,13 @@ function _parse_field(field_id, field_records, column_records, alias_columns, :: # field_id in 0-based index field = field_records[field_id + 1] if iszero(field.repetition) - return _search_col_type(field_id, column_records, alias_columns) + res = _search_col_type(field_id, column_records, alias_columns) + if eltype(res) <: Union{Index32, Index64} + # https://github.com/root-project/root/pull/12127 + return RNTupleCardinality(res) + else + return res + end else # `std::array<>` for some reason splits in Field records and pretent to be a leaf field element_idx = findlast(field_records) do field diff --git a/src/UnROOT.jl b/src/UnROOT.jl index 81e31e85..24dd7073 100644 --- a/src/UnROOT.jl +++ b/src/UnROOT.jl @@ -15,6 +15,7 @@ using Mixers, Parameters, Memoization, LRUCache import IterTools: groupby using LibDeflate: zlib_decompress!, Decompressor, crc32 +using BitIntegers: @define_integers import Tables, PrettyTables diff --git a/src/iteration.jl b/src/iteration.jl index 2ad1187d..5027ce01 100644 --- a/src/iteration.jl +++ b/src/iteration.jl @@ -218,6 +218,10 @@ function Base.show(io::IO, evt::LazyEvent) show(io, collect(evt)) end +function Base.show(io::IO, ::Type{<:LazyEvent}) + print(io, "UnROOT.LazyEvent") +end + struct LazyTree{T<:NamedTuple} <: AbstractVector{LazyEvent{T}} treetable::T end diff --git a/test/rntuple_tests.jl b/test/rntuple_tests.jl index 11c8101d..7023e88a 100644 --- a/test/rntuple_tests.jl +++ b/test/rntuple_tests.jl @@ -42,7 +42,7 @@ end sample = schema2.vector_tuple_int32_string @test sample isa UnROOT.VectorField - @test sample.offset_col isa UnROOT.LeafField{Int32} + @test sample.offset_col isa UnROOT.LeafField{UnROOT.Index32} @test sample.offset_col.content_col_idx == 9 @test sample.content_col isa UnROOT.StructField @@ -110,6 +110,16 @@ end @test df.array_lv[5] == fill((pt=5.0, eta=5.0, phi=5.0, mass=5.0), 3) end +@testset "RNTupleCardinality" begin + f1 = UnROOT.samplefile("RNTuple/Run2012BC_DoubleMuParked_Muons_rntuple_1000evts.root") + t = LazyTree(f1, "Events") + @test t.nMuon == + length.(t.Muon_pt) == + length.(t.Muon_eta) == + length.(t.Muon_mass) == + length.(t.Muon_charge) +end + @testset "RNTuple Type stability" begin f1 = UnROOT.samplefile("RNTuple/test_ntuple_int_5e4.root") t = LazyTree(f1, "ntuple") diff --git a/test/samples/RNTuple/Run2012BC_DoubleMuParked_Muons_rntuple_1000evts.root b/test/samples/RNTuple/Run2012BC_DoubleMuParked_Muons_rntuple_1000evts.root new file mode 100644 index 0000000000000000000000000000000000000000..1ce0ed565ba1dbb459cd31e0e03de57be4f608e6 GIT binary patch literal 31135 zcmb@sbxdVJ_bqrY?oMMDhsNFI;_faDjk~+MySr=SPUFzHyEctGH0}=5-}n3Hy=0P^ z%$rJfok~^eoVE5!PIgt6lfAtQ0C4{k005W(0G{~(0Fe3L*ydkA{EGyrf1N1+;J)#1 zp&tOet|F_=mqtHtwXwdc?CrVyxBCC8O#=S&A{PgbLtB6r0QhhG?`r@6w3>vajVUK1 zlZvYyD>DnLh^W4py{nOpsl2O_p_8?#iN3t6y`8hZlbwsJgN>;^3o|pbshf*4qtkz2 z|9{;Ffc_7TfANnk;K#p6_!s}h^N%Rk|07A8|8l|l@BaUC`ESNd{?EAlCnvz1e@Pel z&&V_1og)SC`T42+f0UqqwEokK{tFo4A7Ib_Nj`Ar-|YVnfFVTx1M?s72FNo20BZWb zDIxo>y#Hn)ME`aFeL|~<*w`BZ0N+%Ben7x96oC3C)4RbmWGNybD3*=Gzn)SpWVRKgp#MXop(^aQ1R<)mXYPi^U1h(V$Gl*rd^#z zzCZlg2GW9GV1#aAmq7N1Zt727m*64kQM4mT40Xau;x8NN>u;>WO0`umVUc;VYS|Ne z^Y4v1r?ziewp;jsU4LOZ*-XHq3)~UWI#$C&n)r|uXlZhOW+Ehl(I_xVPn#IZAxL8?Pk)pHgWE(Yas-aGV}`}Q#Hz_ z%^SmbJzPB0D#l~ zk6@?;|GQw2cmE?8FqAf_N;#m<5xjlf$5JsePUyCfhI z`^93~3>*0joiNWRmZYeRGpG&$0T53>NzXVt?#dmDuwp(*W>CAsV1HsRId+^9H|-8} zNHMRZOC104w#D=uw4@U)chWXoP%*b8B8bxA?r=1q7#Ih^?c{tH_h*jRYyL1~>Lg2* zqs&5KCMS)D(plt?{a9_%G6R#jOi!UR$BAdhsqsK<0zNI7j!HwJGDnFg(+T2WaSVQz zCRvq|N?IX-+v(eW$>_;UMZy9Jm5_p8&J*{6W5*uF2z*>J0Tri$dCo9*sN>DpmA&o=u}NZ(0NGBg!}0(uS+H-|$|aW75aLN+F_44`1AaJkqs)%46!cR0VE z$>waTa6IZW8~x0TdYJy`q!%{<4W2dUp|?M%)=f=!Qehky<)MDu&-F=$?D#sepQ4*2 z>LfWm`Uy%TxDkQzBstpi){Wo0<`o#(X(O=Tvj)XxJFXbbPo}YP;~RaP1c)kWIi zCM&a_lTovOGt^nC3^aaKdug9Hj+;_iU|VoZ(57M2(`jl{SF30jHnN(EkISTBQ|DH5 zYFjpro4AfyC8<-;NomAY<7!hjzBKWgaE#I>ED=`;Xn0rOXstFB8B>n@jm0LQPMK0JB)5($=LtGI&LlUBOX0zH*`GjXlI#E-IJrzD78DCfHh{XF z7RTpkB`ZLgPGaMU)RF}tPp82#^a66ZI9i^peQFGexDODa6U8VxiKO3^W68)Ip`of0cbwRB8kv_(1~?mYC>1h2t3 z+d0v<$vZ@Ee>s9VYUyPNT+7Y|azWTZtOMGRH`Ze}78y1gGqJOj*^W2?^)MO!zQZJvGfi1LO*F>jlJF?l zB+X(bKPJ&K@mR@C9!6r~Gl|&v&DXRFpZaoCTDD- zwZE{@nW;^dWPn+$jamlfBDFD^$j!tjBQlU#5RD!NV#2la@KBlv%s3`3GRBxY*@6w1 z`zI9;nlQ~MCnYi>nXA|!4Ilbqf>&Xhc$$#Ra3=RBX*1-RqYVyw>8FvVkpfqNO%P_l z$@R%i8{6CQL)WS3EKPPM3%#kX6i;+7!dtRKj!DD}9Hu&5y;e9cXs@}OtOMu?>r_oz zCRM%SE)h@H8;HB{eb=#xBpk{*DZThEkSD{9%KrV4>nIR)=qdpbb=4CtG+fTZA|zbQ zqkLM_h3M}#Das)~#Ze(VQPg%JEK$@gT245I$MKXX48K^fCMUw9 zF{PliU;G>X^ZPTQ$S7077O|k9pYPkl)4_G;p5};s9JinS+n=YJYtcRPVfz?;TtP-Z zKR=zf+9&nv-yYt=o}RDvcG8c^22jKGkp=PnSl^7Ey046P z%KA}5_2GY^`?>nL_z}KwJ{evWZ&USM1`q~a6m zlygfzqg|D6j5c{3txen@>lEx1bqhIzS_L-l8K;k2#C<31dfNzSbb-c zv*Aep^fXE+A$%vA8_Ai#Z_oPdrU3&gbIm@xAVR247&iwuxHFXB@b!=eD{j_hZYM2M zHM6lUyF+a@7*#Uml}a6 z7drDUXE?aqOJX8Gm}erL3~+wlg=?l0f%{rDSf2I|gRH<>(^7dS?`GSb5a`zclhlGDF#1lhh@xrW+_jE%- zj>R)MB;j+Om1+IbXZImZ@ z)cLjK-CY8@gpA?5@E>s{qNbopT2uI3}DhHF3{|Q2*HA)Pu?`=juYD zZfM$YXFbSD)XI93R%cR}^LKlA;+ngpK5(IL;R^Jn(oXf#5<72r$;V|e~7ytSSgVZ~P z)9E%!S%?FKKHo5$)g@2&;=&h=2L}J;_L7a;7Cl0gzm9_%zF^CcdJn7!e+@Wz__luq zCJ?O~j8=zq96BN36hDWMi{3hxdsj^u{?#F-8$5Sa;j+))7?rMR*ghYlrIKH)x$9}p zwPAE${rUB71Nq^U+r_ves%3nnJKycKc8_q5gahus?NoLk8Ro$AB zy#@7b{JqTD-GYyyF#W|cSqg8MKz0Y{& zh9ErQG&_-s2{OOd+qn58p1sEBu+%NlfQdrO!CjqUfw|hy=^!HgHxa`q=SW{d&PbJ` zxD2Pf*E9@PY4r16>cs>upBcafEq{d^|@6$4q)&yG(svUK`b=n8tm%tNC0wO;l)#vbakyk%MrwI^*Tgg?JHnnmZ4eb zNfDUyI{keU;aGL1p4}&zlIrLW-5g#-Sp2>r3xUGyTwA;o*LL)Bqnhr_qIPONyX(sc z&L|(56%YPyh#YoDYH~zQ4psFdf>OYfeo_bQ&R3$#s7uJMj=UR*X?co@u63(4Dv4_s zdIx!~DCSd4GhyN>2rqOMD+M4+TQHr6pOnn4JcaV7`_~GcxAHMTz;725l+eAv#G7sq zLaV`06De$so=nJ!PxshmQwho?oMkP`-kMUxgy8JDI071F}sgisU%_APFC6 zVT(bn_j#iz+3Z^Q%)HU0kuZ~T^#peAR0z#nX0+M3f^JF^?*~2$;wbj-$&Z^wX&r?8 zd(uu_1O&UDlcdxk1aboCh2QrXU3wNm4+w6RJ{afhI7D;p8B{ZYw4jrn^3mYU2OrV0 zzlxw%ZYb6&a~~gYD$^pc%!AvPx_lQ+?t z!(iNU4zuJTn7JtLB|3t1Z}dZSi;3pk%%@Lw@&^`&gq+<5IH;Hku zChr^wuCkVCJHVG-eCipW!V_yg`PQN#9Q$~}3AXlz*f2P+nXFK=3*CJyzHU!ay+>I5 zZ*N0SSakoqmrAH2ujoN4OKXckCg!(d@BvhuG2Qpujj!YK z^$|31oOFltxo6Z!E^ccV+rv;uY>L7?0x&8G-Wy#+SBLRDx`3UJ*kPakIuI*;ofhl6 zpw?~MfL*G3jbT@Odsv_hve(NlZl()&Re%VyBH;ZEPA^H$enNky-|qQT3;KybH+b2L zzY7&Js%y^mC}}j32YELhjbtzZH0rynil2TH1u|;da(Jk3Pkl#LY9owlPH&;i8%bzo zXi{2(!0sA>@8is?J~PEj`H0RO>8Wz%SNk%#M+)6q!WciDv%wop9w2CRc;}3-beR#k zNYPKN-*GUwf*bv2FP+3`3*|K;!HJ|#Qa_6QcngE%D7WfYatvKwFMlTY4EQ)|h!dHi`ztvaL+mFPEunjBMeH=l%Z9 zN@fd*IkN6_9iQr2V3~uZYccV>IZ$-(`!Kgc;6SD|iQhXYyqnx%j~4^o2B!)tG1h0+ zglTs-xzN;XQjZibAz)dZis!R8BAQKL?rEyp;nVTHE6J>a%d`5U)6|Pt_BTDZ0fQ=G z+6T4pHafPy4@5d-o%rH-uF-Z6NzG`P1~$P|NjE78wZP67gG&RSfGboM@MM%0+C$djy?i60rK)Gdu7VUfbqU?kVbmH5f^Gb z3nh7IL6`o_q9-psVISdl%+=m)i@Jes>yV2YXEA|SvOA@8uIYjJ7WjrqFWd3u$gcX9 z3Sc#i^A5w__6vI|D^WW)Xst?LtN$5Z`Rls;&2@D$pB+#2V-8K>f!FYxCi@*U_s(XZ zM5aCqLjJhPj<)03sDKrhXO+}Wa>N|3He735jS8OzI*>Em0U>gHL{p zLRS*;xkeq>X3+YCWzMh#6nYQ|_SQUwxsL-yoYJCw?H%_^a%7zWl)!@)5YTQO6xa^6|M zU{buiL^tA(C`koikKTcazcS%1DG%F>qiTvb7W{1-_43v_eKyRM1L6-~P6uYS7X{@=rd$-?5s0kI-^dATv%_6y6LV_-)wQTN zmhOJWYXLs@OM)f!3}*i6AZS>`UYF&(T>(M@8~R4Jtl-0>1zq%)DzuVQ z!i-tKBq@t3mDS?u2TjtTp-?f~@n^^`A)q{Vj-UTA{I=As&O&5K%lKcWT&nLUvdk~? zD8K!?to9Y~q;| zjNz5>q15D2aXb=jYiYvIKM_!1>y2=^5VDxpO$hR~M8t-vkX$*cOEU0f?6T{^DSRP) zNL0Z$VTS2{mYX{Sesj0Cd2##d!v2wAyx7T>v_2Ul)7duYldF+9V5e-gjawxMSX*Eg zdTT~S=>l6*KB)+r^t3${Wd4RGRE)h>>k+l1XprMffVu$bJ>~XY8{7Q_k`v?l`oQ2k z^A2b5M2sca6h+Tar8ct{z%CuRQuj>3c2-&T3p9?+LR*AxItN=K5}?~*zo#^H+@W86 zW8aU9)xcVGB4i-UTflPDzz1Fo6sKo;@m)R#H1bej98>eq^#JQGP<%2zgqMb$RZKy_ zDX|Jr0}iO)GA`MY_^m7t9_6}vE;Js+zRSLg#NL|l8svmq9y@CWbwDO&eSO!qVuP*6 zAEwAe{e5$;$+_TuSOKTWp0wlTB%9SZ5wwT(DUdXBs|8nhLr##Ys1DyAx}HU+WwgDe zYqQbB`iWe5LMs!Mbrp350jkq$4IT=IsZzizK9d_zk83V@#VvNh5g~oaVa*dIA|q4@ z*$=mQYuU4(ah?hR2c*&vR|~Jvbf|e|XA(E1my!NjbR$-FY+IkHGKiiO)yc^x0C-fg zxjoYgJLqS@kI7Sc5ktZJZgVi`K#bpgh5P;y3$vcuxY(t#Gy*xgJ@ri|fl&A0G)HAb zpJZaksM8L)%wWPA!Ne>N-3WX_xlAi$;^!D~!H1MjDBpHp?B1LYLU;ipo7UZ~JujSG zCk}SGCG!DpQW5ty>1Fs%LVm0`{5y!z>4vWZ9$}5M>XPU0J6a14vzu>tX+<|lTu-RZ zBAALWFEp&p{gaJW{BUVe3lTz3l@QuGg)ynpzIiv79_D?L{ zkZ?At{A;TylAbw+y#`gUs8+{E^ z_l40kddEX@@V$F$b7Imv6{&2c$LKkeaV7bQaSWj{V!sC5_pz2V>zpqSF0>I2uSN5k z#x8!n-}LJPuAmY$dDOx-%N;DGUDCecUbz zwl1}|TRQ8fXu9wuU=FPiDD{`A!Jy97xNRl?-lJ}Bfvf!cMkJG9MD@sdBd7%xLFA(l zNglGdn3_rgZ@xZ9J3pr3k?Gs6ULW*Baz58|v)P_nySCl9^?nMu8-FFjs&{#PSA3v( zbY;!Yqy>Z-ZBo}JqHax<+;enQG}KC*S7pUrNQO3E>Pwv?k6asBpnxAFa9|b7e4WZ- z&{wQ1XMi-O3cn$5mih+F!#=~l@A9X9HJ#{)@U}&4mkKthqlPJ5?SgCTX9a{6m{kS4N6GcI?O6t#cG%0;WA=E5*VlQ9E<;~ z4NjwH!C;4CrJLxmL4@M_U#dfCf@3c+huBZxHE&`RlOV=KF+l*(>mt?{5sLIi1D6>u z-0obC!G=$y_No-_r=F!ykZO_o69N2hSRt7%$5a()+G5&e(is?JM#merOAehc!X2$>V^$w4@9ltyE>G)+j?ZR zFrGyAg8X*pn436&htzaFt9E}Se_%e?20#ufQF)8p$M(S{M)pa6!h_dBq;wJ7V0CReTHc zrI6)x(J#d9EGGZkN66|vR~+w%lEiD4B&~brbnN1G_Y%_B5qS?+p8R2{5o36lPpvX` za&i#B6IykJJQVPEiA|OVIeDy`k)FE*J9#+4bX%O9cdHUOcsU;SW;T5$=#=;o1|`S! z!hJKfR)&bb_j4V39;J(U2hohH&Ya**jA!8VxZV>-(JPj0YbPLv&^G$mc72;L5N?`o z=(rn-49?xx?vrS~`Mf$j`QvYk<6J1Bq2Gp^_$6@)r9jkq87aTUh6V1W@uHVW4J--o zf>aylZxdTWRy=GDct_Ye^VtTL@R=D1$&nlrct_9*xe1XWI zLx|rt9~3{TjJ0jO9<&;4kG!(P75KDaF;^{5%iQlA^`1f#7R0Z+|LlafkTZ0UBX0@( zfLOtvgi|b~S??O+ol&s{7bG8cqba|#$JVOb9@!b=2ouz`Sg064<|2IASIC#NOJQ?u zqO8+oCS%rt=W0vdilmYc`;epn5M~$O2s^yxh3}sWiTL}}ejQU)s^u`nq>}e4Ay3DC z*{8tYD7!B7lMVhhEFC+i;1{|6H8^x&T!kA)Yg1hafg45^J(kAgF;2^l3HMOMzxK(h z8=rY)z3VwSxdoJwnNplo&$?J~`fkR2ywzW?$&zY=WfA9(elSEwh3b5Sz5J?l&6&4z z?QFDdffr4zaA14}t+CRmLX&pJfmp<%`(Z&KpUoqiYFhdg7Z{rvFydK|0R~L32yCdm zqs9(Ti*#UYu*^Y1_QuyHnF_XJyYRO%qsFz>)Vw&}%c%~BA!x4M; zW%!0o?u-9zKys^>7Z@w;fngVvgO0ROIvCLt5c+YjpMLZm<-6?pUvPUbKg;Z~;zN`o z`6D+N$*E#s@40uR;_GBp$T$Ir!ut9`WgIjYNJ-U)pl)|Ta-%G-HA?Io;nPv^Wa zx^m3rgjQH-PDb(l-T7$Gl+l&iE5|@hA+ZF#*RKuqNceSfaV?FzEw&?RceKg6%d9L} zp&Ai9(Blx~aLsa?Ki88>6lMUjrR)pu&ELCU`t%rZc;9h9u7-4}MX`tD*{uoxvlGhA*+YDlS$w{e0@7DOQ^0<-D zAR@+$FZdn6Uh?7exXTW1_gyi`f!v;a%7ExuS07&i^cwi;{JWinhd6YTQIe;sEM}P4 z&Vv`eS5?2VbAx*-oLFQ+2;h&EBUR)lObEnvzbis*sS?_MjWo!GRleeluj`y#%s~}_ zx|G#d^pt}z(M#wP`%31Rm6*ZrH;#~@8T4!ls-ax9MhaZp*D|GOz2vZwkhGC9LU9J_V(Ak7-m{mv2w; zm$`3|M!EmOD4e;DwZf_6vpaCSdahym)Uf!=6!F2nmoJZBOn9zJe0?EivWMpuP> zgL|7;j%iVPD8O@c>PWb+;vwgGONQCCbg=h9!IaUl5`T(=92KaEoK570=@73ATFbe% z#8HJ{KQ7&;^KD|R5*?3q9NajL>a(ZkKB407S;5-0`rQL+m$s&LPE2ZnD(WnDLie3P zt;Xyhe=15pS#kcL4xcjKb1hJ~hS$&UGPTAoLA1xyBQqe==4^gW=bw%S6Vi`hfS zzL&{XSyGR+hcI#Tjw%^O?=;yi(&S&zy@Qiha$&tAPrjqcqlO^aQkIAM9&(<#=GR@W zHyyP>E(F1vbTTqYz$X5*LYGR?q+LA40V?sRWFq>raPNUtbp0U1)bpCJSJf@hz*O@0 zSZWcz_H`2tF*m%)au!FV9;X_(a=aV>qvEUjJ=K1-IQafsI~%ibEStZ>UCoLbq|UrB z>hk3f=iJQJZ!y&)$+-EWP*|@5X%tx%R=3mTYcBxh0j?cmA0qt8$KESf211#U zl%@;!1#^E>AFhx4FmL*`m!5~QGAtQ__?-6diN(i_~KEcho;f zAUzm}Q%3^EnV8hxBYE!clEA<|8m4AWDhJ!v(y(?~$GMue)u*g4rKl2k0vI`S=*pCx zi^zX9rJOIxVMks4D!SA>j?%%@>>%c2$lvJT{-iOWOQ_9uzm{GgPXsJmj8}3>#gcQU@qJt# z`)U}`el?u;n9;nAfuISg@b2Nojne1CQ{u;$Z`AP&6e9@uvP^<=42EWF^b%d7Aw8ad zFrG%q3JCUc?6~=cu6Xag6{CZQdxzawaTPaXjFC-YBZGJJMrEp9iMtQ3W}#Kx$!K|D zE7pr=(U%(qB^dG8i`0Rgiq~3e6OgOR;I3{Jyr#W?sJvnI^-G1x+zctjv(P))Fg2dB z*fs`g28&Hu*k6g!z8jcxdr$*csTvs#Q49ZZ03wqb1~B0rMINNm30bUZW4S?zc8kCNu{fUI$HqCDqqIF+<*b zz@sTsZ(UtC*7HAjvBX~|T}TKI`A#Gh#aEkKr=p!v0^ow+Lg3g`w-6L{Ca?J^>6}rq z{=_~*MHYXY3#6|T2@;6icS(5ta)}F_01OPhW2iYolPLJJwK}sYL|%)SID+G>=S6V~ z-`8osFr88!3Mwl6#NmPIIiP#Z(iL~#ZgS#-Qu;tcKKpzMI!G`x`wUHXGfQgrnky|z z=is{+8gD>#(Rs@zQ`HO8I3Z9;xC-@fV_GE_8%_+|7EB#~OQsOa#T)3R73~VA&*Qbd zytI$PyU9}|?^g(sHUe>H={2xgQ0+Y5h%P^&5-3`EYw(%1vdiBpLI-~~3EcskXI;_D z<7)d5!apgFomhX6gEh=1P(xZR7%-ZbA;xxmT@;?__>_)+eU-_DlyMDbX?T!#vFI{8 zOR_IA99Cr6`j7@~b(X8WXI6}+&6VO(eRccoW*Nd64W0F>hB%hayL~r0sBmfX>Vzq0 zB%mG};V#7M4DI{vkBm0zcj)N9pFYv@?dAu82qqtC_^6w-|o9zZl*17_QhylHS|+n0sNfnkX;Uhdw477G`mHSSX@;=ZNDi_o9-g9Qsu zeScLj!24vBZOCS0hDe=sy?Dk*4wGvTjq_hnolw8kRAa8tuC3!H*`wK;=6=;}lxI%E ze39;n)UL4abljK6hYRz?B6QagK{QS&+#M3A_f^?GDHZ_u2+h>G-vbYc4S{=0KX_w@ z7LFmh_}#Opz6l(T4T+WmcYTd4<9e+|GtCG*fU_%)6v6jqcdJL7%r_;WR(dWWzaKMp z?<&Pze8Ux%Ze4#r_pr2HLWJMr@N7SamyhK~Cj{8`?cnGYVRtApZ4i|U1=-T>-p~*h zo0S#Ov&JJ(;f?m^$UdzyKA0bxC~5wJgc@ugiHam%Wwu;}D1AvxQ4qbUXMWu#@&1MS z@~px<%_IHICv%l@gQ7XO$7Q}iFn2%0m)iNwB}!%aIyEO&f+hv zjPT28l%A>cV0P{Ysk?l^&bdK7i;xtqdQNj~xm9|y;`}3?75bH6QWB4160F1hesX#D zs-V_m$vh*u3B=e3oANpoI_Bdp}-xN>X z!w!>7zY|5~N4N^gNI(7!noew<+iA*byhWpP8}L%)&giS7u2SO5Y(6;`6B}re&$x*nzB0#G!0LHXdZ~7KdlhTZwr6Yl9LT zX?lmzVFje9?OAUW6#bgoat*e%Qh%>hNg1hDn8a= zZ{a4k!+)fK+~?D1dyZw1stcuc9jn(|32NRUkkWp~G1BjGgFK^oYV=5`!2VcHJ|(6N z*;o;&yS380A~bA9&R%;G6!qxus-F909j1GS`xP-%^MJILkq0i};T{7Uj9z_9ezb2Z zt=1Me*F0-jAI4A5>C?l=h#FFUVvW`Ab4M1$C(W9a%FX{$hzruDv5flCbbp7QL-EYe zI0zdQpwam^@mX{f?EYG^>z4E5n}&RnH+b7qxR&U$5OKH6@}cW72podziZVq0+yTDG zL%6tu{h5*ISnJ?u06}Pyt4blb1hLzc{?j&GvSlDwI^RNKH_^b;cj*0IPR2FgdAIK| z=EO#iAnfu8OVBLmc&!$1N;aavSp|Y>vm@->wC>HJh^?#$W}Yb< zGFJY3m0Cglr)nCyKnJBFCqy(@83Mlbotb-2xBP7dy}&shiNJ2OgccT>JRx>>oE;I) zx-roo?sZ`gZKAyN9!19}&lJa2BI@#xbh@tnh~AG-4+|A)cvd{-zzd7!i{9+yP8TM$ zCJ{v5j%SNu4inbOXIlARdSi*FG`O5bGzgX(R4C$j?1hxXzu!Do4dFImjns-0dkYy_ z9bC~2U>M7UO^Io>?(E94(p{i1xGW4fFvs*-@|F*NumESUiwAiqfx@UN(2sqkFOHp3 z;859Z;^0oti9xbkbj%-_kyH*a+lEZF3Bdsmf8cZdrw`-RMEVHmv>aenEI`;eGI|j7 z$*BhUU3BYJ-5%#pwRm8^$&t0ad&-{p;OrxGq1$f1+8(FGVS<*M9umt4Jd4PEq&vvB zik>KaeCe0(wbec+tBBfgBj{5lGJ9?t%D3W#vt6hOGBXHPhdLrqZ;1@ls0vBsVF%J= zg5NdXNpO(z&8v*9$8-3W;j^k@6P+<+N4e3-GYpwqxX&#`5mJyai%?8;oXImfQP>~b z6AM^wMBJuZ}JZu2Q;~ZqN(=13X~j7_K1c_MwTG zL@XCB8d#KfC@mzvw81#?^A*w4Ob9c^uTlBR<$0vU{oxj%pY(1Hh9qHxy%LvT3jbVkPHPS3QCN(8C zRMIuh@BjYdvSzIa^ek>gB+%&$Imy0OZ@&%O)K2iK)8hum9~|8yR`cA0y`76!10Y9R zvKL@R#VKf-3bQ+^F6)7KWBkFKE=_h$-e?GjJ^=Ej{P zzeER)Dq`0hlY=dYdwh3dz%lC$Vx{@3nOB%{|BU{XTc4RO*Y#dlDLoQ9wFR$(=#W>?W0Y{ zOZm2=lcMKfxQ>-7MeJH;`FWrTf+Uj$oU*l99R>#{xX>&P5lMbuo4d6z?mG7tGdJw( z6r1Eh!EEX8a38nY%jCU4c*MgT=ej0!C8) zA5+&=xD7Ax| z_gs)Jd_@He>EqwVQ0#`3HWJ0z3NyWVR%dOE0Y%dOL!HHrb0!NFVkWjoy3G2%YnQYeqhw9yr9gJ&&E9nSA@tA3CMr&iysKVWoshJ3WPg}OwzF)6^UbZXmP zCHlMN<0Jy5E;m%R6kfY8Q-C!fVB7ytjw5h%gm|9!$iuXfn}|GQWQykslgN9sA8itr zJg7sVZ`O*EP#_skk>~Mpn)nB|9y8z+ zR5@qXLeC3iKZjNDl)lJ6-SUeg6^yb|S|a#vDSx z4I(ogH}dho`SsVZfmKl*b9rZcMx6;$@}C1R(cy|LixO2Ib{8q<|g`{y@~w&raY@9 z?x3UB8%sVhkOKEwh5s;_-H7`a9*TmPBcXkXzSw9uu@Pq(Q?PxWVq6sLcJBc)WBm)6+PpnWTu({b-(N(1A9&Wm zf^WGnxH)5omK;o;_iiMmf%!ol72z2n&ajPMW{i2t+(y;DV5Lb~( zZQhw*{LqmnU=t+UjBVRM6EP>Bcc$lT1xk&IiJPda;4HXrwHFOP$@aL>ol!#ppjJh< z*`Kg+;-`O4V_f_iY1KJz#L3x04aWrJEN|w>LTWTJB>d+J$%!x&hj@#Au&35%)KJ(l z%XxieoL1LCPX5}rD_+~5pA{gPPANXSRT>rph4j$Wnw0%_X$8?1+aFecaV0S@CB8AD zD;%E2d-zXwnI*^hBHPCIuP~={&-d?W78I@#)V(WWbUS!LqQ`O=8tXFOmOB;fxF7?E zq`B&z%2G;+pLY*SQSb+CjMeGdmz+}b)N$X__ zA}wFbv|-E`Ln5|Q_2qXaMO}2D1`{nemrBGGk z=>Ps}FlnctwXAL~;F%v8AH5pnYJq9(LCbe_H_2u4EEhsKW-g60;eIoXbA> zc8_OZ{i&ahh-nlU6OV>DsDo!PE9NPmA2=R#38{KW=*#g*KN>tU?(`sC{lOz8`i<4< z(sj_}bLW;*PD*4DDFns_#p(6M0FkLDC~K1#-Y?gAIKk5>WB-y?>lSFHlm|J4@EB}( z$Y0s(z&A-lynTE=LZX!5C}#{#vr4t4Pc)*HrawpgXx<~W>M~}O^h3BkZ2bZKAsv=Y zPvJeV62Og~Wo7I>5<#b!MWb<5rWYC}dJCc3aWEP&Ke2RN}+YToe53ee1zhK2! zBlN`aUk1*YoIbR?cZkSCDj2+&PTa%e7K%B-2aHDVN!q`<6&&upL&E8qbl$AR(0$R}Hu{v#7Q{9a)fghj}2D3@ogQ$H2V^ zF1RFptiE7PSHP?Ca?Udkqs&=_(LI&6?dL-jT~2AlJQ16#H-E!wexlpG&|-{V3Zj2r zbJ#IcYBevGYFT}sQh6-FSJug(?HU0{=)p`Fyf;0h_wOlfen6V;?&ughb%W05AJCh1 zwnH9BdX>g~XmcWGb}d*)dQS0~Brgt78Aqv!k6voi{HQdXlFdfR-WrC!8jq*mO4m0d zMEbudjSa(Bi(lf6PMBLlB}3I>f5ydUKxLYC=}47bUT_+#%gt0F1DM;5SMK$d!gOa>OKBI3%J(f!Y*y)jdVkt+a?}EWV zl&=IikDfDkTbYMyNaDVu=%f}q;Lsidul#;vP{XoA2*5gnA_90sFlF&F$zmgy)*;8B zHBTN@stqdG8GvjiPo9Nnz_!+2x>}cO)mWw^)okG^l_~xbT@kVCoRL-dh6m*&n`OJ? zS6W^c3Y5{JbbiYx>I{Eii|MYRi!@9@2yD6&G?n~!A&dF^xcZQ-<*I~}Puk#S+aTdI z$iVtP_3r4sekOevU ztgxSg%i44&Am56~1U?-#taDd1AX_&@0$!WCB_`&6_}C{^u{Jn55LUx$T974cpulCv zsNU;Oij}1KlRARvbHjizPk`?i$1oerp&jGu+V>pdnnM@Dm;tqMzb1Kw2|YE7I+*GX z>WDZ-qw_m5q3zuUN_WQon0c7e{wUOx#9KA0n48%cWPA^Y1sYZFM++3DTIzsd;yGk* z3TW&HTnZ&cOP&c?R3ZQC7=&Y(`al0yYv&xCN%yz;JGO1xwslWz+qN~~#Li4?+nLxl zCeFmRjm`7C?{58eYyaClU0vOM>eTmKUDaLHRehc7!;D1+u$}z!^2=jtX{7Vr&rsJ* zMc)iSd8ANjiQkJLDm%|c(%7{?8|Wc8tSLDS#9W_dd<|kQOucQG_^tx(EN< ztb>lZ@54AC-QbuOtBP2AZ);nm28Y%XhnNskk7G*+%~~-ZJ7u~$_Cwu3T@6p>R!<+; z$(A!s`!-x@Z|g?FW|u3~-|yEahR}5~c#lO@&eihcVO%#_%Js0Vs1koVkVM zuy>az_gkrywiLF7-&64KjWvv1$qS+VpijhYuEl-(HT$WyMRsyHorE@$yHP^QY#YHv z5qa5vhUq@h?~AB@=6bJ2LsU0MVWMm(i)c?Ae5Dd7q+F^D$=@y;Ka;D|{)QvjC+FT; zu11VEB~V_$fgYcQ?-5($XD{9gUXs+q47wvyfASP95SI#s?d`|!9FbPK*rQNgvFR7C zSB{owJv#s6L25eV4%6|$WIZJ$+_Gg`($xmDnlxPK)bp-8fe0+Sv$96}=+nxi8_8d7 zNeNLX3c}ii#oRIulK(!E@=Ad}synW6S0Wt9Pm8`&p&YS-&mEdQZ{8hFq=^Ufu)yQO zdL#=&whn{Qe?VXR9N3A{Tu6HGN`CS*NEThwV{_Y0>qa0^3&>h=HD{Uvb2nMZ)>qkM znsW2b^BXCCW@;eH`3Cj_4Z_NbNR9dljR`0Z7jfDH^z4o_JXXmIKT+0)GAb!(?$jo^ z**vk=9f2jTpMhbUCcV4%s?Oz;Lt9=tYivnp0Pn&)9;Gxa=3FGprDAf@e5WaL)i>#h zX$gd8joXFWRg&rI;yLu)Pntm5g^)iLrP)!5S8&P!sLZ{$55uH@2pw%fXztbi2G3gqVEKSADf6v7h(Mm$2<8?)19D=b%H zEpED-S}mxq34mW*_KqR{jrHiS9zfw^nnhjCred~b+d%&W`*xpqR=UmK?H22LNQbsh z@qD3GqKi&(4^N3;aC1 zj>hI;-wJo~-RO!xd2tLX20PxN6xlbCc%HFp@}<3dfl7I;B8-;pw#5=2tq;6Z6ynwZIO)CjaGdu z)a=9G<-74APhbcq_{w894w;0WYxq7%j8*SgEr`>(ijN|ViT*Hn_DGEhYmbA+pMnYwdK54 zT{TPLubRa7)tr(-L54vtC(ZtdXg_jjjj)B971xBa34QY|7Nc_MZsJYUh0exfQ@pbe zV}iCOXSR>=@O&@#hK3z@XT3IZ^`=dBe`cwdHJc%@y}#-h66O8z&Z`AolYEktJ;md@ z1P)rSfM~vqT-Y$PX}&$K_+3|M zK$&_sC`}fLGmHum)iEobttDX|f`P~qQSp+4B@RCLz>4L1i9NquS_Nhy9W98^hzHu2 zZa)4WiQ`%X)vN%#myM!71;oyMucpEL5wyG;-$*io`xwV~^!acjq2{=%At#l@^>2}W zbz&`nKE`bk<~(H_FsKdq*F?~32(VrKS5>gUyhaFfW3}}r2LqCw6z25bO-k-$ zf{n2Tzd6&n>-!JV_1p1;d-YS{8w8_HW2G+NF%FPq^g;bKxPofA9cppc0RtG()^1al z(fenEL8Imz^hK+)`P|F%m=kT?Hb&^8tp7~V*!jjfkuzX)1N0XcQlWXmFmv$DB@R}A zHJaDBM|n+_PdYEQ>n>zu*vL~sfja8D7SV-ZH_9|!moBupBnhY`+gtZc8m={feR^+F zC8#+N8BxJ`&X)pDyIm|`X^1JFd|WPkZL1S_$9iE5YuSs=7k;e;Jwx2tQXF?v0L16Qf(Mp)=7~9hHw>T_9c(p%HEO1I3^z#${9y7mAD4=>R z=VM!dnYykr#z`~@nL53$#QB@`SzG z%FXDTNUZ=5y_dY4prMVAPV{&_+#$MlibG*s)K({R^d$G>&FfdISs^It2Pnos zH-NOywhI=7XMI0AJCAJ8Cnv3zSDITGzh1Pg;%rM4t zc6?M*UGLf@M$s zrB4{@#26U!0#Mnh!T1??zP6_{1A?t*#om6*{AjhPK8-Oh_>PNetfLflpGVB>-;}$U zBoe!r@(ROu3D&V z@%g^qNfJrs6PTh_GK=>}ws^!pJ@Zh<`qYtz1J5?Ay>GLue1K)k@XRWK_Yxk##+rQm zD-Sw)R17HF7&SmgXd|j|DVXO*qLt+m8vxNTjlA1l4tm@$G#7^9oa7`q6Yr+#xSXz? zeKtv?WZ_)0XIbTtZ3L*X`9;#UB0p8kIyU%@oIE90oU&@!Q}#-llGF=+Ye!|dSvSIw z2@aAHHgSFfWYG7Oemnl5=g4mAfGHp@3Xu~d)0xchW;lf1Mwft9L%}_#=OOL~r}1;z z8?_Ug7VUD3oIR7m?Q@4bi9q9_sh>SB9VFHBm61iZrfth6%$n3rTrD8eWni>=!TTC? zs;@hv=gy4yaO9o?j!te08c68eHP{y*S9@ZyoGmr+U#J$g5LP=brg18 z+H@`|d()rgE6BykAcGPG@_!e4Qx%?@t|>Cp?a9ntx+wHFSIG7W@_y*sS)6nZ{c+?5 ztL0UX9Zf5(KbD`8Be32#r=06MDeJ`Kmq{n@erVj5Ag*)MSdp0?6M3gfHqm7v&}Qj@ zB!Z}aQV-(rK#AB_TEBRMg)NvC9-gWqHT>;X>^p%s(0>-~mc@{jNFN zrO>yrYX#y-jL`|fNN9?uCiRHGcD=~}e3!;O?Lm#bvkO+miaa#Uo#UvVOMtym zN=uIZW8`uv!Bdh;eGE>?LIg)vEwrE9U9FxLj0|T{B-`$B>*9kz+vVS%@NFereZnD8 z`Zq;x%DEP$FkO86izqgYzT(wgCs2Cwo1`z;KfaUT|C{eb5&OSX+{XGJ*{mdHNd^6Wzm8(R)}f8E(d$HgH|^gWYL!bsIBT3U>zCPciYg1#6Y`xvhJr zvO&$C%bdV3@5y)QEL?P;#I*XEdJmv%F_}@y zaR}&9J&|&ZmV_kRHtTX2vvWp7K4{KPdLKf|=yMGR{!2(C{0hS(&|haKPp_$?Elj`3 zl=g>uQsb*bw1obE_#i%)^j;Fs^GU-l7Vd=kme2>^TP`UMD>Bv%8-sCB&FVsY%3AFz~&72eA!-Xez7 zc%{rLX`npR>bLCJ*xyGalDL#B;+MkXTgb3?GUPB`>P5HKntEMSz%X!u*vSqIzfv^h zlE4tZvv^raVfR_6w`h+huRO5j;VF3I1Z>upZvEsYc9}Ckb5JZ{>iS!7r4WKFXpKR0 z*&AWU0%Y<+nhN7rT|IX21J@N<0xuzV+fsntpB!uSTeUfO#5Xe6giU2Sal~61G`ex; zt6*Fy9Rl-tWBtI-}|rr2#6XjB+Ge zS$v5W`2@aB{a0BrS`3C_J0YM{9%k_{tFbZblx$%a81AOWx^lUq>&M3w{Lus4T$)4} zYS9(a4WCF?5ox*>5Tzl^Q=eH7o_WB4bNm5s7AB`J48SZG0DC-uOPNQy(|zgFOv-0Uj`wui_r-LXwb$?*PF?hRxz zewii4RSYzT5E()nLe5YDhTEf(OA_Td4KdMU9P3tL`k4+{nmF%|h%%I#lH^p#SBmAP zAX6NJXAyM8_WpR(-gcfsV$oFrYU{+vKO;pBLYdIpL47yP`q{%FHfU~6r3?0aJo2;S z%jUi?1wLX{1ZBulq3l-_z72Invd>XVK4Qn8#IzWQ#@IW2@2u0r1Met7X*`<}BRewU zl_~Y|Vwl=N3*)qJHLNFZ@bH9F zI>0<$#MpIr>4b+7)!=NKsTpI*LxJ{}+S%>1yPTSArZkNcKk#FMu}pfPY<9`HKMn3A4;%fIi-_FKAL&S!JRVXnyPWDJcypF45LK*a+D$zXzyr@{gN(#HVNXw#%4| zos%eZ)md+H4SE${)Ty^##f@y0>KkK8Ny|2)NybG)U0>`GZ*uBw`Bnd<$6XoUu+zh5 zyQQQ|c1?IT)@4!IT!Uu!L&#uN^$Dh7IQXZJ?^wb5tRIPj9*REi6zq|El@c!sCX4ye zgK=%Z%`jnk1>c#_##{z^WX`+G#(53i=<8ChCP!A$jP@LZX~6TsRa&n3p;*_%lu^xj zkIRSC3EooA^RjDYh~(j18XK2yItI?j{uuHFbk?q$K_=%o7xXw50(qk(^i7nG=ak(z z?^IP1r>?ffES}kWo65~EelXwne$Wd^gH!2}NW{QD#N*h?n#J<&BsTCzdsSmqJ3WC9 z)AEhW;I-`VG5XfwSsq0B#oubP0bKMp43pkT{ICpumfVPfT^fTn$1gYfo6hYvFu=Dg z!3jg%vZSqGPJ3>H;rZqF>YWOFG=Xwv5MY8;cWV-Rmo!X5RotJYDo2ll+`my{L$qB{ z`IAt&oV)H*&G(LuxlytE#{V@?DOVg*k+1VQR+vLe7Cu3Nz{Cp&=g7h|J+j)<6&S|C z&M6X|v7wo{H;T#bMlHC~X|!ZA!})dH!rzci6W{XZTjIgpT>L`$Lp>Ti)gg)IgE>bb zKUQW@=Hf2XV^svdI`LA;k^9Rirj#s|omiz#@{27rr9jwj1{wF?6CS0I#xPP!??rL@ z@m0pAvtQtT=2Qz-op1fBirZBDAnb6cMp^3H3t5atMCp;^+CNe*a3xP$^Hr`%35J=l zk+6)pW=|j$txSuwG`I#pevQ8wHfZLlIym9Vg& z+o>XuPrJD=ImsQ{BJ?6}dJ(i!8ZssKq7>|5%EZ{RTT!u-;OAc}E#B1GM2Sj6lAvs7 zWBlkZuGHwcgK-oS%9!(RvOSKW@az3OzWx#^I8WCk8=EnyGj;cflp7cwXTuF+Eg82% z#vzh~GVpi4YZGi=o;g{O>T{ZsOzJv>C@wkAbTo-g9WgfW@AM6ftm`|93HIG1R}T^9 zyFSa2aDRurjUckZovAVU)hczl5EBBO_}y~JS0-(5oeD;}Qad1Ude!hoUoD$!t_UT` zDuB2dY%jRTGH!=kr#JXO!^nLssoBRp)t2@9|Kx;3>JYIx-Xs>o((;8%eE4Jl2 zl_f|8hdo5?^Tv=x4APYrl9oX-OnfwqE4|>QguK28+Dx?`MW>{wKGR3|M>3sAgcQOA6vCH_Nj zVj$(m4Qb7DBV!|4VQ~pr`gZ#71VSkI2nAkzml;Iy7j*0UesxvO?Km+c!vRJM46SjE zWU{Tl(Qq~9JoluuEWNt?4n0MFbcQf2;G0nrEKo4WM$s*A4BTop>L>HH zz||+bk_diunPD&)mx`6yX8}fkV9Ng@`;;X&%JF z^L#LymA5E&yz!{i=#n1;Zw8SoK0qe@<`dA)9f_or2@Xcx?Q6FiW`xYI8o7c!fdnl1 zGTE`YYI#*awF@+fN`m#y9FS_d5Jt`og_0hbaTQm~4())zhnO;oSt05(K$h1X@ozQ`%!*|ih-*S`zN|WO zuT7+KkL)+AWdWY8jLl4kT-6AF>KrlHX|Gb5i>A>YoK@GYIGuyf={%+A+$>SV<~&gz z1BQ2iU}@LEm=wO_t_(vrtB1MLEc`cOS*MH$yoI`f-`Ps4 zepF3i#Qh|gy!t7%{38RYV^^58!%a+6GV9G#gf+*cT*EyEW_8cT+SrY-5Rye8WEc)sw8^dYa1MwpsB6-^#dX%4X>W%{G z*CK&qepn%TTV6><(#CV^PvL1KmxR5wbYgcX=)9{<^>w|zU;MQRVn5LICL9|zH!P?Y z>IAGeEhd0Tlv_3^#lcKNLm>@**+*0ccKp%c*}f1)5*vX^tIqWhgcBf(1%dT`IPi<> zKvmzBrQ;M3M-nuah=Uv{p6bCmkjfR~-UcUDOHRr4;UI}Ej_iN|5ypUPGAoI$CKq0pq3F-IA%qhetdH3Cj~pnE^@l$lA%59Xv-XzI&VGr-F-2f)@U7s=>cOZ(YHjT zCHFcstl=hYRuHAuCn|&l$w7i^sV0qjt`Tt0(d6#b3R(_A=jDYM^Fqde1yMeC%Q-Fe z_$IQ@MMz`nTm~7p7Oc_sY%T)BB_bY1ROzjYvL2ZiQM}{gA7>Y`{Pb44Zne^_^ZcW z6$#@SvsCOZEP;JGXsSY4^i6Jw@x6o)N#|u$I@%G8$#HWgXEMUA2juMM6!?uTsEV?e z#A;;rTqOSCm%^Vo4DX83g@__zjVz_u^KhIwTPhr@7AJ6TvYLZBS%AM7;iXW|sIKz; zosuFakIF`3{If8}B=X@;rS1Cof4k?sB z*sf`LvXOqZH}NF+F(N%7AQ{!;{7IrO>SYY83+(&xLttwRzP1&b&4LgBzgIjUE~L|c zFIm^L!{J5>f#_@uv_RCUPf0{`GATD=*+Iu+*)RBeDA4JJ71gb4DoIWD4l=6nQ`9+g zndD8Z;c_r_xwp8L6AMSQEsFhl+oH0=j0gJAJe(Jx4G%K z;r^S{Jn`L|Bu#Lxgw@o9b@pdiCSY9NVrtBXwkL5)f94$tJDwkedzykYmgzZvqt9x+ z5O0TSAqIXwvbc|u-JNO)Y1XOPg3@&I-D+aT!%9}j;L)}vhqqd$3j_kT{GQpTZyg6N zb=(69?W9Dk#;P1c{JN_LIaU+&th3|OrEB(nsibm_jM+=Y&__8V?#h&mIlf!);iRSN z0f_WQJ0Gz9Mkchz2&}kd8R0&ei}eD$$Npg@bKWq#O`d|{50kGvuTeZon%yaMrHsk9 z^ghuk|mBSutkdC zJxv^8@@F&b(lZtdi?e5kyq}d(g>;Jtq}C0lJ${q+Ek|Va9;h_WFk(AZ&t>tFLP-8y zXJ_>d$4skyuv!5pXf;t3;w_>t{(JjQZ64~X)UE4#vC3*jrFc3^{KIy~Os~wHCqGX0 zui=-8&rt3)Jy>$LatsZs`?&?8i>`Y0gBu!dWgJ9V9AEOrQ7exgGp=E*tI!GJXS>@; zK5~&rr`RmQ>BhZ!q#2xJ$*)K>aN5daAkgJAc|t=`89+?i{0|DmbTtX@62 zcX9{TYInC#zPdt<(O^Z){I zsk9~SoA2s}z~SejgMFjNpEa?DPvn^G^jnkgkVOS#SOix)q1acf*kHJfnxYe7+|bTb zj8#*W6uSzl)Q;FvD@41<*JG+&S`G-oTsziRGCZg=BrRw+v@lvolzb}&L^>OJz{PGS zpA|bGdwbe52;Da9HAnZBhNojQCbJNehoo4v&QR{I>4Gm3q{iXP3^^Cf`#u?%-7|D= zyziePutnmbp80TXzyin2$4LRA>J&Kk3M1yQ#-QR0HETjz3GJ*+IB63`&z!p;)_bis zE_#Ft5opyuXI|PiKw$c(Bhu=2?>Axh`|{&gwWaFazst;6`_Txx;OJ3w*l@c79a1lm zczAU`J9t0(G1BXR4cei|q(UM2%@#If@32ro+3zw53wyPW3=8mHaxuxeKbCO}hN>JP zJ$#>|dY~@1^q%Db8$L=SeNe^7qt4o0t!1LyLJUvOEDc=>He!V-(&C*dAzu-JVBW>l zQo6Dk*_@_nHsSaI42q6nK*%M|pQ0=}Xu9_bq za>Mx0cgYe8m$^^rKSLn9VTMew)crdXFOsA{>jq>5m@2^5*9+RWq>Py$XX>9D^u0YaDH`UW`IEnNtV4_vJitul(WpD<^h!2LyqAb$H} zS>n*cmr>=k=|kI3erl$9=Ae}!x#s4CL7-mZw^QIy&K=3+J3WT>Vx(-3^AMWYN%u#P zx-ciVI;9sC6pSrf0R&sqVJHd>NFBGnp_jS-{6_INUy@>?C~!ANkM+4>hJ;ZvmnyFF z*>LSkv?c$D)K@jD^*Lc)-`70}uK9z)p_Ha0&!?J~ zegg`jY##u^R}2`U6OF`2a_&tJ_BIS}NR%h4VeLoi(TNri!t0pJgS8l>_hp&YUWUcs zUzQ-hi1VU6$i{FozpZ$|ZEH4f&RJ%xH+rxTqV-uidWi7PysDR9CP08O7@3ZWDgz%= zwqy6R6FpNapYt6*f=gk=?vcV+=d{GAgk-RpEhO`7K_`tiK$0(Kokv(ZTeNx>-eZ7)De2`CO9R85R`3T|`fl1xVuxgCoC}poPwXaE0Z{w-;PY8i#bLD?ZQfdh>bN zGeAlp^eMlh3Hp(Z5muG*CQ4KVXVEQ*;BJ?w^vDuYjifqrf?(>}nAk<19m*u}i#5O4 z2n>+q!|vuXJ+-FehI2L9%zRnMdYn*P{~Q5kZJ#JR4s?UTXBxNU^Ce|uzqz3#BwWAM zdc6tOl^NwYuc3^37l(pgA|?CshHrteBW6yUSVd$HC+kUNv3XezCD?{ZK$T+6Tlye2 zyQ_sJy$Ab!QX<%Az$=4#rYV9>{t9MX=f?}H0+A}vNNZ}o#8tq6j zEHjY&?IEf3LM!k2GnN3%C{bZ z0KXA6o+s5Litn_L?cOZ=WI9p@`o-4E{I!V<*JuoVDFJN=xkoeZMtk)-abUG(0Iawn z9AOPFY#UP0t_~>TP(p#;{e9B*p5kP6LV46{Q^{YruvpT9bcy4JzMBTz%ohXj-vr^5 zljp%3JwXEWnacv&kj4|XcM-)$z2lPQ4jf0gb}f&wkn2C7zSc3av=IE5t&w~6cE!_~ z$J)+!L=LZOEn(p7m#{Qouj}0uhMp6^)!@bi7Gv&Ii7io&5ce-g_bIh9ZP9RIys0rY zvavNahA=n?j@L^GT_rBaTH>)LoZ1vz54hlS2y^2slzZ9$L#GitJY&G*t9rvH8w`UE zT3J`C(WLra$kzRTtv+Ib(%X|uWB3cafohnKB;-Luuq~h^sch}uNM%&TsjEMj`K2=B za6@%P$VI%7?*R#KoUV+DA@E(qvu@8=N9+~(eQ1=fL3#}J+@j0rzVXgq1*03>ONb38 zzH?wx0ttKMvNdLZKv=NJ9A?Nm-O(OJ`I`CHp z2)F||2tkeULJo|)dRt7M=Iv1#^9J*_!3^R-?kH&qRPXWIDiHxwT0`^x(urSbh~W&v zwjvv-W-bz_a?UCVcs!#caEFRL*Mpi8zHU|IY#X8d#fdiYo0NNAan=q`=s4yeh;0R@ z`n1RgIf!Z-Fo$U0snxDj%**Q(QU1^m0Pe%q;YWlGjk^=1b2B54l99%vu8i~@d!&F9 zj_cx_Oquv}HIC)z^G4T4YC%YE;Q_SOdyOH}4}#5>nHF(nnp`0 z?YOaOggntD(p>Nu1$>v!JyENemeI+1E}bSwRcUjeD>Z-c1K$w*fi?dx;+ri)po{O z_EGVw3cZUTE0WYcT8!8nEcw;l#44@2o|Q4UJT-?OiW`w84Tn*k4l0fK1c6Bv??CpH zG}lmn)UwK?(;Xi(r4a_^FRy4gLFXXk@02ot@1EqrD18AgEm~8AFm#_ZiQ<5b{6M$| zLFQE%_hNT>CATI91dO8XvOYJw$(C^_C*yAhl8OfkJe zPxrw#Sd!*_GMu@`E96rOGINizT&s;)L{#hSPha^gg!JV&z5T*n*9<(qD>5mi= z3%|7S!_*iH+{&J{^~x=>I!9G)99Z^18i#e(-df-ZU(Q5h!=mE4EZroVzgFRgA^Wz$ zG4QQpB4p4@ZE?uU)ep{A6B?o0f^Tz#Bl=T8=g5et?kFSI@axC_G3@Db#h_EdGAgWP zTOJcc$%uWp+FuwvYYBW@_w6Nu_v$f3Zr@_21H8xG48Jp58L6wc{1!DiRoBM- z;daz)mT2rS*K;qC2UwpQs?gBpIM$|jq-osFJ z>np*gi9H-GF|;ghUD1LthQKg}bLyB%$fu0)t-aU!oRiG3lSB65+OWLjcJ8=oTN@88 z)%6bB&Qhp`T~-Ixtk<^IMQ%@qJZdtAXTp?*O%4b3cVO*{yleT(Q26*|qT-XD7_jRb z`c;WC==Gcnuz~t@Gzb z#*nD7n-Z*U=9mrOL&(c9g|B1D8gy@Z%JW0^+gUrNPPc2Nv#+*hG@`VQTV6J;g%8{0 z296H{NUTA&iOb%#ab|Bip5_zj`Z1iR@tUSR!SD=%E4y&3LoMXTFO*mXGUi96 za?^E5z06J}F~*(vc@6GBuWjru*%X*NeoJ50*;KI2X5IrGO0ZMBCU`;yl%F%1JzRHZibr%kC>71}-eSN)XFnbSH70((Z?#OxT2?Gp%8JO9Pfql}AI711 za~q~6mQ=sVPK+#KLqcBVcW%QwQz=V*0EL3a0r9StI@_CC2%(zOEdu&kv zo^KEMR*DGjkniIl$T~O%s#87)e>#2ePCpiK`q9N(b2@UdStF2XSeGbym%}Q zN$Ga&&U3VQVYQ623(xX-8S2(OoEU1HgyHGFYy*ErbWL@VDA*yu26R_bstpE|s4+R#Aa+s=zN;lecoPFI z#;LgTU?T>YvoVkEgY()^n0eOD8!t`m7&!OJliJV1Od1{2r)27WL`);rRv3S=uq8At zA=5@QCD!F?&~EE5Kur*{j^3oebSP*i&j>MHUd%zkaPPVaZpvsh`T-*&Y8S^&e0Z-k zmCIr*hF<8x+2tE`R)X6S!{I>sj95BXIYv?xac6z<&Ah@$Wu1vY|h_ z+rq{|AIn1lL?jt^0LJy!B5Sx!_Vpd15l`MClRr>_>YSvpdEC)hhVTb2<5;eB;*37% zx7kd2?-cQ6BG>NORIYy($hWqBi?R922W88<49IOfM{Hdar1_?p(tx3qHD4gX+0nYM zsTPC2OadFGoujnvoJ;4gdb)JGj{ywsL^ex<{i&4x7x!#SSv3A0HXWYD5@i1{A_4zm z>i$oTjC00+Sx}ra{=Af*FPf1hcXOB#x!cIP;Z}g6Q>bbYa=v|CCJg(Qj)?KDOeSY@B!D z++vc@_IK`QOpPWx+BUCt`Bqw#tMfje#wXh3IUYjPkgi+4y?R@>w8LUw&$yrGmJWPM zw%U6CE(+&wYg{V6Lpqxyla6F(vsQtGuUL{hKU7>KZQdD+g>eKYYFTb+r^Q6&H(%9QSDykGq4$>L(1Dk- zMhsP#F2Zx&4!JxeANdezL2tU#-k!tLz^1a(x=;NK4Y8g0ri1rm|-t5qPEy!WXoJd6s_kb|n-I0>?T^)#s zY^CsS6NIbUqkpQ9?aTKL(z3xr+P%oSf(E+lPy8IOI2;~mHpmV=PxP4i9p?v;_5$uR z!-@J9|BzSdwSb$zRL zqqM5*4c2f|s>$=(_dJ(fqo=+lgYfl`{rcxA1zi2_FeSI#ufDJ5_MiDbCSSt<|H71r zuNFW7K?BJ6xfLue$Y3#m9_JaM@6=E#z-X72eSObKq2C6@vwhVOUIB^qM55OQe=I)< z3%t#q`$p|Syg>bX>^^5WpBv7dvO%B$J#@nK|8BVjhS7W3?0j8-5-Cp;vv~$Ny@@|7wu`SHr&;*e`VK|2tLnYvQje|DW#ft61MZ zD#3mKRVn;W?SDwV|FBtBwM<)>&t z@M%NWRa|OHY$cx2tf}+qXL+isA4kY6;yub8eUX;oi_~hUFbyvk@w+A2 ze=(7iHW>i8fw~FG%)t%Fx-cp%I#x=${h_*?!$Gg+5pT6uC;$Pb4%=C~W{Sjd*}{u= znkT5rwBS1OK~nnu$#WEVwENxH>~x!6XtDxYiC*KNw*=K!ryZ338t7+-zic2p8=$i3 z&t^-+=60IaqrLj-kMFtp)hV;-!*$kaej=WQ#+pvvySjz(m@XkLH}7FLI~Ne<6i_O% ztv4uj7K%dCkWA3JH$g1ZJ@l7qcg!N$Z%95hfjx@+1Msw+dDA?Z!=g!-IS*f-&-2c< XHBO{X61IoN@tuXj7qB*4De*r5K$&Vw literal 0 HcmV?d00001