From 6d1df5f1a668df762762b02e959ed9672fa18209 Mon Sep 17 00:00:00 2001 From: perditavojo <117562794+perditavojo@users.noreply.github.com> Date: Sun, 27 Sep 2026 06:01:00 +0800 Subject: [PATCH 01/17] =?UTF-8?q?build(deps):=20=E5=8D=87=E7=B4=9A=20Micro?= =?UTF-8?q?soft.GameInput=20=E8=87=B3=203.5.278=20=E8=88=87=20nuget-licens?= =?UTF-8?q?e=20=E8=87=B3=204.0.18?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Microsoft.GameInput 由 3.5.274 升級至 3.5.278,與 InputWeave.GameInput 重發資產建置時使用的版本一致。 - 本機工具 nuget-license 由 4.0.17 升級至 4.0.18。 - README 第三方授權段落的 Microsoft.GameInput 線上授權連結同步更新為 3.5.278。 Co-Authored-By: Claude Opus 5.5 --- .config/dotnet-tools.json | 2 +- README.md | 4 ++-- src/InputBox/InputBox.csproj | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.config/dotnet-tools.json b/.config/dotnet-tools.json index ff974d2..87217e2 100644 --- a/.config/dotnet-tools.json +++ b/.config/dotnet-tools.json @@ -9,7 +9,7 @@ ] }, "nuget-license": { - "version": "4.0.17", + "version": "4.0.18", "commands": [ "nuget-license" ] diff --git a/README.md b/README.md index b3d7ed5..e6d6888 100644 --- a/README.md +++ b/README.md @@ -593,6 +593,6 @@ Remove-Item Env:INPUTBOX_RUN_UI_TESTS -ErrorAction SilentlyContinue - [.NET Runtime](https://github.com/dotnet/runtime):由 [Microsoft](https://github.com/microsoft) 及其 [貢獻者](https://github.com/dotnet/runtime/graphs/contributors) 開發並採用 [**MIT License**](https://github.com/dotnet/runtime/blob/main/LICENSE.TXT) 授權,作為本應用程式之底層執行環境,相關第三方聲明請參閱 [**THIRD-PARTY-NOTICES**](https://github.com/dotnet/runtime/blob/main/THIRD-PARTY-NOTICES.TXT)。 - [Windows Forms(WinForms)](https://github.com/dotnet/winforms):由 [Microsoft](https://github.com/microsoft) 及其 [貢獻者](https://github.com/dotnet/winforms/graphs/contributors) 開發並採用 [**MIT License**](https://github.com/dotnet/winforms/blob/main/LICENSE.TXT) 授權,提供桌面視窗圖形介面基礎架構,相關第三方聲明請參閱 [**THIRD-PARTY-NOTICES**](https://github.com/dotnet/winforms/blob/main/THIRD-PARTY-NOTICES.TXT)。 - [InputWeave.GameInput 0.0.1](https://github.com/rubujo/InputWeave.GameInput/tree/a3985f29c19b35365124d70cfbf0c21d1596ad3e):由 [rubujo](https://github.com/rubujo) 及其 [貢獻者](https://github.com/rubujo/InputWeave.GameInput/graphs/contributors) 開發並採用 [**CC0 1.0 Universal**](https://github.com/rubujo/InputWeave.GameInput/blob/a3985f29c19b35365124d70cfbf0c21d1596ad3e/LICENSE) 授權,提供 GameInput 執行階段、用戶端、裝置、讀取狀態與震動控制介面。套件固定於本儲存庫的 NuGet 來源 `eng/nuget/InputWeave.GameInput.0.0.1.nupkg`,封裝來源為 [`a3985f29c19b35365124d70cfbf0c21d1596ad3e`](https://github.com/rubujo/InputWeave.GameInput/commit/a3985f29c19b35365124d70cfbf0c21d1596ad3e),套件 SHA256 為 `3e9a3d65861a9211380aec6211ccf9f6b9151eae20df6d8917d3e75a98b9b589`。 -- [Microsoft GameInput Redistributable](https://www.nuget.org/packages/Microsoft.GameInput):由 Microsoft 提供,作為選用的 GameInput 執行階段可轉散發套件。正式發佈 ZIP 檔會隨附 `redist/GameInputRedist.msi` 供使用者手動安裝;本應用程式不會自動安裝。手動安裝 `redist/GameInputRedist.msi` 即表示使用者需遵守 [Microsoft.GameInput 授權條款](https://www.nuget.org/packages/Microsoft.GameInput/3.5.270/License);相關授權與 NOTICE 檔案位於 `Licenses/Microsoft.GameInput_LICENSE.txt` 與 `Licenses/Microsoft.GameInput_NOTICE.txt`,且該可轉散發安裝程式不屬於本專案 CC0 授權範圍。 +- [Microsoft GameInput Redistributable](https://www.nuget.org/packages/Microsoft.GameInput):由 Microsoft 提供,作為選用的 GameInput 執行階段可轉散發套件。正式發佈 ZIP 檔會隨附 `redist/GameInputRedist.msi` 供使用者手動安裝;本應用程式不會自動安裝。手動安裝 `redist/GameInputRedist.msi` 即表示使用者需遵守 [Microsoft.GameInput 授權條款](https://www.nuget.org/packages/Microsoft.GameInput/3.5.278/License);相關授權與 NOTICE 檔案位於 `Licenses/Microsoft.GameInput_LICENSE.txt` 與 `Licenses/Microsoft.GameInput_NOTICE.txt`,且該可轉散發安裝程式不屬於本專案 CC0 授權範圍。 -本專案的詳細條款與免責聲明,請參閱隨附之 [**LICENSE**](LICENSE) 文件;發佈檔 `Licenses/` 資料夾內含 `ThirdPartyNotices.txt`(NuGet 套件授權聲明清單)、`InputWeave.GameInput_LICENSE.txt`、`Microsoft.GameInput_LICENSE.txt`、`Microsoft.GameInput_NOTICE.txt`,以及各元件完整授權文字;[Microsoft.GameInput 3.5.270 線上授權頁](https://www.nuget.org/packages/Microsoft.GameInput/3.5.270/License) 另可於 NuGet 查閱。 +本專案的詳細條款與免責聲明,請參閱隨附之 [**LICENSE**](LICENSE) 文件;發佈檔 `Licenses/` 資料夾內含 `ThirdPartyNotices.txt`(NuGet 套件授權聲明清單)、`InputWeave.GameInput_LICENSE.txt`、`Microsoft.GameInput_LICENSE.txt`、`Microsoft.GameInput_NOTICE.txt`,以及各元件完整授權文字;[Microsoft.GameInput 3.5.278 線上授權頁](https://www.nuget.org/packages/Microsoft.GameInput/3.5.278/License) 另可於 NuGet 查閱。 diff --git a/src/InputBox/InputBox.csproj b/src/InputBox/InputBox.csproj index bd763f3..f874e3b 100644 --- a/src/InputBox/InputBox.csproj +++ b/src/InputBox/InputBox.csproj @@ -53,7 +53,7 @@ - + From c774df30c81afd8a8efa5aa4567c5921f9785e79 Mon Sep 17 00:00:00 2001 From: perditavojo <117562794+perditavojo@users.noreply.github.com> Date: Sun, 27 Sep 2026 06:03:08 +0800 Subject: [PATCH 02/17] =?UTF-8?q?build(gameinput):=20=E6=9B=B4=E6=96=B0=20?= =?UTF-8?q?InputWeave.GameInput=20v0.0.1=20=E5=B0=81=E8=A3=9D=E4=BE=86?= =?UTF-8?q?=E6=BA=90=E8=87=B3=2089b1486=20=E9=87=8D=E7=99=BC=E8=B3=87?= =?UTF-8?q?=E7=94=A2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 以 GitHub release v0.0.1(2026-09-26 重發)資產替換 eng/nuget/InputWeave.GameInput.0.0.1.nupkg;實際 SHA256、sidecar 與 GitHub asset digest 皆為 3342051977f6f1b91f2a18acfc224456320264dd67633ed4bc41c8188c9fcdb7。 - nuspec repository commit 為 89b148669ffe58d9927495ed0d89f9997bf4962a,套件內容僅含 net48、net8.0、net10.0 受控組件與 XML 文件,未納入 GameInput redist 或 native shim。 - 同步 CI 與 release workflow 的預期封裝來源 commit、第三方授權聲明、授權附檔、README 與測試 README 的來源與雜湊。 - Upstream 變更涵蓋 callback 與原生資源生命週期修正、SafeHandle 終結器、裝置事件佇列上限、TryGetCurrent 系列與多目標框架;InputBox 無需修改程式碼即可建置並通過既有測試,實機硬體矩陣尚待人工驗證。 Co-Authored-By: Claude Opus 5.5 --- .github/workflows/ci.yml | 2 +- .github/workflows/release.yml | 10 +++++----- README.md | 2 +- eng/nuget/InputWeave.GameInput.0.0.1.nupkg | Bin 251970 -> 429235 bytes .../InputWeave.GameInput.0.0.1.nupkg.sha256 | 2 +- eng/nuget/InputWeave.GameInput_LICENSE.txt | 8 ++++---- tests/InputBox.Tests/README.md | 2 +- 7 files changed, 13 insertions(+), 13 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index f3912ba..3015e10 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -115,7 +115,7 @@ jobs: Write-Error "InputWeave.GameInput 套件 SHA256 不符。Expected=$expected Actual=$actual" } - $expectedCommit = "a3985f29c19b35365124d70cfbf0c21d1596ad3e" + $expectedCommit = "89b148669ffe58d9927495ed0d89f9997bf4962a" $inspectDir = Join-Path $env:RUNNER_TEMP "inputweave-gameinput-package" if (Test-Path $inspectDir) { Remove-Item -LiteralPath $inspectDir -Recurse -Force diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 7131cf4..ccfccde 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -92,7 +92,7 @@ jobs: Write-Error "InputWeave.GameInput 套件 SHA256 不符。Expected=$expected Actual=$actual" } - $expectedCommit = "a3985f29c19b35365124d70cfbf0c21d1596ad3e" + $expectedCommit = "89b148669ffe58d9927495ed0d89f9997bf4962a" $inspectDir = Join-Path $env:RUNNER_TEMP "inputweave-gameinput-package" if (Test-Path $inspectDir) { Remove-Item -LiteralPath $inspectDir -Recurse -Force @@ -254,13 +254,13 @@ jobs: Add-Content -Path $noticePath -Encoding utf8 -Value '## InputWeave.GameInput' Add-Content -Path $noticePath -Encoding utf8 -Value '' Add-Content -Path $noticePath -Encoding utf8 -Value '- 套件:InputWeave.GameInput 0.0.1' - Add-Content -Path $noticePath -Encoding utf8 -Value '- 來源:https://github.com/rubujo/InputWeave.GameInput/tree/a3985f29c19b35365124d70cfbf0c21d1596ad3e' + Add-Content -Path $noticePath -Encoding utf8 -Value '- 來源:https://github.com/rubujo/InputWeave.GameInput/tree/89b148669ffe58d9927495ed0d89f9997bf4962a' Add-Content -Path $noticePath -Encoding utf8 -Value '- 作者:https://github.com/rubujo' Add-Content -Path $noticePath -Encoding utf8 -Value '- 貢獻者:https://github.com/rubujo/InputWeave.GameInput/graphs/contributors' - Add-Content -Path $noticePath -Encoding utf8 -Value '- 封裝來源:https://github.com/rubujo/InputWeave.GameInput/commit/a3985f29c19b35365124d70cfbf0c21d1596ad3e' + Add-Content -Path $noticePath -Encoding utf8 -Value '- 封裝來源:https://github.com/rubujo/InputWeave.GameInput/commit/89b148669ffe58d9927495ed0d89f9997bf4962a' Add-Content -Path $noticePath -Encoding utf8 -Value '- 套件檔案:eng/nuget/InputWeave.GameInput.0.0.1.nupkg' - Add-Content -Path $noticePath -Encoding utf8 -Value '- SHA256: 3e9a3d65861a9211380aec6211ccf9f6b9151eae20df6d8917d3e75a98b9b589' - Add-Content -Path $noticePath -Encoding utf8 -Value '- 授權:Creative Commons CC0 1.0 Universal(SPDX:CC0-1.0);詳見本 Licenses 目錄中的 InputWeave.GameInput_LICENSE.txt 與 https://github.com/rubujo/InputWeave.GameInput/blob/a3985f29c19b35365124d70cfbf0c21d1596ad3e/LICENSE。' + Add-Content -Path $noticePath -Encoding utf8 -Value '- SHA256: 3342051977f6f1b91f2a18acfc224456320264dd67633ed4bc41c8188c9fcdb7' + Add-Content -Path $noticePath -Encoding utf8 -Value '- 授權:Creative Commons CC0 1.0 Universal(SPDX:CC0-1.0);詳見本 Licenses 目錄中的 InputWeave.GameInput_LICENSE.txt 與 https://github.com/rubujo/InputWeave.GameInput/blob/89b148669ffe58d9927495ed0d89f9997bf4962a/LICENSE。' - name: 產生執行檔的雜湊值(SHA256) shell: pwsh diff --git a/README.md b/README.md index e6d6888..c5ed9f0 100644 --- a/README.md +++ b/README.md @@ -592,7 +592,7 @@ Remove-Item Env:INPUTBOX_RUN_UI_TESTS -ErrorAction SilentlyContinue - [.NET Runtime](https://github.com/dotnet/runtime):由 [Microsoft](https://github.com/microsoft) 及其 [貢獻者](https://github.com/dotnet/runtime/graphs/contributors) 開發並採用 [**MIT License**](https://github.com/dotnet/runtime/blob/main/LICENSE.TXT) 授權,作為本應用程式之底層執行環境,相關第三方聲明請參閱 [**THIRD-PARTY-NOTICES**](https://github.com/dotnet/runtime/blob/main/THIRD-PARTY-NOTICES.TXT)。 - [Windows Forms(WinForms)](https://github.com/dotnet/winforms):由 [Microsoft](https://github.com/microsoft) 及其 [貢獻者](https://github.com/dotnet/winforms/graphs/contributors) 開發並採用 [**MIT License**](https://github.com/dotnet/winforms/blob/main/LICENSE.TXT) 授權,提供桌面視窗圖形介面基礎架構,相關第三方聲明請參閱 [**THIRD-PARTY-NOTICES**](https://github.com/dotnet/winforms/blob/main/THIRD-PARTY-NOTICES.TXT)。 -- [InputWeave.GameInput 0.0.1](https://github.com/rubujo/InputWeave.GameInput/tree/a3985f29c19b35365124d70cfbf0c21d1596ad3e):由 [rubujo](https://github.com/rubujo) 及其 [貢獻者](https://github.com/rubujo/InputWeave.GameInput/graphs/contributors) 開發並採用 [**CC0 1.0 Universal**](https://github.com/rubujo/InputWeave.GameInput/blob/a3985f29c19b35365124d70cfbf0c21d1596ad3e/LICENSE) 授權,提供 GameInput 執行階段、用戶端、裝置、讀取狀態與震動控制介面。套件固定於本儲存庫的 NuGet 來源 `eng/nuget/InputWeave.GameInput.0.0.1.nupkg`,封裝來源為 [`a3985f29c19b35365124d70cfbf0c21d1596ad3e`](https://github.com/rubujo/InputWeave.GameInput/commit/a3985f29c19b35365124d70cfbf0c21d1596ad3e),套件 SHA256 為 `3e9a3d65861a9211380aec6211ccf9f6b9151eae20df6d8917d3e75a98b9b589`。 +- [InputWeave.GameInput 0.0.1](https://github.com/rubujo/InputWeave.GameInput/tree/89b148669ffe58d9927495ed0d89f9997bf4962a):由 [rubujo](https://github.com/rubujo) 及其 [貢獻者](https://github.com/rubujo/InputWeave.GameInput/graphs/contributors) 開發並採用 [**CC0 1.0 Universal**](https://github.com/rubujo/InputWeave.GameInput/blob/89b148669ffe58d9927495ed0d89f9997bf4962a/LICENSE) 授權,提供 GameInput 執行階段、用戶端、裝置、讀取狀態與震動控制介面。套件固定於本儲存庫的 NuGet 來源 `eng/nuget/InputWeave.GameInput.0.0.1.nupkg`,封裝來源為 [`89b148669ffe58d9927495ed0d89f9997bf4962a`](https://github.com/rubujo/InputWeave.GameInput/commit/89b148669ffe58d9927495ed0d89f9997bf4962a),套件 SHA256 為 `3342051977f6f1b91f2a18acfc224456320264dd67633ed4bc41c8188c9fcdb7`。 - [Microsoft GameInput Redistributable](https://www.nuget.org/packages/Microsoft.GameInput):由 Microsoft 提供,作為選用的 GameInput 執行階段可轉散發套件。正式發佈 ZIP 檔會隨附 `redist/GameInputRedist.msi` 供使用者手動安裝;本應用程式不會自動安裝。手動安裝 `redist/GameInputRedist.msi` 即表示使用者需遵守 [Microsoft.GameInput 授權條款](https://www.nuget.org/packages/Microsoft.GameInput/3.5.278/License);相關授權與 NOTICE 檔案位於 `Licenses/Microsoft.GameInput_LICENSE.txt` 與 `Licenses/Microsoft.GameInput_NOTICE.txt`,且該可轉散發安裝程式不屬於本專案 CC0 授權範圍。 本專案的詳細條款與免責聲明,請參閱隨附之 [**LICENSE**](LICENSE) 文件;發佈檔 `Licenses/` 資料夾內含 `ThirdPartyNotices.txt`(NuGet 套件授權聲明清單)、`InputWeave.GameInput_LICENSE.txt`、`Microsoft.GameInput_LICENSE.txt`、`Microsoft.GameInput_NOTICE.txt`,以及各元件完整授權文字;[Microsoft.GameInput 3.5.278 線上授權頁](https://www.nuget.org/packages/Microsoft.GameInput/3.5.278/License) 另可於 NuGet 查閱。 diff --git a/eng/nuget/InputWeave.GameInput.0.0.1.nupkg b/eng/nuget/InputWeave.GameInput.0.0.1.nupkg index 855252f1480bd38ac582305482a7dfc1fe67499c..54f968d6a141640b98498a94cab889592e283c60 100644 GIT binary patch literal 429235 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 WhW!>pUEPVB`5`s5?9_+Mbte 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�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 z'nZ;7+|j9ICutdu}}V5%nIL)VB~U2nB2reydH_N=nLe1u%6R&4xq6|>uRueDUu zfo7Szs*KmbqE-bs*qkL}2wP@@%Z`Z0UXn1lBtTC=sbQCluLFo34qq)vsJyLPi^bOA zEPdp|!$Ke-V^kf;6`$j}7U!Sba)^#w7DQXQ_AVBjmUbm_S>2ElX^K7BM!?aSe_MUF z9~(5|sZm(!Mz?Ylpos2#5=e0ouo3eP`Z{(aw*xR(dTPSkj!2x(%stV_;49o{bogrh zaOq6Nu2G2*XBVz83XoQKpx@ULU?JEnqqA_=i9USLr?0mzFIGm`<9jieD{UChlBJC?CcIqYv?%yft#CnT%%X__5L$ZRcO?MaPVZ?li~_WXFN2NwvK%bo21h@aV&L*NvW z*jJz`@s6DmmeRB>#Mfi$Pqf0Tixox?E9Qy4EmUYvNz@nC{K~b|R4*2B97)C=ujFi0 zXhW}x_4+zDw~Tfc^`6b}aS%w3gYigC@m%Oc)BV0CT4}j^yB_2Y%n9wd@$I|uP4ki^ zCViIFo(PZJ4)J_{dkQFgoyqRsHsJMjtt;wov6;p&;GNm}>Hh1DpAHnEVX`u)@XdH3 zcSvwb>sMs7Qm~^yT7w3A#e{g&y zpKvdC@hrtiQDv`hWhHL0#hN3p&R+(_=1b52WVBqf8>Vv`Gs&@XEwZ{Uv{d=B2-s6j z6gu)OckwN~qRLr93z9F2G=sgSgFRcd;SYD5Rc(}AYO~e}ilY~-A)crUVV9`fD!if# z5^*BJS7%q15hZuru{RD9W#FbIzx7ekHUG`slGZF&;y{)_$>wl}We-fSK8Wj)O=K)F zu&Ea1E*yN-2~tnQz!z7MO~Q0(AY-#gy}cL&tb>zlGD<@Jj8W1UD`uN#{v)Dcr#-b2 z%h7mCvrp8V{95IJM$nuIWZx>G*Zx9DFaW73~Rk^<@wMT9se+WSS+JBzr^3)#^$_o?c>aFlVaY?)QNI@kf_WZa& z3>zMruj$N8u%G*O1(pN% zA(u0_yTM>bUvjy7A!8xhLV+zOlnwT8tv&$`HN_#!7D>rOvF>n2M(HRUX;(x(1WxC8 z>_um6-Lfi!AhEtovP_4u;btoZnoLCpC>g`sgzCntitAJ6 zfk!)HaMD%KG1fgz@vZ<1hP)ynEDE&?T3A(p%5%_Jt>ZGY5Mc$@{|bb7&`oCCw$ zC9A>4Dmi6;wKW#rGHUfHB=8mG6S1=%J~wxjuMwG2ng)@fZJB*hj9`E|f=Zj?X{Gd; z>V?{s)*H^|4k7J;25igLpqcy}w?e0AgDJoIqA__%i31;RmP(&zSVBxab8JIgHQ^K>1Mk7*7;NkdeQU+hZiQ4l!GiPaYG|F~vmCxBLVBz=cZ)F? zQ033v%?<|GrpuM53^;CQH)9zN4|{nlk5vXSw@$9Fo|=p2jM{O{8^~+zucKEtVQ}Hr zbS{Kz#h$e1EB_+37kOU;C`y0bBfZe1m-g&^dm z^wr!YDfWcw&g>WuK@&RgMf}L9yk2ennxGh3eIPsca#fWSyZY+TXTqg42AZWkOVK&l zmSQRH4v5xh>nuThz*iO{TQFeZ@7rnpySOOLryfBR&*pYp)GF*CbN|S;7i=O&q0Xx> z9!i>LVeQ1#U0jr@K zKc*%}hVR4>{eRbAt$^0}D$8mYm>_pM!mEah%!n+a-EI^`!r)9scU9sT{@Jv-Og*%O zR^g%9>GhvyT6e8-OK)lJ>>@gYmx~NbdJ0B)A!+8N%{DE5336$;xQa9g0kr(mKTPz# zvl(JMj#A;T9??XO^)Dsr{|B!*#F}evW&kKZ4rhN`zsYD;p&r#o9Ig0 zVg*C&AiX}ReB7LOVzxM^sl2EiU0Z^B=1bG>lkI}xo=uzPf|c0A>l17xR4q5Mlm&!1 zqnR(bFm$GSDOrpwJ0i4VLY;jg1sbM-Rgv7xj((-eL3>$vpe&5~AnW0wqv%#56e$6% zo0)1^5n@Sv##!%)JN*L=~T7x(2yHf)3S zAewuF>o96%JE@@En~=;UncI`gv`nWGDd`S)(Xy2B8`RIp9zV^)m}nHPVfcVpf*8Xs z4f^W-&`t?!hOPz3!1;o2k|VJ<7d+iP_8#PpwD)BQAnHxOl)dX_3fp4voWojpwyZAV4AowR`l2&y(fS+#^PAiWi;b^lOud)K z2$Y_$GN>&s0lyJjmA;+{r@?QzON`o}1WcxtAkx7}w_|N41dzw-{p87<_Z=Bd)~R!7!6$*d!3PHxB*l=FD1V0 zrHqrs$B6o2{;cntKl|Fm<(hUkaN|M^X}$skbtGcK=M!Xn7uHn#Gwvm#G~2M1R-;=* zvz43e{qcyLy=olRT5tp`&6nL!yk8-BuYp7^{;+AdxpItT?RG?E6GRJ2b;YVp|y0{+%U6F+!oKqX>PSIppFw39DnivlhgZz4`x|6U1bsY ze^~1MY^Mvneb@+4YAJ3wCQ`Hf~O){eDM4f4{&2kw}+& z6M7Mh(*A?2Iw0$u#ltG`y+-50Y@ZpU{^N>Il=bi`F`q@h$q(Vs3$$}hv*R1BSRlW+ zZTFC}W7ZdU)d>wPY2M1A*g+qi*h_>`b_}jiKC$0rAK)Yw=JG%GgvD*05L46`pL6~O z(?nRqKckO>aKpGGQVY9#A~bw1D3B=!n=WT|x(|1H-t0w2uGBbkE)NVF1)i_a`K`$_ zyY0m@+!*j|mj0Ty9QLs$1xsE__kv*%;{5SV1gS5aBI^pfTQg^~J-{=HBF0NgWO~@c ze+d-8zahhY3HgcHR=hyx+YgkJW@STxq`^D`n_LnTqLER<6$0H1Ie{)IR@f1yuvV%T}!rRhT+j&K~IWv`6Kh$flxQ+vOWEZJ@M-mR0ITzwmPw>w)j?Bwt)N+)(g@^;aFkVVSVehyX5&PAHv{PtlSWh95soM= zcogWC(Wh*N@O5skD~3AtFWI@m#gRpRLX2!Sv-`9TB9`;T@J18$16i}c)eMklJ z3?C1M2%O?pYGnAOE*6qZoqaB$DU%!)rs5M zXXn=eMu~JP6dXBqYjYYpZI7g+r!Y&_ifEN35Zp0kbgKi0_4!1s*r^K{E>Cv0dv8NT zAMLT>zVWMkr~)E%X2b%mPPgEOC8m01O-i3z=cbgzedd1Ei@LPQm_6Tolo@0KL-GMbYN(CXVLRwA=`t}msUEbZ4L zj4Ja$-XoOUFi2Y~LltX_E|^WIQ~oITi*Lp4TApdlb|kte-e z*}joH;nKQYirz!&CXOHyoyc6!Pb*@Y|M=&J5~k_mMquH0a=kqeF3oIqW&ho zqf<$t8eprx9IxC9S?|LyPbzM0>;SG^g`dFpAy67aUhA_>tHq=JN*PJ34fW!e z51vyk)Il8J<(3!0nJYDpl4O8glk3+cSum|xWr9XLvkZ5zu{9`8L6b*kRK??QjsjK7 zv`-q%a176LRXjgV+VP@mu*FRBKBlLS!4g-|M-ZVy({8r>u{(SSXFokDDzqsNn$fh2 z0CCW3F|D*~fmurVg=e$L?J^}C;%)8W?W3m5X9hH&Pjz?>2snw@;=Uky0GcUAi8Y6~ zG2uVYv$-^)`LhsY=6jKH_s~=tSX<>)608dw(vAxI747CPEyqtpsUV2kW0nC(d7!S7 zU)QS5HI|*#<>sm(u7*=~b9F#*UYCotmciA>2ze#~ppSDBqe6N+Eb??huc+<~Tc33L zKto8LQ%)b8tjdds$}7&J6rx^G3*Rqm3r51I6?cDsp|2@Bd)@5wKbT_DxT={;3C{?W zzW75&)+3UqIq>B)%<~Rp!?tkl;f0wu52T)+JT){kUCKp4lxU${pPadqj+^f6fDTDb?)!maSA2^YSftAL4`l0xz2Dk@J&TI zyrwT^@6l4`=4TQH3M+1lZ&j_$ZDI(d2k;++*8;Wtir$4pN^~ z%ZXOFj%);;RCUY@{P=0h1Zm6MAo{`BW&>R3<-rvGhKcM|XO-1sNQM>{e;u34r1Mw& zEk#7fx)cO_v?Ru+TcRg){WxEX`|8+Q{%%<A)({IrHGGBe%(1BG!HRGa?(nSRW-@e{I zRh_k;^*q(GQE6X9QW6%vYQD9pA+EsPbv`hr-TJm9_F0RTsJ^RQlTG~?YZU#Z-tepa z9zLFz?j`_pW1+f-x9VCp&c^0Y06-&Z?!=5rd(K@6k^CmLw4`Sm*36LRb|Ry>M!_#_ zfe2NcjhGzUfVYtT02h9T%1j*5iq6swi_@ur9$B(?^;d;f4M1;J^dV%>Yt+X|~L%7Wu zrS`rVHnCtiD_sM1yX>R^HqNC~ls~9H+XZM(Ru=6jW?e5C3CCB*ejAW!%*=K*Y5sL^ zGrJk&zTlGowSh3!snonX%O=VS!fbUwFhxhY;x||M3_(N76Bcsw(VS&5Y;sp@;eFyL zu#nGI<)y7!O>^obKJ}9BydmoUYeWCNyef3iiDQ6LWyK!G78U5nQ|!-^M>bW<^K181 z=aPl2wkq~S+ZRT=wQLgFJN*>-{K*9HR9L<6BMA+3n~x}t+t#x7n0~Y3)EhgAf%0-} z;0MW~cR>piw0uTkizUhW(5t>NUV{;M&X@j1*mO!FsL)ym42MP^Y&wT~CJvPunEW;< zAyHxzS0C_R#+Bw0)G$&iQ;LGx$rno=n;;Px{AOViFOdoV8(=E1AQ;zRLO>zu&Ii0H z-g$&eMCIvRw`ywpca++z3w6AA_t-mcr@1C7HEgKD5RKr3e=NvcjyOtHm1%Mjo)_V+ zDKoz;Hz_6q-7Pba!_&&6@)M_J$Z2V)$=><*I(SisWc^R>Uj=zLz0Y8tUv#A z*mzeZq9rSbc5+F|9*nf-a&t5}U8VUsoyC^^+4?F`Tfp(Eut@xBo=4ILG`LVpw1C+a|cTcgyh=D4tb~Q&k)tr0lV0P! zW}arj__Jt>t%P<(mw*kL>Nu9NhdFiTE+~n_+IejwXh}xYEO)li>BM!-RtWwEb7Z9R zH~Ax+hTu3m3~Wc`J2IMD@=QzYW0qWar`vEJXd<%L`;CCgo523*md&<2b9+VU;F10w|1W{JWcerqM5cBys)EZ_E9unIL z4cbx)_oq_Hq^t6;^Bp3e2{C(~?J{<%5v^N1*(y>b`LP$#$vbfSGIrR4vO;FvfRNx7 z-KiNh;qvZelP`(w`7#_o`s4t@2rg2fY-rIKS})QYl|xaYx|~fk=@+kaZYtY(_y)jY zFv7^%MI_#9NS5QQQ4T^^$%;&JHq-Z_`0kfN-1oyRvhmd5l9CgnDDTRQV*Q)`rQ{%Z z)>u~%p1YtLzI!doRQXfk13Vr{_d?YWHFQzo8lO^OE4xw5x_0S4wj}xm?ZADwkeGds zxZVwo_=2YD^|hAZ!RF744U;FYKqboGIs@*_>h|hhwwjzsa&$!0k=f}K*Eqpq%D*Fr zOs*J#Nq9kBt>P4j23-iO6VV`%S`lFO#yeEV!$9jzaCu~t{uG`%MwT6q^iLL<3BlN7 zWA{nI6|N0!x7ETodetH#oCE{tR zHabhS3 z)q?`NiK`gMQm2nNA@AcsDRXdaFq)!EM9_{xLpp!YdU6pw*CW07`VDJ>5Y@@5Q(KP* zY>M7s)qsVMo462v$1^60y^8r$$sn41Ntt>n-&>-5?^l5?iVv5O)D)M~Z0`{p$?wLY zh^W03o)5v7$Q#zM({GRPQF43ch_qP>OkZ;frIvw}yYY_%*hhOj`QKZ+1P#X2yuX5f z65lXJ2hk3r0R({Vu%uCG6n-G?f8%1uiW`_s^VhG1b~+PCR>kDUvp?YT>4VEHiVof{ z1`q{QzAr*K@v?(=o6T#YcRsTej$*2U=_aX#fA01P98w9#^%)6nP|2zKJL%n&+2_P^r9nv!@p2=ZASS4JTaleTOerO01x=|AjVX0G!fo zY7*)zUl5wJ0ef0xn|{N-50`mVg{-oCsUD)azA>laIg?`L`+b`VtT?q*Lui_-%r5sI zeD_NpIOd1!%s9silw9~EAq?ax1j_;1&+ zmNbnoS3v!MmG{C>$t$fN*N)9la!3x;iYJ~C;mX}WJ61QAPX{;7Tdc@A6tqA&Ba(Ux z`+fMHZ(AEq|0?Ck{>^6r+{r(7a^F<9>?%u~p-1Or8oiGh={d$8%d8~-?1GoAx-KV> zuYu#hgUU!?|GcmCY79T4o~)*HB;y*_Y-NU@#6m1%EOMllB?R|xijrVd!c=bfbTkzJ zqP`D+cRPvIePfyv!X}VI#?7X?9q9MW+qw_Y8kpN~uw8wx!(h8|Z)rjatoJETTUp}R zlWRJ$A1U7m`k6!nzpWeH0noA0xuzHK}EO~es~19nst`c@tFsor2G z$kV#{kUNv?gAz%)Qz20sVHc|Jc2MR=y5E=*v;L?AQ=7jefm`DCukZ9}*J?pYrl+t; zuuCV(j?j@i*RY(`d06HvE(t!C$j?1+6ibcwLR~VWL{ndWE6L&dOT&`+@Mt7flC zN^;OZx}kX&)%t31%SqH9|Ie>%nR=si|1tR>lRy1u{(Wt9Ff@WmxDsq)H?(7eE#SKk zUA?;?D*cyx=Ere1714klX4n4g5M%yVXm$#QgEDE}i&NM2QEN^r)At3dyQ8KNc%w?U zfTG2z4@t+_U*AwA*OcK;e{3^f-54X(V0pJU0QARqN#$sN59NGrOH7kw>AxcMz*$hl zXjn7=U4Np8;b+E8TFo63Gj-^Ktro!L?5*7NdQ;|#V08xOdCcF%(R$;(Hv_28o^G|> zlN#M$tl?g_5aJZD<=cx)Zgen2GXlm@NAFolax?dqi=_AB3%A6j{OlvW2)6AQ4Swvw zWInvthgb*QR)kn%$Wcc-_o9pq?Laqp))qWKJZpcJtqa@iCe}4o3UD3~Qyw;t8-6bL zl)%Zyc;nm!>4`G}(>B;X2>;c_lz{_lEHRSUCyOf=Fz{wy5dO;e!%4hi{0_Qxxlg24 z>RJZ$i-w{tLE||A%p5Pw(luYZ0uaUOMB@MI_NKae>f_xLie9jmPQT1&u=flVTR3^u zlrxjX^snd$frmS1O@Gp*(wUqj;s;JAt$Dv{Q*Zg5_j#?)4hUI}OoE&uZJBdK5hij3 ziCWZ)sn9YS^Y-P~f(-mD7rmib2FNJZqbD7u{nOrbkgm9bYhiFVqcQvFwX zbFCzA4j01)R8@UMP7cM6WmTvD{H$56Y56tPOMIl2ytdln)&=XDE__vZffhg9%zHwp z>`WJr;hpkDQk9!HA4pfB`9@x|RYu0-AolCu(W;;5fM#4?DE|g9b69j#hBejcO_(2o zGP?OY(z&r#&Vf;Dv$~C1WoK&yAOzU&bS}Mtv=o|UYxgD9ednGtke>3;uJ_l>^<=6lxG^2CG6!J5&Sa#=n zB9qCy&hD4inR#54@M9k7FtdKO^K%>IMn;$443Tx($Dy5+gs-KtpDj)whI*?wlC)K7 z-RoFLU6>+T4_@&FR$+5J#&H(Dso?dbjs4C-RA_KtPrR@sAaXTYWs-O1mXN#`yg-_C zC762R&-zcg?_T8>DxnG03Mi|82h}rB%Gnh%&D>{VJ+#ueW;vQj{PvRstR<%$ z_Ne!?SQ`#Fdy7g+`T+%$1#lyku`;~U;DD)YV<}uOOG%`(|8+DS?<+%UbUEh)le&#>>w8r=Uep=7Zer5E??r(>T#sDi*hrr<{Uu(vnH&BgwmGYlHomoq zcV%SmeLp@3TIgcA-t@Q4l8cd*1MKFVOQ7?=@6Pf&I8iQAFQfiAlcO(L zHOim^q*q#nRLW6v7pKAz)0T<^ZJmdUO3t>o1fEkO{7&oKi^_S7e~>v1E=~~|!^udg zX&(&j>ha3^FAp=#-vbx<*InvH+qQmV%YRx@_EK?roZ3mak#vBBL3={rta*q6Fp4hJ z1L)4#k}5O@2_lx+ep=7l4&{oq_;BZu!NZ|{17!7*8~cC!9^CuK5p4Tk>udv~&9(CT zZFmzUQWBI(E#Y!B@MU?a>XR+GZ${}Yg{GeF9r^dQ<&Blr zx{q?8PUVGor`w8QLHkAd*>r023Lf6n5@x0HKUbQQ7>vHIlwsz~+VR$;+p!M4qEb zrxheO1e^Zz6%4xBE$?IX(Yb;K%S#Z%`vX8^RC%jC=k9Fg2+G(V?u2urM8v-P#*5*+ z46-zG3RT=9pm+qmd>U2Q$=}E&rYo4=Pdi7VKNP-09ui0x9<1=I7|k^$u^7-}K8^ms ziOJyd&7$?N^`wG>#BPJ22l@K->~CGol3)p!<}3*lZvwAq)WhHyUQUxah+1p4DSpi< zqM_hBTBwL3$SQ@-O?%!dm#)Y+$o#K44nwH}s|Fy-?%6GRY)Pui4<0#y`~F|)+39Z`+fd1p2y>2p59-OPVt;vXA@Tg8=P7f{vdp&lw_y>LVZIs?LO z(T7p5mgjkypw(2eO98n|R&h?&v?Fu`bNP{PCnMa%ZHXfU#UN%L8IT-xr#{Cc-6oJA zqq(J4nyjz+1B0`n6;B?!`4bo&lE*GLQbA<1OEryA9j_d#x@dgg!364EfBB_sF1-8; zwsPYncN;hy8`lW}^3Bc{O?e?e3EG^+#ynGsj@vOg8Szni@*Z?vHY6}lXEbxA@N3tP13^^fWde|xgl+F5i%)?;0rPp@(% zVd}m!v{qmqLQ9fiCQPkF9f>YF*SNG_RqAmz3*Yup*sZo`u?JMdqorW*09w;1aHy{% zTYf0x=rQgnMFDt?*JLZl2V@&Qd8cTwAuk&-2H@l)>a|sRYfd6|2lPI|>9TNo1$XMuwh7yOU_ddgTGj%QEAvLk&Uz)VQvDON2-T zQpcb$rd~&uBgVgxYyUkC2WVT#m+^m6d~ZPIIu4_|OLn&Tj(8fmfq-J?9I7gqDU34W z^#}3tCAUzIxnUx{s~?}VNzpljt}o@g?Ar!_{$=o%i&4+>=K(rcTDIfS?5WiX`0Roq%_u%;Fg2)kI+v)d;R$DM5JnChCYSPU6gw!c|#z2Z-hI5Zyb(lE%zh#za4O zRaAR=8DCQS;bp#5fq7LC_0~K-h=6oGLL<&Z&4@rtYKs-SzJkH1$UGohy)o1ar-;-_ z6hM1Q=Lq1nx9$)yJ1;CdA2V>$LOtyba2*j@NyTU+Pzp031)^ei7A>}v!Wz!UIIl}( z-~J!2zA`F~CRlrs;O+#6;2zxFH8{Z`1PBT4?(Xgz+%0&J#g_nKaS1MqyX$g!zwg{X z_s5)>sp*-n?y0JNPIXr`%vR|~39icFhxiiGCp(1JmI7Y$K)z(G?`@N-O2U7HOB{On z>p$4PaYpG|j#?SiN71~!T1$75)kHdGKh*QBH)Y=3=%~>zh*gQvj`~QEECaDvdU+|v zACtbtd|Bk82hJYsi-$sk4fIW0p?FwGKu+0<;1KR8jcf0hb&7n~cZP}{qJwE0&d7#F zNT_J*92wm;M#vDLpA}WdRe2F1C#Cm%+Mv0OEEO0pq8f}MS#hB^mZK^6Y@x-jfucKT z#BQd+X;>KJ)!%!iH>S-iRcIjRXYuK6NlC6Gd5nAk6`9B?_&GOk5+yrvy zh;zcqKr%kL(4S;&a-n#3h}qv6$ka7|#>DzaGHJrNOV~o*9^tOH*n{?@zDv*h$5Bol z+_tvXm?+)BZP#eNqRc31HBC2ssfr7Im5$|i%$|yu-a9@86}Y76f@rIveL@-k?Ezdr1Yg%%B=#W50?qAt4{%m_NO$a={ua zl#;n+BoscKuEk}L(<7~y|2}Z zx&~=S&coZ=H<(#h=x?7rGuI0YZN-ar>F$&@kY+Letzi>JFI$)C66wcAud4}j7LEXWM>M060?A}r`t>Kk3l+A znpmZ}_Wma874g7(fg>e*bB5iAkOum69bvA95>o`(%Q&)#J`Z*fLQ*l&Y_@}+I>EP> zrOIdti&A+LQue*CnUlz)?Y#}np)MFQQcZml?{`x2*djDQ0 zBN{X(tUUMLIq1H0lXb|Tb3yd>#g&IovQ}IhsgTK9qjR)85Hly5eN#1!B)SS=8-MXn zqhi0pyrP&Qq_6u>yhB59K1)+;oVtfO()yuqE;mqz$u{Uoo7&#sHH+_1vU#Ci;2W5f zKI@xUXl>G1%E`Tp+2lQP_O3<|1?UV+)`heXKduon6e_O)ui?%j%de`7cuz9QR=KEW zP66dQ?aE;>%0PwpMWF&ZbRogg7kG5*Nu9Du5k!xoG<7Xbw?VVb>l6f0RAV>3Q8-lu zS;N`4GK_3AG^p|sTKjy%-=Z!$lPrm!y1Kse$E$Cw;|gUC{K|X?4MA7N?~oSRyy}qi zp62xNE8<1mox2H13tUEyksk$_IGntjGSH{iJ$1bpHUBMr;qE{i_H6zuOxfRoS%L#I zdfJV`?a(cM=PKMQ0f`rc+pXN!QMQHc1E^BynhgT=j&kZejY-MOTKR^@NXolN2pAn?CkmgLcF+0Oz za?l(#saxXi_}9cPo@AL{wX;ZN2})P4v`)RVCI|_kb1tw?{E8362w~>$5M<2_ju+4`YMLy^K)^qxf2g0YJ~ zWF{#CH74|9wE~hs9;g?Q``g&Je7Gggv_fVlG?q*|cesu66Z#A7ej!vX@aB9Dv|iG0 z2V7d1Bs0{$+aieYdh6c-y7G*}aqH`xc=6D}#>>xyMI$8qgLfGe2b^j5E3nUY^=6~R z6q$iod~@h1q2fRTR%oPV;7$Qp=hVAh2(*62$RVZo<=x3b=Q|>KrW+W(p+ zZ<_*D>gsV38h&k6nV=zI+$J*l_@BO?!v3c*u?qPXW{lg0P0*#WlVYp6dE1ocLFgfP zng>X=+JfG0*}#9s;Q4n%JN?Iv%wW^ z{l?+37YYpgF=0T9dCLLR55;E@4I6pLd>+)L*)yxHkm56m;6kbT?vu?+v8CAFzn4*F zkApmNFcx=cQHk1csIgdKJ^UMv*~+5SerD|_gyI)YS*GqHN|A*#u)%PJaWbR#awT0A zUJrc@p&dQjG`NA1USo6MqZJ8+XPUQga-YqBhbTC)#H|pbu|Q~gJ5IZ})*0PUF}sa# zF9ws;#0jUac&{J5QF;4-wp02Xw{%Ntv}|LrY||ju#3v3+vk|%P>WsLVW2?$CtixYL z_ZR<0p79>9R4ZU!#ZF$WsWs;-bVSZ?n~$u59bNHZ>EEx>UkU#{>PKtt(pXaCB>7X8 zklail5naU3fB!kJ%__}->xk{37lx74@TGlFD>lt6=tlA3UAk6)6f(6J2>s1GAX!h0 zV>gat>ncA)N?y~9KjZvWWzHBM)(K6E5_{zBkHjsI^TOIpMS(=3J-umK6Kz&yN2tpw zwg2wdi>ZR3-+f%ufD7&rWJ>WV1nkoN2%_}u?flo$2E=jrObw=+$3ZRT*9Kz!Ev@rM zQMB5kohDI#y&86W`^LC;Y3>P46I0izqAwrRfO`j5mbJ)K`XO<4T6hGqyONUV4wZHxo*Epyp##@Ajs=y&v~ks4B8MgM&XKUlu?atWMcH;4&DY z6UrS|v$nh{A}S)Ro)I2;r*Y#y^qCSfVpZlye-oy-*s%D|^1N$C3zQ3AV0?r=Bas*t zen$d) z>OC1r{t2Oj7SttOk$t;JnD}T#Cr!}LPIOcJIlCQ&1((oou0NHjg#@o z!+M$V+Xr&ob-YaS%^HSHeC`4aZR5YRP-5eX(Masy+a)rx=>X&^2&BbNz-yD{s(K(b-Or=!y zkuF8|<7k(e!WQT=krU78ncb@-U@3h*Ncfp1;orD_8A)xe{03Ggi3*#mi{am~Ln$s? zrBUr;(>SjhkL1KNyOEgBkfbZ$nVF{sw<fXza1j>HJRY ziR)}^uBF09=71W!$ds;#t29d;B!k&bG>0}8+PzawZj)~D*e?+jZb6PjT>&nq0qu$% z`s>?Qi*25lh=OHwLn8dfxlY80c=n@8x^0Q1*5K{FrFrQ4kgpsUw#{0Q~@dxDkshL;$TGQZF_&3iUA-pb=4$Ip`w* z3Sfa#1bhML0*C+=NDVl>asX)n5u5?Wh9!Ux@C}X)&IvV01RZM{FRKBo1-_oFO;7lf(`(1sK6y!|fwCVDKN1AZ?~ zkO{y8;T{kq1`tQt5C#kYZs9cnaeyfJC^${HICv5SE-Xoea~i-CU=U6fpa@WeSA=V) z48o$uq(-1dHg0O?ABmt7BL0SN70LmYe z+@}>58UY^29SUZV5>HQ4E3Ig90>e!^|1a9{o?RFBnJS-qN4cyQ>Y+JQzTBzw`xveO zuMfZF^83xsfBSrS@v;8lcJey{(>`bRaTjw=S{4KAbVf@=$AoNdAIyf>2mQ^YF-RXE z<>qZKR<>q!>vjXe^j9=n6P9n2lyFB)l5QQ~oZ$?0v}M9&jNw71kt zx`pQ(sp#1AW~IYOjsQr#lA6du1wmtiJI9{hr8LD_ZHW&eUhLSx;{$*RpJW|*PFi9E zK$k0^0MUukCq$DJ+wEw^p+0Y&+6Td*UerHL;EHWT9J3euCk7yc0A3S;8pE74NEpBh zm_@LKpTsby3sU><*TU_?1tHgPF+GR@8e%O0!*IR+dj*_#zcA%aA4Zk?j)v68OqFGN zc|0u$O_zx`h~=}28GPQ0JPmb3A4;E`fB9Kxd; z{86JC)KKs(9u{xm&%S;d!Ok|9366@SX%Ch}BWcWvJ;hVKu8A(-nPODCw!;@oWS7jP zK$GL4aGavrn!AboN!5-zaVqh~W^S%KhDXoPIR6=mvja;LjU_+#njLAaCdyQisQi$x zj6C+~kV7d$ZE$O@ZFjUswry(kZPvbgR?SSgtRpHpp|1s=1~3BkRvTag$h-C0tN{p0 z0hmIU%zZQlWPzptjbR2&?nIxi%pI6am>WhKMm#Hb109mbY;OYDq8O4#f3N!cMP>vM zc2Z~Ll|k!dlxv(hR*iLouXtsv^zudUSwdf2Jb%-3bNueQ6kMotP7;IH_$SnRx+zyw zjXYu#jmD(#wPs!Df;*o-2L0&=e>u&5F9Ah{C(I*80j$cQv=1W^?Y={gk4?f^Q%cOm>4-)8o|YaSe~u<( z$&g@xuTUGkJwGTmKZt6-Rl?^ynj^@r;D_S@xWX(Vqz&R8#SL`{`;_oLtvJqQP-la zJQjO3v2FA|vpdSaWS4q9wjg=Q+Tju94*k-GNL?vn?2e@hx74mFYzrwD*|jiP{zPX> zs!+vgEn%}n-Jiu7lru<~N#T?4b1c=YKQV=Y>*of_vciGAa9`~dMQ! zUo+nyNcN&bj7|fn`d}jPHhq&XO#!w_OzmN5v*_^gq`})J811O|SWj^3ovRkKnCT5n zymtQ}2-77b^1X`O910Z^+D1pm+26pD{DEvCRk-TYkm89StIZ{R9+lbt z3>Wxrm}X}^a%5i}df5-S@HO(t47Nw;cQ^;`!Zz4XCL#yDG8^JPZWu3RboYHF@`8uQ= zGxO#r;!Rti-ZM?l&LbE2B3a9$b*g*FAma=C{pZwj3Pp#Uicbg&l9}d-EM<=sJX}h$ zrcSQ&&7ZG|bJ5W04!$+*+6`yl+S>XagCn&pblT1EowIWu zgBVhEO^qt8sp75`(mP87Npm<>L<4l&YW4R14;yHy9~;C*oeGXi$@BbX#W6YFxYZLD~2?=SADzKAlEUh1Tr5OvV9@?nC9It{j(KA6Zcc1fa(U$ z95Sk)>d=l18>&8T*X!})Tkc)!1=r)p51j>I)_tS36vJ!3-Bo&7SsvL@0bLy8BDOz* z3Z;IS+vL_t!$LGreXa@Aj4yeqT0I5M>c2j0=cQbdk?s+wJTmVo{*0SWG!OZ7cENKf zmUSK}S4e<8*Ma5}<>Qn%N!>zc%Nxx#M>Ra*pEaGR+)=D^&SV9YyEPmY=YS??-#Ytg zejEEngJ>6=IIlHaSM-ThRS!3gV>|%+y@|oG5Zf(zDKN=}ixbZ3m@)a~gEcVCg^~H` zgB4KW)_YW(9%}vzjtHd_Q4lwhG@SihbJ&i>`+fg3YO>3oAI?`+=!AZlKYSistV=-X zI#p6X{d~##894mF&LH`Uj0>JLF)Y|?p2`C*%HjwslFjZdRwUO)P z#3i1aQ$z_7bfpi47(fpampr2J zq%_N_ILDtd!yPP(B`ickF+;*Uz}AU;kq#db4$AbHH>jPkY^KZ$Z3+%A$he%86ukaf zzXCvt{rDwv+aanQ+dG<72N%u!JJknx8dXH;V6CmINER0OLQSp>ddr`*BA|g`*9ti#1qJq`BH?rM-wPDi*fYeDs{!xvbp}%gD7SAAuOARqWGsN`gD>KJTAjxX)VdL? zNT|~dacLRh?BpJlpwb2>EF6Serk+M~2Me zAZa@#GqQ1fCb$ffbN&?dRY{qoPCv<`cCmFXlvGW(~?~1PDg2xKFoF;Yk$>lB@a4Lcq{fMr<&*5 zAi#ekk%{|YpxSqRz#PC=a-Se(v zF(ce!rn!)lB#%a7;FgwdgtTLiR3^bGnr5dk{G^U-Ty&s@sq||Jd^+lrf6)6M(3g8h>=1IwW-UsOOokn zNoMi23wC#2iDyVcvv3}nW}gtKcS15VD3F7eW2KU{vi3Yx{}_4k|Ha#XKIZ{bbjVW2 z=J$|wvJ~}mP9<5xcMK-4S1}ZA3TFNrgVjw`-Y2o1ueUp3Gci|i_4>o;Sclzbv^)pCnkvRG z@sj5i)tgnjm~@zGe~;#WkWlC@@Pqlk+ZwMoThzX6h(dT@D ze$3RVL+y0Q9^{z*@cG@8q+BqL9JS2xM!oxC-~$)-#26|m?g)pTj3;eV*+pOrny}$R zZ8j6Y<4Td=DL4rVpS^^PhuhdiPpLt<|96<@GfQ1c6v@7N+*?A2Pgd0PO&ccB7G|cB zH91((=H*zZU#LH(Yt3vTyltj~A@M>OTiMu9m+)V#e$_!kQT3+mM|}Q(MAjPm{`1br z&6nn@{y$UaIv=Yei;opJ^`&%=1K^~J1J|VnTv8tVA-n-03bXy_bMlJyW}gH~w$n2s4jer3HzZUc*ILC1W0sWQ zzT3Wytw4$U+s38V`oJqHiJNVD$GnhB3O)rEercr6&+ixN=-40{(`?wy4>qA@0lwE2 z0W&5F^!hy`30B)7WGK>UB$E+eSa`_(-nFGED{?*G1eEY}CN?hZU* z^MdY20%3b*4gq_$`ma_yk=n0ayJZlH-1je=S3f8Yumi$S9225%mVy(%h{!vh!mJWTfzOxhoT*}j zoE)&?vw|NIrrMq_f3!tLXnv{JyiVvE)xSbdX6lw<58W?j$7VX7``f1o9VC_1cgSaK znGR_4Po)UC6Ke#1+h})2!DAVjF+gV(;?D3`_)Py(+PiF4>;jOk-{V@SzQgjhr#qbq zy4I_~U9QNHY0Vn{O!xJ1_jK#4LY1SD@a57()6$TZ%gW2`#`M_ddf}(LxlxF+sYu}R zfJoiHr&@|V*a6K26=dDxTtn9r28;0xobqhl`F!x&bFy}y%No%1@Od)>wDP!JMq11KIh1@SMxdG`UNi{*zzLxy-Qc4Xu@7 zg|Dah7HDC((NXQ-U#-@&mr9{Qbt`(kWBmjqz>gH3F#hzY2a&d8Gk6_1A0hrc!4F&Q zGfRtAImGU{xjK(MdObDYjqQjx6Rq$-3p`0@{G|OdPb6al7unId7905eT~^%>Jc`HuD|$}Xaj`aLw$x?q0zEyj7dGO$tGTEyt?@5D0~ffL^dq~OShqxrgY{Vk6{6vwjbpXp3-LNs!(F8hxw z4+i1{=W?0(h7H%H^%3xyc}G6gl~;{7n3sQng4d4|hIeL1@cqP@e^;CZ+hH$>`AZCe zCtG7??_pcNLa|38i!-U}dk#xGBjGbeFJM>eN8&GDo>z~xiL0L7&(UY@0-Rl2(~NaG z;vFxI*k>s1Jzm~wwony~XT_d7=$O@BYaG?{^#OE2>^AyOZ(C2B^<~Zx<j$Oc5tesx!~`~*V|zuvqoq`OcPp&|(AJlq@M>?oD4IVRtmv&hxCGMv~N{@QTeaug`kwG5?pPUA^k?R9A_LfzsB)pEsniw_O+?LX*_pdrv@*Z9sL&e z-`(n420mR!POx`_T(?)Lgzqk%L?F+1KG2NQmc&(|e+7?m&1y$)tja}VoxM&UK*d(= zO??_F5ABT>x~|vNbQf;wybr9@bZaFJ#C$$X`OJ922R#U?(BO5Nc+H^a!XK3LuyiM$8v{heSnq+AI(9cc zxA2LTTPYl^KdojX6R`)%iTw*S@IF>FoU@s~#-R8_DPpV#{c&t(`m&mBL&Tmaq5V2- zHd=+JF~>SUg}H(&l2i3`IzBO6@W&o>l;F=$6Tsl5WB=n->*x03r5LywEWV(9Q*D#; zIbgBk+K;8dW8qQ&oRGhE9-7_h$u4na=l-}qcwGw0>fkZG0oUKni#4e)z5JDY>|2}N zx6zJvM1tM)t?gmGE>lR{KbozRJnptEh+XY5_S`%Nf?BSLGoSAwrf6OciaqtAJq1MC zZQtot3Q+UJ-276X2+yqT7m$Ik9zCZ|&=c+G^T_GCi1ee-z-beS$MGTL!2ABPU;163 zj+<~bzI9Fs&$+g%)H5ThuANsePLsBOub05Gr$iIpt7n}tdq|r2Z9dPY7_i&+>v7^t zy(5St>!Cg)R6{So?WCp9>h)&-50#F`X=ev45~34O{|KV=_xjsHvkruvJ`yfO1iTon zd)^`1XlNiqOnC8OkqwsNL=fB)v8z`we%XMw|23aXClox@)W zHbyFeroVqZ810pV9+Sg;TN5Q72j-_CwE_D>i7gqoZft&!qsV5W0fqO|+c(+(WA13c1?;RW;NeIgb^y#76>o)h)(4(toW4Fk`;Qu# zePijo&DSV*=r}6QEHM7$q3CZjfL z%J*P&nz85Z=j-@s_=Dri#;+rd+NAn>m~|wrio?qRRi`Cz&F}0_{AG1LrSL<6$Uo%r zjQF({?-J{8OArv~I#`)jFhB1hMq3i+{PWlp*o>YY>wNjLKsOy2fWpBXz*-I5t};Kc%Dm+KC@#GrkWr( zyJHYnK#sn=BNzuHk4#UkHQ-r_iDfiu{Barh?RBc%vI~W<*Yo z7w_E0>m?^?)3@&iCRPJZ@tAuHi%v@MnELaJPBQVBZL^C``tg|9Z>OKb5d!w#@2iH9 zOlmPdweXiL{L}noKQR88?6duk{hAhwH?qLozjL=*%=-C%=gzg5pxJ*x!ek}FWbjAd zqiULHdL|;$gvov#e$Udhk#Wt(Ty^KKscGudwHbJD=QsXrGob6ve_YdKp^=YyH^0;X znusVr{O;8_5h3t)db=m*aG?@46e zQ5+g*e)mO$A(3g3eINPJP*~CzVTZ{-{-dF9&0Izy6w@D*zs8}#;*HFX$!|PmK0txV zzp`#V5R62IC9rtz5Q<5~w|K4_iU|@}{At(Rw`eP)Sd7UX&;Nn%U(&p-jA=1uX*~Zd z??0~EsR-|Q{$~DvlS{S(lEp~&@A=v*K85~>f4?$S(KitPUUX@H3LCS)adv}{^J&wz zm`eQo*Pcd5qmr~@Dx!TVqETwt3Ii&k8s1laC4XL!InO3ZZn{o@hROmD)j@^@Se+*&w(s7ZdD@RYg{ObjhoVrRx0r_)Y7>`b^CS4 z6JZ$bzEyD8s(c&V^*~gJD&HoT75Sx-;WpMmJkXTw_x#Uec;l0?b2VVujZF|4D{``WtKh`iW9V;x}`#))c#v zCoqHTSPJ?^PtYZ_hnjRmjfPy!uP?pcTr?B!xUl6BnezY}Y$UifPNG2%T(q(l{{U87zUM!GA*+y_;mR-}?5;8{?t?j=2occgNU4!v1fif7f135$1| z@>+4qUDeK*?xlEoml^#V6@ldeE!~eE?8ea+v;6~rWFZ^Y@8;o&6&D5d;)_$%$zmvS zwUGVQe+9@xrWMyxQ5^k#pE#@yK`9<^(Vp`VAG8fl&S3_B{=H0Ot6D>Bg&6&?_|1=qnWdU-4gsr)BQx^ z41PM%g9E;wdR|GR9IIyao1xMXF>iJXm7Tj1I)wL*;uSiPA*yQbmRFmH$wZqCa1TNB zyc$!eZl>nAEK!Nq1`5sxRXWZ^%m+Wxi{4D}k!uHQ1 zTvSiI>A+Tiie7$zP>g(njsC2>z^5?P&n#p`JAO6|z zkx==42yhxny2s@5S%fNxw7TO_425R`dU%C1E~v5T622g54&hJ?q>3Q5Cwwpj+zwz6 zF8~vJ<7m{)D4|(9iG6Vv6XHU>7wKsAp}m(y4>!(Pjmf!zz#!6G!nK<7aGXU0#;0SY zEN5Is#-6lPiFZ7$F1O$ru5GmNBY-FZPpj+gQWJUVCx4u;#zO~VuH@RUlv`fNL3=`F zd>ii){@nT`TTMd-$hDuSHnSf0=o2bm&AwW#5WfzU;1h3D=#lW69@`WIw+@xG2BFq#iz=Jf;&U5EoD-h^NYv_yVXy`Gqt zH~N|y6R3B=Nj{VHkZzU38L;gI7qo6MtnT24cNWsyU&iEzkNCBE`k5Z(>+$ZqezMi5 z8Qo;wDJv)=RXZnue5Og40{nosjuAXmddrXcb)_G=2jPa==s5$xyz9s=_eTEe2kpJZt!%z5h!IThL0STu*)?EaO0dJj&T5!S5 zrU|=QSWMgD)VHEbbQ&98G%Z4Jo56fQm1<8NbHo6bVEGN1=m zq-0j?l(KkdE1TA(=vVBdvpjrA?^33(-)+ybdXN1@Mx7|c3A@~kk9@|fLf4rBj4z0# zf4t5tjRPwjIe1C-p+R|D1bm4^gYqQ!RFZ6!LzNpwy#oHrs4c{hYn6i&_9XP=E(~rC z{I;8Qi_IfgmZ|gAWkt~y5qvEU{!R$l6jU1G4g5F-{y2IPNjT!UBkV^g@5GDx>!L&_m=j=|uZs|_Y1$lzO*Z}kgEguZE7_Q<}OwdINO z$+Ya&bd+jU|o?I8<;ncV=wFW%%6PbdA{DVJO){( zOL~Y^s3&!TG3=99mmMhY9zEly|&vUGT)@-CiBN6@c!LA);eBKmK}C zg-o@Or7<1gl~5UMi7o2_9!!k#m3-GL)_hon+>9yf0u4-z`n7BLVkm^v(aA5`eAvkN zfdiU#J7y$=Rdj`zpcKeS%w}44Y1YTRguVRscLzQCLfSf>>j~Jr6fA@#+GDou2?B`W zn+Syo0<`YLzV(G*w_kgr5c!RidSZfe31FEiYpUUitOv>dUbW_ZVB=R4MuT(G z1@Q$})e~ogHvv8&7&k3@*pW}D^!IR9-G(wG9CUdIfQgx&g%J6P`DVzevo78-GQv_) z*J-nyLs(yHLrB+|{JQ%knD*GO&-nY|0$rc%uyfPz2PLG4mPE((9opBtolzAww4Tc~nyf-xzXR{ZRLVxZ^HR@p z^9bOEN}|E;bf*f}KyT@ug@(_dJV$ruJ08`LHzbcceopLnv@U_jGoJTs+7|~<@6q6* zOG;g5%)%Y~b4EOlvb%$g@-@uq68RkuTi!EGU!0~otifEKgmIlS3wPoV74CSHrWabi z4a!$pbaCH%?t}xAzX;@EaU|gf&zqA4pE1B+fa29D zR5}-~Rp*g9mwUR;AuP|aEDsihRG-2FmFNQvhw3Z(L8II)5c{h0`s#jAA9ubXs1ofp zgXQ^C!XKEg(ND2-NRM}9>J046BteO4Z98ih9O$fiJL;_KLsfYn#`3Js^02@Hi$>RY zylqm3#a4BJs_q2{UniW!f+PgXgiHuD*n#q*d=j-WYE|bjmJY)qi>mWY7Vof_w{hk( zm3;Ni1&cb4My(?)n71HBu&#_R(MtGCov_8UOo%Psip5bFTmsydW0yzm*^4G6*Y^G> zghfx5V)aX)NiGjhJTkRuuZ6|CAm&Qf_~({1A#tVG8=TPar$J zebJiWZt)Cfc~RDVR$}o^kEzxbH5}q&snd1Nk12P0nDNuBXVC~{@hetdD@oCS?p*sh z=h)tSTxy>YV(_=!%{ne7B~R_<*KVdwHVXXe?AO|_6cS_$?XqpP9U_r~RrPNp28)eV zX$tD%O#T!d1JZp?E(naLTc|bigE3nrY28krJ$}{U(TOnKp*O@KZ6; z4go?&%|(ivBz=GJ5rYrV4)8Bzr6k#XGd6bdq@0%Z(DYH@Gnk(m!;1)0)2>*L%@bZr$oZ83kcAT5v|${U%?|V*d!{Zi@_lVbjSv9upb* z!lsoqd}U(!@i_0aZN{rZK~=uG|I68PsMULfI~UbG`lrD!&CDw$4Kg@Oj)hs> z91O)K$-vrkOF8wUvlq*c8BPykz1;a{5=;!mG8Q?Ulz6F)X-B|FIbrP_V;1F+m%uD~?hf#sby> zE$Cb>=w1rwTngx3w&`3Jvpg)nVG|G?LviM|=UaRC?!~xC{mEaoRplkXZ{6YK@*JEM z2N!-YzMYj7M`--&$26T?P#*{z`coO0;HnCJRUD#nReiaNR)$q(#ihR$80LPL1~y}_QJByFsR(d6YFI({l8uG->CsD%Az zQW!|-j9=)4${u)>ho)Hm12BZ(Dna!jz4-aDFObCf$?UfJo{PM^f1JTqDU2?vdRBPg z<8focfSMR>zLd;AYTH=_8rF7k2K8J^`%C1hV(A0i%Z@Ipx3-kvFQB)<|4If9Ji8vw z!l8A6NJ#9e`ji~~W?D@9xm(OSSOUUhSan5}hICo#^e(;-E>yJZ4Y^m{RxFS-N?G{8 z7Dt?!Pq6vqzv~FfY^sHf6s#u0)E7vc#TVB8lFvLGU=TufvZiy3xqY)&I^GCiQ9{m1 zMDOh3?WH%|%DLrL-Jkm|`DW-#I46#5D{=9~QW0uDQ620JslP1qNwsTkx`iJI9RAXJ zwSLdau{$5Cjw$APap0R7)2Z8)7pw6y1L2N`5au9q&UpV-CiGofzH0|BCSLtHbXhia z2n_CyW!z%jy=n$R=*b|fAFsc!UuE(Dec<7ptHszQ$-l{7$ zQr2*}=k4o9uj!#hueX4G){} zSppPrMphxR~s*SWaxc941^zCu!3@KtKSU7=a+_ayQ zXz4kBi%t5C-C;v4@q2x&ztiMK^!%=SU>ztfEh2RATJ78OvMSz`b*)>b|CG&;1frTj z(=hh*y`(wtw?A3W=n6``ybBaS?`W|NiZ>k9FW;XQF=ZFy`+|(Fw7E({U+M|tcz!Lo z48&GC^LYlf6Fa3ry@;<0FQoMlIs|?#ZNFvXVKlI}cbknU6h6!}d#U&yEu3gw7fcn~ z5^ooP&iaETw^-heX`W5uv(&*06)L`=qOhxb~?Q?h9+K%1>P15Mu>dyam1$I|?bs{0nyY2@Bxpq&k2*iG#} zMPBk}>;$@gzBkig4SibcW|$!IbItG6utU14VT;W^Gng;u{VHZrpx3X8?>Sja4K|ABoNS?^<8dI#P3>d;DgmTz9i`|K6O-TzBNK!>a-@3wyQ4D0C3dLnR5WNXXh_J2bfO1YP;Qy5ML1 z{};GC|Cb4P1F!#ESB@l6K}Y)d59?DDS5NM@Pf^;`F+_#iIMBNqWsCG1F9;rr9AWHE zFx*`T?O2L;fG57fVzZX}pO+VTLOnb{Sr0sIaUHQ)D!J3UgIg&f;pig1pHK2%NNrtf z_HEr~TML`OYrD2Gpr-P+sZFQ#e@}U%{?*;?(X=P-%@#j9A&u?D>j(R;&4q1{snh-9 z&ejCjT0wvU8Tl%LNrHIi%oLKZ4RBzM-(YEGZux*ZF(HB9?WP&iO}Na>t*vlu?T6X1 zZSLS`Ap!D>7=nK-7KU4!(4#Q2$Zui@$+5f6ZL`oMbpNc4)5E;9`z;g2nZuFW&zAD# z0|RIw{b{TS^7ZY_n>(_T+zIPe*x+K7RJYd2P2{Qigd!ioAFG*F-}Cea%NK-Dqm|%5 z8RB-1>+xE@qoZd9lal@^ZF^R;1QWfy*|{*C;5sm6mczsDq?)0F{!@=Fn<73t-N1D+jSmsqyCD7hXfisl;*3?G9{)eY8HnUu8 z=xU2+jZ3qxr`vD4=+$D}n1=fGKfYeRnV*oa4&4@?CYS9T-PsNfzPnyGX4oGVi+CzH z`NvZ-b~s?3XbYPhgjb4Dtg0&j%Qr>$_ubrte&}R9Ds4 zmqSEa%Y~oXFQf-~Qyj9;rZ8`mW4qm#Fb**;oicmudX;i`msf>$&h#X|!4+Xa4-KHl zP5Kyu`C_Z-VhF41^=1!M2?6zqosusF-qLo<0cHcY#nws2dNl!Wk|U%i^f+bb=*n72CLw<+rC*s}Af+lpCwIJl5b~oik@zPRtG5$52MMrXb;kN$%6eE|KzXsf zmIAPNZfQnf|KikYV4wGl-jusj@OQp{XiesnGUfq0#-oo<-l^gHXIVH;V&;zDV3q^^ zz_u(hu%NrafC*c@yw2}({jpx_zZ*5}{k4-V-s+ZD1Nt z=x#rE3@WTUNSk976|c6trDqj7n5$|!b(^^tH6Y;Sv6~(Y3aQw5!AkS`?R&$1X_;2~ ztp2s2OPcX`(=Ksm^z6;%F&*92`|j9$cXiN@Cm(U9Uv}HOt0rAo9gua)!}q>6%P;7~ zOK&J>xc)@a?N{eUE%iHb^1he1jMQy=r@Cd`{wYVL$qj3|<@xn@zVkxh!%Ln1AMP!? zR&&tYaG<=eQfIjMJ_rjn{e7*LTB_!3hkb=3eX_mF!7!k_zu(c-(m6<4nBLm28xKLF zkFlQh@Z)n5=l?ume$mdaw&X9k{MYCARAjz!*`A|iKM&kA^5>tUCMoM`rMD;88rsp* z?M-Edb}X9+x@bxx1jvZX)jk#%rU<7PRs81$2`}4$J8&*S^MhX zRO@N!@sqbVrJ*s_oy#@PO?xrxnugyVH_rJkQ1||V=8_b9a8+$u#0%ZYyDkkqEhS$; zhI*|T0V_WE_a`$}C*1I_C(bLq&t}_l$C!2ZA2@vRcZsXRH!L|Bbz1ZpOGtHnY20PK z;UQt)$%l7e@KV(i_(8bfvds%VJNM4{bz{v(4(*P+I;%6-mqurYquc3=`-An%M|RKr z_1bki*M`oko?dhH(oOHaA};&ju}44JP?!`^@I^dV{GKlNwCs&OJl^_O+3EwYoLm(D z+ha3=%&8MkEa`pn@U~m6H#eP3y8Kvk?Ji%|ZfnLDx7+&CIald#-}2z6WADFo+s7A$ zr+xe8*}ok8x#KbOU!RVCWbVg@VpVZ#xrxq~&K~QLS-tz}zr6Isdo{oHJW_mg>F;9_ zir#(I_}r+FMISp~%CRw+l zHF5Txn1K~xz9hVJg*X04uJs&q*rCpiM{8E@h_qi*zbWGEt#3a2$_*DCUfT2CO~dP# zzGgi`d|DDz4LUMlz3r@DBhv4?XZ60OZE;^jYex?^97(=r!sn?DL)k+|mxO42{oz$` zU-Sdk7w+A9_kC&WcU<82_@w67U%xVDU|`as*9%rnJTR{7g7Z3G_q9cJPhYE}+Tmy; zo$@7d(%P>1&A+r~!+mSR{11G8*TkmlFSu!SePLYfujA|wJ~I7|g19p$QN`v-Z$j(J zt(HZ3SC<6HN1i%(@QZ6AQ-Xh*chjEa3D>_DcKd?cm$jrPW!ZeQu{R`-(POXOMW=x{fIwKRuXI&tCb8!E} zYgeBaSn)&3TNxMcd3`W+??Au})+BXgk7`z}ayq(cP4$iQ^)=RWirc3>Elzm<-!H%W zP5G_53I5kT_V~S*R?Y4HZqB4PN`A?W`Mcz}RJL35Mlv6|{2ioceC^!6VomywpML)4 z*_Zw9U%R*Rct^&Om$rucQW@xK>2x%=_VoJHYyCg1Ek}a7e}DDQsq3Em_3kajCzic< z^@-MxXWhR4gVy1n7F_w(Ph67>bUQn`e33WAT8&}zFZs9Q`Fj^WUGJZ@dBar)cU`?^ z^08&ZM;<--tnrJ9tugAzl^(0cm&#ezt;72!W;}G$o=c|teel9F$EA#lTXR-wzN*Q3 z)V94WWOb4CZ&OiLB_*Yu)-?-ue!u2X!=az&?fGCh?XAy_oTUrve$-Hw9DmjG7alMF zCS0A;sR?{(oo8+cykzLbgy=VtF8XLs%W&}Z@m-gPx6S)^XwTA)XP(;~sZOAtHXA-g z-I!{fdT7C016MrqRa?~uxeeoIl+{Ikx#8@$2fn*)N11URf8}c}YXZ@y9;PU)p%@p8d1`{k@p>!xPEgRGJ-qG-fJ$Iy)V$Y?VA+Yd8L3 zoqSEj@K9Y|Na>t!(QU59li$PhN3XG`nlE$3jN7vD_azy| z2R`=C2+;4$*tx)`mz6!;{Z4zgvtOOah;`wk@6Ee#$*+sk{U^Tk<@0|nf6VmP`8QpA z`S6IwwDa1XZwkJVN?X&@5_rz~_7B!E9}TRW_)FWo^Ui$lT`1vP#b>IGWf7!zq`l{3H>>Fr3tw}c@ zwSM$?&HDjX?eVKF{?|D_ZgF0uC+qq)-jUGs?#B&}tO$0Og0_*92kd>m0eV5S zb>hUc?+mk=-&(w7#Bk5&A3vdOcxKV@!dqr{Y7U>{o!7zL4^us$2Ui9d5+x8ECu&GoUU-3@%o$-wWot-o)&xO%zpYm23WKEvmCahZpqkEu%*PhFU(NTZ43EnC~Vo;*+*BIpDO1WgL zx<~iV#djB_Ub@FYA7FXyt=V_irluWwtD))el(f3k+J;viIR0_nONW~3UYur2JM!X` z+0vb<>9vRNdp2dyr`KG6*=1MH-+I;cv-f^#&Wg{D+*sGNHYT{_s=@UIH&tY9o*vSi z^~0<3p)c1bhAj?1>xVu88R?BxGraAPs_c9xuEelI&|uh|`#cj5ZP z>cH2t*6X70x$?8Nx$kW}aU|u})zflX2EQr1#kOeZ(rXi^#9oy?HTAVbog?YQ#>d&uGn?YqD3vV;v~H@{XXPv37In7ih_C37Q#_1~8l-oDq8c24ahKQ8&~!#@U| zIWaT*sxenB$@}V;Pp`k}v6r4Me!;F?7TO)PQRiRo|IKIm50jdjI=7n{72VdK|V^di96Z?eDHm}<6!hM%D^}iljxJdKfUd!|#%bfDz_k(J#jaW9;zG>{i?2gnM z8b6$$;+Hv;by4}|i=Hi9FgQiOt>}k0gYSPTdgU-u8QcOX=Dh z{od*~qi(DS?zyr&E}VxZHB-<19N z$&Dv}dT7nhzrA(K#oHIY|7Pj?Z+&p!#T_1|8& zG1B?ZFJ79kZSNBMzRUjl=F2S+&2880pSgSa)(h{rZcgqhj9l}ObBF!P+9T)1B;G9D zaq*x1A@9#y^SkTkJJ*gm+?_k3cQ}^}v<&n+ z`q+UBZ8dwk#`g`h3@q&#eX}$Sr6qEX>N!Da>`WWwaF(wigx_ z=C`!x6y{~w$EU=fciwQDa_ERGwDxrMc62)W(mY4oVTX_@I+c{y3x>6w|?;~d#J z_UwYTEW0DKy)`Q@CnL|EotdATnV(sh=g7@%%`0ecFUYpHpwr&Hc!198D-)Ch{WLlo zOLL!MwHRX4i~bobla9hlKa z$NG-;j&28LOfRpjN}XO+Usc{*l}gj&^zw$P*-g`@5abk)o0YM!Y5Ky+)2qs7R81$3 z?9)7QRUSF&5ILuX$jv;>Crj;RQ}ng>39{I;6C8>cTUder=@5^|E=X;(rvQ^*@a zFkE~fXz`5v#tl0nHy%CkA#ADOKLu5C)EBgH;PKecB%JqI}@FOj0VfGa<}?DZqA zKWp|SJ4XF$;0-@tblPS3vb*x+-cRX~_UeMS*Y7yzqN=-|EcwT=y2NB9e1oH_r*F`c z_RPtb!6jnf2M3c2??=`7mJ7Q(_ul$~61I`fnmbzi`I0;i#1=la_S5JeCp|Vcp?}6J zmsG1m&tj*-o>;{(2cEz&0W*JYf9t-YJ&jjaeI1q(mU*WV%d;1+ROUQo_tu|2lMQJl zk;IU17E>eS{`mg00q0gux%!T`x4+$xk*!Lk+0nw4a<*y|;9i1wWc~O8hxp zoxF~fnb8(>;6_wZN#{Q5J#fx`my&vcbZ(mxXO_3ERFG zw*4V&mxS$+^!kO?KW@ALn8M{C#A+oy!szE%qv%f1((nId(yvhZu63+d(vc?%KlYUH zxmw9|TKEJd5&BiGsaOs|fL4;A*GeLSb%T105}~J`IO`Eg&S;Uo6)g^W(n!=IlEU~h zwrT*=Tserc)2o6;5L0`OZk3sgDmTXLN3Vv!i~^IN5n~K6Vm$p^aAr@U>mn@>8ZB#( zrIn0`Gz^N!5Ft@vf??817Os9NTFLA#U^sp6+g($mx27>vK!^y`iW)>qx*&Jq{3t9- zDN!r=D+Ok;bnLs~x(<=O^CF;9i&8(pG*1pfs#Xehx6%yVUAR z*}IS8d3kyW(u7)y-*tK`&k&J8r8fR;N-^4%etb&w22HqY#9wLR9G&Fnz7xbjx9nnn z-5F$6Iv~Pzl`K*d22sU>kxhy*Rzv`TsYLFEV^t1N8ZL;}8>J8BfN^>h49sK-8W2Ag z(9H?<)4?1l=@CcDl1$E6>MrJ#i1giMaWGajM<~ZCo_Qwp^f4e@O)tzrJBGcCG&aMZ zE(yi{v-Ci~WSO<3fDCHMRir0H(qMqwFH|>ZL>zrkJwPW(NRgyqcU8t4q(FpG;3(ao z2~i?_!(AL?wM&$M%(b!}1}RVnlSm(Mm!LtIw45PpNUID4xUTYK&N9jrVG1Y~kqN=d zbbFK`fSPJlfXq^-`&f(no>eF_hh4I>*(JA-UGgW;>rg2Z{fwv`Lm!7Gy~viJLy$70 z;ylY*hkbE(PrsAqcskW8@3wai_ILEh{g8>juMF+pyNF3;;$An`8}&NQpC~K|Q9^cw;HKE)Wr~PHGDIxf9^iNd3Ds zF8*KAhzkTVhO1>grqO&t`XIV47wJo45(M2~Vh|8NJV(~kyv-&$ixOy)FA%*mm^8dp zmQbjb0x?cE=#O@-l;R%J^GRn;i?b$#GTz|UDIEFGz<-X2=dOS1rl_IauK0ygh|jNl2(%dwqzQl5Tr|k{s>jpNv58HI7n|n zA__BxUy@@jRFZdOJ?42zN+n@GVGzW@givaM&pj}e)mC_V` zo*E%TC$T;W_lp&ggcK9}=qn+SN-wY)hHE7mW-6pkM>D;4xrIK!7?04AQdwflXK;}; zSWQc9G&)9>$^J+eVbp4=%wr5N1)2>~9E5n!nrNd{fsNp?+Ch_EN6UA4AWRsgrT0O# z=_5DG&5?j*l)(R~+|5yx=69a9$o_xP7R}LsWnHW%&D_69 zQyVKH5h;fMDNWb*7@%a`3|U!f0;R!V8b~Jk;*Dn^XRBz0wuV_A;h5rw5U=7DNeDER z29w>vOqNsP*vRe0WfzTm|DmR{1FwXoC#KGKH=(5)Bm(vg!j36=u z^z^wP4MwX>Nq@?JG>I*`!K64KblrQhh$NlIqKZ?jEG;r=8WY4pixntZ_ob{ynn>>p zv#}C08VFqXogBm)W1iAv2teR^LFNmRai)TVD5fY&ZGD6sL>7)ZHTJ2Y^`m8fG9E|A z19R7>$_7{{RTHIJuN#c>1*a)HZGE9X{f;VheWfg60%=klO;AAb`suPI0mxXtP-aRc zD;1iM2w2xIll|bjL?>BLMJ115a(Bv9^hB?L7N^{?EN3K9+!5Ii4LZp{`RU0pmJva- znV!_pb&+n+f^sq@%gKIo8?OH;(FtQH(OalMS5tw?Db-4meo6RW3p62_;vS&5*LmZX z|8H^0CS9=pO@G$+$_yju6jRDZ{q&_Q@%96mYaaW-Iu;1pAj%SHloB9V%LPbD0m3%~ z$$I(?m_PhU(Z^HQ6o^Q6D?hW_{B?u$lg8PpenGSp1HJT8jJr@V4?gZgn0UHhtKGWjAJ zWfSF3Z^H+*yA?!nJceLTIJ*qQ=u!deT7S~c7}xnSvx_L+_z*uMGIg}lk;zUidS*L~ z8ELvSh<$PXA?ZL~nm;qnJZ2Z=GpQ9Zt|$;nbd08WZ0W%gK}P~$FAfo?F= zyWcPs0fR#`Wh0r(H0R77vdeDI9@$8HErRhw>tvShSrdTZp(|t!#?w3%LWyS3U7<86 z(>KLrWa}iOyR5DY$?{}I$vm?6(#df0r+$Hic&b1GzdwpAriLK%w(g8JU+F}WzaZ=B z+h2-7w3L=VW>W=_F&Sin>*?D{A*YuwqZ9}k4wsb{$)gpqf!d*hjKfoGGk5>eq#rz-A}gz{AP(BfD2qH< zPb#C>a}lJ&h195}x@ZlO+huK4o{bJ5T|urBqLfJ zlo2ONGDeG9842Vhk&{f$D6xyA?Cv}nv7#u$Pt?Jdzig~qm-oM3Vy$cgeg z!QQ(Ra$?AdCC4+RO&&{^@M&zb9tS})x}J=8U!RM0Uyr1_udmzO*LPCg*JDNQ>nAzx>j~xhy(0gGalY&19QPJY+vvU; zn)Ky}>>Uc1UFTN-@k0}2GtEgM^tHPX8ZMEj7ZK}rs>rD&r-B5NL`2cXD2k*}v>-;2 z;)m0+8cuUX6eSQvQ%Mxcyg|yne(bJ{48THiipVihQ^M?ed}yAmuLSCb`sM0Lz}TTR zav&ne!U-dTjdj;z8YXktdPY{dzi42;;hU^oYZ4cc-s@L4>JW-%3Fg4L302T*hqlQn zFligQ83=6dXT=(>bZgRZZ8F=$4>!yDdZ2uGft=7ljXg?!z=`^d7+GCO#Mx;pe|BVHEPKTC>NTB>8{^k^CJB`2M zQaQQ_2(I(jA&9aIW!nnRVjn#f2%hJWg`Xm`js}94%Ze8sY!2zG6kbzwRQiHOgbWo92oz(hSFX@ex5S7W3j;aEc^wa_@W^s^mzuu9RdD0?(o?yXuW98qLL`%F>h$E-=E zn7WSAW{N-E-xF0D48jyrE-MY|98xa5B#B5SJCmzn9Q*Gd-5ZSHp>zFpqyytvVa}Iz z^s~|+WJywxUxpT=G1}zT57o{jd1$B1+HKqn8c?^(L9|IbC1g7Nw~P@~HD`m6r1OVk0_p`LM0y0PZZDZdC!w>&k=*qGixMF z@r;+5sXKZWL54@w3#h#(unKw_nAvF~vIy*`yF;x)}rkxdb=Ajd1$TX7bD@Kb=c{;>2C1?&%J+e*K)32+UMUXKU zFppeAdPZmDVN{}6IvM9QZZr+9MCA!k+B~3P=bQ>Tn(5+0I+kgU>i&sd`W2O@mrEtwV^NPZboU=jqAXYhv8{=>Z$)OFC$jVF%$ zC|jsO+0mtlc*7uh7q63Lo%=afys|JAodpD~3!(!DofHHM9fai3x*9~YY&6w1gqkpp zJyxP7^!5<_Ho1D;7}@IHl7vu-Y+n*dJBd;30hL>EmaofkpG9A^u24>>0{quaqOUHC zNY<_mbldv+!8$F%(ImqVIG24!YF#rsYzSC4UzSiohN_@jt^?$GCO=vt<#j8P_3$^@ z^e~%5J#?n?B<+~me70__Tj92p)}5Q>z7De$N4suQChceo&3?X(0zXq?#?4W zD1uN?D1&9r1Z?~08sdfmYd+UTrooxP{8;P+vaGV~-j{d!(jY-jx<}A^svxWQZv;7Y z9)VL8W6s~jX#blSInFZ(+%O?lWZbOPa+-DxlJsq zZjfz=sn$WR>tqd`_8DQ52J`#KXP?KXnDU#-@}qS-nDQ&~=2s%pH^^94k^Mla>&L&- znIS=?Gc$(t>?9#}$RzuDPZHSqV3?l~+5GvS*EgMx_~Vq7m8QXIlXzEdCz?Myv$#SD&FqwX107y-C(1izMtU$3W}ta(W^V zCWVc{bnWVBI?zebEoZNIXlZTq!x(CJf8Y5|!XUlhaEGix4z+f)!5o2n?P~UPF~)ty z(=qED%I#@SIXt1agjyc_3a?OG%B=hf?A!Aw2;4RgI&ucoX& z_hcRA&3cwE>$-D+{2{2bmf_k)dD|%O8UJHV&jZ4Tl04a^oiV#LlpQ_9PF7_%MA^kt zc9Z|d?AB6tc29Q6-t209*@e1Xl;0{@PsfDb2RE)EpkQd7Y#=k3Sw3X14zd|Qi9+UP zDj#K-j$Uq*4aobuDErj8j8HC*|EFADbt{-J$~t-m|GsQM@!v)HRvl$MMfu}DL>V@# zqimo2>sos0aO%aQS7pNj?%M3_>$?zW{mb*3q6NcBE64OkR)*>lz)ajWTJaN6- zWcn||iiWT8Y*ZphrGiO&Ai^raMDN$I`HQ{_G-miN*`J!oD7xNvKRQbs-cL^AAy=2w`ZA~n%tKKZqE)kkqQDeE_w$5!cz9Efq18KW$$4KOI`aFeqOmAmB+iz z2mD|=J>?VV>-Q`y?bHyvq)j`S)K5W;{oks?8)_g->=kOUA= zATXeUlmtW};NS$XKp1+c8Wfds2c!rhARR@if)P}T2-5CKroJ=Y_ujScr(6D6XPvCQ z_xYcvtn>Bx;k?}>O?}cDptZ8>?8OHCKt|JfOm!+6g}UFDndl*SVc6}5bdSNZV-gK;$A<9juH+WjDMfIJ*lw}xA17;_S(gk57B+;M4wlo zsvj_&c;9-MvG)68Y$;?0t4$*@VR^>WYom`?B4*kWiz3&WlrIT{O`AD$q#-vC38th- z8OzO{7W+QeBM#fTYkjvS2C^jPUDENv&~;X#rsH*^sMN*kj+Q3T{3sa}^02*B+`H8! zR6(n#qqX+4Ym$pX#ut^bkHWW(!(U+Y(^hy3>tpM>3pru#@k3e3QRB#vPj${|n79-} zIFXV4P-pUADP)*sC9YkFETTWZswSnxv3c~3(X=czkk=N4R&lUq*tS{9AX;sAl_Ebg zOXeq-JY!}xK)!Nj9ok)(IBZp$mr;3h9=C{!Msry{6}YSLzHa+DUIE40YGjkf0&$_J z3AMX;2dBvhRK)zydT;j$b-#Eben82e5~SgQ6|4GkRgcrE?lA^?-5yZ(y_v5x$@7{}G*9fPeCUPz(u$dKv(6^)1sr!4rxvc>^r=t& zU<@=1lu`*l5*9i$JE)!OddX`7Q&*rRhjXK6bMU3f_<*Bap5_`7E4Cx#;4PoRmxl!z zmD`d=l}-q?H#{XdlYDUvh_VKm#yDQ)ea05uS;+y(W&$*h$l*8G0EzmMKP}5rdpz_S zE6le9wyeat?ZVJzudG7qw;(U_i7cCd9s0f3DqY1ub-NWJXX=( zQ}M*JmhZtJ*UiXj*%cER?aL7?y$YLG|*e!<%)(0LkT$bD0;+owvpZZbpA}$e$e_ zxEz7DzLGnA#~O7C0c{cmWqN<#IedUT)0K)oWitzx8Fw=Ii*7oL$*YdZIq%4I#kqZdf_0oT^A@zH zIglW~snBJ!b;o4m^i>3_(Mm=|rv`RQu+VfTp<>oG%Yp4&IPapkr+&zdO?0Zeno`O) zQTpstayYlM{gOh0FRFsCxGmNh=DX$kS)4m- zOsc}lrN=DOyQ=P=Okj;;ihk5rhXK*=C}z}wTbG(f=MlWULj+~w>&L;nmEl_gB9m%8 zA+2A$ZAsClq^Mn@jV(!|`Q(B=PL)xH^nj()u?%9bx{rrCmbs{&GAqg4a8jZ8R1{LK ztF1$c@n)2Y+J4F_Z#Q50B;2v)xl@SnD_K@*OIp|3al1-ChVim+Ow^SLdf(#q+-E3k z%Lu@mNWtTi7aRQT72!;f-2;WChcEAO4P5zdZ&MPks5n$H+fry&>I7--)b#j}E~Ac^ zZlql~HC1OxZ8!eb`4RAPS=IqReNwN_`2%~x6$VoW$CZ7#c~87`%TB=vt{*3?Pg+{Uy>!wq zr*1N?pLb+QI9A-Vk#+m2T60K;`%0y{(@Ld?5<-7;`4Cm3&#t&u-RTI)YmXT|R)j8p zuBi~VZggZJw{mFKEjz&?qEVPkc}78aC@y~{R_CK9)F$Wdx3mTC_jJ$OUjF|2#`dz* zDn8_GFj3;3hK1Sno_tdJtWt;Y3Q_Uu#r6pe%f8sP3?9g*?6^uV3HczUTXyQpQ=MwP z*dN{o+71q)y0Q&E;;r8LBOLjiwF!FN!@h-k1F5BNF~#BamYSM*4%OAt4?{J{UJ|$> z*9Uqwk-dwu^VISNio*lF1Sym5;o-8o!!Xv?xz)83z8;!fi3i4aF7OyHT!>TG;&D&i zPkkB6B!>`(sU(6H)o$*O2i%VY-9sF0zvVDyZK)S|bigN0-^CO=|8nWuR~ihiJ)gDZ zBPD{#*<7n*OF65!@w%%;*U=daL+>S?Oc!C#z+4WDDv{pV#X}E^HwNw7u61Zt3o8wd z9ez7fSa{osq*#8jUUE*=Xx>^X|rsut+S^!26lO zf_?|j=}~Lm^h)E|Z0>etG=(Z)?|-iL6zt4jKH+sFaZD<{Ir_@dobS@k`(g2N0=4o# zzVO)zvKE(8b&_4ZT)+nDQxZ~DyzQwkO3qW!dhbST@DDCp99JnYsn$fNLy{~wBW_^x zFv^DFmTms&4mfOagLOSc&#Gyo8ET-kGFf8Pel1l-#g%>Bsv?0bm-{9B*cM~E92atH zxg@pY-q`T)i^#L5$f2!%f;FEVW{EjSWj^5ZW_N-#*p$TDYxYtVz8nPK{Wh;tl=lCpajkz6*YC~&fG`OQho3oP?Hd>h=yO~H z0#uP_Xe>(r_7#Bi-yi$=pCJZ%f+93@>mSx>^Gab~S*MA{Cv_`e1WP{+Wu7$ zGL+XtQ6K_-wgxd^q3rg zAYk}4H#i6Y5%d@X!P);)ldt)zekFREV1WI1o-TB{a>VbvU_h0AsnhSY7!Cmjx<@4a zY$zR&{99K4?7M$qFVh4CjDP`HfdGJ}yU{9k7R1mqLjw#wQrai)L4UXH&+D{K(@y^q zd+5Iug9W{|cJz)T0T%d!$bZlp!O%PKUVg)x+()5pbPwfI?x01T^lp3JqlaKY{-?{S8n{0|XQR000O8yRAB1bf}q@ z{MP^gUA^-pYY-wUIZe?^dI4?Rbwc;^4L4escX^f)Q ze1k~t&%55};rIbrh{0DBK1y%}g{X2$i4smE{0)_h@+ps)a@nIw`Laqpz`^XpXATQf?oU*P zKIo&`gBHLSt)N#81wn^PwRT7pdUchD!te#WjD*&vGPx2#_p`~_L)(b`Is5@T=iN1U4L;F(WxqeeO)htMZToCK`uJ3 z_^RVNFUbmfA|xuZr&UgtM0UL?MIn+VrnwuEJSYWVlM8{kK|zblDUIX%`bbm*grKWf zTjo@a*9a#o^moKw_Z|XK`5dS6eT36w`e#ldNy2L+CZ;_oq|ZFZ`!6kT>EqM-yEmnk zwbIfpKf)Xqri%G#egAc3<%7O81(!RSF-9ki?1CTV4hzfr%(lKYu8(e1#-_`wV}Lv} zFIsc&RT#@x14Pok=~am`0QB?yZ$e(;1x^(DAh+KB9 zdiFdg!1VxSvU`p58W)p^%1N@u#YmD!F;12^_WD)AN8#RjILZk6WQ7wXjVKZ?axq@x z-P=i~)VLt^doHS6n6He@e9R0L^V7wH`{keBdROO4OSi)9Uf*6X?&sh_50>@OrkQhB52aiNJ=STDhlX`aT zV`lh^v)219AblSSME)+S$;uf9i3?GfQ!M#L`V+aSo%#Oru-I^&zX8IY zQzbr0^$NLLRmWtl6)&cne zJf)Yep~XGC->c1NafR?PZZIy0j!z3J7bjw@hm&N5tt4x4qOiw7LlH#~Jr3>>n!v85 zdex{R^pZ1fc0-iEeE<1>efr7S^F3aO*8dU5{hU4D1JbaORhS|`fCo~pO*oZL5DvAq z2zNa$sGQ126`@Z6U5-AWDMD1^RH6u=aw5O)Pw@&bX~c6IR18RR^C#p8Tz#J`it?b^ z^ij_wWmOeGqoi7jfF~z6HH9RInC2v2QRG2xP>^Eq|KddPoU7RlL}fvW3NfNmZHMDc zv?cJ?r#-MEax)s|rG7$%qoq>AJ`pMF%_pK)qS_G)%28g%KUx5mSQzB{95@9I+v#Siz(o8#`Y92TpdHvc9%oezyXa;pS~bw&Lz&ac@VToiY}O(Lw|BZ|&#O^IOK^aAo1g((}8< z__RK=T^`xT2M!D4K4Z|BS=MJ35VebYd&T{E#6t%mAcntsZA>l{_h*dxx5nf9fd~&9 zSbnQ7y{(K*R~~OvmY%oOHn9H7Gz!1E86`rB7Wr0+^HNN-4OMGTRLDhnMM;}HjF^8y%K`pDK%d||#)F5;dDvTv_sB84 zD$E=6`NP7LF_+WxJI?Da<~PfaUl?<9M)rAW=~nSzQeRyNZ(2Cb3JU^gUf2N9;tCkr z%)OFQiNeK*NczESMy1OFScF64rkokopUxR?4~)r4eQdXwp9|dO7iU{#mxMq+x20nJ zJ+wl4ik7EnSrsj>G>(=w!PkL^4H2h%ow_KsgM!29FAVKEU~Ji1EZAx1fq?zA-@(?J zGhb=o%#rKh#H<4us-K;@L%kX}J!;jbkMZ1>Rp#xDg*^Osal))@;`aH*d6nxWL}H-| zAL`>38~3*L*>(Nh8+6bf>&Y+5l16T7f1tX+RU#6;F)&z{8N~%T)Glm@^eKeI&Vl`w zR=GZ2RKa{B68A;){I?PUktpUSzc?E`&&7lo^}4F5Xq5OsX@)JH>Ra!@Q2PBvJOk%} z?qOlM`X`Lsb0a&ePpp9Yyt8Rc4dK?>8pWu6CG~|V>~pE^Yrtp~y-xg#LPUrYa0y=G z`$-I=4?ZKA#s(;o+DjGl>t-Y&U%8vJR=_Ahc%9Fd9bPxKG{B2O?3*M(7&rtIb=)L~ z7MEk(Admhm*nC=w#uZtTQ>vIYJw8?Z0ARxh8Y;#7CKyheYiNcVo2$mcd*i2hsvlaL z?bL-|w}+JzOuLA>A5Gi8|U8qNNlGz7Zwh7PPi3sGO3LB)XO=o9lAmc;g1;l<3(; zjPNn)v^_IGz%@x|Y)K)!$i;ajHpnaF(+EVdfQ(I$%7d^z7o}z#d{N^e_Q?KfI(*p) z9c&=R@qHR{Yxgc}AXxy!i=}69+>9c_#rFOm0&Y{v$9WNcPf3~}!h>FsUp!bYZA|Kg z8GZK!hNF<$Y{;Gn5atiYp}-x_z;kZN0qwjVRYwZH3knB+!EFDCWr zpY)*|D6@<6rP$#2c$ds|TZLL&(`lPbB$^!Qp2)ULv$Mu8Jzh&nB zmYJ)Lapm=)(&o7F=C4L>oNX?*fvXye!^ZfuksB$0nA4XZ_;#u1HjK?x{EU$s!N|R_ zxmWsm7W`80-W2!N^zC)y*-GWv-SX!6VPX7ZX4v=aKioH_hV;#Q#@oH{l7`Wz$DN??0#HFLMYA&;Y|!GO=Ya5~lqgcbQ(k5< zSQfYk5>==uim_yb2#5H{aM|I9LnG#}unZ{}*=HDAhp76yH~QX=elUe-1FsD4IzLS% zka>s>$)C&8?<_tLHbpSks6@)u&=hV zsm{0^t`Z(XVQ94|btrze1r1o^!fr-^RoxBd3(Vo*z=y_Mw`@Ih+?rYf`$kfc2ZWeE zJubrOGb6@)-h8kzckEHn{gMm_QPK=>V|0b^uq{8iU)tYl6=d=22w2~qD05@t%ne%1 z;loW(tJt%>Kw$emt_caEYJ4K;{l4{wh~q~LG#S~S${Y8>tOBV`{ zpYGRA@iaW1;+1(2)eTPcrZ9B%{H+nZb$!x8+`w-l`iB2z(|G)EB;70XO6-q(T25)r zVDb&N5+~B7!sBvf`sdQ}YGri#l;hULaq-IBi0r)tAx0zs>p&F04V)2*iO)`GmpAX} z*)=^=s1Ki=AGXlB)|U~h!+*K?C=gZA>p#OyBm+d`F8&<{l?!PuDGQQDjR^Y- z)o>Ve;}`cTOLyRPeRNHqc~aSX&>G#d`5b_7aJY&(2(^@XiAzaQJ_V`Pw$Uv|qbWsY zd5czlm>ncbL2ZURe0a{A7lFyw3Sl8f&E=FrX|KV`5Xrh#hJU{l6?P@KJ!Z7yj#q_sm#CAch`&giOM2%m2KYD zN5N=84_Rn8RDxG-I6XM}{}TN@$!l@-Q;t_4$e!Xw zG0pYy3a7?p1sw!D_!0z_6NQAJouhO^r~xLR!$G0-A+RFzlOzNcTps9c0B0`vv{IS^ zMG~HjUSQS0lcj!+@0DaFLBB7`;6G#grH-0jLM=Y1BcqXjABB2d6_{*E0nY3u3iiW7 z7D#S=7=J9k+tv?$I4q1;GD~_sUm1E>TG=!f3YE+vBuTQ{SuXF4R)+2X-L5ZyQ^BOk z^7GZw+{R&H3f;!WwR7}gV5YW+8Td!$dGdmPZ@2Vf(*2<2MQIwpMUm5ZrJrbApTZ}|psdhRIZ<>P zl5s^&^~X7dALIr!S`^opl4#im3Q?A5uYq4o?&B_g^EG!FewC9TGr$g|OVT$76)2)p zR1fm9;05!&(VP@b<)U#xjIk&NY)j&LY5Gdc>vDw1KCi??qN?T&_$04rkQms*C3r0g z#XRoGx%$^%4Uo&aPTs&^OQ3snfmi?E$E#ONhT_cX%87!9R#mE|+g1*r>i zkXK^xYf@G;Gy27g%y>Rjeh8ru6Um`+a&$-EoMj=0nQaJ#1UXPqYhX2UGk4v1z*QD!_3RF8H9O{X ziR50EcWIc*%I>D|uJXoac_UlQXUb!5eRRg0M!Pfm=+n~6mst0Sr>hL#0u2P6qz)Bw zu~3>hfK-RflhV7T($X#Dn}>yL>Fq7Z6Mp(v1P10nTLq%{7)$bm^yCpxlpek=f&;S3zAU+W^V~B~^pE&j@EMyh1kWE6xkM7UG7UnXJ5+Yg@zz z+5hi}b`j0J>$Ynzlvw#a(O6~)GZ%xLfxavf{ot+>O{o>>aT7KW%B!^n_7S(w)90CN zAB3+F?UEc#saIrCh^Eg3zQcH!{fpy`u-U-Z%=@rU*$1m|NxFZTt>e^3E@VS;i-mVmbm5Yklo*X>J1;iTi`?NWAub}=y<0lz(jbTAZp+|sSM>2`ab`EY5Q4aC|})o z6GU#_qtYrp2vwWeK32#_P&s~p7pPX|q)0aa4hzdHn_*@fw^`oG=rapgKg^=xuztsw zqUq6WFUnZ%t}r-bJ$you#&_8IvBm>}?n9fe<&;X=i!%xML@0#8Cr>E0xQ|&ssyGkd zeRy(>NUE%;?Zp%oKN1R8%x6z1ws?!i9zdikpJBoG>fTBWd|@`fetTMfJzrUvgbQMK0Rg$v&$GsZTw^$G9`Td& zS4orz1FV#!DkLb9K~U6*UFWdt*`T0eZ?qWc<5Qx>4e(+LLNz8zS(pUb0CPJv9F$N& zJU&($-mN^G1t)r~d^Zylud=E@O-ZrZWoVztE32D`_W2b)Phg^i^2Xt|3f9yB2 zWVw5Y!ohKSj+Jtnrpf)RYZB9&>s2Z ziNl@>rv?cjlw|4zwX{|yb&?#qPavIAV7G~)nu!_gk1Z!KZ}vh*1(G-M;aEkI4-)MW zO1@-|Q?b-AQG^mqouZu93a8GJM)!%QQ)=u+Yw4&=F#GQKRtYDz$>Z z(jLK8BgO1ggf&Anp`=)6DXX=z?6^p$`=r__wRU~{>d5?5#{(@V#lZBdp#9zO%Y5e`POl&YORPn2D0fs>2^w~-7VUVOqh2(&~hRS%qQ=tXbVh5 zKUUEe43qYVw%|nkQ_)VMC&Iu2myU|I zz}lE&6>Y&VX^&_Nt_(UAZA}qODACq&s%ouhI|j1pKGAkcsogHxYL*mUO2VT|%yEo#LsaYl414%DIjcS*s=8@la7Win~+7?b=E*2i2lF z8M1ZdzX?*Tr>zzDqCCjPE0{&Javyy_O_C@M%e)~-zOld#8Z@TH^sS}R##ZIg1L)YZ zf2Xo^#|i$%C`>TV@12fB|3EhdtmDrqqNJfX-Xym2`jD}*R(|%_$Sxpxc?hqN*GJcI zyWt4$7#jkFyd7V60FRJ1`vM$!Ri5Sm$Ix%$PvmB88nOP1J=JsElw{tFJxb8N90jIV z5}04ho(iNRycT_Cq?{SCmcw4sR70{RxHUjV)(#lBkebYo(2nf9c@A^0Fj)nDp|lm@ ziu<|J@GcUSzOrlVF1U9Uf`oq6#Oy~9A6f(vFu5tH8VpW50xw{IN`6}3ya#h=J4vcn z*o2{zNv^%5PgY24>6KYDr}X-ZpjQWmG)u59#5f*;#mOZwh8SjQgdQaqH1H&5EppVv z6Z^@=deOUQ2?XxIJtCmWr`riw_aLOpRjS}k4tF7${G%M@MSSCOEVQW&pMh&&DBqi= zb5_{DE`RBp34b3EpS%1er@xvs#t*E~qz#+9mwn=!ecm}z&P#bAM%g)U+?x2pmS$6D zB3$X^x;~q=rfT3Ml8#<&?HO0i+@fbbnEx)FL$jK{P3oJ&tEB%4suxU^;sgoD3ebT} zFju9cw^n7i34`+mr9TD3U>ws-@K6frbDaz3hp1ey$V)dUmj(diz%@3tOLYzsX>u0a z+4B*u>NZNlyQOElrN#Zj!jzF+z-ebVMysV;s5+aaRdn!`lu8f<#0L&OYTA3@dlVPO zIl^IS$=a3b9Li+c&SKieO6u@X1dS*H?-g0uyX7nlQ34rFk=1y7zqq$!q3lWbUf>9+ zOLTqQjB7A6?85PJ>zm<*K|6VXD5x5^C(L_rL0=(%P7xJ^xB~z%ER5~K+yc7-s$e_M zTF#E)UOXE#@}v5~R-46u7yU1&X(`%X8t7qM?>ZfA1~TCy3`7z|I zp8n{8UYNnv^yx>%{W^xo2ao2u4ih31M2pKYEhjaMA<;0K!C**n10cTMf3-67e z=3$iDy=`M+;$(nTpBmM38?6K_SIloBMq`-ExVMc%>kzeZ;2aD-HYo<-7JkCquTYY? z#&~;KEgR+S_?gq-cd+#rjGb)x`2&4_@n|u5fzx>P2I75Ekz*;~znVjKdYN;CE6qJF z&8;}uoKx_Dj{a_~xS#8Y^WZ{%KTPX1iKhi`&eW#N6Ac=Jk=t08s#^On*;3CO6wF%6#VKfdHheQunye?_?9d zdvn&IaaR%Ug2dTz0xhn{gVIrWPqUKE3;=*N;3inuL2@&A31eZ2l*a>>pVnu#i+gLv#Du;zg2V1VW`>OH0wk61&x4nA_6L1*2YDH= zvmf>=nb$^c1?)l^g)YtS6!&vAj|I;zKY*A|rl22W^wkA@_@~OygTunIdqc+9xH0#> zG`Delw8ND)$I+RA?AOT7g8yS`2vXJpp+K{N^@Ax$0;Z?*v1ontX=P-?$c>;%QOswI zmye9hQ>TQ0oYAc*BRgwk7trL_52lRVNF_5<8M@EbLM@*NsJPzQXef9<)&{tm@^LNAhm$Y<}I2F|E zSEyDK!AM@OMi~`K*@*gV(8{ zd7>?luOzFahg0Lc!u0sM!y6~xU_E;tOv@V4k}wf4Eo`_dmcf3h2Tai^IjeH72L$cJx;VA2X0_Xly(&?tiEZ&y)+> zVDug=|4Pxx<5bL!{W8&s(??&I<~G7RAdX!JGfmMTHN^ZIvf^sImxh>`<3r`Xh@O`v zJj54gqm+%{Z(k{jtiVq_^f#BcLygNRF~;=?lAy-TW7|n9^w`Wq7o-81CM|eAL_Hrg zeGc3oxP%HE-eIE3o}F;2Ous<&31*rKlBz)}h1|!iZc|u*235m0v9u#7-pP%imFj~A zMSRyD4hvJbfH5|%k7kXD3A{&kztr3TtBF}6?)44}Q_KQe9JcHPeSECAyIT5r-Tx)9 zAE>5+rb0Qx;?~Bid}Zh%Gm7XZk4eXK>Ey^;W8d`t9}?C6#3xv?q)h)!AA&38HI0wP z;lJQ2T|NOuv$z0b)iFDB@$7k9Lj+VL3aHKIXC2BlC|&TUB#|iTb9P2cZUa4@s799` zzo?8&8gmDzD%QCfFl#mzORHe=mBybH_jdHz>C(pQwy4Aw?J@iYJ($@AXksr8AD^bn zSUht<)L`#bWLQU>@#cWcqkQq9+@m4=>E4f`Bi%CB!gyg$OysWf2Bhm+t&!I(`NMw) z2+xjLe@qx7rgt{nTw65?_llYGCCE}}owSLtHbcppQEgV6aT?R^{$wymimL4}WZ!c9 zjZ4TeP>!+8f##GN8;|q?Z>p)e>+5OllsdYpTFlY7tkx$FEo3_a@^{5B9R&IiHtf{mjU8y$l zRHlC}Ew5Har%$9vK27dwJdc&eM#Ey4NO+a0>-K#`=~~nRquw8eJy`aTCYmed!fR?# zgWa)MX>P;F?v!3^m$PH~t0g1%yjuEOc^s-=6}(w}lS2uV5v#mtGui|~(>qzNMY74pVFZrLu{phO_{F3o+Sq5~U$2b!kr!J=t>bf>tt;NTe(`nxxJZljWU zQ+_m6%x~JkWCVhyLDI?uZ--&%|jRfa^9TxY2-$Vdu#1Re-1+shlS1&lE=$@K zEwrM1#S~v=Yz;GVlZqTAs`}ZW5F?y|AK_G@rIKcDCKG|k|7cSdL6-i7`}u`0jdV&H&$p3E_`vmG<#d$ozY*fmfkLvH#YUHrNhD!VuZf1RXmt99==C> zfjY~njmq8wOt>uO*I6xQ_P+jfk`?RSd0cw?*otp?Ha9zEEDj@&gZPV&OTv2DSGbER zYt)%${zde>g+ERd|rsxCqpGMd{B2g3SEwOwL1WSeCWFS5e;E$>vU-fM(Ya zvosx}X}nZb{bEQ}11K)_43=itg9Y!NxE=cv?1(ik`m_hOuMl3PQ5Zq$cW(pEOKHe) z9yO&5(0u*`_MqY=?l=G3^ZDnWV*)$ShsY<@2&*}#ESA-h%6yC{@JRtO-9=TVf}N%G zF}hC3v6Sf1uIP&~2VI$$Lv9Mt*Xpvw@v)cy*U>|1m+uAJ8sMRls0=2M-Qf;!MNmzu zWeuF1JHU3m9^HzemMlpm3NJ8@z^i5_DDy8pv`pO8;L+r=4J}rB;<(U1$&M%h-03;U zcV}$~JbQ3Bb)9^Q*KE!NnjK_@DUK&hpD-<7=Xixs8_*1L(u6Lv5|LaG3xSWe$wH}Wq7vY0c* zOFw3RZYSUJbldbrE1@^e{ z1R%V(=4royBD0cNgbg}`B}AFA-z9wjw~74?P^ZPr5$x(=4@niM6%R_z?Po+%y#+RMtNs~@z3pBdJfVk(LAv! z?deMC?JcMVq1R??<}1Uu@JD!fa=y5qb5bTCqs64K-FWaBLTPlZcI02dtRl#H@irL= zi46)Byu6v8V;meocD&c)6HkugWO}95e2{2J|l? z%HO-{0I%0-#X^h7z$2t;d>U3U&kV_d1HM+6nWq3W7N{cxg)jTE{BB!6_`%ABG_j_2v_#E%i=dLMi?^7j zNz7QX-6jx3IDIs$k56NR(Y65^=*Tj9+D}klfi8#vps*>PsDD*cq?iUnO>8ci>J^13 z#rAVFMgXxS^pero6IFCnjfY%Y4?aU+ZuBJ#zM(k8G#!VF*HUNTnWvMM$5)^JscK1Q z`_vK#952ZVQ%+kBQ9Jz@KX48lD%cj5$rKB+yvm6()oKFP0Q$e zeSQ>dzUnuk&pd}tyiTV-)gthYz)6jICC&aW?m?+I7;Y0Q9lf&e1TBs?MvVw>O(2x% zgihZ`Nvf|X87%|U@xiyo+-KG;QweT+w*m|i8fWYQH8eQN=iY=Mso?zvy;bAWtWyT{ zGzopp$$tfo=L|IaUDVD5YLCSM_8~SVp_Y7gII&WT(H*EH_l0QCimwcf=~))5^Qe3E zp9}2z5BG8F#(cI#^+&FPqsGdM7)a=HrhzHLHDHTt^gWq2TiC$>bXRg;b@)eWps;h~ zSX*lt6h8SoSyALc!n&8&j$~f;#3#d2EPTh2@N7CodfBJhG(~@bI94aH7U9fOFerh= zufl(D7r*)1c7%J&Bqt_Z`6ZbZHtq}KEYx*^O~yfcqF9NEDRfoV6JzO?)rY*PFbXVb z*8#(|6U;wT2pk0UUq_7(%@SgM;R~_YRnqtOF)Ij0pCQ~CAjVIwrl98?{E5~c0?WH< zLd3HNIVEZ8C!bOlN7Y~k*F;J+zrsQA0kFT97eOQR)+>dpf^9yJF~V8aZi z)_6LG($u?I8M>qIuA|6@2;;-I`jZEY5FXwxJ)7=mEZWInLd~?`1Kqfhm%_mCO$Xd3XJ{~3bD~yio;Xust!ab1w{x@MwMP~&nebvDqcxX&%0}x~3Sc4n0 zZZaUf1e?#&5sSbKiu)g+7j0(L2`biT>xTluwOO|C9XP(eh@Q9oc_u_$i5zsiDP}ES zM986PKn)yT6y+$K$V?Y7Z7CbwSf-}U2~>~G%eoY^WPx)O50j>w-2|j8+3*8Z9KSOd z=QUdD?tC=LCpDT-LV3GLcO3J? zkjeCd!K>~g0l&I1vyEPL=TpY?yfHm)6@8@^M+h+zX5$ha-szyDLzk{AoXTJYD zbe-}k9i7tADINLf2s<4zGCTAA=l@#wh)R7 z)A+WLd)ZNsWL5T7LlG0CI8g*GCP%rm?P!>f{etWq8B;gBuB0!-s>};)&?j>t<{U2< zl|^Xv=XOM3=Nz|sU?=XGmdlT3=yKxMc_to0ZWB7Q=XNT~x3M>>Ie}*xu?iCS zv$reDk0Gkyp10mPoTz#MU(&OM9YuhEz{(D1`ic!@mfv@dre3tFKL8D@q^QX$xS{=E4-vA@g#>3 zfu`(w!_}ep;PmClH20PTrNIqIQ-QIilbI^qV-chxXhM`1A#1|oaKvVK0Kyq@@W#;~tnJdk`4oDVj>L#sN8&p2#Ht@jZ%&30w zz>37tZbh#vcXLoh{PS?>=UIJ`CF0<|iupNg{A`S8jNG_Wc(!K0Auf^yk*F;Ljf>4% zpbl|ilW8y$qoJY|OgyCIq{f9LSe?9=tAG{nbhoqYKic`oi@bN%jBz_z8W=7$+=H;U zvD^#hs$`wRXfyzpWIsnZ_#{Or@GQb#n#udT68Z`*tE}+1b6Sw~Z5E_=M2YL`(drBG zd&0i}MOS&L>9mNYSUx{Ca&@|kSs{VY=VsSdO@}uH6>B-Ml|CPhLq}Yw^QDs&36Iq3 z^#;%&e{O^2XuAsDXz#YIAL-VaV}M3e(GvmQ0xKba#%@{1c#{*^ZQrsB<*ftD;Cu4+mOl6=!iVmgkny_i)k?MC&P=SW=+JO`|2tD=`2xYN_g zdZWB@jTU`aVd6{?L&J(%QH(c4MY!dN`4>pVx|^#kjDrzGbKmRkh(|}EVsOkXvlW~T zp>5PNmBq1pO!s^@?|y}9;dBnymIF+3U-TUAV*i*f=}nZkz?tb{YZ zp1~ltDP?9N`|_9qS|ylr3F`hJ-cEbRvMKJs);vwc(c;7n(urFj5v|TN>@z%@tnSs3 z8a<3dYE4;L>H7Gzr-aDq&rfBkJDWUvh1EP*9v+?NH9^<=8V^OS4vn8EF^+pTN*)tRZ zHr2NXth|Xbnkp@n5G9ze0Dl4w4g$PtnK2{B2v>gm0*;1x0{F6>qq#VYg+i7&5u&XV z(q5OYI5=#@3bh9B>%Q`K+O2w#OTJmH>fk(dT(UQ;njMbA(dR zp<7_z9u0&)@an$<3l5vr5+~H%WS^5F80~Ur<+8Y(Vm6{v@2N92!@=Uc$;Jqvd)xZ# zI-3>cV84fjWsA)Q5S00yPJs~d=o{rvK*)_^6K%y_g?k0StA|rlIMk#rx#&VMCm6vO zRFyT+q4dw1m1ZrFG4=I5`$~#2wjP9GSg=eF-x&uqy7EJ-X1?BgrVi_gym|WXb%1+# zlL4_QP#u_W_C;~Ez4hMD@)qb_?w+?D@c6Ma{hqM@x-9j{^#(!Bamy0)stF8RVvrIC zFaI=F-k4~`^i7p|q*$u1!l$`Dfq?nODg#{e15sa0DUh}6pDG!)U6BnUN}3{{rtXX* z2H`ZY`V}d8h1cS=D;uOCGsOYUrde&_6C?qaH|jms2u(rddT}l!CK;!s7*Rx827B?F zuicwuRtrrFGL^}2RsEmL#)S++D_#L2lZsJLR#rw2pkKbnpzSSB7`p2MWB>Fi3q^7>8~!wEWZ<8Py+; zShGGogB>jEqFu-yzDMj8`?z~V$cO}|`2 z4pts*msWQzS9NG0eO>i~yG$pB*Q>y} z;Wo7naV-+5UyIuwe->S5Xh9`6d;y9)vEdw!Sms0_0ewc0zY0*wj*Y6oOARR-a)KA3 zl?8(eba{f*YuX}KRx}f*tWW`R+RFSpeRm!E1>tnrVt%5s2;FST>kFmfT~^wWU8p=8 z)hFjm82`!WKfoEp1zflqPR&3?Z*bSAt6DoybU^!D{xVaMAqK(Rk?i;wc)Q z5Ht*s0(D>{AIS4-4nC@;Hc`y2ChnY4quyyo!SV~w4cYE|uOJGVKvdg|P*X|9$?So| zEb%Or0OvzO)?`IRJ-$!4$vpc`_p6zgkMLpTf!>dU|QAh=%ke zm}ZByhBC(w$U@BOs?GHQ37h5yuc&bz8bf(|aUj4)_VtNnORq8JwvCy$a2>9BF+&U} zmGzgEp}E7tIJ6^2Lw@sKX_rkJrnUFG&_gp*z`TE)B+kZhn++pcpd(^&v7VW%yqJR~ z#vh>d0+#+#FA$UlV25NnLUGENe~aj5f}=4dsBuc*>O%WAD@%XilbR5%!)0(?0ou`I zuAgB3Pn@n$%XM(?Zu!|dlT}ai<@MeA9SAnu{h#wlDu>uiD)N93BXA26h%Lv*q3nv4 zd_Fg3W{U^QN9#^)0ehW%*adz*02)VNVQ;DroZmIB$U9u_-Lvwe`}%YS5Yz#{`uTFL zJG6G)&}HIYj`K>*G6e6f9uZyizYw~9;lv_>Yp$4u{8!DvvcW9HJ`DUfw2)EN2!}mb zAmVpt&6wK>+|>~o7gx>HawSEoqnv+3&SHF5c7KE`Pp&aMq)6!II%Zxze9tOA_vGrg z6HzfXeMwfL4S8htib%G^*w>jXpnZ{P;#6+r`d?zjjJ+jgqAB@<^88YpNkrYLG|ca)n(# zZi(#y%uPsL<*i2c=AOWUONWv-6f27Pbvy$@BNK0qTk>3111RpANeInTJuV3IVM0rw zIDv+`gN_6dHA$jEpWtVmi0H11v!7*G2z~=^^33zc#>yH5Qnr?Ymt+|uNYMBkTdwlx zf&O6f1dufD*PhoJOk@BZ$}$1!v@I9{r>YFH0dNGZSp=YOJ<)%d2!Lfc?Dx2ro#wdT zuV*ZJ?xpyC1s#1Bf40Ahb)V(TROS8yV{+2TuRBO`U&GB_kzo`<>>J5VaiMzz1riIx zCzVU$>YUFBfY*UOBSd*fMLbxpEbnzGhS%og0Vl4(qVe3;iS7R6$Hk1V5zUVpzvl%H zR+wY6uFUN0x!Fg8-pN76RpeJ zrAW5W#<2k3PMBM^h{_zYPT0d}Ct0DT%Pg5F=8uE~8X?7l`_8BUBT=??z4ul<11v_O zf(j0v7=eEFta1kj4OoK443m?n$U{XUQ^T-lvy^s)X?keGN6!KZ`E!b>n!f?9MkE!Z zK@i*dPol`@IC3*73Q<90J-TUvnkaq-e{{X!N^Ao7YjTop*;nvp9lEOXo$+X2 z-MSd8OHt_w{jXmVlXa4XC=XtuOizlYS*eXY_*tL%lcoD0J*3aoCWqqwoyx;Kro=Lm zpQ@h*Tvb3qf84V}_^IJ7R$km|^%h0ar(IWs{(iHp6Mo<{{H4zA>F?I9H(R<%1v*l> zc1eF}bel6jwQigByTU9n?M}R~niwOsfr|{(X@SJTd&L@Ov7NWgV7vrV*kOEEXOu_y zDD?hid=2M@VXn8?UXuPuCpjobYWd8QJ-?z)&bt=13ia4>;Azc`82M2c2Gau0chVFB zi#jX-({Qc18^^d)77!kx{nMxCgOi7q;RSPoGJlbrv#j`IZr|c@DPW4E^O>76zf4=(wMKUy3fYv zX}fUcG8dDhw0;-Ub?B=&`67DW?SG^Vqb(s!%lM+_|KqasA97Or5BOsb*PCKv0j*EC zH^HV_t3hMWv6xWe{-0j?Cie|Y50@oPfu@m4kLAz#B6=PqSW;71_wJ-3$5K(D7rMqE z>O*3RS(@w_kM7>gnJ=Q}KfihLbNau3hV?#Wvkuvmbvh>`E{pbvZ`fj#mq0rAf|Zy8 zjlDO`C16qp?VV`WXVB&bkgv-okJAid_xEj26P+lBwG^hm>gbHxntG&}TTFPXXStwq zDoH@^Eoe-U=E$E@!T>KqaV+zJK|6BqeNhahHzN-6X_f1@BJ$1_O+0H%U^ZEBuj2LL zQnWJ`#$bx?#6%TD11A+#)gZ+d%EjHd2GdOTZ^OJv$Lfyx&4FXOjoHo0=(Kxt7P=XC zp6b~heR0DY=55a3bK{(m8!0_|rf)5kpXN)81?G=&jL1GLWPO;0<5IBsQhDn~NM+7U z`r4;^8l+=^P-$+%!Y_2s;Csg0oRNJF(NF66!_qyLt3CJLasgr)V`+G|vJ6cpTYy-; zeU_g;FmBDjl*ZX9w;OQ^#%G!RY_OLJq>mp=!j#qQE2|%c)n@5vM`EkA)Gq~vL^b-$ zS89~E)l_!??RRO7{J;O7`(I%d)30ulXbLms9AD!I{hU|V#EE78=NcSoDJK%V8P@kN z%CWykg8rueuwUF;4d=z6br<**EWwEJ8qZQxBOKNrz@*)UMJo$6+`@87vsT9c_AfoQ z8+vJ1rd^6+i`>Wcrs?fOwG`!ugNmSO;N?JHAp5NOMSXj{vb3ykzknmruR9ZKi~H01 z=t$}3TV`~s-I<{Dm#=A?hI;chp(Q$;ED_Y?fh8X~pJ*&s+?~+q`l36J(etS`C-8rD zQ&ad0HwBf(mx&tENmEaHl2rsq;9DGjQ-J0H^lO3DRFy~5z}5HiR@k}$ilE}X_k1;h~$=0_Lql zLsxs+x~mT-CXKZH;;{Knhp4593A7J1saS}hWtBke^7S^GPCIz z?d&cL_!2y~GN4iU`v0IGN6&3w3qwc%!$Ib?X00n75LgXwz6G^|T>_1NaoZ>}61MNPMq*<{zjh2oSlQfkhB7t}eFn04l znJXWBR``}_5;#WJvPLFRISGXw)PV4!1kKwO_69pper^Sz%p_US3)9d*t(YUt_ zQ}$-FX8%U-)Y(j-w45((jvJY$#+^r%%q$Fl*`6yGM$Ea+kZuj!^WHZ8US1tDaxc*# zg<&bypS(rX0pEqB@a6KxuCegWYIw|=8q#yP4*?;j*0!T;73pxL&GEy+criZ>V9Ji! zu%@8&U&r!8h)p?~IO>@K6YC3GFbF7nx11ek!~8~{qBy4-$#ik=N%_%6Wq77s*f!@V zZk6U=wI+_#_?3oCTY`iNt2qWTZ^n#St18Nh&p}Ms%bsaJEATB^%$(I<0L!2`A}mB5 zgAg;ahZvoQXLjc`zwEWpn0FEyKq2B;En09en-eGXndcVL;*A(%P&k0EfJ^u3lX_=^ zHPUhz?Vr;&!$-9l26wd34-*ubl6lU7A55c21hx*ghB*;HFn&xG%|p6!U(2+r7>(VE-YKb= z34l#o+4$jKPiN!6w#NFM75(WXYw+&uOzg?GFeg5+cC9#(=U~cWW7YZ#SL+H4TEn9U zdUg#P3f1Zd+%#r4tx36MI3(Avj+LM6TWS=R37IJ@;3;SsB3l=TA3HYr{qIDI$qM+V zLrd^)ul){OjDNWNB{x9d<^*pm33$ZFF1VlRjPJ8-k-)Z_#SdHMjp5RG*2ujqFRmQhS-(~J{(7`dxS|xi<8m^& z8leWB7o11-yLI$}Y{#MTr%QZ75Yu&>-REcPqboS|on9i!Qa@A_1VX_W&*-mTx*ch* zwT=xWR!<)KKs{y%p&FvIiLTvRmt{uOz>C0svuK33Lh-l8_R%z1C@53pRDYc7Q{;rx zYGTR7TuO?@VcIif6UVrO9Y^PS1)5vHYmn1v!!%CwI%6_zQ3;m`s;zq;XMz)xS+s~| zLVteq^WR{`CtVIaJF%ERNlTMC__CR4O=1Y-Pied1pn=xkP^~?3UB=13AS0vRp@m6B zkf7RyF(~djQNd9d69$A>iWk{E(rj!VPEKp>Xb&H2{FCRaUrDJ14C%Tg^8IHVztQ2? zRb7xYLpsRONk9EX^!#ss3jpyZxNok4p?_z^*mzPrxLqE5&P-274lktO&TK=4?d%Jf z{TXm+mLg`Q;2jpS{*>Oz;%agCHk44A4k5M&Tr_rMw3bNZ`k z%s|#Ng=15;EN+GA#mvQ6H`8(#oHoR^+?AzuFs`lp{ST$N zjdErb7}XYS5!~2_l(yI^btKD&6Pi{-uF+1{D?^7kv>rtBixwO2hZ_avJuv_)T_<*}>_wj)4YdIA< zvxav2g6A6r8onF^F=OwCO5tG*h~Wd>0I_RCQtOqx^o>TL#$NYA?AD5re+lJRHGpP5 z(+zODXjuXEjH9$ohX$eNSRn}U&=2W+ss=ork97k`FDOwyMy_c>^hO;p<>_0Hc@@3U zC{$f*1i|%!^MP6*b*XujVKz`M#rwDG$*A@$6#R_I#*DIzusMb{cZpuFmQpcXt`D|G`< zgYtFiAorjys#X`YbYM23SAt&(T7&gRt2f249T0M*9@T?)gUmB(Rw+1O;p!PDnUU;Z z!*XWZ3IqBVJ!WsZJB_M7;IKN`qoD)s7?N65;M`f$XCS{SV9{1W=j-~R^A+U%RVj9> z@m}b195WFVGJVXX2uSa7CyYYXAyLSQ$+7jGy$uPs6mGGAjM;ODdv zBQTK^lVHpoQm-XMGv!#i6?Sh}y5&q;!~xF5{N_nX@oXz5R7v7o?qqhRmF|dpXsn)z zc0^5qJMCXKaUH8o=|^ZL>N-wiY* z7<#+3oY!ZkjKyJhBgXbtxVe>b804nLFUqmd&6wmwl6L68;bm%^i^?&AkwqIaR%(6& zT&0DK#JzP7SMj<54(>az2Z^G*ku7cAtt{t^_YNI$q5a46Fz=+V~^iOT@aBj4BIaJj}6Voe7;)mc2G8XfWKj zMlFv=8*@Xd6SX`oIHr@Gc&k%t)w}Q-Wru&u%)zKD%Jkwe?~3-&FmuwOS|t=~#7n~i zrT|L3;?cf%5kgpLIs-WkfPu@PU1V6bCCssRfXRDV9N#PZ${SmZ&GqR?;n2AyYdUec zJF8)i#7=!{N*~>*Rz&i*%-r8HbDo22jp#GaAxq>UMM^wxIXiZwTskaF;VU#fgie{B znKte{)N{~1qWs~N6M&_qTR1PinBVM7=0t5+HC<}r5FYNTlYrFqYE>tJH6$*v6j)DE zrIMr-DPwIc5OLp!BMRhV4mfh&l;qGp$g94w!R{m>D{07~QXMnt1(oZSQ`l~%dKGsg zH689vG+N+c*K{;i(s8O~oIkQ=qh+NU;Se@td4+q|^%Yxmb$!JzM&kQxH;z?KIRMyD zl$`d96JY^P6jZPC_+sFLMt)RZ*y@ZgJ8z#eBBr{LIn?k->o}gvY~Z(`Y&BvpV34}^mF3-i$cFFZGbU*(ML89g%z&hPy#s2m)lEklpf+6({( z_W2DB471NWo{%;I4m`W1omoABJ8DP<9JEez(!av-7?m{%HGsqTZM2qKE;Y9lXcwFy zJ(^DNY7tZ@ZPnj9DI}zws8vt;QOl19lcL&(NS)4)s=2+^S|#nkv$ivxRv8Y*git3= z)&B#Z)P!h53VxivT1Q7@_QDaGJ&RMbhn>Tm%1`s<_1$Aq>HUC;{85h5V|PrKcW=J_ zM#C*U?nzhT1I~9L6%*vIq!{%p*VW8`;VKUcaD=T;y`uqso2#t+RNj~eQsdB2TAv@_>D8y<>DF-5c(mOeVICNiwl*O`M4*wrzJj(ZsfG+qTuQ zZCj_G|2gls_ghz2)$UrWYwfE0+V}Ol2-7Kui1Js571QQ>qfuStG9Dur@%84J`yTGg z|G|IUOpCGziAG7L#SN)*S#EG8;M~l-#^_w(2J!u-9*PA=!SI!fP2l{|-tbVu=DEfh zE&6pWlC42yHXPOtdX8r9e&Sf#B>oSDpkH<~5fA)#Bl93cf6MNB=i5(hsMi~Ms;Gzd zE(?m|;-Z*lp;BBfSx1Z$RXnu>SDW6fqCH`R4PxF{PvzMxWPAtJW&Lz88WF;j!W|qb zw1p$1xLqIscE0%bY^hu%&gG?C1m0(^hjJ*wUEakq)l)h~yqCQ!M5s1`xl9HCv5 zk?H5-e_tzyg_&MF^y2A)d}bsW;0%4z(J?d{kfS<4INJYPo!2oqnyAP4jYQO6GA)~Z z4~F-9bt^alyve(yjm5;R^}b9M-JEI!UKJcgO(3Cu=o}#z#XaVo)6~4sUklgbd&4ym zI;TnT*89Y^n(tqQKvd{Ls8-I|Y{%UcGrkPG9fsRHNoX2Bn`#vHsh=REP42&tsN!D@ zabhE|(L>&MV_TiV0yf~#W@EW%{~kFeii(|h|F>L9YxGGUQ8^6z(2Dx|i{7laKX01O zx$eOqzpp5#8h?&0$&~f3hX}VRU~DIw#iFsvY%Ed7Mr7qAp)P0L0qU_*8pkzFR*F%< zY(WoX2h_ZzX210$MHTxe&d@*7X-CfdAtAi@iFRo9g$YR83NlY9p%@ca4ih0qM0rIqUlGZT#T)~k@+vdT;vvI*%8>Vf)}n{HsZ~yQ z^+&wd*MP1g1h+B$$q$&+e1Bshc#>Xo7;K3ewf5W;Yk>mt!rG%yYSJ`1!(ZKL9vryjLx{gy@W!8 zcrup|x~6)}bSwXXyTY$1LA{xJrII%va9!WCb$r0=A_NAXG-1Wb+QBNBAF+fs-fB!H zI-4aSA(3%j>(5@FaU^pleu2C>)|V=m-$S!CVa|dnR7B_qPz%6cpr|HhzE*o<_=-?Z z$vWobJ^xDh9mj%-2n7pwwQOAfq1k(Zo+nZNrKy(&0SY_V5my$^;?WJmA-%?g97T)m z%>WrTwsB7zlLCvr}0YCj_L zDA)5NX#XRy^vi=4dm7gDQ>S~^&)b|WQm5mGbIexxrc@qhNf^oNfivG8VZdPGhDC`Y z4tWZ_TbNY7pV!9fP}vBUBOLJ8XAst_l|dI|@G4TbFw8zUup+=bLoWyI?EyJ8Os~LdWY<~3iC=0o!TWK)Wb`A)>y{-q>N&rR7&{4C#KWe*8OVfsAh8LqGi8s{2xtD3t}PIrZA(X=&^O8U?VST^?MJ zR5w;Jj{Vr~Di~jV zLY&=|Rgx3gEk}kH&N=|U3colV*?+c13Phm8vax*kK`}o&6%s+0TR7t$2?+bPY_bcD z=(b{uDY)9wEM-Fja@WC-si1d&1y~ah2e?pC^i>7mS>{Y4NBUpd;G?5c9uM7@D)Kka zj%n?My~xg&_s8w!s15W|DItjW_Y9k%6`e3?xW-|iksL7h~Z$Wku{>|Cg_Dq z@4qW7&?5XE@A(87HlJXMr|EEbS8ng1Uq5$eUxAQvdyDvzz7t0Nj`>6Xsb-6n8TQg$_{Vg}sda$E@tQ*l(b!rPG;7 zc`0Y+eqv_*Gs;KZsnusTriK2xAfiK$@)r{8xo#4oj=z3}VPO7edp{lxeGEZp=b01& zPo1J^5F^){E0YkI@(>b9j4cfs;sYppo2X@mH`)FCah9>9p`BoQ6zwJA)~>#s_>L)a zPe}@lrAoT^oyPV@K$^BRiy9d-qZxc1B!COHV>9P7eMpqB4AYpX=T+^5Gqn@!?$S8X zb>x~^)2v%$-YppaM(!k*%Mm>op=TCD*AIpy7zG!TYo$#YOi9%SPC7=P$qWRW@jm31 zgA-$iG1P%pE*$(OF0nz?T+!{Ry!sMrke`^Ikj>#pc2G&IXexpneO`gg&CCRiZ2KRi zlO*8vfQ;-e!NPFC4q7kA?$<>4Da>mxMx^EBpWsXPK#~7hPHCzRqbFzih4rUuJ056C zA`>vqqJe}Cvt34e>K?^;;PEQIufL^MGcX;`8tceBfKfl6BMRhHcX1pBtjc6t=572~ zDi1|azN+XwZx?kWZnnN?h{M&z%f{Ha<#M<#hx%59?U3j3;bf;n6JDCey~uo>OHdij z-Rt*lYOZUw+zm8lnWETnVQQFCgp5?#U2+0Nz<20MlF2&Ooslq8foe-fmJ`%>m>^-@ z@F9!S7!j>)5daZ*Eu-?!{NS^~th08gbO$CB)|KK=$b$m6&hLzcVBb(L9rePSd5$lD z@HPJ8-RJSzj3@D!Ji?0|iA2*sSCp68xTUUo0jau}$L8+XB6{OFm(XZlgrV6!ldGc9 zWOm>48fLHpFNhMXf=WuidqT_o!iUiOsof*7?%A|enAlc}6Drmsc&&u+3aK$hog@#g z(9lAP+-FTErn)F3o80vG5Yt*IrHHYNx-dFK8^fJSJsanLuK%y&g*Exh)+30O- zy+jbPu!C7!!`)jw#h@bP6TP9X_ULt=59rKwcP%q6FWoA&opwhH`li8{cnmi^dKO+| z)MV`J*XsmNiR)hc>%LdLl!36hmwJi?v8ne2LNevj{jBxdAy4wTc-sh{YQr*`wnUye+=As_MSf^Z zUIuFXV==h4&wn0z`w?!uz92H`SDrt^{b1ua7!guo!*A87v+;MOF;w6`bSS;R3}&26 z8G2++P{Q9s*B7QhAkku*#G!*Dza6!r@gbc@*@t-IyGkuygj<)Ty}Fgr&T?T;fGOmGEOA`bE*87@x;aPirT|2ja6sW_IaXYbTQF4a8j(F@A510CLfb68@`71bG>t=2tN-QsyLJ-DbyhC3 z>;bMx?U`*XY+q8&;dsE!349hl{03t_N~bwYzJV+GDZLo3RGxYF*)6A$cRnvW+x|PLgav2Toif#lbd&>O zAb9Cvrh+Pie@YIOc{~vmNv>-mZRNG#?R)GyS6%ees_;-36&0N|7Bz z0S^!!$$R3JdC23rN-P=q4k7wgi4nA)`FJ`EbF-hC z-}gEUSK*#gqDOy=(&400fe>HXU4Z;KHax;E`)|{nQR(LX7eNGFCu$h&e~cq4Oc3Mf zMH!5$4J(%+RK!>N3{2!<7J1QMp$c1$N(7Rq%_k5oR12nys60|XgE)uTJyk|(hBR=GItT2Q zEn0h_ELiyIQD}US=HhfpPHpP`!s6qB@B6M<( zJM(%j6IivUn{lf6zQET@Kpf=!?4|`bn{*AO$P8g>>Xm!WK?6=o%ci0* zcFLVk#a{*-iVIZdUfi$Zzg3vd=+ZMT87-Q$$5H-(Hu;%MwDV9DX9-mVZX$DTdMK;~ z=RY%$z+Hm!9Qa@<&+j_+Kj%twtROc6(VPh>tAKEAMmbrR=+4F8Jw?9jOiB-xzms%D zAUDP#lrKKIsL!a-!tikpEKvKMoYBY z$*E}GewDZ9ep;0jGst*5ZWQ>y;-x7^oCSQWvFdJs8}p2&KhCNsOOZ$}&X3JsTAvnP z20%+LaEam<<#qjs;*n<5!@2{hRu&UB_^fudoyGONrR=W{$#VgVVp|APJtXm>{@_fO zG< zqkFr`S@M-^G_8PvA=~z$L7yu zGL+bB8rDx6=wK21?V7Pc11=@IRc>--d((8M9ChYyUEFlGL!=6+e?to>IBT|)qw+>B zkvL6u#*QU7ceAt0kt2mAgn5!0?+vwlpP+7X*ok?gEd11@M2JXa z*ZY&n%VNI&6l{UZxUiug6g$8upzI$Y16uycpP~;%p}2TguCcgg`9WI{5{`<P_u?gL-k!ee(`x$YdwfAwq`GJAzv<*pi z>AFUZDgGWKm5C5msutoXZ{~+BZk#(9ascIxt9i2)Kq)r)724$IQ z)A8#D{&!+q7-(2kkJev?u~}2xpdk8JV~qVjtlDfx;%d}GVq$%?&mw=5l{!X7>g4y| z$Ry&@+|)LN-4-Pg8Q0+U-yp4-yKVO+Xv52gp2;U9B}m&nmzLGvUC>k!Egcc+1AfGK z{XvJ446HXFTa8*|2Q^91PTFAHr316o$B%(Z>koh`Kg0!u;-D6(P+Y4fX>}{O<}d0D z`_Y`)89psD1tD}a(Zy%cIehqrPZWoDb2=n7EFZQy!9>o>Aovz$)4%bPH~2)Ke*kf)2Xw(tS!u|J#$yae;R5q2TrBBNN243%gVKkbXyKT7io3|YC+r9ZQv@$SJ z%j?5E%4d))3Xjk8zoH23@*0%imVz8DxafPl{U?3qm{{_R-mfPXFE@vx_xOjjxv&X3 zjXF)I*F6-wvOOm2QE3?x&V5wk=K^eV%)<)kL1ZgNS~1XsrBumU`p3j@tTvPX=_sM% zX7fz2C0feiSq&Z!s2O?E=Uh8JwRs}=_#Zjj8|5-1uv9i6*laoaaPtKpSLP@|V zp}oXbue1K;SDH4GPn$mv>igN&&|3zzzb6N~Jp@$F&3AL45rIjhL=pznIR+?8e(Q(8 z!X8A2p$SCl;fr2`LE1i)cEW!JCipOkZS?NF-a;@jY=LNTPOrV@9{(Bm-?*G)ZJggJ zqzbOwh2J0;2M1~hU~~;X#h?*yzZqNhvk)}|1fISm(o6%5_$b{Eg3(c~yU*k(g9ZW= zCsf7F#2I(;@+#11>HM>ht^qJKlyIGJ)dj67zyH{0JML4scwc8Nh_`)r+Zj86anrbM z!JU`-F&3Wje|!GNgpGkac_nuoRX5%P4rFH2PJat51EU}8K~~)5NTZwU3ScLN=Acgq zHAE)WJ*sr)0)dlv^i5?sH7pSmJ?Lc%JhVVu|LxI?Ep-pt_=jnw%ria>*6jVLv>b8G2M^8koXq%msAC5ulb-Zl1 zA0BE-6U$vyphDwZR7BAKYaw-Mp!Da-$GWQMAlNTxjMY)4W4J zKQ|^;`d~%Jd-3OU_#eb5(>k2ImJp-+z-u%z}f7q-@I*0(eRO+fLRPsViR+ww4msJ zK~l+M1~nkXc{pG4BhE;ZSuxD4hh`uxC+8sgWC^zXFLpGTC|k3fb@bnI3_<+QVkDF}}M; z=mCm*e$gevp6kwffZAgomxpyLP?_30Q^K&a*#XRF!ih=2c$3XSgN3o-lEO+GMF zg(7<{f*h;DDgJqmN~2(o;x0VDIj*x&c~S-+FY!DYo{b!^&JE&lRzkIDs{Y$*J|fZd z-|ades}}Z?Z~SSStm%5aPEkKKoB1r-J6-a!;(gV3Q8~QTU{^uOkjJ6MP|ry*>k-A=({W&?y+S1=NgW@;sAk0I6YS^M%iv(f!Nmf zScG>o5giY2JipU%XgZ(-lh^ylKdAY7vh&E8yH=m4thq@Ih)bGxH4Pbsm;o61jR)KQ zv@NUtC%l;ox;O?~^*i5;8{a%LTbKEuqWt!7vQ=PwG>;zt<@#rr({5h#OZn5WYwgA) zx3?>UD%xwP+MlB-GaXEm9^9vz%IPW6Wa=uk3k(ZPQK6VC#%bv7T8x55vKqM{t;hp*@;W`ZaMn0!nuqs4`#V; z<5Ki&mV5Vv-kq~`CkJ90=NdS92bXBUU(RhrTsalLl7348UM_@*d1a~}Jb zD>mWQ=V!1T72I~!ukFiVsGP@+u+K9)8WDxmU%kIb>?IneQtvL(%_LEcDQ7+3WsU~q z4{UVBuVgg45PEx;djj-<3mf8%XRyD%im;e6m?euyi_EQAd(u~Nl=_BP*J=L#2(ppdbV@*_LdACq%Q^MHIS zY7$N}iVABo*5ZY~Ap$M!6j}c39#574x4Ma4gyMOOkj4lDQHYmPxKhA=5+e`D!Q-@) zDeV+zE0IZvy=>b9nYop>6;mEEd-~X~*J-CVPVK^;#7GYPJw;owp=G+8z%{W?$3&WQ zXKmYk7RRh}>G@MumXJ_yi3_RyoW$eA&2QE$9y*H^KnT9trm{$@dHwcJoWqY-kKfkY zxoF!FwUXNicX#W3LUW0uDJz39X{7-vLtXcnQjqp)K=W*EczPIy^FbG4nYU?gcg&{z z?C_B3yrX}Lw(O3m$;Iz=5b2_ep>ore$3B)XSjT-iC@8X9f3uO!?NZV^#MLlFRl#bZ znH>dt+;llHL`TC}ZPR8lowt)!?Z%;%$oZ%vBA5`coGa#X40}p&TttRGE#*q?TR16n zJa8E462F1?UjS<5y9dq}!_2`9u%x&!)Z71DRAC^_j%C8y`okTTX3bnSu<=c0}I$Sh^$@0N0Jp9#YzcBZ$Ewi@B3R)yyz`;d#Z0tr7CV`P&vZypQ+FjAZ$Q z=S7e?GQXXBH9NsAYVNgVBJ@HofZO5~*oYHpcCCG!kwMj1-a$7f7p5>2)bN6REGi8a z3JXV`YMvmXoR}zsXGl|mP3A!2`(HA3z(@d-nGMmZ0>ndGu9Hzn>}`iub`wJtw4HHS z7;4fiwu~4J!Yk?93|!=U9&dxUa=XdhrEK?0x><4uaW~_eAK98 zHg2!$l z&TJ-sE;$vP_JlitXH3(FdqAK)*^YF3M?yyquP4HL9$aTp5Q^|^IEP?};SA(6!Fyai zQuze@RIggWHdk%4SJ}gMc^>{RE@tXg%NBQ*>in*M^!bwll^Npk;#nhbU8pn)phR56 ztBL%>r{dP5l)XKbb6haCft+PWs(nasiI`=s?{G-Y^C_A6>~%Z8E0jLrA*rNPf5qq6 zR#o=z)q)9CLj@QhU=r<32h6^wIQ|}Fo(yfKDwU=1hn^4F-6ve|zcL|Jg;*n-g`cSQ3O29I6qVn+;n(4!=~uWW&+qlR1$3J$d_8GwJ8fZu<^ zY^S>Tp>t<97Rcgy^^1u(81PQe*xJ$n|BbpY)@vy;Ooc zd}qOk>j4MAKZX~l2qN9uYgwg;VnJ|_gC%!Yvi~Lz&;5am7nl2k+E((lj#5uwBF%PC zf?VvXNB*yeqku6QkiI<~B9)!4Ul zj%55S7X45Kl8M9&Rx}rZ(R;~lHM)81ls;Q@w{`l6KsrxFh+qSil#i;^V2JYe>wxo_ z0S9<+IH-`m*@5t%)1`leAOyc44X4pHhjSwnO2#lyvk}(2H(Ej0{$TAyAIV%<@4UFS ze4Oz-_GVD&;Za}jJgBAluy(2WmV7W38l9#l*JP(>o9Ttofj;+QyQ0;(ps6QTeX}EO zr}Nsow(Q>I!2p-j`q~Wam&rW1JMO^Tj3it2SN%B4W*2-ebUHG8#@RUV)WVk`r&Pl5 zh^qqKtXGH4$NqvD^0}NRO`UYI%0BOcYyoth(ou1fsg1Ki#IdyPt&>EdGMbYk4Q4Di z+*B2euQB^A9t1dmhe;mtXxzYP<6LMd!mkzDS2k+6E@W+N;OVDl*21#TR@aV1 zsed|<{9;k-yvJ_{cAaXV;y!`>9?Z-De^FcKVTx~z06Sc9QJ1H=(SfM5Bv4J;3x8>Y zHx1PVxd^TSJ%lHVz<9omWs2XcwA@}rDnjQw$&5Eoa-l>OVdrXg*0vzzs_#W_0_6Jr z{AZ-bgP3O1*LvSsIK%tb=U3m;LIuwwdd+EW`u)kpb?o)Y(8O;;+l?-dqK`@RA0LR;iNxqa_$>;!5OX$GkUC}H0>V$7@be%OWA9$>bJVs%0M<@JNQ zW}8u8p!pYZ3X^#hbDEp{@V+@SOp6_a4~#BD^MEW_kM|r*BUt88Um)NLkE+46d6`PI z>qwOEypx&qL_V_70fA*zu{KWt{_1}B4BK~xl2 z>a)Ad1$W;B>R?#EKf>PIZ+`Gvlr@tj@Mbh7rq+T_2HyRlzoGlFu$9q@&r|320-cwB zP~4mUyA^X>6q#_R6<$l=_NP1cr7>13tGL1iBv1NTt^5vh0DfAwO;rwOh38pQ&z+!e z8C#5lFAdo2Mh)?L&G@nKyCllG3lJwm>Uptf_Y2VXdy9!-nN1S5G&FW4q(t z?e}n}-rva!^3NNsd6R7)!g`rdzPeCnM{SY;2H*0I;3v}03;Dz)HfV4!Ob^;j zBS7Y{K^nGAok89aulJ1djQHt6#BYDx7UUEah{;jI%W?bZ0hUH?_>DuiqZqP=Q$a52 zvHC;V`zHIG7nO}*%q4Zv(Xs;G!r+q|;OC`|-cwTdMTTZHu*~JF!R@1?`JLXQf~Z^O zHXCooEs+(r97u#E@73Z zUVnG-8>Ryrd>yu`6;~C<8W;zYjwC(DN}71|j7pBF$i8Z@9OMG^WJ@XY8;^%Ek(JaS zi-jM85o+}1#ub~=A_6sn!{kJg;Fvnu%h9@uZSN4mJ!{O~(q9U^ZU>2`M$ z{1t7X_f_Zgg1%r-#eaLL^N_?b+cmk7z8Ss6ncQWgD;N~$khM8y>Bb%k{(igk80iGs zIGP%)j709-x^lNl{;1^a&n-y#PWCFmfK{f(lE0K>ltFn2nhYwEq zPG=3E_9O2O$EGhHrUALns6x~6oAsgs(*QkZ?TdppHkpfnUpS&~SxYJwBhM)&ZB0QG zk;l?1sW8sqABiOJj+GSjM1%*KsABR_*wJ!o3opdOjs!S}4ViMy-|`MTWzs)3(XR7l z^}kedJHc6Gi^G|{;%t&R1dG)U+qjtGoOkxzIYIS(ChJ11JW%4(q9zZT?)CW3QQ0AU z>=A8PJMg8g>?P!ittBUaV^X6`d%(LjJOc9gh^OI;D}c1$Bzu@F-2bpxkFz@aCjhgB zpF5MJrhoFyYBQcVUC#zUOYEF9?RIoG*oY^lLZYb-L6L&k6dk`41_N(AAF;koR?>Ik zpA9juEPW1`)7{pGu7saV`HYr}cuNcWtcJ8b5z>LSgc;q4x=0fNr01tFlRt61S|Mu) zm14z0GBul7lr5fX>t1*P2ro}R7kshI-CJqHB zCN$bxD$-Q+`Uq)xg6ORaW~;rX!jR%|Yn;_FE?frZJVh#Y-3X2Av2PGuYvonc|-QG2i4N~`qRY9a>m%~eQ3Olyc^X1nH;bNi0d@=rhu zO#DTn+uqYCh~6bkqs%NMPG9O4rIqU@xO(EPJg{qDkP5rW)=f9YWKx9O$0u>{l4#hr zCX0Ma>|y>h?Cip4&Q72{G!_KgWUyyR6|W7y#02BOt(gTAY%|`-Jifsp6+Gj`Z|6%^t74y zkZCpTxsF%`|{_Kd-mAle!9Uk@@3qwuQzOe40`f^*f`7rHLWS z8vl_2?U2ze5-)ahG>K74rghO0PH}EoNY%5&H3s!Om7dLL;n4#epSl9sl)00oqtKcs zFBf=dL4QXlimQw(--M`)>#_J_>5q7UTV3hzIi;yTMJPWbON|>ttY~n1H)ZkjCmvUn z#No~Y3V&B4Oe+>?@0y#6e}-LIbG4YoYP#zQA?8p13Jzgh%+!r-7(k&2U}?c}Jlt-fIR3;x z6{2dRg9kKfrKaO<9>`5TpE1D3&X^Ko{%u$_@ zuu$UpuR5 z;d~?;Xo=+O^7ALmBVVgTZgp<)WMgyFa&ST7joH2)2^Fi&^&lfMl?qM5upa z?bHgwnR4Q`Mf+pagB&wbn6C}{bwQxban777y30*ai#2cZAH6d4%yY zUd_cmht%IN*uY7qSR>bp2>t=Gag zk865(PHKKM@I06R4uw#KLADl$+}Uk*FK_ZKwgGs;4v1xrI_j4sp}y34zO0>s;_j{Q z&g&=HUtf0Tr%YZ~iqBULSM<4Tw%!UlU!ES_^gPq8GSP`S)O;+zK6~1`>KYxooV;Nn zgZS>;FrfE7FDfaQ(zAV5wYx>O5!mjvl;$Od2pwacn%V7=cv3X4YkAVry6n}Qx7QJM z%$J_Jv-d$w)F{(?mUW!o;^NJfsSKjCoaL}5#Fq}Yz*Ex zb%B^eW_PXxmld;`r{cr(Aq)HNQ33|7XO%PSX-S^2#%99uH&!VK6Bn_|>Zud{XvRD` z^xjtYAxZV4nyL!{PB;wrr#8oQmfgl%L#t!1i&-PSop2k=bL3~4Dl}5pOsrtS5ta4s z)2}3{O>mCG-aPat(Ha0osU7LJv(fC%11;}?5bLe^MQ{MOlJ)qSA6_!7p@OHro-wny zKWwfylGu^hUg;rn4Hp0dH%L#2=R}K!r-n6YtYSAe5j6}eo4M%A-)@z(>HHO7b|TG% zm(>aUe2o$`tco#6K#Fz7;EQDe=zg_l7Yy)P#d3`moHFA}k_EkVY)kJ#6QWRQ`$)wf z-zDlseJwKnt2~~0#H#K5H)x-iR=!qZHgL}?QyBX(kaYJ7P@-<;U;r#FaRXL599i0^ zFwC!yEl*l&+%=r!&W^Nj57!EeDU@C9=$) zjvC(HE=8AO`@y9#W;9J(4KHUBT#m(dCbDXCASFkhq~X1(Jjd07akwOf|C|U#ND4_y z_Mt=XXa0E@M9*YF8f@JnNdS^c_j2$V(3;yN*Ku8|D8u`OaoTp~?2i%Gx^nRu5M}5Q zxs##c(-wJfwUUyjq-Fu?8-U4RoE=;`4ioH){FRsHMT>vpbdv#a*Rafz{$NyMN5sHCMll zn%3oUh&L^oe_yv}=h2QtQp1 z@wlai!_oM^g%<~WEI8dODsU+a>?#J$OR6J+)^Z?Ti{!~4 z`^7E|Y3h+fPaJ;h>o>(3YY@Z|5uDZa3vqbE8s}H#hNdQOLgmA5mlH&r3Tp3H+hDND zDUTsdKk8_4*!6!Nol&zGau2_elSa? z-JEA^5VX1o>2A98Zi~DTEC!EZP>IZB$?-{R zQwnXQcIy-|UhAgwG$U&4e(8AFCsO(TE+=|7CWS_y0o&p(7c@yKmyEeENQNvS+4K_M zfYy(g18xI0YSABD%htY{rZ{o>Pq)k2$Tj#ZCDX>$RevTfB3Y270~_+~)qJ*i;oXd$ zW%D|;bM2RIP;PaY_|}C%GjkXtw6!|KBQvF9>9+Q~D7EX%6%tQ#K|b^g&4^{plPt_$ zwdJt?tRJ3NH8{eCPQjJ$cf0I0un*(58D~PoIJI9hR?MHivui((W!0@H&iv7Ds}Q_x zhG4%1Yq_w^4?_-QW3Tw=q-SqjX}|Tf*N9}fiD|Yrth6=Fws|(S-rL;e<7XDagLI#L z#OVJgEF9Q%dUoeF3nfkEQhc5ZysU!s4UZ2`(f|YrAOz>A>A1>WTq1A9QqJCA&CcUH z6(^6+-{s2Ys5eH#7J#Cjyo~U z4u%g=6*sC3`NK?%RdzP(h_Cc@fk(ti>Jx75f#Z2b$ft2~)XjFY9@98$qXCyTllM7i zh08Dvpnxcrn~=hk&1DFf0^0nkG3VFIcV_pH_%6=K;t@TIhANwwX1&)_ zl?lr_&YX5+E+->Z%p`@4U>OxRBrYf8Xse+n%Qc0}nWnt>k%jt&`6$$EF}{xuHTyMM zGXT(H^^CUCGuyRF$L{md;OuOYr5-DfCS*kwcXl}gz>WDkJXOP;2nQZ_b4!W@->IWI z-xBX9uh~?LW;-=oO>zmYje7#kXC9$#p)S%RZWu45>~LMCt;*7mQRt$M;%;kOuPYr5 zV!zKK)_Ny4u6!R87p@sUHu}eOE3mMPlTg}<@u2LW%Tyk-i;D+ehpbWH$niJPy{jr4 z6OrkZJ+GN_6J8J5$unCMq=3HovB2@3omYgs3FjlBl{KaF;iSz1_2oR@&VI!otF!^JoD;|8-@&1 zN_R_-ow@)RY@P2zeV<6?gei}8zx0YRRzxo{Mj4BvOuPvcGbJ6IBkI0E*t;5sP|}`X zNFqP4n(@nr;;g9=jvQJX9dm<@d*CZWrv}K4;bml*K?_h-9G&DAyjC1h*Ot7NL9Fmy z5bz%@)K+9kxR8oXQ)>A8AHTfYdfDiMBpR+Lya(vY9eGFG3)Sq`Gis%AtK8M*CvnHCzza5E@v)L^zPyS$ zKXYRMhV=A%g#$W4%seXFf1gqB^?WV2_~t(kL+t|lEIAnUPRff}%G2zGnnh)|{6=c? zQth)e2`#A{%Q{_GJYOy9`bIFFUZCf!#;a#$AILmnNi6EJ zN^ww@MT`4KGa~QE&$tZ*%G#8h3DhI;S6Is@!{yV}Pct?*eZKW9$khK z#79S3>eEFSN2b<s>D2Qj9k_QnOwiQPT*;%Lw|03YwPp?YITXd3by&* z&MqCNoQCK%$@AkT-1H00cvS^LgH>a%&^F?BEYDcrT>j$_2xy-mb-uZ(X$wyo!gD^V zC_7wzJ*R8PB&mh)mcYeNAwLLiQSpzulK_de!K&b(3M>*Mqe=JY(pufx?oQAl_7eKO zXR|y^kMwyz}W; z0oX6TeMB_}^H4W0{|-R@(8av+YDe6QIk;@ZqnN+bay9(SDEzfg+O`KJhrD*NC+R^BQ!nbX;BPszgRfb?EjG=GI7xaN3F() zX5<)hIQ!dLg8oaV$LL_63_AgVw}y`m8^b&c1Tb4hDTKBGRd*}jVpE?J>7xO0rw{S7 z9SgREqD7_|RTf7;G;!l)1%+jhz~|#nJPqHk4j0g2bJde)dah<_>JspdwlQ6)3l==P zlPxok!+htS%p^R0rL%aOyi3}x+x+~=v-BSq6$Ew&Sw=WL8JW%Jr(bXKBjY#ntJ%6_ z@fr#}HMKYHMyWd^%2ds$mb;;ZI}LP>%^CdjJTH>tJ(!}GvazsXXIqX~0R(rvDxt#O zXnAY9%SXcB404d<0N)({s+-~s-)!P%!)>YCZFmI|gl>T{7bac7S8K!0tdN1NQdQze zyO!rmla?#3F-Gj?a0rjf-wfjx0*lc;oJ6jOt=j9ID;1^j-eJvrXu>q@2;@ZIaN!Z_AkvgA6)!Z zw#xCZ>CN-a)e4i*X92{Nt^2ASF0Mh=;Gt!=w)_0tNEd_N@yohNl}}xx{K^tY1aglE z>w0BAmjtB$`Zxt&+a9*941az6K9~vAMejcidDIP%M=Jk0$!OQu9UqbhfmQODhHuDs z^E*ibF4di-UKIA&9ik1rNd>o3RdGA*6XmWuqhm18R2^6=&Y#TpnV`cW>#4;FDi@+{ zv|Kd=9HbHR3XG?tiXBEg)*%x`k<)3D_wIH0Wyh~F+P6O6Ci6U{JJTfH1brC}*(K8% z+>UZjizy(B;8xL-a@DZL%TQ=0)zY0sX1>)$-I)@=wUx4G+*^?Rus9pN(l}$wu53@% zO1AaDo@xgAVhm_Bs#(G9^3rqbd_GW0i_%E-C1Jt>0HD4i{9mAtYne(C6w=&uHz!he z+uHo})=*KQxNhR!*+!gJm84Vof0X`4o@%?z3Q3gD1s~d*8%3Q^2uLA>JrZ>>TU2g= zT0inQ8@IHY9?2voda!k3LJfJznX@k+x{*sh##x1$biVncz2>CP14YzhW6KP3;tv6s z)8EU19r>{ndI07jiFZ~W^gv0eQAIRO3Ii3lu^4oj6$nQqM+~tk@{C2oCEas+{^vkq zJXfSs%r(b~)R7FFaSIN5T;xOMU9M40H6pjE+#mlCCdef%zHsQxg93CKFR_rM-ul~i zmDLa|n$#0``Aa_RduQk!49(af@aClJS%RYf+}pCV=co5DVVx*O)|CezKK#5o;ok3l z-j6VrDW@9))b-&ZSoI}oNnQRQqTV^MvG4l=t!=xhZQHi(c4}kVPHo$^ZM#$3ovAUk zr^d^CzQ6b0A4&GPIk>q=&OLkYwbt?Od7S)HueUGGFd{nH^{{3tyKkuXr3}jJk~s@Q zv^$ztEDN#P`xzKJyI2gg1pmagaeJ&Mpj zt&-2YEoC9H&(Y66cs6EUgZxU-#no)1+sBcaZH&gM_$Sze6Ws{i?P()161=h>M>&RmdNaZ-%qlGNM3TLzIoRM0eXh2o%V&IZb}0_aX7W`uwDvE zfC}&vIlE=Jz7z2A@U@s^dIpBCj*oVFW;hlb3|1fsx4WLQzgr0Oc)5Noul`(IO%6ZA zc6`A`vjgYFegL%n{*Xa^MP-cWaj^hZZ1JG~G^+0sEBX2B9Mj*Mf&buix)7eI@6$s zV5R_Z9&s+rT8zviBr|8uO|r#V%@zCH8xki=Es(OoeX6hxXY<)ES0e6nH#w@C*=^)q zdX58T>#d{jioyREPwTee{dc#Lhj;IDq(1XigY+)RtHLCB!rW52?M2$gc3^VMU>LiY z^8|0^uiExqd~NjkcBt#&s?&GPrMLe-b0mSb0me|TC3vIhkZ9I(cz3;8+;4B6BbDyu z|5oY#*DWm?m{I8Mypubh{qU#HB_Hg{E>G*NSK^q^BKE=!L@+ijELuhE*`!|5lC?D)~w;8JzC4B&VADUEO39(vlnLm?n1gs!5a z2OR55Q-ZJbNvR|WcfZHFxu!!YFvl`rHfifxAe~Tl1r`^|EqJQMGZ3lVKRg{D&D6%` zXAy6a^8Tt9djWInh(`~CnIxKlFKSqq84^B*yrqrIC2HUze-DK0KbH^lsfDZN?Ic@D z6%l=+$8UD+B~mt|xI96MAHM{E?qP!Xmg?j?gta=IF7k zL|A18WzX#tjnlz{X9#W3U&JeygiPO7Y_ttB#QV=1D=M;BuD9bJ69!i$muVS(^0+ZjjM#yAo?y-*#+nu`CU0UtDJWCB&^qhBAggWc>TNhd zZta|?$4lg%x9{Ucz#wodHw=3PfRx=sf7AON!hmQ;-`2PH#m*Jd;O|J@Y>aHN*F|gn z&4*aq=6IWa&yM~N;k>o0d?xm~0I~-mrUs>j?|&HuX2u8aE0pCHve;gKa)oH1?b2Tb zeWD00^tRyH9sw6dhtkgHXQ!*L0@qiNj+NriMJG165>qCQapA(a`VT{%;(HlE@IC!; z_aqdd6bS&U2=X2nWSc*}4;c(q>%2L~BRC%U(As7t_= zd(DpH&xf=b;^OX@aoWsFj*)!M`G2hCf0ei7Nff1;oI|oh_pJ$oYAhIaAQI$(nQG)3 zihq$G1bD@-Mo5xsrgJ8*T4sAk*3eb6hDUZin}94>VuW3(pATw{r0s`T7L<4E?9wT(VTLUj~Y72+6ivCMK8a5pkLSa*D)wc4;@ti3NRreQrp8db?T1gK2RB3R%#05w z=S?t=zaZKzcy+>L$w=hZ-xiO;!oFEqk+ZOivlM$A<7nv43=ne=5;`wgx>>y)m$`nL zoNvy|-o30Q|G4bVCrPKD8&3V^upR_%J4}~}leTqCEv zFHM?ce-mjY))O0hTpHVFXfsV|ZQfFs-rbjInGWoE7bp_x9-0AfLSE~Vg%PfFSBIt> z3PXVVh8R`cx#0YdT1`i0*(6pw@=_kG40g+8JE&+P_u z<0SF$5SaiauT>sA6HfGw?lz)j5aKvQe!_*#zAtkZ_=FBY(K=Gr_iLN;)9(vLUde5# zO27zK^cBaWJSxlTxRKPfSsBMp^@Ltf2f?=0DG=g*;JC@PswPx5V0!VFQpE13a!E5D zx@zDS%aoga3!8mB<4GLAr5Lc-89P}a!Qc!7N0mM>UYssnDZz{@9EvV)e26MvvP`PY z-Rf0RC0u?zge6{P?_gUaQ%yXNyI+3Jh&m9N?~df zw9*y8mFxFfzJ0UEG)F0Eo`9(sI58B<&vlhxodif*rl2YZsys*$M&LPHou0}s#?v-% z!_s!~ygd?xgf$#l1^{eNabXbR7K-|c1x)NiI}%Ngs03tLKwsQg4TE=wNupoKg?Y%1 zs5IE_bVziiawVEc(>Az6$UB{3L!W)O8feGdTs7%OX{eLv%V8!gO`dd9!_>|KqqlXm z$}UPQECeUZ^XTt($F`iH*kc%RE=#{rijZTn(GqE(|WRKN8Ho&ny{w7#N zbwpvMfCcTdrGXB9mq}$GAhZON-r!vz4TyGFCwihqOS+MI< zXYFyvA>RKp1(1yaz6>PWab?Y^e!2C@NmjsHFnf`*jnoRe;dJcjvt{HD_~c z8+mzyHhZg+le993kT>N!o+k>8Qr{NC_FBkZDE-?WHto9zOK}YgzkETu{UTj7aiTS8 z$v%<B8v<3A2(1jZ)Q%s@*N7%5`Q`dUD zIoSVSsXn1PGx4tT_oSyxGoU%>%4QVBX(RQ1Ra3+d^0H+N#pxy0HNF?nU(~j7fYN~= z=N;V)7%j#e85fGC$PC(Dl()d3dX>P9@M{EFV4_ugkYh#pPz5bAQq8eKl_E_Bz@dCJ z?Tbfq(`G`b1f29!D?ZQxYsdm?sHB}#^46RTpzvSbs5n(VhN}P3y_p`CQVBW7riig6 z7HlV*w9N@gKsyp7AHcCH%;w5lB|z*_!0>iPCm|k+5XtsUnCa)ztA@$Yk%UBZxKIw<4G-ahB)7lb~1p zC}Okrk@{y!{xkW3Rj;FpZ@1*}b~NICZlM>@nj_Pz`cW1hHYe4s`zRe3vRyQ(V)e%1)^JhsNk<+j$2atwB3V#m$<`uq3q(~9 zCVKg~p=}LLr#i|VlZ1)taUM17NjG^TLu>A>nPXjSYZVH7R$5{WZP47$RYVaqvu)#{ zvIH_BKQZ-t#OVMYxXB}`3EwHwITvUn3=YW~G0Y7oLX}$Jg3^U)jNx4BkDDT<;mC2+ z%!FOaSkB_ASl&s)S0GY~O6a&7e%b&$%oRY@QoJd~R<#L7km_iRqmt?mZ}6&vcW*fm z6;xhV2u!Fzys42Y<01f{GANmLY^-p}^rXDPXyTwrM(Qc%zu`lxSw#}X*icn7E%!F% zl`-~ohP1Jhjs3Xz>$G;sYxLUa4r>cA5GKfe(um$!+v_T<#~&KKD+H`cf|6r$z8VO4 z?AUb#om!xl+)craTOk1No6$ze8172|Sdtlx5exI>6>)*ZKG-fV6tRS|DpXL57ob=I zNm#&CeGV5I+#TJ?H&F!8bR!-|YK+70Lt$g?)q6dlff321xY8Xy%|VlQelUz3`#eu7 zH&fk#{Vis@@f>v9`LU9APG=xe*r zgRYdwnVn!MNoAYqt-9GEB^Z~0QOLAi-T5mkxG4R)qugjRk;tEkupv}AthOyu{`bFS09G!U}b@2ACHj4Sqq1>FTjW^fR;^Ifyl*zX3 zYK%_!!TDs(p;T1k7g{fFoIwJQ=Oon_g}uv*Ku^O)vcFp5Ji{WZVSlKK*$^B;X9Nn& zhNT;M*`SxzVOBdCMO}g)Hb06i`Y0nqS3f>0I;d6*xXjoQ7GAxzVX8R&SyXTvg^|Z$ zm{{LbMLtUOF8k>x*S-aX;=&)!AY}2B`%!~c{%?_+5iOQ@*UVj-zq0?3Yi+xyz+(A# z{eK4z9!j-7=~I@{4PV&e|2;SB=3FgF$g2c5HFx|j*ILtZ{&jc~nFU7S?Q`vwC5n)JexMzT5Ji^2pwH zgA-Etb;WRD#C?~^9syE()o@|M+O8Q4x839`DSy1GNZ}M3j*C?)n;mYvwutj2un>{T zCJ8L4h)g5_Tq;u80XkUiK}G>eqk|^eS6aJX(dT z7DyB;CiuU&acd+YV8Tx$a!mQ{a6hQR zu4rRA(~=^Qq_1FWnEj==t?5gdI+Lqvd~Nd7G@7;eYr&x{0J7jtYSIne@{GWFs+F37 z(H1To{fD)3To4SDk1}n7g)!NTmZejVKDoP7{z@})Lclch_ppUaysZ2c=G37fWAYCT z(>ugQ`MyDmJH*tC-&AQ6zWS6;l_Q58+LU9R@^RH8hyD>3cS0TVpW(np*i(mojLC1n zMgiKC$WEF31!&38qpV&DQ->m{8T{mF6Jq+5$iU{=rkOs;Q-|5KEIcG>6R?cQ=(H>^ z`KFogN{q>0m1xPyrkOd1tUN$V4QTDN@|2<_hXXsxm^w58c0`&sL8ea`Uomp12ka<% z>QE2ZyiJ>O=a}`SO;#SRTTkr2&-sA|rn!!YugjkmqcsdEf-UZM%G0`lB?Mr4yvAeAS*Rwe z`9oY7jj+C8Gba11L{4Y{O}O+4Ep^koe@B`0DZeBrD8FdaCi-16-+{eL*3-F^v zDHv}CtD1p`5F8hAL6GaitCoJwFwuycIge|2-ciBePXZ@NJ!!?0))M;<2KUB_C;o?L6CBvyG4D@JVsGA*I>bjinWCaWy`m1LG-9gAwa`bNehrl z!|e$(noa*Mj|~*AV5@{{KPbj1E4Yhjg2;U}^O{G+#uAh6qExBc`4HDj$CE^pgloF{ zgbA7^A~|4*AvKlZiS$t@GR3F;*2D?8^b*5QUu&^e>=iB&_Saz!OG)bO?AWE z=ZP=WDrE3!CxL`>EW%1vkF{_7mE=s&$zR(Q0)#$TvK;|r>`>Kcks1H|)EiH@+9HB@IHrEFx;5|hBuGq6%tY`-AwVmm_ zjeYLZVzY-SQ9Rq=}m=ixZN@mc3UM4A|9-^3AyU#3Aq?t74ejC# ztnmdUT1^cEc)Av85kX_n-&EsqDvtoXA02?kA0#!3!IO;(klJqf4qQ143fd_m;bJ6u z&k@I4-J9O82CrH#?5sfoM_OAv=9xe+=srr44Q{$};&1RS*uaD*7ggmOnljO|Ci;Db zTnr2eZNVzWDbno?84;C`qwgB#UdupI`@TXLa`0R;Qz`R8QEeDX~zJDvmFbjR1{@-WToO8c||1mY3@LR7#EsK?itNih-2`9 z=}kjDm7E`Q>dEv!PQ zvwHkcP`7Ci0~z2?U*_2#44BT3`E=}UO`e%SX0!JsL0#*>A+8OghE zeh=0qjEca@2_g-5AqBpFK-pqI81XGh6 z!J0a8yZPr@V6w_c8;`3WD2p@r-I{1FKr{oIaK2d_W+Pv)7$atxK7Pw+N^S-{F7}C< zAXR!(nGXSk0V)$&K>tQaK+BJyMWZ-HN`RfAzIhM3hd!gA;dC6Lq5eI|{l`Md(e{Rg zV(b+c?^ChaA$P-*Tu``x{l#0S)f`p!60!<`_j}N5h1g{7Z zUpaW{*AHxUsWr-@YyQs5)z4fgR9T_t1Jr|jmtiK;ef#Nseq2o2L=cv}lfUil(%0#t z!@m+v|Gj>Nd35Ole4=lcb9BP=l-xt#f~&JsXV;%e0mtMSc16ieO=<$Xe73_nyF*;(ZVMEV zm&f2!4q$$~8`e?=qv3{v`xv_z9 z(Ef1q-8exdb)yjGmoqFG$;Np#N>n6GqWh7tpp!>Dl=X0z=11h9TM*KMGvbP<-jR|K zmg&3W6zLI_L$z1SfqI$e8^_lk&xj3&t^^UZL#~s!0=FUM0h1Pj6tScVPAJPizAw7r z*Ps)0ilehkP`3TbZ3%V9`Eg%RR;+I+Okr`rVBwI)hA)QeAOIu|eY!hlaBHVTCVrLg z>psG(MaRM0p1g(FewmCdv8iO_!NO~m0La3Jx5EHyGN$%O?(L@%Gr3EI_S=*O)LBjc zqXPqVxq!%3FON!~#K%1^Y2X7^j^6$6%;VQok@GRDR$f?3xK(1Wd4gE-1^VPx!7&47 zd*S8xE}h2PZ)~4-Z$v(|LEGi=3;Vu3r?p#!8Yk(kBiGK%iKwxW)C}1S{w%Trj$!MdfA9C4apY)w;PLi&H2b&o z@e)1vKggKO>*~gJ8_`$O(x%JY4@6^bCJYQFoAB>q*qaz)T~>ytv(4XDg+jwG zQEmK3Lcwhs%VIe!?>|Q$k7*oV_#CZMXKMZ@By-%!wjCM|WCFBtrX?JmRjr&2KygeK zg$8_~I|#oUwMnln(rVVm8Ts4p2#O@^t#&I!S%x^%?Z-5`nJ2whcY1)MxqoZP*|d`q zo0~Y*u<8P)cseVYygf7nTSe-kpR9X3-A;&2`}zsyiqwF(eKI@L27ya^u1gl{=v=%5veaKRaIlVPbG4d?oz* zEjxo#QrkQCe$@LZr-}Bt#Tl8{N3uKv)S#*CH0O3a% zhCf_~_4-zH``0>eB_5pyNGnyD2(L(h$tA{Q!j}$s65;n`p;q3FI~ZQrEImN`P{eAN zM}4OsWUYO@@1Adu%p-ddj119e!$x0lnvOvT&q6%`Hw#9~B^u9Re75|{8|9NcA&*nW zdh`JGb3anm5^)gxsJBni&LtjRggW>jbCwAqPNZK}m@yKuosu|1Nc|)C4K5&zCFf~w zzAlPkETZl2q4)VAnJH@z6EO#|L7eIAC8$_22fJ=Bt1dbxf1MtprB#PFPjh5rmPwDP zsu(zDjys~I0Yz_ObJu}r_9NhH{1E<^zC>z%Tw-n1Lw{UM_7xoyvXgb{pllZAB+6wu zO_G;0*&JGfX(pq-6Kq@<`0W+-E5-UxXFQ-#$FR)_+k^GOabWRAi^Xl@)ZejfXyUM) zN;#(&O<*pyma4yY-4AtC7<8peAiFMNS{- z(ke)UCg(Wpups~{?2j_g@Yj?w?BPcolPoBW=Rvh){e_e&2H}r9dAke{Ic@nA^B7S* zuACs5$B^%GrCgmVk6u_@v^?w`MTm958ZJz;`2mH&$S(oP%%RX0ZT|u04Q<^kJ9~6% z0LN8s+>7%~>$b}r)lrY>PM?QyuC5&A~MRsgK?yG6LHI$g0W zQCjY4IJ4>0E2v+e&dPC;THj$p((CV(n?IVcy0UToaj_okaq!?Y!fpEM$FLBaDW0@i zB2$^W+%Sr)S%hxJ*@ts#rC6*Q7E6_yTIeRDIJ zwZ3i=_rmbE?OgtV@Gh$azB+qT^ad4bv@&l*tiGRU-tRMQA4t{mRd4sY0*8RHrY_79 z@~(H#oEZ6DZ@&T*5G7M7{`(4A4Tg|p+Vgt-iywwZ*dRuWT><-m^&MST6yzb0VrfjMGNYS29`5$>`SD5At*hB=jI^b;b#{0;U17T^{^^|buWO`Tf} zVSB=E=VMy0b2Qg@+`7%<90@N`&bmjKLoqzNZ0t1Y z^~yp!%5yt7UKLeJnbJyv{*pNiQYum+yd`274R4PW62X9~a({igMr3l4M(vS@2VzO9 zm*h)KWdq(j)zqsXMRbKSL`B|R^ySkK;;$S{i<)(?mr=B|tO8f!0THpv6BmP8$)-@g zb$#)hz<8(IF=}KzwQ%IXyTfh}&4(|wD!M2Jqy~xn{M;@d(&SE4>#4+AK5JTR>%rFh zDp0SZ)5Yt2!preR9SFBXy`M;6eY{cFPbgKk6~0Ne`SRNg1PVzYw8)GJcL{&~q-7~; z_4}yvJ#f8#N3-58g6>v9O8gPPu69O$!$CbRa9y_-x4c3#;qG1)Qx`TQX5j09oQwHA z$dRhep9|@iHq4i)$lEASH;sOyq5};#-PLlLQ~nQ2&LfkP5v+^Tl1pYc!#^1yf3sRj zma4BSXV+u^*)gwJeT#ZwXT`^`y*XsJ0}mQ;;98 zT;rS5a@!#3CFMHt&H$p>jMe-A(*?xa z)!T_kVKQB*mB{CasS^%znN%1i43Bw`9xgsMTF!w3jalQulkzPJLi+6w+su>}ik2S| zgl?m6aPBgd6$r`RYW$#z`rk})F?j8=R*LpOgmITD=9XYFzV%wd|ES+No_yoG)K%~D zNri;;OPfi*M4-%hG;lTtfkjK`Co%tTLQcL<(Z|&tOdRY^JTug#3ir-OZMX9-hzwdh zQ||LN+}sa87KA}fz)1SG8a(|hVUAv})@j_VvRC;}l?#7#skF;p!P>`|m{AzhEblkW#UqT-g=t|%vyTYFoi`}v z`Io@Q)zyjX)e-WCfI!cjG`okf*8O{NS!A|X&OK1imrb=n^qO^2SbHx!2IJ!1FEMeE zxo3>}aS`7>Y>(q7!KhZ9#MG84d8D^TWa8$Q;kHSM4$>za8AHc3qGXb}XCO;uT+ua? zD!XVsQy7j_hZDvtJ*z9;?;>hMxyd4Gg_?fUn~w&IPkE}>GDP(3>3D%@^2^5p(tU5RR&5VYNd)c7ShU;${zZU z->x}{<{nw}nrn&Qh}zjW20 z8AX^sNY^^ByPT9?RFczZ)}JEcs&*Rm{}`(iwhv3I-x(b(xBZX4rhc(V^eL3} zlP^)&Z*UHm(;0S{n`*NGe=A+ zI(h}RT=fYnwcxr*m z@oI^M>)CJ`#uJB!tsY33*T7VUb^O(JF3Ls(3L!D?!LIC#4}{IOdXXOeSR@UQWWWBr zoL#X6s@4D@rZ{zgqPDDir>3;weu5GFk}V$#L9Q#eASN@FK# zVfdt~g{paYx&P4Z-cPd}T8w~(nwTt`Cn&ck`VLMQFws;mHm!@Bw18RnVF`)+`0vgp zC9{$9awpYLSOsiF?hZLm4u-1(L04A)DO^P9s`M9TJ`0}FunXm>wB5LtEGN#ZS=$K2 zLW<5%`d`CrNfP2Q{VZH+b%5_$%Qr|iZOeuel8V}PJnY*w->Q2L3$L~*AXGA6^DMH~*#6aD9-AJr)?Q8CZ(;b9* zKaP1G-N?UQS2-JtLPY0fdqK)H@bpL_wHd2MWHSUd zz|~5!ikWjQ!qJ+cn0G#qno;EjedCy~<6`0Q^%L&?j!y}D*kh0!a&zxAV}pXH^=_E_ z&&wT@%7=E>prU5I>{7f@Y2s5Pv1)wEAt$YW_AN(waP|K~Q)23QEpx+=*+3KaJ>SE$ zI<4mmgZyHPuwtI*>48W+qc)&h*<`QuN(^!$?0eDTiu!YJ1xn(2w+ac;SAUKFerh^& zdzlQWjNUYP>1$_{SG`H6@o)YLExV~e%&8hx==AEfg0Oy@UGDit@SpAMDZLY^<%K!LB?ZISb)AEDT}wt$9oYPi=q7@^-Y3W7<}yXkD_Nd!K0|j0nOq{ zE*rF|#iDep5QeLzDiXI;Ca(I>wGZnR&uu~w>l_3DP}8*-YkO8V*h4qi*6j8iM*u~5 z9uMqdjVDttr1cB(wtYfaQOp;B;$uEBq4;-^0G#!FNEa3>2+boYM>`hHIY*t3(3+ij zeu_6$fB?Kf83GVi_Z0xPrB?fE)wvfBN==vyI!K_XwQkF{&PaqrA4q)h?b*=pZutA4 zi@`ZjJlDR-y3RkYe}GX1MUt>zg;Ivwcc9TSI6n%dKLs-6D-=gG~jr5yTsQ@fkW?-MGe4*NWwF&Ypwjbt3-poz7n${?$nr5xw|?gN*ZT?oQ1mkn9N|Q#iV0{S zDG#l+E%2C@-9nMx_?d0uw@qmDNed zkXxU_gzMDk8w=n#F$yooo*{Wr$j)yjz$iu^UT}lnSz0qm?aU|kkwCF_`L}Ev)RF)X z+CN0iNBIjup(P8NbaNWIYgqCXD_FHV_W(AxFmJh>Jv+t!GbSiH<+>{oq2Sps+knKO zenxS1PB6NtLEM`jX=>5le>5_@*L}>(Q?0e-S0QI&sJcPhZ{;aDZUUQdv0D9H><@M5 zm8-A~KqG{howr1X0EfVYlNF(22*r8s7E*QM;iB7u%doX((Vj9df$R~UER~1^m*q}g z@cfAbcdR*JFd+*#YW$2MCxLFbSanEm>#seI|Bb@@f1}tFhi~RIi~gT)@k;92+Fi^P znRnFTQM}K2k+Q^eixv!gLe7a>@b)ZxxwLUa^1EP=nuqa50oxJHJ_o}Eg2B`xgpjj_a}4p`n}`|Hc#gVb9kQrd zjp=VC;^ML(_%%Skohf?lxG~_1asCL5F#q6$#RwcJ{}M;T3)p4G8<$o()$58S()@*t zE#ZP!w3~njCo^}}(TpEdWvmL0LZAqat234ztT`MQOyoQyn!FskLyqr`Gw;?(EBulK z@I-iJZF;nXIt@8GIcZ1$Ho?)?1*Zv(@RdR`-Jub`;DbZ`p^ju4k45@e0X7n+$d|U@ zR7jqc9WYG6OHvEi3*z7fEyviSwc>t6hu5?X3Y23&RS8uZ)RkjCy!TRHO&!pi_i&pc z*kuh!%Q%ejORxjo9TtH3{M7_Wtyl6czc_BG!)Fho$~Ec|G5N_x5c0(8qR8Y547<}`& zY`NnlEJB9_8##X?q@#u~4_bF*Ix)JO;Ll>6r)R-VYRvujDd*2RyqxT2MDTS-k>RS7 ztNjih*edk-ydccmZOCqWzY6WF47j35S834uJ;hQHYtJQBhJ7xBK~&fr zuELr*LuL(sRS`loQ@Z_~B$@K~BhID3IFJK1sZg)V7OP2%h_5bgH*vp8d+awY$g3mA&k|JMCMXEN6mKt5tY#t7eiC5;Ez9=iCg1T@{ z&^M8ZKkARo0kA!90el?w-I%D=J$B5H5lH5#h2D#-2)Npk+;Au{BPn|xqF9(eh2a{a zk5USss58<7e-|6~fwTf)7px=y!7e0}tfMX0##94Ljnr4Ya9))N)u9ET&7u{W#(@Fi zD@;&EhwW6T;JM<9`&yV)aHpRFcIVB_TYVG@d@i`uJP>S2vI+c=@~PzX&Dt(j-y~9Z zanDEfi#aa~OhiKdq(PTQsD>}Xp)n4HP6ew)Iaw2S(io@`Va6ZOn5$r@-Qig6=@N~p z#kpELk}wCRKnY02Vdt8&Gm>oR^QeG2-yhLazvN5`Ix6nw{vV7&>iXgztY*RhR2{NH ziBh!;^Tyu-K=joPvi96RIZro_pAuOLGEvkcvZZH-PmmmBj!+WOD(Nyg&j;KN%kzLO z0RxZ$LpyvUXslUop|TGm51I$Aqht9~ih!AK{FIrINrvE4rzw&tkavO4Z_>&@+Y?IX zIlG2118||EJ%2aCaw~#vWPTY1%;{{VnFwdwJrq;-gI{D?k5b9VCnweHlxZG~xG8nTH60<^^EJ)h; zqZal%{0NLgw2UKpbqahDOg6$`MS|i*cStDBNDpIGnoX2DcNi?K(=z22wFI6(x7?sW zjUtK+^(anpWJ`VlyKvH_!e#L$MV6=Gf1+9|pi0aerfR{4&_)#5`jP?gx_9KvH@Fy0 zBd1Y7RK|i0j5jMFjx=12v;?C14Jf^@!hk82*QUxs(XsW5neK$QlAd7f_RxtCTPx^3 z*w{q2o&y0p1L(a0>qd0C5|t1ftEp0pe1?Gj29mi64Qt@N>8S|ikhW?nRQZ)S$_yea z%ADYu6iO{}-}VD0!SkM>EWV9=Pji~Y7tOO-K2N(8{UWhdac)u@bb?VBpR@tP87a`@ z+BLtPt@V&`0ST4^E+d2*fwH@tR(=?e@vFkpgqoqDv++gLLsc!%Yu4jgpvdy_m6w&4|LQ&E3DRAL(wxYV4m*zt&2-;$16s}~a(iN4?&p-&JF{k{5kBADutqGV$2Jz@G7<2JgOPz70pvgZ%nUbTFo+>{nJsYEe zuN#z}GC;c$Xv+X?9iZI_v~@NppQB?GZqgaEc9|wQ2kBUW4+Hi=I$4fEbwW)yV`)wb zSrH9m#Vq*}b2@1@I$)s*b2$t9Qpd?2@VF>KRO0h_K$Ajhbhtt#SP(P<-+i|%q5Tee z9X%p@9M+cVWJHc+^xh|pRHPrIv4I^qjMdMS6il7(CGjY+-|%$CnbY8|o}-VLfJEO< zxVTigOrQn~!D`UplOyUjQp(6x$`(V!n?(E)nhs9cfw{$)Ok{FlVj)(Kgi7#JVnOd5 z_Z{_7rpOY0{TP)$6n(;hFQ8q3xx420Sr|XbLE7we=Ve){LGte23FF_3u~$zg{mkcr z`l(1Ww4;)6Q|yB3*MhMpg-K3;_@U;iIb0!G6ed033)S@gZCtuSHhR}9AV(nylA&Lr zNwsQ`8qF@}P-M~(LW5IL)j9e%_Z~Q{bk74m)rpWh^9cw$@MmzHE8U?pG=$`U01KZz zBr;6F!AM^%VN4ReleS;5*IYa9fdQ}cu89GSm~Su9R-io|BtWa9{LEjyD`RpC_gG{u zvX@*F^b|76M~OUP7Aixe7GpkmRY_0nlceD!*XRk^UD8x=BcnNpIlAwwMU=F|Ab-~# zmDuwGOnvln!xFHkHVsoX)G!|VB2WK9FV~Mq3{CIyB!Dg_IJbD+ItB{AWjY6yJlFD$ ze@1WW#c2vxu%BGN4ut@3P&AWH+VFf?uvsRjA3oGxdt@Ccum55|%8?0YkNU$(Kkw%_ zlxBe$^)CXn3yHhkn@TMUWY$2P!%s8L3@~%K{_F9cU%b1$W7-qHsVpdd2geL!_p_x1 zQ>Pnic#Q8ij9w=l0VXXC6StbUFJS*;o7_V|1pPUOOgw5AmlV~|Jw(xWI|KpCeF^6$STb2{5C~uzZq2p{eqnFcn)ySl|U$hJuroI^fFn z_A@Lt=c!{D`e{;rtw(4HSIxxk@80Q2_A11AB0hpzPFr=P^1$kn4kRi00IE>t-U4)T z+Xh)s<8y9zF--XqG$U?cce~~}%a0#$u{T{Bh(^^TUainHo`ov1Rd&ZGs6_Bf_Gufe zlhWif+d$x5+9dGm!0Z##CTRPTB?o4_?SrutxhTIf(UG`=mFYE zPxjQBRdVpR4mQb+O*S@gItOKJFFXo#(>p|^Kv+3Z?Gohv?#X2eZ?9M@IGsqp;k*3jReojbqhGm1@ z*I9JBN}VNf5n@|q3XV-lZ5)eH)nix>AXFHzn@B32ahPtc&gf)jGa?#iLdnV1>$6?9 zy1xhH0>=hz6j!r2EYLT*glgq&p>U{D51_!K<>+;pVRrz=DFa6?Q{o!L#Y!y!)!FW7 z)7N2Rf8laMU`_^@mMCPE?v1EI$nWdQG|c)PqUO)(sY9(slbSYD*n19|l=%%4cAZO4 z{xNczOS6$maYm(8HErbvkk-e;LMdSp`enYU;?6sYG}~;5c6r0W5rqdP)a2#_@|x(a zNRDDE*n$L4*#b&I8i5PKtCKXZioiS6DF+Pr^!E`#K-GaMYo6&4-Hin1@@eu6L59fz-?lMTGqIzv>* z^hsbBXd)Ik+weABjnv@75Hg@)kp*A~(0)AcBJ^V_^!jPVMYOm48$dM=ls6d(0`}=( z^%!@~P}xHz1|V!Uv3a$rfp}0o=2IFC@|n0<9{Yq6^lfjy1@gjBFnx`po*s>{vj%tq#4UJ8 z7)p-7OJM)+68tCYh^oW@9wKB5bA(ZV9oy4pfzy!Qp3}yn2h(_{h$E^3=}GjD6BMka zIf_OIK5W5DSq-w%2yGAf#$#50?(&hN0=x!SA9Otii_;)`s?*~%!jAqyvERE()3N>e z^)x}NlFQG;x0+_5N4ZE(tyAp4Ze@)g7(E<-pKQ!O`CcCF#E$?m{l23?*DhM?9w(zn zpRQ=#kyAgDoewlz?z^Zi%g`v@cLD{IE{Tfo3*fo`5w^eu=W(&J4w>I6Hv$!*9;}M1 z^nOg+Y%Ky&r7%r{H#o6V|J~-HYv6>}y2Uqs(NpVZktM+;(wo|HAWD+B5K@2%U9!ZB z4OfY&IOo6LxnB9dm?mxfeyED+Vyqzewbjr_6w&u19kd#-*Qnlv7wvYTh6runF1Lop zqA!t6nkHY{mJtF4fs|6mVA>JYCPAO6YcKNpfG?b0jw>pCgn%wvi1pHfEjKC{Tv@`R z8t=d9TDqSli4fQ)vk$EGZ7C~bW8IbxEvKC6|-e1ik9 zAIry>H&lb}OhI{M76EbCnGM2O!BbRr%!0!sKUQLqS2jksdM=^7Hkk`sL-1t6OCc{$ z@B#GnA{JQSXQxjv38TJ`VFYM5MXI_eH#H&+>HxgVN`>h+v}t&#H?&V`d8)pn{punA zxp>T!8CrFDRGl|{nL41|*Ndh@y}2hMXZCs68ZCh7*A z4tT6pB0+w%Eh7Uw&dwLijCKu*J2L8hs^Pb6pn9CI1(x1Ps$t_&9*PLkXko$h5@8u{ zlf1hs0JBWDmIf*K$0TGM-3$R0y7p~YM44JG&trxLE`D&RMwwDbWlFrxnh;H+IqjSPZGE|8!V`8eE$G_4~>xvwKVT4AYHA>Q{j{gK!u{vaiSx%?rG zhnZ~*)QXf{hY_rCnb|E@ts*&VbC{hJ6@pSraHFqATLD70NX5pZadJ%E-WF+5`|y{~ zM2VngpwwdQNP%zvhuD%H;*bEAY3ZxeqxeHPoSrcB>?U1zr?n;sR8e=KYrGQi$1=5_ zV#)e_4fJdALCDm@?`=+S-t9W4X@v+~V|IWaj8F+s1j0=#{XYP+Kuo{F8E8YZ0(a{+6yS;N z^SVg6Nirj!C7attq02J6D}XA8X0>K`S`G-y-K3STQgb( z#SwNiU{*B;f41?POt7j=FD9tprGev?PDr*Jj*I>SOsfVAtAR6aKnKwe3Ze9Ap+t~1yHe1&oG(Wo4Sw7!-a*s45k#Ai+-CqB! z`N1!pI~V)fQDW_e0%Fi%s!TBI!*fupfd#$RsL{sxW6)kYCI*sBNxNz zWtZk)l}0}ugNx2CO-J?`{Yi4ss?e#}dL6$Xvx_K&rCH`5VoftzaT~zUs`x#xXpxQv zY^couTXSjv4GEe%2TaYK(;dywYr6ZY1{W$2;#SvPO?Ncch5%InAT?z4iDqxvTGiH% zLpzFrAdUeedJ-r{dvn8EzU3{SYCZUhD9YBxhn*`Io^7tQA8-6)=|uC~+0M$Pe=MEo zTwd*bdY%4q{^38CPP86;?QNn@-d8_*AAi_fTWkORL+kF@XPajeisIeB-MM33%*b}CTHvT4%ZVH4l|{yg_Q&&5uXcb{xI`MSK87q(hIFR_(P$68^Hl9z|T z@V^btDLONBlfttO*XJqz1d~}B?*mAuCU0CC0*ejppPr`}CB@L_Vk}{%;VZQvP;(GX zkO`DlX*>+WF67B^+K>x}Va8#~KH{$@$axvE%00XG(mq}VEF3JhHV;|-NgI5vM^$I9 z&em2P>&5GA4svx5tE{=+1HRk)KcNL2&zH9E2L#wN=?bzn{fc_I@jOmo7 zl={s`XL7I(b2x@FX?PSxG(%m0bFKG8E5>?QtS4;e!b+JgK9dX}irXyJ5&D!xyGC7HjRDwWdeYzPVbb=baa>|Gh z1{0|$r4n@($9&b&4o-3qrR|SSlO(nk2B}|kybc(gknmUzJ{-#_< zqCTUg4g57G!mnq@w4Na`NJdi$krqDYTXw+E9ME59sduSrB8E{?)owvqAamqrt{cD^ zk}jl@P80Ekyvcc#)WPG+?sQ38bH_9HVld}mjXiIMM3f!Xoo6fU7RZw)jWWNxz)K~m ztgLkJA1tC|9sAWow{qCtV0iD~J*zs6I(xnzo<5KZuwg)OAzqOI-_EzPyS%XGEIyJG zz)}}ExrJr9Q#l`%i(fB=2MB;%yaU*k1=u?XQ3dhhGFw~s+7K)~L{wbn)^=}17T(f@ z*UZ(npbl$MD9><2i*}&qhnX10`AhvQwBnOJ1<2u7*)TS z7E0q0hsObJitQsx6|V$xLHIP>#|h5Q+wCHKoKRk;e{frxWcK1$o_%`K zD34q~&Y|U2s%+b`n-8TAcbk@5`QfBdWaV96*|U!xv!$o41&i&hu)<^arw4ZJ&Pk)_ z{`Ng0m|h-&nYyT~R0Y_Hwa*W7V73e2@|`ueund=c@IJC@S$FyOetGWm6jiyPQQh$6 z@Vc%iu}XT?!~bikC(c*u&jp3N&7D`i^(Wuo1i8rX^U5B}Hu!cP>Qq|bn>D+(>L-1k zy!=DpwBblh*P`#f^A}J{0|XQR000O8yRAB1i_DZ&0ayV50HOi_BLDyZY-wUIZe?^h zE-)`iZg6#US7l*#WiCfyZDmPraCLMpWNd8Ay$5_;#kD_v?%cbxMRj-Om2J7G`)XH` zWx0X7jSa@V$`u>;?v=H+0k2n3W!_8HMbq<)j=^M4&g zR5fj3%P11(8p=Eq_oDl@rlp0%$SYg-SPm zj!DRkaBQca3sU@L%(THj`JkY=uskMcdWK2ncT`Y55q)r~pjP?EuOm(?(#*VW>_#^w zH<@D~SMXPLIqRk=+GhPCuRv|~WL<5m%Kt#tV z+_d8T;5|d5w^R|89R`T@Ps|_+>h#>EvNJ63WBKh8suxCPwNe__~kPTj8rc5HM zGvKS2UV9c%;7wUCO}mCjMvY>WouA68DS$En&k3K)GhdjA*+hYq)s3;Y$gt-iu|y8< z^12M~HdXaB@BB!CFJ!uS*Ne^;QJR8PB$4WXNFt6rQNo!J`+;@!sU|Ax4EXD%PsJND z?72jN`r?pb&m#(it&qjZko8ikoMzH9ZdxWi<5jKiDX)kr;Lco#R3t?q;z$ZYrjyk) z?_ht$yHdnQ63N==43U6Rr@&t6ck~Tmrsg9GE42VdVj&0?v6X2TXRIx-s$f*sWYTX` zdlfX>45C(h2~i-DC(OiBqCmb#g1jISw)`PW=K{RKo=8{*Jt3*xmJtO4vY|{Q5ovrm zm~!C$uoblYN47NoF`Cwk`O6)hGwJ+er>|agZWE;` zSar%aWv6U&CS{wlQ>HVv1!dALkwr)(m!dn3f6An>Wp$=r1a+G%%=lJt^V(k`lAYw} zI(~jXd1FLIS(B0O7e#zq7P&*~^EtGtFO)>VNI)rUmIM}e(_m!DWF@LE$|||iK(-Rq z2Ssv$*38bJ(oB~WqQ(H^b07_ws&qwA9xdOX@;pYEseG=Y+fmmBi6pQng_}%T;^fWg zp28rsQb8D=R1u6qD^ATlE= zl1L$oL)gQJWMpfXp{?~Hk>qqU7H>nt(Ag;K`?}(;&(lbPi-WTl-_6|iD7mu!Or`;+ zQKQlyg9f3@iGrNGh5})aAd)44&b&aUPuQb?M4dJnISK^HgnmHY3!q!>Ji2p`gv{c5 zk7K#Tg^!SlGl>F+hZ2?9XQ2&>_HQp?iI;XLGonl)F6SXcP=;W8AMWMy zyu#i`6xi)0D$73rN1xX=QO~4z_|a%@VfG&*%%CoLDLSJ;UGg$*Uark6VE#Zi`=tSQ3iVUNR-~zthzfcNZ`yYXl9}-7emN8VK2eTN&TRj(Q@&Sn`Hn>Sp3UV8AKM~| zMQ;;>i_P|{vMEP_@*JjwkL}Tv-Hsy(+JdY{iWBWkKnKH<1zc!nA42aKXV))qpG_fGF{km-8u^_&HiQ!`h(!@S8 z+po_i9tYwJnHWBH9*A!irDpqAvkAw8@FFIJkDU*~T2W%!tDuu(glR7#l9pYN_Bh?~ zSj--UX^*vzM+=8ZW5Tb0C;3&z zEGJ`@%9tl+mc+b459cZD>+Bm6IxB{KSyq;O-1gYW$52{*#K}`XN?qmHLv;9t|J(fC z`2U;y37V(Y7joLnf)MoV8%~2BGVIHdpg_p5ufU)`mRIhhi_S@`F-Y$7C6*ysR;GOo zTDpJs(u8SFTqZ3i!Wb`T?pjMEv>egAv#6|)6{3)^Z%@Z6FrY)M!oCuTishAybgcfw z%|tTn>GXvR9jhnZt{2kextVx>N<<;VYk!&NYi+L+wYL2QgO{r?croK&AqtdZjx%go z$Q)eM*S?yoSlg#4^K00yi0lYaEM&F?jI;-bbKLu8-0ka#0&xWUk+Db1_*|Owl#^E$AU# z+|4F#Hf~P$*Y9_HBY>*dO%Q7l(uz?_n^W$Wmn)g&q@?(uwn^QO&tZX;V9mb=sl( z9@c$#Vxmd1Mx?%mKE_Pl2*XO<#2w8fbTl^*1w3{snqaLH^+Z(CP4DwV0)_I;bp8u6 z0{5qNx~wu&e})oKpWbvjKO{nA-{o-2sH!u5DWtx&4lhZ!5K)9E=xG~d=(fg_s5eOl zBo|;_WNW^Ppunv6ncez{uoW`X9Yx6E=Em}>lAVQ;74}U|T7=IlYr4EBro@dPI0yRW z?W_t}x@j?0QfotoQ$hxpP*;C+462P8Lno!2cBP8ep6e_j4xn9^P#9$vZn9_=mm&od zH}M*PNZpJ@5-W8J3^Vn07@pLvFp_|6jZXH3?2@-(=J^exK%vz(2_Ah>jOaTbC8ECI zdpq;>r0xIDOoFEui+NJ+=Xks1cOCZjgHQ!U z#uhiD-V+6_Ounqd(Elu7I$Lv9w!Z$qm92EXrtHt;Yt5ldzFH4E`7-Gr>_S1Ye^Ab% z0H&DP3oV#l#veib)%NdU1tn{Vg%|i@#X(O{Ud!|Gpe$V)mO&ZxpttFXE9S59??Z&z z{%9`Ol6)_EF&V21dchY9r|7}z!@imZUv1(CsAl;=AB3KX5Z&8LB8h1*PiEC>gs(oo z?R0}$eTm1=(d#vz{!}s6S@UV7ip!m~LLVIKO|H?Tg%au+E4P*loxB$ zv)p}9A6mWJS%dS^cCLLCG%b(llIIf1#8b#={2Q96M9co1nz}(=%UQ? zHsmY$%lI=KduH+6Tkn->wc6Pa7)9kRnYBRltAq7=9mE}?__JW)sV&LtER_wSB&s~R z2iz z$o?@=;NVQ6vLdp7q9R0JI~Ds2;BQ)`Jb^`OL!ztC45Bh$erKIWhK%@2SR>5~nabH8 zlitKn(fM`qo=E&>ZW#xt@dOp`1l3Ta7a_MQdDQ1|f1h|+jh<0<(UVo7vq!uvJ)Ser zKVbdH8PA#VSGcE6mn^qox@`T$nX)~J2>KDk3YRoPWDg*U)mI}kucBi1w=ijt`CecA z1gtKjOnfRMods&aS=y%(NywAi$a3=Qa>0sw(@3=jjlIgz<9Iie=aoB&sKy=dK*ZbE z!q{IHNPoP^B-tSSJiP8a8KcrcplI-hMEo_RtV+>_Eng7bbfG6c4y5@(tKJ*5dP$;A z<4IJsz}eIA(2CPDXtpcu3wR*2062R1ln`~dLsq3%`U{?^u5}ld- zT5b*U$v0l-WfT$GvtZW%q@`=X8AL|o;GY7qe~p3jQA`r9$C&9iX#05wqKJ;}0)>+- z`?qNDN~6n#nfjgD_F=$jlL&(gj|UKJ#x zZLg*qKHa`yZM>1whEX7j^F6&b-kI*gj`XrNeywQ#wlkBsmuC{QFb;g5XA?%!me>T~i4B7o@GF_LjcQlmqTZKL^WY~XkRyqF4v$m*6R_6>J z_JfqY!#0mlkgyP7B#wnWfM{0)VHU_mP;f>zja4?NOq zQ&qI`K&Jo1ep?gTn;N3n(XOI^5;PJFK^KHfX}_fwTmx9IE5tBtF%QGSR_8#q;wtT0 zsP;#ka-QvTkpwNLOp0mTELA4Z1*|~~<1)QNm+8k!?~JZKEktGBXo&1jpv!)PWa95i zPX)%-)Xd@T{s}tt*;|NcIPx?^=gHc2fJn%QZ4vm@@p@ zwfy$q&hp#8^zxh6wfwfnNH4z~NiVxhzu1=;U2U)C0%Bu%TU}R zd7ZYoGel_QWW0+gu(er4qT0bc6#oqKGz{Bi)XTbrvq%0K^7wUp7;ld1sjiy#(cH?~ zeY|OMT_4?Jc+38cvysK&Gj-h^eliix=mhOLY|@iKfq=QILzR5ATgm5#gtUJPwna`+ zO4~5hHkn@kA55WP&b%*=8c#$Mui{!kL?`n47b38qB9cnXVE@wbh&#V?fNVfVrPGM% zj>IvSZxhMVsBX^;%A?>3I(wnG7 z+j`9K4Mih$&3<{{ldrn09%mMOx!bBDK$trFhY{l!*Fk2RiWI0=Ah-3v@CW~YxTTT$kDz*$2 z$!fOLiewF228v`YTS`Q72wU<*(q@Z@1f)7|(yrS=jEB(@hREdQB-!A_kqe4RkvtPe zivU7o_RaM?3!VTWGW+Lx?t>>lh|EE`o=JED$Y`gEguR+<#Z)0>iituBRUk&XM6@(I zNSLclo}Xas1WB?EGPAa;P-ah~(_(&Y_hxXgYm;`g-mfc zNo2Hj32IH`8(0YBzDn?1U!7}9)u>Zkwdxet5Pgcv)~C4Y)G4l1lud6c#-=Y-&!#`s zz-A!T$Yx$@D4Y4ICN>LF!`LiLHR~f@h%MSIFb$K*deen8xRFLTGSrQXa3dq#$S5~5 z+Krq5WROTAk1&U5)7EC4Hlx~%X|rCN4cctfCNdeFB9h2tO@pkp8&OlIh~zNGVW@U! z&T>$7`60oF$b$k?HCbe^G3o0#aBe@ZTwqMPf?ZxvE-)r_u*-|8^(ivgc6b|+=!yWw z3k?dKxPpn0@4S$)zsV%4$WUT{{qP1R-;gG+&mte@A|KWh`M(V}d9#Zg_QTk5?24>S zlm8@(e7K8zcu(YCWAY!XEW?;|3A_A6xxko|WEYI%iqvp!(iV34sd9laX$iahOu4|Y zi@<&oJHM=)Vc5lRu4Cs{l=CZT=a4~U2YH0_s`7&o55eyftf_?A?=|HIBVGc(H{jQY z{eG_eV8kQv`vLq)+3y$14@SH%{IK_8_hY};l^=|FfB2mTzcTjwrSgLjAArtvhdq!z z-cTMe;)CF^$R5ldzfvAB;^pudD|q5iWUyg3VI6CTu-{T{FmMhsRv#92r*i9b+@cX4 zi*6KzbxN(n=t?R%s^?vpy-#4|{X%yq=xtue&{|uS@qlLJhXiY_*18^ihaJ-wdZ=}( z2jAg6`a;zTLS|QFW{w9m4)f5i$mkp&XdVX3U6FY?KF~mHe|1Gp&hddJ;`|MBGu%E< zMl~JrxSe0=*%^8m_Jw?1k&RdNZ4p#m<#EFY*}xG+@M71^HS1N{pZg^Ic&J92zj3!8Zw$jUdI zt(}gQ+sz{0Pv$;LBu~VYJ%zBzF&XPvSVtgiavZE9**YH9QEZ(6>wj_AIT6;;>^ce7 z6WBT#))Uz}1=cZaor+Vm$&=tPmK{!JhiPya#}3ok;S|Rq@r;_Y30}XOih9Ds!p3}I zkB2{YAfgz%U{6BL|2&+(X&GA6Y>@T@WIwaa7?AO5Oy9f>W+av;?Hb6i76WTiI#F>C6wnC2U2)p4b=>^!Q)5hZxwW4O&5ux4|EjoU|A=6@B(QkiBhC zfEQ-J4iNN|E)9Evo}hJPOY;wc7PkWlj9HQ9vSrhJdc=r-ss97|zfk|jic15rlllf? z6Z;2ZV+RFdqeI5vvQjmcHQG)#ow2DQ>`54}8g2VCZfd+*hk=Y92mXo(bAzC%;}7fj zYt%XuU)I9>aupHpBgW1YcGRH2Va$XAC)~it+2OG1@Bwzg;-Ii&AnAZZtX*M0JKWA_ zT-f#SJjmD@jh)TdLSZ)mJBP7p8au>TulY2OBcFor5>Cgtl15D9Wm|_yt?{7-1!`s6 zLutE^SQM7^emS^2-o(CxQ`!*sO$X@7`Y?PY}9R{}cREOavo8>0UZpPhYt!}cMM%_(!wVN)d ziFece#7&pe;JfLh$3>UZ{JZIFHyt{Ic(d}D;r4jN<+0xFk<%f#Id{0}a=HgM-BoV7 zoX)~ccdwf+r|WRj{nSmD(~-F8{>x35)2+DaN~DV}r;~BhHM;3?x*Rv%JU88&F2SDd z_IS(XahuztGwo3tZ4{>cM_efBGNQFbWTL5-(N*RiOz!Iogn270$~6+*C(P7vHRl?k z=3FE7oNJVxUceWVhY`-?VX~f0jLdZyILx}O@(djlwbZ&cu#ODrH|@(DqfOg=8i z!sb&Muu*1`E_zbiM&XDtX%k{ z>dNdHM6m*|&u@1T$*+UJSGqLchZ8byczbR~UzEMHqaS~MJBqup`2j@-r| z-|Hg#vrDt;-5!5&dCYTr{541A{_a+}546e!9hHMcxkjQBgqa$xRPF?=Tcfj7X^=>= z#}&N60?mLiJS^-_75b^8JUsr#t~JqY9{>Nhlie}SU{?iV)nR=ZO+<5uf`cxZh4ZM9 zyjVZ!Eu#I839|P8(j?3KO8@0cXWZZ|U7F{WN47NoMvCN*1X+oH@~woP%5A&1mvSTH zbIWatPP^ImkXyW;y5#<%+ao)NnF3X%APiS2{7aWY$SDO_l&dO*6ICgU(WP*rE`|0H zNZb^W9OD$rOm(dWYu%7P44##u@=E0f0~?4alU0gR%b$H_EBTw$LWKMILFO3{$(bfu z_01wV!z3#*s!mxBDfc5=?2$acyaZj8CYD}%6!<1jHC@S-3CqxX7v0O}Xm90{ckJ?c z*=+0UbIG1Fr3+<(+XGp2SB3(2F?f-%Rpy?sQw*>u*9i24wA4^)1C*gd~X!SqxxZCi;_;&Ey+H z{ng!xFil?Ml&M9_h_Ejn%%mXeMl?s*b3Dp*xab@p>=}GMDf^tFz^#d<6^}#qbFv)ci+XTd z+=E+74{l3(a9i4g+p-?qmiOScq6arzkW_aj8&DXzSz49$9@>-l>1pp_J$bK9dk^o) zdwtq_WKZ53)83SW9PPF?D52J&sEWzR!`BV>tFfM zOuw?92=kku*grk%oRT|L?n{KWGHAy6?2y255t&$oG2b+2 ze1S7C%emd?y>|00!RCBd)vi@`Gd??~4;I`D>Sof6&*7fWXyZSqK0U|VHJO$Ogs)$2l&%;7K=hg&!K1SRjGd|y-KxCNTv=`#i zM(4?D=*E~H#Vur=gw>2MVmlAW7N@ONyrqYMqa(jno0R-8=a{4AXGWR_ID^C`1_g!| zI>WrB1_he)t&;hku0CK8iCRwF%h1bsbQ=<1ZcyMLC`zL@2($e=&Oy%y_@L)}40Bc( zIC2Re+|Z9jZxE68?`G320NqNagAXq3JNvO%D?W|S2gf3oknz(DerN@gEg_?_bZJ0} z_-Z8gH+}FL$#nO{fKf`o!af~!qLJ^vbU-blSEvWPFx{J>)_G>?b)H$7H;@ML!&bcN zGees*wF#=|#?0Z}_tS@WXFFpRRcBUlJGcre9wK`U+9E6~f0#bkx7Il3J(AVk!mBea zALU#*Wj5({(@Xs;6rW~cuYmfmhKkM*$=NxFXHHg5Z5Lq}+5)*x5T#(8KDOPg&quf8 zFkFi;O?y3Bv-OH(10;K=uyOK|?;kgoX@sw<7it7|*1L>oX|!2HhI)lMd*i%mavR=> zLq65P&1w01p8yIQQg`|IOcVZbhyvl7)fp3BFThEc*u1v;eAF6gT+YvTLwLQdUW7}`ptZfSfU=C^Zz$NCc=oL4)X{Ed zT!eF+MW0-84ykzbc@z~6b#ILhca{z}ONX1S!_Cp*=CWC6rRFJ%CpBMLWNLx3cvA~q zyr&V-TFrZ(=DkSsUaWbyXx>X4-b)?c%N*XzHA^lV$a$USiNnAlillHR7caPU_1O;> zL!{Qh#V}KAv0#+ikxrAzWwbske5osZyAHoqhu_AgmD<95b~2w)eT6!78HWmw>X(J} z&%(;GumNriX}Oz-HXtpct4|6s3p2F=F$ycSo=s0`Bb$X*YLl{fQkzY(d;#21;`Ez> z)9=p{eV0x1XibI2M%1k_){Izl$dIYHNmgtEY^|`3fNd9SQP|pGD~BxsTcqu7R<*fA zqV1u8b0)|etsE%q-N-`aAZ@7~>`&VQ+J^jL4{amzXXvyVDy`mt7`SYj)k9iiHgsdR zN*$T0Jt}o%ruM4Tk(oN9Tk1Ydr%t-tz)#X`;2ft7RQC`zaT|6(w_%%A8)$c>o4_qb zZ*TOd@SA%K|JiYbS8x1m=_$Nvlc|qJbNC+K_;KRj+GG5t`5(q_eSZA7@l3SMIg_u> z2`g4e0$A~JY{SH5f+bjD=Tq6tQJ>28>-(i4>KDtL$+m}Q&Sc|G+xF}@%w1h-JjdhO&;nz@xMh+&st#Kte>+`hfz7k%pD0Y4Lc!yHgrz+ z?hQ_D6Y{7P^U#=EVWsIP?0o%BmC5f^?Zi7(bBQcDRrnHM8ZVPYz#L)X1 z_BNe+rwog!Ov^fp=e%R^3@V<>zbMaRrL*w=Ae}}32k8v`AEYzEll4P`xf67yE-rHu9&)m*UEMB8eJ!S>2c6&ciZ_ z>9-ETTD}RE&83FE3J?&|z6|<>J+5+R3gr8a<`o%sE7n;|Z?Cc~GVEOj z1#%^7rGkG1a#hI-)4CGf+t(peEdZyQkd2DX89^p3Yq5PaS z>tZ50i`%*-`kv?>=Pt`$HBaM*YO`16@cmPV-Wo<};l%pY^$E zMi3@Lni)B>TbiFpr+FXJy!3w|&Cv5C>p2nv-9T(g&!0R#J?B_^(sR_=Yx$MrT>e}= zpA!5eh~Hj=o4TIPgmbIvjeO_SBrZ_o`)b18dVXt#Z&S%wUeFu46kbQe(#6nsWJ^%m zPov){348rsJBb?W_YU{?!XDg_^W$a67?4b|GjGIs>4Hl$>BbvXDQ<`V;k3hMOYJ&R~xFCu!Dubg?6fG)Y1$SA=3Z9#v~=L`BSk93*WI}f?^dITCZ^ zb?r^r@;dN&^4fO{c|ChP@>2TL(X+gsbM$F_jy^S}g*BE)^dc;H^(3t4kEKr=zK}j0 z{5<(^8hVk>^T#irvwN1$3yyp?=E!GGT0ZM~m(RLh*HUlh3+i$mhl5 zk&jxlJ=9G;JYWA=dclDibYHV|-da9a-2=Ao#NvL5DeN0@*FVuJNFHqBwQ{qo4=j=B z=f(Ns zd$Z&G7vijP;;cHZIDdM)abBq7ye~UWiSn#=;;cTdIA1>AI4{z1K9C(}G2*Oo;;hNU zi8GlO_tHWc6D(y-N8jI#v2_17m(%GASU&fD&Ti|y|lBpdu@ zSD(Qu9Xgf5z8yObFQZ7{QyS>Bk9nov;gJ0%LkX45r2L`!eV+~KcndS}R_4TeGsCYl zybWpi0BNW^&NNi^l!hToD1WT(i?cFy>H9q^T8bG@r%)=PEUVS@4%^za`nene%HnpR^j=Zp+R3 zps?En$>hC)EOnhW5?wAV`%$QKo~bN25*Ufj(asGx3IGd8nM0>RGI@CphsPWak7aRq z%;E5un?n~k+>yiK35UZISsb2lI6UFz;6pC%%;E5~!{O;H4o^EAo_2Exfy0A29G-JH zJeS4cIfuh@`Z#3z`#G0z-F_7Z8d8`m#6mLOZcre3DL49dSfY{Wd1j=!%oO&Ah`0lL#03g5;|HM#DmO1V%wEc3 z_L9R47JayWId8hg&o(Hq`!H@!Z6%7OR_JY2_~NAP3g@IPh9Wrl{E9kN3j+tAAqQOf z#75*cb;wrhH1-OQu&iFu?cgDGNfe~poqgr*XJS_t^l~Ql_2WCUj5y7qMFo#UpLQ`Y6`Kpu0hYR0n2OOwN|zzfRZ5_%wIEk%lX0zMxibB< zH<|wF_+)xncbWd-_+8c!=Ud*n@WBjlq(+WqXu&Ce}nSz0- z*l3w%SeS~@B}%4RW-~Ky8l3KG0xm-numerN8a{@hTrY>~PPndBr!tiD6>yHjd7Unm z({+2X#%V9GQ~-yyj>9_bu+DK&Z z`J&E8$_<9ymbrh?lx~CmmemF^zXWfnF`M0N<kdp0?b6?R z)vcB3$V`=5=X8Io+k^Xpp6ej!HbxT(1s1+>ARaLz8s^V?XMY~>`jQ3pc zF6vD-B#x`zUEWO~+`<9_vk}f#Z|u72Rd(6~`r0jI>y$n|qRJ zzFVe6ZkcY(k?G~^iacTvu4G#6$P^Y8JR?&uFclju(+mq!G5S(Qrkj;aw`f^z*5;OD z$n=xmWLk23GW}9_nFfzfrXfeBTYHje#4Xc)ZkcY*k?ED}iaf@@?8vmnktr-Hct)mR zU@A6RrWqEdVsw>~=~co^ZB;Ve=IR2jLR-HVZT)sF;jP*P6DD_q5o?1s2U{S7-Xy#L?JM^dHcDfH|s`Z2uobRZyr)w&^AAw5jB;Q%(lgjF2 zc?Gqdf!a=Q`nzuY&5ug*MajflkZf-t6BBHlzA0={XHWXuGm)x6!k)#C`h}bF@Es04 zCQ%O}7s^6!BoeXf)w6%;^Ll#R5?5NwY-(K7pwxIgYvNFa zOk`vj!)AuVmB$oioTQAY*s^0uvi@UXOwQ6zy+X9_0{j^7C1QOd3oT zyRe&bB8T7;V_ot-IV110l)U#Tc_+2J_iK5lw7lE3ybox3cW8MZ)M7bH%Xwd}oWT(0 zer=|-*{;n4+U(FKGsG13Y?ZEaRJso7be*f?IXgF=bF{~yTn`R`YuQ|*%xI%M4|Q#= zsr1ui{k#fwBN8HeKGu>Nap>LN1bNL+)N4#W!oSkgchS%$d<9`jLx#N=ErGz-pI{UH zLKa&JYW$~%Jq>v7*6@X;Y$ytP8uCKku0CJEQzG7|Z14qT;%cNb=xOkJwN-lUB}nT~ z(;E{G!40B_x*`ou8)8}!v%y;~$lDP!BIQ^(OvH5gVl4x2eO!%mHrMhM1RUaSzb5-e zfaB%CdVO=L&U=Au2>R_6f@IsFBIh%bvIDfBb6p>By;B&b3GypxQ1U-;SBVZ_A(?L=S8Dfoh$IhujO+Ku_-|rzYbP!&@0T4 z&t57>N_^nRUXF&le`(N%4evlCBW z783SKwUabXmipSBEuvN|$p%;#BK9I^?X9??+}GFkc5j}sMp?=gg+09PP(3<_Ec-Ml zNsyo44>S}8tqk*+hr@(DvR}|sj_$_qVu(C=xy`&D-;8PS>Cb)@2s2XR@mNZIO)Mzm zI29aOI~C*hp zfm$tIaj)W8U47sk!Rxk}{jp*CdkA6OkKTYX*oZr*!jk)6<(m{xB_oOt6m7z3$8TU@ zasbm;I3_{EQsB1$FmL^udQTqhbWKB`HWGGJYq*;+s1K2GNapweHuftxune|g0p^f8N=r~CkUJHmcX5k;^`?P3-Vbeow%1T-oOW+zKG!~tg!+XjgVfS zTIbE`KF$asKBqpN<^K(qA0v`?`8_*(*zzvUh`zJ@Y#ogx7u$qH+4{`C^`GT+B#J_EXy1>D7-Z zXYT0RbmAK4yt5beiN2mmMifyBhuFo=MaZwmN5+L2vRIsOMVLQ*B?T?9aN~pLN{1b>jWZLR~qX zC$Ftcot#Li?>lvJAl>#v<~%&^b>Bu5EbsaZALrmR_pD6c8)As=KsH#!%Y~(ge73UZc8Rjb|@^*;Rqk`|zt}p-WGosbeN}(P9u-yh#l>Z`K3OTl7Hq>v|x3s~!m7rU$~`(BsYjUB|bs(&o&axAe5Gve!LDKFhtXa(m9Y%A@Rx z490)ptgAFRb7@#q@XWdj7?_HUURTMmFcqU8s&$p9D97`x%gr@>Uix$*ykQs=0W z--w>*jsFM@iwp@|Zo)xyKY!Y#p@ct-QV=pVjxFmvez(o_Fl4~1#wicGcdVUnbNOlJ zqRiN2lk1G?>JSYc;G9uy+Z9ZoIX&ii)y(HpGv`%P!5+`6Zc%T@;GOn6GVfrCl4v9l zJB527KGZa9Y)A~Q({KKXwy&j`3HDZzh_)9p?(RsW{W$V|uWXR2)~IuKdBPj<9@)YV z?_(P|;Eg}2-yt#ecR2VitNj$O8C{6(>}lw7q|21{GaxmaOg=AuCy(2o<*w;yK!uQ| zWnbiki5$&SA$sP0aSy!LYERQX?D#5=jgE(9Uy|*U334Rc!))?$JNZp~LsBA*7N@qr ze>C4@8=j*)${$!!pInmmrKlH2!=A{|g2>UlC?T&{PrHl1wR-_k%mgEmW~3tbN&B)) zt_w05H=8W}Cd#+cvciFH708R#h|4oVIGXR4v4!{XaUU>f*%uPUJRG|R!7Yq6j}|!j z_IvFsTwKCd7N;rYf~X_$yg`8u^v}^sVcN6R8i>JT5d7Lc4pM941rSvTvf3tw9JCVX zg=w@3=qqWo8tA~VgVq4ultycTemjj05i0uBSXc&$B%77OzDkgs&23&kBD#lV^%a~+ zs1sxbl)tRImni70!Q{|IyU|TiSdqa-`mJpQ&tkM;MdqzAan<2k)r#rw*c9O# zyv!fLQGZ|L@^pCIpNTu>j{AXh8a>>eeFypuePPmiK~|n3HH*}zpc~YK|FNPX^+jl$ z3B+fXLUhzy_g&2PWaMaLf#gHxi63KB?MGWU9&O=4z-YKh@_SSdX2sQziAx`aw~EZ1 zD9!FsK7`6*{SV`8{6CJ<%jba}=5NBPYRJ(J6=db7qs@*^9r?z$R}dXPb>XXfgi8r) zfS6N%5B$6?eobG99~Nb$ukQPrr%L0axoI5sMbr2L%}?_C{y$_9x%f4I0e;d~_gGpl zO+J6}qm2Fz&*-ly>mFBxpu-m%p2*OR$fA1^1!&$><7;DlJHz)>x1{y=nCq5#%Ha@yrD=6Re%aScY1y`p>UngE zCN?mCx}cp>*mto=I&ITL_?y6;hD|WZ2@fP8p4=^?@EurP%=R7 z;i%ZelLqC3M==h^`8Umo)Uuir>oyway`V&K$fxL+=9Rsm6mbZD^vkj1)#<;knADx!!X2hy7fz-|%*B@b3T`T1uW zris_l$*PIX`?5qU>b07?)2j|mb*DjeHEOh9U2Q={kK_#*uj9k7P=%LvP>+z#rY~LA z<96ob_BbilR$}$&U1+O=t0Y^1M^4$f>_kI`U*Yu`0D)}($;oA8h~^Nhz^bjPb1H8% zY-9Yg$YVx*^&tmWWIL?lW*! zv)Jxficiw?;kml9&6cdRqGZ3#H@&)o`btfE?Nm#fYs)XzPn-Va?|DG8?-=5e1{vhE zeBs>)A`3D6Y>?I&aq=6lT3Es6(?3#I)3(n4U2w>LA{`0th(%-ah%HNsvS0iN!vIwX zJhbCe*26zhvLN;XuDB#)o5KBZ*BKwsQELX9cr%;0)$kX{$5BVCRMs@f6i2JyIBz(g zZmg!Z$yg~>Y(^(0i~rg%56S{f!>fg(t>W|M{(Y>Xx7T_bxKHmjddMS7k6V6rcB&|y zdUE9Gu1;8-Gc`0FZ#Ey#qbEIYO^J~ze2D&|-9rL&93u7Q#EsLXpcA(UWp^^1t0AJ! zM!s$8W@s`yLy>%6Nx*W28A`w{L9c8Nj}H(w%{(MBG(i| zOVwujCa=;*&R6mDaIGS>qpA==7NvoF*s^YRg;yOv%RekACH1zY|49)W~>-x0&6Y^hIDQo$lNFVgGV8QNB&z&-M zjdK(`Oq*DlxBc_DAU%@h)f=Die-d`^sTO(h!SVkdt`cPBj zr?rDCL`WaS=^v$pr8@rzWz2`Geml`^OOnMRb^@0l8K_1XaDN5V? z9yd)&{Dv&K2~|)3#M|H3guQ})Si}0gP$lql$ll5NTYL=&f1d?xkTjZK{4lv_@g$7M zbe;N;-5tkID#Ds;#7`{iZ~B$?{QLKxM+qZ}w}JzX0={?87Rxda`LU?CO?s-2KWSU6 zj4EOi*WU+GZ1%H+=MV_>U?A5vbEGIs3T&{B?$hItY!A5;%QqXAh{*cAKxZbO)S;8#h z@p+tFfp>4HOhQw=Y0JjjgEwtZ=VCD=dQRJ0n9&@k1Cjb{ zeUV*=LlP1KI8Xd^s==OdJ6wO%zj-#7c*RIqHS@kb+oO<;oC-n}f zu=z;2oe4mG%!ei9!w}Z%f zjx17($liCd>stEM7IOI3W`gi6jTeh`f)1fs3Dw_|e_f*3=@WA1C^)C~?U}Lbx|A&6 z_*a-4^4SVI$yppWjb*6y`CiB&?X^wl2<42JDDzwX2q2lz#UgeB4p)STNA3{?&RPn& ziD=gLM}!Ht3l-3 z%&t-fD`T9SDQ6}>CL;yU?Rwk0FzFA_Aug%WJ>{8QQa9A8B&Kz83hcH0M1%>G^gNmq zJ-Ypz0!IUqd`N7>$d2mzeE)+Rb%_9vS6_^rUJEg&F1J%(jGk||qpp!`Z-MjT7u+ra zc~j9=lfIa5>E54@PL&XHm|6>ymBJKu91w-RkT44H6S)}H6L)QU1VfCGs{Bm2kLFan z8FurpcAfWw1aMis>P|uSucK&pc)eaNg{vlaBay+XPRH)DC@i8mEc^3B&H{ZdVbUL0 zDY<@ycV>onCh`)=mB%5ij@vv=8w?(2DMBe^*T{q9K1(Q9`?_`%o?^ASP#&zl6LA}J z_@$~a;eC#cfYxq4KJ`2zvwrPgkQ(^myDZ>axT?Z}BY)eg;BRG6Oea5PAj+&nxR^%Q z!QRVmX{Z#}&H_vanrvhL5g5VkiSI$$egE?Hro)}w>=J7zq3Q~!cP`4?T zx&x6tKilI1N3@VL<8TpEDPUo3cL9~nAsZZG^C4QAtLiZ4X)5;gJYh79JTc}>0fP%wch{r;a1NrBxi~{S+g*ZCQpS2 z(s#u3I%A29A0Ia)K1(?dJC9S)z~v~)O&ye~8sVlG>bQn< z8C3;X8Rql@3TQ&gC;;Ei zBkSjaA4&DgIqZ;YXDC^hzdOvs3edhEPwMQuoA`0x0Nn0XfQb>vk15c=zI&Ry%Pwr4 zE~tW%hm66{wzDeIwn{meVF9V)opzliWu{i+Q;vBw8`sTwpb3ztDfSr}>BQlwjt|oS zJ^R6PvTou*J!8?D41lL~Yj4j#0~H&)J*}BXg}kC}N&U9CO)x-;mXMWAAavLhNiY}e zdvo}XiU2k}*UgGgMbIW#gNzf^riD#c^%X z=J8|!I@#INyWPtGZ|idwG*WX~v1VaIF>^LYnmF1MI=`g2Jj-v|>k(nhAcq|a7FTb_ z&FNW~FLd7aXqo(b)dEcAX4xz`RjlFYsM+xGITOsq(`1fR`wYnFgDqM{+T`n^R^Z7cNK!I9 ziU&RwyQ#Na`-JIE=m<$_$ZMx!#~9}PX?b{C9}kXDlK{Dg3H%1Hm2_{vtsf$KOxkf) z+I7T)EsRFSfKs|0c^SBxLcq(TiKP0YFv=b7ONu@D54C=yWUSe@mZrF=ZUTSbTy0(D zw*CUkAs*qmaR3VxP2$q!N&V)Kk2u`OMv5Fs|6R1S{&>deU%zc>T^bcvG>l2wFB$cy zzB59#Bven>@|*j+ci}ho*B&*OjS26>!%Ywv$8jU?)~+i?;`k7zDwbHRM1ne&7T{4N zHdkL$!@alB#b`QtA9mNb;}O+T`}tU4PnC|u07M5+-B6-N2a|<#9WQ8vienc zp9{Ai!kn=0O6z`%Q=BDK=JtK;%W$R zB2q{p4;+)T$2@IO=r+1%^6=8|p-5*@oiS#kj+ObA4(Ez8`*jS*XGd*!UF=p+JQ^Y! zc`OE{H7#JDRF>yjp}uApos*D^i5lDlwIAg#f!WCZRaNJzk6ct>`+B8jjc*BC(9IDM z{!`OejlFnwHxX6Q>Ta%}aNb-On^$)hnLG~UN>waFo!A@N}mmyluz^XC58{q9$ zCc}|IcpzO};V<+=``_~kWC zT_i=_=nMLNK$B2n`;VSRo3u5a+%jL&fqbqTY#o@(YGD9!_zc7h(O7<XSZ%Ug)7PqIyx)UE-$v-`efB>sCR=$VK(WQBrGUajeZU#Q_To zIa({zcn)Y!$i3$y2z<eqG^ z`d^f6(F&1+l{2xu33@v$g2hRYhzAf)?NKrlaPJU%1)~r}-y(IjBc1(AvYUB|KH$r{ zT1GUsg#E^a4V}#*b=MFgzwn~N-l0B0)w&so5ds4k)>E~*Nwg4_m=L33UZlNa42Z0H zsIabg&K?wJ@V6LBH!HneeBjf?BmFK+=P=weY|-^?do~<caYCyUMesHkSQo}h*+Cvg`uY}W91Ah9mXN*S-C1u|aD+bMgeb<@eWGX4y{Hj{ zWWN$6bE<{!_{AlluB~W`dInK61L00aaJ|KvQ}NO=K-xn-!UwSK8!pO>iWQ0wG5K@AVQ2W`5ie;jPTFwj)P}#5U7UH>{$^y z7}4(n(a%Wa5nsCy&aSh9tEz%ul7fLs$o_#M>z1DPpW8boSe<+ko9_{E(Gb>vEs0xz zZkH;PmgtRpEXeR#VE6>b6Hjj(*$xqs7CXh5GjFdU7PaLaey!=+fGKbbtg?WT72 z=^Qep-X>x0{7PdFi7Q&k*%r#$_D5?!wMZvfe0ej| zmug8ili5>riP8Rd>?XXs$R>+=$=L!fuYK>=B|miQns#3wx#G4TnWbQs7^UGfLaqR_ z#TdZ_k4A}}6Uza}g>6{u9!TrgSSeio85;#yY&i%mZaC|(xnLSON1019;~-4;7UVOZ z@DOEWA@3y?oAiT+<*7eT2v6=*CXmQr?VGSuz6u0mbC?0D&KmXE({XT+>FormlI888 z=P5aRl*sC9)q$$JI==I+cXzQ~H=hzR^D+k95xTjY?zpD4MsK?NJWf+Sottp7{wd8? zmTBO%P)}{(j<13)Yxpc}=u}g_&H18aE}^`Ha89PpaX1$sn^+=YM?01_Z9uc%Is=`R z(Oa>y1r<^&>8Q}`XU5Lh(t6CN!vibvoty0sv zbPEeIUo>0~Ildj2wzW%5izW*v?yzrSwUGBxSH@p$b=E?bu^ug(;((9p3Nypp&l%Je z@fy5OVE|eAj36VL{XaWvvoa4iwYPS(!qZQ;0NEhLsHN4Jv#ZS~Jz0!aA@wse}D9sI2o zT57a&yQCa}oQTt1Wvs8H+;V^k%HV*@QRK!1J*#YOCYx3ILi77#n#KezY)HA*bn%9< zAZm`h{z+-ltkn>l>%{Kfw5l+uK?v88rDjeJ(D=`~s&GMXb%sLki)YL--`D9(0+F($ zf8?B{dTJX~-EKH9URBH@hbD3|OKsP)wz7))I~wu;vZL~(Sv(|rlgBjs(}A07dnY3x zR=hh>@8M?zbuPqaVtsMi00wj!({9>!p)po5&--)Q?sH1{3Ob^CCxJ&tOhhH~^eTPj z3RDAq7Mq^F$hm|IC6*x*p5^-)Co^hQc|QE^_iAFTOeVYw z`rGN_tw7_7BD2p!L_#U@S3wd>Zx8cW?TB znyRS~!au*?mpV&GN}|B?*?pu^RXzWS?w!+kb8=KVaGHJEK5=@#vU@Qw;;UVy*JyiO zzBHG$+IXr*^f^RyLp>A|L-Zr}jrd)%<$nF^mPGXS9V^2KIP?)+@Z`ab z=@Nb6si?o&L0G=X=_y6zwOZQnsl9WOyk;Z|@24^0#vEhOIal0SvkV1`A<(hP)u#)8FeThy5J|M1x*Z_U-DGmMzDSusiRJ2;kNB^i0A41tPWGD7&h-k1%_ z^c7D1#4rJ>YalrzA0j%ORa=#1E zBO+*SK4!j)zSCedv$Ky=daSN%MU{W-e_eECObW-ZKImf9K(({rwhUDG)`F#I!??jI zq|BdqhPn|Es(d|+o|5OtzFGUR57AO0a_Ngc2<9>Oz-umDilxj3jmau2~fc$EP%qs31!3o>q z+njsnbeFsv#&su95X2u+MR2As_Y|Hu)f{9kK>L^65&Xm1iL{p?)GtI=0nTr++2!oS z&qy5Z*ZXz92Tnq%_|s`hE(AEiMzObR;j`bE2p>6H>PxG`8fo7`H}7w6U*-w$)$lw( z`^}nQ;a&Cb_A6Oe#_^V~PGM*2x0`}J!<{|>2X*ydO1{E*y19M>{&GO3o@kX$D+W25)(wsKqrJfqx;m2h**GY~05F>yEQ? zSTw-Ts}1q*dJaHPUG2@uS@iq^n_GSla;m1q?XB?}s`YYk0URfI;!bX(r4ss}V!^!N zhvNOs3zS6>eG2E7nw?>J4YL#6$9By>Jhwg(WhqknHuO5Vmt;)*mhYc<8B`DV(}^$zvmgVoeq^pJn- zonchY;W{+t%)xDO93{N3gt&2~89}VtJyM?y>r;E`_ZNz{95O zvkj=1r;hy@-hPJ2P^z7bL%N-fF3x?^t_+_!Jg}aHAULg$m1E%zYUH}SRoVQX;`AcC zNR?dhnF@1n&<{OG|M8Kc7GPs-Y<>tTeH1HmV%|$*6e;s8-r2x8xV0 zu0}zq`$n3($&$D(v2UJH6dNOwc{*^tS?Qb3|rf3?qr z^5TQvb5xk{g_@fKT%Hid4#s6uYBrEAg!ysM>t-h@SWg-E2JgrU+2FuQVL8%UI zz5j8;O2BI*B9uP3{?#1Hr_b?3XPOLx6athlMc|PP+(LhW&k%d%29GW>d4wbQ;y^5RVSv3`^OHzG)hHu{VtPM z3;EiGPIbhDP6Pq*S|!U6uMz+ASxK`B?sGj;zLuCs*ChJEM&F%}s@-}pG^zt$P2~HV zCsTph-VLK`RmFEQGnG_QDOE9gm^-vdE1Z1NRUty46`W;~>ra)lFm2NsDTh!lfM3M~ zxoTVwReJXIS>ye4sbcQrRb^PR$eNVHcO0|pv-m|CU%}M##!MC5k%v%eQ50<+;w3&| zUlNJ|ZCo*7q50d`y_Ly?@*03&UQ)3K&DEjmaSO@YeZFR%Gntq5z1=)gifPr0*@Pdx5rNBrT!ZWm|&(HZuy0L;TG^XJ$EBQxO}f z(4A`^kq3{|geuP6t{Q3T2pka0{-fAcyNUv)CIKz3Fm(VRoyYUj(a2uhdJObiJp}YZ zI(oof&lMvQis+*orX2cZWaQ-!C+D9j! zv-{ACYJLZ{KoyaC=`3S0{F}Ww71LR<;#N1zYZOHW+N+jJwMv0U>V^olVP^2H*+62R zg8im2Z|9!p7p2`nB3ut)Qo)U<`2%F_b^&2$<`B9e&Zel$i9_ynIY{1r1KLYDDv%#d z!H)Ms%({Z#v@y>1as>j-xVI4|0&ZD?0)nH|OvL~!LKn79!haIcI{0tRg1(qcWH%d=y z`}IBsV6}LlXi}JhKj)5iOF5VbGbg$gvH!X8+IQ+DHN&|aA`<5)h6V<}L^tPB^?${o zHGX9YErt-dkw-=Hh>iVKHgoKC0SRw;iG+jG+%fHcOnhV=K=%{}I!PNubJWuM_RG@5 zFg>$KS?czsuNP6kvw$YsSg>uUno+{C{U1M_{q!(X4LJfbvP0wOY$})Rv?{3&tH7vc z_kavuoJCR)B}NYU;Q+mjy|$ueC3Qv>I7w69>{+J~`r9uV`T#}+`6&4D&&N5;!W3#6 z!GZ9-ZaRrmo;&agTo%QejDZ2-d~mj2z@;pV>TqCn8a8g@XZ8&913bF_VS@7$fU=Gr zr7Ef0b2(oBs>2(YK+k*Ex|P(AM!>BH!>DT@#G3gyo7(I-^;<;m0#oN_N9Y5GD2NC@ z`h#aAoiZo%9$ex5_k9NjpPxjCC=+$H5gNpOmp^Dno;*>?n`WGeHFz7(4(Zj_&ftA} zb<*>1G7^%}9gxamL>Z$Cu~v-qNq2^G^@5Q&`m$stDzU;yET*YFa}{8CZ>gi@WK8&2h8s($nG0gf-@v8_A7bvyS{A~QC(A22Kpyt zWkq#F+$&6b&CaAX{-@JSgc(hAh`tm*99wGCkra|POu1^(-Chm1&-xe|97eDPmoaz zrs^x_nXjm1>56P!DX7abUD%>Foq^xFb^RYrk@X9}WYH@GymjJzfQ{(>?-+4lr#auN z$N+-&BA@%!h#vYKjl5GDK8~EXk2vfCrUWDKY4aTYbj!l54D?dEja~e6!9y%p`4yP) z=bKqm?Vq=gdXo&Mm>DI>JrG|aX(tOb?k0h{oL*kk8Or-y3mBtezpY-GHXI;+9O4LhM) zo^rs65*~(*o^d;SOFg$gqA()Rij19-cihS(EW&0Cqa=+}-C}ukf;Q8l#_p)hsD|Fa z#L2GG@vH*F;iv%`PSlw`IS&7E@cmpU8_WXK$$mE$8eMrO;x{fLbC;lrSD|fWy)`jZc6E-gpqO<-N3gR*&te^=*f zeI!1l68z=zMFN>kCwEtG=aG2tIq_Z}^GNth!lz3&%pkJ zVN%uB$4U^07J^4)UlrVUJfe?}9wn>-C4suKq6}?k4s)KKTvK5gwi>)M^mMHkz^qZm zp`-z3)kU|+Y+1*SZ@}Z*(>V8C7Pu;VD|4~#0B}q5;+;;+u+!YJJIprUK>=Xuo+%cR z7?*?bWT#|TpIV@fqi&#!4L%;N9CP`LZCww&wO##!r#l7EvGTCO#jYPWG2a?7QMVws zr-iAb+WUzCjKER5uK`rW{jccdEr%e1V7q$q6E0#g}M zg_G&r0nX?W-aYW>ra0gTOt@%y*@o)JoM@l)RF5j0?DLcl^-P{<8rxdn=Jm5pa-iZ9 zs;n~}p=uc0>cU+PsD@LxsOR-_CcK0zZ%suYFSV-?_x`J&{ix@ciO;@(wil|KHP0io z_fEx@3CTTRk7C`1&Oi zGf?j|FB}Sg8Q;eCjf-{5`43*M{|}!158nL`&SLvg$6mtAp@>lIdO1u!I%nc8n#5Un zT)2pcGiB&>E;uK!H4T_iCi^GAA7)N|z{PM@aOOW2fIc1`F2g-nU;5rs_CGZ4@P!*% z(F$;S<<38^J0j4Sk~inQu+c^7aA9A_P|2MfeAV~!He-m|)uLcnu2+dZXt0LB?nhBr z4sB3h^ttmp>rjsESB00<2;K^NzdsX0)R#VhNBZwY{=N)Xw%w@CTZY4xB9&~m zwgLKSzY;D`oK_3#2BiPSyGHJAF-7O%nMoDj_E`S*Rp1TfjOE?oWam zD~B3i4JNUYME)tFe|?UW4}qfo7R^91V+MOTdu@Lwe8&TLY&-kfUB`7A{jLP+`bx?V$cbmFh3ild0LCPFJ!xOMV&w<~M!bG1$7;KJgvICFrSg+RQv znovI#h=}#&L%+Pc_0eVm6Jyt(tKY-PD{jL5#-TPx_od5>-}9THfd*!KWX$kA8_}_{ z5>0M9W~Px6t5E(DaALs^Unz`BoTQbs`2wqs)LL=K$&fb|j)r(*|DQmYDDD=kSEYFZscQ;} z0fxohD|U_=`OMyaFTpFw0X7MwR3Y;7$*#)#KnAS>gF&W!-S@w<4giZRkM`fb%S`Gh z3Dw~V9&5YFO(1btlmr$@|C|%NR%KT^S}J?xG%4h-0{=Pk^NS@EP_C%_@|c$m>=OZ9 zPXw0kdgGnP46h#47g<0pr;dm9uo4FgITj zyZ$6NX&%F(`Pt3I(KhSTq|V}AUKwuG7m(rzMV20$r;UAAD|@3+=Dbc;E4N2kOQ(LE zZ!7!BRDsb4gIicZc0${?yZ>RXH+!lz?+D;+U3?y4sm;=HzD3rH1=1_;acr)Oy^Qgf z-+$ru41inAsHRI5x20k+^EwyLRs>YUa{ypdYZ-1dCBV<>WHEGZ^EZ^0VNB7GrP|JZ z_-{RiUFfz?k_8>Sh33KL2=q8XUrEHp!#l&v=TQZNFRTlL3q3Ylph)&BiSyBi0P-xt ztOhZOj$BX=t^Ra@Sp)Qj-k08iP@d<;Rn2l5xETzWQ=OzG=9tGT15wt$H~X!twEnk? zZk@~?iRddOyS|BoYyZI(C*$4S*jdGV$DHg#hQ8_m-)j9nm#Wnan)#BZpLT#~igWJ+ zOT4@MVOCA=0ed_j0FbMx&=Jqhc=lDV)3Bkd^tJIp)hOu&A({qAuoS z+fl!%q*?9$u4i9VV}hEK1uk!$4)9ubPmUUHwEE*U78UWr?ID>Ea~ox?)tS_RX}t5- z36l!afUgtlc&a{MUp?=CT2H}t2CvI%qMLE|z!XF!|3QLX92n5lW}t5y*_U}BbXiO| z8TfHKSD2XYICalUC2kv=<1&|OB*Sc5EWopaaoqZ-Z?hi53By~L{1RDI*;`)1+J2|| zCbYRv1%#dTRN-ncIs=0ZRogK1@q!d<4dw14_{+dUO-vZC??k&QZ%-Z0mq&bGmEN95 zbq4J;B>uUIT7@KjyeH}mV(3rRK6=KK5oG*qH1&8Js{@a7fq3;(RjroCf3P`?asylf zh>|?zK1FEUJPj5$;7Zg%tK&vx1X-eZc-_p`8shrpK-UyJ?~h~nbHQ;^t64W?ci;ZA z=ZT&&TdFxxs2;NM~~Cu%i{zrD&9=s$Ch#GBc>XQY;ajqjYT2@HccV60chSjkKzf{S-Q z!8XR8bsKo`zlZm-=>?H$Ls^&X1h`oQWswHtS`IQw*ptm z(5_-5j>_9AQW-2@TGma~r#OL1xz*+^z zu{55G&O~3_=6J7fav-7CYo0wbSdabU+D0^r6O?p5X0rf)nEdFQv3bRJn&lQ|AI=%49qx2%>kIc<4!w9OY_`NWXdDkL__Ioiok|Xw&}D1FgnhV zt28Z7an~3=nS~b>Pjx1{#N=Vr{c5ew(NEZPT9~igcV1j_V}`?oHW^x4re8e`fFCa2 zsubD*MqKX{J%2GvYw(W6e=p!Z`k5^zZS#b;Qc}RJTHitESR^2)4jlxbQgW({e!)9jV&1aN%0p?=-soQa$>i8tK%c>iS;oX)Ebh_g5ue5i@UJ69#fB z)nv!`@Ny&ndU>m2uax2ng*5WHiM$AIX<&UFaq;ahVw+LUeEQCat94ajHsL~Ofv>r6 zp>*S5@_EFxpNxLn?=X2~JBtwPikaS`c~+y3g^7mDG=(#sY_%f7-yRfz%^Q*KLN$p! zt`C@XFL7eFJlPXIZs2M$T}d1in@_JquX+#KxaY|38v6Hn(JwVsd%iDd86QI4^`b{$ zxw-*=5$)_iO;t#3Gv%*HRhs^=@UG|D%Sgww=TBc=dJBiFqj|J2qRr*~MPLH$MUN*@2E zwZm7zRjSfIdbe87oiA%XhrUTQk{_w6pcRuP13@GL>^eVB@#)f#yTaCAS+U3BPx#x| zML*4C6!@7W@7(3mgP_Pu=wmx^03kBB!jx=|IdZ0x&js6;+<#KM7LMnbez3fS@or31 z;ePUPOKi}C5Ef8bAW}`;U{$1xKJ<9fS>yCDRXk|O*AVSjl>#(hTzViGjO9=ff{Fe^ zonP}jPQDEvE>+w@juw9L?V_pFjF(jd8d9t&0M@aCOMmYL$tmvZcxhh7Q3vWPL2e!= z720wREBA;o_rQY%x;9qRskRuJOmRQd;bXD~^m}s-WSop*k0b$fnUb^%j4D0jP?$wK zz1MrAHN_c?LXw%;+?NVl3gm);EgoU+7YM85vnA8P3bCnj0r6tJ!$6{uPWrbxhU*7? zfGWu+(bmR>7nMx!(RyJe`}kfDTWtqQ3ngAp>{wGA{B1P1Kc?t`KIrvs?8{W9?sNF; z%W#Kr(w-XhuZSrILKCg*B+6dnSJ3)Q>eC2@Z@8Uk-DKe!2rb<)Zvh`>1$mZJgB~g0 zSm2zl#a$>1yN}r<#Knp$q(!E4)W0xCTu&7QnBhwa0`aAoQVvi(Pc7SZAADMV;YgEp~vC;#cg4-G9cvg5bV3v+-_K z8W0-e^k=IlFD4A50-}(!2N7ZPYoZVpC$haA%i!7XEtsyP@S{-BZF?)@`ZurpZ(a>S z!^p=azWMO2)rOz}0=ckufpXXn!24IZ_5QJEj6Nx!eth-1Hngz&RP`^6 zKVJj1G*1%d`AHp1b+;88S5xWc{l z@JZ84?vq=p5%J-?4tescv#|XO@g9k6bT;R;6Xv&KqsOt~6^1`Xy>(H}I zRT$G;kY$bUi)h)LLwDr(Y7zs9(-z0^*g3^bWcT>OXE#W zX`{qgw&DFQsI5sD&ZzxN);WwzlO|VsK@mC}6Z?@LU%DoHI?71(y^+gnm>vOnPU3ww@kL;9&f~t+0#->DBKP75kleHmnBJXjK_dwpAaH%q_ zG-Y05F}}CJ@Sn>SV}TX1?f7(O<&S^THria(sPfo0utOdK@B)`>S8=$b!WEHR%W zF@@&3iCz-85;R@1M2B4KmZ%$<_H^UEEs}m*1Xa3XBA=zbuL70jcLE{@k3h&MHsB4qx@wuG>+b{<8GAaG@aw z;J-dPQBA7R%WqLL&pCZ~8IOBtrMgZiZl)PeIUP7$6D@7utiG7C4alhpY|r1Mb~9U> z#NCcQ+u9UzLMLkvzp(2B?x%ib#sloMpaP?JsUWUxSj}U zW8Ndzzz83!JvD5-5k6?bC{=}6Jqk7iDPNxoy#~?I1oDw@`BzCSlyX$8WqVNieJ+1i zgJ7s`@4K^xwk3OB-+1NxZnvyEEH4`IrGKr|2CARN#hK?xfyxh!DH8Trf0^&FQ}HXH z;M^j{`ryQN_n`25BcM6`>ZUe_;n2fys%t6#<}$R1qk4a3I}7bH2|r%PUhbi85=XF) z_zJ^WF%f*zi%{EbQu}A+9TH8RU`&`wDuSuXTVWIY&|XiOU>kNM%kEF9C_od|m=F|p zDyra*I!JVPOdnu49<`Jd!7rOAccZD)Lt2BZ9-$I&5aRwvB=q@1`z&U7yij;;sPpHI zfY3_}J9P37?c4}dbU7JAuSyBH-~7vnl)ie};CfS^WRqi`_M*Lj?;t9R zVWrmPgpj6oytBAE9bkXS!t!$uJ=6ZiG{Gv2x=*qF658wSxvxpu%P23@e#I*^Trb}X z)6F*g68$XaixzL#7TStATAS0Y7atn=vHgl)p23IBVq)}c3@<=t#<+zrXy_rDr@p#Y zB|Hcvt`PDR!6}sW@wY>k#U=;V8XaEmnIZlVp($1`pIjfie}Tk*2Ur9r&kSeG;Sk=R zrgxr^=Ha?>mZ>?U;U)A%_0#C6Ls(pi183Y#{^7f|+gw74EIAu&Xm3ehc-&%AImCZ* zeC+z7)yFOr#F(?8>u`@1r2K1?eK`zk!v3@Q!~2g$Yzjz+A0np(03+>0{~uLf0To9R{E0gR*TvnPUEG4Z1b26LcY?dS2Li!e zg2Un#+@0VOJmmKK-`#t6?@d)#cfanb>Yk~csh#d$W-W7Veui}RGgpoNNRvVlK5ywp z$VnvmPyD~3{ap}&eezvwNsXBq8HeA>mURe6cv*ck7d*r_XbAb#?h_UnwUC@o?hU{c zamZcthiY5BYMbEr2Jc-!!eO4KUz$8^V$-mi5uH|qu$4_YbDtv1R7?~OOLxnNOW5Uv zdpJ(*>OZ+5WPA>%`jV(WkFT4mL(5rSgo=QTKutj3TNh=48OI_ax4V$i%+xK70QcD9 z_7p&+l-vFNJdolS3hkt7qV-&4Y9Pay`-vH33gP+F50E`e0JD{-N6+nVklMvaxA)1w zreo-TPDN5~6zmBuTv2ZC8-H~l4I9@8hfwdji0;36(8kpVjdi5{@FWF$(wu0Zy#U63 zDW@3v&3x5<*FG?sXMOWN5O1_>DO0ENTFuWu`E5vRN}4eA*=gqL2hH7*&qK_C3+U@MQ+_hVyz7;hse^A72}k3ogaOK5f2sMSPY(Y&gU0ZeQhvW4WlFq${BuG zl_x(3UCLM42mGzYud)~NU075G%Js=L(Wqv^P0*z((d5bTr2%B!D8MB&(WwAQH#D&M z@T6~HB{|#&mp%Jmk+|C_=-auO;8f8lS zu~t=pliq#ckvBxmE1zh0^n_XBzD0p0BG>eLqf5Dpg5|9Id-!ADoNqOODv9ZR#Jl@$ z__4oqM4N5vtomP&dF3-PMzF!vkknXh`WWx;SWJd8z7aBh{xISN7|&%h|l} z3MSKb=FkA}=#XVbl)IiTkJc&}oy=ELbP;5;`eM#6+Z5lq{$c>Rb#uX7$%kU8Zwl4` zna%@-yRha4pnakLH=fS1$*You&2=B73>U}v6uPJ9P2ngW&T_d-7YjNC5LX&)51Vc| zm`VxX_J)}Csbkb-=2)(Sd_0Tey9`vbo>(tKdV{gGsaq}j%wRNcm2e$)Vkrvpm`$PKn#LEyarDKSp5d^&h*!iTXN!EQx#18T*?@ z%0IDGSngGFsT%|NNsV@){|&ZRzMLPHs`rPi^TX`D08N1`uPcis$CoaA(%m`Ay>*|W z2iXzxDEm}D^>escw!o!xI8lR!HT(K(gS(~`qrL4D-um8spId(n`s$3d!%Mnf zzl+~JWIIrQ7q8yfZ9n9)&nqXn)IW=it@+n?6od!$&C1`9;1d8GjiiEO#VKUS7q{2hq>DD2onY#N zZ9#U4euvyl__5p+yH{Il24Xfx^C@N7u4{waC;dIrFC^yt5&<6(8Ib|QUF1;QhITj| zV%={=baVKN1-1|+&$|E3xe)q##TTK+*qZ33-2)=npOCnCPVaY!;1Xh@qWgHW@$B|? zZ>j=4#M&ibx2q@7e@;0?NZe`J^uKwQKwqC7MTLqCb?wDkgrH2g(;juknhDalRB1{T z;t`^=dutREVtC(&Si10x!xAGU_0LnlhnU)mde!D3@^CBxu|*`F8TJk$@{rqcu4n=> zNzvV)je|<_P~q-Kwha0Qd&7kKC)CI%n!^kz!m{8y#n7BF+(O{`1jnIMU-~EzWe*U; zg(wQh(cMB=KJ=1d_yGrC>c6BkPX}Y+xZ@|+aEu)3Jn-+~6!6kF3gRg7$3<|As^hcp zj2wl=C~hHU+hm8(v=;nn4XG?Ax8dR_nzskyWH%I5+gKvKyLxmsJWho8EV<12tKvBeE96-@jWzINsB>PoY+VxAb zJ@GeNMc4Og57rE);svXP_T*?s82{ez(k-d^E9y7cef4ByjMM;G02p!XzqFAv)v(*E9}) zE9B-AW=l9`OoqMZcG)+MS?t76q-vm*j>Ie&+fO-d&OI}t(0$yU%=b#B@E&}xdS@V3 zD3f*~ac7`dI0?STy%S0k(oQ|`J?xAX(oQ=OU}V<`tvC#(eKBVJ^GVBuwY4c!53){L z?^}lB(gcQ`Wmbf_LlT6@TYba^Q@mscQBGd4zOA4{*V9wjK>IRpqw>DEXQ4 z;dmfwB}iqyCRVLjo`-P*4C#UaV0J+Q0LFdcjeVyBn~3RhnXu!+J`P&+8+8zINHjxJ zKk%AFgd)Vxne_)n659xo{O^Nf-2zrRLs_I5ji*NLN;2EJIAb6LvRzTeF%AZ8(GVKQ z4;5`@fQ%#Tp$wf2l13d$*j3~oG9EfIt!b+sax>n^57mp4aYQ>D6Q!Gc%2sj1dolQY zxtv^?c!(%xWVcFs2t6rlWIK-Z7=n^OJP}4Z5T4m2rF|bS-Fp`=y=a7) zK{QEQb(_3atSNv&CzR&}>4(By-T=zsxHBSiGJVnD3srE$z0?QpNn8MQeby#cZNClC zm}JSjX9LX0owrZLVUdexYW)Fks`FlLN~ct){F;rLNufg%gDP#eKJK^7URIPPFf=}V z<^+Bm4D%639L)D4hBz4eBcC`Jl0%C)m}$2zsZjjREU8dOw;xiWq;8^d$X*lK?S^+0 zama>Xw2uvwV)5qm94%S0Lr9Z2Gi^Mx!9 zd7I*;LuhdyirzwR=a3(t-Y5EZVJd+R+b&cPkiyD@xm> zV{gtbE;z(^F^xm+qj_oCwBQ_Ap)pPY>fm-Ti8`t6=Jt$~_ItiC#=!uO4DsRnJ61|V zECRr#A!Y$1r6J%|JI>H%tn)6SordiG0*mHba(wuJglk<~B%Z=H1{2Q0*6e=yijvWL ze4L0BfN7778pWv3TB%srt$rK~c$A!#PPSx$=YSm_r#vm+vd319Vr;w?<&enoJIvpB zWi6bCs)c~EykBtPvSfA-O-!mL5A94G>x2$pisuOJcn5r#Sox&&lvE|$Iyq-*`fR@+``nb41zR7IOx@a&rQhCg4c_`uS0R*7BTr^65Y65)6aIG{vF0Y9$gFmk!VE+ z4`gEC{AD+}kw_-Yl{*poAkF7b!Yrg%s;-D{!D&FY8=m?SKfXnuV}Gj4VfZ$9MD`7? z>8J7|5NxEbTE_5=lkuCYhKo@i-owH7-5w0h8z(0<7q4ihQ+|noHPW)(3uU@bwuh8) zLWinbLQPXu3niL*VijfJ;F6}X8nMQ^(l4QIN0w7Om=BH* zx3QtO&~-HlC)0IJMsBMGjYqyU?VC^trQ;zEnd)l+;=_A&T~!hOO~r=$?`GA4veD<) zTpN-(2(HFwDwgkei3ssIL)J+#X8R@AXd^6d&`9vr5N5?}Kl86mMSWVUD3(vPuWred zKbKwn+}f5J#C&EZ;0AsHU|H0tATF~eg`e!59yr8wpV*|mT2XAS z`HG-xL?cQdcSRw5z(;q2lIS;}#tvHMO5QAZ*y1JnQ?fbQH;qoM#AX}iK4pqL2AUl2 ziCqoPT#qw%Ka*B;dC#QyV@$1?F&&4UXO)E70WZ9m!sa#>4HigDOf_Azl@8%7Al*Y4#o~{D>*!3ynSlyQGKZblZ zDQhhK%C)eP+?V;#TE3&0OC2F27o7ee1MW+BxQrmEexS-Q;xWn0R?JD6S5M`1L$$4q z2t-mqvPZJFw9~GfhwOUmoWcp4SN(uwDtNXb*T*1puOM!mh7hllMFbW#^`_2zr0mR< zZ%;jD*yE&L?vmwVNEe1bG8p6rgsOdvac|%p=BGw|H8b@=Iycx}r#WO;a zg_$X6(#=c5PVLLRr`04R(d0r?l*phhXog@1;EcjgZ5J>T(U)_g?vW*Sk;qSfDORdzMHA);XlJy5G#ja*LS{1J^gVf8{fkY-wIunaN< znjO@7NZmNcn8#fQq$TkUxjd~jE1io5)YDoE0M9Y6jm@N{sEfF()6Q^*epueY@Fp2I z?^Ji$8Cw3?@MVEid*pWPHoxM3Wi-Y#xP?5*NN+x7Np5m8_cWghZH$i@eGHBGGnV}p z>=a)igDk%)4S|~rXUWNV$I(OXw$F~ShXHpImsUm`5_20;rvh=DsFl9wNYmM_%R13_ zhRf#=v`XllNZl{RUG#F8la^OMN-Lq77JRa6d)a;6JPr?p7M&;&h5XO5C`8+teP}m` zKd3dxCxKKnK)W$(kN8?NRBn(40@^hvQD%P)Db4XojH6lMs?F9brf^?BpOs9 zQ)b%8q|b=JY%9w~*O}WeBcDU>O9HO5SggtP8gn>_P}f5Kj;xQQkGz3Ii8e2h4QaV5 zv09n=NFi*BYD!Wzu&0k3u83q7(p6Q67%&af>kaZanM}uo2^2rtV4@DjYhsOW2$DCUA52k|LDu} z85N=+rztPwRLrI%l;vr{|6krBS=dw=At4&AtBIyP1uch%3CSHP?*FPA$AbJ{?mzV* z%I7uZCX}s6xcxu1ZkTRtB?ss;AtDok(Fe_ zZ9y~5K*kLfTo*AWyC_cRM{wzXU8+Z;{a-0Fcudx*JMNgpRzMc^F9X8hTo5iScqHPe zyqc~vsv(hQ3~2+>sHsA9y8Gj>O7tkSA@PRLlw{2#*?}m;?G&nsrj}YrdQ}_=)^>+0 z`G>8D;i9+)FXB9kq#IRnxR1C##4rJir0J>@^=c!(Hf#!47l!GWt_%8;oi>rB}j z`GCK0g66r8>UWYX68*qm&QA7w_|qRYx%)-MJ4C_d*vqsY)NjR~7ld zTJB64c&D}h`-#Hw$lfc z(2wQQDAl)`=nmMD9Mg!yQJu*X z+on@xmTH-0q*CIvl|Q}GlJ8|J>qetY*AQY-F8|yAIropox0MK1jk6Ca9pMBEiEqWr zkn1vO>a)cYrQUVf?9ZpY#Kwq*C>QR%lsAV9KPN%(vhG8*1^%|ay;TbO9@e0j1YaHt z@*Bi2E@L{;32~8l&s^3h(XL@S{b=D#@h(r5mm4}x213Hxv=O|JSKSTdHG?La3rU^- zaj`c@rrmb#qG!l!LJsrttJY-G_JhQOBB(>CDkZ)r z>N*52CtGv!L^%9M+&mExljjnphf&Fdos=}nPDpa;E0Gppbjn^x5ulT@ynYiil^z(e z$q0;iNF$Lz7)Pgkag!W3>7=yywu#9lVML%#Q;(`kU5}zm4~*PQCy{WPM5l~xr2Gs` z)Yk+f{2DT*xBt&$lSUH>9;y;&hN36Sg$@#xZ$`4l(ZZgg%vbRF+0pOB;VqI3yyrBl zw82h_&5C5{RM=Y(Kg&!vBXsoXzbPG%NlfKFM81RWtanXy?Y!kbuq@L>)}+eNJYuu# zQZI8*HBwDvDquzGxV-#Bd>x|C`MZi;xlEllr{ zT^H_e&j#kdu{`-bSv_ezDO@FzIgtqqqX=2~)IP5Mb{#%w8AJc%J*zo8P#9TQQK%tg z?W5(#c2oNpuyoHj%Pz$3yM6b-E0euA1v@=7r7``KyOOOxC7O-smvGPYC->~vVe8O& z#LBFZwDTut(QCqMlxwDI^lii*6`$baz+Z3L&h+Fe{rNlf#JrQ&haejK z6Z5C$Pr%QhpzwF;7p0rLeee36fS-0hkAf0{R9-J11&^N+cL;)ZocWPdxkLDN8tU$BLrw4q=2YnIKl;`_(aGJ z)lQ#$n28w|$UeUM^y1{GVH(ChxpuT02C6oiL@0X`bA}AFfQ~ha; zLNHXe?xQ+_*i-B>T8O*lzkchIZ!15{IkjQGd1FNo2`if)mgxAo-L9d9tig)TLh0BI zS?4kj_EEj_!4`K3K5G6c-hVw4^|Z@eck)iDQ0%@Coae+bS?8HmjOTCA__>6?EtPml zwIOhXUbe^$y`1B3y?$_wx4@1=5!3W43vbs40D*9JW7a@?smRRqX6)NVk#}$lQw+Yp zMQh(y^fbQDf1oli|1AMd*wuZ(n)S%6X_EK|9RC;8#J@VCBIhffC4z4Wlh0n5joh%G zSZ#QiV|e)1J^slfh5Ul5{(=f<2_s8O!VUey!bC`+RQ0Ejy*{1Q-I*dh!Y)4}2j-0} z7Bmblk_q+?B*j5`*M6wy{2Z(sT^>Y};t*ID7bto^u3;jOPZ+ZcN4TKN4UCGP{4gpA zF6DT2teBKh;)3j!t-Ahnppr9qs-r33Xwc% zLMOlvb^kU1TXy(FaR33(CV^5o1Y7-_Pf>nQ4WEn*_<&yP-*Y@g2PjLB@7`b>!bE%T zVeHw5wCxt(O@vh2Qh`%;iI6VlT1K`KCsjwL-ZUdp!`tI{ymoXA@`tD zOLnAgHX$4$Xm2M1SZQ z3enq3^grQ1W5a>cg>V!fIvUG?QzUN8E@X&7EAB+E0WnmP(H{vkWjPr#^w$AiLYMB`^;@2El8&uY8L{X6}){X2uV{VKaYyUqt^bT!}vs0e*K+p_2IjFpI>G z$@lK_-f?#4@`~Uw_}{q${8EB30Izqb&j4~~L=4||Dv^P)pTqMbKVdNbKCe8taQ#C7 zq3!O#M9aPV?{eh)g923E6y5mJe{j2Gj|M|yJlz=Ip7DKRUOw|(K=uoL}PdI&8Ww)F}~F(gm;!p-V7WHPYo*6hA;c^N*^CZJzI zTESmgF;waPSo|ZiqW`1M$$qnE)7a(Ts_?RT^4NVLyMN!6@8-Smtg~>vue_CYbKcq_ zz#$R%#P`I_&RxV+#Mz$rlh5DJ(r^0D>k{*H_nd#*liRiQbwX$nd=SCuJZq`GdV9Q6 zVD~Ri{rSsawWr5hSHoW=rvlb}GqUEk$K!6JI!$B4(9nt0VDc1k&eT7qsKK%+hxNms zMRNI55t6LvtY^lxTqfc<2H-T%;OzPt!M&BU^-8b1GDajm&%flRw2|9G5gq-`=OVCE z9}%$CiBpZfT|3wHKE32p(>`o{sEw>yU$!oPZ2MofJ{kGX2G*r6;r{l`gG*fktYeK` z^Ogkb^j}ZR$t3Q3e>oLQcy>g;q<_tw%aA6bv2{HCH3}uW&|0z#3aUr_YiHuQmJ?;j;2UO;et`0^~ZMQZ@Ew)Cb)ieM!!N zJ}v&o^m}(=@Xp}R6$Nu|s()5wI|)J`f}Q_J-rrage;R*iB39t+zMuv5-3rcOKeP34 z-`GEshaN2`4IC}}*mXNob?M~6F<>J_Wy`ukVapOBHDD|F#Fo{Etyz&5R@1`#O+GrT zh6hKp!d(1I7bI7NQM2$;%oIr5q3g%-;AE@&{N-8x8Lxx0NeYE2ue`X)==B?fMAQE) zgirXLl|tmgCaG8X=LjAgVM@}Z!sI^8K&>v^KxGJN+5LDUsP4Sdtu}aKSMR*yx25Zn zBmS|&vZeP^zOc@iHtYA>;o7T6r{+I-m$r`#lj@JA2c3(ihk{khvwE|v3i1&)gJoy*8G?Mka5HG!n|i)Q6B+RAjzytWoOf;6>Y0k>FcOf336Ct9*CPX zLKbPe;6Ia@>|-=Ec&vSBww#p{)o+uJiV`6rHbRz=jC+tB>aMUj_(H{(^r520i1cO& zWc1X&Y=v4*_d*DWn8~|C>{I(9c+-4*Js3AVEAOm(oBxoB_x+F{F9{x_7KEQ|bX(nD z_ooQu^N&u#=d{e9NbhnAPy&=F^(96OzlQ8F!&fMv8FeF-ZNijoqE<}cdl2M&63~}P z*K0-6*)ylb9r^O|L_xZsK34@n59bX5&iQ$fd5kSV4|f`4!2DE>V;W4mG0=(aeDpnt zReQNzNkvgnF&^#c1V!c#PCRtDGw#6KL{!Pi^nihv-zb2)`K*j^Q93RqWLt4`Lcy5r z`-zf86ZN@^3|~z}^UE15cUNKAxB#3vfq3{@fE9;*`czOLTi$Z?9T5adhm#3!CXeA@ zv+StVcB{CQO2+ty>Vmi3i{gyFax8-|=X?<>p8I-$u`+XpfMDIbm*2g=gC;vZ8WSG1 zAFMk|X3650sQJ4K3+1QG2p=zkmZ__Y@)DwZ*s(1l3s=IfnKP%~(kWUebl%d9BC&c1 zX(r{lT(MBp(v(|yU_!s@!$kiyyeBK~&F+U6aF|uYI8gtKlxk6leWi#QF5RD!cg@fm zu-Tf#95kyv20mKh(Dp)rNPl+$psg2HG1p)Ob%UoT&$3$!TzIjAm=fe?5)74AyX@D*5Y}R9s zMd>B0se0u{36ti5{_WzJe~6HjuD>dicnEjCs1tEQ%~ZOZH4hTt7Bhq0HV`$N`T#l2G;rAMmWa&-IW8@+SRs zPtHisplXx%0-ShTn~;c7k>&Rs!p4tTI=-}MzO>ORFdPrfd zAF)`|z-Jh-=01sde>}7%J^PcZXJ4BeYR+yhvq|TGZ9n|=SB5|TNM3fMMI^{tVY%IU zO+QN*$l6EYjm-@Y=1_K1j4Bt`fG_*E@V19W7d0UFT8OJ3gNQUo(TK;|Urv+8wa#dMp=9=biPa{16jx zLoO{BJxobs*zjhpc6|8WMw@d4Y{u|Y{v@(0eC`|Y0 zQncw5O&Z86_vZ!SY3%XM3^AZFyl<7XZ?&LrmD2daKcKN2as)O)1pgBM4Gs>|9#fmu zENj9pRA0Tb_zZdlTWY~-XA<#Er#g$P$t;6$bKk91zI~D;(MK!e3x?vW)p`gl9jD8; zlj8HtzeQW&=!s8Ktp^kj$5oU3)2sC-C}*|& zqUq$nxTw20E2};&$5)2;!M109qHny-fjA>@k#ched${=_c|?I;jAY^~2&p%%LgI(R zZ|X?(Ow$X4Gd~3SmhFSJg)0Z6mH6=F17l-4qu20aREF)cmCywa;HYf0+Lw&S2H2001=Hc;y7*>$g#ipj<+*?deJ8e{@-Yf+P3ms53Y^Gy=>4^t}XgYCRM%;X}KO97;lMhA%rkyBc767cOi|^f< zD$OaYvwqw;BZ5TOV+p?RXom`xl4JZ*v;As@>~0)mBD99HA(>#shJ~kTn-^QsI8puV zMd5KZR{e#oZ`+DiA zd4y5x_`$}KYH`*$k+ubL1%g-|sK;t7cyp_guW)_*YxOE;Q6m-V`4@eNck&=lSS*hhq7q#^jYgtqeBqq#HHo5PJAUPH!8e)O@&NKzUOZ?45%{f9o@ZF|aW(t5f!b8@@nZ4z#y+4LI^Uy;fzVdOg`2HiV= zH`x5MnL7`fIuDQ38lvh^6A|HJ<+J!KYnK`!-=oF-(SnOnJHJV<@q0IG*ypAlR@a^i1)ficH%X%xTlXo`<&%O~Z z#jyf~v9X1Wd(3iVmJiY z^p5>)SfxgAUvD8t=Jh5Q%F`w&TgWxVB4)~=xxtTHil#`!w9nh&&$(dC?o)ISmhr3j zx`@xr-W#{P0xkM@^@v4_0>8;#fjc-Bw z*uy*soPRnhOPQrKyP}HNJoaZwOu0x(5_!;p-P)ZxyM;bbl;(%@8dY2uKh~PWWR0LbJUosqt8kgMLxg>3q`lEbvj+2@ z;}gf=<*>w3$tKjdt!>B>^kZZL*0!EuvAjT-Av|m#;tUVIGz&cIuyUP^)gnVJE3QT? z%Qdb-_p$+um8W}Uzdy}&_|@IAng4x-18b&tn%n5G8mHySf{uvhO%I5FTZ24f${#ULC#mdr`i&$Az~bgIQ$w~d`ecLs+N|-ley8J zOH!sidD~SGM;h;+MygU9_Q+gA+>loS8B&gx{l_p<+(calnb3S`$ju_;3zgWH+DJi_kIlX_ zl1-2Ignjw5r_xSjp7$@M+uCAUTP-Gwp_|niR!C$D_P$XbQeB8@urE_&jsiuzlSHH* zRn|#f0qn~LUdrB-Yd-V*eW=*& zH-!CS0(x_%7@UHONrx@?>h;N5GzdY3mAzR1+&Lr#f2$0PEYPTV+tF@tC(kw<2{^1& zHTz=tM|e9681l6|y!Z8#oHVVn4{wL+$crsQUr*ZOUvR*LQqpB3Nr&c+>RAhuKiX83 z0W9>nHxHclN<1icvUnF{Pt7Mq$K)}6oJVJfh_!}#B9HP6#?xeqzut3WI=1{YLdLmE~-guyPwxP4dFV?j&D}@bYVd!NF4(fx%~ey%&{DK;jNyt&OR9^&zMEo-kI-0 zUJyXbHNvN1YQkx(Ic2XNZ5DU1Y@@c8p@gsQ{6Ia5*xZuo-#%I~B8~8TLN6l1j@UIO z;WR0i70h7yXy8GJyVR6vVW<_DhlPD-U^g%hWA-8bCWFq6?Wgw1UCYwUV6E{%=X{&v zwaYd(v}$fPf6eUT%pWpV;c$j)9B zO&4zgp|RaaShl@1uV~R-b{W2bT~vW?iU?Q8!$=8=TS~$v+Ud%DI+-JNajH6uQ=t$t zhInqZLbd`#5j$HV=G?iBvVuOcT2B^lRdacLz4=lI8;ZGS4T12I)_K3mMfT|Y*7}7= zt@W`l`uzmzbH0*sCftT`-~hN2+}5Qxj4EqpZ5fuQ`rHze5u1+D7AMCAR1d$gSJ}U~ zrR>r1L;<81VWXPLK}F~$76@BZovkC6vv!>#LUf=^!+ax#GNukfefHnJ&R@rlWLB~ied906Q(;j|G+ zXcL8LtneZy9e*}L31O@+ZiBd5Y zXOHLn>UpLr{MJ^B#7tnoK}t_%RBtvh1XqqY@?cGOg5J@+=?lL&EvnhCsSzSc-$=la z*+1Tn2a4g(>v4^^R5Sf2!qyT?>4g^gpe<9w8T^NtIc0NcZvZducA$gp1+uE7DKr3k z9j7>Re~LLvsTD5$cm}S6<>~WP(x3dvuj6$SZ5$Ant)hymLDg=&qMB6Ubr@~n(m!st z!j|!{2Ht!p+giHu=~>}PxUe9)SBUN=RN!+okCtC{Frnt0aZm;#c%~MX2_OT>5d=m? zxCQepN?htJ%AWSr^u1yqe1MkUS^|SKi`EN-e~UeyryZTy>Lu%eDEl1a87_R5JxbU1 z$8u*J203!mPb*=$e-JHp@qb<4Y7BE-qSHCi7&14rbGP8X9{(~h98a1(PdXlYP+2&} zI<(#+@Q7m{1G3%Yhxq;#H(mpCzb*%h=@%>^Cf1j+Iqh*3%c@C5gO$`b&rPplQeSIV z#jSDs&V>&LM!}rLF;u>Uy_6kThxw`A?#5bK66H@c+fX5DM zlY&TQbdo(e1ylPEaoqV8xV74BhLzVG|Zlk5zSZ{Ku}ci=d}wEui_fMYCMgMFVDZ3p%vag zt(cle-z1_7oI36Baf)Z6PKk!}77gLxY}VRRv13m4fgibH={MN%w`VY0L3)OQJq`)y zXw=I?%K7G|7oX!YDsfH>LIt=cTLS5+c}o+<4=}!6vUc}&?(6uv3D)E%f_gvhoP@7y zKV<>6EnvoDsz)pnQ{Y@RG4+f5-5`slyc+Z4-w z^u-p3+kewZQ`6a@r(20XNHo`cZ(6P|gqP5do`gs8B`9!x?hp1Ove4)GX$L>&0S@b0 z))I#xKVy-}=pi4|lSBhk^~smwn_=vyU}0FSB=NwRqD>p^PY7Iu_!9(ZC!N2_#2OL^ zw{A)U*`^0vj2zN@CH-#|A3p(B7A+TJfb>lwt9w1}*FWgojH%XZ^~i*#O?&X|N)6(M za8PAR_fI|B`HUN;GwLh|C{g2_v)%BQ8(VkDs+7a*VJGG0034&o$tYK=`Ec3}%7f{~ zHai=5eM5nq`2XGr`qX@Uvjbt)*@ix|3072{Eb?EmW-4&Q{nE2p=!&yxYeQ57!}eVI zr$5HZi4JiCYxsNgr)v*h#7ff?paqYOL#kh;cihrxtZMx_3*`ZII`bqGzvolKqz}R-Bo;|89A&! z=R^j@3t92+Jm^An0R9-dhxoF>ps$1P@F<|k2#Y=|)@&lT?Kfz+8ZNwJuJgB&$4FFX-Rw_?G{LtBN3a<9uc=os!zzC6}8tJcf8i4+(i-i zFy%tlMu6h;1EH5Tz#i7d7|KR4WSXdh+H(4Q>O|-}wg>wt%}VR?@THr^>=5V2R+^>U z#axrGfC^;@`8JjVXxC_QX+Z{g$-$-8V9;Kl1qD&)dr9V?jz@Fb`{xpKl2P#;+sqFG z{O+0^XxmOri@YgCtj3i!w!fP(>@T~+o%snlZvBG1)b5JhEdNZFvprw^<8+~$%r*C# zPgvN)S`4BotIR{c=ECeG*HT`wg63PU+Gc5ArdbH=2EUE0Jpy}BJHPP?gQZ%XoPLqT zl`gj+!OzYKb-G#Rb!m$3)Dsv^-8DN|`SP}Bc>^bn@1A?d)DpjcGqd4#jAM3LhK9}C zfS%1p0dXxzmuO~l0d>ZRE71Q6*y;I+2#co6a9)3P*DTuKAAAwRK)by}K%C%uFvtJ& zL#SIirlUQg3g%r_r^lHZ4UV)e%w{C7L~tm%jpFIH{K>5`IzAeiVaXosU}QkEx*aCf zkCvJtLDr6jHFQPt^$n9p+L1hud4yGvEAH%UR>j$zHxm zvHb2xayj|Az(xhXDBlHT1fWRtXzt3Uk#O2?M9-Y1w#7o?yGd3JPEqaod*Sddr-Ro@6HT{n{D4hrSEkVVG=UAA zXZt}^L5vibD!u;9SEi0v3{fI|Uk_d?mY~9dm9I-3!*!2^&lV4Ca|LGNThdsU>ymm1PcSd_gbTOhnGPr0ltLcv)8L>nb6bu4wt4H9<=j2H` z*mgDseBbheNy{T!`zVFqBOVBXJgcvI%bfOKvUfV1*kN0qah8FAunE$IHk?&^+cdz0 zyM%EirS1T>d)k%I(C`aF>bOSGj+0)*h;4r#66$R9LByaaaxg-c=eIm)lIVmWZ*<=z zlub>U&Mi0@Eg@bfYw-t|Szkar!RgQx75-!beP=FweBR72rIb>j!Vglmfy0~IOTNkL z9!XiGA%y1BT}uaJqM!90UnA-%kzTH7e9F7i4(T@v9`xeNF7s`StFMN3Q_gr_>cw3c zdt}S@9E016@mCy2MtDd<32^es`rgbA6jATCB=@4@l{dZ)gbhqvMLKL1Oz$KrTx0dT zIUkN$HEDFHFY|^gd)YMx)g5d;+*@LH2mhSJ4H-?2a}MEX0x|rawk903F6H4Zdlbgn z$@;wNMQD7}Z2ia1g1(!=uC78leh{EM%rU&J((wMCk9HmX8$t1|-nboyq@b^0qiCQ` zWI4IO&7^WQAc#Ki|)fD!YAN9AD_xqn1j{}gr< z&U$9>2h*gDQ@;MW3NO#zbCoB5bMbnGAgP&KG4o|3Yjx z_a5|dl}B7kQjw3Pr_bji#{-H>YAB<)L#0Uz2VY|Mbp?O$Ze+D7ExAQhW5AC{$SA!{XzRn z)q841H6Lb?R-5yQ42}DNXzF+_oNnw0`ze{{N!cS%!1Ro#NH=T{&VNAG=hD8$jJsd% zHeXIqE{J|Yx$ED2{Vqk?CyX?NsrYL|)Tl8xyz%TaW@~#S|gAV-aue z{KJ2&U61{Y2l{pE`Xx5ll|aVCqjCKh6Bt_$CW&jigw%J|lZMbb@SUsq-y{kHJ>5uW z71;R+)}QEI*)~h^6r$a4{Ikz8{8y7JKk1*D{KCD{jg575%*ZyOR>HOdw_Y8_6G$tD z7j}=Z3#W{VE$I`n5QMw7&KYW*5XEHMUe+1!OO!mc!yU@@T~$(72@*r%g`y~=7L1w zhusM=(pw2xN?uPoIMmJPhFZY~jZB8+R`UnEJ-KV?$;*5-c_VGKE~Z=U9|4gJSUjcs z%jLEmxEfQU^#lHq>{1 z6(88)Yf>t4)SL;UyD>pQWXwrk8*`(5TGKy6FS2($Ef^N7-4FP^(2PZw7y|J5T{OhQ zrEmdc`CkBoKzzSY)yo$00yp72kZ=x`T45&emOQIrbUYvLz}9S<`HQ<6TFo{YpBO~) zP6f@`NnB{0x5tkagty2S?82XBy0!2!8Bl@|Bbzt*eI57Yl;N6x$-bG-v&Gb3yLJS^ zCBy{MrP&K)Nqj{V?By$WsT~?ijVy8S`@En9Q$9Ga`c7k{RATS*jFo9F1@|jcK6?#) zM!|^};)CW=GStYh`wL`|>AcXu?w7kTyt;)?XJ1=q5Chwx(%7hpk_B3?AMrQ9*qTOo zNVj%A5e5a9j~$ZY8)5u}bZ=pI0Zs2YQfHsqsu;e?5ne?#z zre5>)?x6IVILoFr6WE55{S!1kwu?(!Hu7h+fM3Ib@d5|fTN!u;OJ8>@F|!qJAc}W0 zp)fU7(#^$=l6K>kitpyHo8a31^&yE3U^mIL1?(pJZ34SF{BRCA?3;D>RToQ0%@jfnEoWsEJERzs?ixGu4ZT$`#0z>yy*B1q1c01%wu>m;JZu#@z7acL7$q+rqS38#5-qBTW!2Or7l9iM=(1SL;fM4^x%@2 z_6!|+O4eOO+XU-(TBVg=hrjlB<(3TRwo!P!$lZ~$E%AR}hL#NLeSe!VvS<7m?DJNL zlZkDyajRWM5UW2cyki%J;T(G~K8ZL9bi2hqi(|-I_1&EmZbLW{vb{A=hVXhpGy;3H z70x`BQ*3J>S7kA=UQ4r{i*@olO?hf#S&HUoU$PXJi_TZeb`)-cc=N`Q zO|jsy8^>k)QB!HhJb1B;d_94JPx<37oV*diWAU=8wY;T?k^l{KJj)VXAp5AM4FAUN zmX~yYR&lkQ=&pSVPkr$dLN9jF+hZ=H8;6K-;hmDk+YsJ+Hv-KJaM*8t^odQ$6>&_FyQ!B`svV93I1c6c{Uix_#7;TFn++`6DISG{elvH3nC!_-HcRDI){wJe?D(=v@ zlXYCN5CnVFQ!xJZE_(24obNiyO>js|H-SB+>q0qXs1Gmg=G3BbOcJ_Sobyfgkanyl z^LUTXH}h_SBNjJ-Qg)*pnfKwvToT&#qj;zlz~aB?Zj+oyrZ6+uDYwzj?)H;;9(rls zwtRHX>WP?nHPj;*m?d{qFX|c|o@?_s^eq@WB`F;a{R74e>`SqT`}V?C*Spba;jMQE z_~ZBN%>m(|OH=7`iF+MW9j*3!X-;I(Lt}M|k01;h?2hm}%(#3W*4>3;HZAA$Ow|Sv z<}qS2$7-5~QDcg|K69XOY|EyNoxAjTc3Bz$_xrRQIaI>OK@sA2l@Xk?L43SMJlKe* zusK$Z{ILr%g7#*LV|%R^seXs0f&GltQm@VYJ0fPc1YbXL4_|M7o_-9@cYwOC;x5X; z@8r_Ob3P1(GUNVjN+@~!e4^wH#$OM%sD{U%)`}YbR3H?J6XFNJ5gy9x!sj{s5?3c@ zizaoQQA}&>4#2-e0VbgYIv6lVE>!Mcwzv1@j=S3qd|_-&IR!gFgIUmF2=Y*bGMJEp zAMZag{_6v~PyOJ|>-WaS^`n11c53!rci(-paW_(8S67}1Ouzb(6LT2Di+7xy`&ISM z@pYqru0N4}=e*qh-MhEy9p$;3|9UTrL%I6V;e|tuXZD^+!8mA8f}^kjMxhLOh+e(z z4={!Aeqx)RIf`k>?b2EUbeN*->X3&t=r9U8Xpn&{>KL;A*pbR=dqu@C9=|8$nxhgG-Uj5L=_MWNRJMtOjsuYS|mD{Dp8PFgP z8OX7!Nnk}GoCXsLh*?uxJAIIYEal4tc-Ql1!lNljQ@S~r1P#(~6jFdCS$q4Ba#*fa zSLbd{e)e0Z&*Wcz@9A6PlZcbsr5jVQZ0`+I|1=gFd&hVR`d}FLKnf!1mG3(_mx4Jk zL4!%kPYOa~Pn{aM^SfEOUGm9OKj<(AS*j_h&sum`R-iBUZS03E)hU+G+1@&os0>9) ztLx+cdh?#)zMK2+Jg!TPd(N&n^y=@w`OfBv=1<#uW>Y~^`?RXZUI z(=g*lyJk1_3KPb`Ag*cFYAZ*1m>Nn4_OV&34sV?JquahQp`88h-mmK^Xon5Z4k>6K zO+g32a=X<0)T#UjzID3p?(}D_8ST3{btjc@^Rm4+=)X#1t6*+0&J^|D45gEUdEPHm zV8T4r;+w8Y0c_)?+X}H$P=GPWQ|*^v1`1e;O2juC2;8CQGk0v+aI5(=P!VaH1~ zi6tqM5O&5jMlD!!mvD_Ur`U=pRU9ot`RoOQMl1HdG3p&m=GYvAB%|1vsNta0MZYXk zJkGGAB*R#LJ^(YIlT73s9V~XtGwT6J%~*2Jr_HF>*zJ$KPqdxIa~<*wJ0z7a*Sq~> zacxa4I;N;@d*L{>@@|r?STc7`o&Cp$huV4!jzJboNK@@tv|Vp3f6ma0=C#Qu?IzaG zuw|?k^N}w*DJItDi^hLlFO+FEEx-W9hqa9{n>Eq|Wi|FTjL|i!u3uWV?V-7qNe~0z zt$y5WylGZl8UWY%=_4qWUw-fPd;eU&_RN33Q*M{u_Is1d_O_2k(x1B(rSf87VU5gPISyGW6U*By z6g`q1W3!~|+ib1jb>bx*W6UbAkj`%X;&tNK=r>cnPM9V!pE~A1(k*;-u+9Ej%j=}E z*e+B%V zoadBIHic{*gJBqiaX0|Il)_=CEzV(|972<`(%3>70*4)H4pWt1rxVrVbpGT09S2X& zNo%85V^=@(k*^hTDqS%-@VOt2*5A=Mfz)ET>o&PvdWX%83$Ae(gzKRT%gr|~99tG| zOMwvVuM_J~C$z%=3_>4tKp)%)*TZJ$hpo^H*TW{*2-^wT4xO-tQrr$*&<;1kAoRi} z=z=ZK4qKrQq@i}$Ot?p+Df^@oZbkVDNnsHKxOZzG`GM2Y^Inn)lTRIX$WK83s+~=QMF>mKPo>)e z{S>l`;@eJj)j=_Bq`bCM{ODc}gU|t6ppRn0R$=+vPIZkj^-|sksoV(lQ<)@q-;XX% z?!53o&xegYf7y`!%nSrlAO%yBq=ZtElxRk8in?OO| zhd2wlauY;Svee3HACZ~>(^H73u;8EN(fqBXF2@ArNVB@IPEuR=H^sl}__r;*rn*+G zyhcSs=4ywO=m}#HtDCvEpMQ7q?{1#JIAy+pV^1jTTd4@(qySC{;IshF2;d$8oMmZd zh5r)sSGm7BE`Y-V$Os@O08;=WFV&M+VQN)U!p*88H9;`k+5~bFgdzdCMGk{3wZ!Eh zNK%W^oTz+4N>o0bh=kOn@U+N@%BO=VXoAK_(1i>)t8t1@t=t=HRx9^Q&FVr-YJz29 zr%w*Is1Ze$xwl1bk=4oRW1a$1Wl zAnXzg%cUk*j_H3{Bq*q1PK~ETw49;IhZ{RXOEMY9Y?r0g61hnHvb-8rOYu4ne=IIZ zt;m3E(K?Yr3}gYaPD!PSgk-D*rCF_9l+?<-A&``~5{O801OiH2QK)l&S+1AEDXEEf z=dVg?G8B>2%7f(ITi2YZ-Ylz0wQ?`Ea1%615s+oI@{N{jA_3n2-Jg1p)#@_#FBX>q zt0BG`@IRJeWWki~m((QY?S4uo5=>N{N~)XG_GOVkbD|47Vxl@;AK`E;BHLJ{SzTzs zt{bXD7aOESN}LGRvB5#K3ehUUdy>2-h4&PBPYLg7@}3snGvqxZy!Vjz9^pMp-m`5H zh3ANUa=c?#Gl^=3qY~9|)#OFUMN>c=O<-}}5Q)0t$h@(rGAkn?D;zPJ^lw}}C_?gVkiG9%OxSzWUx+J4Gq})7j{dlK}{wqpN?>k9B#mve~z-c zSy~NDxPBkSLbX|H!sKIYoH3eOc~B8CD=E22#u28ZQ2MErd$G%49W_BC&nOp-m+I;y z0a87zU%DQMr~M7^Y+9OUbtKxVR_<-3s=|@`V2g|hr4>cQgP|1Qq$z0iIM<=DQY#O} zBcT=JPU1Wfm*q$#s3vjRh@hmo7iYh??2-#|Fe10e5sGUy z$g5#_B&eFJ*#NUXOfaklB_+$M8E=AmONtPYx?MC9P#4yPCTNI+ z)P*i}VZEACyVY)@b&pNK?)vU)_3LlHUAgG$t$Qlk1p>~C0MKV0T4zidqz=vx*Eh{Uk()k%p32!fPU zP$x;&M}moJPohUoEKqeWKq3-JiU3h8w4y*zY7Hq#0+OvEMX{u?$p1JklZJgh@7ZCfPDgFIZ=5kQF$r^vfR+HtXZx83vZP<@PYEY7F(4ztkQlfg3T9rZ|CzDD9~dsI(?_Dv9cs2=OJ7R1Z<-d_EG9TNBlGk{^|)$X9tv34yFAiUI*iomFQ^ zLA_s6yV(~7lv*8-)Nxu9sN+!-o0WUj%DwfGK#R;(2U>xs-8j3pqR1DNL=RCCJ*bC# zRVW$`Pon2dk)XP8m{WL~&57!eq;}(kcTpm3*h8=L!#4Tg0^uf!l)&l`6W zQH{6tqePETg%Um3t_vB5E~1XRbP;tt90{n&7CDO3CQZrpsGLwu$#OUnY>^d|hHB+O zo+gIEsVUJ@7m)=g=}NTR6m^DGPb+4%J07QH(*4$$jHVEQOKhBFei=ygBq~>AYRxMa zrrJZ8YEK{{QDb6x>NpjZC6eGhxJr{-Ea{EPEY9r&Hwam0Ch>oY&LpL@ArO%oLICPQ zs{(-rbzyBo3-z#{lKVUfxZfnIFA3n)1{CwZA{bqP|BaP0PC!wf@(C94iSZ?Max2vTsG03q@o?RwBy5x>XXd1 z>ItWkm8hlHuZSpYx)E_7UWu#vP(*GGDbctjOL3GvfjTMF9Eo^X6V<~qk09=eAl#g& zzE=u`QV_>Aa>T=fA(2IsLP`qOEW9n=1Xcwcc2&S(UIB*#by7VQEz=T-Bq~?9ZhNJL zS9*qIS4Qj|Tv-u`Fh#Q7;;2tlGhv3aQp>nf%c$Mgh(%i_+8T={s+rbUV{D)`7O0bA zA&{fds2T|oMx`w-K<5onMBUe-Zbd9#$8MH$+fg-H!w& zzcBCxp^{cEP$f`=iOPjUZ)=!Db z`52B-E_IazRx0w*Qj}04SU4rcn?PxdupKdsqCshBK%GIY>ewf&Ok$r<7f$eXK;^uw zI+ZQjcOsUm9!UiyoQuOL31dk_>XV9+Og5+sxkTjwMUevls68heXw{R8M?#6pLk((G zZ>5^Jz*iqsF-jc=sDu}oHgmoXLQHJ8w1gsoC@JF&$#5hXRgy|9qC}I?q>_v#7I0~X zZX}S5HsG=-sW6>ats$9t7WxX7P!@bGhDmPGlKpR)-}$HK68FqB&cB3uxs3RbjQm4%Pl6%59f$l9t8_7OUe2Wxy&0PZzx&6JQBbX$_f@j?0QAGe{Cex zC^aUkrv~DQ>Zw(7KuMy{=FHVQaBm{+z(71eoQ?={5jKMb6hWxtnMzcC8sXn-A^~?& ziOLm3)H~qiE*{KeqIyaZfGCUPN}Bsw&?hnIlZ*#fZvtSwV`o)gq_f_jco z??dW+f_k5z-p8otk$PTG&kO2#M!kU43xawVMKR~Qg@89dX$pUSeSi8@5Kb9WU?s|pwYfc zj$j1QWVA6_?|}Wf^T~u2i1(yu)PiCdKO6ATWYmI^cD@tUxT8Ai9XJv$Cb=hA2Z~__ zit$>Jk}=9OFGGmR5V9+&i&aur(i#laE;bmdT@>lbdfx96)nHN)fQ@Vs$QB1u5lF>> zObKMlfs6@c%z<1dkn0@CH7CtU#PXl7eSB!f}j8dWk3jIbO3?@bUuJis0S)R86uV72hh0~eDU9c z5;4aCL$bdhLO~20Y(OWDP70kK7BSVY0>KJ;uU@@+H5fuDj824DWOP#K^q^CrU~zO( z==7jdq3lWM$dnj53OaFgQo$%9>(Hr3Cx*^4bQ;k~prfMGgwAqwn$cN-&Nb*H(OHSk zo6uQ>P76A%=&VL(4LWPlc{4iKqO%U2>(F@%I&Vd%4V|~4^LBLJfzEn#u19ABIya!x zj!p+Uo#<>tXA?S`(b z1D&1d459NLbatV$8=XDq>_ul7oe^|yMrRbAF?7b!*@w=4bPk|%5S>Hl+=9-n=p07p zz3AMA&ICF~(9zJDL??|-1|1!pDRidMnL#Iu&il|gicSulS#W zbjs+=p>qtKkZIuhLd!Jv#z0G%K@5p)!EqUhA2Q;$vz9e~QaE9W;z zmAjXCAJIbExL(sVvXf;~U!QWn5W7CbpP{*_YePH!w?4&x)#IkTUN#Law?0KLrlfc2 z^Yk-lH%+#0oZ38f<5WjSW^=o?QEQgQVl zy!{sHvITwHf*!Y^Cny;@1+kzfF`b7jZ#!kFDkXMeW}g@M%2Oh%-5f~t&~YVh3bIL4 z9T&wK$0*wZ;Y5#BH&-Hj*TqWcG%}q*=Pa#At5S@AWh>DakbDlE`_Q?7&Xb%gg!y|Y z7*?yg9F7LV>O#>9M~vr@;c0Y!iVntAc?q3gq4O#_zd=4gCy0)MP7IwmI?K^XqSJy- z3Y~T6tVgFEolWR;p@T=oRcf<-jQOc$VZNTIJk{7Jg~POFqfdPjY4#$lA?#X#q1Umd zS|0XUO<6o_g;dXDKsXX+t0DS^lJ(KBP#3Kn(Q2lS`H(;?v_|19d^LhBeCfeicsRbO zpwg^NDi{ct5d?%dK+6Wgpz2DY*xJAb&)VQQ8@$g3&)eVy$^mKW7%3^|R754oldHBR zu^xot&C4I9ETE>%D~2lHp(;W|9!4rA9`IE8)e0d(#`=Ts<+XCeqbj}G?rDt7ZK z_V6n9_38^aI+7@zz7YzqsYYe=cjIVb1~Q~)qHTIvoXXC>LiAe({!YC9{ zQ%=umr{|2*bC1(=R_%_Ul>{zr(6pi(A+noDoFH3^?s(z^=crg56^=P+VNP<)DGPIo zV@_L`(;Rcg!kpoldo0X79COyfAf%d!$`!S{E*0RAjE!e<51N%8R8n}fg+mR2hQ^dw z7%`cAO$ra({!tti3PJsIw9l!Y!l@4}Q*fsz6;PAJpth`PmxA1|i4x)?hU}ZxwM#5U z+HCbPElN~=-msi<@sEx+O;moKNQHO`Y_3pKBF$=2U8kV&lG?4d5t4Uc>e2V2MQlCm zsrNR}UN1XcHfIVEcuI-+DockQ_H<#sZ7C|jRQR5OhbCLqWAxYLh)y590f zqhTCql?Nk$)mP2o*Ti!i%t$i68tU3{QyWcS@Wh%-7g8YHHgc~7Q;_JXeIrG zF0q?+x!u^-GtqdW`kVSxKqerr&Y-zM6ld?0BuDYUFdAdcwE(QU;5R78VzF2h1;IJQ zL{mYvat?7yDxlzTPY63oE|QXPGx!QtbP=Zx8imD1Q9<1L!m7Gl7y?REX&~E*>JJmu z?s`Du68u-~34??lMnw6C)r6)eAWN}^iBtoc>NGU`|2(4?`k>GT#W#?G2-WNZ0=GP>y=ak|=t=anrh;f-AoN}LcPEwYAv?`>w&lY} zlAP$T17W$6jDXyl*qMw{%>9Y}2C^Jx!4j3{se+!TP&+ZtI}_C}5$n#x&KNU#W2&{4 zTIDI?-i_S56V<1Qdv{_t^`mx_<|86I+$4a`${T5e%C=T;`;jhe8+;^|K$7^7-1wiX zoKqdQm{7nA)X&-080q{hJD=qS7mS^To;n^&1>{8KN*twV4@zGKQK`mpM` zqWXe}q&rc4fo14KAO+Dt3SwyI7o)z{#VB3m`3)07)!$&osl}Or0OL7XmqOW)iYFF= z42;DS3km~UY^-8q*V)+RHa19LTnfl?V<_&BP$yYJhbc46#X+dFh9W6E`BIc%3R*+h zYYBxm14=X{u|vmDG$qOGjNgj!Fv`4og$wcwMVY}!Vxg22ZH*x)6Br7o0MB?M=)tpI z^j2}Erz3A(Gw1o2&-c}{{Ckdn@8jPKtS=U=jAYmr=#@HUkV+{}>kb60$lBoQO zQ!3ocDW?UQRias4ARthI={XoWvy`XSt6fhu^6=92iM&U&`i{|zKiOK^JG#5@(9&SjX`Pf4ZvRc&@ zC7MXpIlYRakZgVkm7l6khSYTIjK~X0Du6Eb<6xq4p+QlUcq-}$uP91=DkwGZgX}2C zN<2|{DxOru)L>fy#2`R%KZHT)c(_;xXfzv*9c8HPZzAsHp}M)X9JXtM%aFM-(in**lZ`k}M;jxJQ3ZlZV}u33Es$hmG@OFQM0JF+Qysr1 z6;LeuqG~QKj>O-T3M$OZsD`AbLe_l=+PaC?CsPq8N^IZ6>s`FKg%huDOa(0z`f)y} zkEJ9QvgSp+=H7-kql4yS^667SR{8&DHY3ceF{sW2I4MB`Cs zDNZUpn^Dx9X{RNQ0Tb1@BMH>rcuGZnePN@>pZVaw9(BnoXC>w+rqyJ|EBmi z#=qwul9U&iEfI>ANJ>)M)#^NcN7U+kpbeBj z8_0n+XbHCArOP%v#tgOLu1TN`>H`YM0R@u5HfVxqo4D!}YNO>Gx^3iM3A90kpa;lZ zk8b4(!9C?Mc=e%%HyiG&jUHuAC!e%l5gx4|b66iW~be3BA>$VRkd zLY3Eymf+FMuN z5dRzME>V*x4$WRqQDt{gReEeUQ_ku16Cv8HUQ^udOUKYu`wD4I6qP3>h-sNQt(f(V zBQ~l}i{C~$@Sm!BD=$k>KgZ(s=}Fh%>-+W(s?am_**j|M_&-;ff3akln`+DapS!%> z?&5m-Zo_`vxVfww^St+ZN?I=g+6+l3Vfk^DBwL^?0ZdD98!y@R`Tr0z2(&i>n2~`0 zN;THp#?JqMgqY4CifM!B@QNU`1xo-2B^afj-Ax_KnlmZ<6~#)kX3F}d!&Ek(!rzKb@n%UCrc(2TvXM&jDQklS&?rIOs6NGhp}7R0(2*ektYw+1 z)5Q-PXO?9hzaPO^(M*Z}G{Um}#y@`fCm`(^!SHCAbmToU99hp)AW=9pp+Y;SPrOHl zPdI4!hvr|te-cP>a#Z@bG(NczC@GqhtMJ-%d%_RC~vVKl2ae2ix>FzZ2v4RilcT zNf_JN+qroQ@Gy-lc$o2zU!MH8|95)XmHS)kzyJ39LwiR0w<}KoT)r3?Z#uN*rQd!b zdfoZ9oi{JPZp$|ZcU<24qVj`KNM4yzKY3>Rp})Cn^2Lkqn0)b1FaG++t6urDC;$2v z|NXoFbnF+I?SFdh|MOS>^WI;->$$%x{o!|i^NYWD{O9GLG@XsF+zHb2?@qwwP~<&# z-}F@XS>;QWzn6}zfQL?hO8>9PcgaV_V?E#Pg@3+7x^TU8%Uhn`WaxkRnO}Y)cI2*K zeM-Ib&Xq@$I~sP~t%NH>-+?dcaDAZp?LU3t;gd66n^GNfgCG07*;QW~_=C$I`S8{L zZKJ=JEB)E~!n^~!nnPO}XO+h`{_DiM z;A|a~q)RK|IDBa}1RwZVGwg&*3HYX5dE(6NnWJsXpZwN0W07O+=kH(JcqFQg+y^~% z&{}~)sy7h4M~WV;R<7@P^xZv`t-afmy*=xDA5|7A(O~qgQF(*9?%Ck{JKq@*Y->fF8uH` ze062?pTDOZeBa=sUziGZZ@%`CzdZ+kc`o?HtcyQ;V#e_80zixe^ z>7@^!J-OyzqF?&*;O5_4eenb9x}P6>^xQAjoqJ*L!fc~@;*K*<|NRFe+D*sL{OE&` zzq;e4`|ccG{rvl1K4J{7e&FZXaN+%*d*tJP__HI=6dHc}+wa}~?Z0n%&u_n{ed#Z@ zj{nckKX%~i)xR?jEsRyJdnop$;IARwvgT{ym!9c|H5-C2J#z=F`9VyYE3xwvX)7$c}wVJZ7#KDMdW3zoLaLb^0Ia;wWcBR@-t>?&4$R! z&+JdFSsi@&nfcV3ABSFk=GN4j#}{5r)&1my?~SiHxA5u{Z$H)8y721LO_x8M?>(V3 z{G`u}uNe&g@|l_Vn#Vu*+7s_Q+xUq`P9&E<{^1WSymqPanLzWSAHERZ_IUJ}$No6J z?d#EJ9(yjn?c|4F)~4Fltp3o;S~0n1@5x_2vm?3YmJk2){kyu>j6V8W``gbo?t1LC zmv(fm+3?|ierA8yn%nOB=V$u5)|^b7P(J$fV_#Rc9scOkAAIk+HQjH1?TL4Nvhi~} zw>|#xhZe5;#QrZ`_k+5*9k)F4;Ldj(k7q;w*R>B`dh=h_UA}q$k!$qOp8pbj;w|ri ztvAchueq+$d$WAulzQpmHfi_A)Js2Wle+I#Fa2GcbaqGmrMKP!ANsz0;qDceUYU^& zpI&k4Z)T)dzp13!2I1xodFRIx(0XlUwnKjSP1jcLx)?n3gI#dl#o)+~cEPQ8M4#S! zgVg;`*Hwlu2A^K@j>=01rOV%_OKsi{Upu(=^r_}Yzj$!%l~c`+{`TP7?vFG-`X>k1 zo;cO~=&uj1J$N~K|83{uEk8N=#QMF;hTFFnKiafVI2XU;a&+ycy~@R(oIKO=)|02Z z*8cRH(cYDBJ^7QawXwUK9zE5ycK4~Kg>+%Wa?obHsl=26PyE`fF?$F|t;9i{I?(Tu$?p}(!yWM<`H+Szl zyAM0_!+SsG2o>lGyKHO0i}a?^9mMQoG)Akw`i2%&v*xJUiN`pIX{OzYM>L3OCf$k0 z{~CS1=S?H}o49|>o5nwqxc|YMMwfoRhz)^N5@`^f7LZOIyn;@s^*zz!uPcA*o1@3~SN!x#uO98c5n5+OBFUQ{_^k}ly#jhjk|VT{@pkeNItvQZ}H~|hnkL?hRURJ-_n~)7(*dg{jH2pdXa4=OdA@g2d zLg{{JfNY{tU95pWJz0XQzO#c&Sb;KU zh$$wnK-n|I*b`Tv7#U*r@hecz3^CD!6{uZ?n1A95;`DuQ2}SQ8&!78^h>iIaz1f~{ zChgVYJ8)vwsF6h!)NRUbay3+EaPq70w;xg$UaRnyvpBW!ojb+pQtR_gj;C3sOng;7sBVR=3&<;evSTuwM4Y}{mibq*wm9CbptdQzTd+CmTC73q8QXG%}KKw5ZG zc4pc_H{4U^GC4aW?1R7i8sW zxoxCqLS^S~+epNO%FagHNDrTtFVhN0I<2?*fjW0aFH#>eK|{OY4P8LKf#=~7z5ITyetKITKLEtznKpW z{_DGtCIqt-mzByWqO(HewdDXuK`MpL` zzjDKa;joeMNilrwm=7WO)CN+Lzrqo!!h_*SF~aSb0X6xi;o-p^q!`UM%*!?Te?!BA zqe(FwZJE9E^8bc~2jh}rR5lU{+ORk;spFLvQOhYvcBcl@=wry(u%s6jnWm-&%X1)C zG!nk%7nzo%221HlwQqrrYBIzcEe0EFd zeZq2BUP7&_A_>kx&{z4Tt|A$g6O18-tZ_#;KBrNusnW+NhTL&WNIt9KEU(gMA%@&? zM<_b4ajCA-Co6`ms`yI_h>ZQ4#adlavceq0Fxuy@!Fb5DIpr9Qal*W~vT^_T6C0CcK9sh9a4 z=v0OZkMWxQ5wo9?9Hh~yU}=|TzUWl@X_sa;=v0fTmu3p+RQJi3+uzZtCb^#dOD#V( z%|65}K30>j^DS7Y+LN#Iy~<`<;I0*r^H@KBb#cf-LrMLe7i@+Pw)%J|>SJ@0+5)8c-yPr!wG2Tyfo%;VgSW zdWdjUy;$RV=QwaxeOT8B-D3IWKG_;O977Ezw5`a-;@S^vI@1?@U z!y#Drx?;k8M}l9jUx$ZFPl3Le~hfhJ6XduDkNFhG9Tq2@Q}aBHZt< za51{ZBe!Poyii?C1nWUpa=62$>9O^~88wXmIUtU(wNe z$ttGQangRl37enY2;hBXO0Cd6M?ew;+Moj95DsCZ5ct1dcwfCzAK-ew;{B8utA^u3 z+xg6n3g36DL;;6|0v~F6Aw?eB<%EVtotVODDHNUpxw2qJqfSi;G8dvm)1A2gaK-zI zz(xgj(J1E32P(tKRT}nXnPN~Qv&CWHePtc1f-^-z%flTz%K**{Sie#rBYcPMLV(Sv zKY;+q&1N0-&+cV!ejJdyr3fX6cT@TAFjFwxa~*kToef#yy+B*T*eSM>qT*L(2t7=SIQT0_f%2jiPH4$gqY{Z7tphYBph<3 zcsaxd0C~=u+$I6YBJ?WaeWe*Y%NH&`cXuU@;P#9-s=|l zflHCp+!*TcU+k#0qG)Kv=c+Gnhyz^dDJ6)#jCfGIN^yY@K)Cst1t#o!_vZoC*eaD~ zGtscU?XO&JWTYl7ApjZkoeLa1C?J(hml79gZb|KB1Km9R=Lo(EY`5bpmPYN}kRu+{ zJr$Y`)WG7YyIU~^)1_yA29Cp4#{$7G2)*#&nYRf^@C>;#+K%!#xtaOAc$_JC^n)2z z8W?K^hDGlvQgN^3_U;}UAJIpsxIFSkOgTTYM@+dqibilcKhiP^5)3CVvb;Pm{vv;(W<`h);UIp1M| zpW!xx0jzql=4}{gmgm+(*PlE^zwInp;X&2y1K)yyz8^Z4ihM;MWQ?*GAE+RA)Mttv zWp+-);5z9GUb=x=a=%<5*kJ$>dGi1u=D{CKR=~#y8)2`33r?VUdk*ER{IT~m%mlN> zYU%?_SYZp=M+4iZn|Er(U{W(#vbs>x)IsJLfL}fzBFwtmeV~;|KLl@aysJiS6KO|L z(+U8&`>xSXx@dM`7w#g_X!&=T0RVZnQPzc`*uTvnfOsVu2bPHzgdz;wmcyWg5o^w^ z91&|Stzr=(rr>+x>a5##m)&#nHdNX3kpw@N-A(c~T-nV8x`(}C5trRSav!VMPE6U& z6uJvog4e;YpXoX_Xr5}Cw4TWfo2>4BFAjK&3r~(S(8>nGUb%C^Gs6z5b-m4&nG(0og}G(XC47Ex=1|l@l$R-SVg_yFSz$e6OMgfV@fZ!mRyc`&x;g zsbGg4(YiQ8X6t{T*00A(x=?=m*WW{cyBZ|0+7p90_&V*sJiZhgQKfxnj0g>(^@!Rk z3(Z^`0Nuw?D2M&fy-onS!E)5Z#~YW-Nf{P+=9wkQxzr-LhaH^ImF!$;p}DyNfIKmv zf(kjI-Xy}g)LDVEQ-gp76-pS5^*9U=lj{nedGC^dmA+yMR{nLSiAW*WHtWPW%SUHg zj>#q_a?uR|9>?k9oN&p!Sc#co`qe(O!2nG)pZbaJ%?;(3`^8T?E5Nm3Z|ScB{X{sX z*YKen;j6ZTnC!Q?nyF;`LsKAcuV4F#V$H85Lpic~SI11jYJMc&BJD`_ zte9bkuhm(2P!@0mzPVt?mGd{O1FmZ70cZFf{7}FbGtopm=x4AjzIgyWK*GQ4?;MyF zQSXn5R_p+|+av5JIyZkW`PA%8bt8bi1JC|3@*Hj67Je6TuQ7*i;5~eNQ1^<4wlC6b zpGt+;*XYsMlP$U2uc0jwzGqb#C^$By7tr{gCAZwKP#G{zYrl=H{oVkS*%Lzr@xD(n z3^ajZ6+QsSb#5Hc_W%K`7Qi{+%{~@{*a!AFq>GUb1#FtT4qR~gFwlfQ=spt@m_H6& zlc)C79SB*!=}1RrTwH(;d}N5~AFv~P8cu99gA~w!ucmiPwc~VXGA(ptmPmbBP5Ez+ z>ff;TLq~cNV&3r$@EAYF(15z1if?I&J{8}7VH%+BeQY`>?OeLVzN5#!{tw1m6%csz0893RUG{?PI;D ze8kNt`!dD`fZVIb0RKohnt>OkT7=%uogeXKKY+6Dq0ky&!2IT>^KOva>`N;2LhzLm zG;bnd3cjz{5A1fY@rWIy%DmXm}%J_CUb5D7RN2FDG9nV;RrAUO*-*_ z)q-4Mf`n&YK$#l|rj7QP^@o%hcy~W*mUl6q5HWA5}F7ZO10leau3Eo)}-v;twGk5V^ zWnn2%{+xS;Y#R8?+?RyO_yO+r=uzrynv^{r_7eQ?mnjSO5&|SQegV9yZ8@u9YQ+Pq zj6$9tpXfCntg(}&g{6qh9+lvKCz*p`nf9@wsG!E&WS3pu|9#Mv5)HJ?^`W2Vw#|Ja zPj$O}aoa^E*LH4=2i4FU%ya8slnGWcX4{g)lt_~Yk>Y%WKgqt?z`^v`6;`gLJuXFT zP*y6*&zw*atL#WNII(FbzQVYLwqeXgTuHDz?fB6*wUGg4m$>pyH%?m1`1uVFKX7 zfnuyb5v=sp(#;zOcKGHdbnQcrOj;>6F$5SPHU+PaeM>~(7(46?!k7Dnvm>8~AT~Ds z9#@!`Zo&Jml|Yzmdd)zOT*MB!vS5*uBpI^~XvG5YTCxuT-r%f|<@%i1W$Q(MQfF+% z=L20B0|0q-Vqjq&T4kEF7VC*AGzIKCiNLHU*M0&2^mv(r zXM3Xmvyv}Og*XPWj z9Op+)u-bD@BB3JmG}jC~dLtAyiKMjm7EBiu1swfg!|8zmQXa@+U!4+zk92){1_3Ec zB4D+r9wwIbUtJ%FQImv9M=!$(LH&TP3!aD`)A4l`x81Gp7?$QoFQ_0*sx3JTOS5MQ zK`c=Mo*wjlt|;IrXWTJ!a1Y z3?!8}acLEgs1mY=ZljPl@6}RFRi@6o59LHmhAKUI^zN3vlA42eW4L50>}A0-q{C5= ztz_t@919Letq{!mZLgo8*D!S^C%hj}C9!4-9&O=(S-)-KfEqWQ;((-7!lvNkxfG}) zx#vMGD$M$0KMHvKVGMv=pA6SM>^U>xytuUTM07Z}vPE>bw2DOdIgdhfnSS~#`wHQK z8gp>>(M`q2DA_rwzwdt`YuZxHfg>{CqX-8I&*2_8Bf*AEcvTF?n8AI3swh8~R)MMZ z)R{LaQCR6a0Whcknl|{yF)escKKRFd^`R(th81>n-D`R{bsJgxQ@V|T!cn!ZaSHVmuuVvgZ6E0|8;^jtvo_p1e(0Tb$1OrsMmmioBo?2ob z`48Qa^IJb2BjZp%VF6!G{*UPv9GHm`-e2?Z+l-)ccye!v2qa$6`&}3{=B;0bH2w1u z^|bIJv%}E$1e~}TAjp0E!{kJl%LXt~IQl0_@`|3_Jg|i4CznkD;JPH8n1~rAfMW>p zcLeN{6eYHLV@H1g0z`%DiGd`5lE4X8IQ=;FUtYYaeEN^E`<|+Ir^2@V@50OEat4`@ z=I!2Oz_aCKJRQggqQU(0?J(pAKW8{VGZD#PEc`KPoQ#aSNH~M#fJ_nVH&cc;<($=c z`lZ!dP_*O`)88T?0qnz5^t|bDO}o-mc-W01&6fcC*iGZX*Jv^^)uBh0Jsk3YpV;Fa zspe*)bQ3>j!`;3AjwW06=u038^2}!Fib$$|G9Oo4lY0Nqd39!dhuf#Y@au*ap7Cff zequB^Btxbo)<@3VDU}+ig*9ndU)8<}J2*r&lfsy^`Himp2zZrprOq*@;WqmZTZUv835bYvj0 z7Tt*M=)9vSK~lt$5(SHyJWV%KETT3&ejTOI^PqVCm|YL8GgoQBt_n8m%CHIapP2U+ zP11KKHHVjyOGcU3egYSN7U3`0V*2Eq{9p611TKu{ZC*7KHN7S8jjpfJ_^0{)6D1E0 zz#O(9?~`Y`c?b&Md`$7#F|XV+08SZXcx9V$|1?LtwAvI5Ejv*OJtEndOZ*Dl(G}Lf z!A(zpE>w$nJX(p%D49OP{)xS_9f2&c?x^j>Yw_L*Sg1aW{=- zIzM9OK^Y%0ePC@3JBr1?*CK|mQ@o>2Lt_8$qZ+pXhapckIo^nhAU;bq&M5N}S7jWw zUybxng+CM>#q_4$f399s5h`cN8vNi9>aR2FU;aaoA(CIdqk%6QO+EEt9;F_IL*D-? ztZEAX8HZ4}KU0S9`+hH->T)7_Ncv?Ci5rf?WJp9ms~gXwW6wesYUY106KeiVLbzX| zB+_qs$DZTENcbOEU??n{|n}76EGme|}nlQQn=0iP8C1EE5Sf?)KD^h-Q~MJ^hZ-a{U<_+BjW6lslWpBk-C}u}a#PA}NDfm-g;lB-W=Qo> zY_YQy?52|xtF}e`*&k?M~K=S`%T?$i3;YP+5Vl9gO z!l&N79k-30w^-`xD~D+_ol<7Q_!LeYMmQ&*&9BL-bI8ZLTOWk&6jxlNPnxbcBTv9O zy|w&_p$Z5q)gs+cQ6ElVwQ$YQlnqfYPa>W}7rw2u_!e^WqwJds4>H5T-tHVJBC-5} z?G8_NrozD?))Wfo)p#Zrko2@I9i4|~L1?8&1wEbo1aVzeglKidCX!-Q3HGZpMETaf}h35_hl2`7jBNKa0@KX`tRLkwA# zMv5?QOQqor-mV%o8Fls-ESJBM-aB<`W=`=>3zmJ!tuox7na1I>xN20aUI3~AXVtYe z3)AeZ^?0ks=k}z4RWqYn@~MQURP)%>vgN8=Wyo#(|CMnfWtacd{uU)uJvSpioWgea zBZSX-*XK!?ZrHj?IX1CUy`X$5|1$>4KkO)OG+sgLyOmY)7{iIL-I`TN2mdjonyy8$ivY~Y$j0C=g(<>xqbarl9HqCy;Q7<7Pi?bnZ2v*jY*gtI zY(2uQcBTnR=1ez8@aN2?5$F165X3eCobuI+y6F0<3VgHQ^dl&neECLkIil5$G_ekL zr}b}-4Yh*R%NO@6-1VpbX^Om6`hS6>L%pifrv^J2X?dQp z5_@I=q=D!EOuuV8M5A$o-KQ~zw1i9Sa)YxS>M0il@0`A=C&A% zm4J5M_osTCgd`kwcfn-&D^M?Kqn(IBEOq_67-O%U_c*W$8T8;^|rQRSre{?>xE^Un`0*8$MfvgW;uNa9E0iVn}tsW#*Ac)l{8hK27KmtcJEh0q@@ahv6zY6Au<*pDt{A6`^%2`uZB|6WY^`Li!3Y_hIsp9i>i3 zY;ohBM;RiIejDo?)+%1#K7?Gy>rp@1e`C?w9Ij;(AwYDRA|YO$T5e-RULXCW9@~-M zFMo;-IOYT47rLe*JRk6LIug2WW5-kC9}kcA_te2aC$Tf*Z~vtn zErh3}j%c$8J*?S}E$lQ)ICgkkgCht?+qi z?R&gcAaY!8xo~VPj%!jiVXyz_R&lkROU5=ZWZRGB+oH;He!6C7>Jk?`sW-8C2spzW z!qGJ3PmwN_Pm+q5ZNzF~Ns7KmG~6V1QCW!O2%#8wc{kn?^W0u$Kr9duk@a`v+~^hw ztjcxU`0_1XvVL*q5-!Rp^&*S%u4-_fy1)Jz}%KB zJb&?rh|IN*u3Mb0u3td;SVu&*fWWxH>W%%PbVm%L_S(w#6dsLgzOts6v{XR(0#|N& z7I_M9kk)Ifg*BQ_-rC8V2IB91$`k$?*GB0nyA-zl?uX-9$NH*~C^N=VzG^)AdArZC zRqI`_Pc^Y;$KpY~Ur%~l&Z>PC4L#b%17o`1Y31yy>*{R6laH+#{-`Rwbx% zMvPQ@ZD#j8v6_ZS>s$qQy$C4b96|h(Nd1e3N@A5i_Hk~wHU5c=yA3sx{oTJ(7ijQ~ zUwat}(y~%~V~y1%(4>11^mCM#N+J$0YYtW(Rx4AQsQA}R|56!qeKHvIFP!S5)6B5t z0J-Eqbjl~a(|2hj>l*jX(&+8y=P2W{B;r3{S>7Zxif3hC+1&MHA3^<7KFfhqkd_-t z*ajQ3M90C4+V9;_S-|=_sEjs5g74!?~)}| z5+dG=auviNF`L7qRHf?1oJ&(JPoI!54vZ4M8lgfBQf&oG`D0vJ}XJ# zQ@QtRyfxPQGHLTgHLNNl7sIK|oB+S7g448u7#>G_MdN1q>ia*MMwcpJlbgivvV(;H zpNUPT?B|EoMq8cHjvl$C7SvLGPV`2UyA0}-Z;}UG4ZAf}p1T5a%bmT~`3c?4Vj3nb zc{h&R+&#VGoj#>j_W#Rr}YZ`4 zAMg973k3$Nkhp-XTh~E?HRm#ZDu?|L&9D_$2JLnTqg?eKj^n#&uvDg5H_<~t#JaV_ z!*b3k#F&ymMr1{6L*Qk&0sPefBV|={v@5;I0;_6FXQa`w%Q~5eEu@17QvF@ISy`*6 z%lpE&e_}(8spQT`)aTy_Td>N~eaQjtsZ9e!$FG7*-$t;Ui!X;dMZF@4)k9x^_bZy7 z6(lppk#1z&jm^RT{XkT}<-u)A`JH){?HTAh@@lgO^)48FN?8ak6UmR+<;1~YSlW^| zq&!q;4@xY;Chxj27_;+Be4a`tGCJy7WwI_vRy z9!r`V5*w+{UZHt*Syr|is)!O8V@eNSL2Elrqwh@MjZ#@_8_02N%zLdNs6M#4;Ge45 zZaJJT%r02lcDKlRHRe%X;g-%}o5*kLhIz}g+S+?iqR&-Krg|I_-C5gBoo*{^G&dc- z7&=@%k7<8o?{hOq;hn5ajEmTI*cu6 z;(|Ph1-J?k9B%t>)nm$tV^%niHpM{MA%&X@oi0!$vJYSHUiSU(+DZp|EEt;^TMM)z zItC#QiC>ncEur2p};8pRtp?R_`R&@i8?Mc~tvy(K;>mcjQANJp3I6j%SYZ3e-9?a=pt>-&3!` z=V&k)s&3qFoXhMe&WVauEfhY>>E8xD_Yx*7U;f@2!XXi{J^fE^L9L-Kv!-QPm*2{B zq$KaOd=~ymO4{yPJ4ScTqHgK7hh>4y-OicMLh3)%B?29g`P6@HGMqF;nuyyeYx(~?w;u1(n)m#$uJZ;(x-7vHJ zEx-wI{p66fzQM3j=$p+twJgPOE;fK5#!4rL&~SD9%+o$N*LHfisKx$0t)AtGb_68f zqCgBG6`89$l9`}QSYeGQi1CV&*HF!TCNvhDxdS) zIQ*hACUfhllh>)%U|xb*2Z2EDa``g97n?~>ay4gX>$&vTmW`@)74o#b$uAwe7U!kI zqt}Uu8kre`mgH(pmE`olb+y`7Jw`mw%GxBl19AmhGejiXww-t^Q>Ct+Vo0p|nNZpN z@ZxLtvs9!aPM;QUh;-y~a9m*Qo@G;2Up|9^cFsa9F=_wRSBiH0C--RyT$8on zU#D^EyhU>s&dBRTVNaCn2=u9#TIu;xT;gk(GiL)sS?f;Q{8D|KlrLvYQ%>x`s^;Q& zNjzqg0D9haIwEdzzDgbVE8!R**YowEW1M9TauZ-U?2+g96h!rUhZA(Yw?o4F*7V$}T`E}@+> zk!@X0^DX|KXZH~?#4>Sj{-AA>wcY0-;J%tojIrob{@c(?Hh=z3(Jpp3u7iR2i@&3% zv5Q~#(k}{7PZ2-4KCe%2yP1+>x%lZvphaMT?RwOUWHMNk=on~BEZA$V(PpF?fob!C z5vAk zW6H{Lty!ncR(xH5wf8iBBLPJXn+RJ%9m4?!g+KEA%w$({;oTHg(T7?B?%?$0ve|{z zpAfM6u^VpPYfYx%hLxkJ#fJ2dZqJEVza%i#I1kKr9Eug}lo$ArXW1P=@j87664IxMM9&(Qa)`wlN<&(*B^ zLjPBr;TC)SUAr0o>)S68WR0ROzb@W7TCZQmB2u^Sbx0*@~e~!8tjQ++o z$!=Mm=yXz}IxwiwsF~ub@EWfP)Obf*oux5d zD_yxhR$+qq<Thc>&2ZKt6^kD3)NH7Ul^NseVyPbxqsiomO46n^*#6C6 z1R1C@HYc#HyT>-wdto#TH!!+0;NiLPiO!~$OZ14It?XDQx(WQ+KDTpz6`r1}iM3Lki$ueWJs{mYV}9no$t<+FNqdIY+xX(tWfvQKtehF$32uOUj|t1+}U*pz{{2 zVly7EsW5hg`XP2#qs=pg;qZ|~Nv08pe2?^db(W0500&I#X4`j?G`7=B=|`e;Y>LQl2}qtJYa^i0hVnT8MaoZ#XMW)K`i0 z*{GJb`}iGjN4eo9_|WD^g_7C#g})?zVrfX+t-|2qcTT%&!8hZkcZ&`F@jH_|O@%Rp zMhkgRpV671H~jUC#Kp5jHR^uEM14Bf(86(s(uR28(bqOD%NNxdkHDAxnK$pXNQrtC zWS@uJf7&f=+inaNz^a)U(nV-940Eba4B^>hM(w1YEtr_E%y4I+4w|8lJ8I~Ylhft+ z!=UFaH$v^tRQMz=N$MQukC{HP)R%`QF$eCMa$AFi-bd6LH4HC(EC-%qpRvdzD27Z{ zZt7L5cAMue%krZw<}7cEBNr7w$6xz^wW<knK;DiP8^%Hfl`*VeHJbKY|)6L?r}kT|B*RZGiXLZUWH>gF(&h~ zaPvt_NaC5s`MepaqSeU_`0VL7E>F8XR)dq_#Z(y0oNcvmH_7{8&zFYP10>6oKHtMT zUmL!4M7)W0QR;VGG!th#n~UC;lgasQ_<%WR4izv$90j%H9p~+5;&gfXpVFfTLC>Yc z(s`eg;Ez(MWR^@=_nRs9R#S{#$aBGM;pOeW7;M^dVTTu}ToHwSgjq0-5v^Tev8F^< zBX&yTzT}TnU}(ITlRnj|P8wZ`yqTh(IG$I0#>9$K`N*DJLXyh+n?BXUrM;2mVU@(^r^hRw zakOR7JM8!$YM5CP?|w~aiX7-;5KuLS6`r`@UmUQ`Q#MPcj>!=BIOxxp=XR?W6@ zQrpBy8=~VsCu<${unzNpM|b#sMB4-rbj*P-Z%naFC*+eF55$5QFe&u!eywnq1Q zGWS=B&FWR$boV@2IA-O6Zz?E6@pX|?!eB}cubIVNt&3`I$f9Z?lk9!d)H- z!Bz|B&*6MMCO4{AJ(5X%*#T}yefT0RUCY-P`I7jC;;~Ks%{WC=ZNIy&047oA3eeFS zwp1K!$-%Z(Z>mNBc?E6kM?2m1OJDRe-}^PkimY}E_VJknU*&-Tn-1-bYz38)^}8kL zaB-9-z|Xin$*{%ek70~xZ8M#r4u@2;9&$}{_vtxF^B*+pR*r*9_M|Gwi$3TKG-31a zn@+XLqnp(Dq;^32#C>O&1*U>F+zkT>PhvTkpvu-Sgmt&qzj@~%Dw8Qx>6~IB`nwK) z_1v$%P;N2-_>A?=P9CwI?UqOnn$I!y_9YipbM(4UL#Bn;K-3`{32wILWxYk&4&xZT zeDWaR`S?bF2kFObOr`%epx*dLkzL!-Ok8AHTGn;AI7^RKi3i3Dc0?cV)sZYCWNcHp z*6A{Y_FJXDoCIVtPt6a%r4)moD1)C)=hEBQ zLTb+bW0_yseRJef`Ybf(#6J-v&I0{G!lW~|DqK+~yF3XT_8f?$81u6H_+0BMW3D;q zWR&LYfV~QFG|Y^e{f_;d?$R|eH$8ZO)8sE=-P0u}A~zCPZ1>$hSXoLT<}P>r<(TBQ zTHYsBA*`6zdNK>=P5^6JG^{B$l`UF#V)6G3)pThKq_19t!*~XNj&WU2xaDo-z18x2 zSsf-o!-_-T<=4HAbOk#>p}=p5PTY}A^XX)WP^(s!CY=_uZCbSU)W!HW&UW(L8_2{? z-!{acs`KXhZxLgwoRe4;3v_X}WHXL3&VIkFKajo!<2U&}9+ZyC2M|3T@1pHB6`4$I z9g7yb!c+WK|2#A1Uw>btmg8#bG4q+mpnd`cC^U>Ua^Yy2*dZ?@#6To2eWc z^Cab0_YC zbLAUsoUGItg9cL*FB3(PoG-I;tE-=FMvg6C;)6~~6TTiC z^0{W$X?5K{y`b4@`DuG?7hT1na8jMD?Y;Y)z2>r~I|-)OIK*5C?LPj@NFfiu#JTXm zUiIqQ9E{xTuytnBQieCmtc7fr2yplGitzkv_WLM|XT8blBN3251BMU^XTI4_o2m!y z&k85|b=(Ay`+m`u9S^ME88SG|IJ8P~CJkT#t^Op9u689e9c18Hl^;^pN_Kp2k5RyBJ*C)rq*tV6`vWTNFl?nkyd zBxIdxsBn=yZ44(cys1lG~qMY%Bok$71hYUR{Vx>YzWd;ZE-%VJHn{iJE7cFjtVCU3dHV zHy>YDk4w6R0^N}=q%(ul~)Av_GmMRkRA8AkeMvqx$KF#xag7rA4>w}_rBRw zwQau|oP>8zlvA8WHBHG-R~*yu6B`;3$;SAm`9X{(D(yUUNpiqcW2EB;>^U9y83!p_ zqTRbg3$;bL>dmFG|B1g3{-5@~GAOTZS#v`m5G1$<3GOeh!C&0nd4s#VdvFb|!QBG{ zcXxLS?ivz&>f@Yy&$%`;RrBM{RL!$%*V@(H>se2C*V=!3wOZ1sV!e<%3as|je8RxT zd+O%aRIuA^A=;>zaSjSti~wA8W|}FO_gBj?B3f=oxvEbt?j?=iJlumyem4(m;u&0b zWZ*{225Nw|o86hEpG4MLXCN6xx!CfE#b@_-mG%eE?lHSBTkB#!r~-J&a30ESAsAc@ zKgVJN_hj`P6MRe3IO9V`g#zSphBl6y+^cp<{pTC`Y`jEOx08l zeD2Vp_%u;s8}*pXr{TE2J}gqhLJMCGVYP4C?jKPcBbY}FYS&LEepdH|Z`C${ce`G`zZf%VajqvV#klY~ z33rs-o7{|>`)Dt}FfaZRXv@dOrz!?I%o|e!L6*xs`VMkCJg3Ti!?HR3$SSAHg_Wma zo^=AQx%iXX2mL7NGyH{*r>RGTocAw%^~g#RyTSc8?btt95O3}o9=}AT*N~gsj-I?D z1g+a#M#L4$R4DJ7=N~LhH%m)$!9|*6*j!D>{}sTU6%Dk%mdVB1Db&TvaSat1ZN^ ze9K5kPx6j|hre;TVxHL#6!9(gN|Kuo60JqpDfs3ap5$jxjibZwhBI|lQG9zov=}oq z&t5o=y?a?wI>s82BzA!$z{@a_%)0lJM zEPl+SF8!gMBb`7(cu-cNyPCWtE0sP>FxHPWNE#E22@>qX?QA6_Dh?$DU6I~Pfp<_* zVKH}p-|?^U@wP0DjSzSEHaC|Ymv|f<7G-%vAC*3&J2WA@bi=(zX?>o*`AVF%{MfQf zgOk}9?&wx^WZMVIO)8pyRCn9f{_6R5!(*>k{^e$heZQihs@`7eci{-*Mzi~|=pUSk z%40;muVmU~dyx-+l7?nHh?YOSlrO0qr96=(oQ!_A6aXKl`&`Ei8k$qE%C(if6dC!+s*F6{%Ye^)_QW*SVB+EmzIR&lf%!A zT{~Yx)Iad^>UT}GJw5nd*u)rObYXq!Rnq8eGuuw;b^UW!F(&dZ;6{lM2!w3g^u zHqx>gkxhiPcw5i^t7`+Q*2GR}C6U0x1oC9CRKj_5PECNdlfnI4er=*U(5TNeZQa+d zGR1eK$9DB)K!E?{_tdxFl!}EBE8{crTwzjF%t(wBV9`=0K>bi?OY7_s+uKXUpwO}pJo;YdSW*-&a_RcnUqK1AonsDENyCe?f8 z(({b>>&uMlz98eu57!mF=y|L4_G7=i+wuty*wgowO*=Idy60ohIzu_XN0H%_`u!S$ zKU>1W{cLyAT)8^k@b%d{Y$f(^<@B-b!xh~3`b{POz3%wzRGd_RYdM>JzcM0@U@1?$R-RqjQ zj)?ouwCl#2{aw+3pVoIe=7oCtjG^0~PslN*>yN8l>*=(_qh(8csJu81$I(Fsjw=Ka zi#2yAvyovFJ8KKS4&sx1y_y?t6W%y2^=Ep9R0(TbbeKK^p;R53KX|+^md~^+S8HX% zR=+ai_kMc3w&_vrMn}fU`)w`G+EmUt`Jn&ikvdsr1ovviseO6<{m1+Nwsd_K*(8!TAE&Rmn z)kvcaar`(P@gLfVX1n8HabM;AOwXJ9eH*v>gJizTG4-$o-Gf3oURXAtreR0`TeECaP%%2PUlU#y6LLt zcMombgXfs9LM~RsP_xhd6y-F;I@c-j3#kI9vrD$}r|p-|Gd=zvkTBYoy?2(%+&h{$ z@8v6=q_$fL_}yM0+0U-m?M6&i^`CKG_7YJXQ+!_XT-()HF0PjvJD&GSUdBs!T;wj} zygj5|rknwpwgUH=BjQK5y{K*VwVVEEDx!J;E`vLlA;W7#?#YK|isN+)&mHx)7$@B0 z_L{5BoVPe}AnBlD1$L+5-Y;9QKO9RI?I9N&%CrTW^2$<9M-^1kaek6SM^-M;$KcZHrfiwQn95Z(1RR)G1J0uG? z*~WVyNYo+!LwGAtiu9w#8x7X1cH*=^3dP-CEh0JToHlttCD)$2Tbf&6$<8PO>QncQ za@0+Jhq^ zSm-WpSIx-o9OHb%FT%&e_D?d8>)#>5KSEmXq6@?>RVg+gV2er!#Bg@NJFSE2*w%pt zDHo$@cn*})K=?N0D&G-&G9F6VD71+%`BA}}j9#;@d%hs%zL1AzJfa;0js9iwl1Ubj zpQTQa(*JCP7TuCzfx(zC%5uApQR2)ayWaRATV9r-;^Xvvw@nnZkVp~fg(Mau`yU;z z)KUdPKg0>!hyCc`;mQGXEiz8k)QJ4TshIroo(^FusZ5%b3`PqW?kWXjP(5Cp3LQu! z!mUORn=K{M)jo&7;=}66AwwAUE1LZHfzHaT zej*}}MJJVY8z%eofp=chXP?MYT z!g$mQnP=k}!@Yox(p}y&w9!nx3B8Al?7*&YA^lnIBD~DHM*qXi&{r(oPDZ755*F1DeL~BzxWZFtfzzm8p7fOb)PFew71Bru{n6!kNBRV^p z)kB;0d47-=$&@iMU-xmEr&k@0~&pSnbJcxXp3nk}uzYiy1a}PiJ}B23Yz6`x-2v+b6~c=mPj5h7C5{RD9WxOew1xN*8JVG1uONzF_OsGXJlhs8FnY+ zj@qwKmNlYIc^;k8iKTJ7|`=Sd>%g% z{em`CB2K1T0Ixt$za?rK5s{<=t zQCdM!R@L;al*&B?i4z^_k#NNt!tMNv0GdS=^ogNg8yVEfuc6O50hN4L+5*0w+W9}& zw9QNVT|H!RhlZgrS;e`jD?cJ2({=;mOR(J*O8(1Qx#eB4llDFZLOx6$Z}`WIf=lW5 zOp(W8O2Ugh+X+mi6O7%w6AFoBa0y{WpGh;R^Yo}y0GKasjYQ7hEzsJcG4B+r{HBxI z1pg?2Zgr5Y8~9tjYv@#5jqPhe5CU-(uSJx~k>mjwI#xeR2}jQo$sRE57=g#0`y8t_ z>rDSw2hBKviY&9AZUSX$(bGY1k3C@G*(10PwHd+*LTMYrtU{S!EzCpJiu-GGP!?t- zW<4cvL)lvFqza-_S%a<_kRwC<*vDL%lI?lhDRWKSg%7xT7-wbJbk{#>l;2-s9Z{h& zB%pAyyO5@rwRxEp$}7Q9HljKYv65op7RC}o5D7Ls1`Q9FRkD?e8!pb8pf4XB4EtIpX{fp&}9>d5ebjV$h;jW(PWKu?P!~` z*pSubDYeW@5J1kt`St?C*6}!ke0Gbi)(DEJ+(K^VX#*03gawQY@di0;nh{3iGH?(A z#asPvYRWykc8f8s(=W8xYi*jzmgyCWq!!y?i8VmtR0cUf%wg2(~7Bq{K{mnP{X(g}m;2-o2$YlKTOgz*9 zvjYy`wZNH>z&T-Y6z7bGGD8PeCR=3ciqsHN}%YF3Iv$szc`OA!{rpggC-7ostBIR)#R_Q^*HE@AR3%nqF!B)^RTV%qA zv?7HZ=ff^z4#t^FgD=8O)n*Qt95~84jBfmh7{=H^B8;?y!6$>Fk+Y1`iG$lM=ARht z&3pRbl#~SdZEg|0-%fpStU5UDBH<@*O+e11z@WwTtz^Lc=>55OOyT=ec!+Crb_vlf z4MFGCeJ6Aji&=?~|7K~e-n8mRe>e?RDSA?>R5{?!)|f? zM_M(Oo{K2hViiRt8ucY?LA}mqx~?@P<4bbO?F$lu;w3?PfiCe|1% zLGFTSa-;k$?hfjoTFcs6<@hqfWA@;fRZvCp{9;_eC}JzH@^|zncok-ieUej4tx%8O z50r8ysE)!bv5XO!Dj6|7a?jL$*}Xl4%hdAZ)3G#XBVDXdDP||LU?JWUugdaslD&CL zRDqaBC3-2GJ9?li{6;#+?A?bTnYOpzR;xtqRuy!!R-`K~z|Mh0tk63JT7j)>G$&jt z4KynKKhGa+(y71bix&-QgE6zV7woQF;pfelC&{xLQ>a(ZTSxG3D}Mx0w~8;G3zw^- zD5pp(27>^myeSM#@n~M>eLg<5xPS?lL&NPNoCWgH$%uO`S z%pEfaCXltZ+-KF>ErgF=3VlK&Q_3kR}EhatDo-J>qNRM8|Pc zvLTdW=9=`tHxa1P=AdWyQIg3-(_UW(9I7>b*gm2og*mp=81e{w#I>SHs@+ri%~mN$ zCXayJoi30;4Bev^Ahn5A<3zr1s73v(XLb<%>q0%J>!ShRqp}(5)g!8EQ2#Ql08D(i zsAI6$c1DO)PM1m@QQBAHLP~*AH2gVD;u_{=VU1KA1Z3gZOpB>Zm%T*cKwRSqEvL!x zPaoN+PqF_Hy6ioPY+~eYG_X!+kVW))-{81VYM7ONy))&#&fFP&(MV;UP%v?%pBbme zD*u^O-Yb&VbM#f{+~w?>$mjV91Km%H4+huVxxPAx62+(B)t~{Ph1^E=&2J#om_FYMQVtr z_Y4jywt$J@H7vnK5Iy1ccMm~w%|k0ENuI!K)vV^FCy-xB3zMX{MTvVKPq!jSf@QVnW{9GF12y_0zjFv|J}QE=mIrWTC~qoGNn?eYB7e!R}t1Zsy~*ODRRG zR8sTexYM`~8mO=z%xZB>Dz6B{{vuElA8m+#C7~MMJSftq~%~yhNhHTIfxmuPnk9(uac1dV?=t@x`7TZ zai8+qY#BTE?2`bT>xX^OWeV_`s!uc%ultgASo7A-AORYTR7*l}%UD&96rP$}S~k|4 zesEa>T15&~>nyUZE!z6+qEE9vw%43XE*1fybO*tkwrL`=o?+v2k|VL!BG^3R%77U^ zyf+*S1*vR2DPC6=d;5iU=&-e}=i|JVsSaX_O zFkV)u@Szk*I?o&waU_2rcBgbB`Z%DHb4Ig{xOQE9A#}*vshL(_jb(|(5%)2tY}dM5 zdQQlq{R7Gdy55l>UBnM8nN|Jo(@AE=w3rfQ{zu+myem8b!=D9VM}m{Ibuc$NRhvwT zj2aEZu#j6vV?7H=%#$q<*(RBBs9d?bn3|L^r>M^j#)ac&VZt+1tM7ipv=Fea>7~V< z*vRb6lc6gZP0Yl0Zl?wLz|vgJ4?Q2jD=vNVt$naVf2{h7`GLme2*2$uu;1=1P$@5%jlVoO){u{-SAms zid$^4o{y*-4Jad3_UkOvdsZ!o#7gr|RQ&s#z<`<9nA^OZPi(VQ?~N9b&10dpx>2i? zP&_3Cxa9Mkv?{-D)X`2I>3_dRXqU*H!xE_&PyC}jnjbfY5T7mDGH2$xM0NZ*jtwn= zu}1>8t%7=4_@dbYtWCL0E2_;ZV6M&ly`Cs*5UgDnvOFAX|J^xwa?3=f*Kr3ecgRG? z?Hjmm9mbloJGc9-e=QFqo)PMEdP{H!Wi;&7&ZPXr z)ND;7&3JUBkio}TWRjrJR#;R1jNJ5OgSl!ya<(xQGg(x7gqq=im5vt{W zgK2JeHa$7)0{wt>Gs^3d9{qVP;iy- z^r+1HWIIJtMRqlkeC%~gOBW?I`{pD?NiuBKGlRsiI^CKW@eG39YEGiMmvZ>nI!NC* zVT%{+oG5mnlhL1GpqS0^{7L|R|L9PHeq$K2ooLB)c$ zh5bB)Qex7tLCbDS@yPAiC?P5o+Wosfq52iqgFgO_ET0``Rh(=HJ~U zc~~5=FKHNsA2`>`z8L1+sDFzF8ZIvTS#;StEo)7^oj)W+sbV*+)j32SfmW#EI2|n` zZ%swUVd|eqFG?Ez&HA%9Y?%0J2F<5LDgkjG}GAHa8a%+J*-8&Hj*&~HPpWsh=98qY5TXq=0{!gUAg=P6uw6WxH|+@baK`wnV6s;n0EHki`&ir9K)Tf2gV_5FYEgGbl%Z`A&_F~YTe5x%50b|KU>Jy;~Vs*=J)?ug7%%vckIq=$Rw zu5>?UqFAnCp;BpNp(2xxj4!USqega4d6hoH0GcuSWydk*7or`aF^w`RQf<~wqHbru z_trt411Iz?KJhnz{acg;1B-}{fAL^1OQJjN9ld}fUh^uPFoPJJNK!TsA@yBCq6Dt# z%3HGG+~H1C#X+IEO!ng)Vlb^fxS(^Rl1#%e)=QXG3L`b(xOTpZ?I$yVA)UZdZaa8g zB*A3;qY{%wP<>~J;#_98Dx^65l~q=h<-wt!JX5EzV4jiq~%Z_0_%Cade`be0a5Xt9upb3 z;XlgpQXqI$kCkpM6*r_Ztm%Bv?2t;DCPEW~PS7nuP|=G4tc$bvcR) z+OGOLPThR`EImjty+dJyj=Ud5O zghaDcqIh(eSj7bH{P+1+L!(}2t_l%sBUQrJpSC%Rr4ZfVk*r)z^>R(hzAO6%dI7%- z^=m$z+4FRuZ%4L-D5kCUxZJU`UB*EIQIOiJ0P!#tM7ulGZyxXI|ClswiA|rQajAN^ z4`xc?cv2_MZ`R@`|N5b0Adp+Gr*1C$d-TG1o6hOZIX56IU`AMaACyJsbSInJ-zS{B zK}xGZ<8()&c=|SuhM01Aol(iGPWZI55GFE{rb8sbJ5eGh5J6Vlg{HQSTU(D#Ng{0s zG`&OiZPxk>vs8^mSwd{ipUoY?9U{N87Th{B==mw`H;pq1J+a98jNJN1=T49>pgt2p z3ioC-_C?gm-%HeJh^kuWr*&Kai5k&73u}YumE>dDWsRM3D!zn2A{{YIR*@KP3+Ww3 zE6(tBdC43d zLV5jxH^bYRjaBMDg_EoO0ac5upc`F{OrJ!iKNu;BaTLC=-z(8*a9P|x_n?!+()mWs z^KYw}A!rd4z25ToFb1;g}!%n0Br;bY66A#5f_fXdYo`rR*v1G%Wt%Gv)^apW5hjS0R0oMdkL@Ug^L^8#l=6>p?~3)|3J z4esmQh>Q$Xx$!sFr6gB@sd{mVfgHz-RZog?V) zT*2qq;h5zhI={2wQ-UjEFkcOOH)wNpBb8Ir;} z4C-Va8Q_#hmK42u8IV{d*e*jC`fns8a7{wZ4&%J^Q_R7LF)HtRMg`^Sm`3Syo5UGW zzoZ7L*9GbCZJCrXjY21AnlikZ8j9U8n?4MH$3}^x?NCI92&Q{23hYQ4coV(9*9j8^ z7%k01rJqyc(n*Q;Q%McCt>kX)bFrQ0Qboa@J8REu!%{G-ApuMJ#qH7014O}HX{aDX z+>A{eIg`21cvV=%xL}1`_iy+piGkOTAB&sy>u`6I@7>Lfo8PdxSKD%flnGAuZFHG_ znDD)9vi>;BrNuzI>C*MlEAO#PR^=M^CQEWkNGqT=y%)KN*wftO@pKBQxGyGLg>kJG zjpuP6kjmfQQFnLOiFzd3R;2PBz58|5_>}Z}e|JvpJ~}b2_t1@X(lo^w%xeJY?=~w9 zd#)X{G!UDR*2Oz!sA8iFy)w9F;Y#q+2&o_4fC~&7Gk8|B`$HdgdS$A4+@XUYerjo` zZUS=wk%Uhw#^DomF{J0wy3JpF=evAiCCyi9`pXTCO15kXM}^QXzg`+940#l#*+YJ<3A>xN&NNww_$Vt0X+W{2LKQeTL-X}m8`zG z4PfnPXzO5X{MTr`zk6RO0FwWDRNDWYfO-{-3jluq-u~CjHm3i?{ud+w0MO`!22Nhb z;r$IKZ`c3;Py>_!2%rXt0!n}~APL9=asUL71mplQK>jtZ4d(p$UwHm`75MuX%-`nj z{TqN^Bh&zWzyS~g%mFLF7?1>P029FW)ldGqO9gNM^Z^^d5wHUE0Vlv5umx=X&QJ{_ z^X4xOWxxq=0L%d!!1O<1qJE8G`qzgIF!-wmfDS+kKmj6vEnp2;1IB<2-~>1V03ZvP z1BQSDU<)_`wtxxX1dssYfc|UDU#xb3^Q$e$g#-`*$N&=Ht&))rtnykYq6Z43Ob?m~ z02Bb+f91A&)$b0-{hi}4{DVgwFb4Di7r+=G0SsSr`&%vsuU=cg;Z>6ofCWJPYi?k` z7;t>mXb#x@o0|M*yo~>e`oF*g!2c7c8esf-)<3wI0LIss`E~tE10DeN%Hi}HYXj&5 zR{xaM|L)n0fDvE?{Ox{G1JD2zAOjc!rmt*&Rm=`>f6dGkFnd+{*Cp0^JzM_o_P;v) zSM4Hy7cfIC3)Khg2G{{DabKa6T<0O_xP8s~qvkpB@ z6aWAK2mrgSI$g}{)0msp001E&2>>Gi003-hVlQrGbT}?BFG+52b#zx{VRmIMM`3Mc zNp5g;bS`*pZ0x;jQyW>9DEj?God1wf^I=?ZD7ktb_uLp)`;6OF?siO9myhk5x)C>S zOeN9=<#8%gotXk_IwnGZG2&&YF2Dw4;|E~;0Bn~F%OLQ7X)9CGC;q~Xwb#yfN~E5M zD*D4rS!C|qd+qgpe(}FC*hO9xd->>%i*h0<5>1e$PaI3p<?L=mKZPVVDmiF~HUWsQ?~O&B0tlzp62NWY+J z3J>2`>HAS$iV{(zzi^s-gGlbryWZ&G_yJjn!B-SMN^k{*sB%h)5>6!i4V8=XDV4;y z-Zb5<_2oW+ZmyT~$qJ!=66Gi_as#{~@V%nzTyZ{`B$66&@1*qe>ta4r+Im!)y9;4!*)e@)!Pv=`pFhy|7xBl^(k)|Z%y@fnwlX$p z%pFu7-qv?#4hvK6PgI6J=%dpgGgG*rKAJ5*&6gGnA2UPxbVgrUDQ`^}^ZD{m>w2c3 zA54`N3#GZ0kD2L8=An_DEiK(Dz1S&bH_O?v@=s&N?yT|lnNgVem>Kq5^;!R2e{mMk zsVahfT`z(~zNEN8E;_FGs^dB@$qIWSBr39}RZf;fcD*S@A(AGhxf_x^C2q!D_cf?-z9s*JM9H;VqgwtgDXHFqW!fPZZradU6 z&pgNbFD-BBH)e($XzI!WU z$_V;og%c!=C=xGnF<#@{+exO>xFGd=E~;FZuZ+!n%nTLt)5U}P<)7YqSLaGgx5DjS z-(D~7=iovQmi5u6m5~kO&PF9O1QfckSls_mn%f9$urI)Uu#XY>=tIcR}h43+MFfNFWPYWs+Ct|FJlVpXhBx`Y^ zu*X3|5k(L^4(<_}z^+P0x0?-(IgQ zEu%7He~!Jgx}dMTD?ge#EKH%^Y)lOqx$(-K1tYgoS@=<(epK9_acWEWeCgd^KW2v9 zJ2A2gm3w=}kCXc7PH~SdTzdCc{nfNSJ5|hQ^vq=O;I^>~I(C}~_pmV2G%7c^h7*0N zsE(D)Vrk-OY5Yxb_x8ukRI^_xzMlm9<>z_Oa&J!?x$)-d_+w@obm^tH#>0ZXJELds z>Qf8F5BJNPo=50i_;_hT|Z%3bu`#^d{e2oD=reycCNt&B}q9&c2Zp10LDu>Q+53ctD;B}riB6r2~7el@J* z2i^(qaJOi!o`S4`oU~QrON_XghS(|oEg=h&KYkHjLAuTY`2)7 z3*6-wXIo{Lgg`&HrDFX(v_g7{mZxZ06)mqcj+QpT*MW!)5vO~dx+t}Sg2U-A4DC8# zY}r~Y*lFj1fc>=J!Pc5HUuodXk?Y{ZtOFUUpPjlxy&5<@YSpKY@!XeH=IxDzJp6ZY z!mMoK_W8znmFp!$VxbBj>f;p~_qO%fb^YBNbkH8_$uG*1Ms8|7lcnVe&W zz=yC*!=dci^GMP_w5~g;64o*==$l&i#|aR3p@9%yW4MgGMd5@*g2V(~178;)e9A!$ zvc&NmtkbW^DJkal=b<;1h3E!(0RnVATrZ&^-5N}ZI@%PXr4$Li5hdUjw6-j$oRX3x zx|S-N>vG_D;|ArF=-Eb$@GP;F?v!3^L$LqpO6lz__%hz$3;STj`~)~s5AJ@<4B?rbN7WCeV2_*m%J41U21}23 ziyxR9$$0p_H2w^{4!MoW@DuRbjZYUp+&89%^v!$5+r99ThS8_TouKdnP(dt3vojoQ z(Bh)!fbgZ1C{n;vUS=^^7PtozRj4S6v1Eh@hxo{F+2MynBj&KM3@I4dXBbK+nb`&FT2eYoupS{{! zZUcR{PReW*m-?6)26nJeu;`zKKr(O2kETGCLbu@i74$V%av5M;OSd3K62L(9<%gx= zT_pALlSlZG8ld;EueP$O&bS?}5*|WfXtgMHD1NpD4OrvCZbpGs-3{go%;Dg`hsIpD zY&~?`npy(;MpBUngqS})F2d`~DDk_-q@(hP88bcOJ+EkC(m+TUsw zWbx|=Sl^x~b7SJn4O-0M!%a}D*t5MrVEaC<2??TVd?M-nzV(NQ<3|iM8QGu88~4Jk z&r<2GX}p$F@f++X^MqiXrql?B$!oZG%iav}g``3TAg=8Eg!!BI8~SKA%r}}wNwju< zm(ny@Y6dY?x(?S%7YdJ`?$=K7G(4W-m3a`=4Nml?Fm(0&tr5I+ebPeQz;7b@hW}>M zc>Hf9-7E7-?2mj}PHD|x@(s2UC(@DAxF*SltSarTR$=HN>)G{z#Dfo zEp-S2(6}So>&D_RYEg%UW&EX>2Omr6eWA2Fh0)6L*iUSI)68hiyZR!h$ikuhQ)T-*4Ep7Q62M)!VyWo<1|C2uRO5eO&%)hD3zteZu zi}{JlB6XE*-qlCJXh9EIXg5@XS8g~xIPkv1eFtogrJ?HbVH~CCZNMXq4goKBJ-0Z1QlE! z=xqRJF8H)kngT@zWF?R8K!$KBFZhaVkEWg{<4}Lf-j8`&CdOlwndRSW7G!_b#%pxR7vfEiM?~GQ4 z?f~7cFMw0Qq{;I0)zaL?VPOj0#>V7dOFz$7DTFd6CQ9?K;3Ma?F*_(d z;PU;q+`OL-5&0s$y0Eo#^kHD8wul+{N9K9*f`4zf^kUNepyfqr8ox!6(|DzyXk4Gd zC&-|z&{8>3bQ+RzMNaj{IfWnO1~gg}*O!uL*#-(xmT0emUrg@fE`IYhcNu<_lOQv| z4y8-dHwP6cqEl24^0MFs^S#lW6iwx#aY2l+C7vKw32*-=CoixPgB}(@+!owI1 zrF50$GtdR83v!TGV(@EHRx~sE#f!{%1|cE!6L0yVF`hAU zWM(Qucl0|e`qN4C&h@c;JSREO)AYROLvT|pP?3w zzNb%(mY>`|EM%`<{4OZNRbPGxp%4?vp>lF`N8g-fA%~f52!#YWP*H1OHF7g|-FU!N z7H9SB4s10$=5&eVUY2)hn9IuUrtz-w#%6gVTg+$5V{d(Q#+*jGGy3S$(#w}v_lc*g z4Br9`1f8S~6>_mqnmK?}hs=}GyQR|7E##Yrg>32VEyxpo`d0)7=0IBoqWBm~@`Uu{ z5m1yKzAoifjLj$DN2T^-d22$S3d+I?ru={ie{DYJP&e&E36h{WDl+@6h#WZY<3Pe{yT`1cC$^#`;gSyWMXDqxzHtH+R3%eHL zhMt+MyqIfS#0S~`?}>I1&AsckYcG^o`90BCW(hMFgPeiBEE4_Tt`kkE73pykHW13I zwFUMOx6jk(nQR|~uMzE%98IZLWKoEw&jh~1c$oc*gY8JX_M$la zCCSImgb5IQ+9(*~4qBq)$O+5V&r^1&)@gdg>Clr?g z4_!Y;3IIj-VbUeqPN@T!)JH#52PU~*IH8ync6{Dh*Dw8;=IfJ7cksaLD9+>%?MIwc|H}R>45& z7Tmh7r0Z}dCixi4J9=UMwdJJd^YC|6O8J5V z$10}$uxO8*@`prD1y$pu5lT{Zj(%Dzt2#^|-6yP0X|g-TRgI`A{Zq>c%^h6qsFZTY zC684^d7#i9`Q(Yio(iW12_ckZ>IAj4Rwi|l9J)^+ol;=8iK3c`8SIZOCopgJLPrIX zH}T_%(ps7x^X?=2^{fGnww z%Bt!aR>vx}g22)q!Br#0>{Ns`Lo}hJSZ67#wX*EENT>Ux+9|bmef;Xk{8YySEhojm z^v#ZnxxmcNW0i2hFlmpB3(k8z6>m)uOep!*ajI&qh&u+d=|1UpN~zr~+Kx<^cRbK? zA`HwY@2F@COhrFd(H0Do_K3FNMEq0H))c{n5^Wu)s@96OV<4OE6K$uI+TEh<$O<0E z11%@QzygAkwWpIR?=U!BD)TYwrcfx$1LBfLZ@9qu4+VaQmm(~75Ab%$i^#}MYM7seLzi;C=ScKAxOTlzz!NTrpENG zrP9V$<CUwFwgIujzs@JHwCQY&ncp$p*Y?ow(|Orv9eZv_SncS zAbEKRuaMVA*KoVx2=5ph0))IBUv~hHkT&}Q9C=lq<^adgZ{knnW^Ed={);`;bKI0< z-i$p;(7qf6rdJY}U(22fq$9i*eP*Pb8L^hbUeZ)UvL?7SKt|RM7`Tv{%#YBH?7Vpn zbFVO21%9El72%5exzg}15|zHPYwRw#cNKz!e$~Y6M-U%c1Q9T~DX1C@PCEiGV1P<~ zTHm|}b7(tBs#n;Ap_56jy`)c8NNeepSv05g`ir1f2Zl6Dur9~U zB^NaCBxWsg)Wj3}$;NuoyJram?!Y}FpvtG)30U_aq{~&R;7ty9A({N69OXrP<8myt zsSTfjYhWnfo2GMC*uO4+>6;0E9}%Cs{3WNqnl#1_tkI+mo4c2N;+uWmIa1C`c_BvG zId9yW_`;TEQ)ePv>E*gUo3*BD;3SfcUTy6eSIyj_XFiz!E}cWOn!iozo5QQ5{|TxW zOqJpU3C9Z1flM%0rK7i2Ww;50^97|p1;bz*(@gMC3h8s53+9KYT(8JWHz=0|0OPvo26BB@RgKG5Cy~s z4nAtyd*OQ&7sfflVQI$;f6swd4MRW8n`FSdvHNtA%9L06@<7005B|! z?ZVswy8^0UJI`9qj^SQB8#MBx`odP5#ef(6FQ{oL+FlyyVO;Mz9c>0O;UWw~5=A<$ z>AHM_NDY#ShgGW_52uMMvLvTeG0n-)P!Fbt_A7DXsLu9Gmvx<8@xWq0;{wxtfwpZRi3WE(pt=W0Nsqs4OqJu*?JzotTGn_`v1FkOL>= zdC&o8Q5p;Hji2UWl-j**V`AcDfK{Iw)pHxI1T9z0Zz4uxn9I1gjYI1YwQ=Aa3_dm~ z2H_Td!rZS=lDWosds!_TEeSh(2F?oU0c=ZP2eNvHQDd4}F zLw0(ZbA&6+Juc0yIN6+2@PUs0ZmqbV>xlEokd{4%+#&UT=fM@#e=EECO8( z<)I~gHhXdvHK+dMv!%^gj}H=@^Vk-KyAAF3;lh`K3NfX+kfC9(2m4qkj2Oy6$f{|K zXq&I2RTprT&5mUrb#tnG6KNogxZl~=|3F9ED`D@`+&lO{Ob4ksrrtMI5yq(co;or4 z8r>r}<9J87j|4CA{Um0=lVg8{y_i#p=_af(wpCvV8Ot``!qrjR$H*g1{V_jknH3Zl zU{ZGR;CA`xlgi?%y%lRQ{He{X?mJ%4F3BdLQM2#+?|;+k+zr##yOffme+d^v`~LgS z|Eq;2;sv(}XshJZW+OK>TQRYMnNkd@{s)MnsZ`U4ar8V#XK-Wk7R~eWImc8YlBgyt zpPcpVVK6R;#5>TQUbUb?k&Y;Wvr_P8qF6dEYQV+(Bn)KUyzMaz?bypyF~6?oHrTlN zDG>s8#m^&MsB6D@S{HZw79ocYx7)rf83Z^E)DPE%;|cQ$*LKUq@F3q zW=#L=c}~HcFfhAoZd*_hj5uW62D$}pa+5?;8d1-2G1M6buE>MZQFu?YlFbYNfHmMISlB^wGk6JOZb#3) zs&f#zgGBY2=fHR<%R%!UnGG_Y!@`uu1D2oGXSR!bYsSQczBPiw?muRRjO+p=mG94k zmvr_AeRKzT8L+b-_A8m!Ms5Y{LK=lG&F>WVb2X0z&n`cJm`|plA7u2^1%3FZ%Fu(u z!m@iq#@M(q_r5f@aeTDHl{UxGnSt!r$j*ZQV`>Oe)&ikGvw`)4DM$jQr}VLCee`K% zWW&gfph{89XN;GRjLcJ~gn*pUttlfrYh)MD1|QH@UmNpx z!~2)Cbdop~)azHN#=zVx$n;6frA)vp5hipo|H&zL^#_xBc8zL-*4igSH$RR78qtz48~mC&EEE$Q_~Ta) zSL&9~?b-7l#nYJEF&2hDW~Ku55AJ`sSQYm_z%dHw!WoOh#l1Bqr{{L`R|g+6kZfpd zJTdNns0`1P3)^7y9xVS#(aGaf%#Qss(TUSXUzg@K!aE?2T?aEw(I7R%{2Q|3YP^?* zn3>~4<-UlXmnA&J7iXiCjo@!zDT=JXPd)TEm$yTW%PBF&^$C)o#?52fNh|c&%tRNY z0huN(cs@iuA2fXq+#k4v3LM^HqRO6~aH>qdK=lb`nhKJtK`MpZ$E*B%ZFQ@DUJHm;9mjfn}oM|Qu|+ySeJSt9QB4hvJv0$Uum>;!#$ zthl>c`gz^|C9of;rh=wIIm6=C#;bf~=pi$T=qHa!$8+iA$XjFI^!^_b)&9gMShA!{ z|4ko)E9EtfkH+D@;3{1{0YpGS|X*VNOisuJZ<@ z>sqam*DU$Ne+LN9j#+<97$c^4Hr!lWH468Nne!#cQfQsDiLf?9$(m7ZR-17e)9(Ic zFh`22?J#8Da{P@;$T3ikvCM(ylo}h4^aA9Ro`&e#&zw;H{w}3yveXV16t&JkHM!Oxx;iHrMoQnTwoRms`?*eR)XL=P}$_5P7h%eI@g$uae)2e?*l zf^@8@v?5)pHt|%Ze=aSrRz{~!q)0wZ?rJ=bmBvQHVwXsGm8t9YeMRY7)B>a4ABH_x z_K+r;E9Js#YEgsTu~=zt!^rNGUTl}MWBRKlBlo;o`dfJHtXfZbS)zGB-z1p=;FR}~z>XM$BL~9*)r7u5(XkBijJodc2`vPo|DuHb%y`h#Rp1YixD&2ZS z%Q>hC#lq#w#^x&YYZ~3DtloqEGrP0JJ=;5k?*<${sQi)sB{&3q4cwZVOaThEvt2YO zE6_=d7MzRebC@Otcitx`Dl!r-NffBUG(9%F7~%e8dnQ$m7r{tQbAkj`UcW+A71CR1 zqdad-6g;VNXTZKEH+gV~w4kb`d)(5WayJM`Is?VbiN=fYkCdbdBK#Hd#z1b_F4~|( zAoecJeWK(Tv)xJ}k0lgZoFte(7d%Vf&`dPn=N(J*aM8FR#@Js}PVUus0n&qLikcP| zR8KY%lKdG~qS0e|MARNf&jD}-$H2=gOP_MRBq}GU1DR&tu@eeb#S>ypA1{bBXR>PW zt4g7;@1FjEep=@7`;+`fS?VXsSF}9^t;}McMiW+m*sv*jRi^g=eNHi60UZ{`S^5n+*3dhY~GT*sda<@h6e`~Zr~^n(XjfoF** z)&XwmmcBWQ&mR`7vWp?B1+eQ{Y+%L^9g3o|d*8Gn^q~`mnA_Hcv1LIaut|n zf&gPP6EH4I+7&IdqI|^^UuJ9#GjfxP93`sy*`N?3oPr)GrdSK^0lnEN1VG=)0ZT0-nv(k7I%wl?Q0+v5S^ucF129!y=aK zV4IBds>%0#JSw+gGau|x!%hLJ2IV(aXbmoWalSNrTi>10G`&-lCSB8ZTefZ6wr$&8 zwrzIVwr$(C+2tI%rWvX*NTXF%`mJ_+hs`Q4I_OT;wdu`Y`hHxK&@Xqq^t?Yeq8z+9IC;(J5J=-g-lF4WhrBm6 zJECc9Rx-_h#GiV?3^|M!xrkW_k?WAo9=0neM1$&rs~EJH4N(o`g@<6|U)xhR17f~h zjtGBF1(gSb|9uC%dZrQ@li*{jdnT-RK&^O-pU;B^&wO3W&57D-rM32JD)0W8JWQPhwHkMKcrDAx7OEcdH0l&@b!2d+KieP8>Xn}02M=~f?#uC2pZ~&c? zwVH4uU@wJR@cjXM0T8`6od32T-%s;RKzJ9zCn#5;s=3SQ(pHnEd}FBYq=8v>#MR4! zb4#C?yA&oGQ_dFa&Z3zi^)u5&?O_(yF937T#tfkKMNzBtTkt~3 zO7c}^@HsiW1Ma;9J5hycbkbxnj7)I@)#j8`kBs~+a@#BWi$_iH^cvoW9See!aa2It z=iCz>7Isj4K8{>&xxP{BwsT-v_@=+9<0$3wndl8qJ;Ri67vP+iLK&KmK`{DI!!pW( zC5PD*&*c^B;|f2jtxSBzFg_XEXh}aa8ms5CaDuX({APqslz>J>s(^~M6!r`_9~eQK zGFSmHfx8Vv%UND;BSt%0;^D3U%UFCS@saDtOxLL!?`Xl)J>4n-qH$6_`u!OBpxBNt zNM~8fC?UpJ?{B&@WegX_n_6MSw#=}p1z#^eiGa_UjR5f8O{#Q{2iKJ#t-k~kVFLw# ziY=CM;NN(eEG%llhONNj<9>UkDF%Rja{i@9sK1QKDdZ=r?r|R1_}tuhU-9%v&!1n< zmkT~;e*=}uzEJr)Ehhh@(BW%Cm$06bL-TnReBp%-`6$gUA?xu4BNQ(GN4>nZL7#9w z77G;>PJ6ev(ljq+m%cEgD&{Kv#6zeb+i+|T*pHy^H+oqB%}oH)bm^M)vPMF3?VCUN zOUFGJQBV7cReumkbCPx_JWnXOSZ3oMxgSt_A#~nCD@~-`O!FdPjZ&AX?vOmUlF^8aCug6^;zj&%no^JuO>$7G z_7G3RKFr~J>abuQsJ7H)`1txXl&RjQD>-yUM#BFL8MQT@;*0oRf<+t%MAu<$cV!zwbzRSp?tDU+a1!EKx1; zHBw*yZysC$QMhhydqO+hekbYa>DwaW7SVJ=5bDifKQa?ovj>me_3-QEA zGPT!z0aU+kJt`7CF+f^k?Te$qJP$V+1lp&Oag6wR{8}w{r((#^L~NmpVQQU$zmAtO zMf$lUc$yki|A&oU;iQ?=3|o!ytwT;DQF~yovyI)shSdQF&X2%nS4| zs?ir0HVL3cvZtiQ4ODekwb*byT|@ydZfpv?P?CFqENN3(&EHi-t?)H4;yvT6;o2GStgRL&eEyBPZBFc51r z=jV@R+jqfPG|v~V(4$Z;xJq&tHy|DBO+Nd>a3fsFg=LRQi{IOH3q~Ku2^i8k$P=ZU zhbrtzNmtcVVbg=I+z+;oZCk9-t3uoRw1dDQ<5*k)v$Jtco$iJbRqlU7^s4_|u2F?} zW`p*doeThvJB4HW)L)qcvyLAHej(ceXs@-kar{Y~leyTpE-O7zZ<|OjJRm z^+N%UnEmft?x8-@WRw(o@8p^295=9k=~mo=<;R45inJmlsa@6AP)*L$R>ONLnPBLw z)`5pxQD+2Iq42<-4JBg{XHks(4`3TN)R$ggnQ5UU@`<;xiN+M`$_h^LzarNNK&HE` zMMjz-xyh|ADDzb?Bv*|f*2QGl`-g<@fE)VLF@;H=)@Z}3gI!hlr++^n282TL)2WvZ zM$OYzo+;ezABHL}X+_phRhAe=7QX&Y=VvvZIhA#(r#D%BLuSZe7oLs9nkF1TwfsrV zB{*EVOa}0#t$|bfZ_KQIT7lsFGhXk+p8A3@8U*G+$_{l|3E-3upZQbq1niKCM#FGr zYo0v6msYy9vAc?I>xw7Bq5clHe2j@R^XX=L?fNoq z>JjjgD?g*M%Q#=aG?OOfY@J94Lkk2pAa#3Jn`y!3AVP0i5b`OJbv8t?Bt&5i01|Ac zabXrOi*ye*Zgp*`lP@J1*kfAV@U5|Mz;!@;x}x28ELME3eNDiAw8Xi~|7iyNuX!?U*WOLJpJ3jv9AItE_AmS}lHdx(lt@G{^-FF}W;z2dso{^A1!Uub&m` zlwIfI#+Pl1l08dF#H(A%^Fp^oKzqu=<7+xW9|3Io81KRCVmBhne3VT`Q#i_S9qSj|Buh@+DqKl>~oce@LE^Mc+R@ z*W3qc{M@BQYW(*zC|-OP7T(A2(|k%w91Gx-Nb14Q9`$zP z%WrLoKAXz%rs^*mqR6NvT*_ed6q23I*OnRa-@#XS*s7d8btQ}=RWq=*3zROzCwPpQ zsp6K;r|x1#r+Dq&MwB<184x#i7qfB5XU>P~UK9i(_NY9~r|vYNDw(0c-erN?+$>xqR`o!pPp?PQO5S8DjT@d(plT8r8nBF1JtK<^NdNQ1Sba<={zq0U6q!5~_Q$aHOEJ zEAQde!dJlFw+Xh_H1N_vcq!GO#?s_Wnr##05)w<16ii~5T#7JiEnxBKIVyDs@`)*G z`Bl%ER!i4mJ~Z(OYIJ;U^NkaaCb(bBwr$bO82eyiQSV$pJbO9E(dGhtWqv$*#DLOa z?6&Rgz~9TICrP_SMfw>V17f&l{QoF2+Sy(NDGZwnidrpPHGvb3yMg1G3je!-sF6i` z@p@Vh7bWqpN5}J1ZNEhF!~MRfcW&D++ZcB z_94fX-7veBw{5kA=WCfJffA~VsKC1*w8Vj9_S)l~$*7xl08!_0E%XHOaF%t}hW)V~ zCvvKpNwC$W;dFkTwG0ek|BtjWPh3N9hC2PV1fWwXrH{Y|Sz}RMl#bW2ygcb$+~XXJ z;ivWMP!3siI7&x3hEq(u<2d3SQ);v;yP7U01X;{w@A4)>QnJw4afYrLJqNzfZiO{< z0?NX$36#5`3iZkSqM?b)-A7~`BXLQ3-O~j@q&8mLko@Vp1O$V=$%@q(RC`l>0b0*j zNomBzj}I!UCAH)v7d|VW;aW&g+V8e-^TWBScGFV*sWl(jE!kf@E? z%$(%&Ap=B*Ji{6K;)iHg!DqaQ`etB_Pkwaqa0GrSQkMw1c8=|el`p&IW;GFqKStDA zUR(S8#rvDd6+;1juVEm^)>2>b9I>X}YYI)<#&NyUfP!omPrZaxV~dhpLRA(Db&d82 z;6nxPF8V=X5wcfNC|7n&^OH%iuAME8n>uogIf_(oD_Plx2M>EE$Dj&){(M~VWTPJ& z^#h2p=vfG)l=obPAf)><++#(diCAM)yHSHMAMkU;O z_!$l_;!dr-&%5&v7-#x7dF}XjZ;h}6s$)|dkXjRn>m3ImR1-_5bfa*PhDjUjCC$wJX(_pvhC&H7+WRc{T-NcYW9I!Qf zpi_H=tsl0~;+7Dzjsnk>Y14<5#jFj~vthGB#BB;XBXo(Y)T$IfO{2rPl5I zv`j&U|2&%CV_YYJrD+hlEUECAzzt&pY#$m`uU)mUnWZC3kRHG>&p zCpdNQ!Ckx^r&)px?4|ZJp~IycGx$I480Je`LpxsI&sD=_pUkW?8w-CiXODxLg;O`u z$eOjb^~aKh?YF9Vj~m-t;(RMz@8GI5e|zje!t^XLN%?7Eh1)Z=e63(%uM);!$%ikCj#3RVvf2{h|C+td0U34%ZW|3b=Bf;lz(EZeI203*@7EIr>?pTO z*YKd%bhEUw6lK}>QLBca$KVH|jwIX%M|L%8-s^pAEmZSW=UOmuxz|o4} zM2}Kw82yJJ07KuxQkb067dVQq@c=JQ>qLwg*iRy%A4X{^F1Bhw7M>c{IT*7r6+8sS z)hl?#W{X5agAKL3MhVz?YwC;F&jbGx{J?e7*uSU=YR7i!5*9$WYHTIySMcGkQl84< zCMQV8M$hyQVTcUU+v!H6P&nAZ5!Xv;2Fsk~PDtesTECPzE`F^ndY-)T`N( zVdwA=R|~16sQ;sZRk}P*S?g=}f+(x%KuW=GxOkLX7UOrnf(iqPYznyfc@kwq}pLKM}6R}Mbo-`qaVeb zI;Ckh$6NdNO`c?R#mD34oez8{j_vRKM=6@{4LO>JKqOK}Sd<9*@$tf|s8nA8PIL2U z$Z5$-1v_A$T;C0Fe*qvINuys5Rfsuz>~#~odN(`G55=D!t`JBozylxe&b7QP?mG)+ zhX!$vGP5jTx3vVw`cM5xUH%6nB*8Xy8DU?Vvx7~8bfW@rUz{xo%BxV}{8~hZ9u~71 zf1tNlk+Cr~XIGrb#jA>Q0z~JGeKp+!LTMH2nE6Vi&Q5sD4Fr7WX#`%6F4|F*nK}HV zHHwY^3^kSFTUC9$SnV93|C81d@D-jw|Du1X2h3IdPbVOy2T|kTV}k{+@Dm!&5>jvr z>qfcsrU{LdbFt%@PX6Bv^xdn}-Clu%^)CUvz|9-YAVL!{%W#n^NRl{1e&lMTP0<<` z*5;ZJ;%RKydMyCaQ(Hx3$J%WxNJ7B;L$km9%xVbc%8u8TbXCB=OGIBIuDjL56};&H zuNS_Q^2Jtl!W1hYX!rFdLHK8M?svbtjALw4$=!og+P+N{v8r`~-> zz>wLci$wDGEpj8y>Y|(T%`~C>K^-1u9>>R~aKKdB(t^`Xu}P&C-tctm9?pV(j2^%e z*lyPI)^X%af$*nTfG=9;u|UeJ;F^FP!D_X^3LN+s12Uij&A6^!JJNGcI`--<=)7-A z0W}J~9|piB6XlkFJfn8}18U;DG+ECpu9Qr@Z12Minqc9=3%_V6NS z9y)M6NPtw#OG=zitB&s0jr#Zc$q_JR-C)uE_FCli&(Zj3Og-{!JWl^9IHE>|Npsy| zBU>RZdiG+pP{-?IFebO-R@|!-7>-|`tn$b+GeK7o5Y)ZNn?sk+MXEf-C>w{UUiUPM zCVqTNxmlgxre@_l#!_CK<+VM|Kw!qREFOsbRkP%s=~K=f{|0*F+(&AsaO=unB*cRd5!SKSY3Q?}3ah$eWFGlHIZDTa}2B7I5~lWh;}CO5RFo)fh0t z@uhx)HC<20#KA;`o48y7PfPyct^sqt6EFlwq8f0}x`7-{efTp-DBZo;U9vwyQUr$~ z+szI&|L*A6!N-||nQ6$+PA@uC`2u=P1hOON)(KqYA8gzqyG&e=Y4p>XE#rp9L}mj9 zBUGNxl1ct@+~6Q-8a4m?$$wn)OWr^L-2QSD%Yoxn(Ecvl18Nhhl@?k zJ9GT5s>eJbOn-j4YyuvJm=FZ?+g+k#;?egfEgNpxb5mJQ*Lj*|%Hhi{{feC~tQuM6 zbLj7SLzHBt zA(4RXX3@9G19}aEZJTEd@uhNo&CnnJ<{DK0eYUUCx$E=WwOUTyE@^Ncl}>l*04vvQ zR>4;L?C0(wI_7JIo`x(e($=78xD~6Qks+T^9E-->_F1DIFx8D;zM2*(l5bQ`KW4u0 zr@w#IwQm|E{YX)AQ%PFC&m{Br7b(tlW3<9NZ#eH;0h$!=%2*J~Aafo|Xdux%bU@3F zwVk-*9jaLFL4<@Y;RzePqgMsoJ}@6dlUcbtVpbqJq1=q4A|80dF`A&JLkzHNF+hoX zK?z;)a6A-;0n{aqRbV+Z!20E2IZfP(A`o{-;XVwuS2Sps!Ujtj^|f8|W2aW#j>jyR z$;B=Hn9FWw)m-l+-n-WUCGf@c#B$SbMW_G%Ha!tKt9&B9nINub8=C;vDt2%Vmg!Ur zo6I+6C>{Rf8@yAz!pkA1lgkH{CCbDf&jUU|K&GXls`YwPLNczRT!`5!o_a?N7l1R|k+nj(G~&iM7!P7yViD!dh~tpDOHW-H6PBvV(;v)ZDwz?nu`=$776 zF7ad{Uv&tGQN)SvF-Vx#`PNSvu9TA$;lV2PvYq5%4nv;LM$U*s+p+%e`9P(G6=TdO z>UKm7T?~{GU44~k6k}?1rvqYH?!{raM|%7s?tM1Mq$_rFcIvFf#|5Jc+avE{6W`Bi z80W-pZqMa!4j_rd?^EVLpPGLn8x4LE?-Vm3KxgWg5%yQ5;a$b+Qc}unPVQr?+y|$` zBuEJ`L>*#uo!|Ev+s;Y!Ls(S2cpqNkPpjsC-E{^w#x}9?Y;S^-r_>G9>hl9+sG00% z2U5m1soQa#V8$#mzik`Rp-bWk<%UvLuV||Y!&c4DEhUYsTUHps!^GG>rZufo+E>*) zfUZ5PV!!(T<$oIfLSL@8PqKtzJ;pQq3-z6&xjqtU_H&AZXGKkk(u2MB$~e{7FB$w( z_OHQkTNnOxw7?DX4V`W<;vQ#SMU511jc}l3Crq3cmVJB3S*BTI?B5F`e;cm1m1dcK zlyUU-_;cC$wOA|KaYRT|fz|%8kRj1$&AYgtPj6F8jYEGR>0&)Es!jCg^2eFf`KhkC zYt>F>!Bcv@RrYW1M~*^ro*X*lm7^eXLhgJ^I?e6eg|m+$-uT7GN)F1q05?_DH&{;a z)UotPoF!>hMeihaFsXfAya3g}6W}MCpjEY0$>o97*9VP_F5swgr505$+e*uH31H)Y z+~T~Xw0ikOOYTzphPv9cfiJWWjisgCUP7aTDeo_<-YEIPLsPw(?n zk%V|=c7w^ee=t-Npvai;+(C{q5<5~7RH5|`A#b?ebGV!p)ptcxVReo`0-wj( zafCVc>XcA%*RvQY#u$0NqR*S8Fn{>8&;u zkrx^f(16eQqrH4xF(upw-<-NS@~izBuVt93>s#?IFKu4!+yB^#EK9EFo$dGH)c(;O9UOfULiIgs33K_Uh1|&*A8VZj|7MDZ|F-}fCr0J>7q3Hrk_RM9^EuY_6$9KG z3ST=*f%5yuzXC$Zc{?LmQ7NEd;geSLT2?GCi!3&09^3ga0g`$UC{j`1+_DDUrsh*C z%0CPoN_Yed!Hwq%_^VmyZ(Ce#P5R+~>*`nFYa#@j@xNmEUl%)8f#Q*-}YKf;{1v+#dxqX$gHb z-qNg4xFpt_Bq)@*p~LW30`H2zX8)kS`AciC6MtYIW7(5EJUQ7S$kd$QZ$4gIeVqwp zpQ>creqkkB!AK-&vJume3Hui0Zk$bDN6_!$^^Q;BW@x` ziQ7nC*HROY%ES#4!c+!E7wgP_Q8PUo8Vwad1t+;KAC1o}OhYkQzI>-z>}ZEqeKBt~ z|0i*~vME>ClEY{hhnrbGmMfV$LkAbInMaE$G1EDhU=P3jxXbZlV1Uo+%(zG#_KSKg zzejupcrUEv?)YJ>uJLZp+H)ogXUU}l5tz7at*zJ={oJv1_I`NClUWenXew^Ap{(G^ zaQs0uLY_N|>mm~b^%7Q>35v?6JqO=n_)8+ch^riD($(o!`h8Kt%(F~ygX5ISKJ~<~ zl_GBCE%mpYZg40}H8%u{!&r=VHO*Aiys+HHbe@$U?H#?&OwOty&~yPe37r^z2oh^k zI96`Bh5IRc|5fWkh6f6c5b>cly^bSOHYz2c@r1E-7>i}1#1&W{DEoSz>}?UkzT}K` zoxjX6EZK?;;nA{yh>Dh(~^zU;ro4cDUxvR-`CQ5+@_gb#RQ==(klhqGc%}W?Ko#A3gZ+CcH znAHo&Z8mexTIo(RF0%FdxYYbBU2C*7=uB$5eQHZ=5?#y)LSByd?_05`Ntm~CQQ13( z`fmiin1GHia!#SW6EFu_XwQ)ehK~I6qZP1M_T^CS+C@?0zFdvZlo!!)_nB(bz_jw8 zND7}7CyiLC#DTW#QAFM2*n=g{wTWIj#yY$|+WqS9Ki(}09Ytt8f1O!6aS9>w zFmohdy4{|FZO04m%Vm8BkOi_(#<4R2BHW2n=M1zMef_jUKZK3si;(s)BUuqKiP+6 zqC69e(t_WBEV@GgEYLkgheKU(VSvTxhNlW&hdzPNoSdR00%OVkoULfs^%ZQ!H@2fy z8i{%7K0Zd%Ps;App|#U1M~YG=B5Be^HEimEZo%3j9uT68_bpnoC-V-+Rcj-tT>sLz zd+d8pA2hZ6F=jFV;@f7lVN2Do_>=+pgf%sKAt6AJe|Y#nGDXsT9l-wM0-z3Ngw|NY zOjO(G?8DASXGXO+mz^e_KhE+BRt1W_JT04UtvPNP0j{!(}xGfY;qeebMOm3;sA69sL@7DNdlkg_*^%^3%z%dN=@Ge zZ16ewF-V8Vt#$=osFzH{Fw;9|OLET|p`wmGI50{V7FcavW(P>^O*g4tQt0(BZtT#K zFF#a_Eh{^*W#1nBK=+hr%Y8Q&@$*cB#+fbsU^A1bA-r>qJ`m-jrBX4W~;Q_R7M;5t__g%mUH@x+bkwra;^maS7bf+<|sHNj!e~XZ}C5l0zHu1%|F7aZGHx&KdO4^pnYP;{=;I}E zT|}!;Tlwg@%93+Et5vO6yYFz!!U3H4U@a8nb<9_{B8u5Qfi^SSiFLMOQmk5eaa^{==Q z1wR`Z!kr2Yv4{4V?L8Kkyb#;iGuC-x*&`Bh89oPYUiT6`fM?}^mW@ADAu}(NmU_1u(VW{i?J_b?@I1O%ub74-}(@V;HD}$aOK%roid1>jG+-tOHrjXsRW(c z#EuThX)l}<=ExX<%Xv5DXhC42y03BYhK!ijYNAjDpYVSt-r|5{Ic*n9uq%x~{96-zcNR;inB}oVo%x(1ub<&Pz1v zFJJ{Uwfe_5KC6ix@`!8G24v$21qrle0R>?)^Iq9*#6j;XQ<#0A*Z+EBSKp zZ5d179V|8xaKzxfTHe6Gq>RnHXLX#PU^ve|XYL`BUps_4R?Q}iq3k#8{X4vZCSB+` zFKr@mP09GbnOQRhpU?5z24Abu(k+iaKyn?T+x@8T4z>< zhutrGihce?R=??OWsXFh+S8SnLjZXh=l37Aok88_mL|sFlUokLSOF3p(_J_S``)RR z(A85EF7+OG?ION9gftov;oQ2LzomHn&2~ivp+?JrGVGXN+;?JHE7-dCz9Zt{At`@x zF%IWoyqQL(9te#X8vF+PxCq3^#~EyR9CMA$&k8+v`%PbghgVE58o#^+2L$=@4i694 zJkOh#zyX55*Ik;c%^$>TEd_zsqTsUBKXi|k$_~vQIQ(YUlBUbR-i~I8nM1^%rEq7B ztVU(Gy2ndRR+3wxuK1xm9S@mYv=uIuI~QNo*}JAgem&6K#+s{vjW8anM5(a)4>W%z z)KV12Kc`PeQquHg2sw*CTD3VmcQ|M2f9+KhmGkews4wNXB@++1bPtEVABkalz8h)H zL(n-7VszA_`Vy>X+V$0$zylgYSjW&>rQTv-|Lp3TFSXqas@{#dEB-S_laQ=--Pca> zm#V)b!oStarFlu%RURyKd=Wp1`Jah8xBTZC>x@D$rC5aa8b;&P$_Rz zY{MssDPLFvYtHZ1(VjCxhcWMLXY%ZpGJXN-vSB(X?HFN7;U10*+R}+hvYs$LN*idW*r~qIo*krsp8sp|XN{+$FX& zbJoWJ0_?Vsse^nLtJXG)sZ@PCk zSv*35VR)j~fsFZEQh4O)NJCa{_S2hwM0umn`=ML(wxzhavK=ZZ+Mln#5qhFS?#^?AGkp zz_qmYr+X{G^Fo`y4NU6T9|iFW?Z%Qw&td1hDgLr9@xX+$MPMiL#eZzJm@lw#Csb>K z;1?#NU&uslKsc?_is1N5)p)FspE109Uu@;p=yVeF9v#)>H6kbpE7MENmS+yc6FKUY zi&<8x?{@cUTd646YF_lj<1T?XW2j5#AiaC$QK)0rfyfgntMimepOm*2uvn`W^FMJ{ z^erWT%`~i(y8njh1IyR<2XcrJ7=6`&mLTm0s%3t`5Zd`{Fq`RZmjVYz#QJEy{CLBX zDwq)kWOHn9)NjBd^L3yue^aQ7(BUDM0KY>}%`E)e8cg6TL%tyGSyJ=~mJB>g1QZcU zR-T&q*g<29PXYt4VnOS3?=1op4$u?sEI#FvJH}&%ttkb{R{OglvTSVAK6Yj$R+anp zA(ok;jyDf#DmgMys?v)X(#R7XLy?G-_k{gaPOulO2QZq%u|<^I#WA%18CZrDfy#Z1 zn}(^g{hF8UE?23uaicjF>jE-r&+;Tq6b*ryA5PJr(6OW9#Nfw#gublIYQL@;6ZNU= z1gqhW`I~d_n>DK-OLBOXsXG`JpPg9Ypxz)i!v6kUPq}&jw?WBBW0s zWiYygRAmp<_Q91^S7y!@r)K~k_TQZM^Oae_)8x8~XIcSYbBQ~Iw%suF;?mvSaP8Nf zxlLUU*8||9W7~!&>;_89DlNTw72(w5>wj%AOpizy#UrUy9QD&3kSe_-M(-UHI!FLQ zS@h)`xaAVzrYG7Bfnfiha9Ns_YzJe43BoUjH&&0|Wg&Y2?8M0`{I=D->7%_{xWeC6T&aK=lOX3}g7erPgLt@lih;od&vuRNdHj5`TLSGr z+TRFJo&JMc89UBVjj_g89z6y6N$6jR=JYvq-;cq#_jZ*E;#{4TUKwQOaUCsFB^eij z*-88VfI;J@l17@=oz%+v8N(t+sEVTAC;xL+_FNyeP&Lx&FJ!z|GjqQ(v#L$SRR}(%m<^ENX24bm`DgUCeCl1Nd zlVQ;$WoER1Z36e^g6`QZ_{km>X&B^db7Jm<{p1$w+OO?98RW7e_g7g_fBjeDJdf)SGiKsMud!mR)!&JJa)52;!@3L+u7 zL)Bi>@1wf)p7^UcH9IAr!0^qO@rnba zVS$6_O!NiR#~@m)^{m?O8_!UY|3yw|>Q3Tk7x{&a<{EpRX)0n<&@SWG@SPU>O#W(l zl@|dgtIOSiWY#ktf*xHBlMae#U`wx z63houK@=BMhg@$!a@(hEuQau*5i3%>L-0-o?gLzViaJdZSgECh1aZigPF!PENItzS z_ypZnC8Lb7in=sDTo28Yca^XnrmbGY?3ZL;>Y-~mv#QDG)OLj+d}$A}p0=l-R>rTI zj33mNrpD8cBfd3PuE#ssX+@b%>HVxnTELSQQ^G0i?D$1k?Mbt#OVN)Ro(lKB$sb3) z&C)W&Y|4L-2C<@PVNE{%#!}KDb z4fA!bRq=nG!wcH^PygZ0Dx(Pm<>s`Xu^8kl>SnNz7;Nm~uCp*Kgo7BiI7t0@3wjQ0 zHY!-8OteLm~U45OBMImV{5sw%lC z)K+LDqiFhPG16o3sCpUb$5)iQPpU5sqU}xZJynTe2O>Z2{ey^0m8*18NL6(OB9nuH zQW97pRfkbLw|t(*_TZq&EIb^vGx2DfMvo!j?UX!5W#Z)>lwJ6>)(iVe7i`Wp(tJu9 zyWBVo4NCbE%C)mDoN^n0`YzEm!Kcx(fubi_WC^ok9jwd`iO$PFje8~z)AbYKWq1_h z!5aWDlm06TVt5*D1%VPF5jF;?M_x>RtW2N+Cf29)1^Tt%V$LuidyW+S6}i1K2M~#t z+og^jpCZQSvgUbjo+u>_gV+ehw(Z*s!5v9x@g>din7lib<=izSBfb8;{H#9Z&}q_i zMZ@_^mtM$jso=6@s6GBXsYS}E;>}#C_|J6a`fOA4`H;q@FbQ{X{eLRU_YcQbcIP_j z=Stot`13XZL;`ikUvWC)ZM3B$Tx8a$G&oc?kO3YmT)L7PCJpFSqIf99n8N%E=?dRF zE4EoP*3$ROn!>_sci^;dL-OLu(bhuUiz_Buv3j#aeBf)TMTc3 zL<9aRXTcnvf7h$5c+;t!s&4mR`2UqITt0jNMb5`Y-T1RkyzFYH(+4xtsXn* z+^t;93{YdAG4E2ACcs#Rp&l`ao37zcO3hv3KeD|Fr&-TECVHynPkxj%cG< zp@mTiSe`0675&A1c?&%)z(gB3;|snvA`GyRJatEdKUYCu5pIiLLQ-_t(HAB_fJW51 zETQv_+$zo)CU9l)EPF2QxlDZV`8wDSKT4;pxUwEpY0P9J9Sg4kSDxf5X)pw36rd4L zqL4!X3`SxN=OlXj;OMWnYH2qOBjNdDF=66oT8}673*g4)-E8eaf+7SXcMSUd%PGK! zWbYf9ZACtU{v$GCwLu4K&Cl-U*C@UZ1gqg(7RYf~>>KJsMer{VP@{PJhS%cx2#{RqUwrAy)s_raqz5QP4&Vj60D2_9nGfbMueUn! zbU>faOx%ufsNyYAiONL42k_EoV*PLhoP270f?Ymh*OF1?{z()shOQSmiuOOp5fwVXarCYVMAd~+$Pg(Kpmzx* z^1O(+8l+T*sX!$HPSE8a3a}%sldPx<&`5pnjY1>;iB^L7MjA+nC`6ii9)cFH7!X~L zR{}0LGY-Y+k-6O2id6_XS^eduFO~Dq=Vpvty>*W}SZ7q=iXEk|x#adnlI$Df^)QR! z_6*7S2|Wg0&3(nx2OX&k)kjbrYm`G+!0eeRE4@Gx`j@%@=z%R>Z>8$D@av1v^eD~s z#hilX+|#wy_cI^Zp+(y)ZBS0Z|K~ia_&?`S?ys_{go2KfXV-j}7D~4=(gkj2X8G)Xm= zC~HloLP16RKQEEUmCB$R>t@JzY{XfG=L3Z*UUlGua1lSrRJxEeO-WX1tden+ zD%gsS@~Sq>xxgt9p=`tzEyFqm=2lEjD)1Q?YtNtSDi$QEnf~#JAano8*r-kJ+ zx6(xCxkm9)pC(m2Hh45eQ@L=n5Y3`4p}0F8r~nC})uM zbKWWOhsMcLjkyf@{=;gp18mAOnfF8>{VhifeT!Y1@uBO{gA#Wjce;^5gBEUa#O{ zRIKw#fE&x|(Ob7@2IL{Rd{H<7SB?vwGG#?@Z_Or<=9HWy4U;E_+C{R>d=%Y~kum%3 zvC%czfK`SzT#e#H;cAK&Y?2lX?$RNKB9Yfs4yoTi)z=a{aE3G+sbUeS4zo%` zb&fLr`eOcZvUUkCeCb=Up&sn1XXw)OkFC+?j1om8^+>BdtUR)*r)b_348%4~DvaD0 zx{6PP6dT{%m^`Jk_C@kNnGlmn`ZlkNrQE>HdCInP(h@ZI8C6J$cQmX&c96eC9QPZh zMt^asIBao~F*}-PyA)_K_Zwhmvz;K+NJosVAYuKnr<_zYaf`)jJL&e3#QGyzz+cbx zscRxp2PT*%h0()q98!EtS(b|1{;I$2c$7`b2vOwP3( z{iygcS_$Rw2ZI7Mg34|CzdGBu7uIsImnEnB2M*i|gk;q=6Jf9TLiIeHjjBTEnYT z)HpG3j=QEs;lmW|NR3sG?NmaOdQ4n=i1tk+I9;V@Vxmd$=#x}3Da%81N7!Rk3ZC%~ z%+V*fEpxy9ktA(&_1GKPjFcovx6k^9)|VTK2E4U1TyqFkNb zSzcp~iT3c%bka+}w<@UWh3<Fi=x#HbtUr+=Du@MdEh)1j9t%-hJhXN ziOyGZY*IB>q-#XW0R-Iagk~~XSh#PzF2`F95AtMr2C2H1s_Xmh8RtJr8i&K@^IuVf za&w1J`jmkfFSr_Twy&1Ga7HL~Ngp_nh*MZVF?dESV<~KgN~1;7>-z-3uIh-+dRke9 zfb|rY`m+Mvp76X0IEd`UNoq#gFjQ(;E7i=5ry6tlUr$qN?sqQ*JL09C-ZWux)^uXe zhg=({m)1qp64e1#P%Kr-Ao6BK?alpto`O7TSTg>CO-ejQNxgNpX8rAdft6Vk#k9rC z0PbgB+i(Mbzo-B9cn+yuTJGmSApnxhh{X?Sat=|I0vQIyz#K(|q6tM9;EP{{LfAi% zal!pqOYvtC-x>V-@c_!ium`ZkxqJ*-di@vR|KxI!w{!iXkS@9P6#fKd935%EgEBDw z5r>3-05P>5W+7+^3B7nvrI}wd;iL3C{*8)s*MF%%88#B4Jfk6DA;EZ1R8)gPOBa-f zaOVw0LkZIhQ(w}VA*be;?|ekz=69F3BGCoraWHiZ<)Qu1fxRqEJQbbuf6V`su<6=C zQN<%i-M!z46RE|#OK^#GX#BGyAd0&YYjS^Av(`(YGwL5s4Vp{!ge=p$g6HBFe_vZo z4NbsA54darN0vw!eZE+*W&VXUB{r{>eZ!@}SbUn45#)`hU%|z8GF^{nwr&roAy_ZGb8nIkNo*fc2wJL zJ(#_&ph|Lt~bZf$MtZf)DP zZQHi7wQbwx*0$SI+uQbkzP~rm^}IM|l1%cM%#}B6o8YolHXLcYA(!ovdg{5z5_EBST?b zRmadpv=h5FQv`D57Zn+TUG3FF=4^H7xJ> zu!m=(oM7tvcPw|l8Wa1c_R-t8uFc%V+_`nJ%F|4*EVXfwXg#1_0!;ZEGb4vi7Hu+& zFF$SfowNbTmuhcoSx~IFGXl7o=veEdvpK^HHFv|qtXm}F8Q#`q8`5Qvyxt5o7ZUh* zzftv+1fpj z@6`a{a{U|D9}0+3)tF6S_KMWnWbZIP9}gV5Q>E6sej{YPnIBrYQYFt@h#|$Oc20g> zpwuj0Ab*H1YD?;AQJ$90!ufL<56434wZ#e4;jDq|)KZJsZ965>3OwjNCaDt)kZ&Qg zOVe_@-6C(Ana_C@8JI19Tj#wQtho~3ZLYH?r7vVtUs=aZ26PYS%ywJj24j0aYq>#O zht@}}T#&t2@oT0Bhw)$Lk91qJQ+q(5tT;jb$)BDh9IDONy?~P!gh9QZ` zUj4>D^U6QZ+}3#}v^c*#f^7S7C!SMB;A-c)%jr13`M&J!QMGn`lFi4BNdxmaOjGIn z(Nr77v=`&OwqkCcIEAJTGt-_a?I($G_~}LSs?qx!H&iG(CCq;xt?k));((aJ>H{A+ zCse`$Mk(f`t?EdGEDjQRF`-xHqlniu-V+Z;4S$r)AMT%Ow|apKLl4$;i49@&I=+PA zsat2Y3-?)QzpLQ!+BGESs?buzztZK?0I(M7PnN>iq&#kQKC2zyIUe`Ir(3+cM~v>Q zEr+?lYYWB4F%eDW#}_-eqNY^~LtxC%g<#j!FrAa`_^cJ6R%e^)9I;{=~9#)N>Z zO5{2v;r9!rFzE{=HMsX(VK4=6J<;zccJyE6e+%}0A+?ieo&J4$j%6-}ZcGO7zLz*3l-;v26upqq>4)tZ z*z5`Zwm!Ej+IR{n@K=t;Vqhh-)a=3}-cTQJ1(6+D4mhgI+#2Z`ZgF5)e2 z&A(yu=~dG4Xj^dxGV@H?2V|4P6me4>>iS{dEHLd{)xsOhu*C$>zN;f@U)g`3=)Sf` zE5)6ppzK#&DD6yBkqv6R0sVXI+A9o&f7kW>tTJRId5lH5+45?0uCLZhv`+XjF`!Y* z7=oRStyqIXaZVfwX5Cs9J^bZTU!5~Z3WjFRZZ>XiW-v0{qQ*JlZqyW%N)jdNY@+4& zlddSF^nGZNzefyJe6$KbHUXyBDSQ%36l`urQlaXn4s&REOYF>+YuQ3}F}I@m7(^?s zgWzc!fc@y)u(|VdPyJ?d*-1(__84vg6qH;Yjqdt^AzZh_K|NzZ_LYr8k7ZQzhPBsU zSy_B+l{IdNo?Ali-Mk;rGyyh?-4h35yIpyXPWS37LW0{5?6EC;T*?j|5i8jZ@OSop zW;In=oAI-lQ#M*qa}8&{RGU zw7Leok1%ie>T31mxa<*o!gt-)!@=SD4|H2=UT-D7GjBxVYYEmU?#>J70Ogg{3EWKQ zbv@fy?fEWpI-=sIp7Oa*fj+9|h7jp0h2<4a1=#U3JmeZl-e_zgh0^5IbNDIV^HYwb{+P81an(oy1(;EP+e&RJ>w`L0$N1 zo{{bgj5K~F7Fc-Svn&jj0s>L<{wMg2-nKnK=kx;3W)}0h=W=rQ1<&vT-fqEK_!~c5 z%A(+|m7Lon!@Zb6da&6GuFeGl4gkeR^sM1|UgccDoCBg8{`$8Gso{!Xu==8%3w1?gz zH6Qxk+G)e8QCkL-D)<}lk2t|Z-IQKh8B?!lEU>v4ea7uS)yudE zkkYd)!>_Jub_jOEUi1CcZ>cmsiyE(1^Xgc6J9c3PNsYH8w92AckfOf5-X)mEh8iMA zjqVoG>noBv6ATiFgS^p9VZA%nO zFjW_>36<5c`}d0MCvt31z7f6MNP}lGIV0iZ2D5`AW2T)DiEWM0#_;TFlOS8(lk2P4 zBsiK%i~tt30IOW(ar6MhcU^XK#iP@p6>bUm=+OeR$+NE-cOdh?obz3mTcU&*H(E5>hu{c7TENqJFY_56?#wHV)N$ zs!Z#pkGhjF1U0#^CM=rbf$KbajcMa@anh2-@+h);54Ye4gwyuM;|!0DpMR!z94DXN zNG_;=FnknUxR4%_19)VtaQ>bEd+a)=776amF!gbtLO_xUD+|o|$p#k>0UXGq)o-j( zg?&N#Bu-ELtl=fWc*jJbjFB|f#`C;cOzACEZH!ludwJ>#7X{yeYU1zMS`Qyb1X0{! zEo6}^NrwJ9p}w#vmXBMnAy>L4YdFCqOjeY{K{q?{Qb)IKoT!tIrkp?0+->OKqQhDW z2HP8OnLZYbO0;5bSwCmYkfuHPrbqR_LOn8^o+cZvOED7RA-Q|f2SlwAsk^E;#Yltq zMT|M-vE*2!G-K>2a3g6UdG;e7Kd#O26KTVgf1+d33{`}$Rg96A15PeCfo--e%S((6 z?{;o@SeQsJSX5OZ4z#f({Huxa(Q({>u`|buv=QreiDcoXE6Yoy5lfCYOgX+_wW#_R zb_-2Dtb22qqzR*e@DGPKZml8Ud7PwzU)VTF2Vunw-uDo0#b;_hB1(^l|47p*PKC)0 zw;Q`Skt~Bfzq7+)AI7)iI8Bk^0`} zyY6aUhBls0!gHoDbM0zu`1#_WM+mb0I$c};Qsp(PkBZR%)#f*P@3#G;&S4Cf=M{8H z!xllp0-r-{rYjOD#<|WHrE23thj-wB)GogySDal*Ma9$~SPJ#FOpT zxX+e?V7YzJCwk^7aK+n@h^&-BzMJUp(axb!N7k2bTUo$bop?QuPWvUh$sTj`(- zI62?d`bqDaI$QLh=D{9k0j2e1@3Zo6FKy;3df(XP!o7_>O+v1i@}5-pbXa^R)_xw$ zpCeDme&NbPGqd#HtG@-L=5q=jSr)T(5gb3Ux|?$rFG^Z-W}@Y+$$_(ihQ8VhCtERX zJT$L^Vz?*2UnQpow=!~}1$PUF{fAru%Y$r9#1PIhejJUzm#zA*=#<|=ifiMKeYEpl+R6_G1Y^SeY{(Rx7Xb9}}9g0^11M;gks@T^9 zL1R(d6(cmysH_2?GlOiE9i8Vnp6Q(Q7)6ymE_U7zJYI@0b?vWgwO#HkBuiu~Fp*Izpu9p-B%fjqui<|o-`-`y|8N*whzK1d&Sz|GgI&Xp9I6Lo8UC&Rm zJrB~`1m!}ZZ#PyPwQ(#%Op?FQU^;)zZ?((pU>Hx)I7HI=K!Ll1AnaM@HzX1I9kDTr66hh?uOR3*EIRp_92iDKofx2-Sdbilwjq}jO7ncDTB$@4l*%XB9k zUwpOsTKO9TwyjZae^25kpiXhf9NQ%SZrI?F3!0yG*bc~Es=u;cIyCn>E+g;N| zx%OIv3fS-VZd+8j$xyg#rHJy{Gc`y|dR8_l&Q;TXM8rc!|5Eo__Duj zdW!jU7GVEY;GwD$fu^=0B1u)!T`G3qxaM=at975wf0MHXxkmM3$MR;w)BbJqYOJq~ z-fmBP3`TTZz~|QZW7T^nIlhgZ-$s{vzSE`Y1IOBg8^qT3pf((SX88jE@|ZI{GqE@= zZxK#2zj}LfmIcY7g0K##WyMp^vIW6Sr!U6H%H|eikWtGw6KXaG&w(vh&U92Zes&dS zrc1Ms9AUD2#5G2i-|pfU6JXtK3$Tc`#wpabjd-+1%vWl`-X3Pi-N*zp%kL`Bm=h%@ zSe71=Lbkt%Z|iQ^tl50&-c94yud(_5^8A=tUs=CtCHxF}Hm%J$*ZJ&h>fQLdrdT+a zZ=13GekOZc(&KDu!pZL{xVkuvz$u6>R`0XQ@d0e}F8@2TFE=I3w&88x)7`nf&V5Q{ z*XsKR%r6Y;|6zLZb$0L}m`GvN&=moRou3oza+{wVV-aWvK?p`h^E-NE66uJ$(3M_a z-~%jOkbKrod^$2n=8#_jydMS1c07;@4Q2Lj+pj*#ZF(G$XM&@3CIS(1Cv@|XYw&)0 zWpsPyiNR~0Sy;z|d71xmzb)?Cg8BUiOnliHJy!t}SYqgU38zIxF}K!s>-n4;W(#cj zU!Z$3$oJ=ZFslY(YUD*#8zixhzTON0+@3MI9w~j%aMfM)$aiDny_HaBz}{%iPYpg} z8KdZb(e9^BD?`qJjJ_v%h47B|xi0S!?G2%15C(?=}(eCmRpi%8-U*lk_wf0Z!GVLvm?5n=r?m@UReEfc}pj zM5kU-Ti<(jPs5W2X3m6g{Y^6EFpXc+&*^Rb4YQvZ&S{$au3Ef+Jy;7%f zhlHsPN0~@sO-V8bTC6pS-PK|jR`s*Q+OLBJqYF;co3KI(uE|{NVKd`Qxl4SgWRmdH znZiwy?f=U8uW$X^>FU0t-E4x!KBm=5A+U_etRvHD5)1V*U;9DuVYA`0@L{lxqPn-< z1|C%36HT!h*b_Z``&YL}tT@kfDy_I=%ZfFW($a>gidTnw9Qye$Mkb@x zM|VIh+6q)tx*qn95*z-!g7rgls^>#VOhpXPKt&ACdXhCY$--=7h0KD|j7ljIS!{(# zOSm;P_P~xTZqeW8btN&_i{KKOI`~kJ{gax{TNkD7WNxEWuPU2848L{=w(*{N~j=9Q6o8--#t~1MSUeJFI!yP zroMJ8>BX*QP^GCF`*Bgy`15&DnZjrBRQhS=8lp`1-S#0U=-uEZ>CfJJCutI%ugrWt zQ9M(yMFoxg^b})ItN%w5!T4Y@!F`Cc#&3FX2;Xa;FNjFO_D_@Lt_D7=C)1gFCv=XK ziyYXdaPg1oVHrhVg~R5kTQp7tSx;3nCv0kG7lqlZaIw)xy~}%tAdj%o83N2N=-X?4hCBi8h%Li^@^s@pU3VO zym0g^_%5rZL=>p4t~zx>V|}fVRZX|?s(?Y*-Wp!0SgvM#Jl(;%#$EO7?;6z;gJUe+ zq=JkZ$bUXA;&5Pusx_X@m~pWx4OXrO7biAo5b2`Mrj2d_^6vn(p#t%g;M_=}f9gYy z-x_TN!A3L%|89S>Y@zeoo$ZZdx=#H@`t4FE$4pywZJ`P`X3F%dn%KK^_53JF18p(} z)XX;>F*07!Io}a)bV!Y5mEMNG1Bd!YE3}0>j(*!k_P_e43-+BzsOjmOO>NAcpMBP~ z-z)##78Yx0b|zy_-s>LKc9y$#H2?h@3Dur`tf0eBFFW8z3dVgH{h_{ z{VeWzdUU&u;@b9o~ay zdDK=~6d%QRN^}OIL#bTpTDN3UnVEe0nl5`=2)Y)lE~s3FH@{=X4^cSy`CF9^@+rMS z;hwTzZzGo}+*HtZkp&BMBejr2?^D^i%Gfs27+6=^BJ3{5FR#>CGjG^Rr(0TIP=OfJElI;)nj{c~5ag`cc0HK4Mh){B%p=zbt^;GX3m zQ2N&S^WIjZDVr>&OhJiCq3GBMz1AqI(MmRpLLYI@UVhW*kn3vv$^)$ zpUoXk1+LyLxb}jbOs}zDm1p5DDW{Y+2QR{@k_2yTCj*73FCz6`XchLvKQ1Qn zdXBSvhr?}llb1ogIF)RsHUn_dV2l*J4fIVI#R6dpd=W)YMGq@Ze%5n%p<##W3viuj zQ*+fbr%qNM6#PMs!pLJR{SLI>Aa1?f5Hmk>;=sx6+4y>I!QK3c(}AY>S%NuKn!GddqkI2j`qtE zO0PtX)^mV00JAH7LsSU#CBdcIwZEx`#uOk>Jzp0*fY$|1TR zkMB%k)8mFujk?Ijep35PXn5w8~Mt(ZZ zAz(&w>yq-}y46xd4+&y*?k_k15H>psaOn}G=@2;6px`nY$iw*=4tkhK@_Ky_04;f1&kCYc8N5 zt`-eF0UUU__MRvygoFjNMvvxBpDetp!N0s%$g~E5XLRE4m)M`OZl5e9v(Kx=rL~FH zWz?2N$6N7Y190iZ!>8u=om6Iy0nBz#p><-?ID`9EF6}t@wPH}+IL9Ib)D{crc<uN>F4nxZT2Uaef*vSqY z-_fi5+hq$$VGf;GMD?PfWs7+ABH+~ES&4;)`mDA>bS$(bk>s%SVa&d8*Ra9t5(|8_sJVabB%AA7KT>=XOj7Nu*V^r%r8riD$V6zCGWRkW@CV7^*l zMq?r8j_S6z^lCWBk3-rUHLK~=422UkE*Z8tt>JBDPurl`r4Vj|x=2|0tm~L`MDY1~Xk{#45AZPan6gx4cFLc3xIN^G74gX_ZE#^>eDx{lxGiYgRk{ zMoF~)MudeSk92-8BOv-zWsUa0MN?3h=iVX2B#U2?hH(o7XAUwUo6QDGx~ZxLd!#xJ za4gMkX5Jp>**ZPLjMYqfcpMLZBRbH_r}aq1`mGrq!|r2r^PHe=2&gKYclTbijX9VC z#a#*T{VSr$%ovv1`&40Jo_LV*gRzu z;Lo6E(G?FqT1I-*iuu-mbc69iUCEsA+6(EX5!TOg3<}s+!=HY11id>Ib<V4#n6AdLk^~*M{J1uvc93x(^0^0M{7~XxB@s@&gSXbroNw`z~zm>>N zxAlVT1$v!!JI5m?SZYlm?DdeKx;Q=FJ)2zhP9p2hB$pTb!@=nDNlyMQv9!mRVC0BT zn{+!Z*KT8Q1Icx`3%7sLT6R*n0;d!YAY&6M%y4%#jT;O%uU1z zoj+zuJUNj}pIu${FRv@-N5PA8a?g*FI=zup0#O7WH zuoq7I<^|rRGn(GspZeM6jjT+aAoH(X*5Vm+%qJX#EZ*yqddd%-+8IOnx5Z5ROb+dQ z!IaF~oJj8n%;UB}{b+ za8g-2c;({1=GW(zg(sai<(3T>o>w87JUm_kILqQppLi-!sl50mVBtk(Pu&l#!IJCk z*6lE*_-=N&>m3n2GZ9aG2aG0XN+qbhyKesPG$bawiUfNg zl&0ve^Lym`N?4ORnjJppGx#PO>xEzP&furV+&tJr^#8gRoAowOuU#NkrEi`}P(BSB zBaMD?P{nKBzuFVC-3U-duhLUV6laB!On#CX3Fs&1!k0U-$)?bpMSf6R&gnevx7r%d z)wI>~SpcHm9UWU8J|r0sns)`35cExT%%v<+Vxu|RXkLPDJBWiw`P-f{OLz{=mg&<% z4>JhVlJ*y$@2I~@>zK=y&KD*zSS<|?#WV5Nku22k!$Lg%NP3HFd3rynT?~Ytoa#gR zT)J#W-TitIM4+`|7GNK2h?yB%FRjohg`uHj3NVF|eX3+L#tvh>$>XimIB~Q%V5MF7 z{@Zdm@O`z*MV1m|Nn-LMUuQX!z5IK;$Ju?R^@OCAyKeScv%H^cP=LLfNfGZ^v77T# zzy9F85>M7%csc{BJgL5NTJW(<^c;4MZ~5Da61#uS4BmRDPqVyeywt7en*6b&$154A z*Xs8P12LxY-O}_Zd$CG0{l~Rg>Ghp${<=&Xh?aR&rL_|3KdfB0$n!qi{afpPJOh$j z8W@S=<(sYeoLm0~mq#2ZZfl4?L>}9>=H>r}i~I^JbkgBI)_pbdc5bmgF+LOnZOpSP zIOg3S{_vR6?%MA3{kcs;>~=d4xiV^HpZfA*6sr?5hh7&0mMkfy%fIK;n4G-g30m#y$gM*8zMjc& zH2uH3U4hva>ZYyr-OSZB#NnLm5_&V1EV&M*+vlFgcrLveiMR$U=5cm-S9Ln}csbMN z={~Qj@$BJqjj{T(bJ{M?zdz*1r|#r8^7KfOH5K~n8}2-eGxo=oDcg{(4kGdQn`xce zvUwM|-V~<#(M7Ih6Jeq*cAYSS@gBHUBL#g?3O5hdP6dA$<|E2^{csA>FvA(U+riC) z)!(()_K3iX+|`$toOT1#O5$>%7AP*`j-8&~Ey?zsi=N91P~ z&4uH8ZFcFg`^>iW_ovuAZ;764aaSHc<^xW#Y+BcY!jp3H4`qlen5j9MXj4__KPOeP zT)!+pHOD-e5h1phaOB=u5)zs}Utg+SGiO(Fo>oe-c0wO&VhJG})vlH^gI?vN<P<)F%9au%l@O(UycT#k)aBr^0*#GEa};+^*QT|qA|5FJ zq!<)&t?IJO%~v)TaN+@-5O+q(qXZZBgxkw#;kt9L_5ozCUQ%m5$B~(DMKMhZ*AOND zmU&;@fLVRt!zb9L3FL?H0Zy7*kkm|yt*`*a9eN|o1C^{d7NiepdNFs%-!U`bzm$}m zQbJNCHI{Rjj)s+<1F}=_L=%}|%w5M?FukRJ^6iI*Wy(sA27AVE z$ThAUi|067Kof&8!zgX=i@|B_8>rWGg$gfx)z`i*p$liyVI0f-wBpzK?INAMra2uD z*1S+HvrmHFqb)lPApadB>ZMY2Sy|v|JK^nw_{PA;NwU5`9o?8)T@N{wS%0jS)J0I& zbN_ac%Ap9?kkCl~*^-{rzPiG%5)h|T${Ym6;bewXBV0$iA;F?~08yt0*JG?r(2j+jAb>QZ=~pib{f{HxR9h{9DY87t+%mQun*1aH=HcuB_LzR z;F))@+pw7%*p+5IOn4N-k47-P5L?3`h%nKVkFO~5+WdQW|9K8+_pa}F9QocFJ|uta z+%s`{v8I!>WVhl0`z%-oqmSDKP@Sz0P{7+*D-2~LjrT-;dkf>~!j6XD$C7WIQMYh- z`!^QEB?@tx8)598Fi48llqkc8Gn1f;C4l6|FoOhd=UL6}i215|>AxT#d(^h}`^2^; zG3=_69&o#|z1uy7yFZ;}T?Sk^wi5Ca^?6M7C0Kwd_6WJ(z|I^*jUbOJ6FV)R6a5~b zZ5AKB^%TRC0NLguVup4aM@BxkI07Z<8|u<^e6T{J?feYb@YrxVB`#|*zWerC#wTXo z(X4x2wBE;-H%HXHy?ttDGBP)6enIQ>2$iR@60>4iBl-g&_K!@3>o9yG0mT=5( zBKc)>n9;6Q{-CEjG`Otjv}bvWlv3i$QC|n#&zr6U&*c<_lkps+&$>9Pi^U?y z(xxI|WP#dQfPEeT4?#C-G|S88E+UhnkA1bRmEGUU&m|dP(}#ErH@D9x2Te@r&B72d zXhZ=6mVr53Me63&zmsqah4HVJ8T-D4y88SmPDULPX1mGe@63~zfajm)I(}V1aOBO1 zNJb9IQa>Zss43AyFeQykBNE{lr*JPn4PaYg7O{BRx{OQuKaBIq=*M0>pT&>8&-#PU zSKs)suip44UL|m*@wOX3p|Igsi##R(24Ua2BEM^S9Cq`5Kb_IuiG>Hg%V*R%tt4Ol zTAZIJ81zN@%-<$dbh;ux(;-esoCK7KL=46VqBuX3T*fN4STh4tM6iPW`pMzbianl$ z!5P6KL|Yf4rYK^`0%Te`0nm<5LKvjSvQ-ur|AEmj$@2w7?g=A&t~wOYy`|F)|Yq5THFpUWn#yPDrPdziv|Gv|EY>HzH1Ab*VI4t_cE zAm&?u`~AgkMs_tU>2aO^xaDR-GNy4+eLxp^=+$^qyB!!fP-(XJ-P`Vx#W0m`s~r{0 z7lc4AXgFMWE*b;ezpiLqT-20l(*Px@P~RqM{817ZfJl7xhr!z9|y7 zQ5;#>XQ3D+im@OScdBw9+s}}qo+JHjzV8q8o>xY##4+tGwi7_!{4_cKO3V^E790PX3t3!elsiC_erIm+& zPS#jkJ&8wteh>~SlBbB(sSITOA!~=>GD(odXDaWa9>NLzR8Fwk3jkM9)oe}tO6CX) zk!Il^Q>8nMI`_sL#~L1+Z``e9o}!1VW87Zg4m$b)nd`$uqs7l&W3jpiUUTF{bgT-< z+cIL!gQ`{_DK1X#<3tRCxIe*r_KZ;d!onapW1JU!&~dp|J7~VQ<3Oe5LGcl4%p7>o z@4O!;N83G{>+Vw5lJAZFn#^jh@!8Ph)OLxTXBHjSAo0g%jL%r{sRQbk95{ItmBd?Y z#`jw4?@D}@|A=lVpAK4!DUdK{B`^NbwQn6(1lLItu|*l-Vpqgur6|3lf-XlNm?+MW zs1$9$6aY(+-ak%~E>R&`?_l*Hp&B^z>EO8W!%Y<_!|(1)6vz0P$Q% ztOs)oiy6g)ss@Rk^r~z3%mN85kMQ7-V-`SSY;Jw4(3V8QeKJ8wdVmiXcAenue!_?k zN`7|YeR3uCTQyQm(M+Kx@{|ppP|{X=h|s@YJB>faot!kO2WV)LsmdWoP4(V2QbSbe zYmM$Jf2g=EH8bMxD=4CQULD!9K@p1J#JnpqB#|UXWF{#GZ*xPV<{cgn9qLSnG;tvw z2KwOkIN_v{u4pA)IsJX=D;5*E{y;o@|T@0TpE zkG(Zu|0pA6$>v>A3aa2;(QENZxUWVkQMH)L;x^wuartbYPL7>RtTk|z2e zBVqd`yH;n^ievuANr@M{sjBiuscSSgqa^}b0_I*(pM>Vme~25D}Je| zoJUDLepIsghBiT3$B(VxwaKbF>NsVpJjv&}^+dKI8xp$F0|8v+NR6_FM@*IU0VEr_ zstg(=Ugc4j)hIM+l0-$6DSjz*K{9HV;2uiaa^KtP5w9uz!%AkK>SZOp?*7aO+=xh!FIXxpcK~)-@iz{*eo9bleN8D6{j07Djqgqy=)+V(ac06-Ie6kHe&qTm|2Ac@ zHqJ^VPA;oDv{oAIwg)xq~sSSd{XS~LKr9$bydvwoJm@5kG3K{sq=8e z>c#zeO)`jU3n5G?RDZt~qs3dW{<^dgf)|7=D+o~fYvi7$VTBEiy~TtgmFTTdr-tAd zZiRxy1TYm%IY|5W-biU>d52xSPzQ_hj@c0M6)FwTPa#Iz?clD)ttB$oMG=AQK*naJ z!f5G82_lX^0<~xQqxItz(OfV(ApbSSRNz)ui45Ux>~xE4_W03I5Q$)VLIY#mn=O3m z3eaqfjer?t#t}yneA=FFWFue59{6}TxE^;nuEjGve8k+vQXQGjd|^A@dT#BGLNkmNRrY0u%U*a@>!VthkEFv)SSYdAarYiG6zhZWQ z+nRDCi6s?`jIQgg1qDUgnJ7rt!V{-kX)1r7=e@RDF&?$<)IZ4pCqZDuG9uNfchyaCCgEpfY?uSo-DOgmWFZT+dg^ zD2LC&5XY+_pldPD*kmN7!YvAuBjwE$uVP=+Bi6WI5|!360-Amhp0UQz?f)jvSn0>> zi0T~wSJj?Th_~&kO^3l1WY`84W`TAaW+$m+J_wpr%|AiUAX4;qfyIqWH(Z2iA#!xy1aQs!W?RTpqcKz7HTnF8-%TahQ6Ffh$=IMqQngB`&hakv4gh z@z?^bf#WH9ruYv3zaZBCg5^#uy)<#7?#z}x>YO<4@&T0zy!8@q86iotQjOFW$uwaB zQ`OnpS`h8%&C%$>{l{uEyj4H8qBcsSg!dY0&Pr7fdxG#wsVJEwQ#Tbehng&)EOBCF zN+CGKyvrBDZGGJ^HU^jDY72rg!HirB95brA+O2=?}> zyogFUHi-{JRpc?PV zoFZnTNidL!1)azkE$6Nry^Y3GLsf`Ms@?0ysR~?6WQCAXJpY5IZS0D~-Ci0%CDofW zWL=FIG`7mZB6_Co9FhY9DBvjOA`Sv46*Os_9;cLPi~xX0B0)&_DJmv8GN9E?f{P+f zi%6K}hFUWVDu$TD80*Rey=~vN>jnOYdDkYi1u6X|jmIj3o+xXvWHsbZ^1ovT)xw2H zP+0@GKdt#T?ZcL)i6%@k&=3_d0;%b=ezHnSvcaSwEXqh}iHho|PZA&GfD=J@!OTiA z@RVcqIoS}bAM|}rI}()Rb@^E^jKGKUxVu0hVHXCMV6`Uf0TP^8F3N;x|Ng)3^YN>F zFY0tle4uSsMMASybZgWw`m~X|lD3A}?zDcy+0s{6Q%h8b8JN289@p3$)$TTkFVZ%-jvJj_LoG1{Xff-*Bu4mS3a?&|XhIS%gQ$dyH-M+~hNfE1LJ- zL`3L>Co~Dyzz9RO?hAY~i!Mep-oA|xOQGjwclefoAtIjHtjlVCNPMq(rw^E??Bq#DBc z{-{{|OkT1Gm~v5CR8YaF00dDX*7A|xxaR_os%dy}n!j2k;=IHlASq)&sXTOF@c*o1 zV2%BTEGF6%S7jk$qIAcTobPgqs&I$z5%`QFp^|!4tdQ@9%fK9)Jk51YbN0il6I_A1 zqu6dboum@7Lg76YvbZ>@)+hwlsnGWqYa|9BK|*kV%`6Cn=93|n|F&rB4> z>Yf{@{=*T9iq#H}ip)y21NHa3*@G3)z#$T`c~D{bot07pMv|-WILy^tdIiw9jOm>9Brzxk(DE_6+LV#B4`k;9~cnus_Mxv#f=Uc zrBU)&@eu8utV}}lzNLBlpxbuC6&Sz6YyFq9?f%@Pl}!Mg+8WU#icZcRr1+^tFS?i3 zgtCuhFB?z&FCl(0P4BHqK~CT6c$VjX|5lEj@|cXG2$M4hPI-E&(PMXgUvH+!f_v!; zP3^;k%SO&FZYyC;{pjZWVBnh7kU#Ead42|1TEP2^MoP=dvEI$zTM`Q5ekyPAM9}e7 zI9#f;rlU2_;-usZ6l8l>T7nmLgp^C`D}rFFK<+N@Ke!Sd3E39=AZ7uYxJ=|a1SEW> zC_xZ&UV(~-uu;fZRCz|8#<7j9|zm@pHWjKRD%@V1InY1)G!bcTD!w3ov5$)#` z!-bK7elfwS@o^%`I3zP(F01aKjG$z|%z9>l0I)7`&*G9`6ZNW0ymT zwar6Kh5HoF6qRsWn?sX&9AqNAQWB@AJKDhgJ^c+ibmbTmNgHuI=~}5O3*PYu3u1z) zXyLs%X)+aK)!~W=ju0I+eU;edwBe?ACHg9ciqZ3_15IDfwB@vAgC`J?)kvTk*xUj0 zTCu*WkUM46TH-n9qP2n z-W@X6s*w}y!%T0GX%p-!MoxJe9Li)7H zAHYKDkrQA>89e=__W@Ee1ZY!7g7nEysz&z-8stA6GkA(olI^2R?`7$e?JI|mLNv%J z+GXU*hmZUtOz-*IWxm3tWaOeuosy=Gih-d>Q>Un@qZFVajHx3-`s8q+p$HA~c!vz0 zLZG2Y(|bCgA>eIn8fExoO&x7gGg4jJA^h(?U#y`u4B2fg?sUk}J4}W9dudW9+&g4? zt00rZaVSZUk(1XBnhF^c>i#PeLiE2f6ksqKhGjo2|0~0ZAkh!Y4I>eK%2Y89Bk)6Q z?TlZGCrwgR?i0D*A9?CXA6Q*cGID)jkVc1GUompxztld5jDMJa(*IRykbh5_-UF?_ z)fr{{Q>Rbn;22)S z$=_4Ng{Bg#b1(xg{bFXph=&?P6pt9AL(vM=Ihs6+sYg!}I~~Mez`u9|IMqV4RDT4{ zRvML}Qw6?e2m}z%!j`k461@{aO)%2FSydD78;7ZKvej`99{7tZ-bx^bs1&YR5otDuirwg2mre z5y;C2b-FaeU*cS9dQdYa0@DJ0-_$%9J5W%Jw`?B9GuwLme=RdI>81uofRz7 z_5<3>rkM2Ul#d6P9Fc99gI6n2+T5hFH)KuEw^OL2C}@|q1FI?Bq0nF)+yyjjy1+CI zuMjCw=C1?l4cwp_57zJ%NJF-Ze_OL>m|l{jH@GGbLat9#3%V&K0)JaX+!>tXa+OTu za-97iLL1I zh^!`HF2(~W>yEiFxyG$%AdX9~(wgG1xkiqUKBOsEuCW;#)yO0^#(e~NSvQQba23k_ zVlQk2!kHIDV;YkoFq;eN-g1@UGgpTvLyvUaqt5YpP&l9PIfdK?A$Vo5sn>BbFmAOO zBq>(|G?I{Z$2g&bmDrw=7ay$5Lav@_j_L5!P{TEUs_JF|`P$IKNn>T~Xr~;hd$gO! z@DYiiihSz_4@rUAiACZiq?qma7`*4AhNIPEY-yFpD5n~rBp;2?L&tNcDT(}ai2|%4 zLdS=!7sr&WG#a@3Pa24kP=u`UL{SXk~o>g$2JX5jsoZhf-eQRT4|3$Fz@+Qp4{;&POD{fYx<&5@>2EmFpu zJh}?OA8AE&`(-}RlIUA$onufev1fUHECDT zI^fV?d_@(Q#*!MoLEJ1K)~S3Ujm%;Q&+X@Laj8drJ48<`*@}wm8(c?JQ=_NvRU2VC zW%9UwilR=~cWzQBh3;iUEXKGTdySTUlU>wMP^1pe<+y}Ta=to)# zBA>rnmGU|bgl9Ocg^M~2;}_fwG@2f1F8|d#2~$~%h@@}h{8NFSj!^g1#~b(wYI?GS zLqQ)?f3X?zxT{ySFdyfe8>}?`1QunRo=jyp1|)E6U9!9cv}6TwG?o1g2%{yAE(M*~pNGalex#{{@3)>5MhD9YE1wXLR3*zIXhxNx7ZIY!f~}Uc zx zMl`p+!e_wu4nO6HWAo4J-TlEW1nY34Mc%yGr!$PJ+JZroWMQh}?N3iB#*-1ULzwCq zW*PSLy)cZEtq#R#&}#EG_Xu`Ae9V|nPVYtQGy1+{hR{;g3aepVib{BzvR_W?Ma1X7 zK^X6v(e=Kwv_7z$B%UME2&1X+?%B;ZJBOsvc!_`^&sb+gsjKi8=7UII2F*T`$we(=CeA9`rdYm`G(EyPG-3Gu(V^ z7zUy;wM+8+nvJjH;oog(Vy(05ehFNL*};^2Uzv_e;LE+S*?8D>z`GL(ipRe?V0HPy zOB-q(suhlV<9VL<@QYwO+SKoF0hM(UW@%-l*R3e$Vcz@|bb51JGk6|SXg#PX&V3j^ zcl0*-*4B^DX@%;h#AevUnEZ`eD6`zz%4(5$bh9D)OO81(X`4gAwobw5IXOt?cseM& z_|mtY=SCj4H4npMEFU*=JJvgvg;p}wJ5)Sp>Uh~jC{GP-K5qoyO|>j%1Z+D1hW(0* zeAR_|NxEkn_HKP|J!YkE6?_VKT3#829h20aso6-?Ks-)$0=W-t?Hww9Q#%lrmZSCb zw@W_)XP$5QH*A3y#{3<9T@ft0y7f8;yjAM>tgwFyU19d$nx(rlbRbNEKfev1myyCy zJGNOhgsI~Vv260nsnZTkr`t%9tKOF$Em{i^`>UvYl2}+`9`H>!%UK~SGog7x9Y3K5bMJx&B|}K91Y?=Gd1qVyo|u- zc6!ygm9{s$X-lu z8-n-p|8zlU2Dd*aW`5I8rx$LJ6!PdU8&-bmVE?$*>-pKwE-erHyrm%;S7QfrX9)f? z1>YaGbxCv{RG0+4H{(XNeFli!RGMbd+wI3!3NdmRRT5Q_+bu`qQ!0m_UZ1gI)-Z0z z$XhK>Ry!Q*u6T<2Vivt*_>6iVd%a4Yj;0}e1!`c=1BCQ!jcXF%umG8OUhmxKdX>I+ z9iXb#U?;nz94LrnOCx*gM4=S>lP20Gxb_oK5GluyqGKp#x!b>^%Z;es=~M7tP_Oho zcL}2WyV1tA{_qTa;|PJdPo(^uxUE011rC#Pm7bpI9+b!gT(ed|0}PL!(Q6jS!%#;3 z150*(5EI8}!3=Wbn3EC42IoYXp_4nRO0h?GLTK$Y9Ybcpi9UIq?{%tDzMfo8;69J;6ZALqd42-#7z@6yrOtC@IYf>U$>x7jZ z4)yiHeZh7-;7{=1nlr5wl|pD)=oGkQit9;K25AC@ddlZ>HyNIV zK_uy<#71-QD}zj31jniavxCurVhmYB;anR#f!qFp9c|r$}Kq;|IY7d&S< z+S1R8{2$%Ny1Lx9HVjA-$%k)BlMWD?ifF0^&1A9Ktz_+)3%_7}TdtfC{e=IKxMg5n zAEBi*1tU9(mx-4uU=^JR-Ii;bfgIwd%k zy#0iywko9>p@|0=Wc;1A;g|WP<)VueiEe`e9&09jL_*Q`OG(q|C=k~NkwTiASnSb_ z2_NXW&GvDE$;TlGrttVnqG@mIQ^PT@IC{9SFurVI#i?6%|BO;r?Z?M)*I_gl-YyRS z*;$p?3x8j#$>3~_L6)PGL$GIy-wnaP6r8RuyCBM05!_(4Y4Sc@zFMpOo|Sg{1MSz8 zsyY9c5N#-Uc}|lTQ6XVO0WsrvU2bK91Fn}v>CNv_XcJHREAwXqgDB^ZH*5FxI9Aj# zO{TV*QA{!J2zc5j$T;w>HY`27MQCk_z6JinxSkIN=~3^^ ziTr_0yKBC5qkv3Vtg>p9vKT4RU!94H6dB&|c-1MUm{t%W6U6QH>hI;szXLw6e6aGy z8*!pC?)fSm?Y8oMaM84U$ zUAy-=I&q4kU9T9AN_1|;*lFs^!+{9OnI`{;q-u%07uGxlv#nMahx*XI_{bg#8U`hO zW@NbR$e!p`6U}}gs-$8Jnk=SEl6hHdUPF=dLI#R3mf}_mKdzg@)>I?zO)mm@IaOkj z(rldGx;ZLJA~p!!4lA0Ldq^6YuvPSnqY!R=w) zP9$^PUn}n?m#aC5U8h4xTkD~xU%sNY%8!Y4i@knf;w)(kerX7L@wobfZMR*5(4&r? z5)i_zdB$?h!!Z8gs$uVab**OV`I#1xFG^p*3||14fB)U8BVA(9y|F;9{D998=kiQ4_+Dz!f^bR zb`#}!^U^SqA{bEVmI{oUNXmOLULw&HUxrIHU<{sVvhmw5B znJWr4U8i)!)TI_1GJwlkhj3eEx%YW5j9$MOJ}nyd9B;kUd%X$gfY}S}x85dA-SLpC zq(d-KdCbD}ao>>;WNzBinANP_DBa^BCEtIu$vMx&(hWw3HE0S7x2aa01xO6llZTg9 zoxPWj!f#Y^P;`bNNtL{tTn!kWGu%n!41TtMq_-V^`6$TRFl8A(Gr zg?7XI!-kpp&O6kcU?46OT#jA?Tr5%413LG1x($NRZcH*Qb|Hi057W`4r8ji1A5)xAC3_4Jf}>&g_pd$_w6 zp`Kd}HJ-jr%As@q?lzN&-1Aj#5V>!P0meMig-fIH+q1Nc!tnLG(p5#5R-&jCLJwTi zE__xWPzuf28m)}IPk>)^inYKabA0PA7ayT~>K@#eGQqh1&vJ8!ef@+MMSDZ)CoSV& z?OZ`6+$@ZcRnx1?z{7CH)BF6BTwWzdF423n;ZSX-FU@wzfm0Q=j2{ysEOt2AcV|0+ z!4W0P=?lOxTzQ=Of~8}~fFiY-~EeX11$9i;i#F<+$&~l1xn!TH2W3%ZsvV zPrI`QY}O6Iz5OEZfo>x*=#LV05d1BY`U+{94ld^!O^N}JZ??o&QqWIuqBaqC)T$VG z=oe!dh@7F-+SG+ZL*ev^;|M%shi>#Gq6q3Z%6hl6QA>Q&wl*Z5NxKqLmw2023J>vn z#bZPE38oSthd~mtr0P~t3#Gr*^bqQIvng8Ah2F=`$B{9j7OfPir~e69KXGxwU*Zfj zLhr-%zg<`!MRUgz!aVg*I&Q?HBWbe>FL+1Lof>PgXOB+3veE(d{K592_k+(lZ(TB` zTtFUjm50mV1=CByAD(L>V2RG!WD4ewbLI;j2m#jyCOef!F0NuncD~<_Ty#6wvs4N8 z#LZqdW|+3Y|E_7!**Y%x-hB2<4vWUqi{6! zO$l9XG1^|I^9Gb@Usz0B@r^mLQ76E#-s1OI@Rd9WKs*N#Q4!Q_@PBX)nBueS42xN} zpBbJoK!0<`bV>FO@Qf_OZwm%e9M&5W&Gn0FD#S5*29}2n76Vx2YGi69*jYaKuXgvH zZT$s$4jF)q*=x2)X17{)*C`MYwZBgrH4Pg=3$CCM;01|nk4B~l(o3)xebQ3-S4~}9Ilt&nj1rNf{2EN>N#bSO zOBk)P(#?8e^3hv4Zq1qL4=JPnw|XCYB(ScAj1D2xXQ?g9{&!kj+4xOI2dXDVF4f4lS+Wg!rtwFE-pXFi z5!ZSXhL!|=Q2ib30`ty!Kh>y%H_c>ZgZPd@zX%ojG4mOky5OCQ(`eiBq!Ll}r0A#- zg;PwG6A%fV;&Ru9diTXnoZiB$_ib>BoiTvaP5 zo?^G+6_%8`<%TQ{>N}>v@*BMpiYzL87E-0e8xBwnbD4-x=InjGV`;aacvcl3+TIF9 z{^6#2B_6qk+=+sRZ*nH0mF(zC&t$9|xdTGRitQu8+rNIB`b}@*=jZB>LzCJ%s-#g< zSex}goPqLX`foU|Uei}5FV`-AH2cR|_(T{oA+tb5O*D?nc~8w+&RE&3q?`_Km*<i?Zau4TXP4!`V3)VD*N zIF9Qz9DFA!E0O39x@Ra8$2l_?2b8UX7B>yb>Q*{`z8JNn1ZkY*1MXQov$@8{j9+1p zJyqMB4aa`j6DmO^kRsmy_s}QOwd;4}!;Ox|kD>dtTJ=?$B#|BaDYIJ&j|9ys;s~+0 zT8S*{$3)#Zc=}A+NM5fmPS%N@qPad_8bdamlyFmhF=ZX+SF@=udMUmS2_mQuE|<^0 zv>u(j`kcXe1^VRqf1Ve4auRd}35O!1(uu=}kbfQ3g2do@+6!_o_^!Az168r#_dsNO zJnqXOPu?Suq+JaBL_`8taIE&5$e2tv5!11txy0yt1OeNd)qt1Lr*dv({wFR!6yvWL zE$nVvkgkkZ;El~s`IK#^i>HS(gx2Fj1bjKi_ijUoh#O6%W|7YG6JmOM_58^9emg;> z+^Bq;BbVc|)`XW$M-2V$tOm}836L9x3UOOc-==V>K6>!yczh#kP&^IMWgP92`kf4+ zG_~gy^T>d(ozkUzscN?X2xg4HFodSr6?SWwU8ff8CEpbBVpN=LcocxD7yjzy>pw@D zx&uLFPKk30a*`_hTz?26)5(5*8q|eNp?k2DqzciJ)kc!1|JIU2t4u+qA=GGL9{JIw#do^3 zc>=LrLt77Hitx@qj>tF1;vQKGis7dB!=qf4fj+a!IMVR(wEg3A>S-aBOan?=j90l0 zK+AD!cFdHz9lB7e0ISCj{QW+ScQ^p|0j=5p`=e-g+6-iuD4N1yVeKH?!Ni{qr zdqCK*9R>Bdug9!Czw0cuik@w1_jRsSDLPCJn=TxKDK>19xT(zY>sN~WMp7~|d~8UT za771-a?GZyaq$bG$e18mN{ggP@ryZ$k$2i5t8;c^T*Pc(DGwaiPAU2_JQ|}$8Twr? zl@T1;Sg^&Qy)uVuH7!-mHKU#bQdFQw(quQbFUoqNb2f|-{491_-W*0MDWJ*gSM>X&_a*JdKOw6}~$;o`UzxO^DGqY{@Rt%IS z;C=%>Fj~jMz_{y4b$fLdnAy<|_khd=0G?TG_3*ZgN%`o-y`a}M8>zOxT1ieh#9n~o z_~Lwpz-aa7GU_9Ozv)oxENNycX<}dyNb->kGbvW$^@#?+xXMGAlhhq9W9=M$Zwf? zETeupmNFv%d=WT{CfsBF1bK8Ay~nz!QH{J~AD~w#CsY{x4|otkzSVm+%4{JPbtt#7 z+UBA|52mv!ZFM-{kUgq__<=P2M7*M0MNuqrjOHv0!&Ba5Fg{1954mgQcdrgAi}Xyi z3cy@w9ha7>K@=s-6rwCtSV|VxrpkE95TP8DcT*nM-8;BjuH*pRuLMQ+3|YEStHU1c zN8KlkPB$07^^nyrK$C(Pl5f@FXGO80)9FX+kH@- zvD;TJ;|(rU+q8sW+#{cm5AW+AX=3d(Qh#kM#*qRRW-*(rkBS(-u;FF2)mBPuf6Ar$ z9ZZ)IrbMm&R3FaKlWc=k)(%G)_(<;$YmWNCibYGgMeL|4FGD66CMC=Wx+O2R#)`Vi zqQY`E)>5mxVPJr14qb^!nna=>eQ=*?3pdUinTtNTL6f6Vp%pewVJ_-qFTOJRhnkfj zI7e=o@q2J5zY|oC;4TuKp`-om`EIRM+7zOzxMBe;yhyl22EXx*AArRGO}6jLD*O3Q;YA#xX#%fgH=} zGZPLT4pcy<9WUev5wcus8wPoaCmoeRr2cd9wBwGezqB%AE#az&w^z5;d6<%_`3>Og z6n%|ULohU_Xk~}= z-sG+$@Y6{pyK}^d)x$N7vrp={(t7FlyMk!??{`CE8F}8vB}Rnfpa?boypwf#Uq<$dGt=(BCMyNxnwKt`bVy#keCS(kFXm#SI55M&G(~l1qZW z1+s)PeLZ+1tDce&LZL78&@o^f@-e)fxAn(W6Q76iE4P(>2rV!90MJUl7c*g8zj@KB z_Qk-$qY+UmLcT5aB?*m}dt*U)l2?2BL%&e93d=qTS-j_9X%ga;uT$fduQdoDpUukG z&5&(($aXVin}8^Hm))3q&=l+xrfcOGrrT{BrVF+Ys}`&~8Ax_i0Eg8Kp&7#%vC(>>yRG1*hP7`u-wz1F-->P{_$GXKry&j0`H@0P~#)aHbHFqS2QQ)y?!~; z{>PvcQmHQ3+Gcj_Xx3m;8U%Hb+qetRi22o$6TkU+6@M2o1({y3P+6sBwLpd0C|9ip zuN-l!g>q_!M!F2ryJ5_Zk68$epRx8C!PKUQCKe)9*k}|l1r~JfDbI0FMGD-Zch8{g z@yJU~d@=13tiv6LcuDef2Px~l!`m5!T8YPVcdS=`#vxPPomgZe&QZK687@Gpx#-$YXE1GOAMZkXB5a6WAMOeXw~W7xIdZ^_X9Vx0_;q*<1SB=3cBxJ(bRrN%vj^L-AgHqq)?6fynuB&| zr^LbEdZ~JVZmT%F!VQLK$7qPK-&Rnlrd(pV$^D z5K3(m)~67yT$0hjqmFq0T+$oj3z(U#Iag*6>{h7|+QLUMEy{uis1`wpQ>S_-a4^U? z;!RPHx%c1qh4*Z&M`j=5sxg1f(bQajRO2fhNJ&!-n;)p7?X@tm8;oS;u~7=&#B})1X|i_ElFsq?k+5b%O)C_^ z1>ZlbAj*F?R<8XLyoFo5qOXQL7e@X^h^M*#x zyo_kIhydwc^5+bBg4C``5Cs2*D8L66y=UQ`Fn?5ThRH`gnUm4(xX)VZF3+`?!L$nB z<0Q^ZUxMX`!O+7CY4C|{?$B53U_GK>nhZ)7WBpEVP6qA6#~l(QdDWE_=MbDM6-&GPuOJajjtO{xag^r0 zsfpf6WM&9E6cQlMXy$qaA<$7fMME z2n>{pjD5hVn&_2^`XZ~9;kTrO7Rj1Ye}k0{G~sdZ7;knE8zJ#A5{}fT-&atY9K%E! z_uzwaRP&Hhp0?z0&q|b^5>`&qty=*VHKYsS=m}g7dn#mQ@&87en!_r!#Lvr~V;01{ zN@N5yS>co)7Fk)6g|&$N{Gt%5*W9GxuGZW%Yv`eMMbqvlA74Ig%7vo6F{S$6dm!;4SrBE_i0_Q;;I6YJ}ew>4q z5jZ-eQ#*!m;9as~*QhY}u1sTevT+qioUZAX?tpAw>Y|Hp1HIm@y~J$6s)8$xzN2oQ z&8kvo(5#n-s#k8SJGDR3sA%cd>K6mBNoL1%|;a3fZr-cin= zYPpu=qSIDhdSoza1;weJ4sFfDy1#T(G65(5=*fM#HdP>B)l#G|Y7SZj;hGd=_n5M6 zk6?0yLmVWnrKiJ==ZEaDd&$_o3O*jl{*)?EMm2z;cT2^W_`d0yC?RIj9*!ym!Z-4m z$0UPF8}^jaL8`$RAbM!5|2Bh6v<4Y$GI}yp!%n1~m?O*USvMWdevO+HEJ$EGnGsj} z^x(XtZpCk@pzJ;#2zKPKG>=vV{NOZ0%V{Wb$}mzg3R_4Ux5u3iP0H2oq(HkRR92s9 zYD9KS5<2+q7W0l8PstN8;+q>oC3IhaQ?0k}Hui&t6EC62w7NcC6`dN!8Qo=o3sfoP z&_;H6jHRb&2-l1IJz|?rBysB8t2nAc;(% zw=O^%ecFEdy159HbKrJ^Yh!ZeXM)>0n{9#*7Oprd{2_g#GJWn0Oq8<6lwkeu4sEhp0mmNMV`I`L=Vb2@cgCm9s>F~9=Y27`SfGw zlZ&YTV)tEmN7pGUMCNSU1u{k664?LikNxb0s zopxBFU98#kOE6f}nm`>{vE{4iNRD;uK5s~|_Dz7v92FVbs#-2o`}aivF*dgkdRC55 zrBF`s3M3W*8k-iyNPR<3&ZTVw8dMEH%zpd?XL`H2t)`wl+8Y-}oD@dpjz%rySAN#K$6K{HgbNZ$~0{s(S-CqYqGgMkHKmKqk zR)tiQKl#U1BSVL`SIP4ki0-EiPTc-h&r+9r8wA=_Kjs5rW4FM0s{|gsG%g$Moc%2{ z@bdFh`$zrDyvHiPC#&aWe+XnHwY{r(`^kCDux}9}w$r|B`=JpX!$2UZ^Zmzs_c{G& zh|az*AgATh2m^dKzSsBh4|9%1>GwiNm`ceDSq0MXI&aNHYHB^qh`R)gaoCe(!CDgTOW_cV z#F}GUa*uOhP`{Y-d@`HqdboFiri`01S-<_*f3>MmrO6$oVZmVl)juPsuF*!74~(fB zFyRoOAYl#eKSBaO-DTD<0H67@o^Ot7tKJ*eCd1~t44ycag7^K&`unjMM|Q#7CtHDe z&9`FKq#m``J$b(_|2TV1GBN2_c2$UOD5npf%$CvJoLw^@(@9YdPI(K%!wIwHPE5NJ z5#;NKP?j;C!ye;bYbxdY#2ix~zj9)^SXab`TMo!JS3E2%{R8Uslf8-=* zeUbljkxA)W|mi5(4yik)=4*A@=gi>d~ z!`S3`fD{2IOh4}t4Q1`xxvSLeazOsm;9Km`K>W8B&7$_FY{E-*y}Legqpuz`#D8*R zj$Kl5uSd_<7=(kd?)~%h!?&N`2&EDQLA4k+E94XKlAD7>VIZ&A?(p_fp%C>xH|{Z znPF30SNF=Y+w3>wdJqr?LM6?_pqmWqG^8U!_#z_qSeaIFJB}zv8tQTqi?{lJA*dLC_^UbT@9T?C$Jkp2a>{NG-s6BA0N4z*@%5Iai`g^>YYsp?$-tf1x zUP)hoxMFsPy~SfMD%G!WbUiZapR@t&zM z5Ba%oZ!my=R!Af{h;t7L0CqBa z9ZNA1$bc=3`Oily&{Kl zvBx=bq6k0OsO}NET}4s{;69Pk^26$-nT&O^n@mE3@yigD?0K_nMcuW)H8aH!v8TOB zv6l!?HZNQzj6fy5s&1k}f&bho@i317(`bBpO!x2tf2}vD<>?i8`}*tZTcLA*|Hhv` zjZZf}R(?(G`dzqPYh$C<7!A4!wf;iurdCP*(UCLCT_Hb-4)g)ln;9F@2et3QRm~dI z$G5i8_t-z1x_9NS+M^|Mdu$|IBPbq;?Ox^^(iauNj0+GjH$&uI_cWKSBc!H3sMK%X z)05Y=fX+yhXNF|J`gh|kFKFB454K7N?*wYObbA@p8gnMbIi7PJ(>zwJ)3||92uaW=XMgs+n3;6eS1O*C?LW4A$W5|L6 zIp&`)Q+J@F2RqweYc<7xX4Ja~gR_OSwInzIfaD*!cp;|bon5^=b%EyIKsH%(C*a>n zHfJvnSD@v88hX2B)y2XF0Pq+90Hl8yT7dxoG^E9)l%?66to}3GcA#fbnjYj-CC~tx ze`LeJ2LK%HEZCiao}3(P9PIyNS*#o#|I^~vi-oM*B>;eu66rrI9y&w)?-n5*=RYk9 znN%2d3PQ>l3=N?AM;QmDp#R$c8rc`XA-{r3?Gt_W1ultMH!&`5NK=SA+jU3IEg0|GSVlQSkqh)Bn%E;6L5szYWkt b!~cIeNi{_{_`mF+K;BZ2HmV={SMvV=1CdjF literal 251970 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 - /// 目前動態計算的連發間隔幀數(加入生理抖動) + /// 目前生效的連發間隔幀數(首次為初始延遲,之後為重複間隔) /// private int _currentRepeatInterval; /// - /// 目前動態計算的右搖桿連發間隔幀數(加入生理抖動) + /// 目前生效的右搖桿連發間隔幀數(首次為初始延遲,之後為重複間隔) /// private int _currentRSRepeatInterval; diff --git a/src/InputBox/Core/Input/XInputGamepadController.cs b/src/InputBox/Core/Input/XInputGamepadController.cs index 9a49d93..a1209a0 100644 --- a/src/InputBox/Core/Input/XInputGamepadController.cs +++ b/src/InputBox/Core/Input/XInputGamepadController.cs @@ -34,12 +34,12 @@ internal sealed partial class XInputGamepadController : IGamepadController private readonly GamepadRepeatSettings _repeatSettings; /// - /// 目前動態計算的連發間隔幀數(加入生理抖動) + /// 目前生效的連發間隔幀數(首次為初始延遲,之後為重複間隔) /// private int _currentRepeatInterval; /// - /// 目前動態計算的右搖桿連發間隔幀數(加入生理抖動) + /// 目前生效的右搖桿連發間隔幀數(首次為初始延遲,之後為重複間隔) /// private int _currentRSRepeatInterval; diff --git a/src/InputBox/Core/Utilities/GaussianDelayHelper.cs b/src/InputBox/Core/Utilities/GaussianDelayHelper.cs index 10406da..d59f7df 100644 --- a/src/InputBox/Core/Utilities/GaussianDelayHelper.cs +++ b/src/InputBox/Core/Utilities/GaussianDelayHelper.cs @@ -2,7 +2,7 @@ /// /// 提供基於高斯分佈(常態分佈)的隨機數產生器 -/// 用於系統操作的自然緩衝延遲,改善 A11y 音訊避讓與 UI 執行緒排程穩定性 +/// 用於本程式內部排程的緩衝延遲,改善 A11y 音訊避讓與 UI 執行緒排程穩定性 /// internal static class GaussianDelayHelper { @@ -30,11 +30,15 @@ public static double NextGaussian( } /// - /// 產生符合人類反應特徵的毫秒延遲 + /// 產生加入排程抖動的毫秒延遲 /// + /// + /// 僅用於本程式內部的 A11y 廣播避讓時序(), + /// 讓連續廣播不會固定落在同一個排程點;不參與任何對其他視窗的輸入或輸出。 + /// /// 基礎延遲(毫秒) /// 抖動範圍(毫秒) - /// 加上生理擾動後的延遲時間 + /// 加上排程抖動後的延遲時間 public static int NextDelay( int baseDelay, int jitterRange) @@ -51,7 +55,7 @@ public static int NextDelay( double mean = baseDelay + (jitterRange / 2.0), sd = jitterRange / 6.0; - // 若 jitter 過小導致 sd 太低,補上一個極小生理抖動(平均值的 5%)。 + // 若 jitter 過小導致 sd 太低,補上最小排程抖動(平均值的 5%)。 sd = Math.Max(sd, mean * 0.05); double result = NextGaussian(mean, sd); From 1289496191f25560b3b18588e7be46e64cd06c1d Mon Sep 17 00:00:00 2001 From: perditavojo <117562794+perditavojo@users.noreply.github.com> Date: Sun, 27 Sep 2026 06:46:29 +0800 Subject: [PATCH 06/17] =?UTF-8?q?fix(restart):=20=E7=A8=8B=E5=BC=8F?= =?UTF-8?q?=E5=85=A7=E9=87=8D=E5=95=9F=E6=99=82=E5=8F=AA=E6=8E=88=E6=AC=8A?= =?UTF-8?q?=E6=96=B0=E5=9F=B7=E8=A1=8C=E5=80=8B=E9=AB=94=E6=90=B6=E5=9B=9E?= =?UTF-8?q?=E5=89=8D=E6=99=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 原本重啟前以 AllowSetForegroundWindow(ASFW_ANY) 讓任何程序都能搶前景,授權範圍大於需要。 - 新增 RestartProcessLauncher,行為對齊 WinForms Application.Restart()(同一執行檔、只轉送第一個之後的引數),改用 ArgumentList 避免引號拼接錯誤,並回傳新程序識別碼。 - RestartApplication 先解除全域快速鍵並釋放 Mutex,趁舊視窗仍在前景時啟動新執行個體,再以其 PID 授權前景;控制器觸發重啟不會產生 Windows 輸入事件,授權必須在關閉視窗前完成。 - 無法啟動新程序時退回原本的 ASFW_ANY 與 Application.Restart() 流程。 - 新增 RestartProcessLauncherTests(4 項),同步更新測試 README 與 core-engineering 規範。 合規:已即時查核 FFXIV 繁中版使用者合約、第三方授權聲明與宇峻奧汀使用條款、隱私權政策、免責聲明;變更僅限本程式重啟自身的前景授權,不接觸遊戲程序、不模擬輸入,輸出邊界仍為剪貼簿。 Co-Authored-By: Claude Opus 5.5 --- docs/engineering/core-engineering.md | 3 +- .../Core/Services/RestartProcessLauncher.cs | 75 +++++++++++++++++++ src/InputBox/MainForm.cs | 47 +++++++++--- tests/InputBox.Tests/README.md | 3 +- .../RestartProcessLauncherTests.cs | 65 ++++++++++++++++ 5 files changed, 181 insertions(+), 12 deletions(-) create mode 100644 src/InputBox/Core/Services/RestartProcessLauncher.cs create mode 100644 tests/InputBox.Tests/RestartProcessLauncherTests.cs diff --git a/docs/engineering/core-engineering.md b/docs/engineering/core-engineering.md index d3cb46f..e2d496a 100644 --- a/docs/engineering/core-engineering.md +++ b/docs/engineering/core-engineering.md @@ -25,7 +25,8 @@ - **主題還原**:還原預設配色時應將屬性設為 `Color.Empty`,由 .NET 10 主題引擎自動判斷 (禁:硬式編碼 `SystemColors.Control`)。 - **程式內重啟與前景恢復**: - **單次啟用標記**:若為本程式主動要求重新啟動,舊執行個體必須先寫入具短時效的一次性啟用標記,供新執行個體在首次顯示時消費;標記必須於讀取後立即清除,避免重複生效。 - - **前景授權交接**:呼叫 `Application.Restart()` 前,應先透過 `AllowSetForegroundWindow(...)` 授權新執行個體搶回前景,降低焦點落回前一個視窗的機率。 + - **前景授權交接**:由 `RestartProcessLauncher` 自行啟動新執行個體(取代 `Application.Restart()`),並在舊視窗關閉前以 `AllowSetForegroundWindow(新程序 PID)` 只授權該程序搶回前景;不得使用 `ASFW_ANY` 開放給所有程序,僅在無法啟動新程序而退回 `Application.Restart()` 時例外。授權必須在舊視窗仍位於前景時完成,因為控制器操作不會產生 Windows 輸入事件。 + - **獨占資源先釋放**:新執行個體會在舊視窗關閉前啟動,因此舊執行個體必須先解除全域快速鍵並釋放單一執行個體 Mutex,避免新執行個體註冊失敗。 - **新執行個體恢復流程**:新視窗啟動後應先走較強的前景還原路徑(例如 `WindowFocusService.RestoreWindowAsync(...)`),再以有限次數重試 `ShowWindow`、`BringWindowToTop`、`SetForegroundWindow`、`Activate()` 與輸入框 `Focus()`;不可只做單次 `Activate()` 後就假設成功。 - **避免錯誤回切**:當重啟是由程式內設定變更觸發時,舊執行個體應避免再把「前一個外部視窗」覆寫為目前狀態,以免新執行個體恢復焦點時誤切回錯誤目標。 - **格式與診斷紀律**: diff --git a/src/InputBox/Core/Services/RestartProcessLauncher.cs b/src/InputBox/Core/Services/RestartProcessLauncher.cs new file mode 100644 index 0000000..dfb81d3 --- /dev/null +++ b/src/InputBox/Core/Services/RestartProcessLauncher.cs @@ -0,0 +1,75 @@ +using System.Diagnostics; + +namespace InputBox.Core.Services; + +/// +/// 負責程式內重啟時啟動新的執行個體;取代 以便在舊視窗關閉前取得新程序識別碼, +/// 讓前景授權只交給該程序,而不必開放給所有程序。 +/// +internal static class RestartProcessLauncher +{ + /// + /// 依目前執行檔與命令列引數建立重啟用的啟動資訊。 + /// + /// + /// 與 相同:以同一個執行檔啟動,並只轉送第一個元素(執行檔本身)之後的引數; + /// 改用 逐一加入,避免引數內含引號時被錯誤拼接。 + /// + /// 要啟動的執行檔完整路徑。 + /// 目前程序的命令列引數(含第一個元素的執行檔路徑)。 + /// 重啟用的啟動資訊。 + public static ProcessStartInfo CreateStartInfo( + string executablePath, + IReadOnlyList commandLineArgs) + { + ArgumentException.ThrowIfNullOrWhiteSpace(executablePath); + ArgumentNullException.ThrowIfNull(commandLineArgs); + + ProcessStartInfo startInfo = new(executablePath) + { + UseShellExecute = false + }; + + for (int i = 1; i < commandLineArgs.Count; i++) + { + startInfo.ArgumentList.Add(commandLineArgs[i]); + } + + return startInfo; + } + + /// + /// 嘗試啟動新的執行個體並取得其程序識別碼。 + /// + /// 由 建立的啟動資訊。 + /// 成功時為新程序的識別碼;失敗時為 0。 + /// 若已成功啟動新程序則回傳 true。 + public static bool TryStart( + ProcessStartInfo startInfo, + out int processId) + { + ArgumentNullException.ThrowIfNull(startInfo); + + processId = 0; + + try + { + using Process? process = Process.Start(startInfo); + + if (process == null) + { + return false; + } + + processId = process.Id; + + return true; + } + catch (Exception ex) + { + LoggerService.LogException(ex, "程式內重啟時無法啟動新的執行個體"); + + return false; + } + } +} diff --git a/src/InputBox/MainForm.cs b/src/InputBox/MainForm.cs index 75893c1..0f9f660 100644 --- a/src/InputBox/MainForm.cs +++ b/src/InputBox/MainForm.cs @@ -1223,26 +1223,53 @@ private void RestartApplication() // 為下一個重啟後的執行個體建立一次性前景啟用請求,降低焦點跳回前一個視窗的機率。 RestartActivationCoordinator.Shared.RequestActivationOnNextLaunch(); - // 由目前前景執行個體主動授權新的重啟程序可呼叫 SetForegroundWindow, - // 提升 Hosted Runner 與桌面自動化環境下的前景恢復成功率。 - _ = User32.AllowSetForegroundWindow(User32.AllowSetForegroundWindowAnyProcess); - // 在正式結束前同步停止所有控制器震動,防止程序關閉後馬達持續空轉。 FeedbackService.EmergencyStopAllActiveControllers(); + List mainForms = [.. Application.OpenForms.OfType()]; + + // 新執行個體會在舊視窗關閉前啟動,因此先解除全域快速鍵, + // 避免新舊執行個體短暫並存時,新執行個體註冊同一組快速鍵失敗。 + foreach (MainForm mainForm in mainForms) + { + if (mainForm.IsHandleCreated) + { + GlobalHotKeyService.UnregisterShowInputHotkey(mainForm.Handle); + } + } + Program.ReleaseMutex(); + // AllowSetForegroundWindow 只有在呼叫端仍為前景程序(或收到最後一次輸入)時才有效; + // 以控制器觸發重啟不會產生 Windows 輸入事件,因此必須趁目前視窗仍在前景時, + // 先啟動新執行個體,再只授權該程序呼叫 SetForegroundWindow,而不開放給所有程序。 + bool launched = RestartProcessLauncher.TryStart( + RestartProcessLauncher.CreateStartInfo( + Application.ExecutablePath, + Environment.GetCommandLineArgs()), + out int newProcessId); + + _ = User32.AllowSetForegroundWindow( + launched ? + newProcessId : + User32.AllowSetForegroundWindowAnyProcess); + // 安全地關閉所有 MainForm 實例,確保它們的 Dispose 與 FormClosing 被正確觸發, // 從而釋放全域的 SystemEvents 鉤子,防止重啟時發生靜態資源洩漏。 - foreach (Form form in Application.OpenForms.Cast
().ToList()) + foreach (MainForm mainForm in mainForms) { - if (form is MainForm mainForm) - { - mainForm.Close(); - } + mainForm.Close(); } - Application.Restart(); + if (launched) + { + Application.Exit(); + } + else + { + // 無法自行啟動新執行個體時,退回 WinForms 內建的重啟流程。 + Application.Restart(); + } Environment.Exit(0); } diff --git a/tests/InputBox.Tests/README.md b/tests/InputBox.Tests/README.md index 17e892f..0086e78 100644 --- a/tests/InputBox.Tests/README.md +++ b/tests/InputBox.Tests/README.md @@ -40,12 +40,13 @@ | `PhraseServiceTests` | `PhraseService` CRUD、匯出/匯入、併發匯出、併發暫存檔誤刪(含 managed 暫存檔寬限期保留),以及持久化失敗時的記憶體復原回歸保護 | 40 | | `RestartActivationCoordinatorTests` | `RestartActivationCoordinator` 的一次性重啟前景啟用標記、單次消費與過期清理保護 | 3 | | `RestartPromptStateTests` | 需重啟設定的待處理狀態追蹤、標題列提示,以及右鍵選單依 App 設定/系統變更/兩者同時存在而動態切換文案的回歸保護 | 7 | +| `RestartProcessLauncherTests` | `RestartProcessLauncher` 重啟啟動資訊:沿用目前執行檔、不透過殼層啟動、只轉送執行檔之後的引數並保留空白與引號(取代 `Application.Restart()` 以便只授權新程序前景的回歸保護) | 4 | | `RestartRequestDeciderTests` | 手動重啟與設定變更兩種入口的確認策略回歸保護 | 3 | | `SystemHelperTests` | `SystemHelper.EvaluateGamescopeEnvironment` 在不同 DISPLAY、XDG_CURRENT_DESKTOP 與 DESKTOP_SESSION 環境變數組合下的 Gamescope 環境偵測回歸保護 | 11 | | `TaskExtensionsTests` | `TaskExtensions` CTS 擴充方法與生命週期連結保護 | 12 | | `VibrationPatternsTests` | `VibrationPatterns` 與方向性震動設定、語意情境解析、能力感知的多段式微震動序列,以及歷程滾輪阻尼感、字數上限硬牆、震動強度預覽、右搖桿選取粒度、組合鍵進入提示與喚起握手回饋的回歸保護 | 37 | | `VibrationSafetyLimiterTests` | `VibrationSafetyLimiter` 熱保護、Duty Cycle 限制器與極端邊界保護 | 8 | -| **合計** | | **393** | +| **合計** | | **397** | ## 二、執行方式 🚀 diff --git a/tests/InputBox.Tests/RestartProcessLauncherTests.cs b/tests/InputBox.Tests/RestartProcessLauncherTests.cs new file mode 100644 index 0000000..7bd5e87 --- /dev/null +++ b/tests/InputBox.Tests/RestartProcessLauncherTests.cs @@ -0,0 +1,65 @@ +using InputBox.Core.Services; +using System.Diagnostics; +using Xunit; + +namespace InputBox.Tests; + +/// +/// 驗證程式內重啟的啟動資訊與 WinForms Application.Restart() 行為一致,並正確保留命令列引數。 +/// +public sealed class RestartProcessLauncherTests +{ + /// + /// 應以目前執行檔啟動新執行個體,且不透過殼層啟動,才能直接取得新程序識別碼並對齊 Application.Restart()。 + /// + [Fact] + public void CreateStartInfo_UsesExecutablePathWithoutShellExecute() + { + const string exePath = @"C:\Apps\InputBox\InputBox.exe"; + + ProcessStartInfo startInfo = RestartProcessLauncher.CreateStartInfo(exePath, [exePath]); + + Assert.Equal(exePath, startInfo.FileName); + Assert.False(startInfo.UseShellExecute); + Assert.Empty(startInfo.ArgumentList); + } + + /// + /// 命令列第一個元素是執行檔本身,只應轉送其後的引數,並保持原本順序。 + /// + [Fact] + public void CreateStartInfo_ForwardsArgumentsAfterExecutableInOrder() + { + ProcessStartInfo startInfo = RestartProcessLauncher.CreateStartInfo( + "InputBox.exe", + ["InputBox.exe", "--first", "second"]); + + Assert.Equal(["--first", "second"], startInfo.ArgumentList); + } + + /// + /// 含空白或引號的引數應原樣保留,避免像字串拼接那樣在重啟後被拆開或轉義錯誤。 + /// + [Fact] + public void CreateStartInfo_PreservesArgumentsContainingSpacesAndQuotes() + { + const string pathWithSpace = @"D:\My Folder\a.txt"; + const string quoted = "say \"hi\""; + + ProcessStartInfo startInfo = RestartProcessLauncher.CreateStartInfo( + "InputBox.exe", + ["InputBox.exe", pathWithSpace, quoted]); + + Assert.Equal([pathWithSpace, quoted], startInfo.ArgumentList); + } + + /// + /// 執行檔路徑為空白時應立即擲出例外,避免以無效路徑嘗試重啟。 + /// + [Fact] + public void CreateStartInfo_BlankExecutablePath_Throws() + { + Assert.ThrowsAny( + () => RestartProcessLauncher.CreateStartInfo(" ", ["InputBox.exe"])); + } +} From 5951d8975e91735902e36bc8cfcfb215aff7d40b Mon Sep 17 00:00:00 2001 From: perditavojo <117562794+perditavojo@users.noreply.github.com> Date: Sun, 27 Sep 2026 06:46:31 +0800 Subject: [PATCH 07/17] =?UTF-8?q?style(editorconfig):=20=E4=BE=9D=E5=AE=98?= =?UTF-8?q?=E6=96=B9=E7=B7=A8=E7=A2=BC=E6=85=A3=E4=BE=8B=E8=AA=BF=E6=95=B4?= =?UTF-8?q?=20var=20=E4=BD=BF=E7=94=A8=E8=A6=8F=E7=AF=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 原設定全面禁止 var,但與 Microsoft C# 編碼慣例(2026-03 更新)及 .NET Runtime 程式碼風格不一致,測試專案實際也已使用 var 186 處。 - csharp_style_var_when_type_is_apparent 改為 true:型別可由右側直接看出(new、明確轉型)時可使用 var,亦可沿用 target-typed new()。 - 內建型別與其他情況維持明確型別;IDE0008 設為 suggestion,提示型別無法直接看出卻使用 var 的情況,IDE0007 維持 silent,不催促改寫既有明確型別寫法。 - core-engineering 新增 var 使用原則與官方來源連結。 建置維持 0 警告。 Co-Authored-By: Claude Opus 5.5 --- .editorconfig | 9 ++++++++- docs/engineering/core-engineering.md | 1 + 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/.editorconfig b/.editorconfig index c69b4f6..8430fa2 100644 --- a/.editorconfig +++ b/.editorconfig @@ -99,9 +99,16 @@ dotnet_style_allow_statement_immediately_after_block_experimental = true #### C# 編碼慣例 #### # var 喜好設定 +# 依 Microsoft C# 編碼慣例與 .NET Runtime 程式碼風格: +# - 型別可由右側直接看出(new、明確轉型)時可使用 var,亦可使用 target-typed new()。 +# - 內建型別、方法回傳值等型別無法由右側直接看出時,一律使用明確型別;不以方法或變數名稱推測型別。 +# - foreach 迴圈變數使用明確型別;LINQ 匿名型別等必要情況除外。 csharp_style_var_elsewhere = false csharp_style_var_for_built_in_types = false -csharp_style_var_when_type_is_apparent = false +csharp_style_var_when_type_is_apparent = true +# IDE0008:型別無法直接看出卻使用 var 時提示改為明確型別;IDE0007(改用 var)不主動提示,保留既有明確型別寫法。 +dotnet_diagnostic.IDE0008.severity = suggestion +dotnet_diagnostic.IDE0007.severity = silent # 運算式主體成員 csharp_style_expression_bodied_accessors = true diff --git a/docs/engineering/core-engineering.md b/docs/engineering/core-engineering.md index e2d496a..928ad97 100644 --- a/docs/engineering/core-engineering.md +++ b/docs/engineering/core-engineering.md @@ -32,5 +32,6 @@ - **格式與診斷紀律**: - **EditorConfig 強制套用**:每次修改任何檔案後,必須遵循專案根目錄 `.editorconfig` 的縮排、編碼、換行與格式設定。 - **C# 診斷清零**:每次修改 `*.cs` 檔案後,提交或回覆前都必須檢查該檔案的 IDE 與 CS 類型診斷,並修正新增的建議、警告與錯誤。 + - **`var` 使用原則**:依 [Microsoft C# 編碼慣例](https://learn.microsoft.com/dotnet/csharp/fundamentals/coding-style/coding-conventions#implicitly-typed-local-variables) 與 [.NET Runtime 程式碼風格](https://github.com/dotnet/runtime/blob/main/docs/coding-guidelines/coding-style.md),僅在型別可由右側直接看出(`new`、明確轉型)時使用 `var`,此時亦可使用 target-typed `new()`;內建型別、方法回傳值與 `foreach` 迴圈變數一律使用明確型別,不以方法或變數名稱推測型別;LINQ 匿名型別等必須使用 `var` 的情況除外。對應設定見 `.editorconfig`(IDE0007/IDE0008)。 - **Release 日誌門檻**:正式版預設只寫入 `Warning` 以上;`Info` 僅供 Debug、測試主機或 `INPUTBOX_LOG_LEVEL=Info` 臨時診斷使用。 - **可行動診斷原則**:正常 lifecycle、成功 probe、成功或略過震動、一般輪詢健康資料應維持 `Info`;會影響使用者操作、裝置可用性、API 呼叫失敗或資料修復失敗的訊號才可升級為 `Warning` 或 `Error`。 From a771f3169995a9a8e644323afc830aa8c535d2fb Mon Sep 17 00:00:00 2001 From: perditavojo <117562794+perditavojo@users.noreply.github.com> Date: Sun, 27 Sep 2026 06:48:23 +0800 Subject: [PATCH 08/17] =?UTF-8?q?docs(agent):=20=E4=BE=9D=20Claude=20Code?= =?UTF-8?q?=20=E6=9C=80=E6=96=B0=E5=AE=98=E6=96=B9=E6=96=87=E4=BB=B6?= =?UTF-8?q?=E6=9B=B4=E6=96=B0=E6=A9=8B=E6=8E=A5=E8=88=87=E6=94=AF=E6=8F=B4?= =?UTF-8?q?=E4=BE=9D=E6=93=9A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 依 2026-09-27 查核的 Claude Code 記憶與 Skills 官方文件: - 保留 CLAUDE.md 的 @AGENTS.md 匯入:Claude Code 雖可直接讀取 AGENTS.md,但只在沒有 CLAUDE.md 時生效,且部分工作階段無法直接讀取;官方確認此匯入不會重複載入。 - Claude Code 只從 .claude/skills/ 探索 skill,橋接仍屬必要。 - 兩個橋接 skill 的 description 改為先寫主要使用情境,符合官方撰寫建議,提升自動載入判斷。 - agent-support 記錄 Anthropic 查核日期、上述結論與 Agent Skills 標準欄位的可攜性限制。 Co-Authored-By: Claude Opus 5.5 --- .claude/skills/inputbox-dev/SKILL.md | 2 +- .claude/skills/update-inputweave-gameinput/SKILL.md | 2 +- docs/engineering/agent-support.md | 6 +++++- 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/.claude/skills/inputbox-dev/SKILL.md b/.claude/skills/inputbox-dev/SKILL.md index f85a5c8..50a997e 100644 --- a/.claude/skills/inputbox-dev/SKILL.md +++ b/.claude/skills/inputbox-dev/SKILL.md @@ -1,6 +1,6 @@ --- name: inputbox-dev -description: Claude Code 對 InputBox 工程技能的橋接。當修改 InputBox 程式碼、UI、控制器邏輯、在地化、測試或 Git 工作流時使用。 +description: 修改 InputBox 程式碼、UI、控制器邏輯、在地化、測試、工程規範或 Git 工作流時使用,負責載入對應的工程規範;一般只讀問答不需啟用。本檔為 Claude Code 橋接,權威內容在 .agents/skills/inputbox-dev/SKILL.md。 --- # InputBox Claude Code Skill Bridge diff --git a/.claude/skills/update-inputweave-gameinput/SKILL.md b/.claude/skills/update-inputweave-gameinput/SKILL.md index 5eba13e..329202a 100644 --- a/.claude/skills/update-inputweave-gameinput/SKILL.md +++ b/.claude/skills/update-inputweave-gameinput/SKILL.md @@ -1,6 +1,6 @@ --- name: update-inputweave-gameinput -description: Claude Code 對 InputWeave.GameInput 更新技能的橋接。更新 InputBox 內嵌套件、來源 commit、雜湊、授權、CI 或 gh-pages 第三方資訊時使用。 +description: 更新或重新封裝 InputBox 內嵌的 InputWeave.GameInput 套件,並同步來源 commit、SHA-256、授權、CI、release workflow 與 gh-pages 第三方資訊時使用。本檔為 Claude Code 橋接,權威流程在 .agents/skills/update-inputweave-gameinput/SKILL.md。 --- # InputWeave.GameInput Claude Code Skill Bridge diff --git a/docs/engineering/agent-support.md b/docs/engineering/agent-support.md index cc399a6..e2c1475 100644 --- a/docs/engineering/agent-support.md +++ b/docs/engineering/agent-support.md @@ -25,7 +25,11 @@ ## 官方依據與查核日期 - OpenAI(2026-07-30):[`AGENTS.md` custom instructions](https://developers.openai.com/codex/guides/agents-md) 與 [Codex skills](https://developers.openai.com/codex/skills)。 -- Claude Code、GitHub Copilot CLI 與 Antigravity CLI 的既有支援策略最後查核於 2026-05-25;若修改對應橋接或支援聲明,須先以各供應商最新官方文件重新查核。 +- Anthropic(2026-09-27):[記憶與 `AGENTS.md`](https://code.claude.com/docs/en/memory) 與 [Skills](https://code.claude.com/docs/en/skills)。 + - Claude Code 可直接讀取 `AGENTS.md`,但只在工作目錄以上沒有 `CLAUDE.md`、`.claude/CLAUDE.md` 或 `CLAUDE.local.md` 時才會讀取;部分工作階段無法直接讀取。因此保留 `CLAUDE.md` 的 `@AGENTS.md` 匯入,Claude 專屬內容只放在匯入之後;官方確認此寫法不會重複載入。 + - Claude Code 只從 `.claude/skills/` 探索 project skill,不讀取 `.agents/skills/`,因此橋接 skill 仍屬必要。 + - Skill 遵循 [Agent Skills](https://agentskills.io) 開放標準;`description` 應先寫主要使用情境(與 `when_to_use` 合計約 1,536 字元後截斷)。跨工具共用的權威 skill 只使用標準欄位(`name`、`description`、`license`、`compatibility`、`metadata`、`allowed-tools`),Claude Code 專屬欄位只可放在 `.claude/skills/` 橋接檔。 +- GitHub Copilot CLI 與 Antigravity CLI 的既有支援策略最後查核於 2026-05-25;若修改對應橋接或支援聲明,須先以各供應商最新官方文件重新查核。 ## Context 維護原則 From f09a85beb621e44b15b6c5b04f116f94e78315e1 Mon Sep 17 00:00:00 2001 From: perditavojo <117562794+perditavojo@users.noreply.github.com> Date: Sun, 27 Sep 2026 06:56:16 +0800 Subject: [PATCH 09/17] =?UTF-8?q?fix(vibration):=20=E4=BF=AE=E6=AD=A3?= =?UTF-8?q?=E7=86=B1=E4=BF=9D=E8=AD=B7=E5=9C=A8=E5=86=B7=E5=95=9F=E5=8B=95?= =?UTF-8?q?=E6=99=82=E6=93=8B=E6=8E=89=E9=87=8D=E8=A6=81=E9=9C=87=E5=8B=95?= =?UTF-8?q?=E5=9B=9E=E9=A5=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 熱成本為「振幅² × 持續時間 × 權重」,XInput 權重固定為 2、GameInput 為回報的馬達數量, 單次提示的成本就可能超過硬上限 × 1.05(約 189),Normal 優先級會被直接拒絕。 例如「複製成功」在 XInput 強度 100%,或 GameInput 4 馬達預設強度 70% 時完全不震動。 - 新增 VibrationSafetyLimiter.GetMotorThermalCostMultiplier,以雙主馬達為 1.0 正規化權重,XInput 與 GameInput 共用同一基準。 - Normal 優先級單次請求超出剩餘熱預算時,依剩餘預算降低振幅後送出並標記 ScaledByThermalOverflow;只有降到保底比例以下(已接近過熱)才拒絕。 - 新增測試:倍率正規化、所有內建震動模式在冷啟動下於各強度與馬達數都不被拒絕、單次超預算改為降強度、已過熱時仍會拒絕。 - gamepad-api 規範新增熱成本正規化與回饋不得冷啟動遺失的規則。 震動僅作用於本程式連接的控制器,不涉及遊戲輸入、輸出或按鍵映射。 Co-Authored-By: Claude Opus 5.5 --- docs/engineering/gamepad-api.md | 2 + .../Core/Input/GameInputGamepadController.cs | 10 +- .../Core/Input/VibrationSafetyLimiter.cs | 75 ++++++++++- .../Core/Input/XInputGamepadController.cs | 2 +- tests/InputBox.Tests/README.md | 4 +- .../VibrationSafetyLimiterTests.cs | 125 +++++++++++++++++- 6 files changed, 204 insertions(+), 14 deletions(-) diff --git a/docs/engineering/gamepad-api.md b/docs/engineering/gamepad-api.md index 816199d..7004f3d 100644 --- a/docs/engineering/gamepad-api.md +++ b/docs/engineering/gamepad-api.md @@ -12,6 +12,8 @@ - **令牌隔離**:實作類別內部必須獨立實作 `_vibrationToken` (Interlocked),**禁止在服務層級共享**,以支援多控制器獨立運行的隔離性。 - **同步停止**:必須具備同步 `StopVibration()` 方法,支援緊急清理。 - **連結權杖 (Linked Token)**:震動延遲須結合外部取消權杖與內部覆寫權杖,確保視窗關閉時馬達能立即停止。 + - **熱成本正規化**:傳給 `VibrationSafetyLimiter` 的熱成本倍率必須透過 `GetMotorThermalCostMultiplier(馬達數)` 取得(以雙主馬達為 1.0),XInput 與 GameInput 共用同一基準;不得直接傳入馬達數量。 + - **回饋不得冷啟動遺失**:Normal 優先級單次請求超出剩餘熱預算時應先降低強度,只有低於優先級保底比例才可拒絕;新增或調整 `VibrationPatterns` 後,必須通過「所有內建模式冷啟動不被拒絕」測試。 - **Face 鍵語意路由 (Semantic Face-Button Routing)**: - 所有「確認/取消/刪除/選單」行為,必須透過集中化的配置描述(例如 `GamepadFaceButtonProfile`)解析,**禁止**在 Dialog、MessageBox 或主視窗中硬式編碼 `A=確認`、`B=取消`。 - 實作時應優先使用邏輯語意(例如 south/east/west/north 對應的功能)而非控制器字樣,避免 Nintendo 與 PlayStation 模式下產生顯示正確但功能錯置的回歸。 diff --git a/src/InputBox/Core/Input/GameInputGamepadController.cs b/src/InputBox/Core/Input/GameInputGamepadController.cs index 3d13e7f..ac922bb 100644 --- a/src/InputBox/Core/Input/GameInputGamepadController.cs +++ b/src/InputBox/Core/Input/GameInputGamepadController.cs @@ -428,9 +428,9 @@ internal sealed partial class GameInputGamepadController : IGamepadController private bool _supportsRumble = false; /// - /// 熱負載估算倍率(依支援馬達數量調整,2 馬達約 2.0、4 馬達約 4.0)。 + /// 熱負載估算倍率(依支援馬達數量正規化,以雙主馬達為 1.0,4 馬達為 2.0)。 /// - private double _rumbleThermalWeight = 2.0; + private double _rumbleThermalWeight = VibrationSafetyLimiter.GetMotorThermalCostMultiplier(2); /// /// 取得或設定搖桿進入死區閾值 @@ -2130,7 +2130,7 @@ private void UpdateDeviceInfo() _cachedDeviceIdentity = string.Empty; _supportsRumble = false; - _rumbleThermalWeight = 2.0; + _rumbleThermalWeight = VibrationSafetyLimiter.GetMotorThermalCostMultiplier(2); return; } @@ -2143,7 +2143,7 @@ private void UpdateDeviceInfo() _supportsRumble = info.SupportedRumbleMotors != 0; uint supportedMotorBits = Convert.ToUInt32(info.SupportedRumbleMotors); int supportedMotorCount = BitOperations.PopCount(supportedMotorBits); - _rumbleThermalWeight = Math.Clamp(supportedMotorCount, 1, 4); + _rumbleThermalWeight = VibrationSafetyLimiter.GetMotorThermalCostMultiplier(supportedMotorCount); // 更新裝置名稱與穩定識別資訊。Auto 判斷改以 VID/PID 與 GameInput // 原始顯示名稱作為穩定線索。 @@ -2158,7 +2158,7 @@ private void UpdateDeviceInfo() _cachedDeviceName = "Unknown Gamepad"; _cachedDeviceIdentity = _cachedDeviceName; _supportsRumble = false; - _rumbleThermalWeight = 2.0; + _rumbleThermalWeight = VibrationSafetyLimiter.GetMotorThermalCostMultiplier(2); } } diff --git a/src/InputBox/Core/Input/VibrationSafetyLimiter.cs b/src/InputBox/Core/Input/VibrationSafetyLimiter.cs index 195df0e..ebfaaff 100644 --- a/src/InputBox/Core/Input/VibrationSafetyLimiter.cs +++ b/src/InputBox/Core/Input/VibrationSafetyLimiter.cs @@ -54,7 +54,12 @@ internal enum VibrationLimiterFlags /// /// 因可感知體驗保底而回補。 /// - ScaledByPerceptibilityFloor = 1 << 8 + ScaledByPerceptibilityFloor = 1 << 8, + + /// + /// 單次請求超出剩餘熱預算,已降低強度以符合預算。 + /// + ScaledByThermalOverflow = 1 << 9 } /// @@ -100,6 +105,16 @@ internal sealed class VibrationSafetyLimiter /// private const int AmbientPerceptibleFloorDurationMs = 35; + /// + /// 熱成本倍率的基準馬達數量(雙主馬達控制器,例如 XInput)。 + /// + private const int ReferenceMotorCount = 2; + + /// + /// 熱負載溢出判斷相對於硬上限的容許倍率。 + /// + private const double ThermalOverflowTolerance = 1.05; + private readonly Lock _lock = new(); private readonly Queue<(long EndMs, int DurationMs)> _acceptedDurations = new(); @@ -140,6 +155,20 @@ public VibrationSafetyLimiter( _ambientCooldownMs = Math.Max(ambientCooldownMs, 0); } + /// + /// 依控制器回報的震動馬達數量取得正規化的熱成本倍率。 + /// + /// + /// 以雙主馬達為基準(倍率 1.0),讓預算與縮放參數在不同後端之間具有相同意義; + /// 否則多馬達裝置的單次提示成本可能直接超過硬上限,導致冷啟動狀態下也被拒絕。 + /// + /// 支援的震動馬達數量;會被限制在 1 到 4 之間。 + /// 正規化後的熱成本倍率(0.5 到 2.0)。 + public static double GetMotorThermalCostMultiplier(int motorCount) + { + return Math.Clamp(motorCount, 1, 4) / (double)ReferenceMotorCount; + } + /// /// 依目前保護狀態嘗試套用震動請求,必要時自動縮減強度與持續時間。 /// @@ -415,12 +444,36 @@ internal bool TryApplyWithDiagnostics( } } - double amplitude = candidateStrength / 65535.0; double clampedMultiplier = Math.Clamp(thermalCostMultiplier, 0.25, 8.0); - double cost = amplitude * amplitude * candidateDuration * clampedMultiplier; + double cost = ComputeThermalCost(candidateStrength, candidateDuration, clampedMultiplier); + double overflowLimit = _thermalHardBudget * ThermalOverflowTolerance; + + // Normal 優先級單次請求超出剩餘熱預算時,先依剩餘預算降低振幅(熱成本與振幅平方成正比), + // 只有降到優先級保底比例以下(代表馬達已接近過熱)才拒絕,避免冷啟動時重要回饋被整個吞掉。 + if (priority == VibrationPriority.Normal && + _thermalLoad + cost > overflowLimit) + { + double headroom = overflowLimit - _thermalLoad; + double fitScale = headroom > 0.0 ? + Math.Sqrt(headroom / cost) : + 0.0; + + if (scale * fitScale >= minScale) + { + ushort fittedStrength = (ushort)Math.Max(1, (int)Math.Floor(candidateStrength * fitScale)); + + if (fittedStrength < candidateStrength) + { + candidateStrength = fittedStrength; + cost = ComputeThermalCost(candidateStrength, candidateDuration, clampedMultiplier); + scale *= fitScale; + flags |= VibrationLimiterFlags.ScaledByThermalOverflow; + } + } + } if (priority != VibrationPriority.Critical && - _thermalLoad + cost > _thermalHardBudget * 1.05) + _thermalLoad + cost > overflowLimit) { _ambientCooldownUntilMs = nowMs + _ambientCooldownMs; flags |= VibrationLimiterFlags.BlockedByThermalOverflow; @@ -454,6 +507,20 @@ internal bool TryApplyWithDiagnostics( } } + /// + /// 計算單次震動的熱成本(振幅平方 × 持續時間 × 馬達倍率)。 + /// + /// 震動強度(0 到 65535)。 + /// 持續時間(毫秒)。 + /// 已限制範圍的熱成本倍率。 + /// 熱成本估值。 + private static double ComputeThermalCost(ushort strength, int durationMs, double multiplier) + { + double amplitude = strength / 65535.0; + + return amplitude * amplitude * durationMs * multiplier; + } + /// /// 重置限制器的熱負載、占空比與冷卻狀態。 /// diff --git a/src/InputBox/Core/Input/XInputGamepadController.cs b/src/InputBox/Core/Input/XInputGamepadController.cs index a1209a0..eed7e8a 100644 --- a/src/InputBox/Core/Input/XInputGamepadController.cs +++ b/src/InputBox/Core/Input/XInputGamepadController.cs @@ -1895,7 +1895,7 @@ public Task VibrateAsync( out ushort safeStrength, out int safeDurationMs, out VibrationLimiterDebugInfo limiterDiagnostics, - thermalCostMultiplier: 2.0); + thermalCostMultiplier: VibrationSafetyLimiter.GetMotorThermalCostMultiplier(2)); #if DEBUG bool enableDebugDiagnostics = diff --git a/tests/InputBox.Tests/README.md b/tests/InputBox.Tests/README.md index 0086e78..8b1efce 100644 --- a/tests/InputBox.Tests/README.md +++ b/tests/InputBox.Tests/README.md @@ -45,8 +45,8 @@ | `SystemHelperTests` | `SystemHelper.EvaluateGamescopeEnvironment` 在不同 DISPLAY、XDG_CURRENT_DESKTOP 與 DESKTOP_SESSION 環境變數組合下的 Gamescope 環境偵測回歸保護 | 11 | | `TaskExtensionsTests` | `TaskExtensions` CTS 擴充方法與生命週期連結保護 | 12 | | `VibrationPatternsTests` | `VibrationPatterns` 與方向性震動設定、語意情境解析、能力感知的多段式微震動序列,以及歷程滾輪阻尼感、字數上限硬牆、震動強度預覽、右搖桿選取粒度、組合鍵進入提示與喚起握手回饋的回歸保護 | 37 | -| `VibrationSafetyLimiterTests` | `VibrationSafetyLimiter` 熱保護、Duty Cycle 限制器與極端邊界保護 | 8 | -| **合計** | | **397** | +| `VibrationSafetyLimiterTests` | `VibrationSafetyLimiter` 熱保護、Duty Cycle 限制器與極端邊界保護;馬達數量熱成本倍率正規化,以及所有內建震動模式在冷啟動下不得被拒絕、單次超出預算改為降強度的回歸保護 | 16 | +| **合計** | | **405** | ## 二、執行方式 🚀 diff --git a/tests/InputBox.Tests/VibrationSafetyLimiterTests.cs b/tests/InputBox.Tests/VibrationSafetyLimiterTests.cs index 3895773..6511ca8 100644 --- a/tests/InputBox.Tests/VibrationSafetyLimiterTests.cs +++ b/tests/InputBox.Tests/VibrationSafetyLimiterTests.cs @@ -1,4 +1,6 @@ -using InputBox.Core.Input; +using InputBox.Core.Feedback; +using InputBox.Core.Input; +using System.Reflection; using Xunit; namespace InputBox.Tests; @@ -246,4 +248,123 @@ public void TryApply_WhenStrengthIsMaxValue_ShouldClampToSafetyCeiling() Assert.True(accepted); Assert.InRange(adjustedStrength, 1, 60_000); } -} \ No newline at end of file + + /// + /// 馬達數量倍率應以雙主馬達為基準正規化,並限制在 1 到 4 顆馬達的範圍內。 + /// + [Theory] + [InlineData(0, 0.5)] + [InlineData(1, 0.5)] + [InlineData(2, 1.0)] + [InlineData(4, 2.0)] + [InlineData(8, 2.0)] + public void GetMotorThermalCostMultiplier_NormalizesToDualMotorBaseline(int motorCount, double expected) + { + Assert.Equal(expected, VibrationSafetyLimiter.GetMotorThermalCostMultiplier(motorCount)); + } + + /// + /// 回歸保護:限制器剛啟動、尚無熱負載時,所有內建震動模式在各種強度與馬達數量下都必須能送出, + /// 且強度不得低於 Normal 優先級保底比例。先前「複製成功」等重要回饋會因單次熱成本超過硬上限而被直接拒絕。 + /// + [Fact] + public void TryApply_AllBuiltInPatternsFromColdState_AreNeverBlocked() + { + FieldInfo[] patternFields = [.. typeof(VibrationPatterns) + .GetFields(BindingFlags.Public | BindingFlags.Static) + .Where(f => f.FieldType == typeof(VibrationProfile))]; + + Assert.NotEmpty(patternFields); + + float[] intensities = [0.3f, 0.7f, 1.0f]; + int[] motorCounts = [1, 2, 4]; + + foreach (FieldInfo field in patternFields) + { + VibrationProfile pattern = (VibrationProfile)field.GetValue(null)!; + + foreach (float intensity in intensities) + { + VibrationProfile profile = pattern.ApplyIntensityMultiplier(intensity); + + if (profile.Strength == 0) + { + continue; + } + + foreach (int motorCount in motorCounts) + { + var limiter = new VibrationSafetyLimiter(); + + bool accepted = limiter.TryApplyWithDiagnostics( + profile.Strength, + profile.Duration, + VibrationPriority.Normal, + nowMs: 1, + out ushort adjustedStrength, + out _, + out VibrationLimiterDebugInfo diagnostics, + thermalCostMultiplier: VibrationSafetyLimiter.GetMotorThermalCostMultiplier(motorCount)); + + Assert.True( + accepted, + $"{field.Name} intensity={intensity} motors={motorCount} flags={diagnostics.Flags}"); + Assert.True( + adjustedStrength >= (Math.Min((int)profile.Strength, 60_000) * 0.35) - 1, + $"{field.Name} intensity={intensity} motors={motorCount} strength={adjustedStrength}"); + } + } + } + } + + /// + /// 單次請求超出剩餘熱預算時,Normal 優先級應降低強度送出並標記 ScaledByThermalOverflow,而不是直接拒絕。 + /// + [Fact] + public void TryApply_Normal_WhenSingleRequestExceedsBudget_ShouldScaleInsteadOfBlock() + { + var limiter = new VibrationSafetyLimiter(); + + bool accepted = limiter.TryApplyWithDiagnostics( + 60_000, + 150, + VibrationPriority.Normal, + nowMs: 1, + out ushort adjustedStrength, + out _, + out VibrationLimiterDebugInfo diagnostics, + thermalCostMultiplier: VibrationSafetyLimiter.GetMotorThermalCostMultiplier(4)); + + Assert.True(accepted); + Assert.True(adjustedStrength < 60_000); + Assert.True(diagnostics.Flags.HasFlag(VibrationLimiterFlags.ScaledByThermalOverflow)); + Assert.True(diagnostics.ThermalLoad <= 180.0 * 1.05); + } + + /// + /// 熱負載已超過溢出上限、剩餘預算不足以維持保底強度時,Normal 優先級仍應被拒絕以保護馬達。 + /// + [Fact] + public void TryApply_Normal_WhenAlreadyOverheated_ShouldStillBeBlocked() + { + var limiter = new VibrationSafetyLimiter(thermalTauMs: 1_000_000); + + // Critical 不受溢出拒絕限制,用來把熱負載推高到溢出上限之上。 + for (int i = 0; i < 10; i++) + { + limiter.TryApply(60_000, 200, VibrationPriority.Critical, nowMs: 1 + i, out _, out _); + } + + bool accepted = limiter.TryApplyWithDiagnostics( + 60_000, + 200, + VibrationPriority.Normal, + nowMs: 20, + out _, + out _, + out VibrationLimiterDebugInfo diagnostics); + + Assert.False(accepted); + Assert.True(diagnostics.Flags.HasFlag(VibrationLimiterFlags.BlockedByThermalOverflow)); + } +} From 54afe81d4ed71f5829a5d6fcb9ce72bdcde7acc6 Mon Sep 17 00:00:00 2001 From: perditavojo <117562794+perditavojo@users.noreply.github.com> Date: Sun, 27 Sep 2026 06:57:13 +0800 Subject: [PATCH 10/17] =?UTF-8?q?docs(safety):=20=E6=98=8E=E6=96=87?= =?UTF-8?q?=E8=A8=98=E8=BC=89=E5=89=8D=E6=99=AF=E8=A6=96=E7=AA=97=E8=BF=94?= =?UTF-8?q?=E5=9B=9E=E8=88=87=20AttachThreadInput=20=E7=9A=84=E5=85=81?= =?UTF-8?q?=E8=A8=B1=E7=AF=84=E5=9C=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit WindowFocusService 在返回前一個視窗時會暫時以 AttachThreadInput 連結執行緒輸入佇列。 它不送出任何輸入,未違反既有紅線,但未寫明理由容易在日後審查時被誤判。 - 說明返回目標只來自使用者先前的前景視窗,唯一的程序判斷是排除 InputBox 自己,不辨識特定應用程式。 - 列出允許的 Win32 呼叫,並要求 AttachThreadInput 必須在 finally 中解除。 - 明訂此路徑不得加入模擬輸入、輸入訊息、自動貼上或依應用程式身分分流的邏輯。 - 補上程式內重啟只可授權新 InputBox 程序前景的限制。 Co-Authored-By: Claude Opus 5.5 --- docs/engineering/git-commit-safety.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/docs/engineering/git-commit-safety.md b/docs/engineering/git-commit-safety.md index 6ca879f..8db9336 100644 --- a/docs/engineering/git-commit-safety.md +++ b/docs/engineering/git-commit-safety.md @@ -5,6 +5,11 @@ - **零模擬/同步**:行為僅止於「複製至剪貼簿」,不模擬輸入至其他視窗。 - **零自動化**:禁止實作自動化遊戲行為 (如自動連點、自動施法)。 - **零偵測性**:禁止主動偵測特定第三方應用程式。 +- **前景視窗返回的允許範圍**:`WindowFocusService` 只把焦點還給使用者呼叫 InputBox 前的前景視窗;目標由當下前景視窗捕捉,唯一的程序判斷是排除 InputBox 自己,不依程序名稱、視窗標題或類別辨識任何特定應用程式。 + - 允許的 Win32 呼叫僅限 `ShowWindow`(且只在視窗最小化時還原)、`BringWindowToTop`、`SetForegroundWindow`、`SetFocus`,以及切換瞬間暫時使用 `AttachThreadInput` 連結執行緒輸入佇列,並必須在 `finally` 中解除。 + - `AttachThreadInput` 只用於取得切換前景的權限,不送出任何按鍵、滑鼠或視窗訊息,也不讀寫對方程序的記憶體,因此不屬於模擬輸入或修改第三方程式行為。 + - 不得在此路徑加入 `SendInput`、`keybd_event`、`PostMessage`/`SendMessage` 輸入訊息、剪貼簿自動貼上或任何依應用程式身分分流的邏輯。 + - 程式內重啟只可對新啟動的 InputBox 程序呼叫 `AllowSetForegroundWindow(PID)`,不得使用 `ASFW_ANY` 開放給所有程序(無法啟動新程序的退回路徑除外)。 ## 2. 外部合規基準與 ToS 驗證 (ToS Verification) **代理人必須在變更任何核心輸入/輸出邏輯前,使用網頁抓取工具擷取並分析以下網址的最新內容(例如 Copilot:`fetch_webpage`;Gemini:`web_fetch`),確保設計不違反服務條款:** From 37fe66749d63f00baebbd98ff402772345c6fba5 Mon Sep 17 00:00:00 2001 From: perditavojo <117562794+perditavojo@users.noreply.github.com> Date: Sun, 27 Sep 2026 07:00:05 +0800 Subject: [PATCH 11/17] =?UTF-8?q?refactor(gamepad):=20=E5=B0=87=E5=85=A9?= =?UTF-8?q?=E5=80=8B=E5=BE=8C=E7=AB=AF=E7=9A=84=20EMA=20=E5=81=8F=E7=A7=BB?= =?UTF-8?q?=E8=A3=9C=E5=84=9F=E4=BF=82=E6=95=B8=E8=88=87=E5=85=AC=E5=BC=8F?= =?UTF-8?q?=E9=9B=86=E4=B8=AD=E5=85=B1=E7=94=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit gamepad-api 要求 XInput 與 GameInput 的 EMA 平滑係數完全相同,但原本兩個後端各自宣告 8 個常數與相同的學習率公式, 一致性只靠文件規則維持,日後改一邊忘了另一邊就會造成行為分歧。 - 新增 GamepadBiasSmoothing,集中 8 個平滑係數與 ComputeAdaptiveSmoothing 公式;已確認兩邊原本數值完全相同,行為不變。 - 兩個後端移除重複常數,只保留與自身數值尺度相關的 BiasAdaptiveErrorRange 與學習閾值。 - 新增 GamepadBiasSmoothingTests(5 項),並更新 gamepad-api 規範與測試 README。 HandleRepeat 的差異僅在按鈕列舉型別與日誌來源,計時已共用 GamepadRepeatStateMachine; 合併剩餘派送程式碼需統一兩個後端的方向型別與基底類別,風險高於收益,本次不處理。 Co-Authored-By: Claude Opus 5.5 --- docs/engineering/gamepad-api.md | 4 +- .../Core/Input/GameInputGamepadController.cs | 68 +++-------------- .../Core/Input/GamepadBiasSmoothing.cs | 73 +++++++++++++++++++ .../Core/Input/XInputGamepadController.cs | 65 +++-------------- .../GamepadBiasSmoothingTests.cs | 56 ++++++++++++++ tests/InputBox.Tests/README.md | 3 +- 6 files changed, 157 insertions(+), 112 deletions(-) create mode 100644 src/InputBox/Core/Input/GamepadBiasSmoothing.cs create mode 100644 tests/InputBox.Tests/GamepadBiasSmoothingTests.cs diff --git a/docs/engineering/gamepad-api.md b/docs/engineering/gamepad-api.md index 7004f3d..2ca2bfb 100644 --- a/docs/engineering/gamepad-api.md +++ b/docs/engineering/gamepad-api.md @@ -47,7 +47,7 @@ ### 4.1 演算法結構 -- **自適應 EMA**:學習率公式為 `α = base + (max − base) × clamp(|error| / BiasAdaptiveErrorRange, 0, 1)`,誤差越大學習率越高,越快追蹤到真實偏移。 +- **自適應 EMA**:學習率公式為 `α = base + (max − base) × clamp(|error| / BiasAdaptiveErrorRange, 0, 1)`,誤差越大學習率越高,越快追蹤到真實偏移。平滑係數與公式只在 `GamepadBiasSmoothing` 維護,兩個後端不得各自宣告副本,只能提供與自身數值尺度對應的 `BiasAdaptiveErrorRange`。 - **四軸追蹤**:必須對左搖桿 X/Y 與右搖桿 X/Y 共四軸分別維護 `_leftStickBiasX/Y`、`_rightStickBiasX/Y`。 - **右搖桿 Y 軸**:右搖桿 Y 偏移會被學習並**校正用於診斷**(`correctedRightThumbY` 出現於 Health Log 與 Ghost Log),但**不觸發任何導航事件**,亦不納入 `hasSignificantInput` 或 `ShouldForceReleaseDirectionalRepeat` 判斷。 @@ -60,7 +60,7 @@ XInput 以 `short` 範圍 (±32767) 運作;GameInput 以 float `[-1.0, 1.0]` |---|---|---| | `BiasAdaptiveErrorRange` | `1638f` (≈ 0.05 × 32767) | `0.05f` | | `LeftStickBiasLearningThreshold` | `9000` (≈ 0.275 × 32767) | `0.28f` | -| EMA 平滑係數 | 與 GameInput **完全相同** | 與 XInput **完全相同** | +| EMA 平滑係數與學習率公式 | 共用 `GamepadBiasSmoothing` | 共用 `GamepadBiasSmoothing` | ### 4.3 D-Pad 機械耦合防污閘門 diff --git a/src/InputBox/Core/Input/GameInputGamepadController.cs b/src/InputBox/Core/Input/GameInputGamepadController.cs index ac922bb..096c82a 100644 --- a/src/InputBox/Core/Input/GameInputGamepadController.cs +++ b/src/InputBox/Core/Input/GameInputGamepadController.cs @@ -336,56 +336,9 @@ internal sealed partial class GameInputGamepadController : IGamepadController private const int MechanismIdleResetFrames = 120; #endif - // ── 自適應 EMA 係數(Adaptive Exponential Moving Average)──────────────── - // 設計原則:每個軸保有獨立的「基礎值」與「最大值」。 - // • 當估計誤差(rawValue − currentBias)落在 BiasAdaptiveErrorRange 以內時, - // 學習率從 Base 線性插值至 Max,誤差越大學習越快(快速收斂)。 - // • 當誤差接近 0 時,退回 Base(保守維持),避免把有效輸入誤學成硬體偏移。 - // • 不同控制器硬體偏移量不同;此機制讓程式自動適應,無需手動調整。 - - /// - /// 左搖桿 X 軸:偏移估計的最低保守學習率(誤差接近 0 時使用)。 - /// - private const float LeftStickBiasXBaseSmoothing = 0.03f; - - /// - /// 左搖桿 X 軸:偏移估計的最高學習率(誤差達到 BiasAdaptiveErrorRange 時使用)。 - /// Log 顯示 biasLx 在 D-Pad 操作期間漂移幅度大,Max 值不宜過高以防誤學方向輸入。 - /// - private const float LeftStickBiasXMaxSmoothing = 0.15f; - - /// - /// 左搖桿 Y 軸:偏移估計的最低保守學習率。 - /// - private const float LeftStickBiasYBaseSmoothing = 0.03f; - - /// - /// 左搖桿 Y 軸:偏移估計的最高學習率。 - /// Log 顯示 biasLy 恆在 ±0.009 以內,目標穩定,可略低於 X 軸 Max。 - /// - private const float LeftStickBiasYMaxSmoothing = 0.12f; - - /// - /// 右搖桿 X 軸:偏移估計的最低保守學習率。 - /// - private const float RightStickBiasBaseSmoothing = 0.05f; - - /// - /// 右搖桿 X 軸:偏移估計的最高學習率。 - /// 右搖桿無 D-Pad 閘門,低 Max 可防止快速劃過中立區時累積偏移; - /// Warm-up 50 次後收斂率 ≈ 97.2%,起始收斂不受影響。 - /// - private const float RightStickBiasMaxSmoothing = 0.07f; - - /// - /// 右搖桿 Y 軸:偏移估計的最低保守學習率。 - /// - private const float RightStickBiasYBaseSmoothing = 0.05f; - - /// - /// 右搖桿 Y 軸:偏移估計的最高學習率。與 RX 相同理由,低 Max 防止壓力測試時逘速掟移。 - /// - private const float RightStickBiasYMaxSmoothing = 0.07f; + // ── 自適應 EMA 偏移補償 ──────────────────────────────────────────────── + // 平滑係數與公式集中於 GamepadBiasSmoothing,由 XInput 與 GameInput 兩路共用,確保行為一致; + // 本類別只保留與輸入數值尺度相關的誤差範圍與學習閾值。 /// /// 觸發全速學習的誤差閾值(偏移誤差達此值時使用最大係數)。 @@ -2237,28 +2190,28 @@ private void UpdateStickBias( { float errorX = rawLeftThumbX - _leftStickBiasX; _leftStickBiasX += errorX * ComputeAdaptiveBiasSmoothing( - errorX, LeftStickBiasXBaseSmoothing, LeftStickBiasXMaxSmoothing); + errorX, GamepadBiasSmoothing.LeftStickBiasXBaseSmoothing, GamepadBiasSmoothing.LeftStickBiasXMaxSmoothing); } if (!isDPadActive && MathF.Abs(rawLeftThumbY) <= LeftStickBiasLearningThreshold) { float errorY = rawLeftThumbY - _leftStickBiasY; _leftStickBiasY += errorY * ComputeAdaptiveBiasSmoothing( - errorY, LeftStickBiasYBaseSmoothing, LeftStickBiasYMaxSmoothing); + errorY, GamepadBiasSmoothing.LeftStickBiasYBaseSmoothing, GamepadBiasSmoothing.LeftStickBiasYMaxSmoothing); } if (MathF.Abs(rawRightThumbX) <= LeftStickBiasLearningThreshold) { float errorRX = rawRightThumbX - _rightStickBiasX; _rightStickBiasX += errorRX * ComputeAdaptiveBiasSmoothing( - errorRX, RightStickBiasBaseSmoothing, RightStickBiasMaxSmoothing); + errorRX, GamepadBiasSmoothing.RightStickBiasBaseSmoothing, GamepadBiasSmoothing.RightStickBiasMaxSmoothing); } if (MathF.Abs(rawRightThumbY) <= LeftStickBiasLearningThreshold) { float errorRY = rawRightThumbY - _rightStickBiasY; _rightStickBiasY += errorRY * ComputeAdaptiveBiasSmoothing( - errorRY, RightStickBiasYBaseSmoothing, RightStickBiasYMaxSmoothing); + errorRY, GamepadBiasSmoothing.RightStickBiasYBaseSmoothing, GamepadBiasSmoothing.RightStickBiasYMaxSmoothing); } } @@ -2275,8 +2228,11 @@ private static float ComputeAdaptiveBiasSmoothing( float baseSmoothing, float maxSmoothing) { - float t = Math.Clamp(MathF.Abs(error) / BiasAdaptiveErrorRange, 0f, 1f); - return baseSmoothing + (maxSmoothing - baseSmoothing) * t; + return GamepadBiasSmoothing.ComputeAdaptiveSmoothing( + error, + BiasAdaptiveErrorRange, + baseSmoothing, + maxSmoothing); } /// diff --git a/src/InputBox/Core/Input/GamepadBiasSmoothing.cs b/src/InputBox/Core/Input/GamepadBiasSmoothing.cs new file mode 100644 index 0000000..a31fd2b --- /dev/null +++ b/src/InputBox/Core/Input/GamepadBiasSmoothing.cs @@ -0,0 +1,73 @@ +namespace InputBox.Core.Input; + +/// +/// XInput 與 GameInput 共用的自適應 EMA 搖桿偏移補償係數與學習率公式 +/// +/// +/// 每個軸保有獨立的「基礎值」與「最大值」:估計誤差(原始值 − 目前偏移)落在誤差範圍內時, +/// 學習率由基礎值線性插值至最大值,誤差越大收斂越快;誤差接近 0 時退回基礎值,避免把有效輸入誤學成硬體偏移。 +/// 兩個後端的輸入數值尺度不同(XInput 為 short、GameInput 為 -1~1 浮點數), +/// 因此誤差範圍由各後端自行提供;平滑係數則必須完全一致,集中於此避免兩邊各自漂移。 +/// +internal static class GamepadBiasSmoothing +{ + /// + /// 左搖桿 X 軸:偏移估計的最低保守學習率(誤差接近 0 時使用)。 + /// + public const float LeftStickBiasXBaseSmoothing = 0.03f; + + /// + /// 左搖桿 X 軸:偏移估計的最高學習率(誤差達到誤差範圍時使用)。 + /// + public const float LeftStickBiasXMaxSmoothing = 0.15f; + + /// + /// 左搖桿 Y 軸:偏移估計的最低保守學習率。 + /// + public const float LeftStickBiasYBaseSmoothing = 0.03f; + + /// + /// 左搖桿 Y 軸:偏移估計的最高學習率。 + /// + public const float LeftStickBiasYMaxSmoothing = 0.12f; + + /// + /// 右搖桿 X 軸:偏移估計的最低保守學習率。 + /// + public const float RightStickBiasBaseSmoothing = 0.05f; + + /// + /// 右搖桿 X 軸:偏移估計的最高學習率。 + /// 右搖桿無 D-Pad 閘門,低最大值可防止快速劃過中立區時累積偏移。 + /// + public const float RightStickBiasMaxSmoothing = 0.07f; + + /// + /// 右搖桿 Y 軸:偏移估計的最低保守學習率。 + /// + public const float RightStickBiasYBaseSmoothing = 0.05f; + + /// + /// 右搖桿 Y 軸:偏移估計的最高學習率。 + /// + public const float RightStickBiasYMaxSmoothing = 0.07f; + + /// + /// 依偏移誤差計算自適應學習率:α = base + (max − base) × clamp(|error| / errorRange, 0, 1)。 + /// + /// 目前估計誤差(與 使用相同尺度)。 + /// 觸發最大學習率的誤差範圍;必須大於 0。 + /// 誤差接近 0 時使用的最低學習率。 + /// 誤差達到範圍上限時使用的最高學習率。 + /// 本幀使用的學習率。 + public static float ComputeAdaptiveSmoothing( + float error, + float errorRange, + float baseSmoothing, + float maxSmoothing) + { + float t = Math.Clamp(MathF.Abs(error) / errorRange, 0f, 1f); + + return baseSmoothing + (maxSmoothing - baseSmoothing) * t; + } +} diff --git a/src/InputBox/Core/Input/XInputGamepadController.cs b/src/InputBox/Core/Input/XInputGamepadController.cs index eed7e8a..5f8e383 100644 --- a/src/InputBox/Core/Input/XInputGamepadController.cs +++ b/src/InputBox/Core/Input/XInputGamepadController.cs @@ -276,53 +276,9 @@ internal sealed partial class XInputGamepadController : IGamepadController /// private const int MappedDirectionSuppressCooldownFrames = 12; - // ── 自適應 EMA 係數(Adaptive Exponential Moving Average)──────────────── - // 設計原則:每個軸保有獨立的「基礎值」與「最大值」。 - // • 當估計誤差(rawValue − currentBias)落在 BiasAdaptiveErrorRange 以內時, - // 學習率從 Base 線性插值至 Max,誤差越大學習越快(快速收斂)。 - // • 當誤差接近 0 時,退回 Base(保守維持),避免把有效輸入誤學成硬體偏移。 - // • 係數與 GameInputGamepadController 對齊,確保兩路控制器行為一致。 - - /// - /// 左搖桿 X 軸:偏移估計的最低保守學習率(誤差接近 0 時使用)。 - /// - private const float LeftStickBiasXBaseSmoothing = 0.03f; - - /// - /// 左搖桿 X 軸:偏移估計的最高學習率(誤差達到 BiasAdaptiveErrorRange 時使用)。 - /// - private const float LeftStickBiasXMaxSmoothing = 0.15f; - - /// - /// 左搖桿 Y 軸:偏移估計的最低保守學習率。 - /// - private const float LeftStickBiasYBaseSmoothing = 0.03f; - - /// - /// 左搖桿 Y 軸:偏移估計的最高學習率。 - /// - private const float LeftStickBiasYMaxSmoothing = 0.12f; - - /// - /// 右搖桿 X 軸:偏移估計的最低保守學習率。 - /// - private const float RightStickBiasBaseSmoothing = 0.05f; - - /// - /// 右搖桿 X 軸:偏移估計的最高學習率。 - /// 右搖桿無 D-Pad 閘門,低 Max 可防止快速劃過中立區時累積偏移。 - /// - private const float RightStickBiasMaxSmoothing = 0.07f; - - /// - /// 右搖桿 Y 軸:偏移估計的最低保守學習率。 - /// - private const float RightStickBiasYBaseSmoothing = 0.05f; - - /// - /// 右搖桿 Y 軸:偏移估計的最高學習率。 - /// - private const float RightStickBiasYMaxSmoothing = 0.07f; + // ── 自適應 EMA 偏移補償 ──────────────────────────────────────────────── + // 平滑係數與公式集中於 GamepadBiasSmoothing,由 XInput 與 GameInput 兩路共用,確保行為一致; + // 本類別只保留與輸入數值尺度相關的誤差範圍與學習閾值。 /// /// 觸發全速學習的誤差閾值(short 尺度;對應 float 空間的 0.05,即 0.05 × 32767 ≈ 1638)。 @@ -1334,28 +1290,28 @@ private void UpdateStickBias( { float errorLX = rawLeftThumbX - _leftStickBiasX; _leftStickBiasX += errorLX * ComputeAdaptiveBiasSmoothing( - errorLX, LeftStickBiasXBaseSmoothing, LeftStickBiasXMaxSmoothing); + errorLX, GamepadBiasSmoothing.LeftStickBiasXBaseSmoothing, GamepadBiasSmoothing.LeftStickBiasXMaxSmoothing); } if (!isDPadActive && Math.Abs((int)rawLeftThumbY) <= LeftStickBiasLearningThreshold) { float errorLY = rawLeftThumbY - _leftStickBiasY; _leftStickBiasY += errorLY * ComputeAdaptiveBiasSmoothing( - errorLY, LeftStickBiasYBaseSmoothing, LeftStickBiasYMaxSmoothing); + errorLY, GamepadBiasSmoothing.LeftStickBiasYBaseSmoothing, GamepadBiasSmoothing.LeftStickBiasYMaxSmoothing); } if (Math.Abs((int)rawRightThumbX) <= LeftStickBiasLearningThreshold) { float errorRX = rawRightThumbX - _rightStickBiasX; _rightStickBiasX += errorRX * ComputeAdaptiveBiasSmoothing( - errorRX, RightStickBiasBaseSmoothing, RightStickBiasMaxSmoothing); + errorRX, GamepadBiasSmoothing.RightStickBiasBaseSmoothing, GamepadBiasSmoothing.RightStickBiasMaxSmoothing); } if (Math.Abs((int)rawRightThumbY) <= LeftStickBiasLearningThreshold) { float errorRY = rawRightThumbY - _rightStickBiasY; _rightStickBiasY += errorRY * ComputeAdaptiveBiasSmoothing( - errorRY, RightStickBiasYBaseSmoothing, RightStickBiasYMaxSmoothing); + errorRY, GamepadBiasSmoothing.RightStickBiasYBaseSmoothing, GamepadBiasSmoothing.RightStickBiasYMaxSmoothing); } } @@ -1372,8 +1328,11 @@ private static float ComputeAdaptiveBiasSmoothing( float baseSmoothing, float maxSmoothing) { - float t = Math.Clamp(MathF.Abs(error) / BiasAdaptiveErrorRange, 0f, 1f); - return baseSmoothing + (maxSmoothing - baseSmoothing) * t; + return GamepadBiasSmoothing.ComputeAdaptiveSmoothing( + error, + BiasAdaptiveErrorRange, + baseSmoothing, + maxSmoothing); } /// diff --git a/tests/InputBox.Tests/GamepadBiasSmoothingTests.cs b/tests/InputBox.Tests/GamepadBiasSmoothingTests.cs new file mode 100644 index 0000000..a5922c7 --- /dev/null +++ b/tests/InputBox.Tests/GamepadBiasSmoothingTests.cs @@ -0,0 +1,56 @@ +using InputBox.Core.Input; +using Xunit; + +namespace InputBox.Tests; + +/// +/// 驗證 XInput 與 GameInput 共用的自適應 EMA 學習率公式。 +/// +public sealed class GamepadBiasSmoothingTests +{ + /// + /// 誤差為 0 時應使用最低保守學習率,避免把有效輸入誤學成硬體偏移。 + /// + [Fact] + public void ComputeAdaptiveSmoothing_ZeroError_ReturnsBaseSmoothing() + { + float alpha = GamepadBiasSmoothing.ComputeAdaptiveSmoothing(0f, 0.05f, 0.03f, 0.15f); + + Assert.Equal(0.03f, alpha, 0.0001f); + } + + /// + /// 誤差達到或超過範圍時應使用最高學習率,且正負誤差結果相同。 + /// + [Theory] + [InlineData(0.05f)] + [InlineData(-0.05f)] + [InlineData(0.5f)] + public void ComputeAdaptiveSmoothing_ErrorAtOrBeyondRange_ReturnsMaxSmoothing(float error) + { + float alpha = GamepadBiasSmoothing.ComputeAdaptiveSmoothing(error, 0.05f, 0.03f, 0.15f); + + Assert.Equal(0.15f, alpha, 0.0001f); + } + + /// + /// 相同比例的誤差在 XInput(short 尺度)與 GameInput(浮點尺度)下必須得到相同學習率,確保兩個後端行為一致。 + /// + [Fact] + public void ComputeAdaptiveSmoothing_SameRelativeErrorAcrossScales_ReturnsSameAlpha() + { + float xinputAlpha = GamepadBiasSmoothing.ComputeAdaptiveSmoothing( + 819f, + 1638f, + GamepadBiasSmoothing.LeftStickBiasXBaseSmoothing, + GamepadBiasSmoothing.LeftStickBiasXMaxSmoothing); + float gameInputAlpha = GamepadBiasSmoothing.ComputeAdaptiveSmoothing( + 0.025f, + 0.05f, + GamepadBiasSmoothing.LeftStickBiasXBaseSmoothing, + GamepadBiasSmoothing.LeftStickBiasXMaxSmoothing); + + Assert.Equal(xinputAlpha, gameInputAlpha, 0.0001f); + Assert.Equal(0.09f, gameInputAlpha, 0.0001f); + } +} diff --git a/tests/InputBox.Tests/README.md b/tests/InputBox.Tests/README.md index 8b1efce..e1b9715 100644 --- a/tests/InputBox.Tests/README.md +++ b/tests/InputBox.Tests/README.md @@ -23,6 +23,7 @@ | `GamepadControllerFactoryTests` | 控制器後端建立策略,驗證 XInput 預設路徑、GameInput 成功路徑,以及 GameInput 執行階段不可用時退避至 XInput | 3 | | `GamepadControllerPauseTests` | 控制器在 `Pause()` / `Resume()`、連線可用性語意、GameInput 讀取缺失斷線重列舉、裝置狀態過濾、震動停止安全性、`ClearAllEvents` 肩鍵釋放訂閱清除與原生對話框切換時的殘留輸入回歸保護 | 10 | | `GameInputDirectUsageTests` | `GameInputGamepadController` 直接使用 `InputWeave.GameInput` 遊戲控制器介面的守門、callback function pointer marshaling、官方 v3 按鍵位元、快照邊緣偵測、Release 日誌邊界、穩定裝置識別與震動參數保留 | 9 | +| `GamepadBiasSmoothingTests` | `GamepadBiasSmoothing` 自適應 EMA 學習率公式:零誤差用基礎值、超出範圍用最大值,以及 XInput 與 GameInput 不同數值尺度下結果一致 | 5 | | `GamepadCalibrationVisualizerMapperTests` | `GamepadCalibrationVisualizerMapper` 對校準視覺化座標限制、死區半徑換算、D-Pad 導覽防誤觸,以及雙搖桿狀態/控制器連線文案格式化的回歸保護 | 14 | | `GamepadEventBinderTests` | `GamepadEventBinder` 的 LB / RB / LT / RT 與肩鍵放開事件綁定回歸保護 | 1 | | `GamepadFaceButtonProfileTests` | `GamepadFaceButtonProfile` 的 Auto 解析、手動覆寫優先權、GameInput 裝置識別保留 VID/PID 時的 Sony/Nintendo 判斷,以及 Xbox / PlayStation / Nintendo 模式的按鍵標示、助記詞同步、資源化字串、主畫面說明文字、目前生效配置顯示、標題列提示、選單勾選邏輯與 PlayStation ○/× 確認模式回歸保護 | 25 | @@ -46,7 +47,7 @@ | `TaskExtensionsTests` | `TaskExtensions` CTS 擴充方法與生命週期連結保護 | 12 | | `VibrationPatternsTests` | `VibrationPatterns` 與方向性震動設定、語意情境解析、能力感知的多段式微震動序列,以及歷程滾輪阻尼感、字數上限硬牆、震動強度預覽、右搖桿選取粒度、組合鍵進入提示與喚起握手回饋的回歸保護 | 37 | | `VibrationSafetyLimiterTests` | `VibrationSafetyLimiter` 熱保護、Duty Cycle 限制器與極端邊界保護;馬達數量熱成本倍率正規化,以及所有內建震動模式在冷啟動下不得被拒絕、單次超出預算改為降強度的回歸保護 | 16 | -| **合計** | | **405** | +| **合計** | | **410** | ## 二、執行方式 🚀 From 935c49500bd5f43742bac5b0986e18a1159d42f7 Mon Sep 17 00:00:00 2001 From: perditavojo <117562794+perditavojo@users.noreply.github.com> Date: Sun, 27 Sep 2026 07:04:17 +0800 Subject: [PATCH 12/17] =?UTF-8?q?refactor(selection):=20=E5=B0=87=E5=8F=B3?= =?UTF-8?q?=E6=90=96=E6=A1=BF=E5=BB=B6=E4=BC=B8=E9=81=B8=E5=8F=96=E7=9A=84?= =?UTF-8?q?=E5=85=B1=E7=94=A8=E9=82=8F=E8=BC=AF=E9=9B=86=E4=B8=AD=E7=82=BA?= =?UTF-8?q?=20TextBox=20=E6=93=B4=E5=85=85=E6=96=B9=E6=B3=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 主視窗、數值輸入對話框與片語編輯對話框各有一份相同的右搖桿延伸選取程式碼: 單字跳轉目標計算(GetWordSelectionCaretTarget)、選取錨點與活動邊緣推算,以及 EM_SETSEL 反向選取後捲動。 - ControlExtensions 新增 GetWordJumpTarget、ResolveSelectionAnchor、SetSelectionWithActiveEdge。 - 三處呼叫端改用擴充方法並移除重複實作;各自的震動、報讀與選取回饋維持不變。 - 移除 MainForm.Gamepad 不再使用的 Interop using。 - 新增 TextBoxSelectionExtensionsTests(6 項),更新測試 README。 僅調整本程式自身文字方塊的選取計算,不涉及對其他視窗的輸入或輸出。 Co-Authored-By: Claude Opus 5.5 --- .../Core/Controls/NumericInputDialog.cs | 49 +-------- .../Core/Controls/PhraseEditDialog.cs | 45 +------- .../Core/Extensions/ControlExtensions.cs | 80 ++++++++++++++ src/InputBox/MainForm.Gamepad.cs | 62 ++--------- tests/InputBox.Tests/README.md | 3 +- .../TextBoxSelectionExtensionsTests.cs | 102 ++++++++++++++++++ 6 files changed, 199 insertions(+), 142 deletions(-) create mode 100644 tests/InputBox.Tests/TextBoxSelectionExtensionsTests.cs diff --git a/src/InputBox/Core/Controls/NumericInputDialog.cs b/src/InputBox/Core/Controls/NumericInputDialog.cs index b18fdb9..c63b449 100644 --- a/src/InputBox/Core/Controls/NumericInputDialog.cs +++ b/src/InputBox/Core/Controls/NumericInputDialog.cs @@ -755,28 +755,17 @@ private void ExpandSelection(bool forward) => this.SafeInvoke(() => return; } - // 當目前沒有選取範圍,或是目前的選取範圍與我們的錨點不匹配時,重新設定錨點。 - if (textBox.SelectionLength == 0 || - _rsSelectionAnchor == null || - (textBox.SelectionStart != _rsSelectionAnchor.Value && - textBox.SelectionStart + textBox.SelectionLength != _rsSelectionAnchor.Value)) - { - _rsSelectionAnchor = textBox.SelectionStart; - } + // 當目前沒有選取範圍,或是目前的選取範圍與我們的錨點不匹配時,重新設定錨點,並推算活動邊緣。 + (int anchor, int caret) = textBox.ResolveSelectionAnchor(_rsSelectionAnchor); - int anchor = _rsSelectionAnchor.Value; - - // 推算活動邊緣。 - int caret = (textBox.SelectionStart == anchor) ? - (anchor + textBox.SelectionLength) : - textBox.SelectionStart; + _rsSelectionAnchor = anchor; int direction = forward ? 1 : -1; bool wordGranularity = _gamepadController?.IsLeftShoulderHeld == true || _gamepadController?.IsRightShoulderHeld == true; int newCaret = wordGranularity ? - GetWordSelectionCaretTarget(textBox, caret, direction) : + textBox.GetWordJumpTarget(caret, direction > 0) : Math.Clamp(caret + direction, 0, textBox.TextLength); if (newCaret == caret) @@ -791,8 +780,7 @@ private void ExpandSelection(bool forward) => this.SafeInvoke(() => } // 使用 Win32 EM_SETSEL 設定選取範圍。 - User32.SendMessage(textBox.Handle, (uint)User32.WindowMessage.EM_SETSEL, anchor, newCaret); - textBox.ScrollToCaret(); + textBox.SetSelectionWithActiveEdge(anchor, newCaret); if (textBox.SelectionLength > 0) { @@ -841,33 +829,6 @@ private void PlaySelectionFeedback(int direction, bool wordGranularity) FeedbackService.PlaySelectionCue(wordGranularity, _selectionFeedbackBurstLevel); } - /// - /// 以現有的單字跳轉邏輯推算右搖桿在單字粒度下的選取目標位置。 - /// - /// 目標 TextBox。 - /// 目前游標位置(字元索引)。 - /// 方向;正值為向右,負值為向左。 - /// 跳轉後的游標目標位置(字元索引)。 - private static int GetWordSelectionCaretTarget(TextBox textBox, int caret, int direction) - { - int originalStart = textBox.SelectionStart; - int originalLength = textBox.SelectionLength; - - try - { - textBox.SelectionStart = Math.Clamp(caret, 0, textBox.TextLength); - textBox.SelectionLength = 0; - textBox.WordJump(direction > 0); - - return textBox.SelectionStart; - } - finally - { - textBox.SelectionStart = originalStart; - textBox.SelectionLength = originalLength; - } - } - /// /// 處理選取左向擴張 /// diff --git a/src/InputBox/Core/Controls/PhraseEditDialog.cs b/src/InputBox/Core/Controls/PhraseEditDialog.cs index 3d8f88a..75e02de 100644 --- a/src/InputBox/Core/Controls/PhraseEditDialog.cs +++ b/src/InputBox/Core/Controls/PhraseEditDialog.cs @@ -1679,25 +1679,16 @@ private void ExpandSelection(int direction) return; } - if (tb.SelectionLength == 0 || - _rsSelectionAnchor == null || - (tb.SelectionStart != _rsSelectionAnchor.Value && - tb.SelectionStart + tb.SelectionLength != _rsSelectionAnchor.Value)) - { - _rsSelectionAnchor = tb.SelectionStart; - } + (int anchor, int caret) = tb.ResolveSelectionAnchor(_rsSelectionAnchor); - int anchor = _rsSelectionAnchor.Value, - caret = (tb.SelectionStart == anchor) ? - (anchor + tb.SelectionLength) : - tb.SelectionStart; + _rsSelectionAnchor = anchor; int safeDirection = Math.Sign(direction); bool wordGranularity = _gamepadController?.IsLeftShoulderHeld == true || _gamepadController?.IsRightShoulderHeld == true; int newCaret = wordGranularity ? - GetWordSelectionCaretTarget(tb, caret, safeDirection) : + tb.GetWordJumpTarget(caret, safeDirection > 0) : Math.Clamp(caret + safeDirection, 0, tb.TextLength); if (newCaret == caret) @@ -1712,8 +1703,7 @@ private void ExpandSelection(int direction) } // 使用 Win32 EM_SETSEL 正確設定選取範圍(含反向選取)。 - User32.SendMessage(tb.Handle, 0x00B1, anchor, newCaret); - tb.ScrollToCaret(); + tb.SetSelectionWithActiveEdge(anchor, newCaret); PlaySelectionFeedback(safeDirection, wordGranularity); } @@ -1874,33 +1864,6 @@ private void PlaySelectionFeedback(int direction, bool wordGranularity) FeedbackService.PlaySelectionCue(wordGranularity, burstLevel); } - /// - /// 以現有的單字跳轉邏輯推算右搖桿在單字粒度下的選取目標位置。 - /// - /// 目標 TextBox。 - /// 目前游標位置(字元索引)。 - /// 方向;正值為向右,負值為向左。 - /// 跳轉後的游標目標位置(字元索引)。 - private static int GetWordSelectionCaretTarget(TextBox textBox, int caret, int direction) - { - int originalStart = textBox.SelectionStart; - int originalLength = textBox.SelectionLength; - - try - { - textBox.SelectionStart = Math.Clamp(caret, 0, textBox.TextLength); - textBox.SelectionLength = 0; - textBox.WordJump(direction > 0); - - return textBox.SelectionStart; - } - finally - { - textBox.SelectionStart = originalStart; - textBox.SelectionLength = originalLength; - } - } - /// /// 控制器重新連線後恢復輪詢狀態。 /// diff --git a/src/InputBox/Core/Extensions/ControlExtensions.cs b/src/InputBox/Core/Extensions/ControlExtensions.cs index 46ce3d7..374153e 100644 --- a/src/InputBox/Core/Extensions/ControlExtensions.cs +++ b/src/InputBox/Core/Extensions/ControlExtensions.cs @@ -1,4 +1,5 @@ using InputBox.Core.Configuration; +using InputBox.Core.Interop; using InputBox.Core.Services; using System.Diagnostics; using System.Drawing.Drawing2D; @@ -739,6 +740,85 @@ public static void ResetThemeRecursive(this Control parent) UpdateRecursive(parent, Color.Empty, Color.Empty); } + /// + /// 在不改變目前選取範圍的前提下,計算從指定游標位置執行單字跳轉後的目標位置 + /// + /// 目標文字方塊。 + /// 起算的游標位置(字元索引)。 + /// 是否向右跳轉。 + /// 單字跳轉後的游標位置;文字方塊不可用時回傳原位置。 + public static int GetWordJumpTarget(this TextBox textBox, int caret, bool forward) + { + if (textBox == null || + textBox.IsDisposed) + { + return caret; + } + + int originalStart = textBox.SelectionStart; + int originalLength = textBox.SelectionLength; + + try + { + textBox.SelectionStart = Math.Clamp(caret, 0, textBox.TextLength); + textBox.SelectionLength = 0; + textBox.WordJump(forward); + + return textBox.SelectionStart; + } + finally + { + textBox.SelectionStart = originalStart; + textBox.SelectionLength = originalLength; + } + } + + /// + /// 解析延伸選取時的錨點與目前活動邊緣(游標所在端) + /// + /// + /// 目前沒有選取範圍,或選取範圍兩端都不等於既有錨點(例如使用者以滑鼠或鍵盤改變過選取)時, + /// 以目前選取起點重新作為錨點。WinForms 的 永遠是較小的索引, + /// 因此起點等於錨點時活動邊緣在右側,否則在左側。 + /// + /// 目標文字方塊。 + /// 呼叫端保存的既有錨點;尚未建立時為 null。 + /// 本次應使用的錨點與活動邊緣。 + public static (int Anchor, int ActiveEdge) ResolveSelectionAnchor(this TextBox textBox, int? currentAnchor) + { + int selectionStart = textBox.SelectionStart; + int selectionLength = textBox.SelectionLength; + + int anchor = selectionLength == 0 || + currentAnchor == null || + (selectionStart != currentAnchor.Value && + selectionStart + selectionLength != currentAnchor.Value) ? + selectionStart : + currentAnchor.Value; + + int activeEdge = selectionStart == anchor ? + anchor + selectionLength : + selectionStart; + + return (anchor, activeEdge); + } + + /// + /// 以錨點與活動邊緣設定選取範圍(支援反向選取),並捲動讓活動邊緣保持可見 + /// + /// + /// 透過 EM_SETSEL 設定,wParam 為錨點、lParam 為活動邊緣,讓視覺游標跟隨活動邊緣並支援反向縮減; + /// 捲動可避免選取延伸到可視範圍外時,TextBox 在邊界繪製選取底線殘影。 + /// + /// 目標文字方塊。 + /// 選取錨點。 + /// 選取活動邊緣。 + public static void SetSelectionWithActiveEdge(this TextBox textBox, int anchor, int activeEdge) + { + User32.SendMessage(textBox.Handle, (uint)User32.WindowMessage.EM_SETSEL, anchor, activeEdge); + textBox.ScrollToCaret(); + } + /// /// 執行單字跳轉邏輯(智慧偵測空白、標點符號、字元類型轉換,支援全形與 IME 情境) /// diff --git a/src/InputBox/MainForm.Gamepad.cs b/src/InputBox/MainForm.Gamepad.cs index 8a03f16..7fdfaa6 100644 --- a/src/InputBox/MainForm.Gamepad.cs +++ b/src/InputBox/MainForm.Gamepad.cs @@ -2,7 +2,6 @@ using InputBox.Core.Extensions; using InputBox.Core.Feedback; using InputBox.Core.Input; -using InputBox.Core.Interop; using InputBox.Core.Services; using InputBox.Core.Utilities; using InputBox.Resources; @@ -1630,38 +1629,6 @@ private void PlaySelectionFeedback(int direction, bool wordGranularity) FeedbackService.PlaySelectionCue(wordGranularity, burstLevel); } - /// - /// 以現有的單字跳轉邏輯推算右搖桿在單字粒度下的選取目標位置。 - /// - /// 目前游標位置(字元索引)。 - /// 跳轉方向;正值為向右,負值為向左。 - /// 跳轉後的游標位置。 - private int GetWordSelectionCaretTarget(int caret, int direction) - { - if (TBInput == null || - TBInput.IsDisposed) - { - return caret; - } - - int originalStart = TBInput.SelectionStart; - int originalLength = TBInput.SelectionLength; - - try - { - TBInput.SelectionStart = Math.Clamp(caret, 0, TBInput.TextLength); - TBInput.SelectionLength = 0; - TBInput.WordJump(direction > 0); - - return TBInput.SelectionStart; - } - finally - { - TBInput.SelectionStart = originalStart; - TBInput.SelectionLength = originalLength; - } - } - /// /// 取得資源字串;若缺少翻譯則回退到預設文字。 /// @@ -2543,23 +2510,11 @@ private void ExpandSelection(int direction) return; } - // 當目前沒有選取範圍,或是目前的選取範圍與我們的錨點不匹配時,重新設定錨點。 + // 當目前沒有選取範圍,或是目前的選取範圍與我們的錨點不匹配時,重新設定錨點,並推算目前的活動邊緣(Caret)。 // 這能確保手動點擊或鍵盤選取後,RS 選取能從正確的位置開始。 - if (TBInput.SelectionLength == 0 || - _rsSelectionAnchor == null || - (TBInput.SelectionStart != _rsSelectionAnchor.Value && - TBInput.SelectionStart + TBInput.SelectionLength != _rsSelectionAnchor.Value)) - { - _rsSelectionAnchor = TBInput.SelectionStart; - } - - int anchor = _rsSelectionAnchor.Value; + (int anchor, int caret) = TBInput.ResolveSelectionAnchor(_rsSelectionAnchor); - // 推算目前的活動邊緣(Caret)。 - // WinForms SelectionStart 始終為較小的索引,因此若 Start 與錨點一致,則 Caret 在右側;否則 Caret 在左側。 - int caret = (TBInput.SelectionStart == anchor) ? - (anchor + TBInput.SelectionLength) : - TBInput.SelectionStart; + _rsSelectionAnchor = anchor; // 防禦性寫法:確保方向永遠只會是 -1、0 或 1,杜絕任何溢出造成的邏輯錯亂。 int safeDirection = Math.Sign(direction); @@ -2572,7 +2527,7 @@ private void ExpandSelection(int direction) } int newCaret = wordGranularity ? - GetWordSelectionCaretTarget(caret, safeDirection) : + TBInput.GetWordJumpTarget(caret, safeDirection > 0) : Math.Clamp(caret + safeDirection, 0, TBInput.TextLength); if (newCaret == caret) @@ -2582,13 +2537,8 @@ private void ExpandSelection(int direction) return; } - // 使用 Win32 EM_SETSEL 設定選取範圍。 - // wParam 為錨點,lParam 為活動邊緣。這能確保視覺上的游標(Caret)正確跟隨活動邊緣,並支援反向縮減。 - User32.SendMessage(TBInput.Handle, (uint)User32.WindowMessage.EM_SETSEL, anchor, newCaret); - - // 確保活動邊緣(Caret)保持在可視範圍內,避免選取延伸到畫面外時 - // Windows TextBox 在可視邊界處繪製藍色底線 artifact。 - TBInput.ScrollToCaret(); + // 以錨點與活動邊緣設定選取範圍,讓視覺游標跟隨活動邊緣並支援反向縮減,並保持活動邊緣可見。 + TBInput.SetSelectionWithActiveEdge(anchor, newCaret); // A11y:報讀目前選取的文字內容。 if (TBInput.SelectionLength > 0) diff --git a/tests/InputBox.Tests/README.md b/tests/InputBox.Tests/README.md index e1b9715..04fb0ec 100644 --- a/tests/InputBox.Tests/README.md +++ b/tests/InputBox.Tests/README.md @@ -45,9 +45,10 @@ | `RestartRequestDeciderTests` | 手動重啟與設定變更兩種入口的確認策略回歸保護 | 3 | | `SystemHelperTests` | `SystemHelper.EvaluateGamescopeEnvironment` 在不同 DISPLAY、XDG_CURRENT_DESKTOP 與 DESKTOP_SESSION 環境變數組合下的 Gamescope 環境偵測回歸保護 | 11 | | `TaskExtensionsTests` | `TaskExtensions` CTS 擴充方法與生命週期連結保護 | 12 | +| `TextBoxSelectionExtensionsTests` | 右搖桿延伸選取共用的 `ResolveSelectionAnchor` 錨點解析(無選取、正向、反向、錨點失效)與 `GetWordJumpTarget` 單字跳轉目標(不改變目前選取、方向與邊界);原本三處複本集中後的一致性保護 | 6 | | `VibrationPatternsTests` | `VibrationPatterns` 與方向性震動設定、語意情境解析、能力感知的多段式微震動序列,以及歷程滾輪阻尼感、字數上限硬牆、震動強度預覽、右搖桿選取粒度、組合鍵進入提示與喚起握手回饋的回歸保護 | 37 | | `VibrationSafetyLimiterTests` | `VibrationSafetyLimiter` 熱保護、Duty Cycle 限制器與極端邊界保護;馬達數量熱成本倍率正規化,以及所有內建震動模式在冷啟動下不得被拒絕、單次超出預算改為降強度的回歸保護 | 16 | -| **合計** | | **410** | +| **合計** | | **416** | ## 二、執行方式 🚀 diff --git a/tests/InputBox.Tests/TextBoxSelectionExtensionsTests.cs b/tests/InputBox.Tests/TextBoxSelectionExtensionsTests.cs new file mode 100644 index 0000000..a6226cc --- /dev/null +++ b/tests/InputBox.Tests/TextBoxSelectionExtensionsTests.cs @@ -0,0 +1,102 @@ +using InputBox.Core.Extensions; +using Xunit; + +namespace InputBox.Tests; + +/// +/// 驗證右搖桿延伸選取共用的 TextBox 擴充方法:錨點解析與單字跳轉目標計算。 +/// 這些邏輯原本在主視窗、數值輸入與片語編輯三處各有一份複本,集中後以此測試保護行為一致。 +/// +public sealed class TextBoxSelectionExtensionsTests +{ + /// + /// 沒有選取範圍時,應以目前游標位置作為新錨點,活動邊緣與錨點相同。 + /// + [Fact] + public void ResolveSelectionAnchor_NoSelection_UsesCaretAsAnchor() + { + using TextBox textBox = new() { Text = "hello world" }; + textBox.Select(3, 0); + + (int anchor, int activeEdge) = textBox.ResolveSelectionAnchor(currentAnchor: 7); + + Assert.Equal(3, anchor); + Assert.Equal(3, activeEdge); + } + + /// + /// 錨點位於選取左端時,活動邊緣應在右端,並沿用既有錨點。 + /// + [Fact] + public void ResolveSelectionAnchor_AnchorAtStart_ActiveEdgeIsSelectionEnd() + { + using TextBox textBox = new() { Text = "hello world" }; + textBox.Select(2, 4); + + (int anchor, int activeEdge) = textBox.ResolveSelectionAnchor(currentAnchor: 2); + + Assert.Equal(2, anchor); + Assert.Equal(6, activeEdge); + } + + /// + /// 錨點位於選取右端(反向選取)時,活動邊緣應在左端,並沿用既有錨點。 + /// + [Fact] + public void ResolveSelectionAnchor_AnchorAtEnd_ActiveEdgeIsSelectionStart() + { + using TextBox textBox = new() { Text = "hello world" }; + textBox.Select(2, 4); + + (int anchor, int activeEdge) = textBox.ResolveSelectionAnchor(currentAnchor: 6); + + Assert.Equal(6, anchor); + Assert.Equal(2, activeEdge); + } + + /// + /// 選取範圍兩端都不等於既有錨點(例如使用者以滑鼠改變過選取)時,應以選取起點重新作為錨點。 + /// + [Fact] + public void ResolveSelectionAnchor_StaleAnchor_ResetsToSelectionStart() + { + using TextBox textBox = new() { Text = "hello world" }; + textBox.Select(2, 4); + + (int anchor, int activeEdge) = textBox.ResolveSelectionAnchor(currentAnchor: 9); + + Assert.Equal(2, anchor); + Assert.Equal(6, activeEdge); + } + + /// + /// 計算單字跳轉目標時不得改變文字方塊目前的選取範圍。 + /// + [Fact] + public void GetWordJumpTarget_DoesNotChangeCurrentSelection() + { + using TextBox textBox = new() { Text = "hello world again" }; + textBox.Select(1, 3); + + int target = textBox.GetWordJumpTarget(caret: 0, forward: true); + + Assert.True(target > 0); + Assert.Equal(1, textBox.SelectionStart); + Assert.Equal(3, textBox.SelectionLength); + } + + /// + /// 向右與向左的單字跳轉應分別往對應方向移動,且在文字邊界時不越界。 + /// + [Fact] + public void GetWordJumpTarget_MovesInRequestedDirectionWithinBounds() + { + using TextBox textBox = new() { Text = "hello world again" }; + + int forward = textBox.GetWordJumpTarget(caret: 0, forward: true); + int backward = textBox.GetWordJumpTarget(caret: textBox.TextLength, forward: false); + + Assert.InRange(forward, 1, textBox.TextLength); + Assert.InRange(backward, 0, textBox.TextLength - 1); + } +} From a43093d2c2e75d7f5e4c7e7170d693ac9e06e9c5 Mon Sep 17 00:00:00 2001 From: perditavojo <117562794+perditavojo@users.noreply.github.com> Date: Sun, 27 Sep 2026 07:07:19 +0800 Subject: [PATCH 13/17] =?UTF-8?q?refactor(a11y):=20=E5=B0=87=E4=B8=89?= =?UTF-8?q?=E4=BB=BD=E9=96=83=E7=88=8D=E8=AD=A6=E7=A4=BA=E5=AF=A6=E4=BD=9C?= =?UTF-8?q?=E7=9A=84=E9=85=8D=E8=89=B2=E8=88=87=E5=8B=95=E7=95=AB=E9=9B=86?= =?UTF-8?q?=E4=B8=AD=E7=82=BA=20FlashAlertAnimator?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 主視窗、數值輸入對話框與片語編輯對話框各有一份約 150 行的閃爍警示, 其中警示色、純淨底色插值、WCAG 相對亮度前景切換(L≈0.1791)與 1Hz 正弦脈衝/靜態長脈衝退回完全相同。 - 新增 FlashAlertAnimator:GetAlertColor、ComputeFrameColors(純函式)與 RunAsync(光敏安全動畫節奏)。 - 三處呼叫端改用共用實作,只保留各自的套用目標、狀態旗標與結束後還原;深色判斷讀取應用程式層級狀態,改為動畫開始時計算一次與原行為等價。 - 新增 FlashAlertAnimatorTests(7 項),其中驗證整個脈衝過程文字對比皆 ≥4.5:1。 - a11y-safety 規範註明閃爍警示的唯一實作位置,更新測試 README。 Co-Authored-By: Claude Opus 5.5 --- docs/engineering/a11y-safety.md | 1 + .../Core/Controls/NumericInputDialog.cs | 77 +------- .../Core/Controls/PhraseEditDialog.cs | 89 +-------- .../Core/Feedback/FlashAlertAnimator.cs | 173 ++++++++++++++++++ src/InputBox/MainForm.Events.cs | 99 +--------- .../InputBox.Tests/FlashAlertAnimatorTests.cs | 90 +++++++++ tests/InputBox.Tests/README.md | 3 +- 7 files changed, 293 insertions(+), 239 deletions(-) create mode 100644 src/InputBox/Core/Feedback/FlashAlertAnimator.cs create mode 100644 tests/InputBox.Tests/FlashAlertAnimatorTests.cs diff --git a/docs/engineering/a11y-safety.md b/docs/engineering/a11y-safety.md index 7d0c19c..8a18854 100644 --- a/docs/engineering/a11y-safety.md +++ b/docs/engineering/a11y-safety.md @@ -38,6 +38,7 @@ - 深色中性(未反轉,深色主題)→ `LightBlue` (≥7.2:1 AAA) - 淺色中性(未反轉,淺色主題)→ `MediumBlue` (8.14:1 AAA) - **視覺脈衝 (Flash Alert)**: + - **唯一實作**:警示色、每幀配色與動畫節奏集中於 `FlashAlertAnimator`;各視窗只負責套用目標控制項與結束後的視覺還原,不得自行複製脈衝或配色邏輯。 - 頻率:1Hz 平滑正弦波脈衝。 - 基色:固定為焦點反轉底色 (深色用 White,淺色用 Black)。 - **動態 ForeColor 連動**:背景亮度 **L > 0.1791** 時切換文字顏色。 diff --git a/src/InputBox/Core/Controls/NumericInputDialog.cs b/src/InputBox/Core/Controls/NumericInputDialog.cs index c63b449..58b29a9 100644 --- a/src/InputBox/Core/Controls/NumericInputDialog.cs +++ b/src/InputBox/Core/Controls/NumericInputDialog.cs @@ -1215,11 +1215,7 @@ private async Task FlashAlertAsync() try { bool isDark = this.IsDarkModeActive(); - - // 決定警示色。 - Color alertColor = SystemInformation.HighContrast ? - SystemColors.Highlight : - (isDark ? Color.Firebrick : Color.DarkOrange); + Color alertColor = FlashAlertAnimator.GetAlertColor(isDark, SystemInformation.HighContrast); void ApplyAlertVisuals(float intensity) { @@ -1230,73 +1226,16 @@ void ApplyAlertVisuals(float intensity) return; } - if (SystemInformation.HighContrast) - { - bool isAlert = intensity > 0.5f; - - Color hcBack = isAlert ? - alertColor : - SystemColors.Window, - hcFore = isAlert ? - SystemColors.HighlightText : - SystemColors.WindowText; + (Color back, Color fore) = FlashAlertAnimator.ComputeFrameColors( + intensity, + isDark, + alertColor, + SystemInformation.HighContrast); - _nud.UpdateRecursive(hcBack, hcFore); - } - else - { - Color pureBase = isDark ? - Color.White : - Color.Black; - - int rN = (int)(pureBase.R + (alertColor.R - pureBase.R) * intensity), - gN = (int)(pureBase.G + (alertColor.G - pureBase.G) * intensity), - bN = (int)(pureBase.B + (alertColor.B - pureBase.B) * intensity); - - Color flashColor = Color.FromArgb(255, rN, gN, bN); - // WCAG 相對亮度精確切換閾值(crossover L≈0.1791),修復 YUV≈128 近似在切換帶(intensity≈0.75) - // 導致文字對比跌破 AA(3.5~4.2:1)的問題。修復後全程 ≥4.64:1 AA; - // 14f bold 大型文字全程 ≥4.5:1 AAA。 - static float FLin(int c) { float f = c / 255f; return f <= 0.04045f ? f / 12.92f : MathF.Pow((f + 0.055f) / 1.055f, 2.4f); } - Color flashFore = (0.2126f * FLin(flashColor.R) + 0.7152f * FLin(flashColor.G) + 0.0722f * FLin(flashColor.B)) > 0.1791f - ? Color.Black - : Color.White; - - _nud.UpdateRecursive(flashColor, flashFore); - } + _nud.UpdateRecursive(back, fore); } - if (!SystemInformation.UIEffectsEnabled || - !AppSettings.Current.EnableAnimatedVisualAlerts) - { - await this.SafeInvokeAsync(() => ApplyAlertVisuals(1.0f)); - - await Task.Delay(800, token); - - return; - } - - using PeriodicTimer timer = new(TimeSpan.FromMilliseconds(AppSettings.TargetFrameTimeMs)); - - long startTime = Stopwatch.GetTimestamp(); - - while (await timer.WaitForNextTickAsync(token)) - { - long elapsedTicks = Stopwatch.GetTimestamp() - startTime; - - double elapsedMs = (double)elapsedTicks / Stopwatch.Frequency * 1000.0; - - if (elapsedMs >= AppSettings.PhotoSafeFrequencyMs) - { - break; - } - - double angle = elapsedMs / AppSettings.PhotoSafeFrequencyMs * 2.0 * Math.PI - (Math.PI / 2.0); - - float intensity = (float)((Math.Sin(angle) + 1.0) / 2.0); - - await this.SafeInvokeAsync(() => ApplyAlertVisuals(intensity)); - } + await FlashAlertAnimator.RunAsync(this, ApplyAlertVisuals, token); } catch (OperationCanceledException) { diff --git a/src/InputBox/Core/Controls/PhraseEditDialog.cs b/src/InputBox/Core/Controls/PhraseEditDialog.cs index 75e02de..c621893 100644 --- a/src/InputBox/Core/Controls/PhraseEditDialog.cs +++ b/src/InputBox/Core/Controls/PhraseEditDialog.cs @@ -1178,11 +1178,7 @@ private async Task FlashValidationCueAsync(TextBox target) try { bool isDark = target.IsDarkModeActive(); - - // 決定警示色。 - Color alertColor = SystemInformation.HighContrast ? - SystemColors.Highlight : - (isDark ? Color.Firebrick : Color.DarkOrange); + Color alertColor = FlashAlertAnimator.GetAlertColor(isDark, SystemInformation.HighContrast); void ApplyAlertVisuals(float intensity) { @@ -1192,84 +1188,17 @@ void ApplyAlertVisuals(float intensity) return; } - if (SystemInformation.HighContrast) - { - bool isAlert = intensity > 0.5f; - - Color hcBack = isAlert ? - alertColor : - SystemColors.Window, - hcFore = isAlert ? - SystemColors.HighlightText : - SystemColors.WindowText; - - target.BackColor = hcBack; - target.ForeColor = hcFore; - } - else - { - Color pureBase = isDark ? - Color.White : - Color.Black; - - int rN = (int)(pureBase.R + (alertColor.R - pureBase.R) * intensity), - gN = (int)(pureBase.G + (alertColor.G - pureBase.G) * intensity), - bN = (int)(pureBase.B + (alertColor.B - pureBase.B) * intensity); - - Color flashColor = Color.FromArgb(255, rN, gN, bN); - - // WCAG 相對亮度精確切換閾值(crossover L≈0.1791) - static float FLin(int c) - { - float f = c / 255f; - - return f <= 0.04045f ? - f / 12.92f : - MathF.Pow((f + 0.055f) / 1.055f, 2.4f); - } - - Color flashFore = (0.2126f * FLin(flashColor.R) + - 0.7152f * FLin(flashColor.G) + - 0.0722f * FLin(flashColor.B)) > 0.1791f ? - Color.Black : - Color.White; - - target.BackColor = flashColor; - target.ForeColor = flashFore; - } - } - - if (!SystemInformation.UIEffectsEnabled || - !AppSettings.Current.EnableAnimatedVisualAlerts) - { - await this.SafeInvokeAsync(() => ApplyAlertVisuals(1.0f)); - - await Task.Delay(800, token); + (Color back, Color fore) = FlashAlertAnimator.ComputeFrameColors( + intensity, + isDark, + alertColor, + SystemInformation.HighContrast); - return; + target.BackColor = back; + target.ForeColor = fore; } - using PeriodicTimer timer = new(TimeSpan.FromMilliseconds(AppSettings.TargetFrameTimeMs)); - - long startTime = Stopwatch.GetTimestamp(); - - while (await timer.WaitForNextTickAsync(token)) - { - long elapsedTicks = Stopwatch.GetTimestamp() - startTime; - - double elapsedMs = (double)elapsedTicks / Stopwatch.Frequency * 1000.0; - - if (elapsedMs >= AppSettings.PhotoSafeFrequencyMs) - { - break; - } - - double angle = elapsedMs / AppSettings.PhotoSafeFrequencyMs * 2.0 * Math.PI - (Math.PI / 2.0); - - float intensity = (float)((Math.Sin(angle) + 1.0) / 2.0); - - await this.SafeInvokeAsync(() => ApplyAlertVisuals(intensity)); - } + await FlashAlertAnimator.RunAsync(this, ApplyAlertVisuals, token); } catch (OperationCanceledException) { diff --git a/src/InputBox/Core/Feedback/FlashAlertAnimator.cs b/src/InputBox/Core/Feedback/FlashAlertAnimator.cs new file mode 100644 index 0000000..a77d9b9 --- /dev/null +++ b/src/InputBox/Core/Feedback/FlashAlertAnimator.cs @@ -0,0 +1,173 @@ +using InputBox.Core.Configuration; +using InputBox.Core.Extensions; +using System.Diagnostics; + +namespace InputBox.Core.Feedback; + +/// +/// 輸入邊界與驗證失敗時共用的視覺閃爍警示:警示色、每一幀的前景/背景配色,以及光敏安全的動畫節奏 +/// +/// +/// 主視窗、數值輸入與片語編輯三處共用此實作,確保 1Hz 頻率上限、動畫偏好退回與 WCAG 文字對比規則只維護一份。 +/// 套用目標控制項、狀態旗標與結束後的視覺還原仍由各呼叫端負責。 +/// +internal static class FlashAlertAnimator +{ + /// + /// 關閉動畫時以單次長脈衝維持警示的時間(毫秒),讓低視能使用者有足夠時間感知狀態。 + /// + private const int StaticPulseDurationMs = 800; + + /// + /// WCAG 相對亮度切換閾值:背景亮度高於此值時改用黑色文字,否則使用白色文字。 + /// + /// + /// 取黑白文字對比相等的交叉點(L≈0.1791),避免以 YUV≈128 近似在切換帶(intensity≈0.75) + /// 讓文字對比跌破 AA;精確切換後全程 ≥4.64:1,14f 粗體大型文字全程 ≥4.5:1。 + /// + internal const float ForegroundLuminanceThreshold = 0.1791f; + + /// + /// 取得警示色 + /// + /// + /// 選色對齊反轉後的控制項背景:淺色模式(黑底)使用 DarkOrange(8.3:1);深色模式(白底)使用 Firebrick(5.8:1); + /// 高對比模式一律使用系統醒目提示色。 + /// + /// 目標控制項目前是否為深色模式。 + /// 系統是否啟用高對比模式。 + /// 警示色。 + public static Color GetAlertColor(bool isDark, bool highContrast) + { + return highContrast ? + SystemColors.Highlight : + (isDark ? Color.Firebrick : Color.DarkOrange); + } + + /// + /// 依閃爍強度計算單一幀的背景與前景色 + /// + /// + /// 一般模式由純淨底色(深色用白、淺色用黑)線性插值至警示色,避免與高飽和焦點色插值產生髒濁色; + /// 前景色依 sRGB 線性化後的相對亮度切換黑白。高對比模式不插值,強度過半即切換為警示配色。 + /// + /// 閃爍強度(0 到 1)。 + /// 目標控制項目前是否為深色模式。 + /// 由 取得的警示色。 + /// 系統是否啟用高對比模式。 + /// 本幀的背景色與前景色。 + public static (Color Back, Color Fore) ComputeFrameColors( + float intensity, + bool isDark, + Color alertColor, + bool highContrast) + { + if (highContrast) + { + bool isAlert = intensity > 0.5f; + + return isAlert ? + (alertColor, SystemColors.HighlightText) : + (SystemColors.Window, SystemColors.WindowText); + } + + Color pureBase = isDark ? + Color.White : + Color.Black; + + int r = (int)(pureBase.R + (alertColor.R - pureBase.R) * intensity), + g = (int)(pureBase.G + (alertColor.G - pureBase.G) * intensity), + b = (int)(pureBase.B + (alertColor.B - pureBase.B) * intensity); + + Color back = Color.FromArgb(255, r, g, b); + + Color fore = GetRelativeLuminance(back) > ForegroundLuminanceThreshold ? + Color.Black : + Color.White; + + return (back, fore); + } + + /// + /// 播放閃爍動畫:預設為 週期的單次正弦脈衝; + /// 系統關閉動畫效果或使用者停用動畫警示時,改為單次長脈衝 + /// + /// 用於在 UI 執行緒套用每一幀的控制項。 + /// 套用指定強度(0 到 1)的委派,會在 UI 執行緒上呼叫。 + /// 取消權杖;取消時擲出 。 + /// 動畫完成或取消時結束的工作。 + public static async Task RunAsync( + Control owner, + Action applyFrame, + CancellationToken cancellationToken) + { + ArgumentNullException.ThrowIfNull(owner); + ArgumentNullException.ThrowIfNull(applyFrame); + + // 嚴格遵守光敏性癲癇防護與使用者偏好: + // 系統層級關閉動畫效果(UIEffectsEnabled 為 false)或停用動畫警示時,不進行循環閃爍。 + if (!SystemInformation.UIEffectsEnabled || + !AppSettings.Current.EnableAnimatedVisualAlerts) + { + await owner.SafeInvokeAsync(() => applyFrame(1.0f)); + + await Task.Delay(StaticPulseDurationMs, cancellationToken); + + return; + } + + int totalDuration = AppSettings.PhotoSafeFrequencyMs; + + using PeriodicTimer timer = new(TimeSpan.FromMilliseconds(AppSettings.TargetFrameTimeMs)); + + long startTime = Stopwatch.GetTimestamp(); + + while (await timer.WaitForNextTickAsync(cancellationToken)) + { + double elapsedMs = Stopwatch.GetElapsedTime(startTime).TotalMilliseconds; + + if (elapsedMs >= totalDuration) + { + break; + } + + float intensity = ComputeIntensity(elapsedMs, totalDuration); + + await owner.SafeInvokeAsync(() => applyFrame(intensity)); + } + } + + /// + /// 依經過時間計算正弦脈衝強度:從 0 開始、在週期中點達到 1,再回到 0 + /// + /// 動畫開始後的經過時間(毫秒)。 + /// 脈衝週期(毫秒)。 + /// 閃爍強度(0 到 1)。 + internal static float ComputeIntensity(double elapsedMs, double periodMs) + { + double angle = elapsedMs / periodMs * 2.0 * Math.PI - (Math.PI / 2.0); + + return (float)((Math.Sin(angle) + 1.0) / 2.0); + } + + /// + /// 計算色彩的 WCAG 相對亮度 + /// + /// 要計算的色彩。 + /// 相對亮度(0 到 1)。 + internal static float GetRelativeLuminance(Color color) + { + return 0.2126f * Linearize(color.R) + + 0.7152f * Linearize(color.G) + + 0.0722f * Linearize(color.B); + + static float Linearize(int channel) + { + float f = channel / 255f; + + return f <= 0.04045f ? + f / 12.92f : + MathF.Pow((f + 0.055f) / 1.055f, 2.4f); + } + } +} diff --git a/src/InputBox/MainForm.Events.cs b/src/InputBox/MainForm.Events.cs index 2a0220e..fab9a09 100644 --- a/src/InputBox/MainForm.Events.cs +++ b/src/InputBox/MainForm.Events.cs @@ -1533,12 +1533,8 @@ private async Task FlashAlertAsync() try { - // 決定警示色。 - // 修正選色邏輯以對齊反轉後的控制項背景。 - // 淺色模式(黑底):用 DarkOrange(8.3:1);深色模式(白底):用 Firebrick(5.8:1)。 - Color alertColor = SystemInformation.HighContrast ? - SystemColors.Highlight : - (TBInput.IsDarkModeActive() ? Color.Firebrick : Color.DarkOrange); + bool isDark = TBInput.IsDarkModeActive(); + Color alertColor = FlashAlertAnimator.GetAlertColor(isDark, SystemInformation.HighContrast); void ApplyAlertVisuals(float intensity) { @@ -1548,92 +1544,17 @@ void ApplyAlertVisuals(float intensity) return; } - bool isDark = TBInput.IsDarkModeActive(); + (Color back, Color fore) = FlashAlertAnimator.ComputeFrameColors( + intensity, + isDark, + alertColor, + SystemInformation.HighContrast); - if (SystemInformation.HighContrast) - { - bool isAlert = intensity > 0.5f; - - Color hcBack = isAlert ? - alertColor : - SystemColors.Window, - hcFore = isAlert ? - SystemColors.HighlightText : - SystemColors.WindowText; - - // 同步更新背景與前景,確保高對比下文字可讀性。 - PInputHost.UpdateRecursive(hcBack, hcFore); - } - else - { - // 閃爍基色改為純淨底色(黑/白),避免與高飽和焦點色(Cyan/RoyalBlue)插值產生髒濁色。 - Color pureBase = isDark ? - Color.White : - Color.Black; - - int rB = (int)(pureBase.R + (alertColor.R - pureBase.R) * intensity), - gB = (int)(pureBase.G + (alertColor.G - pureBase.G) * intensity), - bB = (int)(pureBase.B + (alertColor.B - pureBase.B) * intensity); - - Color flashColor = Color.FromArgb(255, rB, gB, bB); - - // WCAG 相對亮度精確切換閾值(crossover L≈0.1791),修復 YUV≈128 近似在切換帶(intensity≈0.75) - // 導致文字對比跌破 AA(3.5~4.2:1)的問題。修復後全程 ≥4.64:1 AA; - // 14f bold 大型文字全程 ≥4.5:1 AAA。 - static float FLin(int c) - { - float f = c / 255f; - - return f <= 0.04045f ? f / 12.92f : MathF.Pow((f + 0.055f) / 1.055f, 2.4f); - } - - Color flashFore = (0.2126f * FLin(flashColor.R) + 0.7152f * FLin(flashColor.G) + 0.0722f * FLin(flashColor.B)) > 0.1791f ? - Color.Black : - Color.White; - - // 遞歸背景與前景同步:僅作用於數據內容區域(PInputHost),按鈕保持其靜態視覺狀態。 - PInputHost.UpdateRecursive(flashColor, flashFore); - } + // 僅作用於數據內容區域(PInputHost),按鈕保持其靜態視覺狀態。 + PInputHost.UpdateRecursive(back, fore); } - // 嚴格遵守光敏性癲癇防護與使用者偏好: - // 若使用者在系統層級關閉了動畫效果(UIEffectsEnabled 為 false), - // 則不進行循環閃爍,改為一次性的「長脈衝(Static Pulse)」回饋。 - if (!SystemInformation.UIEffectsEnabled || - !AppSettings.Current.EnableAnimatedVisualAlerts) - { - await this.SafeInvokeAsync(() => ApplyAlertVisuals(1.0f)); - - // 維持一段較長時間(800ms)讓低視能使用者感知狀態,隨後恢復。 - await Task.Delay(800, token); - - return; - } - - int totalDuration = AppSettings.PhotoSafeFrequencyMs; - - using PeriodicTimer timer = new(TimeSpan.FromMilliseconds(AppSettings.TargetFrameTimeMs)); - - long startTime = Stopwatch.GetTimestamp(); - - while (await timer.WaitForNextTickAsync(token)) - { - long elapsedTicks = Stopwatch.GetTimestamp() - startTime; - - double elapsedMs = (double)elapsedTicks / Stopwatch.Frequency * 1000.0; - - if (elapsedMs >= totalDuration) - { - break; - } - - // 使用 AppSettings.PhotoSafeFrequencyMs 定義的正弦波週期(1Hz)。 - double angle = elapsedMs / AppSettings.PhotoSafeFrequencyMs * 2.0 * Math.PI - (Math.PI / 2.0); - - float intensity = (float)((Math.Sin(angle) + 1.0) / 2.0); - - await this.SafeInvokeAsync(() => ApplyAlertVisuals(intensity)); - } + await FlashAlertAnimator.RunAsync(this, ApplyAlertVisuals, token); } catch (OperationCanceledException) { diff --git a/tests/InputBox.Tests/FlashAlertAnimatorTests.cs b/tests/InputBox.Tests/FlashAlertAnimatorTests.cs new file mode 100644 index 0000000..63f56ed --- /dev/null +++ b/tests/InputBox.Tests/FlashAlertAnimatorTests.cs @@ -0,0 +1,90 @@ +using InputBox.Core.Feedback; +using Xunit; + +namespace InputBox.Tests; + +/// +/// 驗證主視窗、數值輸入與片語編輯共用的閃爍警示配色與動畫強度計算。 +/// +public sealed class FlashAlertAnimatorTests +{ + /// + /// 一般模式下,深色與淺色主題應分別使用 Firebrick 與 DarkOrange,高對比模式使用系統醒目提示色。 + /// + [Fact] + public void GetAlertColor_ReturnsThemeSpecificColor() + { + Assert.Equal(Color.Firebrick, FlashAlertAnimator.GetAlertColor(isDark: true, highContrast: false)); + Assert.Equal(Color.DarkOrange, FlashAlertAnimator.GetAlertColor(isDark: false, highContrast: false)); + Assert.Equal(SystemColors.Highlight, FlashAlertAnimator.GetAlertColor(isDark: true, highContrast: true)); + } + + /// + /// 強度為 0 時背景應為純淨底色(深色用白、淺色用黑),強度為 1 時背景應等於警示色。 + /// + [Theory] + [InlineData(true)] + [InlineData(false)] + public void ComputeFrameColors_InterpolatesFromPureBaseToAlertColor(bool isDark) + { + Color alert = FlashAlertAnimator.GetAlertColor(isDark, highContrast: false); + + (Color start, _) = FlashAlertAnimator.ComputeFrameColors(0f, isDark, alert, highContrast: false); + (Color end, _) = FlashAlertAnimator.ComputeFrameColors(1f, isDark, alert, highContrast: false); + + Assert.Equal((isDark ? Color.White : Color.Black).ToArgb(), start.ToArgb()); + Assert.Equal(alert.ToArgb(), end.ToArgb()); + } + + /// + /// 整個閃爍過程中,每一幀的文字與背景對比都必須維持 WCAG AA(≥4.5:1),避免在切換帶跌破可讀門檻。 + /// + [Theory] + [InlineData(true)] + [InlineData(false)] + public void ComputeFrameColors_KeepsTextContrastAtLeastAaThroughoutPulse(bool isDark) + { + Color alert = FlashAlertAnimator.GetAlertColor(isDark, highContrast: false); + + for (int step = 0; step <= 100; step++) + { + float intensity = step / 100f; + + (Color back, Color fore) = FlashAlertAnimator.ComputeFrameColors(intensity, isDark, alert, highContrast: false); + + float lighter = Math.Max(FlashAlertAnimator.GetRelativeLuminance(back), FlashAlertAnimator.GetRelativeLuminance(fore)); + float darker = Math.Min(FlashAlertAnimator.GetRelativeLuminance(back), FlashAlertAnimator.GetRelativeLuminance(fore)); + float contrast = (lighter + 0.05f) / (darker + 0.05f); + + Assert.True(contrast >= 4.5f, $"isDark={isDark} intensity={intensity} contrast={contrast:F2}"); + } + } + + /// + /// 高對比模式不插值,強度過半即切換為醒目提示配色,否則維持系統視窗配色。 + /// + [Fact] + public void ComputeFrameColors_HighContrast_SwitchesAtHalfIntensity() + { + Color alert = FlashAlertAnimator.GetAlertColor(isDark: false, highContrast: true); + + (Color lowBack, Color lowFore) = FlashAlertAnimator.ComputeFrameColors(0.4f, isDark: false, alert, highContrast: true); + (Color highBack, Color highFore) = FlashAlertAnimator.ComputeFrameColors(0.6f, isDark: false, alert, highContrast: true); + + Assert.Equal(SystemColors.Window, lowBack); + Assert.Equal(SystemColors.WindowText, lowFore); + Assert.Equal(alert, highBack); + Assert.Equal(SystemColors.HighlightText, highFore); + } + + /// + /// 正弦脈衝應從 0 開始、在週期中點達到最大值 1,並在週期結束時回到 0。 + /// + [Fact] + public void ComputeIntensity_ProducesSinglePulsePerPeriod() + { + Assert.Equal(0f, FlashAlertAnimator.ComputeIntensity(0, 1000), 0.0001f); + Assert.Equal(1f, FlashAlertAnimator.ComputeIntensity(500, 1000), 0.0001f); + Assert.Equal(0f, FlashAlertAnimator.ComputeIntensity(1000, 1000), 0.0001f); + } +} diff --git a/tests/InputBox.Tests/README.md b/tests/InputBox.Tests/README.md index 04fb0ec..ffde1a4 100644 --- a/tests/InputBox.Tests/README.md +++ b/tests/InputBox.Tests/README.md @@ -23,6 +23,7 @@ | `GamepadControllerFactoryTests` | 控制器後端建立策略,驗證 XInput 預設路徑、GameInput 成功路徑,以及 GameInput 執行階段不可用時退避至 XInput | 3 | | `GamepadControllerPauseTests` | 控制器在 `Pause()` / `Resume()`、連線可用性語意、GameInput 讀取缺失斷線重列舉、裝置狀態過濾、震動停止安全性、`ClearAllEvents` 肩鍵釋放訂閱清除與原生對話框切換時的殘留輸入回歸保護 | 10 | | `GameInputDirectUsageTests` | `GameInputGamepadController` 直接使用 `InputWeave.GameInput` 遊戲控制器介面的守門、callback function pointer marshaling、官方 v3 按鍵位元、快照邊緣偵測、Release 日誌邊界、穩定裝置識別與震動參數保留 | 9 | +| `FlashAlertAnimatorTests` | `FlashAlertAnimator` 共用閃爍警示:主題警示色、純淨底色至警示色的插值、整個脈衝過程文字對比 ≥4.5:1、高對比模式半強度切換,以及 1Hz 單次正弦脈衝強度 | 7 | | `GamepadBiasSmoothingTests` | `GamepadBiasSmoothing` 自適應 EMA 學習率公式:零誤差用基礎值、超出範圍用最大值,以及 XInput 與 GameInput 不同數值尺度下結果一致 | 5 | | `GamepadCalibrationVisualizerMapperTests` | `GamepadCalibrationVisualizerMapper` 對校準視覺化座標限制、死區半徑換算、D-Pad 導覽防誤觸,以及雙搖桿狀態/控制器連線文案格式化的回歸保護 | 14 | | `GamepadEventBinderTests` | `GamepadEventBinder` 的 LB / RB / LT / RT 與肩鍵放開事件綁定回歸保護 | 1 | @@ -48,7 +49,7 @@ | `TextBoxSelectionExtensionsTests` | 右搖桿延伸選取共用的 `ResolveSelectionAnchor` 錨點解析(無選取、正向、反向、錨點失效)與 `GetWordJumpTarget` 單字跳轉目標(不改變目前選取、方向與邊界);原本三處複本集中後的一致性保護 | 6 | | `VibrationPatternsTests` | `VibrationPatterns` 與方向性震動設定、語意情境解析、能力感知的多段式微震動序列,以及歷程滾輪阻尼感、字數上限硬牆、震動強度預覽、右搖桿選取粒度、組合鍵進入提示與喚起握手回饋的回歸保護 | 37 | | `VibrationSafetyLimiterTests` | `VibrationSafetyLimiter` 熱保護、Duty Cycle 限制器與極端邊界保護;馬達數量熱成本倍率正規化,以及所有內建震動模式在冷啟動下不得被拒絕、單次超出預算改為降強度的回歸保護 | 16 | -| **合計** | | **416** | +| **合計** | | **423** | ## 二、執行方式 🚀 From eca21087bef3b0a4576b76cb0b377097019ece7a Mon Sep 17 00:00:00 2001 From: perditavojo <117562794+perditavojo@users.noreply.github.com> Date: Sun, 27 Sep 2026 07:13:08 +0800 Subject: [PATCH 14/17] =?UTF-8?q?refactor(menu):=20=E5=B0=87=201,454=20?= =?UTF-8?q?=E8=A1=8C=E7=9A=84=20InitializeContextMenu=20=E4=BE=9D=E5=AD=90?= =?UTF-8?q?=E9=81=B8=E5=96=AE=E6=8B=86=E5=88=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit InitializeContextMenu 是整個專案最難維護的單一方法。依選單結構拆成以下私有方法,只搬移程式碼、呼叫順序與原本相同: - InitializeToggleMenuItems:隱私模式、允許中斷廣播、動畫式視覺警示、返回時最小化。 - CreateHotkeySettingsMenu、CreateSettingsMenu(組裝進階設定)、CreateWindowOperationsMenu、CreateFeedbackMenu、CreateGamepadSettingsMenu。 - InitializePhrasesMenu:片語子選單。 - 跨子選單共用的 AddNumericItem 由區域函式提升為私有方法(只使用參數與實例成員)。 - 以 MemberNotNull 標註初始化方法,讓可空性分析得知欄位已初始化。 InitializeContextMenu 由 1,454 行縮減為 175 行。建置 0 警告;全部測試通過, 另以 INPUTBOX_RUN_UI_TESTS=1 在互動式桌面執行 MainFormUiSmokeTests 11 項全數通過。 Co-Authored-By: Claude Opus 5.5 --- src/InputBox/MainForm.ContextMenu.cs | 679 +++++++++++++++------------ 1 file changed, 378 insertions(+), 301 deletions(-) diff --git a/src/InputBox/MainForm.ContextMenu.cs b/src/InputBox/MainForm.ContextMenu.cs index 7b2dcfd..0d031d7 100644 --- a/src/InputBox/MainForm.ContextMenu.cs +++ b/src/InputBox/MainForm.ContextMenu.cs @@ -8,6 +8,7 @@ using InputBox.Core.Utilities; using InputBox.Resources; using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; using System.Media; namespace InputBox; @@ -134,6 +135,158 @@ private void InitializeContextMenu() }, RestartMenuAccessibleDescription); + InitializeToggleMenuItems(); + + ToolStripMenuItem tsmiHotkeySettings = CreateHotkeySettingsMenu(); + ToolStripMenuItem tsmiSettings = CreateSettingsMenu(); + + // 清除歷程。 + // 清空目前只保存在記憶體中的輸入歷程資料。 + ToolStripMenuItem tsmiClearHistory = new(ControlExtensions.GetMnemonicText(Strings.Menu_ClearHistory, 'C')) + { + Name = "TsmiClearHistory", + AccessibleName = Strings.Menu_ClearHistory, + AccessibleDescription = Strings.Menu_ClearHistory_Desc + }; + tsmiClearHistory.Click += (s, e) => + { + try + { + _historyService?.Clear(); + + // 清除後主動將焦點拉回輸入框,確保使用者能直接開始輸入。 + TBInput.Focus(); + + FeedbackService.PlaySound(SystemSounds.Asterisk); + + AnnounceA11y(Strings.Msg_InputCleared); + } + catch (Exception ex) + { + Debug.WriteLine($"[選單] tsmiClearHistory.Click 失敗:{ex.Message}"); + } + }; + + // 離開。 + // 關閉主視窗並結束整個應用程式流程。 + ToolStripMenuItem tsmiExit = new(ControlExtensions.GetMnemonicText(Strings.Menu_Exit, 'X')) + { + AccessibleName = Strings.Menu_Exit, + AccessibleDescription = Strings.A11y_Menu_Exit_Desc + }; + tsmiExit.Click += (s, e) => + { + try + { + Close(); + } + catch (Exception ex) + { + Debug.WriteLine($"[選單] tsmiExit.Click 失敗:{ex.Message}"); + } + }; + + // 說明(WCAG 3.3.5)。 + // 顯示鍵盤與遊戲控制器操作對照的說明對話框。 + ToolStripMenuItem tsmiHelp = new(ControlExtensions.GetMnemonicText(Strings.Menu_Help, 'H')) + { + AccessibleName = Strings.Menu_Help, + AccessibleDescription = Strings.Menu_Help_Desc + }; + tsmiHelp.Click += (s, e) => + { + try + { + ShowHelpDialog(); + } + catch (Exception ex) + { + Debug.WriteLine($"[選單] tsmiHelp.Click 失敗:{ex.Message}"); + } + }; + + // 使用共享快取取得選單字型。 + _cmsInput.Font = GetSharedA11yFont(DeviceDpi); + _cmsInput.Opened += (s, e) => EnsureContextMenuReadyForKeyboard(_cmsInput); + _cmsInput.PreviewKeyDown += ContextMenu_PreviewKeyDown; + _cmsInput.KeyDown += ContextMenu_KeyDown; + _cmsInput.Closed += (s, e) => RestorePhraseSubMenuAutoClose(); + _cmsInput.Closing += (s, e) => + { + try + { + if (ShouldSuppressPhraseMenuClose(e.CloseReason)) + { + e.Cancel = true; + } + } + catch (Exception ex) + { + Debug.WriteLine($"[選單] _cmsInput.Closing 失敗:{ex.Message}"); + } + }; + + InitializePhrasesMenu(); + + if (SystemHelper.IsRunningOnGamescope()) + { + _tsmiRecoverGamescopeSurface = new ToolStripMenuItem(Strings.Menu_RecoverGamescopeSurface) + { + AccessibleName = Strings.Menu_RecoverGamescopeSurface, + AccessibleDescription = Strings.Menu_RecoverGamescopeSurface_Desc + }; + _tsmiRecoverGamescopeSurface.Click += (s, e) => + { + try + { + RecoverGamescopeMainSurface(); + } + catch (Exception ex) + { + LoggerService.LogException(ex, "tsmiRecoverGamescopeSurface.Click 失敗"); + + Debug.WriteLine($"[選單] tsmiRecoverGamescopeSurface.Click 失敗:{ex.Message}"); + } + }; + } + + _cmsInput.Items.Add(_tsmiPrivacyMode); + _cmsInput.Items.Add(_tsmiA11yInterrupt); + _cmsInput.Items.Add(_tsmiAnimatedVisualAlerts); + _cmsInput.Items.Add(_tsmiMinimizeOnReturn); + _cmsInput.Items.Add(new ToolStripSeparator()); + _cmsInput.Items.Add(_tsmiPhrases); + _cmsInput.Items.Add(new ToolStripSeparator()); + _cmsInput.Items.Add(tsmiHotkeySettings); + _cmsInput.Items.Add(tsmiSettings); + _cmsInput.Items.Add(new ToolStripSeparator()); + _cmsInput.Items.Add(tsmiClearHistory); + if (_tsmiRecoverGamescopeSurface != null) + { + _cmsInput.Items.Add(new ToolStripSeparator()); + _cmsInput.Items.Add(_tsmiRecoverGamescopeSurface); + } + + _cmsInput.Items.Add(new ToolStripSeparator()); + _cmsInput.Items.Add(tsmiHelp); + _cmsInput.Items.Add(new ToolStripSeparator()); + _cmsInput.Items.Add(tsmiExit); + + // 綁定選單至容器控制項,確保 TBInput 能保留其原始的 Windows 右鍵選單(剪下、複製、貼上)。 + PInputHost.ContextMenuStrip = _cmsInput; + TLPHost.ContextMenuStrip = _cmsInput; + } + + /// + /// 建立右鍵選單頂層的切換項目:隱私模式、允許中斷廣播、動畫式視覺警示與返回時最小化 + /// + [MemberNotNull( + nameof(_tsmiPrivacyMode), + nameof(_tsmiA11yInterrupt), + nameof(_tsmiAnimatedVisualAlerts), + nameof(_tsmiMinimizeOnReturn))] + private void InitializeToggleMenuItems() + { // 隱私模式。 _tsmiPrivacyMode = new ToolStripMenuItem(ControlExtensions.GetMnemonicText(Strings.Menu_PrivacyMode, 'P')) { @@ -298,7 +451,14 @@ private void InitializeContextMenu() Debug.WriteLine($"[選單] _tsmiMinimizeOnReturn.CheckedChanged 失敗:{ex.Message}"); } }; + } + /// + /// 建立右鍵選單的「快速鍵設定」子選單 + /// + /// 快速鍵設定子選單項目。 + private ToolStripMenuItem CreateHotkeySettingsMenu() + { // 快速鍵設定子選單。 // 提供修飾鍵與主按鍵擷取等快速鍵相關設定入口。 ToolStripMenuItem tsmiHotkeySettings = new(ControlExtensions.GetMnemonicText(Strings.Menu_HotkeySettings, 'T')) @@ -465,6 +625,15 @@ void AddModifierItem(string label, User32.KeyModifiers modValue) }; tsmiHotkeySettings.DropDownItems.Add(tsmiCaptureKey); + return tsmiHotkeySettings; + } + + /// + /// 建立右鍵選單的「進階設定」子選單,並組裝視窗、回饋、遊戲控制器與資料夾等項目 + /// + /// 進階設定子選單項目。 + private ToolStripMenuItem CreateSettingsMenu() + { // 進階設定子選單。 // 匯整視窗、回饋、遊戲控制器與資料夾等進階功能入口。 ToolStripMenuItem tsmiSettings = new(ControlExtensions.GetMnemonicText(Strings.Menu_Settings, 'S')) @@ -486,6 +655,131 @@ void AddModifierItem(string label, User32.KeyModifiers modValue) } }; + tsmiSettings.DropDownItems.Add(CreateWindowOperationsMenu()); + tsmiSettings.DropDownItems.Add(CreateFeedbackMenu()); + tsmiSettings.DropDownItems.Add(CreateGamepadSettingsMenu()); + tsmiSettings.DropDownItems.Add(new ToolStripSeparator()); + + // 歷程容量(需重啟)。 + // 控制記憶體中保留的輸入歷程筆數上限。 + ToolStripMenuItem tsmiCap = new(string.Empty) + { + AccessibleName = Strings.Settings_HistoryCapacity, + Tag = new MenuMetadata(Strings.Settings_HistoryCapacity, 'H', 1, 1000) + }; + tsmiCap.Click += (s, e) => + { + try + { + int? val = AskForValue(Strings.Settings_HistoryCapacity, AppSettings.Current.HistoryCapacity, 100, 1, 1000); + + if (val.HasValue && + val != AppSettings.Current.HistoryCapacity) + { + AppSettings.Current.HistoryCapacity = val.Value; + AppSettings.Save(); + + RefreshMenu(); + + AskForRestart(); + } + } + catch (Exception ex) + { + LoggerService.LogException(ex, "歷程容量設定失敗"); + + Debug.WriteLine($"[選單] tsmiCap.Click 失敗:{ex.Message}"); + } + }; + tsmiSettings.DropDownItems.Add(tsmiCap); + + tsmiSettings.DropDownItems.Add(new ToolStripSeparator()); + + // 開啟資料夾。 + // 開啟應用程式設定與資料檔所在的資料夾。 + ToolStripMenuItem tsmiOpenDataFolder = new(ControlExtensions.GetMnemonicText(Strings.Menu_OpenDataFolder, 'O')) + { + AccessibleName = Strings.Menu_OpenDataFolder, + AccessibleDescription = Strings.Menu_OpenDataFolder_Desc + }; + tsmiOpenDataFolder.Click += (s, e) => + { + try + { + if (Directory.Exists(AppSettings.ConfigDirectory)) + { + Process.Start(new ProcessStartInfo(AppSettings.ConfigDirectory) + { + UseShellExecute = true + }); + } + else + { + AnnounceA11y(Strings.Msg_FolderNotFound); + + GamepadMessageBox.Show( + this, + Strings.Msg_FolderNotFound, + Strings.Wrn_Title, + MessageBoxButtons.OK, + MessageBoxIcon.Warning, + gamepad: _gamepadController); + } + } + catch (Exception ex) + { + Debug.WriteLine($"[選單] tsmiOpenDataFolder.Click 失敗:{ex.Message}"); + } + }; + tsmiSettings.DropDownItems.Add(tsmiOpenDataFolder); + + // 開啟日誌資料夾。 + // 開啟本機例外與診斷紀錄所在的日誌目錄。 + ToolStripMenuItem tsmiOpenLogFolder = new(ControlExtensions.GetMnemonicText(Strings.Menu_OpenLogFolder, 'L')) + { + AccessibleName = Strings.Menu_OpenLogFolder, + AccessibleDescription = Strings.Menu_OpenLogFolder_Desc + }; + tsmiOpenLogFolder.Click += (s, e) => + { + try + { + if (Directory.Exists(LoggerService.LogDirectory)) + { + Process.Start(new ProcessStartInfo(LoggerService.LogDirectory) + { + UseShellExecute = true + }); + } + else + { + AnnounceA11y(Strings.Msg_FolderNotFound); + + GamepadMessageBox.Show( + this, + Strings.Msg_FolderNotFound, + Strings.Wrn_Title, + MessageBoxButtons.OK, + MessageBoxIcon.Warning, + gamepad: _gamepadController); + } + } + catch (Exception ex) + { + Debug.WriteLine($"[選單] tsmiOpenLogFolder.Click 失敗:{ex.Message}"); + } + }; + tsmiSettings.DropDownItems.Add(tsmiOpenLogFolder); + + return tsmiSettings; + } + + /// + /// 建立「進階設定」中的「視窗與操作」子選單 + /// + /// 視窗與操作子選單項目。 + private ToolStripMenuItem CreateWindowOperationsMenu() + { // 視窗與操作。 // 包含視窗還原、剪貼簿重試與切換緩衝等系統互動參數。 ToolStripMenuItem tsmiWinOps = new(ControlExtensions.GetMnemonicText(Strings.Menu_Settings_Window, 'W')) @@ -615,58 +909,6 @@ void AddModifierItem(string label, User32.KeyModifiers modValue) tsmiWinOps.DropDownItems.Add(new ToolStripSeparator()); - // 新增數值設定選單項目。 - // parent: 父選單項目。label: 標籤文字。mnemonic: 助記鍵字母。 - // getter: 取得目前值。setter: 設定新值。defValue: 預設值。min/max: 值域。 - // a11yHint: 選填的無障礙播報補充說明。 - void AddNumericItem( - ToolStripMenuItem parent, - string label, - char mnemonic, - Func getter, - Action setter, - int defValue, - int min, - int max, - string? a11yHint = null) - { - ToolStripMenuItem item = new(string.Empty) - { - AccessibleName = label, - // 將範圍資訊與補充說明封裝至 Metadata,支援動態 A11y 描述生成。 - Tag = new MenuMetadata(label, mnemonic, min, max, a11yHint), - }; - - item.Click += (s, e) => - { - try - { - int? val = AskForValue(label, getter(), defValue, min, max); - - if (val.HasValue) - { - setter(val.Value); - - AppSettings.Save(); - - RefreshMenu(); - } - - // 焦點還原。 - // 當數值輸入對話框關閉後,將焦點精確還原至原選單項,最佳化螢幕閱讀器導覽流暢度。 - _lastFocusedMenuItem?.Select(); - } - catch (Exception ex) - { - LoggerService.LogException(ex, $"數值設定 [{label}] 失敗"); - - Debug.WriteLine($"[選單] {label} 設定失敗:{ex.Message}"); - } - }; - - parent.DropDownItems.Add(item); - } - AddNumericItem( tsmiWinOps, Strings.Settings_WindowRestoreDelay, @@ -728,8 +970,75 @@ void AddNumericItem( }; tsmiWinOps.DropDownItems.Add(tsmiResetWinOps); - tsmiSettings.DropDownItems.Add(tsmiWinOps); + return tsmiWinOps; + } + + /// + /// 新增數值設定選單項目;點選後以數值輸入對話框調整並立即儲存 + /// + /// 父選單項目。 + /// 標籤文字。 + /// 助記鍵字母。 + /// 取得目前值。 + /// 設定新值。 + /// 預設值。 + /// 最小值。 + /// 最大值。 + /// 選填的無障礙播報補充說明。 + private void AddNumericItem( + ToolStripMenuItem parent, + string label, + char mnemonic, + Func getter, + Action setter, + int defValue, + int min, + int max, + string? a11yHint = null) + { + ToolStripMenuItem item = new(string.Empty) + { + AccessibleName = label, + // 將範圍資訊與補充說明封裝至 Metadata,支援動態 A11y 描述生成。 + Tag = new MenuMetadata(label, mnemonic, min, max, a11yHint), + }; + + item.Click += (s, e) => + { + try + { + int? val = AskForValue(label, getter(), defValue, min, max); + + if (val.HasValue) + { + setter(val.Value); + + AppSettings.Save(); + + RefreshMenu(); + } + // 焦點還原。 + // 當數值輸入對話框關閉後,將焦點精確還原至原選單項,最佳化螢幕閱讀器導覽流暢度。 + _lastFocusedMenuItem?.Select(); + } + catch (Exception ex) + { + LoggerService.LogException(ex, $"數值設定 [{label}] 失敗"); + + Debug.WriteLine($"[選單] {label} 設定失敗:{ex.Message}"); + } + }; + + parent.DropDownItems.Add(item); + } + + /// + /// 建立「進階設定」中的「回饋」子選單 + /// + /// 回饋子選單項目。 + private ToolStripMenuItem CreateFeedbackMenu() + { // 回饋。 // 集中管理震動開關與強度等回饋設定。 ToolStripMenuItem tsmiFeedback = new(ControlExtensions.GetMnemonicText(Strings.Menu_Settings_Feedback, 'F')) @@ -874,8 +1183,15 @@ void AddNumericItem( }; tsmiFeedback.DropDownItems.Add(tsmiResetFeedback); - tsmiSettings.DropDownItems.Add(tsmiFeedback); + return tsmiFeedback; + } + /// + /// 建立「進階設定」中的「遊戲控制器」子選單 + /// + /// 遊戲控制器子選單項目。 + private ToolStripMenuItem CreateGamepadSettingsMenu() + { // 控制器。 // 提供遊戲控制器輸入 API、死區、重複輸入與校正狀態重設等設定。 ToolStripMenuItem tsmiGamepad = new(ControlExtensions.GetMnemonicText(Strings.Menu_Settings_Gamepad, 'G')) @@ -1234,206 +1550,15 @@ void AddFaceLayoutItem(AppSettings.GamepadFaceButtonMode mode) }; tsmiGamepad.DropDownItems.Add(tsmiResetGamepad); - tsmiSettings.DropDownItems.Add(tsmiGamepad); - tsmiSettings.DropDownItems.Add(new ToolStripSeparator()); - - // 歷程容量(需重啟)。 - // 控制記憶體中保留的輸入歷程筆數上限。 - ToolStripMenuItem tsmiCap = new(string.Empty) - { - AccessibleName = Strings.Settings_HistoryCapacity, - Tag = new MenuMetadata(Strings.Settings_HistoryCapacity, 'H', 1, 1000) - }; - tsmiCap.Click += (s, e) => - { - try - { - int? val = AskForValue(Strings.Settings_HistoryCapacity, AppSettings.Current.HistoryCapacity, 100, 1, 1000); - - if (val.HasValue && - val != AppSettings.Current.HistoryCapacity) - { - AppSettings.Current.HistoryCapacity = val.Value; - AppSettings.Save(); - - RefreshMenu(); - - AskForRestart(); - } - } - catch (Exception ex) - { - LoggerService.LogException(ex, "歷程容量設定失敗"); - - Debug.WriteLine($"[選單] tsmiCap.Click 失敗:{ex.Message}"); - } - }; - tsmiSettings.DropDownItems.Add(tsmiCap); - - tsmiSettings.DropDownItems.Add(new ToolStripSeparator()); - - // 開啟資料夾。 - // 開啟應用程式設定與資料檔所在的資料夾。 - ToolStripMenuItem tsmiOpenDataFolder = new(ControlExtensions.GetMnemonicText(Strings.Menu_OpenDataFolder, 'O')) - { - AccessibleName = Strings.Menu_OpenDataFolder, - AccessibleDescription = Strings.Menu_OpenDataFolder_Desc - }; - tsmiOpenDataFolder.Click += (s, e) => - { - try - { - if (Directory.Exists(AppSettings.ConfigDirectory)) - { - Process.Start(new ProcessStartInfo(AppSettings.ConfigDirectory) - { - UseShellExecute = true - }); - } - else - { - AnnounceA11y(Strings.Msg_FolderNotFound); - - GamepadMessageBox.Show( - this, - Strings.Msg_FolderNotFound, - Strings.Wrn_Title, - MessageBoxButtons.OK, - MessageBoxIcon.Warning, - gamepad: _gamepadController); - } - } - catch (Exception ex) - { - Debug.WriteLine($"[選單] tsmiOpenDataFolder.Click 失敗:{ex.Message}"); - } - }; - tsmiSettings.DropDownItems.Add(tsmiOpenDataFolder); - - // 開啟日誌資料夾。 - // 開啟本機例外與診斷紀錄所在的日誌目錄。 - ToolStripMenuItem tsmiOpenLogFolder = new(ControlExtensions.GetMnemonicText(Strings.Menu_OpenLogFolder, 'L')) - { - AccessibleName = Strings.Menu_OpenLogFolder, - AccessibleDescription = Strings.Menu_OpenLogFolder_Desc - }; - tsmiOpenLogFolder.Click += (s, e) => - { - try - { - if (Directory.Exists(LoggerService.LogDirectory)) - { - Process.Start(new ProcessStartInfo(LoggerService.LogDirectory) - { - UseShellExecute = true - }); - } - else - { - AnnounceA11y(Strings.Msg_FolderNotFound); - - GamepadMessageBox.Show( - this, - Strings.Msg_FolderNotFound, - Strings.Wrn_Title, - MessageBoxButtons.OK, - MessageBoxIcon.Warning, - gamepad: _gamepadController); - } - } - catch (Exception ex) - { - Debug.WriteLine($"[選單] tsmiOpenLogFolder.Click 失敗:{ex.Message}"); - } - }; - tsmiSettings.DropDownItems.Add(tsmiOpenLogFolder); - - // 清除歷程。 - // 清空目前只保存在記憶體中的輸入歷程資料。 - ToolStripMenuItem tsmiClearHistory = new(ControlExtensions.GetMnemonicText(Strings.Menu_ClearHistory, 'C')) - { - Name = "TsmiClearHistory", - AccessibleName = Strings.Menu_ClearHistory, - AccessibleDescription = Strings.Menu_ClearHistory_Desc - }; - tsmiClearHistory.Click += (s, e) => - { - try - { - _historyService?.Clear(); - - // 清除後主動將焦點拉回輸入框,確保使用者能直接開始輸入。 - TBInput.Focus(); - - FeedbackService.PlaySound(SystemSounds.Asterisk); - - AnnounceA11y(Strings.Msg_InputCleared); - } - catch (Exception ex) - { - Debug.WriteLine($"[選單] tsmiClearHistory.Click 失敗:{ex.Message}"); - } - }; - - // 離開。 - // 關閉主視窗並結束整個應用程式流程。 - ToolStripMenuItem tsmiExit = new(ControlExtensions.GetMnemonicText(Strings.Menu_Exit, 'X')) - { - AccessibleName = Strings.Menu_Exit, - AccessibleDescription = Strings.A11y_Menu_Exit_Desc - }; - tsmiExit.Click += (s, e) => - { - try - { - Close(); - } - catch (Exception ex) - { - Debug.WriteLine($"[選單] tsmiExit.Click 失敗:{ex.Message}"); - } - }; - - // 說明(WCAG 3.3.5)。 - // 顯示鍵盤與遊戲控制器操作對照的說明對話框。 - ToolStripMenuItem tsmiHelp = new(ControlExtensions.GetMnemonicText(Strings.Menu_Help, 'H')) - { - AccessibleName = Strings.Menu_Help, - AccessibleDescription = Strings.Menu_Help_Desc - }; - tsmiHelp.Click += (s, e) => - { - try - { - ShowHelpDialog(); - } - catch (Exception ex) - { - Debug.WriteLine($"[選單] tsmiHelp.Click 失敗:{ex.Message}"); - } - }; - - // 使用共享快取取得選單字型。 - _cmsInput.Font = GetSharedA11yFont(DeviceDpi); - _cmsInput.Opened += (s, e) => EnsureContextMenuReadyForKeyboard(_cmsInput); - _cmsInput.PreviewKeyDown += ContextMenu_PreviewKeyDown; - _cmsInput.KeyDown += ContextMenu_KeyDown; - _cmsInput.Closed += (s, e) => RestorePhraseSubMenuAutoClose(); - _cmsInput.Closing += (s, e) => - { - try - { - if (ShouldSuppressPhraseMenuClose(e.CloseReason)) - { - e.Cancel = true; - } - } - catch (Exception ex) - { - Debug.WriteLine($"[選單] _cmsInput.Closing 失敗:{ex.Message}"); - } - }; + return tsmiGamepad; + } + /// + /// 建立右鍵選單的「片語」子選單;項目會在每次展開前依目前片語重建 + /// + [MemberNotNull(nameof(_tsmiPhrases))] + private void InitializePhrasesMenu() + { // 片語子選單。 _tsmiPhrases = new ToolStripMenuItem(ControlExtensions.GetMnemonicText(Strings.Menu_Phrases, 'F')) { @@ -1501,54 +1626,6 @@ void AddFaceLayoutItem(AppSettings.GamepadFaceButtonMode mode) Debug.WriteLine($"[選單] _tsmiPhrases.DropDown.Closing 失敗:{ex.Message}"); } }; - - if (SystemHelper.IsRunningOnGamescope()) - { - _tsmiRecoverGamescopeSurface = new ToolStripMenuItem(Strings.Menu_RecoverGamescopeSurface) - { - AccessibleName = Strings.Menu_RecoverGamescopeSurface, - AccessibleDescription = Strings.Menu_RecoverGamescopeSurface_Desc - }; - _tsmiRecoverGamescopeSurface.Click += (s, e) => - { - try - { - RecoverGamescopeMainSurface(); - } - catch (Exception ex) - { - LoggerService.LogException(ex, "tsmiRecoverGamescopeSurface.Click 失敗"); - - Debug.WriteLine($"[選單] tsmiRecoverGamescopeSurface.Click 失敗:{ex.Message}"); - } - }; - } - - _cmsInput.Items.Add(_tsmiPrivacyMode); - _cmsInput.Items.Add(_tsmiA11yInterrupt); - _cmsInput.Items.Add(_tsmiAnimatedVisualAlerts); - _cmsInput.Items.Add(_tsmiMinimizeOnReturn); - _cmsInput.Items.Add(new ToolStripSeparator()); - _cmsInput.Items.Add(_tsmiPhrases); - _cmsInput.Items.Add(new ToolStripSeparator()); - _cmsInput.Items.Add(tsmiHotkeySettings); - _cmsInput.Items.Add(tsmiSettings); - _cmsInput.Items.Add(new ToolStripSeparator()); - _cmsInput.Items.Add(tsmiClearHistory); - if (_tsmiRecoverGamescopeSurface != null) - { - _cmsInput.Items.Add(new ToolStripSeparator()); - _cmsInput.Items.Add(_tsmiRecoverGamescopeSurface); - } - - _cmsInput.Items.Add(new ToolStripSeparator()); - _cmsInput.Items.Add(tsmiHelp); - _cmsInput.Items.Add(new ToolStripSeparator()); - _cmsInput.Items.Add(tsmiExit); - - // 綁定選單至容器控制項,確保 TBInput 能保留其原始的 Windows 右鍵選單(剪下、複製、貼上)。 - PInputHost.ContextMenuStrip = _cmsInput; - TLPHost.ContextMenuStrip = _cmsInput; } /// From 5fa4c6c6eb3a8ebc10ba742eb83e3601e72c5c14 Mon Sep 17 00:00:00 2001 From: perditavojo <117562794+perditavojo@users.noreply.github.com> Date: Sun, 27 Sep 2026 07:19:45 +0800 Subject: [PATCH 15/17] =?UTF-8?q?refactor(dialogs):=20=E5=B0=87=E5=9B=9B?= =?UTF-8?q?=E5=80=8B=E5=A4=A7=E5=9E=8B=E5=B0=8D=E8=A9=B1=E6=A1=86=E4=BE=9D?= =?UTF-8?q?=E8=81=B7=E8=B2=AC=E6=8B=86=E6=88=90=20partial=20=E6=AA=94?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit NumericInputDialog(2,422 行)、PhraseEditDialog(2,201 行)、PhraseManagerDialog(2,012 行) 與 GamepadCalibrationDialog(1,217 行)比照 MainForm 的分部檔做法拆分,只搬移成員、不改任何邏輯: - .Layout.cs:DPI 與系統偏好變更、最小尺寸、智慧定位與焦點視覺。 - .Gamepad.cs:控制器事件訂閱、方向與按鍵處理、選取延伸。 - .A11y.cs:報讀、閃爍與驗證回饋。 - 各自特有的分部:NumericInputDialog.AccessibleNumericUpDown、PhraseManagerDialog.Phrases(清單操作)、GamepadCalibrationDialog.Visualizer(校正繪製)。 - 欄位、建構函式與對話框生命週期保留在主檔;PhraseManagerDialog 的 #region 由分部檔取代。 - 各檔只保留實際使用的 using(以 IDE0005 分析移除)。 已比對原檔與拆分後所有檔案的程式碼行,除類別宣告改為 partial、新增檔頭與移除 #region 外完全一致。 建置 0 警告;全部測試通過,MainFormUiSmokeTests 11 項於互動式桌面通過。 Co-Authored-By: Claude Opus 5.5 --- .../GamepadCalibrationDialog.Gamepad.cs | 375 +++++ .../GamepadCalibrationDialog.Layout.cs | 177 ++ .../GamepadCalibrationDialog.Visualizer.cs | 258 +++ .../Core/Controls/GamepadCalibrationDialog.cs | 766 +-------- .../Core/Controls/NumericInputDialog.A11y.cs | 158 ++ ...ericInputDialog.AccessibleNumericUpDown.cs | 130 ++ .../Controls/NumericInputDialog.Gamepad.cs | 629 +++++++ .../Controls/NumericInputDialog.Layout.cs | 442 +++++ .../Core/Controls/NumericInputDialog.cs | 1393 +--------------- .../Core/Controls/PhraseEditDialog.A11y.cs | 305 ++++ .../Core/Controls/PhraseEditDialog.Gamepad.cs | 715 ++++++++ .../Core/Controls/PhraseEditDialog.Layout.cs | 435 +++++ .../Core/Controls/PhraseEditDialog.cs | 1418 +--------------- .../Core/Controls/PhraseManagerDialog.A11y.cs | 64 + .../Controls/PhraseManagerDialog.Gamepad.cs | 686 ++++++++ .../Controls/PhraseManagerDialog.Layout.cs | 339 ++++ .../Controls/PhraseManagerDialog.Phrases.cs | 408 +++++ .../Core/Controls/PhraseManagerDialog.cs | 1447 +---------------- 18 files changed, 5186 insertions(+), 4959 deletions(-) create mode 100644 src/InputBox/Core/Controls/GamepadCalibrationDialog.Gamepad.cs create mode 100644 src/InputBox/Core/Controls/GamepadCalibrationDialog.Layout.cs create mode 100644 src/InputBox/Core/Controls/GamepadCalibrationDialog.Visualizer.cs create mode 100644 src/InputBox/Core/Controls/NumericInputDialog.A11y.cs create mode 100644 src/InputBox/Core/Controls/NumericInputDialog.AccessibleNumericUpDown.cs create mode 100644 src/InputBox/Core/Controls/NumericInputDialog.Gamepad.cs create mode 100644 src/InputBox/Core/Controls/NumericInputDialog.Layout.cs create mode 100644 src/InputBox/Core/Controls/PhraseEditDialog.A11y.cs create mode 100644 src/InputBox/Core/Controls/PhraseEditDialog.Gamepad.cs create mode 100644 src/InputBox/Core/Controls/PhraseEditDialog.Layout.cs create mode 100644 src/InputBox/Core/Controls/PhraseManagerDialog.A11y.cs create mode 100644 src/InputBox/Core/Controls/PhraseManagerDialog.Gamepad.cs create mode 100644 src/InputBox/Core/Controls/PhraseManagerDialog.Layout.cs create mode 100644 src/InputBox/Core/Controls/PhraseManagerDialog.Phrases.cs diff --git a/src/InputBox/Core/Controls/GamepadCalibrationDialog.Gamepad.cs b/src/InputBox/Core/Controls/GamepadCalibrationDialog.Gamepad.cs new file mode 100644 index 0000000..1993ed8 --- /dev/null +++ b/src/InputBox/Core/Controls/GamepadCalibrationDialog.Gamepad.cs @@ -0,0 +1,375 @@ +using InputBox.Core.Configuration; +using InputBox.Core.Extensions; +using InputBox.Core.Feedback; +using InputBox.Core.Input; +using InputBox.Core.Services; +using InputBox.Core.Utilities; +using InputBox.Resources; +using System.ComponentModel; +using System.Diagnostics; +using System.Media; + +namespace InputBox.Core.Controls; + +// 阻擋設計工具。 +partial class DesignerBlocker { }; + +/// +/// 顯示遊戲控制器校準狀態的視覺化診斷對話框(遊戲控制器與輸入分部)。 +/// 本分部檔案包含遊戲控制器事件訂閱、確認與取消、按鈕焦點導覽,以及校正狀態重設等成員。 +/// +internal sealed partial class GamepadCalibrationDialog +{ + /// + /// 指派控制器實例,並同步診斷快照與事件訂閱。 + /// + [Browsable(false)] + [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public IGamepadController? GamepadController + { + get => _gamepadController; + set + { + if (ReferenceEquals(_gamepadController, value)) + { + return; + } + + UnsubscribeGamepadEvents(); + _gamepadController = value; + + if (_gamepadController != null) + { + SubscribeGamepadEvents(); + } + + UpdateSnapshotFromController(); + } + } + + /// + /// 訂閱目前控制器的所有輸入事件。 + /// + private void SubscribeGamepadEvents() + { + if (_gamepadController == null) + { + return; + } + + GamepadFaceButtonProfile profile = GamepadFaceButtonProfile.GetActiveProfile(); + + _gamepadController.APressed += profile.ConfirmOnSouth ? HandleGamepadConfirm : HandleGamepadCancel; + _gamepadController.StartPressed += HandleGamepadConfirm; + _gamepadController.BPressed += profile.ConfirmOnSouth ? HandleGamepadCancel : HandleGamepadConfirm; + _gamepadController.BackPressed += HandleGamepadCancel; + _gamepadController.YPressed += HandleGamescopeSurfaceRecovery; + _gamepadController.LeftPressed += HandleDPadPrevious; + _gamepadController.LeftRepeat += HandleDPadPrevious; + _gamepadController.UpPressed += HandleDPadPrevious; + _gamepadController.UpRepeat += HandleDPadPrevious; + _gamepadController.RightPressed += HandleDPadNext; + _gamepadController.RightRepeat += HandleDPadNext; + _gamepadController.DownPressed += HandleDPadNext; + _gamepadController.DownRepeat += HandleDPadNext; + _gamepadController.ConnectionChanged += HandleGamepadConnectionChanged; + } + + /// + /// 取消訂閱目前控制器的所有輸入事件。 + /// + private void UnsubscribeGamepadEvents() + { + try + { + if (_gamepadController == null) + { + return; + } + + _gamepadController.APressed -= HandleGamepadConfirm; + _gamepadController.APressed -= HandleGamepadCancel; + _gamepadController.StartPressed -= HandleGamepadConfirm; + _gamepadController.BPressed -= HandleGamepadConfirm; + _gamepadController.BPressed -= HandleGamepadCancel; + _gamepadController.BackPressed -= HandleGamepadCancel; + _gamepadController.YPressed -= HandleGamescopeSurfaceRecovery; + _gamepadController.LeftPressed -= HandleDPadPrevious; + _gamepadController.LeftRepeat -= HandleDPadPrevious; + _gamepadController.UpPressed -= HandleDPadPrevious; + _gamepadController.UpRepeat -= HandleDPadPrevious; + _gamepadController.RightPressed -= HandleDPadNext; + _gamepadController.RightRepeat -= HandleDPadNext; + _gamepadController.DownPressed -= HandleDPadNext; + _gamepadController.DownRepeat -= HandleDPadNext; + _gamepadController.ConnectionChanged -= HandleGamepadConnectionChanged; + } + catch (Exception ex) + { + Debug.WriteLine($"[GamepadCalibrationDialog] 取消訂閱控制器事件失敗:{ex.Message}"); + } + } + + /// + /// 控制器連線狀態變更時更新快照並播報連線訊息。 + /// + /// 控制器是否已連線。 + private void HandleGamepadConnectionChanged(bool isConnected) + { + try + { + this.SafeBeginInvoke(() => + { + UpdateSnapshotFromController(); + _announcer?.Announce(FormatConnectionAnnouncement(isConnected, _gamepadController?.DeviceName), true); + }); + } + catch (Exception ex) + { + LoggerService.LogException(ex, "GamepadCalibrationDialog.HandleGamepadConnectionChanged 失敗"); + Debug.WriteLine($"[GamepadCalibrationDialog] 控制器連線變更處理失敗:{ex.Message}"); + } + } + + /// + /// 處理控制器確認按鍵,觸發目前焦點按鈕或預設按鈕的點擊。 + /// + private void HandleGamepadConfirm() + { + try + { + this.SafeBeginInvoke(() => + { + try + { + if (IsDisposed) + { + return; + } + + if (ActiveControl is Button activeButton && + activeButton.Enabled) + { + activeButton.PerformClick(); + } + else + { + (_btnReset ?? AcceptButton as Button)?.PerformClick(); + } + } + catch (Exception ex) + { + Debug.WriteLine($"[GamepadCalibrationDialog] HandleGamepadConfirm UI 失敗:{ex.Message}"); + } + }); + } + catch (Exception ex) + { + Debug.WriteLine($"[GamepadCalibrationDialog] HandleGamepadConfirm 失敗:{ex.Message}"); + } + } + + /// + /// 處理控制器取消按鍵,觸發關閉按鈕或直接關閉對話框。 + /// + private void HandleGamepadCancel() + { + try + { + this.SafeBeginInvoke(() => + { + try + { + if (IsDisposed) + { + return; + } + + if (_btnClose != null && + !_btnClose.IsDisposed) + { + _btnClose.PerformClick(); + } + else + { + DialogResult = DialogResult.Cancel; + Close(); + } + } + catch (Exception ex) + { + Debug.WriteLine($"[GamepadCalibrationDialog] HandleGamepadCancel UI 失敗:{ex.Message}"); + } + }); + } + catch (Exception ex) + { + Debug.WriteLine($"[GamepadCalibrationDialog] HandleGamepadCancel 失敗:{ex.Message}"); + } + } + + /// + /// 處理 Gamescope 專用 surface recovery 組合鍵。 + /// + private void HandleGamescopeSurfaceRecovery() + { + GamescopeSurfaceRecovery.TryRecoverFromGamepadChord( + this, + RecreateHandle, + _gamepadController, + context: "GamepadCalibrationDialog Gamescope surface recovery 失敗"); + } + + /// + /// 處理 D-Pad 向前(左/上)輸入,在搖桿不干擾時移動焦點至前一個按鈕。 + /// + private void HandleDPadPrevious() + { + if (ShouldHandleDirectionalFocusNavigation(_gamepadController?.CurrentCalibrationSnapshot ?? _snapshot)) + { + FocusPreviousButton(); + } + } + + /// + /// 處理 D-Pad 向後(右/下)輸入,在搖桿不干擾時移動焦點至下一個按鈕。 + /// + private void HandleDPadNext() + { + if (ShouldHandleDirectionalFocusNavigation(_gamepadController?.CurrentCalibrationSnapshot ?? _snapshot)) + { + FocusNextButton(); + } + } + + /// + /// 將焦點移至前一個按鈕。 + /// + private void FocusPreviousButton() => MoveButtonFocus(-1); + + /// + /// 將焦點移至下一個按鈕。 + /// + private void FocusNextButton() => MoveButtonFocus(+1); + + /// + /// 依方向在重設與關閉按鈕之間移動焦點。 + /// + /// 方向值;負值移往重設按鈕,正值移往關閉按鈕。 + private void MoveButtonFocus(int direction) + { + try + { + this.SafeBeginInvoke(() => + { + if (IsDisposed || _btnReset == null || _btnClose == null) + { + return; + } + + Button nextButton = direction < 0 ? + ActiveControl == _btnClose ? _btnReset : _btnClose : + ActiveControl == _btnReset ? _btnClose : _btnReset; + + nextButton.Focus(); + }); + } + catch (Exception ex) + { + Debug.WriteLine($"[GamepadCalibrationDialog] MoveButtonFocus 失敗:{ex.Message}"); + } + } + + /// + /// 從控制器取得最新校準快照,更新狀態文字並觸發畫面重繪。 + /// + private void UpdateSnapshotFromController() + { + GamepadCalibrationSnapshot snapshot = _gamepadController?.CurrentCalibrationSnapshot ?? new GamepadCalibrationSnapshot + { + IsConnected = false, + ThumbDeadzoneEnter = AppSettings.Current.ThumbDeadzoneEnter, + ThumbDeadzoneExit = AppSettings.Current.ThumbDeadzoneExit, + TimestampUtc = DateTime.UtcNow + }; + + _snapshot = snapshot; + UpdateStatusText(); + _surface?.Invalidate(); + } + + /// + /// 判斷目前搖桿是否靜止到足以安全處理方向焦點移動,避免搖桿偏移誤觸焦點導覽。 + /// + /// 目前的校準狀態快照。 + /// 若搖桿偏移量低於安全閾值(或控制器未連線)則回傳 true。 + internal static bool ShouldHandleDirectionalFocusNavigation(GamepadCalibrationSnapshot snapshot) + { + if (!snapshot.IsConnected) + { + return true; + } + + float normalizedDeadzone = GamepadCalibrationVisualizerMapper.CalculateDeadzoneRadius( + Math.Max(snapshot.ThumbDeadzoneEnter, snapshot.ThumbDeadzoneExit)); + + // 門檻必須低於 normalizedDeadzone,確保 LS 剛跨越 ThumbDeadzoneEnter + // 觸發搖桿→D-Pad 映射的瞬間,保護邏輯已阻止方向焦點移動。 + float navigationThreshold = Math.Clamp(normalizedDeadzone * 0.75f, 0.06f, 0.18f); + + return MathF.Abs(snapshot.RawLeftX) <= navigationThreshold && + MathF.Abs(snapshot.RawLeftY) <= navigationThreshold && + MathF.Abs(snapshot.CorrectedLeftX) <= navigationThreshold && + MathF.Abs(snapshot.CorrectedLeftY) <= navigationThreshold; + } + + /// + /// 重設控制器校準資料,播放音效與震動回饋並更新快照。 + /// + private void ResetCalibration() + { + try + { + _gamepadController?.ResetCalibration(); + SystemSounds.Asterisk.Play(); + PlayResetCalibrationFeedbackAsync().SafeFireAndForget(); + UpdateSnapshotFromController(); + _announcer?.Announce(Strings.A11y_Gamepad_CalibrationReset, true); + } + catch (Exception ex) + { + LoggerService.LogException(ex, "重設校準視覺化狀態失敗"); + Debug.WriteLine($"[GamepadCalibrationDialog] ResetCalibration 失敗:{ex.Message}"); + } + } + + /// + /// 播放重設校準的三段式震動序列回饋。 + /// + /// 代表震動序列播放過程的非同步工作。 + private async Task PlayResetCalibrationFeedbackAsync() + { + IGamepadController? controller = _gamepadController; + + if (controller == null) + { + return; + } + + CancellationToken token = _cts?.Token ?? CancellationToken.None; + + VibrationProfile[] sequence = + [ + new(22000, 26, 1.0f, 0.18f, 0.52f, 0.04f), + new(22000, 26, 0.18f, 1.0f, 0.04f, 0.52f), + new(18000, 22, 0.62f, 0.62f, 0.18f, 0.18f) + ]; + + foreach (VibrationProfile profile in sequence) + { + token.ThrowIfCancellationRequested(); + await controller.VibrateAsync(profile, VibrationPriority.Normal, token); + await Task.Delay(20, token); + } + } +} diff --git a/src/InputBox/Core/Controls/GamepadCalibrationDialog.Layout.cs b/src/InputBox/Core/Controls/GamepadCalibrationDialog.Layout.cs new file mode 100644 index 0000000..c906899 --- /dev/null +++ b/src/InputBox/Core/Controls/GamepadCalibrationDialog.Layout.cs @@ -0,0 +1,177 @@ +using InputBox.Core.Configuration; +using InputBox.Core.Extensions; +using InputBox.Core.Utilities; +using System.Diagnostics; + +namespace InputBox.Core.Controls; + +// 阻擋設計工具。 +partial class DesignerBlocker { }; + +/// +/// 顯示遊戲控制器校準狀態的視覺化診斷對話框(版面配置分部)。 +/// 本分部檔案包含 DPI 變更處理、最小尺寸與智慧定位等成員。 +/// +internal sealed partial class GamepadCalibrationDialog +{ + /// + /// 視窗 Handle 建立後,更新最小尺寸並定位至初始位置。 + /// + /// 事件引數。 + protected override void OnHandleCreated(EventArgs e) + { + try + { + base.OnHandleCreated(e); + UpdateMinimumSize(forceRecalculate: true); + this.SafeBeginInvoke(ApplySmartPosition); + } + catch (Exception ex) + { + Debug.WriteLine($"[GamepadCalibrationDialog] OnHandleCreated 失敗:{ex.Message}"); + } + } + + /// + /// 使用者完成調整視窗大小後,重新套用智慧定位。 + /// + /// 事件引數。 + protected override void OnResizeEnd(EventArgs e) + { + try + { + base.OnResizeEnd(e); + ApplySmartPosition(); + } + catch (Exception ex) + { + Debug.WriteLine($"[GamepadCalibrationDialog] OnResizeEnd 失敗:{ex.Message}"); + } + } + + /// + /// DPI 變更時更新字型、最小尺寸,並重新套用智慧定位。 + /// + /// 包含新舊 DPI 值的事件引數。 + protected override void OnDpiChanged(DpiChangedEventArgs e) + { + try + { + base.OnDpiChanged(e); + this.SafeBeginInvoke(() => + { + try + { + _a11yFont = MainForm.GetSharedA11yFont(DeviceDpi); + + if (_a11yFont != null) + { + _lblIntro?.Font = _a11yFont; + + _lblStatus?.Font = _a11yFont; + + _btnReset?.Font = _a11yFont; + + _btnClose?.Font = _a11yFont; + } + + UpdateMinimumSize(forceRecalculate: true); + ApplySmartPosition(); + _surface?.Invalidate(); + } + catch (Exception ex) + { + Debug.WriteLine($"[GamepadCalibrationDialog] OnDpiChanged 延遲邏輯失敗:{ex.Message}"); + } + }); + } + catch (Exception ex) + { + Debug.WriteLine($"[GamepadCalibrationDialog] OnDpiChanged 失敗:{ex.Message}"); + } + } + + /// + /// 依目前 DPI 與可用工作區重新計算並套用對話框的最小尺寸。 + /// + /// 是否強制重新計算,忽略 DPI 未變更的快取防呆。 + private void UpdateMinimumSize(bool forceRecalculate = false) + { + try + { + if (_layoutHost == null || + _surface == null || + _lblIntro == null || + _lblStatus == null || + _btnReset == null || + _btnClose == null || + _buttonRow == null) + { + return; + } + + float currentDpi = DeviceDpi; + + if (!DialogLayoutHelper.TryBeginDpiLayout(currentDpi, ref _lastAppliedDpi, forceRecalculate)) + { + return; + } + + float scale = currentDpi / AppSettings.BaseDpi; + Rectangle workArea = Screen.GetWorkingArea(this); + (int maxFitWidth, int maxFitHeight) = DialogLayoutHelper.GetMaxFitSize(workArea); + + int targetWindowWidth = Math.Clamp((int)(600 * scale), Math.Min(maxFitWidth, (int)(420 * scale)), maxFitWidth); + int contentWidth = Math.Max(220, targetWindowWidth - Padding.Horizontal); + + _lblIntro.MaximumSize = new Size(contentWidth, 0); + _lblIntro.Margin = new Padding(0, 0, 0, (int)(6 * scale)); + + Font boldFont = MainForm.GetSharedA11yFont(DeviceDpi, FontStyle.Bold, (_a11yFont ?? Font).FontFamily); + DialogLayoutHelper.UpdateButtonMinimumSize(_btnReset, boldFont, scale, 120, 56, 32, 20); + DialogLayoutHelper.UpdateButtonMinimumSize(_btnClose, boldFont, scale, 120, 56, 32, 20); + + int buttonHeight = _buttonRow.GetPreferredSize(new Size(contentWidth, 0)).Height; + int introHeight = _lblIntro.GetPreferredSize(new Size(contentWidth, 0)).Height; + int statusHeight = Math.Max((int)(96 * scale), _lblStatus.GetPreferredSize(new Size(contentWidth, 0)).Height); + int availableSurfaceHeight = Math.Max((int)(160 * scale), maxFitHeight - Padding.Vertical - introHeight - statusHeight - buttonHeight - (int)(36 * scale)); + int surfaceHeight = Math.Min((int)(280 * scale), availableSurfaceHeight); + + _surface.MinimumSize = new Size(contentWidth, surfaceHeight); + _surface.Size = _surface.MinimumSize; + _lblStatus.MinimumSize = new Size(contentWidth, statusHeight); + _lblStatus.Size = _lblStatus.MinimumSize; + _buttonRow.WrapContents = _buttonRow.GetPreferredSize(Size.Empty).Width > contentWidth; + + int preferredHeight = _layoutHost.GetPreferredSize(new Size(contentWidth, 0)).Height + Padding.Vertical; + int targetWindowHeight = Math.Min(preferredHeight, maxFitHeight); + int minWindowWidth = Math.Min(targetWindowWidth, maxFitWidth); + int minWindowHeight = Math.Min(targetWindowHeight, maxFitHeight); + + ClientSize = new Size(minWindowWidth, targetWindowHeight); + DialogLayoutHelper.ClampFormSize(this, minWindowWidth, minWindowHeight, maxFitWidth, maxFitHeight, ApplySmartPosition); + } + catch (Exception ex) + { + Debug.WriteLine($"[GamepadCalibrationDialog] UpdateMinimumSize 失敗:{ex.Message}"); + } + } + + /// + /// 將對話框位置限制在螢幕可視範圍內,避免視窗超出邊界。 + /// + private void ApplySmartPosition() + { + try + { + if (InputBoxLayoutManager.TryGetClampedLocation(this, out Point clampedLocation)) + { + Location = clampedLocation; + } + } + catch (Exception ex) + { + Debug.WriteLine($"[GamepadCalibrationDialog] ApplySmartPosition 失敗:{ex.Message}"); + } + } +} diff --git a/src/InputBox/Core/Controls/GamepadCalibrationDialog.Visualizer.cs b/src/InputBox/Core/Controls/GamepadCalibrationDialog.Visualizer.cs new file mode 100644 index 0000000..d1c8090 --- /dev/null +++ b/src/InputBox/Core/Controls/GamepadCalibrationDialog.Visualizer.cs @@ -0,0 +1,258 @@ +using InputBox.Core.Configuration; +using InputBox.Core.Input; +using InputBox.Resources; +using System.Drawing.Drawing2D; + +namespace InputBox.Core.Controls; + +// 阻擋設計工具。 +partial class DesignerBlocker { }; + +/// +/// 顯示遊戲控制器校準狀態的視覺化診斷對話框(校正視覺化分部)。 +/// 本分部檔案包含搖桿校正繪製面板、狀態文字格式化與搖桿軌跡繪製等成員。 +/// +internal sealed partial class GamepadCalibrationDialog +{ + /// + /// 使用雙緩衝避免繪圖閃爍。 + /// + private sealed class BufferedPanel : Panel + { + /// + /// 初始化 BufferedPanel,啟用雙緩衝與縮放重繪。 + /// + public BufferedPanel() + { + DoubleBuffered = true; + ResizeRedraw = true; + TabStop = false; + } + } + + /// + /// 依目前快照更新狀態標籤文字,並同步重設按鈕的啟用狀態。 + /// + private void UpdateStatusText() + { + if (_lblStatus == null) + { + return; + } + + _lblStatus.Text = FormatStatusText(_snapshot); + + _btnReset?.Enabled = _snapshot.IsConnected; + } + + /// + /// 依連線狀態與裝置名稱產生無障礙廣播訊息字串。 + /// + /// 控制器是否已連線。 + /// 裝置名稱;可為 null。 + /// 格式化後的連線狀態廣播訊息。 + internal static string FormatConnectionAnnouncement(bool isConnected, string? deviceName) + { + string template = isConnected ? + Strings.A11y_Gamepad_Connected : + Strings.A11y_Gamepad_Disconnected; + + string message = string.Format(template, deviceName?.Trim() ?? string.Empty); + + while (message.Contains(" ", StringComparison.Ordinal)) + { + message = message.Replace(" ", " ", StringComparison.Ordinal); + } + + return message.Replace(" .", ".", StringComparison.Ordinal).Trim(); + } + + /// + /// 依校準快照產生狀態文字標籤內容。 + /// + /// 目前的校準狀態快照。 + /// 格式化後的狀態文字;控制器未連線時回傳中斷連線提示訊息。 + internal static string FormatStatusText(GamepadCalibrationSnapshot snapshot) + { + if (!snapshot.IsConnected) + { + return Strings.Dialog_GamepadCalibrationVisualizer_StatusDisconnected; + } + + return string.Format( + Strings.Dialog_GamepadCalibrationVisualizer_StatusConnected, + FormatAxis(snapshot.RawLeftX), + FormatAxis(snapshot.RawLeftY), + FormatAxis(snapshot.CorrectedLeftX), + FormatAxis(snapshot.CorrectedLeftY), + FormatAxis(snapshot.RawRightX), + FormatAxis(snapshot.RawRightY), + FormatAxis(snapshot.CorrectedRightX), + FormatAxis(snapshot.CorrectedRightY), + snapshot.ThumbDeadzoneEnter, + snapshot.ThumbDeadzoneExit); + } + + /// + /// 將正規化軸值格式化為帶符號的兩位小數字串。 + /// + /// 正規化軸值(-1.0 ~ 1.0)。 + /// 格式化後的字串,例如 "+0.75" 或 "-0.12"。 + private static string FormatAxis(float value) + { + return value.ToString("+0.00;-0.00;0.00"); + } + + /// + /// 繪製校準視覺化畫布,包含雙搖桿軌跡圖與死區圓圈。 + /// + /// 事件來源。 + /// 包含繪圖 Graphics 的事件引數。 + private void HandleSurfacePaint(object? sender, PaintEventArgs e) + { + if (_surface == null) + { + return; + } + + Graphics graphics = e.Graphics; + graphics.SmoothingMode = SmoothingMode.AntiAlias; + graphics.Clear(SystemColors.Window); + + Rectangle clientRect = _surface.ClientRectangle; + + if (clientRect.Width <= 20 || clientRect.Height <= 20) + { + return; + } + + float s = DeviceDpi / AppSettings.BaseDpi; + int margin = (int)(12 * s); + RectangleF contentBounds = new( + clientRect.Left + margin, + clientRect.Top + margin, + clientRect.Width - (margin * 2), + clientRect.Height - (margin * 2)); + + Color axisColor = SystemInformation.HighContrast ? SystemColors.WindowText : Color.DimGray; + Color deadzoneColor = SystemInformation.HighContrast ? SystemColors.Highlight : Color.FromArgb(72, 120, 120, 120); + Color rawColor = SystemInformation.HighContrast ? SystemColors.WindowText : Color.FromArgb(90, 90, 90); + Color correctedColor = SystemInformation.HighContrast ? SystemColors.Highlight : Color.DodgerBlue; + + using Pen outerPen = new(axisColor, 2f * s); + using Pen crossPen = new(axisColor, 1.5f * s) { DashStyle = DashStyle.Dash }; + using Pen deadzonePen = new(deadzoneColor, 2.5f * s); + using Pen deadzoneExitPen = new(deadzoneColor, 2f * s) { DashStyle = DashStyle.Dash }; + using Pen rawPen = new(rawColor, 2.5f * s); + using Pen correctedOutlinePen = new(axisColor, 2f * s); + using SolidBrush deadzoneFillBrush = new(Color.FromArgb(SystemInformation.HighContrast ? 60 : 48, deadzoneColor)); + using SolidBrush rawBrush = new(Color.FromArgb(SystemInformation.HighContrast ? 100 : 64, rawColor)); + using SolidBrush correctedBrush = new(correctedColor); + using SolidBrush centerBrush = new(axisColor); + + if (!_snapshot.IsConnected) + { + TextRenderer.DrawText( + graphics, + Strings.Dialog_GamepadCalibrationVisualizer_StatusDisconnected, + _a11yFont ?? Font, + Rectangle.Round(contentBounds), + axisColor, + TextFormatFlags.HorizontalCenter | TextFormatFlags.VerticalCenter | TextFormatFlags.WordBreak); + + return; + } + + float labelHeight = 54f * s; + float plotGap = 16f * s; + float plotVerticalPadding = 6f * s; + float plotWidth = (contentBounds.Width - plotGap) / 2f; + float plotSize = Math.Min(plotWidth, contentBounds.Height - labelHeight - plotVerticalPadding); + float verticalOffset = (contentBounds.Height - labelHeight - plotSize) / 2f; + + RectangleF leftPlot = new( + contentBounds.Left + ((plotWidth - plotSize) / 2f), + contentBounds.Top + labelHeight + verticalOffset, + plotSize, + plotSize); + RectangleF rightPlot = new( + contentBounds.Left + plotWidth + plotGap + ((plotWidth - plotSize) / 2f), + contentBounds.Top + labelHeight + verticalOffset, + plotSize, + plotSize); + + DrawStickPlot(graphics, leftPlot, "LS", _snapshot.RawLeftX, _snapshot.RawLeftY, _snapshot.CorrectedLeftX, _snapshot.CorrectedLeftY, axisColor, outerPen, crossPen, deadzonePen, deadzoneExitPen, rawPen, correctedOutlinePen, deadzoneFillBrush, rawBrush, correctedBrush, centerBrush); + DrawStickPlot(graphics, rightPlot, "RS", _snapshot.RawRightX, _snapshot.RawRightY, _snapshot.CorrectedRightX, _snapshot.CorrectedRightY, axisColor, outerPen, crossPen, deadzonePen, deadzoneExitPen, rawPen, correctedOutlinePen, deadzoneFillBrush, rawBrush, correctedBrush, centerBrush); + } + + /// + /// 在指定範圍內繪製單一搖桿的校準圖,包含死區、原始與修正後軌跡。 + /// + /// 目標 GDI+ 繪圖物件。 + /// 搖桿圖的像素邊界矩形。 + /// 搖桿標籤(如 "LS" 或 "RS")。 + /// 原始 X 軸正規化值(-1.0 ~ 1.0)。 + /// 原始 Y 軸正規化值(-1.0 ~ 1.0)。 + /// 死區修正後 X 軸正規化值。 + /// 死區修正後 Y 軸正規化值。 + /// 座標軸與外框顏色。 + /// 外框圓圈畫筆。 + /// 十字準線畫筆。 + /// 進入死區圓圈畫筆。 + /// 退出死區虛線圓圈畫筆。 + /// 原始軌跡線畫筆。 + /// 修正點外框畫筆。 + /// 死區填滿筆刷。 + /// 原始位置填滿筆刷。 + /// 修正後位置填滿筆刷。 + /// 中心點填滿筆刷。 + private void DrawStickPlot(Graphics graphics, RectangleF plotBounds, string label, float rawX, float rawY, float correctedX, float correctedY, Color axisColor, Pen outerPen, Pen crossPen, Pen deadzonePen, Pen deadzoneExitPen, Pen rawPen, Pen correctedOutlinePen, Brush deadzoneFillBrush, Brush rawBrush, Brush correctedBrush, Brush centerBrush) + { + graphics.DrawEllipse(outerPen, plotBounds); + + float centerX = plotBounds.Left + (plotBounds.Width / 2f), + centerY = plotBounds.Top + (plotBounds.Height / 2f); + + graphics.DrawLine(crossPen, plotBounds.Left, centerY, plotBounds.Right, centerY); + graphics.DrawLine(crossPen, centerX, plotBounds.Top, centerX, plotBounds.Bottom); + + float deadzoneRadius = GamepadCalibrationVisualizerMapper.CalculateDeadzoneRadius(_snapshot.ThumbDeadzoneEnter) * (plotBounds.Width / 2f); + graphics.FillEllipse(deadzoneFillBrush, centerX - deadzoneRadius, centerY - deadzoneRadius, deadzoneRadius * 2f, deadzoneRadius * 2f); + graphics.DrawEllipse(deadzonePen, centerX - deadzoneRadius, centerY - deadzoneRadius, deadzoneRadius * 2f, deadzoneRadius * 2f); + + float exitDeadzoneRadius = GamepadCalibrationVisualizerMapper.CalculateDeadzoneRadius(_snapshot.ThumbDeadzoneExit) * (plotBounds.Width / 2f); + graphics.DrawEllipse(deadzoneExitPen, centerX - exitDeadzoneRadius, centerY - exitDeadzoneRadius, exitDeadzoneRadius * 2f, exitDeadzoneRadius * 2f); + + float dpiScale = DeviceDpi / AppSettings.BaseDpi; + graphics.FillEllipse(centerBrush, centerX - 3f * dpiScale, centerY - 3f * dpiScale, 6f * dpiScale, 6f * dpiScale); + + PointF rawPoint = GamepadCalibrationVisualizerMapper.MapToCanvas(plotBounds, rawX, rawY), + correctedPoint = GamepadCalibrationVisualizerMapper.MapToCanvas(plotBounds, correctedX, correctedY); + + graphics.DrawLine(rawPen, centerX, centerY, rawPoint.X, rawPoint.Y); + + float dm = 8f * dpiScale; + PointF[] diamond = + [ + new PointF(rawPoint.X, rawPoint.Y - dm), + new PointF(rawPoint.X + dm, rawPoint.Y), + new PointF(rawPoint.X, rawPoint.Y + dm), + new PointF(rawPoint.X - dm, rawPoint.Y) + ]; + graphics.FillPolygon(rawBrush, diamond); + graphics.DrawPolygon(rawPen, diamond); + float cr = 6f * dpiScale; + graphics.FillEllipse(correctedBrush, correctedPoint.X - cr, correctedPoint.Y - cr, cr * 2f, cr * 2f); + graphics.DrawEllipse(correctedOutlinePen, correctedPoint.X - cr, correctedPoint.Y - cr, cr * 2f, cr * 2f); + + Rectangle labelBounds = Rectangle.Round(new RectangleF(plotBounds.Left + 12f * dpiScale, plotBounds.Top - 44f * dpiScale, plotBounds.Width - 24f * dpiScale, 30f * dpiScale)); + graphics.FillRectangle(SystemBrushes.Window, labelBounds); + TextRenderer.DrawText( + graphics, + label, + _a11yFont ?? Font, + labelBounds, + axisColor, + TextFormatFlags.HorizontalCenter | TextFormatFlags.VerticalCenter | TextFormatFlags.EndEllipsis); + } +} diff --git a/src/InputBox/Core/Controls/GamepadCalibrationDialog.cs b/src/InputBox/Core/Controls/GamepadCalibrationDialog.cs index cb9e69e..6efd013 100644 --- a/src/InputBox/Core/Controls/GamepadCalibrationDialog.cs +++ b/src/InputBox/Core/Controls/GamepadCalibrationDialog.cs @@ -1,14 +1,8 @@ using InputBox.Core.Configuration; using InputBox.Core.Extensions; -using InputBox.Core.Feedback; using InputBox.Core.Input; -using InputBox.Core.Services; -using InputBox.Core.Utilities; using InputBox.Resources; -using System.ComponentModel; using System.Diagnostics; -using System.Drawing.Drawing2D; -using System.Media; using System.Windows.Forms.Automation; namespace InputBox.Core.Controls; @@ -19,24 +13,8 @@ partial class DesignerBlocker { }; /// /// 顯示遊戲控制器校準狀態的視覺化診斷對話框。 /// -internal sealed class GamepadCalibrationDialog : Form +internal sealed partial class GamepadCalibrationDialog : Form { - /// - /// 使用雙緩衝避免繪圖閃爍。 - /// - private sealed class BufferedPanel : Panel - { - /// - /// 初始化 BufferedPanel,啟用雙緩衝與縮放重繪。 - /// - public BufferedPanel() - { - DoubleBuffered = true; - ResizeRedraw = true; - TabStop = false; - } - } - /// /// 目前指派的遊戲控制器實例。 /// @@ -107,33 +85,6 @@ public BufferedPanel() /// private System.Windows.Forms.Timer? _refreshTimer; - /// - /// 指派控制器實例,並同步診斷快照與事件訂閱。 - /// - [Browsable(false)] - [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] - public IGamepadController? GamepadController - { - get => _gamepadController; - set - { - if (ReferenceEquals(_gamepadController, value)) - { - return; - } - - UnsubscribeGamepadEvents(); - _gamepadController = value; - - if (_gamepadController != null) - { - SubscribeGamepadEvents(); - } - - UpdateSnapshotFromController(); - } - } - /// /// 初始化遊戲控制器校準診斷對話框,建立版面與控制項。 /// @@ -295,83 +246,6 @@ public GamepadCalibrationDialog() PerformLayout(); } - /// - /// 視窗 Handle 建立後,更新最小尺寸並定位至初始位置。 - /// - /// 事件引數。 - protected override void OnHandleCreated(EventArgs e) - { - try - { - base.OnHandleCreated(e); - UpdateMinimumSize(forceRecalculate: true); - this.SafeBeginInvoke(ApplySmartPosition); - } - catch (Exception ex) - { - Debug.WriteLine($"[GamepadCalibrationDialog] OnHandleCreated 失敗:{ex.Message}"); - } - } - - /// - /// 使用者完成調整視窗大小後,重新套用智慧定位。 - /// - /// 事件引數。 - protected override void OnResizeEnd(EventArgs e) - { - try - { - base.OnResizeEnd(e); - ApplySmartPosition(); - } - catch (Exception ex) - { - Debug.WriteLine($"[GamepadCalibrationDialog] OnResizeEnd 失敗:{ex.Message}"); - } - } - - /// - /// DPI 變更時更新字型、最小尺寸,並重新套用智慧定位。 - /// - /// 包含新舊 DPI 值的事件引數。 - protected override void OnDpiChanged(DpiChangedEventArgs e) - { - try - { - base.OnDpiChanged(e); - this.SafeBeginInvoke(() => - { - try - { - _a11yFont = MainForm.GetSharedA11yFont(DeviceDpi); - - if (_a11yFont != null) - { - _lblIntro?.Font = _a11yFont; - - _lblStatus?.Font = _a11yFont; - - _btnReset?.Font = _a11yFont; - - _btnClose?.Font = _a11yFont; - } - - UpdateMinimumSize(forceRecalculate: true); - ApplySmartPosition(); - _surface?.Invalidate(); - } - catch (Exception ex) - { - Debug.WriteLine($"[GamepadCalibrationDialog] OnDpiChanged 延遲邏輯失敗:{ex.Message}"); - } - }); - } - catch (Exception ex) - { - Debug.WriteLine($"[GamepadCalibrationDialog] OnDpiChanged 失敗:{ex.Message}"); - } - } - /// /// 對話框顯示後啟動重新整理計時器並播報開啟訊息。 /// @@ -495,642 +369,6 @@ private void HandleDialogKeyDown(object? sender, KeyEventArgs e) } } - /// - /// 訂閱目前控制器的所有輸入事件。 - /// - private void SubscribeGamepadEvents() - { - if (_gamepadController == null) - { - return; - } - - GamepadFaceButtonProfile profile = GamepadFaceButtonProfile.GetActiveProfile(); - - _gamepadController.APressed += profile.ConfirmOnSouth ? HandleGamepadConfirm : HandleGamepadCancel; - _gamepadController.StartPressed += HandleGamepadConfirm; - _gamepadController.BPressed += profile.ConfirmOnSouth ? HandleGamepadCancel : HandleGamepadConfirm; - _gamepadController.BackPressed += HandleGamepadCancel; - _gamepadController.YPressed += HandleGamescopeSurfaceRecovery; - _gamepadController.LeftPressed += HandleDPadPrevious; - _gamepadController.LeftRepeat += HandleDPadPrevious; - _gamepadController.UpPressed += HandleDPadPrevious; - _gamepadController.UpRepeat += HandleDPadPrevious; - _gamepadController.RightPressed += HandleDPadNext; - _gamepadController.RightRepeat += HandleDPadNext; - _gamepadController.DownPressed += HandleDPadNext; - _gamepadController.DownRepeat += HandleDPadNext; - _gamepadController.ConnectionChanged += HandleGamepadConnectionChanged; - } - - /// - /// 取消訂閱目前控制器的所有輸入事件。 - /// - private void UnsubscribeGamepadEvents() - { - try - { - if (_gamepadController == null) - { - return; - } - - _gamepadController.APressed -= HandleGamepadConfirm; - _gamepadController.APressed -= HandleGamepadCancel; - _gamepadController.StartPressed -= HandleGamepadConfirm; - _gamepadController.BPressed -= HandleGamepadConfirm; - _gamepadController.BPressed -= HandleGamepadCancel; - _gamepadController.BackPressed -= HandleGamepadCancel; - _gamepadController.YPressed -= HandleGamescopeSurfaceRecovery; - _gamepadController.LeftPressed -= HandleDPadPrevious; - _gamepadController.LeftRepeat -= HandleDPadPrevious; - _gamepadController.UpPressed -= HandleDPadPrevious; - _gamepadController.UpRepeat -= HandleDPadPrevious; - _gamepadController.RightPressed -= HandleDPadNext; - _gamepadController.RightRepeat -= HandleDPadNext; - _gamepadController.DownPressed -= HandleDPadNext; - _gamepadController.DownRepeat -= HandleDPadNext; - _gamepadController.ConnectionChanged -= HandleGamepadConnectionChanged; - } - catch (Exception ex) - { - Debug.WriteLine($"[GamepadCalibrationDialog] 取消訂閱控制器事件失敗:{ex.Message}"); - } - } - - /// - /// 控制器連線狀態變更時更新快照並播報連線訊息。 - /// - /// 控制器是否已連線。 - private void HandleGamepadConnectionChanged(bool isConnected) - { - try - { - this.SafeBeginInvoke(() => - { - UpdateSnapshotFromController(); - _announcer?.Announce(FormatConnectionAnnouncement(isConnected, _gamepadController?.DeviceName), true); - }); - } - catch (Exception ex) - { - LoggerService.LogException(ex, "GamepadCalibrationDialog.HandleGamepadConnectionChanged 失敗"); - Debug.WriteLine($"[GamepadCalibrationDialog] 控制器連線變更處理失敗:{ex.Message}"); - } - } - - /// - /// 處理控制器確認按鍵,觸發目前焦點按鈕或預設按鈕的點擊。 - /// - private void HandleGamepadConfirm() - { - try - { - this.SafeBeginInvoke(() => - { - try - { - if (IsDisposed) - { - return; - } - - if (ActiveControl is Button activeButton && - activeButton.Enabled) - { - activeButton.PerformClick(); - } - else - { - (_btnReset ?? AcceptButton as Button)?.PerformClick(); - } - } - catch (Exception ex) - { - Debug.WriteLine($"[GamepadCalibrationDialog] HandleGamepadConfirm UI 失敗:{ex.Message}"); - } - }); - } - catch (Exception ex) - { - Debug.WriteLine($"[GamepadCalibrationDialog] HandleGamepadConfirm 失敗:{ex.Message}"); - } - } - - /// - /// 處理控制器取消按鍵,觸發關閉按鈕或直接關閉對話框。 - /// - private void HandleGamepadCancel() - { - try - { - this.SafeBeginInvoke(() => - { - try - { - if (IsDisposed) - { - return; - } - - if (_btnClose != null && - !_btnClose.IsDisposed) - { - _btnClose.PerformClick(); - } - else - { - DialogResult = DialogResult.Cancel; - Close(); - } - } - catch (Exception ex) - { - Debug.WriteLine($"[GamepadCalibrationDialog] HandleGamepadCancel UI 失敗:{ex.Message}"); - } - }); - } - catch (Exception ex) - { - Debug.WriteLine($"[GamepadCalibrationDialog] HandleGamepadCancel 失敗:{ex.Message}"); - } - } - - /// - /// 處理 Gamescope 專用 surface recovery 組合鍵。 - /// - private void HandleGamescopeSurfaceRecovery() - { - GamescopeSurfaceRecovery.TryRecoverFromGamepadChord( - this, - RecreateHandle, - _gamepadController, - context: "GamepadCalibrationDialog Gamescope surface recovery 失敗"); - } - - /// - /// 處理 D-Pad 向前(左/上)輸入,在搖桿不干擾時移動焦點至前一個按鈕。 - /// - private void HandleDPadPrevious() - { - if (ShouldHandleDirectionalFocusNavigation(_gamepadController?.CurrentCalibrationSnapshot ?? _snapshot)) - { - FocusPreviousButton(); - } - } - - /// - /// 處理 D-Pad 向後(右/下)輸入,在搖桿不干擾時移動焦點至下一個按鈕。 - /// - private void HandleDPadNext() - { - if (ShouldHandleDirectionalFocusNavigation(_gamepadController?.CurrentCalibrationSnapshot ?? _snapshot)) - { - FocusNextButton(); - } - } - - /// - /// 將焦點移至前一個按鈕。 - /// - private void FocusPreviousButton() => MoveButtonFocus(-1); - - /// - /// 將焦點移至下一個按鈕。 - /// - private void FocusNextButton() => MoveButtonFocus(+1); - - /// - /// 依方向在重設與關閉按鈕之間移動焦點。 - /// - /// 方向值;負值移往重設按鈕,正值移往關閉按鈕。 - private void MoveButtonFocus(int direction) - { - try - { - this.SafeBeginInvoke(() => - { - if (IsDisposed || _btnReset == null || _btnClose == null) - { - return; - } - - Button nextButton = direction < 0 ? - ActiveControl == _btnClose ? _btnReset : _btnClose : - ActiveControl == _btnReset ? _btnClose : _btnReset; - - nextButton.Focus(); - }); - } - catch (Exception ex) - { - Debug.WriteLine($"[GamepadCalibrationDialog] MoveButtonFocus 失敗:{ex.Message}"); - } - } - - /// - /// 從控制器取得最新校準快照,更新狀態文字並觸發畫面重繪。 - /// - private void UpdateSnapshotFromController() - { - GamepadCalibrationSnapshot snapshot = _gamepadController?.CurrentCalibrationSnapshot ?? new GamepadCalibrationSnapshot - { - IsConnected = false, - ThumbDeadzoneEnter = AppSettings.Current.ThumbDeadzoneEnter, - ThumbDeadzoneExit = AppSettings.Current.ThumbDeadzoneExit, - TimestampUtc = DateTime.UtcNow - }; - - _snapshot = snapshot; - UpdateStatusText(); - _surface?.Invalidate(); - } - - /// - /// 依目前快照更新狀態標籤文字,並同步重設按鈕的啟用狀態。 - /// - private void UpdateStatusText() - { - if (_lblStatus == null) - { - return; - } - - _lblStatus.Text = FormatStatusText(_snapshot); - - _btnReset?.Enabled = _snapshot.IsConnected; - } - - /// - /// 依連線狀態與裝置名稱產生無障礙廣播訊息字串。 - /// - /// 控制器是否已連線。 - /// 裝置名稱;可為 null。 - /// 格式化後的連線狀態廣播訊息。 - internal static string FormatConnectionAnnouncement(bool isConnected, string? deviceName) - { - string template = isConnected ? - Strings.A11y_Gamepad_Connected : - Strings.A11y_Gamepad_Disconnected; - - string message = string.Format(template, deviceName?.Trim() ?? string.Empty); - - while (message.Contains(" ", StringComparison.Ordinal)) - { - message = message.Replace(" ", " ", StringComparison.Ordinal); - } - - return message.Replace(" .", ".", StringComparison.Ordinal).Trim(); - } - - /// - /// 判斷目前搖桿是否靜止到足以安全處理方向焦點移動,避免搖桿偏移誤觸焦點導覽。 - /// - /// 目前的校準狀態快照。 - /// 若搖桿偏移量低於安全閾值(或控制器未連線)則回傳 true。 - internal static bool ShouldHandleDirectionalFocusNavigation(GamepadCalibrationSnapshot snapshot) - { - if (!snapshot.IsConnected) - { - return true; - } - - float normalizedDeadzone = GamepadCalibrationVisualizerMapper.CalculateDeadzoneRadius( - Math.Max(snapshot.ThumbDeadzoneEnter, snapshot.ThumbDeadzoneExit)); - - // 門檻必須低於 normalizedDeadzone,確保 LS 剛跨越 ThumbDeadzoneEnter - // 觸發搖桿→D-Pad 映射的瞬間,保護邏輯已阻止方向焦點移動。 - float navigationThreshold = Math.Clamp(normalizedDeadzone * 0.75f, 0.06f, 0.18f); - - return MathF.Abs(snapshot.RawLeftX) <= navigationThreshold && - MathF.Abs(snapshot.RawLeftY) <= navigationThreshold && - MathF.Abs(snapshot.CorrectedLeftX) <= navigationThreshold && - MathF.Abs(snapshot.CorrectedLeftY) <= navigationThreshold; - } - - /// - /// 依校準快照產生狀態文字標籤內容。 - /// - /// 目前的校準狀態快照。 - /// 格式化後的狀態文字;控制器未連線時回傳中斷連線提示訊息。 - internal static string FormatStatusText(GamepadCalibrationSnapshot snapshot) - { - if (!snapshot.IsConnected) - { - return Strings.Dialog_GamepadCalibrationVisualizer_StatusDisconnected; - } - - return string.Format( - Strings.Dialog_GamepadCalibrationVisualizer_StatusConnected, - FormatAxis(snapshot.RawLeftX), - FormatAxis(snapshot.RawLeftY), - FormatAxis(snapshot.CorrectedLeftX), - FormatAxis(snapshot.CorrectedLeftY), - FormatAxis(snapshot.RawRightX), - FormatAxis(snapshot.RawRightY), - FormatAxis(snapshot.CorrectedRightX), - FormatAxis(snapshot.CorrectedRightY), - snapshot.ThumbDeadzoneEnter, - snapshot.ThumbDeadzoneExit); - } - - /// - /// 將正規化軸值格式化為帶符號的兩位小數字串。 - /// - /// 正規化軸值(-1.0 ~ 1.0)。 - /// 格式化後的字串,例如 "+0.75" 或 "-0.12"。 - private static string FormatAxis(float value) - { - return value.ToString("+0.00;-0.00;0.00"); - } - - /// - /// 重設控制器校準資料,播放音效與震動回饋並更新快照。 - /// - private void ResetCalibration() - { - try - { - _gamepadController?.ResetCalibration(); - SystemSounds.Asterisk.Play(); - PlayResetCalibrationFeedbackAsync().SafeFireAndForget(); - UpdateSnapshotFromController(); - _announcer?.Announce(Strings.A11y_Gamepad_CalibrationReset, true); - } - catch (Exception ex) - { - LoggerService.LogException(ex, "重設校準視覺化狀態失敗"); - Debug.WriteLine($"[GamepadCalibrationDialog] ResetCalibration 失敗:{ex.Message}"); - } - } - - /// - /// 播放重設校準的三段式震動序列回饋。 - /// - /// 代表震動序列播放過程的非同步工作。 - private async Task PlayResetCalibrationFeedbackAsync() - { - IGamepadController? controller = _gamepadController; - - if (controller == null) - { - return; - } - - CancellationToken token = _cts?.Token ?? CancellationToken.None; - - VibrationProfile[] sequence = - [ - new(22000, 26, 1.0f, 0.18f, 0.52f, 0.04f), - new(22000, 26, 0.18f, 1.0f, 0.04f, 0.52f), - new(18000, 22, 0.62f, 0.62f, 0.18f, 0.18f) - ]; - - foreach (VibrationProfile profile in sequence) - { - token.ThrowIfCancellationRequested(); - await controller.VibrateAsync(profile, VibrationPriority.Normal, token); - await Task.Delay(20, token); - } - } - - /// - /// 繪製校準視覺化畫布,包含雙搖桿軌跡圖與死區圓圈。 - /// - /// 事件來源。 - /// 包含繪圖 Graphics 的事件引數。 - private void HandleSurfacePaint(object? sender, PaintEventArgs e) - { - if (_surface == null) - { - return; - } - - Graphics graphics = e.Graphics; - graphics.SmoothingMode = SmoothingMode.AntiAlias; - graphics.Clear(SystemColors.Window); - - Rectangle clientRect = _surface.ClientRectangle; - - if (clientRect.Width <= 20 || clientRect.Height <= 20) - { - return; - } - - float s = DeviceDpi / AppSettings.BaseDpi; - int margin = (int)(12 * s); - RectangleF contentBounds = new( - clientRect.Left + margin, - clientRect.Top + margin, - clientRect.Width - (margin * 2), - clientRect.Height - (margin * 2)); - - Color axisColor = SystemInformation.HighContrast ? SystemColors.WindowText : Color.DimGray; - Color deadzoneColor = SystemInformation.HighContrast ? SystemColors.Highlight : Color.FromArgb(72, 120, 120, 120); - Color rawColor = SystemInformation.HighContrast ? SystemColors.WindowText : Color.FromArgb(90, 90, 90); - Color correctedColor = SystemInformation.HighContrast ? SystemColors.Highlight : Color.DodgerBlue; - - using Pen outerPen = new(axisColor, 2f * s); - using Pen crossPen = new(axisColor, 1.5f * s) { DashStyle = DashStyle.Dash }; - using Pen deadzonePen = new(deadzoneColor, 2.5f * s); - using Pen deadzoneExitPen = new(deadzoneColor, 2f * s) { DashStyle = DashStyle.Dash }; - using Pen rawPen = new(rawColor, 2.5f * s); - using Pen correctedOutlinePen = new(axisColor, 2f * s); - using SolidBrush deadzoneFillBrush = new(Color.FromArgb(SystemInformation.HighContrast ? 60 : 48, deadzoneColor)); - using SolidBrush rawBrush = new(Color.FromArgb(SystemInformation.HighContrast ? 100 : 64, rawColor)); - using SolidBrush correctedBrush = new(correctedColor); - using SolidBrush centerBrush = new(axisColor); - - if (!_snapshot.IsConnected) - { - TextRenderer.DrawText( - graphics, - Strings.Dialog_GamepadCalibrationVisualizer_StatusDisconnected, - _a11yFont ?? Font, - Rectangle.Round(contentBounds), - axisColor, - TextFormatFlags.HorizontalCenter | TextFormatFlags.VerticalCenter | TextFormatFlags.WordBreak); - - return; - } - - float labelHeight = 54f * s; - float plotGap = 16f * s; - float plotVerticalPadding = 6f * s; - float plotWidth = (contentBounds.Width - plotGap) / 2f; - float plotSize = Math.Min(plotWidth, contentBounds.Height - labelHeight - plotVerticalPadding); - float verticalOffset = (contentBounds.Height - labelHeight - plotSize) / 2f; - - RectangleF leftPlot = new( - contentBounds.Left + ((plotWidth - plotSize) / 2f), - contentBounds.Top + labelHeight + verticalOffset, - plotSize, - plotSize); - RectangleF rightPlot = new( - contentBounds.Left + plotWidth + plotGap + ((plotWidth - plotSize) / 2f), - contentBounds.Top + labelHeight + verticalOffset, - plotSize, - plotSize); - - DrawStickPlot(graphics, leftPlot, "LS", _snapshot.RawLeftX, _snapshot.RawLeftY, _snapshot.CorrectedLeftX, _snapshot.CorrectedLeftY, axisColor, outerPen, crossPen, deadzonePen, deadzoneExitPen, rawPen, correctedOutlinePen, deadzoneFillBrush, rawBrush, correctedBrush, centerBrush); - DrawStickPlot(graphics, rightPlot, "RS", _snapshot.RawRightX, _snapshot.RawRightY, _snapshot.CorrectedRightX, _snapshot.CorrectedRightY, axisColor, outerPen, crossPen, deadzonePen, deadzoneExitPen, rawPen, correctedOutlinePen, deadzoneFillBrush, rawBrush, correctedBrush, centerBrush); - } - - /// - /// 在指定範圍內繪製單一搖桿的校準圖,包含死區、原始與修正後軌跡。 - /// - /// 目標 GDI+ 繪圖物件。 - /// 搖桿圖的像素邊界矩形。 - /// 搖桿標籤(如 "LS" 或 "RS")。 - /// 原始 X 軸正規化值(-1.0 ~ 1.0)。 - /// 原始 Y 軸正規化值(-1.0 ~ 1.0)。 - /// 死區修正後 X 軸正規化值。 - /// 死區修正後 Y 軸正規化值。 - /// 座標軸與外框顏色。 - /// 外框圓圈畫筆。 - /// 十字準線畫筆。 - /// 進入死區圓圈畫筆。 - /// 退出死區虛線圓圈畫筆。 - /// 原始軌跡線畫筆。 - /// 修正點外框畫筆。 - /// 死區填滿筆刷。 - /// 原始位置填滿筆刷。 - /// 修正後位置填滿筆刷。 - /// 中心點填滿筆刷。 - private void DrawStickPlot(Graphics graphics, RectangleF plotBounds, string label, float rawX, float rawY, float correctedX, float correctedY, Color axisColor, Pen outerPen, Pen crossPen, Pen deadzonePen, Pen deadzoneExitPen, Pen rawPen, Pen correctedOutlinePen, Brush deadzoneFillBrush, Brush rawBrush, Brush correctedBrush, Brush centerBrush) - { - graphics.DrawEllipse(outerPen, plotBounds); - - float centerX = plotBounds.Left + (plotBounds.Width / 2f), - centerY = plotBounds.Top + (plotBounds.Height / 2f); - - graphics.DrawLine(crossPen, plotBounds.Left, centerY, plotBounds.Right, centerY); - graphics.DrawLine(crossPen, centerX, plotBounds.Top, centerX, plotBounds.Bottom); - - float deadzoneRadius = GamepadCalibrationVisualizerMapper.CalculateDeadzoneRadius(_snapshot.ThumbDeadzoneEnter) * (plotBounds.Width / 2f); - graphics.FillEllipse(deadzoneFillBrush, centerX - deadzoneRadius, centerY - deadzoneRadius, deadzoneRadius * 2f, deadzoneRadius * 2f); - graphics.DrawEllipse(deadzonePen, centerX - deadzoneRadius, centerY - deadzoneRadius, deadzoneRadius * 2f, deadzoneRadius * 2f); - - float exitDeadzoneRadius = GamepadCalibrationVisualizerMapper.CalculateDeadzoneRadius(_snapshot.ThumbDeadzoneExit) * (plotBounds.Width / 2f); - graphics.DrawEllipse(deadzoneExitPen, centerX - exitDeadzoneRadius, centerY - exitDeadzoneRadius, exitDeadzoneRadius * 2f, exitDeadzoneRadius * 2f); - - float dpiScale = DeviceDpi / AppSettings.BaseDpi; - graphics.FillEllipse(centerBrush, centerX - 3f * dpiScale, centerY - 3f * dpiScale, 6f * dpiScale, 6f * dpiScale); - - PointF rawPoint = GamepadCalibrationVisualizerMapper.MapToCanvas(plotBounds, rawX, rawY), - correctedPoint = GamepadCalibrationVisualizerMapper.MapToCanvas(plotBounds, correctedX, correctedY); - - graphics.DrawLine(rawPen, centerX, centerY, rawPoint.X, rawPoint.Y); - - float dm = 8f * dpiScale; - PointF[] diamond = - [ - new PointF(rawPoint.X, rawPoint.Y - dm), - new PointF(rawPoint.X + dm, rawPoint.Y), - new PointF(rawPoint.X, rawPoint.Y + dm), - new PointF(rawPoint.X - dm, rawPoint.Y) - ]; - graphics.FillPolygon(rawBrush, diamond); - graphics.DrawPolygon(rawPen, diamond); - float cr = 6f * dpiScale; - graphics.FillEllipse(correctedBrush, correctedPoint.X - cr, correctedPoint.Y - cr, cr * 2f, cr * 2f); - graphics.DrawEllipse(correctedOutlinePen, correctedPoint.X - cr, correctedPoint.Y - cr, cr * 2f, cr * 2f); - - Rectangle labelBounds = Rectangle.Round(new RectangleF(plotBounds.Left + 12f * dpiScale, plotBounds.Top - 44f * dpiScale, plotBounds.Width - 24f * dpiScale, 30f * dpiScale)); - graphics.FillRectangle(SystemBrushes.Window, labelBounds); - TextRenderer.DrawText( - graphics, - label, - _a11yFont ?? Font, - labelBounds, - axisColor, - TextFormatFlags.HorizontalCenter | TextFormatFlags.VerticalCenter | TextFormatFlags.EndEllipsis); - } - - /// - /// 依目前 DPI 與可用工作區重新計算並套用對話框的最小尺寸。 - /// - /// 是否強制重新計算,忽略 DPI 未變更的快取防呆。 - private void UpdateMinimumSize(bool forceRecalculate = false) - { - try - { - if (_layoutHost == null || - _surface == null || - _lblIntro == null || - _lblStatus == null || - _btnReset == null || - _btnClose == null || - _buttonRow == null) - { - return; - } - - float currentDpi = DeviceDpi; - - if (!DialogLayoutHelper.TryBeginDpiLayout(currentDpi, ref _lastAppliedDpi, forceRecalculate)) - { - return; - } - - float scale = currentDpi / AppSettings.BaseDpi; - Rectangle workArea = Screen.GetWorkingArea(this); - (int maxFitWidth, int maxFitHeight) = DialogLayoutHelper.GetMaxFitSize(workArea); - - int targetWindowWidth = Math.Clamp((int)(600 * scale), Math.Min(maxFitWidth, (int)(420 * scale)), maxFitWidth); - int contentWidth = Math.Max(220, targetWindowWidth - Padding.Horizontal); - - _lblIntro.MaximumSize = new Size(contentWidth, 0); - _lblIntro.Margin = new Padding(0, 0, 0, (int)(6 * scale)); - - Font boldFont = MainForm.GetSharedA11yFont(DeviceDpi, FontStyle.Bold, (_a11yFont ?? Font).FontFamily); - DialogLayoutHelper.UpdateButtonMinimumSize(_btnReset, boldFont, scale, 120, 56, 32, 20); - DialogLayoutHelper.UpdateButtonMinimumSize(_btnClose, boldFont, scale, 120, 56, 32, 20); - - int buttonHeight = _buttonRow.GetPreferredSize(new Size(contentWidth, 0)).Height; - int introHeight = _lblIntro.GetPreferredSize(new Size(contentWidth, 0)).Height; - int statusHeight = Math.Max((int)(96 * scale), _lblStatus.GetPreferredSize(new Size(contentWidth, 0)).Height); - int availableSurfaceHeight = Math.Max((int)(160 * scale), maxFitHeight - Padding.Vertical - introHeight - statusHeight - buttonHeight - (int)(36 * scale)); - int surfaceHeight = Math.Min((int)(280 * scale), availableSurfaceHeight); - - _surface.MinimumSize = new Size(contentWidth, surfaceHeight); - _surface.Size = _surface.MinimumSize; - _lblStatus.MinimumSize = new Size(contentWidth, statusHeight); - _lblStatus.Size = _lblStatus.MinimumSize; - _buttonRow.WrapContents = _buttonRow.GetPreferredSize(Size.Empty).Width > contentWidth; - - int preferredHeight = _layoutHost.GetPreferredSize(new Size(contentWidth, 0)).Height + Padding.Vertical; - int targetWindowHeight = Math.Min(preferredHeight, maxFitHeight); - int minWindowWidth = Math.Min(targetWindowWidth, maxFitWidth); - int minWindowHeight = Math.Min(targetWindowHeight, maxFitHeight); - - ClientSize = new Size(minWindowWidth, targetWindowHeight); - DialogLayoutHelper.ClampFormSize(this, minWindowWidth, minWindowHeight, maxFitWidth, maxFitHeight, ApplySmartPosition); - } - catch (Exception ex) - { - Debug.WriteLine($"[GamepadCalibrationDialog] UpdateMinimumSize 失敗:{ex.Message}"); - } - } - - /// - /// 將對話框位置限制在螢幕可視範圍內,避免視窗超出邊界。 - /// - private void ApplySmartPosition() - { - try - { - if (InputBoxLayoutManager.TryGetClampedLocation(this, out Point clampedLocation)) - { - Location = clampedLocation; - } - } - catch (Exception ex) - { - Debug.WriteLine($"[GamepadCalibrationDialog] ApplySmartPosition 失敗:{ex.Message}"); - } - } - /// /// 建立符合眼球追蹤規格的大型按鈕,並附加懸停回饋。 /// @@ -1215,4 +453,4 @@ protected override void Dispose(bool disposing) base.Dispose(disposing); } -} \ No newline at end of file +} diff --git a/src/InputBox/Core/Controls/NumericInputDialog.A11y.cs b/src/InputBox/Core/Controls/NumericInputDialog.A11y.cs new file mode 100644 index 0000000..a7cf810 --- /dev/null +++ b/src/InputBox/Core/Controls/NumericInputDialog.A11y.cs @@ -0,0 +1,158 @@ +using InputBox.Core.Configuration; +using InputBox.Core.Extensions; +using InputBox.Core.Feedback; +using System.Diagnostics; + +namespace InputBox.Core.Controls; + +// 阻擋設計工具。 +partial class DesignerBlocker { }; + +/// +/// 專門用於數值輸入的對話框(無障礙輔助功能分部)。 +/// 本分部檔案包含 A11y 廣播與視覺閃爍警示等成員。 +/// +internal sealed partial class NumericInputDialog +{ + /// + /// 執行視覺警示閃爍效果 + /// + /// Task + private async Task FlashAlertAsync() + { + if (IsDisposed || + !IsHandleCreated || + Interlocked.CompareExchange(ref _isFlashing, 1, 0) != 0) + { + return; + } + + // 僅在對話框生命週期仍有效時建立警示權杖,避免關閉途中留下失去連結的動畫。 + CancellationTokenSource? newAlertCts = _cts.TryCreateLinkedTokenSource(); + + if (newAlertCts == null) + { + Interlocked.Exchange(ref _isFlashing, 0); + + return; + } + + Interlocked.Exchange(ref _alertCts, newAlertCts)?.CancelAndDispose(); + + CancellationToken token = newAlertCts.Token; + + try + { + bool isDark = this.IsDarkModeActive(); + Color alertColor = FlashAlertAnimator.GetAlertColor(isDark, SystemInformation.HighContrast); + + void ApplyAlertVisuals(float intensity) + { + if (IsDisposed || + !IsHandleCreated || + _nud == null) + { + return; + } + + (Color back, Color fore) = FlashAlertAnimator.ComputeFrameColors( + intensity, + isDark, + alertColor, + SystemInformation.HighContrast); + + _nud.UpdateRecursive(back, fore); + } + + await FlashAlertAnimator.RunAsync(this, ApplyAlertVisuals, token); + } + catch (OperationCanceledException) + { + // 正常取消。 + } + catch (Exception ex) + { + Debug.WriteLine($"[NumericInputDialog] FlashAlertAsync 失敗:{ex.Message}"); + } + finally + { + Interlocked.Exchange(ref _isFlashing, 0); + Interlocked.Exchange(ref _alertCts, null)?.CancelAndDispose(); + + // 確保 UI 狀態還原。 + this.SafeInvoke(() => + { + try + { + if (IsDisposed || + !IsHandleCreated || + _nud == null) + { + return; + } + + // 關鍵修正:遞歸重設顏色,觸發 .NET 10 原生主題引擎還原正確配色,防止閃爍殘留。 + _nud.ResetThemeRecursive(); + + // 恢復焦點視覺狀態。 + UpdateFocusVisuals(_nud.Focused || _nud.ContainsFocus); + } + catch (Exception ex) + { + Debug.WriteLine($"[NumericInputDialog] FlashAlertAsync 還原失敗:{ex.Message}"); + } + }); + } + } + + /// + /// 內部 A11y 廣播方法 + /// + /// 要廣播的訊息 + /// 是否中斷目前的廣播 + private void AnnounceA11y( + string message, + bool interrupt = false) + { + if (IsDisposed || + string.IsNullOrEmpty(message)) + { + return; + } + + long currentId = Interlocked.Increment(ref _a11yDebounceId); + + Task.Run(async () => + { + try + { + // 統一 Audio Ducking 避讓延遲。 + await Task.Delay(AppSettings.AudioDuckingDelayMs, _cts?.Token ?? CancellationToken.None); + + if (Interlocked.Read(ref _a11yDebounceId) == currentId && + !IsDisposed && + IsHandleCreated) + { + await this.SafeInvokeAsync(() => + _announcer?.Announce(message, interrupt && AppSettings.Current.A11yInterruptEnabled)); + } + } + catch (OperationCanceledException) + { + // 正常取消。 + } + catch (Exception ex) + { + Debug.WriteLine($"[A11y] 對話框本地廣播失敗:{ex.Message}"); + } + }, + _cts?.Token ?? CancellationToken.None) + .SafeFireAndForget(); + } + + /// + /// 取得目前對話框所屬的主視窗 + /// + /// 若 Owner 為 則回傳該實例,否則為 null。 + private MainForm? GetOwnerMainForm() => Owner as MainForm; +} diff --git a/src/InputBox/Core/Controls/NumericInputDialog.AccessibleNumericUpDown.cs b/src/InputBox/Core/Controls/NumericInputDialog.AccessibleNumericUpDown.cs new file mode 100644 index 0000000..00b1de9 --- /dev/null +++ b/src/InputBox/Core/Controls/NumericInputDialog.AccessibleNumericUpDown.cs @@ -0,0 +1,130 @@ +using System.Diagnostics; + +namespace InputBox.Core.Controls; + +// 阻擋設計工具。 +partial class DesignerBlocker { }; + +/// +/// 專門用於數值輸入的對話框(無障礙數值輸入控制項分部)。 +/// 本分部檔案包含內嵌的 AccessibleNumericUpDown 控制項。 +/// +internal sealed partial class NumericInputDialog +{ + /// + /// 繼承自 NumericUpDown 以公開受保護的成員方法 + /// + /// 父對話框實例 + private sealed class AccessibleNumericUpDown(NumericInputDialog parent) : NumericUpDown + { + /// + /// 父 NumericInputDialog 實例,用於回呼邊界撞牆通知。 + /// + private readonly NumericInputDialog _parent = parent; + + /// + /// 遞增數值,若已達上限則通知父對話框播放邊界回饋。 + /// + public override void UpButton() + { + try + { + decimal oldValue = Value; + + base.UpButton(); + + if (Value == oldValue) + { + _parent.HandleBoundaryHit(true); + } + } + catch (Exception ex) + { + Debug.WriteLine($"[NumericUpDown] UpButton 失敗:{ex.Message}"); + } + } + + /// + /// 遞減數值,若已達下限則通知父對話框播放邊界回饋。 + /// + public override void DownButton() + { + try + { + decimal oldValue = Value; + + base.DownButton(); + + if (Value == oldValue) + { + _parent.HandleBoundaryHit(false); + } + } + catch (Exception ex) + { + Debug.WriteLine($"[NumericUpDown] DownButton 失敗:{ex.Message}"); + } + } + + /// + /// 主動觸發無障礙狀態變更通知 + /// + public void NotifyAccessibilityChange() + { + try + { + // 主動通知輔助科技(AT)數值已變更。 + AccessibilityNotifyClients(AccessibleEvents.ValueChange, -1); + } + catch (Exception ex) + { + Debug.WriteLine($"[NumericUpDown] NotifyAccessibilityChange 失敗:{ex.Message}"); + } + } + + /// + /// 強制驗證編輯文字,確保 Value 屬性與目前輸入內容同步 + /// + public void ValidateValue() + { + try + { + ValidateEditText(); + } + catch (Exception ex) + { + Debug.WriteLine($"[NumericUpDown] ValidateValue 失敗:{ex.Message}"); + } + } + + /// + /// 覆寫滑鼠滾輪行為,確保「一格跳一格」 + /// + /// MouseEventArgs + protected override void OnMouseWheel(MouseEventArgs e) + { + try + { + // 強制攔截並阻斷 Windows 系統的「一次捲動多行」設定(預設為 3)。 + if (e is HandledMouseEventArgs hme) + { + hme.Handled = true; + } + + // 手動精確執行單次增減,不調用 base.OnMouseWheel(e)。 + if (e.Delta > 0) + { + UpButton(); + } + else if (e.Delta < 0) + { + DownButton(); + } + } + catch (Exception ex) + { + Debug.WriteLine($"[NumericUpDown] OnMouseWheel 失敗:{ex.Message}"); + } + } + } +} diff --git a/src/InputBox/Core/Controls/NumericInputDialog.Gamepad.cs b/src/InputBox/Core/Controls/NumericInputDialog.Gamepad.cs new file mode 100644 index 0000000..2692e92 --- /dev/null +++ b/src/InputBox/Core/Controls/NumericInputDialog.Gamepad.cs @@ -0,0 +1,629 @@ +using InputBox.Core.Configuration; +using InputBox.Core.Extensions; +using InputBox.Core.Feedback; +using InputBox.Core.Input; +using InputBox.Core.Services; +using InputBox.Resources; +using System.ComponentModel; +using System.Diagnostics; +using System.Media; + +namespace InputBox.Core.Controls; + +// 阻擋設計工具。 +partial class DesignerBlocker { }; + +/// +/// 專門用於數值輸入的對話框(遊戲控制器與輸入分部)。 +/// 本分部檔案包含遊戲控制器事件、數值加減、游標移動、延伸選取、刪除,以及觸控式鍵盤等輸入處理成員。 +/// +internal sealed partial class NumericInputDialog +{ + /// + /// 設定控制器實作,並訂閱事件 + /// + [Browsable(false)] + [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public IGamepadController? GamepadController + { + get => _gamepadController; + set + { + // 如果控制器相同,不執行任何操作。 + if (ReferenceEquals(_gamepadController, value)) + { + return; + } + + // 安全清理舊控制器的訂閱。 + UnsubscribeGamepadEvents(); + + _gamepadController = value; + + if (_gamepadController != null) + { + GamepadFaceButtonProfile profile = GamepadFaceButtonProfile.GetActiveProfile(); + + // 訂閱新控制器事件。 + _gamepadController.UpPressed += HandlePlus; + _gamepadController.UpRepeat += HandlePlus; + _gamepadController.DownPressed += HandleMinus; + _gamepadController.DownRepeat += HandleMinus; + _gamepadController.LeftPressed += HandleLeft; + _gamepadController.LeftRepeat += HandleLeft; + _gamepadController.RightPressed += HandleRight; + _gamepadController.RightRepeat += HandleRight; + _gamepadController.RSLeftPressed += HandleRSLeft; + _gamepadController.RSLeftRepeat += HandleRSLeft; + _gamepadController.RSRightPressed += HandleRSRight; + _gamepadController.RSRightRepeat += HandleRSRight; + _gamepadController.APressed += profile.ConfirmOnSouth ? HandleGamepadA : HandleCancel; + _gamepadController.StartPressed += HandleOpenTouchKeyboardFromGamepad; + _gamepadController.BPressed += profile.ConfirmOnSouth ? HandleCancel : HandleGamepadA; + _gamepadController.BackPressed += HandleCancel; + _gamepadController.XPressed += HandleBackspace; + _gamepadController.YPressed += HandleReset; + // 已由 D‑Pad (`LeftPressed` / `RightPressed`) 處理游標移動,移除 LT/RT 綁定以避免語意重複。 + _gamepadController.ConnectionChanged += HandleGamepadConnectionChanged; + } + } + } + + /// + /// 取消訂閱控制器事件 + /// + private void UnsubscribeGamepadEvents() + { + try + { + if (_gamepadController != null) + { + _gamepadController.UpPressed -= HandlePlus; + _gamepadController.UpRepeat -= HandlePlus; + _gamepadController.DownPressed -= HandleMinus; + _gamepadController.DownRepeat -= HandleMinus; + _gamepadController.LeftPressed -= HandleLeft; + _gamepadController.LeftRepeat -= HandleLeft; + _gamepadController.RightPressed -= HandleRight; + _gamepadController.RightRepeat -= HandleRight; + _gamepadController.RSLeftPressed -= HandleRSLeft; + _gamepadController.RSLeftRepeat -= HandleRSLeft; + _gamepadController.RSRightPressed -= HandleRSRight; + _gamepadController.RSRightRepeat -= HandleRSRight; + _gamepadController.APressed -= HandleGamepadA; + _gamepadController.APressed -= HandleCancel; + _gamepadController.StartPressed -= HandleOpenTouchKeyboardFromGamepad; + _gamepadController.BPressed -= HandleGamepadA; + _gamepadController.BPressed -= HandleCancel; + _gamepadController.BackPressed -= HandleCancel; + _gamepadController.XPressed -= HandleBackspace; + _gamepadController.YPressed -= HandleReset; + _gamepadController.ConnectionChanged -= HandleGamepadConnectionChanged; + } + } + catch (Exception ex) + { + Debug.WriteLine($"[NumericInputDialog] 取消訂閱控制器事件失敗:{ex.Message}"); + } + } + + /// + /// 處理控制器連線狀態變更 + /// + /// 是否已連線 + private void HandleGamepadConnectionChanged(bool connected) + { + try + { + if (connected) + { + _gamepadController?.Resume(); + } + + // 告知使用者控制器連線狀態變更。 + AnnounceA11y(connected ? + string.Format(Strings.A11y_Gamepad_Connected, _gamepadController?.DeviceName) : + string.Format(Strings.A11y_Gamepad_Disconnected, _gamepadController?.DeviceName)); + } + catch (Exception ex) + { + LoggerService.LogException(ex, "NumericInputDialog.HandleGamepadConnectionChanged 失敗"); + + Debug.WriteLine($"[NumericInputDialog] 控制器連線變更處理失敗:{ex.Message}"); + } + } + + /// + /// 處理邊界撞擊效果 + /// + /// 是否為上限 + internal void HandleBoundaryHit(bool isUpperLimit) + { + this.SafeInvoke(() => + { + try + { + // 利用 _isFlashing 作為防呆機制,避免控制器長按連發時造成音效與語音播報卡頓。 + if (_isFlashing == 0) + { + FeedbackService.PlaySound(SystemSounds.Beep); + + FeedbackService.VibrateAsync( + _gamepadController, + VibrationPatterns.ActionFail, + _cts?.Token ?? CancellationToken.None) + .SafeFireAndForget(); + + AnnounceA11y(isUpperLimit ? + Strings.A11y_Value_Max : + Strings.A11y_Value_Min, true); + + FlashAlertAsync().SafeFireAndForget(); + } + } + catch (Exception ex) + { + Debug.WriteLine($"[NumericInputDialog] HandleBoundaryHit 失敗:{ex.Message}"); + } + }); + } + + /// + /// 處理數值增加,並保留焦點以支援眼動儀連發與鍵盤連點 + /// + private void HandlePlus() => this.SafeInvoke(() => + { + try + { + _nud?.UpButton(); + } + catch (Exception ex) + { + Debug.WriteLine($"[NumericInputDialog] HandlePlus 失敗:{ex.Message}"); + } + }); + + /// + /// 處理數值減少,並保留焦點以支援眼動儀連發與鍵盤連點 + /// + private void HandleMinus() => this.SafeInvoke(() => + { + try + { + _nud?.DownButton(); + } + catch (Exception ex) + { + Debug.WriteLine($"[NumericInputDialog] HandleMinus 失敗:{ex.Message}"); + } + }); + + /// + /// 處理游標移動 + /// + /// 是否向右(前進)移動 + private void MoveCaret(bool forward) => this.SafeInvoke(() => + { + try + { + if (_nud == null) + { + return; + } + + TextBox? textBox = _nud.Controls.OfType().FirstOrDefault(); + + if (textBox == null || + textBox.IsDisposed) + { + return; + } + + bool hasSelection = textBox.SelectionLength > 0; + + bool canMove = forward ? + (hasSelection || textBox.SelectionStart < textBox.TextLength) : + (hasSelection || textBox.SelectionStart > 0); + + if (canMove) + { + if (hasSelection) + { + if (forward) + { + textBox.SelectionStart += textBox.SelectionLength; + } + + textBox.SelectionLength = 0; + } + // 組合鍵:任一肩鍵 + 方向鍵 執行單字跳轉。 + else if (_gamepadController?.IsLeftShoulderHeld == true || + _gamepadController?.IsRightShoulderHeld == true) + { + textBox.WordJump(forward); + } + else + { + if (forward) + { + textBox.SelectionStart++; + } + else + { + textBox.SelectionStart--; + } + } + + textBox.ScrollToCaret(); + + // 取得目前游標位置(1-based 報讀)。 + int pos = textBox.SelectionStart; + + AnnounceA11y(AppSettings.Current.IsPrivacyMode ? + Strings.A11y_Cursor_Move_PrivacySafe : + string.Format(Strings.A11y_Cursor_Move, pos + 1), true); + + FeedbackService.VibrateAsync( + _gamepadController, + VibrationPatterns.CursorMove, + _cts?.Token ?? CancellationToken.None) + .SafeFireAndForget(); + } + else + { + FeedbackService.VibrateAsync( + _gamepadController, + VibrationPatterns.ActionFail, + _cts?.Token ?? CancellationToken.None) + .SafeFireAndForget(); + } + } + catch (Exception ex) + { + Debug.WriteLine($"[NumericInputDialog] MoveCaret 失敗:{ex.Message}"); + } + }); + + /// + /// 處理游標左移 + /// + private void HandleLeft() => MoveCaret(false); + + /// + /// 處理游標右移 + /// + private void HandleRight() => MoveCaret(true); + + /// + /// 處理選取範圍擴張 + /// + /// 是否向右擴張 + private void ExpandSelection(bool forward) => this.SafeInvoke(() => + { + try + { + if (_nud == null) + { + return; + } + + TextBox? textBox = _nud.Controls.OfType().FirstOrDefault(); + + if (textBox == null || + textBox.IsDisposed) + { + return; + } + + // 當目前沒有選取範圍,或是目前的選取範圍與我們的錨點不匹配時,重新設定錨點,並推算活動邊緣。 + (int anchor, int caret) = textBox.ResolveSelectionAnchor(_rsSelectionAnchor); + + _rsSelectionAnchor = anchor; + + int direction = forward ? 1 : -1; + bool wordGranularity = _gamepadController?.IsLeftShoulderHeld == true || + _gamepadController?.IsRightShoulderHeld == true; + + int newCaret = wordGranularity ? + textBox.GetWordJumpTarget(caret, direction > 0) : + Math.Clamp(caret + direction, 0, textBox.TextLength); + + if (newCaret == caret) + { + FeedbackService.VibrateAsync( + _gamepadController, + VibrationPatterns.ActionFail, + _cts?.Token ?? CancellationToken.None) + .SafeFireAndForget(); + + return; + } + + // 使用 Win32 EM_SETSEL 設定選取範圍。 + textBox.SetSelectionWithActiveEdge(anchor, newCaret); + + if (textBox.SelectionLength > 0) + { + AnnounceA11y(AppSettings.Current.IsPrivacyMode ? + Strings.A11y_Selected_Text_PrivacySafe : + string.Format(Strings.A11y_Selected_Text, textBox.SelectedText), true); + } + + PlaySelectionFeedback(direction, wordGranularity); + } + catch (Exception ex) + { + Debug.WriteLine($"[NumericInputDialog] ExpandSelection 失敗:{ex.Message}"); + } + }); + + /// + /// 根據選取粒度與速度播放不同的右搖桿文字選取回饋。 + /// + /// 選取方向;負值為向左,正值為向右。 + /// 是否為單字粒度選取。 + private void PlaySelectionFeedback(int direction, bool wordGranularity) + { + IGamepadController? controller = _gamepadController; + + if (controller == null || + !controller.IsConnected) + { + return; + } + + DateTime now = DateTime.UtcNow; + _selectionFeedbackBurstLevel = wordGranularity ? + 0 : + (now - _lastSelectionFeedbackUtc).TotalMilliseconds <= SelectionBurstWindowMs ? + Math.Min(_selectionFeedbackBurstLevel + 1, 3) : + 0; + _lastSelectionFeedbackUtc = now; + + FeedbackService.VibrateSequenceAsync( + controller, + VibrationPatterns.GetSelectionSequence(direction, wordGranularity, _selectionFeedbackBurstLevel, controller.VibrationMotorSupport), + _cts?.Token ?? CancellationToken.None) + .SafeFireAndForget(); + + FeedbackService.PlaySelectionCue(wordGranularity, _selectionFeedbackBurstLevel); + } + + /// + /// 處理選取左向擴張 + /// + private void HandleRSLeft() => ExpandSelection(false); + + /// + /// 處理選取右向擴張 + /// + private void HandleRSRight() => ExpandSelection(true); + + /// + /// 處理刪除按鍵(Backspace 與 Delete)的共用邏輯 + /// + /// 目標 TextBox + /// 是否為 Backspace 鍵 + private void HandleDeleteKey(TextBox textBox, bool isBackspace) + { + try + { + // 擷取刪除前的狀態。 + string oldText = textBox.Text; + + int oldStart = textBox.SelectionStart, + oldLen = textBox.SelectionLength; + + // 檢查是否可以刪除。 + bool cannotDelete = isBackspace ? + (oldLen == 0 && oldStart == 0) : + (oldLen == 0 && oldStart == oldText.Length); + + if (cannotDelete) + { + FeedbackService.VibrateAsync( + _gamepadController, + VibrationPatterns.ActionFail, + _cts?.Token ?? CancellationToken.None) + .SafeFireAndForget(); + + if (isBackspace) + { + AnnounceA11y(Strings.A11y_Cannot_Delete, true); + } + + return; + } + + this.SafeBeginInvoke(() => + { + try + { + if (textBox.IsDisposed) + { + return; + } + + // 比對內容是否真的減少。 + if (textBox.TextLength < oldText.Length) + { + if (oldLen > 0) + { + AnnounceA11y(string.Format(Strings.A11y_Delete_Multiple, oldLen), true); + } + else + { + int deleteIndex = isBackspace ? + oldStart - 1 : + oldStart; + + if (deleteIndex >= 0 && + deleteIndex < oldText.Length) + { + if (AppSettings.Current.IsPrivacyMode) + { + AnnounceA11y(Strings.A11y_Delete_Char_PrivacySafe, true); + } + else + { + char deletedChar = oldText[deleteIndex]; + + AnnounceA11y(string.Format(Strings.A11y_Delete_Char, deletedChar), true); + } + } + } + } + } + catch (Exception ex) + { + Debug.WriteLine($"[NumericInputDialog] HandleDeleteKey 延遲邏輯失敗:{ex.Message}"); + } + }); + } + catch (Exception ex) + { + Debug.WriteLine($"[NumericInputDialog] HandleDeleteKey 失敗:{ex.Message}"); + } + } + + /// + /// A 鍵:按鈕 → PerformClick;輸入框為空時開啟觸控鍵盤;其餘情境走確認驗證。 + /// + private void HandleGamepadA() => this.SafeInvoke(() => + { + try + { + if (ActiveControl is Button btn) + { + btn.PerformClick(); + return; + } + + if (_nud != null && (_nud.Focused || _nud.ContainsFocus)) + { + TextBox? tb = _nud.Controls.OfType().FirstOrDefault(); + if (tb != null && string.IsNullOrWhiteSpace(tb.Text)) + { + ShowTouchKeyboard(tb); + return; + } + } + + HandleConfirm(); + } + catch (Exception ex) { Debug.WriteLine($"[NumericInputDialog] HandleGamepadA 失敗: {ex.Message}"); } + }); + + /// + /// Start 鍵:在輸入框焦點時直接開啟觸控式鍵盤 + /// + private void HandleOpenTouchKeyboardFromGamepad() => this.SafeInvoke(() => + { + try + { + TextBox? tb = _nud?.Controls.OfType().FirstOrDefault(); + if (tb != null) + { + ShowTouchKeyboard(tb); + } + } + catch (Exception ex) { Debug.WriteLine($"[NumericInputDialog] HandleOpenTouchKeyboardFromGamepad 失敗: {ex.Message}"); } + }); + + /// + /// 聚焦指定輸入框並非同步開啟觸控式鍵盤。 + /// + /// 要聚焦的輸入框。 + private void ShowTouchKeyboard(TextBox tb) + { + if (tb.CanFocus && + !tb.Focused) + { + tb.Focus(); + } + + AnnounceA11y(Strings.A11y_Opening_Keyboard, interrupt: true); + + Task.Run(async () => + { + try + { + await Task.Delay(150, _cts?.Token ?? CancellationToken.None); + + if (TouchKeyboardService.IsVisible()) return; + + await this.SafeInvokeAsync(() => + { + try + { + bool opened = TouchKeyboardService.TryOpen(); + + if (opened) + { + FeedbackService.PlaySound(SystemSounds.Asterisk); + } + } + catch (Exception ex) + { + Debug.WriteLine($"[NumericInputDialog] ShowTouchKeyboard 內層失敗: {ex.Message}"); + } + }); + } + catch (Exception ex) + { + Debug.WriteLine($"[NumericInputDialog] ShowTouchKeyboard 背景工作失敗: {ex.Message}"); + } + }, _cts?.Token ?? CancellationToken.None).SafeFireAndForget(); + } + + /// + /// X 鍵:刪除選取文字或游標前一字元 + /// + private void HandleBackspace() => this.SafeInvoke(() => + { + try + { + if (_nud == null) + { + return; + } + + TextBox? tb = _nud.Controls.OfType().FirstOrDefault(); + + if (tb == null || + tb.IsDisposed || + tb.ReadOnly) + { + return; + } + + // 實施手動字串處理以符合「不模擬按鍵」的安全性紅線。 + // 透過直接操作 TextBox.Text,能觸發 NumericUpDown 的內部驗證機制且不依賴 Win32 訊息注入。 + if (tb.SelectionLength > 0) + { + tb.SelectedText = string.Empty; + } + else if (tb.SelectionStart > 0) + { + int start = tb.SelectionStart; + + tb.Text = tb.Text.Remove(start - 1, 1); + tb.SelectionStart = start - 1; + } + } + catch (Exception ex) + { + Debug.WriteLine($"[NumericInputDialog] HandleBackspace 失敗: {ex.Message}"); + } + }); + + /// + /// LT 鍵:向左導覽游標 + /// + private void HandleLTNav() => MoveCaret(false); + + /// + /// RT 鍵:向右導覽游標 + /// + private void HandleRTNav() => MoveCaret(true); +} diff --git a/src/InputBox/Core/Controls/NumericInputDialog.Layout.cs b/src/InputBox/Core/Controls/NumericInputDialog.Layout.cs new file mode 100644 index 0000000..546e57f --- /dev/null +++ b/src/InputBox/Core/Controls/NumericInputDialog.Layout.cs @@ -0,0 +1,442 @@ +using InputBox.Core.Configuration; +using InputBox.Core.Extensions; +using InputBox.Core.Interop; +using InputBox.Core.Services; +using InputBox.Core.Utilities; +using InputBox.Resources; +using Microsoft.Win32; +using System.Diagnostics; + +namespace InputBox.Core.Controls; + +// 阻擋設計工具。 +partial class DesignerBlocker { }; + +/// +/// 專門用於數值輸入的對話框(版面配置與視覺分部)。 +/// 本分部檔案包含 DPI 與系統偏好變更處理、最小尺寸與按鈕約束、智慧定位、透明度,以及焦點與游標視覺等成員。 +/// +internal sealed partial class NumericInputDialog +{ + protected override void OnResizeEnd(EventArgs e) + { + try + { + base.OnResizeEnd(e); + + // 拖曳結束時執行智慧定位修正。 + ApplySmartPosition(); + } + catch (Exception ex) + { + Debug.WriteLine($"[NumericInputDialog] OnResizeEnd 失敗:{ex.Message}"); + } + } + + protected override void OnHandleCreated(EventArgs e) + { + try + { + base.OnHandleCreated(e); + + UpdateMinimumSize(); + + // 使用 SafeBeginInvoke 讓字型替換邏輯排在 Handle 建立完成「之後」才執行。 + this.SafeBeginInvoke(() => + { + try + { + // 套用透明度。 + UpdateOpacity(); + + // 執行初始位置檢查。 + ApplySmartPosition(); + } + catch (Exception ex) + { + LoggerService.LogException(ex, "NumericInputDialog.OnHandleCreated 延遲邏輯失敗"); + + Debug.WriteLine($"[NumericInputDialog] OnHandleCreated 延遲邏輯失敗:{ex.Message}"); + } + }); + + // 先解除再訂閱靜態事件,防止 Handle 重建時產生重複訂閱。 + SystemEvents.UserPreferenceChanged -= SystemEvents_UserPreferenceChanged; + SystemEvents.UserPreferenceChanged += SystemEvents_UserPreferenceChanged; + } + catch (Exception ex) + { + LoggerService.LogException(ex, "NumericInputDialog.OnHandleCreated 失敗"); + + Debug.WriteLine($"[NumericInputDialog] OnHandleCreated 失敗:{ex.Message}"); + } + } + + protected override void OnDpiChanged(DpiChangedEventArgs e) + { + try + { + base.OnDpiChanged(e); + + // 當 DPI 變更時,強制全視窗重新讀取全域共享字體。 + this.SafeInvoke(() => + { + try + { + // 重新取得 A11y 字型實例(從快取池取得)。 + _a11yFont = MainForm.GetSharedA11yFont(DeviceDpi); + + // 同步更新所有按鈕的基礎字體。 + if (_a11yFont != null) + { + _btnOk!.Font = _a11yFont; + _btnCancel!.Font = _a11yFont; + _btnPlus!.Font = _a11yFont; + _btnMinus!.Font = _a11yFont; + _btnReset!.Font = _a11yFont; + } + + // 數值顯示區字體需重新依據新縮放比例建立。 + if (_a11yFont != null && + _nud != null) + { + // 2.0x 放大字體(來自共享快取,不需手動回收)。 + _nudFont = MainForm.GetSharedA11yFont(DeviceDpi, FontStyle.Bold, _a11yFont.FontFamily, 2.0f); + + _nud.Font = _nudFont; + } + + // 更新佈局約束。 + UpdateMinimumSize(); + + // 強制所有控制項重新套用最新主題與字體。 + UpdateFocusVisuals(_nud?.Focused == true || (_nud?.ContainsFocus == true)); + + ApplySmartPosition(); + } + catch (Exception ex) + { + LoggerService.LogException(ex, "NumericInputDialog.OnDpiChanged 延遲邏輯失敗"); + + Debug.WriteLine($"[NumericInputDialog] OnDpiChanged 延遲邏輯失敗:{ex.Message}"); + } + }); + } + catch (Exception ex) + { + LoggerService.LogException(ex, "NumericInputDialog.OnDpiChanged 失敗"); + + Debug.WriteLine($"[NumericInputDialog] OnDpiChanged 失敗:{ex.Message}"); + } + } + + private void SystemEvents_UserPreferenceChanged(object sender, UserPreferenceChangedEventArgs e) + { + try + { + if (e.Category == UserPreferenceCategory.Accessibility || + e.Category == UserPreferenceCategory.Color || + e.Category == UserPreferenceCategory.General) + { + this.SafeInvoke(() => + { + try + { + UpdateMinimumSize(); + + UpdateFocusVisuals(_nud?.Focused == true || (_nud?.ContainsFocus == true)); + } + catch (Exception ex) + { + LoggerService.LogException(ex, "[NumericInputDialog] SystemEvents 更新失敗"); + + Debug.WriteLine($"[NumericInputDialog] SystemEvents 更新失敗:{ex.Message}"); + } + }); + } + } + catch (Exception ex) + { + LoggerService.LogException(ex, "[NumericInputDialog] SystemEvents 處理失敗"); + + Debug.WriteLine($"[NumericInputDialog] SystemEvents 處理失敗:{ex.Message}"); + } + } + + protected override void OnHandleDestroyed(EventArgs e) + { + try + { + // 確保靜態事件在視窗控制項控制代碼銷毀時被絕對釋放。 + SystemEvents.UserPreferenceChanged -= SystemEvents_UserPreferenceChanged; + } + finally + { + base.OnHandleDestroyed(e); + } + } + + /// + /// 更新控制項焦點狀態的視覺表現 + /// + /// 指示控制項是否具有焦點 + private void UpdateFocusVisuals(bool isFocused) + { + try + { + if (_nud == null || + _nud.IsDisposed) + { + return; + } + + // 綜合判斷:只要數值框本身有焦點,或是旁邊的加減按鈕有焦點,數值框都應該保持高亮。 + bool shouldHighlight = isFocused || + (_btnPlus != null && _btnPlus.Focused) || + (_btnMinus != null && _btnMinus.Focused); + + if (shouldHighlight) + { + if (SystemInformation.HighContrast) + { + _nud.UpdateRecursive(SystemColors.Highlight, SystemColors.HighlightText); + } + else + { + bool isDark = this.IsDarkModeActive(); + + // 淺色模式:黑底白字、深色模式:白底黑字。 + _nud.UpdateRecursive( + isDark ? Color.White : Color.Black, + isDark ? Color.Black : Color.White); + } + } + else + { + _nud.ResetThemeRecursive(); + } + + // 當具有焦點時,強化游標。 + if (isFocused) + { + UpdateCaretWidth(); + } + } + catch (Exception ex) + { + Debug.WriteLine($"[NumericInputDialog] UpdateFocusVisuals 失敗:{ex.Message}"); + } + } + + /// + /// 根據 DPI 與無障礙設定更新數值框內部游標寬度 + /// + private void UpdateCaretWidth() + { + try + { + if (_nud == null || + _nud.IsDisposed || + !_nud.IsHandleCreated) + { + return; + } + + // 尋找 NUD 內部的 TextBox 子控制項。 + TextBox? innerTextBox = _nud.Controls.OfType().FirstOrDefault(); + + if (innerTextBox == null || + !innerTextBox.IsHandleCreated) + { + return; + } + + // 基礎寬度 3px,隨 DPI 縮放。 + float scale = DeviceDpi / AppSettings.BaseDpi; + + int caretWidth = (int)Math.Max(3, 3 * scale); + + // 高對比模式下額外加粗。 + if (SystemInformation.HighContrast) + { + caretWidth += (int)(2 * scale); + } + + int caretHeight = innerTextBox.Height; + + // 若寬高與上次一致,則略過 Win32 API 調用,減少 UI 閃爍感。 + if (caretWidth == _lastCaretWidth && + caretHeight == _lastCaretHeight) + { + return; + } + + _lastCaretWidth = caretWidth; + _lastCaretHeight = caretHeight; + + // 使用 Win32 API 重新建立游標。 + if (User32.CreateCaret(innerTextBox.Handle, IntPtr.Zero, caretWidth, caretHeight)) + { + User32.ShowCaret(innerTextBox.Handle); + } + } + catch (Exception ex) + { + Debug.WriteLine($"[NumericInputDialog] UpdateCaretWidth 失敗:{ex.Message}"); + } + } + + /// + /// 更新視窗不透明度。 + /// + private void UpdateOpacity() + { + try + { + // 根據規範,若系統開啟高對比模式,則強制為 1.0 以確保絕對可讀性。 + if (SystemInformation.HighContrast) + { + Opacity = 1.0; + + return; + } + + // 數值輸入框鎖定 1.0 不透明度以確保輸入清晰度。 + Opacity = 1.0; + } + catch (Exception ex) + { + Debug.WriteLine($"[NumericInputDialog] UpdateOpacity 失敗:{ex.Message}"); + } + } + + /// + /// 更新視窗最小尺寸與按鈕佈局約束 + /// + private void UpdateMinimumSize() + { + try + { + float currentDpi = DeviceDpi; + + if (!DialogLayoutHelper.TryBeginDpiLayout(currentDpi, ref _lastAppliedDpi)) + { + return; + } + + float scale = currentDpi / AppSettings.BaseDpi; + + // 內容感知:更新所有按鈕的佈局約束(Bold 預測)。 + // 確保按鈕在獲得焦點變為粗體時,物理邊界保持絕對靜止,達成 Zero-Jitter。 + UpdateButtonConstraints(_btnOk, scale); + UpdateButtonConstraints(_btnCancel, scale); + UpdateButtonConstraints(_btnPlus, scale); + UpdateButtonConstraints(_btnMinus, scale); + UpdateButtonConstraints(_btnReset, scale); + + // 改用內容偏好尺寸作為基準。 + _tlpGrid?.PerformLayout(); + + Size contentPref = _tlpGrid?.GetPreferredSize(Size.Empty) ?? + new((int)(450 * scale), (int)(250 * scale)); + + Rectangle workArea = Screen.GetWorkingArea(this); + + // 計算邊框與標題列所需的額外空間(比照 HelpDialog.cs)。 + int frameW = SystemInformation.FrameBorderSize.Width * 2, + frameH = SystemInformation.FrameBorderSize.Height * 2, + captionH = SystemInformation.CaptionHeight; + + (int maxFitW, int maxFitH) = DialogLayoutHelper.GetMaxFitSize(workArea); + + // 視窗寬度:內容寬度 + 表單 Padding + 框架,以工作區上限為準。 + int formW = Math.Clamp( + contentPref.Width + Padding.Horizontal + frameW + 8, + (int)(450 * scale), + maxFitW); + + // 視窗高度:依實際內容偏好尺寸計算,上限為工作區可用高度(保留 40px 邊界)。 + int desiredMinHeight = (int)(300 * scale), + naturalH = contentPref.Height + Padding.Vertical + captionH + frameH + 8, + formH = Math.Clamp(naturalH, desiredMinHeight, Math.Max(desiredMinHeight, maxFitH)); + + MinimumSize = new Size(Math.Min((int)(450 * scale), maxFitW), desiredMinHeight); + + Size = new Size(formW, formH); + + // 佈局擴張後,執行智慧定位檢查。 + ApplySmartPosition(); + + // 高對比模式下強制 100% 不透明度。 + if (SystemInformation.HighContrast) + { + UpdateOpacity(); + } + } + catch (Exception ex) + { + Debug.WriteLine($"[NumericInputDialog] UpdateMinimumSize 失敗:{ex.Message}"); + } + } + + /// + /// 更新單個按鈕的佈局約束與最小尺寸鎖定 + /// + /// 目標按鈕 + /// 目前 DPI 縮放比例 + private void UpdateButtonConstraints(Button? btn, float scale) + { + try + { + if (btn == null || + btn.IsDisposed) + { + return; + } + + // 取得專屬於此視窗 DPI 的 Bold 字體實例。 + Font boldFont = MainForm.GetSharedA11yFont(DeviceDpi, FontStyle.Bold, btn.Font.FontFamily); + + // 眼動儀友善:抗抖動寬度鎖定(Anti-Jitter Lock)。 + DialogLayoutHelper.UpdateButtonMinimumSize(btn, boldFont, scale, 120, 60, 32, 24); + } + catch (Exception ex) + { + Debug.WriteLine($"[NumericInputDialog] UpdateButtonConstraints 失敗:{ex.Message}"); + } + } + + /// + /// 執行智慧定位修正,確保視窗不會跑出螢幕邊界 + /// + private void ApplySmartPosition() + { + // 脫離目前的佈局計算循環,確保所有 StartPosition 與 AutoSize 已處理完畢。 + this.SafeBeginInvoke(() => + { + try + { + if (IsDisposed || + !IsHandleCreated) + { + return; + } + + // 強制同步最新的實體佈局尺寸(關鍵:確保 Width/Height 是縮放後的真實值)。 + PerformLayout(); + + if (InputBoxLayoutManager.TryGetClampedLocation(this, out Point clampedLocation)) + { + Location = clampedLocation; + + // 告知使用者視窗已修正位置。 + AnnounceA11y(Strings.A11y_SnapBack); + } + } + catch (Exception ex) + { + Debug.WriteLine($"[NumericInputDialog] ApplySmartPosition 失敗:{ex.Message}"); + } + }); + } +} diff --git a/src/InputBox/Core/Controls/NumericInputDialog.cs b/src/InputBox/Core/Controls/NumericInputDialog.cs index 58b29a9..723d35d 100644 --- a/src/InputBox/Core/Controls/NumericInputDialog.cs +++ b/src/InputBox/Core/Controls/NumericInputDialog.cs @@ -20,125 +20,8 @@ partial class DesignerBlocker { }; /// /// 專門用於數值輸入的對話框 /// -internal sealed class NumericInputDialog : Form +internal sealed partial class NumericInputDialog : Form { - /// - /// 繼承自 NumericUpDown 以公開受保護的成員方法 - /// - /// 父對話框實例 - private sealed class AccessibleNumericUpDown(NumericInputDialog parent) : NumericUpDown - { - /// - /// 父 NumericInputDialog 實例,用於回呼邊界撞牆通知。 - /// - private readonly NumericInputDialog _parent = parent; - - /// - /// 遞增數值,若已達上限則通知父對話框播放邊界回饋。 - /// - public override void UpButton() - { - try - { - decimal oldValue = Value; - - base.UpButton(); - - if (Value == oldValue) - { - _parent.HandleBoundaryHit(true); - } - } - catch (Exception ex) - { - Debug.WriteLine($"[NumericUpDown] UpButton 失敗:{ex.Message}"); - } - } - - /// - /// 遞減數值,若已達下限則通知父對話框播放邊界回饋。 - /// - public override void DownButton() - { - try - { - decimal oldValue = Value; - - base.DownButton(); - - if (Value == oldValue) - { - _parent.HandleBoundaryHit(false); - } - } - catch (Exception ex) - { - Debug.WriteLine($"[NumericUpDown] DownButton 失敗:{ex.Message}"); - } - } - - /// - /// 主動觸發無障礙狀態變更通知 - /// - public void NotifyAccessibilityChange() - { - try - { - // 主動通知輔助科技(AT)數值已變更。 - AccessibilityNotifyClients(AccessibleEvents.ValueChange, -1); - } - catch (Exception ex) - { - Debug.WriteLine($"[NumericUpDown] NotifyAccessibilityChange 失敗:{ex.Message}"); - } - } - - /// - /// 強制驗證編輯文字,確保 Value 屬性與目前輸入內容同步 - /// - public void ValidateValue() - { - try - { - ValidateEditText(); - } - catch (Exception ex) - { - Debug.WriteLine($"[NumericUpDown] ValidateValue 失敗:{ex.Message}"); - } - } - - /// - /// 覆寫滑鼠滾輪行為,確保「一格跳一格」 - /// - /// MouseEventArgs - protected override void OnMouseWheel(MouseEventArgs e) - { - try - { - // 強制攔截並阻斷 Windows 系統的「一次捲動多行」設定(預設為 3)。 - if (e is HandledMouseEventArgs hme) - { - hme.Handled = true; - } - - // 手動精確執行單次增減,不調用 base.OnMouseWheel(e)。 - if (e.Delta > 0) - { - UpButton(); - } - else if (e.Delta < 0) - { - DownButton(); - } - } - catch (Exception ex) - { - Debug.WriteLine($"[NumericUpDown] OnMouseWheel 失敗:{ex.Message}"); - } - } - } - /// /// 預設數值 /// @@ -262,214 +145,6 @@ protected override void OnMouseWheel(MouseEventArgs e) [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] public Func? ConfirmBeforeClose { get; set; } - /// - /// 設定控制器實作,並訂閱事件 - /// - [Browsable(false)] - [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] - public IGamepadController? GamepadController - { - get => _gamepadController; - set - { - // 如果控制器相同,不執行任何操作。 - if (ReferenceEquals(_gamepadController, value)) - { - return; - } - - // 安全清理舊控制器的訂閱。 - UnsubscribeGamepadEvents(); - - _gamepadController = value; - - if (_gamepadController != null) - { - GamepadFaceButtonProfile profile = GamepadFaceButtonProfile.GetActiveProfile(); - - // 訂閱新控制器事件。 - _gamepadController.UpPressed += HandlePlus; - _gamepadController.UpRepeat += HandlePlus; - _gamepadController.DownPressed += HandleMinus; - _gamepadController.DownRepeat += HandleMinus; - _gamepadController.LeftPressed += HandleLeft; - _gamepadController.LeftRepeat += HandleLeft; - _gamepadController.RightPressed += HandleRight; - _gamepadController.RightRepeat += HandleRight; - _gamepadController.RSLeftPressed += HandleRSLeft; - _gamepadController.RSLeftRepeat += HandleRSLeft; - _gamepadController.RSRightPressed += HandleRSRight; - _gamepadController.RSRightRepeat += HandleRSRight; - _gamepadController.APressed += profile.ConfirmOnSouth ? HandleGamepadA : HandleCancel; - _gamepadController.StartPressed += HandleOpenTouchKeyboardFromGamepad; - _gamepadController.BPressed += profile.ConfirmOnSouth ? HandleCancel : HandleGamepadA; - _gamepadController.BackPressed += HandleCancel; - _gamepadController.XPressed += HandleBackspace; - _gamepadController.YPressed += HandleReset; - // 已由 D‑Pad (`LeftPressed` / `RightPressed`) 處理游標移動,移除 LT/RT 綁定以避免語意重複。 - _gamepadController.ConnectionChanged += HandleGamepadConnectionChanged; - } - } - } - - protected override void OnResizeEnd(EventArgs e) - { - try - { - base.OnResizeEnd(e); - - // 拖曳結束時執行智慧定位修正。 - ApplySmartPosition(); - } - catch (Exception ex) - { - Debug.WriteLine($"[NumericInputDialog] OnResizeEnd 失敗:{ex.Message}"); - } - } - - protected override void OnHandleCreated(EventArgs e) - { - try - { - base.OnHandleCreated(e); - - UpdateMinimumSize(); - - // 使用 SafeBeginInvoke 讓字型替換邏輯排在 Handle 建立完成「之後」才執行。 - this.SafeBeginInvoke(() => - { - try - { - // 套用透明度。 - UpdateOpacity(); - - // 執行初始位置檢查。 - ApplySmartPosition(); - } - catch (Exception ex) - { - LoggerService.LogException(ex, "NumericInputDialog.OnHandleCreated 延遲邏輯失敗"); - - Debug.WriteLine($"[NumericInputDialog] OnHandleCreated 延遲邏輯失敗:{ex.Message}"); - } - }); - - // 先解除再訂閱靜態事件,防止 Handle 重建時產生重複訂閱。 - SystemEvents.UserPreferenceChanged -= SystemEvents_UserPreferenceChanged; - SystemEvents.UserPreferenceChanged += SystemEvents_UserPreferenceChanged; - } - catch (Exception ex) - { - LoggerService.LogException(ex, "NumericInputDialog.OnHandleCreated 失敗"); - - Debug.WriteLine($"[NumericInputDialog] OnHandleCreated 失敗:{ex.Message}"); - } - } - - protected override void OnDpiChanged(DpiChangedEventArgs e) - { - try - { - base.OnDpiChanged(e); - - // 當 DPI 變更時,強制全視窗重新讀取全域共享字體。 - this.SafeInvoke(() => - { - try - { - // 重新取得 A11y 字型實例(從快取池取得)。 - _a11yFont = MainForm.GetSharedA11yFont(DeviceDpi); - - // 同步更新所有按鈕的基礎字體。 - if (_a11yFont != null) - { - _btnOk!.Font = _a11yFont; - _btnCancel!.Font = _a11yFont; - _btnPlus!.Font = _a11yFont; - _btnMinus!.Font = _a11yFont; - _btnReset!.Font = _a11yFont; - } - - // 數值顯示區字體需重新依據新縮放比例建立。 - if (_a11yFont != null && - _nud != null) - { - // 2.0x 放大字體(來自共享快取,不需手動回收)。 - _nudFont = MainForm.GetSharedA11yFont(DeviceDpi, FontStyle.Bold, _a11yFont.FontFamily, 2.0f); - - _nud.Font = _nudFont; - } - - // 更新佈局約束。 - UpdateMinimumSize(); - - // 強制所有控制項重新套用最新主題與字體。 - UpdateFocusVisuals(_nud?.Focused == true || (_nud?.ContainsFocus == true)); - - ApplySmartPosition(); - } - catch (Exception ex) - { - LoggerService.LogException(ex, "NumericInputDialog.OnDpiChanged 延遲邏輯失敗"); - - Debug.WriteLine($"[NumericInputDialog] OnDpiChanged 延遲邏輯失敗:{ex.Message}"); - } - }); - } - catch (Exception ex) - { - LoggerService.LogException(ex, "NumericInputDialog.OnDpiChanged 失敗"); - - Debug.WriteLine($"[NumericInputDialog] OnDpiChanged 失敗:{ex.Message}"); - } - } - - private void SystemEvents_UserPreferenceChanged(object sender, UserPreferenceChangedEventArgs e) - { - try - { - if (e.Category == UserPreferenceCategory.Accessibility || - e.Category == UserPreferenceCategory.Color || - e.Category == UserPreferenceCategory.General) - { - this.SafeInvoke(() => - { - try - { - UpdateMinimumSize(); - - UpdateFocusVisuals(_nud?.Focused == true || (_nud?.ContainsFocus == true)); - } - catch (Exception ex) - { - LoggerService.LogException(ex, "[NumericInputDialog] SystemEvents 更新失敗"); - - Debug.WriteLine($"[NumericInputDialog] SystemEvents 更新失敗:{ex.Message}"); - } - }); - } - } - catch (Exception ex) - { - LoggerService.LogException(ex, "[NumericInputDialog] SystemEvents 處理失敗"); - - Debug.WriteLine($"[NumericInputDialog] SystemEvents 處理失敗:{ex.Message}"); - } - } - - protected override void OnHandleDestroyed(EventArgs e) - { - try - { - // 確保靜態事件在視窗控制項控制代碼銷毀時被絕對釋放。 - SystemEvents.UserPreferenceChanged -= SystemEvents_UserPreferenceChanged; - } - finally - { - base.OnHandleDestroyed(e); - } - } - protected override void Dispose(bool disposing) { try @@ -510,505 +185,88 @@ protected override void Dispose(bool disposing) } /// - /// 取消訂閱控制器事件 + /// 處理確認按鍵事件 /// - private void UnsubscribeGamepadEvents() + private void HandleConfirm() => this.SafeInvoke(() => { try { - if (_gamepadController != null) + if (IsDisposed || + !IsHandleCreated) { - _gamepadController.UpPressed -= HandlePlus; - _gamepadController.UpRepeat -= HandlePlus; - _gamepadController.DownPressed -= HandleMinus; - _gamepadController.DownRepeat -= HandleMinus; - _gamepadController.LeftPressed -= HandleLeft; - _gamepadController.LeftRepeat -= HandleLeft; - _gamepadController.RightPressed -= HandleRight; - _gamepadController.RightRepeat -= HandleRight; - _gamepadController.RSLeftPressed -= HandleRSLeft; - _gamepadController.RSLeftRepeat -= HandleRSLeft; - _gamepadController.RSRightPressed -= HandleRSRight; - _gamepadController.RSRightRepeat -= HandleRSRight; - _gamepadController.APressed -= HandleGamepadA; - _gamepadController.APressed -= HandleCancel; - _gamepadController.StartPressed -= HandleOpenTouchKeyboardFromGamepad; - _gamepadController.BPressed -= HandleGamepadA; - _gamepadController.BPressed -= HandleCancel; - _gamepadController.BackPressed -= HandleCancel; - _gamepadController.XPressed -= HandleBackspace; - _gamepadController.YPressed -= HandleReset; - _gamepadController.ConnectionChanged -= HandleGamepadConnectionChanged; + return; } - } - catch (Exception ex) - { - Debug.WriteLine($"[NumericInputDialog] 取消訂閱控制器事件失敗:{ex.Message}"); - } - } - /// - /// 處理控制器連線狀態變更 - /// - /// 是否已連線 - private void HandleGamepadConnectionChanged(bool connected) - { - try - { - if (connected) + _nud?.ValidateValue(); + + // 關閉前執行呼叫端的驗證回呼(例如低不透明度警告)。 + if (ConfirmBeforeClose != null && !ConfirmBeforeClose(Value)) { - _gamepadController?.Resume(); + // 使用者在警告對話框中取消:保持 NumericInputDialog 開啟。 + return; } - // 告知使用者控制器連線狀態變更。 - AnnounceA11y(connected ? - string.Format(Strings.A11y_Gamepad_Connected, _gamepadController?.DeviceName) : - string.Format(Strings.A11y_Gamepad_Disconnected, _gamepadController?.DeviceName)); + // 發送與控制器對等的震動與 A11y 播報。 + FeedbackService.PlaySound(SystemSounds.Asterisk); + + FeedbackService.VibrateAsync( + _gamepadController, + VibrationPatterns.CopySuccess, + _cts?.Token ?? CancellationToken.None) + .SafeFireAndForget(); + + // 直接在 UI 執行緒同步播報,避免 Task.Run 路徑在 Dispose 取消 + // _cts 後因 OperationCanceledException 而遺失此關鍵訊息。 + _announcer?.Announce(Strings.A11y_Returning, false); + + DialogResult = DialogResult.OK; + + Close(); } catch (Exception ex) { - LoggerService.LogException(ex, "NumericInputDialog.HandleGamepadConnectionChanged 失敗"); - - Debug.WriteLine($"[NumericInputDialog] 控制器連線變更處理失敗:{ex.Message}"); + Debug.WriteLine($"[NumericInputDialog] HandleConfirm 失敗:{ex.Message}"); } - } + }); /// - /// 處理邊界撞擊效果 + /// 處理取消按鍵事件 /// - /// 是否為上限 - internal void HandleBoundaryHit(bool isUpperLimit) + private void HandleCancel() => this.SafeInvoke(() => { - this.SafeInvoke(() => + try { - try + if (IsDisposed || + !IsHandleCreated) { - // 利用 _isFlashing 作為防呆機制,避免控制器長按連發時造成音效與語音播報卡頓。 - if (_isFlashing == 0) - { - FeedbackService.PlaySound(SystemSounds.Beep); + return; + } - FeedbackService.VibrateAsync( - _gamepadController, - VibrationPatterns.ActionFail, - _cts?.Token ?? CancellationToken.None) - .SafeFireAndForget(); + // 發送與控制器對等的震動(比照返回動作)。 + FeedbackService.PlaySound(SystemSounds.Exclamation); - AnnounceA11y(isUpperLimit ? - Strings.A11y_Value_Max : - Strings.A11y_Value_Min, true); + FeedbackService.VibrateAsync( + _gamepadController, + VibrationPatterns.ReturnStart, + _cts?.Token ?? CancellationToken.None) + .SafeFireAndForget(); - FlashAlertAsync().SafeFireAndForget(); - } - } - catch (Exception ex) - { - Debug.WriteLine($"[NumericInputDialog] HandleBoundaryHit 失敗:{ex.Message}"); - } - }); - } + // A11y 播報在 FormClosing 中已處理。 - /// - /// 處理數值增加,並保留焦點以支援眼動儀連發與鍵盤連點 - /// - private void HandlePlus() => this.SafeInvoke(() => - { - try - { - _nud?.UpButton(); + DialogResult = DialogResult.Cancel; + + Close(); } catch (Exception ex) { - Debug.WriteLine($"[NumericInputDialog] HandlePlus 失敗:{ex.Message}"); + Debug.WriteLine($"[NumericInputDialog] HandleCancel 失敗:{ex.Message}"); } }); /// - /// 處理數值減少,並保留焦點以支援眼動儀連發與鍵盤連點 + /// 處理重設按鍵事件 /// - private void HandleMinus() => this.SafeInvoke(() => - { - try - { - _nud?.DownButton(); - } - catch (Exception ex) - { - Debug.WriteLine($"[NumericInputDialog] HandleMinus 失敗:{ex.Message}"); - } - }); - - /// - /// 處理游標移動 - /// - /// 是否向右(前進)移動 - private void MoveCaret(bool forward) => this.SafeInvoke(() => - { - try - { - if (_nud == null) - { - return; - } - - TextBox? textBox = _nud.Controls.OfType().FirstOrDefault(); - - if (textBox == null || - textBox.IsDisposed) - { - return; - } - - bool hasSelection = textBox.SelectionLength > 0; - - bool canMove = forward ? - (hasSelection || textBox.SelectionStart < textBox.TextLength) : - (hasSelection || textBox.SelectionStart > 0); - - if (canMove) - { - if (hasSelection) - { - if (forward) - { - textBox.SelectionStart += textBox.SelectionLength; - } - - textBox.SelectionLength = 0; - } - // 組合鍵:任一肩鍵 + 方向鍵 執行單字跳轉。 - else if (_gamepadController?.IsLeftShoulderHeld == true || - _gamepadController?.IsRightShoulderHeld == true) - { - textBox.WordJump(forward); - } - else - { - if (forward) - { - textBox.SelectionStart++; - } - else - { - textBox.SelectionStart--; - } - } - - textBox.ScrollToCaret(); - - // 取得目前游標位置(1-based 報讀)。 - int pos = textBox.SelectionStart; - - AnnounceA11y(AppSettings.Current.IsPrivacyMode ? - Strings.A11y_Cursor_Move_PrivacySafe : - string.Format(Strings.A11y_Cursor_Move, pos + 1), true); - - FeedbackService.VibrateAsync( - _gamepadController, - VibrationPatterns.CursorMove, - _cts?.Token ?? CancellationToken.None) - .SafeFireAndForget(); - } - else - { - FeedbackService.VibrateAsync( - _gamepadController, - VibrationPatterns.ActionFail, - _cts?.Token ?? CancellationToken.None) - .SafeFireAndForget(); - } - } - catch (Exception ex) - { - Debug.WriteLine($"[NumericInputDialog] MoveCaret 失敗:{ex.Message}"); - } - }); - - /// - /// 處理游標左移 - /// - private void HandleLeft() => MoveCaret(false); - - /// - /// 處理游標右移 - /// - private void HandleRight() => MoveCaret(true); - - /// - /// 處理選取範圍擴張 - /// - /// 是否向右擴張 - private void ExpandSelection(bool forward) => this.SafeInvoke(() => - { - try - { - if (_nud == null) - { - return; - } - - TextBox? textBox = _nud.Controls.OfType().FirstOrDefault(); - - if (textBox == null || - textBox.IsDisposed) - { - return; - } - - // 當目前沒有選取範圍,或是目前的選取範圍與我們的錨點不匹配時,重新設定錨點,並推算活動邊緣。 - (int anchor, int caret) = textBox.ResolveSelectionAnchor(_rsSelectionAnchor); - - _rsSelectionAnchor = anchor; - - int direction = forward ? 1 : -1; - bool wordGranularity = _gamepadController?.IsLeftShoulderHeld == true || - _gamepadController?.IsRightShoulderHeld == true; - - int newCaret = wordGranularity ? - textBox.GetWordJumpTarget(caret, direction > 0) : - Math.Clamp(caret + direction, 0, textBox.TextLength); - - if (newCaret == caret) - { - FeedbackService.VibrateAsync( - _gamepadController, - VibrationPatterns.ActionFail, - _cts?.Token ?? CancellationToken.None) - .SafeFireAndForget(); - - return; - } - - // 使用 Win32 EM_SETSEL 設定選取範圍。 - textBox.SetSelectionWithActiveEdge(anchor, newCaret); - - if (textBox.SelectionLength > 0) - { - AnnounceA11y(AppSettings.Current.IsPrivacyMode ? - Strings.A11y_Selected_Text_PrivacySafe : - string.Format(Strings.A11y_Selected_Text, textBox.SelectedText), true); - } - - PlaySelectionFeedback(direction, wordGranularity); - } - catch (Exception ex) - { - Debug.WriteLine($"[NumericInputDialog] ExpandSelection 失敗:{ex.Message}"); - } - }); - - /// - /// 根據選取粒度與速度播放不同的右搖桿文字選取回饋。 - /// - /// 選取方向;負值為向左,正值為向右。 - /// 是否為單字粒度選取。 - private void PlaySelectionFeedback(int direction, bool wordGranularity) - { - IGamepadController? controller = _gamepadController; - - if (controller == null || - !controller.IsConnected) - { - return; - } - - DateTime now = DateTime.UtcNow; - _selectionFeedbackBurstLevel = wordGranularity ? - 0 : - (now - _lastSelectionFeedbackUtc).TotalMilliseconds <= SelectionBurstWindowMs ? - Math.Min(_selectionFeedbackBurstLevel + 1, 3) : - 0; - _lastSelectionFeedbackUtc = now; - - FeedbackService.VibrateSequenceAsync( - controller, - VibrationPatterns.GetSelectionSequence(direction, wordGranularity, _selectionFeedbackBurstLevel, controller.VibrationMotorSupport), - _cts?.Token ?? CancellationToken.None) - .SafeFireAndForget(); - - FeedbackService.PlaySelectionCue(wordGranularity, _selectionFeedbackBurstLevel); - } - - /// - /// 處理選取左向擴張 - /// - private void HandleRSLeft() => ExpandSelection(false); - - /// - /// 處理選取右向擴張 - /// - private void HandleRSRight() => ExpandSelection(true); - - /// - /// 處理刪除按鍵(Backspace 與 Delete)的共用邏輯 - /// - /// 目標 TextBox - /// 是否為 Backspace 鍵 - private void HandleDeleteKey(TextBox textBox, bool isBackspace) - { - try - { - // 擷取刪除前的狀態。 - string oldText = textBox.Text; - - int oldStart = textBox.SelectionStart, - oldLen = textBox.SelectionLength; - - // 檢查是否可以刪除。 - bool cannotDelete = isBackspace ? - (oldLen == 0 && oldStart == 0) : - (oldLen == 0 && oldStart == oldText.Length); - - if (cannotDelete) - { - FeedbackService.VibrateAsync( - _gamepadController, - VibrationPatterns.ActionFail, - _cts?.Token ?? CancellationToken.None) - .SafeFireAndForget(); - - if (isBackspace) - { - AnnounceA11y(Strings.A11y_Cannot_Delete, true); - } - - return; - } - - this.SafeBeginInvoke(() => - { - try - { - if (textBox.IsDisposed) - { - return; - } - - // 比對內容是否真的減少。 - if (textBox.TextLength < oldText.Length) - { - if (oldLen > 0) - { - AnnounceA11y(string.Format(Strings.A11y_Delete_Multiple, oldLen), true); - } - else - { - int deleteIndex = isBackspace ? - oldStart - 1 : - oldStart; - - if (deleteIndex >= 0 && - deleteIndex < oldText.Length) - { - if (AppSettings.Current.IsPrivacyMode) - { - AnnounceA11y(Strings.A11y_Delete_Char_PrivacySafe, true); - } - else - { - char deletedChar = oldText[deleteIndex]; - - AnnounceA11y(string.Format(Strings.A11y_Delete_Char, deletedChar), true); - } - } - } - } - } - catch (Exception ex) - { - Debug.WriteLine($"[NumericInputDialog] HandleDeleteKey 延遲邏輯失敗:{ex.Message}"); - } - }); - } - catch (Exception ex) - { - Debug.WriteLine($"[NumericInputDialog] HandleDeleteKey 失敗:{ex.Message}"); - } - } - - /// - /// 處理確認按鍵事件 - /// - private void HandleConfirm() => this.SafeInvoke(() => - { - try - { - if (IsDisposed || - !IsHandleCreated) - { - return; - } - - _nud?.ValidateValue(); - - // 關閉前執行呼叫端的驗證回呼(例如低不透明度警告)。 - if (ConfirmBeforeClose != null && !ConfirmBeforeClose(Value)) - { - // 使用者在警告對話框中取消:保持 NumericInputDialog 開啟。 - return; - } - - // 發送與控制器對等的震動與 A11y 播報。 - FeedbackService.PlaySound(SystemSounds.Asterisk); - - FeedbackService.VibrateAsync( - _gamepadController, - VibrationPatterns.CopySuccess, - _cts?.Token ?? CancellationToken.None) - .SafeFireAndForget(); - - // 直接在 UI 執行緒同步播報,避免 Task.Run 路徑在 Dispose 取消 - // _cts 後因 OperationCanceledException 而遺失此關鍵訊息。 - _announcer?.Announce(Strings.A11y_Returning, false); - - DialogResult = DialogResult.OK; - - Close(); - } - catch (Exception ex) - { - Debug.WriteLine($"[NumericInputDialog] HandleConfirm 失敗:{ex.Message}"); - } - }); - - /// - /// 處理取消按鍵事件 - /// - private void HandleCancel() => this.SafeInvoke(() => - { - try - { - if (IsDisposed || - !IsHandleCreated) - { - return; - } - - // 發送與控制器對等的震動(比照返回動作)。 - FeedbackService.PlaySound(SystemSounds.Exclamation); - - FeedbackService.VibrateAsync( - _gamepadController, - VibrationPatterns.ReturnStart, - _cts?.Token ?? CancellationToken.None) - .SafeFireAndForget(); - - // A11y 播報在 FormClosing 中已處理。 - - DialogResult = DialogResult.Cancel; - - Close(); - } - catch (Exception ex) - { - Debug.WriteLine($"[NumericInputDialog] HandleCancel 失敗:{ex.Message}"); - } - }); - - /// - /// 處理重設按鍵事件 - /// - private void HandleReset() => this.SafeInvoke(() => + private void HandleReset() => this.SafeInvoke(() => { try { @@ -1044,553 +302,6 @@ private void HandleReset() => this.SafeInvoke(() => } }); - /// - /// A 鍵:按鈕 → PerformClick;輸入框為空時開啟觸控鍵盤;其餘情境走確認驗證。 - /// - private void HandleGamepadA() => this.SafeInvoke(() => - { - try - { - if (ActiveControl is Button btn) - { - btn.PerformClick(); - return; - } - - if (_nud != null && (_nud.Focused || _nud.ContainsFocus)) - { - TextBox? tb = _nud.Controls.OfType().FirstOrDefault(); - if (tb != null && string.IsNullOrWhiteSpace(tb.Text)) - { - ShowTouchKeyboard(tb); - return; - } - } - - HandleConfirm(); - } - catch (Exception ex) { Debug.WriteLine($"[NumericInputDialog] HandleGamepadA 失敗: {ex.Message}"); } - }); - - /// - /// Start 鍵:在輸入框焦點時直接開啟觸控式鍵盤 - /// - private void HandleOpenTouchKeyboardFromGamepad() => this.SafeInvoke(() => - { - try - { - TextBox? tb = _nud?.Controls.OfType().FirstOrDefault(); - if (tb != null) - { - ShowTouchKeyboard(tb); - } - } - catch (Exception ex) { Debug.WriteLine($"[NumericInputDialog] HandleOpenTouchKeyboardFromGamepad 失敗: {ex.Message}"); } - }); - - /// - /// 聚焦指定輸入框並非同步開啟觸控式鍵盤。 - /// - /// 要聚焦的輸入框。 - private void ShowTouchKeyboard(TextBox tb) - { - if (tb.CanFocus && - !tb.Focused) - { - tb.Focus(); - } - - AnnounceA11y(Strings.A11y_Opening_Keyboard, interrupt: true); - - Task.Run(async () => - { - try - { - await Task.Delay(150, _cts?.Token ?? CancellationToken.None); - - if (TouchKeyboardService.IsVisible()) return; - - await this.SafeInvokeAsync(() => - { - try - { - bool opened = TouchKeyboardService.TryOpen(); - - if (opened) - { - FeedbackService.PlaySound(SystemSounds.Asterisk); - } - } - catch (Exception ex) - { - Debug.WriteLine($"[NumericInputDialog] ShowTouchKeyboard 內層失敗: {ex.Message}"); - } - }); - } - catch (Exception ex) - { - Debug.WriteLine($"[NumericInputDialog] ShowTouchKeyboard 背景工作失敗: {ex.Message}"); - } - }, _cts?.Token ?? CancellationToken.None).SafeFireAndForget(); - } - - /// - /// X 鍵:刪除選取文字或游標前一字元 - /// - private void HandleBackspace() => this.SafeInvoke(() => - { - try - { - if (_nud == null) - { - return; - } - - TextBox? tb = _nud.Controls.OfType().FirstOrDefault(); - - if (tb == null || - tb.IsDisposed || - tb.ReadOnly) - { - return; - } - - // 實施手動字串處理以符合「不模擬按鍵」的安全性紅線。 - // 透過直接操作 TextBox.Text,能觸發 NumericUpDown 的內部驗證機制且不依賴 Win32 訊息注入。 - if (tb.SelectionLength > 0) - { - tb.SelectedText = string.Empty; - } - else if (tb.SelectionStart > 0) - { - int start = tb.SelectionStart; - - tb.Text = tb.Text.Remove(start - 1, 1); - tb.SelectionStart = start - 1; - } - } - catch (Exception ex) - { - Debug.WriteLine($"[NumericInputDialog] HandleBackspace 失敗: {ex.Message}"); - } - }); - - /// - /// LT 鍵:向左導覽游標 - /// - private void HandleLTNav() => MoveCaret(false); - - /// - /// RT 鍵:向右導覽游標 - /// - private void HandleRTNav() => MoveCaret(true); - - /// - /// 執行視覺警示閃爍效果 - /// - /// Task - private async Task FlashAlertAsync() - { - if (IsDisposed || - !IsHandleCreated || - Interlocked.CompareExchange(ref _isFlashing, 1, 0) != 0) - { - return; - } - - // 僅在對話框生命週期仍有效時建立警示權杖,避免關閉途中留下失去連結的動畫。 - CancellationTokenSource? newAlertCts = _cts.TryCreateLinkedTokenSource(); - - if (newAlertCts == null) - { - Interlocked.Exchange(ref _isFlashing, 0); - - return; - } - - Interlocked.Exchange(ref _alertCts, newAlertCts)?.CancelAndDispose(); - - CancellationToken token = newAlertCts.Token; - - try - { - bool isDark = this.IsDarkModeActive(); - Color alertColor = FlashAlertAnimator.GetAlertColor(isDark, SystemInformation.HighContrast); - - void ApplyAlertVisuals(float intensity) - { - if (IsDisposed || - !IsHandleCreated || - _nud == null) - { - return; - } - - (Color back, Color fore) = FlashAlertAnimator.ComputeFrameColors( - intensity, - isDark, - alertColor, - SystemInformation.HighContrast); - - _nud.UpdateRecursive(back, fore); - } - - await FlashAlertAnimator.RunAsync(this, ApplyAlertVisuals, token); - } - catch (OperationCanceledException) - { - // 正常取消。 - } - catch (Exception ex) - { - Debug.WriteLine($"[NumericInputDialog] FlashAlertAsync 失敗:{ex.Message}"); - } - finally - { - Interlocked.Exchange(ref _isFlashing, 0); - Interlocked.Exchange(ref _alertCts, null)?.CancelAndDispose(); - - // 確保 UI 狀態還原。 - this.SafeInvoke(() => - { - try - { - if (IsDisposed || - !IsHandleCreated || - _nud == null) - { - return; - } - - // 關鍵修正:遞歸重設顏色,觸發 .NET 10 原生主題引擎還原正確配色,防止閃爍殘留。 - _nud.ResetThemeRecursive(); - - // 恢復焦點視覺狀態。 - UpdateFocusVisuals(_nud.Focused || _nud.ContainsFocus); - } - catch (Exception ex) - { - Debug.WriteLine($"[NumericInputDialog] FlashAlertAsync 還原失敗:{ex.Message}"); - } - }); - } - } - - /// - /// 內部 A11y 廣播方法 - /// - /// 要廣播的訊息 - /// 是否中斷目前的廣播 - private void AnnounceA11y( - string message, - bool interrupt = false) - { - if (IsDisposed || - string.IsNullOrEmpty(message)) - { - return; - } - - long currentId = Interlocked.Increment(ref _a11yDebounceId); - - Task.Run(async () => - { - try - { - // 統一 Audio Ducking 避讓延遲。 - await Task.Delay(AppSettings.AudioDuckingDelayMs, _cts?.Token ?? CancellationToken.None); - - if (Interlocked.Read(ref _a11yDebounceId) == currentId && - !IsDisposed && - IsHandleCreated) - { - await this.SafeInvokeAsync(() => - _announcer?.Announce(message, interrupt && AppSettings.Current.A11yInterruptEnabled)); - } - } - catch (OperationCanceledException) - { - // 正常取消。 - } - catch (Exception ex) - { - Debug.WriteLine($"[A11y] 對話框本地廣播失敗:{ex.Message}"); - } - }, - _cts?.Token ?? CancellationToken.None) - .SafeFireAndForget(); - } - - /// - /// 取得目前對話框所屬的主視窗 - /// - /// 若 Owner 為 則回傳該實例,否則為 null。 - private MainForm? GetOwnerMainForm() => Owner as MainForm; - - /// - /// 更新控制項焦點狀態的視覺表現 - /// - /// 指示控制項是否具有焦點 - private void UpdateFocusVisuals(bool isFocused) - { - try - { - if (_nud == null || - _nud.IsDisposed) - { - return; - } - - // 綜合判斷:只要數值框本身有焦點,或是旁邊的加減按鈕有焦點,數值框都應該保持高亮。 - bool shouldHighlight = isFocused || - (_btnPlus != null && _btnPlus.Focused) || - (_btnMinus != null && _btnMinus.Focused); - - if (shouldHighlight) - { - if (SystemInformation.HighContrast) - { - _nud.UpdateRecursive(SystemColors.Highlight, SystemColors.HighlightText); - } - else - { - bool isDark = this.IsDarkModeActive(); - - // 淺色模式:黑底白字、深色模式:白底黑字。 - _nud.UpdateRecursive( - isDark ? Color.White : Color.Black, - isDark ? Color.Black : Color.White); - } - } - else - { - _nud.ResetThemeRecursive(); - } - - // 當具有焦點時,強化游標。 - if (isFocused) - { - UpdateCaretWidth(); - } - } - catch (Exception ex) - { - Debug.WriteLine($"[NumericInputDialog] UpdateFocusVisuals 失敗:{ex.Message}"); - } - } - - /// - /// 根據 DPI 與無障礙設定更新數值框內部游標寬度 - /// - private void UpdateCaretWidth() - { - try - { - if (_nud == null || - _nud.IsDisposed || - !_nud.IsHandleCreated) - { - return; - } - - // 尋找 NUD 內部的 TextBox 子控制項。 - TextBox? innerTextBox = _nud.Controls.OfType().FirstOrDefault(); - - if (innerTextBox == null || - !innerTextBox.IsHandleCreated) - { - return; - } - - // 基礎寬度 3px,隨 DPI 縮放。 - float scale = DeviceDpi / AppSettings.BaseDpi; - - int caretWidth = (int)Math.Max(3, 3 * scale); - - // 高對比模式下額外加粗。 - if (SystemInformation.HighContrast) - { - caretWidth += (int)(2 * scale); - } - - int caretHeight = innerTextBox.Height; - - // 若寬高與上次一致,則略過 Win32 API 調用,減少 UI 閃爍感。 - if (caretWidth == _lastCaretWidth && - caretHeight == _lastCaretHeight) - { - return; - } - - _lastCaretWidth = caretWidth; - _lastCaretHeight = caretHeight; - - // 使用 Win32 API 重新建立游標。 - if (User32.CreateCaret(innerTextBox.Handle, IntPtr.Zero, caretWidth, caretHeight)) - { - User32.ShowCaret(innerTextBox.Handle); - } - } - catch (Exception ex) - { - Debug.WriteLine($"[NumericInputDialog] UpdateCaretWidth 失敗:{ex.Message}"); - } - } - - /// - /// 更新視窗不透明度。 - /// - private void UpdateOpacity() - { - try - { - // 根據規範,若系統開啟高對比模式,則強制為 1.0 以確保絕對可讀性。 - if (SystemInformation.HighContrast) - { - Opacity = 1.0; - - return; - } - - // 數值輸入框鎖定 1.0 不透明度以確保輸入清晰度。 - Opacity = 1.0; - } - catch (Exception ex) - { - Debug.WriteLine($"[NumericInputDialog] UpdateOpacity 失敗:{ex.Message}"); - } - } - - /// - /// 更新視窗最小尺寸與按鈕佈局約束 - /// - private void UpdateMinimumSize() - { - try - { - float currentDpi = DeviceDpi; - - if (!DialogLayoutHelper.TryBeginDpiLayout(currentDpi, ref _lastAppliedDpi)) - { - return; - } - - float scale = currentDpi / AppSettings.BaseDpi; - - // 內容感知:更新所有按鈕的佈局約束(Bold 預測)。 - // 確保按鈕在獲得焦點變為粗體時,物理邊界保持絕對靜止,達成 Zero-Jitter。 - UpdateButtonConstraints(_btnOk, scale); - UpdateButtonConstraints(_btnCancel, scale); - UpdateButtonConstraints(_btnPlus, scale); - UpdateButtonConstraints(_btnMinus, scale); - UpdateButtonConstraints(_btnReset, scale); - - // 改用內容偏好尺寸作為基準。 - _tlpGrid?.PerformLayout(); - - Size contentPref = _tlpGrid?.GetPreferredSize(Size.Empty) ?? - new((int)(450 * scale), (int)(250 * scale)); - - Rectangle workArea = Screen.GetWorkingArea(this); - - // 計算邊框與標題列所需的額外空間(比照 HelpDialog.cs)。 - int frameW = SystemInformation.FrameBorderSize.Width * 2, - frameH = SystemInformation.FrameBorderSize.Height * 2, - captionH = SystemInformation.CaptionHeight; - - (int maxFitW, int maxFitH) = DialogLayoutHelper.GetMaxFitSize(workArea); - - // 視窗寬度:內容寬度 + 表單 Padding + 框架,以工作區上限為準。 - int formW = Math.Clamp( - contentPref.Width + Padding.Horizontal + frameW + 8, - (int)(450 * scale), - maxFitW); - - // 視窗高度:依實際內容偏好尺寸計算,上限為工作區可用高度(保留 40px 邊界)。 - int desiredMinHeight = (int)(300 * scale), - naturalH = contentPref.Height + Padding.Vertical + captionH + frameH + 8, - formH = Math.Clamp(naturalH, desiredMinHeight, Math.Max(desiredMinHeight, maxFitH)); - - MinimumSize = new Size(Math.Min((int)(450 * scale), maxFitW), desiredMinHeight); - - Size = new Size(formW, formH); - - // 佈局擴張後,執行智慧定位檢查。 - ApplySmartPosition(); - - // 高對比模式下強制 100% 不透明度。 - if (SystemInformation.HighContrast) - { - UpdateOpacity(); - } - } - catch (Exception ex) - { - Debug.WriteLine($"[NumericInputDialog] UpdateMinimumSize 失敗:{ex.Message}"); - } - } - - /// - /// 更新單個按鈕的佈局約束與最小尺寸鎖定 - /// - /// 目標按鈕 - /// 目前 DPI 縮放比例 - private void UpdateButtonConstraints(Button? btn, float scale) - { - try - { - if (btn == null || - btn.IsDisposed) - { - return; - } - - // 取得專屬於此視窗 DPI 的 Bold 字體實例。 - Font boldFont = MainForm.GetSharedA11yFont(DeviceDpi, FontStyle.Bold, btn.Font.FontFamily); - - // 眼動儀友善:抗抖動寬度鎖定(Anti-Jitter Lock)。 - DialogLayoutHelper.UpdateButtonMinimumSize(btn, boldFont, scale, 120, 60, 32, 24); - } - catch (Exception ex) - { - Debug.WriteLine($"[NumericInputDialog] UpdateButtonConstraints 失敗:{ex.Message}"); - } - } - - /// - /// 執行智慧定位修正,確保視窗不會跑出螢幕邊界 - /// - private void ApplySmartPosition() - { - // 脫離目前的佈局計算循環,確保所有 StartPosition 與 AutoSize 已處理完畢。 - this.SafeBeginInvoke(() => - { - try - { - if (IsDisposed || - !IsHandleCreated) - { - return; - } - - // 強制同步最新的實體佈局尺寸(關鍵:確保 Width/Height 是縮放後的真實值)。 - PerformLayout(); - - if (InputBoxLayoutManager.TryGetClampedLocation(this, out Point clampedLocation)) - { - Location = clampedLocation; - - // 告知使用者視窗已修正位置。 - AnnounceA11y(Strings.A11y_SnapBack); - } - } - catch (Exception ex) - { - Debug.WriteLine($"[NumericInputDialog] ApplySmartPosition 失敗:{ex.Message}"); - } - }); - } - /// /// 初始化對話框組件 /// @@ -2320,4 +1031,4 @@ void StopRepeat() btn.Disposed += (s, e) => StopRepeat(); } -} \ No newline at end of file +} diff --git a/src/InputBox/Core/Controls/PhraseEditDialog.A11y.cs b/src/InputBox/Core/Controls/PhraseEditDialog.A11y.cs new file mode 100644 index 0000000..332c73e --- /dev/null +++ b/src/InputBox/Core/Controls/PhraseEditDialog.A11y.cs @@ -0,0 +1,305 @@ +using InputBox.Core.Configuration; +using InputBox.Core.Extensions; +using InputBox.Core.Feedback; +using InputBox.Core.Services; +using System.Diagnostics; +using System.Media; + +namespace InputBox.Core.Controls; + +// 阻擋設計工具。 +partial class DesignerBlocker { }; + +/// +/// 片語編輯對話框(無障礙與驗證回饋分部)。 +/// 本分部檔案包含 A11y 廣播、驗證失敗閃爍,以及字數上限回饋等成員。 +/// +internal sealed partial class PhraseEditDialog +{ + /// + /// 針對驗證失敗的輸入框提供焦點、音效、震動與視覺提示 + /// + /// 驗證失敗的輸入框。 + /// 要播報的錯誤訊息。 + private void NotifyValidationFailure(TextBox target, string message) + { + if (target.CanFocus && !target.Focused) + { + target.Focus(); + } + + AnnounceA11y(message, interrupt: true); + + FeedbackService.PlaySound(SystemSounds.Hand); + + FeedbackService.VibrateAsync( + _gamepadController, + VibrationPatterns.ActionFail, + _cts?.Token ?? CancellationToken.None) + .SafeFireAndForget(); + + FlashValidationCueAsync(target).SafeFireAndForget(); + } + + /// + /// 暫時閃爍輸入框以提供驗證失敗的視覺提示 + /// + /// 要閃爍提示的輸入框。 + /// 非同步作業。 + private async Task FlashValidationCueAsync(TextBox target) + { + if (target.IsDisposed || + !IsHandleCreated || + Interlocked.CompareExchange(ref _isFlashing, 1, 0) != 0) + { + return; + } + + // 僅在對話框生命週期仍有效時建立警示權杖,避免關閉途中留下失去連結的動畫。 + CancellationTokenSource? newAlertCts = _cts.TryCreateLinkedTokenSource(); + + if (newAlertCts == null) + { + Interlocked.Exchange(ref _isFlashing, 0); + + return; + } + + Interlocked.Exchange(ref _alertCts, newAlertCts)?.CancelAndDispose(); + + CancellationToken token = newAlertCts.Token; + + try + { + bool isDark = target.IsDarkModeActive(); + Color alertColor = FlashAlertAnimator.GetAlertColor(isDark, SystemInformation.HighContrast); + + void ApplyAlertVisuals(float intensity) + { + if (target.IsDisposed || + !IsHandleCreated) + { + return; + } + + (Color back, Color fore) = FlashAlertAnimator.ComputeFrameColors( + intensity, + isDark, + alertColor, + SystemInformation.HighContrast); + + target.BackColor = back; + target.ForeColor = fore; + } + + await FlashAlertAnimator.RunAsync(this, ApplyAlertVisuals, token); + } + catch (OperationCanceledException) + { + // 正常取消。 + } + catch (Exception ex) + { + Debug.WriteLine($"[片語編輯] FlashValidationCueAsync 失敗:{ex.Message}"); + } + finally + { + Interlocked.Exchange(ref _isFlashing, 0); + Interlocked.Exchange(ref _alertCts, null)?.CancelAndDispose(); + + // 確保 UI 狀態還原。 + this.SafeInvoke(() => + { + try + { + if (target.IsDisposed || + !IsHandleCreated) + { + return; + } + + if (target.Focused) + { + ApplyInputBoxStrongVisual(target); + } + else + { + ResetInputBoxVisual(target); + } + } + catch (Exception ex) + { + Debug.WriteLine($"[片語編輯] 驗證提示動畫 UI 還原失敗:{ex.Message}"); + } + }); + } + } + + /// + /// 依剩餘字元數分級,僅在接近上限時回傳有效 bucket。 + /// + /// 距離上限的剩餘字元數。 + /// 警示等級(0 ~ 3);超過警示閾值時回傳 -1。 + private static int GetTextLimitWarningBucket(int remainingCharacters) + { + return remainingCharacters switch + { + <= 0 => 3, + <= 2 => 2, + <= 5 => 1, + <= TextLimitWarningThreshold => 0, + _ => -1 + }; + } + + /// + /// 當片語欄位長度變動時,提供接近字數上限的物理預警與硬牆回饋。 + /// + /// 監控中的輸入框。 + /// 欄位的最大字元數限制。 + /// 上次觀察到的長度(ref,會被更新)。 + /// 上次警示的 bucket 等級(ref,會被更新)。 + private void HandleTextLimitFeedbackFromLengthChange( + TextBox textBox, + int maxLength, + ref int lastObservedLength, + ref int lastWarningBucket) + { + if (textBox.IsDisposed) + { + return; + } + + int currentLength = textBox.TextLength; + + if (currentLength < lastObservedLength) + { + lastObservedLength = currentLength; + lastWarningBucket = currentLength >= maxLength - TextLimitWarningThreshold ? + GetTextLimitWarningBucket(maxLength - currentLength) : + -1; + return; + } + + int remainingCharacters = maxLength - currentLength; + + if (remainingCharacters > TextLimitWarningThreshold) + { + lastObservedLength = currentLength; + lastWarningBucket = -1; + return; + } + + int currentBucket = GetTextLimitWarningBucket(remainingCharacters); + + if (currentLength > lastObservedLength && + (currentBucket != lastWarningBucket || remainingCharacters <= 2)) + { + if (remainingCharacters <= 0) + { + FeedbackService.PlaySound(SystemSounds.Beep); + } + + FeedbackService.VibrateSequenceAsync( + _gamepadController, + VibrationPatterns.GetTextLimitSequence( + remainingCharacters, + _gamepadController?.VibrationMotorSupport ?? VibrationMotorSupport.None), + _cts?.Token ?? CancellationToken.None) + .SafeFireAndForget(); + } + + lastObservedLength = currentLength; + lastWarningBucket = currentBucket; + } + + /// + /// 使用者在字數已滿時仍嘗試輸入一般字元,播放硬牆回饋。 + /// + /// 目標輸入框。 + /// 欄位的最大字元數限制。 + /// 上次觸發硬牆回饋的 UTC 時間戳(ref,用於節流)。 + /// 按鍵事件引數。 + private void HandleTextLimitKeyPress(TextBox textBox, int maxLength, ref DateTime lastWallUtc, KeyPressEventArgs e) + { + if (textBox.IsDisposed || + char.IsControl(e.KeyChar) || + textBox.TextLength < maxLength) + { + return; + } + + if ((DateTime.UtcNow - lastWallUtc).TotalMilliseconds < RepeatedBoundaryFeedbackThrottleMs) + { + return; + } + + lastWallUtc = DateTime.UtcNow; + FeedbackService.PlaySound(SystemSounds.Beep); + FeedbackService.VibrateSequenceAsync( + _gamepadController, + VibrationPatterns.GetTextLimitSequence( + 0, + _gamepadController?.VibrationMotorSupport ?? VibrationMotorSupport.None), + _cts?.Token ?? CancellationToken.None) + .SafeFireAndForget(); + } + + /// + /// 廣播無障礙訊息 + /// + /// 要廣播的訊息 + /// 是否中斷目前的廣播 + private void AnnounceA11y(string message, bool interrupt = false) + { + if (IsDisposed || + string.IsNullOrEmpty(message)) + { + return; + } + + if (Owner is MainForm mainForm) + { + mainForm.AnnounceA11y(message, interrupt); + } + else if (Owner is PhraseManagerDialog phraseManager) + { + // 嘗試寫往主視窗。 + if (phraseManager.Owner is MainForm main) + { + main.AnnounceA11y(message, interrupt); + + return; + } + } + + // 本地備援 + long currentId = Interlocked.Increment(ref _a11yDebounceId); + + Task.Run(async () => + { + try + { + await Task.Delay(AppSettings.AudioDuckingDelayMs, _cts?.Token ?? CancellationToken.None); + + if (Interlocked.Read(ref _a11yDebounceId) == currentId && + !IsDisposed && + IsHandleCreated) + { + await this.SafeInvokeAsync(() => + _announcer.Announce(message, interrupt && AppSettings.Current.A11yInterruptEnabled)); + } + } + catch (OperationCanceledException) + { + + } + catch (Exception ex) + { + Debug.WriteLine($"[片語編輯] A11y 廣播失敗:{ex.Message}"); + } + }, + _cts?.Token ?? CancellationToken.None) + .SafeFireAndForget(); + } +} diff --git a/src/InputBox/Core/Controls/PhraseEditDialog.Gamepad.cs b/src/InputBox/Core/Controls/PhraseEditDialog.Gamepad.cs new file mode 100644 index 0000000..1fab53c --- /dev/null +++ b/src/InputBox/Core/Controls/PhraseEditDialog.Gamepad.cs @@ -0,0 +1,715 @@ +using InputBox.Core.Extensions; +using InputBox.Core.Feedback; +using InputBox.Core.Input; +using InputBox.Core.Interop; +using InputBox.Core.Services; +using InputBox.Core.Utilities; +using InputBox.Resources; +using System.ComponentModel; +using System.Diagnostics; +using System.Media; + +namespace InputBox.Core.Controls; + +// 阻擋設計工具。 +partial class DesignerBlocker { }; + +/// +/// 片語編輯對話框(遊戲控制器與輸入分部)。 +/// 本分部檔案包含遊戲控制器事件、欄位切換、游標移動、延伸選取、右鍵選單,以及觸控式鍵盤等輸入處理成員。 +/// +internal sealed partial class PhraseEditDialog +{ + /// + /// 遊戲控制器 + /// + [Browsable(false)] + [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public IGamepadController? GamepadController + { + get => _gamepadController; + set + { + if (ReferenceEquals(_gamepadController, value)) + { + return; + } + + UnsubscribeGamepadEvents(); + + _gamepadController = value; + + if (_gamepadController != null) + { + GamepadFaceButtonProfile profile = GamepadFaceButtonProfile.GetActiveProfile(); + + _gamepadController.APressed += profile.ConfirmOnSouth ? HandleGamepadA : HandleBackOrClear; + _gamepadController.StartPressed += HandleOpenTouchKeyboardFromGamepad; + _gamepadController.BPressed += profile.ConfirmOnSouth ? HandleBackOrClear : HandleGamepadA; + _gamepadController.BackPressed += HandleCancel; + _gamepadController.LeftPressed += HandleLeft; + _gamepadController.LeftRepeat += HandleLeft; + _gamepadController.RightPressed += HandleRight; + _gamepadController.RightRepeat += HandleRight; + _gamepadController.UpPressed += HandleFieldPrev; + _gamepadController.DownPressed += HandleFieldNext; + _gamepadController.XPressed += HandleBackspace; + _gamepadController.YPressed += HandleOpenContextMenu; + _gamepadController.RSLeftPressed += HandleRSLeft; + _gamepadController.RSLeftRepeat += HandleRSLeft; + _gamepadController.RSRightPressed += HandleRSRight; + _gamepadController.RSRightRepeat += HandleRSRight; + _gamepadController.ConnectionChanged += HandleConnectionChanged; + } + } + } + + /// + /// A 鍵:按鈕 → PerformClick;輸入框為空時開啟觸控鍵盤;其餘情境走確認驗證 + /// + private void HandleGamepadA() => this.SafeInvoke(() => + { + try + { + if (ActiveControl is Button btn) + { + btn.PerformClick(); + return; + } + + TextBox? tb = GetActiveTextBox() ?? _txtName; + + if (tb != null && string.IsNullOrWhiteSpace(tb.Text)) + { + ShowTouchKeyboard(tb); + + return; + } + + HandleConfirm(); + } + catch (Exception ex) + { + Debug.WriteLine($"[片語編輯] 控制器 A 鍵失敗:{ex.Message}"); + } + }); + + /// + /// Start 鍵:在輸入框焦點時直接開啟觸控式鍵盤(可在已有內容時修改) + /// + private void HandleOpenTouchKeyboardFromGamepad() => this.SafeInvoke(() => + { + try + { + TextBox? tb = GetActiveTextBox() ?? _txtName; + + ShowTouchKeyboard(tb); + } + catch (Exception ex) + { + Debug.WriteLine($"[片語編輯] 控制器開啟觸控鍵盤失敗:{ex.Message}"); + } + }); + + /// + /// B 鍵:若焦點在輸入框且有內容則優先清空;否則執行取消 + /// + private void HandleBackOrClear() => this.SafeInvoke(() => + { + try + { + TextBox? tb = GetActiveTextBox(); + + if (tb != null) + { + if (tb.SelectionLength > 0) + { + tb.SelectedText = string.Empty; + + _rsSelectionAnchor = null; + + AnnounceA11y(Strings.Msg_InputCleared, interrupt: true); + + FeedbackService.VibrateAsync( + _gamepadController, + VibrationPatterns.ClearInput, + _cts?.Token ?? CancellationToken.None) + .SafeFireAndForget(); + + return; + } + + if (!string.IsNullOrEmpty(tb.Text)) + { + tb.Clear(); + + _rsSelectionAnchor = null; + + AnnounceA11y(Strings.Msg_InputCleared, interrupt: true); + + FeedbackService.VibrateAsync( + _gamepadController, + VibrationPatterns.ClearInput, + _cts?.Token ?? CancellationToken.None) + .SafeFireAndForget(); + + return; + } + } + + HandleCancel(); + } + catch (Exception ex) + { + Debug.WriteLine($"[片語編輯] HandleBackOrClear 失敗:{ex.Message}"); + } + }); + + /// + /// 聚焦指定輸入框並非同步開啟觸控式鍵盤。 + /// + /// 要聚焦的輸入框。 + private void ShowTouchKeyboard(TextBox tb) + { + if (tb.CanFocus && !tb.Focused) + { + tb.Focus(); + } + + AnnounceA11y(Strings.A11y_Opening_Keyboard, interrupt: true); + + Task.Run(async () => + { + try + { + await Task.Delay(150, _cts?.Token ?? CancellationToken.None); + + if (TouchKeyboardService.IsVisible()) return; + + await this.SafeInvokeAsync(() => + { + try + { + bool opened = TouchKeyboardService.TryOpen(); + + if (opened) + { + FeedbackService.PlaySound(SystemSounds.Asterisk); + } + } + catch (Exception ex) + { + Debug.WriteLine($"[片語編輯] 觸控鍵盤開啟失敗:{ex.Message}"); + } + }); + } + catch (OperationCanceledException) + { + + } + catch (Exception ex) + { + Debug.WriteLine($"[片語編輯] 開啟觸控鍵盤失敗:{ex.Message}"); + } + }, + _cts?.Token ?? CancellationToken.None).SafeFireAndForget(); + } + + /// + /// 取得目前焦點所在的 TextBox(名稱或內容)。 + /// + /// 具有焦點的輸入框;兩者皆無焦點時回傳 null。 + private TextBox? GetActiveTextBox() + { + if (_txtName.Focused) + { + return _txtName; + } + + if (_txtContent.Focused) + { + return _txtContent; + } + + return null; + } + + /// + /// 游標左移(比照 MainForm.Gamepad.cs 的 MoveCursorLeft) + /// + private void HandleLeft() => this.SafeInvoke(() => + { + try + { + TextBox? tb = GetActiveTextBox(); + + if (tb == null) + { + // 焦點在按鈕區:D-Pad 左向在確認/取消按鈕間循環。 + if (_btnOk.Focused) + { + _btnCancel.Focus(); + AnnounceA11y(_btnCancel.AccessibleName ?? _btnCancel.Text, interrupt: true); + FeedbackService.VibrateAsync(_gamepadController, VibrationPatterns.CursorMove, _cts?.Token ?? CancellationToken.None).SafeFireAndForget(); + } + else if (_btnCancel.Focused) + { + _btnOk.Focus(); + AnnounceA11y(_btnOk.AccessibleName ?? _btnOk.Text, interrupt: true); + FeedbackService.VibrateAsync(_gamepadController, VibrationPatterns.CursorMove, _cts?.Token ?? CancellationToken.None).SafeFireAndForget(); + } + + return; + } + + bool hasSelection = tb.SelectionLength > 0; + + if (hasSelection || + tb.SelectionStart > 0) + { + if (hasSelection) + { + tb.SelectionLength = 0; + } + else if (_gamepadController?.IsLeftShoulderHeld == true) + { + tb.WordJump(false); + } + else + { + tb.SelectionStart--; + } + + tb.ScrollToCaret(); + + FeedbackService.VibrateAsync( + _gamepadController, + VibrationPatterns.CursorMove, + _cts?.Token ?? CancellationToken.None) + .SafeFireAndForget(); + } + else + { + FeedbackService.PlaySound(SystemSounds.Beep); + + FeedbackService.VibrateAsync( + _gamepadController, + VibrationPatterns.CursorMove, + _cts?.Token ?? CancellationToken.None) + .SafeFireAndForget(); + } + } + catch (Exception ex) + { + Debug.WriteLine($"[片語編輯] 左移失敗:{ex.Message}"); + } + }); + + /// + /// 游標右移(比照 MainForm.Gamepad.cs 的 MoveCursorRight) + /// + private void HandleRight() => this.SafeInvoke(() => + { + try + { + TextBox? tb = GetActiveTextBox(); + + if (tb == null) + { + // 焦點在按鈕區:D-Pad 右向在取消/確認按鈕間循環。 + if (_btnCancel.Focused) + { + _btnOk.Focus(); + AnnounceA11y(_btnOk.AccessibleName ?? _btnOk.Text, interrupt: true); + FeedbackService.VibrateAsync(_gamepadController, VibrationPatterns.CursorMove, _cts?.Token ?? CancellationToken.None).SafeFireAndForget(); + } + else if (_btnOk.Focused) + { + _btnCancel.Focus(); + AnnounceA11y(_btnCancel.AccessibleName ?? _btnCancel.Text, interrupt: true); + FeedbackService.VibrateAsync(_gamepadController, VibrationPatterns.CursorMove, _cts?.Token ?? CancellationToken.None).SafeFireAndForget(); + } + + return; + } + + bool hasSelection = tb.SelectionLength > 0; + + if (hasSelection || tb.SelectionStart < tb.Text.Length) + { + if (hasSelection) + { + tb.SelectionStart += tb.SelectionLength; + tb.SelectionLength = 0; + } + else if (_gamepadController?.IsLeftShoulderHeld == true) + { + tb.WordJump(true); + } + else + { + tb.SelectionStart++; + } + + tb.ScrollToCaret(); + + FeedbackService.VibrateAsync( + _gamepadController, + VibrationPatterns.CursorMove, + _cts?.Token ?? CancellationToken.None) + .SafeFireAndForget(); + } + else + { + FeedbackService.PlaySound(SystemSounds.Beep); + + FeedbackService.VibrateAsync( + _gamepadController, + VibrationPatterns.CursorMove, + _cts?.Token ?? CancellationToken.None) + .SafeFireAndForget(); + } + } + catch (Exception ex) + { + Debug.WriteLine($"[片語編輯] 右移失敗:{ex.Message}"); + } + }); + + /// + /// 上方向鍵:在名稱欄位與內容欄位和按鈕之間切換焦點 + /// + private void HandleFieldPrev() => this.SafeInvoke(() => + { + try + { + if (_txtContent.Focused) + { + _txtName.Focus(); + } + else if (_btnOk.Focused) + { + _txtContent.Focus(); + } + else if (_btnCancel.Focused) + { + _btnOk.Focus(); + } + else if (_txtName.Focused) + { + _btnCancel.Focus(); + } + + FeedbackService.VibrateAsync( + _gamepadController, + VibrationPatterns.CursorMove, + _cts?.Token ?? CancellationToken.None) + .SafeFireAndForget(); + } + catch (Exception ex) + { + Debug.WriteLine($"[片語編輯] 欄位向前失敗:{ex.Message}"); + } + }); + + /// + /// 下方向鍵:在名稱欄位、內容欄位與按鈕之間循環焦點 + /// + private void HandleFieldNext() => this.SafeInvoke(() => + { + try + { + if (_txtName.Focused) + { + _txtContent.Focus(); + } + else if (_txtContent.Focused) + { + _btnOk.Focus(); + } + else if (_btnOk.Focused) + { + _btnCancel.Focus(); + } + else if (_btnCancel.Focused) + { + _txtName.Focus(); + } + + FeedbackService.VibrateAsync( + _gamepadController, + VibrationPatterns.CursorMove, + _cts?.Token ?? CancellationToken.None) + .SafeFireAndForget(); + } + catch (Exception ex) + { + Debug.WriteLine($"[片語編輯] 欄位向後失敗:{ex.Message}"); + } + }); + + /// + /// X 鍵:刪除選取文字或游標前一字元(比照 MainForm.Gamepad.cs 的 X 鍵刪除邏輯) + /// + private void HandleBackspace() => this.SafeInvoke(() => + { + try + { + TextBox? tb = GetActiveTextBox(); + + if (tb == null || + tb.ReadOnly) + { + return; + } + + if (tb.SelectionLength > 0) + { + tb.SelectedText = string.Empty; + } + else if (tb.SelectionStart > 0) + { + int pos = tb.SelectionStart; + + tb.Select(pos - 1, 1); + tb.SelectedText = string.Empty; + } + else + { + FeedbackService.PlaySound(SystemSounds.Beep); + + FeedbackService.VibrateAsync( + _gamepadController, + VibrationPatterns.CursorMove, + _cts?.Token ?? CancellationToken.None) + .SafeFireAndForget(); + } + } + catch (Exception ex) + { + Debug.WriteLine($"[片語編輯] 退格失敗:{ex.Message}"); + } + }); + + /// + /// 右搖桿左推:擴張選取範圍向左(比照 MainForm.Gamepad.cs 的 ExpandSelection) + /// + private void HandleRSLeft() => this.SafeInvoke(() => + { + try + { + ExpandSelection(-1); + } + catch (Exception ex) + { + Debug.WriteLine($"[片語編輯] 右摘桿左移失敗:{ex.Message}"); + } + }); + + /// + /// 右搖桿右推:擴張選取範圍向右 + /// + private void HandleRSRight() => this.SafeInvoke(() => + { + try + { + ExpandSelection(1); + } + catch (Exception ex) + { + Debug.WriteLine($"[片語編輯] 右摘桿右移失敗:{ex.Message}"); + } + }); + + /// + /// Y 鍵:開啟焦點 TextBox 的原生右鍵選單 + /// + private void HandleOpenContextMenu() => this.SafeInvoke(() => + { + try + { + if (GamescopeSurfaceRecovery.TryRecoverFromGamepadChord( + this, + RecreateHandle, + _gamepadController, + beforeRecover: CloseActiveTextBoxContextMenu, + context: "PhraseEditDialog Gamescope surface recovery 失敗")) + { + return; + } + + TextBox? tb = GetActiveTextBox(); + + if (tb == null) + { + return; + } + + // 在游標位置附近顯示內建右鍵選單。 + Point caretPos = tb.GetPositionFromCharIndex(tb.SelectionStart); + + tb.ContextMenuStrip?.Show(tb, caretPos); + + // TextBox 沒有 ContextMenuStrip 時,透過模擬 Shift+F10 觸發原生選單。 + if (tb.ContextMenuStrip == null) + { + User32.SendMessage(tb.Handle, 0x007B, tb.Handle, unchecked((nint)0xFFFFFFFF)); + } + } + catch (Exception ex) + { + Debug.WriteLine($"[片語編輯] 開啟右鍵選單失敗:{ex.Message}"); + } + }); + + /// + /// 在重建 PhraseEditDialog surface 前關閉目前 TextBox 的右鍵選單。 + /// + private void CloseActiveTextBoxContextMenu() + { + GetActiveTextBox()?.ContextMenuStrip?.Close(); + } + + /// + /// 擴張或縮減文字選取範圍(比照 MainForm.Gamepad.cs 的 ExpandSelection) + /// + /// 方向,正數表示向右擴張,負數表示向左擴張。 + private void ExpandSelection(int direction) + { + TextBox? tb = GetActiveTextBox(); + + if (tb == null) + { + return; + } + + (int anchor, int caret) = tb.ResolveSelectionAnchor(_rsSelectionAnchor); + + _rsSelectionAnchor = anchor; + + int safeDirection = Math.Sign(direction); + bool wordGranularity = _gamepadController?.IsLeftShoulderHeld == true || + _gamepadController?.IsRightShoulderHeld == true; + + int newCaret = wordGranularity ? + tb.GetWordJumpTarget(caret, safeDirection > 0) : + Math.Clamp(caret + safeDirection, 0, tb.TextLength); + + if (newCaret == caret) + { + FeedbackService.VibrateAsync( + _gamepadController, + VibrationPatterns.ActionFail, + _cts?.Token ?? CancellationToken.None) + .SafeFireAndForget(); + + return; + } + + // 使用 Win32 EM_SETSEL 正確設定選取範圍(含反向選取)。 + tb.SetSelectionWithActiveEdge(anchor, newCaret); + + PlaySelectionFeedback(safeDirection, wordGranularity); + } + + /// + /// 推進某類觸覺回饋的 burst 等級,用於快速連發時做輕量阻尼。 + /// + /// 上次觸發的 UTC 時間戳(ref,會被更新)。 + /// 目前 burst 等級(ref,會被累加或重設)。 + /// 視為快速連發的時間視窗(毫秒)。 + /// 更新後的 burst 等級(0 ~ 3)。 + private static int AdvanceFeedbackBurst(ref DateTime lastUtc, ref int burstLevel, int fastWindowMs) + { + DateTime now = DateTime.UtcNow; + burstLevel = (now - lastUtc).TotalMilliseconds <= fastWindowMs ? + Math.Min(burstLevel + 1, 3) : + 0; + lastUtc = now; + + return burstLevel; + } + + /// + /// 根據選取粒度與速度播放不同的右搖桿文字選取回饋。 + /// + /// 選取方向;負值為向左,正值為向右。 + /// 是否為單字粒度選取。 + private void PlaySelectionFeedback(int direction, bool wordGranularity) + { + IGamepadController? controller = _gamepadController; + + if (controller == null || + !controller.IsConnected) + { + return; + } + + int burstLevel = wordGranularity ? + 0 : + AdvanceFeedbackBurst(ref _lastSelectionFeedbackUtc, ref _selectionFeedbackBurstLevel, SelectionBurstWindowMs); + + FeedbackService.VibrateSequenceAsync( + controller, + VibrationPatterns.GetSelectionSequence(direction, wordGranularity, burstLevel, controller.VibrationMotorSupport), + _cts?.Token ?? CancellationToken.None) + .SafeFireAndForget(); + + FeedbackService.PlaySelectionCue(wordGranularity, burstLevel); + } + + /// + /// 控制器重新連線後恢復輪詢狀態。 + /// + /// 新的控制器連線狀態。 + private void HandleConnectionChanged(bool connected) + { + try + { + if (connected) + { + _gamepadController?.Resume(); + } + } + catch (Exception ex) + { + Debug.WriteLine($"[片語編輯] 控制器連線變更:{ex.Message}"); + } + } + + /// + /// 解除目前片語編輯對話框所綁定的控制器事件 + /// + private void UnsubscribeGamepadEvents() + { + try + { + if (_gamepadController != null) + { + _gamepadController.APressed -= HandleGamepadA; + _gamepadController.APressed -= HandleBackOrClear; + _gamepadController.StartPressed -= HandleOpenTouchKeyboardFromGamepad; + _gamepadController.BPressed -= HandleGamepadA; + _gamepadController.BPressed -= HandleBackOrClear; + _gamepadController.BackPressed -= HandleCancel; + _gamepadController.LeftPressed -= HandleLeft; + _gamepadController.LeftRepeat -= HandleLeft; + _gamepadController.RightPressed -= HandleRight; + _gamepadController.RightRepeat -= HandleRight; + _gamepadController.UpPressed -= HandleFieldPrev; + _gamepadController.DownPressed -= HandleFieldNext; + _gamepadController.XPressed -= HandleBackspace; + _gamepadController.YPressed -= HandleOpenContextMenu; + _gamepadController.RSLeftPressed -= HandleRSLeft; + _gamepadController.RSLeftRepeat -= HandleRSLeft; + _gamepadController.RSRightPressed -= HandleRSRight; + _gamepadController.RSRightRepeat -= HandleRSRight; + _gamepadController.ConnectionChanged -= HandleConnectionChanged; + } + } + catch (Exception ex) + { + Debug.WriteLine($"[片語編輯] UnsubscribeGamepadEvents 失敗:{ex.Message}"); + } + } +} diff --git a/src/InputBox/Core/Controls/PhraseEditDialog.Layout.cs b/src/InputBox/Core/Controls/PhraseEditDialog.Layout.cs new file mode 100644 index 0000000..09fe8ef --- /dev/null +++ b/src/InputBox/Core/Controls/PhraseEditDialog.Layout.cs @@ -0,0 +1,435 @@ +using InputBox.Core.Configuration; +using InputBox.Core.Extensions; +using InputBox.Core.Utilities; +using InputBox.Resources; +using Microsoft.Win32; +using System.Diagnostics; +using System.Runtime.CompilerServices; + +namespace InputBox.Core.Controls; + +// 阻擋設計工具。 +partial class DesignerBlocker { }; + +/// +/// 片語編輯對話框(版面配置與視覺分部)。 +/// 本分部檔案包含 DPI 與系統偏好變更處理、字數標籤、最小尺寸、智慧定位,以及輸入框焦點視覺等成員。 +/// +internal sealed partial class PhraseEditDialog +{ + /// + /// 建立控制項 Handle 後套用最小尺寸、系統事件訂閱與初始定位。 + /// + /// 控制項事件參數。 + protected override void OnHandleCreated(EventArgs e) + { + base.OnHandleCreated(e); + + UpdateMinimumSize(); + + SystemEvents.UserPreferenceChanged -= SystemEvents_UserPreferenceChanged; + SystemEvents.UserPreferenceChanged += SystemEvents_UserPreferenceChanged; + + this.SafeBeginInvoke(ApplySmartPosition); + } + + /// + /// DPI 變更時重新量測按鈕尺寸與對話框最小尺寸。 + /// + /// DPI 變更事件參數。 + protected override void OnDpiChanged(DpiChangedEventArgs e) + { + try + { + base.OnDpiChanged(e); + + this.SafeInvoke(() => + { + try + { + // DPI 變更後刷新字型快取引用(共享快取依 DPI 分開儲存,必須重新取得)。 + _a11yFont = MainForm.GetSharedA11yFont(DeviceDpi, FontStyle.Regular); + _boldFont = MainForm.GetSharedA11yFont(DeviceDpi, FontStyle.Bold); + Font = _a11yFont; + + // 輸入框使用 2.0× 倍率字型(已明確設定,不繼承 Form.Font,需手動更新)。 + Font sharedInputFont = MainForm.GetSharedA11yFont( + DeviceDpi, + FontStyle.Regular, + _a11yFont?.FontFamily, + 2.0f); + _txtName.Font = sharedInputFont; + _txtContent.Font = sharedInputFont; + + // 重新掛載眼動儀回饋,刷新 ButtonVisualState 中儲存的字型引用。 + _btnOk.AttachEyeTrackerFeedback( + baseDescription: Strings.Phrase_A11y_Btn_Confirm_Desc, + regularFont: _a11yFont, + boldFont: _boldFont, + formCt: _cts?.Token ?? CancellationToken.None); + + _btnCancel.AttachEyeTrackerFeedback( + baseDescription: Strings.Phrase_A11y_Btn_Cancel_Desc, + regularFont: _a11yFont, + boldFont: _boldFont, + formCt: _cts?.Token ?? CancellationToken.None); + + UpdateButtonMinimumSizes(); + UpdateMinimumSize(); + ApplySmartPosition(); + _btnOk.Invalidate(); + _btnCancel.Invalidate(); + } + catch (Exception ex) + { + Debug.WriteLine($"[片語編輯] OnDpiChanged 延遲邏輯失敗:{ex.Message}"); + } + }); + } + catch (Exception ex) + { + Debug.WriteLine($"[片語編輯] OnDpiChanged 失敗:{ex.Message}"); + } + } + + /// + /// 使用者結束調整視窗大小後重新套用智慧定位。 + /// + /// 事件參數。 + protected override void OnResizeEnd(EventArgs e) + { + base.OnResizeEnd(e); + + ApplySmartPosition(); + } + + /// + /// Handle 銷毀時確保解除靜態系統事件訂閱 + /// + /// 控制項事件參數。 + protected override void OnHandleDestroyed(EventArgs e) + { + try + { + SystemEvents.UserPreferenceChanged -= SystemEvents_UserPreferenceChanged; + } + finally + { + base.OnHandleDestroyed(e); + } + } + + /// + /// 系統偏好設定變更時同步更新按鈕尺寸、最小尺寸與焦點視覺 + /// + /// 事件來源。 + /// 系統偏好設定事件參數。 + private void SystemEvents_UserPreferenceChanged(object? sender, UserPreferenceChangedEventArgs e) + { + try + { + if (e.Category is UserPreferenceCategory.Accessibility or + UserPreferenceCategory.Color or + UserPreferenceCategory.General) + { + this.SafeInvoke(() => + { + UpdateButtonMinimumSizes(); + UpdateMinimumSize(forceRecalculate: true); + ApplySmartPosition(); + + _btnOk.Invalidate(); + _btnCancel.Invalidate(); + + UpdateNameCharCount(); + UpdateContentCharCount(); + + TextBox? active = GetActiveTextBox(); + + if (active != null) + { + ApplyInputBoxStrongVisual(active); + } + }); + } + } + catch (Exception ex) + { + Debug.WriteLine($"[片語編輯] SystemEvents_UserPreferenceChanged 失敗:{ex.Message}"); + } + } + + /// + /// 輸入框取得焦點時套用強化焦點視覺。 + /// + /// 觸發事件的輸入框。 + /// 事件參數。 + private void HandleTextBoxEnter(object? sender, EventArgs eventArgs) + { + try + { + if (sender is TextBox textBox) + { + ApplyInputBoxStrongVisual(textBox); + } + } + catch (Exception ex) + { + Debug.WriteLine($"[片語編輯] HandleTextBoxEnter 失敗:{ex.Message}"); + } + } + + /// + /// 輸入框失去焦點時還原一般視覺樣式。 + /// + /// 觸發事件的輸入框。 + /// 事件參數。 + private void HandleTextBoxLeave(object? sender, EventArgs eventArgs) + { + try + { + if (sender is TextBox textBox) + { + ResetInputBoxVisual(textBox); + } + } + catch (Exception ex) + { + Debug.WriteLine($"[片語編輯] HandleTextBoxLeave 失敗:{ex.Message}"); + } + } + + /// + /// 套用與主輸入框一致的強視覺焦點樣式(高對比優先,其次主題感知反轉)。 + /// + /// 要套用焦點樣式的輸入框。 + private static void ApplyInputBoxStrongVisual(TextBox textBox) + { + if (textBox.IsDisposed) + { + return; + } + + if (SystemInformation.HighContrast) + { + textBox.BackColor = SystemColors.Highlight; + textBox.ForeColor = SystemColors.HighlightText; + + return; + } + + if (textBox.IsDarkModeActive()) + { + // 深色模式:反轉為白底黑字。 + textBox.BackColor = Color.White; + textBox.ForeColor = Color.Black; + } + else + { + // 淺色模式:反轉為黑底白字。 + textBox.BackColor = Color.Black; + textBox.ForeColor = Color.White; + } + } + + /// + /// 還原輸入框為系統預設背景與前景色 + /// + /// 目標輸入框。 + private static void ResetInputBoxVisual(TextBox tb) + { + if (tb.IsDisposed) + { + return; + } + + tb.BackColor = Color.Empty; + tb.ForeColor = Color.Empty; + } + + /// + /// 更新片語名稱字元數提示標籤({current}/{max}),近上限時顯示橙色。 + /// + private void UpdateNameCharCount() + { + if (_lblNameCount == null || _lblNameCount.IsDisposed) + { + return; + } + + int len = _txtName.TextLength; + int max = AppSettings.MaxPhraseNameLength; + string countLabel = GetPhraseTextOrFallback("Phrase_Edit_Name_Count", "Name length: "); + string countText = $"{countLabel}{len}/{max}"; + + _lblNameCount.Text = countText; + _lblNameCount.AccessibleName = countText; + _lblNameCount.AccessibleDescription = $"{Strings.Phrase_A11y_Edit_Name_Desc} {countText}"; + + if (SystemInformation.HighContrast) + { + _lblNameCount.ForeColor = Color.Empty; + + return; + } + + _lblNameCount.ForeColor = len >= max - 10 ? + Color.DarkOrange : + Color.Empty; + } + + /// + /// 更新片語內容字元數提示標籤({current}/{max}),近上限時顯示橙色。 + /// + private void UpdateContentCharCount() + { + if (_lblContentCount == null || _lblContentCount.IsDisposed) + { + return; + } + + int len = _txtContent.TextLength; + int max = AppSettings.MaxInputLength; + string countLabel = GetPhraseTextOrFallback("Phrase_Edit_Content_Count", "Content length: "); + string countText = $"{countLabel}{len}/{max}"; + + _lblContentCount.Text = countText; + _lblContentCount.AccessibleName = countText; + _lblContentCount.AccessibleDescription = $"{Strings.Phrase_A11y_Edit_Content_Desc} {countText}"; + + if (SystemInformation.HighContrast) + { + _lblContentCount.ForeColor = Color.Empty; + + return; + } + + _lblContentCount.ForeColor = len >= max - 50 ? + Color.DarkOrange : + Color.Empty; + } + + /// + /// 更新按鈕最小尺寸(抗抖動 + WCAG 2.5.5 AAA 44×44) + /// + private void UpdateButtonMinimumSizes() + { + float scale = DeviceDpi / AppSettings.BaseDpi; + + UpdateSingleButtonMinimumSize(_btnOk, scale); + UpdateSingleButtonMinimumSize(_btnCancel, scale); + } + + /// + /// 預先鎖定動態字數標籤的最小寬度,避免數值變化時造成版面抖動。 + /// + private void UpdateCountLabelMinimumWidths() + { + UpdateSingleCountLabelMinimumWidth( + _lblNameCount, + GetPhraseTextOrFallback("Phrase_Edit_Name_Count", "Name length: "), + AppSettings.MaxPhraseNameLength); + UpdateSingleCountLabelMinimumWidth( + _lblContentCount, + GetPhraseTextOrFallback("Phrase_Edit_Content_Count", "Content length: "), + AppSettings.MaxInputLength); + } + + /// + /// 鎖定單一動態標籤的寬度,讓最長狀態文字也不會改變物理尺寸。 + /// + /// 要鎖定寬度的標籤;為 null 時略過。 + /// 標籤前綴文字,用於計算最寬狀態。 + /// 欄位的最大值,用於計算最寬文字。 + private static void UpdateSingleCountLabelMinimumWidth(Label? label, string labelPrefix, int maxValue) + { + if (label == null || + label.IsDisposed) + { + return; + } + + string widestText = $"{labelPrefix}{maxValue}/{maxValue}"; + Size measured = TextRenderer.MeasureText( + widestText, + label.Font, + Size.Empty, + TextFormatFlags.NoPadding | TextFormatFlags.SingleLine); + + int width = Math.Max(label.MinimumSize.Width, measured.Width + 6); + int height = Math.Max(label.MinimumSize.Height, measured.Height); + + label.AutoSize = false; + label.MinimumSize = new Size(width, height); + label.Size = new Size(width, height); + } + + /// + /// 更新單一按鈕的最小尺寸,避免焦點加粗造成版面抖動 + /// + /// 目標按鈕。 + /// 目前 DPI 縮放比例。 + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private void UpdateSingleButtonMinimumSize(Button btn, float scale) + { + try + { + if (btn.IsDisposed) return; + + Font boldFont = _boldFont ?? MainForm.GetSharedA11yFont(DeviceDpi, FontStyle.Bold); + + DialogLayoutHelper.UpdateButtonMinimumSize(btn, boldFont, scale, 44, 44, 24, 16); + } + catch (Exception ex) + { + Debug.WriteLine($"[片語編輯] UpdateSingleButtonMinimumSize 失敗:{ex.Message}"); + } + } + + /// + /// 依 DPI 更新最小尺寸,讓片語名稱/內容輸入框有更充足的可視範圍。 + /// + /// 是否強制重新計算,忽略 DPI 未變更的快取防呆。 + private void UpdateMinimumSize(bool forceRecalculate = false) + { + float currentDpi = DeviceDpi; + + if (!DialogLayoutHelper.TryBeginDpiLayout(currentDpi, ref _lastAppliedDpi, forceRecalculate)) + { + return; + } + + float scale = currentDpi / AppSettings.BaseDpi; + + UpdateCountLabelMinimumWidths(); + + int desiredMinWidth = (int)(BaseDialogMinWidth * scale); + + Rectangle workArea = Screen.GetWorkingArea(this); + + // 小尺寸螢幕保護:保留 40px 邊界,避免高縮放下最小尺寸超出可視區。 + (int maxFitWidth, int maxFitHeight) = DialogLayoutHelper.GetMaxFitSize(workArea); + + int + // 正常情況至少保留 320px 的可編輯寬度;若工作區本身更窄,則以工作區上限為準。 + minWidth = maxFitWidth >= 320 ? + Math.Clamp(desiredMinWidth, 320, maxFitWidth) : + maxFitWidth; + + int desiredMinHeight = (int)(340 * scale), + minH = Math.Min(desiredMinHeight, maxFitHeight); + + DialogLayoutHelper.ClampFormSize(this, minWidth, minH, maxFitWidth, maxFitHeight, ApplySmartPosition); + } + + /// + /// 保持對話框位於目前螢幕可視範圍內 + /// + private void ApplySmartPosition() + { + if (InputBoxLayoutManager.TryGetClampedLocation(this, out Point clampedLocation)) + { + Location = clampedLocation; + } + } +} diff --git a/src/InputBox/Core/Controls/PhraseEditDialog.cs b/src/InputBox/Core/Controls/PhraseEditDialog.cs index c621893..668e910 100644 --- a/src/InputBox/Core/Controls/PhraseEditDialog.cs +++ b/src/InputBox/Core/Controls/PhraseEditDialog.cs @@ -2,15 +2,11 @@ using InputBox.Core.Extensions; using InputBox.Core.Feedback; using InputBox.Core.Input; -using InputBox.Core.Interop; using InputBox.Core.Services; using InputBox.Core.Utilities; using InputBox.Resources; using Microsoft.Win32; -using System.ComponentModel; using System.Diagnostics; -using System.Media; -using System.Runtime.CompilerServices; namespace InputBox.Core.Controls; @@ -20,7 +16,7 @@ partial class DesignerBlocker { }; /// /// 片語編輯對話框(新增/編輯單一片語) /// -internal sealed class PhraseEditDialog : Form +internal sealed partial class PhraseEditDialog : Form { /// /// 片語編輯視窗的基準最小寬度(96 DPI) @@ -154,50 +150,6 @@ internal sealed class PhraseEditDialog : Form /// private float _lastAppliedDpi; - /// - /// 遊戲控制器 - /// - [Browsable(false)] - [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] - public IGamepadController? GamepadController - { - get => _gamepadController; - set - { - if (ReferenceEquals(_gamepadController, value)) - { - return; - } - - UnsubscribeGamepadEvents(); - - _gamepadController = value; - - if (_gamepadController != null) - { - GamepadFaceButtonProfile profile = GamepadFaceButtonProfile.GetActiveProfile(); - - _gamepadController.APressed += profile.ConfirmOnSouth ? HandleGamepadA : HandleBackOrClear; - _gamepadController.StartPressed += HandleOpenTouchKeyboardFromGamepad; - _gamepadController.BPressed += profile.ConfirmOnSouth ? HandleBackOrClear : HandleGamepadA; - _gamepadController.BackPressed += HandleCancel; - _gamepadController.LeftPressed += HandleLeft; - _gamepadController.LeftRepeat += HandleLeft; - _gamepadController.RightPressed += HandleRight; - _gamepadController.RightRepeat += HandleRight; - _gamepadController.UpPressed += HandleFieldPrev; - _gamepadController.DownPressed += HandleFieldNext; - _gamepadController.XPressed += HandleBackspace; - _gamepadController.YPressed += HandleOpenContextMenu; - _gamepadController.RSLeftPressed += HandleRSLeft; - _gamepadController.RSLeftRepeat += HandleRSLeft; - _gamepadController.RSRightPressed += HandleRSRight; - _gamepadController.RSRightRepeat += HandleRSRight; - _gamepadController.ConnectionChanged += HandleConnectionChanged; - } - } - } - /// /// 初始化片語編輯對話框 /// @@ -544,92 +496,6 @@ protected override void OnShown(EventArgs e) ApplyInputBoxStrongVisual(_txtName); } - /// - /// 建立控制項 Handle 後套用最小尺寸、系統事件訂閱與初始定位。 - /// - /// 控制項事件參數。 - protected override void OnHandleCreated(EventArgs e) - { - base.OnHandleCreated(e); - - UpdateMinimumSize(); - - SystemEvents.UserPreferenceChanged -= SystemEvents_UserPreferenceChanged; - SystemEvents.UserPreferenceChanged += SystemEvents_UserPreferenceChanged; - - this.SafeBeginInvoke(ApplySmartPosition); - } - - /// - /// DPI 變更時重新量測按鈕尺寸與對話框最小尺寸。 - /// - /// DPI 變更事件參數。 - protected override void OnDpiChanged(DpiChangedEventArgs e) - { - try - { - base.OnDpiChanged(e); - - this.SafeInvoke(() => - { - try - { - // DPI 變更後刷新字型快取引用(共享快取依 DPI 分開儲存,必須重新取得)。 - _a11yFont = MainForm.GetSharedA11yFont(DeviceDpi, FontStyle.Regular); - _boldFont = MainForm.GetSharedA11yFont(DeviceDpi, FontStyle.Bold); - Font = _a11yFont; - - // 輸入框使用 2.0× 倍率字型(已明確設定,不繼承 Form.Font,需手動更新)。 - Font sharedInputFont = MainForm.GetSharedA11yFont( - DeviceDpi, - FontStyle.Regular, - _a11yFont?.FontFamily, - 2.0f); - _txtName.Font = sharedInputFont; - _txtContent.Font = sharedInputFont; - - // 重新掛載眼動儀回饋,刷新 ButtonVisualState 中儲存的字型引用。 - _btnOk.AttachEyeTrackerFeedback( - baseDescription: Strings.Phrase_A11y_Btn_Confirm_Desc, - regularFont: _a11yFont, - boldFont: _boldFont, - formCt: _cts?.Token ?? CancellationToken.None); - - _btnCancel.AttachEyeTrackerFeedback( - baseDescription: Strings.Phrase_A11y_Btn_Cancel_Desc, - regularFont: _a11yFont, - boldFont: _boldFont, - formCt: _cts?.Token ?? CancellationToken.None); - - UpdateButtonMinimumSizes(); - UpdateMinimumSize(); - ApplySmartPosition(); - _btnOk.Invalidate(); - _btnCancel.Invalidate(); - } - catch (Exception ex) - { - Debug.WriteLine($"[片語編輯] OnDpiChanged 延遲邏輯失敗:{ex.Message}"); - } - }); - } - catch (Exception ex) - { - Debug.WriteLine($"[片語編輯] OnDpiChanged 失敗:{ex.Message}"); - } - } - - /// - /// 使用者結束調整視窗大小後重新套用智慧定位。 - /// - /// 事件參數。 - protected override void OnResizeEnd(EventArgs e) - { - base.OnResizeEnd(e); - - ApplySmartPosition(); - } - /// /// 處理命令鍵 /// @@ -716,109 +582,6 @@ protected override void OnFormClosing(FormClosingEventArgs e) } } - /// - /// Handle 銷毀時確保解除靜態系統事件訂閱 - /// - /// 控制項事件參數。 - protected override void OnHandleDestroyed(EventArgs e) - { - try - { - SystemEvents.UserPreferenceChanged -= SystemEvents_UserPreferenceChanged; - } - finally - { - base.OnHandleDestroyed(e); - } - } - - /// - /// 系統偏好設定變更時同步更新按鈕尺寸、最小尺寸與焦點視覺 - /// - /// 事件來源。 - /// 系統偏好設定事件參數。 - private void SystemEvents_UserPreferenceChanged(object? sender, UserPreferenceChangedEventArgs e) - { - try - { - if (e.Category is UserPreferenceCategory.Accessibility or - UserPreferenceCategory.Color or - UserPreferenceCategory.General) - { - this.SafeInvoke(() => - { - UpdateButtonMinimumSizes(); - UpdateMinimumSize(forceRecalculate: true); - ApplySmartPosition(); - - _btnOk.Invalidate(); - _btnCancel.Invalidate(); - - UpdateNameCharCount(); - UpdateContentCharCount(); - - TextBox? active = GetActiveTextBox(); - - if (active != null) - { - ApplyInputBoxStrongVisual(active); - } - }); - } - } - catch (Exception ex) - { - Debug.WriteLine($"[片語編輯] SystemEvents_UserPreferenceChanged 失敗:{ex.Message}"); - } - } - - /// - /// A 鍵:按鈕 → PerformClick;輸入框為空時開啟觸控鍵盤;其餘情境走確認驗證 - /// - private void HandleGamepadA() => this.SafeInvoke(() => - { - try - { - if (ActiveControl is Button btn) - { - btn.PerformClick(); - return; - } - - TextBox? tb = GetActiveTextBox() ?? _txtName; - - if (tb != null && string.IsNullOrWhiteSpace(tb.Text)) - { - ShowTouchKeyboard(tb); - - return; - } - - HandleConfirm(); - } - catch (Exception ex) - { - Debug.WriteLine($"[片語編輯] 控制器 A 鍵失敗:{ex.Message}"); - } - }); - - /// - /// Start 鍵:在輸入框焦點時直接開啟觸控式鍵盤(可在已有內容時修改) - /// - private void HandleOpenTouchKeyboardFromGamepad() => this.SafeInvoke(() => - { - try - { - TextBox? tb = GetActiveTextBox() ?? _txtName; - - ShowTouchKeyboard(tb); - } - catch (Exception ex) - { - Debug.WriteLine($"[片語編輯] 控制器開啟觸控鍵盤失敗:{ex.Message}"); - } - }); - /// /// 驗證片語名稱與內容,驗證通過時以 OK 關閉對話框 /// @@ -869,110 +632,6 @@ private void HandleCancel() => this.SafeInvoke(() => } }); - /// - /// B 鍵:若焦點在輸入框且有內容則優先清空;否則執行取消 - /// - private void HandleBackOrClear() => this.SafeInvoke(() => - { - try - { - TextBox? tb = GetActiveTextBox(); - - if (tb != null) - { - if (tb.SelectionLength > 0) - { - tb.SelectedText = string.Empty; - - _rsSelectionAnchor = null; - - AnnounceA11y(Strings.Msg_InputCleared, interrupt: true); - - FeedbackService.VibrateAsync( - _gamepadController, - VibrationPatterns.ClearInput, - _cts?.Token ?? CancellationToken.None) - .SafeFireAndForget(); - - return; - } - - if (!string.IsNullOrEmpty(tb.Text)) - { - tb.Clear(); - - _rsSelectionAnchor = null; - - AnnounceA11y(Strings.Msg_InputCleared, interrupt: true); - - FeedbackService.VibrateAsync( - _gamepadController, - VibrationPatterns.ClearInput, - _cts?.Token ?? CancellationToken.None) - .SafeFireAndForget(); - - return; - } - } - - HandleCancel(); - } - catch (Exception ex) - { - Debug.WriteLine($"[片語編輯] HandleBackOrClear 失敗:{ex.Message}"); - } - }); - - /// - /// 聚焦指定輸入框並非同步開啟觸控式鍵盤。 - /// - /// 要聚焦的輸入框。 - private void ShowTouchKeyboard(TextBox tb) - { - if (tb.CanFocus && !tb.Focused) - { - tb.Focus(); - } - - AnnounceA11y(Strings.A11y_Opening_Keyboard, interrupt: true); - - Task.Run(async () => - { - try - { - await Task.Delay(150, _cts?.Token ?? CancellationToken.None); - - if (TouchKeyboardService.IsVisible()) return; - - await this.SafeInvokeAsync(() => - { - try - { - bool opened = TouchKeyboardService.TryOpen(); - - if (opened) - { - FeedbackService.PlaySound(SystemSounds.Asterisk); - } - } - catch (Exception ex) - { - Debug.WriteLine($"[片語編輯] 觸控鍵盤開啟失敗:{ex.Message}"); - } - }); - } - catch (OperationCanceledException) - { - - } - catch (Exception ex) - { - Debug.WriteLine($"[片語編輯] 開啟觸控鍵盤失敗:{ex.Message}"); - } - }, - _cts?.Token ?? CancellationToken.None).SafeFireAndForget(); - } - /// /// 片語名稱欄文字變更時,更新字數顯示並提供接近上限的回饋。 /// @@ -1016,1079 +675,20 @@ private void HandleContentKeyPress(object? sender, KeyPressEventArgs e) => HandleTextLimitKeyPress(_txtContent, AppSettings.MaxInputLength, ref _lastContentLimitWallUtc, e); /// - /// 取得目前焦點所在的 TextBox(名稱或內容)。 - /// - /// 具有焦點的輸入框;兩者皆無焦點時回傳 null。 - private TextBox? GetActiveTextBox() - { - if (_txtName.Focused) - { - return _txtName; - } - - if (_txtContent.Focused) - { - return _txtContent; - } - - return null; - } - - /// - /// 輸入框取得焦點時套用強化焦點視覺。 - /// - /// 觸發事件的輸入框。 - /// 事件參數。 - private void HandleTextBoxEnter(object? sender, EventArgs eventArgs) - { - try - { - if (sender is TextBox textBox) - { - ApplyInputBoxStrongVisual(textBox); - } - } - catch (Exception ex) - { - Debug.WriteLine($"[片語編輯] HandleTextBoxEnter 失敗:{ex.Message}"); - } - } - - /// - /// 輸入框失去焦點時還原一般視覺樣式。 + /// 從資源檔取得片語文字,若失敗則回傳後備文字 /// - /// 觸發事件的輸入框。 - /// 事件參數。 - private void HandleTextBoxLeave(object? sender, EventArgs eventArgs) + /// 資源鍵值。 + /// 找不到資源時使用的後備文字。 + /// 資源文字或後備文字。 + private static string GetPhraseTextOrFallback(string key, string fallback) { try { - if (sender is TextBox textBox) - { - ResetInputBoxVisual(textBox); - } - } - catch (Exception ex) - { - Debug.WriteLine($"[片語編輯] HandleTextBoxLeave 失敗:{ex.Message}"); - } - } - - /// - /// 套用與主輸入框一致的強視覺焦點樣式(高對比優先,其次主題感知反轉)。 - /// - /// 要套用焦點樣式的輸入框。 - private static void ApplyInputBoxStrongVisual(TextBox textBox) - { - if (textBox.IsDisposed) - { - return; - } - - if (SystemInformation.HighContrast) - { - textBox.BackColor = SystemColors.Highlight; - textBox.ForeColor = SystemColors.HighlightText; - - return; - } - - if (textBox.IsDarkModeActive()) - { - // 深色模式:反轉為白底黑字。 - textBox.BackColor = Color.White; - textBox.ForeColor = Color.Black; - } - else - { - // 淺色模式:反轉為黑底白字。 - textBox.BackColor = Color.Black; - textBox.ForeColor = Color.White; - } - } - - /// - /// 還原輸入框為系統預設背景與前景色 - /// - /// 目標輸入框。 - private static void ResetInputBoxVisual(TextBox tb) - { - if (tb.IsDisposed) - { - return; + return Strings.ResourceManager.GetString(key, Strings.Culture) ?? fallback; } - - tb.BackColor = Color.Empty; - tb.ForeColor = Color.Empty; - } - - /// - /// 針對驗證失敗的輸入框提供焦點、音效、震動與視覺提示 - /// - /// 驗證失敗的輸入框。 - /// 要播報的錯誤訊息。 - private void NotifyValidationFailure(TextBox target, string message) - { - if (target.CanFocus && !target.Focused) - { - target.Focus(); - } - - AnnounceA11y(message, interrupt: true); - - FeedbackService.PlaySound(SystemSounds.Hand); - - FeedbackService.VibrateAsync( - _gamepadController, - VibrationPatterns.ActionFail, - _cts?.Token ?? CancellationToken.None) - .SafeFireAndForget(); - - FlashValidationCueAsync(target).SafeFireAndForget(); - } - - /// - /// 暫時閃爍輸入框以提供驗證失敗的視覺提示 - /// - /// 要閃爍提示的輸入框。 - /// 非同步作業。 - private async Task FlashValidationCueAsync(TextBox target) - { - if (target.IsDisposed || - !IsHandleCreated || - Interlocked.CompareExchange(ref _isFlashing, 1, 0) != 0) - { - return; - } - - // 僅在對話框生命週期仍有效時建立警示權杖,避免關閉途中留下失去連結的動畫。 - CancellationTokenSource? newAlertCts = _cts.TryCreateLinkedTokenSource(); - - if (newAlertCts == null) - { - Interlocked.Exchange(ref _isFlashing, 0); - - return; - } - - Interlocked.Exchange(ref _alertCts, newAlertCts)?.CancelAndDispose(); - - CancellationToken token = newAlertCts.Token; - - try - { - bool isDark = target.IsDarkModeActive(); - Color alertColor = FlashAlertAnimator.GetAlertColor(isDark, SystemInformation.HighContrast); - - void ApplyAlertVisuals(float intensity) - { - if (target.IsDisposed || - !IsHandleCreated) - { - return; - } - - (Color back, Color fore) = FlashAlertAnimator.ComputeFrameColors( - intensity, - isDark, - alertColor, - SystemInformation.HighContrast); - - target.BackColor = back; - target.ForeColor = fore; - } - - await FlashAlertAnimator.RunAsync(this, ApplyAlertVisuals, token); - } - catch (OperationCanceledException) - { - // 正常取消。 - } - catch (Exception ex) - { - Debug.WriteLine($"[片語編輯] FlashValidationCueAsync 失敗:{ex.Message}"); - } - finally - { - Interlocked.Exchange(ref _isFlashing, 0); - Interlocked.Exchange(ref _alertCts, null)?.CancelAndDispose(); - - // 確保 UI 狀態還原。 - this.SafeInvoke(() => - { - try - { - if (target.IsDisposed || - !IsHandleCreated) - { - return; - } - - if (target.Focused) - { - ApplyInputBoxStrongVisual(target); - } - else - { - ResetInputBoxVisual(target); - } - } - catch (Exception ex) - { - Debug.WriteLine($"[片語編輯] 驗證提示動畫 UI 還原失敗:{ex.Message}"); - } - }); - } - } - - /// - /// 從資源檔取得片語文字,若失敗則回傳後備文字 - /// - /// 資源鍵值。 - /// 找不到資源時使用的後備文字。 - /// 資源文字或後備文字。 - private static string GetPhraseTextOrFallback(string key, string fallback) - { - try - { - return Strings.ResourceManager.GetString(key, Strings.Culture) ?? fallback; - } - catch + catch { return fallback; } } - - /// - /// 游標左移(比照 MainForm.Gamepad.cs 的 MoveCursorLeft) - /// - private void HandleLeft() => this.SafeInvoke(() => - { - try - { - TextBox? tb = GetActiveTextBox(); - - if (tb == null) - { - // 焦點在按鈕區:D-Pad 左向在確認/取消按鈕間循環。 - if (_btnOk.Focused) - { - _btnCancel.Focus(); - AnnounceA11y(_btnCancel.AccessibleName ?? _btnCancel.Text, interrupt: true); - FeedbackService.VibrateAsync(_gamepadController, VibrationPatterns.CursorMove, _cts?.Token ?? CancellationToken.None).SafeFireAndForget(); - } - else if (_btnCancel.Focused) - { - _btnOk.Focus(); - AnnounceA11y(_btnOk.AccessibleName ?? _btnOk.Text, interrupt: true); - FeedbackService.VibrateAsync(_gamepadController, VibrationPatterns.CursorMove, _cts?.Token ?? CancellationToken.None).SafeFireAndForget(); - } - - return; - } - - bool hasSelection = tb.SelectionLength > 0; - - if (hasSelection || - tb.SelectionStart > 0) - { - if (hasSelection) - { - tb.SelectionLength = 0; - } - else if (_gamepadController?.IsLeftShoulderHeld == true) - { - tb.WordJump(false); - } - else - { - tb.SelectionStart--; - } - - tb.ScrollToCaret(); - - FeedbackService.VibrateAsync( - _gamepadController, - VibrationPatterns.CursorMove, - _cts?.Token ?? CancellationToken.None) - .SafeFireAndForget(); - } - else - { - FeedbackService.PlaySound(SystemSounds.Beep); - - FeedbackService.VibrateAsync( - _gamepadController, - VibrationPatterns.CursorMove, - _cts?.Token ?? CancellationToken.None) - .SafeFireAndForget(); - } - } - catch (Exception ex) - { - Debug.WriteLine($"[片語編輯] 左移失敗:{ex.Message}"); - } - }); - - /// - /// 游標右移(比照 MainForm.Gamepad.cs 的 MoveCursorRight) - /// - private void HandleRight() => this.SafeInvoke(() => - { - try - { - TextBox? tb = GetActiveTextBox(); - - if (tb == null) - { - // 焦點在按鈕區:D-Pad 右向在取消/確認按鈕間循環。 - if (_btnCancel.Focused) - { - _btnOk.Focus(); - AnnounceA11y(_btnOk.AccessibleName ?? _btnOk.Text, interrupt: true); - FeedbackService.VibrateAsync(_gamepadController, VibrationPatterns.CursorMove, _cts?.Token ?? CancellationToken.None).SafeFireAndForget(); - } - else if (_btnOk.Focused) - { - _btnCancel.Focus(); - AnnounceA11y(_btnCancel.AccessibleName ?? _btnCancel.Text, interrupt: true); - FeedbackService.VibrateAsync(_gamepadController, VibrationPatterns.CursorMove, _cts?.Token ?? CancellationToken.None).SafeFireAndForget(); - } - - return; - } - - bool hasSelection = tb.SelectionLength > 0; - - if (hasSelection || tb.SelectionStart < tb.Text.Length) - { - if (hasSelection) - { - tb.SelectionStart += tb.SelectionLength; - tb.SelectionLength = 0; - } - else if (_gamepadController?.IsLeftShoulderHeld == true) - { - tb.WordJump(true); - } - else - { - tb.SelectionStart++; - } - - tb.ScrollToCaret(); - - FeedbackService.VibrateAsync( - _gamepadController, - VibrationPatterns.CursorMove, - _cts?.Token ?? CancellationToken.None) - .SafeFireAndForget(); - } - else - { - FeedbackService.PlaySound(SystemSounds.Beep); - - FeedbackService.VibrateAsync( - _gamepadController, - VibrationPatterns.CursorMove, - _cts?.Token ?? CancellationToken.None) - .SafeFireAndForget(); - } - } - catch (Exception ex) - { - Debug.WriteLine($"[片語編輯] 右移失敗:{ex.Message}"); - } - }); - - /// - /// 上方向鍵:在名稱欄位與內容欄位和按鈕之間切換焦點 - /// - private void HandleFieldPrev() => this.SafeInvoke(() => - { - try - { - if (_txtContent.Focused) - { - _txtName.Focus(); - } - else if (_btnOk.Focused) - { - _txtContent.Focus(); - } - else if (_btnCancel.Focused) - { - _btnOk.Focus(); - } - else if (_txtName.Focused) - { - _btnCancel.Focus(); - } - - FeedbackService.VibrateAsync( - _gamepadController, - VibrationPatterns.CursorMove, - _cts?.Token ?? CancellationToken.None) - .SafeFireAndForget(); - } - catch (Exception ex) - { - Debug.WriteLine($"[片語編輯] 欄位向前失敗:{ex.Message}"); - } - }); - - /// - /// 下方向鍵:在名稱欄位、內容欄位與按鈕之間循環焦點 - /// - private void HandleFieldNext() => this.SafeInvoke(() => - { - try - { - if (_txtName.Focused) - { - _txtContent.Focus(); - } - else if (_txtContent.Focused) - { - _btnOk.Focus(); - } - else if (_btnOk.Focused) - { - _btnCancel.Focus(); - } - else if (_btnCancel.Focused) - { - _txtName.Focus(); - } - - FeedbackService.VibrateAsync( - _gamepadController, - VibrationPatterns.CursorMove, - _cts?.Token ?? CancellationToken.None) - .SafeFireAndForget(); - } - catch (Exception ex) - { - Debug.WriteLine($"[片語編輯] 欄位向後失敗:{ex.Message}"); - } - }); - - /// - /// X 鍵:刪除選取文字或游標前一字元(比照 MainForm.Gamepad.cs 的 X 鍵刪除邏輯) - /// - private void HandleBackspace() => this.SafeInvoke(() => - { - try - { - TextBox? tb = GetActiveTextBox(); - - if (tb == null || - tb.ReadOnly) - { - return; - } - - if (tb.SelectionLength > 0) - { - tb.SelectedText = string.Empty; - } - else if (tb.SelectionStart > 0) - { - int pos = tb.SelectionStart; - - tb.Select(pos - 1, 1); - tb.SelectedText = string.Empty; - } - else - { - FeedbackService.PlaySound(SystemSounds.Beep); - - FeedbackService.VibrateAsync( - _gamepadController, - VibrationPatterns.CursorMove, - _cts?.Token ?? CancellationToken.None) - .SafeFireAndForget(); - } - } - catch (Exception ex) - { - Debug.WriteLine($"[片語編輯] 退格失敗:{ex.Message}"); - } - }); - - /// - /// 右搖桿左推:擴張選取範圍向左(比照 MainForm.Gamepad.cs 的 ExpandSelection) - /// - private void HandleRSLeft() => this.SafeInvoke(() => - { - try - { - ExpandSelection(-1); - } - catch (Exception ex) - { - Debug.WriteLine($"[片語編輯] 右摘桿左移失敗:{ex.Message}"); - } - }); - - /// - /// 右搖桿右推:擴張選取範圍向右 - /// - private void HandleRSRight() => this.SafeInvoke(() => - { - try - { - ExpandSelection(1); - } - catch (Exception ex) - { - Debug.WriteLine($"[片語編輯] 右摘桿右移失敗:{ex.Message}"); - } - }); - - /// - /// Y 鍵:開啟焦點 TextBox 的原生右鍵選單 - /// - private void HandleOpenContextMenu() => this.SafeInvoke(() => - { - try - { - if (GamescopeSurfaceRecovery.TryRecoverFromGamepadChord( - this, - RecreateHandle, - _gamepadController, - beforeRecover: CloseActiveTextBoxContextMenu, - context: "PhraseEditDialog Gamescope surface recovery 失敗")) - { - return; - } - - TextBox? tb = GetActiveTextBox(); - - if (tb == null) - { - return; - } - - // 在游標位置附近顯示內建右鍵選單。 - Point caretPos = tb.GetPositionFromCharIndex(tb.SelectionStart); - - tb.ContextMenuStrip?.Show(tb, caretPos); - - // TextBox 沒有 ContextMenuStrip 時,透過模擬 Shift+F10 觸發原生選單。 - if (tb.ContextMenuStrip == null) - { - User32.SendMessage(tb.Handle, 0x007B, tb.Handle, unchecked((nint)0xFFFFFFFF)); - } - } - catch (Exception ex) - { - Debug.WriteLine($"[片語編輯] 開啟右鍵選單失敗:{ex.Message}"); - } - }); - - /// - /// 在重建 PhraseEditDialog surface 前關閉目前 TextBox 的右鍵選單。 - /// - private void CloseActiveTextBoxContextMenu() - { - GetActiveTextBox()?.ContextMenuStrip?.Close(); - } - - /// - /// 擴張或縮減文字選取範圍(比照 MainForm.Gamepad.cs 的 ExpandSelection) - /// - /// 方向,正數表示向右擴張,負數表示向左擴張。 - private void ExpandSelection(int direction) - { - TextBox? tb = GetActiveTextBox(); - - if (tb == null) - { - return; - } - - (int anchor, int caret) = tb.ResolveSelectionAnchor(_rsSelectionAnchor); - - _rsSelectionAnchor = anchor; - - int safeDirection = Math.Sign(direction); - bool wordGranularity = _gamepadController?.IsLeftShoulderHeld == true || - _gamepadController?.IsRightShoulderHeld == true; - - int newCaret = wordGranularity ? - tb.GetWordJumpTarget(caret, safeDirection > 0) : - Math.Clamp(caret + safeDirection, 0, tb.TextLength); - - if (newCaret == caret) - { - FeedbackService.VibrateAsync( - _gamepadController, - VibrationPatterns.ActionFail, - _cts?.Token ?? CancellationToken.None) - .SafeFireAndForget(); - - return; - } - - // 使用 Win32 EM_SETSEL 正確設定選取範圍(含反向選取)。 - tb.SetSelectionWithActiveEdge(anchor, newCaret); - - PlaySelectionFeedback(safeDirection, wordGranularity); - } - - /// - /// 推進某類觸覺回饋的 burst 等級,用於快速連發時做輕量阻尼。 - /// - /// 上次觸發的 UTC 時間戳(ref,會被更新)。 - /// 目前 burst 等級(ref,會被累加或重設)。 - /// 視為快速連發的時間視窗(毫秒)。 - /// 更新後的 burst 等級(0 ~ 3)。 - private static int AdvanceFeedbackBurst(ref DateTime lastUtc, ref int burstLevel, int fastWindowMs) - { - DateTime now = DateTime.UtcNow; - burstLevel = (now - lastUtc).TotalMilliseconds <= fastWindowMs ? - Math.Min(burstLevel + 1, 3) : - 0; - lastUtc = now; - - return burstLevel; - } - - /// - /// 依剩餘字元數分級,僅在接近上限時回傳有效 bucket。 - /// - /// 距離上限的剩餘字元數。 - /// 警示等級(0 ~ 3);超過警示閾值時回傳 -1。 - private static int GetTextLimitWarningBucket(int remainingCharacters) - { - return remainingCharacters switch - { - <= 0 => 3, - <= 2 => 2, - <= 5 => 1, - <= TextLimitWarningThreshold => 0, - _ => -1 - }; - } - - /// - /// 當片語欄位長度變動時,提供接近字數上限的物理預警與硬牆回饋。 - /// - /// 監控中的輸入框。 - /// 欄位的最大字元數限制。 - /// 上次觀察到的長度(ref,會被更新)。 - /// 上次警示的 bucket 等級(ref,會被更新)。 - private void HandleTextLimitFeedbackFromLengthChange( - TextBox textBox, - int maxLength, - ref int lastObservedLength, - ref int lastWarningBucket) - { - if (textBox.IsDisposed) - { - return; - } - - int currentLength = textBox.TextLength; - - if (currentLength < lastObservedLength) - { - lastObservedLength = currentLength; - lastWarningBucket = currentLength >= maxLength - TextLimitWarningThreshold ? - GetTextLimitWarningBucket(maxLength - currentLength) : - -1; - return; - } - - int remainingCharacters = maxLength - currentLength; - - if (remainingCharacters > TextLimitWarningThreshold) - { - lastObservedLength = currentLength; - lastWarningBucket = -1; - return; - } - - int currentBucket = GetTextLimitWarningBucket(remainingCharacters); - - if (currentLength > lastObservedLength && - (currentBucket != lastWarningBucket || remainingCharacters <= 2)) - { - if (remainingCharacters <= 0) - { - FeedbackService.PlaySound(SystemSounds.Beep); - } - - FeedbackService.VibrateSequenceAsync( - _gamepadController, - VibrationPatterns.GetTextLimitSequence( - remainingCharacters, - _gamepadController?.VibrationMotorSupport ?? VibrationMotorSupport.None), - _cts?.Token ?? CancellationToken.None) - .SafeFireAndForget(); - } - - lastObservedLength = currentLength; - lastWarningBucket = currentBucket; - } - - /// - /// 使用者在字數已滿時仍嘗試輸入一般字元,播放硬牆回饋。 - /// - /// 目標輸入框。 - /// 欄位的最大字元數限制。 - /// 上次觸發硬牆回饋的 UTC 時間戳(ref,用於節流)。 - /// 按鍵事件引數。 - private void HandleTextLimitKeyPress(TextBox textBox, int maxLength, ref DateTime lastWallUtc, KeyPressEventArgs e) - { - if (textBox.IsDisposed || - char.IsControl(e.KeyChar) || - textBox.TextLength < maxLength) - { - return; - } - - if ((DateTime.UtcNow - lastWallUtc).TotalMilliseconds < RepeatedBoundaryFeedbackThrottleMs) - { - return; - } - - lastWallUtc = DateTime.UtcNow; - FeedbackService.PlaySound(SystemSounds.Beep); - FeedbackService.VibrateSequenceAsync( - _gamepadController, - VibrationPatterns.GetTextLimitSequence( - 0, - _gamepadController?.VibrationMotorSupport ?? VibrationMotorSupport.None), - _cts?.Token ?? CancellationToken.None) - .SafeFireAndForget(); - } - - /// - /// 根據選取粒度與速度播放不同的右搖桿文字選取回饋。 - /// - /// 選取方向;負值為向左,正值為向右。 - /// 是否為單字粒度選取。 - private void PlaySelectionFeedback(int direction, bool wordGranularity) - { - IGamepadController? controller = _gamepadController; - - if (controller == null || - !controller.IsConnected) - { - return; - } - - int burstLevel = wordGranularity ? - 0 : - AdvanceFeedbackBurst(ref _lastSelectionFeedbackUtc, ref _selectionFeedbackBurstLevel, SelectionBurstWindowMs); - - FeedbackService.VibrateSequenceAsync( - controller, - VibrationPatterns.GetSelectionSequence(direction, wordGranularity, burstLevel, controller.VibrationMotorSupport), - _cts?.Token ?? CancellationToken.None) - .SafeFireAndForget(); - - FeedbackService.PlaySelectionCue(wordGranularity, burstLevel); - } - - /// - /// 控制器重新連線後恢復輪詢狀態。 - /// - /// 新的控制器連線狀態。 - private void HandleConnectionChanged(bool connected) - { - try - { - if (connected) - { - _gamepadController?.Resume(); - } - } - catch (Exception ex) - { - Debug.WriteLine($"[片語編輯] 控制器連線變更:{ex.Message}"); - } - } - - /// - /// 解除目前片語編輯對話框所綁定的控制器事件 - /// - private void UnsubscribeGamepadEvents() - { - try - { - if (_gamepadController != null) - { - _gamepadController.APressed -= HandleGamepadA; - _gamepadController.APressed -= HandleBackOrClear; - _gamepadController.StartPressed -= HandleOpenTouchKeyboardFromGamepad; - _gamepadController.BPressed -= HandleGamepadA; - _gamepadController.BPressed -= HandleBackOrClear; - _gamepadController.BackPressed -= HandleCancel; - _gamepadController.LeftPressed -= HandleLeft; - _gamepadController.LeftRepeat -= HandleLeft; - _gamepadController.RightPressed -= HandleRight; - _gamepadController.RightRepeat -= HandleRight; - _gamepadController.UpPressed -= HandleFieldPrev; - _gamepadController.DownPressed -= HandleFieldNext; - _gamepadController.XPressed -= HandleBackspace; - _gamepadController.YPressed -= HandleOpenContextMenu; - _gamepadController.RSLeftPressed -= HandleRSLeft; - _gamepadController.RSLeftRepeat -= HandleRSLeft; - _gamepadController.RSRightPressed -= HandleRSRight; - _gamepadController.RSRightRepeat -= HandleRSRight; - _gamepadController.ConnectionChanged -= HandleConnectionChanged; - } - } - catch (Exception ex) - { - Debug.WriteLine($"[片語編輯] UnsubscribeGamepadEvents 失敗:{ex.Message}"); - } - } - - /// - /// 更新片語名稱字元數提示標籤({current}/{max}),近上限時顯示橙色。 - /// - private void UpdateNameCharCount() - { - if (_lblNameCount == null || _lblNameCount.IsDisposed) - { - return; - } - - int len = _txtName.TextLength; - int max = AppSettings.MaxPhraseNameLength; - string countLabel = GetPhraseTextOrFallback("Phrase_Edit_Name_Count", "Name length: "); - string countText = $"{countLabel}{len}/{max}"; - - _lblNameCount.Text = countText; - _lblNameCount.AccessibleName = countText; - _lblNameCount.AccessibleDescription = $"{Strings.Phrase_A11y_Edit_Name_Desc} {countText}"; - - if (SystemInformation.HighContrast) - { - _lblNameCount.ForeColor = Color.Empty; - - return; - } - - _lblNameCount.ForeColor = len >= max - 10 ? - Color.DarkOrange : - Color.Empty; - } - - /// - /// 更新片語內容字元數提示標籤({current}/{max}),近上限時顯示橙色。 - /// - private void UpdateContentCharCount() - { - if (_lblContentCount == null || _lblContentCount.IsDisposed) - { - return; - } - - int len = _txtContent.TextLength; - int max = AppSettings.MaxInputLength; - string countLabel = GetPhraseTextOrFallback("Phrase_Edit_Content_Count", "Content length: "); - string countText = $"{countLabel}{len}/{max}"; - - _lblContentCount.Text = countText; - _lblContentCount.AccessibleName = countText; - _lblContentCount.AccessibleDescription = $"{Strings.Phrase_A11y_Edit_Content_Desc} {countText}"; - - if (SystemInformation.HighContrast) - { - _lblContentCount.ForeColor = Color.Empty; - - return; - } - - _lblContentCount.ForeColor = len >= max - 50 ? - Color.DarkOrange : - Color.Empty; - } - - /// - /// 更新按鈕最小尺寸(抗抖動 + WCAG 2.5.5 AAA 44×44) - /// - private void UpdateButtonMinimumSizes() - { - float scale = DeviceDpi / AppSettings.BaseDpi; - - UpdateSingleButtonMinimumSize(_btnOk, scale); - UpdateSingleButtonMinimumSize(_btnCancel, scale); - } - - /// - /// 預先鎖定動態字數標籤的最小寬度,避免數值變化時造成版面抖動。 - /// - private void UpdateCountLabelMinimumWidths() - { - UpdateSingleCountLabelMinimumWidth( - _lblNameCount, - GetPhraseTextOrFallback("Phrase_Edit_Name_Count", "Name length: "), - AppSettings.MaxPhraseNameLength); - UpdateSingleCountLabelMinimumWidth( - _lblContentCount, - GetPhraseTextOrFallback("Phrase_Edit_Content_Count", "Content length: "), - AppSettings.MaxInputLength); - } - - /// - /// 鎖定單一動態標籤的寬度,讓最長狀態文字也不會改變物理尺寸。 - /// - /// 要鎖定寬度的標籤;為 null 時略過。 - /// 標籤前綴文字,用於計算最寬狀態。 - /// 欄位的最大值,用於計算最寬文字。 - private static void UpdateSingleCountLabelMinimumWidth(Label? label, string labelPrefix, int maxValue) - { - if (label == null || - label.IsDisposed) - { - return; - } - - string widestText = $"{labelPrefix}{maxValue}/{maxValue}"; - Size measured = TextRenderer.MeasureText( - widestText, - label.Font, - Size.Empty, - TextFormatFlags.NoPadding | TextFormatFlags.SingleLine); - - int width = Math.Max(label.MinimumSize.Width, measured.Width + 6); - int height = Math.Max(label.MinimumSize.Height, measured.Height); - - label.AutoSize = false; - label.MinimumSize = new Size(width, height); - label.Size = new Size(width, height); - } - - /// - /// 更新單一按鈕的最小尺寸,避免焦點加粗造成版面抖動 - /// - /// 目標按鈕。 - /// 目前 DPI 縮放比例。 - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private void UpdateSingleButtonMinimumSize(Button btn, float scale) - { - try - { - if (btn.IsDisposed) return; - - Font boldFont = _boldFont ?? MainForm.GetSharedA11yFont(DeviceDpi, FontStyle.Bold); - - DialogLayoutHelper.UpdateButtonMinimumSize(btn, boldFont, scale, 44, 44, 24, 16); - } - catch (Exception ex) - { - Debug.WriteLine($"[片語編輯] UpdateSingleButtonMinimumSize 失敗:{ex.Message}"); - } - } - - /// - /// 廣播無障礙訊息 - /// - /// 要廣播的訊息 - /// 是否中斷目前的廣播 - private void AnnounceA11y(string message, bool interrupt = false) - { - if (IsDisposed || - string.IsNullOrEmpty(message)) - { - return; - } - - if (Owner is MainForm mainForm) - { - mainForm.AnnounceA11y(message, interrupt); - } - else if (Owner is PhraseManagerDialog phraseManager) - { - // 嘗試寫往主視窗。 - if (phraseManager.Owner is MainForm main) - { - main.AnnounceA11y(message, interrupt); - - return; - } - } - - // 本地備援 - long currentId = Interlocked.Increment(ref _a11yDebounceId); - - Task.Run(async () => - { - try - { - await Task.Delay(AppSettings.AudioDuckingDelayMs, _cts?.Token ?? CancellationToken.None); - - if (Interlocked.Read(ref _a11yDebounceId) == currentId && - !IsDisposed && - IsHandleCreated) - { - await this.SafeInvokeAsync(() => - _announcer.Announce(message, interrupt && AppSettings.Current.A11yInterruptEnabled)); - } - } - catch (OperationCanceledException) - { - - } - catch (Exception ex) - { - Debug.WriteLine($"[片語編輯] A11y 廣播失敗:{ex.Message}"); - } - }, - _cts?.Token ?? CancellationToken.None) - .SafeFireAndForget(); - } - - /// - /// 依 DPI 更新最小尺寸,讓片語名稱/內容輸入框有更充足的可視範圍。 - /// - /// 是否強制重新計算,忽略 DPI 未變更的快取防呆。 - private void UpdateMinimumSize(bool forceRecalculate = false) - { - float currentDpi = DeviceDpi; - - if (!DialogLayoutHelper.TryBeginDpiLayout(currentDpi, ref _lastAppliedDpi, forceRecalculate)) - { - return; - } - - float scale = currentDpi / AppSettings.BaseDpi; - - UpdateCountLabelMinimumWidths(); - - int desiredMinWidth = (int)(BaseDialogMinWidth * scale); - - Rectangle workArea = Screen.GetWorkingArea(this); - - // 小尺寸螢幕保護:保留 40px 邊界,避免高縮放下最小尺寸超出可視區。 - (int maxFitWidth, int maxFitHeight) = DialogLayoutHelper.GetMaxFitSize(workArea); - - int - // 正常情況至少保留 320px 的可編輯寬度;若工作區本身更窄,則以工作區上限為準。 - minWidth = maxFitWidth >= 320 ? - Math.Clamp(desiredMinWidth, 320, maxFitWidth) : - maxFitWidth; - - int desiredMinHeight = (int)(340 * scale), - minH = Math.Min(desiredMinHeight, maxFitHeight); - - DialogLayoutHelper.ClampFormSize(this, minWidth, minH, maxFitWidth, maxFitHeight, ApplySmartPosition); - } - - /// - /// 保持對話框位於目前螢幕可視範圍內 - /// - private void ApplySmartPosition() - { - if (InputBoxLayoutManager.TryGetClampedLocation(this, out Point clampedLocation)) - { - Location = clampedLocation; - } - } -} \ No newline at end of file +} diff --git a/src/InputBox/Core/Controls/PhraseManagerDialog.A11y.cs b/src/InputBox/Core/Controls/PhraseManagerDialog.A11y.cs new file mode 100644 index 0000000..56addef --- /dev/null +++ b/src/InputBox/Core/Controls/PhraseManagerDialog.A11y.cs @@ -0,0 +1,64 @@ +using InputBox.Core.Configuration; +using InputBox.Core.Extensions; +using System.Diagnostics; + +namespace InputBox.Core.Controls; + +// 阻擋設計工具。 +partial class DesignerBlocker { }; + +/// +/// 片語管理對話框(無障礙輔助功能分部)。 +/// 本分部檔案包含 A11y 廣播成員。 +/// +internal sealed partial class PhraseManagerDialog +{ + /// + /// 內部 A11y 廣播 + /// + /// 要廣播的無障礙訊息文字。 + /// 設為 可中斷目前朗讀(需設定允許中斷)。 + private void AnnounceA11y(string message, bool interrupt = false) + { + if (IsDisposed || + string.IsNullOrEmpty(message)) + { + return; + } + + if (Owner is MainForm mainForm) + { + mainForm.AnnounceA11y(message, interrupt); + } + else + { + long currentId = Interlocked.Increment(ref _a11yDebounceId); + + Task.Run(async () => + { + try + { + await Task.Delay(AppSettings.AudioDuckingDelayMs, _cts?.Token ?? CancellationToken.None); + + if (Interlocked.Read(ref _a11yDebounceId) == currentId && + !IsDisposed && + IsHandleCreated) + { + await this.SafeInvokeAsync(() => + _announcer.Announce(message, interrupt && AppSettings.Current.A11yInterruptEnabled)); + } + } + catch (OperationCanceledException) + { + + } + catch (Exception ex) + { + Debug.WriteLine($"[片語] A11y 廣播失敗:{ex.Message}"); + } + }, + _cts?.Token ?? CancellationToken.None) + .SafeFireAndForget(); + } + } +} diff --git a/src/InputBox/Core/Controls/PhraseManagerDialog.Gamepad.cs b/src/InputBox/Core/Controls/PhraseManagerDialog.Gamepad.cs new file mode 100644 index 0000000..7fc2fbf --- /dev/null +++ b/src/InputBox/Core/Controls/PhraseManagerDialog.Gamepad.cs @@ -0,0 +1,686 @@ +using InputBox.Core.Configuration; +using InputBox.Core.Extensions; +using InputBox.Core.Feedback; +using InputBox.Core.Input; +using InputBox.Core.Services; +using InputBox.Core.Utilities; +using InputBox.Resources; +using System.ComponentModel; +using System.Diagnostics; +using System.Media; + +namespace InputBox.Core.Controls; + +// 阻擋設計工具。 +partial class DesignerBlocker { }; + +/// +/// 片語管理對話框(遊戲控制器事件處理分部)。 +/// 本分部檔案包含遊戲控制器事件訂閱、清單導覽、片語快捷跳轉與按鈕焦點循環等成員。 +/// +internal sealed partial class PhraseManagerDialog +{ + /// + /// 設定控制器實作,並訂閱事件 + /// + [Browsable(false)] + [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public IGamepadController? GamepadController + { + get => _gamepadController; + set + { + if (ReferenceEquals(_gamepadController, value)) + { + return; + } + + UnsubscribeGamepadEvents(); + + _gamepadController = value; + + SubscribeGamepadEvents(); + } + } + + /// + /// 判斷片語管理對話框目前是否應接手控制器輸入。 + /// + /// 若對話框可安全處理控制器操作則回傳 true。 + private bool CanHandleGamepadInput() + { + return Visible && + !IsDisposed && + (ActiveForm == this || + ContainsFocus || + _lstPhrases.Focused || + _lstPhrases.ContainsFocus || + IsButtonAreaFocused()); + } + + /// + /// 控制器向上輸入時在清單項目或按鈕焦點之間移動 + /// + private void HandleUp() => this.SafeInvoke(() => + { + try + { + if (!CanHandleGamepadInput()) + { + return; + } + + // 焦點在按鈕上時,D-Pad 上下切換焦點。 + if (IsButtonAreaFocused()) + { + CycleFocus(forward: false); + return; + } + + if (_lstPhrases.Items.Count > 0) + { + int newIdx = _lstPhrases.SelectedIndex <= 0 ? + _lstPhrases.Items.Count - 1 : + _lstPhrases.SelectedIndex - 1; + + _lstPhrases.SelectedIndex = newIdx; + + FeedbackService.VibrateAsync( + _gamepadController, + VibrationPatterns.CursorMove, + _cts?.Token ?? CancellationToken.None) + .SafeFireAndForget(); + } + } + catch (Exception ex) + { + Debug.WriteLine($"[片語] HandleUp 失敗:{ex.Message}"); + } + }); + + /// + /// 控制器向下輸入時在清單項目或按鈕焦點之間移動 + /// + private void HandleDown() => this.SafeInvoke(() => + { + try + { + if (!CanHandleGamepadInput()) + { + return; + } + + // 焦點在按鈕上時,D-Pad 上下切換焦點。 + if (IsButtonAreaFocused()) + { + CycleFocus(forward: true); + + return; + } + + if (_lstPhrases.Items.Count > 0) + { + int newIdx = _lstPhrases.SelectedIndex >= _lstPhrases.Items.Count - 1 ? + 0 : + _lstPhrases.SelectedIndex + 1; + + _lstPhrases.SelectedIndex = newIdx; + + FeedbackService.VibrateAsync( + _gamepadController, + VibrationPatterns.CursorMove, + _cts?.Token ?? CancellationToken.None) + .SafeFireAndForget(); + } + } + catch (Exception ex) + { + Debug.WriteLine($"[片語] HandleDown 失敗:{ex.Message}"); + } + }); + + /// + /// 控制器 A 鍵依目前焦點執行按鈕、插入片語或新增片語 + /// + private void HandleGamepadA() => this.SafeInvoke(() => + { + try + { + if (!CanHandleGamepadInput()) + { + return; + } + + // 如果焦點在按鈕上,執行該按鈕的動作。 + if (TryGetFocusedButton(out Button? focusedBtn) && + focusedBtn is { Enabled: true }) + { + focusedBtn.PerformClick(); + } + else if (_lstPhrases.Focused && + _lstPhrases.SelectedIndex >= 0) + { + InsertSelectedPhrase(); + } + else + { + AddPhrase(); + } + } + catch (Exception ex) + { + Debug.WriteLine($"[片語] HandleGamepadA 失敗:{ex.Message}"); + } + }); + + /// + /// 控制器取消動作時關閉片語管理對話框 + /// + private void HandleClose() => this.SafeInvoke(() => + { + try + { + if (!CanHandleGamepadInput()) + { + return; + } + + Close(); + } + catch (Exception ex) + { + Debug.WriteLine($"[片語] HandleClose 失敗:{ex.Message}"); + } + }); + + /// + /// 控制器刪除動作時移除目前選取的片語 + /// + private void HandleDelete() => this.SafeInvoke(() => + { + try + { + if (!CanHandleGamepadInput()) + { + return; + } + + DeleteSelectedPhrase(); + } + catch (Exception ex) + { + Debug.WriteLine($"[片語] HandleDelete 失敗:{ex.Message}"); + } + }); + + /// + /// 控制器新增動作時開啟片語建立流程 + /// + private void HandleAdd() => this.SafeInvoke(() => + { + try + { + if (GamescopeSurfaceRecovery.TryRecoverFromGamepadChord( + this, + RecreateHandle, + _gamepadController, + context: "PhraseManagerDialog Gamescope surface recovery 失敗")) + { + return; + } + + if (!CanHandleGamepadInput()) + { + return; + } + + AddPhrase(); + } + catch (Exception ex) + { + Debug.WriteLine($"[片語] HandleAdd 失敗:{ex.Message}"); + } + }); + + /// + /// LB/RB 捷徑切換左側片語清單中的上一筆或下一筆,讓使用者可快速瀏覽而不影響右側按鈕區焦點邏輯。 + /// + /// -1 代表上一筆,+1 代表下一筆。 + private void HandlePhraseShortcutStep(int delta) => this.SafeInvoke(() => + { + try + { + if (!CanHandleGamepadInput() || + _lstPhrases.Items.Count == 0) + { + return; + } + + int currentIndex = _lstPhrases.SelectedIndex < 0 ? + 0 : + _lstPhrases.SelectedIndex; + int targetIndex = Math.Clamp(currentIndex + delta, 0, _lstPhrases.Items.Count - 1); + + _lstPhrases.Focus(); + + if (targetIndex == _lstPhrases.SelectedIndex) + { + FeedbackService.PlaySound(SystemSounds.Beep); + + return; + } + + _lstPhrases.SelectedIndex = targetIndex; + + FeedbackService.VibrateAsync( + _gamepadController, + VibrationPatterns.CursorMove, + _cts?.Token ?? CancellationToken.None) + .SafeFireAndForget(); + } + catch (Exception ex) + { + Debug.WriteLine($"[片語] HandlePhraseShortcutStep 失敗:{ex.Message}"); + } + }); + + /// + /// LT/RT 捷徑直接跳到左側片語清單的第一筆或最後一筆,加快大量片語時的巡覽效率。 + /// + /// true 表示跳到最後一筆;false 表示跳到第一筆。 + private void HandlePhraseShortcutBoundary(bool last) => this.SafeInvoke(() => + { + try + { + if (!CanHandleGamepadInput() || + _lstPhrases.Items.Count == 0) + { + return; + } + + int targetIndex = last ? + _lstPhrases.Items.Count - 1 : + 0; + + _lstPhrases.Focus(); + + if (targetIndex == _lstPhrases.SelectedIndex) + { + FeedbackService.PlaySound(SystemSounds.Beep); + + return; + } + + _lstPhrases.SelectedIndex = targetIndex; + + FeedbackService.VibrateAsync( + _gamepadController, + VibrationPatterns.CursorMove, + _cts?.Token ?? CancellationToken.None) + .SafeFireAndForget(); + } + catch (Exception ex) + { + Debug.WriteLine($"[片語] HandlePhraseShortcutBoundary 失敗:{ex.Message}"); + } + }); + + /// + /// 控制器 LB 捷徑切換到上一個片語。 + /// + private void HandlePreviousPhraseShortcut() => HandlePhraseShortcutStep(-1); + + /// + /// 控制器 RB 捷徑切換到下一個片語。 + /// + private void HandleNextPhraseShortcut() => HandlePhraseShortcutStep(1); + + /// + /// 控制器 LT 捷徑直接跳到第一個片語。 + /// + private void HandleFirstPhraseShortcut() => HandlePhraseShortcutBoundary(last: false); + + /// + /// 控制器 RT 捷徑直接跳到最後一個片語。 + /// + private void HandleLastPhraseShortcut() => HandlePhraseShortcutBoundary(last: true); + + /// + /// 控制器左向輸入時回到清單或將片語上移 + /// + private void HandleMoveUp() => this.SafeInvoke(() => + { + try + { + if (!CanHandleGamepadInput()) + { + return; + } + + // 左方向鍵:若目前在右側按鈕區,回到清單。 + if (IsButtonAreaFocused()) + { + _lstPhrases.Focus(); + + if (_lstPhrases.SelectedIndex >= 0) + { + IReadOnlyList phrases = _phraseService.Phrases; + + if (_lstPhrases.SelectedIndex < phrases.Count) + { + AnnounceA11y( + AppSettings.Current.IsPrivacyMode ? + Strings.Phrase_A11y_Selected_PrivacySafe : + string.Format(Strings.Phrase_A11y_Selected, phrases[_lstPhrases.SelectedIndex].Name), + interrupt: true); + } + } + + FeedbackService.VibrateAsync( + _gamepadController, + VibrationPatterns.CursorMove, + _cts?.Token ?? CancellationToken.None) + .SafeFireAndForget(); + + return; + } + + MoveSelectedPhrase(-1); + } + catch (Exception ex) + { + Debug.WriteLine($"[片語] HandleMoveUp 失敗:{ex.Message}"); + } + }); + + /// + /// 控制器右向輸入時進入按鈕區或將片語下移 + /// + private void HandleMoveDown() => this.SafeInvoke(() => + { + try + { + if (!CanHandleGamepadInput()) + { + return; + } + + // 右方向鍵:由清單進入右側按鈕區;若已在按鈕區則向後循環。 + if (_lstPhrases.Focused || + _lstPhrases.ContainsFocus) + { + FocusFirstActionButtonOrClose(); + + return; + } + + if (IsButtonAreaFocused()) + { + CycleFocus(forward: true); + + return; + } + + MoveSelectedPhrase(1); + } + catch (Exception ex) + { + Debug.WriteLine($"[片語] HandleMoveDown 失敗:{ex.Message}"); + } + }); + + /// + /// 在清單與按鈕之間循環焦點 + /// + /// 是否向前循環焦點 + private void CycleFocus(bool forward) + { + // 建立焦點順序:清單 → 各按鈕(依面板順序)→ 關閉按鈕。 + List focusOrder = [_lstPhrases]; + + foreach (Control ctrl in _flpButtons.Controls) + { + if (ctrl is Button btn && + btn.Enabled && + btn.Visible) + { + focusOrder.Add(btn); + } + } + + if (_btnClose.Enabled && _btnClose.Visible) + { + focusOrder.Add(_btnClose); + } + + if (focusOrder.Count == 0) + { + return; + } + + // 找到目前焦點在列表中的位置。 + int currentIdx = -1; + + for (int i = 0; i < focusOrder.Count; i++) + { + if (focusOrder[i].Focused || + focusOrder[i].ContainsFocus) + { + currentIdx = i; + + break; + } + } + + int nextIdx; + + if (currentIdx < 0) + { + nextIdx = forward ? + 0 : + focusOrder.Count - 1; + } + else + { + nextIdx = forward ? + (currentIdx + 1) % focusOrder.Count : + (currentIdx - 1 + focusOrder.Count) % focusOrder.Count; + } + + focusOrder[nextIdx].Focus(); + + // 播報焦點目標。 + string? name = focusOrder[nextIdx].AccessibleName ?? focusOrder[nextIdx].Text; + + if (!string.IsNullOrEmpty(name)) + { + AnnounceA11y(name, interrupt: true); + } + + FeedbackService.VibrateAsync( + _gamepadController, + VibrationPatterns.CursorMove, + _cts?.Token ?? CancellationToken.None) + .SafeFireAndForget(); + } + + /// + /// 嘗試找出目前在按鈕區取得焦點的按鈕 + /// + /// 輸出的焦點按鈕。 + /// 若找到焦點按鈕則回傳 true。 + private bool TryGetFocusedButton(out Button? focusedBtn) + { + if (_btnClose.Focused || + _btnClose.ContainsFocus) + { + focusedBtn = _btnClose; + + return true; + } + + foreach (Control ctrl in _flpButtons.Controls) + { + if (ctrl is Button btn && + (btn.Focused || btn.ContainsFocus)) + { + focusedBtn = btn; + + return true; + } + } + + focusedBtn = null; + + return false; + } + + /// + /// 判斷目前焦點是否位於按鈕區 + /// + /// 若按鈕區有焦點則回傳 true。 + private bool IsButtonAreaFocused() => TryGetFocusedButton(out _); + + /// + /// 將焦點移至第一個可用動作按鈕,否則移至關閉按鈕。 + /// + private void FocusFirstActionButtonOrClose() + { + foreach (Control ctrl in _flpButtons.Controls) + { + if (ctrl is Button btn && + btn.Enabled && + btn.Visible) + { + btn.Focus(); + + AnnounceA11y(btn.AccessibleName ?? btn.Text, interrupt: true); + + FeedbackService.VibrateAsync( + _gamepadController, + VibrationPatterns.CursorMove, + _cts?.Token ?? CancellationToken.None) + .SafeFireAndForget(); + + return; + } + } + + if (_btnClose.Enabled && + _btnClose.Visible) + { + _btnClose.Focus(); + + AnnounceA11y(_btnClose.AccessibleName ?? _btnClose.Text, interrupt: true); + + FeedbackService.VibrateAsync( + _gamepadController, + VibrationPatterns.CursorMove, + _cts?.Token ?? CancellationToken.None) + .SafeFireAndForget(); + } + } + + /// + /// 控制器連線狀態變更時更新恢復狀態並廣播無障礙訊息。 + /// + /// 連線成功為 ,斷線為 。 + private void HandleGamepadConnectionChanged(bool connected) + { + try + { + if (connected) + { + _gamepadController?.Resume(); + } + + AnnounceA11y(connected ? + string.Format(Strings.A11y_Gamepad_Connected, _gamepadController?.DeviceName) : + string.Format(Strings.A11y_Gamepad_Disconnected, _gamepadController?.DeviceName)); + } + catch (Exception ex) + { + Debug.WriteLine($"[片語] 控制器連線變更處理失敗:{ex.Message}"); + } + } + + /// + /// 訂閱片語管理對話框使用的控制器事件 + /// + private void SubscribeGamepadEvents() + { + try + { + if (_gamepadController != null) + { + GamepadFaceButtonProfile profile = GamepadFaceButtonProfile.GetActiveProfile(); + + _gamepadController.UpPressed += HandleUp; + _gamepadController.UpRepeat += HandleUp; + _gamepadController.DownPressed += HandleDown; + _gamepadController.DownRepeat += HandleDown; + _gamepadController.APressed += profile.ConfirmOnSouth ? HandleGamepadA : HandleClose; + _gamepadController.StartPressed += HandleGamepadA; + _gamepadController.BPressed += profile.ConfirmOnSouth ? HandleClose : HandleGamepadA; + _gamepadController.BackPressed += HandleClose; + _gamepadController.XPressed += HandleDelete; + _gamepadController.YPressed += HandleAdd; + _gamepadController.LeftPressed += HandleMoveUp; + _gamepadController.LeftRepeat += HandleMoveUp; + _gamepadController.RightPressed += HandleMoveDown; + _gamepadController.RightRepeat += HandleMoveDown; + _gamepadController.LeftShoulderPressed += HandlePreviousPhraseShortcut; + _gamepadController.LeftShoulderRepeat += HandlePreviousPhraseShortcut; + _gamepadController.RightShoulderPressed += HandleNextPhraseShortcut; + _gamepadController.RightShoulderRepeat += HandleNextPhraseShortcut; + _gamepadController.LeftTriggerPressed += HandleFirstPhraseShortcut; + _gamepadController.RightTriggerPressed += HandleLastPhraseShortcut; + _gamepadController.ConnectionChanged += HandleGamepadConnectionChanged; + } + } + catch (Exception ex) + { + Debug.WriteLine($"[片語] SubscribeGamepadEvents 失敗:{ex.Message}"); + } + } + + /// + /// 解除片語管理對話框使用的控制器事件 + /// + private void UnsubscribeGamepadEvents() + { + try + { + if (_gamepadController != null) + { + _gamepadController.UpPressed -= HandleUp; + _gamepadController.UpRepeat -= HandleUp; + _gamepadController.DownPressed -= HandleDown; + _gamepadController.DownRepeat -= HandleDown; + _gamepadController.APressed -= HandleGamepadA; + _gamepadController.APressed -= HandleClose; + _gamepadController.StartPressed -= HandleGamepadA; + _gamepadController.BPressed -= HandleGamepadA; + _gamepadController.BPressed -= HandleClose; + _gamepadController.BackPressed -= HandleClose; + _gamepadController.XPressed -= HandleDelete; + _gamepadController.YPressed -= HandleAdd; + _gamepadController.LeftPressed -= HandleMoveUp; + _gamepadController.LeftRepeat -= HandleMoveUp; + _gamepadController.RightPressed -= HandleMoveDown; + _gamepadController.RightRepeat -= HandleMoveDown; + _gamepadController.LeftShoulderPressed -= HandlePreviousPhraseShortcut; + _gamepadController.LeftShoulderRepeat -= HandlePreviousPhraseShortcut; + _gamepadController.RightShoulderPressed -= HandleNextPhraseShortcut; + _gamepadController.RightShoulderRepeat -= HandleNextPhraseShortcut; + _gamepadController.LeftTriggerPressed -= HandleFirstPhraseShortcut; + _gamepadController.RightTriggerPressed -= HandleLastPhraseShortcut; + _gamepadController.ConnectionChanged -= HandleGamepadConnectionChanged; + } + } + catch (Exception ex) + { + Debug.WriteLine($"[片語] UnsubscribeGamepadEvents 失敗:{ex.Message}"); + } + } +} diff --git a/src/InputBox/Core/Controls/PhraseManagerDialog.Layout.cs b/src/InputBox/Core/Controls/PhraseManagerDialog.Layout.cs new file mode 100644 index 0000000..518ae97 --- /dev/null +++ b/src/InputBox/Core/Controls/PhraseManagerDialog.Layout.cs @@ -0,0 +1,339 @@ +using InputBox.Core.Configuration; +using InputBox.Core.Extensions; +using InputBox.Core.Services; +using InputBox.Core.Utilities; +using InputBox.Resources; +using Microsoft.Win32; +using System.Diagnostics; +using System.Runtime.CompilerServices; + +namespace InputBox.Core.Controls; + +// 阻擋設計工具。 +partial class DesignerBlocker { }; + +/// +/// 片語管理對話框(視覺與佈局分部)。 +/// 本分部檔案包含 DPI 與系統偏好變更處理、按鈕建立與字型、最小尺寸、透明度與智慧定位等成員。 +/// +internal sealed partial class PhraseManagerDialog +{ + protected override void OnHandleCreated(EventArgs e) + { + try + { + base.OnHandleCreated(e); + + ApplyFont(); + RefreshList(); + UpdateButtonStates(); + UpdateButtonMinimumSizes(); + UpdateMinimumSize(); + + this.SafeBeginInvoke(() => + { + try + { + UpdateOpacity(); + ApplySmartPosition(); + } + catch (Exception ex) + { + LoggerService.LogException(ex, "PhraseManagerDialog.OnHandleCreated 延遲邏輯失敗"); + + Debug.WriteLine($"[片語] OnHandleCreated 延遲邏輯失敗:{ex.Message}"); + } + }); + + SystemEvents.UserPreferenceChanged -= SystemEvents_UserPreferenceChanged; + SystemEvents.UserPreferenceChanged += SystemEvents_UserPreferenceChanged; + } + catch (Exception ex) + { + LoggerService.LogException(ex, "PhraseManagerDialog.OnHandleCreated 失敗"); + + Debug.WriteLine($"[片語] OnHandleCreated 失敗:{ex.Message}"); + } + } + + protected override void OnDpiChanged(DpiChangedEventArgs e) + { + try + { + base.OnDpiChanged(e); + + this.SafeInvoke(() => + { + try + { + ApplyFont(); + UpdateButtonMinimumSizes(); + UpdateMinimumSize(); + ApplySmartPosition(); + InvalidateAllButtons(); + } + catch (Exception ex) + { + LoggerService.LogException(ex, "PhraseManagerDialog.OnDpiChanged 延遲邏輯失敗"); + + Debug.WriteLine($"[片語] OnDpiChanged 失敗:{ex.Message}"); + } + }); + } + catch (Exception ex) + { + LoggerService.LogException(ex, "PhraseManagerDialog.OnDpiChanged 失敗"); + + Debug.WriteLine($"[片語] OnDpiChanged 失敗:{ex.Message}"); + } + } + + protected override void OnResizeEnd(EventArgs e) + { + base.OnResizeEnd(e); + + ApplySmartPosition(); + } + + /// + /// Handle 銷毀時解除靜態系統事件訂閱,避免遺留參考。 + /// + /// 控制項事件參數。 + protected override void OnHandleDestroyed(EventArgs e) + { + try + { + SystemEvents.UserPreferenceChanged -= SystemEvents_UserPreferenceChanged; + } + finally + { + base.OnHandleDestroyed(e); + } + } + + /// + /// 建立動作按鈕 + /// + /// 按鈕文字 + /// 輔助功能描述 + /// 快捷鍵字元 + /// 已設定樣式、快捷鍵與無障礙屬性的動作按鈕執行個體。 + private static Button CreateActionButton( + string text, + string a11yDesc, + char mnemonic) + { + Button btn = new() + { + Text = ControlExtensions.GetMnemonicText(text, mnemonic), + AutoSize = true, + FlatStyle = FlatStyle.Flat, + AccessibleName = text, + AccessibleDescription = a11yDesc, + AccessibleRole = AccessibleRole.PushButton, + BackColor = Color.Empty, + ForeColor = Color.Empty, + Margin = new Padding(2, 2, 2, 2), + Anchor = AnchorStyles.Left | AnchorStyles.Right + }; + btn.FlatAppearance.BorderSize = 0; + + // 暫存 base description 到 Tag 供後續 AttachEyeTrackerFeedback 使用。 + btn.Tag = a11yDesc; + + return btn; + } + + /// + /// 套用字型(Regular + Bold)並掛載眼動儀擴充 + /// + private void ApplyFont() + { + _a11yFont = MainForm.GetSharedA11yFont(DeviceDpi, FontStyle.Regular); + _boldFont = MainForm.GetSharedA11yFont(DeviceDpi, FontStyle.Bold); + + Font = _a11yFont; + + _lstPhrases.Font = _a11yFont; + + foreach (Control ctrl in _flpButtons.Controls) + { + if (ctrl is Button btn) + { + btn.Font = _a11yFont; + btn.AttachEyeTrackerFeedback( + baseDescription: btn.Tag?.ToString() ?? string.Empty, + regularFont: _a11yFont, + boldFont: _boldFont, + formCt: _cts?.Token ?? CancellationToken.None); + } + } + + _btnClose.Font = _a11yFont; + _btnClose.AttachEyeTrackerFeedback( + baseDescription: Strings.Phrase_A11y_Btn_Close_Desc, + regularFont: _a11yFont, + boldFont: _boldFont, + formCt: _cts?.Token ?? CancellationToken.None); + + _lblPhraseCount.Font = _a11yFont; + UpdatePhraseCountLabelMinimumWidth(); + } + + /// + /// 更新每個按鈕的最小尺寸(抗抖動 + WCAG 2.5.5 AAA 44×44) + /// + private void UpdateButtonMinimumSizes() + { + float scale = DeviceDpi / AppSettings.BaseDpi; + + UpdateSingleButtonMinimumSize(_btnAdd, scale); + UpdateSingleButtonMinimumSize(_btnEdit, scale); + UpdateSingleButtonMinimumSize(_btnDelete, scale); + UpdateSingleButtonMinimumSize(_btnMoveUp, scale); + UpdateSingleButtonMinimumSize(_btnMoveDown, scale); + UpdateSingleButtonMinimumSize(_btnClose, scale); + } + + /// + /// 更新單一按鈕的最小尺寸 + /// + /// 要更新最小尺寸的按鈕。 + /// 目前 DPI 相對於基準 DPI 的縮放比例。 + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private void UpdateSingleButtonMinimumSize(Button btn, float scale) + { + try + { + if (btn.IsDisposed) + { + return; + } + Font boldFont = _boldFont ?? MainForm.GetSharedA11yFont(DeviceDpi, FontStyle.Bold); + + DialogLayoutHelper.UpdateButtonMinimumSize(btn, boldFont, scale, 44, 44, 24, 16); + } + catch (Exception ex) + { + Debug.WriteLine($"[片語] UpdateSingleButtonMinimumSize 失敗:{ex.Message}"); + } + } + + /// + /// 更新最小尺寸(依按鈕面板實際內容高度動態計算) + /// + /// 設為 強制重算,忽略 DPI 快取。 + private void UpdateMinimumSize(bool forceRecalculate = false) + { + float currentDpi = DeviceDpi; + + if (!DialogLayoutHelper.TryBeginDpiLayout(currentDpi, ref _lastAppliedDpi, forceRecalculate)) + { + return; + } + + float scale = currentDpi / AppSettings.BaseDpi; + + UpdatePhraseCountLabelMinimumWidth(); + + // 加上非客戶區(標題列+邊框)高度,MinimumSize 是外框尺寸。 + // OnHandleCreated 時 Height == ClientSize.Height(非客戶區尚未就緒), + // 故以 SystemInformation 估算作為最低保底值。 + int nonClientH = DialogLayoutHelper.GetEstimatedNonClientHeight(this); + + // 以主版面實際偏好尺寸作為基準,避免最後一顆按鈕在 row 0 被裁切。 + _tlpMain.PerformLayout(); + + Size preferred = _tlpMain.GetPreferredSize(Size.Empty); + + int desiredMinWidth = (int)(BaseDialogMinWidth * scale), + minW = Math.Max(desiredMinWidth, preferred.Width + Padding.Horizontal), + baseClientH = Math.Max( + (int)(300 * scale) - nonClientH, + preferred.Height + Padding.Vertical + (int)(8 * scale)), + minH = baseClientH + nonClientH; + + Rectangle workArea = Screen.GetWorkingArea(this); + + (int maxFitW, int maxFitH) = DialogLayoutHelper.GetMaxFitSize(workArea); + + minW = Math.Min(minW, maxFitW); + minH = Math.Min(minH, maxFitH); + + DialogLayoutHelper.ClampFormSize(this, minW, minH, maxFitW, maxFitH); + } + + /// + /// 更新視窗不透明度 + /// + private void UpdateOpacity() + { + if (SystemInformation.HighContrast) + { + Opacity = 1.0; + + return; + } + + Opacity = AppSettings.Current.WindowOpacity; + } + + /// + /// 智慧定位 + /// + private void ApplySmartPosition() + { + if (InputBoxLayoutManager.TryGetClampedLocation(this, out Point clampedLocation)) + { + Location = clampedLocation; + } + } + + /// + /// 強制重繪所有按鈕 + /// + private void InvalidateAllButtons() + { + _btnAdd.Invalidate(); + _btnEdit.Invalidate(); + _btnDelete.Invalidate(); + _btnMoveUp.Invalidate(); + _btnMoveDown.Invalidate(); + _btnClose.Invalidate(); + } + + /// + /// 系統偏好設定變更時同步更新尺寸、定位與按鈕視覺。 + /// + /// 事件來源。 + /// 系統偏好設定事件參數。 + private void SystemEvents_UserPreferenceChanged(object sender, UserPreferenceChangedEventArgs e) + { + try + { + if (e.Category is UserPreferenceCategory.Accessibility or + UserPreferenceCategory.Color or + UserPreferenceCategory.General) + { + this.SafeInvoke(() => + { + try + { + UpdateButtonMinimumSizes(); + UpdateMinimumSize(forceRecalculate: true); + ApplySmartPosition(); + InvalidateAllButtons(); + } + catch (Exception ex) + { + Debug.WriteLine($"[片語] SystemEvents 更新失敗:{ex.Message}"); + } + }); + } + } + catch (Exception ex) + { + Debug.WriteLine($"[片語] SystemEvents 處理失敗:{ex.Message}"); + } + } +} diff --git a/src/InputBox/Core/Controls/PhraseManagerDialog.Phrases.cs b/src/InputBox/Core/Controls/PhraseManagerDialog.Phrases.cs new file mode 100644 index 0000000..0978560 --- /dev/null +++ b/src/InputBox/Core/Controls/PhraseManagerDialog.Phrases.cs @@ -0,0 +1,408 @@ +using InputBox.Core.Configuration; +using InputBox.Core.Extensions; +using InputBox.Core.Feedback; +using InputBox.Core.Services; +using InputBox.Resources; +using System.Diagnostics; +using System.Media; + +namespace InputBox.Core.Controls; + +// 阻擋設計工具。 +partial class DesignerBlocker { }; + +/// +/// 片語管理對話框(片語清單操作分部)。 +/// 本分部檔案包含片語清單重新整理、新增、編輯、刪除、排序與插入等成員。 +/// +internal sealed partial class PhraseManagerDialog +{ + /// + /// 重新載入清單內容 + /// + private void RefreshList() + { + int selectedIndex = _lstPhrases.SelectedIndex; + + _lstPhrases.BeginUpdate(); + + try + { + _lstPhrases.Items.Clear(); + + foreach (PhraseService.PhraseEntry entry in _phraseService.Phrases) + { + _lstPhrases.Items.Add(entry.Name); + } + } + finally + { + _lstPhrases.EndUpdate(); + } + + // 還原選取位置。 + if (selectedIndex >= 0 && selectedIndex < _lstPhrases.Items.Count) + { + _lstPhrases.SelectedIndex = selectedIndex; + } + else if (_lstPhrases.Items.Count > 0) + { + _lstPhrases.SelectedIndex = Math.Min(selectedIndex, _lstPhrases.Items.Count - 1); + } + + UpdateButtonStates(); + UpdatePhraseCountHint(); + } + + /// + /// 更新按鈕啟用狀態 + /// + private void UpdateButtonStates() + { + bool hasSelection = _lstPhrases.SelectedIndex >= 0, + canAdd = _phraseService.Count < AppSettings.MaxPhraseCount; + + _btnAdd.Enabled = canAdd; + _btnEdit.Enabled = hasSelection; + _btnDelete.Enabled = hasSelection; + _btnMoveUp.Enabled = hasSelection && + _lstPhrases.SelectedIndex > 0; + _btnMoveDown.Enabled = hasSelection && + _lstPhrases.SelectedIndex < _lstPhrases.Items.Count - 1; + + UpdatePhraseCountHint(); + } + + /// + /// 更新片語數量提示(例如:片語數量:12/50)。 + /// + private void UpdatePhraseCountHint() + { + if (_lblPhraseCount == null || + _lblPhraseCount.IsDisposed) + { + return; + } + + UpdatePhraseCountLabelMinimumWidth(); + + string countText = $"{Strings.Phrase_A11y_List_Name}:{_phraseService.Count}/{AppSettings.MaxPhraseCount}"; + + _lblPhraseCount.Text = countText; + _lblPhraseCount.AccessibleName = countText; + _lblPhraseCount.AccessibleDescription = + $"{Strings.Phrase_A11y_List_Desc} {countText}"; + + if (SystemInformation.HighContrast) + { + _lblPhraseCount.ForeColor = Color.Empty; + + return; + } + + bool isNearLimit = _phraseService.Count >= AppSettings.MaxPhraseCount - 5; + + _lblPhraseCount.ForeColor = isNearLimit ? + Color.DarkOrange : + Color.Empty; + } + + /// + /// 預先鎖定片語數量提示標籤的寬度,避免數字變化時擠壓旁邊元件。 + /// + private void UpdatePhraseCountLabelMinimumWidth() + { + if (_lblPhraseCount == null || + _lblPhraseCount.IsDisposed) + { + return; + } + + string widestText = $"{Strings.Phrase_A11y_List_Name}:{AppSettings.MaxPhraseCount}/{AppSettings.MaxPhraseCount}"; + Size measured = TextRenderer.MeasureText( + widestText, + _lblPhraseCount.Font, + Size.Empty, + TextFormatFlags.NoPadding | TextFormatFlags.SingleLine); + + int horizontalPadding = (int)Math.Ceiling(12 * (DeviceDpi / AppSettings.BaseDpi)); + int width = Math.Max(_lblPhraseCount.MinimumSize.Width, measured.Width + horizontalPadding); + int height = Math.Max(_lblPhraseCount.MinimumSize.Height, measured.Height + 2); + + _lblPhraseCount.AutoSize = false; + _lblPhraseCount.MinimumSize = new Size(width, height); + _lblPhraseCount.Size = new Size(Math.Max(_lblPhraseCount.Width, width), height); + } + + /// + /// 新增片語 + /// + private void AddPhrase() + { + if (_phraseService.Count >= AppSettings.MaxPhraseCount) + { + FeedbackService.PlaySound(SystemSounds.Beep); + + AnnounceA11y(Strings.Phrase_A11y_Full); + + return; + } + + // 暫時解除本對話框的控制器事件,防止子對話框開啟期間事件同時觸發。 + UnsubscribeGamepadEvents(); + + try + { + using PhraseEditDialog dlg = new(string.Empty, string.Empty, _a11yFont) + { + GamepadController = _gamepadController + }; + dlg.StartPosition = FormStartPosition.Manual; + dlg.Location = new Point(Left + 20, Top + 20); + + if (dlg.ShowDialog(this) == DialogResult.OK && + !string.IsNullOrWhiteSpace(dlg.PhraseName) && + !string.IsNullOrWhiteSpace(dlg.PhraseContent)) + { + _phraseService.Add(dlg.PhraseName, dlg.PhraseContent); + + RefreshList(); + + _lstPhrases.SelectedIndex = _lstPhrases.Items.Count - 1; + + FeedbackService.PlaySound(SystemSounds.Asterisk); + + AnnounceA11y(AppSettings.Current.IsPrivacyMode ? + Strings.Phrase_A11y_Added_PrivacySafe : + string.Format(Strings.Phrase_A11y_Added, dlg.PhraseName)); + } + } + finally + { + // 子對話框關閉後重新訂閱控制器事件。 + SubscribeGamepadEvents(); + + // 防止 Owner/Child 失焦競態導致控制器殘留在 Pause 狀態。 + if (ActiveForm == this) + { + try + { + _gamepadController?.Resume(); + } + catch (Exception ex) + { + Debug.WriteLine($"[片語] AddPhrase Resume 失敗:{ex.Message}"); + } + } + } + } + + /// + /// 編輯選取的片語 + /// + private void EditSelectedPhrase() + { + int idx = _lstPhrases.SelectedIndex; + + if (idx < 0) + { + return; + } + + IReadOnlyList phrases = _phraseService.Phrases; + + if (idx >= phrases.Count) + { + return; + } + + PhraseService.PhraseEntry entry = phrases[idx]; + + // 暫時解除本對話框的控制器事件,防止子對話框開啟期間事件同時觸發。 + UnsubscribeGamepadEvents(); + + try + { + using PhraseEditDialog dlg = new(entry.Name, entry.Content, _a11yFont) + { + GamepadController = _gamepadController + }; + dlg.StartPosition = FormStartPosition.Manual; + dlg.Location = new Point(Left + 20, Top + 20); + + if (dlg.ShowDialog(this) == DialogResult.OK && + !string.IsNullOrWhiteSpace(dlg.PhraseName) && + !string.IsNullOrWhiteSpace(dlg.PhraseContent)) + { + _phraseService.Update(idx, dlg.PhraseName, dlg.PhraseContent); + + RefreshList(); + + FeedbackService.PlaySound(SystemSounds.Asterisk); + + AnnounceA11y(AppSettings.Current.IsPrivacyMode ? + Strings.Phrase_A11y_Updated_PrivacySafe : + string.Format(Strings.Phrase_A11y_Updated, dlg.PhraseName)); + } + } + finally + { + // 子對話框關閉後重新訂閱控制器事件。 + SubscribeGamepadEvents(); + + // 防止 Owner/Child 失焦競態導致控制器殘留在 Pause 狀態。 + if (ActiveForm == this) + { + try + { + _gamepadController?.Resume(); + } + catch (Exception ex) + { + Debug.WriteLine($"[片語] EditSelectedPhrase Resume 失敗:{ex.Message}"); + } + } + } + } + + /// + /// 刪除選取的片語 + /// + private void DeleteSelectedPhrase() + { + int idx = _lstPhrases.SelectedIndex; + + if (idx < 0) + { + return; + } + + IReadOnlyList phrases = _phraseService.Phrases; + + if (idx >= phrases.Count) + { + return; + } + + string name = phrases[idx].Name; + + // 暫時解除本對話框的控制器事件,防止子對話框開啟期間事件同時觸發。 + UnsubscribeGamepadEvents(); + + DialogResult confirmResult; + + try + { + // 確認刪除對話框(與應用程式其他訊息框使用相同風格) + confirmResult = GamepadMessageBox.Show( + this, + string.Format(Strings.Msg_ConfirmDeletePhrase, name), + Strings.Wrn_Title, + MessageBoxButtons.YesNo, + MessageBoxIcon.Warning, + gamepad: _gamepadController); + } + finally + { + // 子對話框關閉後重新訂閱控制器事件。 + SubscribeGamepadEvents(); + + // 防止 Owner/Child 失焦競態導致控制器殘留在 Pause 狀態。 + if (ActiveForm == this) + { + try + { + _gamepadController?.Resume(); + } + catch (Exception ex) + { + Debug.WriteLine($"[片語] DeleteSelectedPhrase Resume 失敗:{ex.Message}"); + } + } + } + + if (confirmResult != DialogResult.Yes) + { + return; + } + + _phraseService.Remove(idx); + + RefreshList(); + + FeedbackService.PlaySound(SystemSounds.Asterisk); + + FeedbackService.VibrateAsync( + _gamepadController, + VibrationPatterns.ClearInput, + _cts?.Token ?? CancellationToken.None) + .SafeFireAndForget(); + + AnnounceA11y(AppSettings.Current.IsPrivacyMode ? + Strings.Phrase_A11y_Deleted_PrivacySafe : + string.Format(Strings.Phrase_A11y_Deleted, name)); + } + + /// + /// 移動選取的片語 + /// + /// -1 為上移,1 為下移 + private void MoveSelectedPhrase(int direction) + { + int idx = _lstPhrases.SelectedIndex; + + if (idx < 0) + { + return; + } + + bool success = direction < 0 ? + _phraseService.MoveUp(idx) : + _phraseService.MoveDown(idx); + + if (success) + { + RefreshList(); + + _lstPhrases.SelectedIndex = idx + direction; + + FeedbackService.VibrateAsync( + _gamepadController, + VibrationPatterns.CursorMove, + _cts?.Token ?? CancellationToken.None) + .SafeFireAndForget(); + + AnnounceA11y(string.Format(Strings.Phrase_A11y_Moved, _lstPhrases.SelectedIndex + 1)); + } + else + { + FeedbackService.PlaySound(SystemSounds.Beep); + } + } + + /// + /// 插入選取的片語(設定結果並關閉) + /// + private void InsertSelectedPhrase() + { + int idx = _lstPhrases.SelectedIndex; + + if (idx < 0) + { + return; + } + + IReadOnlyList phrases = _phraseService.Phrases; + + if (idx >= phrases.Count) + { + return; + } + + SelectedPhraseContent = phrases[idx].Content; + + DialogResult = DialogResult.OK; + + Close(); + } +} diff --git a/src/InputBox/Core/Controls/PhraseManagerDialog.cs b/src/InputBox/Core/Controls/PhraseManagerDialog.cs index fceb5d6..77350d8 100644 --- a/src/InputBox/Core/Controls/PhraseManagerDialog.cs +++ b/src/InputBox/Core/Controls/PhraseManagerDialog.cs @@ -1,15 +1,10 @@ using InputBox.Core.Configuration; using InputBox.Core.Extensions; -using InputBox.Core.Feedback; using InputBox.Core.Input; using InputBox.Core.Services; -using InputBox.Core.Utilities; using InputBox.Resources; using Microsoft.Win32; -using System.ComponentModel; using System.Diagnostics; -using System.Media; -using System.Runtime.CompilerServices; namespace InputBox.Core.Controls; @@ -20,7 +15,7 @@ partial class DesignerBlocker { }; /// 片語管理對話框 /// 提供片語的新增、編輯、刪除、排序功能,支援遊戲控制器操作、深色/淺色模式與無障礙。 /// -internal sealed class PhraseManagerDialog : Form +internal sealed partial class PhraseManagerDialog : Form { /// /// 片語管理視窗的基準最小寬度(96 DPI) @@ -122,29 +117,6 @@ internal sealed class PhraseManagerDialog : Form /// public string? SelectedPhraseContent { get; private set; } - /// - /// 設定控制器實作,並訂閱事件 - /// - [Browsable(false)] - [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] - public IGamepadController? GamepadController - { - get => _gamepadController; - set - { - if (ReferenceEquals(_gamepadController, value)) - { - return; - } - - UnsubscribeGamepadEvents(); - - _gamepadController = value; - - SubscribeGamepadEvents(); - } - } - /// /// 初始化片語管理對話框 /// @@ -523,76 +495,6 @@ await this.SafeInvokeAsync(() => }; } - protected override void OnHandleCreated(EventArgs e) - { - try - { - base.OnHandleCreated(e); - - ApplyFont(); - RefreshList(); - UpdateButtonStates(); - UpdateButtonMinimumSizes(); - UpdateMinimumSize(); - - this.SafeBeginInvoke(() => - { - try - { - UpdateOpacity(); - ApplySmartPosition(); - } - catch (Exception ex) - { - LoggerService.LogException(ex, "PhraseManagerDialog.OnHandleCreated 延遲邏輯失敗"); - - Debug.WriteLine($"[片語] OnHandleCreated 延遲邏輯失敗:{ex.Message}"); - } - }); - - SystemEvents.UserPreferenceChanged -= SystemEvents_UserPreferenceChanged; - SystemEvents.UserPreferenceChanged += SystemEvents_UserPreferenceChanged; - } - catch (Exception ex) - { - LoggerService.LogException(ex, "PhraseManagerDialog.OnHandleCreated 失敗"); - - Debug.WriteLine($"[片語] OnHandleCreated 失敗:{ex.Message}"); - } - } - - protected override void OnDpiChanged(DpiChangedEventArgs e) - { - try - { - base.OnDpiChanged(e); - - this.SafeInvoke(() => - { - try - { - ApplyFont(); - UpdateButtonMinimumSizes(); - UpdateMinimumSize(); - ApplySmartPosition(); - InvalidateAllButtons(); - } - catch (Exception ex) - { - LoggerService.LogException(ex, "PhraseManagerDialog.OnDpiChanged 延遲邏輯失敗"); - - Debug.WriteLine($"[片語] OnDpiChanged 失敗:{ex.Message}"); - } - }); - } - catch (Exception ex) - { - LoggerService.LogException(ex, "PhraseManagerDialog.OnDpiChanged 失敗"); - - Debug.WriteLine($"[片語] OnDpiChanged 失敗:{ex.Message}"); - } - } - protected override void OnShown(EventArgs e) { base.OnShown(e); @@ -613,13 +515,6 @@ protected override void OnShown(EventArgs e) } } - protected override void OnResizeEnd(EventArgs e) - { - base.OnResizeEnd(e); - - ApplySmartPosition(); - } - protected override bool ProcessCmdKey(ref Message msg, Keys keyData) { const int WM_KEYDOWN = 0x0100; @@ -672,1342 +567,4 @@ protected override void OnFormClosing(FormClosingEventArgs e) Debug.WriteLine($"[片語] OnFormClosing 失敗:{ex.Message}"); } } - - /// - /// Handle 銷毀時解除靜態系統事件訂閱,避免遺留參考。 - /// - /// 控制項事件參數。 - protected override void OnHandleDestroyed(EventArgs e) - { - try - { - SystemEvents.UserPreferenceChanged -= SystemEvents_UserPreferenceChanged; - } - finally - { - base.OnHandleDestroyed(e); - } - } - - #region 清單操作 - - /// - /// 重新載入清單內容 - /// - private void RefreshList() - { - int selectedIndex = _lstPhrases.SelectedIndex; - - _lstPhrases.BeginUpdate(); - - try - { - _lstPhrases.Items.Clear(); - - foreach (PhraseService.PhraseEntry entry in _phraseService.Phrases) - { - _lstPhrases.Items.Add(entry.Name); - } - } - finally - { - _lstPhrases.EndUpdate(); - } - - // 還原選取位置。 - if (selectedIndex >= 0 && selectedIndex < _lstPhrases.Items.Count) - { - _lstPhrases.SelectedIndex = selectedIndex; - } - else if (_lstPhrases.Items.Count > 0) - { - _lstPhrases.SelectedIndex = Math.Min(selectedIndex, _lstPhrases.Items.Count - 1); - } - - UpdateButtonStates(); - UpdatePhraseCountHint(); - } - - /// - /// 更新按鈕啟用狀態 - /// - private void UpdateButtonStates() - { - bool hasSelection = _lstPhrases.SelectedIndex >= 0, - canAdd = _phraseService.Count < AppSettings.MaxPhraseCount; - - _btnAdd.Enabled = canAdd; - _btnEdit.Enabled = hasSelection; - _btnDelete.Enabled = hasSelection; - _btnMoveUp.Enabled = hasSelection && - _lstPhrases.SelectedIndex > 0; - _btnMoveDown.Enabled = hasSelection && - _lstPhrases.SelectedIndex < _lstPhrases.Items.Count - 1; - - UpdatePhraseCountHint(); - } - - /// - /// 更新片語數量提示(例如:片語數量:12/50)。 - /// - private void UpdatePhraseCountHint() - { - if (_lblPhraseCount == null || - _lblPhraseCount.IsDisposed) - { - return; - } - - UpdatePhraseCountLabelMinimumWidth(); - - string countText = $"{Strings.Phrase_A11y_List_Name}:{_phraseService.Count}/{AppSettings.MaxPhraseCount}"; - - _lblPhraseCount.Text = countText; - _lblPhraseCount.AccessibleName = countText; - _lblPhraseCount.AccessibleDescription = - $"{Strings.Phrase_A11y_List_Desc} {countText}"; - - if (SystemInformation.HighContrast) - { - _lblPhraseCount.ForeColor = Color.Empty; - - return; - } - - bool isNearLimit = _phraseService.Count >= AppSettings.MaxPhraseCount - 5; - - _lblPhraseCount.ForeColor = isNearLimit ? - Color.DarkOrange : - Color.Empty; - } - - /// - /// 預先鎖定片語數量提示標籤的寬度,避免數字變化時擠壓旁邊元件。 - /// - private void UpdatePhraseCountLabelMinimumWidth() - { - if (_lblPhraseCount == null || - _lblPhraseCount.IsDisposed) - { - return; - } - - string widestText = $"{Strings.Phrase_A11y_List_Name}:{AppSettings.MaxPhraseCount}/{AppSettings.MaxPhraseCount}"; - Size measured = TextRenderer.MeasureText( - widestText, - _lblPhraseCount.Font, - Size.Empty, - TextFormatFlags.NoPadding | TextFormatFlags.SingleLine); - - int horizontalPadding = (int)Math.Ceiling(12 * (DeviceDpi / AppSettings.BaseDpi)); - int width = Math.Max(_lblPhraseCount.MinimumSize.Width, measured.Width + horizontalPadding); - int height = Math.Max(_lblPhraseCount.MinimumSize.Height, measured.Height + 2); - - _lblPhraseCount.AutoSize = false; - _lblPhraseCount.MinimumSize = new Size(width, height); - _lblPhraseCount.Size = new Size(Math.Max(_lblPhraseCount.Width, width), height); - } - - /// - /// 新增片語 - /// - private void AddPhrase() - { - if (_phraseService.Count >= AppSettings.MaxPhraseCount) - { - FeedbackService.PlaySound(SystemSounds.Beep); - - AnnounceA11y(Strings.Phrase_A11y_Full); - - return; - } - - // 暫時解除本對話框的控制器事件,防止子對話框開啟期間事件同時觸發。 - UnsubscribeGamepadEvents(); - - try - { - using PhraseEditDialog dlg = new(string.Empty, string.Empty, _a11yFont) - { - GamepadController = _gamepadController - }; - dlg.StartPosition = FormStartPosition.Manual; - dlg.Location = new Point(Left + 20, Top + 20); - - if (dlg.ShowDialog(this) == DialogResult.OK && - !string.IsNullOrWhiteSpace(dlg.PhraseName) && - !string.IsNullOrWhiteSpace(dlg.PhraseContent)) - { - _phraseService.Add(dlg.PhraseName, dlg.PhraseContent); - - RefreshList(); - - _lstPhrases.SelectedIndex = _lstPhrases.Items.Count - 1; - - FeedbackService.PlaySound(SystemSounds.Asterisk); - - AnnounceA11y(AppSettings.Current.IsPrivacyMode ? - Strings.Phrase_A11y_Added_PrivacySafe : - string.Format(Strings.Phrase_A11y_Added, dlg.PhraseName)); - } - } - finally - { - // 子對話框關閉後重新訂閱控制器事件。 - SubscribeGamepadEvents(); - - // 防止 Owner/Child 失焦競態導致控制器殘留在 Pause 狀態。 - if (ActiveForm == this) - { - try - { - _gamepadController?.Resume(); - } - catch (Exception ex) - { - Debug.WriteLine($"[片語] AddPhrase Resume 失敗:{ex.Message}"); - } - } - } - } - - /// - /// 編輯選取的片語 - /// - private void EditSelectedPhrase() - { - int idx = _lstPhrases.SelectedIndex; - - if (idx < 0) - { - return; - } - - IReadOnlyList phrases = _phraseService.Phrases; - - if (idx >= phrases.Count) - { - return; - } - - PhraseService.PhraseEntry entry = phrases[idx]; - - // 暫時解除本對話框的控制器事件,防止子對話框開啟期間事件同時觸發。 - UnsubscribeGamepadEvents(); - - try - { - using PhraseEditDialog dlg = new(entry.Name, entry.Content, _a11yFont) - { - GamepadController = _gamepadController - }; - dlg.StartPosition = FormStartPosition.Manual; - dlg.Location = new Point(Left + 20, Top + 20); - - if (dlg.ShowDialog(this) == DialogResult.OK && - !string.IsNullOrWhiteSpace(dlg.PhraseName) && - !string.IsNullOrWhiteSpace(dlg.PhraseContent)) - { - _phraseService.Update(idx, dlg.PhraseName, dlg.PhraseContent); - - RefreshList(); - - FeedbackService.PlaySound(SystemSounds.Asterisk); - - AnnounceA11y(AppSettings.Current.IsPrivacyMode ? - Strings.Phrase_A11y_Updated_PrivacySafe : - string.Format(Strings.Phrase_A11y_Updated, dlg.PhraseName)); - } - } - finally - { - // 子對話框關閉後重新訂閱控制器事件。 - SubscribeGamepadEvents(); - - // 防止 Owner/Child 失焦競態導致控制器殘留在 Pause 狀態。 - if (ActiveForm == this) - { - try - { - _gamepadController?.Resume(); - } - catch (Exception ex) - { - Debug.WriteLine($"[片語] EditSelectedPhrase Resume 失敗:{ex.Message}"); - } - } - } - } - - /// - /// 刪除選取的片語 - /// - private void DeleteSelectedPhrase() - { - int idx = _lstPhrases.SelectedIndex; - - if (idx < 0) - { - return; - } - - IReadOnlyList phrases = _phraseService.Phrases; - - if (idx >= phrases.Count) - { - return; - } - - string name = phrases[idx].Name; - - // 暫時解除本對話框的控制器事件,防止子對話框開啟期間事件同時觸發。 - UnsubscribeGamepadEvents(); - - DialogResult confirmResult; - - try - { - // 確認刪除對話框(與應用程式其他訊息框使用相同風格) - confirmResult = GamepadMessageBox.Show( - this, - string.Format(Strings.Msg_ConfirmDeletePhrase, name), - Strings.Wrn_Title, - MessageBoxButtons.YesNo, - MessageBoxIcon.Warning, - gamepad: _gamepadController); - } - finally - { - // 子對話框關閉後重新訂閱控制器事件。 - SubscribeGamepadEvents(); - - // 防止 Owner/Child 失焦競態導致控制器殘留在 Pause 狀態。 - if (ActiveForm == this) - { - try - { - _gamepadController?.Resume(); - } - catch (Exception ex) - { - Debug.WriteLine($"[片語] DeleteSelectedPhrase Resume 失敗:{ex.Message}"); - } - } - } - - if (confirmResult != DialogResult.Yes) - { - return; - } - - _phraseService.Remove(idx); - - RefreshList(); - - FeedbackService.PlaySound(SystemSounds.Asterisk); - - FeedbackService.VibrateAsync( - _gamepadController, - VibrationPatterns.ClearInput, - _cts?.Token ?? CancellationToken.None) - .SafeFireAndForget(); - - AnnounceA11y(AppSettings.Current.IsPrivacyMode ? - Strings.Phrase_A11y_Deleted_PrivacySafe : - string.Format(Strings.Phrase_A11y_Deleted, name)); - } - - /// - /// 移動選取的片語 - /// - /// -1 為上移,1 為下移 - private void MoveSelectedPhrase(int direction) - { - int idx = _lstPhrases.SelectedIndex; - - if (idx < 0) - { - return; - } - - bool success = direction < 0 ? - _phraseService.MoveUp(idx) : - _phraseService.MoveDown(idx); - - if (success) - { - RefreshList(); - - _lstPhrases.SelectedIndex = idx + direction; - - FeedbackService.VibrateAsync( - _gamepadController, - VibrationPatterns.CursorMove, - _cts?.Token ?? CancellationToken.None) - .SafeFireAndForget(); - - AnnounceA11y(string.Format(Strings.Phrase_A11y_Moved, _lstPhrases.SelectedIndex + 1)); - } - else - { - FeedbackService.PlaySound(SystemSounds.Beep); - } - } - - /// - /// 插入選取的片語(設定結果並關閉) - /// - private void InsertSelectedPhrase() - { - int idx = _lstPhrases.SelectedIndex; - - if (idx < 0) - { - return; - } - - IReadOnlyList phrases = _phraseService.Phrases; - - if (idx >= phrases.Count) - { - return; - } - - SelectedPhraseContent = phrases[idx].Content; - - DialogResult = DialogResult.OK; - - Close(); - } - - #endregion - - #region 控制器事件處理 - - /// - /// 判斷片語管理對話框目前是否應接手控制器輸入。 - /// - /// 若對話框可安全處理控制器操作則回傳 true。 - private bool CanHandleGamepadInput() - { - return Visible && - !IsDisposed && - (ActiveForm == this || - ContainsFocus || - _lstPhrases.Focused || - _lstPhrases.ContainsFocus || - IsButtonAreaFocused()); - } - - /// - /// 控制器向上輸入時在清單項目或按鈕焦點之間移動 - /// - private void HandleUp() => this.SafeInvoke(() => - { - try - { - if (!CanHandleGamepadInput()) - { - return; - } - - // 焦點在按鈕上時,D-Pad 上下切換焦點。 - if (IsButtonAreaFocused()) - { - CycleFocus(forward: false); - return; - } - - if (_lstPhrases.Items.Count > 0) - { - int newIdx = _lstPhrases.SelectedIndex <= 0 ? - _lstPhrases.Items.Count - 1 : - _lstPhrases.SelectedIndex - 1; - - _lstPhrases.SelectedIndex = newIdx; - - FeedbackService.VibrateAsync( - _gamepadController, - VibrationPatterns.CursorMove, - _cts?.Token ?? CancellationToken.None) - .SafeFireAndForget(); - } - } - catch (Exception ex) - { - Debug.WriteLine($"[片語] HandleUp 失敗:{ex.Message}"); - } - }); - - /// - /// 控制器向下輸入時在清單項目或按鈕焦點之間移動 - /// - private void HandleDown() => this.SafeInvoke(() => - { - try - { - if (!CanHandleGamepadInput()) - { - return; - } - - // 焦點在按鈕上時,D-Pad 上下切換焦點。 - if (IsButtonAreaFocused()) - { - CycleFocus(forward: true); - - return; - } - - if (_lstPhrases.Items.Count > 0) - { - int newIdx = _lstPhrases.SelectedIndex >= _lstPhrases.Items.Count - 1 ? - 0 : - _lstPhrases.SelectedIndex + 1; - - _lstPhrases.SelectedIndex = newIdx; - - FeedbackService.VibrateAsync( - _gamepadController, - VibrationPatterns.CursorMove, - _cts?.Token ?? CancellationToken.None) - .SafeFireAndForget(); - } - } - catch (Exception ex) - { - Debug.WriteLine($"[片語] HandleDown 失敗:{ex.Message}"); - } - }); - - /// - /// 控制器 A 鍵依目前焦點執行按鈕、插入片語或新增片語 - /// - private void HandleGamepadA() => this.SafeInvoke(() => - { - try - { - if (!CanHandleGamepadInput()) - { - return; - } - - // 如果焦點在按鈕上,執行該按鈕的動作。 - if (TryGetFocusedButton(out Button? focusedBtn) && - focusedBtn is { Enabled: true }) - { - focusedBtn.PerformClick(); - } - else if (_lstPhrases.Focused && - _lstPhrases.SelectedIndex >= 0) - { - InsertSelectedPhrase(); - } - else - { - AddPhrase(); - } - } - catch (Exception ex) - { - Debug.WriteLine($"[片語] HandleGamepadA 失敗:{ex.Message}"); - } - }); - - /// - /// 控制器取消動作時關閉片語管理對話框 - /// - private void HandleClose() => this.SafeInvoke(() => - { - try - { - if (!CanHandleGamepadInput()) - { - return; - } - - Close(); - } - catch (Exception ex) - { - Debug.WriteLine($"[片語] HandleClose 失敗:{ex.Message}"); - } - }); - - /// - /// 控制器刪除動作時移除目前選取的片語 - /// - private void HandleDelete() => this.SafeInvoke(() => - { - try - { - if (!CanHandleGamepadInput()) - { - return; - } - - DeleteSelectedPhrase(); - } - catch (Exception ex) - { - Debug.WriteLine($"[片語] HandleDelete 失敗:{ex.Message}"); - } - }); - - /// - /// 控制器新增動作時開啟片語建立流程 - /// - private void HandleAdd() => this.SafeInvoke(() => - { - try - { - if (GamescopeSurfaceRecovery.TryRecoverFromGamepadChord( - this, - RecreateHandle, - _gamepadController, - context: "PhraseManagerDialog Gamescope surface recovery 失敗")) - { - return; - } - - if (!CanHandleGamepadInput()) - { - return; - } - - AddPhrase(); - } - catch (Exception ex) - { - Debug.WriteLine($"[片語] HandleAdd 失敗:{ex.Message}"); - } - }); - - /// - /// LB/RB 捷徑切換左側片語清單中的上一筆或下一筆,讓使用者可快速瀏覽而不影響右側按鈕區焦點邏輯。 - /// - /// -1 代表上一筆,+1 代表下一筆。 - private void HandlePhraseShortcutStep(int delta) => this.SafeInvoke(() => - { - try - { - if (!CanHandleGamepadInput() || - _lstPhrases.Items.Count == 0) - { - return; - } - - int currentIndex = _lstPhrases.SelectedIndex < 0 ? - 0 : - _lstPhrases.SelectedIndex; - int targetIndex = Math.Clamp(currentIndex + delta, 0, _lstPhrases.Items.Count - 1); - - _lstPhrases.Focus(); - - if (targetIndex == _lstPhrases.SelectedIndex) - { - FeedbackService.PlaySound(SystemSounds.Beep); - - return; - } - - _lstPhrases.SelectedIndex = targetIndex; - - FeedbackService.VibrateAsync( - _gamepadController, - VibrationPatterns.CursorMove, - _cts?.Token ?? CancellationToken.None) - .SafeFireAndForget(); - } - catch (Exception ex) - { - Debug.WriteLine($"[片語] HandlePhraseShortcutStep 失敗:{ex.Message}"); - } - }); - - /// - /// LT/RT 捷徑直接跳到左側片語清單的第一筆或最後一筆,加快大量片語時的巡覽效率。 - /// - /// true 表示跳到最後一筆;false 表示跳到第一筆。 - private void HandlePhraseShortcutBoundary(bool last) => this.SafeInvoke(() => - { - try - { - if (!CanHandleGamepadInput() || - _lstPhrases.Items.Count == 0) - { - return; - } - - int targetIndex = last ? - _lstPhrases.Items.Count - 1 : - 0; - - _lstPhrases.Focus(); - - if (targetIndex == _lstPhrases.SelectedIndex) - { - FeedbackService.PlaySound(SystemSounds.Beep); - - return; - } - - _lstPhrases.SelectedIndex = targetIndex; - - FeedbackService.VibrateAsync( - _gamepadController, - VibrationPatterns.CursorMove, - _cts?.Token ?? CancellationToken.None) - .SafeFireAndForget(); - } - catch (Exception ex) - { - Debug.WriteLine($"[片語] HandlePhraseShortcutBoundary 失敗:{ex.Message}"); - } - }); - - /// - /// 控制器 LB 捷徑切換到上一個片語。 - /// - private void HandlePreviousPhraseShortcut() => HandlePhraseShortcutStep(-1); - - /// - /// 控制器 RB 捷徑切換到下一個片語。 - /// - private void HandleNextPhraseShortcut() => HandlePhraseShortcutStep(1); - - /// - /// 控制器 LT 捷徑直接跳到第一個片語。 - /// - private void HandleFirstPhraseShortcut() => HandlePhraseShortcutBoundary(last: false); - - /// - /// 控制器 RT 捷徑直接跳到最後一個片語。 - /// - private void HandleLastPhraseShortcut() => HandlePhraseShortcutBoundary(last: true); - - /// - /// 控制器左向輸入時回到清單或將片語上移 - /// - private void HandleMoveUp() => this.SafeInvoke(() => - { - try - { - if (!CanHandleGamepadInput()) - { - return; - } - - // 左方向鍵:若目前在右側按鈕區,回到清單。 - if (IsButtonAreaFocused()) - { - _lstPhrases.Focus(); - - if (_lstPhrases.SelectedIndex >= 0) - { - IReadOnlyList phrases = _phraseService.Phrases; - - if (_lstPhrases.SelectedIndex < phrases.Count) - { - AnnounceA11y( - AppSettings.Current.IsPrivacyMode ? - Strings.Phrase_A11y_Selected_PrivacySafe : - string.Format(Strings.Phrase_A11y_Selected, phrases[_lstPhrases.SelectedIndex].Name), - interrupt: true); - } - } - - FeedbackService.VibrateAsync( - _gamepadController, - VibrationPatterns.CursorMove, - _cts?.Token ?? CancellationToken.None) - .SafeFireAndForget(); - - return; - } - - MoveSelectedPhrase(-1); - } - catch (Exception ex) - { - Debug.WriteLine($"[片語] HandleMoveUp 失敗:{ex.Message}"); - } - }); - - /// - /// 控制器右向輸入時進入按鈕區或將片語下移 - /// - private void HandleMoveDown() => this.SafeInvoke(() => - { - try - { - if (!CanHandleGamepadInput()) - { - return; - } - - // 右方向鍵:由清單進入右側按鈕區;若已在按鈕區則向後循環。 - if (_lstPhrases.Focused || - _lstPhrases.ContainsFocus) - { - FocusFirstActionButtonOrClose(); - - return; - } - - if (IsButtonAreaFocused()) - { - CycleFocus(forward: true); - - return; - } - - MoveSelectedPhrase(1); - } - catch (Exception ex) - { - Debug.WriteLine($"[片語] HandleMoveDown 失敗:{ex.Message}"); - } - }); - - /// - /// 在清單與按鈕之間循環焦點 - /// - /// 是否向前循環焦點 - private void CycleFocus(bool forward) - { - // 建立焦點順序:清單 → 各按鈕(依面板順序)→ 關閉按鈕。 - List focusOrder = [_lstPhrases]; - - foreach (Control ctrl in _flpButtons.Controls) - { - if (ctrl is Button btn && - btn.Enabled && - btn.Visible) - { - focusOrder.Add(btn); - } - } - - if (_btnClose.Enabled && _btnClose.Visible) - { - focusOrder.Add(_btnClose); - } - - if (focusOrder.Count == 0) - { - return; - } - - // 找到目前焦點在列表中的位置。 - int currentIdx = -1; - - for (int i = 0; i < focusOrder.Count; i++) - { - if (focusOrder[i].Focused || - focusOrder[i].ContainsFocus) - { - currentIdx = i; - - break; - } - } - - int nextIdx; - - if (currentIdx < 0) - { - nextIdx = forward ? - 0 : - focusOrder.Count - 1; - } - else - { - nextIdx = forward ? - (currentIdx + 1) % focusOrder.Count : - (currentIdx - 1 + focusOrder.Count) % focusOrder.Count; - } - - focusOrder[nextIdx].Focus(); - - // 播報焦點目標。 - string? name = focusOrder[nextIdx].AccessibleName ?? focusOrder[nextIdx].Text; - - if (!string.IsNullOrEmpty(name)) - { - AnnounceA11y(name, interrupt: true); - } - - FeedbackService.VibrateAsync( - _gamepadController, - VibrationPatterns.CursorMove, - _cts?.Token ?? CancellationToken.None) - .SafeFireAndForget(); - } - - /// - /// 嘗試找出目前在按鈕區取得焦點的按鈕 - /// - /// 輸出的焦點按鈕。 - /// 若找到焦點按鈕則回傳 true。 - private bool TryGetFocusedButton(out Button? focusedBtn) - { - if (_btnClose.Focused || - _btnClose.ContainsFocus) - { - focusedBtn = _btnClose; - - return true; - } - - foreach (Control ctrl in _flpButtons.Controls) - { - if (ctrl is Button btn && - (btn.Focused || btn.ContainsFocus)) - { - focusedBtn = btn; - - return true; - } - } - - focusedBtn = null; - - return false; - } - - /// - /// 判斷目前焦點是否位於按鈕區 - /// - /// 若按鈕區有焦點則回傳 true。 - private bool IsButtonAreaFocused() => TryGetFocusedButton(out _); - - /// - /// 將焦點移至第一個可用動作按鈕,否則移至關閉按鈕。 - /// - private void FocusFirstActionButtonOrClose() - { - foreach (Control ctrl in _flpButtons.Controls) - { - if (ctrl is Button btn && - btn.Enabled && - btn.Visible) - { - btn.Focus(); - - AnnounceA11y(btn.AccessibleName ?? btn.Text, interrupt: true); - - FeedbackService.VibrateAsync( - _gamepadController, - VibrationPatterns.CursorMove, - _cts?.Token ?? CancellationToken.None) - .SafeFireAndForget(); - - return; - } - } - - if (_btnClose.Enabled && - _btnClose.Visible) - { - _btnClose.Focus(); - - AnnounceA11y(_btnClose.AccessibleName ?? _btnClose.Text, interrupt: true); - - FeedbackService.VibrateAsync( - _gamepadController, - VibrationPatterns.CursorMove, - _cts?.Token ?? CancellationToken.None) - .SafeFireAndForget(); - } - } - - /// - /// 控制器連線狀態變更時更新恢復狀態並廣播無障礙訊息。 - /// - /// 連線成功為 ,斷線為 。 - private void HandleGamepadConnectionChanged(bool connected) - { - try - { - if (connected) - { - _gamepadController?.Resume(); - } - - AnnounceA11y(connected ? - string.Format(Strings.A11y_Gamepad_Connected, _gamepadController?.DeviceName) : - string.Format(Strings.A11y_Gamepad_Disconnected, _gamepadController?.DeviceName)); - } - catch (Exception ex) - { - Debug.WriteLine($"[片語] 控制器連線變更處理失敗:{ex.Message}"); - } - } - - /// - /// 訂閱片語管理對話框使用的控制器事件 - /// - private void SubscribeGamepadEvents() - { - try - { - if (_gamepadController != null) - { - GamepadFaceButtonProfile profile = GamepadFaceButtonProfile.GetActiveProfile(); - - _gamepadController.UpPressed += HandleUp; - _gamepadController.UpRepeat += HandleUp; - _gamepadController.DownPressed += HandleDown; - _gamepadController.DownRepeat += HandleDown; - _gamepadController.APressed += profile.ConfirmOnSouth ? HandleGamepadA : HandleClose; - _gamepadController.StartPressed += HandleGamepadA; - _gamepadController.BPressed += profile.ConfirmOnSouth ? HandleClose : HandleGamepadA; - _gamepadController.BackPressed += HandleClose; - _gamepadController.XPressed += HandleDelete; - _gamepadController.YPressed += HandleAdd; - _gamepadController.LeftPressed += HandleMoveUp; - _gamepadController.LeftRepeat += HandleMoveUp; - _gamepadController.RightPressed += HandleMoveDown; - _gamepadController.RightRepeat += HandleMoveDown; - _gamepadController.LeftShoulderPressed += HandlePreviousPhraseShortcut; - _gamepadController.LeftShoulderRepeat += HandlePreviousPhraseShortcut; - _gamepadController.RightShoulderPressed += HandleNextPhraseShortcut; - _gamepadController.RightShoulderRepeat += HandleNextPhraseShortcut; - _gamepadController.LeftTriggerPressed += HandleFirstPhraseShortcut; - _gamepadController.RightTriggerPressed += HandleLastPhraseShortcut; - _gamepadController.ConnectionChanged += HandleGamepadConnectionChanged; - } - } - catch (Exception ex) - { - Debug.WriteLine($"[片語] SubscribeGamepadEvents 失敗:{ex.Message}"); - } - } - - /// - /// 解除片語管理對話框使用的控制器事件 - /// - private void UnsubscribeGamepadEvents() - { - try - { - if (_gamepadController != null) - { - _gamepadController.UpPressed -= HandleUp; - _gamepadController.UpRepeat -= HandleUp; - _gamepadController.DownPressed -= HandleDown; - _gamepadController.DownRepeat -= HandleDown; - _gamepadController.APressed -= HandleGamepadA; - _gamepadController.APressed -= HandleClose; - _gamepadController.StartPressed -= HandleGamepadA; - _gamepadController.BPressed -= HandleGamepadA; - _gamepadController.BPressed -= HandleClose; - _gamepadController.BackPressed -= HandleClose; - _gamepadController.XPressed -= HandleDelete; - _gamepadController.YPressed -= HandleAdd; - _gamepadController.LeftPressed -= HandleMoveUp; - _gamepadController.LeftRepeat -= HandleMoveUp; - _gamepadController.RightPressed -= HandleMoveDown; - _gamepadController.RightRepeat -= HandleMoveDown; - _gamepadController.LeftShoulderPressed -= HandlePreviousPhraseShortcut; - _gamepadController.LeftShoulderRepeat -= HandlePreviousPhraseShortcut; - _gamepadController.RightShoulderPressed -= HandleNextPhraseShortcut; - _gamepadController.RightShoulderRepeat -= HandleNextPhraseShortcut; - _gamepadController.LeftTriggerPressed -= HandleFirstPhraseShortcut; - _gamepadController.RightTriggerPressed -= HandleLastPhraseShortcut; - _gamepadController.ConnectionChanged -= HandleGamepadConnectionChanged; - } - } - catch (Exception ex) - { - Debug.WriteLine($"[片語] UnsubscribeGamepadEvents 失敗:{ex.Message}"); - } - } - - #endregion - - #region 視覺與佈局 - - - /// - /// 建立動作按鈕 - /// - /// 按鈕文字 - /// 輔助功能描述 - /// 快捷鍵字元 - /// 已設定樣式、快捷鍵與無障礙屬性的動作按鈕執行個體。 - private static Button CreateActionButton( - string text, - string a11yDesc, - char mnemonic) - { - Button btn = new() - { - Text = ControlExtensions.GetMnemonicText(text, mnemonic), - AutoSize = true, - FlatStyle = FlatStyle.Flat, - AccessibleName = text, - AccessibleDescription = a11yDesc, - AccessibleRole = AccessibleRole.PushButton, - BackColor = Color.Empty, - ForeColor = Color.Empty, - Margin = new Padding(2, 2, 2, 2), - Anchor = AnchorStyles.Left | AnchorStyles.Right - }; - btn.FlatAppearance.BorderSize = 0; - - // 暫存 base description 到 Tag 供後續 AttachEyeTrackerFeedback 使用。 - btn.Tag = a11yDesc; - - return btn; - } - - /// - /// 套用字型(Regular + Bold)並掛載眼動儀擴充 - /// - private void ApplyFont() - { - _a11yFont = MainForm.GetSharedA11yFont(DeviceDpi, FontStyle.Regular); - _boldFont = MainForm.GetSharedA11yFont(DeviceDpi, FontStyle.Bold); - - Font = _a11yFont; - - _lstPhrases.Font = _a11yFont; - - foreach (Control ctrl in _flpButtons.Controls) - { - if (ctrl is Button btn) - { - btn.Font = _a11yFont; - btn.AttachEyeTrackerFeedback( - baseDescription: btn.Tag?.ToString() ?? string.Empty, - regularFont: _a11yFont, - boldFont: _boldFont, - formCt: _cts?.Token ?? CancellationToken.None); - } - } - - _btnClose.Font = _a11yFont; - _btnClose.AttachEyeTrackerFeedback( - baseDescription: Strings.Phrase_A11y_Btn_Close_Desc, - regularFont: _a11yFont, - boldFont: _boldFont, - formCt: _cts?.Token ?? CancellationToken.None); - - _lblPhraseCount.Font = _a11yFont; - UpdatePhraseCountLabelMinimumWidth(); - } - - /// - /// 更新每個按鈕的最小尺寸(抗抖動 + WCAG 2.5.5 AAA 44×44) - /// - private void UpdateButtonMinimumSizes() - { - float scale = DeviceDpi / AppSettings.BaseDpi; - - UpdateSingleButtonMinimumSize(_btnAdd, scale); - UpdateSingleButtonMinimumSize(_btnEdit, scale); - UpdateSingleButtonMinimumSize(_btnDelete, scale); - UpdateSingleButtonMinimumSize(_btnMoveUp, scale); - UpdateSingleButtonMinimumSize(_btnMoveDown, scale); - UpdateSingleButtonMinimumSize(_btnClose, scale); - } - - /// - /// 更新單一按鈕的最小尺寸 - /// - /// 要更新最小尺寸的按鈕。 - /// 目前 DPI 相對於基準 DPI 的縮放比例。 - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private void UpdateSingleButtonMinimumSize(Button btn, float scale) - { - try - { - if (btn.IsDisposed) - { - return; - } - Font boldFont = _boldFont ?? MainForm.GetSharedA11yFont(DeviceDpi, FontStyle.Bold); - - DialogLayoutHelper.UpdateButtonMinimumSize(btn, boldFont, scale, 44, 44, 24, 16); - } - catch (Exception ex) - { - Debug.WriteLine($"[片語] UpdateSingleButtonMinimumSize 失敗:{ex.Message}"); - } - } - - /// - /// 更新最小尺寸(依按鈕面板實際內容高度動態計算) - /// - /// 設為 強制重算,忽略 DPI 快取。 - private void UpdateMinimumSize(bool forceRecalculate = false) - { - float currentDpi = DeviceDpi; - - if (!DialogLayoutHelper.TryBeginDpiLayout(currentDpi, ref _lastAppliedDpi, forceRecalculate)) - { - return; - } - - float scale = currentDpi / AppSettings.BaseDpi; - - UpdatePhraseCountLabelMinimumWidth(); - - // 加上非客戶區(標題列+邊框)高度,MinimumSize 是外框尺寸。 - // OnHandleCreated 時 Height == ClientSize.Height(非客戶區尚未就緒), - // 故以 SystemInformation 估算作為最低保底值。 - int nonClientH = DialogLayoutHelper.GetEstimatedNonClientHeight(this); - - // 以主版面實際偏好尺寸作為基準,避免最後一顆按鈕在 row 0 被裁切。 - _tlpMain.PerformLayout(); - - Size preferred = _tlpMain.GetPreferredSize(Size.Empty); - - int desiredMinWidth = (int)(BaseDialogMinWidth * scale), - minW = Math.Max(desiredMinWidth, preferred.Width + Padding.Horizontal), - baseClientH = Math.Max( - (int)(300 * scale) - nonClientH, - preferred.Height + Padding.Vertical + (int)(8 * scale)), - minH = baseClientH + nonClientH; - - Rectangle workArea = Screen.GetWorkingArea(this); - - (int maxFitW, int maxFitH) = DialogLayoutHelper.GetMaxFitSize(workArea); - - minW = Math.Min(minW, maxFitW); - minH = Math.Min(minH, maxFitH); - - DialogLayoutHelper.ClampFormSize(this, minW, minH, maxFitW, maxFitH); - } - - /// - /// 更新視窗不透明度 - /// - private void UpdateOpacity() - { - if (SystemInformation.HighContrast) - { - Opacity = 1.0; - - return; - } - - Opacity = AppSettings.Current.WindowOpacity; - } - - /// - /// 智慧定位 - /// - private void ApplySmartPosition() - { - if (InputBoxLayoutManager.TryGetClampedLocation(this, out Point clampedLocation)) - { - Location = clampedLocation; - } - } - - /// - /// 強制重繪所有按鈕 - /// - private void InvalidateAllButtons() - { - _btnAdd.Invalidate(); - _btnEdit.Invalidate(); - _btnDelete.Invalidate(); - _btnMoveUp.Invalidate(); - _btnMoveDown.Invalidate(); - _btnClose.Invalidate(); - } - - /// - /// 系統偏好設定變更時同步更新尺寸、定位與按鈕視覺。 - /// - /// 事件來源。 - /// 系統偏好設定事件參數。 - private void SystemEvents_UserPreferenceChanged(object sender, UserPreferenceChangedEventArgs e) - { - try - { - if (e.Category is UserPreferenceCategory.Accessibility or - UserPreferenceCategory.Color or - UserPreferenceCategory.General) - { - this.SafeInvoke(() => - { - try - { - UpdateButtonMinimumSizes(); - UpdateMinimumSize(forceRecalculate: true); - ApplySmartPosition(); - InvalidateAllButtons(); - } - catch (Exception ex) - { - Debug.WriteLine($"[片語] SystemEvents 更新失敗:{ex.Message}"); - } - }); - } - } - catch (Exception ex) - { - Debug.WriteLine($"[片語] SystemEvents 處理失敗:{ex.Message}"); - } - } - - #endregion - - #region A11y - - /// - /// 內部 A11y 廣播 - /// - /// 要廣播的無障礙訊息文字。 - /// 設為 可中斷目前朗讀(需設定允許中斷)。 - private void AnnounceA11y(string message, bool interrupt = false) - { - if (IsDisposed || - string.IsNullOrEmpty(message)) - { - return; - } - - if (Owner is MainForm mainForm) - { - mainForm.AnnounceA11y(message, interrupt); - } - else - { - long currentId = Interlocked.Increment(ref _a11yDebounceId); - - Task.Run(async () => - { - try - { - await Task.Delay(AppSettings.AudioDuckingDelayMs, _cts?.Token ?? CancellationToken.None); - - if (Interlocked.Read(ref _a11yDebounceId) == currentId && - !IsDisposed && - IsHandleCreated) - { - await this.SafeInvokeAsync(() => - _announcer.Announce(message, interrupt && AppSettings.Current.A11yInterruptEnabled)); - } - } - catch (OperationCanceledException) - { - - } - catch (Exception ex) - { - Debug.WriteLine($"[片語] A11y 廣播失敗:{ex.Message}"); - } - }, - _cts?.Token ?? CancellationToken.None) - .SafeFireAndForget(); - } - } - - #endregion -} \ No newline at end of file +} From 285ab1a42e1d9c620b5582c2b92242aea0db43c7 Mon Sep 17 00:00:00 2001 From: perditavojo <117562794+perditavojo@users.noreply.github.com> Date: Sun, 27 Sep 2026 20:41:19 +0800 Subject: [PATCH 16/17] =?UTF-8?q?fix(vibration):=20=E7=9B=B8=E5=90=8C=20Cr?= =?UTF-8?q?itical=20=E9=9C=87=E5=8B=95=E8=87=AA=E5=8B=95=E9=80=A3=E7=99=BC?= =?UTF-8?q?=E6=99=82=E9=99=8D=E7=B4=9A=E4=BA=A4=E7=94=B1=E7=86=B1=E4=BF=9D?= =?UTF-8?q?=E8=AD=B7=E7=AF=80=E6=B5=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 實測按住方向鍵頂著邊界時,操作失敗回饋(Critical,強度 53861、200ms)約每 150ms 觸發一次, 5 秒內連發 25 次;Critical 不受熱溢出拒絕,熱負載累積到硬上限的 5.7 倍,馬達被高強度連續驅動。 - VibrationSafetyLimiter 追蹤最近一次 Critical 請求;相同強度與時長在 500ms 內再次出現時視為自動連發, 降為 Normal 並標記 DowngradedCriticalRepeat,交由熱保護與占空比節流。視窗隨每次連發延長,停手後恢復為 Critical。 - 第一次失敗回饋仍以 Critical 完整送出;強度或時長不同的 Critical 序列(例如控制器識別)不受影響。 - 新增 3 項測試(連發降級且熱負載不超過第一次脈衝、視窗過後恢復、不同序列不降級), 並調整 2 項以相同 Critical 快速升溫的既有測試改為間隔送出,維持原測試意圖。 - gamepad-api 規範新增 Critical 連發節流規則,更新測試 README。 Co-Authored-By: Claude Opus 5.5 --- docs/engineering/gamepad-api.md | 1 + .../Core/Input/VibrationSafetyLimiter.cs | 48 ++++++++- tests/InputBox.Tests/README.md | 4 +- .../VibrationSafetyLimiterTests.cs | 102 +++++++++++++++++- 4 files changed, 146 insertions(+), 9 deletions(-) diff --git a/docs/engineering/gamepad-api.md b/docs/engineering/gamepad-api.md index 2ca2bfb..da8690a 100644 --- a/docs/engineering/gamepad-api.md +++ b/docs/engineering/gamepad-api.md @@ -14,6 +14,7 @@ - **連結權杖 (Linked Token)**:震動延遲須結合外部取消權杖與內部覆寫權杖,確保視窗關閉時馬達能立即停止。 - **熱成本正規化**:傳給 `VibrationSafetyLimiter` 的熱成本倍率必須透過 `GetMotorThermalCostMultiplier(馬達數)` 取得(以雙主馬達為 1.0),XInput 與 GameInput 共用同一基準;不得直接傳入馬達數量。 - **回饋不得冷啟動遺失**:Normal 優先級單次請求超出剩餘熱預算時應先降低強度,只有低於優先級保底比例才可拒絕;新增或調整 `VibrationPatterns` 後,必須通過「所有內建模式冷啟動不被拒絕」測試。 + - **Critical 連發節流**:相同強度與時長的 Critical 請求在 500ms 內重複出現時,限制器會視為自動連發並降為 Normal;不得在呼叫端以輪流改變強度等方式規避,以免按住方向鍵時不受熱保護地連續驅動馬達。 - **Face 鍵語意路由 (Semantic Face-Button Routing)**: - 所有「確認/取消/刪除/選單」行為,必須透過集中化的配置描述(例如 `GamepadFaceButtonProfile`)解析,**禁止**在 Dialog、MessageBox 或主視窗中硬式編碼 `A=確認`、`B=取消`。 - 實作時應優先使用邏輯語意(例如 south/east/west/north 對應的功能)而非控制器字樣,避免 Nintendo 與 PlayStation 模式下產生顯示正確但功能錯置的回歸。 diff --git a/src/InputBox/Core/Input/VibrationSafetyLimiter.cs b/src/InputBox/Core/Input/VibrationSafetyLimiter.cs index ebfaaff..e108714 100644 --- a/src/InputBox/Core/Input/VibrationSafetyLimiter.cs +++ b/src/InputBox/Core/Input/VibrationSafetyLimiter.cs @@ -59,7 +59,12 @@ internal enum VibrationLimiterFlags /// /// 單次請求超出剩餘熱預算,已降低強度以符合預算。 /// - ScaledByThermalOverflow = 1 << 9 + ScaledByThermalOverflow = 1 << 9, + + /// + /// 短時間內重複的相同 Critical 請求被視為自動連發,已降為 Normal 交由熱保護節流。 + /// + DowngradedCriticalRepeat = 1 << 10 } /// @@ -115,6 +120,15 @@ internal sealed class VibrationSafetyLimiter /// private const double ThermalOverflowTolerance = 1.05; + /// + /// 判定相同 Critical 請求為自動連發的時間視窗(毫秒)。 + /// + /// + /// 例如按住方向鍵頂著邊界時,操作失敗回饋約每 150ms 觸發一次;若仍以 Critical 送出, + /// 會不受熱保護限制地連續以高強度驅動馬達。視窗會隨每次連發延長,停手超過此時間後才恢復為 Critical。 + /// + private const int CriticalRepeatWindowMs = 500; + private readonly Lock _lock = new(); private readonly Queue<(long EndMs, int DurationMs)> _acceptedDurations = new(); @@ -129,6 +143,9 @@ internal sealed class VibrationSafetyLimiter private double _thermalLoad; private long _lastSampleMs; private long _ambientCooldownUntilMs; + private long _lastCriticalRequestMs = long.MinValue; + private ushort _lastCriticalStrength; + private int _lastCriticalDurationMs; /// /// 建立震動保護器。 @@ -302,6 +319,28 @@ internal bool TryApplyWithDiagnostics( DecayThermal(nowMs); PruneDutyWindow(nowMs); + // 相同的 Critical 請求在連發視窗內再次出現時視為自動連發,降為 Normal 交由熱保護與占空比節流; + // 第一次仍以 Critical 完整送出,強度或時長不同的 Critical 序列(例如控制器識別)不受影響。 + bool downgradedCriticalRepeat = false; + + if (priority == VibrationPriority.Critical) + { + bool isRepeat = _lastCriticalRequestMs != long.MinValue && + nowMs - _lastCriticalRequestMs < CriticalRepeatWindowMs && + _lastCriticalStrength == strength && + _lastCriticalDurationMs == boundedDurationMs; + + _lastCriticalRequestMs = nowMs; + _lastCriticalStrength = strength; + _lastCriticalDurationMs = boundedDurationMs; + + if (isRepeat) + { + priority = VibrationPriority.Normal; + downgradedCriticalRepeat = true; + } + } + if (priority == VibrationPriority.Ambient && nowMs < _ambientCooldownUntilMs) { @@ -317,7 +356,9 @@ internal bool TryApplyWithDiagnostics( } double scale = 1.0; - VibrationLimiterFlags flags = VibrationLimiterFlags.None; + VibrationLimiterFlags flags = downgradedCriticalRepeat ? + VibrationLimiterFlags.DowngradedCriticalRepeat : + VibrationLimiterFlags.None; double currentDuty = _windowOnTimeMs / _windowMs; @@ -533,6 +574,9 @@ public void Reset() _thermalLoad = 0.0; _lastSampleMs = 0; _ambientCooldownUntilMs = 0; + _lastCriticalRequestMs = long.MinValue; + _lastCriticalStrength = 0; + _lastCriticalDurationMs = 0; } } diff --git a/tests/InputBox.Tests/README.md b/tests/InputBox.Tests/README.md index ffde1a4..a95a95d 100644 --- a/tests/InputBox.Tests/README.md +++ b/tests/InputBox.Tests/README.md @@ -48,8 +48,8 @@ | `TaskExtensionsTests` | `TaskExtensions` CTS 擴充方法與生命週期連結保護 | 12 | | `TextBoxSelectionExtensionsTests` | 右搖桿延伸選取共用的 `ResolveSelectionAnchor` 錨點解析(無選取、正向、反向、錨點失效)與 `GetWordJumpTarget` 單字跳轉目標(不改變目前選取、方向與邊界);原本三處複本集中後的一致性保護 | 6 | | `VibrationPatternsTests` | `VibrationPatterns` 與方向性震動設定、語意情境解析、能力感知的多段式微震動序列,以及歷程滾輪阻尼感、字數上限硬牆、震動強度預覽、右搖桿選取粒度、組合鍵進入提示與喚起握手回饋的回歸保護 | 37 | -| `VibrationSafetyLimiterTests` | `VibrationSafetyLimiter` 熱保護、Duty Cycle 限制器與極端邊界保護;馬達數量熱成本倍率正規化,以及所有內建震動模式在冷啟動下不得被拒絕、單次超出預算改為降強度的回歸保護 | 16 | -| **合計** | | **423** | +| `VibrationSafetyLimiterTests` | `VibrationSafetyLimiter` 熱保護、Duty Cycle 限制器與極端邊界保護;馬達數量熱成本倍率正規化,以及所有內建震動模式在冷啟動下不得被拒絕、單次超出預算改為降強度,以及相同 Critical 自動連發降級、熱負載不失控的回歸保護 | 19 | +| **合計** | | **426** | ## 二、執行方式 🚀 diff --git a/tests/InputBox.Tests/VibrationSafetyLimiterTests.cs b/tests/InputBox.Tests/VibrationSafetyLimiterTests.cs index 6511ca8..744ecba 100644 --- a/tests/InputBox.Tests/VibrationSafetyLimiterTests.cs +++ b/tests/InputBox.Tests/VibrationSafetyLimiterTests.cs @@ -140,11 +140,12 @@ public void TryApply_WhenThermalCostMultiplierHigher_ShouldScaleEarlier() out _, thermalCostMultiplier: 4.0); + // 第二次呼叫刻意落在 Critical 連發視窗之外,避免被視為自動連發而降級。 bool normalSecond = limiterNormal.TryApply( 45_000, 200, VibrationPriority.Critical, - nowMs: 1, + nowMs: 600, out ushort normalSecondStrength, out _); @@ -152,7 +153,7 @@ public void TryApply_WhenThermalCostMultiplierHigher_ShouldScaleEarlier() 45_000, 200, VibrationPriority.Critical, - nowMs: 1, + nowMs: 600, out ushort fourMotorSecondStrength, out _, thermalCostMultiplier: 4.0); @@ -349,17 +350,17 @@ public void TryApply_Normal_WhenAlreadyOverheated_ShouldStillBeBlocked() { var limiter = new VibrationSafetyLimiter(thermalTauMs: 1_000_000); - // Critical 不受溢出拒絕限制,用來把熱負載推高到溢出上限之上。 + // Critical 不受溢出拒絕限制,用來把熱負載推高到溢出上限之上;間隔超過連發視窗以免被降級。 for (int i = 0; i < 10; i++) { - limiter.TryApply(60_000, 200, VibrationPriority.Critical, nowMs: 1 + i, out _, out _); + limiter.TryApply(60_000, 200, VibrationPriority.Critical, nowMs: 1 + (i * 600), out _, out _); } bool accepted = limiter.TryApplyWithDiagnostics( 60_000, 200, VibrationPriority.Normal, - nowMs: 20, + nowMs: 6_100, out _, out _, out VibrationLimiterDebugInfo diagnostics); @@ -367,4 +368,95 @@ public void TryApply_Normal_WhenAlreadyOverheated_ShouldStillBeBlocked() Assert.False(accepted); Assert.True(diagnostics.Flags.HasFlag(VibrationLimiterFlags.BlockedByThermalOverflow)); } + + /// + /// 回歸保護:按住方向鍵頂著邊界時,操作失敗回饋(Critical)約每 150ms 自動連發。 + /// 第一次應以 Critical 完整送出,之後的連發應降為 Normal 交由熱保護節流,熱負載不得持續累積失控。 + /// 修正前實測 5 秒內連發 25 次會讓熱負載累積到硬上限的 5.7 倍。 + /// + [Fact] + public void TryApply_RepeatedIdenticalCritical_IsDowngradedAndThermalStaysBounded() + { + var limiter = new VibrationSafetyLimiter(); + double multiplier = VibrationSafetyLimiter.GetMotorThermalCostMultiplier(4); + + bool first = limiter.TryApplyWithDiagnostics( + 53_861, + 200, + VibrationPriority.Critical, + nowMs: 1, + out ushort firstStrength, + out _, + out VibrationLimiterDebugInfo firstDiagnostics, + multiplier); + + Assert.True(first); + Assert.Equal(53_861, firstStrength); + Assert.False(firstDiagnostics.Flags.HasFlag(VibrationLimiterFlags.DowngradedCriticalRepeat)); + + double firstLoad = firstDiagnostics.ThermalLoad; + double maxLoad = firstLoad; + + for (int i = 1; i < 25; i++) + { + limiter.TryApplyWithDiagnostics( + 53_861, + 200, + VibrationPriority.Critical, + nowMs: 1 + (i * 150), + out _, + out _, + out VibrationLimiterDebugInfo diagnostics, + multiplier); + + Assert.True(diagnostics.Flags.HasFlag(VibrationLimiterFlags.DowngradedCriticalRepeat), $"repeat {i}"); + maxLoad = Math.Max(maxLoad, diagnostics.ThermalLoad); + } + + Assert.True(maxLoad <= firstLoad + 0.001, $"maxLoad={maxLoad:F2} firstLoad={firstLoad:F2}"); + } + + /// + /// 停止連發超過連發視窗後,下一次相同的 Critical 請求應恢復為 Critical,不得被永久降級。 + /// + [Fact] + public void TryApply_CriticalAfterRepeatWindowElapsed_IsNotDowngraded() + { + var limiter = new VibrationSafetyLimiter(); + + limiter.TryApply(53_861, 200, VibrationPriority.Critical, nowMs: 1, out _, out _); + + limiter.TryApplyWithDiagnostics( + 53_861, + 200, + VibrationPriority.Critical, + nowMs: 700, + out _, + out _, + out VibrationLimiterDebugInfo diagnostics); + + Assert.False(diagnostics.Flags.HasFlag(VibrationLimiterFlags.DowngradedCriticalRepeat)); + } + + /// + /// 由不同強度或時長組成的 Critical 序列(例如控制器識別的前後兩段)不是自動連發,不得被降級。 + /// + [Fact] + public void TryApply_DifferentCriticalProfilesInSequence_AreNotDowngraded() + { + var limiter = new VibrationSafetyLimiter(); + + limiter.TryApply(43_000, 110, VibrationPriority.Critical, nowMs: 1, out _, out _); + + limiter.TryApplyWithDiagnostics( + 55_000, + 130, + VibrationPriority.Critical, + nowMs: 150, + out _, + out _, + out VibrationLimiterDebugInfo diagnostics); + + Assert.False(diagnostics.Flags.HasFlag(VibrationLimiterFlags.DowngradedCriticalRepeat)); + } } From 6a3af4dc3d7c13e9a2bdf2038350e517fa028a7e Mon Sep 17 00:00:00 2001 From: perditavojo <117562794+perditavojo@users.noreply.github.com> Date: Sun, 27 Sep 2026 21:00:37 +0800 Subject: [PATCH 17/17] =?UTF-8?q?fix(restart):=20=E4=BB=A5=E4=BA=A4?= =?UTF-8?q?=E6=8E=A5=E5=8F=83=E6=95=B8=E8=AE=93=E6=96=B0=E5=9F=B7=E8=A1=8C?= =?UTF-8?q?=E5=80=8B=E9=AB=94=E6=8E=A5=E6=89=8B=E5=96=AE=E4=B8=80=E5=9F=B7?= =?UTF-8?q?=E8=A1=8C=E5=80=8B=E9=AB=94=20Mutex=EF=BC=8C=E4=B8=A6=E5=BC=B7?= =?UTF-8?q?=E5=8C=96=20Critical=20=E9=80=A3=E7=99=BC=E7=AF=80=E6=B5=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 回應 PR #79 的 Copilot 審查意見: 1. 重啟時的 Mutex 交接競態 舊實例原本在啟動新執行個體前就釋放 Mutex,若恰好有另外啟動的 InputBox 在空窗期取得 Mutex, 重啟出來的實例會喚醒它後自行退出。 - 舊實例以 --restart-handoff=<舊 PID> 啟動新執行個體,不在啟動前釋放 Mutex, 改於關閉所有視窗後、Environment.Exit 前於主執行緒明確釋放。 - 新執行個體依 SingleInstanceHandoff 規則在主執行緒等待並接手 Mutex(最多 10 秒,遺棄的 Mutex 視為接手成功), 不喚醒既有實例;逾時才退回一般流程。 - 交接期間另外啟動的執行個體喚醒失敗時,若偵測到重啟請求進行中(RestartActivationCoordinator.HasPendingActivationRequest,不消費標記)則結束,不 fallback 多開視窗。 - 轉送命令列時移除舊的交接參數,避免連續重啟時累積。無法啟動新程序而退回 Application.Restart 時維持先釋放 Mutex。 2. 交錯的 Critical 可規避連發偵測 連發判定改為「前一個 Critical 之後 500ms 內的任何 Critical」,不再要求強度與時長相同。 3. 啟動路徑測試缺口 交接參數解析、啟動動作與 fallback 判斷抽成 SingleInstanceHandoff 純函式並補齊測試。 測試:新增 SingleInstanceHandoffTests(16 項)、RestartActivationCoordinatorTests 與 RestartProcessLauncherTests 各 2 項, VibrationSafetyLimiterTests 以交錯節流與冷啟動短序列測試取代原「不同序列不降級」測試;共 447 項,436 通過、11 略過。 實測:兩個實例模擬交接時,新實例在舊實例關閉前持續等待、關閉後立即接手(waitMs=2972),全程單一實例; 從選單連續重啟兩次成功,最終只剩一個實例且交接參數未累積。core-engineering 與 gamepad-api 規範同步更新。 Co-Authored-By: Claude Opus 5.5 --- docs/engineering/core-engineering.md | 3 +- docs/engineering/gamepad-api.md | 2 +- .../Core/Input/VibrationSafetyLimiter.cs | 23 +-- .../Services/RestartActivationCoordinator.cs | 28 +++ .../Core/Services/RestartProcessLauncher.cs | 20 +- .../Core/Services/SingleInstanceHandoff.cs | 171 ++++++++++++++++++ src/InputBox/MainForm.cs | 19 +- src/InputBox/Program.cs | 79 +++++++- tests/InputBox.Tests/README.md | 9 +- .../RestartActivationCoordinatorTests.cs | 33 +++- .../RestartProcessLauncherTests.cs | 28 +++ .../SingleInstanceHandoffTests.cs | 98 ++++++++++ .../VibrationSafetyLimiterTests.cs | 58 +++++- 13 files changed, 533 insertions(+), 38 deletions(-) create mode 100644 src/InputBox/Core/Services/SingleInstanceHandoff.cs create mode 100644 tests/InputBox.Tests/SingleInstanceHandoffTests.cs diff --git a/docs/engineering/core-engineering.md b/docs/engineering/core-engineering.md index 928ad97..bc1d034 100644 --- a/docs/engineering/core-engineering.md +++ b/docs/engineering/core-engineering.md @@ -26,7 +26,8 @@ - **程式內重啟與前景恢復**: - **單次啟用標記**:若為本程式主動要求重新啟動,舊執行個體必須先寫入具短時效的一次性啟用標記,供新執行個體在首次顯示時消費;標記必須於讀取後立即清除,避免重複生效。 - **前景授權交接**:由 `RestartProcessLauncher` 自行啟動新執行個體(取代 `Application.Restart()`),並在舊視窗關閉前以 `AllowSetForegroundWindow(新程序 PID)` 只授權該程序搶回前景;不得使用 `ASFW_ANY` 開放給所有程序,僅在無法啟動新程序而退回 `Application.Restart()` 時例外。授權必須在舊視窗仍位於前景時完成,因為控制器操作不會產生 Windows 輸入事件。 - - **獨占資源先釋放**:新執行個體會在舊視窗關閉前啟動,因此舊執行個體必須先解除全域快速鍵並釋放單一執行個體 Mutex,避免新執行個體註冊失敗。 + - **單一執行個體交接**:舊執行個體以 `--restart-handoff=<舊 PID>` 參數啟動新執行個體,**不得在啟動前釋放** 單一執行個體 Mutex,必須在關閉所有視窗後、`Environment.Exit` 之前於主執行緒明確釋放;新執行個體依 `SingleInstanceHandoff` 規則在主執行緒等待並接手 Mutex(被遺棄的 Mutex 亦視為接手成功),不得喚醒既有實例後退出。交接期間另外啟動的執行個體若喚醒失敗且偵測到重啟請求進行中,必須結束而不得 fallback 另開視窗。退回 `Application.Restart()` 時新執行個體不帶交接參數,才可先釋放 Mutex。 + - **全域快速鍵先解除**:新執行個體會在舊視窗關閉前啟動,舊執行個體必須先解除全域快速鍵,避免新執行個體接手後註冊失敗。 - **新執行個體恢復流程**:新視窗啟動後應先走較強的前景還原路徑(例如 `WindowFocusService.RestoreWindowAsync(...)`),再以有限次數重試 `ShowWindow`、`BringWindowToTop`、`SetForegroundWindow`、`Activate()` 與輸入框 `Focus()`;不可只做單次 `Activate()` 後就假設成功。 - **避免錯誤回切**:當重啟是由程式內設定變更觸發時,舊執行個體應避免再把「前一個外部視窗」覆寫為目前狀態,以免新執行個體恢復焦點時誤切回錯誤目標。 - **格式與診斷紀律**: diff --git a/docs/engineering/gamepad-api.md b/docs/engineering/gamepad-api.md index da8690a..be519a0 100644 --- a/docs/engineering/gamepad-api.md +++ b/docs/engineering/gamepad-api.md @@ -14,7 +14,7 @@ - **連結權杖 (Linked Token)**:震動延遲須結合外部取消權杖與內部覆寫權杖,確保視窗關閉時馬達能立即停止。 - **熱成本正規化**:傳給 `VibrationSafetyLimiter` 的熱成本倍率必須透過 `GetMotorThermalCostMultiplier(馬達數)` 取得(以雙主馬達為 1.0),XInput 與 GameInput 共用同一基準;不得直接傳入馬達數量。 - **回饋不得冷啟動遺失**:Normal 優先級單次請求超出剩餘熱預算時應先降低強度,只有低於優先級保底比例才可拒絕;新增或調整 `VibrationPatterns` 後,必須通過「所有內建模式冷啟動不被拒絕」測試。 - - **Critical 連發節流**:相同強度與時長的 Critical 請求在 500ms 內重複出現時,限制器會視為自動連發並降為 Normal;不得在呼叫端以輪流改變強度等方式規避,以免按住方向鍵時不受熱保護地連續驅動馬達。 + - **Critical 連發節流**:前一個 Critical 請求之後 500ms 內再出現的任何 Critical 請求(不論強度與時長是否相同),限制器都會視為自動連發並降為 Normal 交由熱保護節流,避免連按或按住時不受熱保護地連續以高強度驅動馬達;冷啟動時 Normal 仍完整送出,短序列不受影響。 - **Face 鍵語意路由 (Semantic Face-Button Routing)**: - 所有「確認/取消/刪除/選單」行為,必須透過集中化的配置描述(例如 `GamepadFaceButtonProfile`)解析,**禁止**在 Dialog、MessageBox 或主視窗中硬式編碼 `A=確認`、`B=取消`。 - 實作時應優先使用邏輯語意(例如 south/east/west/north 對應的功能)而非控制器字樣,避免 Nintendo 與 PlayStation 模式下產生顯示正確但功能錯置的回歸。 diff --git a/src/InputBox/Core/Input/VibrationSafetyLimiter.cs b/src/InputBox/Core/Input/VibrationSafetyLimiter.cs index e108714..3d4b39a 100644 --- a/src/InputBox/Core/Input/VibrationSafetyLimiter.cs +++ b/src/InputBox/Core/Input/VibrationSafetyLimiter.cs @@ -62,7 +62,7 @@ internal enum VibrationLimiterFlags ScaledByThermalOverflow = 1 << 9, /// - /// 短時間內重複的相同 Critical 請求被視為自動連發,已降為 Normal 交由熱保護節流。 + /// 短時間內接連出現的 Critical 請求被視為自動連發,已降為 Normal 交由熱保護節流。 /// DowngradedCriticalRepeat = 1 << 10 } @@ -121,11 +121,12 @@ internal sealed class VibrationSafetyLimiter private const double ThermalOverflowTolerance = 1.05; /// - /// 判定相同 Critical 請求為自動連發的時間視窗(毫秒)。 + /// 判定 Critical 請求為自動連發的時間視窗(毫秒)。 /// /// - /// 例如按住方向鍵頂著邊界時,操作失敗回饋約每 150ms 觸發一次;若仍以 Critical 送出, - /// 會不受熱保護限制地連續以高強度驅動馬達。視窗會隨每次連發延長,停手超過此時間後才恢復為 Critical。 + /// 例如在空白輸入框連按 B 時,操作失敗回饋約每 150ms 觸發一次;若仍以 Critical 送出, + /// 會不受熱保護限制地連續以高強度驅動馬達。不論 Critical 的強度與時長是否相同都一併判定, + /// 避免不同 Critical 模式交錯出現時規避節流。視窗會隨每次連發延長,停手超過此時間後才恢復為 Critical。 /// private const int CriticalRepeatWindowMs = 500; @@ -144,8 +145,6 @@ internal sealed class VibrationSafetyLimiter private long _lastSampleMs; private long _ambientCooldownUntilMs; private long _lastCriticalRequestMs = long.MinValue; - private ushort _lastCriticalStrength; - private int _lastCriticalDurationMs; /// /// 建立震動保護器。 @@ -319,20 +318,16 @@ internal bool TryApplyWithDiagnostics( DecayThermal(nowMs); PruneDutyWindow(nowMs); - // 相同的 Critical 請求在連發視窗內再次出現時視為自動連發,降為 Normal 交由熱保護與占空比節流; - // 第一次仍以 Critical 完整送出,強度或時長不同的 Critical 序列(例如控制器識別)不受影響。 + // 前一個 Critical 請求之後的連發視窗內再次出現 Critical 時視為自動連發,降為 Normal 交由熱保護與占空比節流。 + // 第一次仍以 Critical 完整送出;冷啟動時 Normal 也會完整送出,因此一般節奏的操作與短序列不受影響。 bool downgradedCriticalRepeat = false; if (priority == VibrationPriority.Critical) { bool isRepeat = _lastCriticalRequestMs != long.MinValue && - nowMs - _lastCriticalRequestMs < CriticalRepeatWindowMs && - _lastCriticalStrength == strength && - _lastCriticalDurationMs == boundedDurationMs; + nowMs - _lastCriticalRequestMs < CriticalRepeatWindowMs; _lastCriticalRequestMs = nowMs; - _lastCriticalStrength = strength; - _lastCriticalDurationMs = boundedDurationMs; if (isRepeat) { @@ -575,8 +570,6 @@ public void Reset() _lastSampleMs = 0; _ambientCooldownUntilMs = 0; _lastCriticalRequestMs = long.MinValue; - _lastCriticalStrength = 0; - _lastCriticalDurationMs = 0; } } diff --git a/src/InputBox/Core/Services/RestartActivationCoordinator.cs b/src/InputBox/Core/Services/RestartActivationCoordinator.cs index 5a64459..bcb3b3f 100644 --- a/src/InputBox/Core/Services/RestartActivationCoordinator.cs +++ b/src/InputBox/Core/Services/RestartActivationCoordinator.cs @@ -97,6 +97,34 @@ public bool ConsumePendingActivationRequest() } } + /// + /// 查詢是否有尚未過期的重啟啟用請求,但不消費標記。 + /// + /// + /// 供其他正在啟動的執行個體判斷「目前是否有程式內重啟交接進行中」, + /// 標記仍保留給重啟後的新執行個體消費。 + /// + /// 若存在且尚未過期的請求則回傳 true。 + public bool HasPendingActivationRequest() + { + try + { + if (!File.Exists(_markerPath)) + { + return false; + } + + string payload = File.ReadAllText(_markerPath).Trim(); + + return long.TryParse(payload, NumberStyles.Integer, CultureInfo.InvariantCulture, out long expiryTicks) && + expiryTicks >= DateTime.UtcNow.Ticks; + } + catch + { + return false; + } + } + /// /// 清除殘留標記(若存在)。 /// diff --git a/src/InputBox/Core/Services/RestartProcessLauncher.cs b/src/InputBox/Core/Services/RestartProcessLauncher.cs index dfb81d3..5b18af5 100644 --- a/src/InputBox/Core/Services/RestartProcessLauncher.cs +++ b/src/InputBox/Core/Services/RestartProcessLauncher.cs @@ -4,7 +4,7 @@ namespace InputBox.Core.Services; /// /// 負責程式內重啟時啟動新的執行個體;取代 以便在舊視窗關閉前取得新程序識別碼, -/// 讓前景授權只交給該程序,而不必開放給所有程序。 +/// 讓前景授權只交給該程序,而不必開放給所有程序;並以交接參數讓新執行個體等待接手單一執行個體 Mutex。 /// internal static class RestartProcessLauncher { @@ -17,10 +17,15 @@ internal static class RestartProcessLauncher /// /// 要啟動的執行檔完整路徑。 /// 目前程序的命令列引數(含第一個元素的執行檔路徑)。 + /// + /// 舊執行個體的程序識別碼;指定時會附加 交接參數, + /// 讓新執行個體等待並接手單一執行個體 Mutex。既有的交接參數一律先移除,避免連續重啟時重複轉送。 + /// /// 重啟用的啟動資訊。 public static ProcessStartInfo CreateStartInfo( string executablePath, - IReadOnlyList commandLineArgs) + IReadOnlyList commandLineArgs, + int? handoffProcessId = null) { ArgumentException.ThrowIfNullOrWhiteSpace(executablePath); ArgumentNullException.ThrowIfNull(commandLineArgs); @@ -30,9 +35,16 @@ public static ProcessStartInfo CreateStartInfo( UseShellExecute = false }; - for (int i = 1; i < commandLineArgs.Count; i++) + IReadOnlyList forwardedArgs = SingleInstanceHandoff.RemoveHandoffArguments(commandLineArgs); + + for (int i = 1; i < forwardedArgs.Count; i++) + { + startInfo.ArgumentList.Add(forwardedArgs[i]); + } + + if (handoffProcessId.HasValue) { - startInfo.ArgumentList.Add(commandLineArgs[i]); + startInfo.ArgumentList.Add(SingleInstanceHandoff.CreateHandoffArgument(handoffProcessId.Value)); } return startInfo; diff --git a/src/InputBox/Core/Services/SingleInstanceHandoff.cs b/src/InputBox/Core/Services/SingleInstanceHandoff.cs new file mode 100644 index 0000000..b967f1d --- /dev/null +++ b/src/InputBox/Core/Services/SingleInstanceHandoff.cs @@ -0,0 +1,171 @@ +using System.Globalization; + +namespace InputBox.Core.Services; + +/// +/// 單一執行個體啟動時應採取的動作。 +/// +internal enum SingleInstanceStartupAction +{ + /// + /// 已取得單一執行個體 Mutex,繼續正常啟動。 + /// + Proceed, + + /// + /// 本執行個體是程式內重啟的接手者,應等待舊執行個體釋放 Mutex 後接手,不喚醒既有實例。 + /// + WaitForHandoff, + + /// + /// 已有其他執行個體持有 Mutex,應嘗試喚醒既有實例。 + /// + ActivateExisting, +} + +/// +/// 喚醒既有實例失敗後的處置。 +/// +internal enum SingleInstanceFallbackDecision +{ + /// + /// 允許以 fallback 方式繼續啟動新視窗,避免使用者看不到任何畫面。 + /// + TryFallback, + + /// + /// 已找到可喚醒視窗但前景切換被系統阻擋,結束本次啟動以維持單一實例。 + /// + ExitForegroundBlocked, + + /// + /// 程式內重啟交接進行中,接手的新執行個體會自行顯示視窗,結束本次啟動以免出現兩個視窗。 + /// + ExitRestartHandoffPending, +} + +/// +/// 程式內重啟的單一執行個體交接規則。 +/// +/// +/// 舊執行個體在持有 Mutex 的情況下,以 參數啟動新執行個體, +/// 並於關閉所有視窗後才釋放 Mutex;新執行個體據此等待並接手 Mutex,而不是把 Mutex 視為「已有實例」而喚醒後退出。 +/// 如此可避免舊實例先釋放 Mutex 時,恰好另外啟動的執行個體搶先取得 Mutex,導致重啟出來的實例退出。 +/// +internal static class SingleInstanceHandoff +{ + /// + /// 標記「本執行個體由程式內重啟啟動」的命令列參數前綴,後接舊執行個體的程序識別碼。 + /// + internal const string HandoffArgumentPrefix = "--restart-handoff="; + + /// + /// 新執行個體等待舊執行個體釋放 Mutex 的上限。 + /// + internal static readonly TimeSpan HandoffWaitTimeout = TimeSpan.FromSeconds(10); + + /// + /// 建立交接參數。 + /// + /// 舊執行個體的程序識別碼。 + /// 交接參數字串。 + public static string CreateHandoffArgument(int processId) + { + return HandoffArgumentPrefix + processId.ToString(CultureInfo.InvariantCulture); + } + + /// + /// 從命令列引數中取得交接來源的程序識別碼。 + /// + /// 命令列引數(第一個元素為執行檔本身,會被略過)。 + /// 找到有效交接參數時為舊執行個體的程序識別碼;否則為 0。 + /// 若包含有效的交接參數則回傳 true。 + public static bool TryGetHandoffProcessId(IReadOnlyList commandLineArgs, out int processId) + { + ArgumentNullException.ThrowIfNull(commandLineArgs); + + processId = 0; + + for (int i = 1; i < commandLineArgs.Count; i++) + { + string arg = commandLineArgs[i]; + + if (arg.StartsWith(HandoffArgumentPrefix, StringComparison.Ordinal) && + int.TryParse( + arg.AsSpan(HandoffArgumentPrefix.Length), + NumberStyles.None, + CultureInfo.InvariantCulture, + out int parsed) && + parsed > 0) + { + processId = parsed; + + return true; + } + } + + return false; + } + + /// + /// 移除命令列引數中的交接參數,避免連續重啟時交接參數被重複轉送。 + /// + /// 命令列引數(第一個元素為執行檔本身,會原樣保留)。 + /// 不含交接參數的命令列引數。 + public static IReadOnlyList RemoveHandoffArguments(IReadOnlyList commandLineArgs) + { + ArgumentNullException.ThrowIfNull(commandLineArgs); + + List result = new(commandLineArgs.Count); + + for (int i = 0; i < commandLineArgs.Count; i++) + { + if (i > 0 && + commandLineArgs[i].StartsWith(HandoffArgumentPrefix, StringComparison.Ordinal)) + { + continue; + } + + result.Add(commandLineArgs[i]); + } + + return result; + } + + /// + /// 依 Mutex 取得結果與是否為交接啟動,決定啟動動作。 + /// + /// 是否新建並取得單一執行個體 Mutex。 + /// 是否帶有有效的交接參數。 + /// 應採取的啟動動作。 + public static SingleInstanceStartupAction ResolveStartupAction(bool createdNew, bool isHandoffLaunch) + { + if (createdNew) + { + return SingleInstanceStartupAction.Proceed; + } + + return isHandoffLaunch ? + SingleInstanceStartupAction.WaitForHandoff : + SingleInstanceStartupAction.ActivateExisting; + } + + /// + /// 喚醒既有實例失敗後,決定是否允許 fallback 啟動新視窗。 + /// + /// 喚醒流程判定是否允許 fallback(例如找不到任何可喚醒視窗)。 + /// 目前是否有程式內重啟交接進行中。 + /// 喚醒失敗後的處置。 + public static SingleInstanceFallbackDecision ResolveFallback(bool fallbackPermitted, bool restartHandoffPending) + { + if (!fallbackPermitted) + { + return SingleInstanceFallbackDecision.ExitForegroundBlocked; + } + + // 交接期間舊實例的視窗已關閉、新實例尚未顯示視窗,若此時允許 fallback 會多開一個視窗。 + return restartHandoffPending ? + SingleInstanceFallbackDecision.ExitRestartHandoffPending : + SingleInstanceFallbackDecision.TryFallback; + } +} diff --git a/src/InputBox/MainForm.cs b/src/InputBox/MainForm.cs index 0f9f660..108c4df 100644 --- a/src/InputBox/MainForm.cs +++ b/src/InputBox/MainForm.cs @@ -1229,7 +1229,7 @@ private void RestartApplication() List mainForms = [.. Application.OpenForms.OfType()]; // 新執行個體會在舊視窗關閉前啟動,因此先解除全域快速鍵, - // 避免新舊執行個體短暫並存時,新執行個體註冊同一組快速鍵失敗。 + // 避免新執行個體接手後註冊同一組快速鍵失敗。 foreach (MainForm mainForm in mainForms) { if (mainForm.IsHandleCreated) @@ -1238,15 +1238,16 @@ private void RestartApplication() } } - Program.ReleaseMutex(); - // AllowSetForegroundWindow 只有在呼叫端仍為前景程序(或收到最後一次輸入)時才有效; // 以控制器觸發重啟不會產生 Windows 輸入事件,因此必須趁目前視窗仍在前景時, // 先啟動新執行個體,再只授權該程序呼叫 SetForegroundWindow,而不開放給所有程序。 + // 新執行個體帶有交接參數,會等待本實例釋放單一執行個體 Mutex 後才接手, + // 因此不在啟動前釋放 Mutex,避免另外啟動的執行個體在空窗期搶先取得。 bool launched = RestartProcessLauncher.TryStart( RestartProcessLauncher.CreateStartInfo( Application.ExecutablePath, - Environment.GetCommandLineArgs()), + Environment.GetCommandLineArgs(), + handoffProcessId: Environment.ProcessId), out int newProcessId); _ = User32.AllowSetForegroundWindow( @@ -1254,6 +1255,12 @@ private void RestartApplication() newProcessId : User32.AllowSetForegroundWindowAnyProcess); + if (!launched) + { + // 退回 WinForms 內建的重啟流程時,新執行個體不帶交接參數,必須先釋放 Mutex 才能正常啟動。 + Program.ReleaseMutex(); + } + // 安全地關閉所有 MainForm 實例,確保它們的 Dispose 與 FormClosing 被正確觸發, // 從而釋放全域的 SystemEvents 鉤子,防止重啟時發生靜態資源洩漏。 foreach (MainForm mainForm in mainForms) @@ -1264,6 +1271,10 @@ private void RestartApplication() if (launched) { Application.Exit(); + + // 所有視窗已關閉,在同一個(持有 Mutex 的)主執行緒上釋放 Mutex,讓等待中的新執行個體接手。 + // Environment.Exit 不會執行 Main 的 finally 清理,因此必須在此明確釋放。 + Program.ReleaseMutex(); } else { diff --git a/src/InputBox/Program.cs b/src/InputBox/Program.cs index bafe847..b48b373 100644 --- a/src/InputBox/Program.cs +++ b/src/InputBox/Program.cs @@ -64,9 +64,32 @@ static void Main() name: @"Local\InputBox_40A57F4D-4C7E-45FD-9DC7-BE96DC026D66_SingleInstance", out bool createdNew); + bool isHandoffLaunch = SingleInstanceHandoff.TryGetHandoffProcessId( + Environment.GetCommandLineArgs(), + out int handoffProcessId); + + SingleInstanceStartupAction startupAction = SingleInstanceHandoff.ResolveStartupAction(createdNew, isHandoffLaunch); + + if (startupAction == SingleInstanceStartupAction.WaitForHandoff) + { + // 程式內重啟的接手者:舊執行個體會在關閉所有視窗後才釋放 Mutex, + // 在此等待並接手,而不是把 Mutex 視為「已有實例」而喚醒後退出。 + if (TryAcquireMutexForHandoff(handoffProcessId)) + { + createdNew = true; + startupAction = SingleInstanceStartupAction.Proceed; + } + else + { + LoggerService.LogWarning($"SingleInstance.HandoffTimeout pid={Environment.ProcessId} sourcePid={handoffProcessId} timeoutMs={(int)SingleInstanceHandoff.HandoffWaitTimeout.TotalMilliseconds}"); + + startupAction = SingleInstanceStartupAction.ActivateExisting; + } + } + Interlocked.Exchange(ref _ownsMutex, createdNew ? 1 : 0); - if (!createdNew) + if (startupAction == SingleInstanceStartupAction.ActivateExisting) { LoggerService.LogInfo($"SingleInstance.MutexCheck pid={Environment.ProcessId} createdNew={createdNew}"); @@ -101,15 +124,28 @@ static void Main() return; } + SingleInstanceFallbackDecision fallbackDecision = SingleInstanceHandoff.ResolveFallback( + fallbackPermitted, + RestartActivationCoordinator.Shared.HasPendingActivationRequest()); + // 收斂策略:若已找到可喚醒視窗但前景切換被系統阻擋, // 則不允許 fallback 啟動新視窗,避免破壞單實例預期。 - if (!fallbackPermitted) + if (fallbackDecision == SingleInstanceFallbackDecision.ExitForegroundBlocked) { LoggerService.LogWarning($"SingleInstance.FallbackSuppressed pid={Environment.ProcessId} reason=foreground_blocked detail={activationDiagnostic}"); return; } + // 程式內重啟交接進行中:舊實例的視窗已關閉、接手的新實例尚未顯示視窗, + // 此時若 fallback 啟動會多開一個視窗,由接手的新實例負責顯示即可。 + if (fallbackDecision == SingleInstanceFallbackDecision.ExitRestartHandoffPending) + { + LoggerService.LogInfo($"SingleInstance.FallbackSuppressed pid={Environment.ProcessId} reason=restart_handoff_pending detail={activationDiagnostic}"); + + return; + } + // Fallback 次數防護:確保同一時間只有一個 fallback 實例能繼續啟動。 // 若另一個 fallback 進程正在執行中(視窗尚未出現),則靜默中止本次啟動, // 防止快速多次點擊造成多個視窗同時開啟。 @@ -189,6 +225,45 @@ static void Main() } } + /// + /// 程式內重啟的接手者等待舊執行個體釋放單一執行個體 Mutex 並取得所有權 + /// + /// + /// 必須在建立 Mutex 的主執行緒上呼叫,Mutex 的所有權才會屬於之後負責釋放它的同一個執行緒。 + /// 舊執行個體若未釋放就結束,Mutex 會成為被遺棄狀態,仍視為成功接手。 + /// + /// 舊執行個體的程序識別碼(僅供診斷記錄)。 + /// 若在逾時前取得 Mutex 則回傳 true。 + private static bool TryAcquireMutexForHandoff(int sourceProcessId) + { + Mutex? mutex = _mutex; + + if (mutex == null) + { + return false; + } + + long startTimestamp = Stopwatch.GetTimestamp(); + bool acquired; + + try + { + acquired = mutex.WaitOne(SingleInstanceHandoff.HandoffWaitTimeout); + } + catch (AbandonedMutexException) + { + // 舊執行個體未釋放即結束,所有權已轉移給本執行緒。 + acquired = true; + } + + if (acquired) + { + LoggerService.LogInfo($"SingleInstance.HandoffAcquired pid={Environment.ProcessId} sourcePid={sourceProcessId} waitMs={(int)Stopwatch.GetElapsedTime(startTimestamp).TotalMilliseconds}"); + } + + return acquired; + } + /// /// 系統結束處理常式 /// diff --git a/tests/InputBox.Tests/README.md b/tests/InputBox.Tests/README.md index a95a95d..7886ba1 100644 --- a/tests/InputBox.Tests/README.md +++ b/tests/InputBox.Tests/README.md @@ -40,16 +40,17 @@ | `LoggerServiceTests` | `LoggerService` 測試環境專屬日誌分流、Release-like 日誌門檻、環境變數覆寫與正式日誌隔離保護 | 8 | | `MainFormUiSmokeTests` | `MainForm` 使用 FlaUI 驗證主視窗啟動、右鍵選單主要命令、設定中的控制器子選單、控制器校準視覺化對話框、片語子選單、片語管理視窗、片語編輯視窗、HelpDialog、返回時最小化確認對話框、程式內確認重啟後主視窗保持前景,以及基本複製流程的 UI 冒煙測試 | 11 | | `PhraseServiceTests` | `PhraseService` CRUD、匯出/匯入、併發匯出、併發暫存檔誤刪(含 managed 暫存檔寬限期保留),以及持久化失敗時的記憶體復原回歸保護 | 40 | -| `RestartActivationCoordinatorTests` | `RestartActivationCoordinator` 的一次性重啟前景啟用標記、單次消費與過期清理保護 | 3 | +| `RestartActivationCoordinatorTests` | `RestartActivationCoordinator` 的一次性重啟前景啟用標記、單次消費與過期清理保護;以及查詢待處理請求不消費標記、無標記或過期時不判定為交接中 | 5 | | `RestartPromptStateTests` | 需重啟設定的待處理狀態追蹤、標題列提示,以及右鍵選單依 App 設定/系統變更/兩者同時存在而動態切換文案的回歸保護 | 7 | -| `RestartProcessLauncherTests` | `RestartProcessLauncher` 重啟啟動資訊:沿用目前執行檔、不透過殼層啟動、只轉送執行檔之後的引數並保留空白與引號(取代 `Application.Restart()` 以便只授權新程序前景的回歸保護) | 4 | +| `RestartProcessLauncherTests` | `RestartProcessLauncher` 重啟啟動資訊:沿用目前執行檔、不透過殼層啟動、只轉送執行檔之後的引數並保留空白與引號(取代 `Application.Restart()` 以便只授權新程序前景的回歸保護);以及附加單一執行個體交接參數、連續重啟時取代舊交接參數 | 6 | | `RestartRequestDeciderTests` | 手動重啟與設定變更兩種入口的確認策略回歸保護 | 3 | +| `SingleInstanceHandoffTests` | `SingleInstanceHandoff` 程式內重啟交接:交接參數解析與移除、啟動動作矩陣(正常啟動/等待接手/喚醒既有實例)、喚醒失敗後的 fallback 判斷(前景被阻擋、交接進行中不得多開視窗);對應 Mutex 提早釋放被搶先取得的競態 | 16 | | `SystemHelperTests` | `SystemHelper.EvaluateGamescopeEnvironment` 在不同 DISPLAY、XDG_CURRENT_DESKTOP 與 DESKTOP_SESSION 環境變數組合下的 Gamescope 環境偵測回歸保護 | 11 | | `TaskExtensionsTests` | `TaskExtensions` CTS 擴充方法與生命週期連結保護 | 12 | | `TextBoxSelectionExtensionsTests` | 右搖桿延伸選取共用的 `ResolveSelectionAnchor` 錨點解析(無選取、正向、反向、錨點失效)與 `GetWordJumpTarget` 單字跳轉目標(不改變目前選取、方向與邊界);原本三處複本集中後的一致性保護 | 6 | | `VibrationPatternsTests` | `VibrationPatterns` 與方向性震動設定、語意情境解析、能力感知的多段式微震動序列,以及歷程滾輪阻尼感、字數上限硬牆、震動強度預覽、右搖桿選取粒度、組合鍵進入提示與喚起握手回饋的回歸保護 | 37 | -| `VibrationSafetyLimiterTests` | `VibrationSafetyLimiter` 熱保護、Duty Cycle 限制器與極端邊界保護;馬達數量熱成本倍率正規化,以及所有內建震動模式在冷啟動下不得被拒絕、單次超出預算改為降強度,以及相同 Critical 自動連發降級、熱負載不失控的回歸保護 | 19 | -| **合計** | | **426** | +| `VibrationSafetyLimiterTests` | `VibrationSafetyLimiter` 熱保護、Duty Cycle 限制器與極端邊界保護;馬達數量熱成本倍率正規化,以及所有內建震動模式在冷啟動下不得被拒絕、單次超出預算改為降強度,以及Critical 自動連發(含不同模式交錯)降級、熱負載不失控,以及冷啟動短序列仍完整送出的回歸保護 | 20 | +| **合計** | | **447** | ## 二、執行方式 🚀 diff --git a/tests/InputBox.Tests/RestartActivationCoordinatorTests.cs b/tests/InputBox.Tests/RestartActivationCoordinatorTests.cs index 9be3810..7cb888b 100644 --- a/tests/InputBox.Tests/RestartActivationCoordinatorTests.cs +++ b/tests/InputBox.Tests/RestartActivationCoordinatorTests.cs @@ -65,4 +65,35 @@ public void ConsumePendingActivationRequest_WhenMarkerExpired_ReturnsFalseAndDel Assert.False(coordinator.ConsumePendingActivationRequest()); Assert.False(File.Exists(_markerPath)); } -} \ No newline at end of file + + /// + /// 查詢待處理的重啟請求時不得消費標記,標記仍須保留給重啟後的新執行個體。 + /// + [Fact] + public void HasPendingActivationRequest_DoesNotConsumeMarker() + { + RestartActivationCoordinator coordinator = new(_markerPath, TimeSpan.FromSeconds(5)); + + coordinator.RequestActivationOnNextLaunch(); + + Assert.True(coordinator.HasPendingActivationRequest()); + Assert.True(coordinator.HasPendingActivationRequest()); + Assert.True(coordinator.ConsumePendingActivationRequest()); + Assert.False(coordinator.HasPendingActivationRequest()); + } + + /// + /// 沒有標記或標記已過期時,不應判定為重啟交接進行中。 + /// + [Fact] + public void HasPendingActivationRequest_WithoutMarkerOrExpired_ReturnsFalse() + { + RestartActivationCoordinator coordinator = new(_markerPath, TimeSpan.FromSeconds(5)); + + Assert.False(coordinator.HasPendingActivationRequest()); + + File.WriteAllText(_markerPath, DateTime.UtcNow.AddSeconds(-1).Ticks.ToString(System.Globalization.CultureInfo.InvariantCulture)); + + Assert.False(coordinator.HasPendingActivationRequest()); + } +} diff --git a/tests/InputBox.Tests/RestartProcessLauncherTests.cs b/tests/InputBox.Tests/RestartProcessLauncherTests.cs index 7bd5e87..5c9e7bb 100644 --- a/tests/InputBox.Tests/RestartProcessLauncherTests.cs +++ b/tests/InputBox.Tests/RestartProcessLauncherTests.cs @@ -62,4 +62,32 @@ public void CreateStartInfo_BlankExecutablePath_Throws() Assert.ThrowsAny( () => RestartProcessLauncher.CreateStartInfo(" ", ["InputBox.exe"])); } + + /// + /// 指定舊執行個體的程序識別碼時,應在轉送的引數之後附加交接參數,讓新執行個體等待接手 Mutex。 + /// + [Fact] + public void CreateStartInfo_WithHandoffProcessId_AppendsHandoffArgument() + { + ProcessStartInfo startInfo = RestartProcessLauncher.CreateStartInfo( + "InputBox.exe", + ["InputBox.exe", "--first"], + handoffProcessId: 1234); + + Assert.Equal(["--first", "--restart-handoff=1234"], startInfo.ArgumentList); + } + + /// + /// 連續重啟時,舊的交接參數不得被重複轉送,只保留本次的交接參數。 + /// + [Fact] + public void CreateStartInfo_WhenAlreadyHandoffLaunch_ReplacesPreviousHandoffArgument() + { + ProcessStartInfo startInfo = RestartProcessLauncher.CreateStartInfo( + "InputBox.exe", + ["InputBox.exe", "--restart-handoff=111", "--first"], + handoffProcessId: 222); + + Assert.Equal(["--first", "--restart-handoff=222"], startInfo.ArgumentList); + } } diff --git a/tests/InputBox.Tests/SingleInstanceHandoffTests.cs b/tests/InputBox.Tests/SingleInstanceHandoffTests.cs new file mode 100644 index 0000000..c532953 --- /dev/null +++ b/tests/InputBox.Tests/SingleInstanceHandoffTests.cs @@ -0,0 +1,98 @@ +using InputBox.Core.Services; +using Xunit; + +namespace InputBox.Tests; + +/// +/// 驗證程式內重啟的單一執行個體交接規則:交接參數解析、啟動動作與喚醒失敗後的 fallback 判斷。 +/// 防止重啟時舊實例提早釋放 Mutex,被另外啟動的執行個體搶先取得而讓重啟失效,或在交接期間多開視窗。 +/// +public sealed class SingleInstanceHandoffTests +{ + /// + /// 帶有有效交接參數時,應解析出舊執行個體的程序識別碼。 + /// + [Fact] + public void TryGetHandoffProcessId_WithValidArgument_ReturnsProcessId() + { + bool found = SingleInstanceHandoff.TryGetHandoffProcessId( + ["InputBox.exe", "--other", "--restart-handoff=4321"], + out int processId); + + Assert.True(found); + Assert.Equal(4321, processId); + } + + /// + /// 沒有交接參數或交接參數的數值無效時,不應視為交接啟動。 + /// + [Theory] + [InlineData("--other")] + [InlineData("--restart-handoff=")] + [InlineData("--restart-handoff=abc")] + [InlineData("--restart-handoff=-5")] + [InlineData("--restart-handoff=0")] + public void TryGetHandoffProcessId_WithoutValidArgument_ReturnsFalse(string argument) + { + bool found = SingleInstanceHandoff.TryGetHandoffProcessId(["InputBox.exe", argument], out int processId); + + Assert.False(found); + Assert.Equal(0, processId); + } + + /// + /// 第一個元素是執行檔路徑,即使內容符合交接參數格式也不得被解析。 + /// + [Fact] + public void TryGetHandoffProcessId_IgnoresExecutablePathElement() + { + bool found = SingleInstanceHandoff.TryGetHandoffProcessId(["--restart-handoff=99"], out int processId); + + Assert.False(found); + Assert.Equal(0, processId); + } + + /// + /// 移除交接參數時應保留執行檔路徑與其他引數的原本順序。 + /// + [Fact] + public void RemoveHandoffArguments_KeepsOtherArgumentsInOrder() + { + IReadOnlyList result = SingleInstanceHandoff.RemoveHandoffArguments( + ["InputBox.exe", "--a", "--restart-handoff=1", "--b", "--restart-handoff=2"]); + + Assert.Equal(["InputBox.exe", "--a", "--b"], result); + } + + /// + /// 啟動動作矩陣:取得 Mutex 即正常啟動;未取得時,交接啟動等待接手,其餘喚醒既有實例。 + /// + [Theory] + [InlineData(true, false, "Proceed")] + [InlineData(true, true, "Proceed")] + [InlineData(false, true, "WaitForHandoff")] + [InlineData(false, false, "ActivateExisting")] + public void ResolveStartupAction_ReturnsExpectedAction( + bool createdNew, + bool isHandoffLaunch, + string expected) + { + Assert.Equal(expected, SingleInstanceHandoff.ResolveStartupAction(createdNew, isHandoffLaunch).ToString()); + } + + /// + /// fallback 判斷矩陣:前景切換被阻擋時一律結束;重啟交接進行中時結束以免多開視窗;其餘允許 fallback。 + /// + [Theory] + [InlineData(false, false, "ExitForegroundBlocked")] + [InlineData(false, true, "ExitForegroundBlocked")] + [InlineData(true, true, "ExitRestartHandoffPending")] + [InlineData(true, false, "TryFallback")] + public void ResolveFallback_ReturnsExpectedDecision( + bool fallbackPermitted, + bool restartHandoffPending, + string expected) + { + Assert.Equal(expected, SingleInstanceHandoff.ResolveFallback(fallbackPermitted, restartHandoffPending).ToString()); + } +} diff --git a/tests/InputBox.Tests/VibrationSafetyLimiterTests.cs b/tests/InputBox.Tests/VibrationSafetyLimiterTests.cs index 744ecba..ccc30dd 100644 --- a/tests/InputBox.Tests/VibrationSafetyLimiterTests.cs +++ b/tests/InputBox.Tests/VibrationSafetyLimiterTests.cs @@ -439,24 +439,70 @@ public void TryApply_CriticalAfterRepeatWindowElapsed_IsNotDowngraded() } /// - /// 由不同強度或時長組成的 Critical 序列(例如控制器識別的前後兩段)不是自動連發,不得被降級。 + /// 不同的 Critical 模式交錯快速出現時,也必須被判定為連發而節流,不得藉由輪流改變強度或時長規避。 /// [Fact] - public void TryApply_DifferentCriticalProfilesInSequence_AreNotDowngraded() + public void TryApply_InterleavedCriticalProfiles_AreStillThrottled() + { + var limiter = new VibrationSafetyLimiter(); + double multiplier = VibrationSafetyLimiter.GetMotorThermalCostMultiplier(4); + + limiter.TryApplyWithDiagnostics( + 53_861, + 200, + VibrationPriority.Critical, + nowMs: 1, + out _, + out _, + out VibrationLimiterDebugInfo firstDiagnostics, + multiplier); + + double firstLoad = firstDiagnostics.ThermalLoad; + double maxLoad = firstLoad; + + for (int i = 1; i < 20; i++) + { + ushort strength = i % 2 == 0 ? (ushort)53_861 : (ushort)49_312; + + limiter.TryApplyWithDiagnostics( + strength, + 200, + VibrationPriority.Critical, + nowMs: 1 + (i * 150), + out _, + out _, + out VibrationLimiterDebugInfo diagnostics, + multiplier); + + Assert.True(diagnostics.Flags.HasFlag(VibrationLimiterFlags.DowngradedCriticalRepeat), $"repeat {i}"); + maxLoad = Math.Max(maxLoad, diagnostics.ThermalLoad); + } + + Assert.True(maxLoad <= firstLoad + 0.001, $"maxLoad={maxLoad:F2} firstLoad={firstLoad:F2}"); + } + + /// + /// 冷啟動時的短 Critical 序列(例如控制器識別的前後兩段),第二段雖被視為連發而降級,仍應以原強度完整送出。 + /// + [Fact] + public void TryApply_CriticalSequenceFromColdState_SecondStepStillDeliveredAtFullStrength() { var limiter = new VibrationSafetyLimiter(); limiter.TryApply(43_000, 110, VibrationPriority.Critical, nowMs: 1, out _, out _); - limiter.TryApplyWithDiagnostics( + bool accepted = limiter.TryApplyWithDiagnostics( 55_000, 130, VibrationPriority.Critical, nowMs: 150, - out _, - out _, + out ushort adjustedStrength, + out int adjustedDurationMs, out VibrationLimiterDebugInfo diagnostics); - Assert.False(diagnostics.Flags.HasFlag(VibrationLimiterFlags.DowngradedCriticalRepeat)); + Assert.True(accepted); + Assert.True(diagnostics.Flags.HasFlag(VibrationLimiterFlags.DowngradedCriticalRepeat)); + Assert.Equal(55_000, adjustedStrength); + Assert.Equal(130, adjustedDurationMs); } }

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 G4&a{@bilX( diff --git a/eng/nuget/InputWeave.GameInput.0.0.1.nupkg.sha256 b/eng/nuget/InputWeave.GameInput.0.0.1.nupkg.sha256 index 9bf9889..6f58ea6 100644 --- a/eng/nuget/InputWeave.GameInput.0.0.1.nupkg.sha256 +++ b/eng/nuget/InputWeave.GameInput.0.0.1.nupkg.sha256 @@ -1 +1 @@ -3e9a3d65861a9211380aec6211ccf9f6b9151eae20df6d8917d3e75a98b9b589 InputWeave.GameInput.0.0.1.nupkg +3342051977f6f1b91f2a18acfc224456320264dd67633ed4bc41c8188c9fcdb7 InputWeave.GameInput.0.0.1.nupkg diff --git a/eng/nuget/InputWeave.GameInput_LICENSE.txt b/eng/nuget/InputWeave.GameInput_LICENSE.txt index e5efddc..b40dfcf 100644 --- a/eng/nuget/InputWeave.GameInput_LICENSE.txt +++ b/eng/nuget/InputWeave.GameInput_LICENSE.txt @@ -1,15 +1,15 @@ InputWeave.GameInput 0.0.1 =========================== -來源: https://github.com/rubujo/InputWeave.GameInput/tree/a3985f29c19b35365124d70cfbf0c21d1596ad3e +來源: https://github.com/rubujo/InputWeave.GameInput/tree/89b148669ffe58d9927495ed0d89f9997bf4962a 作者: https://github.com/rubujo 貢獻者: https://github.com/rubujo/InputWeave.GameInput/graphs/contributors -封裝來源: https://github.com/rubujo/InputWeave.GameInput/commit/a3985f29c19b35365124d70cfbf0c21d1596ad3e +封裝來源: https://github.com/rubujo/InputWeave.GameInput/commit/89b148669ffe58d9927495ed0d89f9997bf4962a 套件檔案: eng/nuget/InputWeave.GameInput.0.0.1.nupkg -套件 SHA256: 3e9a3d65861a9211380aec6211ccf9f6b9151eae20df6d8917d3e75a98b9b589 +套件 SHA256: 3342051977f6f1b91f2a18acfc224456320264dd67633ed4bc41c8188c9fcdb7 授權名稱: Creative Commons CC0 1.0 Universal 授權識別碼 (SPDX): CC0-1.0 -授權檔案: https://github.com/rubujo/InputWeave.GameInput/blob/a3985f29c19b35365124d70cfbf0c21d1596ad3e/LICENSE +授權檔案: https://github.com/rubujo/InputWeave.GameInput/blob/89b148669ffe58d9927495ed0d89f9997bf4962a/LICENSE InputWeave.GameInput 採用 Creative Commons CC0 1.0 Universal 公眾領域貢獻宣告。 在法律允許的最大範圍內,作者已將此套件的著作權與相關權利貢獻至全球公眾領域。 diff --git a/tests/InputBox.Tests/README.md b/tests/InputBox.Tests/README.md index e778274..17e892f 100644 --- a/tests/InputBox.Tests/README.md +++ b/tests/InputBox.Tests/README.md @@ -123,7 +123,7 @@ xUnit v3 為每個 `[Fact]` 建立獨立的測試類別實例,`IDisposable.Dis - Microsoft.Testing.Extensions.CodeCoverage:原始碼儲存庫為 [microsoft/codecoverage](https://github.com/microsoft/codecoverage),由 [Microsoft](https://github.com/microsoft) 及其 [貢獻者](https://github.com/microsoft/codecoverage/graphs/contributors) 開發並採用 [MIT License](https://github.com/microsoft/codecoverage/blob/main/LICENSE) 授權,用於測試覆蓋率收集。 - FlaUI.Core:原始碼儲存庫為 [FlaUI/FlaUI](https://github.com/FlaUI/FlaUI),由 [Roman Baeriswyl](https://github.com/Roemer) 及其 [貢獻者](https://github.com/FlaUI/FlaUI/graphs/contributors) 開發並採用 [MIT License](https://github.com/FlaUI/FlaUI/blob/main/LICENSE.txt) 授權,作為 Windows UI 自動化核心函式庫。 - FlaUI.UIA3:原始碼儲存庫為 [FlaUI/FlaUI](https://github.com/FlaUI/FlaUI),由 [Roman Baeriswyl](https://github.com/Roemer) 及其 [貢獻者](https://github.com/FlaUI/FlaUI/graphs/contributors) 開發並採用 [MIT License](https://github.com/FlaUI/FlaUI/blob/main/LICENSE.txt) 授權,作為 UIA3 後端,用於 WinForms UI 冒煙測試。 -- InputWeave.GameInput 0.0.1:原始碼儲存庫固定於 [rubujo/InputWeave.GameInput 封裝來源](https://github.com/rubujo/InputWeave.GameInput/tree/a3985f29c19b35365124d70cfbf0c21d1596ad3e),由 [rubujo](https://github.com/rubujo) 及其 [貢獻者](https://github.com/rubujo/InputWeave.GameInput/graphs/contributors) 開發並採用 [CC0 1.0 Universal](https://github.com/rubujo/InputWeave.GameInput/blob/a3985f29c19b35365124d70cfbf0c21d1596ad3e/LICENSE) 授權,作為 GameInput 直接使用與震動型別守門測試依賴;套件固定於 [../../eng/nuget/InputWeave.GameInput.0.0.1.nupkg](../../eng/nuget/InputWeave.GameInput.0.0.1.nupkg),SHA256 為 `3e9a3d65861a9211380aec6211ccf9f6b9151eae20df6d8917d3e75a98b9b589`。 +- InputWeave.GameInput 0.0.1:原始碼儲存庫固定於 [rubujo/InputWeave.GameInput 封裝來源](https://github.com/rubujo/InputWeave.GameInput/tree/89b148669ffe58d9927495ed0d89f9997bf4962a),由 [rubujo](https://github.com/rubujo) 及其 [貢獻者](https://github.com/rubujo/InputWeave.GameInput/graphs/contributors) 開發並採用 [CC0 1.0 Universal](https://github.com/rubujo/InputWeave.GameInput/blob/89b148669ffe58d9927495ed0d89f9997bf4962a/LICENSE) 授權,作為 GameInput 直接使用與震動型別守門測試依賴;套件固定於 [../../eng/nuget/InputWeave.GameInput.0.0.1.nupkg](../../eng/nuget/InputWeave.GameInput.0.0.1.nupkg),SHA256 為 `3342051977f6f1b91f2a18acfc224456320264dd67633ed4bc41c8188c9fcdb7`。 本測試專案的相關說明詳見本文件;主專案授權與完整聲明仍以 [../../README.md](../../README.md) 及 [../../LICENSE](../../LICENSE) 為準。 From 355ec672ab0a356c374f4681827be46610ac63a7 Mon Sep 17 00:00:00 2001 From: perditavojo <117562794+perditavojo@users.noreply.github.com> Date: Sun, 27 Sep 2026 06:03:10 +0800 Subject: [PATCH 03/17] =?UTF-8?q?docs:=20=E5=B0=87=E3=80=8CXbox=20?= =?UTF-8?q?=E5=85=A8=E8=9E=A2=E5=B9=95=E9=AB=94=E9=A9=97=E3=80=8D=E6=9B=B4?= =?UTF-8?q?=E5=90=8D=E7=82=BA=E3=80=8CXbox=20=E6=A8=A1=E5=BC=8F=E3=80=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Microsoft 已將「Xbox 全螢幕體驗」正式更名為「Xbox 模式」,同步修正相關文字: - README 常見問題標題改為「從 Xbox 模式切換回 Windows 桌面後,應用程式視窗過大」。 - MainForm 視窗還原與 WindowFocusService 前景切換的程式註解改用「Xbox 模式」,並修正原註解中的錯字;僅調整註解,未變更任何執行行為。 Co-Authored-By: Claude Opus 5.5 --- README.md | 2 +- src/InputBox/Core/Services/WindowFocusService.cs | 2 +- src/InputBox/MainForm.Events.cs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index c5ed9f0..c66fc20 100644 --- a/README.md +++ b/README.md @@ -393,7 +393,7 @@ 若需使用控制器目前配置下的取消鍵關閉觸控式鍵盤,可將其「鍵盤配置」設定為「遊戲控制器」。 -### 2. 從 Xbox 全螢幕體驗切換回 Windows 桌面後,應用程式視窗過大 📺 +### 2. 從 Xbox 模式切換回 Windows 桌面後,應用程式視窗過大 📺 可手動縮放視窗大小(使用手指或滑鼠)。 diff --git a/src/InputBox/Core/Services/WindowFocusService.cs b/src/InputBox/Core/Services/WindowFocusService.cs index 9c3311e..836c067 100644 --- a/src/InputBox/Core/Services/WindowFocusService.cs +++ b/src/InputBox/Core/Services/WindowFocusService.cs @@ -150,7 +150,7 @@ public static async Task RestoreWindowAsync( { // 第一段:先用低侵入方式切換,避免不必要的執行緒附加。 // 僅在視窗確實處於最小化狀態時才呼叫 SW_RESTORE, - // 避免對全螢幕(Xbox 達陣全螢幕)或最大化視窗呼叫後造成畫面跟版。 + // 避免對全螢幕(例如 Xbox 模式)或最大化視窗呼叫後造成畫面跟版。 if (User32.IsIconic(targetHwnd)) { _ = User32.ShowWindow(targetHwnd, User32.ShowWindowCommand.Restore); diff --git a/src/InputBox/MainForm.Events.cs b/src/InputBox/MainForm.Events.cs index 49073f7..2a0220e 100644 --- a/src/InputBox/MainForm.Events.cs +++ b/src/InputBox/MainForm.Events.cs @@ -118,7 +118,7 @@ await Task.Delay( else { // 強制還原視窗,避免在 Windows 桌面(平板模式)下自動最大化。 - // 對「Windows 遊戲:全螢幕體驗」(Xbox 全螢幕體驗)不受影響,一樣會自動最大化。 + // 對「Xbox 模式」不受影響,一樣會自動最大化。 User32.ShowWindow(Handle, User32.ShowWindowCommand.Restore); // Restore 後執行位置修正,確保 WINDOWPLACEMENT.rcNormalPosition 夾回工作區範圍內。 From 8a87555b505f5b611f49cde59234003cfd8100a3 Mon Sep 17 00:00:00 2001 From: perditavojo <117562794+perditavojo@users.noreply.github.com> Date: Sun, 27 Sep 2026 06:33:09 +0800 Subject: [PATCH 04/17] =?UTF-8?q?fix(release):=20=E8=A3=9C=E4=B8=8A?= =?UTF-8?q?=E9=81=9E=E7=A7=BB=E7=9B=B8=E4=BE=9D=E5=A5=97=E4=BB=B6=E7=9A=84?= =?UTF-8?q?=E7=AC=AC=E4=B8=89=E6=96=B9=E6=8E=88=E6=AC=8A=E8=81=B2=E6=98=8E?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit InputWeave.GameInput 89b1486 重發資產新增相依 Microsoft.Extensions.DependencyInjection.Abstractions 10.0.12(MIT), 該組件會隨發佈檔一併散布,但 release workflow 的 nuget-license 未列出遞移相依,導致 ThirdPartyNotices.txt 缺少其聲明。 - release.yml 的 nuget-license 加上 -t(--include-transitive),完整列出遞移相依套件。 - README 第三方函式庫授權聲明新增 Microsoft.Extensions.DependencyInjection.Abstractions(dotnet/runtime,MIT)。 Co-Authored-By: Claude Opus 5.5 --- .github/workflows/release.yml | 3 ++- README.md | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index ccfccde..0ba59d2 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -232,7 +232,8 @@ jobs: # -i:指定專案檔路徑。 # -o:指定輸出格式為 Markdown(讓純文字檔內有整齊的表格排版)。 # -fo:指定輸出的檔案名稱(File Output)。 - dotnet tool run nuget-license -i ./src/InputBox/InputBox.csproj -o Markdown -fo ThirdPartyNotices.txt -ignore Microsoft.GameInput + # -t:一併列出遞移相依套件(例如 InputWeave.GameInput 相依的 Microsoft.Extensions.DependencyInjection.Abstractions),避免隨附的函式庫缺少授權聲明。 + dotnet tool run nuget-license -i ./src/InputBox/InputBox.csproj -t -o Markdown -fo ThirdPartyNotices.txt -ignore Microsoft.GameInput if (Test-Path "ThirdPartyNotices.txt") { Write-Host "✅ 成功產生專案依賴套件的 ThirdPartyNotices.txt!" diff --git a/README.md b/README.md index c66fc20..883246b 100644 --- a/README.md +++ b/README.md @@ -593,6 +593,7 @@ Remove-Item Env:INPUTBOX_RUN_UI_TESTS -ErrorAction SilentlyContinue - [.NET Runtime](https://github.com/dotnet/runtime):由 [Microsoft](https://github.com/microsoft) 及其 [貢獻者](https://github.com/dotnet/runtime/graphs/contributors) 開發並採用 [**MIT License**](https://github.com/dotnet/runtime/blob/main/LICENSE.TXT) 授權,作為本應用程式之底層執行環境,相關第三方聲明請參閱 [**THIRD-PARTY-NOTICES**](https://github.com/dotnet/runtime/blob/main/THIRD-PARTY-NOTICES.TXT)。 - [Windows Forms(WinForms)](https://github.com/dotnet/winforms):由 [Microsoft](https://github.com/microsoft) 及其 [貢獻者](https://github.com/dotnet/winforms/graphs/contributors) 開發並採用 [**MIT License**](https://github.com/dotnet/winforms/blob/main/LICENSE.TXT) 授權,提供桌面視窗圖形介面基礎架構,相關第三方聲明請參閱 [**THIRD-PARTY-NOTICES**](https://github.com/dotnet/winforms/blob/main/THIRD-PARTY-NOTICES.TXT)。 - [InputWeave.GameInput 0.0.1](https://github.com/rubujo/InputWeave.GameInput/tree/89b148669ffe58d9927495ed0d89f9997bf4962a):由 [rubujo](https://github.com/rubujo) 及其 [貢獻者](https://github.com/rubujo/InputWeave.GameInput/graphs/contributors) 開發並採用 [**CC0 1.0 Universal**](https://github.com/rubujo/InputWeave.GameInput/blob/89b148669ffe58d9927495ed0d89f9997bf4962a/LICENSE) 授權,提供 GameInput 執行階段、用戶端、裝置、讀取狀態與震動控制介面。套件固定於本儲存庫的 NuGet 來源 `eng/nuget/InputWeave.GameInput.0.0.1.nupkg`,封裝來源為 [`89b148669ffe58d9927495ed0d89f9997bf4962a`](https://github.com/rubujo/InputWeave.GameInput/commit/89b148669ffe58d9927495ed0d89f9997bf4962a),套件 SHA256 為 `3342051977f6f1b91f2a18acfc224456320264dd67633ed4bc41c8188c9fcdb7`。 +- [Microsoft.Extensions.DependencyInjection.Abstractions](https://www.nuget.org/packages/Microsoft.Extensions.DependencyInjection.Abstractions):由 [Microsoft](https://github.com/microsoft) 及其 [貢獻者](https://github.com/dotnet/runtime/graphs/contributors) 於 [.NET Runtime](https://github.com/dotnet/runtime) 儲存庫開發並採用 [**MIT License**](https://github.com/dotnet/runtime/blob/main/LICENSE.TXT) 授權,作為 InputWeave.GameInput 的相依套件,提供相依性插入(Dependency Injection)抽象介面。 - [Microsoft GameInput Redistributable](https://www.nuget.org/packages/Microsoft.GameInput):由 Microsoft 提供,作為選用的 GameInput 執行階段可轉散發套件。正式發佈 ZIP 檔會隨附 `redist/GameInputRedist.msi` 供使用者手動安裝;本應用程式不會自動安裝。手動安裝 `redist/GameInputRedist.msi` 即表示使用者需遵守 [Microsoft.GameInput 授權條款](https://www.nuget.org/packages/Microsoft.GameInput/3.5.278/License);相關授權與 NOTICE 檔案位於 `Licenses/Microsoft.GameInput_LICENSE.txt` 與 `Licenses/Microsoft.GameInput_NOTICE.txt`,且該可轉散發安裝程式不屬於本專案 CC0 授權範圍。 本專案的詳細條款與免責聲明,請參閱隨附之 [**LICENSE**](LICENSE) 文件;發佈檔 `Licenses/` 資料夾內含 `ThirdPartyNotices.txt`(NuGet 套件授權聲明清單)、`InputWeave.GameInput_LICENSE.txt`、`Microsoft.GameInput_LICENSE.txt`、`Microsoft.GameInput_NOTICE.txt`,以及各元件完整授權文字;[Microsoft.GameInput 3.5.278 線上授權頁](https://www.nuget.org/packages/Microsoft.GameInput/3.5.278/License) 另可於 NuGet 查閱。 From 213e7a127cfeda2fb274fb924679df9d773f641c Mon Sep 17 00:00:00 2001 From: perditavojo <117562794+perditavojo@users.noreply.github.com> Date: Sun, 27 Sep 2026 06:44:56 +0800 Subject: [PATCH 05/17] =?UTF-8?q?docs(comments):=20=E7=A7=BB=E9=99=A4?= =?UTF-8?q?=E5=BB=B6=E9=81=B2=E8=88=87=E9=80=A3=E7=99=BC=E8=A8=BB=E8=A7=A3?= =?UTF-8?q?=E4=B8=AD=E5=AE=B9=E6=98=93=E8=A2=AB=E8=AA=A4=E8=A7=A3=E7=82=BA?= =?UTF-8?q?=E6=A8=A1=E6=93=AC=E4=BA=BA=E9=A1=9E=E6=93=8D=E4=BD=9C=E7=9A=84?= =?UTF-8?q?=E6=8E=AA=E8=BE=AD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - GaussianDelayHelper 改以「排程抖動」描述,並註明僅用於本程式內部 A11y 廣播避讓時序,不參與任何對其他視窗的輸入或輸出。 - XInput/GameInput 控制器的連發間隔欄位註解原寫「加入生理抖動」,但 GamepadRepeatStateMachine 實際為固定的初始延遲與重複間隔,改為符合實作的描述。 僅調整註解,未變更任何執行行為。 Co-Authored-By: Claude Opus 5.5 --- .../Core/Input/GameInputGamepadController.cs | 4 ++-- src/InputBox/Core/Input/XInputGamepadController.cs | 4 ++-- src/InputBox/Core/Utilities/GaussianDelayHelper.cs | 12 ++++++++---- 3 files changed, 12 insertions(+), 8 deletions(-) diff --git a/src/InputBox/Core/Input/GameInputGamepadController.cs b/src/InputBox/Core/Input/GameInputGamepadController.cs index 827b5e6..3d13e7f 100644 --- a/src/InputBox/Core/Input/GameInputGamepadController.cs +++ b/src/InputBox/Core/Input/GameInputGamepadController.cs @@ -32,12 +32,12 @@ internal sealed partial class GameInputGamepadController : IGamepadController private readonly GamepadRepeatSettings _repeatSettings; ///