From 4b97b44f66e3db5d70b18988cdcf1f23ee54ef43 Mon Sep 17 00:00:00 2001 From: Tomas Bezouska Date: Sun, 6 Oct 2024 23:04:31 +0200 Subject: [PATCH] Post release fixes (#57) * ui: show env only when set * chores: use hex instead of npub * chores: increase limits * feat(logging): log processing errors as warnings * fix(core): json escaping of some characters * feat(deploy): merge deploy with build * feat(deploy): only build & deploy on main & PR * feat(deploy): use github.sha * feat(deploy): show correct version * feat(ui): favicon * feat(ui): larger favicon --- .github/workflows/build-deploy.yml | 14 ++++- .github/workflows/build.yml | 53 ------------------ .github/workflows/release.yml | 3 +- Netstr.sln | 1 - compose.yaml | 1 + .../{Extensions => Json}/JsonExtensions.cs | 2 +- src/Netstr/Json/NostrJsonEncoder.cs | 29 ++++++++++ .../UnixTimestampJsonConverter.cs | 2 +- src/Netstr/Messaging/Events/EventParser.cs | 2 +- .../Events/Validators/EventHashValidator.cs | 5 +- src/Netstr/Messaging/MessageDispatcher.cs | 2 +- .../FilterMessageHandlerBase.cs | 1 + .../UnsubscribeMessageHandler.cs | 2 +- src/Netstr/Messaging/Models/Event.cs | 2 +- .../Messaging/Models/SubscriptionFilter.cs | 2 +- src/Netstr/Netstr.csproj | 1 + src/Netstr/Views/Home/Index.cshtml | 11 ++-- src/Netstr/appsettings.json | 6 +- src/Netstr/wwwroot/favicon.ico | Bin 0 -> 67646 bytes test/Netstr.Tests/NIPs/01.feature | 16 +++--- test/Netstr.Tests/NIPs/01.feature.cs | 8 +-- test/Netstr.Tests/NIPs/Types.cs | 2 +- 22 files changed, 78 insertions(+), 87 deletions(-) delete mode 100644 .github/workflows/build.yml rename src/Netstr/{Extensions => Json}/JsonExtensions.cs (97%) create mode 100644 src/Netstr/Json/NostrJsonEncoder.cs rename src/Netstr/{Converters => Json}/UnixTimestampJsonConverter.cs (96%) create mode 100644 src/Netstr/wwwroot/favicon.ico diff --git a/.github/workflows/build-deploy.yml b/.github/workflows/build-deploy.yml index c3f2298..519bd57 100644 --- a/.github/workflows/build-deploy.yml +++ b/.github/workflows/build-deploy.yml @@ -3,6 +3,7 @@ name: Build & Deploy on: push: branches: [ main ] + pull_request: jobs: build: @@ -36,8 +37,14 @@ jobs: - name: Get docker tag id: tag - run: echo "IMAGE_TAG=latest" >> $GITHUB_OUTPUT - + run: | + echo "${GITHUB_REF##*/}" + if [[ "${GITHUB_REF##*/}" == "main" ]]; then + echo "IMAGE_TAG=latest" >> $GITHUB_OUTPUT + else + echo "IMAGE_TAG=${GITHUB_SHA}" >> $GITHUB_OUTPUT + fi + - name: Build and push id: docker_build uses: docker/build-push-action@v6 @@ -80,4 +87,5 @@ jobs: NETSTR_IMAGE: "ghcr.io/bezysoftware/netstr:${{ env.IMAGE_TAG }}" NETSTR_ENVIRONMENT: dev NETSTR_ENVIRONMENT_LONG: Development - NETSTR_PORT: 8081 \ No newline at end of file + NETSTR_PORT: 8081 + NETSTR_VERSION: ${{ github.sha }} \ No newline at end of file diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml deleted file mode 100644 index 615637f..0000000 --- a/.github/workflows/build.yml +++ /dev/null @@ -1,53 +0,0 @@ -name: Build - -on: - push: - branches: - - '!main' - pull_request: - -jobs: - build: - runs-on: ubuntu-latest - permissions: - packages: write - outputs: - image-tag: ${{ steps.tag.outputs.IMAGE_TAG }} - steps: - - name: Check Out Repo - uses: actions/checkout@v4 - - - name: Login to Github Container Registry - uses: docker/login-action@v3 - with: - registry: ghcr.io - username: bezysoftware - password: ${{ secrets.GITHUB_TOKEN }} - - - name: Set up Docker Buildx - id: buildx - uses: docker/setup-buildx-action@v3 - - - name: Cache Docker layers - uses: actions/cache@v4 - with: - path: /tmp/.buildx-cache - key: ${{ runner.os }}-buildx-${{ github.sha }} - restore-keys: | - ${{ runner.os }}-buildx- - - - name: Get docker tag - id: tag - run: echo "IMAGE_TAG=${GITHUB_SHA}" >> $GITHUB_OUTPUT - - - name: Build and push - id: docker_build - uses: docker/build-push-action@v6 - with: - context: ./ - file: ./Dockerfile - builder: ${{ steps.buildx.outputs.name }} - push: true - tags: ghcr.io/bezysoftware/netstr:${{ steps.tag.outputs.IMAGE_TAG }} - cache-from: type=local,src=/tmp/.buildx-cache - cache-to: type=local,dest=/tmp/.buildx-cache \ No newline at end of file diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index c028e43..5a19307 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -66,4 +66,5 @@ jobs: NETSTR_DB_PASSWORD: ${{ secrets.NETSTR_DB_PASSWORD }} NETSTR_IMAGE: "bezysoftware/netstr:${{ env.IMAGE_TAG }}" NETSTR_ENVIRONMENT: prod - NETSTR_PORT: 8080 \ No newline at end of file + NETSTR_PORT: 8080 + NETSTR_VERSION: ${{ env.IMAGE_TAG }} \ No newline at end of file diff --git a/Netstr.sln b/Netstr.sln index 4d22922..20c0a78 100644 --- a/Netstr.sln +++ b/Netstr.sln @@ -23,7 +23,6 @@ EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "workflows", "workflows", "{320F094E-4B63-40D7-8D8B-AB5B01F6FCB0}" ProjectSection(SolutionItems) = preProject .github\workflows\build-deploy.yml = .github\workflows\build-deploy.yml - .github\workflows\build.yml = .github\workflows\build.yml .github\workflows\manual.yml = .github\workflows\manual.yml .github\workflows\release.yml = .github\workflows\release.yml EndProjectSection diff --git a/compose.yaml b/compose.yaml index 9a2500b..ba5d818 100644 --- a/compose.yaml +++ b/compose.yaml @@ -8,6 +8,7 @@ services: - "${NETSTR_PORT:-8080}:8080" environment: ConnectionStrings__NetstrDatabase: Host=db:5432;Database=Netsrt;Username=Netstr;Password=${NETSTR_DB_PASSWORD:?Password must be set} + RelayInformation__Version: ${NETSTR_VERSION:-v0.0.0} ASPNETCORE_ENVIRONMENT: ${NETSTR_ENVIRONMENT_LONG} depends_on: - db diff --git a/src/Netstr/Extensions/JsonExtensions.cs b/src/Netstr/Json/JsonExtensions.cs similarity index 97% rename from src/Netstr/Extensions/JsonExtensions.cs rename to src/Netstr/Json/JsonExtensions.cs index 65e8360..d1249c3 100644 --- a/src/Netstr/Extensions/JsonExtensions.cs +++ b/src/Netstr/Json/JsonExtensions.cs @@ -1,6 +1,6 @@ using System.Text.Json; -namespace Netstr.Extensions +namespace Netstr.Json { public static class JsonExtensions { diff --git a/src/Netstr/Json/NostrJsonEncoder.cs b/src/Netstr/Json/NostrJsonEncoder.cs new file mode 100644 index 0000000..0a09c00 --- /dev/null +++ b/src/Netstr/Json/NostrJsonEncoder.cs @@ -0,0 +1,29 @@ +using System.Text.Encodings.Web; + +namespace Netstr.Json +{ + /// + /// Json encoder for nostr events which follows NIP-01's character escaping rules. + /// + public class NostrJsonEncoder : JavaScriptEncoder + { + private static int[] EscapableCharacters = [0x0A, 0x22, 0x5C, 0x0D, 0x09, 0x08, 0x0C]; + + public override int MaxOutputCharactersPerInputCharacter => JavaScriptEncoder.Default.MaxOutputCharactersPerInputCharacter; + + public override unsafe int FindFirstCharacterToEncode(char* text, int textLength) + { + return JavaScriptEncoder.UnsafeRelaxedJsonEscaping.FindFirstCharacterToEncode(text, textLength); + } + + public override unsafe bool TryEncodeUnicodeScalar(int unicodeScalar, char* buffer, int bufferLength, out int numberOfCharactersWritten) + { + return JavaScriptEncoder.UnsafeRelaxedJsonEscaping.TryEncodeUnicodeScalar(unicodeScalar, buffer, bufferLength, out numberOfCharactersWritten); + } + + public override bool WillEncode(int unicodeScalar) + { + return EscapableCharacters.Contains(unicodeScalar); + } + } +} diff --git a/src/Netstr/Converters/UnixTimestampJsonConverter.cs b/src/Netstr/Json/UnixTimestampJsonConverter.cs similarity index 96% rename from src/Netstr/Converters/UnixTimestampJsonConverter.cs rename to src/Netstr/Json/UnixTimestampJsonConverter.cs index 6ed85b7..905976e 100644 --- a/src/Netstr/Converters/UnixTimestampJsonConverter.cs +++ b/src/Netstr/Json/UnixTimestampJsonConverter.cs @@ -1,7 +1,7 @@ using System.Text.Json.Serialization; using System.Text.Json; -namespace Netstr.Converters +namespace Netstr.Json { /// /// Converts Unix time to DateTimeOffset. diff --git a/src/Netstr/Messaging/Events/EventParser.cs b/src/Netstr/Messaging/Events/EventParser.cs index 9a22446..59a08a2 100644 --- a/src/Netstr/Messaging/Events/EventParser.cs +++ b/src/Netstr/Messaging/Events/EventParser.cs @@ -1,4 +1,4 @@ -using Netstr.Extensions; +using Netstr.Json; using Netstr.Messaging.Models; using System.Text.Json; diff --git a/src/Netstr/Messaging/Events/Validators/EventHashValidator.cs b/src/Netstr/Messaging/Events/Validators/EventHashValidator.cs index 24ec3ba..89160ad 100644 --- a/src/Netstr/Messaging/Events/Validators/EventHashValidator.cs +++ b/src/Netstr/Messaging/Events/Validators/EventHashValidator.cs @@ -1,4 +1,5 @@ -using Netstr.Messaging.Models; +using Netstr.Json; +using Netstr.Messaging.Models; using System.Security.Cryptography; using System.Text.Encodings.Web; using System.Text.Json; @@ -12,7 +13,7 @@ public class EventHashValidator : IEventValidator { private static JsonSerializerOptions serializerOptions = new JsonSerializerOptions { - Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping + Encoder = new NostrJsonEncoder() }; public string? Validate(Event e, ClientContext context) diff --git a/src/Netstr/Messaging/MessageDispatcher.cs b/src/Netstr/Messaging/MessageDispatcher.cs index 22a8516..0f372ac 100644 --- a/src/Netstr/Messaging/MessageDispatcher.cs +++ b/src/Netstr/Messaging/MessageDispatcher.cs @@ -31,7 +31,7 @@ public async Task DispatchMessageAsync(IWebSocketAdapter sender, string message) } catch (MessageProcessingException ex) { - this.logger.LogError(ex, $"Failed to process message: {message}"); + this.logger.LogWarning(ex, $"Failed to process message: {message}"); await sender.SendAsync(ex.GetSenderReply()); } catch (Exception ex) diff --git a/src/Netstr/Messaging/MessageHandlers/FilterMessageHandlerBase.cs b/src/Netstr/Messaging/MessageHandlers/FilterMessageHandlerBase.cs index 4e3ad64..7a8d15d 100644 --- a/src/Netstr/Messaging/MessageHandlers/FilterMessageHandlerBase.cs +++ b/src/Netstr/Messaging/MessageHandlers/FilterMessageHandlerBase.cs @@ -1,6 +1,7 @@ using Microsoft.Extensions.Options; using Netstr.Data; using Netstr.Extensions; +using Netstr.Json; using Netstr.Messaging.Models; using Netstr.Messaging.Subscriptions; using Netstr.Messaging.Subscriptions.Validators; diff --git a/src/Netstr/Messaging/MessageHandlers/UnsubscribeMessageHandler.cs b/src/Netstr/Messaging/MessageHandlers/UnsubscribeMessageHandler.cs index b8427a4..37368ea 100644 --- a/src/Netstr/Messaging/MessageHandlers/UnsubscribeMessageHandler.cs +++ b/src/Netstr/Messaging/MessageHandlers/UnsubscribeMessageHandler.cs @@ -1,4 +1,4 @@ -using Netstr.Extensions; +using Netstr.Json; using Netstr.Messaging.Models; using System.Text.Json; diff --git a/src/Netstr/Messaging/Models/Event.cs b/src/Netstr/Messaging/Models/Event.cs index 1e197fd..827ce97 100644 --- a/src/Netstr/Messaging/Models/Event.cs +++ b/src/Netstr/Messaging/Models/Event.cs @@ -1,5 +1,5 @@ using Microsoft.EntityFrameworkCore.Diagnostics; -using Netstr.Converters; +using Netstr.Json; using System.Numerics; using System.Text.Json.Serialization; diff --git a/src/Netstr/Messaging/Models/SubscriptionFilter.cs b/src/Netstr/Messaging/Models/SubscriptionFilter.cs index ff007f7..fed661e 100644 --- a/src/Netstr/Messaging/Models/SubscriptionFilter.cs +++ b/src/Netstr/Messaging/Models/SubscriptionFilter.cs @@ -1,4 +1,4 @@ -using Netstr.Converters; +using Netstr.Json; using System.Text.Json; using System.Text.Json.Serialization; diff --git a/src/Netstr/Netstr.csproj b/src/Netstr/Netstr.csproj index c25c05c..1a273a6 100644 --- a/src/Netstr/Netstr.csproj +++ b/src/Netstr/Netstr.csproj @@ -6,6 +6,7 @@ enable Linux ..\..\Dockerfile + true diff --git a/src/Netstr/Views/Home/Index.cshtml b/src/Netstr/Views/Home/Index.cshtml index daa0497..ee92264 100644 --- a/src/Netstr/Views/Home/Index.cshtml +++ b/src/Netstr/Views/Home/Index.cshtml @@ -41,10 +41,13 @@ Software @Model.RelayInformation.Software - - Environment - @Model.Environment - + @if (!string.IsNullOrEmpty(Model.Environment)) + { + + Environment + @Model.Environment + + }
diff --git a/src/Netstr/appsettings.json b/src/Netstr/appsettings.json index 94d8a0e..2e6c109 100644 --- a/src/Netstr/appsettings.json +++ b/src/Netstr/appsettings.json @@ -29,10 +29,10 @@ }, "Limits": { "MaxPayloadSize": 524288, - "MaxInitialLimit": 100, + "MaxInitialLimit": 1000, "MinPowDifficulty": 0, "MaxFilters": 20, - "MaxSubscriptions": 30, + "MaxSubscriptions": 50, "MaxSubscriptionIdLength": 128, "MaxSubscriptionLimit": 1000, "MaxEventTags": 1000, @@ -46,7 +46,7 @@ "RelayInformation": { "Name": "netstr.io", "Description": "A nostr relay", - "PublicKey": "npub1q84c9lheynjl33u6ha5ulfdd25yw0p90w2zqx6f23w6cjrn7w76s373p35", + "PublicKey": "01eb82fef924e5f8c79abf69cfa5ad5508e784af728403692a8bb5890e7e77b5", "Contact": "bezysoftware@outlook.com", "SupportedNips": [ 1, 2, 4, 9, 11, 13, 17, 40, 42, 45, 70 ], "Version": "v0.0.0" diff --git a/src/Netstr/wwwroot/favicon.ico b/src/Netstr/wwwroot/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..c341ffa858d46a21f3d47ad4204ce20e695ede54 GIT binary patch literal 67646 zcmeHwbzGL&*7kY-`~LX8--($sUB@03yAToS?(XjH?vgG6DMbVoMZ`c66)Z3SL2SV8 z?vCrb_A_VBJ7-=!bDTNOYjFF!eIA~^_u6~y71z4fAO7%P{1+GZ2mb%vA4dJ3|N6rx zfB3^6M)BlB;z7yd;_l0i{QP_jo*(WQVDK0mfx!_N9D%_R7#xAY5f~hS!4Vi7fx!_N z9D%_R7#xAY5f~hS!4Vi7fx!_N9D!dLffp}c;Q90Cc>e4eo;`hvr;i`w$%BV@a{mFI zK6-?wPoBK`eEbAYcs~8<`Qz(f_Slclz2x=@ANyCQo&C3t-{8|OR;KxIhJJRqdXxE^Ma$0?ct9U z2Tw$r+9TM&5&`<=@YOX%fVLTYHO=6uX##HzWB8~U!CTD`UOc_kd7r0`xD|h^ipLG$ zrm6>b6$767@KiN`2XEbZ>#wZO`+9Iw(f#2u-goDH@p{RrtP5BE?XIc|Z{GLh^R9f( zlb`9z$9(v=FF(UgRUgiLovV@#-1xempW<;>@mYVrbyMc&E9=0WkBRU5@m73}_-tQw z16~JjwM-D8!|T;GLx8S1BFyZN<`anG_#`aM$ini1BCM;d!uH1X*tdNL4s~^*@4x|^ zIC>P9&Ys1CyLTn)>TR1BVol$>eFxQE@z+#*%Oh!w?cCrE-rzpW`stRl-E5e%hZKwYCX~+B4Qxsr3 zO%Zm}lpy|goUQ_AX;nB%tH4E^GgaUrrwKpK6)PEK6hq*-u`%|{NsLcT51Ci?)iUO~2a^ywFBh<|UH?Cd#`)kE}emsBj8Pv`H{rC^M`iIZ{>38ro;&p#N#rJJq zwHD^1r^908OoYrdgxgpZXn!*v^CIIVvVGgu_3QqgL;HFV>*9qJ7jIN^-Y?FXN7?6M z?cy5jSiKgZ7B)D0;^aSlY*+hkgqqr*mh+^gel^dvDCauK^NT<>&)k4$%*Dd|dAM`y*3Vz|oBtNFKX>9Jd^C-aXzB=WIUU%KRzR?{2^_{KLjL2S zC{9SmL$2|6`4DscY~KJDr)5(ICS%{Wo#@!S6~~YDp>}>5nrR#S{1ERs)YXkZb1S5{ z`ykcH6VcokOSwlBNMujBhj1Sea_2fNi%mnrf@<`(Y)3~+D-LemffKz4(Z0C_VQ!wd zdHwp&zv7jD3%PW)?ZT4$Vl=H-CDF03eDSY*;`y`ZSe#c37X=+ykDQ8N+6w7T-td&w zgUk1-2%c%iIiLi!Plli*DNSPg{>raz#{kJY%#)id9P{=*Co%YR-y7>9iXLx+?{wwWR z@!k|Ke^f>%VKMiRlITSG5UE&}TZmna8*zktOn>hIoZ5c?{d>D`^3V~iC@#Z>`i9^8 zGXLfG-MD%U$2m7c4Q=2*TL;m`PFxR#NOkdp$82?k)BewL4~LhmAv~vOAw2maSbW+dv;>4jt zIKgr4<2-2Dun~JVZ$pH$2hP(!dRvam=gz}J-4MoOrQt9|9`+Mwb1vr~-qxKyh5=&q zt?92QAj>Tb(K-&Wqc7kit%pDjD;STQ4$aR;U>Wxeu~y!<;L&HFHOWi zYPqK8y7-`d%?9*xKAbps2&d==pBWgy#S^Ef>o4O#R}WHx!m**Q{;i3Zi0jIxU+YNU z)PB+&XnZ}IHvd#CpbeX0?+N?q@<_FFLy(pk;xru)u4sV}bqn|^7{XOr6T$j+Fd9Au znqQ1WL-`_!|MJR#dXJwFakw>%BL&+yVNKOi9HYL!c=`-3pE<{Q(2up$_i>CTtf^i8 zR*lh}8#m!8VhB1`j7O+K^PADo7%qiu2M;9MxFE~fo3W8pq&WH@R@xl7+FmfCPnhK% zj1U7mIL}Z)q>%#*hmMCf=fEb~rD8pNsK@y;XRy4Y60!8vqny1EN#8Ppa<49}z&Xx` zx9zxa>NM=9$|Ib9UXZROY^KbH(4{TR6S%fPF|jr zjd&XmxXEiF!q^JxUkryX=fLjf)^}DXJ--^!^ zabOX%bdXVj$(U&pSx1;yK~HKjRxu79M_r%l;foCwi%=95k0fVL6of>J1a9elipmljU&y;L*3@x_{|MY+14r z#qxoOm32a2@1b9M`8)aiZQ6RJwB^jkNFzYqT#^$^uyeu|#=C3si(nuvhgI}p5AW?j z|AB)z(sKaomenE9(G}a9HvQw8A3c1CRL3AR+0~%lq6%S}R#-vZ;lbQtl!-O`bxkCG zqv}UP;3TV#b0<&z)HgEbyZXJeUxmK!J8%fmmM+Xas=;EsEcbO+RA%L3 zeoO-L!lDrG8;G5h@q)YpB>M+pZcr!^d;?HfRE+ay{%5S>#+7Txa1KSQ%PK6>Ek%r( zJ8H5EP|vt|B4e9@1{Uz5O`!7UA#9v>)$10zrC>u7L#P*tz>{O6G!T4 zPlVYx;1F|Jb>)>v^zmoz_M&7Q#Oogt|8kporN_j=a07qk_*~YE&r*ZZpT9$-mD3x^RlV}ZeSlAh{LnS#;14k0u&a3sdUot0 zP9qm)Qqr&+KMUT9dZ?tmzLq(OHOxV{=o+HDU>@cD;8%^7m>M@OUq+ms6LxrRLXA-g zGCYFNSiJ;IJd?Zv=vUgqWwJapxfc{gB)s#vf?qXIzr&lZQ@>UuWx;8tDs0Enf14-= z+i^0mpdGG5e=JZ*AAa)Ms4pzTzFm8e91@20E9(9ud)=wNex#cEpgXt?rG{C^BZj7V zMFTd~*K!W{A;#1WE{rJ~eK!urdU}6{(fF{w;^NtJ@X+<~%N4xP&NIPh5P7FY!iy(0lyh!d6dm_lJ)h^YO$Sr_#3f zBDOfg)faQU1K_Mv-Eg{~6c02tWH* z93syeW^M}~V#mW7%TFN&C58FtYQ}7KG&M``!c~mPq*4B>a!ZjJ5{=F4*8hrc`fYFd z-yG+k|8f!M+sGVs5^=u*PhCpP)|vh{yC?qiH;B3!5oZfAvxnt4X;>0#;Yi&7g7h5R zBnInsk3!aBh9 zy~ur((J!%`r~p6aC`^c3(f)V@Ea)%q-m+DKk$;n8Bi4CYVmd6pp8*FcIhYTd3iF{; z=&#GdXxL;pDQUBo;`Q<+9ou%mdV&o6S)U|yK`n8Il^NMsUR1)k-v-17hSCntLsQLi zBye7c8n+MixOn<3>vQJ7RYo1rR;~zSO_upLQZV^a3g#oFv32$OH#!G4)-}M6wL=!8 zXR?lHDr|UP@7wWE`FJ=?ISnE{JE%lE~f8rCv)Q zHa*nJ0kzcsJ;a^|IJw{mai|~i(b2jc&N8a3XP~{z^)KrCd{_gg^W|8$4QIS;m^3yr z-}NSR)_vBS1F%Pf7`KSl2PewuKn@Q07dK^kpGk$UO1WwnhfiZIsUnhz&q^VNYa#2wcF?xpwx$v8hGytz zoxyF^V!jDo_KKhNPCP8)rMawK^CsRs+1ZzRKofB`uABq@aGIk6L(YLr84uVGQ^v~D zAL=oGeqo|^@&Rju1Rmz6hZyVY#CbPX*CJ5Q0tO={!(E;=*-E<58#Vz3LnpwBb;F*r zTCDq3Cx+SpmaH9inXOCxKLYx!uhsZ;1T?=KjdZ_I2)xG64^d+)F!??zhK%vgMuedy zvO*%Txq2CnG44{CI}a-tE&lo22LJxa2;66Va%w;rf*2Q@%UGG4oErB5ZzRxP@@B1z z=@*lbC+82xp-QaPsraY0DE8gzf)d!xQb81BE$z&+-lY$Jh_yXstO0VFtp<}3lUN^P z#Qj|ff!y;m-2+(%E(iTDM!}wYfbp0a#75}AZ;lR}xfkeC=WBoVJ@hDdVGr6%t8=bQ zLX5o!@m6;vd(jVb?mp&v1i)a(1Vj+a5n}4Ve4h&PgCntL{YIRnAM0gijjPPb4j%t{ z1jM+;x_BVL)&*(af#g}xMy6jNvV6keKz;4-?JO)*iHH4gc~s`GzKME69H&_G=Om+s zU_;`ZxUQ{GH{<}ZNOs7b7q8Aklo zG?>%=7qZs)gzKJrzZTcN(THiZ4V7W|w<**EqoMT4NCcbMBaV5KvbotPjY);`bR}3! zkcA6z6$$1pNcRdw6>E`;sMFjHO|gVH^TFfa8vzk-39_<7Jn{LNz9I0Zta4bNli?K% z>xnaA|2GBHYURR`dqGZY0@l?mLon?HOXk*-96gca5r`1h#Tbm743{~Ya3*Fxhujg1 zqEq-fJ8W9A9A(MraMmK%hrKguD4X-F0hphV0(Kfk2+3(ObSk+xrXXC~lJ(|JNV4}q zhG!sSm|l#pCm@mbOCdQ-gncu3yxs^LCDzr8axV*ym-qyJDmvu<2|yP4JPf`XDZ$d@ z_(Y>DA|3w3w+0a7ZaZ}rf=#W^OuSnT{Vl6$a^!~zho_}AV*CTKY27;9U~T^|+27qe zc9Rn%0lHs}gBsVo+MkC*k^Bnse;oof+6%^`rbCCefxj&If8_OH&RAs>^LV+$>2If> z+TFer13kU4lUA1C_!DR|tSVcCi>&D!JpTO==;0dm&@@1XTL8Hq$|dy>3sdqCp>IPD z1YInR%YwV2KDj>};6NMEhx|`LoC}rNd05A~zgS~Cn90cFD((MYim{$JHh@Lh^D);a zoLFfKDE?&#H2yRKDm;~``;|EdwCE37OUbgXa*V_;aG0P#AKw$+wEHb4&cd?PJRE4> zi*xh^_qXk#KRAgzM2avY&QFhih5>7O(y7n-$u%KzO@qh39s#jVTUfUi#Ta^qO9;nr z8Zphzk~o3&BpJj}?(Veva@>N+qos?vP605VFbko?UG3l9fhFmA@L}vlR96KxHxkH-=#JB+^INLUY_$^5`{iEm)aJcT;#0AD%c zcT8On&3da~=K9hDLb0->f>>)y@=?to-bb5p3_W-e=j$k|A&EB_4WEFL_!L|tK2XG! z&k&2>!{2*&AM4TAtVbRBk2Wk@DXCW-IC2bv2jJh0Kfmfa-_^%OK6Tx~CGh)R6Y(-u zRv~3BnWJ!;y0t_<%1$@3$fyG}ZLgSCas29G20ri8)Cu5<>{Xky4 zhx0{)`2h#=&ZP;?D)JRZur}X(=w#**bQx0+Hi9l|d(03_Th)(yMUa*`{K;2n#X3Kw z&%cM}Uq?ahW6m|k8Xc#q!COX;`^!WGvz9Mdo;-i@M$rClJj{t1H)Q~sK8h`KN?z3aF08e3o25ZN z#SBqKj>LhIuR+I>H9yL*XDy!bkcm+Ld@TLSp|ml%=E>{kK85kF&!-|>#u%ZpX2j}i zz-pWv@noj(WL(-~h8pX-N5gQU462w@x<>ovLpTI3Cy`^kSU(ks(ys7TF@l@6K3d7` z(7L=1{p5EzO1s;`%I2kezR(51#hMOeMCHN>k7-Mu`o=}_dCi5|z2mB1xzYHaZ*J!wn zSA@-HGDwcVH#@iQl+*^Oe!JW2)+el?( ztN9>V%@$tLtRwhl95gtOTxn03PMQT1#y{hoeNaVCx|7HHUpf}=@`D%8o#R^a#_GTt zglc#ofY@pm*10w;s>Zof|Ff=D#Fck6Z6*g`B7(@1<0GvN%daQH`m@Qf{d77UznG1H zp_<4T?}!C55m=#+fmMn*Xi!YY^4W=)Kh>SjD;_Ix){ba^Gh3T+KQ2TBy?BrCjpS)M^+c9wD2sw~#Q5{(b%PETJ+WvBU zhVYyGv`yjsH~NLcw2(N)0?AVJC&xJ=i}KDG?|{^?Hb@*v`|MjS_0Bg;WSTV&v1b2P&pWod)4Hdsc@oPqD`GyYvC%11$)uf z7dk-e<1xgR&4L#>p(B`^60sorSxU%Zo-AQEquF=?QY^i&b6Epg%9avWXolXTohUa*;<}&0@1BHMa$P1BkPO; zh(Gk@S>PRvWX3(;M?3M{>C?!KO(J%43-|k%^c1QGZQ>2Ws$1;T&Y*j153e_~&eIg6T&!l1c z@dU(tZv>k!q~SQ49MZ!T$kS&_P96ogsp%ulJ&5+5GOUNpf+=kYFXof|^vtP)V&Tl# zRi1A+3cblsYwC+C=NJSqmKbmA$^5q`^Gym8zrtq>Z5#Wg6HhO^%32V#*KA z@5Wp$&LhUWeWvRWFQw0zh!=GKHUR;QHx&4X6L+wI_?9AsSv$c&Spx^iAMifTfnU;V z;+i*AEJyel^0R*{hxk#ZD4G$#y*?TBDp^>goQw6!1=y%kj7=&f*rHm7R<(s_QD1~+ zuKhKN%<;)Er}UK?Jid^Foeln%K)N?Dt|3^nBTuFIN-?7%42eFtK$y)Sdk zlaXfQhhpOx1gqJjW7~Ed?e0V%<#~8ZFOuwh$QR&FKG^BBKPOA_Us_*}g@-KXIr&bb ziKW(`EJMCfS;ijJI1g+X2mN*2roS}CZ}an_cSO`ULsWAgPav0!#ix^?^U+AyeLMpJ z-)bP?dn*)jJ}lQr$0n;vv^gxp9?KQjqrU=swU%RtRt496Dx4_$;yIi*v=8$q1)x!7 zKKF)&Xp}EQuhu&3HL8O#~T!Q=FiGRFnwrioZ$pADCx z^xwW!g7>%T2pn#Nb;|iTVAx2RH{!6)MjSQRg5x?n(5zI2_!-V9XHD0ZntC)ZS%KEY zwTL11ccErBGGv3uJs*Z-;=;II$i|{hE){F!v(c!K zhYgC{11Q^#s`=a#vapQ%L&eN6gpV>twNf(n>ege2W*s&w)nLDB3yv7=K)+cVx;2_` z#<&xGJoDuuQ4~8DYl|zn$7^F-&2nVYXRFr8K(Rs+Vr-qUjJm!oDgjO8a>@)NZ(C6j zx$c=mGB!s>KnPL{ypc1_8-7FdxYxU&earTjicHK0aaP2qv5tI-1ovVwocjP{177Td z5Kn*8nRce#1m+;fg+0$FNRs~+@A(jp<42Dno3@q({k&`$^59T5b#iG~t;9WFX&%1p)q?nak-GZxCHq9S`9_EKgIrHjzAvH`i=@7L&*lA|vU%k$_Sgip_ia9iIUZ_c3&U?G!g}a5n0`Z? z$S8HjaO@>MKqccUOXnnDsZtu2spnt?xf2^KO0e3l9E~oEvEHK^RTf$B_*j)bpFft& z&cr6A1?W*}#DGp4w#=-;d6Ql|vbcf!*0*rRpc7~9x=}PI4oyo}VBqKx93_|Ez@dYz z`SQay>v|+=keiG6@a^k1vQNl-Y+(&{MH1tf#ET@F_##uv9y@7w9@F2Be)D$Dfm+1s zJL2kJ$v6bQNQ$h z1Q(hY^KJ%TNWpie27DQhabm31d7M1-KO&~@Pov@VIqS2yw?~ZBN5Uv`q>UwhW4tp; zri5V8%vdaCyfk~ zs}|y*;U-)#@4^+U!#Ly8$2zF#=qF$GFCCj1_e>%$*n+ey=o14KO_>*`WuPc!F0t;B zh$DB{Idb5B2#3&bg8$M=inV;K8}Xf`1wZCYyx2RzajXIyzL7yJZNJ>f&R94j2&?7h zqD8qJZJM>{px*5^Xhf%BGdj)JVeVu%czmXgVyPhPRbW0|uO01j>v7rm1Rh&H#8Y!} zFIwKlb&HGGtkr;I#%M2|I)h`x{$06r4F`!|Nt1U+T@-abYkhOrhoG^HdcUX?sbR5* zH}_%;S|7Et@z}4o5~s}e;HuRj+;TmO3vQ?2IbIJpul;f_5`k@LA*V|<^~#C`m5A~7 zLt=0!s^^#DPbIuQO@$w~{Ier>DmaaspW)!NO3b4FvAx?Je$2Ptu)guV=$^W6wyubM; zo%)v|Gn{Z(L(&RQHb*?_~A+i*Of z8wV5jB5ax~<}?1=NFSkHmH1JsGq~??2S@DpVBxG3q^Sp>Wl1CXmJ6|+b^WIX`mu58 zD$JGlLX%q!F{@GN+q)0jmagSq9EHlX0vHf8u0i~W{g=~FKEn^K^h3^3_usTUjz{KK zam(ih4n^!^Z%GqLAGudw?cg&%9|6IkZ8uSt99ssg-JK3!;_m~si5ny5mIvdr4pUU& z#9AIx=1r>Rgwd~GLH*u@1E$+?(7p}(0$Z@oYZ2z_#iN*c{|d!uczvsls@XZ{vfGMn zX6ukH5y&Te|{m|rEg(xjoY^hp_=CT_0w9LZ% z$Q1Tzmok5cV>7cu`Ce`Iq@0H&6F-#BibQwN zR&*`f%HFZo$dM01rB)I=ryC;MIgmZ*l28;7hfrM`)&?@K!`zbILi`piqh~%{AyS*@#k|BnkKNhq{md3lYEasUG%y^QX=f7+zl`L*g+M;LP}F zG2^3_W0@ZxZ-Oeub?v5WBGS?ciBA5ACI5=$s41va3`LjaQXIA3g7w-pNR#qI&Xizm z_N~W;h%&@avA|ZhrAV3W0@EQ8rA2aKYlMtTr;48gZnfMMCsWQ zqu_=lYftv1RfMP&Q5IN1;`}5S!oQ9|AZwVShU*|?h!$~%s_^(+5$>O;!u}IE=zKh$ zecsr6HZBR5FI;%#H4i=kVxym+xwZk8BjzA}9I=2SREe2jEvSJt`R->Unf+LEw3z#~ zNJEiR0Z!bGy%Bhc-FAQX^INZ_o zH`Tqr&vQiNcNS&MgVXo&$ew7!n0){OM;pSDvG62vi6jzd;iqYYJV!s&rZDzP40U~e zr34dF5*15ZtqvPjt{}F03HhIFu}m!ol}f3|r=HK3jlv4kGPJojqBWo%D+6lKkX(iG z&Y-`Oe&lB4)mMQRao!H>CoODDoo}U>$Nw8^1zAJH+^i|<0X)fR z5X8BW&0J3va{((03$c+g;RUIw2)44t;=*~@Qdh?u&uXmZZ;G@e&PYjp&<=RXBo;XC z68cj9-xCiv$q|d0*U1{^Ol+SbyoM{ommF;6$!Wx5_#lck#dWOr-MnTU){zIhsj>#{ z+6I!opPf5*qNlB$Ttll6B=3ke+r?O_myKeTIAkdXAz7KZc1>5z(~3i~j2Ehticpiq zybbeqDc=5!=Pg3-mTj!}^JY&THJA~TsY?IOnD&PoOLs-j6$-pBT|gqvC_I6N1YELQYi>~8aH9* z#*JuQyB;eT&pp9>({0AtcJpylV)cW_BjK-RLOvUj%k^h}?gW%EAD_gY4kZbxk~~li zdrynr@Pd;)n7Ki3_GN%W&9#za(2adia;WzQSYLXd zx%3Xk<&s$&nh_C+?dzLxa2IP11DWMVE^QRz0$e*@oq^>pl_?f|vH~>HP^a(Juf*=15(kC9A z{h9Jv-?}tsK5Lwo(uP@uR@RShrhZyYT~){5y)?HRA+!Uci08S&dZobw=-t%;r}4@t zVtl@KdMui>i;2(zfD6&QY8$ zI)QzQw3(HnWpN0&1W zP@P$X>a;@kB~GIq5RN!QHv}tLGu~^3#OVP@mi33>my=loG!|j(>1jK0HnFbk-(zZt zn&OgozQ_A-nZtsg)mOntg43(&QDucU57;6|30EJT4zGB)JY zqb{Qg3uAMU%=)7QVm6cfLNGTX1Pj=wV*_jb&YnE|k9fOSqi*cm<|D0wQ0o6+*82%Q zia>31I179}=Yu{mTN>mS(fGe3;QNg#3MYAD9r48n^qO$avJdNZmcs12N%RMl5lv2$ zT=sn2zH$xPSFd9~^9V%qx4#VM{#(ZNU3qUM`=N!6)m{mY#UoD25&n$%xYIU_k+(vSDs6Vg1&_XjgHhxW z53nA04fFY}*t2v6*<4`ciy;i6~5B?sAqnDpTkDXH;G5kNF5Z<@WOIp zx_cZqVxdtQk{PdCH75%lR&`ixnvUqP=2)*ALad#Zo1`D; z%f9d5eN4pY_R@#&v9ZG;%4!8Uw!P(v8&ub4ZI&|YzSY=^lRSXhW=OI3WL$!nypN=a zDRShx&qBA+YMeJaf?L*CaN6!DqLtjxwYe3?m@^XfzDGF^MX&N>l=orc3-+~aWk2&3 zc2;t&#d994(#S_5eZ`154tT&l=ia4ahlucZ|rSsM$e{J>?beq0roTXW&GIxYh~0CliZ=Z1ZS-F;-Bm6tVfKkTD5-7i@9CAygQJ`WUHq)}x-|$Uzd=7a=01eu+=){N zXKXBqm>DzHN9Rv+MU`|Ib`!5R5ZaAIIZqT#al=Nr6708Y#wy=RcoFy6ro0UGnnj2w z#%dkwIP$sQHtNp9yqO`y2D{?kox8t!_)hor6PN8O;VbX!>c#=eUYtFg6Wv?4VITdA z{rtO^Sde3UKA--m=T|dPI>m!|pE8^@BbLCHIe+UrILZ89q>?*1h)&@#ZIGu=9!v1P z7fzo+|G`6&{*T8gYr!oeKC6SZ%$r&J8q4p${tGyEAThSZ66JbgYD4rgL{YK3wV2)qt{52{CSV27Bdc9ICqK_C) z`$5zP{+dJlmIw!D$(lbw`3O08bHCn4xpY(RBBmtzc8Ym%nwX&SQ05*!n~s9By#GapJV;*M9ASCXsdnWTpI$@6Ctyygqe1;JG;^oz)EiaF3vo29R7 zKf3rmE9bGNLqya+Y|vkGE$_;Egn#8GrAAwyH5jr*IAPn3?cp2P2i+12W&E*IwGM}E z_F`=k`94P(VzcTZblWr`da6A(>6c^a>QS#(h}8xaNK^~P-8-)@e}SAcJ`{2&qs7=j>)z{OIJcjdD;Lf-wwI~-8 zOSBH1+UtoyAQqHdLU-@q!c)ro#q+0>J?8FxL#&ogBPNqNHKmt2)0y_aH&)F~!ztq~oSu6G zVd|DBoEU^I{Z?$TTa1JW&geE>iv=@Mh}~#IiEc7>&{s&-3YGNyc-c|q8u z`x!Gj*tQE@J9gp#>rfB3@1dR6iGJcfy4N+sU0_kZl0o=z)@m?LT|lg968EKu@3ay6 zr4C%bVDAG(L(23p*ZyOP{GUI2fhVkKd@6Ln3!x95OZ38X^4ng&a1m#Y_5Xby9L5p) z2Avx>Bar!nm+{lS?zO$GuNV3@*nl;^(t+5ou@1*m4k5+NkF|K@ag+(i0sSpF>wW-h z)0QH5xE@;M7ov~0)dJJGD3M9TL8C2LDO-rX@D60FN1)etH`1-cC3Q8gbIl^}kR1`t zUh3`W<6bO$wEf~_jJCI(I$#gwzik)F0ux|K3~$g-4WxW;hRE+U;q@u|K>lSsEXgrq zN=_-WzevIOqjBW6n!q@r1?DHFvv#Kmk7$z$o*(gD{0~$FlD*)`v!{5(oYxi30bzTb z<~%&vdl0=l+EJ0ndX}o1*SVB;>a`*d9ymh}tqM6f5Z8ueD_;Z;)0O0XHYu0j3S+a! z3VRSR$C{5tpLLF;_7Rhr;$@UTE?wYlmMoIHI>^ z0x{K>$V1S>Jzw$V|#FfxVVA zNh8QXJk9}mL`125UOZiSHs8sFWMBN7|xbf(xprg_3qpz4A!+4+%;EdLO6zk>hdwJ-E7d&A>LkFachIb*Ynu)eAm(W4Ep zVpbHoS&Mnu^$d1av?79>IW^MZIB3v<3$FdBb}W?S^e#(J9<7-`|Sc}25`OhCei7x8@UdnzSeer!l547zj)++|q)yPLc4j-)moLI1_L+O1abqGjo9{uM z-)ZjL<4bYD<~YujpN5};B`T)-VeRZ(T(TX&5uXlJ*wNQxjo)dLUD&76g7eWAP->Tg z-5xtp=9iD-)Ss_&2wyygw)Q#dB8jiZzA!!8cA}HEUwi#JI1Za5vFl2x)2n2{uv|VG zP0H!msZody))*etUyb9e9ldC=57({x==Wd1UAyzRV}A~3ExS=B6NKoQtVvR{K&*xp zA{nC&m1Q4c_N8%_n*Bq)KWzo=uST;c0dYj%kh5~=IARW_A)K|oT^lx$2hsbzmj9g_ zHxN3@04rz3;Fw_>E+?NvmO}^+|W8Z?g#0V6SH=xwP8x>xxRUj8Y4RczNACaut->I+|=K}js>YfPm&nB{_Gm<#k0-Uv?T^!Jd1%dfUlJ~}C zizB#dF@T%?m(iTR7PgEbXVCB4+Vpz5UtGV)@$X^${Q%?c2WjgI`3u|c;MO+Skqa)7 zIfarb-l(4=^nEtAsgPTaMo>@Bb3nr%O7=FCGFbJm{HMhGCjG<#+^ zdW^SWqxKTy8AV_%F=5;0k$WgT8$l|XNFpYrjhKM$@+$0@$M{tY`w2O_GG`r+UjBxg ztbMvjTOgJE5trWMp1z%2Z_#6QvD3T?DO!O@^$TLGM+*(~|GTtTylEU# zCUYz-SX1YC4VQ~9lVc+Ro9fn*W49VlpFVxS{~&o3dg$*9zfZ*9y0^8Vv2Y=4 z3#G{$tQk0C*~N8#g7saOah`fVLW=wiei3M1&iwL%8vdq6 z;+aZW^Jjp4hV3}Rd9so*s-+&u*h+4Qt;7s$&o9Lia>vB67f~ARyk_=|y>k8{aV*p! zm#?wr@G@?kJ%_TeXyz+>Ui;eKl{Z|we3?9IcI>U{g@cT(F3y@y?58c7L{*< zU%-N(BDg4%|4KTPHCz3->30L&OS_QGoWG<7o_U*JbHsc4((XUNy`S+uuDNbu`?a>S z$GZtR#%7~L+KcsLT>C0{M6TM|~3FR~6*#|fpnL*Le`gRg~ ziVTDHw`1A!!W)}bHo#|s8LrVDc<6W!$1RVb&2Sa!wDaIPUJVt*v7A1BioFXS;>n}O z+`k@3{5`=DeT_MQI~OluSxTlPPW)@G?_GJ1Si3@wqV_e>+?P4NP;_doP9G*i^VP53%H(p8S(5LaQ@WU-*kydl>ZUVIf47?W}IKF|6ay=g2~I~`OO^K zZ@#P_Nkpsqd~_PDM4wqJ&f0Y2hBdJR%5-2yu{ti!_>Pw@EZ6A35yV`2^;FgI{Z z$p7*c+`DvzTv7$^z5IU^;$8Mr3nd5VnmK9InZ39WcothyHz3N+6^)CQU_NccTV7YO zF_E#~yyD+%7ti$x;JT-;&v@HD+Wq^O=i9xu8S&(5NFwfJ0q5Zwmo!cOXKEm~LWwL~jYvS3>n8;=?I_#g9jl$5M~IXfm)?k^7VFQ=ZT8 zgtw=BP9Ry;gLdZu3AgbR5htcU{Fpq}0>>!iFM3SfrTmwX3*sXEln>#!#eN>qvWD2M zvJjVj&*E6_A!M=MT41{OGai#a%MYDiEl4D8>o&*fw;uDN>Q3e?A-mMyw$ViXsouGCa3stk3Ql?t0%tPv$OIj+8@BM>k_XlsiwM`yVn+ zEaZQaYhUaEcP?HgCs6WxZU6mLhGP9kDj8$1P6bZo971VyChE!gB#yfrml$&w_LB?6 zm5UdD`nF$ve-&f0D|6@l5cd;)Kl|6V60095qm4Ln4A#n!cZWPu9lFagV7wC-t$T2j zHJ$fuuh8y)i0d}jh*xta$NyBx`d8-K_c6AXto@5yA%$6=B0q21p>UvO7bGX%$T#P|AG z&OFm5@<#2U&v(Ln8?IO%pv`v{ckSuxTR+4DyGPhmmmue*&>uQZgATkerW?>}J9>IeCYobX-tFS&O9f&>?Q znQ^Jrko5VK*!FMmf<@jXfLv_{xb6?p2JC3v%GmEttYtqz zmv3jHa(W2k`9%`j@09s&as~C{wvCAIUB@Fk&PBV&cx?9sZQ8By_)-f7e;iFtf{Cm_ zbY%|-=CWk7aM$%3p1M573;P#%`w%`Hv{&TMV$JG5#xc`fskl+No zdj7mb9~@^sQskrtk2f;{BCejoc*73*?IP#f)v`_E18%Qh&G@V=@g2t4qEx~-ZzFS3 zdl}ZCFe0$W59naniOAQTIKIF$$0xM? zp5RXSJshsu!(MjUtXb;ABkJ|X4{7uBl;i}Nj}X|eo7b;#zq?6{XqUtfcr#Z&_^Dz9 zS{l}n%OMUuf5&<4r4M+B{=g#ElGuMef!O0z9M;{4^QL>q6V#7;c9-yw@_%a2-VBue zV+Y!Gj`Up}pW(67Q#^KgiYHFY={Ymc&%dAB68pi|J+yy_D+_O;#=l5n6AByV$^FN; z|L7id{XIPAJ}2zItHc6`zi;sQ;|B+Oi@oVtdi&;0#M`+@^6eu2)7dI;p1j@Mf;4Lf z_KZ+LyV_EmF(hXk<2S2Y| z#9XlF>%#A%ukHXm6|K;B=n(xqq4)3O9%cRD?j78ty?29l|4m|$9?{OZe)cRb5jXrk z=l+iZwvQ-+JJj`?%Tc#%X11~FEx{O=%MH{VGi2tARgFU#a(iR zJ?8p<%vjEyJob;i$sSbqDeL}wxLj}-k6g(o=SW@PK-tshyAyO1=U1Pi|H8WC=v3UJ z+@I3UdHC=iM9k+g<$asnaJP60JK!1PLAUAu-=jY?c)a-$5WIYmhSBd@e=QF z?NhgV@qXMb+-kl@-v316d6=v0J;E9lA@c`Z=Z`3FuK#;?CES1l2l9fr5P=cA$NoqH zBQbdVJ|iGQrs0|F7_;DN(E-4dBTr0kz^jY}|K z^c8Pi6FUEa1P>;`2oocCmvd6Y!v~MwZv<-c3YmvZM(3th^b(WPMI9h&$aj+GHIlm9 zi#eM`lf%)izaGcJ58{e1b2P%I_q&Y?DVK1e@*>VvoX52q%6;PrH0IYK%8>nr$N_Mb z_`(PDHy`p8z3zqV#VPO)LjJ=37yhoe75<>;bwFkC`(6CtH%YMLS-}xlo|+@E0lH`l zidul9tOM-hxw@d!EK@{oY}|GZn8XFnWs*1 z55%^Hb?gyNT##7HFP=(lI*E_Zz5NAGVe{X(LK}~M{$u(8LJvH;FXBLA-T(gAKKPA4 zjDYaB9?~Yy2?#?aIi5Q=G|?~E!u8*YlZSdS(02r<`v-7^Slx5SPm}v)DYlR|peQ+= zJSH_bd6>Mf*KW|Ce=foKzu;c};wj?;#QHyf&O9&uzI(TC;WlGDVh%jydFSR0iQPXa zgSTe{9&#-VYaGG3 zzJ6TbzHpg3;mT=oo{{JVVfzW3`AI$}_LU#}yC3cRhZ39rZN2Wn-}TQUAZocqPwKL` z6eK&kW3IC|%A=F9ium1aIAcz