From 9647f6b22aec6784e4d5f4c55a108327c30bf6ba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20M=C3=BCller?= <1005065+DeepDiver1975@users.noreply.github.com> Date: Sat, 29 Aug 2026 23:22:19 +0200 Subject: [PATCH 1/4] feat(atemschutz): play an audio cue when a Trupp's Druckabfrage comes due MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The pressure-control reminder was visual-only (an amber banner) -- easy to miss when the operator isn't looking at the screen, which is exactly when it matters most. Adds AlarmSound.ScbaControlDue, reusing the existing alarm.wav tone (same choice/rationale already recorded for AlarmSound.TaskDue: a spoken sentence would be more noise than signal for an event recurring every few minutes per Trupp). Plays once per due-crossing per Trupp, silencing again the instant a pressure reading is recorded until the next Abfrage-Intervall elapses -- mirroring TasksViewModel's one-shot due-sound pattern, including its choice to gate only on IsReadOnly (not IsRemote): sound is local feedback for whoever is looking at a device, not a journal write that must only happen once. Marked as a draft PR: not yet ready. Co-Authored-By: Claude Sonnet 5 Claude-Session: https://claude.ai/code/session_01UwN31QccH98YV9eEc2bue2 Signed-off-by: Thomas Müller <1005065+DeepDiver1975@users.noreply.github.com> --- .../Services/SystemAlarmService.cs | 2 + .../Services/IAlarmService.cs | 3 + .../ViewModels/ScbaViewModel.cs | 27 +++++ .../ScbaViewModelTests.cs | 98 +++++++++++++++++++ 4 files changed, 130 insertions(+) diff --git a/src/LageBuch.App/Services/SystemAlarmService.cs b/src/LageBuch.App/Services/SystemAlarmService.cs index a642b27..1a92024 100644 --- a/src/LageBuch.App/Services/SystemAlarmService.cs +++ b/src/LageBuch.App/Services/SystemAlarmService.cs @@ -31,6 +31,8 @@ internal sealed class SystemAlarmService : IAlarmService // Generic tone (already bundled) — a task falling due is frequent enough that a spoken // sentence would be more noise than signal. [AlarmSound.TaskDue] = "alarm.wav", + // Same reasoning as TaskDue: a Druckabfrage recurs every few minutes per Trupp. + [AlarmSound.ScbaControlDue] = "alarm.wav", }; private readonly byte[]? _wav; diff --git a/src/LageBuch.AppLogic/Services/IAlarmService.cs b/src/LageBuch.AppLogic/Services/IAlarmService.cs index 8589784..d0ff9e1 100644 --- a/src/LageBuch.AppLogic/Services/IAlarmService.cs +++ b/src/LageBuch.AppLogic/Services/IAlarmService.cs @@ -11,6 +11,9 @@ public enum AlarmSound /// "Aufgabe fällig" — a task's timer expired while still open (#88). TaskDue, + + /// "Druckabfrage fällig" — a Trupp's pressure-control interval has elapsed (#78). + ScbaControlDue, } /// diff --git a/src/LageBuch.AppLogic/ViewModels/ScbaViewModel.cs b/src/LageBuch.AppLogic/ViewModels/ScbaViewModel.cs index 1e2db9d..990d4f0 100644 --- a/src/LageBuch.AppLogic/ViewModels/ScbaViewModel.cs +++ b/src/LageBuch.AppLogic/ViewModels/ScbaViewModel.cs @@ -162,6 +162,11 @@ public sealed partial class ScbaViewModel : ObservableObject, IDisposable private readonly Action _onChanged; private readonly IDisposable? _subscription; private readonly HashSet _alarmLogged = new(); + + // Druckabfrage due-crossings that have already sounded. Unlike _alarmLogged (a one-way state + // that only ever grows until the Trupp returns), control-due toggles on and off every Abfrage- + // Intervall, so an id is removed once no longer due, letting the next crossing sound again. + private readonly HashSet _controlDueAnnounced = new(); private readonly IncidentSettings _settings; // True once the user has hand-edited the Einsatzzeit; after that a Trupp-type switch must not @@ -559,10 +564,32 @@ private void OnTick() RefreshHeader(); var tripped = LogNewAlarms(); UpdateAlarm(tripped); + AnnounceControlDue(); if (tripped) _onChanged(); } + /// Plays a cue once per Druckabfrage due-crossing per Trupp. Unlike + /// this is local feedback, not a journal write, so it runs on joined clients too (not gated on + /// IsRemote) — only a closed/read-only workspace stays silent. + private void AnnounceControlDue() + { + if (IsReadOnly) + return; + foreach (var trupp in _session.Incident.ScbaTrupps) + { + if ((trupp.IsActive || trupp.IsWithdrawing) && trupp.IsControlDue(_clock.Now)) + { + if (_controlDueAnnounced.Add(trupp.Id)) + _alarm.Play(AlarmSound.ScbaControlDue); + } + else + { + _controlDueAnnounced.Remove(trupp.Id); + } + } + } + /// Appends one ETB entry per Trupp that has newly entered the alarm state. /// Returns whether anything was logged (so callers can persist). No-op when read-only. private bool LogNewAlarms() diff --git a/tests/LageBuch.AppLogic.Tests/ScbaViewModelTests.cs b/tests/LageBuch.AppLogic.Tests/ScbaViewModelTests.cs index efc39d1..2ffdd67 100644 --- a/tests/LageBuch.AppLogic.Tests/ScbaViewModelTests.cs +++ b/tests/LageBuch.AppLogic.Tests/ScbaViewModelTests.cs @@ -1,3 +1,4 @@ +using LageBuch.AppLogic.Services; using LageBuch.AppLogic.ViewModels; using LageBuch.Domain.Atemschutz; using LageBuch.Domain; @@ -335,6 +336,103 @@ public void A_second_trupp_newly_alarming_re_arms_the_sound_after_ack() Assert.True(alarm.IsSounding); } + // --- Druckabfrage audio cue (issue #78 follow-up) --- + + [Fact] + public void Control_due_plays_the_cue_once_and_not_again_while_still_due() + { + var clock = new FixedClock(T0); + var ticker = new FakeTicker(); + var alarm = new FakeAlarmService(); + var vm = Vm(clock, NewSession(clock), ticker: ticker, alarm: alarm); + vm.NewControlIntervalMinutes = 5; + var row = Register(vm); + row.StartCommand.Execute(null); + + clock.Now = T0.AddMinutes(6); // past the 5-minute control interval + ticker.Fire(); + ticker.Fire(); // must not sound a second time for the same due-crossing + + Assert.Single(alarm.Played); + Assert.Equal(AlarmSound.ScbaControlDue, alarm.Played[0]); + } + + [Fact] + public void Recording_pressure_silences_the_cue_until_the_next_interval() + { + var clock = new FixedClock(T0); + var ticker = new FakeTicker(); + var alarm = new FakeAlarmService(); + var vm = Vm(clock, NewSession(clock), ticker: ticker, alarm: alarm); + vm.NewControlIntervalMinutes = 5; + var row = Register(vm); + row.StartCommand.Execute(null); + + clock.Now = T0.AddMinutes(6); + ticker.Fire(); + Assert.Single(alarm.Played); + + // A recorded reading re-anchors the next control interval, silencing the due state. + row.PressureInput = 250; + row.RecordPressureCommand.Execute(null); + ticker.Fire(); + Assert.Single(alarm.Played); // still just the one from before + + clock.Now = T0.AddMinutes(12); // past the next 5-minute interval from the reading + ticker.Fire(); + + Assert.Equal(2, alarm.Played.Count); + Assert.All(alarm.Played, s => Assert.Equal(AlarmSound.ScbaControlDue, s)); + } + + [Fact] + public void Readonly_session_never_plays_the_control_due_cue() + { + var clock = new FixedClock(T0); + var store = new FakeStore(); + var seed = LocalIncidentSession.StartNew(store, clock, new SessionOperator("Müller"), "/x.fwincident", Array.Empty<(string, bool)>(), Array.Empty<(string, bool)>()); + var seedVm = Vm(clock, seed); + seedVm.NewControlIntervalMinutes = 5; + var seedRow = Register(seedVm); + seedRow.StartCommand.Execute(null); + clock.Now = T0.AddMinutes(6); + seed.Close(); + + var ticker = new FakeTicker(); + var alarm = new FakeAlarmService(); + var ro = LocalIncidentSession.OpenReadOnly(store, clock, "/x.fwincident"); + _ = Vm(clock, ro, ticker: ticker, alarm: alarm); + ticker.Fire(); + + Assert.Empty(alarm.Played); + } + + [Fact] + public void Two_trupps_due_at_different_times_each_sound_their_own_cue() + { + var clock = new FixedClock(T0); + var ticker = new FakeTicker(); + var alarm = new FakeAlarmService(); + var vm = Vm(clock, NewSession(clock), ticker: ticker, alarm: alarm); + + vm.NewControlIntervalMinutes = 5; + var first = Register(vm); + first.StartCommand.Execute(null); + + clock.Now = T0.AddMinutes(2); + vm.NewControlIntervalMinutes = 5; + var second = Register(vm, truppfuehrer: "Huber", truppmann: "Mayer"); + second.StartCommand.Execute(null); + + clock.Now = T0.AddMinutes(6); // first trupp's interval elapsed, second's has not + ticker.Fire(); + Assert.Single(alarm.Played); + + clock.Now = T0.AddMinutes(8); // second trupp's interval (registered/started 2 min later) now elapsed + ticker.Fire(); + Assert.Equal(2, alarm.Played.Count); + } + [Fact] public void Dispose_stops_the_alarm() { From 5b3565382ced6c14133f0ff25c1db7cbfa478462 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20M=C3=BCller?= <1005065+DeepDiver1975@users.noreply.github.com> Date: Sat, 29 Aug 2026 23:50:37 +0200 Subject: [PATCH 2/4] =?UTF-8?q?feat(atemschutz):=20replace=20R=C3=BCckzugs?= =?UTF-8?q?alarm=20siren=20with=20speech,=20spoken=20Druckabfrage=20cue=20?= =?UTF-8?q?(#81)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Aligns this branch with issue #81: renames AlarmSound.ScbaControlDue to PressureCheckDue and gives it its own spoken clip (voice-druckabfrage.wav) instead of reusing the generic alarm.wav tone, and replaces the looping Rückzugsalarm siren with a spoken "Rückzugsalarm" cue (voice-rueckzugsalarm.wav) repeated every 15s while unacknowledged -- mirroring ReminderViewModel's existing repeat-until-acknowledged cadence for the ILS reminder, just at 15s given the life-safety stakes instead of 60s. IAlarmService.Start()/Stop() are removed entirely now that nothing loops a siren anymore -- they were only ever called from ScbaViewModel (4 call sites), confirmed by grep across the whole app. Both voice clips were AI-generated and supplied as MP3; converted to mono 16-bit PCM WAV @ 22050Hz via ffmpeg to match every other bundled voice asset and SystemAlarmService's existing WAV-only playback paths (Windows winmm PlaySound and Linux aplay don't decode MP3). Co-Authored-By: Claude Sonnet 5 Claude-Session: https://claude.ai/code/session_01UwN31QccH98YV9eEc2bue2 Signed-off-by: Thomas Müller <1005065+DeepDiver1975@users.noreply.github.com> --- .../Services/AndroidAlarmService.cs | 2 - .../Assets/voice-druckabfrage.wav | Bin 0 -> 59470 bytes .../Assets/voice-rueckzugsalarm.wav | Bin 0 -> 55374 bytes .../Services/SystemAlarmService.cs | 25 ++-- .../Services/IAlarmService.cs | 20 ++-- .../ViewModels/ScbaViewModel.cs | 31 +++-- .../ReminderViewModelTests.cs | 5 - .../ScbaViewModelTests.cs | 109 +++++++++++++----- 8 files changed, 120 insertions(+), 72 deletions(-) create mode 100644 src/LageBuch.App/Assets/voice-druckabfrage.wav create mode 100644 src/LageBuch.App/Assets/voice-rueckzugsalarm.wav diff --git a/src/LageBuch.App.Android/Services/AndroidAlarmService.cs b/src/LageBuch.App.Android/Services/AndroidAlarmService.cs index e79f5ac..ceafce8 100644 --- a/src/LageBuch.App.Android/Services/AndroidAlarmService.cs +++ b/src/LageBuch.App.Android/Services/AndroidAlarmService.cs @@ -9,7 +9,5 @@ namespace LageBuch.App.Android.Services; /// public sealed class AndroidAlarmService : IAlarmService { - public void Start() { } - public void Stop() { } public void Play(AlarmSound sound) { } } diff --git a/src/LageBuch.App/Assets/voice-druckabfrage.wav b/src/LageBuch.App/Assets/voice-druckabfrage.wav new file mode 100644 index 0000000000000000000000000000000000000000..404a065e6c52b7f3e827548a02d15c261ec6448f GIT binary patch literal 59470 zcmYIw1z;3A*LE^9D|Mw%thiI0V)x?i?(XjHc5!!i=i=_}QYccq6l)9hc5Nof|D^lg z|6|zg>_{d#Ir^NFY16ntg9dSgbgbQ>{(#}*^7#`&D7FF}2&s3J5QX@YW{umn%ZcNS zTQq3dxNU=WzSwWpd%}Rq<-^P2f7$Y+U+;0f30k2<2ovt%f?!YnlWlP!f6H$!G@PZl zU;a~xhJA`}6~DBsU+z8mt>9xK=B%saUFNLoO!$_^1`Eyz0<{{HvvZb^<(0i{$t*FalxOzxh^qjFD<&wWIWPyUv)k^kg* zihjANfTsV~8`)omKFB^B@^Drk<$dyQ*_H*Hq=cj{#YfUg!!Zy1m7Aonyw1HRzvZ>= zXS-)hwk5BUcgZ`<#G3Wn1HV1djt9QYS>INCTXEF-|DWrArhBBaKeA_%Z!8#-96itC z8TY)(*>XQ!K1I^UglpZsly}LtWRKi@CXcxJ#?4u>*Rp*{OG$T0GXwOJbfHAf55q^! zq7xrEgYqgj&2(HXIYRc#{Vn%o3wQ+PO8#~8jU0*lIqts7mSs=nc{fkFXGXRn?^Mx- zoHfZwvTy&*q?}LpIOK@jBXQGQK1Yt!JvaYxgB*k8M9DcCaiQO63P&Vo%2B!b^1mbh zNu-;zW$W^Y`=5J!^7(S~vIX~FckkW&FWZy-kTNAV3qEpgJ&89qPiz*Pl}F?`*>5+O zX*j0gsN@sLdG1-0Ey;N|W5kk|WN+O2a!j&Ul5b^yvZ$!l&ZxqB<;R6beWB`G8C zb91SbYxf+>He^pEC%N^5q@|91d5yfs&4*Ic$dSqU|4(1Zr?_X>O)I%CX=lokASq2= z_$@cN?}7WJRB52R`(5+Qir&$my{nVQPSE;`Ii>bt!d<3{>L@)8hN){Cgn3EZ%7%G+~Vd9 zOIDlmY3`@Gb-1*yZa$DBk+hdokfWAdFJ()P(T+V^*2wLki=+jEb+i5NN=Y5Lx#`Gp zj}v!fh)iq_{FPfKj%4BvITO+@+Hk#mid#~3wB(jpIn#3fB#k9aBxU8;3_lccE=zvX@MYDqbJ)@IAPO8%1PGqUc?z&-BY@>|M`yhF~R1DoVp z8}@COh5zQqj^lDx8jbnb;d@+;3_{cpulk&KGe&tNc zd*pn2;A6?!^TwW>-=P0L(*d|%9`(zbTPY8c7u?b#IZDce?3L7rvS*Up+`r@*_q<9g zB>%bflUq}`d0x`lZ7@x;4mu9;>A9e{_|yfm?B<+;&g)Olonr zR&iTnJOXXX=SlnO=55JGQbJ{GZf=%;|7+E47i7z_f6`t`DR$o@HMZnzDFO0+IeMun z{^NJai;`OZ{gynJiI1CqCEv-r9a(ouipqQClcjcdbGN)w_DS|aj!e?o-8b1=xAlJtnQ7JTB){9(PNHn-}FB@*}xV>K$q0-I`v`x_qYOQ+dX%%_Yyu z=gOna{>a|D z?YY}GmY%Gnl$#6P^p%?6|F}h3Q7Hv-w%oiYxj@d16Tc_3v@ydo**@zY+K4- z8qQ@3Us90d1wB&4PmzG@3G|SKq~n~GsZNSH-QQBl+veZ?yA z0F*62x|12?5SdLnk`bgAX-q1Uog^pyMa;ApJxx88K8mLPrFKyFsPohhN^`nd+~>LY zH1V_BcP}wOJV6hA z$Zzq9#3&tMT&yI&aQ89cDQ@u(A`clrx{zmL8#ui-=C1_pj(Z-0 z^4aMj@)_JR5iPD2Z^b5XSVi)fTm^lG;I7srUK|je!0Az97C6;|bQ8Bl2q_BLjTXVA z9JoI_THXLkP9VofE68o;Ai4o4nUF}3Q zNbehR7wvr&w?r+`3{vh-?6~HrsDP_ih=F7ptwv{%Y-EL)CU)RVRqTHimqDon(HMQ3 zMkauAsiYotlEvgWewi??iKIE&c_7Gex8bBV*B{9b`HvVnYi%@T|Yk;$6`3iwK4E1(Falj0_<&Az|OdDd7is><7KF zPP7;O#4e1#J4WnJhJ%}PV&+PKFUygOqLlc?t)jAc35w(=xyT{WRvf_-&Cn~!IC=mY zb|`59IrswY^b2G4B0Hg(K8UH1?hBZ`7-)<)pwvFGUTi_nuHds&%mt-%aAa*zzX~XO zQoI5`e83$$#5u89ECe-=;QF27uy_ak`V;pr1W!!BZyR*zbntEmQ3&$*92)cj&V@s> z^cQPzSDg4HwqkETc%}eG@m9c_;3nXf zYNCc{BUWRK$=FWg-ks>jZ1nJX*0@v9@&)L;@6emqF~9r8S7^A8=zAjUM-bXC4o#RF z^lpV&8H+jThP`#fpRS=!T2d*lG=c1QQRXR46;7|w>2w~wLVwfjN?WD0VpYm0&6O$8 z4eyj_<&?5ZnXT+r5)?zRDLK@>>I-$OmZq&iw%s?JwOszcOp^@_4hIjfw& zU9o66nMTpYXnQO5qCGLMC&UPG9-QGP3h_p4ud&j4qo9bV zBh-hc*&bcJ%lHoRE8}PKz3J1;r;1lqk1CdY+I1R6F0j{nUj2gevb~9YoBfL2?ilJE z;P7)iaujfC&KO5=M~rQht)wka=B|v58NbqBq|eBhkU8B}+i~0Z+I7%qz;}xdw7(Lm zgrnCHYLqfsQIsxp6}TpoujaG)d|nc|eJ(Eo+7}`1$zP;1q#;5)z_<7_)^UF_K%7aX^oKV6IU>P8^TV4wL+NO4io4RUZ1yrJ{{+=s7XQN}Fe znDLL%#h8cjH(^J3Yw&(I;v{$J24%BiQa;fbT8X|QH(-(W5l?EOZD=bcMEyrCt}W2E zXrHtT+6b+g_63x$tX>4A^C*w#7~IjCyvNf5A!(`576l;_Q!(fLX+HXt%z|unfHs;f ziok6w2ifQZO_~Dz*OU&yJmtf)-z%zGOZ8R%DBkK3WvVhz301Dp3iLanG=lz38`5dC z2@R$L(PAPQN=MT1^esI@-_hMl5%mmss+m$*8Kyi|dMbWOMp}Wh*HvePGv0B^QQP6NH*~CYTz7nTggFm8pE{$QR@YuvjLS=J zuY2pA^?iDGIHyI7SbdB!h!x^(_kX@$7=J zLT{xvbIo;jcBQ&X>MM00Ba|Iu4mOVe!?*ET+{T)7okg=N?2l0t4)1a{0{%}+K8l~^ ziQ*o3_z(P*v+5k}tG3GY(xjRTnM2LF%tg%>^H$RUQ#Vru(|65k3O4IZIKt?pCq(6Qi{z2Lalq#+#yZo5veDaX}3TBLeYwP}jEoTZ;-vAL|d zmFcwUo_VL~hSo`IrTVL5lzq@X8Q|vKG)?KMu2NP)zZFyVW8QP%%uuBXT51gct*+V# zevyZgO^sLDDecv(N@qGpxv6}I_vN9Sr;U`gIBugQz|Ti$cV)7&5>oh(Yy@vqBtK{q zWfu5v4XooTSi6m)6*&f-Tw8>RG`^R=;`ezsSm8)MhgaqOSbz48mlqSDJ-Wh@wGd7= zObn+g86w(3DmRhoG!FWA3%#fGQYz4y%27I-d?hjPVit;i{0Jw!Fssgb8l8+%MlF4* z?$l#+U!#dJMgOVqGDhh~^an;m<8R}n(V5j|2iaa;j+f4s&B$jg(ld?k`Y_{mu@ zBx993YB_M@J;jGUA${m}vH%|HbuvPv^1Y%Ky!7MZxA@H8!ejG-FSJ19CuKz|_LBUkIP_Y5$*$RCYBUGg+tww6o$LO;PO?E8$E@RldQMrK9LR@J9wYO1_W=pz}C!jPHY-Z)6XQ zIV|0Ht#>yfjaT|+y^3*LFRMoweT)LePUD(kGbXdI{1-fq+hiA2Va58Y9;!vtwWZo^ zEyC2y6s=9r`e{YAzqIWtQ=TY2lw-6aod{ko34gsKJpUi?G%Lb?52Z7pIYy~J)x4&O z=6#kkR+mR9uRh*yeX9Ezekc8_2JQ-69T*gJA}~E5J|Nz|yRWlQSUw5A#9nLF%0&Uvo3 zMqBt((-G5bRO+cYG^Wio`I>8(x#_bh#guAVXv$;y0*|yN=#)n@)S6m8t&bLBI&bP? zE@l~H4e@;G7491x5E+ysdy$+^a(B*Gqu|uSIf`vB(X`Z{(sjaDg!c{4Tl!AP$l{%g z3@GT4&zfs$$gsc&pI8g53NP;T&zzaE{ZH@sV?W|!Z^VRs&h;_dhkft1ML&wJ65Sx$ z7CrafviBh$JwDfqc^Z59$FR8ezjGx&NgHN6>?$nEt6MCay?XhT2r3;Cl_PsDQ=Te$ zKjdu@b~W$7Jo9oL%rPz7uYip{T|7KYx@fCkw>?f>n7BHA$d78VU%piTG~`2*_r>2W zkNzjR(z~d4>WAGQ$9^6g(?53Q_r*Vt#w|-o{u7a$H+4b!>dZFw_Rf)d9adY6poP^N zS{w6C%SY=)kK3Ldyn?(hdQbM=;qBvd!n?P3ig&7a4WGt-z5%_0BC@{;?VEdFK1ad! zMUIphAAY9nr3zCkFNl~?<#?6l5ko3huh^j6k}& zzkAloN-=$C#^9v(aTjBoe}3~W;dN-#naGdN;-B_^I_qiGXZo{Rkq=)yigLUj68-ai z>kCyVy0=8>(lg66DsQdSs`BZG%2k(Ctx&a6mBW>%RNPmtO8B@E zAw^92zvpTlGS0t`=OJwoKjc`P-aTnseDfcNzn=V5|9$JXXI|ZV`6RO4^Ks8gJp1&t z=d;DnS4A#=`S{i7x0l{e_?#!U`Ohl9uOy3%XRaz_v1yK1^MI2fQ*#f>|GjXj5`9X4 zEpxkEM)_~$SCrdWW^<_<#cCHS5tcVp2|D8)Z5k-bIv=H#OBBCqd}E)ReJBvU_4S3Q z2QR)vj*2W6St;@fDB%%x;MJfv3!`VfKl5?)m%OnTzn}bdI^jiPq0~khE9_rgr`b2s zR?Tki9QNybF_%G|=c zWk98n`nlr6jus?EXB6*PvTUhZr4E*SQoLW$Hic&AOU$KZ4-H)7?PaM&xlZi)({3fc ziy!ba*SEF0QyVU5T(O08?M7MnB|K9qc{KtUL9x+K@JAJ?TvqgNiKj)Js zrq;^vwm)`yu|mXGt!ZxW(aU?g-@d@eYzsnTb34Lv6-+67qF9cSr%H7Re^aJ;*_~zg zl{J@bQ6_)5QtDLkMMb9;`kJptp4*}OvK0!*?!&E{wM`@&>+L*~`994vrFWw5@1JpA zzk2?7{q08V&adlZf@5}nsr#kcm-=5$eK{9%_-kD3lkaDLeu^9UyKz$Y)B_p*j?KD{ z7^?g*#aXv{HTNCs-!SlX(2wA$*^7yOuYKLc7ii5SKRnt*?;BwHTl=mU#sGd#NSA$_2+P6c=Df=<7w+NYS?@o5w0L0 zklV!-+E2}AN;Yq@miIj8Rl;YhZ+`zJ0pA0M2OrONGbA}X34I>gJ*P8g?Oc^}mCu!w zb9l}Rp$BqI&R#fVdGMXUyZ*;~`+4W{bXhK&I;f55Ut$*XGTOR!I}Y3L+g4>NnQbyI zq?bv*kv2Z9VA}Q6*{QWsohb<^FH-KOB&C!}J)T-IEl0XFBQ>LnZI`{Q^Mh-FQJh~B z6X;hZzt+=K#r($H(z4Dn!V+j%Vm@YCuhmj*bOSMq4Xl9i$Tij3)Y0F*!j_r2D6>*# zSZ4Rk$C(XmuWi%p9UYaO4ri+CgZ|Puz~=Ktz=Wp23s{1Pu)MNd`3kSFHzGbmZLCc~ zTv^C8#uQ}=GmkPqFk3C{EEg>{OSrY8b&z$6b%}Mdb%3?LHQ4&ca>_E((%KSgi83!S zH!ug9ADZTy>X{5}zt&STY3tQo>INlD*+tFpVqXDA+{80j7xu^qGq&gj^|P*Su9B`G zm*F(KD!694p1P{*TlFwwuaT4OXQ6x+|H*TTzu|>W2X^$A@DMlo0PfBAu`nWq-l-EiFb)Ra67xJ%`s+BkOHLWonHeED5GDVu6n{Jyf!}@kN zg`1Laey|p-Jygf3-s%pen(~&8K;mfwFuOy*C}V*J=iqk{B^P2pjHAX}qrFiYkp?mB zdb*yXr|B+TF{t4UDi$(|8r6)}MhBz6F~OK^Y%tav2M}XFF%k_6e6o&g8av9~umIkQ zFNAky7Inoxz(9+Wk-#8BX(z<;2CWI)>Xl+qD($Sq}qql*pR)eSZ5}4s?;H0B5>)k|0Y#o4l z))CEt`$@z$54eDe-~1zgi|FwIzs(;ahP=;TAZkkEiUQ(PBoiWQmX{d zGMkpB-cx6*rPZ%MM8cKlbTsv){{r!{i#<9>caH3aHBz_87c8(ugn= z=jY5z!ySCOe3o0Fg$tr^5g4hi4sC zqJSuBh}-k41=XBtA$(NzyK+rg4HY7%C1q*7FQ16(u$5!+PcnXZD?iNFLy`E@py z1+$yRbfX-2_kq4cAE)=!Tj-5|p7hoy=^OMrh|o(LLyfbBm32i1D1=YtpTRTxfyxab zkIYlHzi&*&^PT#A{j|Ot+im>^bj)z$vXKp3n#Ov7lX?NqZb4okiaJgMl>y2HNJCxV zh*#A2DpS3+yjo$cfR;h3>4{1Er6fY&a5(ot74ZTU%g0EXrPF^D} zUq`wk8|r~v=QBj_tB{47iF}a6<9k4kYCv065+#sn3q>9xC-BmeIMx*!<~TUH2y!8( z@SG-eJCzvP2H?oK)gI~$b(4Au-1T04rCv}^sB?iZl~R8IN9v+b6~ zVx9ahpTP6+NT4+{AyYt%jknM=*P&_l;q$_{X&g2_K-*K&SfyV;rXx1UK)1J?IDQ;v6Kp zCZ1ayav|NZ8{mi=B zOsS>4RO`|xSf!hwpN%K*G!X{;Zze5+%wu)MoBrngVXLpRx<)eeTPT}}KK3V@l`dL> zDYvD!<&$ZIHc*?aEEQ$=WupZ!+RA#Oe#fZIsv@Iw4s}*CLhnLa3Bp(KD!d3=#RGwB zeG|u#Nn3*X;v^4Ug6!ce@*7#YKYRu9=r&}xh3KzzQx+(v)IH$WI?4#qjO{drLa*f1 zN9#X~N2~(oIhr<6TPpW~QzeTxyclnZKKz7-QJ9B{VPvP$Rx7XlQd6`zbtDZ!UiTe4 zZIsf7={JlY%m?_-2pXmKG8Hr}fn|S$Ymd`lQd7jTRO1yg6ggQKa+rtEPAEL6K=mfA z0bl1FFTo1JHg7QU8@qse|H}e-CH^n0Ra>A-dqp}Q3munRoZxx5FMkOhYQPJMqCl$p z(7AL2t)?7PMgf2MLo;a=;H)p`TC~rUb?SX}IC3#L)IrKm=-fhd1UV^sLk+j>f zkn|eJY*-wcV|zaiI(x1u%V^FuMyzp!~8vD zrad2)g@RW`{{N5IMiNN_dYfKGZukkXoB-+#U!@pw9X*lJsHF^sO&_DQf)6u>enSnx zUifQ2fy9mnKaS%Ec?_qb7&JpZJmV$*i+_SYa*Ew$pV%zk0@YOKNqzb+4NzLZ|4O3g zpnF=-RI-|60R5~E+$kDJUTJ8j#WVPW6yj3>0z}o-+tKcs91S$Oz4ZW@`_B zqY2s?h&of#%)*DjzM|6SQHG=FH6(QJq0MFbHKSgFs*FrD$g68js%w!8# zz)4~q(C#D1JXXR}wnD-_fRBCP374Z2pkJmz(=MU4>2I7lgkH{pjv0zdil=y12vEB* z@UC`XoMFHaH}EUaVx`b(UueV<@NEhpOI8?u%u?j>UjzLf1Z>esO4FgpA#DQ<>qC2N zLJqkPP{p3eYfi%mH^S!&K@NR2+Ws5)S8rI!QqbS^(C6jIH%0=bjzgYQ*2!teiPa>d zp}*e|KUxag-=LvJuabj6bvpnt){(1z18b6wI+m;8xM#rp_5!=?2wy8)7(5+4&Wm}O zgy$UuAB918W+PQF#&O6K_D5glkvrrbq}v2d(iSLVL)w%!rlH7wjfWNg37W2hU$sNb zgFWAhZ2nC6SOG#ouPcJzyNVm=Wi_C?LqWk$&Qb{wa0Zv zx9R8g21Yhxt3E>??E3Af={)2-1m^{bESQs?WrwSX19z- zws=P#2g#&qTayJ=L#>~!**yk(-18{l z`N6Xk(93~-&HMxXyZAQq79Lm3wNx$!vy#R*{iAD~YqK-bal}#9G0OhR_A7Ht=0e1V z?J_rK+A=l!OUF*vM&mNyKo%(v)sor{Z3FN@e=QxJZ&z(HVz~;4WelyhW>falMdWXh z!d4lRK%aEivaG1BvVKy7LBRd{7ZjW+Pr3IIv2%Dwm!7Q!^d75<3!_OT88y$D2{wOc8v z9#ns;PvC+5M(*8HxeT6>`1h-4;h(%z8zMidn0A`poBYkx zT*36W)=nLuT!k&KP0qpB${`%c1bFhFOb1?X;-_JCTeE`5U$2AL{T;}5AguH}$W>j` zge*ipc09afFJv*Eqh`Sje^rN$$cOr_IpREG%MUEhs01F|ufIX8=Yz;@hH(((j!yVI z7vb$3Kz7sv@nB!07vjEujlbD><_)`93b9y8K9^l%`FVC&<7?p95qf=OQ!5$AjXH>z zyBWt_Rb3riW1YQS`(3$R1H}`wkJlf+)j?Z>XJkK=<6Ur_fLp#LyjS}y^1I^m-e;HJ zL%){(<@_SN+E|%+vi68};yoSv(lb+>N%ND`BwJ#sl+Wn{?0KCh9MkMBo71+#zSxoO zsHnFUZ`5Me6`r5H3i*!muNrXEKi+qhcXO}l9xu)LHJt>Cp<)QKC?@{XIIk~p#n|g- zR7f=?4^L{B9GKES^AAlinEShik;)<#Ykw#Jjm`pg7*L?LuK{(Lvex(LiTyRG8ARYao1KL z^LhH{^egGpGBPqd+mAVN0+AVOcp)R+6Or25^TP& z9a8d;Oy<%fTxO?X_poob4X}CJj$}5;?3#Hgvx=>XeY9hTlerEUjrb2SjpkNgYQ@aG zF_){XwXKINJIwt|L$w0xT-t~<6O}k+v-EW5MaMq-JzF!I18qFZG%{D%2HHzI<~e)n zquDL-hptp}mUF}@| zV5Vxh`nvvh<x)r*M&R_!-nTx5_&cJ%HXd-{=w#e1HSXTQ>{xaSIvji3qWP^h(MO$ z3bZ*=^gq$@v*T!dM8b|glT&78%y-!IE&L<7tG2S#^7Qece*OGX{YLvw^DF0D#wW;o zw%2{nvL0hCm$X*YpR2ArnXA&iCGSm~@n_ZV9SO@4{v@3L-7_&JnWf#f4RhUOA#|Y{ zY?^64YdK~8>5NnYspBY``JfjeoOzERw?aVYC`IqG%YC%~~zXO^@5q3pst)`BJ~Oe)at#Q8yOqJ=*i2b*g!Wc362!>Of!ZH>&Fgohu#O z-p5|T-pFpZMcTsb4ei72zwC`2XB?}X8(j7D%X%`9EEnRr-}(!90lV}qh`j#R&H8=U z1((ZpRUc@?7$?|B`0Bag8ERrPYG4Wj1>VcNSP7$_PV{Z?vhKM2vubfdjW6)LTIvOK z4b>Z+Q7<$IT6TqKO}^4@+8fJ0@4EpvFhk|S+7~!nsBhuEg)0>PR zFx`@7q|{CENokVuC}mt~8PGX4Ju_pXZKUIy>l~Yk%t=wxLGvz4DPZLrt^2GOp`XI6 zbu8R8Uwfwvq~%fhfT}tEh0Ot;QP-FUFKvx$1#s+dt}wj{wvu|F9tMo8j1kQ0@J-?f zxl9i!!_|twmXDZ5noX7tmfe+erpOfjnSgjVAz{GG?3OuZOCH28R+95Jy@^p z8s$9YNVeCpAF-9TrDi_Jq_&Q>ueRQHm;HfbxwEUQw4U1tV-*pP^(AeAP8?QDK*l?x z(x@=1ezv3bBof~FOH>)$g-<>Jan%&m>1~2neh6soF2o>_s0pr&`ke117;)A?$X!u* zd2f{L>IyYoEeq^05@@pX3L}5e$+qTYF69Ot-YU+Ew)Dq0$=_OZyRrd`B%&5LqQ&p5&-{ee2(LtR;SwhC20IS^@$ zhYfd+z}xM^(~MyB7%z z@+2_s8MFs22qf|t@XPY3joXb%nr843h3=c-Mco3DSo}>;UlvAi; zQc>lS4_>7&aMaU?2LA%WaTc@=gKcSrJj7h&1MVARjgrO>{hYo@pQ?`ne@xUD14R{j zV`GPrYScj`ik-FQJGluNliNTq#v>9+0gl=MXu-cUiH1NE*2Gpy$%$&d=kydj<~2aU z`T_L{LxpoR(5`*3S7(6{J|xdjJ^cho;7jroGusyR=bsRbcUKMoiSwm&X6GVdBQI#JJguxE< zDH$|)fr#)HFuDV%WSNR6u@55l-iSj-p;qPy&U^xgxsbPLk80UHK*(PL)k#I4ZXyRW zp4Oxay^H$-$qwWI-lN7p7#4XvtAg5+^YF#T8iS27#wy_9+-MBT{R#DcJy5Urma9M~ znjyz2=KO)< zcR`))B+T$^WSiR1qQHZ$p%%U-)*Ebr)c62LS`BR70VHVx5aD1(nFBMLkF`Q&XdFD~ z^Sl~r#ajYPsRF)8LTytA;8YWp;h3u@NYHk0+*8z>?V&R}F- z2~Y%L_vg@Oqk#3j0UB>cPP7_oHn%`x$|JXiI6sI|9=e540i z0e*0iaPp$%q370Bsuy>}(czXBJvnon=$5 zgZA&htq#=W)dnx_f({M~R+0xq!8p6o$-v~cH|A-5c;(s*14TR4~IhX3IgRyM?UBqPsSJnfrIo! zuZ}?z5Y!+x0~WXoYi-g<30f9-+X!p}LD9aLpVmO%3IRuXhzw+7;AJ`_^C;HjOhP}0 zf>tdct=*u-reKz~1M54F^?A%bc){JK<&K#7dKX==EvX?i`rC*^u*DuqmHO5_IZ2 z)Imm(x4<6v<7hY7_Exadf023^a~)C)(rke|zk zY}9OIkDI{GP%M=c~G!$M)51`^j;Dz@&2Stq11eUBWPgQqnhq5C4>-<;oI+ph z@By=-jY`Om^#_i=4_;(Ao?QrNvs{%*K+*hUELJV{CbK|?*O+B9kTV}L7?zfh2(-8n z^FAAyi~?joRy)b{FCCEmdk-6Ifa?7*8#Cc+ZUqlTVBJ*=o;M3?pqfFVPJuIGpl`Oq zKxp$EP9E zAIaYV0Z0CT)B;VjqcXq?Ir&Pcd4DecB^NO6qp0z)W41OR!|{(;gTD4a-S1{(fzw4M z*+hFmVye=S;s%+E9!yluiPw^WYR9O7ou z1inQLQ)msnLH^|j_x3E@rF;)q-#@PCTO7rMcXvmV(iKCan$ty8O)o1~%!0CtF zN-8wC4+(+(i5AN-p1R79_}*E<|fL$YPP7p5|$g;g+bk)PV|nV}9F^AE>vVM>dNld_3vQ9U_T$b4!?oi zh!<}}H6B2su>xrV$$>n_ROF${ljb4{{Te0`Xgz4;HCQF8C`Wh{Jf={wL21bcEBDA< z{z)0nhbl)=A^uv~%Uh^>#0IiaJ-~>%1gjbDDm{?-yaUesN$k8CN#ZxjSiTgJGlu6> z2J%j@X;$8n=HUmCw{6bb(5bu!JxngMUdl8sy@;_qg-+*pp*!27j(G$dP7aGpY&`wJ zQX$D_SbN$Y$Lf;Cyu31;HK17A$m5motf$%lYY_&jv8=0_fVn84tmLEUasFH^r&C!g z`bXU0WfjJk!;3r4bm9f6IY$=pbh;i|dn+9ascBEDh+_04c*UmpiqWKxvWaIZb9oDR znfti68qEiYCDh>FH;nucG|z4_mK6~k8Iw3M5y+$&Iju?1iqlDTt zmHJUR|OK{a$L=`ikxnaw&vUMG)#vhTgbQ3J*d0GlKs5ba0FIrd!OS%A-a0$t-Bq9odw+TAS)dB)*B&@V7 zZ-CW3(eQt}@}2O5tD#=wBL4;duR1cPOGIZ>VyqFcv+zi!(~=nJF<3JPZ3s&=f=(d2 z;k)?@gY>57LYm0c=igcwFO2I5g@)&|(Sl*|%6DIuhvM7Qxeb5M<4Nl zu*bE)eFgY>734fX#%4 zI?mp}?%jcJRa6W{A9ljen8j~lz4jHv@`Mk+y=} zKhJi;x4p_1qovVUA7LU#)vc^Mc%?G0MEWq3I7jOtGf~wq5oj;=&AXg0Q*WXhs?@gbGyg&fI!aH0nuCQv5i_?6Mcx4oz zA!IgxMF+8p=xtA)jCz3p1HNoRql-*XS80xAhkQ(su#`bs}lAxBXE6T=VEfA|37ov6k(h;`6S zhs0Ra9`yq69D%JnAU5)9bPy~OxESGF+t zw4$0; zJ3^KUKe_<<_vOIL=8%fC7WCmUtbe(T>Q|1KWDeHo3?$8f;q1gp|7+rJc#*%v8QzZ^ z<&W8PK8RiA15kHb8~S$|{epFM$?#hg)bc+_Qb*4+nNnQxmQH3y{bD__xkPKdgjD)wp5HVgTGU^8q z?+$_PX@EMIvxrg{;p4eSL6TiqKlqc|@Rose__d$;719xC9_1XWZ>j^^=!i(`6)a*=%$fpi;@}!; ze?8zal|aPO2Xtr*Z{rj)JqJ*am%-}_3+l3D?Os{nXAV-FeneeIG3cX)$Ybnzu*J}~M-YFUhIXDSS5+d8_JnP_02DG+`~#b{12NTaNZbKv z*FenMH@s2B3V%8hYq55sYG@SdLN=ji?chD0$FbjhGLWz!@eI`*$giSTZ4fmmh+pf$ zYLtXWoC{8%fylIK9&*B8EBcOXB95c4fUoZJ!_?t6%y zSEBZ^5ip`+h{!kbaLmU6#FYsccL>&*ZGe}z5k7_&Dr-)_;#7sc9|KCiL4{pwKA7c3 zwckghE3=|jsUl+Xjlh#Q?DkMZ>>tpRNQwKfs!|fu5Fxp zDOk5Vi>?Mr>qAe0KNdqvi=H)8&jS1EhL~m) z_@pnYc={urNfJvD13U%7I~!5)OSEwmNG%oHk-L0{c={wihUoJhR_Vqd*PV!{r65)f z@1@ItIToQupgVV=W~x1qp+NqOHAWp|dBph%i0&JpBB3I3Z3D1Ua4s;|9PGXE!)U~M zuy?3Xn8E7+n+QUdUDm4h1<$;NhP;clun$>J;3;iURT%?Rv^zL75{OqNu>p3cDsKfW z_W-JSui}LiOgHrNSTR@wS^dG#Wgod`*2>})kmZ%&!O>{v0BSx`fiScIXTAhhkO-XC zh8klB-X>5CNZV}GqzTkPH$_!hQ~rdtWG7h%+{0i~uJIsvV{3q)CP0o_!h?T=HI3s) zAw-FIKMrV-0C_UQ6TC0xA(E?txT7ifZW-k35>Veq=zDKa`W9$52hnPIpq!V%O*^4Q z-ocX%gx^+_<^Y8 z{z=gGx8Vl^Kg9aV+CT}S5WBw+J)oZ~sP}3PT%{Yd#SI`~8Sv$Xp!L;22kybv-@?rI zLKNB+?~R#>n0hw2@F=|CV6=V@9>@(;df8zghC%PN1yVQzTKpRjf)jXJ3-snRv_fro z(=#zg2KRtXUIK07gtdDOO;#6p@ogOW0bA7+n6W1?rizFM!+|B_B}LHIZS*S~nzcUk zav9jSaj?=Qpk?x4o>Q=D_69250wCl0@kCEL1m1Zyat)ji2^`@cc(9|<-h61y49qv) z!~#y}gVFDXb}0dlje`zJ6?i`a(6hIwD;$7I!nHtmDkI`K3Us0as5=vJ;&ViUzfgzz z43X?;*x2=`M(RaAiNTovni`L>HG{@qFRnu>pMbL(Bd78Tx>A4=6-gU9 z7AVGHaNZd7u`cid1{A9y8AIy=h1dZ^C12x`&}6xR>Gpu;5b$4okdd4T4`wh~ z3fZU)jn*4)Da!-d?hWm*2RQdVS`lwEd8t&vo4;16)wJTKx8~f|SnE9x?lI4!yvGQS zSy%p79stbT=GH2{{Qf|$pzu*JqN*G=aOM>)rB`z(7s`#PK17Ms}v)jnGs zF6UG|%2>%7z(;~~K$9-O8&1lhQobj0n3a*uG$Z@b7TJ$Xpx60HK2e?zMa_F14TeGqj{f(%{99CO&c z1@H-8<4q$CVQA(WwT-eyF{3_e=l5Ve%@w>uVk_QO(g$^T%TO(}*0_q*JmFZQ@Sct0 z0nj@6;FVEEdTYR62s%@-`&tqna? z&vTwdy?nf1dcW~G>X$d5X<&n(=0T?eSwQuGHvWtJmZGk~;+4bWsQIjBD1QS7yvld8 z)<%@8gmbjLo~?Z5+l=oSUo&!L=FFU!SD$t8rmGo?G8$#}vE8xv zaz1pGHpXMsO?Dvt^?}7NKqlP|Z)g~DU`2oz+F{FoVI{{zRJYx7J$E`C9Uam3>-JQ; z6SXHr9CIDind(&a1pO=O>Kh@8FdCNN5qXO@s%%y}Yq45C(>&8wtZ6@m)rh4{&+!hR zpP-W+Jj3C&#DlBrLRSBQ&oUa-Vcn2lyNi`k6|tf&)F^B;H?|omMs}>7yN>rbbmZGn zw|@=Ul-$s)%iu{rfb2a7HYJh#zwl;=6Y!TS0(p&ve>)x(n7@$~+RJ8xx2hp;R~Xer z^;rq{K69}?Vy8Y||5uMk^+9RmqW>{sjbW%gaB*lTMD5|wDgA&T6h@_e4|smr)aGg$ z-p}(&vul-1g)o*1rn}lmZLbz)T43sJ-fEd7roM4SNZ#Om4N~wP-o#;%`UexCbTd%KlWjOczKbp=0KB}u} z<9qK~Hl7e%g1bAxy;yN8UZl7ccPLVu|?vQAsnFJYZ!ie&WgC7r{$ug(utx>yV0e?2Wg!5DhyNJsC)}R0hBLIvV^Xo^=EI zwfu^VH{n`hsA<~a3HQXi&%5K?+uV=co6#hry#DyA zDi1IgHa#`vur#r@45(sD7nl$@J!p4uh0v(*ZjlGm<%mijwKm;vk%z)JgjEZj9vl+1 z%BBYNwR|ykpudlkD;a`6blsce9_GsKoNix{Ha~4kT9jRN%yPos^4iTyy@wNyiD-;|0eqgm_Y z)4cZa&J6B-9)lK4-?sl?ZH!hPC`HuLbiBHW&#Qt@t!LcLh7tG?TfI{}ZQa>iX^#Ak zo%U*QNGsTT*|*tCIvzVVI7hnXx^H@7y&JTyWVEIkY~^{1sn<3In9jlT z3pTFA7F;L0Ult7YFf}g^h&8`Z5mi)M3Quzj{h2ls&kSYucM{b+)#8W^?Bra43L$5O3l!adI{+cp&)gA!K3--lBK}9emM2J^cr{&_l#WRlt;vc)NQ&%(?=9v^Fe; zzS>|shYVba9aN<*+TTOv@&L7*F}rcUnuprN3RHqtK=-#t6CXFvwRE@E4Cr8sK@K(q z-3wk3S|U6qVtZugbpJ-?irg1*49$NhG-v3i;NrpEf{F!x2?(_gG~11H)aFX6K3QAm z`Og*S7+{~7b}aQ~>Zr8t_5+T(uIKJtuqo1mkkwFhWrJGC*nuxbn+0!PbmQ2l)+9P!*ZCd|IYipnExaln69^o0{EeGEvA2E%E zDCLx)Ke4cxt}~Zmk^D_0+D>1k-GlKTNgMJM=SO;XHMZYFE+3>-vTwHMb!>Iya2|Db zcjb21@C^0N*4BfvjwH%GP7Pg8<9lO0(8h!#X#ra60v+pKk>NHfe-U#u z(63TWV}q%0rx$6O_W~%y5brxG#dp(ZtREVBrDqE)s$pUpuK|+@DKgTM#HqY=)DdyQ3I~fLG;4k#5!-u zhv*=IYmkjI_=orK*`q)n0zo=^z%E*aT5oGdqyoIoQf1Y#Ta;889-OVObyKAEd#9U0%qAZ2fh#55b`AKd&I_c zd!jm}Z=L>PRKcjG>GX&q5eviDhP?r`Hox{OUhzG}V(da^nJSk1md}<8mX(%2EWwtM=B=i` zj9#)SAH4DI_s(#~vb6Q7sVN&$=A?{DnU%6R=zpiYkti*AQ29tP%h*Lv84bzH?=OgI-8ZE!^cGU1YGbIhYeG+>Wia$M!j3KE8AHWj zKDyPN_1e%ON$4`^%~_Z4U%=n12FGKKl9@HtoF2MG)Jw$kML2q}QXGrv1u19<1Fsgf zW7WV(pP&Jk!89B}FV8u|pWF4dhKb5*HQF@Hyxy|WS~}oNz((8Fz|z4LLw^nL5t%cp zc={{p&!#t|ZxmHCUAM?15p5!JM|26_7FIsAL~wNAY-^m==_} zDEVR1rKIagwUcwC+(?<3+BR)R+RL;SSP7S7l539Vkd|yHXiRVJW65AGWqo1kW_fDv zW`1oNM~(O#n4`~Fb%pe!UU+v@DJ*mzbtKrKucsPQOQh^hK9SrurA_LDw9_!i8?mOJ zx|?`r(MQh;YB>-dWnU z+m)B@6DCh@s>kMgqu}xlBZ^x?er7N@;YJulJ&}&KSj$$5gI)_ah?;^}y$$K=2~z<3 z(Gw)J4Lr66{2l_TsSv}~M}j;=qz?_P;WW9>`190FNV9YRuuv!5g$@%pjW6j3>83Ji zDW2JRwVHYqmRw$VzY+YuR;fgH#~IYDUo3jRtg&d8vsT5HJ+MMh3>}Tmh5Q+M zF!VN$!=X{MvA(19V@f+q(a4KP|en!g$UQcEcX4Q?tn_j~%g^SI7A z7TG7Ktxf%&(k&%hiZeMVrE1E86gzU!GA)}u%n{=JKqbHycLz@xT^aw?#_D4YU8!D8 zRfikT8=tcl%Ypv4QQhP%nt^(~Co(Ta3>XhPu(x-Y$LyKl4s@S(&2n{e6>w?Jr_M{x zo6d{QIOkXVzs|08u8*!Ts<{Tk-#z8FQ^VhuUIsyE$kM|glCe#~53P!)xP}#cn<~~f^m=vTo2+8aN~2GYg45SR*CxVm z`WKI_IG9TZ_=dZ@ji}8!NPMt?#|~`8Vr<3$`c9Uk3rAH?dn&%3(9vN8`HG5Q-S@Gb zwZR+?;t!S~Z!(|!;0JscdRF5{w}&Y`5gF-$Uo?!h-Ap8L1D?!A$PqD&_d=6^8!kepz?Z=(Li2zJNH!gc6ul#yEAxdP>(jjGmklZMRi_b{NcWI0$mQz@dy#r zX;_Nq=}_^)`<0#v3idUt?sM{OK8te=*iGhi-PU9vhYUV~7zSb2Yh%F#m)x`i<+D2mVqBH2(-le2O6l zlF*(Rn!>wW0?*V_%?XY81jg@ zh-Xf4+!17yDiI51pn}#y#@m6%`xE~qfqYdM@?9HbY9$EU58{^c_+~?plm#Hv&$y1N zWI^uG>v4*Do^H3T&_JJ!CFlxr%w#jSAkKbZjnz!Zga_>{lk22#os;e>ELm>H@Q2yt?s*6-q~o~33T&W z?%M7;&zeu?u0*$xrEvBGsnT8KdCm&!LjTOKWMl_3hmT-l)dFE%g3o;mELF#+iohD1 z!ABjimu?cTuV8LklCQJrpI~0EB$LpJ%u^)(`+ekX4RY59`D;ZrKwI?5NUFECAb+o6 zc4p*ro#AHQ#J4X(RJaw~Ef3M_e(C|5!nD0W7P$z>&Y#4e>tSf`g&RMce!1(|r@pue{!8M12)GsCfa|G_{b#ew*$uc}5C-Dr1{8xC6U%~y3<5|ol zH?#oUZV_DW#UQM6(Sd`>9o7W(E>3KllMGH>P{D@8bdAC4o8f780=;cT{MwD2;uIpH zz2ML1Kx#gc32;j11w%C1hZ684O5>x9MAMAru>^K>96f8QfO5sEp~lk2nZ{IORntP# zXH!A*K=VcOYjYM$LrZVVBFj4w{3^3rt=*+k$FQaZ(w! zTSj`Z!)7rJ)RS2Ie z*t3w4oJEeY6LEATXuNb3AAqNo6`t=#SlqYiy1kFA$w+vw(O9GF*yufAu3gcVr^sk~ z$sJXrFaH6$*!)37Z+@!0AEEsx(oZ&*Cp$GK<)|iDPk-X{AUsphFv8E?M4$97$XroI z-3=S%8@(zYsCC#4;W1UvElr(F-RV@>lx{)=Og3WHEqEh=#^ZF6`H!oZ0TP{CABU}3 zL|xEUPb*M?f8F`r_g#Oxs=B^8&p97C&p1_AO{#^Y^YCUWKiYbZdeYH@DTm++toF8a z8Ewj31R#Uc)K%0B996Fot=;116kV5ogWY`?W_@9LUH1j&x6o6g5YgydWHJMtX3n#F zzz#YsFJSZ*B7>LEpqh6a?9()@EvU#v@=^K76>LBv@?*jFqnp~PbLf7)UyWCtcppaN zeY*6d;In9S>d8iTmk#tJzHTgNs$d#pT4CyM+F<%=s%xfS7#8M{wQj(4s@Y?y>pjK) zp|%dTtF{}qz`%TgarDNV8F1Qq!jcO1)fG=Lqp_{JU)hDPy-geI?Mk{P#=~&}%IHu9@d5Nn7HBKI|s5M$sBC#dRO?PZ$f>N7mCoA@J z3EiGf7`GaKHGZI<@l8DK2jmY@$u0>q@eydx9#05o`{?@J<)U7pE1Z($F$OPmWtly zrpl&wblI9oukAv{$8>ZmsLsKc`v-)5G<<;W;8vBrNyyv{cVBlB(a0{>Djq9blU)O; zc4|UpYJX~+Z1h!n>mEWsmj=Y4E;5>J=)trLtu+c1tEXgjx#x7s2fVJHk8bLpsf9b^g3Cl4Cd-@-2tG>kHdFb;+zdAH?aV*SD>N9?& znk9>IB);r*V_j2Ob9zfJ>&k$9wkNj3fmZ?}gIWd^4Vn?81g{M)A2L2jo`rG zO@W_mp9AJw6D@bmx+&B&PaUj87?R8Ere%x(NKr_k@9K_yx=HxGuqPt$2yiQYZtO`spJgG5*_RZUFd~J(+Zs7 zcUI&v?`AM21z+c`){0&yLF9KEqOpr&>8|GGNr>SR2i;LSM+eX3~$r^tb_o<31VSE@;raWE}UCg*paS-U`;q zbfVityy~M^sZZ3AjY99fS30O^RKs*pR^bn11l=glCnv+b+DSk1ZeY5j=|LB5&Tk0{ z$ZX3H7!ouj=xosLpzlGqgUrF-s4@12v<)2)S~+xnNL+Ay(EY%*wiW>`tR*cm<{YLs z>NPlIJz!9-_s*q)|A))r40ZnDcyC{A-)?_lujq(%bR~;0)%Do*)78;^-`xo7yWIO5 z-q1Jw8a;oGVjcF=m#ZiKT?*O8?qtdw;CR*b7p$yP*yw)5_Ep`-U431-UGdJd&Ldz` zo9GL2f#cRe8v+{9MxpsN~}qL?=-C&+0FD=?MB2CXIazrsq4!`{%bIPM>8VX zY-$quqGLXPuqwT@4q(x8l4qU<&!Q0Z1HaK*<2E*}D!%Cz&ohsgDoDF0lsZbWV=cYo z@w%h&NpF)6n@FCc1-?KtaO_b?!&7)LldzZVe6pJne4-?tKrUEoOZn6%vh;nq4?#e# zX*s~(cZ2-Cp})mxw9I#|+6oIh1vK%s5>A)3X2iBT$m3m8RpTP#Be2|B#*gYAdIVk| zmspr^SNscJ@nW)w5v!#s(7mc7u}+e)DL(9RF!;>)u`}r|eh)7!hKiJdaKPHrA*%&3N{IH&8;kv1 z3G1i@UR)Cp#(zL`=hAPl4?Vd?5+BV3Bb~)c&yyiJe{Lqs=*k+H1{xm<_=|M^U@%%wVQJX&ZJw4UQT$T1Dx=)kY^kM;?Qv;vh z8%^}l)q4jo`MGx~*YOuvrxlLNQ%!Orun0h@7Zdfw!5)x(RVt!6ior11PQSC_@KL1p z(_ttHU~~t9oBe3sx(TI)6WYk?gZO@56?v8_bmEk1IWolX0RmLxwnRs#4{h1miR48 z)Qia0Cc^+sWAOf#35++fBdA{BU>kQO{5o zFQE$9`%h}K3c(jRPySBoUS`5GxJo7OWa;z-+aNpax@dK+vKXs4+%Ocp_Bq=6KKYsp z_>JLUv=?C&w4r`w8Vru_Ap7;`XcPpez(Gf%zVHc;pxI99w+w$ML1>HHR9uYX_+63E zZc1ZAKcrV!I(Zq(Si=JJ%4oXOlwd5o5p{;cWHeEAw##szQQZw&<_lerqWEk!7&&v% zyYQHmmEaaPlz$nY0m>zGWf^4|tiW8#A;xZ=VHbX_&Uk+#UvLk7nt?0ZMXq5#BRvc6 zt`qUC89cQFjKekfH1nyiE zFEk|LeXXOWDZ~M*o&>qKo%@aOT%_DGTq70G$q6Kk-D7&9I-2%!`c%cm(;h? z-=@AV|8r0)2ao+Yj2as=mPiNuvW7Aw>CPs70>b`_am`h&q3TQuzd~^YnLUa|Ai{-mvD?qfl{r8DLkC4d|NsgzM(d| zE86ZC_VAhuTO>C*j7|DnWG{t#YKm+Wg{S@smQ6)+n_Kl88vAD9FYP0*SepAANj>9I z=5I2LiULXx*g{F{Y~{t4mj#8nX@~<;u85tXt_gPRb{;e7CTUj2A&DbkUJRvbCK;Z> z3f6D3HUg&8Q?TC}Wa4(w|ECeL?I@)5l=hGaxHofOlW0d+Oqt*f96`?5g9E!(*>IO` zZto3w)c#5tH4m}r4rMx;`WnYO3}0jjy>C8pwI}g7+*$>gbG^|OhxONRg*#%Ys=|a? z!wQ&#AIRQf#1LQU4s(=aW<%1y6N|RwoQtU$9?E(h%N3l~dl6Y?B&+t6)w7ToWj(p{ z?qpOOvC^)=$CK*M!+5Frn4w-sX$Le@Ii&#Ca}tiJ?ANoKIQ9c;vMBk#KMbq&gXoJ` zGJ)He_np|ADD5n9bwg(P2czJ`=en=K)&Y-dNyTCu`0NL=?6ZhZ4{vr;x2FGD2g6S-%oo+J zR9aAVQJJ;rro!M9SAG<}W^Q!wSTKQR%4T$BCf15uZ-|5)GqhJ15Mc)?qtN>i$}Dw0 zzT-b|z0xClTZ!?rC^lK`4J0PWVzkQMc8rWls?qZX-L@~Jh;W$L5|uO4pcd0WB`8mU~F-MR)(ud(68u0 z_);#cSs8r9WoWB5beHIDXo%joz*##^6=EIoQIYyv!&FegvFaSIyC&81?1V=aY#V-< zQ6J|0Ky_VSsY~J;5A?@|ylBw{x)bzl5O-A#iI@jYJqp~jDR!@i+w7gngQ znc<PMAE`1ZBPX3R8{SE{H(VN<--TB5st)gPdHd#g{CQVO-PbZ7eqFSQcr+f`ULdA zVbK0qbkcJD6>N*&pbg(;z5WKhJiWpU}(ObpvtscVzSk4B&0_4Jo8M(P;rn zd&3niJFLW<^hCW$&wxB?RpmZo_FW4{KRq%0iRbnVoFWFF?<6?`cErJNe}QkXhAVnv z=&jaP%D~W~GM&ycb-g{wV1Co47`*JcR)Zc*pjdJWuw2Z364zMT37;bChJgYp*yfNAeJnQT5 zxT?^hb_~0VMuM%y(NX9tG9L<)w<=e=3UA4a?KnuxkW+bQ_=lRK-JsPc(S<{a-$T$) z*9;yFHY*xpBYMm2oq^mp(DvfLTeZ#JeOdsSr5yNvH}DcqW4Ea(q8s@`Sk?{kBz72L z$w=>m=eL0~P) zN+rXu*y5MEQR$maKJU7@Tp+Cf4OMvIQl%vH_rcI&;zq7V=B|5pm{Jm@&Wd zxlefN&pB5i#yAgAKvt?7UQ?ai0>Ahfn3@6YI0T+gTO~hta{%i-Q-1)%KAE^D8+}*; zKrqgOWp`u*+tU%G1#wS*Efju4M%GnhZ0rrL@gVd3jf~xFEYcb{MqZ@ii`E^+b!)uE zYI>}tl!uW?@xFgM+VU z9LC}8EU*%3YU%5< zvWslf7d+-PI5o%V9_-PIVm*t)?tg}tP>C#1Wjxc)$ex|!#k1#8Ph##0Y8~e5F?z2% zda4z^@=0u+0k3Q!k-~3`#t?d^N7Ef`B7Ha$w68GX+k+IIfsd4nYN{A4Q5}xCpDT4^ zE#DHoOh9uui1FIv1I=VEZ@`=SN>7GRVza$u!!$6((cbd#1s~Dfvkn-;EAMbE7S>!( zdg*LICLCzwv-mjwfDUY6-q%sn&xQwhu7BaxXw1WPSOMGN%#;Nu+k%%<81%QI_n5aA zHD;a3?i>JZT1h`8+2wQ^X#Xf|h7pgU593^1$%3A&q{b7sE@1to=TTG{pd_(7-3V~& z!7#=G8D;6yyPEo$BSd4@+1ai)$iobEA~L%uZ|0Xf_ zW$*-V;*Bpw5}IJ6`or;`gdh5p$ZrCEi4!j@AKL79u0DZh<#=x>}Kn=Ht{j ze8%2AQRcG)YBkX8>FRr!GMR}-!>NF34}a{O@wl-LU9t<%@%$kf>lkupM#gY0SVAuP zg>^QTVn-^YX$k$LCb6&T9^(g7H_KG(j({**w}69mJM&tqS-)F%1zZSN6Hq*0fOWWK zqdCI-%(Q@fN_%4ul?qlpK&$IxcJGs#K~S#3o=WcYt~t(K&f2awuD9+zuzM?bGs3tF zp_6_QI9%nh$Vsf8gUHbbR)$W7tF2OutX*Lusk2&fMluFg&pfim*{MET>3QScOaI?l z?$PiO&b#l@3GYAmJoa{Y@2*0Q^1G)xx~(C5``z@GLVGnp{|qNiiz9|jV>SGR|MG!+ z(KArKXm4N7MRx~wqdX6)KiAdVRn}GBRl!vQ?vat~PhpUr8J^*wJ%4+S({KD4K1?W{ zsRNxn6PsI!x}H%Wd>X8>%=$)p8{VLz@D(fOIzCV)ZKhZA^d);XklbP?5TRtc|0J`v zGgF-GP_1Uo|5yCJ5qRAhVJW?3U%5tn-vGk4naoNBx|ilL_cb@Qgj!En zlLFFgivoWMx)l@`6d#l&xJK~S;D3XA1V0JZf-eS#1y>Im6IjQ#Bw&@bnZ;^eOGas$ zQV(BxthSb&_Aa`Mx@)`sb{=q89j)x$;fda{*Mlp3hi-PMuEy~EGqckLJE)*rx`LSh z3zpR!Of(h@F;Y!{YknOaIsyIk82@qri0CR1w<(?jP>s$=`#L7OV zV_+~;q37CrcT0NdTD|>2%X_ho77^2RKyS>)NujGqjk8x}YN+3BV+2i^B4`?sp(f7)SHpJ8b#QDHKf z9yfipqo9c?o|m4F^e-#tiKRQD15Qj~u;-Gl+OC7-e5)XHe|{aHy8TCzuVZyA=C)%uz>x_oX1C4bY+%qTia}b#^q>Xx4p6 zvZ32}bvco4BOgnk1i5B6-q(Kog}=e=_k({#VN(XOf=cqd41Jlts!N&iF!K^~UQ3K6 zd%(=VtSaMic_`I;~p~)e6gL?!9*{lKkEuT!6ji;&2 z@2^$xnmnsqkDP6t6CF$KQ`6#7e@i`(GB2fmYR{?RGw9j~0U7}1THoQm%k~Mfi1C_7D z*pGkVN|RT4f-hYb{ZdaULB8of(=X=FV9ScB zlJO}y$cp4i&BmiJJpLid>PLmRMa%0Q0FNffz0Q@-b;dcs*%67H#NnMV9E7^(h%kJ6X=lV7NdzN&=LZSE_7Zv{!(VNh8AN6Bf< z1rvJ(5?}-QdI5%e#$B}*$bJYJZ-Y76{LPX(V7%>4(Djf{p~J%>!bXJ# zg>DVW6S6CKQ1Ip8P9beWP6uxZIu0iFsRl+sfdD`*9UeK=EbJ)9(HSXldN+rZXx+-s^`}Sr}XY}O|*fJAA zB3_XhilvG-56qiLYIti>*ZBhLSQDP=e$e$D-azjp&pmfG_g=bBPI8TREug38Y1ac+ z3|+{jKl*TQApG;vtfPt`yeHVv)O2_APm+VOXDKeNr;i@hk=@0Z=Bw^Hvrj0{I< zys{Hyh1RfdashVKiSgWamvNthEwj?K6fVFq*JoEL?9WekSr}>0JQZP36{EAERHLtk zEnJKI-Dg7~IB!kCCPKiQ7vkqGK`)FXBU2otbQ^P@O@E80b%QF}lH>@og7%gK9hNTT zky!n`#IZ??z)M4rQU$h}@RB4O(^)A*S1cV%*i!E$rB0^H@?f8YU}Viv061HAHtlgFtB z<}jO@;wNNc!iaxM;NLBU|9Ke;orw2$oj%9w@%9X`z&8{Byg}2JA%C@pjF!_-9glMd zy;%OlR~pUFLb|c;BsLvNmM@VNy^}RqgLwTYUaLwUgPL?Am`Wb10JYeY@e*y`XYkFg z(Kr5IyoceQad41l;W^$WM>L2G)ElJn7i|Sdzk=`3lt}D2*qM!Jr!mN`bgQ4u?~cr1 z5V_tI=2HWIRe1ItU-1k`?sYgOXC+>1Oo^or(S=dK0crmhDP5}O84vw}2&Qfm>#R}NMzwqJ*lgmp` zy08yfMY4i<$lIM{2h$0r`liCHo+NV->uzfS>oXW=bu8;FW33OYPpx?aN(Ph)NMYB! zA=cW~9M&M~V|KRLY?_Jxet`P;)pR#3NO!Uq%uQkMbN5R+eCKi9cb0c9ccgP1un)HP zp$?_2y`_D*{gb`AqlzPoqq5@!dZ&o%i|a2Kz$2*^>j*=lHY;Z&*km*O;s*vJv0WGL zUZKxw1bfw|pee_okz>GIKeCGU5y!nI`;dbkI7jfqO5iIjg@Klbyx%K!4Vy^DzO^Sm zJBNAjI(|~IIGkMo-g%08Ta!tA?rp`{x)G6W2S2_=#8;UvsH@e|#%cIyA;ycK204w5 zV6|*FcBLw27O~`X*riX&7%f6WR|22eg^!R*6=OU4$@X^J+{a*@0Xj&M$Mu7i7f zk;f-z2KX+g;OehO7cRrE7>_pWi#A+x&_OI~^PI zoeK5xXsvO`&;=||A`x*5;_L~;b7QFV=>b=M70So1w;w$;8~nUIYoaBu zYuNJTSeMRp0SqIPbOz>PU(nG2n1dH#e67ajj|K7g4IR^#nw8=380WF0_!H(RikPJZ zJrVA~eQV(B*(EW5P4vWJ^miMq`h4X$GLsqB@M1V(JK=YZ=dqZK{CsM8Yr{4TKx*Id zx%wcRH_!uh(6Mw@W41aGxsId@=zZeK^x9LRtOoS+cHo8NVSn>qxst&|sYAJ{@vMwU zKKmb8lP|=k#o-ieL(63%6C=F_wsYT4&=-aABHDt0WTjTe4hH=buE90r`Uz;-7Bo;< zV$W#!iiKcNCX$mq!{Z^AEf?CdEg4cXxPTk2(FVEM%r~!+gME+9)5%H~@_9m)sS0D0 zb!<;X`dxNGs(PS@N|382&&s1HYcm%))Q7BI;fMExA9jN%CWub0^@;WOQv14w3Y+Ha zi82EA)))48++-b zPs2sxJ_@s?ENVvHHTuoP`G~U5m$)-)cyuW_GIIKVxqWfTm8R z18OZ8)LwQyxbHmy^K~{7G#WXYNhCa;IU5PvWD&f-b+7;*f~N%_?Onj|&X7NIgS1wq z`h6T(^q=Hkj*%zwlEr_-IOigMoaC#E*$VUIPjaRcmBr}(smy9RG7>%U10t{**FemA z<5zru%TiCviwuQ<5AFkPYT+%*zEm~gpmg9`{(|?i8YbIquAmlN`V-oF&fbw6(s7t1 zdEl}SgWG-x)a5Dj<)&t~3B1lG#O#vMbRjv?NBSh3&g1y8-H?!a$VPSKCo9&=!qxNz z-RQ&X#qh3v1@mi$^@`_;P=zk#Y3Kt3Ac`*h|^4SCmwF3*Tg z`@&V+hZ~#1IK=U|!4(Nt_9$rGW)Q}o1`G044Hm^*m`{tag+~-k8N?ojR^sU!)Nz+I zuA+V|6ReXMdN36*1)5TfdDt^&5<4%}F};T$SC(p(2U!2M?A3Q3+xiAA@rJSNL(NDE z5|ISnP>~om+4GghbXm7d7W z5j4^Z*dLeq{hEF`GZ^*B@OGYq5B;RqZzknBaZwD%e}G;)13x#577wOT-+LR|7>8#w zz|)ESP&2cpW_b$3PWTULJ_XiN4raj&vcS>!E0xiLr@{JrBcTiMLLY+!rg6SUoavhK zgpL9C74_;PL-3N`4mI)Erx z`WUUpq8&uvZsk7v;YkL8I6Ma1?2EiLCErsRcE~{VP-|qVHTO9XIg8-YhQFF)?~ZUa zS?L56NLT0LaQz#BU%J(W#%8APRQ8;~U+!k=ON2Y$bll`J%`k6)U;U>!${cUnh<;M2 zzhVyr@cC1$L@&PV6trd=eH~q!yOO;bL-j>xqSVgpPTHEfl^C9PL0Xl?%V9A zbrptTI`%2L07|(44qO#{-Mw%~E7F-I9!uYqtoA*47WLr0R3|1VMQ+E1_FfKKp(i6> z6Dybjp2TXr?#&iBXc+dWO5>rii=t808=NCylOD9?JszgeX$BvSnKc6 zguTIs|HO_iCEBeG_PL2_@Gz{_J0DYPA2MjS z<;0E+C3a3^K3Y;4u#bHb&L}1EU}|D@`>H2k(7we>nSnLVV=O@hT_0Y(Nj2b6{GSd; zsR!=b82Y}aQk9HdkxLyc2TK3{>3!!$`VIO=0E_!zp-+ z$N3QZc$GYX7Zg5?s<1R(2`1}N0W{uwQ;7YqWOyHA-fx| z0{x3qs~B}^1v`V1C8>|_lQp$Db@cI6Wmi$If#I}NR^tav$Nuerz4;5wuw&Ta-OSDk z$@VZZO{suhi}g54)_o%tITO&dt27gx@fMMXh$5Rlj;`jl(2PUT8G&$fbZq$zxF3hG zD~qry)v+GZNj`>Au1FpAI&!uH@k!2jOK7F2zzJqwCJ(OLSL$Z}VO%S-ilg-}S{z;G zhQSb7j3>PVy`D_gy%dpTYdqCzmi`8d4)2eJX*# zX2TyT%eCbM4W306#YKD_=?d_YD_l;rz8oDt4y+&!Z~83NBrkbv)AoSq4P*bz<=}b} zKZmi>gUP19dj@gAKj@1+XhW&>iH2V}3g%#Dd>k{9@DI%24R{li@V7?edtGMt;`ey; zCZeF_K40Sjnd~&>B{*GgkjgFaUq9iI%_K5!0)y9xwhf}Yz$Er^k3S6Z5)Uv zv=9Gj7c2wGkWOIqx{&$lha~QTA@Bho`8Kk85Kren7)F;3VMLZE@VCzLGmA%WJgo-A zcwwxp)`mG8v9ZrbKMN=E26ri43B&Qi8ghrt;1m?c|LVw32(kYvIA{flRW)S%n6GEq zA<+A9y!0%rh*Yj@HW}23co1iZA7(IG-{=V9Wv$&~-PffSEE>c-mAz#<=;7o;`hkK= zmEc@_$j>mWN5e7bNxt_o{Ez_hYeTT#p>R7o!oQzK4}u8tJt}^4Ml}6fEYEsgnZtJ@ z;i*kTvu%V~b_ri1GoDYhb{21{E8g=pyo_7elecshc!x#VO5c|pRC+f-(gVnb-bbz` zan_?+bFi`T!g|9Z6eQA}hwdqe#GWMUz8P=z9^=`7@f$*9^BT-$1S2;TN!>(_AQK$I zEXZyUzboVST_NVFz?uprml%V6{1?ovI@#s?*uBAE5W(tRYku( z#DmRG%$FJMQJ$Fj23|)D{#RDI5#CW&F{4sR&=X9o02SBpN3}z+yqfc^{an>e7_uuk zM>;B-&Zxt{lNT@#Ta`WN8;h~K`j+{=1w$$mQFCT$b;9ue%aAkgLdT=i9AOz&V!J-Y za0!39K9=5M$j0hD0oK(LKf4i(6#5~6U)P4&VpHmZDlek*Tt?=KQrn*QJz zFPQr@vT}lPE~md`Z+JIXneE~D7}Y_r6T!4bFjKwI@S%o@dRsL4G_2P=tqp92ZS=`Z z&!{!i_wea{+*wh&NA=-o)2WuZ0N!e&5871ykoKQ1s+ypuk+oi61*wwo1B7Fc7#D(oY?g{@%d~0lc5jnAoi32 zFDi~Uy@8h)i^ZypS0sBAl*CrlRB9OdQnPrUzOO~d&h&t*))3yQ^nT9I-@)jsWV*43 z(HXk~T(k->la}JGNT>AGjQBzPwP_$KS*W%=j*Tu0H&wxUti?mh!fv+Hk-{hBOkRL9 zzJ^CtUZ2L9rA9FcIlIc(CD1cjLrWfkm-dI!2Y%E#O}dt?LelEOs>`NiCFlQyb4#bT zKj4myf?Ht4MILmi)fLzQX zs_Bkz6t7#A|5&k8uyt;FMTf%)mQI@Is8rpLWPT^|N)~n%zExeMWEP|HoHJ(7Yv415 zfOP!O*E7CX;k9mLPB!c3Juki2V8J_?*<#uTF!1(zUB$xg3751mV3!bANaOP zoIV(ziT;xX^X!i|~N=X6c)i7HVcgRpe`v;Vbx{fs`E*4#W>> zJVM~h+}59gh>OoHX!f?9hr9-RTd{5HC^pwbC{moBKvVYMbZOXSm6DtXkUXvRK< zJ@kiIqjy3R)`S67P07g)1JT63n?V11rse4}+;T9~OQmSiHBi9x#%p;>)i9lehwRZUH?f`e>`*pf^Ap94D(coHh7`7~==` zHyF#9Ms>q5M)_Z~ADv&ZjH}sIp_Vd(F_@sisZvU_k3wH?hT&+KXzuqJk%R0s@tFCY z1D-U2EBk?`T8w$#hGlsJ-!?)y&wY1dww}Yg?*M*2AIYV65+3v@ceL$$2xCFc-LnBScnWJe0Qrd1W!;r7bFL0V7fZ2)?Z5}>VhN&Ii^ai)TY}dnv;Ir)nu$m!3m9-;V&yZi zuy5&^!1)`(%I!gHx|khodMW3)!{4axio>sIModtdii2j#YUXqU)k-#HFA|xFikKO2 z4x*LQRD+qxN4$sgeN>;M)ul^)5|K=Hyo3VGMOQS?NY-^ly#4i{5zQI3szd-Uv8J=p z8o^-qYZ>tXpTD2P47bP6YtDWC3xlu|W0jE=6~rC((y!x-72)dhlatNI{dCt?6K5Vk zw(k=8HpMS}sy(4nAP@BkZr<4ht9d=2K20P!ikLSEO<0pWR&`cJeZvms@e{rI3Ml=! zq8yy7CijXjOa?rPHGhI@e1jKPkkzySmOekl>a9OA!rNKbn#K?CmfE$hAx8LCOl zMJaMBc@4SXx|PQ=CSel`5#PLHeEJi&R6zD_pp)5S3*3Ot^Y{hxsR!(i_fVLsf>^ZL zQLvtzFlED7zq0FA2e^g7XyTLj@gIoFE)yaAiM1+AHPGM0ZV9~B2~?*j67~(t`cR95 zuMYA`tgw#P&xn@--g^whvI8>rnQQ7zta_Em&c!Nifeg-MPWEwkN8z;p&5GGfeliPL znmnAp7XET+81WHY&F^4)z0t$V7}Y-bld<$`TEejhQYBmr&6pjmG#vcpHQ%|9j;##G zx(T-QGd}D)yeKDm(=MtI7`F;YAEY$cuz z;OJkFgR*2X&Y~;Z84j@mXCR9SShal|XBHB04$JkH)my=Leb-qJiPY`1C2}9kS{78T z66<*b(M<(b%2uwdKa%+pYt;|QEP@Za0v{^~j{8hvhYO&Z0mKy1zO}lE?_8nx^lvcI zb`U9-V#dznEA(KNsT*NVWWP1pDenz6Sv^@bL-FVTWxUN?eLwV5aq4$=gZfqn6_mf`(dxu%L@@tiVZI?@^UydS@yOaD?*;gLA0%%fBea6wW02*~ z#8BN?^RK}p$cHoAwb2ICSx-^m_PdFFf|-NSjLA~u;T)@{H0V$a<5>)Qbp=@~kA$kA z@_)d23xU%X3RctwsZ0ldeIz(;VXi+1UhiSn&q3G`rC|35(RXb*kc~a-_OtoS zcGwhsS+73riGCWxoQ=n#^n!mkhxMAu&q?fAGIy3rEHVULwGRz_7X812Q9p%bOhfah z`7+G+iO_zcQ({?D-F;)7AFSaRqg;ozR*L($N`1>@Y-17P0AV3t;GW{Zb=NQ>SMl#2 zV=E70$bbz2{?` z#Bo*Gh~?f=k-wWUoyRc(IID(Mz0ci7ajm(TB@5@FA`q11D_2|s&RaI5Nct{*;M`8$ zdBtkUh$ig9-DG0^La~K8u^Snf@tWXWLx~29Ay;*HR+QIr@%=n}b`bV4g3-T^6qn=O zXuOuMtnK#5`LCSiKJRGgx>9J5a$IQ!74C)iyY?#U2`+O zM$S@;SF&<-F^*vV+$n-N}E=SPt>@$#`uyDTjNWC3R^_Ee-#PO~$ zcV1@iEC|O#qPh=U&wKRFQ^w~5zh&o8_9x&Sd3ZQh05ca2HW0v==VSb;^E(q`T?b#b zG-DIMs?Uj~EP|Fv$BdO@<}0&?Q~7QNW*`QcisExc8Bt*)WXFFBVb?lM5=1~KHmi$RhZ9L=Jl$4voJ@h zz}yt$rzB^H$eOcoZk3s%RVp)@%DubLGbSYa2VSPg_eW-e>U3sDMH)Ov z8&qt3I?*4ZvvgKTI94u+Pk!NB-+Ao`kDILbRMy5@B5pO9|zhk0B^f~cZp#XsVm6U^O7=JL5u zrr$B|ahy-#itN7Y_G16TnEf1#K|bzZdV2Z)MIo;#e9Fr`I9c1$=PQBhH!+7!uIne? z%*Gss^L<&z1sK7K%xf0bRe9#ID!+>{_I3HIKJzJ@vx>|^X~ti^Cw^iy-I1$al{oO$^>E7zNY^NK8GT?Xf@%2r18wntR?U}6Iw^-^<>63*e5?GWW~m{%DxXdxY~65m6Bik%&vko=9CBy5b4fpT_eO ztohrFlH9YP{>PE8YkV&OYju5!37o~1)hzHsd%1^I5EPkw^XG%9N#iYt@3 z6xqqjiYUgKs^*jXQv5Gn<{B~oRha*V*nN?L8oXAApV~ehDesDHEss8K#Ag~JB_%k9 zd{g$$Er+a$JeEa{imsSZfRPakLKoVw;38|pLH$1z;XW#SM zW1ipT3~!jHFU->${(g^rH8SUJu3A=eD(^_fKxR(v={xuGo%e#67Z=C*>XRKae><5i zm(Mx}Aw4o$QOu55f^hCM7vq?Tzk+#H<~#=ykeQjz#E4Q2$^RLc(Qx0Girk5oh-Bu) z5(oZI8daXj=b|`X1P=?}mySkOJ{!h&WZzryHG(*b=35go+D@+bt4}A%O8JR2rf^Sh zd}A!DSst%_8ZnV^NafQX8JSnSD!F@+_jtaM%=0^pk&$(f#OLfh9IOMIPkTrmw3`Z5 zS-+`_K?D*i8qvY4qP?S#lLVeyxnh@ZOs#w-nDwc%HdHK&tXHYh7mFfnF%RohJW?BX z@8VUlyE4iKevG^?M->SSX1zr6Ong;&UCwOenb?aoUSlU^uEE21EIv8?$#F$vi>?;U zmdgBzry}zCoxA>s1bk(D68P&A|BH=wa(2-bDU70pN$Uzck6VE}$(92&|{uh77%sq&H5)BZ=cLF&>nD0)kzN1ERFJf2a z-sCtU8M0?ndX8>EilTTw9q(r5x7>F$dL$!{%*a?I-x0YJKP;HfWaTxnpqY4xlx5_3 zcAksA$-w`aIfA^JjpLX(ga6#3oy1;9u2^)LjJ9|H;?>Bi7uiqZN03PxLNbD{8Rs-c zFOk3P{Qkjse)g>;u{^TljqFG&x>K27bg+i-cP_n%uRAE0%|jM2NNdinOG1_1{?$;sbx-mG9i^4_-^;j#H5+`8%1{ zWqf}6-q(2D$z7-LTvmX*ad6O9Gh%kTFbPka{nr1+Na`7JXcKYnjiX2WsXGV zEX=a_2nw@f`ro+8I2f1-vVKUiSXDFs%Qr2oDe);&`P;*HWNc-ob^bOp;<9>V{d$>k zkwRIyVuRChmLNu2WKiLM=_qUBFX`T)a0Ia*CPrSyOLTJ@|BL*Xd}oo_aq-N^Ck>p_ zztThp$mqz~#GkZq9$8mz{7ms>4ZibFCwf*m zZ{jzJW{|sFxx83IvH50> zXz^)EozWIer0~qjxdbN=Js-fg#kxiK)|_ZL@nmGaWd#RuB+=AXuF1qm%L)-Wl~wYQ zyMM>pNW=?x$Eyulb)`1pj}+8b0H1v7vGWU-9g^k zgU2`D9V*Ojs!v0t`E-HKcz)yYoja2;_D6-Hzmj=X>~kWcB(f>qk(0j?nZ2*R^_t9x z*%`r~zSWTYKWP`gT{KMqVv8D2=%F$#USbZ`tzPzkK53{CV#l%jFyo#ohb*pn7vNHT=k&J`iw{vqx zNjyBf;=g{;_o6vPuL}wznpXUtFZ`W~e5P{WB3<&H+?PC)zeF#{x|RC=K%_>bQAXK@ zgo;J*uK@9?MZ$u3RqjM)Ozy;gKk{5On~nSP+hwt3B8PHJzm^uCNRBLHAkrd#%U>qn zkLV}SUgCL)))Xx)x=5SAW|vUBU;bpd)2QGWOO996KVg(XT?7gJ1-I;>qH`)Fti={ z6#S@k++z@*&cNCd-&;mF5dD{ldse_-#ddxmx_Cge5zo~mVN)fZc+a)IMvvSe1`(dJ z#48Vc@yUJU;vJuTiGcul;- zB#u8F&S-zKf?Gg!SA#XL_XmjD6cIeCvuoCt^ZgPWDHqq96IpaHTCy|qGBSB%;XCvtC)9;}M=uz@(?Ft^!jqZG zJA=q+^#RTAOdfO)49{WkBS!Fv$vh_TN9^^N=lPPV+UmdygejIZ#T&*?a?RJBd z9R$xf=^OJ?%*1)HjobVm&zwpOdXHJT$e0}_W3UmtehayW_58mTOk*b~$1c8qfot8z zV-KG?2!1Pw+YM&&G4k-7*%zBG67mTd6%XqRuYLE)sH{WLN@gAw^t4!7(d2?d=J!SA zm3W9GIs?9Ja9%^o}kkz4CR7VCE&-TCRn7|Y)s_)GB521N3eK?G_d71fCL%YhaN z5>%4k1&H%yr?fK2M;RY}KsNzquRiEN4N#*pe6BRJQNj250zN+=v(KK02Q8LD^n=7T zUY|B|@LPN%v8|#p#aE+@gwGlHyr7GIuUg`4(b}?dB@z-OO6-rIY2qi^(F}e)k;tn0 z#;SkENJ;!AHX;Pw;NiFU3G!{xRT2fI$D2uyY)h0Z@pKd`Bt5^gAnSr``=e?%XA})3 znol&YSZVQlB~lhoJAv~EW-F1ummfK!#MTmf`8_MKxDt;@94@0EHd?$~iBz17h3HVR zAo4vgcP^GjVq?)n;^R5^OZ-&%q};E>KrYVrlh4~Zw?y1x5e3%}WJK_aCuj;mHXiX? zP~)d)ls7&cLo`J^()9}YdXAI|mLX_~L=zI3h)w#*U5TVgJSO+~lj{&oEIVYmxoa8W zAACllUO_NLgGto(mFto@k+Be4F5{5MGkHbsO6874AB%00Q<5Xf%HL5OL*`gK z9MRk9SshV~zMM-uDkIk{~i|N zD~k+^os{TZB2KZCV*hL$T`Znh%s}6{WDNW_WP#}>^iTs23oPV_B>>>P!cPti1teeC)g17sTHi<;i@k}bi#VX5n$wS6K za2bDeC2_BKm*V+Jq%0nV#8Lh^6Kn0CTR~-Hj0Eivk4~`CMBo1+8U8p#Vsx?Cf{X}0 z;?MiMLDnR$6b$JFk_l@D*%ZW1GC~jjht)mfuiHMked&{2LEl~=qk^cu=2-IoH;ylB z-R}>{wWaY){)xpC+bXfQ=o;~}MMp?XE+a0Z9nKv}WEsZ);(Z%^^WcyAWvz-$7cW@W ztY8Egc!)nJmQbP(zXvXuNqU}%=7?aX#QuwiBO@#xxA+v|4axY5rWPMX&}ES)KQ`d^ zHN@MK2>2WCeCEpi*t3kW$eOGriRmPJATuJ7fmnr~yek-hc$D&<=n0v5S$8sHk{1)r zDt9RUmq?*_g%+NPzLBWcpUV|_^UITXbn;9PZjmOD8k_HK1Y5E2EFIqt^+}}oHR3CX zG)lh`LBVtRMnO=bY>Z%5eoID7{3AhwB_olC=Mp*Q^{r#Ui}UhKuq26@<@gbtUw%jV zu3Sb`)|Pl&g64>plwJ8m{ydD8c;F)Kf*=Xjo{BU}{4TMUWIM&Plr<;XMWRK~-11r) z$CObLJj#!-x%ppWf0;iSB{LdIJ}I*(D4={w{73Ol#nvPt-EVw0`Xf>-wIc6*dQkEl zg2sH}6M~6;;Q42M1T&Gj65m#i;eQB@Efz~Mq4Jl^y1XO4qP!;>Hi_SY8;KT@c^6MW z=2~Xgg6{I`6p32p>eIMN!AoRK%la0NUhY6?Nh~R(GFcQ;CuYZ{d z(Kea*Ez!F~iV_QouP!nnnlzN72!19A-2dwf(SH)}$$Arc|9|8~tgqM$@yewJTGs9l z-@J%M@#|ah%LV+K)F=KH>`Of5w|q;o z0%Dav@JX@H|DSF1Yb!6uknD(zo-`U!o}_Vl;67VZ1KdT-Ji% z*M3w=G^$uE|0sm=DH$c%(MxjKVZNgazT~$BGWHTZ%SsfaMdBFwOQIvOi-KcIUellb z@JD81tK_I+9sH4p_!0gUE2~phiXgI9W=v3B(MEC>K?nS+Sh54+;mDmx#3E6@tZ=y( z(NzI_TaGCniXd4Mlga(dJF@CTiey!Z1c}tiT}brhx14eZDa?=`YZ6~hG_b5w(Q6`~ z{y7wzAh?TUNkoEW75L{?Q$NJ1OS&y=k#1j;biRcTFL%)@m5teKA2g(4~gt$ zuKY(5|5ffua9Gi5{(E(E=XUN(qKRORD7b>G5Xn>6IF{H?@l<5J7=2eI=k{Z^f{uJ+ zd}XZU8z%IwNQ!u{lJ66wN8(q11TDU#%(Sf96y`~o5Z`(3N0vpm%A9@Wk;>JHe7Klx znSKAf`E`Sb>lPUn>n7fctT;tEN zefYMwBPW?@nLd#o)RM)PIWKEvoH&r~^xoAgV!muf=9z~p-(@{84qUpb6%S(lRW4~a z#spt+#qS9(MX;HWeB%lse7#(RTRvc{aZf!3WB5;TUvKj*I@5eS;u0$~(*R z!W#9-u-0|B9lazaoK8#whgCsoE9AgTVcq@g#l7Y6XdZt@e(XqI?#0YA8zD{B94Crp z{T#1gJ;lWG#ypKTBmtS#H^=kEKVn=Ol_iK!XpdDi8lIR1{Ab~~_@6^R=sh-9 zV7BY1)~afzsw}_$Wm@HraSI*;;>#cN|6)|pntMPUQndcq11ZW@TGhNK^oHv6L&gFV zf~=no|NMTwi8?=ymxh$slHX=kX;!CE`Gc|i2JT4XL=3zT--K7gVp4+sv_*zrB(NNf z&Ok*yI3f?>J3e5e%kGbH-~ry)FP+qFRRnlw)&0j=eQ!h#ag~STN|j;SFS1rWrb|3$ z`CbgB3Y|Bug6Wz09PEVWQn4j5^+(l>uZL{p4OBbIy25PM4rf@t3<6KZGW?0vSP`Vh z>(n2APd|Ld?;wGw6H4(s{3SkE#BRngOSKhNl}#zD!oNW+)+i#DGx5!MTE{Z*W>^=V zcrq`^VydCr ze)EA-la_h}{otR(eJleaTY_{F%*1^tyybh zNrES)XK`vi%~(v_87>x5>v64h5y3k0QQpX>9184$ne@Mn>|lld*3wM*>Q~d_e-7SF zuJFV3@o{RwPjhd-JPCPND7FIOr>1_ zJF~;^)kr2GR}G9-LK7=cAv(O$93B|?Au-Ynq6bf*j9gSW^7H)p89=nb$s9P zjofRs)_WcA>g#nq@odwVR6Ms;wr|Y!Y@e%b-)gUF7w z9kb`>mFL;^{XhQO6-Z7i|65JEeUmJywsd>-Q`_^;X`9=3+p^XVYj{l?j|U0)1fCbO Hh?y|T;AV%EXT_Eo6cCpLF-TfjLce%Lx8+UgjN<1Va1cJ-5Hq!k) z!~MVCu*>X7OVv|V-CfU2=TF&_x&(WHCyu+fu>_z^-Vwy5reG(S#=K>SGCR$aOl z!0}e?V>-0z64TWO`)vnJ8CJ7u#VYu#T$TJWXwo2pQrukS65-s%HO{c<*c|zrf-?&C zI6iLf#J7S?$CXO{Z#VYU{A+ADV&@q=hugSJEW|`4v_iz586OMkHprAa|jfCQl&qkf}ghSn+EC_~6^vGHx(?SZl= zTB@LLS!lb_{w(w|8`tOHTSJW=`Rz1XYqZy&1mNROd{Co=bCeiTwPDLb|82N0FTXwp ziP%v>4o~C1cs!5eulalafqz2{cHAN1ejoHsLZ40fB^%|3p${SGMPU+&{&?dW27TC3 zt|4C?Qnli^56*btP8G*9_-{x&3uo<+p9$yv(MqFaUzBXco)07uhB6D{I~=9^qf`-n zcA~vTU;iuHKtdkco6U2v8NJViyqu_$pbZpqH!x_(%qY_j+6jb~3~3np^2NuBvm&&j zpv8{-veWZhmxA_X;F!@5H!xvf(ZH1x{|${wD9?n=19cdv5}+lX-&Yy?LcV-CuFgWK zhCK7|KNlYZ(QatYsLg?1=+Lc~_6YVt0x8ta>|NqN1&|+xB6TLOC?1OTQGR^stG4O6juiW|HPP8Qt`wY_i z&+c6Lk~A=GMk|fYf-(#X^2#sG(7sWoC;l7S{r@&*w8&`be|uyaYW143q#+G zvJ6xNLc@iz70X9ZIDQ9VGZ5>G^TF6RbmxzD2j;ijXos5LLj%Pc%9e>M-%eEg`tO_u zsTf}2zuvfU)bJ;UW(<8X^x4pwj`M21%yOY6162mP{%dt^ejoC1J{KRO4=S|iMhyl6 zocT3t_~n3fjB`d^|KY>9)A()NW9ZtjG&_zNoAKLdr4#=RDH$K5Oyj75FasIJF9mgF z;VuIuhIJbM|7(YFy*vN6aj)SSRn(y8W0Ij)hW04>Xn36e&~NxWg8m!YF}}_Ddj?KT zkfhz>IVaA^E-@u+xrqNnMj)qq>WNml=6YenZDCXOaC+;>u{|1V^al{0j8s5+F zf>!JqzYRTG^D!djUt^%hGykZ884v7x;Jkq?W6$&duC?ZC|39x`pvxQQJ@7GO&$!$8 zCE_j_Z8iF-|KGQP3qjv+Mx8h#7tuOSTsV+KwP#278G1Nn9!&cLqWRh9gxB}2vrYAk4palZ{-F&k$M zKW6wFBLchfC1u3Ybo9e0BNLu8i6>+4KbtUWF#NpH%XGw*WO#q$nqNExWf=QT{5K?! zi@1}4|CzYXh(Mnad4BLu*h|Mb1D7WFf&%aZhK~%&_YL9rT@aC?1c@RwNj*}ZG$*z3 z%kUqC5m$}KT85M-rSiQ?QFwkMx)^vfJWnK!7liNi#%~XJ8N<^UzBmeZ)Wuerl*Cp8 z13ndppeFm-xF~%T9q*Gu$-Z*bTDTaqL zqP^jrP5C-8<98HlH>{BXlSaG_z%K)HGRh0ZFO?gXMTw0kVlyQ43R^5b&k(6IpjnC< z4ZIjJ-i0Ia{0YCuA0mo>LNtGeSpF*?Cx+f-_^k~76L-f!C-?dP_+@O5c>@24qejH^ zCzVK3^gIaqPr_9R(CZys{~2}0;yW9C@`iRl;9MN;J;!hIV|)+a$!GHkd=tN(-zo*A z|AKT3tSZpxb6j~p|85!mHCk%M|8k@yse|u8lxJ9sf$cQ3-)Omw8=4A1-;J?GFg$}X z5;DFyBqdaRqap=X}?I`qc%#Bzl9I3l!?PIvEs4K`CRgy?{0y{cVC)<)=0!#g0(2lY_$3-@_LnkhKX(2`fcTq@ce zj`Ahcz=6O@D9!No99K5LzAs9N!tV^UG8>*F1>a_rO~`AMoesYdkCuMtU+_u9SsP0H z0yMjzF&p}1_*geL##Wh-)hkHRh$?Zgk54%64K4aWrooVAB1-znAMx}25Z}%Z@{@cE zKg{o#qyl=Z@fWz}Fv|K0nG5;e$?%cJ$i52vM<($816Fkv_r8V{Z(-Ym zwn^kIbQwTCK_=et@|;&jTa5nbki8%Lm@)DUq#Xi{|%37c+pfKEDfd9fb_!A+U7uY9pEB^he12x=&un2f}zc?Xh9-m znuL4ufD2>pP!+fxM>dhQWF1*eCc+XLp)HkxxZmiN;Sr4Oe~^+1wcLYNve4J!u$HoD ze=~T^iD+|2G96YKNj~!j{2HWpgYSd9e?Y#aNMDqG8|9BB8%Z4Yo1s^q;qgA=I{{Z3 zKIJ0XUk->!g3L6ujlw!KoPEw$!6HJ@vr?!n23~&@8BaElrKq(Nup$F-X^@`|xo?Gz zPVlqvR7t>JB~l%d{s0XY##JiHx&+Vl3ZD$<;u~ZUg%bLb5s;7$Exkp1jEJ0v-p1lA zfh0@idut7N@WSyVU}GLIaGWoP-Q3`}`5RbOMY5bs0-B!y4@Kdpe&PI9eiU{!i*JVB z6Ckq$w9tu`_@f_EB7g(u{1Kb%d>#DkLOu@Y zj00v0ke)za7jlFA3u_k0WArx{?K=*6XW+8|I57b|ozeR9K-hHB82AfEeTl%&e#klv z{ak_i_M-lxxT*^oLi_({h3w?OO(SVb9lgFIdkn5{{Mkd@?5Aha%d&lm9V z=-C8FwLh=P>p&)#Ak7Zg>XF`%(+%`F31@5ZF(~aQ`T#dTCXfL7lKev+l0{?*FcpPz zyO5XAjuUllK}3i`^el)vf`FKTK++5JVHR%y3_k_3YLVmo0MPjnrFSOBVZ*8D@pb6I z@Oteb0~KDOFg!>k?yrE-3*&eq@X{GAn}K#Iyaee6c@%^HdyP1El8*xRf=LSh2iD<5 z4xy&AxV|~L#3!M~hmg!W^dXq{0@l~^);QZ1{jP!%ACT{mM`<#T>>$_3Uex&>7)^p~ zZ=tvG{1m?e>4!sdTghLDPt9QW#emossN)st9*pu{16vW~178FQR)Qq1p@et5CYb`X z1)}v9vK;=e66_&^PvO-d^EL2z_aTD-(u+(bYsg}91}Odty9vQn$9Ng;VBLW46DYej ztnDBf4yl$T1ISH2mv`ejE5dv5WV6E*X06 z!3P18HOY2z3|m1uo(`Z*=}Nkh4yJXfo9qLwZbA!#F)AnsYwZuebsGA64BW;-C)ZHp zVU#xm<+zzI?+f|Agr$1mjy>cs^xO}%_9Sy43z=RgSK%i^aP&BN0zK~`voX#%%+34- zJH$L$ID5t9$qXhmZ&?6iJNFUFd&CaebwVm)-LK3mV$r=VOv&QRV==FeW} z7xZ=d82zJGMEjwhQm3e8)HO;CMN+Q2`?^cI!`+o#MV!|hlJk}Gq-&0Qq~cJw>wj^p z@JT9V_VDQMxx)LD?=t_x0Z#(sf|dps3TY5pJ?wc{-|*$(eZ!xIDWS7Ml7g-TX8T|B zv3l+?M@T2hWj#nO=^AVgu(9mpSz^|T%*>228C^1#WTa&r%G{LIGyAWcsQQunblvQ>Ui6;q_bi}i(AeNIAxA@a$llPBVG&`+LVt&B5562I1$6eS=Hv3*mjywE5Y>avNqp&OD!? zrCmwwo$C7Sl|1`b^w00#`+xgi{O$N7@$J4I`67O6_REo-t~W3@^!X>i9XK!FaYg$#UaHV{=%HB1<)oa%@G5T2ahnQt8gIe~EuHW=zLuak>l_!_(QKUy`Des@+ zPW5$Or|dcz15&FcZ}@TkbDg-Yub#Y2eL3^ht5-K(1U}#JEH(Dm>kID#z83m1HJM}% zwolZa30KXxJ%9RL3ymyXvxK9}`|>drHdQ!Q>21}6H6PY#S2wP9c+JqN3oA@0yRvkb z61$7EiZ~Fw&v&e~s>wxv>G#~xj-R%%xn**)GyA81OYM<5C3R!ksEpm2BQm>Xmd~n~ zy({OMt-PawYnQva;;B?|mvk+5esipJ^m1h9iMGW#b+RvJ4#|j3-!_V12!hZZpc${!7q2c%DU+;fv`SI2J&hIoM zX-_shh`2lBj?dk{?v;Ib<;j=Wl5f_0sPO%9O0T>+db;q~RNFe+`>Fq^@aj=PrCGUq zmC95*T61B&M~yc%FWTZ}i#jo3&7U^u+h9`7+m%X{=^Zt)V0!rP;G=#It+S+ytd-ir zJ=xjS(Jaq1yG>eZ^4eds6IcD3oLn=-EA2@7@(eNaN9LNWZrOu!Yud*VkOE)p7JjvZ&P&J?5t*K zsY!X?13$*TT=lT$jfa<(T?jh2|4g5AZ!Q$MQt6iT@Zqx}Z&E%EOBkGX+);(}G>x-b zePRRb;cJQ|R_s)JbAyb=&6>ZDNodL2ENdUqerKD|mZoL}8#JwTrgF(LuBeQH1;TCx z^z!*+`Ip+2miCmaR_QxarX`*JQTyAhFV#Oi{ZRYEA0LK(Ece;=rR2Bh9~FO{NPeEu zA#GlINM>Tz#+=)^BW&kwnys?^FGrxWr}K>CcwXJy@a!My*54I>h@X>Q_kQ;H;f%ZL z&Ae-wm%5zaelGc}<;=flx}Ps`CF!Bx*N+)f+!q9^X^o|2U`$b^%)82~YL=+ow%&;5 z1KWM*+_0Cc|L=jthTIwUW|(X6_x{y-oM~-o{JK_l#crh<6&1rr`P7y!yANfS{rd|9ecbd#y|@=&F8-R6`OMLX-!L364edOyAu``}Md+Psu#*36!AKrX^TRyIQ-0`?J?+br2e_ivv zQevB=MZYJd)y{01Guz(7ov1uh!rYVWVL5FwUj81D`2PE!Ut-_?{r2t4^UtE5^mx$o zw&%^_w|3oM{pR0a&$E*qPt^?Fn{acu|J0!P(9;DYi`6SPt@hWZjazCRF7^1?=dXd% zu(rdT15Bq%i7u*>5m*+lVq{Az%Wx}#|XP;+2nsM*-_1+hE zoSuCA>CrJK$DbQ}wcFiOkE%Q^A6x!S)sLay3;n*Iwb;3rjP>jiI z*GBK?(``)m_FWftY~OZt%ZAZko6Kl9zFxmt9jlPCm7@w4_~_>_m1g(t*E9Y~Uht#L z*G=!)>z*$vKY#M9-Sg?s!(%7Mwt2qbS-0oIV~@P3{ASnt^v{RB=O(UA9{l^?-%%-R zQc_Z?r5;JC^4mYTS<FCv_yp> zV?+P)9M2coY9w#^vheMg=jwwkxAU&8zdYh%-wTH>?z^(``o&vy@6CJo?eXEKGh&Co z3H{TBV`8y`8VR6@l!Rjbz+SZ7ef3r*%We-d*dCNic$O!4UI&8{{X*RWgd z4^@LJEGj-N;%Pvxr7M5z^v`LXHYPbB@%*=5pV-^xFMmG!{$$c)%cDgPhTLy|f5iRJ z2hAT{dvgA1;PX;1C%oDC&i7;ePenhC`jqxL_-@x}N^|B>qwA!?uq;KYa7x z{li_4^PaSN-uYFBxbq*wzstY3WS?@E5#lX*K1%|HkiOw(3$7^YS4yc6Q?&;qak}0g z^{?04T`Q?d&5H45-6f9|`&n>c$WOl#UiHlTgaZ07=a<|9nX`Vk`q}^Mi+2}Z9g2;6 zw(M!Cr{PahAN~EP!^6@K#@^4q+x?#VLA%EfpWb{P6Z_#s>$ff5_j#Z7QU98qur&3n zZHX&LFD0bNeLSD~)e1Zjys*IQBEF^HSGrxJU!5HEd_nW3EjzaA(sF&vdMz`eS2eBN zXn#FdZB}c24WFv}E1oMms>GE-twZK}jwjn)Q*B~a!}Q#g!ATQ;pm*_gK4r)Kc=alF zVQl*si(YZ1eK?t2?j7xAWfyzs-7kD{kaF-w*Z=yFZ5T(8QOYKyDitA4cF^6I;5X4H6B{d={LY745>uYR^#OqCH8 z7nd7V`j6t}3-<{B7O>eT$@9AElu_|4vOhnbaexUQ+Gk zlD`vvH%MKQ{vabYvv$s!+~B;2jy*1_q^mi4Lw=2<(@MfkI)^r+hcOSqteZ_?-t2+4 zNiC<;aP@MWwtLxo*?e=C=gi6}l2anPS7wp)=V@W-sc9q9SEbQZnzlUsditN~gVJke zY|6Zposi?qxs*H9wkL0|BgQq}9i{Hkuk#vowU8n9mjldU9&fE3yaIfh`IQZ*7{r5z zh29RUQDAVykVt!EP{B?G9~T^2D5Fqfp;Cng6r34ZIihNTX<;2gt_3v?ED;dr*T(m` zx9a)bW4^hw{7kq=oa}$vPvx4sv#Wu#pCd2tl5M_ikFAewt!bs*W$DedJsFxT3|j{o>C!EaEX4h zWQsTKF}Ja3mK={w){&mQy@I?o?>wK!zP0^!`i1#-_HW@Y_#gJG=9lJs+*k9d?(?Vj zBCpe)cdeT|T3cew9ZkjMNXb*YL{E{wd1p36zpO=RQ`LrQG4+#jRoSNerHoe|C~uX= zO0LpI-J^@UfN-Gm|9KsRc*>^<%04*WttMEoOfS# zr@9L(Qza;P5UYX}gE6EK{YhsF>B3;~jA)TY zN^hkoxvRWQekE&iB~w#VGgA*!KT~^Cd6UU>O>QTDlX^%i#TP=f@S66b5?ze7s=1gA zr?Zu;6Em|}dS(5awo+@Y$=W0Jt6Er_qP^1!=) zRQ`|5}E1{8b%6Y|K-Kcg%YU#M%oPB2f zFwfmaB2fnwP6$0kU0f_BNX_JOLNwuu%uZE~y)Nkq% z%}bx8f6<$qv_wkm&hsx0QbBgtIMiT}ZT_%|s=$I@)tS9l_n7Hf(1#A;%7v9#zX z`iQbvOl&9i78{8s@qsX2C?VXV_30h59;**UF?&CU6^?e0%L~?&eb*Q2rSzLxZEYP| z@m)EitWee{7ZsPXLM;kRJ=f~!`*n($@MO%jKeI+y)$2ks$a%V1SR%$q-=)U#WcjlE zM&2(kk%!8|o-Zsm~sv8%f4v2&QSzSHc?b-Z_+bNuVrYUbW_(W*HE{g602-f`)DO} zkrm|CNiAAjNEQx>bEUy@J(Jrs-E6XKwpcxydw6;5w?tdw%^S=$%qLA1O($e3w~;!E zErq7EE7{0Du@Ke|J#VI+RfE)y${BZCcX4+mcU}CCc2960au-l`!%NiDy66kpTK*3i zLZgHa!gSF?nj|@-KjbSiHI*<$n99Ne{xtn<+GpBe>SPLq{!^rA>9`m!t`lkq=jfj_ zif+T&*LvQN=do|>HM_tLvazfVQ}i?X0$AN&u(?V4L_G%R{Hkrx8fl_-U)`y$Rfhl_ zZsjGk(p71$gkx)_^it+1N0lE+O?9^#2pt9Jr}UmI04wLKNDtajh!P{DK-nq3H61cH zuspN0@Yw9}(j&lH(Hd!u^BC@tZW(HMZVofYn3l?Cq7V^`TOtlhL^n*JVM?y$a0AFcP(2SaM>^)32Z{UC4}hc%mF zY#WP%G&=D)So2eP3$h!2@Lw7zY!ottCgLh_kNB@RP3#Ao@e#iY+k~!yzYs@{($O@4 zp25217p$t~vT4A_C;hy>9VK7FXS2QuesQIKO?T-H*j%((VXcv$FkvM%gY>0WXo%1g zJzR=ynlMF}E-Vuc2>XS-_}@{86du!cbOP;-C|!W2VAX62*2XGeRW%2z-!j&#llTs- zYnH_-UNly8Z(%(;1Z!UY@MA{Ct`wO`ULp-0Nqy)otp3k|S8Rz@{H0jI{!S9Gve*r) znS0>VD?_I7kl!q31GXacty(edw|Yh02fsF5ZKImi_sTit5MoeJPV zLib~(!U=pW_8Dekgo>WTyQ$7j1ekDJV_sad{0`h&Suk=G4DyqUt z!AqD=^RWKIckz+DJ}{}gXcerfu0>8K4%vaGJb*uCe*?23%hEsS&-AOn(|P@fep&ynmu1u0 zL-??1khqQ4MP6q+@;g6?4bmu%)!CY~Hm!s2X0#pliqSBtp)F_f*Zmt|efSGv_(DE{ zcf~q*3#`aa!kYaPWG6zfV!M}oA|fqP(0->p365i7bbQ@hom(eA36UH(->0H`}mZEVeFMymz z4kemb;Ki}JZDV$(GA|y&y|JPj$L;}N8(DW&h6ONRR-Sc%&0c0XtOC}`mt(#A1ag(j zq3Omv3N}|9-yhgGR*t>WyJNL?m)2ZMR*$GFv8p>qJp?PMtnJjoFph|Zzv_z2Kv`t^ zev_JL*B4p`Scn%IiT{ZAM3Yoc>I~axCizO=#0_G5(I%|G=;RGu41E&%5i8>d$QF!X z20=DPcCtJ&J>3zT$6<7{0+t+06cS7;(uTm(AUd4>0gbiAx_Vi}k-`{FrIAGP3|9XY ztKp}RbC`f}Pz#hIl4t1C6kZzRjrZ(0Tf+LW<`~(@EDz{=t-rKqE#%2R0<6tj~U`_wB z{p=L3`VC79fZcQjBG14QgOPcfi#$vgDM7o_DRc|{MuRZ|?FH@56aE!03pa#^!Y$#E z@LTW@J;Vgzh|o>&6TZ=tbQ+DJp7b5L0F>;5Lf3BX4*UZ90rm)DX0^gnhny2f2I@BQFx&ax$cn9jtr|IUl^1~*?2p{eQj7-IlcSLJ zZREgi0X+wiA6bu)@>p1RFT|K?$iQ&qEA7bp#lb&r;Zu2UpuP+|V<`Gp8TqB2IJOdb z)*bLgkHL&EGW$lxw;*KPj0}Soc91*d9mypcu$fDe$P03joCo^01F>^3GL1pp?1QY0 z!2)TB{Bk|yxisX_jC^TiJ}1N&z0O2yw*mbJpxI;Oe;B?04NY}{{u-m6=D4mnV%<07 zhc>`3_Jmg|2;207FIQL+#sJsZ86a*8^mZAes1#&!s=|U#A5#${AgCSMS06dEBH%21fDEU>XO`iCJPGLD3J*PrO@!{pvLUQ5wt*Py&SndN z`77)fi-LDN4w?HS-i}8G?kDj_u4@9_L!VF`F`*`+`&eNvV!~2k5%Aqds3&*`$@D5v zzaG~$p}s)#9<;3{;=Ga5KLYQw36?S)K6?T(s;eRSyLYO=L52Kb=$VGl672((3({Rl777MY0kJv^WCH^Ij5&MhLVr{X6=!s(aXb@ zuqFs8or5(P41l_bGV2jT;xQsB2y5y~XVU3(B;xcG+5?``i^h|?@F3gCG@!B)7!Gb= z}` zn^-YQs82g%L^+c7!z{Z4N{^tK==Wx1O1mPiFqC|bFGjg_;g=Z8KvZ}J3;LI>MJ!yz z<{?6?fUIv|gzd{~!`@~fo~I$6#~`Mxfqg!Pw_+p;qnZ||WjQ@UA7dQx9;*T0=tYbq zMk7A8fCl2x`o58~V;!8Y>3R-v}0a`0OIyy?ZaTF0Bh|rGOGcN8YR?)2k8ZGI};MB4_wbjM5%#Qj>?D?!{Kv%F`6=1@j>`+@X!sW zW(G#Zm*Ky5^7ZiiOChJJ!0lS}E*iP~?#S_XhZMpPyF7Rza_Dgw0e?p({V>K)Hs%Sx zYiAO!=m>7cJn&SER-S@xe_`(3EWfS>7=4U@XB?05%c6YmzMJfVeV@YkXfEtx1AP2E z;Nux0$RNa%eI%4#MqhdZ#oxhGX@e-!m{bv*;v=CC*}yYME=D{}$z1S#N@G?rlNaV| zNq_3(wcwYQ^P2>00gOKeKrdMU&Di+VKQk+SCb-$ z$9>3f*a(Lu3?|=zV^k!|^_48p9BMsD9jcX07xsyR$$q^Wd&s+!vn&kO z(UCu59WXvl)T8w4x|yf3VEu_!5Z+)Z`+yl?F7qPeG1hO4dB}W>zJq|<-{cEc-~wp~ zm>460in&;snut-{GZI3_&`^2|Xqo~%y~YghC`JgK5F2U(ofNEu8Th`&9s{ktc}0F6 zV=ONqy#o+y%IC!F1WI1;sqk=n5cQ9M&(r~aCxWcw$B9HIkxk%E?IexpI&v2yv%ACz zUQQQ`d2W%Tv=ZsVHu8Z&H(G^7kW0cux)!KuP5q=GVJ~L$GiVF(mavPjBPE4QvXJ%? zb`d{5k@lo}*#;m|hGq$|vj}zoULs9@sS9Ke-Oirs1u%YWg>%C(O3Ve0j1ky2jFd_M zakT_9EzB}`N8zb}Cmz^5+C;oU-y`-GAu*Dl@I#?`dAWyJTJzVZk|MMbTAZyt)gJ>H zyV+KESKe6e$-LA`h!fuA8I{>xMWolnL1dU#Slca55u0hf^b5i_NOvVYtS9ou!aTZw zw$yL&HKK{0U>$(Ke|Qtx4r9R*7-f~Abuq3o(;;LKpUB@qSLtjo^`n}8nck#f)|ujLc^Jg=x|;{iT{Ac9lBv zAKGHRT3jw9>EHB38Xz7f6_sg(N>*N))zycRdeno(=q347rt;I|nED)Z|6Y0x@s{3Q zS;gB+>)1~WL96TFCJTEtADYC*bC;NisN7trNdIJgrOm|06)C5gXSyD0<3&{t<*!{E z$OQ44xKEqwnk2RqSC9a0w!4o!K|J8T!RL}Htg_&(%Y2*gUQJ<&B|`n`xMHeEyU;k@ zTm7G~K>UYP(^Hwoy2!JIKCUV}+%%MwQf`TT_yBfC4$>;ZPkiTdtr_k%PTBm))JNa# z`Y2Zwy6e|WGqhMG*peg8aCg+~mce2hcL_a92({GHpK80P%ym(cek;eFr!A2lQ{5#n z@jGlCAQ!N;&zcj|!E;E~NViGIkx!V5sNS|sLV|Y!A8g;CUpJQ`ahlBQO6$ot*L72O z>4K{rvq=4+o6LU{&+6+MtReQ9zDWfg6SYl3L#Zo9 zY+cn$$}itqYMT8ska)*D#1`wmWoabeR^B=G3)7_yWHq~^bt9j|cxKhV&?>}Jwy_A; za530tp7WFag=ID!C$#4^6+BTu|1_198rsL?4)c2Ccha7m5hT_1o+8)GdyrGinqb|p z`M5SaFY;m`!&u9-vic9-YUX}6ljzS5yPtS1^5|{zu=n@=X&SCh=O)`#kBR}y^Saq5 zX!E^-tUYqa=e3d|ypqW&Jvd8I$A$ePS4%17NcOK|n&8fKd}6(5nr8!(BfEoA*3{Rt zmk{iHuJzaUd8K(>%+1W+C#ilrEI-p*IEwf@7b%T(XE+vlB+7lrD~HWFUdpuka+;T< z1WBLFA6T|MK+85qO5MO^=}9`7+o27HZ(i@1m^Z-`Vy)|OIdQu4bMT**wz)nIK{`ac zSueQHWyjFML2pda8D(sD&FLYR93$t{^li?OLXPDw-{DMD#`zXy$8&X_OylKptd*-Q=_9VC z&-q!`X6?9VVe)70XY*20SsQ9$JXAGlU9E%7*Yi#(PP4xm@x@hJoiAh)>w4S@MiwW*+;%Aa6d~`oiM6)XN(~G;W(h+iT{z`kos?$7S zf_OzarN@xMVvw{!32?8Ly2^{hXm@w*k=R6Z5~jNNTz$86N$NsLPJi0ocZ)Jg)3tKK zZ<9kUfmutQ-dfzD$M85|h3?_5VsctO>FKt!!b(#LyQF^SCB+H)OHx~il{UIt(3@se ztEbkWcg&^v9M=Q(L9XW!ZSSR|c@VvlI7w*he4*Fyc!>z{+dh`PH^q>u!YOBcwU(G` zDk>DkgNR|$O4DO9z~zti(4%%aJI|!LQ1i-bYK( zH_z(D*xn#)NZZ;=DCvYs)^CZ z3o^nylLol=@xR0}rZGb8oGrq9k92LRmV&XYOXw%`WgA>yrE8|PYDM=nVUjQbWA-ps zftFU*V>%g)73T^199l-mb$SUO*jTxW`JU2_uXVK+>RJ%Z!`yiUYoeygA1 zg7DjJQU9{oO&1-nb3RI+JhtdP-JSFyN+A6v4Hd4bUtOKdpUwYj1JxPgD*lPo6Pl}U z^fvM^i-(YI4|lKiE@RDAUOHFmf$}Etf>2KB;9iF{?!NT8R#WSTG1L{Zf@TTdotx-; zQxkVVww{a-zN?|`>)K~J*R)cM<d}r9bpH=2LpOb0$d;)?u{bEgaA?`7L>r_|WO=Tw%KBvCX;K6~;!1Dw)II z(e1jGzQ#IgSAv-~Eu}WlrpOjcM^SReX+N;;*bt+JuWSPB<%E`||6;P_Ay;D-Ws#=w z2SG5%KO@dD;RxuW`~ za+JnPzi3J2AO4=G7|}jfXL3mjlU8twQD;&52Au5s%6&b{)STP2cj^V<3Mq!w8ga;cDMllIg(SbrjIqiqQjDk`hoJBgVWRPSmG`G5#;q|YRknl=CZ7eI#M6a zf2eNW6M4_K^t9fQ#0fcMCf(0AD*xzB*A?E5kkZ;+lkHad? z12zR5;q&?x@Tr|{&E6cr#x_3*nLE|9Kn|)Xxm+} z?&It@<}-h?`HEGkrLU2)De^!%Jku;+_#kEXvzEv-%$H^G!j%X(}v{w2smLj|p z%=&b_n*LUq;C`vy!braytD}b_w{w||raH0)zro!Y&6m-S%u8FWPuC{!%F=VwS!p+- z{XdxFdvcR|DlI~W zd;+v@5?{$bWtk>no*N|$kfw^WgnvjCv7M=b>6vMw$t`sjCkr#AgOZn6Mrti~!U|hm z$xD8RCj{OipHNAdgY0|=*3jo-Wp)9bO7~$sqATXuk1_MVg1mi4WMh8`J*DOHE6m2c zXg#4ET~CT({g%`B;uh%&-Ak>KCafbtSoOKXpW|tSZdk#Ns&HE41tSC6tir?&@v~K1yX}nY*5Ag=?lO2u}^1x`QE*FY{H}a8Ubi}tK zUv-)~gl6I?p%j=TuduTH1x&C@LIPInwzG@e4h}{uv9Z_|459b5EMCA+9Sk9>R96&4 zf9bpIZ+U9EX*z2eZK-4J;x*N?f_0eH$C~0#4gx z*dLmEn!;S&U4z|gT$!#6SE@^NA9NLW&T=+$-*#742DoRq7Atcw>g%KRP|R+#YooKL z(pyVJ%nWwLI8QlOfjM%=HO>Ce-qkt9(bMJSUhYWCt6|^es0a4MP-iE{4*O4Mtnx}* zPB%)8O!YmsTMv4^^Qz->+4q0GalYgIsQ;?K1|e<3j)#pXa66)9i?KwJx9F8n4{LSzXgN}je`HQQK#$cvsp*PY zovNm&hRnNwt@1z_2%j6NlyQG{XS*-B4mb}vTe&8=4!e%HhPdXtCb)=ew{wm2kYk^t zrc-gmIHub#+Yi{A*oQl6J5|RH=MHCp^DpOE*B>skJIdYOWp{0L%Sw=P*LA`bsytHr zLEqQZX=)F3xN_K?=&IoA=IriV?wsf>=*)2_&P3-%$79DTr=N3-W4HZ7UaqZ`?XfM= zmX>R?U9fL;jB)OCQkReWmv)F074Mp>dn%q$-nV?K1V}+Ig4%`Tg$9JX3Ji;UUa(Q& z`h^=7epmQVk)=f+7jYE!DBLO1ufV&|FTtTfg#!-xEVPa@my*xZkNQcqpnJZfkv%5w zy-l)p&z+ycvZ`eTWF=-!&HR-4IrBhfjja0FA9Ie|Qu7`-5?mA1smz=96Vs&xIny-B zlHsuvFM!x%on@_Jb$YzBW?Ii!)2&Oa*Q_0_)Y{wnr$8?;^3^dSAS*i?Ga<#pDm^Q>cR_n_eYP!;23uoEvC3yWV+oD8jubnbFK zbl!2sJ7s4{$1g`a=*#My;cVmV;T+-e1@Ee_ySp+0tsaKt0?#6vMsAJV z7r8m|XT+9>$q`4x_l7MFT^sx~aDxAIpJSdgJ-p3jrDQTl|EA=*emPF(HO;+^XR0ij zhteOX%}ZO7_B{1^swJ&MT1wjK^bvUaBqVE0_Tii;TY6roGuL%exuKbOD%mewmkygg znl(#=wV7u{uPt6VUWL3Tdk^<+>s{G|ISs%UD3S@OwYs0DP@p4Lwl;Z^uPHy z@{)EEKZ;+)O;U_JQr;}jGIcj!GACM6J=S?_w&Ym~dMvbbF}E~jfrr;fS|qL%2GGys zBrnO{YW1~aYH8(*>$LN_qpo9#{bF8~yg{~Vwt2QfcuwoIZK&;pjoF&zEzFCsU$FZ- zo;$ufcez@-iz};?xvDoJS}x`|A>hz#UrRIjPrK_V^T1;>gA;UFJE-4ac(VjOC7hM)vbXtxWvTUs=S#1B zKGpnE{aXi)4qA_=*2K`Sq4)8*9Xch;*){0}mYwiDWe=Q&sM1c$AM>ALB=sknKndAWJ6c?{N8GEFI_1*U4IZ*rWx zOU{w%OSi?DVsXqB6KE@pJ}x0+bs3r6)5xwxBTntsmubhe(Xh~mVDsHpx2SW~cj^o9 zJUeQ;z&>25{nC8(y80DlFbW~N9f54tEDlBo;`DV|9}J_nLU-}J_&_WsH3qMAt#m>9 zDV>srN)<5!bBb5MGrc3!1^X2&cs$Fw8gtYT?$H0#cj@uk9L--dfnS-dtXAyq?`}c4 z=dR#(x$3z`;rYax&_yIZJ! zelTnlalaHMpOeR#QcXL-&wgv^;<3x4iFK{@jaBdr@vP&iTC=SdPq+1d)}~f(>)#$e z9*N+A&M?QDYM7SG*;03Dl6XWYE*u0Cx)J%8d-9j8Cd<@U>E8MgAiE8im+#cRYHPI* zW?GHG4mM%GJ^0rlkWV$Wg4$DUhwm|9U2jxp!|#4j|Ip@X6SYO!8?0DN#TY&ww$T;r z=?vB!EX0Gzl~)0y<2877MZk1BLEq7InoA1^1;ERGgG}mDIv<(wrpSw}LteZI@^|ww zyA!}dEWqEv!$+{rV2kSdBXD@$gTwPm_hNs5%NEN_m;)yBzQ`y4iF{LGS`B&T(O?~H zpxfyK)N_W$(R*|<@=X%5xV!LfjMK;`kHfRGRoHJZCRgZ+wn>`|j$jJ-ro+_!=wUi| z<|~v1;0OAF3A#%up^j4bgQFd)d1`00YG9{d(!<$5-~o(9HnT3Wz8^>{uvc0j5BeDW zY6r$KCZS-=8C-~)U@t`=Ki`cW#oGqzBDWksrXZKU7@Vt6fyR{<=KB77a2icwyBWJlM4$?%Z31t;hX@@79tXUJ?OokcHEU!k{9O(-qIfJ5XX zo)#KlZ1WDx#Y13b^anF}!#M7FyU^7uJ;#@-1_D2-OS@D_j}$o39KKDZ}xn1APQqrr!m21djJl-3$o z`Cy$i3e3K{;EfpX3pvmK1Pb4P-!mDw`U4i}2_|w;cFYE1|U1!4|)3jd?xnx zA%A`rT%ZSNK_K~vTw@?Omr2MaXX1%|3-)&7>H)}8{sp#KC^CG-Fh=-^IB*%>Cl(wN z4gX&;2lDCX@jOBZcd>f7qY2t^2%M?QV7L0Bt%H#D?1y$=MLzBZ#-*q5jQB4p#93o{eHx?@8JQqLPH~vMRns%Bj2DM49?Dr0^){?)1FWtd5gWYx+Tr6Mk!BU{PINlmI@f3*tBcFM;9PEbS zK=F6v>KD>C;8WH{6!XMWJvZo38Vy$HJYb_VGW=bf zk^zWdjc7w4XA`{WY>YXU!hTMGr}Y(9UWZ%wJ}?0KgDu&U-v^7SEUft`B2QnuspB{> zTNPJifrsJ36Ci=CFdvP#zS#9nECG4>e&FQ!fB`WcTxK60&MxTFFs3+!xOWM0pb^GZ zc%uX&$pPM!gb4|>FdpXV!50EOb9fX3w@X+rrqBwovN++m7$-C*H<>S)E)*2NG-7@E zPk4m>@TnEh?*8z?SAhM+u=_jkWnMt=ap1ck>|_}HXD&O!tHG;ZAR#=H-6b=HL39{c zMDctN4G>be2sT^*?Jj(PHHL!$6d(!$LFE2~9?c~QEK2{W2Z5u}8SLzu;4X!N%>k|p zAFW@~BEide&sJjX^9pl776;%*pYp%RG@8hl=$~{jUxjEA&Z@Eh$J1GWH+g=4|FJwt z>V~wqySwXfr!d@IhQn~i7&hF8yKJ~K+;!M+x8dG4$>Z-Q{r#`^dak5to2JQqpZnl_AD0#fT z_7w7SO~rCT3^|pK_D!J*NQYfkPOG|5S#2&=2icz}`IRD0Q}*VrbX86ide~_km$X!z z2_|Kc`NeJ`Z4X*EYM6IHorHpf%w;b%PY5-gD66S+hTf>Nretn(+A2Am6HCSw+ws-$#MjO4PlIk=ir@h)}Z-=-}so#tr^ag@gsjUvQ-|0u}+R9Q_cKbo# z7bBB=)#Y{O`fJ$tlq^)~&g)&sNA?z4I&S;DG2iu4tZn{k9}(**>G1JNS#6xZ+;_w% zqn`a9RCysglW@bSD3z0vtS)vBOIKzJhqYuYmsDJix3@U~qk&z=y+nNLZ(>$cnoG;9 zDuD_1AX$+IImyO1N|%{0bDbVp_>BiZ%o!aD1)I2f;?uARZ0 zC4O~I2p^4U))z4gXn4Ol**qcF@GddC`tl2x+~1|kdR_ChGC++G6_CDeUiU}on=#2K z;mmU9lG|&)TcxDG-Fd}5{urUWcc(Kaa9kcGeY0=ro#YQ<5u*{lM_;+KR^NH(Dn=|B z=jvy73XG@Ar@M1U%jSGnmq|Yvy7|yG%sL@|ma`bgjk|8cHQaazj_4bAw| z9^q z>x1XEebB#5Xf789k=9g-5xQ$X$%gk2{a2%s@L08_$<`rbhO^%NLHNmjK_PsiGLx#@ zW&5V2ipQkk`hUhT^%XihjhtQ|@063;%aK;KK%(oaQr^sOesw*z584~#>W*Y}wcjf) zA*=Pw=_8#{1}Z~%hfl>1?ov)K?T+x$)j`Y$(@s}qg*wfCYMv8IDUYn`=5yh1JFnOe z+ii+vt*z1*K{UDwSLCTqF|#`vbW6_RG}il=Z-m=QIy))3o3kf;oINxpyRcraD@;YI zAKG`sT2gLfGB8yVjrcIw9g;wH1l4RYU_#_@5XNN8qs(v46my2pImq^-XdqQ5?y#smFB=JYhhut|OOmed7 zAK}t!uiuf{T0@M3^s(%=G6yEfb6p?IpUiLOH~F-D(<~XtEFX4Nw(^^9OLpxNV9p!|BS1adzAU!zfZ29HZh0zpLvQZEmBU4Yt&nUY^=0q%Ugt>oh6n} zI76)e3p`>oL`S^htTkWAi%j?()iu=AvbzULZM2U7ai562?eieZiYeu-op{p)1fMuW zE+FJ}wkXf73f4k#qcUAs8W>|=Q^VbgMm8?AT*$=aFTUcT#oQx(fk3opi2Jm@#ede- z#rq+ty*V^&r4x}-*{&E;mwIppO%>0Ego*=vhd@K^6f*@hdw@`%`qf78$A zL0xVx(f5lYy~yZ`r&L3BKm-3HMmx)u$96F> zovWQVlgz_D`HdBjRHvxkQeCSo)c-c}d-F?~0||nm7~))gkXb`+E^pJP*jwfM);loY ze}Q4Y>d$KxcQ=tYrr7$3@O@V4Z+qotq1SwGec!yr9Z?&tjFp-gE+<8PVl}rOnM;HS zb-4y>plh>zSr{TU6K?D8T`skP)=Ymdhj>h9MeW8%0R23F^9Taz!@x+5G<{^vsK9` zE!O86*%U`P>GU(UI0uypu8I0HqqEdkzHC)A`(k_A;rkS%?`^8x*`6x35vDqY?UR=3 zbd|>obu?R85h7W&Q~Jp3Lq=%tjOFeo&M0l7^T^%DSsGX_yptouon{yNl=M-!B_-Q6 z1KX5KifnzRGc#6f>0V_n(ptDA(XfXJ+rM0ubIXpAT00TO8MU6Y&G)-_%bj2@(5eZ8T_w#7 zAU|`0J?Uv2R?53p8;gA7l~JLg{_vz<)O(??^%5yLr6kW>@t*d`IxLq~CR^=|@y=S8 z?rhOZOHI||;v?PfY*6-#P0YU5O;>BNuF=hEDt~Z&HRV7XG0Bt7Y~x!gFINv4J*;Dr zB966s8*Qb#YF0B#V3W(I^%Ab z>8X_8Hl^5-FP7_p0r_VAB4x1( z>aB!K(judoo zT_8j1DxvOSo_R`VDZRScvsS)n&y|;8%a2jrE-ZJDrqj6=BGnP*)2VWaewy9zT}(6^ z;|G;86U<0D+;*FVkc>7_hT zeou}lEggH0>9*`B7n7F?AB5M`G+&X~e&RF|reiyISP}LnXR!UyJY+2+7Tsk1Zg#bX z+kLI)<|}g_@1~uV2~>JD=RYgf9!V_miawL#M8r+V9Ap$v6XPa|jliSllE;W`h+@Wo z!EQ=#MIo|Mi-?d%u#m_nIorz&v5c{X)vu2ad6TMCn zpMj9SO~2q+G6KWsJDJbd&%~OAdFPMl?3ltQ`d|xmjolJ>lN5-nQNv z-ie+W?tpsO^-xYHSCf{5CRjoCuCD#3)xw$#zsP5p0d8saUpZucIq&WF);Kz>FT)H_ z1_sAFRwa5gdeb|(7Fj$5gXRli96rTiDZl(o&Z$h0OUtk2_sTYx(Z61gxVjZtl&$oYr_fVemecYp+?dDc-);#W zq9u4OL)6IXAE7HK8`z*waVJ@}|6rNjL|5n>=TCAyqn&*A6tlEd$eL%ynXAp-Rva~( zwbX@Z7K;OWUz@K^+ zOLPX>KMH%@F`;ru(a^i$Qq+LR;^9TYZ$`vMcZoU>Q6_3$RI`XYVco(`hb;|x<38+K zC$AL}%%Op0zI!PLlk+8aOc{|9my#vJCW(Wjl|=OeUGH7>)W6h0?kb+Gp8q_rJuN|T=5$5MZZLV< ztSsgSYE;GbIojO7CcoFe#@C;#tFOIpx9`2LoWD?DjuvLTB{T3^{6pTUbagdQQ`8^a zJ=`DM9Xy#m3*BYh<=t7_GgQO%i|eQ|Lry3CCfu}(Sif^FXJ~n}`K;mgKp>DytE2s; zm7?ll8k@~|)>3<#GgRm#HX=G&rd)SzQbXPS-ILwn?k%v2jE3JNROup5lX{9Zggx{M z4<>(j+pJ^OH>$8-4bUn-YJP33ZtItg@n$8ffUVpAI=8{$d>1cBP2@dtW@VV-arJbK zbDeeFa{WOizN^wyNs=v?2DXzwJ|dh&*JiVikauihJu|PHS->;?Ys$z?CK!9RQE&Qz zzCO*ak0+cq*gY&pONHq=|vHxxP@SSE}4$k!`39LjkAkBlKdr*XVB?GM*V#O|SLBykTxJADQo{h#oQ{ ztZimq^Q3vxTw`3-6OH1=dcC!Q zDCBndiHKK`PopwLpNQNP9v1c`WIE{e#E`t+yzbv!OO@yHVQIK{)LBHm`=Wj&P{`LQ z`F4^o`6Jv}L-hvcSbL997auC0^1CZZRp3c+JVQJu-7e2Ro}u1HFs3AUS9=^zNT_tn zUT3B?rfY=)nf*O{{e0hjwf&?0LZG9jgE1UqRih8=268eApSF%%-&Mpt-!sm8)H|G0 z(b#>%^^bB_9zZTE$sTLv1NXN>ucQ|StFcD!sqfP620r@7VH58AhX;0QosHVoT^m1C z+%4r$Cb{~nf2(uVZfbh<3rN8GQao%wcj2F?EX@*!2=$y^_5iDkS&QoW39X8DEpR-L zQTtoFqUSLSTmM-r@l|@0eZ40{k_CJs=7n29mir@hALT5HmmI_rxtzQg1e``)C)%k@ zA6HK+z4h8ut$=w7gm){m47&P|S&C|5l2wsv?R2LGnBRCQy?j^hOhr0c*#Vo1O|7jJ zOdW-!dvI19r91Eg`IS*<{0HQ;kHVsR277Uy>g8~%nz@`qc0RQ7XtLjXsX!H?x9u36 zxWUSAKK|}IS>uu59ewa{Oee2@5WO12^&JuWir-<#m`etH1z5E?RNpGmm<(~1 zF5!b&Snm=j z=^yI*l=62Z+=|kouD; z$Z5|uql~HA22eY-Q_`m-rsVML@Q=_Y7y~SyU655Sjz4w|Iawx!$erYjis&lix~~jS zN+=KHd~#JOqqrD!!5GtR__UuvE6&osX*TO z7)nLgBW1i&P+2d(m*S*~VtsJUY3$0@DKpXRY<@CFQdJhQs;{i}U`P6b!>BA)mCDKi zuzx@E9+tRvf=bGvl#}z5AFwg(e*VJDl&?xZ8pAS4mVeLp@4_?+!Mt5_CxeavEIO`-p z_9DVF@q)5bt?yY8x;@%X*C9j33_`;A_`&H4#YRO$hCFeHxy!4Q$v|CjY~F2kI44fp z3oXU0XuQ&{_|GSg{w^g|_Z`)T*#pISN^Vc@&^qDyBWgrsiMSaa6TUvw_-6Pz_*VLs`>SXjjhEIPu(q|_O2~H*hr7cbhYkqI zk-V*Q4m4^}tFw9B(Dj>IslXxM?UWfQ&r`1Z5(Bl!)0VcAoUvk( z)KwYm%B7xB^CM}h+Fx;~c6AmnkYPGchyE!}{5Y!~JW>brX#JG7NBd9Pq8~H%nzH@K zxh8Is^SWZx59)2VH?~u8>kzVA;QC3V=cSFVz2|-cEk)Z0 z)?a(1ozxe=vTw zq@WEb!efEg;L|o~VR|_|hn5~0A#-KaHEw{-YGt0Xe+FsWS+4H>A!Km)fT&4n0~wcQ z?w@5=mK>RnXPBIBR?M349wBo)Rq0?%l!iMKkoO)|3O2m6Q5dTkA6Ve)nSAE^wWL?R zcls?mR0>rKgyf0%Eoxfy+2}#hXQQe{_6wgIlAnINFGPp;u;QC+iIpyDEisE33$%`b zRsMGVM1M`tbYlaX^*C#WGgf-$>gcT*mMg*?nT+gQ3(FFk$s6hRxN6Gl#AD8LYo_^= zQBSX_tqz0)qWpeZDRw14OO8)jm7@D@1di#COgg|tUHVs;W z94_~iM$u&)WcT}Q7lT9n9js69jeSNf<2iQwp)uE7Wo>s(h=pN7t4;jWLumtI>YLnK z7UZ4MQSn#d85KR78t@;&Y-cYR!}Z{#yP94zihN8byP$K*E=rehIJL}SR0JFF`$E=4 zQ-IUzqmjcLYj(3rVYAMeHvjdwanx94bTUGWbVf$r!DPJ+IMmEWZ_q0}%zefLy@}Q$ zP|t7re)iw?4-M2tHd|^5fxW&SDSFb;r1HsglJlbzeJSJoO9L_5Kl&RwQl6nFGF$Tv zmtI>Nt3B458rf}0TrGD~i+C4>_6$E8DaP$j@6K2?)A@{xG8pkw(pOE}F1AtBvG6lt zAz^=nOmZ)k)6h|Ij_PeQxYg@v*Zdj$i&J(bjs2eV{dvj;ZHl?oUMakiV$|H;e4&-X zW{2er9~yofzddtkSMM^8t1j@fwKNKzHcdQQ*y#{S;~J8 zMB*CrhW(Hl+C}BOYn+LPe9>Tcj(tS)smQ0_~$#6pf>mEu*-1|pIC zXur?b#Q%?fAQ-<%`eP%^%0*@WrITLF1;5n+>5SA%&Z_hTgFR2~CD)Pv?MX%k_>8358K+PO%ivlxukdbs}bTd#jHZHyLM0-9>DS;#zP%!0e@H$#LWFjoIn(?CYH_Mh?f@pbo2 z^&Rll^N$Yf)@JJ$KooxCjBn76z>9fZdkT&;Q7=ur@F`Ff{j-f|zMSy_oz@k^>Mj38 zKItxfzj@LY$&+*zcMFT15_T7Jw;qlz7#+|9pSAtE*9s95q(;iG?)%;`q5iND5vQY@ z#x+g5KmF$TgoKEMuJLMo+jL9P9F033YsGk?i$;72J?ow3Ddc|38UJKQnQyhsfwsQa z$(@oPBv<$C_1l4Zx@Ekkj*?5dCT|7HcFk48{i~;;_my{6$cRuYv|!lE&KFdJFF+aH`*e6BH)CPm8{Tx_zmO$?WIN-^?R>7isvdGH;-N>OrWd5-)^nj!WQ z#yI=INUQ-9-iM6K5VO1a(O68rWtXwY*kf!%FWkiMjRT8#R=cUy)eRk%Lvt;DWoNrG zIrv045wlw3%yO`84Flzt#XfHpAZloBPBpT_(`dk&x?YkJ=R3FydfXo6rqj#q+EBRaqlvmQD#hoCq+~ zvF1?YvHl~Rw~{t6;0~PeU+@UTN)MgI!@%2VXmx+^zyDsT)i$1I5eWOPWhZ zK;CbXKgd5Q!<8w@I(lIaEBkoV4OAwpQpFg(_tGU_15%C?9o3XQSn9}aDZ2gT-2>zk>Sh%#&b63w;K46 zY~UO+fTfBcl8EQMR3^96T-l_oP?jsZm9feVGCfmaI$Q#lW)BQdFYrvjf^nMT%uz(<&8yvdq)<;9I(jqgOIj-kWS8wOA8 zJ0sNW1tRqeI=`Y>7o28yvPDJ6tc_s`$5=3`S*)(0R130)&EWE>fqgFkBgH0r87RUs z_9`+s56w`kGy3Km=+(UTJhZxIR!856U_ZZ*<=VoD+HQS7A{+X`O(> zEEjPm{IKO4BF!9Pr8u!mg& z4Cov%{+E>m@>u0PWxS@hW5~XcS0Uv?_tLAAKD0{6FJ8ZAr01@?zI%$g!nI!MCs)8? zv?i+v{FIp~<5T9PyiaNBJLj9`Zx&FsQ`!Q3tTD)J zXtlJ*;lWlCUyB{3lTtAd6fKnt$_HY%ez1SmqU*#|J}Xz0NlFwMucJ~V5oHnx%`a32 zJk*Xx;!CDC_ma=OiidoNyw~f%ia^IeOdxw;4D7wP0^{lWxkZQ7e_B`aIztV?>lj(Y-pp7+{NU03AYp^*2FCx)w1Dj|I z&TXvuuW<}-vmie|OT7QU447BVf8o!z$by8CZ+=b(Uqka(^O>0rsfZ&V{s+FuQPB6t zU}QdHOhzLF4+!`Q7t9@a@$%`FoG=kx6%wHY867OU8Boi5C z?KCFQRnk2$)-U@f`5wT6o-O4;^77;r$v2XVr7TE!Nw?KU-+KS#KyR%h8Mr29KC2}8 z>@!Y%m~^~E@FV1c=ywq==N_(6WG9cf9=JZaw!!+`!sXDHS610iSJ-CBhTF3fI)~|8 zpf`(?SNv{NN81&mS8*(vDUr^W#dNeZK;IV)lnGP{^a-pFi0~~>(NeUL`dhu2F`DyP z+-%C(%)x24t={;J2jPHwYu}?Q;31EK6|cSY3ap|AHHvPDJ+PQ%x9RqUIXNSY>7PxB z-QI+RWWwe&GVmIBy~4;vIcgZ$K=OB|zu_$LKtVH^0k37vZggkdHDl2k>tXlZ3bWK8 zaz7=p8t1?Z_7d{L7S&hUMh>*En&kF-c6ob+{193^>_S+{@c4)lk>#S|qIX2c#Y~UM z9s4zQVcc(VVR0Q|m&DA9ZWHB+93CDSwl<`x_YhrMA<7`>2eQOjoc&gUc~l=qKJg0L z;8XITPGzcAjLhSkM6DclktOZVhAN`#uh z?RRgX$EUk@5Vs$^(ToRHyc<33Jhr==`>GnJHgt`^Ti-+mnW<6EVSA&s!8}ZTs3N^v zA?O7uaLT{dzZm_WEzmx&FYqQ%LtBgoGF2~UJTj)5Wx=_wvP*$3o+!K#rc$XJA+3b* z_K+mWndFRAN88AQVI zJ&)|53k-5RmBFQ5r1MUNt`<>pF zpk^uxGWCK}T&$0NERCmCN!j3zg|&7IG)&~w96#aqu?(R;^J%CpY>S~Xpl zl*w{KDTkPwsRLhOFEn9p%uJQqL$7Rzz1f-%Yj#e$W@BKpeuOi?&7^LTs}|EwK&?_;qqy94d3)HGZ*`LfgYTxob$ZKYxHa@`O?}6G zZ~dZHop{7+wnGE>tVggzhJfzBAeO}P zroEp&E@ODcTN$@zESzCLLi6;|>1L-1i<4vCMNA7j>n-W=sjBO+d_%ZtwKW84@xTNPWpAZ%PA@-A>D*w5zsC|jtu6cg&{^MOj@2BbYc{;f_y7GbU zJ!Ko_RwJK&Ik4UTfey<(z?^n8HZX%0YThPR;#Fp1whFaV6z*E=zySEdb!bA5B zb%Se%d_+9xT(X)lb>q19PatC;BCyWioTxYhJ<6ZSa+lKPYQ^Z@O)&eh{`Z{<;yv;| zg_O$Z`suPya^NaxEM=A!v7?Vb7?>c|w}Ct8#Jx(+{yeOQAB1mYlKX+MSWVwiKH}?+ z^j$orsvAUySGU))i;?);5ms94u>wnZaqt^0jDEx(nazx3>qGJKtFXsu@yO27AveO> zgqN4!T4Vl*cUX))eNP;-$QVFYKRy22Tm6*2UQc6`F^Yl@Yha|KCo2n#?E~T4?qp5I zn=U~ee4#nejKoLTWZdWZJ@gw|UF}?8c_1x0zKQ`OFj_MMYqa*rkU+;*5vv~3ox|x$ z{HTzRPL^Ewz8#d=MC}vg_0kUKEmo$!jg2QnIOq-1FV@+*{~F)aa$Jt@>TNTnCj*%1Y^^kj@FUW*UmV1&!{a zGP=oE*zXQB*UspL&3^WJVWBjMx}{&8=Wa$mAUieCqUr=!F4s=wj(kblCr*SV=pB{* zvBqeRH|eO0=IkCb73*g(G`(S-y=e<%hmz@CSV+!)9)7)JW+KBo1wO_{MDYDU zcdnzyGSN6jH2YcGtZk&jah3K3B*!88*#0p}k`1V0ow17W9=E`>(Spda2KT+J2<(Jy zJ|W^*XXYdZOr#1K)J>bUdD>N8A>1fnn5;w-`17|Lk$8tbYc+ME7-tpSkh?(ce*^zt zU6ADUplt37=dIUH44JHcV9C0Z8#^hDa@Fy?4vUUCly*nL>r7j+gk)wb;n*P zG?4Df(_Pu!S+F3jn3Zwd^WFWQdXzrluhL_xX?2}gJKEZB?APCE^{HS_Cm(()5KC?? zr*2`7zL~c5-ahUOqn{}f=G{X~SNMUQT`YA&FT8=R{R;9>fgaGE@Q+^ylhGFMJqKT( z6VnFK9s7`@Dd0O6VKsWv7gGQYyN=cCL$}*5x{0Ekx%hS0t>x6W zTIx;pI{G*~jt6={`f;Bab-;8?wHo40gkS-`z>r%F-uQaF_rK_n{2Lt1D9}SCk&FXm zN~V%w4(2W|8_mgZ?E!Ug%j|)#TFn_iuTC-aT^IOB-l2mJOY7xzax3X~X)=8u<*jqf zx@m%LS#11lTA%<5iDjt%H&_4lE(@<6GcN7N^nEi-&9o_FQpWWePN#pHZb9si(Ul^T zL-Kozx%Nq2MTyGDXJR0~ImD2Re%j=~V}Ba|ZhsCk+0_k~B{)^Y7t%guzIxQ%+FL(l zM9A=vD&Dv52=%_)M>1Le6SF*`*;=XiC^ik=VcKq0-13ZlzZ>4|8)0T5(K$T|_5vRihaArDJ@3q&vj5 z5A@+iWpk-Df&Q>kaEq?C%aai)1M7lFm1F>&WZ8&me}Y}QE7N8@!X9xKi1C?VvTB0m z{4teBzah`)#>(s$B9)@CtKg#Ic}+aK=p_}-^{^}Psu)z?@RVW69&Oi-7)Ytu8`9af1M z-uKvpQc7b<6Y@B1sifQ_H}X4{H_SX>)HgC?1^4P<^aZ!a^NTTez{&c8`sQ9Z(29cE z5!6NMR`nsV;UuM&++E5i=Ac3`1smWuYST%41qsQ5Kl64vgw_J#K(?_!fA?VQ@$nquY5NJ#$CtG(3hs zHi_TO1as4r{>J0_<6jTAkj zahQrzc@Qm^!1bK4R#Ck!ipO1-`ePCH?+3b=bK9S+o#ZZTtWSSzo6mTKZEKU7U9HVK z3dhSX!aRjOOlmkl&gTjdX9n>hr??G>x5|nOeBNuhh^$Ma>HK<5k7x_}>#q^@M8oO+ zm!L{HUGKfs!gIy6O`9%#sSM9E3`+1N{F{D3nh|lgqE3fj54-1CslIoOmC}Iyd1F_H z-#?O`>wflQ8FZ#$ zKV{y|0%|i~u#^u#^YkVPC~W?YWc&^b%MrZsuVAL~SzoNobh^zE|B*J!8;SNJ<(V*jgMN_l*qW@;B(PBrU_`$U8~sW+skftPGSVGg0`}!Wc%hZ)^sY?bX<>0Z zm1%<*=P4DbVX$8}Pvs+MKn3+6G3rZt-trMs93T@EMb2_Q^@=mbfB3(ZU`CyXOuWOB ztVDmy47yEMaX*R~A&Pa@oCYUgg!u}|KEYr8L0-WE7rEB_fIKX>b`g86A%hj1Q4nPM z?}qRD71qnCupJDw6X81$?djCS`kN=IZl9v|l0*MU9cHPv7r&zuTc4Jn~EAdA<{z^-|q=M2KF+KiNCa{tv>F~b*CbTl2ucF=9Ss{ii7d>Ue zL!!5**`2;n0z*kNR?qM-K~2AjxzBRcl<)^3`P@5{4`NlSLW8Yh_}D%WIvMtC$2U*3<(b&hd zR1%6Aw%(dZtf-ljKH83O_Pyk@FM-WqGd;WiScyc_*PJK8ZbNAp@nRM7OcTI}Tmt2p ziw>nz&MdpTRUi3s8~1e4D9;L~GiRGAW_wOfm|Y*waERR=zJLVq9RDz%+ryfkCI@i9 zsQ^;A7=5x^#iyWImV!vy1|sP&*n$vH!iAjb$jUAHoomzkzm2IDFNAljZ++o1yzoQq z6tavP%>kVG#zc-gumc0hEMK**aeINUzl2C6(%Q~BcA2}4*+_0rqR{O`$9b9H*N3dd zOzM}ju`bn-klW-GTNz*UWPPi?jrnpVkd+Epq-K_zPCCu*gb(bdqyHHE#baO(=uhA9 zV!Gb9gAz?7r|}t|w={ZX0M_jResLLI^#^Jpi_Ht@u+DUg4z>%^`Q1T?rjI!dt65&2 z4!-L)6`_h`fNYpVHZU9JKKf`FwX~VUPK`jkY$D6K&JGc`%DtG|JUBde)SB2gY38R} z7ax~UC81M7!T5ve64Snm?Gb%CqDN?J&jQz~M8ZpR0wbPP|tKs?%JXlt1P6;EWw-t3Ak<<-zDOlO18Z^w*yRZ2pj=8` zgvS{nmZp2V2YBzjoXDQWD|nEy5(iu-m++q^=#`o7w@;5ie{VPPpoy=T6*$YLHP((o zBMwIAeq*9tZuz8KR+-EkGm|REai$pVlAlN^?1zTbG^K`=-df3IAO(cX4r7in!#Dtf z`3ah$8b58xez&4BRh7Ah&5@p|Xo7v_UM$TPVv9BAa%8C=`__Z!6k}$*!xX^Nco6HT zi(W+6g^;nRVpe8v2clVyV^<`qAKURjYU7c9hl{NRsQ2=)+6BPLd+7ge$;^>Wc-_;a zQA`}`3-?6{vht6ZJVAwD41T4?K;UL^A63h#+g$?j#cElU+Y)2^EWW2Z zH=D4AZh?DvESabiKEsPQEd|aTnfaw@@tS(jXK12Av&B&GJu}Mw$_kCiCjSStQG;N_2%!FE=?b)eeAxd}{p*!u*tVgo@N< zi!L+%Lk%?1A0Qd;+X35x!>2qw?9*V7-^{dxwVdy9)Wzz$isy6&-S-Hlk*{z*M6(8^ z@w9r;Co&a&gk#K=io|A?qC=xP(`zd8I3J$3NQ9$O00neuFtIqD_a(h!R|~7SPVvU75UUvJldE#-RZHQ3$o}(`x;2)NthYN z!io~?Q)$j_6adk=pS-~^BIwrA4JP-klV$ql4l9|cLWHSpK*b(VU#RKa72Olu``mln zYu%IFosqVUY9@87tFtAIiS*!O{vg*pO$ve2D{jkv}%wA{%62CvwEoRa=<->Pd z4Z?q{^%JJK zSYb1=A>niOW%U(ih)iPE#|?N8zQgWO5EhCFXt6uYRQV`81P!zgmV)W5OmnL0U-4hZ zfL)CxqjUwSn{W4LQffXV;u{+95+3YgqUX-A9F_+Uk&j$fS^6`2V-tR3ZtE&A4f~0M zKVkzzkfbblmF1DFc38-pdifhU`$CT6E7~W3ECsMdUZRrvbX05w5%AG@i&tfk^~(ou$3SM!sGxCY z5vv^pn|GASXrINmXp!4^EGJUgh*n{X$H9tHL^K79Ea7G5quis*DG$?ep0Gm6oR#)u zdw;{b|3KV095g!SLYecWr@@4!eI?x*fW?k?_(?l0;& z^$)eTnxOvWs^i+Lq*0br?O21hJY(+=O6+o>`AWOkw6 z(8K&0>py{*ViHls0&^=?;5soz2ndDB#HO9dN^ZiJkijX;f$wS)C-^UR=REygK4Qf5 zXo*6wtrWsPEki z{fcT?dQN{Xo?D;lNCqN?*X(A13QA6Twt{_HrO>33^Nm{nd-Td<{^~06;}UdD7jPf> z@lX9|xCzwOb6elRUR=VK9U@C`jGmxnoRB5dbvE<)c7VjVXr98VUg0^n_^cU-k84|f zk@NRc{b8yaxStk%cK)MV=G|12x^}?@QqY~WvL6Naw1;X4bF$gBqcv5#ROw^ zP7p;8>@fYv1MDSRG@5P(y2apmxk27ZVRq*yP)d8~-5V)hXHw%#a!S46qe@^h)I+i` zDdfU8yWYCKFd;URnn#_Z9;VNvzh?`bRrl#L>EmhUsqNY2dE?3I9q4`Lz2M#N-AZ;X z(OcB}-m}9~%X8n|#C=}P!DLsTQeWA_Osjg*W;(EIGRd}$^N?7NX}#8YG{Q3w45N*j zMm{F`KBLaHijJw)dMEB@^LQP8%~}1UUKTday~JNRh(`aWCLK?7(VL3Q0rbZkJaC^C z4eGHjGYh+bU>QcPpcgrat>mY^a28YS51@tblX-r`zP)9qA9A`k!1FSf?AL56Rl_;; zgUBzm!Fr6~)bGO<1o6cuVS+iq*}g`G>@#u@PM%HV)Js^?NN~|%AS^2pJ9J_i(qN>k z4%Rj=c~_dDIrnKC3yraZSFQzCD=k%`Fwk2666b7U8tZ7Z(_p%yMzQDP!Q>19S>2nf zk5!eLO*SN`qE(+P{wzM{T%OYfk9soR%{QiSG)7Ymz=HO}()DH%*H-Yq$2kozd5^{5 zh+BX*xIyRCH8MoQvEb8qT#YzC2}y~^E?vQ=DM~ar6s=Q28bW?KD-q&l(7`F_pfIx3 zUO4LeO9fyBijjh|xLn-MFu{1NGR!p|dosZVZjKsvAG+>*YCrcb_e=NB?m6x+TpeLk zEbsl*d(wN>`^1~#-Rzy?UF6N@ec}1TQ^51iJ&m0FO0}%o%XL{Pql}SF<{VyOO67GX z;jN}_RT<=CemFWOo4L)4WQwYRHTg`fVu3z{JY-p_pr!TddVS`4@78aVU#&onVIoL! zAN9y>#M(v4fp%ske@4^aq2ks7`*4dh`|K^PJXl4j zx#~RQ16m?zErN5Q-eWs<5S#QPcTtIaYtGbJlNR2~CAgVJ5+fI}@}eET?hsnyj^Is=_#04>0F_Ma_gsu%wr>Lcj>YJOst!|18@$*L zbY7`aIQ%(P$XC~;PwEYFqw)M&%CT}! z7#IJd$IP#kWA62Nr02FPomxfRqZ(=+_i^`by2GxyXSzGOJJ55M-z~ad!eD(_9jV5s z7hN@7$CX^5^(x92kw~|+KvelZHlHViOkrsd_*=+R)doLxfZ5J?7y!5ig_^D_)wj73_k%O|CsJ^KCPNkSf4zzozW- z`qcA(2D#bB^ilT0kI*PY0`W3w+-8$YeXPT|w)3k?R$9(TgUkO@(@bvl_Ok6?oRmvG)&Q z%zJ{T@R=!X!TDzrbJo(stThH-@;5xxF8Cz_U^6%Yi)28ErOW9JGdBOh#})Bqi!rIK z8$CoFz%7)3+3!bjllVp~h+O2BBs9gDRHiK%S*e5fIDkC2v{0 zv;kS`il_XOSQVDH*LXo2@a!%jjWx+z`@}lrG}kc4_ypd_Nl>%>z)foMkIDjNJzSob zmG??fSE6eG9WJMdr}o1t+Qn5Bgxy|#KLd}q9zMuUc^tD8_rYeEkN>)o`GV=FOZO)~ zdKm8~5?+JdX!^0Re3ilf`+(Jj|A7vuJlO8xWJ~_Rvh1K*){Qe6PxZezr*J%ycFMYl z2H(zk4RS%wA@8%A2^;e3Mg^Q!fZGa1M0mPCqjvr9U)m-}QwEGrufp!w`v z#BZVeG==92?5f00+aS8a$&?o+x~a+jw?{VmpxdYMKBsVv!L>Qotc1J*k~cH#q(@DV)A1;jgx@Il|>j|Z*DP&|;F!X2b) z7x|%Uu$09Sy$mE$9Zz1dTI$s4Wb(}Y@Y;`}Z-TwYYtTT!s5si_t{*52?E!5w`HT_NQLw`9w#F zx90N>*YYVHK4S)|FMg)-76Pr+T&#%P*C#iYNLO7SxGZ~fU!V71gluB)Ic1UH;QZ;* z*voso#&{-Nloc1Hku3mz+8Hdj4&f4@~I%6{`5#^a$oL7iPALRohQ2}3|0=dSfSgZjse-0;p z9*KsU2*2MHDxce#S$hJu?JZo}xSip1qZ4&(KU!tEGJpKmk_5-utsuc<0rW-jJAZa0aYE|URRi3J@18e=u5 z<}%rU`^fx5BDx2hAQyj^joFT|y!*_|TrSQlHfHC?a*h`AF4l6br;~0Ya})aa<5I~elX{7XzKkye%qdvDZy$4*Cqq`mf(cpAhV@L?%)M`@diGh zPv~-)DsXT@<`eS%FY)yvIh8^5c}cPj4UoN&$n+xK!wOb@0}=|Y``ZvHsuWIL(I}>bX69Yy;C)7ONmQ63_?n)-$;K@Mw+LRv&;N`ghY_65T9e#PkbSl} zJKh878%M2n0-21UbS&h41~NG|btY(kG(|gPr#||)DCZy}|1BB$(%94B?%qK%53mC} zxSb~tdxsUg#m|ls&7UPpcM{!lgPr=ye^26kzTuILbj0v(v%vaLk$2OO|Im${9)yGj z>+iv7&((OJC0KWl;Ag#pKEeYSL(cMQSGjJID?g8Rzn?1kclj@e*}dbulN0Fuqg*FB zB^Oe!hxiu3+1bJMm08&k=B@sZJ+%;WOg)vgYysl&XR@+WImuJ_{7YDi3CQR`&iP1m z<{;ixSDw{|l?cwEu7LDsO_lu!Ud_YnhVgl_u{)XAvpDukU{}M~t5U?pmDsWDoW*qP zN*rDJ8QH7s>`yfBMWplYDWB*9>vfWKyNV1xg6ZNqkIrx%=5q$+<`o%{B-ZX3*T3Zb zuAmDp@!Wq|i)(0u%lzaJpFcR){2Z@!5Uubh`g{l8_CX|eBRS0VNcjTtG82*AiP+nP zoRdGeR-#G&M5ebfP(HiFwvTz$B@u%m5|xAxpOP2KDEyh<%(sxoWSi1n<>*NVJ)rPN(7 z#(f1ic5CtMhOBr{Uh4?u_*$3$T#v^!SkdCFbQIDZhb*OKwOvU5cd}VeIAeE_mb#_^>o%wv)v0NiLrNP`wbK>M;Xn{QBYSLiu{!7iu-p1BECenUuf5bB}sr`N6 z(!oH)fLe`9&ASvtmsCZYwBy|O;GB2nQ9C$nn!~5uhif2__eio>L5`4_tnxfocmsLF z!$|Ra&P~w2EzD=G&L`=NjvL3BTZP3qfVZ4_3c0*1jBGKm#~l3-P!-_XY5c6Yx00@EzVW z|M))MNAQ({{HZ~IV=1}a$;kXK@Gp!t2TIo@j_);SD)m*ltJ?4!+J2{!`E<2G77X zw9mhsmbaW0rqpug6;7vx6bH3xPzMO;E`^_Z(MKs`5R8%qtufZJaL!!KPOW^#bIP?JMUvT*V5FzUJMiOYGiF8-%TbW4E97$$1cs~ zoGs&8jU?>ir0wQ@GiP!+-*4b_ZovCp$?Y#Zunl~s^{m!jo^z1(`WtD zZ}?=vIoh@pg9eFWXTnoYL3(sj4m40v^iDqZtO)uwcusT(5j zdIP+TcEXSBcsI`SApGJ%WbcFazCU(b!mjG)GHbrxVs8_`icXrys8!^hFwRHAY7SKTEaL&sQEjk~j5p7ej9I zWAAdKYcpU;f_lQ8swWJ5iEns{&soiDT!)aOHSF08q-_%NHkQ0}P)|%|?`Cp_7qYio z*yWw<+ZJx?xpuN=%aQ42{C*C9HJRIJ?t^~FZ=k7v=YA2tSJk6;% z!)`vrR^Ctb23{ktNxY+P$lG`9RL~bN*R=8PDByy@QRwCCmZ5}HO41u%6(&MfDO1$#On%rNo{%5f@gO}f3`-0w&ZHWGpZAV zluON_=OF)`l@5VeG;k&|>+$I8cs#f~WD`nJ7b}eqSBwA9kiTr7s)vV=_w0{vJUmr{ z3};7wZTG0FK!ZTJsc$y-y(DBqKa&vm}^ZD~4iIur(vgWl| zpT@{x(3TBjt%tDMGq8HW$ZS2{>RvSIRha2s5m&rIC;O?3g`#a^VC>4wmB1|zRovV} zZF$9MGBKAlLj&^!`!&;hp&E!Du(ghu@1+ z&;kjl%lW9pyNm@*m(1S0OZAbiBU}6UjLVSQ-^jI$VIBH%^X4txDW#r>=1Y zY*|^VRyDC`C0WrTP6fWJh@YGvTbJPEW9>6@MX~bfS^s$UA)1|tMD+d3fGOtyi zOmllIVQ2o^c+S8)q<$;cVYKBb zEYmYA+Y932kE}xQ7L54;bF-!nIUfg3dKYMcG^}ZM)-W5j&D_|$!mMmTkefwW-|Vb( zR-O^Tin?I053cD8UiStz?$xpgvlI)i}ZapTR1g#ztM^wBEs@eIRxUMr0}IJ_}j*q6u@M8S`Q# z$|B7d$;yS_oGVqY1!osz;uh2|5!}aOlT~b)ik(j43dVb{ zu*gqRZE!Ghdd%bh>C6|{!pB_q(4)_=i9vnt;|hAK3Og6cNe)BfCvb~G?!x(+jz_`! z48)TAxEm8ke zs~Gfkha*Env6d5woF?%&7&}kl@k})BRBp3~w&x>l!FQOk)w#o-Uqb?} z;5%GESMNjD9Y9m>!B<&_9s6JAbrG?^EbP=&}3pI^usCx-~y(iGFUy z)e#-tgYSPtXE)<{9nrMy_?sR)>de=6-1p{j5A<$uPS8*^&S2+fu5nm~saV3GY;NEk z?BiVp{h14?{>(%C^yln#aJoYSp>JB?g;AU(pbWBcn7sp zWwseUKu}T>kON_HEb*`EFEkox;h{B`iTtG33uh7D;*@wsM z#1o|R0n&Sq>n`6t`~On=jNe>Av;4o(&g?g?tB&IyFEiek#CGB(PMjvOv(XTOLLndu zkBA~fg?NDn7KsNQ;HCcyQl%h-c!;P1qC!GcLPba@N+~36oHS12EFQ-*u^o@?@oo>F z&+la9BrOsWzPihtd(OG%{Fd);Id?o)u|j``8t=g){k%VOekVBgF4*}VcZ{I_#`y{n z;Rm4UI9~S0^!Je79--GWXvh@Td9EKv$u#Ez_Y+MwSlh3In!SvF2>Ok%orZ>=L+j56 z9lwIieFG|L<=()md=qIG3%(5%zR%U0(CkgNAE3|Q!SYDSZw0OO@_q=-%+Y@jjSvfd z5@kQ)_+vJI=|)`m83^%n^yMu!J<4C;O}>Tp{4}hYvM*kI7cRUJ{@m9hDm)XkAI1Y3 zWc>WrC|f6yo^gDZ6_*NFwhl@Zq4)!&-t7w8`$5M)frXceY%d}6@38+SJnoBl-Fo70 zqX%yzlfPvD6=jz>UZln)>iw3oi){Mqzs4_5`$g_t;@%%P{|-L=5pVtXJn1iR$Ve!~ zALH)H5il(@lqpdQP=V}^$ zKB3kVe6ZPwBWHQS5|-bnYz^EiLl3@!!|t!_G(_eo6Uf#KwQ_jC<`efpNoCn=kzVm$ zj=gN%>>_ao6c&j)snH(w+M`}KHJWK-tldkE{oL&e%`^igKjcl0D7*y(ZlNFZm)(@w zdoMg3iVVq7Y|at1_ylMD^CMu}dCsqbw<8>Vm&-T0jw7qX?1SL(LE0V-`8|xyIz;&q z>YhY9KT99_YRA}5hjgE$%$`O#9_M(1@-ytmLDAD_vd=imm1uef`9DRCFXC6fhQwV! z=gmB&%{Hf~FXp@wsN469Ud9sqn>S{tZmC@&aU(R(f(zUDI_a;BbZ!Jf7)vgNhRVe! zaC90enL=tGfD^Yva<8G=M$xy~Z-5tO3qRocD%w95+dn~!50NjU?`t5;7*{tb`v@Ov z44J!z)cuPZMi%2--Q;`+DZEa9V|+G?rX9T<_l-bq(~CGViIf!>li6B-)2PS@9ixb% zEaoZko^K1?2`MaaZyxELr`>$aOq;zFGv;gAoXzuPp-CfBWrV7QH)pdCPO8xZaU9}! z41Nv=XO9MV2dO*(S??;_6XeM36=DWd-shIy1J>H^Zg0m<-PM>Dh^+BZReeO>1`7R?! zTM-?dXM8K6gWGsm8D?y*ryuDZ{jYe4RMn-7DkVFHytz0;TZ+c&E2lpwC&_ z7m>BaC>0$G)Scm(>fHvsSV9)XS|!z1mMfjMv6T{ArpGkGB4_c{nl)&)-tro4%;;`| zv1)iWbiWN6nZp-T#msh)PkGgsZQ-+cDP6oHP4{xPv=vEkRp9{F?SZ4c&^jSoAG6knI~dw8rKCwabgrR}^w4&!2F2I0V)}nM^uIZ> z4_S^GdTwNIf;!vqr504kK%pF^{%wOf{A>o#6LH#kVn62&C@TH4(bAC^8Hm|+)RQ}{ zv|6PdKf+00?v}ZpVus&ijy74I(#F%8*&T(rmSKDwP<#{m7=P?k+K~S`yu%WdF_&ZM zHu&Yp>Zskw9F0-xqirKSJAb}-Mq90RE&Z>8AI3oy+H2j-StSWMz8rDfYxKQH&6I0(bmo%G&d$?1%<_ z-^$acQTwEvD@85zB({i3B5F4{n(VPUI23l{BzAf@{DKo`litE`#BoDhi)wAORFlk> zHo(tTdTFMli95AWdy8kSFiO`MouL#^n;Y4bHZjmxG5I}vkYl4sz0wx?R}PfaJzR;R zB0?Qckpj7Adb`1ljZ@WOy}c5g5U&;~nd8|dH1H9cl@H|mDD2lbdiMZ5y$Ke&_G?_H zXW%NYk;Qeam(hT+#yGvM(v$eL2CeHDnd9tW7W-q|gUsSER2c{hbc#~funwb-C!m*e zXr+ET8r8-uTG&M@wIcaT5&a zwn7`EP8Yq&+r5luIJlNFaNS%RhxbF_4zxfSuS1%}8J}0j{}lEY5ZB>QJz0F^QhZy7 zciTKywA2b$s3o?$I;Yh5EdREVFnwlwYDLPH7_**QGxL;>%BPf^f;$V$sKi;nXA<5N zILfbkl<3V{av!cuK@&AdS$@hmOFX@vzEc)gnNxm6Jm+S1LjPHt>*|$QX?*5NZ5!j{ ze-=U&t%NJPgY2&24#KZK>dTpGwqlsJjiFEa{Nh!!h#jQsPWn-V;e_g)Z@CXV}FQGFcJ1fkLzAY`mI1QwN>lALthD9 zUDp*QMCpN`=>CWlj^Oo-Amc;O?L%YB5b2Gr#04>;na@U0+8u3@@4W5MMhq8g z%w1J2zSd1#T1BR{5b|UTs%ZPQFXlj&bn7D&X_lbH_si0wJ=rYnX z%^i6nZyrLiTcHh4q1h~S*YhpVrX1}{&`s;SObhwYzkZCnMa?KFU$4 zH)cKt{fzcUW8{aB`NNbdl{rSYg50_iy3G^KP%Loty#pgda|#unsdbv5#0YUVP;;K~ zPJ$@+DAB)E){GM;!p9uvo+xQHY6{PD467wtCcM^jRd!sDTZYSKY(-zQ7HLIaZP9C1 zzts)5HtuSR^Z{K}kY{F6N%qy-HLoTO^s$xbWqK7$<)U(rlr zN=BKNS!uDscXx~##Db>yz2FR((8l#%N^@N6W7g2WrIqjv^+TnDF@z}M**BH+QM%~4 zf!1bt%)KbR<}P}WS##l9*!>)v=|L~%735=tmg<*&xX9$YT|?~Jssr3M2RtC})+0(n^f)sq{pR9Q@dd@uY0n7C5XAp%rQrkT_6 zJ%oOwMQ=opO;1>EbTcPCn#4upz2q(E`N_$>wA4GR<=D#T&F;2xRGOQhg@`P28WBi! zw<6@)Jw_$9JVhVN44#od4_e?l zyP3gPK}EG9Wz5CSKIUcy+L@+!M2S*5H$s~9qP#XzlA_|vBzUK#O*!6Vh0WUM;f+YU zN}FUql{IZn@~s+?I61AJo2k(9i3|FL>VUKsRR*v$hXUP24!wCZtfIVc4WxW-7EVa@ zZtnNeQV-Nv(B~_6nb1IW**EVq@XAQbEO8?>(tC;g%S@iCG>UGHOP^4iz5}K8dPUzE zuHBS>{Y>qHcEUJd1}Zq)v|1u1D%3M(G_NNf=nHJ%fg9EHv&W3W=(U!6*`S88zoW@e zcctQ8EvQkV2%=@Mu65KIt*yEy*F|BYR>!Mf;l28h#|*zDAt!dw2l*soskdenl_-Cc z-7Ke@*ssRTg+%FPscDO}muEHcv{ooAcDnZ?F-C!AbbQZGc^0G1xBEtieCrR4HS!W~ zt(^-DZli^Kk}}fUJc0HvWeAL?MVd9nqRi;$i?32$FIxH-p|8LbeT;=?R1@RO5Ur5? zXo4QvP2)D>CR;opn%v}@zyIJ3jtajlH%nAG#G1nAgIZtbJDYusr=2yTF0zWgsiU7` z{GmUl|9B1^nMKoDiGJpg|18<5Jbg|RwHmvQli4dW8uL%e-z-=oLOrIf6g5ZGgsyMF z-wZN72+tHh zcG9@n+@kqX_1eso@+M8}!z*JydE>P+*I!!US!M+E7OW-Dv~+5{k)|H4Sm2)?sH^y* zks2*ltI@Ui=w@Wi+b&UJWTH=!L)s=-7d^*%e7^G6$|$q{7!7`xT9@f_mCVUwBqmdH z1Fe3F^yRU0<~sGYud(~4t2y74BX&&MRPC`NHn#17TMI~53smo@nZpO`f@@iF4~}Ss z_wc$HM;f*H5VgUqruN2nR2qp6S8+pq=Ms4 z^{thp!;z)C>2tNceVE&Eoaw&j>XxXQK2`g%mL!$R-Ll=%)MpxR_5SnyeEN0uiPiIqBiZde_4wawz1;irHPdw( z*~|6*-_J>kKE0Pu-uq<9Zp#qB=MHMs%YSNsI#At|eNjv8)MATX<`l$)boQv9DDu_T F{0ETS6h;65 literal 0 HcmV?d00001 diff --git a/src/LageBuch.App/Services/SystemAlarmService.cs b/src/LageBuch.App/Services/SystemAlarmService.cs index 1a92024..185d98c 100644 --- a/src/LageBuch.App/Services/SystemAlarmService.cs +++ b/src/LageBuch.App/Services/SystemAlarmService.cs @@ -7,21 +7,17 @@ namespace LageBuch.App.Services; /// -/// Audio for the desktop deployment. The looping life-safety alarm (/ -/// ) uses winmm's PlaySound on Windows and is a no-op elsewhere, unchanged. -/// The one-shot spoken cues () work on Windows, macOS and Linux: winmm in-memory -/// on Windows, and afplay/aplay on macOS/Linux fed a WAV extracted to a temp file. -/// Every path degrades to a silent no-op when the asset or the player is missing, so a build with -/// no voice clip yet — or a host without the CLI player — simply stays quiet rather than crashing. +/// Audio for the desktop deployment. One-shot spoken cues () work on Windows, +/// macOS and Linux: winmm in-memory on Windows, and afplay/aplay on macOS/Linux fed +/// a WAV extracted to a temp file. Every path degrades to a silent no-op when the asset or the +/// player is missing, so a build with no voice clip yet — or a host without the CLI player — +/// simply stays quiet rather than crashing. /// internal sealed class SystemAlarmService : IAlarmService { private const uint SndAsync = 0x0001; // play asynchronously private const uint SndNodefault = 0x0002; // no default beep if it fails private const uint SndMemory = 0x0004; // pszSound points to in-memory WAV - private const uint SndLoop = 0x0008; // loop until the next PlaySound call - - private static readonly Uri AlarmAsset = new("avares://LageBuch.App/Assets/alarm.wav"); // One voice clip per AlarmSound. A missing entry or missing file just means that cue is silent. private static readonly IReadOnlyDictionary VoiceAssets = @@ -31,21 +27,15 @@ internal sealed class SystemAlarmService : IAlarmService // Generic tone (already bundled) — a task falling due is frequent enough that a spoken // sentence would be more noise than signal. [AlarmSound.TaskDue] = "alarm.wav", - // Same reasoning as TaskDue: a Druckabfrage recurs every few minutes per Trupp. - [AlarmSound.ScbaControlDue] = "alarm.wav", + [AlarmSound.PressureCheckDue] = "voice-druckabfrage.wav", + [AlarmSound.RetreatAlarm] = "voice-rueckzugsalarm.wav", }; - private readonly byte[]? _wav; private readonly Dictionary _voiceBytes = new(); private readonly Dictionary _voiceTempFiles = new(); - private bool _sounding; public SystemAlarmService() { - // Load the looping alarm WAV once. Only needed on Windows; skip the work elsewhere. - if (OperatingSystem.IsWindows()) - _wav = TryLoad(AlarmAsset); - // Preload the voice clips (all platforms). Absent files are simply skipped. foreach (var (sound, file) in VoiceAssets) if (TryLoad(new Uri($"avares://LageBuch.App/Assets/{file}")) is { } bytes) @@ -77,7 +67,6 @@ public void Play(AlarmSound sound) if (OperatingSystem.IsWindows()) { - // One-shot (no SndLoop). Deliberately distinct from Start's looping playback. PlaySound(bytes, IntPtr.Zero, SndAsync | SndMemory | SndNodefault); return; } diff --git a/src/LageBuch.AppLogic/Services/IAlarmService.cs b/src/LageBuch.AppLogic/Services/IAlarmService.cs index d0ff9e1..22a4a9b 100644 --- a/src/LageBuch.AppLogic/Services/IAlarmService.cs +++ b/src/LageBuch.AppLogic/Services/IAlarmService.cs @@ -12,23 +12,21 @@ public enum AlarmSound /// "Aufgabe fällig" — a task's timer expired while still open (#88). TaskDue, - /// "Druckabfrage fällig" — a Trupp's pressure-control interval has elapsed (#78). - ScbaControlDue, + /// "Druckabfrage fällig" — a Trupp's pressure-control interval has elapsed (#78, #81). + PressureCheckDue, + + /// "Rückzugsalarm" — a Trupp has hit its time limit or return pressure (#81), + /// repeated until acknowledged. + RetreatAlarm, } /// -/// Sounds audible cues. / drive the looping life-safety tone -/// (the Atemschutz Rückzugsalarm) and are idempotent so callers can drive them straight from state -/// on every tick. is a fire-and-forget one-shot spoken announcement. +/// Sounds audible cues. is a fire-and-forget one-shot spoken announcement; +/// a caller that needs an insistent, repeating cue (e.g. the Atemschutz Rückzugsalarm) calls it +/// again on its own cadence rather than this service looping anything on its own (#81). /// public interface IAlarmService { - /// Begins (or continues) the looping alarm. Safe to call when already sounding. - void Start(); - - /// Silences the looping alarm. Safe to call when already silent. - void Stop(); - /// Plays a spoken cue once. Fire-and-forget; safe to call from the UI thread. void Play(AlarmSound sound); } diff --git a/src/LageBuch.AppLogic/ViewModels/ScbaViewModel.cs b/src/LageBuch.AppLogic/ViewModels/ScbaViewModel.cs index 990d4f0..e536636 100644 --- a/src/LageBuch.AppLogic/ViewModels/ScbaViewModel.cs +++ b/src/LageBuch.AppLogic/ViewModels/ScbaViewModel.cs @@ -167,6 +167,15 @@ public sealed partial class ScbaViewModel : ObservableObject, IDisposable // that only ever grows until the Trupp returns), control-due toggles on and off every Abfrage- // Intervall, so an id is removed once no longer due, letting the next crossing sound again. private readonly HashSet _controlDueAnnounced = new(); + + // Rückzugsalarm speaks instead of sounding a looping siren (#81), repeating on this cadence + // while unacknowledged so it stays insistent -- mirrors ReminderViewModel's ILS cue exactly, + // just at 15s instead of 60s given the life-safety stakes. Reset to null by AcknowledgeAlarm + // (so the next cycle announces immediately) and by a newly-tripped alarm (so a second Trupp + // alarming after an ack is heard right away rather than waiting out the window). + private static readonly TimeSpan RetreatRepeatInterval = TimeSpan.FromSeconds(15); + private DateTimeOffset? _lastAlarmAnnouncedAt; + private readonly IncidentSettings _settings; // True once the user has hand-edited the Einsatzzeit; after that a Trupp-type switch must not @@ -388,8 +397,8 @@ public string AlarmDisplay [RelayCommand(CanExecute = nameof(CanAcknowledgeAlarm))] private void AcknowledgeAlarm() { - // Silence the sound; the visual banner stays until the trupp is back. - _alarm.Stop(); + // Silences the repeat cadence; the visual banner stays until the trupp is back. + _lastAlarmAnnouncedAt = null; IsAlarmAcknowledged = true; } @@ -397,18 +406,23 @@ private string AlarmReason(AtemschutzTrupp trupp) => trupp.IsTimeAlarm(_clock.No ? "Einsatzzeit erreicht" : $"Rückzugsdruck erreicht ({trupp.LatestPressure} bar)"; - /// Sounds or silences the audible alarm from current state, and keeps the banner - /// bindings fresh. A newly-alarming trupp re-arms the sound even after an earlier ack. + /// Speaks the Rückzugsalarm cue on its repeat cadence while unacknowledged (#81), and + /// keeps the banner bindings fresh. A newly-alarming trupp re-arms the cue even after an + /// earlier ack. private void UpdateAlarm(bool newAlarmTripped) { if (newAlarmTripped) IsAlarmAcknowledged = false; - if (IsAnyAlarm && !IsAlarmAcknowledged) - _alarm.Start(); + if (IsAnyAlarm && !IsAlarmAcknowledged && + (_lastAlarmAnnouncedAt is null || _clock.Now - _lastAlarmAnnouncedAt >= RetreatRepeatInterval)) + { + _alarm.Play(AlarmSound.RetreatAlarm); + _lastAlarmAnnouncedAt = _clock.Now; + } else if (!IsAnyAlarm) { - _alarm.Stop(); + _lastAlarmAnnouncedAt = null; IsAlarmAcknowledged = false; } @@ -581,7 +595,7 @@ private void AnnounceControlDue() if ((trupp.IsActive || trupp.IsWithdrawing) && trupp.IsControlDue(_clock.Now)) { if (_controlDueAnnounced.Add(trupp.Id)) - _alarm.Play(AlarmSound.ScbaControlDue); + _alarm.Play(AlarmSound.PressureCheckDue); } else { @@ -614,7 +628,6 @@ private bool LogNewAlarms() public void Dispose() { _session.Changed -= RefreshTrupps; - _alarm.Stop(); _subscription?.Dispose(); } } diff --git a/tests/LageBuch.AppLogic.Tests/ReminderViewModelTests.cs b/tests/LageBuch.AppLogic.Tests/ReminderViewModelTests.cs index a5a7107..bf37d5a 100644 --- a/tests/LageBuch.AppLogic.Tests/ReminderViewModelTests.cs +++ b/tests/LageBuch.AppLogic.Tests/ReminderViewModelTests.cs @@ -9,12 +9,7 @@ namespace LageBuch.AppLogic.Tests; // audible output fired without real audio. internal sealed class FakeAlarmService : IAlarmService { - public int StartCount { get; private set; } - public int StopCount { get; private set; } - public bool IsSounding { get; private set; } public List Played { get; } = new(); - public void Start() { StartCount++; IsSounding = true; } - public void Stop() { StopCount++; IsSounding = false; } public void Play(AlarmSound sound) => Played.Add(sound); } diff --git a/tests/LageBuch.AppLogic.Tests/ScbaViewModelTests.cs b/tests/LageBuch.AppLogic.Tests/ScbaViewModelTests.cs index 2ffdd67..af0ea0f 100644 --- a/tests/LageBuch.AppLogic.Tests/ScbaViewModelTests.cs +++ b/tests/LageBuch.AppLogic.Tests/ScbaViewModelTests.cs @@ -244,43 +244,70 @@ public void Tick_past_max_duration_sounds_the_audible_alarm_and_sets_banner() var alarm = new FakeAlarmService(); var vm = Vm(clock, NewSession(clock), ticker: ticker, alarm: alarm); vm.NewMaxDurationMinutes = 30; + vm.NewControlIntervalMinutes = 999; // keep Druckabfrage out of this Rückzugsalarm-only test var row = Register(vm); row.StartCommand.Execute(null); Assert.False(vm.IsAnyAlarm); - Assert.False(alarm.IsSounding); + Assert.Empty(alarm.Played); clock.Now = T0.AddMinutes(31); ticker.Fire(); Assert.True(vm.IsAnyAlarm); - Assert.True(alarm.IsSounding); + Assert.Contains(AlarmSound.RetreatAlarm, alarm.Played); Assert.Contains("RÜCKZUGSALARM", vm.AlarmDisplay); Assert.Contains("Trupp 1 (Angriffstrupp)", vm.AlarmDisplay); Assert.True(vm.AcknowledgeAlarmCommand.CanExecute(null)); } [Fact] - public void Acknowledging_alarm_silences_sound_but_keeps_banner() + public void Acknowledging_alarm_silences_the_repeat_but_keeps_banner() { var clock = new FixedClock(T0); var ticker = new FakeTicker(); var alarm = new FakeAlarmService(); var vm = Vm(clock, NewSession(clock), ticker: ticker, alarm: alarm); vm.NewMaxDurationMinutes = 30; + vm.NewControlIntervalMinutes = 999; // keep Druckabfrage out of this Rückzugsalarm-only test var row = Register(vm); row.StartCommand.Execute(null); clock.Now = T0.AddMinutes(31); ticker.Fire(); + Assert.Single(alarm.Played); vm.AcknowledgeAlarmCommand.Execute(null); - Assert.False(alarm.IsSounding); // sound stopped - Assert.True(vm.IsAnyAlarm); // but banner remains while the alarm condition persists + Assert.True(vm.IsAnyAlarm); // banner remains while the alarm condition persists - // A further tick with the alarm acknowledged must not re-arm the sound. + // A further tick with the alarm acknowledged must not re-announce. ticker.Fire(); - Assert.False(alarm.IsSounding); + Assert.Single(alarm.Played); + } + + [Fact] + public void Repeat_cadence_is_fifteen_seconds_while_unacknowledged() + { + var clock = new FixedClock(T0); + var ticker = new FakeTicker(); + var alarm = new FakeAlarmService(); + var vm = Vm(clock, NewSession(clock), ticker: ticker, alarm: alarm); + vm.NewMaxDurationMinutes = 30; + vm.NewControlIntervalMinutes = 999; // keep Druckabfrage out of this Rückzugsalarm-only test + var row = Register(vm); + row.StartCommand.Execute(null); + + clock.Now = T0.AddMinutes(30); + ticker.Fire(); + Assert.Single(alarm.Played); + + clock.Now = T0.AddMinutes(30).AddSeconds(10); // still inside the 15s window + ticker.Fire(); + Assert.Single(alarm.Played); + + clock.Now = T0.AddMinutes(30).AddSeconds(16); // past the 15s window + ticker.Fire(); + Assert.Equal(2, alarm.Played.Count); } [Fact] @@ -291,24 +318,29 @@ public void Alarm_and_control_reminder_persist_through_Rueckzug_and_clear_on_Abg var alarm = new FakeAlarmService(); var vm = Vm(clock, NewSession(clock), ticker: ticker, alarm: alarm); vm.NewMaxDurationMinutes = 30; + vm.NewControlIntervalMinutes = 999; // keep Druckabfrage out of this Rückzugsalarm-only test var row = Register(vm); row.StartCommand.Execute(null); clock.Now = T0.AddMinutes(31); ticker.Fire(); - Assert.True(alarm.IsSounding); + Assert.Single(alarm.Played); // Rückzug alone does not silence the alarm -- the crew is still consuming air. row.WithdrawCommand.Execute(null); Assert.True(vm.IsAnyAlarm); + var countBeforeRemoval = alarm.Played.Count; row.MarkRemovedCommand.Execute(null); Assert.False(vm.IsAnyAlarm); - Assert.False(alarm.IsSounding); + Assert.Equal(countBeforeRemoval, alarm.Played.Count); // returning does not itself announce + + ticker.Fire(); + Assert.Equal(countBeforeRemoval, alarm.Played.Count); // and no further ticks announce once cleared } [Fact] - public void A_second_trupp_newly_alarming_re_arms_the_sound_after_ack() + public void A_second_trupp_newly_alarming_re_announces_after_ack() { var clock = new FixedClock(T0); var ticker = new FakeTicker(); @@ -316,24 +348,59 @@ public void A_second_trupp_newly_alarming_re_arms_the_sound_after_ack() var vm = Vm(clock, NewSession(clock), ticker: ticker, alarm: alarm); vm.NewMaxDurationMinutes = 30; + vm.NewControlIntervalMinutes = 999; // keep Druckabfrage out of this Rückzugsalarm-only test var first = Register(vm); first.StartCommand.Execute(null); // Second trupp goes under air 10 minutes later, so its limit falls after the first's. clock.Now = T0.AddMinutes(10); vm.NewMaxDurationMinutes = 30; + vm.NewControlIntervalMinutes = 999; var second = Register(vm, truppfuehrer: "Huber", truppmann: "Mayer"); second.StartCommand.Execute(null); clock.Now = T0.AddMinutes(31); ticker.Fire(); // first trupp alarms (limit at T0+30) + Assert.Single(alarm.Played); vm.AcknowledgeAlarmCommand.Execute(null); - Assert.False(alarm.IsSounding); clock.Now = T0.AddMinutes(41); - ticker.Fire(); // second trupp now past its limit (T0+40) → re-arm + ticker.Fire(); // second trupp now past its limit (T0+40) → re-announce + + Assert.Equal(2, alarm.Played.Count); + Assert.All(alarm.Played, s => Assert.Equal(AlarmSound.RetreatAlarm, s)); + } + + [Fact] + public void A_new_trupp_alarming_after_ack_reannounces_immediately_not_after_the_full_window() + { + var clock = new FixedClock(T0); + var ticker = new FakeTicker(); + var alarm = new FakeAlarmService(); + var vm = Vm(clock, NewSession(clock), ticker: ticker, alarm: alarm); + + vm.NewMaxDurationMinutes = 30; + vm.NewControlIntervalMinutes = 999; // keep Druckabfrage out of this Rückzugsalarm-only test + var first = Register(vm); + first.StartCommand.Execute(null); // starts at T0, alarms at T0+30:00 + + // Second trupp starts 5s later than the first, same 30-minute duration, so it crosses its + // own threshold at T0+30:05 -- 5s after the first's ack, well inside the 15s repeat window. + clock.Now = T0.AddSeconds(5); + vm.NewMaxDurationMinutes = 30; + vm.NewControlIntervalMinutes = 999; + var second = Register(vm, truppfuehrer: "Huber", truppmann: "Mayer"); + second.StartCommand.Execute(null); - Assert.True(alarm.IsSounding); + clock.Now = T0.AddMinutes(30); + ticker.Fire(); // first trupp alarms + Assert.Single(alarm.Played); + vm.AcknowledgeAlarmCommand.Execute(null); + + clock.Now = T0.AddMinutes(30).AddSeconds(5); // second trupp's own crossing, 5s after ack + ticker.Fire(); + + Assert.Equal(2, alarm.Played.Count); // announced immediately, not after waiting out 15s } // --- Druckabfrage audio cue (issue #78 follow-up) --- @@ -354,7 +421,7 @@ public void Control_due_plays_the_cue_once_and_not_again_while_still_due() ticker.Fire(); // must not sound a second time for the same due-crossing Assert.Single(alarm.Played); - Assert.Equal(AlarmSound.ScbaControlDue, alarm.Played[0]); + Assert.Equal(AlarmSound.PressureCheckDue, alarm.Played[0]); } [Fact] @@ -382,7 +449,7 @@ public void Recording_pressure_silences_the_cue_until_the_next_interval() ticker.Fire(); Assert.Equal(2, alarm.Played.Count); - Assert.All(alarm.Played, s => Assert.Equal(AlarmSound.ScbaControlDue, s)); + Assert.All(alarm.Played, s => Assert.Equal(AlarmSound.PressureCheckDue, s)); } [Fact] @@ -433,18 +500,6 @@ public void Two_trupps_due_at_different_times_each_sound_their_own_cue() Assert.Equal(2, alarm.Played.Count); } - [Fact] - public void Dispose_stops_the_alarm() - { - var clock = new FixedClock(T0); - var alarm = new FakeAlarmService(); - var vm = Vm(clock, NewSession(clock), alarm: alarm); - - vm.Dispose(); - - Assert.True(alarm.StopCount >= 1); - } - // --- Crew entry (issue #15) --- [Fact] From 307518e1fd694b6afac854e20e10aadf4d54c72b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20M=C3=BCller?= <1005065+DeepDiver1975@users.noreply.github.com> Date: Sun, 30 Aug 2026 22:17:22 +0200 Subject: [PATCH 3/4] fix(alarm): serialize cue playback so alarms no longer overlap MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit SystemAlarmService.Play() was fire-and-forget on all platforms, so two cues becoming due in the same tick (e.g. a Trupp's RetreatAlarm and another Trupp's PressureCheckDue) played concurrently and talked over each other. Playback now goes through a SerialAudioQueue that runs cues one at a time on a dedicated background thread, with a watchdog timeout so a hung OS player can't permanently block later alarms. Signed-off-by: Thomas Müller <1005065+DeepDiver1975@users.noreply.github.com> --- src/LageBuch.App/Services/SerialAudioQueue.cs | 43 +++++++++ .../Services/SystemAlarmService.cs | 15 ++- .../SerialAudioQueueTests.cs | 93 +++++++++++++++++++ 3 files changed, 148 insertions(+), 3 deletions(-) create mode 100644 src/LageBuch.App/Services/SerialAudioQueue.cs create mode 100644 tests/LageBuch.App.Tests/SerialAudioQueueTests.cs diff --git a/src/LageBuch.App/Services/SerialAudioQueue.cs b/src/LageBuch.App/Services/SerialAudioQueue.cs new file mode 100644 index 0000000..a3fa57d --- /dev/null +++ b/src/LageBuch.App/Services/SerialAudioQueue.cs @@ -0,0 +1,43 @@ +using System.Collections.Concurrent; + +namespace LageBuch.App.Services; + +/// +/// Runs enqueued playback actions one at a time, in FIFO order, on a single dedicated +/// background thread — so cues that become due close together play sequentially instead of +/// overlapping. itself never blocks the caller. +/// +/// Each action gets a bounded time to finish (see constructor); if it hangs (e.g. a stuck OS +/// audio player process that never exits), the queue moves on to the next item anyway so one +/// stuck cue can't permanently silence later ones. +/// +public sealed class SerialAudioQueue +{ + private readonly BlockingCollection _queue = new(); + private readonly TimeSpan _perItemTimeout; + + public SerialAudioQueue(TimeSpan? perItemTimeout = null) + { + _perItemTimeout = perItemTimeout ?? TimeSpan.FromSeconds(10); + var worker = new Thread(Run) { IsBackground = true, Name = nameof(SerialAudioQueue) }; + worker.Start(); + } + + /// Queues to run after everything already queued. + public void Enqueue(Action play) => _queue.Add(play); + + private void Run() + { + foreach (var play in _queue.GetConsumingEnumerable()) + { + try + { + Task.Run(play).Wait(_perItemTimeout); + } + catch + { + // A misbehaving cue must not stop the queue from serving the next one. + } + } + } +} diff --git a/src/LageBuch.App/Services/SystemAlarmService.cs b/src/LageBuch.App/Services/SystemAlarmService.cs index 185d98c..28e42c0 100644 --- a/src/LageBuch.App/Services/SystemAlarmService.cs +++ b/src/LageBuch.App/Services/SystemAlarmService.cs @@ -15,9 +15,10 @@ namespace LageBuch.App.Services; /// internal sealed class SystemAlarmService : IAlarmService { - private const uint SndAsync = 0x0001; // play asynchronously private const uint SndNodefault = 0x0002; // no default beep if it fails private const uint SndMemory = 0x0004; // pszSound points to in-memory WAV + // No SND_ASYNC: playback must block the queue's worker thread until the clip finishes, + // so cues play one after another instead of overlapping (see SerialAudioQueue). // One voice clip per AlarmSound. A missing entry or missing file just means that cue is silent. private static readonly IReadOnlyDictionary VoiceAssets = @@ -33,6 +34,7 @@ internal sealed class SystemAlarmService : IAlarmService private readonly Dictionary _voiceBytes = new(); private readonly Dictionary _voiceTempFiles = new(); + private readonly SerialAudioQueue _queue = new(); public SystemAlarmService() { @@ -65,9 +67,15 @@ public void Play(AlarmSound sound) if (!_voiceBytes.TryGetValue(sound, out var bytes)) return; // no clip bundled for this cue yet + _queue.Enqueue(() => PlayBlocking(sound, bytes)); + } + + // Runs on the SerialAudioQueue's worker thread; blocks until the clip finishes playing. + private void PlayBlocking(AlarmSound sound, byte[] bytes) + { if (OperatingSystem.IsWindows()) { - PlaySound(bytes, IntPtr.Zero, SndAsync | SndMemory | SndNodefault); + PlaySound(bytes, IntPtr.Zero, SndMemory | SndNodefault); return; } @@ -78,11 +86,12 @@ public void Play(AlarmSound sound) var player = OperatingSystem.IsMacOS() ? "afplay" : "aplay"; try { - Process.Start(new ProcessStartInfo(player, $"\"{path}\"") + using var process = Process.Start(new ProcessStartInfo(player, $"\"{path}\"") { UseShellExecute = false, CreateNoWindow = true, }); + process?.WaitForExit(); } catch { diff --git a/tests/LageBuch.App.Tests/SerialAudioQueueTests.cs b/tests/LageBuch.App.Tests/SerialAudioQueueTests.cs new file mode 100644 index 0000000..00ede32 --- /dev/null +++ b/tests/LageBuch.App.Tests/SerialAudioQueueTests.cs @@ -0,0 +1,93 @@ +using System.Diagnostics; +using LageBuch.App.Services; + +namespace LageBuch.App.Tests; + +public class SerialAudioQueueTests +{ + [Fact] + public void Enqueued_actions_do_not_overlap() + { + var sw = Stopwatch.StartNew(); + var events = new List<(string Id, long StartMs, long EndMs)>(); + var done = new CountdownEvent(2); + var queue = new SerialAudioQueue(); + + queue.Enqueue(() => RecordTimedRun("a", sw, events, done, TimeSpan.FromMilliseconds(150))); + queue.Enqueue(() => RecordTimedRun("b", sw, events, done, TimeSpan.FromMilliseconds(50))); + + Assert.True(done.Wait(TimeSpan.FromSeconds(5)), "queued actions never completed"); + Assert.Equal(2, events.Count); + Assert.True(events[1].StartMs >= events[0].EndMs, + "second action started before the first one finished"); + } + + [Fact] + public void Enqueued_actions_run_in_fifo_order() + { + var order = new List(); + var done = new CountdownEvent(5); + var queue = new SerialAudioQueue(); + + for (var i = 0; i < 5; i++) + { + var id = i; + queue.Enqueue(() => + { + lock (order) order.Add(id); + done.Signal(); + }); + } + + Assert.True(done.Wait(TimeSpan.FromSeconds(5)), "queued actions never completed"); + Assert.Equal(new[] { 0, 1, 2, 3, 4 }, order); + } + + [Fact] + public void Enqueue_returns_without_waiting_for_playback_to_finish() + { + var queue = new SerialAudioQueue(); + var started = new ManualResetEventSlim(); + + queue.Enqueue(() => + { + started.Set(); + Thread.Sleep(TimeSpan.FromSeconds(2)); + }); + + Assert.True(started.Wait(TimeSpan.FromSeconds(1)), "action never started"); + + var sw = Stopwatch.StartNew(); + queue.Enqueue(() => { }); + sw.Stop(); + + Assert.True(sw.Elapsed < TimeSpan.FromMilliseconds(500), "Enqueue blocked the caller"); + } + + [Fact] + public void A_stuck_action_does_not_permanently_block_later_ones() + { + var queue = new SerialAudioQueue(perItemTimeout: TimeSpan.FromMilliseconds(200)); + var laterRan = new ManualResetEventSlim(); + + queue.Enqueue(() => Thread.Sleep(TimeSpan.FromSeconds(30))); // simulates a hung player + queue.Enqueue(() => laterRan.Set()); + + Assert.True(laterRan.Wait(TimeSpan.FromSeconds(2)), + "later action never ran; the stuck item wedged the queue"); + } + + private static void RecordTimedRun( + string id, + Stopwatch sw, + List<(string Id, long StartMs, long EndMs)> events, + CountdownEvent done, + TimeSpan sleep) + { + var start = sw.ElapsedMilliseconds; + Thread.Sleep(sleep); + var end = sw.ElapsedMilliseconds; + lock (events) events.Add((id, start, end)); + done.Signal(); + } +} From 1d3ce59e585efa333c88193bd2b76d1a31b5c17f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20M=C3=BCller?= <1005065+DeepDiver1975@users.noreply.github.com> Date: Sun, 30 Aug 2026 22:40:02 +0200 Subject: [PATCH 4/4] fix(alarm): remove dead looping-siren methods left by a bad rebase merge MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Start()/Stop() referenced _sounding, _wav, SndAsync and SndLoop, none of which exist anymore — the branch rebase onto main kept these method bodies from main's old looping-siren SystemAlarmService while also keeping this branch's removal of their backing fields (main's siren was already fully replaced by spoken Play() cues here). Neither method is called anywhere (IAlarmService doesn't declare them), so this was dead code left by an incomplete conflict resolution, breaking the build (CS0103) on both CI platforms. Signed-off-by: Thomas Müller <1005065+DeepDiver1975@users.noreply.github.com> --- src/LageBuch.App/Services/SystemAlarmService.cs | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/src/LageBuch.App/Services/SystemAlarmService.cs b/src/LageBuch.App/Services/SystemAlarmService.cs index 28e42c0..4f08074 100644 --- a/src/LageBuch.App/Services/SystemAlarmService.cs +++ b/src/LageBuch.App/Services/SystemAlarmService.cs @@ -44,22 +44,6 @@ public SystemAlarmService() _voiceBytes[sound] = bytes; } - public void Start() - { - if (_sounding || _wav is null || !OperatingSystem.IsWindows()) - return; - PlaySound(_wav, IntPtr.Zero, SndAsync | SndMemory | SndLoop | SndNodefault); - _sounding = true; - } - - public void Stop() - { - if (!_sounding || !OperatingSystem.IsWindows()) - return; - PlaySound(null, IntPtr.Zero, 0); // null sound stops any current playback - _sounding = false; - } - [SuppressMessage("Design", "CA1031", Justification = "A missing player binary must stay silent (see comment); a failed alarm never crashes the app.")] public void Play(AlarmSound sound)