From 579affceb7dc82c3e82149e6404efd51ce111ec8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Zsolt=20B=C3=B6l=C3=B6ny?= Date: Fri, 13 Dec 2024 18:56:45 +0100 Subject: [PATCH 1/6] Add UDS support --- README.md | 17 +++++++ native/Cargo.lock | 31 ++++++++++++- native/yaha_native/Cargo.toml | 2 +- native/yaha_native/src/binding.rs | 17 +++++-- native/yaha_native/src/context.rs | 44 ++++++++++++++++--- .../NativeHttpHandlerCore.cs | 10 +++++ .../NativeMethods.Uwp.g.cs | 3 ++ src/YetAnotherHttpHandler/NativeMethods.g.cs | 3 ++ .../YetAnotherHttpHandler.cs | 7 +++ 9 files changed, 122 insertions(+), 12 deletions(-) diff --git a/README.md b/README.md index 85a29ea..d086128 100644 --- a/README.md +++ b/README.md @@ -229,6 +229,7 @@ Once the handler sends a request, these settings become immutable and cannot be |Http2MaxConcurrentResetStreams|Gets or sets the maximum number of HTTP2 concurrent locally reset streams. See the documentation of h2::client::Builder::max_concurrent_reset_streams for more details. The default value is determined by the h2 crate.| |Http2MaxSendBufferSize|Gets or sets the maximum write buffer size for each HTTP/2 stream. Default is currently 1MB, but may change.| |Http2InitialMaxSendStreams|Gets or sets the initial maximum of locally initiated (send) streams. This value will be overwritten by the value included in the initial SETTINGS frame received from the peer as part of a connection preface.| +|UnixDomainSocketPath|Gets or sets the path to a Unix Domain Socket to be used as HTTP communication channel instead of the default TCP.| Most of them expose [hyper client settings](https://docs.rs/hyper-util/latest/hyper_util/client/legacy/struct.Builder.html), so please check those as well. @@ -301,6 +302,22 @@ using var httpHandler = new YetAnotherHttpHandler() }; ``` +### Using Unix Domain Sockets as HTTP transport layer + +Unix Domain Sockets can be used as the HTTP transport layer for local usecases (e.g. IPC based on gRPC), instead of network-based TCP. + +Set the `UnixDomainSocketPath` property to enable UDS-based communication to a server listening at the given path: + +```csharp +using var handler = new YetAnotherHttpHandler() { Http2Only = true, UnixDomainSocketPath = "/tmp/example.sock" }; +using var channel = GrpcChannel.ForAddress("http://localhost", new GrpcChannelOptions() { HttpHandler = handler }); +``` + +Note: +- HTTPS is not supported over UDS. All HTTPS related configuration properties are ignored if UDS is enabled. +- The grpc-dotnet library doesn't handle non-HTTP schemes (like "unix://"), so keep passing an HTTP URI to `GrpcChannel`, e.g. http://localhost. + The actual HTTP requests will be redirected to `UnixDomainSocketPath` by YetAnotherHttpHandler internally. + ## Development ### Build & Tests diff --git a/native/Cargo.lock b/native/Cargo.lock index 68326ad..bfb05ca 100644 --- a/native/Cargo.lock +++ b/native/Cargo.lock @@ -1,6 +1,6 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. -version = 3 +version = 4 [[package]] name = "addr2line" @@ -252,6 +252,12 @@ version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024" +[[package]] +name = "hex" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" + [[package]] name = "http" version = "1.1.0" @@ -292,6 +298,12 @@ version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d897f394bad6a705d5f4104762e116a75639e470d80901eed05a860a95cb1904" +[[package]] +name = "httpdate" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" + [[package]] name = "hyper" version = "1.3.1" @@ -305,6 +317,7 @@ dependencies = [ "http", "http-body", "httparse", + "httpdate", "itoa", "pin-project-lite", "smallvec", @@ -367,6 +380,21 @@ dependencies = [ "tracing", ] +[[package]] +name = "hyperlocal" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "986c5ce3b994526b3cd75578e62554abd09f0899d6206de48b3e96ab34ccc8c7" +dependencies = [ + "hex", + "http-body-util", + "hyper", + "hyper-util", + "pin-project-lite", + "tokio", + "tower-service", +] + [[package]] name = "indexmap" version = "2.2.6" @@ -1192,6 +1220,7 @@ dependencies = [ "hyper-rustls", "hyper-tls", "hyper-util", + "hyperlocal", "rustls", "rustls-pemfile", "tokio", diff --git a/native/yaha_native/Cargo.toml b/native/yaha_native/Cargo.toml index 291570e..e612833 100644 --- a/native/yaha_native/Cargo.toml +++ b/native/yaha_native/Cargo.toml @@ -41,7 +41,7 @@ http-body-util = "0.1.1" tokio-stream = "0.1.15" futures-channel = "0.3.30" futures-util = "0.3.30" - +hyperlocal = "0.9.1" [features] default = [ "rustls" ] diff --git a/native/yaha_native/src/binding.rs b/native/yaha_native/src/binding.rs index c553ce2..d1d7362 100644 --- a/native/yaha_native/src/binding.rs +++ b/native/yaha_native/src/binding.rs @@ -335,6 +335,18 @@ pub extern "C" fn yaha_client_config_http2_initial_max_send_streams( .http2_initial_max_send_streams(initial); } +#[no_mangle] +pub extern "C" fn yaha_client_config_unix_domain_socket_path( + ctx: *mut YahaNativeContext, + uds_path: *const StringBuffer, +) { + let ctx = YahaNativeContextInternal::from_raw_context(ctx); + + let uds_socket_path = unsafe { (*uds_path).to_str() }; + ctx.uds_socket_path.get_or_insert(uds_socket_path.into()); +} + + #[no_mangle] pub extern "C" fn yaha_build_client(ctx: *mut YahaNativeContext) { let ctx = YahaNativeContextInternal::from_raw_context(ctx); @@ -497,8 +509,7 @@ pub extern "C" fn yaha_request_begin( (req_ctx.seq, builder.body(body).unwrap()) }; - // - if ctx.client.as_ref().is_none() { + if ctx.tcp_client.is_none() && ctx.uds_client.is_none() { LAST_ERROR.with(|v| { *v.borrow_mut() = Some("The client has not been built. You need to build it before sending the request. ".to_string()); }); @@ -512,7 +523,7 @@ pub extern "C" fn yaha_request_begin( (ctx.on_complete)(seq, state, CompletionReason::Aborted, 0); return; } - res = ctx.client.as_ref().unwrap().request(req) => { + res = ctx.request(req) => { if let Err(err) = res { complete_with_error(ctx, seq, state, err); return; diff --git a/native/yaha_native/src/context.rs b/native/yaha_native/src/context.rs index 63aaf93..6742e1d 100644 --- a/native/yaha_native/src/context.rs +++ b/native/yaha_native/src/context.rs @@ -2,18 +2,19 @@ use std::{ num::NonZeroIsize, sync::{Arc, Mutex}, time::Duration, + path::PathBuf, }; use futures_channel::mpsc::Sender; use http_body_util::combinators::BoxBody; use tokio::runtime::{Handle, Runtime}; use hyper::{ - body::Bytes, - StatusCode, + body::Bytes, + Request, StatusCode }; use hyper_util::{ - client::{self, legacy::{connect::HttpConnector, Client}}, + client::{self, legacy::{connect::HttpConnector, Client, ResponseFuture}}, rt::{TokioExecutor, TokioTimer}, }; @@ -23,6 +24,7 @@ use hyper_rustls::ConfigBuilderExt; use hyper_rustls::HttpsConnector; #[cfg(feature = "native")] use hyper_tls::HttpsConnector; +use hyperlocal::UnixConnector; use rustls::pki_types::{CertificateDer, PrivateKeyDer}; use tokio_util::sync::CancellationToken; @@ -61,10 +63,12 @@ pub struct YahaNativeContextInternal<'a> { pub connect_timeout: Option, pub client_auth_certificates: Option>>, pub client_auth_key: Option>, - pub client: Option, BoxBody>>, + pub tcp_client: Option, BoxBody>>, pub on_status_code_and_headers_receive: OnStatusCodeAndHeadersReceive, pub on_receive: OnReceive, pub on_complete: OnComplete, + pub uds_client: Option>>, + pub uds_socket_path: Option, } impl YahaNativeContextInternal<'_> { @@ -80,7 +84,8 @@ impl YahaNativeContextInternal<'_> { ) -> Self { YahaNativeContextInternal { runtime: runtime_handle, - client: None, + tcp_client: None, + uds_client: None, client_builder: Some(Client::builder(TokioExecutor::new())), skip_certificate_verification: None, server_certificate_verification_handler: None, @@ -92,13 +97,20 @@ impl YahaNativeContextInternal<'_> { on_status_code_and_headers_receive, on_receive, on_complete, + uds_socket_path: None, } } pub fn build_client(&mut self) { let mut builder = self.client_builder.take().unwrap(); - let https = self.new_connector(); - self.client = Some(builder.timer(TokioTimer::new()).build(https)); + builder.timer(TokioTimer::new()); + + if self.uds_socket_path.is_some() { + self.uds_client = Some(builder.build(UnixConnector)); + } else { + let https = self.new_connector(); + self.tcp_client = Some(builder.build(https)); + } } #[cfg(feature = "rustls")] @@ -180,6 +192,24 @@ impl YahaNativeContextInternal<'_> { let https = HttpsConnector::new(); https } + + pub fn request(&self, mut req: Request>) -> ResponseFuture { + // Precondition (`uds_client` or `tcp_client` is set) ensured by `Self::build_client` and `yaha_request_begin` + if let Some(uds_socket_path) = &self.uds_socket_path { + // Transform HTTP URIs to the format expected by hyperlocal + let path_and_query = req + .uri() + .path_and_query() + .map(|pq| pq.as_str()) + .unwrap_or("/"); + let uds_uri = hyperlocal::Uri::new(uds_socket_path, path_and_query); + *req.uri_mut() = uds_uri.into(); + + self.uds_client.as_ref().unwrap().request(req) + } else { + self.tcp_client.as_ref().unwrap().request(req) + } + } } #[cfg(feature = "rustls")] diff --git a/src/YetAnotherHttpHandler/NativeHttpHandlerCore.cs b/src/YetAnotherHttpHandler/NativeHttpHandlerCore.cs index a477fbd..cb10290 100644 --- a/src/YetAnotherHttpHandler/NativeHttpHandlerCore.cs +++ b/src/YetAnotherHttpHandler/NativeHttpHandlerCore.cs @@ -184,6 +184,16 @@ private unsafe void Initialize(YahaNativeContext* ctx, NativeClientSettings sett if (YahaEventSource.Log.IsEnabled()) YahaEventSource.Log.Info($"Option '{nameof(settings.Http2InitialMaxSendStreams)}' = {http2InitialMaxSendStreams}"); NativeMethods.yaha_client_config_http2_initial_max_send_streams(ctx, (nuint)http2InitialMaxSendStreams); } + if (settings.UnixDomainSocketPath is { } unixDomainSocketPath) + { + if (YahaEventSource.Log.IsEnabled()) YahaEventSource.Log.Info($"Option '{nameof(settings.UnixDomainSocketPath)}' = {unixDomainSocketPath}"); + var strBytes = Encoding.UTF8.GetBytes(unixDomainSocketPath); + fixed (byte* buffer = strBytes) + { + var sb = new StringBuffer(buffer, strBytes.Length); + NativeMethods.yaha_client_config_unix_domain_socket_path(ctx, &sb); + } + } NativeMethods.yaha_build_client(ctx); diff --git a/src/YetAnotherHttpHandler/NativeMethods.Uwp.g.cs b/src/YetAnotherHttpHandler/NativeMethods.Uwp.g.cs index 0fb06f8..dcc95ce 100644 --- a/src/YetAnotherHttpHandler/NativeMethods.Uwp.g.cs +++ b/src/YetAnotherHttpHandler/NativeMethods.Uwp.g.cs @@ -107,6 +107,9 @@ internal static unsafe partial class NativeMethods [DllImport(__DllName, EntryPoint = "yaha_client_config_http2_initial_max_send_streams", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)] public static extern void yaha_client_config_http2_initial_max_send_streams(YahaNativeContext* ctx, nuint initial); + [DllImport(__DllName, EntryPoint = "yaha_client_config_unix_domain_socket_path", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)] + public static extern void yaha_client_config_unix_domain_socket_path(YahaNativeContext* ctx, StringBuffer* uds_path); + [DllImport(__DllName, EntryPoint = "yaha_build_client", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)] public static extern void yaha_build_client(YahaNativeContext* ctx); diff --git a/src/YetAnotherHttpHandler/NativeMethods.g.cs b/src/YetAnotherHttpHandler/NativeMethods.g.cs index 37d62d5..97d399c 100644 --- a/src/YetAnotherHttpHandler/NativeMethods.g.cs +++ b/src/YetAnotherHttpHandler/NativeMethods.g.cs @@ -112,6 +112,9 @@ internal static unsafe partial class NativeMethods [DllImport(__DllName, EntryPoint = "yaha_client_config_http2_initial_max_send_streams", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)] public static extern void yaha_client_config_http2_initial_max_send_streams(YahaNativeContext* ctx, nuint initial); + [DllImport(__DllName, EntryPoint = "yaha_client_config_unix_domain_socket_path", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)] + public static extern void yaha_client_config_unix_domain_socket_path(YahaNativeContext* ctx, StringBuffer* uds_path); + [DllImport(__DllName, EntryPoint = "yaha_build_client", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)] public static extern void yaha_build_client(YahaNativeContext* ctx); diff --git a/src/YetAnotherHttpHandler/YetAnotherHttpHandler.cs b/src/YetAnotherHttpHandler/YetAnotherHttpHandler.cs index 0efa4c8..1935193 100644 --- a/src/YetAnotherHttpHandler/YetAnotherHttpHandler.cs +++ b/src/YetAnotherHttpHandler/YetAnotherHttpHandler.cs @@ -169,6 +169,11 @@ public class YetAnotherHttpHandler : HttpMessageHandler /// public ulong? Http2InitialMaxSendStreams { get => _settings.Http2InitialMaxSendStreams; set => _settings.Http2InitialMaxSendStreams = value; } + /// + /// Gets or sets the path to a Unix Domain Socket to be used as HTTP communication channel instead of the default TCP. + /// + public string? UnixDomainSocketPath { get => _settings.UnixDomainSocketPath; set => _settings.UnixDomainSocketPath = value; } + private NativeHttpHandlerCore SetupHandler() { var settings = _settings.Clone(); @@ -236,6 +241,7 @@ internal class NativeClientSettings public ulong? Http2MaxConcurrentResetStreams { get; set; } public ulong? Http2MaxSendBufferSize { get; set; } public ulong? Http2InitialMaxSendStreams { get; set; } + public string? UnixDomainSocketPath { get; set; } public NativeClientSettings Clone() { @@ -261,6 +267,7 @@ public NativeClientSettings Clone() Http2MaxConcurrentResetStreams = this.Http2MaxConcurrentResetStreams, Http2MaxSendBufferSize = this.Http2MaxSendBufferSize, Http2InitialMaxSendStreams = this.Http2InitialMaxSendStreams, + UnixDomainSocketPath = this.UnixDomainSocketPath, }; } } From e2e4607177a85d17ad5b78f9c0263bc0d694819d Mon Sep 17 00:00:00 2001 From: Mayuki Sawatari Date: Tue, 17 Dec 2024 16:16:03 +0900 Subject: [PATCH 2/6] Fix for building on Windows --- native/yaha_native/Cargo.toml | 2 ++ native/yaha_native/src/binding.rs | 8 +++++++- native/yaha_native/src/context.rs | 31 +++++++++++++++++++++++++------ 3 files changed, 34 insertions(+), 7 deletions(-) diff --git a/native/yaha_native/Cargo.toml b/native/yaha_native/Cargo.toml index e612833..4e9244c 100644 --- a/native/yaha_native/Cargo.toml +++ b/native/yaha_native/Cargo.toml @@ -41,6 +41,8 @@ http-body-util = "0.1.1" tokio-stream = "0.1.15" futures-channel = "0.3.30" futures-util = "0.3.30" + +[target.'cfg(unix)'.dependencies] hyperlocal = "0.9.1" [features] diff --git a/native/yaha_native/src/binding.rs b/native/yaha_native/src/binding.rs index d1d7362..7eb8973 100644 --- a/native/yaha_native/src/binding.rs +++ b/native/yaha_native/src/binding.rs @@ -335,6 +335,7 @@ pub extern "C" fn yaha_client_config_http2_initial_max_send_streams( .http2_initial_max_send_streams(initial); } +#[cfg(unix)] #[no_mangle] pub extern "C" fn yaha_client_config_unix_domain_socket_path( ctx: *mut YahaNativeContext, @@ -509,7 +510,12 @@ pub extern "C" fn yaha_request_begin( (req_ctx.seq, builder.body(body).unwrap()) }; - if ctx.tcp_client.is_none() && ctx.uds_client.is_none() { + #[cfg(unix)] + let client_is_none = ctx.tcp_client.is_none() && ctx.uds_client.is_none(); + #[cfg(not(unix))] + let client_is_none = ctx.tcp_client.is_none(); + + if client_is_none { LAST_ERROR.with(|v| { *v.borrow_mut() = Some("The client has not been built. You need to build it before sending the request. ".to_string()); }); diff --git a/native/yaha_native/src/context.rs b/native/yaha_native/src/context.rs index 6742e1d..71d742f 100644 --- a/native/yaha_native/src/context.rs +++ b/native/yaha_native/src/context.rs @@ -2,7 +2,6 @@ use std::{ num::NonZeroIsize, sync::{Arc, Mutex}, time::Duration, - path::PathBuf, }; use futures_channel::mpsc::Sender; use http_body_util::combinators::BoxBody; @@ -24,7 +23,9 @@ use hyper_rustls::ConfigBuilderExt; use hyper_rustls::HttpsConnector; #[cfg(feature = "native")] use hyper_tls::HttpsConnector; +#[cfg(unix)] use hyperlocal::UnixConnector; + use rustls::pki_types::{CertificateDer, PrivateKeyDer}; use tokio_util::sync::CancellationToken; @@ -67,8 +68,11 @@ pub struct YahaNativeContextInternal<'a> { pub on_status_code_and_headers_receive: OnStatusCodeAndHeadersReceive, pub on_receive: OnReceive, pub on_complete: OnComplete, + + #[cfg(unix)] pub uds_client: Option>>, - pub uds_socket_path: Option, + #[cfg(unix)] + pub uds_socket_path: Option, } impl YahaNativeContextInternal<'_> { @@ -85,7 +89,6 @@ impl YahaNativeContextInternal<'_> { YahaNativeContextInternal { runtime: runtime_handle, tcp_client: None, - uds_client: None, client_builder: Some(Client::builder(TokioExecutor::new())), skip_certificate_verification: None, server_certificate_verification_handler: None, @@ -97,6 +100,9 @@ impl YahaNativeContextInternal<'_> { on_status_code_and_headers_receive, on_receive, on_complete, + #[cfg(unix)] + uds_client: None, + #[cfg(unix)] uds_socket_path: None, } } @@ -105,9 +111,17 @@ impl YahaNativeContextInternal<'_> { let mut builder = self.client_builder.take().unwrap(); builder.timer(TokioTimer::new()); - if self.uds_socket_path.is_some() { - self.uds_client = Some(builder.build(UnixConnector)); - } else { + #[cfg(unix)] + { + if self.uds_socket_path.is_some() { + self.uds_client = Some(builder.build(UnixConnector)); + } else { + let https = self.new_connector(); + self.tcp_client = Some(builder.build(https)); + } + } + #[cfg(not(unix))] + { let https = self.new_connector(); self.tcp_client = Some(builder.build(https)); } @@ -193,6 +207,7 @@ impl YahaNativeContextInternal<'_> { https } + #[cfg(unix)] pub fn request(&self, mut req: Request>) -> ResponseFuture { // Precondition (`uds_client` or `tcp_client` is set) ensured by `Self::build_client` and `yaha_request_begin` if let Some(uds_socket_path) = &self.uds_socket_path { @@ -210,6 +225,10 @@ impl YahaNativeContextInternal<'_> { self.tcp_client.as_ref().unwrap().request(req) } } + #[cfg(not(unix))] + pub fn request(&self, req: Request>) -> ResponseFuture { + self.tcp_client.as_ref().unwrap().request(req) + } } #[cfg(feature = "rustls")] From 2521356555340c88f81a60327e080c5bc0db3474 Mon Sep 17 00:00:00 2001 From: Mayuki Sawatari Date: Thu, 19 Dec 2024 14:58:23 +0900 Subject: [PATCH 3/6] Add unit tests --- test/YetAnotherHttpHandler.Test/UdsTest.cs | 41 ++++++++++++++++++++++ 1 file changed, 41 insertions(+) create mode 100644 test/YetAnotherHttpHandler.Test/UdsTest.cs diff --git a/test/YetAnotherHttpHandler.Test/UdsTest.cs b/test/YetAnotherHttpHandler.Test/UdsTest.cs new file mode 100644 index 0000000..b8fbe7d --- /dev/null +++ b/test/YetAnotherHttpHandler.Test/UdsTest.cs @@ -0,0 +1,41 @@ +using System.Security.Cryptography.X509Certificates; +using Cysharp.Net.Http; +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Hosting; +using Microsoft.AspNetCore.Server.Kestrel.Core; +using Xunit.Abstractions; + +namespace _YetAnotherHttpHandler.Test; + +public class UdsTest(ITestOutputHelper testOutputHelper) : Http2TestBase(testOutputHelper) +{ + private readonly string _udsPath = Path.Combine(Path.GetTempPath(), $"yaha-uds-test-{Guid.NewGuid()}"); + protected override YetAnotherHttpHandler CreateHandler() + { + return new YetAnotherHttpHandler() + { + UnixDomainSocketPath = _udsPath, + Http2Only = true, + }; + } + + protected override Task LaunchServerAsyncCore(Action? configure = null) + { + return LaunchServerAsync(TestWebAppServerListenMode.SecureHttp2Only, builder => + { + builder.WebHost.ConfigureKestrel(options => + { + options.ListenUnixSocket(_udsPath, listenOptions => + { + listenOptions.Protocols = HttpProtocols.Http2; + }); + + // hyperlocal uses the 'unix' scheme and passes the URI to hyper. As a result, the ':scheme' header in the request is set to 'unix'. + // By default, Kestrel does not accept non-HTTP schemes. To allow non-HTTP schemes, we need to set 'AllowAlternateSchemes' to true. + options.AllowAlternateSchemes = true; + }); + + configure?.Invoke(builder); + }); + } +} \ No newline at end of file From 08fd9629d2121c802ced1a68d22abc8bc8a4fb34 Mon Sep 17 00:00:00 2001 From: Mayuki Sawatari Date: Thu, 19 Dec 2024 15:06:36 +0900 Subject: [PATCH 4/6] Skip UDS unit tests on Windows --- .../Testing/ConditionalFactAttribute.cs | 14 +++++ .../Testing/ConditionalFactDiscoverer.cs | 27 ++++++++ .../Helpers/Testing/ITestCondition.cs | 11 ++++ .../Testing/OSSkipConditionAttribute.cs | 62 +++++++++++++++++++ .../Helpers/Testing/OperatingSystems.cs | 14 +++++ .../Helpers/Testing/SkippedTestCase.cs | 49 +++++++++++++++ .../Helpers/Testing/TestMethodExtensions.cs | 33 ++++++++++ .../Http2TestBase.cs | 48 +++++++------- test/YetAnotherHttpHandler.Test/UdsTest.cs | 2 + test/YetAnotherHttpHandler.Test/Usings.cs | 1 + 10 files changed, 237 insertions(+), 24 deletions(-) create mode 100644 test/YetAnotherHttpHandler.Test/Helpers/Testing/ConditionalFactAttribute.cs create mode 100644 test/YetAnotherHttpHandler.Test/Helpers/Testing/ConditionalFactDiscoverer.cs create mode 100644 test/YetAnotherHttpHandler.Test/Helpers/Testing/ITestCondition.cs create mode 100644 test/YetAnotherHttpHandler.Test/Helpers/Testing/OSSkipConditionAttribute.cs create mode 100644 test/YetAnotherHttpHandler.Test/Helpers/Testing/OperatingSystems.cs create mode 100644 test/YetAnotherHttpHandler.Test/Helpers/Testing/SkippedTestCase.cs create mode 100644 test/YetAnotherHttpHandler.Test/Helpers/Testing/TestMethodExtensions.cs diff --git a/test/YetAnotherHttpHandler.Test/Helpers/Testing/ConditionalFactAttribute.cs b/test/YetAnotherHttpHandler.Test/Helpers/Testing/ConditionalFactAttribute.cs new file mode 100644 index 0000000..38df7ee --- /dev/null +++ b/test/YetAnotherHttpHandler.Test/Helpers/Testing/ConditionalFactAttribute.cs @@ -0,0 +1,14 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; +using Xunit; +using Xunit.Sdk; + +namespace _YetAnotherHttpHandler.Test.Helpers.Testing; + +[AttributeUsage(AttributeTargets.Method, AllowMultiple = false)] +[XunitTestCaseDiscoverer("_YetAnotherHttpHandler.Test.Helpers.Testing." + nameof(ConditionalFactDiscoverer), "YetAnotherHttpHandler.Test")] +public class ConditionalFactAttribute : FactAttribute +{ +} \ No newline at end of file diff --git a/test/YetAnotherHttpHandler.Test/Helpers/Testing/ConditionalFactDiscoverer.cs b/test/YetAnotherHttpHandler.Test/Helpers/Testing/ConditionalFactDiscoverer.cs new file mode 100644 index 0000000..574884f --- /dev/null +++ b/test/YetAnotherHttpHandler.Test/Helpers/Testing/ConditionalFactDiscoverer.cs @@ -0,0 +1,27 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using Xunit.Abstractions; +using Xunit.Sdk; + +// Do not change this namespace without changing the usage in ConditionalFactAttribute +namespace _YetAnotherHttpHandler.Test.Helpers.Testing; + +internal sealed class ConditionalFactDiscoverer : FactDiscoverer +{ + private readonly IMessageSink _diagnosticMessageSink; + + public ConditionalFactDiscoverer(IMessageSink diagnosticMessageSink) + : base(diagnosticMessageSink) + { + _diagnosticMessageSink = diagnosticMessageSink; + } + + protected override IXunitTestCase CreateTestCase(ITestFrameworkDiscoveryOptions discoveryOptions, ITestMethod testMethod, IAttributeInfo factAttribute) + { + var skipReason = testMethod.EvaluateSkipConditions(); + return skipReason != null + ? new SkippedTestCase(skipReason, _diagnosticMessageSink, discoveryOptions.MethodDisplayOrDefault(), TestMethodDisplayOptions.None, testMethod) + : base.CreateTestCase(discoveryOptions, testMethod, factAttribute); + } +} \ No newline at end of file diff --git a/test/YetAnotherHttpHandler.Test/Helpers/Testing/ITestCondition.cs b/test/YetAnotherHttpHandler.Test/Helpers/Testing/ITestCondition.cs new file mode 100644 index 0000000..661bb62 --- /dev/null +++ b/test/YetAnotherHttpHandler.Test/Helpers/Testing/ITestCondition.cs @@ -0,0 +1,11 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +namespace _YetAnotherHttpHandler.Test.Helpers.Testing; + +public interface ITestCondition +{ + bool IsMet { get; } + + string SkipReason { get; } +} \ No newline at end of file diff --git a/test/YetAnotherHttpHandler.Test/Helpers/Testing/OSSkipConditionAttribute.cs b/test/YetAnotherHttpHandler.Test/Helpers/Testing/OSSkipConditionAttribute.cs new file mode 100644 index 0000000..4ddf399 --- /dev/null +++ b/test/YetAnotherHttpHandler.Test/Helpers/Testing/OSSkipConditionAttribute.cs @@ -0,0 +1,62 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// https://github.com/dotnet/aspnetcore/tree/v7.0.0/src/Testing/src + +using System.Runtime.InteropServices; +using System; + +namespace _YetAnotherHttpHandler.Test.Helpers.Testing; + +[AttributeUsage(AttributeTargets.Method | AttributeTargets.Class | AttributeTargets.Assembly, AllowMultiple = true)] +public class OSSkipConditionAttribute : Attribute, ITestCondition +{ + private readonly OperatingSystems _excludedOperatingSystem; + private readonly OperatingSystems _osPlatform; + + public OSSkipConditionAttribute(OperatingSystems operatingSystem) : + this(operatingSystem, GetCurrentOS()) + { + } + + [Obsolete("Use the Minimum/MaximumOSVersionAttribute for version checks.", error: true)] + public OSSkipConditionAttribute(OperatingSystems operatingSystem, params string[] versions) : + this(operatingSystem, GetCurrentOS()) + { + } + + // to enable unit testing + internal OSSkipConditionAttribute(OperatingSystems operatingSystem, OperatingSystems osPlatform) + { + _excludedOperatingSystem = operatingSystem; + _osPlatform = osPlatform; + } + + public bool IsMet + { + get + { + var skip = (_excludedOperatingSystem & _osPlatform) == _osPlatform; + // Since a test would be excuted only if 'IsMet' is true, return false if we want to skip + return !skip; + } + } + + public string SkipReason { get; set; } = "Test cannot run on this operating system."; + + private static OperatingSystems GetCurrentOS() + { + if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + { + return OperatingSystems.Windows; + } + else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) + { + return OperatingSystems.Linux; + } + else if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) + { + return OperatingSystems.MacOSX; + } + throw new PlatformNotSupportedException(); + } +} \ No newline at end of file diff --git a/test/YetAnotherHttpHandler.Test/Helpers/Testing/OperatingSystems.cs b/test/YetAnotherHttpHandler.Test/Helpers/Testing/OperatingSystems.cs new file mode 100644 index 0000000..9c4d9f7 --- /dev/null +++ b/test/YetAnotherHttpHandler.Test/Helpers/Testing/OperatingSystems.cs @@ -0,0 +1,14 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; + +namespace _YetAnotherHttpHandler.Test.Helpers.Testing; + +[Flags] +public enum OperatingSystems +{ + Linux = 1, + MacOSX = 2, + Windows = 4, +} \ No newline at end of file diff --git a/test/YetAnotherHttpHandler.Test/Helpers/Testing/SkippedTestCase.cs b/test/YetAnotherHttpHandler.Test/Helpers/Testing/SkippedTestCase.cs new file mode 100644 index 0000000..a5f08f6 --- /dev/null +++ b/test/YetAnotherHttpHandler.Test/Helpers/Testing/SkippedTestCase.cs @@ -0,0 +1,49 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; +using Xunit.Abstractions; +using Xunit.Sdk; +#pragma warning disable CS8625 + +namespace _YetAnotherHttpHandler.Test.Helpers.Testing; + +public class SkippedTestCase : XunitTestCase +{ + private string? _skipReason; + + [Obsolete("Called by the de-serializer; should only be called by deriving classes for de-serialization purposes")] + public SkippedTestCase() : base() + { + } + + public SkippedTestCase( + string skipReason, + IMessageSink diagnosticMessageSink, + TestMethodDisplay defaultMethodDisplay, + TestMethodDisplayOptions defaultMethodDisplayOptions, + ITestMethod testMethod, + object[] testMethodArguments = null) + : base(diagnosticMessageSink, defaultMethodDisplay, defaultMethodDisplayOptions, testMethod, testMethodArguments) + { + _skipReason = skipReason; + } + + protected override string GetSkipReason(IAttributeInfo factAttribute) + => _skipReason ?? base.GetSkipReason(factAttribute); + + public override void Deserialize(IXunitSerializationInfo data) + { + _skipReason = data.GetValue(nameof(_skipReason)); + + // We need to call base after reading our value, because Deserialize will call + // into GetSkipReason. + base.Deserialize(data); + } + + public override void Serialize(IXunitSerializationInfo data) + { + base.Serialize(data); + data.AddValue(nameof(_skipReason), _skipReason); + } +} \ No newline at end of file diff --git a/test/YetAnotherHttpHandler.Test/Helpers/Testing/TestMethodExtensions.cs b/test/YetAnotherHttpHandler.Test/Helpers/Testing/TestMethodExtensions.cs new file mode 100644 index 0000000..ad83947 --- /dev/null +++ b/test/YetAnotherHttpHandler.Test/Helpers/Testing/TestMethodExtensions.cs @@ -0,0 +1,33 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Linq; +using Xunit.Abstractions; +using Xunit.Sdk; + +namespace _YetAnotherHttpHandler.Test.Helpers.Testing; + +public static class TestMethodExtensions +{ + public static string? EvaluateSkipConditions(this ITestMethod testMethod) + { + var testClass = testMethod.TestClass.Class; + var assembly = testMethod.TestClass.TestCollection.TestAssembly.Assembly; + var conditionAttributes = testMethod.Method + .GetCustomAttributes(typeof(ITestCondition)) + .Concat(testClass.GetCustomAttributes(typeof(ITestCondition))) + .Concat(assembly.GetCustomAttributes(typeof(ITestCondition))) + .OfType() + .Select(attributeInfo => attributeInfo.Attribute); + + foreach (ITestCondition condition in conditionAttributes) + { + if (!condition.IsMet) + { + return condition.SkipReason; + } + } + + return null; + } +} \ No newline at end of file diff --git a/test/YetAnotherHttpHandler.Test/Http2TestBase.cs b/test/YetAnotherHttpHandler.Test/Http2TestBase.cs index 14ba7c6..4ce0ed1 100644 --- a/test/YetAnotherHttpHandler.Test/Http2TestBase.cs +++ b/test/YetAnotherHttpHandler.Test/Http2TestBase.cs @@ -18,7 +18,7 @@ public abstract class Http2TestBase(ITestOutputHelper testOutputHelper) : UseTes protected Task LaunchServerAsync(Action? configure = null) where T : ITestServerBuilder => LaunchServerAsyncCore(configure); - [Fact] + [ConditionalFact] public async Task Get_Ok() { // Arrange @@ -40,7 +40,7 @@ public async Task Get_Ok() Assert.Equal(HttpStatusCode.OK, response.StatusCode); } - [Fact] + [ConditionalFact] public async Task Get_NotOk() { // Arrange @@ -62,7 +62,7 @@ public async Task Get_NotOk() Assert.Equal(HttpStatusCode.NotFound, response.StatusCode); } - [Fact] + [ConditionalFact] public async Task Post_Body() { // Arrange @@ -88,7 +88,7 @@ public async Task Post_Body() Assert.Equal("application/octet-stream", response.Headers.TryGetValues("x-request-content-type", out var values) ? string.Join(',', values) : null); } - [Fact] + [ConditionalFact] public async Task Post_NotDuplex_Receive_ResponseHeaders_Before_ResponseBody() { // Arrange @@ -118,7 +118,7 @@ public async Task Post_NotDuplex_Receive_ResponseHeaders_Before_ResponseBody() // NOTE: SocketHttpHandler waits for the completion of sending the request body before the response headers. // https://github.com/dotnet/runtime/blob/v7.0.0/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/Http2Connection.cs#L1980-L1988 // https://github.com/dotnet/runtime/blob/v7.0.0/src/libraries/System.Net.Http/src/System/Net/Http/HttpContent.cs#L343-L349 - //[Fact] + //[ConditionalFact] //public async Task Post_NotDuplex_DoNot_Receive_ResponseHeaders_Before_RequestBodyCompleted() //{ // // Arrange @@ -142,7 +142,7 @@ public async Task Post_NotDuplex_Receive_ResponseHeaders_Before_ResponseBody() // Assert.Equal(timeout.Token, ex.CancellationToken); //} - [Fact] + [ConditionalFact] public async Task Post_NotDuplex_Body_StreamingBody() { // Arrange @@ -183,7 +183,7 @@ public async Task Post_NotDuplex_Body_StreamingBody() Assert.Equal((1024 * 1024 * 10).ToString(), responseBody); } - [Fact] + [ConditionalFact] public async Task Post_Duplex_Body_StreamingBody() { // Arrange @@ -225,7 +225,7 @@ public async Task Post_Duplex_Body_StreamingBody() Assert.Equal((1024 * 1024 * 10).ToString(), responseBody); } - [Fact] + [ConditionalFact] public async Task Post_ResponseTrailers() { // Arrange @@ -251,7 +251,7 @@ public async Task Post_ResponseTrailers() Assert.Equal("bar", response.TrailingHeaders.TryGetValues("x-trailer-2", out var values2) ? string.Join(',', values2) : null); } - [Fact] + [ConditionalFact] public async Task AbortOnServer_Post_SendingBody() { // Arrange @@ -273,7 +273,7 @@ public async Task AbortOnServer_Post_SendingBody() Assert.IsType(ex); } - [Fact] + [ConditionalFact] public async Task Cancel_Post_SendingBody() { // Arrange @@ -304,7 +304,7 @@ public async Task Cancel_Post_SendingBody() } #if !UNITY_2021_1_OR_NEWER - [Fact] + [ConditionalFact] public async Task Cancel_Post_SendingBody_Duplex() { // Arrange @@ -331,7 +331,7 @@ public async Task Cancel_Post_SendingBody_Duplex() } #endif - [Fact] + [ConditionalFact] public async Task DisposeHttpResponseMessage_Post_SendingBody_Duplex() { // Arrange @@ -361,7 +361,7 @@ public async Task DisposeHttpResponseMessage_Post_SendingBody_Duplex() Assert.IsAssignableFrom(ex.InnerException); } - [Fact] + [ConditionalFact] public async Task Cancel_Get_BeforeReceivingResponseHeaders() { // Arrange @@ -392,7 +392,7 @@ public async Task Cancel_Get_BeforeReceivingResponseHeaders() Assert.Equal("True", isCanceled); } - [Fact] + [ConditionalFact] public async Task Cancel_Post_BeforeRequest() { // Arrange @@ -420,7 +420,7 @@ public async Task Cancel_Post_BeforeRequest() #endif } - [Fact] + [ConditionalFact] public async Task Grpc_Unary() { // Arrange @@ -436,7 +436,7 @@ public async Task Grpc_Unary() Assert.Equal("Hello Alice", response.Message); } - [Fact] + [ConditionalFact] public async Task Grpc_Duplex() { // Arrange @@ -473,7 +473,7 @@ public async Task Grpc_Duplex() } - [Fact] + [ConditionalFact] public async Task Grpc_Duplex_Concurrency() { // Arrange @@ -526,7 +526,7 @@ public async Task Grpc_Duplex_Concurrency() } } - [Fact] + [ConditionalFact] public async Task Grpc_ShutdownAndDispose() { await using var server = await LaunchServerAsync(); @@ -572,7 +572,7 @@ async Task RunAsync() } } - [Fact] + [ConditionalFact] public async Task Grpc_Error_Status_ErrorCode() { // Arrange @@ -589,7 +589,7 @@ public async Task Grpc_Error_Status_ErrorCode() Assert.Equal(StatusCode.Cancelled, ((RpcException)ex).StatusCode); } - [Fact] + [ConditionalFact] public async Task Grpc_Error_Status_Unavailable_By_IOException() { // Arrange @@ -605,7 +605,7 @@ public async Task Grpc_Error_Status_Unavailable_By_IOException() Assert.Equal(StatusCode.Unavailable, ((RpcException)ex).StatusCode); } - [Fact] + [ConditionalFact] public async Task Grpc_Error_TimedOut_With_HttpClientTimeout() { // Arrange @@ -627,7 +627,7 @@ public async Task Grpc_Error_TimedOut_With_HttpClientTimeout() #endif } - [Fact] + [ConditionalFact] public async Task Grpc_Error_TimedOut_With_Deadline() { // Arrange @@ -644,7 +644,7 @@ public async Task Grpc_Error_TimedOut_With_Deadline() Assert.Equal(StatusCode.DeadlineExceeded, ((RpcException)ex).StatusCode); } - [Fact] + [ConditionalFact] public async Task Grpc_Error_TimedOut_With_CancellationToken() { // Arrange @@ -662,7 +662,7 @@ public async Task Grpc_Error_TimedOut_With_CancellationToken() Assert.Equal(StatusCode.Cancelled, ((RpcException)ex).StatusCode); } - [Fact] + [ConditionalFact] public async Task Enable_Http2KeepAlive() { // Arrange diff --git a/test/YetAnotherHttpHandler.Test/UdsTest.cs b/test/YetAnotherHttpHandler.Test/UdsTest.cs index b8fbe7d..2a473c3 100644 --- a/test/YetAnotherHttpHandler.Test/UdsTest.cs +++ b/test/YetAnotherHttpHandler.Test/UdsTest.cs @@ -1,4 +1,5 @@ using System.Security.Cryptography.X509Certificates; +using _YetAnotherHttpHandler.Test.Helpers.Testing; using Cysharp.Net.Http; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; @@ -7,6 +8,7 @@ namespace _YetAnotherHttpHandler.Test; +[OSSkipCondition(OperatingSystems.Windows)] public class UdsTest(ITestOutputHelper testOutputHelper) : Http2TestBase(testOutputHelper) { private readonly string _udsPath = Path.Combine(Path.GetTempPath(), $"yaha-uds-test-{Guid.NewGuid()}"); diff --git a/test/YetAnotherHttpHandler.Test/Usings.cs b/test/YetAnotherHttpHandler.Test/Usings.cs index 28c3087..20fb7f3 100644 --- a/test/YetAnotherHttpHandler.Test/Usings.cs +++ b/test/YetAnotherHttpHandler.Test/Usings.cs @@ -1,3 +1,4 @@ global using Xunit; global using _YetAnotherHttpHandler.Test.Helpers; +global using _YetAnotherHttpHandler.Test.Helpers.Testing; From 8a28a11b847350065219be80ac016e7edef96c1d Mon Sep 17 00:00:00 2001 From: Mayuki Sawatari Date: Thu, 19 Dec 2024 15:25:54 +0900 Subject: [PATCH 5/6] Update README.md and THIRD-PARTY-NOTICES --- README.md | 5 +++++ THIRD-PARTY-NOTICES | Bin 350536 -> 208658 bytes 2 files changed, 5 insertions(+) diff --git a/README.md b/README.md index d086128..ae81ac5 100644 --- a/README.md +++ b/README.md @@ -53,6 +53,7 @@ Architecture/Platform | Windows | macOS | Linux | Android | iOS - TLS 1.2/1.3 with ALPN - TLS support is powered by Rustls + webpki - Client certificate + - Unix Domain Socket (macOS, Linux) ### Not supported yet - HTTP proxy support @@ -335,6 +336,10 @@ When creating a package, The following artifacts directory is used. - native/artifacts/{.NET RID}/{lib}yaha_native.{dll,so} +```bash +# Generate THIRD-PARTY-NOTICES using cargo-about +cargo about generate about.hbs > ../THIRD-PARTY-NOTICES +``` ## License MIT License diff --git a/THIRD-PARTY-NOTICES b/THIRD-PARTY-NOTICES index fd92936e5d2a7a5ba29df54d198ca586282564e3..d87aade316454ab2c628f61cd50d5e7e55760614 100644 GIT binary patch literal 208658 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

hi6>umvxE#t5#*FeQh?BAe1x)7BM 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

J-cmf)`{UYKBK|P1nX$wZ~Yr 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 literal 350536 zcmeFaYmZe|mZrPE_L2HOL?e|dQl|l9r=8`jPbACC-K?KWsDc`+{Ji<_g^j}JdCHF#V5SU zI4@(IOPl|>`G1zbcQ!x9r!V5)r}6*mWroM`FQYz;8D1?bcod(ovWLqE{Cm3j{qp|B z_~z;|-@};y+xYF)+viS~-#?7mK6v}=7n_@#2i;SwhLLV=?r*NGe*1^`_IiB#Q9OGs z*7J3&PIFw?+>W_kZ!W~Q-^Xr_;-`D@3A^HnN6R<$$~@;6@y0*mIpFzqym>c9{pM`9 zyLNNu3^(^tk3oP5GfZvl?^SANmS^Nb-Hy;M1uWUZq{N^owFUCl}=09NJS?mr7{bTdj*wf$RC#e1? z_Ht?SyZHOjvYWrfUS9^hp}foS=Se&V&4aB=3v{2wr=JBZpm)Z+yfX6Tcu(-=iLYbC zmoeXq)#q8`4>8{JfaDL$`2QKtKa967E}!b{=P}Yrtollx`KmhEus2WMD1bT{S(@xtqn0cos)W;pM&2U*Ph;=! zA)JUb1>(|;@P;_`Sv-|;6uFEeJEoJ;GL zE6UZrS$O!fv$>4dAA%BI1pRy;JJD_uX2N80LULixR~MF*f^Y2|JekLV(Q&NpH}QYY z3yrcz_76A0!{EozfNsjqdG2Mb6PToRsqtFKldf9HyvHDjFj~_4lz*o>`NJ8jmtV7s^{30-qXMrB@+Q8VYSocVtwAlJKY+S(@ zTv>Jr?%1uT%cpQ-E#*>zipIq|`^h@I1-KBr!Z*@y&sKMvJOrj5FYDze^i;lUEeXYA zy$Zw72QY%F;3Mlj@ZG|KckE~Sed)@h_y)R`=LuZU-pnr!J&kW`|A$Y!M@cp0ig>@) zjJc+EJ>?j@DcaR&&zBuNS?0(Q#63vcbvxxwaI<}eeW1^*@M1z*{PHR!erlJ;flnm2 zq##m-_XP8k4$??XzCV3CYPkn-c0PkIY`j@Y;2oEAlzHg|ydAI7M)+ISVBZ(e ztMQ72l?}pbMIDaux<@xwR-o7rf8R%m(gk?UnSUv9)(mE>EIq<$ZE8c0;8eGs{Fw8)s;#`l+Ew9l6H8%|hhwN2fwE-kZ>mB31OQDJQdS!UN< zn3O1KX^sUd$Q7P$R|d2cpH3-bx?x?y33fB1oGkQCbnAJ@QLIsY|IP9V6e&9yc=C=Y z52i|4bk%aHcA10C5HI< zNrwUNvZuyc19~Pu-$TV~TetX(PjrlU*<9Pwg{(T}f=g2#dW1tU04#Deae-+;o)?&q zFaD;35kAE?K~YE_TNYYjsr^KYmS+ih+YrJ=(qckTRBOnNv|;)?Eu_o=in5&7D?uKo zjgb)=Ti3aNFu*M6Hn4LN^ex(GSGM1N_K{~AUyu{-&^2vj5FB3!`I~DMt}b-=EaL>G zTI)Q|g|tz80J~b2G&6`R(1MD$2>!1Zoh0f2Iy`#j1BH(Eu!5Y7G7vQN+}B*11sY+)+FFtP+y~Y%auOj(c{mO!F*9`ZPOjN zI*qjxYtDE;?h>mMip1&>PCcIG32PFbTTEitw*K`t>@u?Cuegq9@fq>QSRo$vX#U9wH@?XK)F*U{=BJN0E_W{m@pe zZ!g7jtgKz#g~1!p!@7R%v2M&+&agLd{8M5^Yt(2vlPJKp{T?lN1wKe|>{ZDV>>+s| z=72hSE?&@%T3AW$BHR9J;X>dn%3#M(j-tM@yM<@RkA?4+j$5mV+}Y9Qk1-A_0H?BR z!D{P0mUtlhg;$JTaNGq6P)b|bg!|-zn6uqGD;I~<^TLT_o#fT@)F*h7??9T1zB7*@ zE1Fd*A}O3IGRVI#V@J|L?Rs7>&^`$|1H$kaE5T|fYn@U6&O@L1+l$Le;bUSce2S!b zv&=$#<6`WcmFhbp==}C$JcF07C_%dxFyCV5B<6+Il!G)btkLkfh>L3$={Wfa$oAcq z9~kPbd8Dl?IYgI|wD|a6$KKd&|BRq*+kj_8=k*Tw+yEPq~6Vc^pa`uV^pqLb&N|v-do_TS2Px%3l#R|y4i+A$pr(rRW1*9^q zVx!0u@vOM2-7hr~NC0P6k&u!OsUMW7Y$1moMNC6F zqa1fl5=y=&hp*`a_9m;#wkc6<@Qy{uXIRzPTu1;UGXEp7Q)>%8Naz+<{jBoAk7I1; z1C0U{fSaU=){Pv077~=XSY2j0U3Y-(0B*L=(5}ZeK#x;XP#GEA2EBS8RKkfrT7M83 zb~E5+z1psb9l}-Ep7_K-qURdEC%>1FAjhjH7jH|ZgC$8)M&ma!uzi+m6cb1Hf^oF6 zY0WqR8~B#2jyzs|&*;oertIs`|3Hknja$50#T;EHDq3qfs)dSZVY^kSo$;hNo00di z^z8N3PzQTxQ+OB|HeL~s01j!>Ge3~7amLz8ULgj+d&nN`U2s!Oy?(dkZn&^rN!o1M ztz?I-wl-@rvJ|bQwH9H-vJLsANXyBxRxnO1${tg@8qvLMV`KHvLaDth?5S9*Benvi zJnCYXzg?_`d&_q`TS8tO2!DC+=nQbt+jeR5j4dYcik}I*ZRu+_?S2zZqS4)!lg439 zf|7YgxQ8-W6SY%NM@lG-@899To+{U)pQV=5jQiVeyqkVMS{PZ+K13^mcMBPIf}dat z7nQZO;^H87Y+2@d?smN6m<>6S*hTX*J`zP%g8kgof-10W98p`lua8!y;8tjjimr9iG|*UlfV>>Qq9cIJjAMaLe$re}Li#)2WW3x_Qp zyziFUr5$PsB%2i*<|I~UIzTt5Qc-*)y_C`)>k^)F42!3dE7+)tZ({SwT&NSBg|YpBSg6RO1Rg$hX4bHq4+~c42lG z)je9MPPSPK3DKIPm(mLGIuX7*OBM08s6Hk#ht2W#WzD8{un8B|yJ18m(b}$hy(Ikx zb!c^^#jtDdB?io={R}{ntN~QLwl1)paA0qeu+Xr5kEDHbpW(SL#;tR zEJzEz#0#7tivsAq8`@o4&mk0TOzx&#)~y`^L9A;cd(wXLm)6#kItc6{6~Fia$ykQ6k7Yyy$m1imC;eLa&+qsR z(v4UkihV%EFBY5rL5u{2n)7X`?MK%&g__%$1)D*1Pjmoy+A;uclBui;EZ21`;K=cq z?GUPUTH0dl)3kXj=7Pr*bsl*ss!Onas|*(B8ra21->*TYg?&v+ySQs#O@Ty8E+Cfw zD0a8DCiyPndtk}CRAB%Q;_c*&GUf%wYK)dLr?qL)TIo4;Z9QN`k~B4jR+N5-sA3Fz zTQF&BVO_iKOPMXxvTQ_h!@DG6NjXre?Q7uC(hoapcW2FRzjvLYdfT*&Dq zGFQmXlY_8t#ysM+)H2lgZ=o$ZL7O;|D>+b}`6Z^y$`pynnGJ8=HfQ(tmAHSu(^Qhu zmc1j3TiSIW_`omhuEm+x1N4v=NsqfZ)%=7GDl7bISfd$og^rfD>u6&nhM@RdRSvzD zm;7XB8HcUCY01AAiYe}!{P@0lAM!t5NefoIOIrl^I zsIp4c4#<1&<=P_sdz@2Y&8b5)gJR-_t}IK%^EoTx3^e=?r$DtCmtfDpqqhM}32Q6R zUKtM`GBuc@^3YFPEoK@6MzY9-twiE)TLw+|CSL$a{S}k?R_~| z7-?6uhH2>4^rRS>B$I58y7EsFzFddaKcY8LkgZ1kzrA47a|z3;uBat9UJ(^DiVjFS zL#2Ak`FG)=gdCWZHvyfXD}h8Uh5Kqj^Gv-fTX~W&S@p_Oy=*0yfIKMAjJ=7uU&XVQ z=jczx-0-J}kto`NG)?wNSvyivIf;2=@0*;32cZ+WtpGV+4!Y%bWKenwdjq^czc-=J-f8R_LqdKTSF{ZWJmb2L_5i`BHrdd2UD=Xnrk8PU(I!9WzaH_3L`wgwOpz{O%6cRhL zUEs^(eYNZx3SbtUJ*{;_4_nF9%mHIh`K*hwXX5u3KFOV6NYp4;)irBK!j=wN3mM8c z%~^1jkV%t}n{YSc@q0}BzgKPax`&h>vtt zyDsq%y$&7(Mci0c2Ib$5>@NHLZ0Uz^JF44mMDK+g3+$MmpYH|cK0kx!)xgEg7=dyA zV;Mzj_-y&)c05h@ne5GQwS&;z1wX9hT43zf@*90_zKnV9#)|0W0I%87u>X$a!QPUM zBP^(o5SEO&#?lIDWBmuz1$k3?3mtJFUM2YDY>%WxVjAs)l1$atmWDSM-bTy9OIQw)$A(I|7Ci;NeTG?l2;8ZaYoVnGRq`r$l4Ml&U|jV; z^z2Dc6uO4hpm%?>P_=kUnws1{yda$KW52VL^bO7@_o;_*EuOqQXqvTRPa_Frxfy!c zYpU0PLt6N>J4Fvt7m8#i$Edv>qE|{g)l#aL@EVsDw<}^NsqLi0%=5{`SU0Q+P6P+w zwU(ylANlCO+W6vGxU>9>+Hsy>Zfe5XRcU-hvY<{qW%!6Hu*I{+SR*lexmI(6A)|~a zSYvgv8<1>pDRUC%5tjQ(9M%slaN64ALg~C)>vyDysT5nhe46iUk?9%ct+~{;gr5^X zwJ=I~Hs-2*&Up0jGR~>~vVKMCK8fF{$VJ+zj;~$M>t)ZJ$HN0dhLdN5W}p~wMyx@; z33{B9cZ@}>Hz5X{ah3?)1xKtvAhMJ?QB!wo zADdFI#;V{_LtIcAYml!NszVw3jfZA4>%26yAp}@we@9F&EOpaO6Gtg|g+q2$T-}NI%s! zqAJRPK6>L>{11#ry3-QFdsQ@`l??Pfkfuxv6$oiRmzQ;b6<0d&o#iDoCyNT1ly(a< z@?DEBu+LsIQ}TI?Pxl-!qz*dltcH*&EopVU<`EVpm!S*gd)gJrJ4riB=OM*iaGFjb z8n^A!wp~TF=pdeGd5v{B2B8t)U604AcZ=@-(~8`dQvfN*cpdGr0Oev5|IF;?_5@239tvSno0CYkApwP(G)XmOX4* zxr|45J!Y4$yKj#@_Ts<4=DwY*jdjx34J%mZht>NLZ{^DJt-BO%@7Z}T@PxFw79-J7 z1&iWxe1?8HiEl2)PuLA~#zY55veB=zp51Wc|1xHLzMrqgN{~^?kk|6@{4@M%ffsT} z@@962oZTVolc~rnq@`p$5>~QOk<0t>TiVJzH@ib3fn+ygCtoP2znU@fJ2Co5nIAmAo9JAcSpT;TND{@l|4~*Zh}TQ zXT^@kIhp$b6FgzZviclqNr6d!j0o=nPwbP~9g;dTU?B@r6%fw5Ln&BxDIM`3p#Z38 zc87$nuu7j*R+xDp?O$sRXqlMg><&quWu5OY#kZfu_x6FH&$g<*m2Byih>~lM2)@4_ zbW3D;Jx*WhCdW{rf9DEWhvk-}rF|5%6>^2A+m#U?)S0c!RGMyBm-dOAWfVnJiN($C zkU(ZTr2xMYL;O6uLuSMPcsOSw|6Li!KDUpp)zlkhcxd>Wh?xiuKr2 z#r|mfDb4PXWKn>SBv?kvGExt{&+d@et?QK>`&16JG8%g1z7X>E^@$YZGZqk%S#e4< zzMhgTsa%q(FOb{B^0hj0IccTZj<@ygh!(N8*&Q;iB~?EHW$e&!ppyF)6fKD$Gr zR5sp)1n_;D8?F#l49;3Q^;N3_o^%_ooaw{dIBeCbQa?2TTtVFbetc3csB?FLOD9&>E4=PgyUvUhk-`2ml`3RG1J@8r+2WY7w;JEXOM?0A=2Tk?j=>{jMn3mlDXg4rF?SwVORuEMiaP4kFr_?~Ju z{+Ab2SGP%~Q#qLVdwwGWn^7}c~21OJ0@77YXucpn~6J?zwMP2h*p1NVCQ4H2vT5A#ar*%-qUXk6iJEVD) z{}WE4h~1Wx@QrL$WE|Q^+&il`yF<1dcO3jN?w2^bLzZ1zTp2<1i)fr}q1hc0*}98A zTdFg!!?lu(maHRROTHKur(%h9B%NU<}Xat#`i zr@JvbyF>1#U%W5X$FD&fY?oPAqC)60XgIT|*hSEOOIiC;uI(!2ZINhe>#3u78NnF$ zeSo*#4ehS2=Maicj@u=bShwv2d^04w&L#k1JhZj-$i^^_!0|{YGJ57)#h{2MadINh zZ+X6Lo!X>hs2^8$C1btYaHi-lk}$b@e^|`!knq*0-mK2#?nhHTWwwpO+`))Q43!_r zWzf~^4q5B8w8g-aIj_uQ=*B495$JuM)Y&he)&tHyg*cX)YaHL|-daNLq6)2ex2BMl zqPskv1Vzm5kXS8(y)s+QCKJth5n6S(L@X)C(s_-3zs_N3p=DUsV4b=BZ&# zTsBweeYfk_1_fbuq~&Wkm{#pS06%>;yF)^+BY5;amMP&{K(CH18rsMPXHoQ-YsZ`+ zROcR^0sE#g-jnUVt17Ie4p|nKFOmwzcB$FKFJ;7#9Dm=3NLfk65_fShQ0u)vW*@~e zp?_;UYJ8N*P+V0SHl>4PPAN&Wet93Y98vz#{xAREUZ~r1NqVaKI{jhxiB~kcLsD7Y zQwmaNc87#!$xhDhknj~eIJ-k~x0+zl%Hr(efozv7majg$L(cAyWRF{lk(D~TL&{=l zp)EZQ*GVW><+1D7TArh(A+rT#lp(#9x)U8XQu;60 z=B{0lZO<*b(G$a@GTp4lYteH;oLrJqcWLdc)3jt|0yF;do|8;eTRLt{gbnm~r+#Em; zy?=qGu)lFpu z{Wk#zR`p#xq1!bsZ2r9YOPnxnSAtB*3JyldITNzZBxmPy?20#w6-Wg*)}U-KG@G+$ zoVPg+J&8p7=lHa?zvSY1MJ?60?Q zA%@SnVdoDy$xGJc>zFxx46oSt!uT6Of&G6KBS0tg28I6QW8~P1!MQfD@9v%>OV)vH zY%{R$+kF_H%z^qa`W78^*OoR>1gGw_VR!+ZtjJ;%y`#OgaN!IGP~o&Xc|zWHo(Nv0 zu7n;zvL6i}pjp>4x|gx44GlLanm3{G-YTuBug)MR-6pn2l_h8j_ zL05gUF9a9;Yr+5GZk?CHdvonU>AxvMmNcl^H=p4Wq{S)75PWiIiS?%x@p|gjl=(2( zI=K@1a%W8^`DsJge%*LX$zvd$(3b2!3XD_p`a|fQ%kk&+^5;^lH}%V zwU(MPB-4K>sghW!SMkfj;_qkFSxUC|L8I&Ic>nOIY4w+-k`Y|$^}J8`)Rg-^Aycp9 z=Y>gH!}i|J^Zzyv`usDD{cb$+e_L#Mya1ix|1j*955k@~&s?@U&*!Z&W6rwoZ9aJ` z>z9j{%bxCq&wDriy%SNqFT(?-28df>`HmZOugCxMP88QGxV~DkuSa3i<0H;HQ53ax z45vIZl2I~w;5s*?=tK6U0ER@F?SrrRy`_|xccMUl(Va7^G+0>{6kw4$JHGi*5=NB^tmEY z-G#7-zS+2=Ae84!D0Nq4_V6cCmMP{-#wDKv3*_(TohWD|G#3`;=!`niVs7ztW;V0U zy+%=N-Plz`zKp%A?jX+?3P)r;$T`hBQLJfX&nl9xyp=P)&S|B$k#nt>%U`t?YfMw#;sszcbm@PtAezfa2j&~S^yd`;SvXs~?vP=4NuA0-M;z5$P(WyN0 z{?tRN`^9fos!T3~KZM;yep$2$-DRJz($@+ZL4eJs=BfS|#by(y)=bb2m zw7sXbTeC_G@$g7PF;ezNodfX?^7m(|(t?*3+>p_f|>}kN9Ts4Cb9E*cA4LiAc+st!?DI~P|6ZJQ96Zk*EUu@Q1kXNtvJaq% zw3CrS^G=lHs+w<+s5;-p2@>Qj_N-5PA$ftMyG#?Ou)m1?K_xf#81I$iI+D?9NXhqH z%bGr5PDR|P4Ivsh??iEAa2xdGllX2IPB?%W-mvegI5ZyT&G1)!YPQ7_auu#3`#kSN zu|Fftf(6pkt-V2coIH8h?RU<()KCX|Xj56HFT41HR)lw2+qisAzO3d~);8}%DSJC0 zv!L?&W*@~@oW=C%m*kP(Mka$wFX9C}TiUat1HNz1Xn{lJPt^4kskYr>0Js^*}d7o7vmE6Qzapao}v;iGs8u-i~c0Di+m{iRPR$ zG^_mAyc2~!3yy4=zjpCwOLf*jX%|_#^b$yw0Is2s40#j!04Yb6EOF6NFYr4OjD9uq zP89hL*uBP;a&zQNMiKrJGw{ML%+5PeWY=$_U-S>MrMGtsZCP0-@f0)*uI8O6h7JEK zW|Jqv-7h3>yF1T4AkL@&Z}@?X2OfraW8R6Ps_puQUdPRl9({iX<7``v78wsLzrOYc z8IR>prFY*wU>`}un)*1QSLHEn8~S{^fWExe}rRMmsMs;aco zif67-=Zdm^3QvmP(ZoBlzJggmiFrObHW-_;PxsuJEB-+;s{tlLpY zWhG4)aFTomRt1)+ro?x|wqn&8kJ%0(XefJ9E>)7ZEbb7h}~k(V;>L~+ck$0)HA zbV2! z`lC2sSoY7cMU9M7Z=r`F?O%pgK?7i=K?z8;tlvh%D@&WJl5R64tgS#=%(;NnV4lr; zLT))00OjdD)h)ZST%Yx_v|W=d3-41l?MSm}p0Z+?9RIi@46DN?5Dlv*n6y8hb#jg{ z(ynL?(`W%(PxDR`L07ht=?bcoXKku1^G9GSdph~#!ckB%(8NE~4Q}X9Wxt_%@_fox z^cuj}sCiP9f^|0UM1f|(%DfW=2?%A(J5lDHC^zF|KPS}wu(=vP@mudNzu#VMtxi&X zB+?YU3s;xXGJbxtd}@hk{lpt>A2r^##IAefW>(54rgi2gHDc_#{Ss=VW|mq|eN zr}oyQj^tI~k@INs@`$!0C$Oh==GW8%HBh%n-0F1kITBm)D2NX~S>DzuRieh!h0<-A zjH+z0wE7rPHa^r0twE2-7fZ0x!nc&_{S}SNirW>j6IUvEE_)aDi07RsU=Ir!THv&` z`FYLvF($27>KLhW#=;7?oOhxaVv0;ZUL;~xETV(W8@^RjeyZZwEmfy?uQ;}Pa!Vd7 z#$401NB2!IVEQ+Ug`ikFyr&FAN`o<%wJX6pLzZWS{k#(;HL-BIJH93z4hOKiIQ0~cpAPHrC^oKJ5hF@K_O4~EOeZ0ZrcF1Eo?934PLFpL!S|Yda-Cs zEEr;zDZ%TCY1!0RQjU>g{pgf9@mk*7C37`{s~^B}f5KcESg|u`0Z6!pUe=U7fO5Xt z-y?=>E%Ye-%8ZRlr}VICZFYLWUyo7l#MymrrnnImlwX8Doqh4HEuHe{j_0m<_Zz!^ z-iabxTK~>FQSe7v9<L2aj|ezt!)cQT`M> zLsx&zadg(Zf8K+lYQu!Kx#y>KmYw&YsNaHez_LoQr{+B<^B$D*-M9jWVtsxeQtoJT zC1S(e=Wr$d@Qt~3`^_hhmiJGB4#^{5emfo`V99C zN4LM5j_T&2pVmu#Uk~r+>Y@&XtNs}47YfSUWNWYWH^1Qt6TfUbk=nc1zi!A;1Vz5V z60tmSsZIiVU1b&rxq*c@%I#T;5?h56v_ENB)kxisPcwqdb64UoYbQhVDkKs)oloO$ zM(34xYb(*WLyCw1+41eLf^%DIxa?!DxPmwuED>ucySY8x{3G_`Xi9R7aj|QBp2Nl` zjtwlbzlftB9;vpLM|)SL&`FGPW062w?`{}K!U%H-b7jwjDb?|}P#8!0%NT#Y;hcQ# z7s%*jFx|?bJ=dbw-w^XMe0j=|9w@c;GI)=S0^=qo>e14R63q$rxz3-fEBddcA38h> zlK& zRf>q-B{_grRwt`-y}PuNJtB9ElvDKq+?Vo$5uS#8;WHxOV>tG_tk^i5>+Y?;T;KD$ zM#55PtwJK@RdT6g6Ueh&QmZ_X#D1lbIF-6xZlj}qo?hqdST(@#iYQ^9zI?10Ea&Z= z`h$@z4&ylYY~Igj@J?)d zn0xT4N_t6Z0Xpk=ONegktLTh0T@9>rxVzT9;A{MyzngiDMV%OP#0!p5T}evF?0CTb z*ZY`Xh})^rjoZB@7S^&u8~}t^1-z;ABcUFih~V?8Hc zkM**SwZ8bZ{5~JL~DK)>)pz&-ak6qZCAI|HK^LYlYuxlpVL`2c*N zIn$+em1i0C%VuoRJ=#n03c=E~zoHvkk#q^^`*B;!moO^NboUgbIlvAp?)8QA5G#|8 z>Ny%59nw`CiX)0LTEB2Uf{*MwRUgS`LiXZQYh9%;la{o8$|w+8y^lIN1#fZZlT`J=oeOzgcsx2+bnvNb@=66$mtzk`HaOG)OuS8vu z2ZC4bkDF}{?;(zr+4`;9aM{W}o`o;)e^?v7r>f!FW&bd@(!Mb56;^+{KB9+BD-1Fs6CF2Crc0Zaj2Y4NUhPEd@neWJ#Xvki1Y;} zS;>r)AmX435YzZbKWQ(y8p%$i)VuEzPPX!B^T&WTvnnQt&bSto*7|8B)Hz{;&xuq| zUp%b=$pNgs!%s@X1JWn;jBxue+ZkLI+euIo+ywuy2JGhNk&8{FTed5&)_}Fj!yg|16o|1#EjXO1&NBrvL?dE;T(?U zmMqoDc|?_mb7$VANJip^K+1bIxrBINa>=i;(|2ZY;i$*4Ui<;u?O1HGS&{AjS*LN)e~vrI!s<11EWagMwlIUD1pJFXw9sL~Ly=7nID$qBzS1o%c?IBx=@20PJKcBo_cfv+e zvm)fBR-zRni=TyrMvBPF=PBEetQHLqmbcH4bekt)^>*n)i&DTF(w+?bHi*?bI8QHc zc7=CDa!99)3L~i1-@RO#2%=g1(QgMCkxJe$GNWWtizQ}ZJcUd?JV}MYDmLtXjR#XWhYCmg_(K|A+CgGcYH(t4?~r6-L|jW5Iw#FL__ z#5l1b?(Io@MBJDio)&k&KaLSn&&en`(s9i2zB+O5#v!tXU0~^#`eejQYdwLF zLoWS3RnJ1Dps?EuPsk znCIK11b8{uvc6lLkFXSS4`BI0?qv(DibgGmYg%pNjI4#-?!s8V*M4vElFDvu^2nr< z65q-ly_;U!a8WsjQ`7wNu}cHg2V$MnQ2@GjA>JIgu5YZ1LCc7;xI_fPQ^yvM%fi)XY2 zsa0lG49}i^giUB#>%#Wjmtyr!DP?7Gz@t#0&s`uHkQJp3;uV3_+&goN+sF|)a*=dh z$}upqFKyb^(aBciLXYLz#!9=m#6n6DAogykvtP*})M~u#rp}aG!WeQH>Jio8ne;2E z?V^#MRK$kJ5c-jLCbWltAxdg{5|3!Or^+#g#AaQ20A+ihFIa|sY@j@9#BlldN#W4=|NWbZ$d32AMLJ&*ciV@)2E$Qe?^9UMSbINCGOypMIuf7PX*dHdb_~r_=?J7(EnP zLJR(uC6DAmyIH=ZBrPk>MzEB;G5s)(Ya`ijedDRtN?eurR?6`=vHC+hRvRj{))8D8 z|EKk;{$$DZKZuor%e?VRJ>?&)a5=K+`*<3CWBr;@WMrXq1N4OLp*)J{+mWh-vFA=& zBsL7xRLO({Y*zzH+VN_e&(XV-^}k!F z=z6S&b(5zd)2Xbb_~xr+udYPVnZGXsK8i>}M?E|x9W!T{^%KqoiHj2^hx7~W=bSo!@?Ij^og~jwD%6tI%;GZhB z-&HT^c6ZXw?8XvQ(G6Q-%0^O62Yj$=p*v@=WK$4@AOmR{9Z6|%0ycP3F#c6)d)YeX zWLpMxuU+P29WBn_7_4i!3~o1ec((lvNx&1#O}$aBM3cm35~YgL$#O zbS@n&SX;iXe$+X0>3Ad+{L7p~RqZ3^Y9zIO4LzevT|R>TKDGNjjErITO*Yh?1oWub z#EMrHSicm zrDimzrsT9&KV9_f)qofB5Ubvl+uEsy^3_-cyl40Vb9rR&e6HbAeEQYmH6bHq)vjsF z#DVvfv?&;0k1^n^^)r8#)bFAnv?;_K4kg0NP#%7)JsfBY?l zd|r4g^=O$hRTe>&EzTP(ub~cOszxwn#c#<{8_rhD!ditUz&&;leWu0L9kHlZ_ z-V(FKOP?;a!1AH+wB3oza3|A6e>rSr=*i}aAcPZSorMDcFLjFYn*J;6`rObz+C%sn`=i|y{{X4z?h?~(J!0%CA*KACfm zvaRYl*I?^OdP$KgJSDUinnlr-l#rr+_C&-FnTN!q4y2VDj#45w$|{?ldosf990ESe z?0T3vAK@Q5N{eH5J*-aw$Pz10943`3?;_5GvSeq;R+?Q8?X#o9q{*;>sBA>GI7`=7 zvPuI2b=Mau+p!Nf?_<>__FC(x=B$mH{axkmYVEqp|e8a>+eY2~Z(&#nZVa zAmqxvtgTROJ1Y`3Do5s;4CMUmdI&|0<$H+_ex6+q*J_MQI&8b@S!b7AB5HK@IpJ(g z?@9-InAY9oTJdW9IaWg3hbaAvT$Sc?Wgc3KIk6gM*TdQM5bn?1;mG<;N|F^kyB=oN z7Hx=z5l<$h*7@DsTgQzYy-?hAc0II@w!gfyZ8W)-Q=i4RAh*Jo#Z+8W0_CW&14zNMGmX_ zJ@xJEdYESz5-N%!KzYPLh%+jK!sp7hmih;{&aQ{ZFRbyJP8I3)iOffZZl7Hb$ukj= zNV?0@-q>r;2kh*F*FVzV_^T zC@tZB0?PKt^TMv1T@Tl}Xm&m1By*_?T*ZvE_X$jV^V#*#wQiO-_+XsGAvR&_OlOWW ze+%SxMJmvf(yeG-dN|CkhwA8G$8H>7Qm#4e22<>|`X3-XyB-n&Eh7TN5b#50*F)cs zS>{6e_?}PW<#|L-fsM``!pWrvC*9oBY^$s5X#OtAp(v1~hSxTVtjdbl?G8^u-p{Uw zWNTdMj{cin4@c)26_0?TX4gY}Vq)5vTf??qs}-wz8`UyGU9HM^t?STyhn4;B();fD z+V*~JZ8#o`mQ;*5`<1wpK^gV6#7WuY$g<*4%mhc! zszzqlL&XaW6nym$U03_qq0V4jhy+h57*Op{%H$T@R5k`$dD{!P)h&j9965 zcy>LM2ch_q@<8gJJ-Z%em7UIW%&v#%@Vu44@sn|c?1( zZ-?x=x%v0y_P)=<-g+I<(7AWjFqe6|Z9Uce-kTUjeIQ>i_S<)brLQRDgZLbO`(2H% zSbp{}Q0|U=0@gx(w{Pk~BAkk^aCU_oB#5W_ETLjujO=J>IVv78CtA>@)aO#op<7Aw zOwuK7{~Vv{xvV?MRXFO~uK0f~oraF${s7es03Y2zN`xFNtKX?&z@6`hQJjb|z=iKjQ9oyC0YyOC^O1rP5J?O$ir&$#5*DX1 zFOYy{h-&d3(B}St4*BMqjHdn@{4Ws{wPU3|p3cGZymb`LfR4WBe}Od=T#dJLJrF zF$Pp{b*amB9~kz`-#Q`zbVr$j@uvljdH$XAfFH!?#|xbai}g$wV%Pt=tUz3@ zm^zYH`0|Z)qSU(L8ticzNL|Fm)phm}tBmgxXDPetbtncSyCv5^*XXRoqB_l#WpB$A zSC0lgs@@IQ{*MK7F9YYl-&~GAua`fU;u$Cyyb=R~)1Jh)Ckw9Oec~Xe@yV^wOWb{Y zd%30LV$cXsHRisIC!rK^Cp=!?jO2a+K8Le*lMib?k6Jv13J%w4?Uha&ozPP`G1=vW&A_O97|qg^1m&V1KsF+4;to!&2Ja^vHvXI`}ri8 zA@(4o*uBjc%WYb-C$DuISd#rq*3Ow@ac`LuR*V6A3;yma|7-a6VY#&? zbO(i3B0oT*T9)(w`du>lhBKDAUo05qjPVGeJ!x>~GodT_iqhWL4?HDLz|WTYf)Vjo zY?}%)^*pTwCfMgXXHQ)F^!cSV}&lS*J9C41SS z)zK~Chj<_sA$p#>%!u^nU5TY0H;>o8xhw>HL{@?AsngqO9WZjP#1WFx@~UHRX^Y7A zV%$0wsQudF$auEqR8-!pHB55_$FUwF1w@C49um`L|C+6?jU&>f**qSe8GfJkO8kw8 zB~k6y5v%I$zw7ZWdtJLHZk;MvC6O-gV5HZzwjT3Gac6Dztc=N-8JH2mfIMs}H!S32K}@dBsUS?G4n#rC16;Rh{IBGR>a6$i>-{*Pb-gfmbt< zOi&A19eL0Ak@9Ze6naJ7-W0oZ21uHq)K{WL$5RM7-_ML zAEdn1e2%fBb(j+^IeYS!`CWSw*b&xy)>XEKkRG}>iUX0niq?Tr+iJ$#g_!lv`A{6ut6>mu_@4T7>@%pqHlpE3%h95ZhbgW%0v7ub@Oq&wu5$DnS5 zjJ{_jN1gANwud7|*rD(>aSq0-<4W2gmKJe2?o<|4SXz{IuRXTR@8;e%=d5Uo;-<4F zuc@=FXW1_A;8{3#_T+U<$?VB1Ie^uN#E?{nuO(UFHN%Q;;lPwB@Tt79l9y#|6LBIZ zzE;Bvt^Jhc_i1J$H$ge4v&9lPhPYdrxh(*6C-`UT}eyTgDC^hKO@*$k0YyR zPhK)jwRM43om?XB##spZ;R3)dY^m1{i? zyg&z7nOL1*R@T1s3Hs|4ZJ~zXuZt& z?b-pgSIF|-Grkm`-dt>GX~J9!yMklT&cr6zea{hmU-vqlJ$a##lrzR@${Qe=c$F1Y zLmFJ6RgrPXq{NEoPw$j<9ej?JUSo(kXHQ-vcTcC1`mSGg{T+~=J$Y5BUeev{$t#^I zj(i$?M!gJi5!=YJC2HP=E0cF!L$@mrgvJ@y505;d^=_iGCogsz7;|Md_Ejy1>wKC0 z6WM6;RFSH?FxKN3{f!QAH@;CVo~%a2uM^*y4P~{ZJm+^=dDxa%p7>~ds>oZv3RX~R z3D=O7Syt%RS(>Eb?Qm(WlhU#@mCFLJZ{X!Uo%wOBQ#LhgNQlun)87LDIL{d5Ilgsd z82DtD(;fm|=`IYebJ6U{JA3l3QD;wYhfr&B+b-%%xh0uGbRUZz`6ADxUrFhOsLrE4 z)dy$!6y51^ma(=}(LuMPc7VP#oGD?o@HBJUY8p$mM+2QF|D)#C{r3-d)~hpLugj^C z=AAuxN4UvYfbwUhX9=7~XVzK`!tX?`q|MNooLPb!kk5FT4`L*&Bl|A4o_0}gO@m2! z&K5bNBVWg>a73B)K@nj$&D9oO`Ychlg zA9bYWW&6ZPySDbKrxM%rB9{TtFa z%2O))2nKieK2VhI{dPb|y;gTZaJ0iGJw$taYT0JJf(&hY6!4s-?(E4cPNqu))In|Y zH=%jpdHc=8l5GP3>6+6MNAlB_znCugWQs2537+Sryly_6Owu-2qtR-dQqG>a|!yb&Xq4V$79fO_u*|WK3BP_He}JTUgJ)G$SV|0QYIC@{O%dth z*|ag31@1TOcu%KHgeBllu7EwL&at-JR8tJZkxkFyf8ffe2@&l-<5}{rYgmJCte?7K z4LZ_JW=~#u5TXdEm@`31m$em{d<1?SHP;C6rD9KIEx)jBy-?z6%UN8Cmg%*~4bR^QN?J$aEk=wE3?Nfb#c ztl#vgktayR*^{@ua~KJaU9(?LUiIRokFL8PUX1r;S(NAc;adJ;2j*E4u+T;tz}~jb zkI4N$EqWo(tIr;~z;^b~m7R?JW{FtS8~zrw*+=ESc zZ?dZ1Zv>g0%pSVu>wEhy--7RmV5xIBvX5xW%g{p5*$3f0f4JPadq`K^a*WHXqg$f7 z>i9hWZUo`VXkmX<3!^>Oh;ZlClH7U{CMVQez^C%E+sGhNQ%E zMngJSKBQupWmJZ5?Yk-d2bPGAjB9O@8Wb@Y$xzqWXPjF5lWbK5$NiWg&ziD|EAba; zP2Bob_*_J~KaIcg&iKYMn>>fIB1CD^j~YP=`)@a_fJ=MJKz6XP73r9-qFiOaqNkgG z#D46_CXB3oc8$+-s^rri^PIl@Pmfen!D#QZ!|v>`%lQy$IoBfkWlqH0Do=?Rs5{SO z6;4Je@d$_z!Fi5Bk`=;B7mZ?d<>_FabLK;Ql-!Z=FEW+Hc#u6>2bqSa%h}`PL*yOj z&MXs5{^ADE5e8LIzEGnyY3>>IF~)v0IVOo5Sf2iZ>@wz zohLRd*0RJYuTlz1noFMTl3L{%2KFnBG&}5~(TG;MD;4}yECR`Sd2X_#sY zXeARcP-Umr=JPBG7i{=%VlVhW&P!`;rLC(qIlhu`PN?x&#%yvo@}La;krqq8C|9NV z^zQk+05oXkY%;c?{gpchW30cdb`Z7Yn)chnr5NS2GcU()jLxjm>y+;u3-awv89Rfb zFN7p*@iRN@?yk~HtU+8cnW(pOLEM2TuXR5x+5U}|>Q&9m3y564Ys zhh5RhA@UCSgl#lC>{>s~4!hVK`)53`RZ`ZaJ}Gs#qLKU5!pYVY1!p7-3YEspN)8_#ym3){Lzvh{9`}~TP{xl++D0@d5Zm6oTI2r!1npiGwp0Dv{f~^ zguA1~-B>QO!!GqB@Z#*SE8jw%CG~G;6*4>Im8c%nsU1ZX@Z8GIqR#$mjBms4E&DHB zTWsXMGsWz%OU4cF4etba6W!q_Nj&@qzMma-9jAd)#jk=Bbmx180r#!=-bG5IFkNV>hcn%Q#QkQDv0fmQ-6SI?6Iyqn13K z@s%=jYK_QFw6lbTJdHZG#ThBlDp3Yy#K&~1b&;dPSDqbqMOmg+omNa(uSW)i2IeyA-P? z^Fx;2R7*4kX?GOTOjXs%7g-CT>MQC9W`|wH^})FHL7BTN<%J+lww&x78bfh~7SCV~ z%=4`!i%*z{OHViJolqaH;1f%Md70G_^`xJgRQUA~KAh3QhtI_g={3pSr6V^3XR z)fnbU&ep`R-rb;QBQg?=U0TC4~;W6eMA^aI4+4R!V_IfPo1 z+je1#6>D$87#0iGkKztU;C>~wT{O~@v%@aXOfJ&d-QFHSLSv(I*3^`?Kkm?2*gzv0 z>Cuc^^Pq35!Wx0EiDI%=X~jAozaQ<8o0FB+Q_AeHJCZ527E1dUNoE;V$E3-Vrad`3 z?878v9dK&?)s)#Z=pl?zB;30O?Uz zeyF>SygQAp9vof+UU$Y1;2ETt`v%Bgly0v*wSqW0gA#5zk#)5BGI$QVNGHk7 zQ%D=MsjB}u^N0MlCyLdY-aXn_Cmj;*#`v{(PUj`;y_v4yb!eM^^_eS@WQn$wNTzDu zll8o-;wV=m&F{U5%SXCMTv^7^r~(?FQX65eFVLl2MQujNZAVK<}5&b-$h4$&BR`t>;}K6L~n;qSf?It7$ZI7Xt+!R3p^ra&*L z9!gnmOMKfMma$}*)R6)iUVBufPKRns`(EB97)L`(13+nYZ$V1}`OKUpVK!IJ%38+) zQDl;uFCsorlVKvtg+ARQL-#$V?U68Ijjj@H_hQRSoQf`L^^JMPlr9d1l9dapVN=_D zjnjLms*<4Eg*J+U30#luaw@lAWG9kY01IgH~sUU3hpb7bWqr3b22HFTET5Z2Q^luqzu& zb?`c$KC&}Y?xk&XyvW8{D-kE!UAqr%>Mq2#{bq+2MC@Cav&<6IzCU#>+yfpARJQzz5fQ(^Ws+ox?w${(z) z$dsV0$We2RP@Xv}*HT7A(rOs_HS(yX+weyj*R`FDVyc}Tb``BsrQ29;f^F;rxE{F) zEL*I+iBD&TT_Qw|J0(P32W*HFW&A?k^Mm*t3Z*-^Xw%V=Z9Uu8$A^!Ut5OdGOKbUR zb(LG_YPFX^c`@hj~j# zpYhBX5^J&cei19WxU7hi7RX9sDah1AJM1dLt0)SqItsZ#BnFu9x3&#{Lt8Hmw6@6) zq{O&~BYv`B*!Lv-P1H`Z0?9Q+zuBoZw`0nTfIS10O-FS+TaW`w?rw_xpqP4X7qORm z$C9De-nKchbh5&aIx^D$G>pFYzUt8=FAdw-TbCS|sBR5j!fc-(GXQekdwFa)BRd*; zJXzL9+`g{17;$^O%Cs^V=Uw)}{W->Bjnu+FkChS!L1F+2y6VzH^*lXwFTTaX#TXZ> zRGGUso6Cc_%>A;-&iC&&dCT~RjyjglNbcEV_x4*|ID72c+Ja+dk6j`d(ob0%V2Nvq zy(TNgp;$e$$L{R0JA3TT9=k{m>|E6lW6zz0e33`ICM8nWn>JHp*6cN<(2H{ ztk9P{+as-8V|u>od}UA)kgV~(SgCk7Pp zaV!nX3Ln+B7qYI7?eU2vXBnTCtgEY#9V^cj9LMOqk3=OJNUR(mU6Qe`bt4|8*=+CO znIUy0%l{tVlUpKd{yNV4rmt-K?|OX8UVmKniH&8Y3R91>u)bpj+tnVsNl`z~UOT}3Msz_^o=1o-xK8_iQ@q!iA4kVqMTg_*V zgdJXy&~x;)n2j~S)#bTo?4Ju%A zajF#BlPy|XY3piDj=BO{!8xJEXI@j;nK&(Ibj3)E%^tg|-NgbXGVNFrQegJjHKpMJ z>a@>3b$UtPP~7aXoA+c}=9^a&QtSL~+1cihB`KAInmu++o!Fj+*mik`CPNF)9=n!# zv&XKoo>+amPgskWlY^nUQJe}*f_JpNw#=s}rLi*-28GHZaJHYkz9MM+JA3S69nBuQ zv&Zg#PcAtQ9;U-reabaY*4MEd$rrrWyjc`)v+QrypNSS^s1l-z3VB4V3eQXROH{j* z=WbQQBtQ6Z)D0mIErpny8cMz`e^wm{yf}O8$^wxu=+lI=$L^Z`lW*)U!LQG(vfeYk z6cl%JsbZ5ROwEgL0>|LJ%^thhwWG5Du1E!1SjMx*Zd*k*vfi>v7W=M^7L}1R#rLRY zBM!)KNulyI>e$xou`55#F*N5aGQvk@Q+MSc zjQ!bT7mDulK$11~vmGH`^MuyB&VIAfb+)|WIqBm2g)WHLDR;(CIvZ^(h4)^>AEE)u zjfpRP?ySt+m2qKZ2e52hajLjN^1i(=v>7X!J$5-(*WB07AYVp3e)<*3<`IT@a`xDD3@Oix$V)UQ}$D+t4Xebom!Ri2qW zcG3SjgI4Q$X%ynS>QaY=@O40vSSs(}Wj+Ym500>Fl(*;Kk)2Rm^y7YAjE{|LoQpq< z|HP~E;dPcrRRTV<4R4M*r_LU`rLScUl9wRO1?0d3y;oHQ1!vh>v}~*KhX*%%?4nCk zpIZO=#GxSSJ_2QD1p5SK#hk6`*<%+-^)`$nG?FTUHBWB$Xrc4OkgG(j$FmQ{Zad4o z($wov&&5^d+vF7zzcE^%@&eMy?O2-6pH6BT_9GE-X z$@58(857`*Q6wm9sy<${#Qo6Ds@>sCc#XSjXPTp}wwgV5(Sv=hLm5Y#J$CK&LWi>D zoE?^BT|x`~RyLSy4B8D|sij8Q$;SNPXr(L+tjUxZSsTeyeLg9>#n?JM>dwPwh6yc7 zzDkk#(ta_wjwk{t!i{+J6fhK0mTluNc%Q$YoY`{jbBoSWrr0*#h|7^p-^bj*#b^36 z8*i_vKC^5)qCEQ#+%f`^^2jx!v&Zi2u`9oWx?>--}+zpGTh*KD)a4Lp*nD8RtKiCxqkA zmQQZS)A!@gQH*yd-lMxpuHkO{b}z=b8RLB!WANM2=5G9aFaEs~@7-9WvHb^o#GFba zLZk|NWPaTpO=nze)1uw1x1fFN1<`V@MtsH1C(!59fGKYgds6ovK@4f_5wuh0A6ezn z!9B--EBFPw8Qp|7v>wgXu!7UG3MD;BWXG%GebY+mM@eh?ISr7!) zZ-TxOLgVv6$T(s+^y2|fHIK0hECg1k+ntE3{br$C@r$&tySNI&y%$lggVigK1Vo{R zy3@RB^R`Rv*<%+j8_PxWhWtO^YwUnuIIsLHyUIX4C7whL*`G?^+wK+iv4+8(C=^jDO@~;+<~2(e+mCvN z8EX!--uH8QFIQ6Pa>1z1Y3)+$}b@PWt@;y-<{_(XV6d~5h~_Y4Wr2|9wN(?6K?m1|&Q@sOn5IOh_C4 z618hP0Dl<0B(H4#C1~?OyhB`J)OWHzNvaZQb+kRVE6mz&v`kt0)H+ABomsK0-rC!3%wi?w#39~d_vsr+M->EwO!nN81JfU zDA@ZlaF#Xz+V$|rhP5Wy5cI~Iqi;d)56V@%Uf*;~jY*z5pM(FV> z`tCm|K`(^O%eu%Xv5pHd2AMv*62>DtrH)^=r}62DgCIN0tcD{G&`0?>&&iT1&pXMU z&UKV;WVIP_5aOYDOXR__B1ikoI7kU8W^A)=ioE1rl?Bn7a}}cun)d}H1dHq{Kdr=obW`{hbLAt%Jq zYbP^uC5-2{dB+h9aTh!=yY1pn&ThMCy4h_P4oU8TOWL?qd5TBcUHV@!fs*qTPv8^l zr7}`o#w{GNdL8po8Ja6lEgaUx?6zCNd3M{iUrh{*>N0FfSyqzsScIG|#k#^;l+Hl@ ziyG_hr=~nxM|IqlnC=e|d7$P_(Kl0UYt<&@w$^POLt~A*Gw)@6xoeFh5j8qbo^W=xrC^^PW>&VygEEhfv{?E@xhl=)+CtSB$v-^A3qa~*U*@Nq ze^mR!3v{1hD2rLj+l57Kxu*U0u#aRi9W$ci_alFMcH2!#!_$}FvybL8k;AOX$fTvMb<>QlZhK_1byYF*J=@ zb{7&I5q(d1q*dnkG7`RfZ<2TS1742eVaE__FK?)EM~`RWqcJmoKU(~?KgP4nOH^AP z+1>cv_GzCHqKg&K`_I?|XAg`k%ht&y)V=(4E;)`dX185am3gG(Vr7Mp5oNV*&5iJ) zDoOL4qI=Xx#xR4sry*04^6Q%6a$Ls-l85CJCEs3)F_nk&9X8@gW>b_3TZfg;Zo8_= z?IEVj;q12iIyBR(&`&Ry+^u2-oF}yBl{D3IOVX#PZ+6>tOf)MX%Gioe?X;>XBL_C#3No^Buu{my6Me<9 zn%#E4UL=C4_E|uL`atS?-2c`vOFvpxHK)3%rdAXZZ?~qwq+}#V(yJ@=cH5=M8e971 z=p$a5-FAWNalnh}oF1QWg1cYJ!y?9EX9RQ@}2a^*Bzw;uVej8TmVsbjCNa z7oGLv+tRAy_v|&}h>yk~lH9KXiCKD3t|uz9tkAEsH2cEE&@-i%mZhm&7I=L!nfGij zwrfa;)qM`-IU0kkP-mPZ&*aJ4|LP&&mF~jeIu|`!=t?&dcr@?3&d;ds4BjRBb?2;4 z#*L+t49nPE27MMr`m5dnBaVAe_VgociYoAmq3eAqR+yIN-A18k3`xcwwrCdD;h=lj zIo!sHJ6ri=zezFo!xe^S>R^dE|yU4(c#W-W9~tEz`1mK(JAX!!P$QcN<-q&ujA2j zY68DoHJz>W=J(lcx3oWqg(4H_MeEOjt#ZSBGm?M3L}?*i%eq~XV_!KhE5co+$$>u# zTIg3}Ul^+aUE>|1eTXy9Zo7{I@5t)?PX<{3V$p4mADDQwekHc9(!$uyf3othjp|yl8osrR@Q!l@Nar$}Q|_Eq z@&1~HXm6&sUemKhswgr8jpeCDD8v#cSL2ano0U|-^GT7cN_LC%2;bI`pvgu5c;mKPa==jjrz;)ODfHoNV*&nxzfq_eFaQD_M*_*<4dJb@;(e903EWyP8K zp_FlwHz_f)Hj<}$`IwzQQ;xq0UVIhLS|$@0#YU6=GP~_MB28=v)gXwEVF(B zZu>g)n7BCQY4RMJO7c|Fpss znB8{KD@Yt{@Z_hHutPISUV7}A9k2V?BH7SRj=9^8wY0+z!%v*uc8PXc7t5En{SM54 zI+*~pD)AP<-p}d1#8auuN6_D=c3*V~Sn*W1VJSGaF}v*&L!8}qofCwAM{%6-$*-hM zNtoTyC{Z`FVBsK998Iu~iH$nD?apqyXe|00kZYXXb|vM-Wkg|Sw_RZ1>UXrLU^Bbz z!Y$i+w%OiLY!5Dby}<6fMH(wBIJ@m;j_OiC=s3=)5G$G8c6IVo*;d)OK#GV*TCA>f zF;A)%e|Fo2f-;+hEiVX;>Kl-5SVH@E+x;-k1aY2<(Y}ilK6quEBVv@7O9WrN62Ma# zOT^x*Z`85pvQ3I$xs5wH!Yv+wo^xdf*$Yw2_OA=2w3!7}8L$pz0U1Hnrb$ipnHs^b z%oeg^-Fodfo#2Z^tkUp6E}F%3(85cY z?fneVqWDDgdm(h${TS(H{7Xl?KP?B)&b6Q$@u|@KAg67EiQiB-S_t zdgkvwU2fm!GptdT-;3x-&913QJc?erm*V&AQSIK>r)S--skMhjITLv)WCz;q@=}4% zT^4lceG&5L@?dPuNaP0iK8z=c^>h9mx~F?9e?MHHx8JO%F%sTR&N&`kGn0Sdgzn>| z&WE`;5qe1PU~WpKx<+|s_E?U|EOcRd7<*F9w;*rn@vmCMuYOJJnsb`WU zfpoqcKSOyMn>D-BJ5`{(qch2#^ANnXbU7NC86U?SKNkD?-2t$JwqC^B-^Wf8jvA4% zkqeRlmLZ=W2)P`={G6W%$JAy0EvSNw*6Y}dX1Wqocxm(T0ei{yCmlfZ_2`m*w#$$|Fyq=LnE z?bD88`e{FBMxysf=)W%W8Jkehm4oE-)n&!pboy=ViB9s!PWMIq>oSilTxO)Q6iLE7 zAI3~2p11GK5G(b7Mr4fVG553B%fpx-$Xbscim^3nX~$m@#u?<{RVB5(bL==m4zkPaWfVSsT$gTV(9{ z%0WE1{|cCe9M|82`)$z(X83ca+C%tpM6)@|<-i8NeH*x79%K`85WTX#5^z+0e;QIn zXN>-Swn`-AAvk&$t1MShuh5(*`0?HOZIs-%=8z1st zc@EKm^wI%-==ss8n$6w3@L`n0`)<*}>URKVa3ix;AlV)S7QL0g-%Pzm2m$mWNXL`@`|F$URdBz?`J&A|T`)h75*aE6hkh*&z zMX@Y>V&pWwsqxxJiR&I5R8~V98BZ+h-1!E%1~u_hIaAiTAiZ{-;Yn)nn0eh&D~@$zf%k<-EV9?6uOLY(ql` z=EuQ_^ZptnA=2yk3@R7SD#4IxbW#~hHOV%`LdcDBP8i!3x)*eBgN*SLryUuO(61(j1!hW;I%Xo*DtFo^iFDu2; zLdWI1uHVESb({w2zjn^H#Z(B4hgD>3C8o= zykos9iH7Ac@2`QX=lwNU{`3ACI3&4eWOUN!2uHbm#*m-|VYvVenh|I=TOD%_V#1bbuA&HLF_H5C3mi$>&ZFy*E&k26z;f$5U z1>>RVkQeyU=s$btsn0BBMJFkfb#j&1G#kCSUz%wD~cMpX(`)AD>Ej0i*mt73>;jnps zjbKmTg?WDs+UsPI(~|ieDYv%nm_@49rnw}$Vby};*o;Yu`MfPuh3m7__ zToN7Iumsm^fq8!oR@MF)4{Vi`b?AR-{u0lM(6}SW2=Me8*YDzHj*-udw!r#z zZ+O`P)xs7sm)O_n`;Cdq6u%a4;i<@n zT_0)L1n=o-s+)@&KYaK{iv5-pwcUXebL9jSLg-^bf@cNHO(hmnO`$z#ni7o()dS#TO>h!*5BUs$nU)O?_fStH~YM zM?IZtU9ORQR7Cfv?K|4si@Db7XZYThBeEX)?(MCV*Znwf6Ev(-J!q$LAGycme@UL* z_L}4ltI>$&hk1WZS&K*J2OXbSL_b4^#OBZ!D0x1M0{sY&6j_(n9@xPUG~oxe6XhKAHE|ls(7|aU^D+op2{#V+!~R zn+fr<>ci4n+PCZtX6aN~mYzF3Vx(VI%FX+0+^b6Z3$2TNZw;VGa#FV8+3OJ5kYioG zpPrEBHTU&1prz*hHHsD?nZQzcyHbxO#gMWKgRFLIk`~vNZ@aJsj;+U81E))%9#IVv zxL-+WPl$uDsHmJZH|oY=iT3bnp~uF#?oxQw*f6=|BqTumwLp^O7{@sw(Xo%p{I83-5SGIJG<0pFBZK<8DG$iWkZ_+PuHUUN8A%d85t_ z%layz1%JzuhbPc(k_e^LC{JV<2Uuv9ak9TtV$Az%RG%q(2Fo^cr-F5Tb_L6Y+?Zrx z+S|%=)z*n?MCbiA%0}g>#FQP#1adW^_S!qNq)E-(>KpTnDP58udM~rz{&swCY|8rI zEfMzXu@+9_J9h)`SWkZyc4gTgmx%k9F&ElXoj6(He+6~mos@nNr@W=T=KVG6eFx;)F_tSQG{pVpM?nl}ZCN2Wi#yvWk)N@|=p_(#GkTburQ}knaaqA>oE(%l z!IMOGyeh0=(~5m^WJ`T=Qd*tJ$VmS%@;GtPiqDGYU}EZH*1A_8Vfc~VaDKzD_cB*%K zHP%zcMFbgq^qTq@_p7DG85ybi0^X~0Dw-|#?|r4#6pVLAqx2@+#oocXqY18KA?`o# zubKDPU@u`+C0(9|oun9F%|}p?y?VYEU&5ovnWS2Ao3&&qN5=flxIB$D$GGTn%L-F% z>T1Ue;1#TcXYs$H@ufAwH`LzpOgTO@Pi;RoqE3*Hsy4-C?2IT+S~ZSTdv916HJ>LG zSRXx-@JrHfWi1*#{b3}WtYG9Tx|8+Q^_9Gr@@ou7@ZkzI#sikQ9%1E8e9D>_zn5~} zSI$&>R*bIID;t#YV9C869w}RIM3(t_yniQp`W$T@M9-6Zn=h80`B%@rxfb8?%+2`r z=JNCXW&P~o>gI0z(HJ*3{~mqOk2asjTDYs$xp&0_Sfl0Uww`K!FCp@J+1qzTg`m9W z2k|-ZdROC%9WosNVE;fBI!(_TlC0o@C>$0!rzPrqS>0Dll3jTU zM`wg@$$e2)uH^LXY!_l|W&rDYgIX9YM9#{~nloKK3>y3)Bo@z057*S}dNj#utUBal z&RWwK9FWwMl*w8I!BKq!5*|xPwV-9sKV)pXxZH* zA7*Y0K58QnaP~Io1*iXMfd_CAR@5yOE;5Asj)n7H8?r%{0%DxgyBu<`!~}g~Z-wr; zwrHCB@$bdxmFga}P~Mk;^Rx$$hv$n;!wW<&@N2-obeL$>=h*p8@lbSm+0TlV^xlI; z8c|YBZ}2rTVr>Lb6LJF`Fz>a27oP+MR5gXQsl4J^G*J>496?<=-=C5R$nVBc+D(k} zKJTpAXKvPrj91PMeWUZzbpM5auAK9x2xSg68u#6_GcYfIUH5mM|F=om^Nc-~%E;?? z+jrMD7`zS}>~+8x`&1sycKK$Q?Q4P4gY!<<>g45+i0tHE{C_w8y%W~@mmw`}uk)R) zdF=T6@y)&X{}1t$pYi;&^R8_$B*K;Wi`FKdJv;BZV!)Et_DrqEQbvmJXXo9F)YiT~ zcBwKI_?KxLm!5?^HO_6~i+vXF5GOF~YYzdMmCeidwkKxiT_7fZI$@4fRt10Qy<}W0 zvuTd5aB6mT-bE7PH6EW);_SRDn>;xZ|6z9CC7zk~b)H%&y?JYhJHeg4M+w?;9I8Hz zOr}e)=3gR;`5Z7OK1#;Y`YF%V@up8VDk5=GSg5v->D_>IE#qJ2{d`6-K703)ww!mr zAMd&wajp#8i}g5OotCU4`01OJ9w<_aUKENn;+d9rL`lC8Nn$qa@%GHhdN<`V zIxi1Nqj5VPaUI7o&@A$XQ$kXY$tsDq^R4bS8{yZPGH_ew>=UEr9!Gnv$I80|c#|j@ zyVR)}y@hlKt}PD0WkR^5u^K<%8|dNva|0nzCV!yZ%Wkib^(cnMDu9P#Uc#XCP8lH_ z#iN9OMLkOWFCAV|kVe&hWedP%v-57reS%Ag@uUOuI9P*zfSzM7v-7UKcH}8BW2CBV z(4=y>9sa{=mCTV;2I{VHRpx0QZr;bLP3*PSZS8xo#_O>r)&VD@3y@>k-vT*SN+8SK zn#0&1yHSN(QVH-tTJUtP2?*(IX-W<29#$l3MAq@X@~Fu9=P`cTQM2=IDc?(c@bi-b z-qsa8z12F)I>gUg3n8tQeX$*}ej3TxYcs25hXv`yq>`LRnBPs2S|QW{eUBs)Fd%oM zyd8cc99GxYVgI=Qtn)ltTgfF_lcZp2n^@CZm-bMTCiCYbEtXl8_Cq*#o!`wKB}l@1q(f`Hh!C8nC8Z z*M&g`TXwVVG4(h$p7@!5-R*X);|J&tb;?HL$QE}EvUE-BCpgPcLmJ-~ zixnMCb~brM+DV=OzE#N~P(JZDW`=*Xs*(@zt@$Q>CG36M$@RM>&%$B3hU}S8#vXhY zqRkU18gMICTG}X%yChFrO4V^m_Ch8K=xJxU4&@p$5{mE0*(u&>r5bcxcZk-yT%|la z?~1Zat@xHD-K|Fkp(T4wWGLQAAC40@1HK zOHC=Y`oyl#Np06s=`Ur>-~wqfq}GUg6qD?+Io9R7_N%?r+}F>bXe?32QWqG*@UiPT zc#=pT77O%gD__!>h=uoOjO-xYd(+Ru270JQLcZwnSFp?7S;YNQMzBVs_p| z|Lf+IR(kWhD#nzJMH+A-6*_&f#D^aQWg#WZ&$1dulCGxQF%L7ovPJeJpjzuGxJ0^6 z^%r%P2a5)LDpnxdwdbE&3#EO8B(n^wy&9t6_JYvPJgI!SKPM{V^QU9^*RP|6bj_u^ zB*(sTURH$ZoXimVtY3}11ZgfH=N*F0*?AWY`v13guFZKIxfSNu{0l~#s>qv2v>kh6 zJ6DRLWMy>=Nm=XK+DfdO?Tsv{D0vm;WBz!8rwfztpQ z(<|@F_t5$ekVEa{9oJ{4Ctc9))KccWvQ;|=2_42Xyvq4bk~zjO#=O!hTA!@LT+w(Y zQe!9@PHSUI>?uivv3UJ?tvFujT(R-KH)->TlY)68_wIYq*sZk^y^bTqniJyN%pZQA z#05!>Tbi0bJTKbk$$AP+@WhlSC?hJp@~$zSx$AjKzROc?8}qX`v=-|8KC*zO zPj)W5E`{HdmRU2(TC|Ol7YQ4oNc=E+OxC%kK$K6(l_W)bkNdIO-yQWLc~gu(Jqy~A zP?v(NAgGch6}|<_^~$?&A$8eS@T!fw*n5_%^f!lCZs>&|+nu^8)2kf6?CV2qqFLyb zcO6yso|*hBeB92rw^mmc5^G%^A5f+2gY^YS&9yUn<=u=~V%5z}PBKu9r?u;=R5=*y z*Vcl|PpUnRH8)w!o=0{<_%~C7j@O&C-?&}*gl6Yaxo)KJIR7uIj37PQEAP(2oA0`Xy4B+Ve#DP-DO>Rd5iFW_cu6EPnnh@=Jzdga}h z!5N`NcukgUa%lQw7PLrawK7w^@~*ttvRSzU>Xmo3UVG);UU?S{!k!e{ ztvzb5yekb#c2cjr3lFgBc#N>~;?1;&4_`8SajX%0S!(!T*ZAp`cWu|P;))8&Q($Z_ zPf;7aPgKw=@A|C1{pQ13!GBpYc;uZ#mw`f+i-U(8AGK<3%SR5j1z~3eVo++%#q>Tn z=R-KmnYQTAgR(}xi$2rmXIh<;;%`7_?}{(=anZYAHMFoaaNTyBDOuOm$Tqbm8I5++ zz4C6xCURDL<=rc>LjIv>Iqh63PMeXBB))n#BF)c=V&yq5 zl&h)ss&bByb>#RKYeAOfNwlo|FEpg~I#W4iZEMn|w8+n21m$EyzKQkpRaDa52x?ZV zP1$Sj5}|;r%XpYC*0+otW)$1m{ktKBvH3hl4j<~M}{SzSbxyTN>yqw?;2?bhq@>aEh& z5YEt+yn-(eUsrPou#%;!f7y z?V8OUr&eyS$7`Q4nQ*U)&J<_BZps7c^?0>r9aYI(LTnlM)OBidzc=(LJ63|%18qNy z%V~`#&wD*yYFpw@B8rs0`I?X8wX8h@CvAE?-j~4zS}|EuSwyF7X26ldE|R$Jw#weRUku_9;)>F-wY%s)iXYCTdWu9o*seYP#jy z$$QwD>;`25<88&GizoMe__xM3 z<7Sb@*%eY}*BtXYuRZreyDr+=)u%OE&v>r(dgjsDHOB4rc)j07pURSvivmhzr8s{? z=&IM_6^@5PI$fN3u(myLP11-Bf~z_Who0~Cc#){AvfAtM_IkW`V}(#Z=4Gs#?V@)S z$8II1*W)EWxYy&YaX1L2*W;B%sy%YDK0-Z-;o6hh_5#Rn+UxPkzbTKA_x0?-h801x z{~$?dfvzK3i7Wjkl>$s60OyF(OH9#xmmR$T<%kd z5UsD>E<0wBu2;j>#EjRJ_IkY6Vm^93UOYnbIipoM2}cZD(y2N%^`29btb14$$h7uW zvtm~nNzYyE_#97qa2M^jojbB<&z%0XTr0gEZ?DHomK;7as^BBJ=y~*cdeZ9iE*Zha zSE~2afkS8o*~hm_EA`*XDM6>(@1V6YJ^@8b%8tc*tK0`$Y_E};nqH4LbqMxN@kduT zRot!DcpXUXe%@!oei z3B_VaZ;WM}S#>^#vIe9d$s))IpyhffJIl(Zu}-hYtNBGz$Zp4{D5)XKWjs5rO=1PN zC;HGWcx?1OlU|P(3{M7NTMY@{EKxY{Ho3mWN2w_ntu*X2*lJ2gx;0i3{WxP=GXtKV z%3^B$@r(LLKWJpLtVH?(@LuQ~w%?6|mY6!PraY~*AbjricwKi_9w6oqU5E?`1;E>0 zkJokShwlJLKh<~@j`dsGuk`qe+uH51ViiAM-qNr_oPns*xw1ZJ+WoMDAmcG5itZ$W zK4|a`mT?#@p^a?E2oXd#UuJAeL3FAZfxpnzPsyxN+(ur-l)0ph6$?M|Y{yV5n2J^p zT9Svn)vgh2VxOjIXg&MrOLPnGaHTEzF~wb;PKuH*j@72;)Y(|PD;5pqr_gapiDqkv zd1Vim;fY%tQv%)0P)gh)?aNp-;$f~>%imTACd3l|2U3h=L*fl)Q zKBLj=@oFFA8Q%(CwH`O0&A@ge+x)L$c}7n-Ky$Lb=6Omf zkma|&&?@)cwT{tRsB^}p&4%yFV!oGMmy)8Sg?^{}5v(5LnqH6B^26G4ZX_Jn+pz05 zlx1zu)Z+&sbw9_w*2x)RVs}k0zdZA`RWk2et0Rd(i{J&_4@pGUdOcn|C|QBsxWm>Z z>sO4ue8crt<9qo&T%kY~0N%Hi2(1bDhI@oqTtU`az1QPa{hsx;MGS^88uxP2!%I&C=LmKDy0KPyz_p3s`R*W<-6#jb}H;XHb+rFtIP+6izwt)n&7 zlwAR1%DN_|`J==ZTEej)>FyH)Cb7 zW25dElECiiaY)ltUCPa%g7sMY1Y|i{>APOqU?&Z-Rs4+ShCVEMOG)saKV?(Wz1SP2 zC(#m&9gSjdg7=u55AXGOdp%yofqFgOI)6f|3@=Qt$2+a}rXw)MI;ne8xAuCxw(Hut zlCc9O{ULO-_53(`pSGaah*ZjJCv~r5S&)nRDJ{6jWwtfdUdTH zc6V)_-ul|_15N7RAEM3Qmpukvd?QSJO~YsM%;X;mvSUT#AIO*hIJVyVTfXO2ibRKe z6Fu)2w2Mc1eNB}g@kP1?YSGm_^?JP0xOj6|Gv7y*Pi$7s#oM?tzhdQSd8b$PKY-(T zHzg7)|H63xpgqx)EVXig-<7@StQI6s_&FB8@vYb6#S5TaCwzmi@=vkSk*=YakUJL7 zQ6eYWnO_a};=hH)S23!e*8U?_6X!x1B~^JpS>xTF9~a%XTwPxF_Ha=3BbE2EAM0}1 zK7I1@tLSO$i_^|M@8Pa?75KaM>QEbVdRzKbSzRxVwD|hkucOW5Yw6#QG|lGP!)R}7 z?dzxo@`uplLrqkF|55bqeTwRjpJw&(kIE=D!h7Ml-izLl<uES6?+q(5SJJOSR%S^Hce=G!$2&T&*p|3}OgQ($ zd0F&oNx`p&91H6!n+SAp8o4D<>6mhQDraSvc-Mg!4PTf>Bf4Y*+Sj?^v%Z`wRlh~q`3!9?31gk!Yu5QJ#=r2l_QutCj+QQ7PtKp(k1NZ$n7JqT@D_d~z@Okv)u(FUvb z)1U!ejui0M-^aB((Tb47X0*;MklTDW{vx_X-#-`Bf`oh>S6&rrRF4|`DmwKR2Rx*k zLHEn}oq3N)D0qjpv|n0v&3)+IiK}A_1lN$IS4LB_kLq2E*l}7}ZOxxwpi!xBQvecQKf zC)`rXKKOh$H7nTMIO|n_=1*DPGBuHI$0_jvrdpt>M=ji zt963zs&|2@n`|}5Zx*31G$JE+wi8saw@aOr`^tZkCyF$x$d=Fhb361ySDi~U{iTa)L zG#NkKjUKuat!%}8kAe>VzFn@0hV}UTpwLY_LY=e*HBiX&9_=#yLEEi(=3ex^Q;w|vTR zX-1(Hs<(m?&(YMit+)@_6A$mkz0k88qvu(A;F=_4`%oU>$G7FGooM>{YJdKzsYYVdr)VfcVd@k#naIwePp=FwQ0 zQH?p*l=xL&r6tL6t9K>ITA}p8EN_Nfpn;(To=c9blcWWptJND@o` z_beCxEp%ezl&Qg6pxB*Uk32oTSR?P{W6`9&4X;1X|(eCIs z!NVIzZK6xvYT8$|_OPIn)`tj2A^*?kgA!3A0lC{y6*ld2jM2vU>Ulgf4@20OKsyJ8 zXQFIaGc&QA(S-1su?O|2=u22d8NtsFy$<;{9d>MtVvH4`vEBP5ie?5x)fCRFcNWI1 z^_Zt{jx)KmAK@ugd1t?7jLiP@WqeYf$}1kupI6%Q7)f}B_1mHuw}b}eZ}bh?d}y~> z^RmiQh$cB@&pbOn^cgw|4T1iX_JM+FbT>pq+2`^oCn-4|+CdMkf=z~eTZ}W3!ZBi) zLL0+tvIwi-2R&ij+MtGePFq>1 zWZto;ccPd3m2Qyzn6ksm*-lBJu#nx zrNtFq23rV$g7wngV_$h@dYz;uxOf{lp8_~!TecqFyR);98zm+(Wg%NX;^)N%+zu;; zUsAr#J7IsG25p+pUmyKuM`Pbv?o%(`MiTwGd^QrQE{BaIdgQsxwRbjla%?5BY>VwA z+)Dj$k#-VF&fiXgQrX*hzcjTQ&pEt2R#NkJnXM!gUOp=cRp)Ib(E}Sr6Cg?a%(qq- z|1C67C`cb@PTdh%-lHZ}zHtOj@EnB#E}>y zwwQ`0pTs||FK3B~Ph!hohlL{7Y2&axTbX&bP5ao-qVKJUy6u+;+uh>f$BjZRu}#c=b&(PKx8$@x@Fobfql*K`xD@Y#H5TO}T@tWVDw z-UYp*j2v}FJ{2M7x-z2MY;~?{P8?q+uaBrOR6Pye>J1TZ`9)T%7KInZM>d4d8W;G#DAgK>U6fFqO}>rY3WiXrS1QG z|BLeTW@j}L>m%;FIHyrrqtJW5jEG3MqT-oVw^{}P+#2Q(WQ2cF9_um)60R%vl6h#O z|BlXQei`&QF4N|*EgP@*oJ_^(GYd{*%zlwVXATZy@Xj~TJX%iWp*fCsWbDaQD_%`) zq&{hcd)vWF_(R4nI~o3hXMT3rcCJ z{49gip0+d(xis#$!RPQalGbv&b8c@oO=n z<@|f{N?Z%{`7%yjZ-j4Qs;7RqbGyOXVIfkCzXM>PTxHiBsH{$X8o8<8cw#Ob*g^MYLQlYJIz=t$fZ5yzFMRe zdK?>_I{RKRxnxEr-k0 zd+W7>0)Ea5XVI4tAlW{PGulpyv*_{cGTK_4MPH|jw1)X`^sszR+wqZ>=ILy5+Qt@K z)sBr=h8!GXEoZTv6lpO=A@`GDt;C39q(u);107z5tTt#_Hm~h;uogYe&sIzgJ}a9B zyu%K1Tm!JJZ-b237TJom`D4y&gDU6RFUo8?9kfM{Sq+DC@GWJlWwy;jTl923nQinm zRk`nEcq{SI6xyQCUpn4mjAWQiBd(P3*{H}FeqK?ta@*)>I=gLl+qqtOdJ*Ee=_)Ki?_L+0S=AIn+!2d}lvh&`%eviovkn_Sb%h=R2YQbkNe-wE~UQPdErl$-sIV z9xdT9z4wjpm&@0mg~x`i(;`31;#+8ukb232uq-rM`e@5;zG z@o6~I|| z!{fJsc*yY2%(5@b_2n?#IKt`nXq%tKxC@`!bd@!?abB2<{$wSVMO{6=tbV^1{OkE; zi8D@8GYww${Iaakmvz&6ewkxdr;*K%ob~*&lUGiIk3GL^_!hI_`AJJ|&o4t>@O*t2 zyL{Cjr9uX0D%tC*`uz3qYbj6vxM-~HVcci-^w~;pj2Yv;aZg$i<9Ec=wd|=OPsX70 zyJ+plK&8|OQH2m%!=!x1~29 zWb4Deh|2CqeGR{39OQX+{iT=jljsFnmPfYpMnp@?c^bi*YN=yQqWNc$$=A^XS&J~%m}Tu56n&`n)uOaAL& zwUPA|V!_NRdzAH%M|LFifH(Zj(Rqs3rBYizUvd1pZu4r5h})N;(g^2~d83^wR6Yq= zXk{(qz{rg6ldNR*y`F>D-=D=vyZ@oLc2=ijDz) z5;c0cb9qmh+e_b{t_=Glx|-PU@5A$V(l@MP!?Q2?TjZ4!=EEze=ek#}d*xQce@I!6 z0H5>?4R8?@br~=qv@DAPdp4kRs(Ln{d_+`5;k?Q>@q;H3X&NKJlUDcb)#l)9_sX3P zwuG07ovsD`BQJ12^fB39oU|n-`|&B_Kzf}2_Jl>qO}TsD78CS z6=*yNoJ4%%KVqk?+G)JoO7(^D_)TLxupoC6jk_K`yVp_2uD-T0qh0CBw{en!7~QjY zKLl0V)Z3TQ(!4i+4c{WM6@6$|z8@Bn{)g>uH2Cyd^h(r@$}z2{ky^^D^gI=1)_X6q z4@PPaX@ROd0mKWq;jjy?tN#>5BreWIAWYbcwQI` z+K{iFfjD(0K{yN^btIM3AkL;)mGTtMK^YueyHtK3e$1kE2S{ zKC|_;tB2mSkBkBe&J{FZAWhX?8wkF*OA-28iK64j@&wO8|Dm7 zdD4)TvwTDCs=hSn!C$l)r-bj6zxLL?E!g{UoO{_m^c?MkU63cK*KbaL8oZm0+|Din zd^#;deOqtud};^MZ^v-o6@=?EuVg*Sf*cgo+A$n4YvTR={O{>TL0Ns>`_{d0J7L>* zON5B3Zb-#xocvJy%$^NmTU6&GzP5Tb7HFDX`|l#7p-|Q_+)m6c)hf3OT4bL2WG^jm zI(ZO2mA@^rb$Mf=%;jth$G4}0w$824%@Qz>c2>)tfQm zXT?MIK0e)!@lriP?+$j~-S3Bg^X(yA_veNg6%Bn82=8@7c%O%T#k-`d&jRP7 z(Rn+uYFNJt+$)X$bHRnGqiy^9D6X}4W>nR2>Gpf#*vJn*oOb>>`sRH0LHt&=I$3wo zgY8$`d8&6#@a)Ia==j@lh&u$-bIxRyZm9?Kl4gj@$$N_jA|2Pe< z+=5TneiOW0<>b$P;qbfQ3)uy;TKDYimHiIAy@~l@7sYue=lH*iYj|z>9#wP84ZAc|Y{^Xq%e8`F4!i_pFzBBljtvcgtI`b6Jnw zwzx$6hyJO_1WmN56JH+R^!LR5xsx%yC_JZn)V*l+f1(xbgcz}9?yL9~P9ewlQS_)$k%z*ZtH!%>CV2LBS+hI|U*QVtmv?}KL>%u|H^z4yA74wIru;(%dJWJQ3M|u^_qFVgSr=SrDRQ*G0XiIv~dR&*r zkPO$eOil;qdq6`&xd;?8%n-gchbJ zX5%34XI-&I(O^&FH>>YO%)&;I5V!&Fxr^^4=R=PCOSJc0Jo8US5_cz_np(dezgrrv z81w02__*#x3vdv<%Q{JYuU6oZzJFe%yyZP_^X3k0j$}qUA4&0fF(`x=FXP%q{D=qb zwKpNXZ{pOaud?rhrfdbd(X4MC>M!={e^X}YSv(1U=|NhM8Q{GQ{O|D*wcd?LF!VqJ zXFWAutsZ^0W|5YYjrq5rpXzhwHIn#!8I$A)KN9*QB~<#v^PqlNiCcxDp$@wh&r5Sk zlQ7m_AN^CE>)XWxsk%B_F>m){EZfoNjTq5`X!p1AcRoW4dq?`7U3JR+R(z5TzI8b7 zMhkD_t|t|SP{y}MF}BYBW~facmUd*Vp}0mK@|*stXe27PkX1(v9xnhIQ{DlzPsR%2 z^1V3K$=s3c1+VpHa69dC%7QF<~cm5Uj+YYm7kkstmwnEY#YVCZNy!&fS(uJ_euQ!c|6Ng@X9}@gOtv$ z73f4KzlzoC3X=G9SIOvnQd&S0y$#(Xbh>fWsyVR{YjHg^_2u{nRcHqg#Oxa5;F~Xl z7uSw(jWGjfzupvmX$|@?Mx471Rxo~MRV9YQI-$)v#X6)mes;JfpeCu>iF?ND*f2#4Pv|YwnTDLBea$U-T1DerbfPK2edWX0IlInQ@DY}Wd5yj zv;$+6plmCon}^JUv}wyVdX^>l zsc;ty$9!22CX(VE=wM+qqBV5Rb5e^OST{@S!?o1F*aTTp?;gfu&)J;EHOUK>oPCSl zc?cg&i+?L>vzR}Us%iNFNg4sbAI&s-Yjp32#wDS@}V_XRD4UF^IgcX&>pK5D<>U4MHjLH^3$sJ zoiE}lYZaV?#xnl2)=4x%`$NiES8XnON{mMJrbsGU$()|j1=^Q`ZQjTItmyBHY(ua1 z)6(Obvnv(Gt7VdP%(z$`KbIBGc*Zoc_Td`(2#to$dQvo}X`HY3hg^`p9ct=XZE>O$ zZHPDIU75|RAy29#qFvbg;KKX(M$~B!^|E~4558;!BD!)k6G_WwrLDapo9H6yMQcW{ zjOVmtbe}R6wlge=u)CWdUNkEmxw+4Zp`_^ zk`MJwe4<9f&A4(S_SWni$g-c>Igmf~Z}Ht$+_S#+pYdY|ka+m{-jVOlls+D0YHB4}y8qBHFZ}!W;HFyClTfo6Pi;m974pXlnB3fd~O2VLsb zafNZ>*Y+%GplAhW`P!v2Tt=#+cC=V zIqsS#!;Dh+n4?E?Y20*b-!vp?({0%na>8COB@jmK(+)*QE z?V+~IRi2QqnH_0TbG2aNgFv>~ms=)+NR`#viY^D^2X z17c%N5A@H^qgeguBec16vaAXg8tqcYdaym%zS>G$i~Fp_*_(0JQTEB&b%@-u=X&(C zg8zdUjN?&nc!oP!?JHoKL`E~d@Ahs*af*F-!wjL=fwNGjj%7S zL6PoN zoAyGiHb(r|L=w?ONS|Z(M49RTec6LE0%>f?-!f8wzrudqu}nM+*}=k~JLp}JGp{Q= z#_aFJ`Q>EfVCDI3xbfC7*5qNJ4qXAe zO`}qc#CNrp$b04Mu_I@%wEHqL4;+d9O^mSBu;Ky{4tTp+RvzolEuqy}Pi^EG-m(K2XNyeXmc4ks z%|?Ax+OuzVHQS6eY)5;&Aef(m_T=ot!#<(XK6mxD0NPW^ZxA)EG?vu)WNEQ|!hPE$IbKD<;F-)|kfg zH;fU0%#^VJdeyUOq1v^hQ7Dc@`<7n*&isgjB3FvNTgqCj#Qo!_uH;d(;b<}|RXYpy zWfY{Cfu&#-{?WH*T;s{u$GiBhUI9p}?jaVz-a9$7N}u$|Dr7aX3jh@+X0&Xu4v|hM z)Xt!ek~3Cjh)5wwUhCdk(-9?X=XXW=xkDPlvy^k09LTZPnnh79kSjE|5h%+K*H3?D zz{8BG9?z3A9gkMxv<|u%v%yZy=qp!9>gM@2(->iBHL*_e!;d2+SK_m( zxCOexA5O%AZ^n@gVGXc3-jn-*AHgEv-`Y1)BeR|0QnnB8620se6v6Y$Mnk3$5VLkS zdXcAFW2&!drjz%IEvZ-LTyej(ds;vVBZz>sxZ zg!)=U6<7)B`DYE_J-!>?Xr_<^)l$IIwJ1ViO56AZ)SN~=ujRb?+Dq`xcyKLP8mT3g zAe;*|L+`#wPxUYMjr6M%-2zBVW^=}!)?c@2P^@8 zZ?ryE5t{8=GM7D?DKt=XI_Dib{Qn Date: Thu, 19 Dec 2024 15:31:11 +0900 Subject: [PATCH 6/6] Update README.md --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index ae81ac5..faa3703 100644 --- a/README.md +++ b/README.md @@ -318,6 +318,7 @@ Note: - HTTPS is not supported over UDS. All HTTPS related configuration properties are ignored if UDS is enabled. - The grpc-dotnet library doesn't handle non-HTTP schemes (like "unix://"), so keep passing an HTTP URI to `GrpcChannel`, e.g. http://localhost. The actual HTTP requests will be redirected to `UnixDomainSocketPath` by YetAnotherHttpHandler internally. +- When using Kestrel on the server, you need to set the `KestrelServerOptions.AllowAlternateSchemes` option to `true`. ## Development ### Build & Tests