From 5bb1c37fefe394e2e37b0015c9560ce0e441c6c2 Mon Sep 17 00:00:00 2001 From: Claude Date: Tue, 29 Sep 2026 06:58:51 +0000 Subject: [PATCH] Fase 1: on-prem web UI (IIS or Windows service), light design system - ASP.NET Core Blazor static SSR: overview with KPI tiles, instance page (findings, CPU/batch/PLE trends, top waits, file latency, blocking, deadlocks with .xdl download, not-measurable rules, resolved), finding detail with explanation, evidence, fix script and references - Light-first design (sidebar, cards, self-hosted Inter, teal accent), optional dark theme via toggle; strict CSP, no inline styles - Windows authentication (Negotiate/IIS) with optional group restriction; refuses to run without authentication outside Development - Hosting: IIS (in-process ASP.NET Core Module), Windows service with Kestrel, or systemd; web reads the repository with db_datareader only - docs/installation.md for repository, permissions, agent and web - Fix: CPU used by other processes is not derived on Linux (SystemIdle is unreliable there); deadlocks are not re-reported or stored twice after an agent restart; Dapper sends datetime2 so time comparisons are exact Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01E3EExwndy8Z22EK2Qpt6BK --- Directory.Packages.props | 2 + docs/installation.md | 108 ++++++++ .../Monitoring/InstanceMonitor.cs | 21 +- .../Performance/CpuCollector.cs | 5 +- src/SQLInsight.Core/Data/CpuUtilization.cs | 8 + .../InsightRepository.cs | 47 +++- .../SQLInsight.Repository.csproj | 3 + .../Performance/ResourceRules.cs | 5 +- src/SQLInsight.Web/Components/App.razor | 18 ++ .../Components/Layout/MainLayout.razor | 40 +++ .../Components/Pages/AllFindings.razor | 16 ++ .../Components/Pages/Error.razor | 5 + .../Components/Pages/FindingDetail.razor | 76 ++++++ .../Components/Pages/Home.razor | 77 ++++++ .../Components/Pages/Instance.razor | 235 ++++++++++++++++++ .../Components/Pages/NotFound.razor | 5 + src/SQLInsight.Web/Components/Routes.razor | 5 + .../Components/Shared/FindingList.razor | 32 +++ .../Components/Shared/Icon.razor | 40 +++ .../Components/Shared/SeverityBadge.razor | 6 + .../Components/Shared/Sparkline.razor | 50 ++++ src/SQLInsight.Web/Components/_Imports.razor | 12 + src/SQLInsight.Web/Display.cs | 60 +++++ src/SQLInsight.Web/Program.cs | 86 ++++++- .../Properties/launchSettings.json | 23 -- src/SQLInsight.Web/SQLInsight.Web.csproj | 6 + src/SQLInsight.Web/WebOptions.cs | 15 ++ .../appsettings.Development.json | 5 + src/SQLInsight.Web/appsettings.json | 12 +- src/SQLInsight.Web/wwwroot/app.css | 156 ++++++++++++ src/SQLInsight.Web/wwwroot/app.js | 22 ++ src/SQLInsight.Web/wwwroot/favicon.svg | 1 + .../wwwroot/fonts/Inter-OFL.txt | 93 +++++++ .../fonts/inter-latin-ext-wght-normal.woff2 | Bin 0 -> 85068 bytes .../fonts/inter-latin-wght-normal.woff2 | Bin 0 -> 48256 bytes src/SQLInsight.Web/wwwroot/theme.js | 3 + .../AgentPipelineTests.cs | 18 ++ .../CollectorTests.cs | 2 + .../RepositoryTests.cs | 2 + .../SQLInsight.IntegrationTests.csproj | 2 + tests/SQLInsight.IntegrationTests/WebTests.cs | 160 ++++++++++++ .../PerformanceRuleTests.cs | 10 +- 42 files changed, 1453 insertions(+), 39 deletions(-) create mode 100644 docs/installation.md create mode 100644 src/SQLInsight.Web/Components/App.razor create mode 100644 src/SQLInsight.Web/Components/Layout/MainLayout.razor create mode 100644 src/SQLInsight.Web/Components/Pages/AllFindings.razor create mode 100644 src/SQLInsight.Web/Components/Pages/Error.razor create mode 100644 src/SQLInsight.Web/Components/Pages/FindingDetail.razor create mode 100644 src/SQLInsight.Web/Components/Pages/Home.razor create mode 100644 src/SQLInsight.Web/Components/Pages/Instance.razor create mode 100644 src/SQLInsight.Web/Components/Pages/NotFound.razor create mode 100644 src/SQLInsight.Web/Components/Routes.razor create mode 100644 src/SQLInsight.Web/Components/Shared/FindingList.razor create mode 100644 src/SQLInsight.Web/Components/Shared/Icon.razor create mode 100644 src/SQLInsight.Web/Components/Shared/SeverityBadge.razor create mode 100644 src/SQLInsight.Web/Components/Shared/Sparkline.razor create mode 100644 src/SQLInsight.Web/Components/_Imports.razor create mode 100644 src/SQLInsight.Web/Display.cs delete mode 100644 src/SQLInsight.Web/Properties/launchSettings.json create mode 100644 src/SQLInsight.Web/WebOptions.cs create mode 100644 src/SQLInsight.Web/wwwroot/app.css create mode 100644 src/SQLInsight.Web/wwwroot/app.js create mode 100644 src/SQLInsight.Web/wwwroot/favicon.svg create mode 100644 src/SQLInsight.Web/wwwroot/fonts/Inter-OFL.txt create mode 100644 src/SQLInsight.Web/wwwroot/fonts/inter-latin-ext-wght-normal.woff2 create mode 100644 src/SQLInsight.Web/wwwroot/fonts/inter-latin-wght-normal.woff2 create mode 100644 src/SQLInsight.Web/wwwroot/theme.js create mode 100644 tests/SQLInsight.IntegrationTests/WebTests.cs diff --git a/Directory.Packages.props b/Directory.Packages.props index b99d1f5..30d90f3 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -10,6 +10,8 @@ + + diff --git a/docs/installation.md b/docs/installation.md new file mode 100644 index 0000000..02b4f13 --- /dev/null +++ b/docs/installation.md @@ -0,0 +1,108 @@ +# Installation + +SQLInsight Pro består af to programmer, som begge installeres hos jer (on-prem): + +| Del | Hvad den gør | Kører som | +|---|---|---| +| **SQLInsight Agent** | Overvåger SQL Server-instanserne og gemmer fund i repository-databasen | Windows-tjeneste (eller systemd på Linux) | +| **SQLInsight Web** | Lokalt websted, der viser fund, trends og anbefalinger | IIS-websted **eller** selvstændig Windows-tjeneste med indbygget webserver (Kestrel) | + +Begge bruger en **repository-database** på en SQL Server 2016+-instans, der helst ikke er en af de overvågede. + +> Installationstrinene er skrevet ud fra Microsofts dokumentation for ASP.NET Core-hosting. De er endnu ikke gennemtestet på en ren Windows Server. Meld gerne afvigelser tilbage som issue. + +## 1. Forudsætninger + +- Windows Server 2016 eller nyere (eller Linux til agenten) +- [.NET 10 Runtime](https://dotnet.microsoft.com/download/dotnet/10.0) på agent-serveren; **ASP.NET Core Hosting Bundle** på webserveren, hvis IIS bruges +- To tjenestekonti, gerne gMSA: én til agenten og én til web-UI'et +- Til SQL Server 2000: en Windows-agent med en ODBC-driver, der understøtter 2000 (se [legacy-versions.md](legacy-versions.md)) + +## 2. Repository-databasen + +```sql +CREATE DATABASE SQLInsight; +GO +USE SQLInsight; +CREATE LOGIN [DOMÆNE\svc-sqlinsight-agent$] FROM WINDOWS; +CREATE USER [DOMÆNE\svc-sqlinsight-agent$]; +ALTER ROLE db_owner ADD MEMBER [DOMÆNE\svc-sqlinsight-agent$]; -- agenten opretter og opgraderer skemaet + +CREATE LOGIN [DOMÆNE\svc-sqlinsight-web$] FROM WINDOWS; +CREATE USER [DOMÆNE\svc-sqlinsight-web$]; +ALTER ROLE db_datareader ADD MEMBER [DOMÆNE\svc-sqlinsight-web$]; -- web-UI'et læser kun +``` + +Agenten opretter tabellerne selv ved første start. + +## 3. Rettigheder på de overvågede instanser + +Kør [`db/permissions/grant-least-privilege.sql`](../db/permissions/grant-least-privilege.sql) på hver instans efter at have oprettet agentens login. Agenten bliver aldrig sysadmin. + +## 4. Agenten som Windows-tjeneste + +```powershell +dotnet publish src/SQLInsight.Agent -c Release -r win-x64 --self-contained false -o C:\Program Files\SQLInsight\Agent +``` + +Ret `C:\Program Files\SQLInsight\Agent\appsettings.json`: `SQLInsight:Repository:ConnectionString` og listen `SQLInsight:Instances`. Opret derefter tjenesten: + +```powershell +sc.exe create "SQLInsight Agent" binPath= "\"C:\Program Files\SQLInsight\Agent\SQLInsight.Agent.exe\"" obj= "DOMÆNE\svc-sqlinsight-agent$" start= delayed-auto +sc.exe description "SQLInsight Agent" "Overvåger SQL Server og gemmer fund i SQLInsight-repositoriet." +sc.exe start "SQLInsight Agent" +``` + +For en gMSA angives ingen adgangskode. Loggen kan ses i Windows' Event Viewer under *Application*. + +## 5a. Web-UI'et på IIS + +1. Installér **ASP.NET Core Hosting Bundle** for .NET 10, og kør `iisreset`. +2. Publicér: + ```powershell + dotnet publish src/SQLInsight.Web -c Release -o C:\inetpub\SQLInsight + ``` + Publiceringen danner en `web.config` med ASP.NET Core Module (in-process). +3. Opret en **application pool** med *.NET CLR version = No Managed Code*, og sæt dens identitet til `DOMÆNE\svc-sqlinsight-web$`. +4. Opret et websted, der peger på `C:\inetpub\SQLInsight`, med en **HTTPS-binding** og et certifikat fra jeres interne CA. +5. Under *Authentication*: slå **Windows Authentication** til og **Anonymous Authentication** fra. +6. Ret `appsettings.json`: `SQLInsight:Repository:ConnectionString` (Integrated Security, så app pool-identiteten bruges), eventuelt `SQLInsight:Web:AllowedGroups`, fx `["DOMÆNE\\SQL-Admins"]`. + +## 5b. Web-UI'et som selvstændig Windows-tjeneste (uden IIS) + +Web-UI'et har sin egen webserver (Kestrel) og kan køre som tjeneste på en server uden IIS. + +```powershell +dotnet publish src/SQLInsight.Web -c Release -r win-x64 --self-contained false -o "C:\Program Files\SQLInsight\Web" +``` + +Tilføj et HTTPS-endpoint i `appsettings.json` med et certifikat fra maskinens certifikatlager: + +```json +"Kestrel": { + "Endpoints": { + "Https": { + "Url": "https://*:8443", + "Certificate": { "Subject": "sqlinsight.domæne.local", "Store": "My", "Location": "LocalMachine" } + } + } +} +``` + +Opret tjenesten og en SPN, så Kerberos-login virker: + +```powershell +sc.exe create "SQLInsight Web" binPath= "\"C:\Program Files\SQLInsight\Web\SQLInsight.Web.exe\"" obj= "DOMÆNE\svc-sqlinsight-web$" start= delayed-auto +setspn -S HTTP/sqlinsight.domæne.local DOMÆNE\svc-sqlinsight-web$ +sc.exe start "SQLInsight Web" +``` + +Åbn porten i Windows Firewall for de brugere, der skal se UI'et. + +## Linux (systemd) + +Begge programmer understøtter systemd (`Type=notify`). Windows-login på Linux kræver en Kerberos keytab; se Microsofts dokumentation for Negotiate-autentificering på Linux. + +## Opdatering + +Stop tjenesten (eller app poolen), kopiér de nye filer ind uden at overskrive `appsettings.json`, og start igen. Agenten opgraderer repository-skemaet selv. diff --git a/src/SQLInsight.Agent/Monitoring/InstanceMonitor.cs b/src/SQLInsight.Agent/Monitoring/InstanceMonitor.cs index dbf97cb..8afb51e 100644 --- a/src/SQLInsight.Agent/Monitoring/InstanceMonitor.cs +++ b/src/SQLInsight.Agent/Monitoring/InstanceMonitor.cs @@ -102,7 +102,11 @@ public sealed partial class InstanceMonitor( try { - _previous.TryGetValue(collector.Name, out var previous); + if (!_previous.TryGetValue(collector.Name, out var previous)) + { + previous = await SeedAsync(collector, instanceId, now, cancellationToken).ConfigureAwait(false); + } + var result = await collector.CollectAsync(new CollectorContext(opened.Connection, info, capabilities, now, previous, cancellationToken)).ConfigureAwait(false); _previous[collector.Name] = result; _data.Set(collector.DataType, result); @@ -116,6 +120,21 @@ public sealed partial class InstanceMonitor( } } + /// + /// State a collector would otherwise lose when the agent restarts. Deadlocks continue after the newest one + /// already stored; the others simply start over (cumulative collectors need one extra sample). + /// + private async Task SeedAsync(ICollector collector, int instanceId, DateTimeOffset now, CancellationToken cancellationToken) + { + if (collector is not Collectors.Concurrency.DeadlockCollector) + { + return null; + } + + var latest = await repository.GetLatestDeadlockTimeAsync(instanceId, cancellationToken).ConfigureAwait(false); + return latest is null ? null : new Core.Data.DeadlockSnapshot { CapturedAt = now, NewDeadlocks = [], LastEventTime = latest }; + } + [LoggerMessage(Level = LogLevel.Error, Message = "{Instance}: could not connect")] private static partial void LogConnectFailed(ILogger logger, Exception exception, string instance); diff --git a/src/SQLInsight.Collectors/Performance/CpuCollector.cs b/src/SQLInsight.Collectors/Performance/CpuCollector.cs index b931703..6fe402f 100644 --- a/src/SQLInsight.Collectors/Performance/CpuCollector.cs +++ b/src/SQLInsight.Collectors/Performance/CpuCollector.cs @@ -37,7 +37,10 @@ public sealed class CpuCollector : Collector context.CancellationToken).ConfigureAwait(false); samples.Reverse(); - return new CpuUtilization { CapturedAt = context.Now, Samples = samples }; + var platform = context.Instance.Version.Major >= 14 + ? (await Db.QueryAsync(context.Connection, "SELECT host_platform FROM sys.dm_os_host_info", r => r.NullableString(0), context.CancellationToken).ConfigureAwait(false)).FirstOrDefault() + : "Windows"; + return new CpuUtilization { CapturedAt = context.Now, Samples = samples, HostPlatform = platform }; } /// diff --git a/src/SQLInsight.Core/Data/CpuUtilization.cs b/src/SQLInsight.Core/Data/CpuUtilization.cs index 987bc52..9343d40 100644 --- a/src/SQLInsight.Core/Data/CpuUtilization.cs +++ b/src/SQLInsight.Core/Data/CpuUtilization.cs @@ -8,6 +8,14 @@ public sealed record CpuUtilization { public required DateTimeOffset CapturedAt { get; init; } + /// + /// Windows or Linux (2017+). On Linux the ring buffer's SystemIdle is not reliable (it reads near 0 in + /// containers), so CPU used by other processes cannot be derived. + /// + public string? HostPlatform { get; init; } + + public bool OtherProcessesMeasurable => !string.Equals(HostPlatform, "Linux", StringComparison.OrdinalIgnoreCase); + /// One sample per minute, oldest first. public required IReadOnlyList Samples { get; init; } } diff --git a/src/SQLInsight.Repository/InsightRepository.cs b/src/SQLInsight.Repository/InsightRepository.cs index 9b1e623..2dac9f4 100644 --- a/src/SQLInsight.Repository/InsightRepository.cs +++ b/src/SQLInsight.Repository/InsightRepository.cs @@ -14,6 +14,15 @@ namespace SQLInsight.Repository; /// public sealed partial class InsightRepository(string connectionString) { + static InsightRepository() + { + // Dapper sends DateTime as the legacy datetime type (≈3 ms steps). Since SQL Server 2016, comparing + // datetime with datetime2 uses the exact binary value, so .127 no longer equals .1266667. All columns are + // datetime2, so send datetime2. + SqlMapper.AddTypeMap(typeof(DateTime), System.Data.DbType.DateTime2); + SqlMapper.AddTypeMap(typeof(DateTime?), System.Data.DbType.DateTime2); + } + // PascalCase: OPENJSON ... WITH matches property names case-sensitively. internal static readonly JsonSerializerOptions Json = new(JsonSerializerDefaults.General); @@ -36,6 +45,13 @@ public sealed partial class InsightRepository(string connectionString) return new DateTime(utc.Ticks - (utc.Ticks % TimeSpan.TicksPerSecond), DateTimeKind.Utc); } + /// UTC truncated to milliseconds, matching datetime2(3) (deadlock times must survive a round trip exactly). + internal static DateTime UtcMilliseconds(DateTimeOffset value) + { + var utc = value.UtcDateTime; + return new DateTime(utc.Ticks - (utc.Ticks % TimeSpan.TicksPerMillisecond), DateTimeKind.Utc); + } + /// Registers a successful contact with an instance and returns its id. public async Task UpsertInstanceAsync( string name, InstanceInfo info, string provider, bool usedLegacyFallback, DateTimeOffset seenAt, CancellationToken cancellationToken = default) @@ -240,11 +256,10 @@ public sealed partial class InsightRepository(string connectionString) } private static Task SaveCpuAsync(SqlConnection connection, int instanceId, CpuUtilization cpu) => - InsertMetricsAsync(connection, instanceId, cpu.Samples.SelectMany(s => new[] - { - (Metrics.CpuSqlServer, s.Time, (double)s.SqlServerPercent), - (Metrics.CpuOther, s.Time, (double)s.OtherProcessesPercent), - })); + InsertMetricsAsync(connection, instanceId, cpu.Samples.SelectMany(s => + cpu.OtherProcessesMeasurable + ? new[] { (Metrics.CpuSqlServer, s.Time, (double)s.SqlServerPercent), (Metrics.CpuOther, s.Time, (double)s.OtherProcessesPercent) } + : new[] { (Metrics.CpuSqlServer, s.Time, (double)s.SqlServerPercent) })); /// Blocking shorter than this is normal and not stored. public const long BlockingThresholdMs = 5000; @@ -298,12 +313,13 @@ public sealed partial class InsightRepository(string connectionString) foreach (var deadlock in snapshot.NewDeadlocks) { await connection.ExecuteAsync(""" - INSERT insight.Deadlocks (InstanceId, OccurredAt, ProcessesJson, GraphXml) - VALUES (@instanceId, @at, @processes, @graph); + IF NOT EXISTS (SELECT 1 FROM insight.Deadlocks WHERE InstanceId = @instanceId AND OccurredAt = @at AND GraphXml = @graph) + INSERT insight.Deadlocks (InstanceId, OccurredAt, ProcessesJson, GraphXml) + VALUES (@instanceId, @at, @processes, @graph); """, new { instanceId, - at = Utc(deadlock.Time), + at = UtcMilliseconds(deadlock.Time), processes = JsonSerializer.Serialize(deadlock.Processes, Json), graph = deadlock.GraphXml, }).ConfigureAwait(false); @@ -311,6 +327,21 @@ public sealed partial class InsightRepository(string connectionString) } } +public sealed partial class InsightRepository +{ + /// + /// The newest stored deadlock for an instance, so a restarted agent continues after it instead of reporting + /// deadlocks it has already stored. + /// + public async Task GetLatestDeadlockTimeAsync(int instanceId, CancellationToken cancellationToken = default) + { + await using var connection = await OpenAsync(cancellationToken).ConfigureAwait(false); + var latest = await connection.ExecuteScalarAsync( + "SELECT MAX(OccurredAt) FROM insight.Deadlocks WHERE InstanceId = @instanceId;", new { instanceId }).ConfigureAwait(false); + return latest is { } value ? new DateTimeOffset(DateTime.SpecifyKind(value, DateTimeKind.Utc)) : null; + } +} + public static class Metrics { public const string CpuSqlServer = "cpu.sqlserver"; diff --git a/src/SQLInsight.Repository/SQLInsight.Repository.csproj b/src/SQLInsight.Repository/SQLInsight.Repository.csproj index 782372b..0d679c9 100644 --- a/src/SQLInsight.Repository/SQLInsight.Repository.csproj +++ b/src/SQLInsight.Repository/SQLInsight.Repository.csproj @@ -10,6 +10,9 @@ + + + diff --git a/src/SQLInsight.Rules/Performance/ResourceRules.cs b/src/SQLInsight.Rules/Performance/ResourceRules.cs index 7532f7f..f3407ef 100644 --- a/src/SQLInsight.Rules/Performance/ResourceRules.cs +++ b/src/SQLInsight.Rules/Performance/ResourceRules.cs @@ -97,14 +97,15 @@ public sealed class CpuRule : Rule throw new DataUnavailableException("CPU-historikken har endnu for få målinger (scheduler monitor skriver én pr. minut)."); } + var cpu = context.Data.Get(); var sql = samples.Average(s => s.SqlServerPercent); - var other = samples.Average(s => s.OtherProcessesPercent); + var other = cpu.OtherProcessesMeasurable ? samples.Average(s => s.OtherProcessesPercent) : 0; var findings = new List(); var evidence = new[] { new Evidence("Periode", $"{samples.Count} min"), new Evidence("SQL Server gns./maks.", $"{Format.Number(sql)} % / {samples.Max(s => s.SqlServerPercent)} %"), - new Evidence("Andre processer gns.", $"{Format.Number(other)} %"), + new Evidence("Andre processer gns.", cpu.OtherProcessesMeasurable ? $"{Format.Number(other)} %" : "kan ikke måles på Linux"), }; if (sql >= 75) diff --git a/src/SQLInsight.Web/Components/App.razor b/src/SQLInsight.Web/Components/App.razor new file mode 100644 index 0000000..d3ef523 --- /dev/null +++ b/src/SQLInsight.Web/Components/App.razor @@ -0,0 +1,18 @@ + + + + + + + + + + @* Applies a saved theme before first paint. Light is the default; dark only when chosen. *@ + + + + + + + + diff --git a/src/SQLInsight.Web/Components/Layout/MainLayout.razor b/src/SQLInsight.Web/Components/Layout/MainLayout.razor new file mode 100644 index 0000000..d59d2c3 --- /dev/null +++ b/src/SQLInsight.Web/Components/Layout/MainLayout.razor @@ -0,0 +1,40 @@ +@inherits LayoutComponentBase + +
+ + +
+
+ Gratis og open source · kører on-prem + +
+
+ @Body +
+ +
+
diff --git a/src/SQLInsight.Web/Components/Pages/AllFindings.razor b/src/SQLInsight.Web/Components/Pages/AllFindings.razor new file mode 100644 index 0000000..77b2acb --- /dev/null +++ b/src/SQLInsight.Web/Components/Pages/AllFindings.razor @@ -0,0 +1,16 @@ +@page "/fund" +@inject InsightRepository Repository + +Alle fund · SQLInsight Pro + +

Alle aktive fund

+

Sorteret efter alvor på tværs af alle instanser.

+
+ +
+ +@code { + private IReadOnlyList _findings = []; + + protected override async Task OnInitializedAsync() => _findings = await Repository.GetActiveFindingsAsync(); +} diff --git a/src/SQLInsight.Web/Components/Pages/Error.razor b/src/SQLInsight.Web/Components/Pages/Error.razor new file mode 100644 index 0000000..665f763 --- /dev/null +++ b/src/SQLInsight.Web/Components/Pages/Error.razor @@ -0,0 +1,5 @@ +@page "/fejl" + +Fejl · SQLInsight Pro +

Der opstod en fejl

+

Fejlen er logget. Tjek, at repository-databasen kan nås.

diff --git a/src/SQLInsight.Web/Components/Pages/FindingDetail.razor b/src/SQLInsight.Web/Components/Pages/FindingDetail.razor new file mode 100644 index 0000000..13f1de3 --- /dev/null +++ b/src/SQLInsight.Web/Components/Pages/FindingDetail.razor @@ -0,0 +1,76 @@ +@page "/fund/{Id:long}" +@inject InsightRepository Repository +@inject Display Display + +@if (_finding is null) +{ + Ukendt fund · SQLInsight Pro +

Ukendt fund

+ return; +} + +@_finding.Title · SQLInsight Pro + +

Instanser / @_finding.InstanceName / @_finding.RuleId

+

@_finding.Title

+

+ @if (_finding.ResolvedAt is { } resolved) + { + Løst @Display.Time(resolved) · + } + Set første gang @Display.Time(_finding.FirstSeenAt) · senest @Display.Time(_finding.LastSeenAt) + @if (!string.IsNullOrEmpty(_finding.Subject)) { · @_finding.Subject } +

+ +
+

Hvorfor er det et problem?

+

@_finding.Explanation

+
+ +@if (_finding.Evidence.Count > 0) +{ +
+

Målinger

+ + @foreach (var e in _finding.Evidence) + { + + } +
@e.Name@e.Value
+
+} + +
+

Hvad skal jeg gøre?

+

@_finding.Recommendation

+ @if (!string.IsNullOrEmpty(_finding.FixScript)) + { +

Forslag til script

+

Gennemgå og test scriptet, før det køres. SQLInsight Pro kører det aldrig selv.

+
+ +
@_finding.FixScript
+
+ } +
+ +@if (_finding.References.Count > 0) +{ +
+

Læs mere

+
    + @foreach (var r in _finding.References) + { +
  • @r.Title
  • + } +
+
+} + +@code { + [Parameter] public long Id { get; set; } + + private StoredFinding? _finding; + + protected override async Task OnInitializedAsync() => _finding = await Repository.GetFindingAsync(Id); +} diff --git a/src/SQLInsight.Web/Components/Pages/Home.razor b/src/SQLInsight.Web/Components/Pages/Home.razor new file mode 100644 index 0000000..a2d464d --- /dev/null +++ b/src/SQLInsight.Web/Components/Pages/Home.razor @@ -0,0 +1,77 @@ +@page "/" +@inject InsightRepository Repository +@inject Display Display + +SQLInsight Pro + +

Overblik

+

Status for alle overvågede SQL Server-instanser.

+ +@if (_instances.Count == 0) +{ +
+

Der er endnu ingen data. Tjek, at SQLInsight Agent kører og har instanser under SQLInsight:Instances i sin konfiguration.

+
+} +else +{ +
+
@_instances.Countinstanser
+
@_instances.Sum(i => i.Critical)kritiske fund
+
@_instances.Sum(i => i.High)høje fund
+
@_instances.Count(i => i.IsFailing)kan ikke nås
+
@_instances.Sum(i => i.NotMeasurable)regler ikke målbare
+
+ +
+

Instanser

sorteret efter alvor
+ + + + + + @foreach (var i in _instances.OrderByDescending(i => i.IsFailing).ThenByDescending(i => i.WorstSeverity ?? (Severity)(-1)).ThenBy(i => i.Name)) + { + + + + + + + + + } + +
StatusInstansVersionFundIkke målbarSidst set
+ @if (i.IsFailing) + { + Fejler + } + else + { + + } + @i.Name
@i.ServerName
@(i.ProductVersion is null ? "–" : Display.Release(i.ProductVersion))
@i.ProductVersion @i.ProductLevel @i.ProductUpdateLevel
+ @if (i.Critical > 0) { } + @if (i.High > 0) { } + @if (i.Medium > 0) { } + @if (i.Low > 0) { } + @i.NotMeasurable@Display.Ago(i.LastSeenAt)
+
+ +
+

Kritiske og høje fund

Se alle fund
+ +
+} + +@code { + private IReadOnlyList _instances = []; + private IReadOnlyList _urgent = []; + + protected override async Task OnInitializedAsync() + { + _instances = await Repository.GetInstancesAsync(); + _urgent = (await Repository.GetActiveFindingsAsync()).Where(f => f.Severity >= Severity.High).ToList(); + } +} diff --git a/src/SQLInsight.Web/Components/Pages/Instance.razor b/src/SQLInsight.Web/Components/Pages/Instance.razor new file mode 100644 index 0000000..644e84b --- /dev/null +++ b/src/SQLInsight.Web/Components/Pages/Instance.razor @@ -0,0 +1,235 @@ +@page "/instanser/{Name}" +@inject InsightRepository Repository +@inject Display Display + +@if (_instance is null) +{ + Ukendt instans · SQLInsight Pro +

Ukendt instans

+

Der findes ingen instans med navnet @Name.

+ return; +} + +@_instance.Name · SQLInsight Pro + +

Instanser / @_instance.Name

+

@_instance.Name

+

+ @_instance.ServerName · @Display.Release(_instance.ProductVersion) (@_instance.ProductVersion @_instance.ProductLevel @_instance.ProductUpdateLevel) · @_instance.Edition + · sidst set @Display.Ago(_instance.LastSeenAt) +

+ +@if (_instance.IsFailing) +{ +
+ Seneste forsøg på at nå instansen fejlede (@Display.Time(_instance.LastErrorAt)): +
@_instance.LastError
+
+} +@if (_instance.UsedLegacyFallback) +{ +
Forbindelsen bruger legacy ODBC-laget, fordi instansen er for gammel til SqlClient. Krypteringen kan være svagere.
+} + +
+

Aktive fund

@_findings.Count fund
+ +
+ +

Belastning, seneste 24 timer

+
+
+
+
+
+
+ +
+

Største ventetider, seneste 24 timer

uden harmløse baggrundsventetider
+@if (_waits.Count == 0) +{ +

Endnu ikke nok målinger (ventetider kræver to målinger).

+} +else +{ + var total = Math.Max(1, _waits.Sum(w => w.WaitTimeMs)); + + + + @foreach (var w in _waits) + { + + + + + + + + + } + +
Wait typeKategoriVentetidAndelGns. pr. waitSignal
@w.WaitType@w.Category@Display.Number(w.WaitTimeMs / 1000.0, 1) s @Display.Number(100.0 * w.WaitTimeMs / total) %@Display.Number(w.WaitingTasks == 0 ? 0 : (double)w.WaitTimeMs / w.WaitingTasks, 1) ms@Display.Number(w.WaitTimeMs == 0 ? 0 : 100.0 * w.SignalWaitTimeMs / w.WaitTimeMs) %
+} +
+ +
+

I/O-latens pr. fil, seneste 24 timer

+@if (_files.Count == 0) +{ +

Endnu ikke nok målinger.

+} +else +{ + + + + @foreach (var f in _files.Take(25)) + { + + + + + + + + + + } + +
DatabaseFilTypeLæsningerGns. læsSkrivningerGns. skriv
@f.DatabaseName@f.FileId@f.FileType@Display.Number(f.Reads)@Ms(f.AverageReadMs)@Display.Number(f.Writes)@Ms(f.AverageWriteMs)
+} +
+ +
+
+

Blocking, seneste 24 timer

+ @if (_blocking.Count == 0) + { +

Ingen blocking over 5 sekunder.

+ } + else + { + + + + @foreach (var b in _blocking.Take(20)) + { + var head = b.Sessions.FirstOrDefault(); + + + + + + + } + +
TidspunktHead blockerBlokeredeLængste
@Display.Time(b.SampledAt)@b.HeadSessionId @head?.Status @head?.ProgramName@b.BlockedCount@Display.Number(b.MaxWaitMs / 1000.0) s
+ } +
+
+

Deadlocks, seneste 7 dage

+ @if (_deadlocks.Count == 0) + { +

Ingen deadlocks registreret.

+ } + else + { + + + + @foreach (var d in _deadlocks.Take(20)) + { + var victim = d.Processes.FirstOrDefault(p => p.IsVictim); + + + + + + } + +
TidspunktOfferGraf
@Display.Time(d.OccurredAt)session @victim?.SessionId @victim?.ClientApp.xdl
+ } +
+
+ +
+

Ikke målbart på denne instans

+@if (_notMeasurable.Count == 0) +{ +

Alle regler kunne evalueres.

+} +else +{ +

Disse regler kunne ikke vurderes. Det er ikke det samme som "OK".

+ + + + @foreach (var r in _notMeasurable) + { + + } + +
RegelÅrsag
@r.RuleId@r.RuleTitle@r.Reason
+} +
+ +
+

Løst de seneste 30 dage

+@if (_resolved.Count == 0) +{ +

Ingen.

+} +else +{ + + + + @foreach (var f in _resolved) + { + + } + +
FundAktivt fraLøst
@f.Title@Display.Time(f.FirstSeenAt)@Display.Time(f.ResolvedAt)
+} +
+ +@code { + [Parameter] public string Name { get; set; } = string.Empty; + + private InstanceOverview? _instance; + private IReadOnlyList _findings = []; + private IReadOnlyList _resolved = []; + private IReadOnlyList _notMeasurable = []; + private IReadOnlyList _cpuSql = [], _cpuOther = [], _batches = [], _ple = []; + private IReadOnlyList _waits = []; + private IReadOnlyList _files = []; + private IReadOnlyList _blocking = []; + private IReadOnlyList _deadlocks = []; + + protected override async Task OnInitializedAsync() + { + _instance = await Repository.GetInstanceAsync(Name); + if (_instance is null) + { + return; + } + + var id = _instance.InstanceId; + var day = DateTimeOffset.UtcNow.AddDays(-1); + _findings = await Repository.GetActiveFindingsAsync(id); + _resolved = await Repository.GetRecentlyResolvedAsync(id, 30); + _notMeasurable = (await Repository.GetRuleStatesAsync(id)).Where(r => r.Outcome is RuleOutcome.NotMeasurable or RuleOutcome.Error).ToList(); + _cpuSql = await Repository.GetMetricAsync(id, Metrics.CpuSqlServer, day); + _cpuOther = await Repository.GetMetricAsync(id, Metrics.CpuOther, day); + _batches = await Repository.GetMetricAsync(id, Metrics.BatchRequestsPerSecond, day); + _ple = await Repository.GetMetricAsync(id, Metrics.PageLifeExpectancy, day); + _waits = await Repository.GetTopWaitsAsync(id, day, 12); + _files = await Repository.GetFileLatencyAsync(id, day); + _blocking = await Repository.GetBlockingAsync(id, day); + _deadlocks = await Repository.GetDeadlocksAsync(id, DateTimeOffset.UtcNow.AddDays(-7)); + } + + private static string Ms(double? value) => value is { } v ? $"{Display.Number(v, 1)} ms" : "–"; + + private static string LatencyClass(double? value, double threshold) => value >= threshold ? "bad" : string.Empty; +} diff --git a/src/SQLInsight.Web/Components/Pages/NotFound.razor b/src/SQLInsight.Web/Components/Pages/NotFound.razor new file mode 100644 index 0000000..0e3e4c6 --- /dev/null +++ b/src/SQLInsight.Web/Components/Pages/NotFound.razor @@ -0,0 +1,5 @@ +@page "/ikke-fundet" + +Ikke fundet · SQLInsight Pro +

Siden findes ikke

+

Tilbage til oversigten

diff --git a/src/SQLInsight.Web/Components/Routes.razor b/src/SQLInsight.Web/Components/Routes.razor new file mode 100644 index 0000000..b06c87a --- /dev/null +++ b/src/SQLInsight.Web/Components/Routes.razor @@ -0,0 +1,5 @@ + + + + + diff --git a/src/SQLInsight.Web/Components/Shared/FindingList.razor b/src/SQLInsight.Web/Components/Shared/FindingList.razor new file mode 100644 index 0000000..f1d8eee --- /dev/null +++ b/src/SQLInsight.Web/Components/Shared/FindingList.razor @@ -0,0 +1,32 @@ +@inject Display Display + +@if (Findings.Count == 0) +{ +

@Empty

+} +else +{ + + + @if (ShowInstance) { } + + + @foreach (var f in Findings) + { + + + @if (ShowInstance) { } + + + + + } + +
AlvorInstansFundRegelSet første gang
@f.InstanceName@f.Title@f.RuleId@Display.Ago(f.FirstSeenAt)
+} + +@code { + [Parameter, EditorRequired] public IReadOnlyList Findings { get; set; } = []; + [Parameter] public bool ShowInstance { get; set; } + [Parameter] public string Empty { get; set; } = "Ingen fund."; +} diff --git a/src/SQLInsight.Web/Components/Shared/Icon.razor b/src/SQLInsight.Web/Components/Shared/Icon.razor new file mode 100644 index 0000000..e95dede --- /dev/null +++ b/src/SQLInsight.Web/Components/Shared/Icon.razor @@ -0,0 +1,40 @@ +@* Simple stroke icons (24×24, currentColor). *@ + + +@code { + [Parameter, EditorRequired] public string Name { get; set; } = string.Empty; +} diff --git a/src/SQLInsight.Web/Components/Shared/SeverityBadge.razor b/src/SQLInsight.Web/Components/Shared/SeverityBadge.razor new file mode 100644 index 0000000..79026c4 --- /dev/null +++ b/src/SQLInsight.Web/Components/Shared/SeverityBadge.razor @@ -0,0 +1,6 @@ +@(Severity is { } s ? Display.SeverityName(s) : "OK")@(Count is { } c ? $" {c}" : "") + +@code { + [Parameter] public Severity? Severity { get; set; } + [Parameter] public int? Count { get; set; } +} diff --git a/src/SQLInsight.Web/Components/Shared/Sparkline.razor b/src/SQLInsight.Web/Components/Shared/Sparkline.razor new file mode 100644 index 0000000..13d52ed --- /dev/null +++ b/src/SQLInsight.Web/Components/Shared/Sparkline.razor @@ -0,0 +1,50 @@ +@* A small inline SVG line chart; no JavaScript. *@ +@if (Points.Count < 2) +{ +

@Label: @Empty

+} +else +{ +
+ + @foreach (var line in GridLines) + { + + } + + +
+ @Label + gns. @Display.Number(Points.Average(p => p.Value), Decimals)@Unit · maks. @Display.Number(Points.Max(p => p.Value), Decimals)@Unit +
+
+} + +@code { + private const int Width = 600; + private const int Height = 90; + + [Parameter, EditorRequired] public IReadOnlyList Points { get; set; } = []; + [Parameter] public string Label { get; set; } = string.Empty; + [Parameter] public string Unit { get; set; } = string.Empty; + [Parameter] public double? Max { get; set; } + [Parameter] public int Decimals { get; set; } + [Parameter] public string Empty { get; set; } = "endnu ikke nok målinger."; + + private double Top => Max ?? Math.Max(1, Points.Max(p => p.Value) * 1.1); + + private IEnumerable GridLines => [Top * 0.25, Top * 0.5, Top * 0.75]; + + private string Y(double value) => (Height - value / Top * Height).ToString("0.#", System.Globalization.CultureInfo.InvariantCulture); + + private string Path + { + get + { + var start = Points[0].At.Ticks; + var span = Math.Max(1, Points[^1].At.Ticks - start); + return string.Join(' ', Points.Select(p => + ((double)(p.At.Ticks - start) / span * Width).ToString("0.#", System.Globalization.CultureInfo.InvariantCulture) + "," + Y(p.Value))); + } + } +} diff --git a/src/SQLInsight.Web/Components/_Imports.razor b/src/SQLInsight.Web/Components/_Imports.razor new file mode 100644 index 0000000..8f223d9 --- /dev/null +++ b/src/SQLInsight.Web/Components/_Imports.razor @@ -0,0 +1,12 @@ +@using System.Net.Http +@using Microsoft.AspNetCore.Components +@using Microsoft.AspNetCore.Components.Routing +@using Microsoft.AspNetCore.Components.Web +@using SQLInsight.Core.Data +@using SQLInsight.Core.Findings +@using SQLInsight.Repository +@using SQLInsight.Rules.Engine +@using SQLInsight.Web +@using SQLInsight.Web.Components +@using SQLInsight.Web.Components.Layout +@using SQLInsight.Web.Components.Shared diff --git a/src/SQLInsight.Web/Display.cs b/src/SQLInsight.Web/Display.cs new file mode 100644 index 0000000..d2395e8 --- /dev/null +++ b/src/SQLInsight.Web/Display.cs @@ -0,0 +1,60 @@ +using System.Globalization; +using Microsoft.Extensions.Options; +using SQLInsight.Core.Findings; +using SQLInsight.Core.Instances; + +namespace SQLInsight.Web; + +/// +/// Formatting for the UI: times in the configured time zone, Danish number format, severity names. +/// +public sealed class Display(IOptions options) +{ + private static readonly CultureInfo Danish = CultureInfo.GetCultureInfo("da-DK"); + + private readonly TimeZoneInfo _zone = options.Value.TimeZone is { Length: > 0 } id + ? TimeZoneInfo.FindSystemTimeZoneById(id) + : TimeZoneInfo.Local; + + public string Time(DateTime? utc) => utc is { } value + ? TimeZoneInfo.ConvertTimeFromUtc(DateTime.SpecifyKind(value, DateTimeKind.Utc), _zone).ToString("dd-MM-yyyy HH:mm", Danish) + : "–"; + + public string Ago(DateTime? utc) + { + if (utc is not { } value) + { + return "aldrig"; + } + + var age = DateTime.UtcNow - value; + return age.TotalMinutes < 2 ? "lige nu" + : age.TotalHours < 2 ? $"{age.TotalMinutes:0} min. siden" + : age.TotalDays < 2 ? $"{age.TotalHours:0} timer siden" + : $"{age.TotalDays:0} dage siden"; + } + + public static string Number(double value, int decimals = 0) => value.ToString("N" + decimals, Danish); + + public static string SeverityName(Severity severity) => severity switch + { + Severity.Critical => "Kritisk", + Severity.High => "Høj", + Severity.Medium => "Middel", + Severity.Low => "Lav", + _ => "Info", + }; + + public static string SeverityClass(Severity? severity) => severity switch + { + Severity.Critical => "sev-critical", + Severity.High => "sev-high", + Severity.Medium => "sev-medium", + Severity.Low => "sev-low", + Severity.Info => "sev-info", + _ => "sev-ok", + }; + + public static string Release(string? productVersion) => + SqlServerVersion.TryParse(productVersion, out var version) ? version.Release.DisplayName() : "Ukendt version"; +} diff --git a/src/SQLInsight.Web/Program.cs b/src/SQLInsight.Web/Program.cs index 5d37520..797fb03 100644 --- a/src/SQLInsight.Web/Program.cs +++ b/src/SQLInsight.Web/Program.cs @@ -1,7 +1,89 @@ -// On-prem web UI (dashboard, findings, history). Placeholder until Fase 1. +using Microsoft.AspNetCore.Authentication.Negotiate; +using Microsoft.AspNetCore.Authorization; +using SQLInsight.Repository; +using SQLInsight.Web; +using SQLInsight.Web.Components; + var builder = WebApplication.CreateBuilder(args); + +// Runs as a Windows service with its own Kestrel web server, or behind IIS (ASP.NET Core Module), or +// as a systemd service on Linux. Each call is a no-op when not hosted that way. +builder.Services.AddWindowsService(o => o.ServiceName = "SQLInsight Web"); +builder.Services.AddSystemd(); + +builder.Services.Configure(builder.Configuration.GetSection(WebOptions.SectionName)); +var web = builder.Configuration.GetSection(WebOptions.SectionName).Get() ?? new WebOptions(); + +var connectionString = builder.Configuration["SQLInsight:Repository:ConnectionString"]; +if (string.IsNullOrWhiteSpace(connectionString)) +{ + throw new InvalidOperationException("SQLInsight:Repository:ConnectionString mangler. Angiv forbindelsen til repository-databasen."); +} + +builder.Services.AddSingleton(new InsightRepository(connectionString)); +builder.Services.AddSingleton(); + +// Danish text (æ, ø, å) as characters rather than æ entities. HTML-significant characters are still encoded. +builder.Services.AddSingleton(System.Text.Encodings.Web.HtmlEncoder.Create(System.Text.Unicode.UnicodeRanges.All)); +builder.Services.AddRazorComponents(); + +var windowsAuth = string.Equals(web.Authentication, "Windows", StringComparison.OrdinalIgnoreCase); +if (windowsAuth) +{ + builder.Services.AddAuthentication(NegotiateDefaults.AuthenticationScheme).AddNegotiate(); + builder.Services.AddAuthorization(options => + { + var policy = new AuthorizationPolicyBuilder().RequireAuthenticatedUser(); + if (web.AllowedGroups.Count > 0) + { + policy.RequireAssertion(ctx => web.AllowedGroups.Any(ctx.User.IsInRole)); + } + + options.FallbackPolicy = policy.Build(); + }); +} +else if (!builder.Environment.IsDevelopment()) +{ + throw new InvalidOperationException("SQLInsight:Web:Authentication = None er kun tilladt i Development. Web-UI'et viser oplysninger om jeres SQL Servere."); +} + var app = builder.Build(); -app.MapGet("/health", () => Results.Ok(new { status = "ok" })); +if (!app.Environment.IsDevelopment()) +{ + app.UseExceptionHandler("/fejl", createScopeForErrors: true); + app.UseHsts(); +} +app.Use(async (context, next) => +{ + context.Response.Headers.XContentTypeOptions = "nosniff"; + context.Response.Headers.XFrameOptions = "DENY"; + context.Response.Headers["Referrer-Policy"] = "no-referrer"; + context.Response.Headers.ContentSecurityPolicy = "default-src 'self'; style-src 'self'; script-src 'self'; img-src 'self' data:"; + await next(); +}); + +if (windowsAuth) +{ + app.UseAuthentication(); + app.UseAuthorization(); +} + +app.UseAntiforgery(); +app.MapStaticAssets(); +app.MapGet("/health", () => Results.Ok(new { status = "ok" })).AllowAnonymous(); + +// Deadlock graph as .xdl, which SSMS opens as a graphical deadlock graph. +app.MapGet("/deadlocks/{id:long}.xdl", async (long id, InsightRepository repository, CancellationToken ct) => + await repository.GetDeadlockAsync(id, ct) is { } deadlock + ? Results.File(System.Text.Encoding.UTF8.GetBytes(deadlock.GraphXml), "application/xml", $"deadlock-{id}.xdl") + : Results.NotFound()); + +app.MapRazorComponents(); + +// The web UI only reads. The agent owns the schema and migrates it, so the UI's login needs no more than db_datareader. app.Run(); + +/// Entry point, visible to integration tests. +public partial class Program; diff --git a/src/SQLInsight.Web/Properties/launchSettings.json b/src/SQLInsight.Web/Properties/launchSettings.json deleted file mode 100644 index 9138b24..0000000 --- a/src/SQLInsight.Web/Properties/launchSettings.json +++ /dev/null @@ -1,23 +0,0 @@ -{ - "$schema": "https://json.schemastore.org/launchsettings.json", - "profiles": { - "http": { - "commandName": "Project", - "dotnetRunMessages": true, - "launchBrowser": true, - "applicationUrl": "http://localhost:5225", - "environmentVariables": { - "ASPNETCORE_ENVIRONMENT": "Development" - } - }, - "https": { - "commandName": "Project", - "dotnetRunMessages": true, - "launchBrowser": true, - "applicationUrl": "https://localhost:7224;http://localhost:5225", - "environmentVariables": { - "ASPNETCORE_ENVIRONMENT": "Development" - } - } - } -} diff --git a/src/SQLInsight.Web/SQLInsight.Web.csproj b/src/SQLInsight.Web/SQLInsight.Web.csproj index 71968bf..213b2b1 100644 --- a/src/SQLInsight.Web/SQLInsight.Web.csproj +++ b/src/SQLInsight.Web/SQLInsight.Web.csproj @@ -4,5 +4,11 @@ + + + + + + diff --git a/src/SQLInsight.Web/WebOptions.cs b/src/SQLInsight.Web/WebOptions.cs new file mode 100644 index 0000000..cb31b2f --- /dev/null +++ b/src/SQLInsight.Web/WebOptions.cs @@ -0,0 +1,15 @@ +namespace SQLInsight.Web; + +public sealed class WebOptions +{ + public const string SectionName = "SQLInsight:Web"; + + /// Windows (Negotiate/Kerberos) or None. None is for development only. + public string Authentication { get; set; } = "Windows"; + + /// Windows groups allowed to use the UI (e.g. DOMAIN\SQL-Admins). Empty: any authenticated user. + public IList AllowedGroups { get; } = []; + + /// Time zone for display, e.g. Europe/Copenhagen. Defaults to the server's local time zone. + public string? TimeZone { get; set; } +} diff --git a/src/SQLInsight.Web/appsettings.Development.json b/src/SQLInsight.Web/appsettings.Development.json index 0c208ae..dfca35d 100644 --- a/src/SQLInsight.Web/appsettings.Development.json +++ b/src/SQLInsight.Web/appsettings.Development.json @@ -4,5 +4,10 @@ "Default": "Information", "Microsoft.AspNetCore": "Warning" } + }, + "SQLInsight": { + "Web": { + "Authentication": "None" + } } } diff --git a/src/SQLInsight.Web/appsettings.json b/src/SQLInsight.Web/appsettings.json index 10f68b8..df471aa 100644 --- a/src/SQLInsight.Web/appsettings.json +++ b/src/SQLInsight.Web/appsettings.json @@ -5,5 +5,15 @@ "Microsoft.AspNetCore": "Warning" } }, - "AllowedHosts": "*" + "AllowedHosts": "*", + "SQLInsight": { + "Repository": { + "ConnectionString": "Server=sqlmon01.eksempel.local;Database=SQLInsight;Integrated Security=true;Encrypt=true" + }, + "Web": { + "Authentication": "Windows", + "AllowedGroups": [], + "TimeZone": "Europe/Copenhagen" + } + } } diff --git a/src/SQLInsight.Web/wwwroot/app.css b/src/SQLInsight.Web/wwwroot/app.css new file mode 100644 index 0000000..fb8f24b --- /dev/null +++ b/src/SQLInsight.Web/wwwroot/app.css @@ -0,0 +1,156 @@ +/* SQLInsight Pro design system: light first, neutral surfaces, one accent, semantic severity colours. */ +@font-face { + font-family: "Inter"; + src: url("fonts/inter-latin-wght-normal.woff2") format("woff2"); + font-weight: 100 900; font-style: normal; font-display: swap; + unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; +} +@font-face { + font-family: "Inter"; + src: url("fonts/inter-latin-ext-wght-normal.woff2") format("woff2"); + font-weight: 100 900; font-style: normal; font-display: swap; + unicode-range: U+0100-02AF, U+0304, U+0308, U+0329, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF; +} + +:root { + --bg: #f6f7f9; + --surface: #ffffff; + --surface-2: #f1f3f6; + --border: #e4e7ec; + --text: #101828; + --text-2: #475467; + --text-3: #98a2b3; + --accent: #0e7490; /* deep teal */ + --accent-soft: #e0f2f6; + --accent-text: #0b5c72; + --critical: #d92d20; --critical-soft: #fee4e2; + --high: #e04f16; --high-soft: #ffead5; + --medium: #b54708; --medium-soft: #fef0c7; + --low: #1570ef; --low-soft: #d1e9ff; + --info: #667085; --info-soft: #f2f4f7; + --ok: #079455; --ok-soft: #dcfae6; + --radius: 12px; + --shadow: 0 1px 2px rgba(16, 24, 40, .05), 0 1px 3px rgba(16, 24, 40, .06); + --sidebar: 256px; + font-family: "Inter", "Segoe UI", system-ui, -apple-system, sans-serif; + font-feature-settings: "cv11", "ss01"; + color-scheme: light; +} + +:root[data-theme="dark"] { + --bg: #0c111d; --surface: #161b26; --surface-2: #1f2533; --border: #2a3140; + --text: #f5f5f6; --text-2: #cecfd2; --text-3: #85888e; + --accent: #22b8cf; --accent-soft: #0e2d36; --accent-text: #7dd9e8; + --critical-soft: #3b1512; --high-soft: #3a1d0d; --medium-soft: #3a2a07; --low-soft: #0f2744; --info-soft: #1f2533; --ok-soft: #0b2e1d; + --shadow: none; + color-scheme: dark; +} + +* { box-sizing: border-box; } +html { -webkit-text-size-adjust: 100%; } +body { margin: 0; background: var(--bg); color: var(--text); font-size: 14px; line-height: 1.55; } +a { color: var(--accent); text-decoration: none; } +a:hover { text-decoration: underline; } +.icon { width: 18px; height: 18px; flex: none; } + +/* Shell */ +.shell { display: grid; grid-template-columns: var(--sidebar) 1fr; min-height: 100vh; background: linear-gradient(to right, var(--surface) calc(var(--sidebar) - 1px), var(--border) calc(var(--sidebar) - 1px), var(--border) var(--sidebar), transparent var(--sidebar)); } +.sidebar { position: sticky; top: 0; height: 100vh; display: flex; flex-direction: column; gap: 1.5rem; padding: 1.25rem 1rem; } +.brand { display: flex; align-items: center; gap: .6rem; color: var(--text); font-size: 1.05rem; padding: 0 .5rem; } +.brand:hover { text-decoration: none; } +.brand strong { color: var(--accent); } +.logo { display: grid; place-items: center; width: 32px; height: 32px; border-radius: 9px; background: linear-gradient(135deg, var(--accent), #155e75); color: #fff; font-weight: 700; font-size: .8rem; letter-spacing: .02em; } +.nav { display: flex; flex-direction: column; gap: 2px; } +.nav-label { font-size: .72rem; font-weight: 600; text-transform: uppercase; letter-spacing: .06em; color: var(--text-3); padding: .9rem .75rem .35rem; } +.nav a { display: flex; align-items: center; gap: .65rem; padding: .5rem .75rem; border-radius: 8px; color: var(--text-2); font-weight: 500; } +.nav a:hover { background: var(--surface-2); text-decoration: none; color: var(--text); } +.nav a.active { background: var(--accent-soft); color: var(--accent-text); } +.support-card { margin-top: auto; padding: 1rem; border-radius: var(--radius); background: var(--surface-2); border: 1px solid var(--border); display: flex; flex-direction: column; gap: .35rem; } +.support-card .icon { color: var(--accent); width: 22px; height: 22px; } +.support-card p { margin: 0; color: var(--text-2); font-size: .82rem; } +.support-card a { font-weight: 600; font-size: .85rem; } +.main { display: flex; flex-direction: column; min-width: 0; } +.topbar { display: flex; justify-content: space-between; align-items: center; padding: .75rem 2rem; border-bottom: 1px solid var(--border); background: color-mix(in srgb, var(--surface) 85%, transparent); backdrop-filter: blur(8px); position: sticky; top: 0; z-index: 5; } +.topbar-note { color: var(--text-3); font-size: .82rem; } +.theme-toggle { display: inline-flex; align-items: center; gap: .4rem; border: 1px solid var(--border); background: var(--surface); color: var(--text-2); border-radius: 8px; padding: .35rem .7rem; font: inherit; font-size: .82rem; cursor: pointer; } +.theme-toggle:hover { color: var(--text); background: var(--surface-2); } +.page { width: 100%; max-width: 1320px; padding: 1.75rem 2rem 2rem; } +.footer { color: var(--text-3); font-size: .8rem; padding: 1rem 2rem 2rem; } + +/* Typography */ +h1 { font-size: 1.6rem; line-height: 1.25; letter-spacing: -.02em; margin: .2rem 0 .35rem; display: flex; gap: .6rem; align-items: center; flex-wrap: wrap; } +h2 { font-size: 1.02rem; letter-spacing: -.01em; margin: 0 0 .75rem; } +h3 { font-size: .95rem; margin: 1.1rem 0 .3rem; } +.lead { color: var(--text-2); margin: 0 0 1.5rem; } +.muted { color: var(--text-3); } +.crumbs { margin: 0; font-size: .85rem; color: var(--text-3); } +.mono, pre, code { font-family: "Cascadia Code", "JetBrains Mono", Consolas, monospace; font-size: .82rem; } + +/* Cards and sections */ +.card, .panel { background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius); box-shadow: var(--shadow); padding: 1.25rem 1.4rem; margin-bottom: 1.25rem; } +.card-head { display: flex; justify-content: space-between; align-items: baseline; margin-bottom: .75rem; } +.card-head h2 { margin: 0; } +.card > table, .panel > table { margin: 0 -1.4rem -1.25rem; width: calc(100% + 2.8rem); border: 0; border-top: 1px solid var(--border); border-radius: 0 0 var(--radius) var(--radius); box-shadow: none; } +.section { margin-top: 1.75rem; } +.grid2 { display: grid; grid-template-columns: repeat(auto-fit, minmax(400px, 1fr)); gap: 1.25rem; } +.grid2 > .card, .grid2 > .panel { margin-bottom: 0; } + +/* KPI tiles */ +.kpis { display: grid; grid-template-columns: repeat(auto-fit, minmax(180px, 1fr)); gap: 1rem; margin-bottom: 1.5rem; } +.kpi { background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius); box-shadow: var(--shadow); padding: 1rem 1.2rem; display: flex; gap: .9rem; align-items: center; } +.kpi .kpi-icon { display: grid; place-items: center; width: 40px; height: 40px; border-radius: 10px; background: var(--c-soft, var(--accent-soft)); color: var(--c, var(--accent)); } +.kpi strong { display: block; font-size: 1.55rem; line-height: 1.1; letter-spacing: -.02em; } +.kpi span { color: var(--text-2); font-size: .82rem; } + +/* Tables */ +table { width: 100%; border-collapse: separate; border-spacing: 0; background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius); box-shadow: var(--shadow); overflow: hidden; } +th, td { text-align: left; padding: .65rem 1rem; border-bottom: 1px solid var(--border); vertical-align: top; } +th { background: var(--surface-2); font-size: .74rem; text-transform: uppercase; letter-spacing: .05em; color: var(--text-2); font-weight: 600; } +tbody tr:hover td { background: color-mix(in srgb, var(--surface-2) 60%, transparent); } +tr:last-child td { border-bottom: 0; } +td .muted { font-size: .82rem; } +.num { text-align: right; white-space: nowrap; font-variant-numeric: tabular-nums; } +.bad { color: var(--critical); font-weight: 600; } +meter { width: 64px; height: 8px; margin-right: .4rem; vertical-align: middle; } + +/* Severity */ +.sev-critical { --c: var(--critical); --c-soft: var(--critical-soft); } +.sev-high { --c: var(--high); --c-soft: var(--high-soft); } +.sev-medium { --c: var(--medium); --c-soft: var(--medium-soft); } +.sev-low { --c: var(--low); --c-soft: var(--low-soft); } +.sev-info { --c: var(--info); --c-soft: var(--info-soft); } +.sev-ok { --c: var(--ok); --c-soft: var(--ok-soft); } +.badge { display: inline-flex; align-items: center; gap: .35rem; padding: .12rem .6rem; border-radius: 999px; font-size: .75rem; font-weight: 600; white-space: nowrap; color: var(--c, var(--info)); background: var(--c-soft, var(--info-soft)); } +.badge::before { content: ""; width: 6px; height: 6px; border-radius: 50%; background: currentColor; } +.counts { display: flex; gap: .3rem; flex-wrap: wrap; } + +/* Charts */ +.chart { margin: 0; } +.chart svg { width: 100%; height: 90px; display: block; } +.chart .line { fill: none; stroke: var(--accent); stroke-width: 2; vector-effect: non-scaling-stroke; } +.chart .grid { stroke: var(--border); stroke-width: 1; vector-effect: non-scaling-stroke; stroke-dasharray: 3 4; } +.chart figcaption { display: flex; justify-content: space-between; gap: 1rem; font-size: .82rem; color: var(--text-2); margin-top: .5rem; } +.chart figcaption span:first-child { font-weight: 600; color: var(--text); } + +/* Alerts */ +.alert { border: 1px solid var(--c, var(--critical)); background: var(--c-soft, var(--critical-soft)); border-radius: var(--radius); padding: .85rem 1rem; margin: 0 0 1.25rem; } +.alert.warn { --c: var(--medium); --c-soft: var(--medium-soft); } +.alert pre { white-space: pre-wrap; margin: .5rem 0 0; } + +/* Finding detail */ +.evidence { box-shadow: none; } +.evidence th { width: 38%; text-transform: none; letter-spacing: 0; font-size: .85rem; background: transparent; color: var(--text-2); font-weight: 500; } +.recommendation { border-left: 4px solid var(--ok); } +.script { position: relative; } +.script pre { background: var(--surface-2); border: 1px solid var(--border); border-radius: 8px; padding: 1rem; overflow-x: auto; margin: .5rem 0 0; } +.copy { position: absolute; top: .5rem; right: .5rem; border: 1px solid var(--border); background: var(--surface); color: var(--text); border-radius: 6px; padding: .2rem .65rem; font: inherit; font-size: .8rem; cursor: pointer; } +.empty { background: var(--surface); border: 1px dashed var(--border); border-radius: var(--radius); padding: 1.25rem; color: var(--text-2); } + +@media (max-width: 900px) { + .shell { grid-template-columns: 1fr; } + .shell { background: none; } + .sidebar { position: static; height: auto; background: var(--surface); border-bottom: 1px solid var(--border); } + .support-card { display: none; } + .page, .topbar { padding-left: 1rem; padding-right: 1rem; } + .grid2 { grid-template-columns: 1fr; } +} diff --git a/src/SQLInsight.Web/wwwroot/app.js b/src/SQLInsight.Web/wwwroot/app.js new file mode 100644 index 0000000..e34ffab --- /dev/null +++ b/src/SQLInsight.Web/wwwroot/app.js @@ -0,0 +1,22 @@ +// Copy buttons for fix scripts and the theme toggle. Everything else is server-rendered. +document.addEventListener('click', async (event) => { + const copy = event.target.closest('button[data-copy]'); + if (copy) { + const source = document.getElementById(copy.dataset.copy); + try { + await navigator.clipboard.writeText(source.textContent); + copy.textContent = 'Kopieret'; + } catch { + copy.textContent = 'Markér og kopiér manuelt'; + } + setTimeout(() => { copy.textContent = 'Kopiér'; }, 2000); + return; + } + + if (event.target.closest('[data-theme-toggle]')) { + const dark = document.documentElement.dataset.theme !== 'dark'; + if (dark) document.documentElement.dataset.theme = 'dark'; + else delete document.documentElement.dataset.theme; + try { localStorage.setItem('sqlinsight-theme', dark ? 'dark' : 'light'); } catch { /* ignore */ } + } +}); diff --git a/src/SQLInsight.Web/wwwroot/favicon.svg b/src/SQLInsight.Web/wwwroot/favicon.svg new file mode 100644 index 0000000..54199d9 --- /dev/null +++ b/src/SQLInsight.Web/wwwroot/favicon.svg @@ -0,0 +1 @@ +SI diff --git a/src/SQLInsight.Web/wwwroot/fonts/Inter-OFL.txt b/src/SQLInsight.Web/wwwroot/fonts/Inter-OFL.txt new file mode 100644 index 0000000..40589da --- /dev/null +++ b/src/SQLInsight.Web/wwwroot/fonts/Inter-OFL.txt @@ -0,0 +1,93 @@ +Copyright 2016 The Inter Project Authors (https://github.com/rsms/inter) Inter-Italic[opsz,wght].ttf: Copyright 2016 The Inter Project Authors (https://github.com/rsms/inter) + +This Font Software is licensed under the SIL Open Font License, Version 1.1. +This license is copied below, and is also available with a FAQ at: +http://scripts.sil.org/OFL + + +----------------------------------------------------------- +SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007 +----------------------------------------------------------- + +PREAMBLE +The goals of the Open Font License (OFL) are to stimulate worldwide +development of collaborative font projects, to support the font creation +efforts of academic and linguistic communities, and to provide a free and +open framework in which fonts may be shared and improved in partnership +with others. + +The OFL allows the licensed fonts to be used, studied, modified and +redistributed freely as long as they are not sold by themselves. The +fonts, including any derivative works, can be bundled, embedded, +redistributed and/or sold with any software provided that any reserved +names are not used by derivative works. The fonts and derivatives, +however, cannot be released under any other type of license. The +requirement for fonts to remain under this license does not apply +to any document created using the fonts or their derivatives. + +DEFINITIONS +"Font Software" refers to the set of files released by the Copyright +Holder(s) under this license and clearly marked as such. This may +include source files, build scripts and documentation. + +"Reserved Font Name" refers to any names specified as such after the +copyright statement(s). + +"Original Version" refers to the collection of Font Software components as +distributed by the Copyright Holder(s). + +"Modified Version" refers to any derivative made by adding to, deleting, +or substituting -- in part or in whole -- any of the components of the +Original Version, by changing formats or by porting the Font Software to a +new environment. + +"Author" refers to any designer, engineer, programmer, technical +writer or other person who contributed to the Font Software. + +PERMISSION & CONDITIONS +Permission is hereby granted, free of charge, to any person obtaining +a copy of the Font Software, to use, study, copy, merge, embed, modify, +redistribute, and sell modified and unmodified copies of the Font +Software, subject to the following conditions: + +1) Neither the Font Software nor any of its individual components, +in Original or Modified Versions, may be sold by itself. + +2) Original or Modified Versions of the Font Software may be bundled, +redistributed and/or sold with any software, provided that each copy +contains the above copyright notice and this license. These can be +included either as stand-alone text files, human-readable headers or +in the appropriate machine-readable metadata fields within text or +binary files as long as those fields can be easily viewed by the user. + +3) No Modified Version of the Font Software may use the Reserved Font +Name(s) unless explicit written permission is granted by the corresponding +Copyright Holder. This restriction only applies to the primary font name as +presented to the users. + +4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font +Software shall not be used to promote, endorse or advertise any +Modified Version, except to acknowledge the contribution(s) of the +Copyright Holder(s) and the Author(s) or with their explicit written +permission. + +5) The Font Software, modified or unmodified, in part or in whole, +must be distributed entirely under this license, and must not be +distributed under any other license. The requirement for fonts to +remain under this license does not apply to any document created +using the Font Software. + +TERMINATION +This license becomes null and void if any of the above conditions are +not met. + +DISCLAIMER +THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT +OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE +COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL +DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM +OTHER DEALINGS IN THE FONT SOFTWARE. diff --git a/src/SQLInsight.Web/wwwroot/fonts/inter-latin-ext-wght-normal.woff2 b/src/SQLInsight.Web/wwwroot/fonts/inter-latin-ext-wght-normal.woff2 new file mode 100644 index 0000000000000000000000000000000000000000..479d010d2902fa3a5b48e84a973db1978b2e9949 GIT binary patch literal 85068 zcmV)ZK&!uZPew8T0RR910ZdE)6#xJL0^png0ZY&T0RR9100000000000000000000 z0000Qi(?ytiYy$36hBB-K~j|wKTTFaQeFmNKT}jeRDn(>CIF5~FKiJA3WJRdg3~Gs zjbH#Ug!=#iHUcCAn>+*{1%@sM!ZZvATWq_Mf-uH#5dD(YZ@P&Hu)S)HRb$5yj~E(b zy)Zt4PNzeRZ7DGI+wSuT2k@pVvvNDILzB8Y(f|Md|Gz1j#F$=Qy(Gy4fT99bwa&I} zw}B;9g;BU6(ovg$qwV?#xMJ{%=(=&=?4yo*^3d1DqnnP|RaA$b&TX4*+G(yEliOR0 zOPeiv!U!cLC25@*C}vfVV5qY+nsAf8uKwoIix)bs;%2Zo^;JYf+@;TGr6M0CJr)_; zc;D{Hc4EGlwW2% z`Xh6!1!~=F3mteIhRn z=6fJsaxet;l(WNN_*kE@u8HGPSj415HEHq(-zRtB4S%g*FI*4<<>%orQrcfH>9&SV z&fELm=(9A|otv9>Ed1`=Q!Xqf#TP-AlVXteCRONm+PHQ&vyC5E82Z$bF0;51c5Tp6 zFq=}VDmzeE!%kM_m}33;Y@1jv_$R)ks!&Pf+46=yg%>DTVA+Zf7UmYZ!_V@wNdDiE zmw-5Ko`NN!>>h2z(XM!IebGYy{I}Gq&VAi80!v0^39SGSe*-T8eG#JUWO|67+uwU{ z%@_m5=n=vgJw~KBVzfj{v`9%gYNS|*h=qy;D1IzN3@i*pL@Y#FL|R1UOGpgF&7ymL zyR$R9_kQpL%+nyvIEnIrH1Rh(Ky&LJB}6c23jt}75o3%Ri%2#W#fq`9WQ-o8Qd%Sg zR4@pmP~XTejISuaZ|y(pR^!Y(+CP60)pEkBdP1nkt&mYUkyDGrHVi^X#pd0@o{BmOdVjy(ECF!(YmB<(zSsG>wshX0A2e3XHs4;w+&cD zO(QNw3(pd>0A|%~@??JS3A)tq{D1rP|IS@i=QKXxFj$oLz7Hf!Mx3hEeFG%J!hWHD z;uvgrc!GxKdAt92?Z}v!_}))>-+2+bbWo}8qlzl1dsVDbXYH%|l-kWc1~9ze91uoR zrvY#ypdlGdx6d|Gb%n(1i~S1t2F#RqnhLe5I?A)fE;vXL#Dwe-I#Xg5(>6^~Pn-x5f(JPcIF93hJKzpK4m%`pEL$r! zLVr;~hS-i18=jxe-v3FOw55u4;M>838Mm9*-F}k7=C|X_xE&|X6vpiTANvv2#u{sq zCQXfsQFUxXrEqiz=GGA-QYFe45ZWRXMJ!^3M2{XLSI}dO8nA>7SriO}-Y8Mn08xq3 z<`D}qu=2HEKG3q|@{VBFNQ`Zh`=!-M7I_X`gs@psQ)y#8VRA3NtWh@$-iOtPGAYChQzD2A?B(5dt^F^L@0^c zZskPHTB2{OthCbW?%g0XH1u$%px^+~0K-A)AJgmk))WPy0$;z2vLHz%>17z0mj0c+ zI~X{q@0Y*t_wJcFONc8h7y$~OgbY~;gvTlB3;C5vS?$38_xtVl;gLNQQWYzmNND)t zRHieOP9zkGX8(IOzdy09|37mE#sS2R8#u@MQdY_UuB{w?hc z0f!+tk8@xUPC^yjQfc-;!sMaQQ$X(T0gHullX`ie8{isnH&pyKvvdG1?7yq>1|^V6 z5!AE}A4;dSA)z{FlSAvDBvi)=QDW}$mpTmyD9~w(T^^0g+IvX`R8M}J=a(n?pA`le zh;4+s{r{!v*Y@24$Oas`K}tt1b}ZW+9>0A~m+kJoQil|lohKxqiVzEdauJmL3jnDp zLelR7AleTA`F{}*Z4wlN`1RGaoYl6RGQWPx4*=Q!5ft48KstsqW#`V(xl@e0IkVW! za+cGp-Q>7SVY8m)ES5dH?JSldU770l=?)g4mUxahy}N_nIr6LvBD!-<(m5M_Yj%2e zFgrU~5?Bx<3@L%2_(YI0pe)JfFuTAK1R;LPe)%)jkvwPht%-c}Gh9k$EDNvA2aE~VbKVo?jNdg4Rgp!9QBSN6g)hCuj)NX zCs4TE7K#wAGJf{q!~cJK`)2FD+Vw+Ct~Uu>dIaN|K9C&`hf*`S z|1VPV2+Q)fYI65v;fM;y^4KUGQsF>Igv2N?)&kG}PfMxSdUw3X9yuNG5V{T^S!NzW zwEF-3ZF=Kr&qcFxlS}KU6*Lo+F$)U}PZp369>Q1%0D=F_r24*Wdzpa|DIyYr1h>mP%;^*m0_e)**yo5Z>+IcJ+QNdmRkff8}TCac^ns%PN-yl~rO! zMPhAlZBruW+~Eg@^2j414xOHmK{^KSXFsj>!J4UsB!(aoM3kz1%KzSdMKg^lRvYMC zsn@6|5H-qJvdzyw+0Wt;Q_t=<<8|DhTdAdrKN>MYgh)d2ASrYABM1`6o3ojFfr)x4 zKv0o>$f8IIItB&|v0;Zj2i$oQAc*aD5GR3TY4GGxpomgsTymMq>bT|x_uQw&OYe1> zHsgn1<}K2ntdO7u&z+OgKE%-Y4}Snx;(BZ(7Y!sy(@ZO-oLiS` zjcejx1kb}VE}8SdhDTn>>$zRdk*kD|NVqg2M9T{OrXPJVU#mu%>wcTEGM!nQY{jO# z@V``$3RA5vy!GBkpTY|qaTHO9$p68OndOwL^4d|I^lU#}_e?k#uDaBfcY3cMtAS{J z5#?1~Q|*rofsO|uAY?m}6*VLgXsP%jMYU4fHL@f(y)RD)ghWtcHH-iSIXEBz^@!*& z;1DI)L38r(BxmwBTaF|urBWsXGNC*wsT$Q+PqbdAbel0|WCSK@QYLM(7PSfIaS4}n zS=Z=m{|?KLj`<|5T_hx<3|Z)Mqq&L7B=celi#l5UXT$#401PW{rd*5CZ@N zppr=C^oJWe3}!ouxjlr>Ptl=pG!{>G`@@lG*)D;p#C}$0O<{>tMyhoNo81{sHkkd% z8p`6RVD}+2%8k8@t5}jK&$9st_%k>F*wfP=dcZWEl!4lJf4vPR=d{XMXkAc_WuSE_ zU(G`f6aWS(00CJbhq>%f#wF*K^Dw&m8O=t3@@1J^QVxLLf%r**0mx_z;sOj<&Ums zp<|Q`5UYABgw<;S4E;_3#i|JlkZ~bFf6d`R0UY3Z7vANk^BOw?Vzj0vDXUMB{3up^ z>6PqhK*}>nh*ee;vXT0?N=q-+b%?|w=_CvPnOJ=3uC4nS@cmI_B)(Y0YLc*XG^VH{ zx=f}RxQpq?WZ^bk&V&$G>@Qyc8<7?lR_mOJi(ih8US*=CL#h>#-7nr&hhZVigefsG z#uESkOo_#V;1Dn(T4bMZ5DO~U9L0nbZdOu>3=*hBx~9WTsY~o8mE0C6T6ZpA0o!VC zE&ZBafn{47&x#fwryl z8I(OaY>?sWcx7}W9qwQUGOjU2$AOMH1mkVhmSuw}IZ zlFW|i4G*P1zyhH z-6#?8z866WDMKl2x~zO}L$q zbv=vjip;%4!D;<%jR~+3A-0I@Dl$ETB(y*>piw4M{_fj`7i7jZBfn~G5{cmSDNQGp zeK`<)P_)XeA_#$aSC)i^8lss~5b-Ay(k2hYhUn?lwte*RM*1V(#DXJLg^IN8RL7=Q`XoTH5+BDHMiOw_njSL1XW3J^+> zUBlQ{%zsNx9|2{aO>1Cd`nW=kXEFKst9l0+0%HKvpxGTfjSnTCeljYBGB@9J3`!5P zl8D_e-gNWA&6p?e*-etHgk!DJxOaHl3~AN9;py)GkLoM-h4(bTt3)v6A~W&0OZn;CH61a;gP@I0eC!4L8)nh#!cR> z4HGaCXrwZ0o`aLZ5F}G4YK&0No*T>~xrT0}bywq<3PBWjGDKNo&TZ6vz{tIn} zr7rvU_L^o1na>1zGCIzdP1!5{S)S__UVju3WEQK-Lh<`~XrRvYVxXT}%_)MhgCBNx;w@1&Ru6WB#RW=iCtC{UZ`JNFUn z+5?_(7uT_=V2coKJjW$rUb9Dl+4QrbhU&MaWnhL(t*jh7&A8DTJo~)TErsfZ}u+_f&z3V#M z1QkpTEmx(==HR=DM)TCu;w*z8((c6Q?VWYQ#Tv8zTkS$8+VwMOvZa*_EN_`d%FXS=w%=2 z7vHG`dqHa13{zS>J!TtoJ9T^MJWSHk_Kz9{=*Cxle0u zEE%e)I1qmCJEG}Ek6rte9et4aT5>;_cXO^QA1Xaa|1=(XR398AVX ze6trwg%A8XA8d_z4K}rjsq-Ri<6MQ!E=l6v0U~*ZwKeMzw)`9Q%z~})U1se_f8N1Q zQJdXvM?9_>@x?(h9an?P+r2$|*u>@lkvw93)>~7un7gl7ol1LRH)oLan%7JS`r;?( zM8%ZOYw$wiX9&PgklF~v%=D_Xss|5c-vstesEO~i%=Gr9RgW|;ISE!P<4u6k#B^NJ zzRO|CpL8$m1o%tBe5bPBYr}^PyavIc(XElx8@h+bDgmCbMtTe{1C!$+m}_g+7k&hqfH1KHwM5!upxtnE86i{Csre3#1n*9T+4;JbSP>8hT{ z+?LL!dzoip0?+_+Tche6RbE&3yWw=J!B>8P#-vvrrQ7>Ey_f|%j0jxO*6{S7-aCDb zZjO)Nzj}^`qvlPp_|t$k#yOvgOd^dN$2*_lo8 z+a)jI@Xq8sL*E#BR#gO_)T`5(Y0smaK99U8IdX)O#g6bnE*YWW%d1gZY!D=lH0*61U@pP{&Q=PSUj*y5XF2y?&=Dn~IXm4hnz)W?cgqbC1O5JS? zw`HuLJ6alpq6PDVDf9eI=KOn!Z5mngPwjtPI{!BGdW&Z1f!zPC@K{G2`~vBA^^OAE zg5{Fg=VgyF0b0~4EOv6ZE6lRSCB>+wbBYrTxtjR-!qNDArg+Bf^GUWQlhyes%*T#- zzPqRH=JO$L9xZ&he=0v@iM^mfGk?Ma>@vU-xlgs{ZWErp0pt;6QesOegqv;_D^&HI z)?qckcv8bi@00F;E%`aTaNhesfeN$d>Falh;ZUbB1`4zDn~fZd9JXmhtXpI#>OA? zF~)>u4us_wVwyi6FG&zgjtzHgCevJCnN`-<0|Nmf3^<5U@((`Xe|*ZBT$&bx^SsZm z?ByuO>EqA*i~Dka&I3G{N2kJgj3+pjR)AmCUWjwOm*xhqoNK%;>;do2%|2LLCcd(L z%8NF3vMal%w%8N%bk+@SN~w?agiYBZMLj|=8T8_N5mXpWZ?b?>@4sU(Srd)V@_V@Y zfsbUd3a=6fDdQO{|2S>dL9uV_#Fj^QJpUaQiDTrC>wCr*v}`5cUJijD2@&mH+f_E< zqmD#(hr1u4rYk>-C-fqcp=bHyk@Mv7{B4C2-MThqk56Ajmqh0yNZviOJA7}T5nIYl z4ggOYQ;|@h+oug##231)6Y&v}t4x6e3A$z>l^QTvjN%e#JTn6I_Dx_s(hp6*6T7?v zFL5C+A=u-OBz~{roA8kE_yP~Z(tV^ivI!Pu#R=R2L3{x|L1f5n8JVM00y@-_bZc~n z|4(MrHjm*CDf7x&W`9}4Fs%7YePT*u8`{98F{vR4^Q29cI)*LBjx!h_f+JM&SN<(9 zDnE{I^++6#j})R7l_?9y%9er@rRV=dE%l!X5?ZrlH8Dc2@*+j(rNrC2Ec#pRbCYhe zoy=a8T7iSg`z!Y>O-wBk&rK_;*pMpBFa?MZDD*5mMI($i*ismJ6HK!C0?G^`6=ZH= z1%Nmy?@Kx6x!mgB`Jr^@?UyE{>&&@)N{fV7d8;(K5bz>uWa~E9QWF{hrg)uC!4vMT zjX5`)>S7bJ4qs6UZGgSp3B0ux0Ji;JYz=7fnCsM#<0%|(##6Bu_HkhQ0U(o)qOw(H z=ua*i&=B=iu&{+DhYI{H5Zn3~KeEA!9W)ZzQhFAjd*GuG9j5Pp9-gdRas{CR?3^q) zWQiO~YbqejlV8JXwef$|+(c69&C%Fu&yEdM*4h5*EB?$QJ|2vN|Hy|9NAXy75fhuZ zNoPi24x7EI)05l@cxeJ*xKt;ePfT|~3azAxr6IWrb9(y8+GsAuUD(mlob>g(X+%Ox zzp|-!O6mkROW0TB64|AMD@0|HKs|{B7rJ$;(&tEI?|>Ye-@)5?sI$#U(|A3e00nj< z+Paih1-Eryl+FgO)#Jkkq9oa<1ytOMj{laVH2ZyuG#@3$$Km+_M*dGJQDhz^R3|N+ zX<3Zy=ee(NH6?b6rIuH=z^1ts-UiB&YKWpKKEl^j6uR_cymV{*yiJ9j(BqMP0d20_ zhAR7QAd+g2ejh5m25oMgY3)LfF=jYC`gkUaD+3`iD5H-77PcJ)amR;HB1m-c5Xc@K z9^a_s9aM9X$2_5xHa@ryO!PCQ>n(F-(lQUT%PgQ_kr&v^c0vec4-9nB#RxNOaKxWv zc9BUTWgO--johV~r*!lW5=imY!B4LxsT(}?vyrb_imw;*KHu|Getyky_~kz5k1>xz zRz^EYLwR4pPlBLfW7Lu z5yaIj4*S|IY$(0`5VNjY@GB3d5EB?_WRXV|Z49x-7FX>o31Dzq{G~y^(7HDwa*&r; z)g(MEfC|qBzy!cXyb(4h1rs+3`Z>X%0uBTR3g|fk1nIrAO!WZ*j`ck#0Yfu9WRPR} z;sw{0X~fu!&$Vd!FSY%;!;#Yl5x@ae22jzS#EQ3Ez4b3-zr# zBjnx=&i!5L-8dLan`QwCpi7L;}uTNZWn zBf19L@5PLO1pk@=X$(~bmxhR^emv06B(00wTza)V>7L3lQqV@8s8ZsAdq4674U$*z zsjJPGQ?lWMF=7-s1V9=!rf?3I3=~lVo>!H~`_aE9 zq`7*f9A7q5#_zS$ox<8d$hYI3O1*Ax!M>_1O|?se@uY_C??e7yup@+oS@sS$e>es1RZC(FBxdg)ZpWi%}>nyTg zPg4UIAM5|IbzkX)U{cHGU3$Uqkh=C!s%DOkx6a?A_B;*N);_W|*`ELPFE7V6kVWA? z{}bZL?%VEIkCSrNzOJI4>D6r0dW4V2$Da6s z`~54-VRtYAr9XL+dWpFi*cE5rq6})os|w#mAnN#$&4Hexug@{JUZNgrAWx z-+%>rgfI9t^T@*vGRGwUXBbd#5)cP~rgw!7&OM97R=O=OTRlswFqVTfo^I=&;?#|OEzFE5|E~OZBqp+O_F6Q)Xco)* zXCivGeEeEj%VS1tMq)SOPFzjS7iIo37r&pU$#cEaVHx6w=9p3p)>o>B4EG`pc*Dk| zXmM|O=UImQ&e$-P+ROjoTPnTn_{_}qwY_6Im3gHm*6z=)S`!&u+zAcdc;&Y1S9!OU z*KZZ|A?~%d zwu5^?_Xa@xy!kLR+> z!MP6?TUdCaCFFNUbgMeQqDUeIo{pt!9oMP!LN8aDz>Fmv zvT~+l=nR8QSF_8?^F26NxX8s~F=%KwI2XfXE@$;`SL%`3$%E#3I8s7&h2+~PMpa!aMD#mg@}kmL#Pqz2B=1*U)%&6039)tXkcRPQGU3)Yi1C& zsM5%g!4Q77nO$3gvh_kngNOqOYr%>?C6z)hrr;%c1s;T9C08^Kbgf*Gl5r|95RB@S zN(v5$S-y>`2g6zYA`M~<%-I6XhOok2;4JeSD)_>t3eynfn;~2hT}MLX1j=lP;uRf9 zCShTOCM08_{v@)K|Z2rlD+mUqoB_zQmhX2%m75BfuWl@S`8OU zbOahS5GX;x2FiB(3-(zmMo9@sk~xHVDB(3Ch>B=pE^JR)k@D$NbRd`bZD|gsu7DCs zSMxP?qOw=!WL{uMVvxWig974+O6rLeSg8~cmEFdwn8PA?Fb8%&t!^3%#%fed4-2Ex z3T(?VS&qgTtrAQ!%Ssg}nyMKw(;cs~yR?mfyD%*eAq$k!lz*3^1+W=F&h%DasJk8b&^hd@FL?bZweh6m-lT2$~H; z4I?uLVq8N-R<>aX&!8h=(V~$cK~;m(wNee6QjmI-vfHC*rZ|dH_C(o~ebdm+{v4=g z2~pH?5O1@kIV7`8QFL-Rif)cXVdQ8Oy&Q|8pW}EjS&>Raq@9A47lWiXzX!H3>ehgC zkAh?*ibh6hMvR5gxCTa76gulsNH(bXdo~hfXB9JGCH`C;8R+C>{db#*0TTQOyCfK) zKp=>vnXxo2mgWSUC}R$?@R;K%^}tj1HDeAFf*MMa)bs5YEyN3Ci7x4TCVVso$GC4a zn7)i7hfSzLg@__B^kZ}tR=0pVD9O|vOf{h(!4J?xcS$WYJzHSCm+Mm>OOSW>mlxBK z%0P@#u@z$lC8B^)pT$c(JGH`+)Q`Kso7>^{i)F1)gjB#D+pm;Ppd>igm@XnOIM;2r zu6hAO)ChaSJGOOKEqL!g#L@?eO6p$W3K~j1!2z|v4i=Oc1BNgWTcU+=rKRL*3nTv_ zx@+t`LEXwQis=c~a{Z1*%Aitx!6aLWB~~%-dqn3gYAcyUYwMG=kTU+7{bj4S6-v2e zf=_O-#9L>dRjwjqg{5)1fA=4@{_Cx^b`~kb0(B;<${KH$-!0?}^6is+2NY4f2v1_& zDaWQ@ge`WxQBHWlp4*PJbJd8~h}J*_0uVzA^ej9p1`L6;U(Tt&3lx)SF09%<9QN+g z`;2$=&s%*hzXOZ_<@&jPTpQmXX3%$|%j%a^d7JyP{KV{rUfb-<>=3%P_ZNe6;ThqM z4>1)tc3+h~i(SR~JR_emww`JhGrG$CtY4AwV57!S>D>LHQ6|Q$`A2sJ}v!r|?E$RbyD)bk}Dm>D7}*#pE$1G45Y7>Si_cjsV^~`ofASqTW=!FYMz* zKXm@$D9ixX6VGlEsHGUmDb6S*Qj$wWsrvc)6IMq=6g>xZst`;pY#dxD9zFpf5itx- zLP{27RWwXvcHVAiKFGzst@Zo`rD?bf90s`DrIrjj<(EG(~z+3}J_D<&loqb>SRGrhm0XXbA=5?6gM7y`-SD3D@!7H!tBp_Atov)jKY|d}01(&*ou>VWjSd(C zcYBlJECZlx;M!!j0zT$__R9&@r<|<3X5UINl8~#|p14-hv4Ir#WA?ZyI7tOaYr8Cs zi)@jf%)GO(o;cyQD#|cNd){|P1G@?^C!aom5IOj3Dqgcl zlOa=96l?$qM>8KJs;Sas$drXASAk-C;#x_^l+P7l>%>Sxu3~%QT1iI-;k?r1f6Xv~ z%z`sRL{%z)uU0i&QtPrhS6p@74fSqna7&}x?zrodZoT>q`C`~tBSwuGHxZMyeU0@F z`aOYm??x8Rv=KQdygl~XCs~SA2c-uMy+}c8a44~=GCH2yLk(aTeReq)6O_+*@{(b zakDD?VHF5E5z7NUSNAs$wj(EX%Pr zwY-xmh=e=ty63(J9(ojyM^bM-He1`)h$n!VcX!-%&wUR(^e7$|c%%a#vMuZBuw)I} zh%sv&OR#rhG`pjTfXyVtMk3lOAAt4=E$&e`P>Qk`xVY7*Rj)y#CLYbaTC{05Z^3bkmYj0h8D}k9v1%=DjwEbj&Vr?2 zA>fiBq)3$^6A}s<238gV3c4D#7?|p@aq#d72#GXkB-W%&dn{G>c>#h{sWn<1(o+UZ zGc3moq9hwlid+d4FG+Wd{sAT!z+A5M^@HU~v)|DJT_;Ag1szkZwUr>u3zDoIM>yyx zo4N2usvOd;n9)Uu0Cnm1E)nYOZ_X!-aEK0?sG)3$aEV5aQdwS-S5uJdN+LdjI2l@F za_i^gP;b<|5mIK;4_wzPOBwCDu0ECAKXGelD~9wCqFQNR}Xw?5gT za+RAVPKjrkhFS0HZ9slt6zPHmTW=^UMN$VRT$q>Wd`d!G$!rgJ)cv7Feg!jl~F zjAuADqvLo~c#YFkaxoq{peMs;o=)U=Ry{9@o_8S7hrx@_`t%rWOa^1mW`558*Z;tu zSen{RQec^b-C+d zX_iu*d~+z)wD)*lH`iQq%{A9tbImo^>{=^&-=YxO-W8*(U^KvU!__C(;MM1JbOXE% z5BY)r_^)UB3Nhq{O$oE2roqr^G3LZ#W3p?GgYMU}9n8;NsyEk&=;9(a|#~XH>zgl7*Fxor6;q7q=R< z>NRN8#G{#4%Uvsg0d3TF%v*5Wq9v!CcE(xDR;*fcbN&`c0=M09*FE<=@X(`pJOKRx z%!jryXTegi5OB#5Qe?=4go1{Fl_e+7eyK>yiGRfv>q7hm~2Bvx} zY#cm%0zx7U8i_UC_A-X!t89l4EyKwEScc^}6FL`gQ9q9nVgJn71nk!)sd3pN|J?85$E(ZKtO4fr@eL$|UPay8JExdsmRNJg4% z=zX2j-8RUY7bIIqndlrlwS`yOz1HE4x8BA3nbuUiMMOkIL_|bHL_{v$0vjE00*1pO4~8lVAcLc7%Qww4+UiS&-2}W~fSkmI_!;Wq0&B=j4hoyR;C= zf^|Ph=gNF72l};E4l@RzL4@Tn zjc=I3Bqo}12p6fLnkp`Qj>8HQm}mu9(#H}(!bLU6pbsj7F)$h<5v26@9b|q+8J%@M z=uG_`W-n;dN~+Bo>%rI;lZe9sEz5;x+|EL|T*um=Wz-+SMbNpLKN1VjOafO1ZK_8> zOpgMY83i^k3fkSk7Ge-DvvP-T(Gc}^^#27|jhxt^QaJMWG)LkZ^g`*cm|KPHdD-1% z%kD@x8js6P^*~R>-Q~A?l1t1B_5~0VktFMx#LD6YMTfFSOe6(=3VJ;ElM-_h*hNCi zE-EY=e7`D*2z<835BIG|+{8pnWmIpk)2s2Y>D6}GSuNy24Vlqw;fAd;wRur#Evelh ztZh@~9QRpRVkhjf1@*@WRz|}6whCUsh4#Z^!F#YvynuZE<5K8&0l8!3{jouLvSj1w z9XIHIu%roGFmNJ1VE)P3Lm0IFnDxzuwHCYGzze)&%*d{bOg3u4rYz#0`OUDQvuIoQ zXHk7Gw_4|(@TJU}1cD6;ji-=*_0)tL@&|oSmiwCI8Gq^Uzza8kc}=4A1%_!yu#dD^ znTAK`vP?6rY5GICbcUK!DHVJ8gzVB-cPeW}n@8_Bs>W8GLfIRL?h{wxKJ&xz-4lKQ zek&;!{~zo7b4b1fr|d6I~;W#h7t zMz3XiMfrBk{?@ZBy7a{3p_>45fbkm3&oyTV3*+l=lZ+WsR|Yx9%Csl&B@sLGuCeej zaN>sGCU62Ocud?SOFAT3;gq5a;;Rjppir*dRPf1?Ntq&X;wi*uo>a7aq@lDB8?2w} zJz&m@Og;IC0x`Jx<>%Dt*%0wi@4F)`QLTH&<)Nuh>#pWpF?c8W{0n_2yUgMMHHVj> zoDksKnTs$UC&>RoxsMM7?9XPPFX#cd4|pON0s|&!3QiD~31XHNw`JW!Z&tEomA9O$ zaCzYSLX|I1P~#tzzx<&K0qP@=8^no-WJg3=i1I?FiFn_(l{XuRLgmfI4(=Aps4_*3 zG+Ox4fsUTaFzv|0P3*&jvF_|Xh8?!=+Yu$5R<}#Z9x=N|B3;c9;<#He#HNs{Q7ZT< z71b&&ZWhutNk_EG#I?%9yeh)CDvujUfoWBVWL1T8Rn71!lF3yR@l`Ezs~AqMV!2z% zvACMg+-fnLRVUn4Cq1jBuvcAVSKVB#^zg0LQCO{u96*48fdByt#xQb@2uFseg9s3y zn{QZvEs_@L5Xno(q&ONAnhrh8tu>)%H<&eq?BX+G+u#mdhf#-Srz?FxeQ+Oc01+@y zhaGOqZ8~DGxb{Twz0P3D=~hI$Z~G*N^67><$~s0mLpuYX6`oa?RhXlhXZnudJn4-{ zoI>(kfX87Fs}@#HpaSUJ|EJ3htK=0@Mk?B%_(Gv#xylu)CR@Hz+d!+=yfKm``~neov3R*k|$s{FQ+C z-7s73ZT&yspWDhGfM)u7(T>B92D>&$oBVQr`?2x5DIxg-B|Uql3S-b1{kshM#GfZm zS^3^R|BA(-faMQ0Yo4ma3BCyBLZMk z;47}I2m};x!v)DI@dAJ@x|Yupa9~bRN&)Fa;g1W}u%JT)0S49v00=-JfIHM){g~}b z`IznUbhzI!TdDJBx1@uXZ9&Y50nr?i{Ox*d4i}vL%FMoJo(&|> z&%gMxTtnXrIhFJ6J#rKQQcb9lN#@0{L8FzM-!E;bp{Wfmu7b@lS2MIi9*a$?J6HYvvoj|0d%ADlmcL4Z_C)+AAX#|LD&|-Hf^& z^)TwmlQ>g6d-<4Psse` z8~P{qu4{jVZO21$CM{;IV=yb7UF4FMr|Rojb<_}`o*E<+nWeLhtzr7qS*tLOW_RdE z)1BH?cJ{8eYlQyuXk*2}O8^8VP*xok>8Pr~CK+hT%oVjUbTdX;W9$}8WMirgPO@>9 zgNs~T<>95809AxqL6{c8wGyG7$egu+9X66+OTLokVbUF9m&3VZ1=)5}VZ`Q zuxSKQd*b-Y4G7;Lm^~lZW|Zx1`|RFUANn@i+L*ehTj%9H<-0sB^5=~e4sNnk39FcQ zQuC&&5vZ#=DG7`97$j?YX|L*8Ha)s)EvkVXT<8bS*s!J7g$=Sero!hO@~UbHfA@)b zr_y=EV~D3Y5%B9d>Xq$|CV*H4999EVGjLk7)`BJqR!t0SAn(Xnk;hNJ);JpD$_W{m zlqV;Vo}D1R%aMgs9i@#Fo!6Jnh@g4o9#tq$U5YtVuBrj~_?j9t-)Rf2YRRRwX%|{p z*;{6cSeYw(+W$MdTG*;JgkZn=4l5+ooJdOzTKmPn2j<(Y{lnK{>9?1$mwUXBLq2t( ztw!;26cPES{H{J&CWWKVr9Zv7gxqWY$!PCg7D61aR)BOa)?frU^Nmq%!y7f*m zxrO!4KI{DREV2HXko`M-0;3kBh10FDOIYxVG7Y1cxQt(!*nI7Tx@F1Ps@(K~*>fGCmM&F2|@jJ1n_Cro23=Vgff04n{Wp z0sF?|P%+!df&FFE&Ci=yj?|*DrHwkt%_~pGP)R^Yn`dqC1wb0e+HvT`kEoLwvYPW3 zD1R|;RN*(tOMpFj8PlJbx)!EEix}3lAt~N5ZA45B%ITZ8Jq-!|MO#Z&8FAirQxL}V zvM6hT%(sLHR636Msq#&Q35$txu|0KS|3qL+(?K9h$vaFP0OMjW?yZDz=!g=q3~VS} zjxK}6^dujIryk`!1p z#kLoP`9Kzgw|cY<*$$IXAzF_-Ac)bJMJT<}vgC#NxEd&Xnt>J|xfCTSe19szwJquF z6Q6K81(4U>bZWW1@FiPo1JhP;@^#^t1Y4(IG*OCc0>Bl0_^{MebB#K50YRO145y^F z&Be6+s$$^=3eXiNa;reuDWoj3F1TDY^rm)GVU;znf0}kkYJ%o0MBqvJ8K%;JS51{A{_>MReyJ%lQsdX)rnK0pt3qh_O znNHW^naenp#57@Un^)WDA%;%+kycM_RSH2Hr8>9iUP|jX7I#Hj)~sA2CxlEKhK6$mg)fxFW=N$UHDtnIBr%BHdm+RkKnJ{OXpHph&NKp# znT#ciNysz}+oQ@kHYgmCBsid?w=MFeo=lqHT1$jmB(pUdT~UVR_iSdDW<&lw|DOlg zgf>bcK+@;~x17KgghbFc(Hx;-I-pXJB?;~UXp})8zCN~WC_591zkx{G7=cac?h4p8 z)r8QA-bU&~v}w_n+pw_=z;3IYje@Pjd}o&Vc!EU7KOGix$r-2sfDxH(itjJXn|*H1 z*pfE!Jfpx5*t~4cxJ?Mq)SB5x$xB6pu)Bx^6I7`Tl4C;cCu~Q7Idp0r4P2Ij*%O_F}`1h7vsGK-|$42 zoefw~8;n})Hi>`sF;eU20~1qG_~q;AHA-x#RQD`oXwrl!goBuZMC&eZxTvYb-Ub$# z`pGU90+C^(V~wj`o5XV=dgpxfovmG2PAt9XM4LiXKCKtE+r>xdniyIMCs3u3(*tuW z7e1P9m%hj%OqD$Aw@t*lYbq?I>^4uKI~^#C*pF7n!AeM5ZzY7~Zo+DLyEDBtnFFYU zv6Rs@M0fmQM7mpsxpx_}D3uAkl#myGGA zZrgcplNAWpP?4o*#mjZ2*$z8>u`rm;=?SIO!MtcLSwEj6z(qCti4 z?y_T>ykpXGx=SM3`i20Db=cmG9YO~$o@O9T$D2{~%-EPfe>0^mr$Gu5NaWqRw1dvD z1sh5t+4Qv8ZcU(}*;`8{ho1`+rr=}!nFR+>um z(C!h^BV4&G;x)mJbFfX2u*7ZfJ-ECzQ<4T%h9w4myrRjX0C2q&o~WRJsocez;{2M4 zx8x3~ei>4*7l(#}8oFh4Wakac$#}q$I01Vk3 z?d>PkfE1Nc-0m7fqZwDv)=QeOxQ$+j?+ZuDx8G$sosZ0tIy00Cf4Hw~UZRvKmOInn z2=Q)QwQvbmrg`|c+C}t^p%5GC!WdlhiTS$VIeMQoQCbY3oJ(Mm8S_Pp+HqMRf|>iC zbeqJq9%GInHedm1*eLK4j3~*9kO8QlPb_kyV5;E5*f=R6HN?HxfV%EyCaz}1YxaIB zUR+l)Tl^X!L~}E-UyS5y^n(NhZoy_c%mis}YR5DneBY_a%sE%mQ%daMZ=dGGH_~4@ zmnMH%E0&lIlHxQ!Jm(WRn(Mkvz}9P=9K2lA0eG$PFc!<257UhJ%xDW(K#1ec@^1P2 zFfv?K76o)RGYP^sBEJ6ZTb4`Y0R5~V-e2JpNJBkgG`42Mm`<1L*LlHJd+* zHB;QR#o;Qg0?{;h#$J^dbr0O{TbS%eo~BLp zgt_GD0Wd}o9(gPA13f`vV+FxNh|}`c7IYq_jTkCfTlw%^g4D;?bXZ$F?ul97{#x-# zE<>at&Xm^Pmrv$y7Bi9Z5tT?EM1FX^^-5)OT*^N$E6%|@*8&xUjD}_sljUf}Q{5JP zgA5RqvEG~~d5)ruA^B6QcnZLPly9tYCImIW%ava@uoK2k_=nEnRQX51CJNCPT#7!-X0Sp80vay zqQd2sZK3h0UG9Q)p-WnPvDkQRUdSpa6>=}mT8ycd^Ee-;?(chRrx4=dQX5{hfKHV> znv~U5GvalCJv{Ckch9(+S}FZ;Yp9pKZRwB==umyTHI`EA3<(Dw?+CT(JM*#`P9L%wXeoT8cD>jFXE02E%JijsigV&8RxId z@2T*Ra4Kflgpe~0Ke@B_mfcgBd;zQIry1&GKW{XawrFO_$`Mck5a8+pJK|UFP2+1~ zMn(=!rkOJ@HXv4_NN`B>^#Fscie%wH!8-~k$Q6*R!-_ROWk539&>1$mVNvh`kay}; zZJ_+M;gIY*A!908m^IL*X5J@~+(Fp9O7jM*I-uh?%ArMf8x}au`XL5d`mOuB#2q(Q zsfLE}|C+D>%Ub45Ub`0hiU725R93CK`4kv%-VH?MnF0dFEKoT($tUP**T^e}<1o)j z3Sf=6$5}BF1==$0y9rnDqP~g^F{*RbQ>puoAzD$_=0p{^hcp+Z5=+=zMmpseO6VXT zDRfEAc8jI_VrwZ>g=eAi4qrLEFP&X3-@}{0(EuSvBCpGkh!9`L3NQQo}CbHlWz|%eQ795$ya<(AoJM&$(j1 z=L(R=Jo(L7h08%pPi>hhd*hNG%V!zg%HP=IG1f`u@T!9qhMlz-vyXGy>jtCdPkRXC z`$~$tl)iE1gHnfv$QXd`^EZuOHrLJSVLQ1|;`PT%8|8hoe-1v{sMRP%2rqq}q7^4k zKFDoy+q|$nmVeai*31s6n}id=x7f>qgq_P-YvNU&O%Dep_0cD4O6oO{!++Z{(bwO; z!EW`3{*-L|i6AS5^Pr`C0s&ZRcffbuJF#u<(&7a95QbNkR2rv=>FH=tp! z#pDS0Q#fPnTG}DEnJG3|db%BBx*<4#)R!)Rh=suO?PMFvZF}SI;O4No93*hR+ zJstLl!zb)E_Su?AI*B(o^7N2P{J?dI3=OOcOF zBLNp<$$q`9k^}%`cC>Df!`1%~ zfCS>}XdDspJe}!di(^RbuN)C|DeQRTFXS}^qF90svHr=2uZojxDWNVm_olk+ zys^PpHResK9pyf>-rJI)nsCP!gdMBK4k{)`Q~MIPAF=@XyICh?$uj=pMs@p6W>yB> zIvhtgWEz9IOm15?st3Y_KhaLNrnO30Y!Ta=(5VHiRv& z2@G+&(zL=4BLdHzld-SXoLA~USqa{0V8lG8qwy24{O#2&O@>(Gobf>-S#6KDQkz9gy+l%P|HM1|)&;dx+L;fi#_LdgQA3Cn!N2oJ{W!1+)J>GH zbg>KNnUSr^LwvEHKw7LBg@W#TW&p9CN5*{qlHr!1>|BJxz6?nGD+uP=k5is{J_@IQ zuj*Ae7U!A*0S;138^~YsOZRSrY6pw}EC$vxt_9sExrp$;RP{)?{h&%EsNdD~KFsxk zijNKO%d?hQk!eg5Zz?xAYCt%;KlLl@6^f7qkQzioqHg|(a`_lNXYrCXI&2^%5P2aI zpi;iN-3LCJ6)++pd^g&c%d~c$eGoBFh{FMsAx5@e5gF_z(Z!0r6QP>L6F3QmGbVbb zHpTMB!LifXKdJ3DFKER{V(}0L(*qn1?P!GiS8zOr(^iX@;hN*PjR6c?c9tzpBL#_zGA4<(Ip&42T@gjuSRmT5CgO=hX!7&VmBb38^HNxQp#~PMVPikH^B#_^I z1C>MTnSK`)25@}`MiOMow@hLmCJ4uPq?X}1y&B0zcBZw3`&J@F7;p`lM#-OnZb8ju zJa+iBr^Y+}B}72%tQ>n+jd3}hZG|tciKr;ADdiAlI6F+5W7`uR&hk^>qwE7=z2MvI z{c3%^P1@_-+FfWaVVe^mWrffdQ;YcJ%JNjT?A}A9Z|+tmN1s?}Nh(fI$H7Pn0H)Y< zuC$hA#zQBG@&OQ%u#qB&9i+m#?D9v;R5?wkUDf(6BYTtntahu-P7c{d=GV-4xT=iM zo|xYgr*Ci{YuGm<6}9Y;piUC5m~=`{T9nM&x$hwod4(p`PE~YX)-+tzrk2uR0x%u& z=;2xZe6O$sxn|tC6GC33&8c$@7t5x4ez8Gs2 zjqjUFc-YkXEE~vNr^Z66918z!10YM=qJY*jw7mo%qW=VWqq{PH>Ua}`*FJAP-dy>d z5N6MoJJ%K-|1aym6~B;u*MIlkB9~o~3z2_^{^I0cvfHkJNIn) z;dbc8WxYAvRtEVOlWW#F*F%2El0vhsn4|Om&jUDaw?j*iWV&STpVg24bE&{P?<}YG zJpRzq)AHB7o)f?~ASvn780yiM!4|Lv_;yz|U&W-Zlp|1XBLTj18%Bu{lQ?b5Q?I^_ zIwO~g2m7fhfux#t5<)YD4{LytDk(B=GbaRWYWvOckx_v-Q7ZH3%?VOf-d&PbnkM;{uF0L8v=T@QT3u z@}V#0y_15hAHx(8a+gb69%|Meo@PytX!JWqk_U+1wVtylH*Uxie_%L0 zmo~`9$rKRP-m3UvY2=f=R_i<515GRo&qVhyB{MAS-i~o8?EOdm#mer|6#hE2y#X^E zs=saMM>1;|O{uh|XS52H=_VrNKChNIrNi8&G0sa4&5obc4H*QaYeJ2fueBi?j~+?? z+784hI-bevH>N~q9+cLOjKo*~kNSHW`bw%VQwARAmcQL`L1*aZJ>u&OPXEgB>u&K* zmNufiyN#rEQdjAN)oc)H!&rue-krZ+-wm6j*L2hu7U=D%v0t};{_{21*L%$cs;tvi zRbTyJy{xx)+bxGF2iWjArkLpV)bvLNFImyPzB~13i*G|dye+F!@9hBQenp62=7yb8 z=4ZcuwDe%a7T~M3B8tk(4S%k`VUZediLJch_{cIZ-WsdAY1lcS+q#b%BXD@a$cI8j>Z$);8A7E|RVA2}*^cv$sB7GVZJPIyn7P+bxZJv+gye-te1m>Oq zj%u?))9(Jq`Yyd}ITv=E=$4$sRvg%DR6VcUVbA3MxYF2bk@F1Pr!F5#U?>yV6zJ#r z$tj0ReXx%ol;&`8@-+1>ji@p?P42`~Y4_;-)Fct|qh64)fGICP`v$4jLh81JtoMyZ zN3yv|$gRn`&6@ttzNYuuOK&^S2Bu5G|os}#lVZc1e5Ugz5zo4`^r6-zVpz+}zm@LE~tHk+zf zo+5d@uaWetME<>rnZ96B!@cfw0iIUsm_lUmhrx1#U*w!>IqmX$Bv?bv-Mv1S(N^|R zm-RT6c(JjHIR7}8^{wP1tE-Mw-Nj{{rbX^#|Frx(%f{xV|dgu$w4=rCVgR3SP8?!odiY@rqA@eb9hS4_0gKagm1;1Ud ze?{lp@lbr+kmcChpy}H$Uz_pUWZZcZ>hhyaN@tCQhu$zaVISV?u(1`r{aYiDXKg`r z#VMlSx$Ch9Qz*$2{vTas31LzY<}HtV+an`7twZr|E0>(i<7e`}by#(Y%`aK^s{;HF z;!vh{Y@axXk^7S?$jN5PU^+SBg9p=3ujRn>-*NGAU3XSGX965E81*cUAHgzn1eUa` zqQjdusQ{dvQ-r7+fUqlmip*_n^g7J0?etQ4vk(-a@3^8!vq!7dVbd#5`|7&D=qnoi zWSt(6Ve^)EPWGP1y{jra!W<6d=Mt8XwLlQzr^EOEiTH_!cBe0i^NK) zkXf3Qv-gu4s|Cg+cy5AOqGgO45hO<~dNh`@B~7bBd*(3}tgEyvn@TrlVu=w;2U1mi zm8U^mXt${+6gJWHbf`fqk;QDzEuKuTrTDqg<4Xbh;_a~-++(VFwkRSzzkpJf1UPU` z;+3Ro5_P6`t6*GZnrsTglz}7p(Z{0fvkZcG;v^Qsn+uyvW4uu{=ER2YyV@n%wK~rj`&hMJL9DA_? ziPUu&d@tLIaO+)p;8>)t0S^_Whn*Uoy$ba%VQCtfS2LqPrY-trG*bH@S;OFpZ&~hSP|QN9u8N4}~pt!TVNp(q6f`p4G9= z3>7Qi5w|yDS(W}bi}B{$)t#HI?b7&PttAp})Mr)wttcODthcm&EO`1Y`IP zk!y7@`%;1Tr*|&k7R`*_AkS$-Zq#p6-ca_D7i5%&8?#HIdv4!JyQ z#jqEb!47)5Bz%rL(NAyhdET`=xKv`Ago^mO1RHVxq7iCg`)Wl$*F?r<3K*qF`h#I> zI)4TclKs82~y-l1ZflMcir;gVeqd&9HN;-)WKB3Mk`RLCugSpO)ROsBF0N zGEeBb8B#xNpcCNkcpq76X5O)g3IhXWkY~z3JVn;+PQkVjNLH$FuG2EIHkz%w5u4q z){*%HoHG^T&UB@MyfhQ|iz(U$o#l%Iy}aQSqf+6FjHK`}pHn)YR5icZa50@MGG-A< z2gK3mn<-IaL-3U5$!6-MgWL<%^@PRcJW$~Ex7CSloX8$5tTZ`&?T0y;QjciwUDY5M zVVEaB840p^)>!SkNM-&>5&UxZ#gVaU8mB0%4nt@LwoI}^`Cw=p{1mWF7T8X#ET{c> zKGySG`1Ffbq`x_|D33Mv?d~}TG6zL%*2gT$(jK*LG_|k@kqwyR&C=yQM7G94{vR?@ zO#KB=$oXytlVZ6TZ0Y^O$Z4Q`bGR=wJAU4hisQ3@V(~@Ci{hhW3yuq7;D0f`8Uu9@ zSqx_@BK*6Kznp&e&WYW{P(`}tB==}SB|)Ie&X}fE6f1w<^3jJi7k@6kQu>rgLV=JItiJ>fPR9eW2;Cv&q+YQN_X9>%>c?7w_!;9(9X30LL8 zCE?2t5@`trc;)%lJy2{>bnwcyRAdqOx4!!qe+uLLx!-Q(H*Joz&Qn!`e{H$9YE^zJ zI0U-y$()r458bk};fwb3k6+wR1Aq1mOXPM>0p2xq*q|yZl%=g2Ld40Avfw8gzpi~- zLNALa8DRP4xVPlLORZUgs4T=d1UEp`gNyR3MAjyXVl=Z>j7=H{6pp3>!jLv(=){{c zHLl^KPc}Hn`Xh|kxBQn`j5NP4#oK2(20OrAKtnR~F__xk@%4)$y(IgN1z^q9H{Gh( zput|++c}a@ToV0X>_41O#Gf4Lm*nv6W7M7t$kv=Eb@Z}-a+(x>J6!87;vY+7?}*r> zRVeVTTNVGss`8MOEF>^?`Y@C`GOA-wwee++DW4vwRC@X7+wwUU=v8AbX1x!WAK(4A zRFLTUTjoyIrYK01(vG;e=RFsLBgtIBEeKAB)X(1P?j5ngMt$I~x4U6$txsHtjh=+q z)f-^4>+tb1pQH#g0P85>2M$u$YdqX6^*emRdgYFh;`JduKfH~X=+*lzYd2{L%U&#; zHML`^tnDxHu-N6xlh#M9o)oV#pssoQrZf&Aoy-T z=Q4oin6*%ycA6DNNgd$2?n zTaXa@<2C75$h`D4CU3qMOn$?DFwQ^|V}4vj^!^x|kS~wzqw>E5E#irH?=Cbq-9;ra zA`;7;Au6pY>;31Zh4Y_p_OEa2vYY?0D{85zq4$tPJgYX*)NI!tnWeSiEy;#3S_mmm`WTQ|NSO6m=#=uag;+9-%KxK$Jxs zw_8f|2@6w=BX?s!*8xPFI}WaZnc=?>wpcKFhd9dSqJHv!*zj+F_f#*36`b6cOaR#s zmLF1&6%;EVoU&B>vwY4gvzYyBlWgqQhX)A#?h#drA9c6B0AAX`2w{@*u^kGWww`am zTS^EKo10dA@J)APaz9ZCdgXfS-_P0Z|y{#nR%lEOw&wZ)n zov7`npP_L-4fAt&F+mLcRy*(X`Sw-$YWzN|uK;KyYVrlYR7u)jq5NFgK$zr}9u3xy zyyz9HhmaKgs<2BnRrCvk$aI7;2~EyTqr!xPvQQzpQ6(s3v0Krh9XgM-gM2CyRNRx` zg~5~iDoz%bw6)b^Q;kDcB9ANHnPn&ZrkoJvGC%e0ot(>C=MIsz>5Wm^@gb5AkJ@7J z!R=A+i-7{A&yK{$#XWDkSiZajF$3SxUjuZwmGOb$wls?Ip{X3c@KI=^20z}KjJ&%a zs&(e8Z=t#cq`ZLlzKL~N&Z9TWeq@8RJQ@xbUvGJBmR9@^?Wp;_k;DHgXq!KuCRgUm zEc{1t!eal}k$)64EuT->EUosghm%u|+AZjFlS4Vl#~r2(h$j`GHP#VX2Kz_pef*=K zd!Nx`M^8jbnX+HdYj&L0|AK%>H-fgQ^kv4%zDR0c3QC-c!uCN}U2iOQWKq|OZg&0y zW{^9R;gV!HrZa~z_ZQGHxNF?HToB|JxSO_Lw0kZ6@sBCXe)O}e-wWrrjX+}g;>sEb zEdvt_%zVTdEoNj`g|1K(_i-fqwVPT8KKp;#mF|)7Gp*NF+aE-GmuX6CvWcNB`{p{4 zQ4s7KxJMQY2UhmLgLTbvNu~QI`m~kIYPNLpqx;33;)DCq<|A)TKLbQ=Qg-52i4@05 z4BfZYCIukV?>+n=8lJT0h0w8%3{+)|{;6z*-o8(guF@6?vMB@tFM{M=s6)0MtSCn+ zvPm$?o2KRur;aoT6O4g|NN%r3KkUEv|Jc|&AUQV>6GlP}(M80gT-r+%4lhv3P3-e| zdd-YnEM!*|5m7MuE0|0Hb1}cm9?Lh3Or>hH^tXTVROO|Xh#PMvfbuV>a-1m02Kd40Sre<5?SpcVI;4z`> zllIQCwZ}MK5NlIiG6#B)lEZgef3#c`x6kI)?Ly`p-1mX!4t)|Oj2+&ZglNq^gYK+; z@rb~iN@b7(#%;yK#rC8WS%>KOk^@f|>j(nbdX0;r_+HuW1F{mk{{qlgKn z3`#2K@)QX3n=^J{rG~cU<823PkAPUzXz?M9q5s9;O8Wu=T^+?=Opl;g_JFZwT-R|ru0fmDq1y1ZqjAol1^hqeB}+gdEnZMq|)Akmq@arBdc}k`0_@G z8mvU>)vOS)ZQ-S7lfH3_kf+dV23w!!z=ce62Gz@MZs>9?VI7dA%j~@`g(e@I$fr5* zEEJ_#lCQV$BPfgMQG9LnaYRx5&ETwl&8}!Mi+ThE%wIcy{{&j&oQ!_tW-Thm)q@v~ z(xNMBV2fTY8_uu(4sDcV+dGwqSAjL&=-T9-! zthZG3y2s`Zjm{g4&L18FU>CvfSANq_v7R+_I>OzIN74Xa?RDVWT_#;2U>=l~>K?A( zPqj)vF93+qe3zv&&P(R;<{d3cHENml`6L^^X@cKnly&mO@C#hd!)komt^2rP-_L%o zrHxs38F&kEo(CYG)zt|ZN17?crtF7z?E>E1!o%=0WU}igSR-lP$=QN+n`JWh&(NVI z{s65_f1P`u8_Y?=T!81)_plMb@tI8Xg!&Hb$`0CC{`UxYaHtj8bP6bfFRHYwVe*Z1iU!soTSCea%p`!GmAR{0?G z7nK^b{=7k`uN)QP=XaQv_Jrs>HCRbCIj=#1u75%S=~}|hmF#72F>x#eq;n6!PV8we zr+A%WzoqVKc6n_VrF}C7+&T7jcF;^1_c1r*i<#5m1(FwzM#QUx$kg4^r;l2deuCe1SRKF-s{#+1DBGk3}5#+_%ehCT|Lt zBIK?~6KVaOZMy(>-+86`fUe9eoV&PY6JH}m^}j$+8h$f8q4le8k~I&JMv1boUscp? zQm8LRh|SM;va?XZh}xWFq|H6y6IQ8TJ6e9}Sl)WdmIw})Ci5~d#F5U{(XbZka@cv5HSJuwTar4|l7CeW5DlS06A$XX)0APm8 z0bkR?^jf~ojileKUpiB&@K`7mJz|t944o;4+?F!2x2~vy<|ss6ZqLT5yVU;rJDM`w zdM6g()xZI0?eYOmZIIW*g_Vjdod|Bm;u=eu*WmKYTH9F(jsjd+zuATzxUEFkT)+^I za1&PAS4JPhyk+tfkjd2zY_*4@&z~KVu_xH6VIq;|;zaScrxZ#_m{9ip)TiMyXGQ@F z1ug;Sfis%7Be-JA1v}=;!LjkNha!)_69Y2!6FiT1%=H%FQ({oGWunb(N-rBS?KW+p z+K_N1he69AsGe_sX+oeMICN@Q^N7Ie(L@L8)+nmjbU~B#S_=>L@+yhf6TX81L@m%% zoGOFbWAfRtpDw7PaZ|s)f{(TRWgH*tqN4F^*&8vo>gO}H1pi>s6ZgY_MeF(D&n$G@ zU4jpd1NeHJS-j9`hu`XFG^R(~w2ejq0;_he`` zw=s(;c+j-HrtU8tjzr1hO4OV~h`sgM;@Ah_iH%@@l$Ay{V}m<2IrNTZuTX`WvBy7e zY3GR?&0rKRz9}+J#bgT|q7~*S0aJnak z6wgNN?zY>;v&OR|&_dVFR3)sG(OgJt(&f-Qyk4O)EhT-6qgNHiH;zN)HkLrdV(}Gh z4qr`Y2*f~$@(;=VX$!GxCTIswOtC=WDs=Z!&H-jI23LXr{C!CJetq=S#Jae+y2K>< z?F9JyeH>sM_vSheFm^ZS%#c14Uw}|CZu4_M8#UZ;kc zD#u^hNU@es=+EktoOmfyf7dHDt0f`}i-T{q3Fqay zY-O6aIx_ye{}$#<*~ZgwW*E0Ox?Z0f&b(H(0X9XG_O*eLomCf^C`!6?8f6}XN`ULR znzisMU?`?#G_#U&NHUADK*Z6-$~r(6$*y7??3BbyPwrga-6fZR}VXE z2>~UkQ*g>4tQVQs(0)L$yCdxVcFpBpX&;xHx}|b-bWQ) zZzLC9TFdRI=rUz=(ERIhnCan$JTR6v^&}T}k4(bNtYO=^4a-AxZI$XK?x;tA@ym19 zkko)}ZU4(0^7T?U_OLevzD>()={Zfr=+E8HWj3v(k(ZUMV?OvOl?Os**b5QmL<-T| z1mjiBRppFf!dwgr%hm@^;dn5>%0=YmXKCQay7_rj?8qwR1sr*yjt$l_b{rse4HGwt_sc(4>!cml}pzVcn zWxIDZ;pBYubNXqP&OcSND%%31I~*5ng1)-dWM;ixQ2rXLGWF32zD#$PoipsG0Plr0 zpL7W@%bF9r%P52Oj09>vp$z>7C}XX?NfY!vO|4$9rPJU3JxM=dQBK8k_PC7jCD%~r zfBy{%aF6W=`nPW@J>Q;kkx}N;4^V&l!l5+Oh;-gHci?kG`}s(P_R_mbM2YDA`SKG& zA^26L8>LP!e`_Dz$LqRUoczT=;l08xu41?RBV44L%o$9nZ36z>C7^QYQ>=Wy9SD{@ z-wgY=Z80wJ@YoY<>D`(WB{!brHpNul|38nq^1kD(HPJy;9mtf!KwIeWm-4!|x_>?Y zB{|i^<@7g6dQ&4Pl;HMTQjwRsW!u@Y{@yO$gKycu@7sT`u3o*L_Cfk09sgo|X6Wot zA$s4?L_ajW8SP~!(hKb#1U3X^e<6U7%LD%|0!VioYI=3HG*KN&T#uH-&wQZ@$bSN6=x#FDbEK8qD;PZFS z6R;KK?s{Lj#PD+_LTbOB4Ca zkCuYvZV<aM`NvA*8Sl zYv_E&EKwX9CMew&OWV*VOn&ROBJAbPEUbpwKQ%zu6?J<$5@JaXvaVA`wTcsF9Yvh^?KGulN%7`0>g3@p5R!>@_6AERM9R5KPqA^|_zv~T~zDlke ziOB5rWjsHeXSk+kRt1sxZ6yG;R@!ccM9eED6OP@=D4KuHNBubd6&L+;K+r{+L1nM_ znC2l##8yL&)0DoH@GgGW5+N6WatPPk$Itk9(g}g>HCMOv>dzPaH(1{&UOiFx?|)$~ z-NOY+&E^-DwdNDTOBhT>@@AA(m^p8y45^g4)cGp~`ZmL9%+5sX?y^Sdk)vR0sEQqFB4Soa#}E~ zzc#6`ZJL88%=DGRmWW=cFW%e95cUnbz>0mfUmVYXtO;|iKO%gz5axB z#Vc{Z7sS*u5c^Y(#rXJd?PbdbwqXG2?z-Z`J)w(l<#5CtNA8FK(S!xi+)aycNKKchT zfa-`6Bv;Z9l_WaJ(TPfx9xbS0J+pY9M%e#NTSsgLnUkLmA{9GhFpWnu{Rgq3^qL+# zylW(XET~3mXY@bRN>(}PlW#2Qjfy9p?yX;p25#Q)>pb$E$}-38Kk?PRLA?){<WPgjQT2WHfSpA!;?DA1n-& zg{gBB;J^;TF?Q53Ct|HWHbKb0QN-Xu^Xb_8N^8k(Km&W;{=4C1AUgtE8&w;IJ%Zh> z5d|g9Z@tJP$laiU@kE=^RgrNreowQ$SdwEBw^pb{%_$=Y$8M$` z)sz&iblbgU2SO>?GqjEe-(L0w$nPAR2}Uq;M7c~7xPq0w;cx^@V?atX8O2~JNva!I zkEk5DkIXzK{8KUDILCM(S5v|C>5OUQHUhDF?>kGJ7VZhqKaZEP&%GvTqx=bXzX|Rro41Y5~q+z5wb%$to)a=&_`~-C>L&zHZ#WF1@+y#j6s@Gt=GDhYxg*_ zrZ4XLlACk7Diz%VgjOTRwSoo8a7;Xl3D(8*-SRdcD`B%B8DC|BO z2G0$u(>pY-O3-qkx^txF*pi6Vvwu)9L|$;&{)xtZVzqaX&vJCpP6xjIM_OCYod;Vv z%Ok+IGpT&(e5DJmw2K_pEl1E>yZqrjBY9&%)$i&5Nf%lB=EvykjhyP07X+bg+RwWX zaC3H}B0okgHCAE$JW2E;&ji??N0X<}3M;zqAX1_ZCwuUx0&gL}I74r*1YN+`+mH)2 zaiEW{0~OHubG1T2)eFE;hWXo1OW_-2n9WQAn#Obuu3liB`|G^I*<7(OX(aVrd%kS^j6=i<6KWG?U}W*~lTuLnn_IER zN(^9()^5sJjCYe~uMqOJHhZ7HX->HubNvREI&)8i`L7bvoBgv-&_tZiC|m%B_eaf@ zY>cy-nxC);8~;Vk5jMtH&A4#}dB|t+Po6P5zBeGtSU@0@7ZCLEz0t-M@YP04D#2Jp zFvRz0{vr*q!xn*R7&vtb_%b_%C(x>;r?tvtHi(PlF07dy{NFBkF4M+F zom&3A@0?-rfre7W{+PHEPBi!AwRAC#pX8>IUCevB!2K(s#G$hZ#YT&fDb5eeTi&w_ zZss#dA6w^B*a*tG1o+Xi4Dswa1m#V*{GyGbPQ&8W859WMdq!_7$yXl5!In~9FQxK) zp%e@!Z)yQw6{f7e^jy}LJ2mKMPx7p~8k7N2q@NyAS z+0fK$R{geKS=-6VbcZ%)1!U(>0lvCBULDx-3V`V4hu%o%(ufBYd+<39I<7LXQ`gfg zuDx|{F)!rIavBfXu-hVPH5HT&8<7>=F5I78b4vhLIWIAucbeUiK5#Qfkbdh5Hg5j6 zc}k(4ob^qv-__2+)obdeBRmM=TPoCqK0?&3#JQFqcA|vPeG5=IH7}~tG%=2CQ|DZi zx>*4yzV6o|;G(XJrjXxpxbEwqc#d8<*M?@@*1-obWqrIR~j`5w~!sIN)i*AFf>1o{nY_Z=4&Up%^Ai4=DV%=L(j zgkfhQ5ZwiT@hCoGH6~KIBgmJ3lt-sB@E2Do6)JxxTy!bEQsHB+Ccf$rH!hf~{fs^%j9`L)L_ zu{2wmSRa2py&p$-?B8xDU~t)EA9 zyUnRA|5PbT&b3fbbwHx=8vKcgwfNR8#P5WEr%jtG5)%47o|*(cMi|8$_7ecmS&k$_ zlKL1f7njhNKQJlQ*@!PWpxP~r;4ejw8E|)(9#Fgfj^83ahj$0Af(jLiH1#9+DLt;; z*8HCxTYke?^Rl}gdky(fK0aoJV&HrQ4|uNSwfDE@OaKu!uL4My1Ne4<0JMu;w^MbX zyB-AmH@vF05Gzm{8NQu#_c@!s1Hky2iofdIQM(fZiPp?#x8v>@KDR)|Tp^!`JYJk} z2w6@gLdMx|jR6uXlKjY4gN#=qs^-U>FnsQr`fzr;Y5KoVX8?oAr zMombg2WI76G4*1&p!=A-Gl8e~L`)#SzR1Zr?Z?%6F?9h}F~_tI?X2^EXAl|o`q8-5 z40_)7ik0(8tBp=BUNq@P$?(XC$Ui0b#ftVb)9e%c+dWsKHs@u~OHzSHvC#0P*&*9E zSoUuW_09Sj04$`t{DHk}ZeXtRfkRm&{#GBzo~t)N-x-iSuzxT*w9sdOuLe4>1Gk|1 zHHmMm*{_uOg`J!O?Om)^*4B>-nkoUz;?QC?V-joOWFPe~CUYK4&8&B|g}Dt!0gJ3EIXU~}77}m)3xtMLt97UzPN~*HB+QF$i|zBYFlWO{V^J zp?6F`ChBi55;3@*MnT7NF_>bbJ+z>@MiL0spYtz9Va?bmrqb{P`w~nJvt6yp`G|wT zczlj}+?PNC5SIQ!3ASc-R-cJy!l*IO08%e7HjT#TF4-h3?q}}%G}(zO+Y}$f;2RlE z03VmtD&RPN6T@v;7qLqvEly~2-21BI!TP0G3jjgQ5xbT@xmM}VSOCz=v3keu8zQFO zgBd;W(46FoBkQ z3g?F26{eov=jlDocNagIs`BG+R~%mRu_``$h}OjsNkd;dI?Nc|WJeNm1(`NrF`kq? zxE=>n;eWqonfikGt+db<4uyymVKAx@J)GhPs4W!uOij$%uTzqj-tIY!$So*99Rj`Q zzW+V283q)+$HJm$d>YxdGRTpQo|gr<1ebf{$T)}d<(O41#%9V3)OWu#La6V8z~Z+4 z_v-xK7*L7dlm5znk9(U3K2`70k#>>ZnESqn;M4mwmUDZ%$AS2wDFSd->5$khfujVqa^mEhMrTr%* zXW-}E=Ybt=yT+QtVCRe2D8ThEp1@Vfkxq5(IoQ4ffPEUq8$ipUhPY#&-mZ=VN!>IW z4Rmx$>6Sf#L$k+x8C( zo}q4GcktSc^s(^O#=vguN1UX+fJw(8uvk!I4>+>_Kok>1PGT>P%_0~Ghsy$+n6kza z4vU12Ac8j=n*IF-SA`+>C^^OP$3}nn>tLO?SNV>J5633rz{EeKUN(aRD(nSQSrt9F`Fv7+Y(54@%)!O(m}SryAhSulYwQC-zL}3sLk>=Z z$cZ9bwy#8~~#wVfKC(hI6h z&-+fsW^VQYNHw3=%h1i3Mb%+I%2M7+ZAbuN`?8fPqU>@qy3foqmGPqIvCbvzdt)D< zmC89Rj;hW#Q=Y+@nQH4tA<3`|F$m0C{6TujR65|E;ftUjpDeXwkJB!lLlh6TJ&SS;65Hz)B5S z7s|9`W}0%qM;3!tvpy&p){rlpnV11cBRS2LIpiYQ=n{2mC=81sorI+=iop3REN3SV zm>L*mrH1asQD!8#PRul#zse1+W;95=1fet_)q|rh!=d}HzDz$1#!)5;F7a?MM9`|q z-9t`8%6mWPd`TL6-E3fm`Xw}>975ykL~R)lSrb3iK+{8VPr1 zU7j9yA;@wti#u!3)M&FuHZ6Pi7}>7B_La2tUt52FBheL;|)eu-^=pid- zWZ1wc%mv?hc{M$WnIp_U)bht>{PQRdZ-r*|99h1=FoE z4!TZ_A`V=rTr&-!HSC2S*kt{0cX87ECrYndZ3Sf2C^6SxGR3AcXq)RpzRS%_E5dDY zz#{MUm`mk#Jk_QYIK#BdfFEj-$uxB=JLk-3nIT@HstN1mp^nE~SZo)aJIA$kE)JKi zm@8Y6Q?{adslp{NtW?u*stj0ZKdf`aihxurVV9wqmmPcvaN8eCS|ldHcCqwLZK&nu zEt@&JY-QCrXFd$&;Y)q0t`Pl&T?PiH_WXs~rPj_pjZs1_7;2TV^S&hQ+JnNq#4Z4~1v>K)!JZ1<7!%j7c={Zft z-WYIqx646`Hf;!t?lfs`b=~ z2ggkGS?eqEn%0=hRkG%#)TtpjEC%>&=je6)(AL`DF5wA0T*=*>$}W~{@Jawcy-vJ? zZ9|)2X25*_HDr)7jit$Iwpn9L@8lYbYunJ%I{c-T4MaXdpBoGmwV8Dj6R0+R37hIq z&RLfY`T8${+Y)5x&a?Z|ML_D*OqRZ1Tg>!y&F|TDxXkah)PdvcK@2!*I9T0DzWw-r zu6+jj0Pj7@8kl^RM`zR{f*-)U95*nWHj6Imb2?%<-N`udhvzN`iY_ym0Jw0k7;gNw z9!B@wGi8Whk+<|b%6;(CeQQ8yI9$vq@!zY%*LG#p?osr zdmI=e5C?~SAlss0R^nlKKJchjPb3ba>T^uEkM;L{utzWYZ_~XTJttf4gol+2Jm4t?{Te$)8m@zqXn}3eII<_OFSnLM5r>p47CcI!H zDVt^O*!{fj^N*&Kt$Ad@{=9fA7b0(id366h;T5^S>$;2$atLX4loVCPHjSR$&`i2c!FKdb{=!#P`l{dIgX`Z@>#T08$6B1DNQ}mslNX*QIf#vz9k2_ zWON_wG8o=`r$2c#_B=@7S2ZU>JE^|bzlpqBGg1fN!kO!inkGtaphr?RT|2*Jo&(z^ zcA@HN>cpeB`au6cRGk{a_#hJS*5{{5JF>fO8~tps_@}|6E@Qoyg(!NJMZ$|H8pY0~ zB3y%t%=GyI5Cg02T<|J6ACDUqGxm#?*}NVk7-;s_yk)o`G(K(Fw*;rp}B= zOzK?VlADYe)vW`@Mz`1n7Qcnka@otKQW!C=FD7NNH#g`wrv^(7^7!VP5Bb5)@=f47 zmlg%V^=i63dv5#e3@3({HWxduu6PzQN5MTFuBMETiIDj{@?oCe3t0bQxvxA_mKR6d zgCjSo0AmjQneCTJ{}Mbw=)V!WdPbaoqy7U+sV|M}u40qermB6-E1!lhpT7UaX*wd- zf0X|fPbZ17IVEkWb{Eq_a=*iHZVGa_mXf+_vN4Spsa$lM!mDa^s3VS@Pk$cIRineM z|3x70VjriU28vyUg$3Uk78n%!52sH$DCbUl;$a%eF8Xn>uY=mJgF&|aKV=4ZdRxvm zDtF+w_7;W};egV3Mf>MUt>PWMSKeRIX(0YbtFNn<>t-vbavu8c9X?1Y8taHu179?N>JE-V?eh6-{!R#9s)PebH105$n}N?C7( zC7h*X(%J~-@Adq-%^2r*|WrIDGYSyr(y?nvi6HM`dwaa~bfT8Mc2C%At60ey_ zU$RZzkOykz4c&ODS@ulr=nF=f!CHD>(F_4y2b#%qcRH3)vn|)O?kp&)Gvl*xrkXyn zb5XWuKsPOb4(^==WvSE^auttwZ$n~te8@3WTDK0(3L@F*DPDRQkYhyceyD6aG6;E0 ztyWh&A>w0ptoYLNEIpgyY4Da%rj_N_!6@blS#^W-xwk9?$aDx7a)|bM$U+v_pF#kZ zi@rixok}&cRoy|qCcqC&&`#HwsiEaYhz{y&>N(6kZYo1RcwXzW#Qns8(|>&MTGLbr z!VnA8P1O(0PaRV*s`I$@`Scutx=pyj79aNCLwhaL=H#adQ?2R_c}Nfl22T$l=6Wx8 z(Lp`9&Qt}_tjj8?FGJ|(VfJ806R%b1grcyqVpRa-CEU_YPy+o$cU$oq1(#)Nz!yXp zQ$t7-S@suE4<$A#Y6Cm~2xs#8Zoh_H;iw&`-r)9*iewF>uZ({kaO~*x2Y`Zpjmr@# z7_ZS1=f1dA=K*z)&^>X?ly^k3ZqJi@0~jRZ7Hjh!TJ!r#+5pfpC}TG8jJz;ZYvi?7 zET@HlGI?*9J7Rz;8$;Ggu7#ZXsz}!#teTcgfLuozYlQ`JDoUjO_!yEYINR%F8M8n8 zq-DrAGaJ)yTOf*cR2=s`asyj9-Z7?9K{QjVbf`a7hCD(cuPG*J8Dz|`({_e1V$Ixp zJ7zD{7@1^0Q4GMt7t(LEj0T8KcQpF6A!8fGrfTM`;InP|4W%$^6;#*l0x2n^^7x zOx&Zh45Zbgg9w&n!(54wr=1v}{x=L&x>1CXPE^PA!>Io0lXkYID~WrXnq%#pA08~x z0Q7C;>}*d>Q&Z=LNiUUG#c*cjBxj|$&Q9STF0Cs;2BS@8g{A!1G0wOuvwcHPS&1p6LGApuuaZFEZ?{xJB?YRc)kCYKHNELUg5s*9O&Yb~Ip*3F zT>G=zoR0lOTX<#*`vc(jfd1cqVpH^gS^oP?_QZoQ65&zG8Lskxc73M&0St+&tiIOn z^RXTF$2x8)i6&KKhxDi~B1*233sUF`s5a@ztZ({b2qT73^g-ttXFtcd*hgLEdOvoD z2mH-TeKv$xGBj`@g^j4g7)~J_zlieqzZhOV?HSF6WTh-?vn!41&xSmf)+AX?@Mjrq zY@wP?*0aEVx)^4zYDC1VsW_#mJ+E=Wha%bz2MJ~$F9rTOC&Vmy> zTjyrnPS@`Gy*=J-uiqQRcjMJ~C+6caY{N}hj;%O^8*w*AF^w~X$pT?Skdk+nseV@7{8s*$8@Zo1@MGM{NuJ<* z-KqV$s>gb3Jy%aPZH;JFHai+#^QMprg|LaR$cY|-3R+~^kJ=Bqy`Apf_22K`^b5n0 zVPhZ$W+=&0Vp&KdH%X3ENV9B`a_N-yvLO2u_HS4g=R%z`vVp}a_J>!P49^XzcPoL)vb3U7S)7(05 z(D8k1_eb|HKiGV5%>n)LJug4`@@p@D^70S+5AW|k;7{KADzrzmN1bw};;AOd63HgX z)smgB-u>zmufF=~$FF{O@ZiDI2S*N85ApYY_``1w9eOOBdH6N3<>YJ6z4kV8ckVx= zwBJfsQJ+kIbSxJR3ToOxN9i(sy?Ls6v3axkt#i5Vjj!Hb|Fy0kcm1*J!Nb^_*gM&< z)Uel}RJashI&#~-j`B-K2KVnH;-jYK+8 zOf(Q(#MYn*t`G~&M2P4i#)vDr87Y%0(nQ)yGLt6Kx-_c~lMVT;hBc=>WRy&kGlq&n zr${J^wa2IrsNFSlEm&);^-!JE5H(lr@_^DRX-8?NXn%!a=$Gl2!tR7U5BuWzyE_c$ zGBqM7EcHkV>$l*j8jgDOGz3yX0jC7sBHbizswQkC`ZT{a<$whACdRSZ=@M0 zY7~#tjg@NUMding7*(%oMD;b+N)1+btM4Lh%J^kh%f80#&~P-TH9zAIYvo#_)}{4o zx!M-(EP4_B6#XMX9pj*b>MXhjU9FCzYt_BR{7h8FM(W?hzRrRft{ZM-A1FUxKA(Lv z`&stqWRj6>e3R>4v1Hm|nl`=3=bJyL>s2OHPFZvd%`6_PsnuqSv^i`|wtq5D*c%-V zjvNQd@tEM`yipQVRa4bg^}N*AHRT$tRw>Jga(WQ`T+Q}YbWLNeW}8i$bDMW9qgGja zq;`$r)-GaPW14lanIp_s?W11wu&Ah_hr#0Tl8MhwoEgo`&b3-HcQvWA+2Nz#LI>$p zT3gMX>CYuQk^O}IcVB3qOJ6vrhI5K@o2%RJ&((5UxdLuGcaVFD`-G=IaBu+08|U5N zZypTc_wwcZM}p0V!v%wa*TOL2pzyMARrpHy&v5wg{$Zx*wdnhZ?})?5z7gLBQA0&T zeS@H(vtg#;_o#d0OyfhbkATAy+*EP$`VW<)vh!-I0x(8!boB%C67{uKRYi}i)}SOZ^|6EBQCXy`KF z!~K=(HIJjf!0SJ)(gH02ZeM%*pwWn zeQ32iZ5U1vz(3|A`+S2w2OK!v5kwtFN`WDQ@MHhZN@XK7(p^>5PnFpA#np=12$M`h z*TA#4HHhW=#y;Ahkq>t4T9EAYwI5jvqMfi7;&#C*bAUlO>6n9v?<k(TjQ<_Pvg!jJ(ZwBv<#2!e;E4aG7>@n_E?6eruI^yL z$7B>6wn-dJZib`r-{VN0{mV+@-~%b7JrtU-&!&TSTJ(C8N`@Cst$$$?IWJyUh+lB+ zanO?1Z@%3}%VCv~6_^6K5J|NI{$z`*)%zu6E;YIm=m&wSCl&~zqq;u$5VIrH%BS55 zb%u&+4qHgzHSrb09K{R2alRe=8QYlZB*S_*42zbkC)h%>%EYpyS;>px`T)>%z&vb*|~| zT6viH3}NzE3<4p^FkZ}QO0#+8gaB$G&@blsHRBiYA*t$$%p|t7_(H+&+T-2ea+Hka z!2g#BGj^g%iB&6U;N;{ZdJ)*Z!LX+&BD1y_R`!S&3R{0}nTVBbv?T zCRujqbOHV4ZiOHRj;XLi5ecqC$`f(1TIYWSMS`z+vyF`1@XCNt$J&X4@dQ4clO+ zVTEQWBy6fkE+&LZ-F-5pcU&ON^D0f>105Mq$>cla7$a=c64vq{V(YRl{Tv&QUsPm3 zGf#p$Hmj&_LKYboUqnJZWi(fV^N{ET4RRVXTHA?mFNNGCe60T(tfhIbtg|enfpQD2 zpH$;b=i8Qm_rssR&xOxK+jI#9Bs@|K5w^`h|D0_Z=kO|beKP4t%n~pJ2NQMP@6QHu zp@@~!+<|DxxPYWN$v)S!Mrx=f`@x(uLi-w_mKzqL=$1chWzUD#|JG%Pi|VaQ;ns^f zXfj9KWmWV;+x7Y&fN6|Tnf@d3e1-ayam;zJ!fMHJKP&`90#CYH$iB#?XgvUS-}%gO;fl4o~;qoeh-N5n?n&4a?gCa_;W z@{;z^wJ<~vBR%?U3b~lT=xYOZ0sKDck9nba9*nPm!2@u9TpsT8$`I$GB=~HwuLdzB zvysgjyj8)reAU<8cierP#QXQ>_hV4~{uY7WjumHg=g`dg&S$4esjw1+xzP>}cph|F zjkT_Faw7XaDD=WI!kkY zZgu2yGZz4dvd*ERqhl_|yU}NjzEbqLx^+Et-296dpz?%&fB3w~&0IDWBjfW9)!;De zuOiv%C!5WsabdyzweP=@KIzM!_kTXJFOH?|y>;>eh$5+@Sj>v#Ex-2l_FX&9ydOT7 zsDI54I8`n?IgR0|vL>YHU=E%p%IozfQvOiT3*p&jL+1F^sP-;*6S$VP=!imP+}|mo ze5C5Ett)cxiGx^%M~%r$b_L+Dw?G;-kM$FSU+gf ztIHYgUjz(?wSS*!7N-P|yl#zPeSV`L^6Hxnd-L76-RXQUzFUdkT_!Td4Rw&=M#30x zQpxjTMyr{+%DF@x&|dQa9C@pvp+UL=VdGt7jto)msXz;jk%d*>#}-9@)APZg>c6$d zX`)_^RcB?F;c?&PjvaP7zcX=xK)M~U zfzgLHQd0;H*%puPThltEl?cNiqdx!CiNfL>xgqBmvYr@Cm4mqA2&y~}vTT4M@30hi0MfN850dP{e!-g(w(lJ7`F{#{;jKe&zw+;K z&RPIUnqOo44-dJxz|6jc|4d*G^D7OgWV5$VQ zDkSjO;^z$el(}kJh#i_9SF~KG{7`=_LLR1}lD}1UYvn*?v3Go@_#eY2wJ^VDG>uJC z3~Zn=vZUSfc9aEel7*NRUXOSUUfB!X?IgO#_K4U8n1N$98XgHIh?O$-^i;74 zn*{(}F$nGkA|g}(;5}r(R-Y|cZ4K=rcp*E7wIwr$`lx;04ZzVH+ZXh0h@SJ?lfZ`xi42AJv+Hkk@~ou90WZbUzz=O7rYgzrNT z-yBc0rez5cWX;DP3B*jMy}Z-FUr%Cb%v>>eMztssUp)V7{k@!mc=sQqst`iGcIm;3{hYDpu3 zD4ZfZD_@bo{_8zOp?<3*x!^w%gsS)WP9qmdAmf{VeK-i*u2Rxyc$&D8B` z<#wS*ZES@|kfw5?cmfNxp+ZO*Qq!Ch8Xyh~_zD-uI#*K3Rjebig%^w#)LPY?!DtUe z3L-Z(TR5Jn+ZK$(qN%~K*N%50zD&>q@459xR|x`FBO=n{BQ?Rlb9rq{3qFTJaKV2o zyU9Y~YON!h1;?e#66d>~S+2%=^g~R`w$4g5E~$$uAT*jafvyT+Q)eQte`%%x=KX*m zDQL!n$|JHtcg`np}@P~i{a6_S;zh0V6#LI047-QB#vV!+mE|$7GhJzkwLSUD! zDMoTS^-!zFJ60ie!TiCDjSvpXrYp6`pw4Q%0g<|-!hUejTIcoITxMluf4cc?pUt*L zn|&V@;S)3S1P{{qn{kNf@m&xA$6(lsPoBP0@aU}q@m)`5#t2^NDL0*de!3@6S!CEd z4uG3H4{0d{UOvE1Ud6*6^$eWvxspG8unF;1dRf4r4{yV?tg!ciKrv3cCYEa7!qJRh z-34ePx@XP@pU`st(6jd31fcp`J`JyKp@F0BVVvy@Sx{(FTve)cdX;+6pZ@^tm>;c} z!BlmCrwSFkD$qaw04?^J`gD*Nk7!Zvz>U_h3Iy0lIn?2SBNRhFoK=*@&`E}d6&Or2 zt*H)7f)6jBlh$VK26!+sPKDKf3AdJmdN$aguBQjT0~;2O2A%$62qBIULX|KWBY0I7 zYR%e`p%>0DjL-qibhg3u&-=;O>AA~b!#qYm5kD;b9q#$P9io{7^|LnT(kh)`UmiTs z9s|;#&>R{~c8OTRtq=O@OAOC-|G6h94b>O$i-+hHnrhe)W?u!|cGb*tRSmclJJS~f z9ek;}$e-4X&d5vcN)mkvl+)Dd`6&C?traPc^gg9HVs`Yw2G2uM8mzalmaTk~x3RPD zZG>`V_tl(*)%Vj`=nE=~U@SBw-&#D%H>^kk+MC`jZR5sEUegl}chs9##KFYOC(wnG zyo93s!e0~X^)q?J=>u=qdix#RXmRB`dp-nwP~Tkh!PJW$FELZ3j{S)rn$ygU8;t$f z(_PFkiGC8lxz&su>v6M<8z2jc(-aSe24@VUaR6ThaWmuzI3R*XPV?YBtC9H~#fc}QXYV=H>^o)L# zC0*Wdq*)3)dp|yaJwbimO1D4?l{*P$c-%kF`HoeLi_B-sJ{gESwI;7mj+|*-&+^p$ zYLug^xMMT*xjNj|W#f=#thEfEDlFLOUDMUlWHwi5ILc)zeog0hP%p!fOz_ZS=N*sQ zJXVUSgk{Pi<%CEtT0C1i$8B+d5iq-YRVetE<}Tlgo-1yY$qZ(*u?~!b)5qG{-svQC zbXP17E&^n)jSYd}lH^s~TH5h{Jrkk13Vs3EpwwdJnpsl(ao9w8gAS0n^&QvOU%%I2 zZeCOyG7_>ZFU}hbcYWtyS2X0-U)+%C&ea`BLL>e)Kah(<}JoWmX z1J6iU6@n-{=?#Eh=~JGEr?|BP_|k-^?zV*hcV|Yx{dJlr&p7dq)Q?#dv*twgW$33V#E&ZOscq~(eiD{{j z{e2w{U^=v2>?r^!R6r}k;^tB|$3rSpcCL^z8}sR>syT}of+nsT)EXYPp_eV!wW1*k zS1j4XL=>mQauh&2&%ihiqUiEPLJVss85X&csob8KV4*OHNz(d%EkSforDa|)D#jen zmOvzrC9*F60VTI6Sh$@gJ&!L-UdAm^@|z;YM?nvKm+Gi&@XASZ?wjrJY|G&P`4y%~ z)}9hINykpp!B+~OmB0({vRwrR)J%X-u*Tqs2tJJzgLT?#4B5DE+GN@7QdL5ZNr$jp zv*CiuI$N+W*kJQ|cNv5I*9p^%1Qsti60JsWjaC)g)B#&XBqkw)#m%vtBIlxTEQBtu3FbkN-D+2uGl}ThqO$F5ILLs-Pw$Uo_8O0z z9F6>Yqh}7VBo#OgTMVL*rQRsd`q^hEnf9)RLv6Un)0yZlU2y8I+XMMlxKM0Sfw+z$ zZkj8rr#TI~2neA>Wrbpj)xYJ?o2v9=SWT1pYPq3_#zy3!H3uoa@7_%NIFg&~dbkg3 zz!4OhP750EzU-jiF`8LXQ6j#DEiH82``AB(OZ$7azb>BHa6@B98Q!}QBMp+ zB+<)62r@+~yr_Sy?Kp`CXG4eI=s;D^el~Y3f2r1VnIs-6YkuaY46Nate zuiO^&7*)aJ%hhV7cN^_R&&s_O1Iko}6ppf^=&Dnrg8r@nc%7u9t+f~b(-8(LDsI`q z5)D3G){<-gG4jS9>Zg@{A_jhzRY+h+)7wk!#Cs&rc9Z7wmDD{mlHg$wPy&_f3M`f0 zuS7V5EIANeTkfU;2Q%=e%j6B|C$5slzV@IP>tR05NJ#%GP^nYCJLLG!c0F?P+$hsxP_E7oyC!KFz#(H8_2+4bxtN7q zg3ci?zcreq$Y-#S2OJ^7Fl>rmS!eXebCZu&his+62R(Y_O&ZhhNW}tshgv~L^HKK= zIgbbDs`}JG18gTyPSd96ZMI4iv|2$~1cq@Iz@CS-WI|X{7V(k(m59kv5aYGgK%i`8 zSeCQ;FR#lY{w-?-wI3xr)blKP!SI@|4evLJJ{OLi!Okti&7A+`cQ#A?f&+<}1~55N zL2KxX$x11>_F>LqoNbd_#1G#!=@WpBTq%Hi6s<=7H4$af(HZ4O_HUuWFxUmU|4E|p zf$7kQPjlSbY|O=r0V( zg*maYoliIytkZ7)&O<{Nram~Mq}*1eJyI!#s)c)X2R?|m#ap=N7(zOdvCUvF{h^(? zB9k1x`QY?;1}J*c?T+NpT7jF>Xr70(6poc~*y-nq2pW24A2u8G%c#R<(l-yqyLh1?o+YN)%+BQfMDww$+fSp#b5i6 zwa~JESPKn1(m>=u$Cmg9U-2A6!A@z7b;6bohjHW_m>{*v;Lb<$714IAQJHp}<=#0^9-?y-=anSNo*l99mPPFgXkUuqUNM-QZ1z2QQg0gsy2wJD4Rh1}n( z#k`h_GMQ+1OBmq(+sXS0F4GDxuVTTuTz0AvCjklD*hsFuV-;Os0P~9iY%mCOV)_>J zry6e*eXQHxyuO!mMg(;Ccc}NQC=hYi=~0{|56kb z|9P_sNp{AmEw}s$bQiY^jJRrWjBC@#pRDF%!3*ze5UGwJwWy7lAA*G3_IEU&azyl9 zB(!ymBtcwJn^ArUPIFg@gA6FRQP#tn>ls_WutX>;V)9XYx7}$v4-{#=-ynrQ61!dZ z@&O8i!n7f)>)cYW$>IB*19U;;Vm}u4M|fW+;Oq@Hsmo zjZ!{Wme|l#Kx}#CwvZGuU3Zar8pn`PR0xLlW<_RvR{%UpwG)9G6#S+u`V>PKsx>7d zoE1f9a-zbhyEU09{Nrmvd_m|lAc%>IwP<|KTJU;aOl$6RPye?t5GyNz5oUcN^1?-rf(zP=WPHUhP3u9O zt!}gwW6szVOT&8QI^=>{6L5`5G`I>QISW3Mjcc0FY%r?-<%Af^)+Uh34j5g|cxb!@ z^ST1b-uhgyEWDQF7P%AQQp}Sz`N6nW?Hm_BBTrFXoOTOm)X^89vG<0YweEYh2~}(T zOsbFxIx1*5vpTkef`ED%lzWFaFJtqF1j=alKgs07&idUGGaeVQca~SXv)9ougY{mh z!y8QGa4*YsZI!@yVVOX?d`W=%-=pW4empeVO`0?Zx6>O~td-$g6LPLO)vPna78uPW z1B(;moq~q*Go#>%I>3|Tn9D{M=N2Ec(>ac>9K}<3r$+k$U^LI>hJd2 z36axRnT0Bkyil}FZqb`nBK^?3T>>uBM<;S}RgY_D=c)U{)KuPmeL?%ggugBvjU}5F zD(u(h7mgAb*5DOcq^E(H0-uzLhgy@bkq4r)bMZr6h}bt7t0QySF2aW)MIj*rH*L`t zDMkYhpm<>i*C~o~oUBeUvcJOXNqBg z`IWwv<4xqQ-{bYz`LpIL`V6kXy+}4zY=?y_p~UL&bqSdS>S_AedUCPO)o!(XP45SF zlO)NQM>3}csMMzvZaVPwF&-UoS7ewzyP@4$&5=Xnlc7RT3d7%QhtW>XIF^ktd^xwU ziW`TzZ^eH2xT5;@tA(>wMes@|%qISOUh?e^Va%a)V+z5=>p&;2pCG%e=G(QU=?f7? z&%|jR3rZ!Bg%Z|@GQN~TS6eT)YaONSPwH-P>1kP3o>rTPzZM;gPt_l5 z(`(|Zr6PJ(__sIXlw)!+%mg3i|BZ{M zS6U8N&+Fj@Hzma_gBYH?sHCq{%qJTE^u{w?!xKS!@s99Db|F#X zC2WKH`+n$vZ$TVyrR%@|MbwtcCpK0xWL#|4qEKL-%%Q zEm#OvO3>lY-%(be_e*Nly2Q*1104QhNt%mS&>9i+X*RIMC)*BRA=9=tHAN4 zRpDea%!A#Rle?473UJ)?eWdZC!RMQXG#OmSX;?Sz36|`R6;fV|oQk<;U7_qWp^~7r zmuHTqoK%krVB*6xtU__Df0i#V70hE*{|)*+r0T>tSom6Zb!da=!WMS*!c=#&Qh6t| z&-Y#A<+@I8Xk>x2kh_32d(@^QsDq@&tCQvu4I)9Is^Ia0OmCfd33$J8oO%M>aZNsZ zHFtuA73-i2f}m)ITxV{*U!iaa{OgOc%l-T&8U9eIsU8t)UyiE|hDR7dy`|XksN;q! z7JHQOde9Y~V$Z_zaIpL^J4w3YvT62;vea6MTcKT$xivbSN+{4c)CIb%e1aX>qxlso zew2YG_Y)DG=Zg#Srszhh)R^iaZDLHqX!4?Y0k-Cy^}lF$BsEqZE5fG1HN46uP$G8Monu-1L03(>!JP!pNDi$@QzcM{rvix zVVpB(DkcN+JbE4tB`4!jmskqwPH8^`Eq&?2kFeurCN90L3{{?!- zgQuFoyEiR#4`3n{0jzO>R2jAuY8HAYM{T>@K`XZzoR+KV?3uX88gQGRjZdabNM;v@ z2Le8))D5Q*4efDSdQB1hI{VBewTs7k6{k}xH|sd{b<|uUZcW~DHnY7ab<)MK+3_ZU6% zT4az&btaR+udKgfif-Dk_+>xiAiqx5>Kjai0h@|?yeZV8K6=+KhJ5 z&jgqWDxpn{?Fg;sx=|#N2ryKn(>R4zQ&#jx<1pA#_dHd!nVpgKy`tsf(WzyB@*U&c1mpuu!&w85t#ep{p5Z%U zEzK65vCpaK`fYuI`@|3aXvCN0+D!uro5?snqf)ku+NNJ86=!X&#n<4q8OmQGs^a=* zbcbcnIb8#Tz7%g12F2l?U;6QWj31*ciBU4n$!>P3!4JErcsjxW&Jz+0Fk*f+|-jJgW}W)D%tIA%XAh9WGZ zgz@qJ-x|ChlvICYLwR6=p1)aw+uh8q{@(X`SAj)4>`n)mA3y7&q9Pgw1-~nZRe3~7 zs;7u3cK2*EBm2dcmXm-Jh3%(J>8$ku-vG{iqfM} z!O;E{!!j$m3r4n?%|B@WS#35WHVHw-5A3LyPUhyT+OIXX)|CCC1XgaS(Gch4HrKq& zyYHm^+mrVduk~21eFK zN+b46_27||vwNk%Ra*+l(py&fc9=bCQbD)Q*`H3w^W^964KpADwv!uRE|0sMz8~gd zohXg{M{{eey1ND)lZbH&tUs_arA0U@R&uSB9MNeljy;J zbsSeD%o8K@twmdWZG1T&`l&M&0D&||ftPkT_T&GF;gMupcZx;5S1N8eJBDD7=OH5> z!jwA;b?|>v`yh)Z2OV$lzrz z%7m`A#n$&p5KFHk)NtkF8zsuH@-|g!F^fvNlQ>+yO8{4&xpaH^Dn3vi@3)W{yWK(( zWUKgNPz@FK;81iFf?O^bGKoPhXt|20RuL5R9YRg;XpTEw1q;a&n`wQ3?yP8n&6+=(yi}$iUJtGJYMhxa4Kw=5B{Fp z#|exJ4}nu}P2%gp-y89ff>O6MvMlRuhXL`vtCS<-{WZ{_6KYb&tOIY5UL(!p%#TJ@ZT8s&nJ%Gyc-ng-|gyu%BB};&`9{yryU75`3~3>E8`g zTymjsgb7$wxvI)KbyY7Ai3s|XpZ1O0HB5|I^55)CoTgM?Q>?jNv5gc^=poIe;(MBK z?d=HqHlZe+6mWWcAxkXQVg*3obP{A=C@a6g+}H<>cpeI}2O~Lve}t}8dC19SJQuR` zfdV?ik}ij+umm>ev>eu-@`mvV+hvU?f#FnXp>^+E5Ej$JfGijpEyG{mV&hHT<_3FK_EmIG!G!x;?2s_p;HjIt9 z$=y}8A83H21Y090xjvRxsa4W5q4`?tG*F~cI;t{tkZQYU_w#!d+}Qb>I8}}u%t7S z@iUuUVJ#!ODVjK=BZ{*7yWB0Jpfg{8Z4~Ex$Rv;jB)>d0%-zYPr>Ut~sSElhb7TUa zbbu>>_dP0U-H#AhB6pRIE;8+`$6}VFbPqhGIBHc> zS2O64s!$^C@ckZjOu}bYG3Fwo%mo%b(zT#krQDTBQ{dtXp=PJu?&iZzF3Q)JNT}+J z60b;5`E?T?2=&J$Yd=!;s;^Wrm4jxphx1*8q1!{=Io1q~%qSOAWAZPd;Z!P|c<--< z2p}Jn#}#q(_~Xd?na2^$4TrO)>h%$e*=!L^;U2BgD$xT(W(mw>4Fp9m`m-vmh=qF& z-9J@-8*H_E4=I#2v^zI2%&=-XZurcI7Fu~lE2py53p^d;GP{zTgNcoki;g&ljj-X%?@ek7Mgy zrmyKbDQVjZ2HduwXA{%qSfY!ds6I}vxM(+|uOGZkJeal}jvK?XfE{YV`2!cRlcjgaRavgEg~U-CI z)C2$9E4eHK{o18X^Xoh>S$NFl5#<4(x1EoS>;uQ3dBNYG*DIXkSGI~rbhs9aR^iJ( z*sM~4=Yf+$Y&DPeW)hEXodxS>F)_uK{eppC?JI#cw)TF^vy^3WBR-$u!-d}OcS0;;Zd zr&z)UprGIYLqNR0?2SV}$ZIp7H&DD0ZyL%!rQlR}$a<`jmbuU#2d>z+1O^23Qm zmltj%9OnB@glkrB0&q+?E}RD~s8&}UC&?2~4)NrVl@b^z5d*$OzxW4#?&3SA zCipDHdVE?N;Ek>aI{m!6ASWf}gg_E{RatJs>QGA(g9ev9a9N55T=7Td`9%is8KIX=}tHA-31@ zo3!lJ*7fr_+GP0iH*ehw&m~YXzV@?D@RaqvSe{rUB~xeFz|63qHKTr6awI zS=(w|{K;FNzd{Y#d6c*C!#|rn#(6phjW%vmr^GFkxSe6GJ30*-XW!+9IV@ zyo+3_poG>Ojjg+?;ZxTwlbww}y!j=p2>yp6i%!tdlrPcQ7xyR#&LS&MOfnJ_-#h}A zTT;0E)51SO2bI*Sk|A3T+ycy9fllz>_wE-^_pASPcW-u{E9fMoeV?-B`?B zoNKVgFN402Fvjd13<$2QEtpCpm#hF$i5z~54?UUnQr@yGU!|XivgP5MG%#j52XHL2 z5VH>UGdy_rbq;Iwb~T>e3AtDbtphN@O1*G&GwSV7 z)MkNDNEzj+_Dxn98dYAhz964)j5#RaeDJEpl;zrr53dH8d@}Vqb}c}wu0{**OBc?$ z2WxQcdAgwv?ROy9DQTG&R2O!!YTy)<)vSqjYKo(}oK4oQ%sK`#b)YVz3}^|oFhG|8 z(hvl}E8iRZIg5DzmzSptsf5uHWPR2G4cXTuo3jm%llR*INIw%{RO66gt zS|tw!eR73FN>VC9btM~_)7e}+=sjU1AB(lh?qLW63?<@9PK9%lrUxZ!LZsZ9r6WeC z_%B()*A4g3m8u~N&*plqpr4LdgC6rTq*2~r%L)-|oPKG>n_!2;#3si@-h7fEa0Me2 zQgIn^?Map^?4*W7-twmsDfDhU}U1&f~rdsrHV-)iEXm zZNemc$LHpoP2400Vmse~ARpImWS<*l{O8;_*a-&V!6+!^=os19VCMJhjeVv;&YC-y58vmCJV^WyNN)Cof6PTP1&Lo!yTOdxau6 zwM9at7uJ`aSf98m?73=C&PDXU5%|XsibHvV)~@Ab9eeoFu{54tVNYiuS0Z%CcR#@Bh>Zht)C^+UU38jl9j zj^NL^bn$7G$`&hMOLq!**r(LL?lOZJgE}L(F66Gj;rv@WbE(Z|V92flo@BEqC(w~S znAubpL5pMdQU?i34|;CGpwXcF!u|>0 zZAXDqSq&B{s!g!z<-u$gOz|2-HE$$JR=FOAwq(XH-8GTknZxmZ!n zQ-eNZwIeq{L1*r9{hcH!Wxo7hOgJ-J*PqwgG_An(| z2{W5E=D7;{YR zC@jp{u${TH*>*rfkJ5?acox1ESSjP!;t5p8*&#Q(dK_2-c?UdaY*d*1sR%)piZ$!< z!rJGv&F3qm8_th`-mvuPqGpUlV$rDEl?jLKa>Nl-R~XxDP@PZ8j7$Ni@;bvM$xKnE za~kAk8ID+f@(sV-4?(tol({vaADBI-X#$_~0~M4v*SwYbyx>c39_hma!CyVlOl}yA zJ*DkbXRHK0S&{t=2OP|tLy?Qw+f>TulggF)e)^v2F$Fz&=e8aq7Q0E`p!lD~DYVD* zeFm_QV3gH7o2g-m(sbkg#hKbe=Oiiy^+niZlkYVTUp=6Ye6kXP1SLoaoQlw*jBq5^ zoqwLR9x?&SkS-C@HCxeMG4#VIFk4u%vrJgEy446YojvnBUlX_VXeI)BA{%@Mq>_g? zn>%NF*|*A5PW?P5ha=VVYNB~=I#05u^O<~np;b!#G(D}!-5SsM@>QL| zHO5NMV}#UBR2ew#ikSPMqGy_n4^lTvNz9yYjZ}rc&x4udJ|ysT8(2WcWqF-`APX8u z#BRW-=u-fq=HR*vKI-x;*&<7o1Cw{JckuXQxn+7?G*U^*DA7~H^G zW+ohai{~=6*sf8Q5L~z0*)GmybF5)AuKE-jYA&SRkxD2KK5s@)5=?R7^(Ogvp2&duhsjnv#)p_;?j~&w*uaJWIS)5dJ6;vt9EA49Nc#T!x&~a`y%^2C;h&c zy`T_QIYsM=3+?4A+V2*K0bp!Yp*^i{fwPiKhB$D}nAo0&a9}K_mH*j|Gu+M!^@8p-%JYp=(`j<8Iyqf zvos))%hDgIkDM!fWPK)+s&AR}x>xP_WHo;MT9A?OZ5)C(xW|p2Op&=T8r+z@J|0A1 z;oTmlo_N|;SoGPjw9EoJ#>Y)X#iPX1pu@G1)bEwwWzw59m-Nv6U0^EMqr%6NM`SWZ za_2<EMqiWTDy8T!V;CJR)9q##8~1Mf-iCug(L$xL!w?*b|lmA^3q%%mf%IrC-sZ7 zV$IbaY;s1U>D;cKmly=Qp;phndvY7-*{4Yvha-^6gf>?G+R@l>oYr6c@mtpueiF4} zrbW14-Gb+e*?H~}D>)+(rXfC!@fGt}H)(22H?Fbo`}=UCJl&u#F_5w8bN!Gl5guDo zqPil2W}qch%+p()1X@PM;saU>j2BO;t^Iz6%*-F~YVGC89>nhG-eOEhW8|!_o9sJ$ za^Uc*9-yQjK8I{&?MS_q^k=lFcZ2>9-fsu5LNKJIxnv6FaqXip3|C|4byev3>0Da% zq&d{>N``b2Bx41xrdBZciVb8^BSpcYY8its9FO}s19G{nq{i5xBl^pf7cr>y5TDHF zv;e_6cS;u^W`#;nQ*ObDU;W^r%Yj?NwhMc-`Y zi^R#}-Ma({%rMus3>Tu&>%iVjBfVwa^G-Ma=@=m^4PEQ21@FaO*Oc zd&^xT=XC_ifi*bj$U8l0ya9UoB22v_74&Hcq12Vc4iZ|;JrP8~AmTW!rL2^B zvcF6!x}HVKJ*qC(S+2cZPWote2*uCMOTT3-=X1rF=2mv5OCP+C$(V}Q{ zVIHe`*2ojYZ3~O4}tssSz(8-uIuUGf$TobmCej~%Fg*g?L&_Lq2f>M!CUB2l>h^^aD!1EXa2#@IW z*~Txk*+Lv+%d#$jwJT_-bK)*{mp1@K2sBBBut-ZN=t|`!HG$JO9l9H^Fw`Z)<-ihb zQlK89Ll@_Sx}sBfvVbQz(m8G-}dx=A+AaH@`HK) zZx=ldJmIzILcRyN^Fz@QI0@Qg6Ue9VR%`NX@waB9 zpttvPSRIUERH~{Jyn%LnMjJq! z!0l$4&H;i@1#DoencL02$#pvm!FYbYON_YdbECzezj=I^pyBMMG7u|de7Z^QQ$e*v z*4GVXEg7y#_Pn@Tbb1fo^rXvXpEdz<+y5x6sL1lrmO z9v1Q$&T<*93}jwTA@ZNt$nchTF|_essGPmgUD4YwZRsBg+gIKvcmI5+XqXB5FmOvs znLuf?w_@@#PKSF;0l40WP!8Myw4O&FjORfD6K#7@V0qJt)hI54DVp{_CXvVU*tijb zMW`;{^pQ(oCOGw=Ya$wT^zpgSqj50}+aMdKH)$2}Q|)AoP6TOiI(pKcqEHklNa#Ox z(O-BY#5l4{Q;t}S$X8G4WxqGeyGRiBm5t{n#!YPpA4+8FNQIUoQQ!J!K=z|16sx?k zQBJqCJPTe;{@PY4jVr?NmeisxPUqe-vm~Vply-JVI~sic&X3GZl;6ayUG^9HN1veK z0vSkCsrmtMeisnY<)OaP6i%mRJS{7~zOc+xX?5vOGjjzq{z}ks(Wey?WuRF23Xl9T zuA~vnTR#)K7jQbQgJOuSt4c%5{RZklJI##yvyHgg=4sSBBPkNH36A7)1i_M-$YkBBl=9Ngm&_J=;nVQwn6}2f@uE^mG6^&=kuO@!$+ACxzE1b zkm$0^bOz$mwU`ICQW)b=!A#g;{!zw=Ul7lOsS5Seh?V}zKggH;08F?NW#IM~l5%P| zmnG!FWMZ0k_bDHqT1jWf!uG^&dnl(g7|kR^+xffv-blRB;V0p)hjj?5stJR9{`SV8(p2n%-xSfN5omYMArEkQkeua(TW`CR^HZu-hsv11mjjV() zw8@??$r}cDj=t0^hUr4H*#(#X7Xf3I8;vRkp870Y=e-n3cn-Yi^LbzEp_AsXZfE<& zMh7{9LT~S+0x)dY)`Y0?dF`!5-qa#!lPo!MJarG*5S?1#YXAQ!p{ z3e3RgvtKpivHMpv;bza{<7TU+j;+a+j~sNSr&Ej%UqZ!xPQ{bjY_}!hpuOMiHumx{ zxQ8x&D1NE2_@mT>&ZiV)$o)t(+}A}5Z|tx4-|i);^zL0%b@B39Jp7hIpTasDm!zkm z5|W-Zu#H?>1VyE>Gn9UJ?8)1G5!Hl*i?kCoo=Bcpk_l>pX_Ts$&V-WdvNk|M$v|%s zvG<(@Dirq9GaaE_3la>3>`2I4R=jbCYi7)>`V_1|7!)q8Kiv)S*;_3rsgi3%s2qXp z0YHHbVK+m!+fDD<)yC z%6nWEKNl)r3S1FRBq8r!qRgem(AAcTD3co$BnC>QbN`32FC{Yt6y(#CBtv5 z;jw=|KtG!OCt*tZnTn}$`6n|;0zk_R*XdVXQBWJCzlKXVXPr3JieKPaFaUd%AIRAa zrq|ZzofC3Aw{5V&%=)4L5ZuPPBlnexeybGsjjC>U*2@7XcRQ|-rXepn!Mn*XcbSXe zR|7(+WX?e7_A4z2J6nQy z`&NKFAIN#QFEDA)=xRaacH$8bQ*EbKEp%0S776(5B0 zUUej}0dJlBGQB!z_p4x0D$O>VC2W81gmGi}g~?oShcrmIr?Jh{>#y@lOHH9ppHEI$ zMnR4?;@yeiNmW#U+$m9?TIW_b2>)yF0R3O^qaGO3~u&a?PeaG@8@`-|1a83o!%^B2gJ1N0W`rX!aMWCJF zOL6-76R)~z2_%A+p4&~GqC;CK!Lajp>2ngTmwYiPRWw+vfem?ahI&D5E~$X0eac63 zyS!i*v@Al4@7qj`RtoM<6mXv3$+pu!{JEi*S6>WUGoo6IP~edYxg^#LG^%J6LB11V z<$~(NR|msBv5{R&l}N9(cx`ONR^@H){&N=?qVlRNtbL~^w%H5ffJed_O&tZvb#Ii% zGs`DjOXrnJg=ZjI@2_VSTlh@zFZbwb(5~wA*PUv|qIpfO0rpVj0-IZn#z2rSytra~ zcpylmLH+K#xTQYcuB)LQmuW>dl>}OZF@a>MxU-Mc5(B1tylpH9aYl-c4r4=?@TAmz zTaCOp@`HO=!w=Cupm|Nf8Ny890U8<}VOrTce+KbVN>}kAp|>8W7%`(=AKuqZS9i2A znMYx+QjN`q@`5)~*NP9MKvoib@uHXgA&c%CXXK{n&dXd4?Ye!w&UOB%obuL2{?{_< zD^FAB+ZOgH0phKRF`Tr-S%t37L^nKiL0M~ggt2DW=`5d-YgHyCfueXUtZgsW>Am5^ z`h&H5XblmgE92YRXRtt9G*+rJtR&g?3z>jUVzFk# zbv;a)m`{k#-5lgNaUYKPSUc7b!<6SL{t-nT@sog~lEeMFBKdTEF3urN@liZo2~98vuI3+jgR^`;gNRP|+Ub5hOPV-w9I5=EPBHvN=tP@KQ_I8VD<;TKYy z^-9@cj%GxRT(~r4CO3QQ))g$Y67f1ot2)hk!7#9J)@;rWU8I2)@Ey~vUqj)bm|&@mHH%4Cx3>ZX zY%y3)4JD+a9HR#}tt`Q7E|$%BYv~aS?~<0{D|_cc{o75+o>;p|PM5;p?BvvcsbgJL zs2cxTd!a}{fHQi1LR%XR4rMPpwpaV{F8bh1QKAe43v^aUCv43ntGsgCjzbWLTJf~T zlSTQznA0{Q7N3|eW+$U2X`CZWL`A{u&$`+FY#N#t`Tox>CPQZPbN0H9I!DT@)@TG> zpK;vlaO|>(C&Ei#sFj(axh9Ycwxg0Y6s2On!`zG0{$tR$v&LLnuVhG*o#|^fe0j5{ zWsD2G^TyULH^-r&)_Fhmzcudl$mDBMI$HQbVe>LwrS)B(`4JZOuCgPrdZN;&|21tk z4SFSmPIjhW82XaWmWFF-d>1U>qD#F2p<4HZEz}ci42G_pWf|+QQpC<{ce!OXKQ zF+?Vl0eqd01s}H);~vuuqgX;*16sgpAmVx7^ob=jE>x z-4^eLNN1u531pd0EneDSMJ__7zoop&O_^nApiVx*zRbvF_F8|mgN_ecs$W~P3(Req z)>oI@4W`6)x?&I;@hasz!Somuv4G*)XMiL>uhI!M#x7dEWhl6tVlp9X4r+!SUzn=d0{i%d}N@RioXc zB-m|i`G&<}6{Cvxf@$}7gf;&EmDt_c#ri$}m=#K{k+ne$FZ)6hiSZ?atS=oz5M65G ztv4tyaUY173oW(>l0HAOU9@d&O*ZD@HRV#i=J2NW>3#BiVH|+q!^X_6c|JI?o81YHsffuai>p{IH$gRjI87v{K%>j@+( zX}Y+~zOz#oLDxOiux_PpeSR&nH8K2_-|}_b@%tp0K=|_xO`tvC8lC*;(#;Why6O|R zxW#h5uA$AffJI3k)q1iXW}lu~>TuAW$)lS~-DQAm}K%h%2puD<_-V@k`>@>elG4wRp9B zg_go9ku_ORc#^R=LTXi|;(JTs3_8R&1sB&p^rK0#5Jm|ip+fM%U~5J&Ru60lKE#^y zgJR@;_KfL#2lC5e<-c*}u3`z^tefU6qr<0jwIZ{=!#&5%|<^%(*h*A8z`C+5cEN}HJm72}=gLD3$4(*I&I=I=H z$W6&{i%%rh(J1M#`0XpZYvCdW5>exHTQm$BPl<@;pO6T%F}YMiffsnCA+OcFVmYl? zD4yI<87KCDCEc7dtCgQn(onY1niKyQLSSqWb+z;m_jg$I5<35zf^<>;W|;_*K4lM zE&sfOXu*%RLnv@NYy;o4oZeXWIX2d#jqi(z&os*G^3WUa#@@_&){R!SeWMp8UP?Ld z*+s~5jih8(u+*7)*Xl-zV~-Cik`|TcWnanzrPAP8UHgV`1|kq&Nuh5j*r)Q(UZsN9 z7@HdB{gnhK|o{XIBr=GfM z`r#M;$%#5$MCbge$NV>hd{3jk!0d>3*XNzWFkO$8f!NCa|1Ylk7Z87sP%1|kw?#Li zq&w_y@L70Tg8atuct37jH@w#=7#x*JpID`I-qgf=?skDi#$Bw7+)Ds=F9&~1H#rnN z0eVj)q@}~~J=&WA892k*`0tTx3Pz7%xpXwRs5K}4tXTi$Ev2tN8kH>OZB|QmatDb2EfiWT z?lzZv>vN$HziEvEXYBwJglrD&xm&uqGO!CL8RkQH$+RP$UK;?}0~@f>@{YD>OyynB zer^RtzDXqD#^V7cVk>g}9gdv(ie(@!CF#M_`X8|&7dMG>CD3b->#uq$NCdY{nm*)r zz@QqKFS7y~vc*{z_O``PqluTHX5v@GvFCd<{nUcUWDe9^y4z|Ew#nA@66bptq*zDs zTIb&keG#+9cS$v-be_--0$9LV7(aZHySK9zX*%J6w zDswDkGRWZ3s8g$GAAD|vlo_p&=!nqfmr5tLWP`p@UBzW+DnF+~AiIw8c)|V}HrmD{ z!kAc4qxqNMA1nr$T?Tk^)eSG*ccg^s_DJ>~KX7h!Pc`XBnHX+mv)1fZ3OHgs@2d4I zW+CL=8=7mMN1j^r`GltpczZC`4xTd`fwp-Xcs?5(S2^;SW%=MgpgMh)-#nuAgoRaj z_4&PMaeM`r`l4epW%ivwFcL!{Zk48z%6ehBkvEctWt@<*+21hF^L~0_2I)h!IEwCf z{h+0jKfl(0WG;OZyOn*{v?ud zzg|hEa9BpJG3q~x4aamI(GZCQ{n5VAJ6)e}uFty932J1i;=lV9qXY+CouZ5>C+Q)c zNLo&-S2s+ltz_|0B;}E_a9ZCSS=97;|4gqIeno$;3|HR!lelIkzIKFu41a#m+bX=y z!HVlh=X(KV5N$0Bn3^oJ{rPf~nL>qK{_|1~d4cF!I_SjIK0OWY)NH@FEU8i4K^MtS zhS*?cC203vg=&~?+r2)E3TG3EP0C`)GRJ31+{C$x4h)a2s6BDu}D8ZU=8Vp5yK0aaa z?n?+Ic_*x{*TkE9?*_kJEAI+x6}2Kd1Du{2|LtRxv`QfBoqkYZ!+ zPkfG0c^~_>Bgf4c=0OZP!wIUO<-7hCQ464NsArOQVCOx`;(@XN&sg2k^}K0#QJq}X ztkr(-d@rO_u3`+-mlQ;QEYfJs(dd?IXoRA)v1@$5`u`3`#q1nU=&-p|GaA?=%kGad zStP(RHR%tMv9w$kdv=BE>uuLYELoL11`+A-`uQ|~HO4QwkyT6|q#d^S>|V-@Y(eI8 zE@KH8q1b*0NszJ;3w$3Q&dXV8V@H&~#l+;#Lwa$P_zpOJHnz^=^Z34mk8D?CXAs&8 z`s)ZNtKsPk1+fWa-YOO-E!peasQlQhLP57JI}5YpS9l!3PRDclPd^BnSgiAB3QdiT zKBf3@yFKf!K!F*;tjssKlvns;8zPjpVLp2u{|^jpSy*i2l~VIGwuvFqLd@<1X1SCX$~MOzUb-eMl`Gp# z`n;g@NlFA=V$T>PU4>(Zy(}vPusZvxVFOg)P7U7k0f-WMf7j7!1k<5>r z59Z-$#n#VGEEx-3N5c`dsy5|!(8N{zf)$@Fg{@2+jcAAyUQtQ#j2?=!IuPDS!a2cO zngwnI{pWEU?n;SKStU|fz;dNX)=8&R>LQF8AriQAkdt8g)HVDVL}UX?y(ls3CZ?7z zN4hNL=$cmh@K^WK;w>@6%}ku9!qR{E6MSzY1Gbp%T2W1<88xLpP<@_M<6add?-H(-i8jMNJucONOyJoO=xA^@9i;NI8`F_6X9?yiyEEm{>0J?8VO;ULc_GxWgf zs|Leknu>Awy1)oOr!5qrSjL#ns$4`*sihTxrs+Aod&jK=m_MU1Y_U0`x`?eiRNB14 z?cRiq<^K}|j-oiL*wku`ZnE2>k8*um8+)f)&oWL{I~$!H?~3MGzIv)cjV2asG4-0p z?cT~)Zm%f@SfNQoAT?7QC=TmNnKglcj*AITJb2h?GKntAU(R~Y&K$qj*H2d?f6Xq&E6jNVJS%~WI!-bI?-vqiH}rVlo-*6zayW#t zZZVNz(7&TA0S_XQ+GD~z>6lq|zDcV`VlO95NYASnQ8d+o4)4XTSCW968)>xiLi$9L z+7MaQppJkn7^IlRVv&qaYjFB#9*@1gLtArxc}@#YfKB1mz1{q-);YnJMJyxyzlhB|ACEE6Gcw|`^RFI(7;ma= zBOZYu$g$u$?c1T*OH{}g?-!}!gRvHKD&d{OH0t@sHQ$QF4LV1lq0XWwy1xaC28D83 zH)=siu2X$H%rlwI)Hw{f%RrY||6c{W-X7T*@3r?&tnKn&L(iekVb-A?shJ zn#hh!A=dcP038fAeA4M)zX_nv#ze0vlErQT_;a@O8{;7lP9ofC^tY7!<6UmmpVJmEBm`+Ekl*W5_`c|({Z-+UhR@Jdzo){tD4DGAnQCT(%mVOt%vGnmIB(p?MUPqaBKfH^c)Qirjix%Mq`eJoRyKHO*D0JKvS_>3t}Sn zXPt1!@=iy{qZ2^NYfwdoUf-vDRM>n|=9y3>`ia&k`4|NNLb~lrT73=Q z5jzxFd-)4QScpHHKZ}5C>HNtK!jTnW-fh{zCZ!tyF(g?CFr~WgIFJNr?(>JibSR7)?5-gmCiu$!7`v zBWl2oo|T^kDpHHoAY`8pN($w^d1h9Cd>SznqoAHc2(pt(+r{GO4Gb)g`7q(_@|I=Y zu4{bK&_+fp*KitGcq!Qp8;E290oxgY2{q>Vp0kv;?0ig)4(Wpfa>q~jR z({3|k)v#U)L3a1<+Iq&GC3=lMw$S%fvRS3iF7*gKA@s*WbTg~3l*P|gi( z36n{2A*XXzVN^8L0_$%r!(02ejA6{?HV3&~oS^71$EjdR=mOq?VYI;qOML!0EZ_$K)B(O!VtbKd^i7a+fd|I!5J<;ORVftit z3`J;|5H1?IbvCPkFZr;{{=(t>3O<`XY8*}%Q6)@S7EvH{yGr%6b(2y0`DD z8Nnn;#Kg6ksV#HgQz@zyHyB7>b`oqs(^lXm0aI*Y({6~Jk3@dt{#!WmS9<^-N}#oE zENDAuM5oWRM#3VQSd8NnnYIT_Gpv>?#gy^{$Utf~C3%83iFzTe3xq<#bec2g9MMuG zg^Oz~j{h|+0F;NsVw~sY*c&D7abHrO4aDlRV3yi1`MCwdg;F)*KMtCh+=fIAu?B_$ zcVXfat}1*Gi{)Axlv#`GDjo@Ra9=z|F^M9>?bN-}^%c>gw%|e^OG)c3 z84(01 zgeX)$qyD&^O*=GZ&o_DsWb%|&D}hE4zYUCOG@0ZgEG32Js01tK_cKgMl4?IMoD@>6 zVo$)c^Q>we1%AIjRlThh8Dd`|=?svIn>bQ0nry}6KarqY4Pb+zHGw>(+wn6No)5pwQi=KciQbSzt02o zz3i%Adls~?UVD}{RWW2!4p|Z08196*S*p1#^+e%C;atiW?W4qbAGyG(&yC_!#b@=>muWuLy<`u#w*=y$7l@5BvIiV`G*lDQ>R$Iq|p zxFvtiMTT##nJC#C8rX1mB_#l(ylLd-HkB|^>MRGpV^7VO6oy>TTw4Fr##G1VmLslHU!+gdRv!p>`>ve_M4; zfAewzq(W*jUPA+tQB_Etov3h)(QbEDYyIFor}yS5t!c1LJl#RLU`H3yCbExUfhGEY@Uka)sp zYhzugJDM-2E^2v$!b@AH3r|Z0qVZVV=S{dmnS7>D1QC3}-;|2q2r}-xqv0RSo7hNB zW_2kk*jymMM;yu1`72(JA%)cV?g3T;=lNb^kp^!0Ls2TLOv1$RM8;!}e zmF-oiW$Go)Lg8B!Lm67!{;ZsBlZ}#BRQAcTC6>CC8aJ7}jb+sf8E^1ftkzi54l}#~ z>&_L#^?GgW_FKOqnTV!d$UruoNTuL81~-zzKpfn;vSzZg5JMWIm6vX%o^#lo;cU`j zGP&FJ6S>)BPqkjd?8hyz{bxI@)yac+Y29?;rLk1Ptuwj2UXv^}|1>rIlM%fp6u*E# zVDDuMrwzF|4Ma#n2QGUmA$!ReZ!?Bl5Wv!ZL`|J@%XFq9cof3t91`u2wLR z-C}Vi>M*Od=_p0TXtA1AScL%-ib|G1(z=>6^kA6F6XLkI^n^d<6}3`PyH+Gih-z_; zMGaY0c=YmwT<<7&B+&aEt^~s&1#yfo=l-R>*J|@9o8-Bfj?qrJ2h6;jgz6sOqHt!- zP>GB(*fbK3oy$wefb@`*cSv^s)H&5ERFfYedG|B&YiU42JL`VhYnaIAbGb4}g5G!2B9Kibvbm?T3ry0AMLzh3)vAadD3>^o-IJs~ z*kXNEPLke=FduFZ;vk_;kw)=Qw@SC{A^pUL2c;mCGKpd4T7JGTK0gy0ADGtCnpOTy zDg`C0BM;-e_mIFQI7)YEBiYU_qU!RzeuONHzy<0fV%|wTI&3k+DCV%OdGlN-K*y5Z z_HEBuw+uu=p&;r&?6&hDp9k<^rdymEwaMgo=8$Hb(@IJ!o(GPzq`DJ#nQllfK^CWd&4U`PX5BuQmzFipb@u>G zw&36FA7&QJ8OEA{bPEjg=r^r+ewEWsw0QD&m$sscpS{_jHFL|sXf!7IcdgvMI})~8 z7Pu7Z0uXVsW#Y;I+en6;RfZAiTw#*@_SuIs=b}4(KKuEi128~6Eb6Mun8WEyIXT56 z-D(I51ZjWEy)42|m`_UJL^jL6)2WopSYY)qbFFbQ(?25%Sx>A)w0StG(%R~sR-MIT z#i#i-d}34Sn%waP(z zhuhqIJIR_>J@;l9F&42rP2%`b)xCFrk}>4?PDuTaHgu41maFsh_MbMM?RXdwp3B-k z7`dFwui*e^U&BASmNop93pE~veXx(k*j+-uAF&W)m{`<|{)~wXl9HN`RWcd4&>&&0 zP39ch|LI^d#?PnZFsYQj%@3+IgxDYh1aU!3Px_-CDOi=zs??nI|N4?8+T5{uZ3u$x z21BZUFmfzyHgZ6)HFC^hHyfHln(WPy!hM#Iu2ki)lN}%m_88Dt_I9yl`RnZ+cPUuZ z%00a1kGcp;=!fIl0Gzv%@ z6RZ|EJKzlTy9sHH(`V~7e3Knoof!=KL@^X9_&AcB&{CUX3kSyc8kmelpq7`LgD!_k za$TF>KdG_vgMbK)GyG!=Lx}t%FZKJY9$u&`UAY4MKAQEu3y0dbe7^zu|8oFA6e>_Y z7&>6>_dJge5z!LsA`7h{kVR2^S_doO#aWGa9(P8&okXfue2_1YMrW!hGD@WS;7f5; zqOrZ+US39IPI+0?*mqsB&sZB`R^JB+pWvPyy20a@BbA-d@7qK*26{@YIr>BOd8U?* zdx~oZ7>KcryaeDtC-BR@E{3oQXPwtXOJvNAu_>qJLA}2nOa@!?FWY3&4g)^Ih>R~DtU;BQmNbOF3D`7hZHVtSw7kF%M#03;B;&-wrrEF_RB73 zn}Hl;YL}pGYCty*f;(+Rv>^NgEky!Jsenn?COoM+`G4b7#=^9#a3$~T=m4`d5cGNO z{JQ887F<^H3MC`KXxt~dZMJd&JOu(_L&O}mvq1utgrnLQQCo^;vwdzb)Gt&!7w}?p zmn&$$kSBjw$LX{7;0mIyK=A|Ed|KFu!SP=Fai?Q)@I&Ohb?7YE{C$g|%LpOY@K`r_ zy#O>;qez%?h4xsME$ftaO@b~Z!uH8o*C+k}V|4XGIosK!py$2abB%B&%FN!7+SYN< zLSrSclCdqc{>+JN{wITIJVeyCAm4S_;Q9l`W^sEk7)?)v#rj;{6Nj)3lCnga+gaub zp-P+1WE(!eS&>JwlAS8+A-aj`H}mmGm>H;JDta8Oqbtzz<$he*+QMuyU(jlQRfe!~ z+k@WrU(=M=iLuCVxkachf$?hsJR@V7b>!o)tCNQRKR%jtvbC)aLeGt{!R*D4(Z>9M zs|ryWgFpifa}+!SVXGavEnqIrDSFefb@U%nGc4_PpC8z9n?{7V-eV**WO_3KlodBY z34}r-g@38Sz6AA{&OxNUK`G(Wx>2Z7s-~=5r_jn8##e81E}GihEGL+ItVzU8AqpFq z(?ijo-{qM>!g>4aQzPi9QG8yD!|*KEl-8IegVNd5S?#PsUcR_i+jX(wMYC4XEIH+m zO@E`|XVg)!$vpKL-I&mTMVE87Bvsy(LI^buC1 zq98*8?5zhKif3cd4!!Q=+%&@uCs$5irQOhkE23z-XZumZm`6OlT0RuNYgLdddld|Z zy6J<4xt3I&g9b{MatUAL@w`g+LJZp&>&7tE< zr|$T!;2Gl1R;hov_{_pwS(2^ev%y-{4Ua!1K+G2rJQeVp9w@&{0^epB=84$|L7?M~ zj9GUlU1}%#ES5uePde+Yq05%L@ojr(!3>ubiY(AFX%6to=ECvHNG#Cu;v8#3B7vX@ zc!_t--be)0lo>wW94dhnrCEogh|XX?GV3C373oEJ&1I=PRp=UO1Drq2O^o!=$BAiBa(Mu zu~MTrDC8z1o0C)5Ht(g3p%J-teLhWhpW+5zYj9 zC88w&N6PSq!tS?-IyBY59fA$!Z}ucl5Tn;3Aw3fA&Zk_E-;a!?UR>a2ADPe8E0wFmJUB^Y-DWR@c=fRwyR z#_djy=~5OvvN(a)67YE{OtyMxNN;`2Su7r8uLk6GRG!+*t23Vw?4nZ3(l^`#H5TTw3u| zVaYSA{Tus?f&C+Z+UYvx*(!$N?YH?CH!Go4zhFkk;UD|a9jXxsBB9I<+_=m(@66mp zWYD8-1U5Eu_Gut|wsgiupw*QD4t}p`LToLOlU8gtyk1lyPzY&Js8*}E(Jm{@NH*D5 znJ!6*-YiBbv+{^%THcpne}BJWsHz6ftb4|KZ4NBVWk*;L8%ruH(XFd4rukaL;fZmj zG<94fe9Y>kO#DWnF{vPD`uGnZ)J<9TLCxTB$hZXWy08xUiz&F1R@7ZJDs5I7icKfY zL~q7K51GC0%qcIDN+8A=@cQFep(OCP`>sC2ABXZ8p`ndZ9m{{7zHKgyYDm}ePFAb< zPTgrXC9glr%yQ>cINc~yu+;Ba=0MWnnJJB*9Jm*?Q_Bn~bIK~weX}W-U)o&W+Er8l z1zM(5piKmY)r&T^2gx0o+);`W9Q%S0gUOT$l95x9!8Yjh;*sFnnh zk6H{PGVnm5p>3)!l&iVgGFfYkoT}BwS1Q@e81`A?xs8UtnRwiM8tcHc+ghfY8YW8g z9R6gVL0iDij6etg@?|B%8=c;0C*s9=wa)lZlm4;l$2~p4v=djpCl~87pJcM9Hd{MM z;IGd+3j}wqIhhCUi&m`YcozP?Sv@a5JIz|_s0bzk;Jizr+OXJibS_S(RG5h?uJebhIV}PrTr8TaJR0Zv&K?JJ%>)ht_(nY-T34Bv{ z(@^-{Y;Xdp)BE()D2hn zXU4EVaCMAK-uH3Y#%h*s9bFOymUc)OLcQ(hNq=Yo zh?k|}=H*;rzDsklN>hKBrP-80ZFhgnQ4OJ!E6(Dsqj$JeR}=e*XCYTykO4gmG|rAR zBL;J*D_Lj>@f>`M`l5Rv5zs>*U{;F@(3V~g6a|}^iNukCHwP}<@KZHfLA|=q8f~++ zg&iBzBaTj=YwFbQE8Va3UovFGp_2l>01aqaw#?%LWefiJqm?z#7ui_+Q^TeAj zxW2h~odmIQz(P`oHl6djx)cA-Eva4nqa(^0X>`?f7G{ZYx?oh(-2D_-h z)Y?6DIwG>B4#Y>tGid2XFy)3SxNA|!9=Ce?%IcQ&9>SRVLsv}!q{(c zxjx$SPJ?^!h+-O*ee$xaaR!b?)~yD-i_#L1BRCI(f)qkeR5NC zl+6a+tmXiX!_^Dl9V25HhE|3Qeb~X6(Vv&fO=AILgisTI!2Vl!UgIgAq%mJwKdx1>5IatXxQ= z!m6$#3dMD^#cYc74D0Qg)8{FXQ}fIy4y1wW z?pKOYA>!qmVDrwZWa~V$)MH@%|F}#cw4lA;uMysQ%eMzLnBJ3_#|Qo^K=h^vd> zzRScQC`@4$*VkS$_wdvHf*AkD)J3dT=>RyFq7uS7W;gh{Yo-L$ zpDP>&(+hTcmrz-1;m@r{PZ6w5A^9QW^MxcQ@yj{1c+!(-;tQ#7*;{;z6_ANRn!E+# zLyq>Lak`f@tte5}O4?*KTab~aPItvP)YSDuSqxLe{a1mZNw_yamG?x#bU`-Tx;H3LocaDt^3SU(uZ$f_>4ueU0fEhLpYUu zMBLWAlmZX>!6i!?Ee0b7bCg*)TG2%*Em<3RI4oX7MDax$OPa>+$B!Q+j{GpI zIK~c%bf(+b@xuEAc_EApFoF+)?ZGu|NUZZN7*EzTluVPHpt$SU0jeJMQWO1PG}sQY zWKVz)-n(t4CA&!wpGhvJSUb~vxb5d41;q@+}fo}1fo8~hjLePqT}J#Tm4vq@=O4el%jQK-FP>!&t*B;J*HP2$nNV&1tvfUB(6*~? zMc7%#$^~+aKD`|kh=(JznB`spfcoq@oCIK}%2~ES8DHM+0%{>3iN@mIXnWa(IljcXE7E-yNzBlpQiZ11 ztHp%c^9Czdtk#!(+}XxGPz1+2Lcxi>dmN5+L5vl@++l~2-KyI;QoWk5&0Xzr&MK%D zAm&nEka4KWO!#}FZ@m~MF_{1_9cOo48{8~kLY}V*+2gED5!kWRN~>)DfYEGFFG=Qm zvL|s=1Tw}Q)_FcANsu}AQRvh~BHH2qlV;22+?m!Bv&d3lVho zg6nU&cK7ViYU}ETAv={9-IF9}lf8V5%`uOQ!dg{Z&K~nR91V zbiz-%VC~X$t3!Ar?w#3!wDjNCZ8=;G_S)q$5<6~^bWxh`z?KCvD zL_^DVEn|=f{BD4p776w};eLG|On+r2KF*^CmrAye)hIQf1`HZ}PSvVdTYkflTq z_KvP&;n5h~N!8-NO`cOPcA#b?Z;?2dN)-su%UYY?uj=(hpeL5HuT-?F(Gg~Iz#0#f zjU=OyoXB-J2&F}thp&Z1=c1jMF8y`M^p28Ks2=wZo7+o4iFNr%fGaa+D+1x+293#;~OF(La)=1!-^z zp|J^BVCd>ir|$f=$3kx|8D08Mv&%HoeRD&R`JTk=W_eTr!YMwv<6{LPy0iR%O zu7Ka)nIBW-r{U9Y=l#6jXFUM}m_`iND$!Ge?fN65e2u}NwZJCE+vJTYftcc&8uzVd z*7W1z=a087l-MKtFxCXAtt@4 zdROlKnoa=0+3cLFmnoDAN?XolI32%-2u9fnf;$Dv8vILS?#w*b|FCppA9Yj^h0P|@ zzw3>LAaszG(_T}-{Y+J+T%vt~au>b+eCiAptkfiGCeo5QEedWhkR+v+@iZpZh(rc$ zd9%Y;vIq`;F?17t;~S8|o6h}>7zY|+4F=*1eTM7)P#l@r$&%yP*2sHOw#K_v?uCd< z|JL3#Xr*3eA(ZV_>l>l)TphUnt;jks)}-v*_kWW>RRG^VWCMq{ue-ADx5T4$-gGLJ z_9`SE9OhNHnRe04Oz)|gceyPO8CjnRfxl5s`lq?e#n3Hx3xfQwH5y$cF`IXBtGpM; zSXaRXFXsab#6DuESI8okEZ#jf77az>Zw`HEtZuJ8E_w%hOXm7degFOtgi`V=`nyc`Y3OxCn`#cKpD{3@!J@^;> z>zlpQfNe?{T3|Gh$a%#ssu|kI?jLA$V7Ya$bFW_{UUwhkJZ5;p2fqpRyy?uZiAUf7 z9P%T$VR!Qh#9Hst%3i2{k0=x$=z~pS`c8QykntBij>3{%#2T{Onsh#2L2d`~)d+$5 zE57aKuLs^6GrehgkTuS8Z*7vl9(>A=_KQo&3i$McohO5hSkd0b^7sEjBLt|<8}mkrr4V!baMj^`MgheYivW(xJ?#q1Ku z{qTa_nyad8dAn2~5E(k>e;CC8$A#l>#95U@xFwIB5zSYn18P*xgB-zTi@E(IUC;UOS`MX8+ki+4ZXDpVd{9BLW4u^Oi{&p^;kwuptS)_NRA z0V|#V?YHh~q{!Aq>N^Ztx&EdsXNLMxiS-8PrHO#6jXydOM~ePMoI>KmL6_5J9zjk^ zv|lVzR*UMO5GY_D4b8=`1XfHasf8TQ8AoGVBTmSwJEG^f0BYb#pgADF`1R~zI;vCF zMyK)X2NLZx7n8kBo9xvskfPHJzGD~9XtQIB)RT-2DzRO)NUNG!SFO0lpxV*+g2!_W zabia=<=PAIKZL4bq~{!gwJAClOF1qGCZeTmB%*@O7 zAD>x;l|9Pw3@~~FmaE1`B?W-Bzca?y}u9%&2xMV~;UNgxF=r<+>SHg75 zvA}$w=%M=Qo3h((1x?)dIT-iF8ht5RB&b+13QQLm($bj6n{)Izm#`(pr1?u3WzlY3 zqN+&2$%D<%bT@=V)*%}Xl`ht=u{Z70JMRPwAbx=5_N!+y3r7t=Jg4h9rnoS(HEz*G zdu{&bd8g&eA_agaIf3|W9f(9?5I--lUZ?@f1dLIAHQIN%iBAy5{I?RS>au3D5m$`g zLV^)@v_T^8d=-e#S(t(Il^lOdyaq2q5E2DLpl=y`vic!lav9*uH)ya0S1U0?5mmk$ zJCXQeppcoT2=7E61uxIbi}(EW<% zWaRwXWIm{tg36yvh4CV|8t|hMxc{tKx#noo#tpU&q)yakiz~%QN9x+{|Bqrwc{EtS zA&(n|{Wt-Bm}=Vr_n#vu%x2My+}a2<-A#9d88pI8EnhCvnjdG)@0OLrV0olD=g%Pj z5Pyijz+bI+dGw0GZ2n{UVd2~nS-Fq@$nfpqo8{&5Qu#;uTlr^s@kpA=PnG?sygyX( z_w$ePC;5Z?G5#!ng1^A&!zn5I=#uKBksbWwJR0eMphkAwNC}=b$?2y(J^r)UU6d{K z*UrpQNJ!Ml@ot)+^ubl^ifPp>dJ|Xb&?i-CJC#hi;_mD8S45!H8YP0#)K>c7(J4v(o+GLf-VSt5qtt&j^;|}1hfY_1QnE|hs#{6Y=bKzNgMYvLEek@zAs%37%l%m}57C(log}7j zeBtGL6-xR28lKWJFM;1KLg?>FaQa0C;)A%1jYE#hw4|`>6`CH@Po+#}(C%$L4g5Oz z(OSLD7BYf@|d7Zsl@7{gnGlG zY#)rodT1qlbQW!W+FxSYsL{)ubhtNMqP6Mt z;^>qm_Fd;ij;1-W)=k_|HHgWD{L!uP<}Xx?o^8EX{T`s2qQOTAgn=^J-@_ zp4$s(x!(V`9V-}vnV4kq7I1e=lG*0cbU&S3_4QkmwdT;2XubSp{E_VlG@kic9Mi1( z)#nvBT~oc`>xylbzhPTWjM}JUidm;bKseM+R|L7}94S2qjY2qN+!s%X|C%SrQsMNf zwKWYeLO-nhh4dg_m;(`y zL6w+Q-CU{ul2<@LC$#%b;iTU27C2wFO6JNLC-Tc|H1w14+!_x_?Yrdf+fc1>&!3=l zYqh2NLJ}dD{!@BIGFD6`PER;F&1UOFgOSeTSVkkesr0Nq)_CB!TB7RY)G-=gH0uZ0 zJV&~j-g3%ekGWmPkSOj!&z;+pmv(bR=Ow}1Q5*VEwjPfBd=lbb26I*a5|Kr2Vx&~K zIWhUcuTW#3W(VIJ46UD8am%Is@EKi9%|uE_M!AxwNil+I**yGpoFodX7c?0-Wn6vc zHOshO``!Oe6)*1t36)Ask+?>IDV0*$B9n(J)ph8CdvS1=3%#Uuz$RcgDxmnU*T*LTHcr28W` zaUKCDvQb395kXF2m<<1VNs-vKOi&HC%!j;1`OTD4?!_NBnOfWe32ZmuC|q!vs0y!U zp&R(i01^vr0Q@WYS2!cgT)s0B&W@hj@0lfBt+qy=^N)*}TWWj~ls2k?4&Xr?L0jTB zaTVW>O~~5=H-E@W-{)J{;$4GM@_Y0?YhPiB)Txp~HJhzb!8nfd}0fflWc* z271BgLg41-Q1?F-yaft@&y;#Br(B$bgqaFuKYYPR<)tY{#_rRksHA>c%F}Kdbf3VU zB6y}7?4jY8e`q)+|9t9=9X6Ph%IWSa#mQqQcyIZ=k(-uKA*fbDlvIlr8rPULw0!4M zH39*=ot^Gf?uwJ_gWXj^P#%6p!ds%PK|WvZ3M>f9bHM0}Dfr%tO;zJ*!yHa2Ui(ch z>HaJ2wsA-J0|RImKs=vp1m8r0i)C>t$q~puM7KTrc^DhUUac5V>=xP^0ypzWc&ZeU z^ljfHxAi3*5XZg*NPvuTImh35L{!<07s`6w6h7)kqs^Pm_)@Q8!ebgTh$SnD?>)Cc z=_r7Kpo|i$taLEwmIq_Cg)(O-E(_TZOZ{Hy#?m#N@5F&nTyL(hEFrqJGhZ{;+rs6# zASo{!DfXT@d#BZC-tKaH1g{aPQYkq zXsuk%p`k&PK5rW?{-2O1Ic;@dI)QE*Fea>s31U>M#!_SXB*^ zW2C2C;T)cINk`P>@@hb+;X71SBQyT+T90By%4K#9eee)|wZ~)0r8KuyNhP}gOZpiq z#Z{afZq8D@zO5?y*&EO2z&Z90X9$TzB0uSTJ>*>&dy`v=BKH`Pfb zj8UejVzJF6xV!<|A%akSy@UvKK}A*IS!&)Di37_rPEaHmUA(;42A?psSg?PrW z|D|t8ioctBaqwCR+d%LzX*N=@j;^~<0wY!_Xr$Wrl--zS9G3PO3cZB;B;l}2JhRyN zqJgL}kzv0hxPyfSlI-S-L&lWd@Onb~9g(3)pT=7HdY{gwCd}f@s$i zAPFM;d81e@4kJ@hlE3-8NZZ-B&EGn06laASZsbgE-s`b?mSoJ#hg-(kp^~#`cZtbJ zwGj{;d}si3%dtR?HXC=9*kc_v{u~|a1rn2R=snX_K{*BEt?=n?%b!z;-ExGU5?mry zKtgydC@8K0pTw&Yt5Ve4`V$jD5;pntk`;@0uZKA*x^WLm{_1{<97eAX;7m6Kf(YOo zej`RpIkB^gwmnFe*j(F?mW*&3aH#GXZZkJQm!B}u+DS2u}^=b@<%}fQH>AiaE4L9K~ja?G0wu^>H zw|p9I)B9+6C=}cxzeT2T9{pGs$4=f3-WLeC)QnQ6JSd30X@cW`)`EesRD#P{)s_zU zFMq+Orm)3Dl%ynNRCJ#nnTcQx&WtyS_Xr5ex-yGZu7k8-@_6FSqgP7ay;0%ms&bo+ z$8h$D^Q(?JX(X<*)q7K=)ev8|{~(^%-lghSO~E^XAAp}c!Z*Qh9}x_N z-dLzC-$x52RpyZvDacm=zt;8^kmhA=^H~s+3H%LgzxCgCGzBovVcq#s)Ys%!Q*FBX zKOQn*rBxnc;&dn5Sbyq$E-yCmiwE8m)3uSuEv{#yJe`>?hMY(*j zJ+0Z3C}*A4$UMu+g#QryIlI?%5eL!co$-W;!iqH0Gy8EWB^;QBbqF4o4LHsj#&MD2 zqQ}Kje&*BTi8cCA%pc|pE_ZgsIFkqcp{hP)^oXM1)7{m2?Cc&1#)+Km4Y_}JVx{<# z4Yl?gO1)Ka^rr%(pKx)5!O%EwL8!kJLXxx3sJW)fg|;xeNU#PkUBJ(C2CmKI5H`uf zggmuHn z{D7|I=Ugj{5i;Rivg7K4#~FvgceBQ|nH>(t^kMVksU9}u3b5nKKO9k^Yqj8X6Q(I) zfN0X4azMWe{v2{N_UkGce-e936cbh0)`^gXj zlj%wQsfIKEv5l<1yy%XVePQuMi8DzQhiUg5-Jf zy?ZLFX*^=GMq9ZF3P{`&6^n&> zat<^El;uQ4zn#|w-IH0K%1WjBcInbAv0<%J26j>`bZ!JjlXTSKCqfJ)QWypUs#Zi# zDVfO+6~I3f)AlEhJ=N^&slT7~CW;7`V{>Q4{tOGNZ@~SxFXrFNn~uj-pwU+XX`0|Y zgW>oa%ywZoLdm1g9=i{2zQ1_v4$QVHUHGD?7d%Oy#^+$!D_r~f! zJ2}S(T#tMh`Ald z{v13GD`)10{kNv_^!UU*d(l z@#O78y?bB|`JB;gV$y>L`XVG}%gjL&#MASp?f#X<2o2d!k4%9WOWmi^sUGf;0cKK6 z?sspOIi$m}kO{JQvE5*|+uw-zTedVcQ7=C{D?*pV>bK0zbJ);Q#bTNI5Bm1MV$3?# z?;d-2gLH8$7Ld)ROM6hxSq?aCFX?Bj18Z^UyMq!zLV`q)eAibQ(**thW7wjd%K#Mf zt@^&|Nb|N)a*5`m#<1FGbvUd>uv!2xl%a%DBt(|pk&dRD_dAjJJ6-1%nq3OGD~Fjf zMRk=pO?7&8LI@=f``W?E$t@*#gos5KvD+U*36 zS`F%9ryHzheReVw3a2;@nzHdLgN;tdrJ7S1g}@)TR@bauP;Zd6*>G7p?&Yj{awk@& z(F~Dzgi;v1(U4OQ5??d|frv$dOT;CtWU}aebuOjO*s+mu*m>$sUaAmo6h){17Ort| zkT!!z)yn3azT7_h+ja8;$cxfSJ5QItyz-^y1@E1wZ}f@NI&nR+^wLLv@CG-2@&)y} zsZ60q_JI7N_BUyVHUc|#+ED|bHnqA3i}`Y79_INtfP!aO&#Q6|cPG1&v&* zeN%Vu-w zOaOhCo4ozXlzh(mc^7D#hi{>}IE9fM>q`?*|MD!Lvn4v2A(`dSFS+7@XAFEfX)O${U zY3*Lyt!`g191q1?jB^25a0G#eI!fki|2N@_>KiqJ1L{Q_j&Q@$N8K%P5j%bW2qQf@0B1JRyW@ zxLGjlnhUynQVM@Q&#E<|!8y2aHH>n@dBW`?qYlH3tIVQdl;9OmhuBHo4vqZslBr_C zwuBlLrWJ35QX>tChNc8p=t0ZL)@%g!Vm?yhaYI1}xl^t<(+YB4PBIbhRJVbE)?cok zqz)pCVym-05w1od`aDw1PySQ+$e_T{&j_G$wqhp-gc=7~RonW_y);bmup!wYhfrMN zl8MHeN3|)Q()Zb)VzQ@#%QLiLC~k}q5sByqaqB!}iUyavT&a^KU<;U+~(&G+6J#|4UlSv(uqFkE~`ChIFDt%+7hR5oVhr>iV2S2C4zdD_$(vmgXin>ZSmAZm@#=?z%a&Qv!Ekv^_@b( zS}?A}q{0ZUSG(Va{t@7%i91j-)4R-sY@5?*3P21(BHO|7EE+`I8m23Nq`Ij@3jXhf-37=7@1QJqAH`|f zze#@Pu_w25ZI$Lb>QleED-J_w64v1Vu3$~d!EW~(Ts35E(-#Y{h0V(s3N%`@r~#jQ|EoJH z6pNKQolYqh!*lL*ZK-nmjf+xJRF){Ar*C3^pJ8Ljqbh5-8%^F4cKDn)}sO(gxK@s)WOInAiune0r3F7Fp^U(DVULehCMmh# zf|VtTHO3kU)F}Zst>Yyu#~8h$e2-1Cj1?g_kMyG|Uh@L4H+VGa3iMJ~Jo=b@=&E z(5m5O2_y1f-oJK`Lq~3SV$SYfTESsg^MHgST~MKuG9E%Zr*pD6z%WHZil+!nJ_k(< z))gL%Qh9;1SpY*4QdukPXEGAP)S~?FG$}4+f^?fRtHg*E54ZPoT>c1M_xknc8+4792T*&4DuNMWIvL;=>7SNx)E z=BFwLAWpTh4NSS}NF2N_B_o~1R$cIp?B-r&k^dTfv05ng*a@v7l0Pg4AkwsT`dsvlTCi9H z4ByW{ft3B2iBXNi#Oh!O?c&+kH$-Ao7rpW7iG%#4}YDm=tv{|ZdJG~ zqfLEcnv9gGs;4fkbBz0*y?Z`augr~=WBX#JiB0!LBoSyoWn#gd6pLc{edMm{y&EUU zB!Je+748sHX3AZOH@ZL(y4>hXMhH+8bH?SdXp&Zv%%^yLmo{T&>VM3aC>}lE$MI^G>#2j1h$ z?Nhl8VuxY0yfoe!D0IOrjIm~rhDaol2QMImwy;ETN&DB#P3-T}MKs^?nSzzZC62!? zUTN9Ha*GxP0sk!}QyG#h^_7s&h(1z7vMKDBQF;$=cg`Zd@yTo-I;DxpVzJ@Gc90#x zAv+f;_Foz{!Alsg?WGtOA0m_jvXws>uj50yD?!_b#ccv^UVRigsw_m_Rp>H#PL)J_ zM27A5Q#>B&E!KD4q1QWTFm`OmOpDoaV^!lL%YE#`J-uuMRLn^g^ct~46B79JP`vq; zno@|6%)><+Shvn)RKpBnuF?pufbUrI z@-Sk(uD`VD)z?FafT5IfW*sROlb@+p_5gBo@(z58Nw>ggr_3xC=(3HV%Zy*CMHWwX za9z?`?vAo0g776SOi{jAgJRFOc_>6MIlXBF%W56TywMjnH*uNGwf(+Z(MS-{D|Zws zgzL7K-Z~|ZH`QMHb>lkD(fcc~&9x@5d^K;&1i+B+2=O(O2|wzTnAq2a0^Puuw*CT- zSAHawHoQ9%0JO|S-TsXamr5p(-3F{}awFh>_ z^9qzm=2UL04pZ0oI;5g_QSq3pvAyZ{vZt0kq$?JuUNO6zrMBFE8&lzKHKp(7$^T|M--5|koPAV@=_IfC<~Z8~%p z9T23BR_po&#^7xRm3)f!F&2Ce1DKi2XD30cghzRpUWbDrP>7&PBI|?KP2>D+!4DQq z`WK0nC|I!gha2tS7pYJ~coRSYil3V-COYGtNs7n`p#NS^@hmoWn|td^5V;4uKQ48U z2Zeh}Ad^|6;lS>?cq$$TXM&Q@VGJojDAp+B=Q_>g@a1#up4cmtY)LDD5HDC*<{C3_ z1NYgGu~G}}ueB<`s=I4Plbz!lI24J5RmNG2X=frU@w$TSiyW1uq%cioEKmJ;)AopN z6k}%cuY2+ZsB^c}*h^ZBYL;qeSp75QMUzx^I25O z6NS|_h^oa8N)U5{Bc6 zv1k)(yZPrs7uq=BP|-Q$b(Ed{f1-P_-<0uFceWS9V5~%HMJ%5j8HQo$8Zn}|3Cv~&q3s6FdvdiueYs4w!OHh3It6^ zW0?Y{v?;25F@1_I+w?MW7g)&aRX(-lMo=ck*Srt+-SII_ytZ!WLJLR2DxG9axs-ZI zlJXB6N`gnmD-#G|HyN`Mh(*j5pT>?Xo|APc$30h4D)1 zTh)yQ376C5PuD8v@_l303u`V3qi=w&!DxbCc$qm zATBrp(STLKgZ7W0VWrU(t6uvoC^+f7XWNO&K{Vq|l|b;u5~%E;051_pG zW0M1aMPO=q!jqx&JPe8|F*Ee^zSD98!;!AK5mBH)@Fzu4hxF}J$TfHT*O$e)w;XT> zxL^KE-Y4Ap?M32!7zeohIATJx|7H$!0e$=8=Va8A+M75s@MG=r8l*uH4r^)&vHUdwYM=7g_zuAvgeA|9^S1Pi4*Np8vFeIDG{~ z0T@7c0`NZuuD&Q+vX>48l39aT>gq z;hmDU2AL7=XGwv3*xW`~*?>M~r1+tyhm7Lj^7^xj*CGl#^QeMz%`piI>S5W^Nu6Njn<0b)e2pv}jLLl=8G z-ov!k^ixoSOS`<%r%Bi-{LEb!YscUxGgv_%9;z156Mco7_yuu}B2=~L$ithhk!Gqg zC43A(n+sqo6A4fh1g<6?;8B@$lIyDiZg5qhoQE^xfHb&Z0s`P@$bt;+0WHvtW0V>r z4^P>GyK4y^U=k)TQpFg!$zyIrAw6VZEScp*q5|xQ%E%JL@hl*EV`*%xT+Y&X* zQ#tSx@v)v^h!li_Ihy<@`ZqKlFBt*{5lD3Wld}hF^0`pez?V z3KZc7nmgfIY#Gl|h{=o9m*H@qCdLMzq`Tzsnh66XA1H|wRM<7KzgL3SML=ow#5FQW z&3oC%zSye8b^R$F&lw}(4GyijY|)^#7esXvxHS$It-?9FtawqfJB`uk5;|>?#QSCSRNdzpy zVbp}`sQs98l-EFK+`H8}K>d~Ud^4Ob6CA3Rj6&g?9wBZ@vQVxfm98ek!z4L0OixD- zXSDyOoZgKyg!E{<{f#mhRf2J=hgHUyR2a`HQ+9^S8AOB<0?!z6O(a&yD^a1Lw?=fcb3blB7N?cUYW zMtD-)3eVu1Z%A)vr8qY%^05^CWYx{(2EZ?+IC9yRb7EIQV3ZXxk)kEk1|<3AG#-r5 zX^-2Z!G3XENmas?QauZa#N|iQ%eDzH>4#BOl(jc_w{3|ZqiGUW;NgcE!cLMpgN+Do z2=ycC7_5qC(Psq%K>qNjeHo`DQU?U6E7%T!AkaX_{bv5wf+T^m zA(=fPFm;+x$f-A>F@b*>vp&ekE+BFB3lIc|oX4aOj*5v1g`&v-0+~0k(!K}Xk&mZo z`*gBH$#fQA!E_MD6bjU+nXdLRl_T7S({|tm**4% z?ARZ&sNw*KR~U~?c)X0{Re6JjS6;rdLX9~#;jrc_QsLQI;1izV zrA!6Nj8_i?g!D}$mx9Zwh}X@m6pk%xWr$`E)5}JspI{DVwhB9VepXgo4iRLA$5P_K z>7Q&tx`~K)9-)>mQ8?atXC>#3f+uHFVJj2`AXdG3F3eT2=>J2~F7hFN>0j6Be@5&V z922>ZI%N^;O+px0ICum^6ev-lgD!gL)4g`UGQ&wo5oB4A&Dlgz4Z5MIvQpE~($O<8 zGBLAcV`XFK;N;@w;pO8O5EK&5E+U#kOkAQV2c)EBWOK@)&=@QQB^7l#T4?F$85o&b z_f2LN)^sgmPtOugE^Z#)^sV9-5EQ}-H_>lIW7;e(k%4Ve(lWAg@(PMd%CTIds-~`? zsYTG%(bdy;U4uqVJeqm6Xw{}&M~3dyrCU$N?$xK?fI){188%`x6T6J}w?JncG3lr& z(`L+O>IHM=EjaFklNK!j01N;0IhC0=opIK(6|2^qbKV6PU2@qKS6#F2x*HZLEKyQX zx6k*q?e`$Z@XdaBd!61hTGv&o6*N3knH~h>D40 z>h(QVvco+nEhCGQ>qw6)#4B0>p#M4=f&cL;2ZIm}hG7Io!Dtu*V__VOhY7Fz&tdfP5jh%y26<18v+-lUSQxAhqSeHRMa%Ibo7=P7@3$sEMQhPb_fTQ6IPtJ;oQZ0j~9XD;}<}c;4{GzeIYC&DkhGR zz#27Xyr22Sq)W=COczu%t71-7?d1fdlUor{F>!%}r10=4m6lURmTZfbSq^cyJQ(2% z(EqXje&weh@%)Q2xk4GDp~9nhn1VrlyETMXr#Fxk&9Fw3*@}In?8r$E;sfUJSgBd*SAfPi&M;K2j6))x=yyBXFu!gcoYCj;I3@8j9Pjeckfp zyc~@iH(=hj(~LnpI8DdQAiHMq_}7SKwL}h4a2IQVkB+%;;Q0YzgGq#T%+tL1UL3St z9_#6CW?7WO>>IwYSha|%r3(xDn3BGy_7@TKQm2aV9LS%x4dzq{Xk3nomUVQ+{Y4tj zy1$eXNCMnu^vLQ>wruB$r?G6M_gP+_v$3c%V;Z`h=dBK5x=v!J=J24q%IUcBovpIn z+U>Ts_dEu1UuM{`{Q>60CM1xZqcd$os)9`E>Imp3sqtL7sj*G5phnsxZ% zpyT1d)TmqC#U!qOkUe_cqb8}w{Zt+#ve`682Cfk+axJl<+j_UWjV4PUE9 z(PdN=ayukN&KD(Tj4(E|CV!UIlgrvPGAu(Sd6W z-b8YZzCEZFnAs)HFqX9vF@%oUFycd#L~_1RoLqo{KZPKJ#UdCi0$>pUL{3Rf^0W5? zpCHH}QUqf+;Budcb{BJAFUi*}ubelx@DUk9lb@BZC2C@G_-p@;EW&m4Jido9O3k-k|I%bMy2QQ1L8WineE~|Tplmp6Kqf*w$hQvfz65S51 z^-{H<5v}4U+%KwW9A(vrR@0ZI)zS*4p*RzvLkJyX@JmifT_?G=h~Be~#;uv6jA#=k zFE^7JX|hJAA*vpA)3gm@Ybs+Le!m_^H>H6rWXxFUrZ#-?J^9U@GwCcWiQ0+$IGLSU^2b1IOw}0P` zx80cSmi`2v zSIJyDZ)KHQ3C#jF2`}yc%#I{)NcX+dncjjhKP{Fw zx6hu|BH-g6_+_^s=UMlJuh)fo{@8Fdm&Z|ri=QG5xM@Oal?dhxsoj!U0Zql}O1VIn zGB@Nxt_^MCpx~>jt3}t#<`#4?~&nmDMbv zYO6UO0*#x3$%y@Vb6 zPCia9*24h5;lDj7+)4+Arh|S(Yx)Ua*M^F?{8{RC&gl2 zMzgg00QIBW0*O3w%B|W|(HTlO=C!l6G<6W#eQ)UZonfIo&Y^YP^^&BsHFtxVsm zG%9b%z9ZDJvSIn%M%PWY+~+Uh(5EVAUQE`gRb)MrqroWzgoJIeQ|$QaNScSHjX*Hp zQ&t`o03jHm(J`FCWU-UJCusQoe9PnI=hKYMv>8y2a%2^Z)XrfCG#$ z?zJN`C3KKU8~U@4X26E-(6J-Yv2>>;Pxv&1%gDDM9Az6eWtk@Hat}>6D1y>+t#dN` z(ihHQQ0N^KV;wYPHE`@0MIyMTCi116WCBUS4y-KUns?_;yCR z!kSBLm4HjonEf*1vX{3h!j!v}Nez)JoEMecb*mL-@q*CRyif0uu>c$Z0 zcjFijmmui|MZg^TU^-%}L+fxlvX1ItML>bQt#CHorr4=PSWgRP^WZQ$*WUr9BcpA} fwhlSw(iO%qv!1W8%B(8B@!|{ra~hSq00000tZl!e literal 0 HcmV?d00001 diff --git a/src/SQLInsight.Web/wwwroot/fonts/inter-latin-wght-normal.woff2 b/src/SQLInsight.Web/wwwroot/fonts/inter-latin-wght-normal.woff2 new file mode 100644 index 0000000000000000000000000000000000000000..d15208de03cd1ad7c5199f0a0ce915fe841e4722 GIT binary patch literal 48256 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∾Na#*TBTU(!jF?9zmR-!C*+RdvGrd0&{`| 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 0) + { + Assert.Equal(RuleOutcome.Passed, results!.Single(r => r.RuleId == "SQLI-DLK-001").Outcome); + } + } + [Fact] public async Task Unreachable_instance_is_recorded_as_failing() { diff --git a/tests/SQLInsight.IntegrationTests/CollectorTests.cs b/tests/SQLInsight.IntegrationTests/CollectorTests.cs index 98015d5..bdb6741 100644 --- a/tests/SQLInsight.IntegrationTests/CollectorTests.cs +++ b/tests/SQLInsight.IntegrationTests/CollectorTests.cs @@ -119,6 +119,8 @@ public class CollectorTests(SqlServerFixture sql) // The ring buffer gets its first record about a minute after startup. Assert.All(cpu.Samples, s => Assert.InRange(s.SqlServerPercent + s.IdlePercent, 0, 100)); Assert.Equal(cpu.Samples.OrderBy(s => s.Time), cpu.Samples); + Assert.Equal("Linux", cpu.HostPlatform); // test containers run SQL Server on Linux + Assert.False(cpu.OtherProcessesMeasurable); } [Fact] diff --git a/tests/SQLInsight.IntegrationTests/RepositoryTests.cs b/tests/SQLInsight.IntegrationTests/RepositoryTests.cs index 2108647..dd59ffb 100644 --- a/tests/SQLInsight.IntegrationTests/RepositoryTests.cs +++ b/tests/SQLInsight.IntegrationTests/RepositoryTests.cs @@ -216,10 +216,12 @@ public class RepositoryTests(SqlServerFixture sql) : IAsyncLifetime var config = new ConfigurationSnapshot { CapturedAt = at, Options = [new ConfigurationOption("max degree of parallelism", 8, 8)] }; await _repository.SaveCollectedAsync(id, "deadlocks", deadlocks); + await _repository.SaveCollectedAsync(id, "deadlocks", deadlocks); // duplicates are ignored await _repository.SaveCollectedAsync(id, "blocking", blocking); await _repository.SaveCollectedAsync(id, "configuration", config); var deadlock = Assert.Single(await _repository.GetDeadlocksAsync(id, at.AddHours(-1))); + Assert.Equal(InsightRepository.UtcMilliseconds(at), (await _repository.GetLatestDeadlockTimeAsync(id))!.Value.UtcDateTime); Assert.True(Assert.Single(deadlock.Processes).IsVictim); Assert.Equal("", (await _repository.GetDeadlockAsync(deadlock.DeadlockId))!.GraphXml); diff --git a/tests/SQLInsight.IntegrationTests/SQLInsight.IntegrationTests.csproj b/tests/SQLInsight.IntegrationTests/SQLInsight.IntegrationTests.csproj index f08f1f4..78581d7 100644 --- a/tests/SQLInsight.IntegrationTests/SQLInsight.IntegrationTests.csproj +++ b/tests/SQLInsight.IntegrationTests/SQLInsight.IntegrationTests.csproj @@ -4,6 +4,7 @@ + @@ -11,6 +12,7 @@ + diff --git a/tests/SQLInsight.IntegrationTests/WebTests.cs b/tests/SQLInsight.IntegrationTests/WebTests.cs new file mode 100644 index 0000000..c08d5eb --- /dev/null +++ b/tests/SQLInsight.IntegrationTests/WebTests.cs @@ -0,0 +1,160 @@ +using System.Net; +using Microsoft.AspNetCore.Hosting; +using Microsoft.AspNetCore.Mvc.Testing; +using SQLInsight.Core.Data; +using SQLInsight.Core.Findings; +using SQLInsight.Core.Instances; +using SQLInsight.Repository; +using SQLInsight.Rules.Engine; + +namespace SQLInsight.IntegrationTests; + +[Collection(SqlServerTestGroup.Name)] +[Trait("Category", "Integration")] +public class WebTests(SqlServerFixture sql) : IAsyncLifetime +{ + private readonly string _database = "SQLInsightWeb_" + Guid.NewGuid().ToString("N")[..8]; + private WebApplicationFactory _factory = null!; + private InsightRepository _repository = null!; + private long _findingId; + private long _deadlockId; + + public async Task InitializeAsync() + { + await sql.ExecuteAsSaAsync($"CREATE DATABASE [{_database}];"); + var connectionString = sql.DatabaseConnectionString(_database); + _repository = new InsightRepository(connectionString); + await _repository.MigrateAsync(); + + var info = new InstanceInfo + { + ServerName = "SQL01", + Version = SqlServerVersion.Parse("15.0.4355.3"), + ProductLevel = "RTM", + ProductUpdateLevel = "CU28", + Edition = "Standard Edition", + EngineEdition = EngineEdition.Standard, + }; + var id = await _repository.UpsertInstanceAsync("prod-sql01", info, "SqlClient", false, DateTimeOffset.UtcNow); + await _repository.SaveRuleResultsAsync(id, + [ + new RuleResult + { + RuleId = "SQLI-CFG-001", + RuleTitle = "max server memory er ikke sat", + Outcome = RuleOutcome.Findings, + Findings = + [ + new Finding + { + RuleId = "SQLI-CFG-001", + Severity = Severity.High, + Title = "max server memory er ikke sat", + Explanation = "SQL Server må bruge al hukommelse ", + Recommendation = "Sæt max server memory.", + Evidence = [new Evidence("max server memory (MB)", "2147483647")], + FixScript = "EXEC sys.sp_configure N'max server memory (MB)', 58983;", + References = [new Reference("Server memory", new Uri("https://learn.microsoft.com/sql/"))], + }, + ], + }, + new RuleResult { RuleId = "SQLI-DB-011", RuleTitle = "VLF'er", Outcome = RuleOutcome.NotMeasurable, Reason = "Kræver SQL Server 2016 SP2" }, + ], DateTimeOffset.UtcNow); + await _repository.SaveCollectedAsync(id, "deadlocks", new DeadlockSnapshot + { + CapturedAt = DateTimeOffset.UtcNow, + NewDeadlocks = [new DeadlockEvent { Time = DateTimeOffset.UtcNow, GraphXml = "", Processes = [new DeadlockProcess { Id = "p1", IsVictim = true, SessionId = 60, ClientApp = "Sales.Api" }] }], + }); + _findingId = (await _repository.GetActiveFindingsAsync(id)).Single().FindingId; + _deadlockId = (await _repository.GetDeadlocksAsync(id, DateTimeOffset.UtcNow.AddHours(-1))).Single().DeadlockId; + + _factory = new WebApplicationFactory().WithWebHostBuilder(b => + { + b.UseEnvironment("Development"); + b.UseSetting("SQLInsight:Repository:ConnectionString", connectionString); + b.UseSetting("SQLInsight:Web:Authentication", "None"); + b.UseSetting("SQLInsight:Web:TimeZone", "Europe/Copenhagen"); + }); + } + + public async Task DisposeAsync() + { + await _factory.DisposeAsync(); + await sql.ExecuteAsSaAsync($"ALTER DATABASE [{_database}] SET SINGLE_USER WITH ROLLBACK IMMEDIATE; DROP DATABASE [{_database}];"); + } + + [Fact] + public async Task Overview_lists_instances_and_urgent_findings() + { + var html = await _factory.CreateClient().GetStringAsync("/"); + + Assert.Contains("prod-sql01", html, StringComparison.Ordinal); + Assert.Contains("SQL Server 2019", html, StringComparison.Ordinal); + Assert.Contains("max server memory er ikke sat", html, StringComparison.Ordinal); + } + + [Fact] + public async Task Instance_page_shows_findings_and_not_measurable_rules() + { + var html = await _factory.CreateClient().GetStringAsync("/instanser/prod-sql01"); + + Assert.Contains("Aktive fund", html, StringComparison.Ordinal); + Assert.Contains("SQLI-DB-011", html, StringComparison.Ordinal); + Assert.Contains("Kræver SQL Server 2016 SP2", html, StringComparison.Ordinal); + Assert.Contains($"/deadlocks/{_deadlockId}.xdl", html, StringComparison.Ordinal); + } + + [Fact] + public async Task Finding_page_shows_explanation_evidence_and_script_html_encoded() + { + var html = await _factory.CreateClient().GetStringAsync($"/fund/{_findingId}"); + + Assert.Contains("Hvorfor er det et problem?", html, StringComparison.Ordinal); + Assert.Contains("2147483647", html, StringComparison.Ordinal); + Assert.Contains("sp_configure", html, StringComparison.Ordinal); + Assert.DoesNotContain("", html, StringComparison.Ordinal); + Assert.Contains("<script>", html, StringComparison.Ordinal); + } + + [Fact] + public async Task Deadlock_graph_downloads_as_xdl() + { + var response = await _factory.CreateClient().GetAsync($"/deadlocks/{_deadlockId}.xdl"); + + Assert.Equal(HttpStatusCode.OK, response.StatusCode); + Assert.Equal($"deadlock-{_deadlockId}.xdl", response.Content.Headers.ContentDisposition?.FileName); + Assert.StartsWith("", await response.Content.ReadAsStringAsync(), StringComparison.Ordinal); + } + + [Fact] + public async Task Security_headers_are_set() + { + var response = await _factory.CreateClient().GetAsync("/"); + + Assert.Contains("default-src 'self'", response.Headers.GetValues("Content-Security-Policy").Single(), StringComparison.Ordinal); + Assert.Equal("DENY", response.Headers.GetValues("X-Frame-Options").Single()); + } + + [Fact] + public async Task Unknown_instance_and_finding_are_handled() + { + var client = _factory.CreateClient(); + + Assert.Contains("Ukendt instans", await client.GetStringAsync("/instanser/findes-ikke"), StringComparison.Ordinal); + Assert.Contains("Ukendt fund", await client.GetStringAsync("/fund/999999"), StringComparison.Ordinal); + } + + [Fact] + public void Refuses_to_run_without_authentication_outside_development() + { + using var production = new WebApplicationFactory().WithWebHostBuilder(b => + { + b.UseEnvironment("Production"); + b.UseSetting("SQLInsight:Repository:ConnectionString", sql.DatabaseConnectionString(_database)); + b.UseSetting("SQLInsight:Web:Authentication", "None"); + }); + + var ex = Assert.ThrowsAny(() => production.CreateClient()); + Assert.Contains("kun tilladt i Development", ex.ToString(), StringComparison.Ordinal); + } +} diff --git a/tests/SQLInsight.Rules.Tests/PerformanceRuleTests.cs b/tests/SQLInsight.Rules.Tests/PerformanceRuleTests.cs index e8d1cdf..1af6072 100644 --- a/tests/SQLInsight.Rules.Tests/PerformanceRuleTests.cs +++ b/tests/SQLInsight.Rules.Tests/PerformanceRuleTests.cs @@ -96,9 +96,10 @@ public class PerformanceRuleTests } } - private static CpuUtilization Cpu(int sql, int idle, int minutes = 15) => new() + private static CpuUtilization Cpu(int sql, int idle, int minutes = 15, string platform = "Windows") => new() { CapturedAt = Now, + HostPlatform = platform, Samples = Enumerable.Range(0, minutes).Select(i => new CpuSample(Now.AddMinutes(i - minutes), sql, idle)).ToList(), }; @@ -110,6 +111,13 @@ public class PerformanceRuleTests Assert.Equal(RuleOutcome.Passed, Run(new CpuRule(), With(Cpu(sql: 30, idle: 65))).Outcome); } + [Fact] + public void Other_processes_are_not_judged_on_linux() + { + // SystemIdle reads near 0 in Linux containers, which would look like 98 % CPU used by others. + Assert.Equal(RuleOutcome.Passed, Run(new CpuRule(), With(Cpu(sql: 2, idle: 0, platform: "Linux"))).Outcome); + } + [Fact] public void Cpu_needs_enough_history() {