From 82aa266eff16aba3592688d13e7b83c0bae16cfb Mon Sep 17 00:00:00 2001 From: skfd Date: Fri, 14 Aug 2026 15:36:43 -0400 Subject: [PATCH 1/4] Give Download the Explorer folder dialog instead of the old tree FolderBrowserDialog on .NET Framework is still the SHBrowseForFolder tree: no path bar, no search, no typing or pasting a path. There is no AutoUpgradeEnabled to set on net4x, so the Explorer dialog has to be asked for directly through IFileOpenDialog with FOS_PICKFOLDERS. RootFolder = MyComputer made it worse by rooting the tree at This PC, so every download started the walk from the top. Download was the only place left on the old dialog; the three upload paths already use OpenFileDialog, which is the modern dialog on net4x anyway. FolderPicker falls back to FolderBrowserDialog if the shell call fails, so nothing is lost where the COM dialog is unavailable. It also reopens on the folder used for the last download, and the dialog is now disposed, which the old code never did. Co-Authored-By: Claude Opus 5 --- DocTemplateManagerControl.cs | 15 +- Futurez.Xrm.Tools.DocTemplateManager.csproj | 1 + Helper/FolderPicker.cs | 170 ++++++++++++++++++++ 3 files changed, 178 insertions(+), 8 deletions(-) create mode 100644 Helper/FolderPicker.cs diff --git a/DocTemplateManagerControl.cs b/DocTemplateManagerControl.cs index 1c1c35e..386cf87 100644 --- a/DocTemplateManagerControl.cs +++ b/DocTemplateManagerControl.cs @@ -27,6 +27,9 @@ public partial class DocTemplateManagerControl : PluginControlBase, IStatusBarMe private EditTemplateControl _editControl = null; private UploadMultipleSummary _uploadSummary = null; + // Where the last download went, so the picker reopens there instead of at This PC. + private string _lastDownloadFolder = null; + public DocTemplateManagerControl() { InitializeComponent(); @@ -292,16 +295,12 @@ private void PerformDeleteTemplates() private void PerformDownloadTemplates() { // choose a folder for the save... - var folderDlg = new FolderBrowserDialog() - { - Description = "Select a destination folder for your download", - RootFolder = Environment.SpecialFolder.MyComputer, - ShowNewFolderButton = true - }; + var saveFolder = FolderPicker.Pick(this, "Select a destination folder for your download", _lastDownloadFolder); - if ((folderDlg.ShowDialog() == DialogResult.OK) && (folderDlg.SelectedPath != null)) + if (saveFolder != null) { - ExecuteMethod(DownloadDocumentTemplates, folderDlg.SelectedPath); + _lastDownloadFolder = saveFolder; + ExecuteMethod(DownloadDocumentTemplates, saveFolder); } } diff --git a/Futurez.Xrm.Tools.DocTemplateManager.csproj b/Futurez.Xrm.Tools.DocTemplateManager.csproj index 0a0bfe1..80d19e3 100644 --- a/Futurez.Xrm.Tools.DocTemplateManager.csproj +++ b/Futurez.Xrm.Tools.DocTemplateManager.csproj @@ -233,6 +233,7 @@ + diff --git a/Helper/FolderPicker.cs b/Helper/FolderPicker.cs new file mode 100644 index 0000000..26ff0fb --- /dev/null +++ b/Helper/FolderPicker.cs @@ -0,0 +1,170 @@ +using System; +using System.IO; +using System.Runtime.InteropServices; +using System.Windows.Forms; + +namespace Futurez.Xrm.Tools +{ + /// + /// Folder picker built on the Vista-era IFileOpenDialog, i.e. the same Explorer window + /// users see everywhere else, with a path bar, search and the usual navigation pane. + /// WinForms' on .NET Framework is still the old + /// SHBrowseForFolder tree, so it is only kept here as a fallback. + /// + internal static class FolderPicker + { + /// Returns the picked folder, or null when the user cancelled. + public static string Pick(IWin32Window owner, string title, string initialFolder) + { + try + { + return PickVista(owner, title, initialFolder); + } + catch (Exception) + { + // Anything odd about the shell (older OS, blocked COM) falls back to the old dialog. + return PickLegacy(title, initialFolder); + } + } + + private static string PickVista(IWin32Window owner, string title, string initialFolder) + { + var dialog = (IFileOpenDialog)new FileOpenDialog(); + try + { + dialog.SetOptions(FOS_PICKFOLDERS | FOS_FORCEFILESYSTEM | FOS_PATHMUSTEXIST); + dialog.SetTitle(title); + + var start = ExistingFolder(initialFolder); + if (start != null) + { + object item; + if (SHCreateItemFromParsingName(start, IntPtr.Zero, typeof(IShellItem).GUID, out item) == 0) + { + dialog.SetFolder((IShellItem)item); + } + } + + var hwnd = owner != null ? owner.Handle : IntPtr.Zero; + if (dialog.Show(hwnd) != 0) + { + return null; // cancelled + } + + IShellItem result; + dialog.GetResult(out result); + string path; + result.GetDisplayName(SIGDN_FILESYSPATH, out path); + Marshal.ReleaseComObject(result); + return path; + } + finally + { + Marshal.ReleaseComObject(dialog); + } + } + + private static string PickLegacy(string title, string initialFolder) + { + using (var dialog = new FolderBrowserDialog { Description = title, ShowNewFolderButton = true }) + { + var start = ExistingFolder(initialFolder); + if (start != null) + { + dialog.SelectedPath = start; + } + + return dialog.ShowDialog() == DialogResult.OK ? dialog.SelectedPath : null; + } + } + + private static string ExistingFolder(string path) + { + if (string.IsNullOrWhiteSpace(path)) + { + return null; + } + + try + { + var full = Path.GetFullPath(path.Trim()); + return Directory.Exists(full) ? full : null; + } + catch (Exception) + { + return null; + } + } + + private const uint FOS_PICKFOLDERS = 0x00000020; + private const uint FOS_FORCEFILESYSTEM = 0x00000040; + private const uint FOS_PATHMUSTEXIST = 0x00000800; + private const uint SIGDN_FILESYSPATH = 0x80058000; + + [DllImport("shell32.dll", CharSet = CharSet.Unicode, PreserveSig = true)] + private static extern int SHCreateItemFromParsingName( + [MarshalAs(UnmanagedType.LPWStr)] string path, + IntPtr bindingContext, + [MarshalAs(UnmanagedType.LPStruct)] Guid interfaceId, + [MarshalAs(UnmanagedType.Interface)] out object item); + + [ComImport, Guid("DC1C5A9C-E88A-4dde-A5A1-60F82A20AEF7")] + private class FileOpenDialog + { + } + + /// + /// IModalWindow + IFileDialog + IFileOpenDialog flattened into one declaration: the + /// slots have to appear in vtable order, and the ones this tool never calls are + /// declared with blind arguments just to keep the layout right. + /// + [ComImport, Guid("d57c7288-d4ad-4768-be02-9d969532d960"), + InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] + private interface IFileOpenDialog + { + // IModalWindow + [PreserveSig] + int Show(IntPtr parent); + + // IFileDialog + void SetFileTypes(uint fileTypes, IntPtr filterSpec); + void SetFileTypeIndex(uint fileType); + void GetFileTypeIndex(out uint fileType); + void Advise(IntPtr events, out uint cookie); + void Unadvise(uint cookie); + void SetOptions(uint options); + void GetOptions(out uint options); + void SetDefaultFolder(IShellItem folder); + void SetFolder(IShellItem folder); + void GetFolder(out IShellItem folder); + void GetCurrentSelection(out IShellItem item); + void SetFileName([MarshalAs(UnmanagedType.LPWStr)] string name); + void GetFileName([MarshalAs(UnmanagedType.LPWStr)] out string name); + void SetTitle([MarshalAs(UnmanagedType.LPWStr)] string title); + void SetOkButtonLabel([MarshalAs(UnmanagedType.LPWStr)] string text); + void SetFileNameLabel([MarshalAs(UnmanagedType.LPWStr)] string label); + void GetResult(out IShellItem item); + void AddPlace(IShellItem place, int order); + void SetDefaultExtension([MarshalAs(UnmanagedType.LPWStr)] string extension); + void Close([MarshalAs(UnmanagedType.Error)] int result); + void SetClientGuid(ref Guid client); + void ClearClientData(); + void SetFilter(IntPtr filter); + + // IFileOpenDialog + void GetResults(out IntPtr items); + void GetSelectedItems(out IntPtr items); + } + + [ComImport, Guid("43826d1e-e718-42ee-bc55-a1e261c37bfe"), + InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] + private interface IShellItem + { + void BindToHandler(IntPtr bindingContext, ref Guid handler, ref Guid interfaceId, out IntPtr result); + void GetParent(out IShellItem parent); + void GetDisplayName(uint name, [MarshalAs(UnmanagedType.LPWStr)] out string displayName); + void GetAttributes(uint mask, out uint attributes); + void Compare(IShellItem other, uint hint, out int order); + } + } +} From 2e6dccfa20fe24e96e963679e9a9c18eaad2566a Mon Sep 17 00:00:00 2001 From: skfd Date: Fri, 14 Aug 2026 15:37:13 -0400 Subject: [PATCH 2/4] Build and run the tool the way the sibling tools do build.ps1 and xtb.ps1 mirror the other xrm-* tools, so this fork is driven the same way: build.ps1 drops the dll into the XrmToolBox in Downloads, xtb.ps1 brings up a throwaway XrmToolBox holding nothing but this tool, pointed at the active pac organization. Two things had to differ, because this is the non-SDK, packages.config project inherited from upstream rather than a project written here. dotnet build cannot compile it at all -- the .resx files hold images, and the SDK build refuses those unless the project takes on a System.Resources.Extensions dependency upstream does not have -- so build.ps1 uses the full MSBuild and hands the result to Start-XtbSandbox as -DllPath -NoBuild. And the dll lands straight in bin\Debug with no target framework folder, which -DllPath has to spell out. Retargeted to v4.8 because the 4.7 targeting pack is no longer installable and nothing here needs 4.7; XrmToolBox itself is built against 4.6.2. test_doc.docx is the one from the X-Ray tool, put on the clipboard at launch because uploading needs a local .docx and that is the thing you always hunt for. Co-Authored-By: Claude Opus 5 --- .gitignore | 7 ++- Futurez.Xrm.Tools.DocTemplateManager.csproj | 2 +- build.ps1 | 46 ++++++++++++++++++ test_doc.docx | Bin 0 -> 25025 bytes xtb.ps1 | 50 ++++++++++++++++++++ 5 files changed, 103 insertions(+), 2 deletions(-) create mode 100644 build.ps1 create mode 100644 test_doc.docx create mode 100644 xtb.ps1 diff --git a/.gitignore b/.gitignore index 707d5c0..e26e613 100644 --- a/.gitignore +++ b/.gitignore @@ -287,4 +287,9 @@ __pycache__/ *.odx.cs *.xsd.cs -NuGet/ \ No newline at end of file +NuGet/ + +.claude/ +.nuget-apikey +# The private XrmToolBox instance xtb.ps1 builds, including its connection and its token cache. +.xtb/ \ No newline at end of file diff --git a/Futurez.Xrm.Tools.DocTemplateManager.csproj b/Futurez.Xrm.Tools.DocTemplateManager.csproj index 80d19e3..93b21bd 100644 --- a/Futurez.Xrm.Tools.DocTemplateManager.csproj +++ b/Futurez.Xrm.Tools.DocTemplateManager.csproj @@ -9,7 +9,7 @@ Properties Futurez.Xrm.Tools Futurez.Xrm.Tools.DocTemplateManager - v4.7 + v4.8 512 SAK SAK diff --git a/build.ps1 b/build.ps1 new file mode 100644 index 0000000..3d6aa8b --- /dev/null +++ b/build.ps1 @@ -0,0 +1,46 @@ +# Builds the tool and drops it into the XrmToolBox you use for real work. +# +# Unlike the sibling tools this is the non-SDK, packages.config project inherited from +# upstream, so two things differ. Packages are restored by nuget.exe, because dotnet restore +# only understands PackageReference. And the build runs on the full MSBuild that ships with +# Visual Studio rather than on dotnet build, because the .resx files hold images and the SDK +# build refuses those (MSB3823/MSB3822) unless the project takes on a System.Resources. +# Extensions dependency that upstream does not have. + +$ErrorActionPreference = "Stop" + +$solution = Join-Path $PSScriptRoot "Futurez.Xrm.Tools.DocTemplateManager.sln" + +if (-not (Test-Path (Join-Path $PSScriptRoot "packages"))) { + $nuget = Get-Command nuget -ErrorAction SilentlyContinue + if (-not $nuget) { + throw "packages\ is missing and nuget.exe is not on PATH. Get it from https://dist.nuget.org/win-x86-commandline/latest/nuget.exe, then re-run." + } + & $nuget.Source restore $solution + if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE } +} + +$vswhere = Join-Path ${env:ProgramFiles(x86)} "Microsoft Visual Studio\Installer\vswhere.exe" +$msbuild = $null +if (Test-Path $vswhere) { + $msbuild = & $vswhere -latest -prerelease -products * -requires Microsoft.Component.MSBuild ` + -find "MSBuild\**\Bin\amd64\MSBuild.exe" | Select-Object -First 1 +} +if (-not $msbuild) { + $msbuild = (Get-Command msbuild -ErrorAction SilentlyContinue).Source +} +if (-not $msbuild) { + throw "MSBuild was not found. Install Visual Studio or the Build Tools with the MSBuild component." +} + +& $msbuild $solution /t:Build /p:Configuration=Debug /p:Platform="Any CPU" /v:minimal /nologo +if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE } + +$pluginDir = "C:\Users\kk\Downloads\XrmToolbox\Plugins" +if (-not (Test-Path $pluginDir)) { New-Item -ItemType Directory -Path $pluginDir | Out-Null } + +# No target framework folder in the path: a non-SDK project writes straight into bin\Debug. +$source = Join-Path $PSScriptRoot "bin\Debug\Futurez.Xrm.Tools.DocTemplateManager.dll" +Copy-Item $source -Destination $pluginDir -Force + +Write-Host "Built and deployed Futurez.Xrm.Tools.DocTemplateManager.dll to $pluginDir" diff --git a/test_doc.docx b/test_doc.docx new file mode 100644 index 0000000000000000000000000000000000000000..0890752264415d7ba3d5b5a2209e4b4640ce1e60 GIT binary patch literal 25025 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 QVnBtXPk@61h8!OK8%Zpi2mk;8 literal 0 HcmV?d00001 diff --git a/xtb.ps1 b/xtb.ps1 new file mode 100644 index 0000000..a43a2b6 --- /dev/null +++ b/xtb.ps1 @@ -0,0 +1,50 @@ +# Builds the tool and launches a private XrmToolBox instance that contains nothing but it. +# +# The instance lives in .xtb and is created from scratch, so it cannot disturb the +# XrmToolBox you use for real work: its own Plugins folder, its own settings, its own +# connection list. Delete the folder to undo everything this script did. +# +# .\xtb.ps1 # build, wire up, launch +# .\xtb.ps1 -Reset # throw the instance away and rebuild it +# .\xtb.ps1 -NoLaunch # set it up without starting XrmToolBox +# +# The connection points at the active organization of the current pac auth profile. Pass +# -Environment to aim somewhere else. +# +# test_doc.docx is left on the clipboard, because the tool takes a local .docx to upload and +# that is the one thing you always have to go and find. +# +# Unlike the sibling tools this is a non-SDK, packages.config project inherited from +# upstream, which dotnet build cannot compile at all: the .resx files hold images and the SDK +# build refuses those. So build.ps1 does the build on the full MSBuild, and the sandbox is +# asked not to build again (-NoBuild) but to take the dll build.ps1 produced, which lands in +# bin\Debug with no target framework folder in the path. +# +# Everything that is XrmToolBox rather than Document Template Manager lives in the XtbSandbox +# module (github.com/comentality/xrmtoolbox-sandbox), shared with the other tools. + +param( + [string]$Environment, + [string]$XrmToolBoxPath, + [switch]$Reset, + [switch]$NoLaunch +) + +$ErrorActionPreference = "Stop" + +if (-not (Get-Module -ListAvailable XtbSandbox)) { + throw "XtbSandbox is not installed. Run: Install-Module XtbSandbox -Scope CurrentUser`n(see https://github.com/comentality/xrmtoolbox-sandbox)" +} +Import-Module XtbSandbox + +& (Join-Path $PSScriptRoot "build.ps1") +if ($LASTEXITCODE -ne 0) { throw "Build failed with exit code $LASTEXITCODE." } + +Start-XtbSandbox @PSBoundParameters ` + -InstanceRoot (Join-Path $PSScriptRoot ".xtb") ` + -ProjectPath (Join-Path $PSScriptRoot "Futurez.Xrm.Tools.DocTemplateManager.csproj") ` + -NoBuild ` + -DllPath (Join-Path $PSScriptRoot "bin\Debug\Futurez.Xrm.Tools.DocTemplateManager.dll") ` + -ToolName "Document Template Manager" ` + -ConnectionName "DocTemplateManager E2E" ` + -Clipboard (Join-Path $PSScriptRoot "test_doc.docx") From 9e7ca4bed97fd7cd5f092109d2e3352396ba3b41 Mon Sep 17 00:00:00 2001 From: skfd Date: Fri, 14 Aug 2026 19:45:57 -0400 Subject: [PATCH 3/4] Seed mock templates and photograph the two folder dialogs The download path could not be shown working at all: the test organization has no document templates, so the grid is empty and Download stays disabled. seed.ps1 creates six against tables the organization actually has, and takes the names from the tables so the grid reads like a real system rather than "test 1, 2, 3". Three things about that were not guessable. associatedentitytypecode reads like an integer type code but is a string holding the table's logical name. Setting it is not enough either, because the server takes the association from the template content's customXml and overwrites the attribute from that, so seed.ps1 rebinds the customXml of test_doc.docx per table rather than uploading it unchanged -- otherwise every record lands as "none" with no formatted value, and the tool throws "Unable to load formatted value for associatedentitytypecode" and takes XrmToolBox down with it. And the record has to be built in C#, because assigning through Entity's indexer from PowerShell stores a PSObject the WCF serializer then refuses. dialog-shots.ps1 opens each dialog directly instead of driving XrmToolBox: the old five lines for the before, FolderPicker out of the built assembly for the after. It is also the one place the two PrintWindow flags are documented -- the modern dialog needs PW_RENDERFULLCONTENT and comes out blank without it, while the old dialog's tree is a child window that only appears under flag 0. ui.ps1 photographs the grid. It is left in as the only way to see the seeded data in the tool, but it is not reliable, and its header says so. Co-Authored-By: Claude Opus 5 --- docs/shots/dialog-after.png | Bin 0 -> 37158 bytes docs/shots/dialog-before.png | Bin 0 -> 11989 bytes docs/shots/grid-seeded.png | Bin 0 -> 76477 bytes tests/dialog-shots.ps1 | 149 ++++++++++++++++++ tests/seed.ps1 | 275 ++++++++++++++++++++++++++++++++ tests/ui.ps1 | 293 +++++++++++++++++++++++++++++++++++ 6 files changed, 717 insertions(+) create mode 100644 docs/shots/dialog-after.png create mode 100644 docs/shots/dialog-before.png create mode 100644 docs/shots/grid-seeded.png create mode 100644 tests/dialog-shots.ps1 create mode 100644 tests/seed.ps1 create mode 100644 tests/ui.ps1 diff --git a/docs/shots/dialog-after.png b/docs/shots/dialog-after.png new file mode 100644 index 0000000000000000000000000000000000000000..818036f8e6ca40fa3841939328f60d6bae9e06be GIT binary patch literal 37158 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 literal 0 HcmV?d00001 diff --git a/docs/shots/dialog-before.png b/docs/shots/dialog-before.png new file mode 100644 index 0000000000000000000000000000000000000000..8f89274fddaea34e442245b2288d5d557dcde54e GIT binary patch literal 11989 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 OtU>mcl|SA3^?w1W*A4*y literal 0 HcmV?d00001 diff --git a/docs/shots/grid-seeded.png b/docs/shots/grid-seeded.png new file mode 100644 index 0000000000000000000000000000000000000000..51833d0c88faba9dd5094df34b34593238959d6f GIT binary patch literal 76477 zcmcG$30RV8|36w&X-%dzEmm&LG>w_LWG1eVW92lB+D_&|re>yyO6~%alvbwHXl|&~ zR9czhiaTVcrif^yD5z)(riiEr$bQgw-uM0e&vu=2o$EZ;CCl^h-1q%_*UxvkeQ?&@ zb<6jAzhARv&6d-@ojAW{%?8aiYt|WW)KH&6J5SoH-`2vu<^Mr|chB;d6gVwM2oi)#I z%KdZAoizsUD=)oVbD;HJ>Y6(nG>*Ki`{DQF;2*xT_NG+zHYM=x4{mcn%4+wE?6ys{ z*H0mVsXF!*{vGLlt|v|5=;%sBN(Ao`w|2b#d)O-&OQZ8U9VxrgyE*^=Y zcYzY7W0D&F*PrNmhu^W2%~l=76Qwinx;5@K`btWlng4szpR{39;qzWBX_j65(oK!sqkhJ)Oy=NWBuE_n%=iVml9H=cs3G<~Z@=FmDZlxSytzMRGw0 zCoe7S*>G@20mx93T~!IU{Z_cEY36N7w?WMCIc;Wy&F-aE=af(vcvMt>e#~fGO=YTi z!>7cr+i@FbisC89=s7VY*~lFlAsF%^n#Q0avC*D^3Uh{JFq$N)!Ecy2A4R^YGVQ2` zPB3Z(+ysMP`k`kULnHI?KJG)sP}=OzJi_CSzi1+OsH&FP?=~eW__4Oc$@rzd7b9ZS zhH`mOxLng9I38LckBSalT)uCHW`>y{LdBbzMwP=e(#}I-2UI=?L9@OLZBA4~eHoy# z!rW_FGC?%?SSR853fDf4SC6wSP?9t7se+idqqk{po(6U!y^MM4sO;uiKU$sVkeBU2 zC+P(4%ZHZ6xdzjXnk0cribIPMc@%789~=-;*;CCR)I1LTA<*_)%3)f8BUWig= zPwfq&0h3obDtL~t?@j)*(tF@Zpy1iA?`{Qp`AvoQN~b+g_8T=zk+$FbQ=pcEyR@Zu zuHpQ!Q3K=Gy3(TGB1T>|1b#`f@fw)2in(N-O6aa=xV-1Y$Dj4Paa*6tvYAuYY0#QT zgS_-jp7bHHUBFERJjchvZ0s*#UjF2j$7_B6AmJt>_J*|Lih`S~r2_$laVf%c%+(GvrriFa3$#&$~0-6)!+et0i&yz{+VWZ~OQC-Hfa^BZkcGfwd$wXM0 z0viz58p@0kRI$zfj9?Dd@GY`I%_L=+Bf$_!8j4#MWXbLj-nrL$S4frv&AofOX60<+ z*LI04c@_oe>0v>PQB0X2L-DFVLJ-Ad;Yi-6P{>G9WW&V!0Ref$zHvHWjKj|^8|HZt zx`nQxB(ZoWX_)06mK&fN;@b#Q*wGo}ncK2vFL#uuH>*A{23pH2sWci+^l<`JS5C+U z54|<*bn4~AvNAnUZF4@JrO85}-JrrD~J89EN{l=4}*A~0(0J;f|*us!S++pT)oFgm`r zEV6OAf&Fy+foT;@!t91!NQTY*;+<@4B`+6bk}WzK{ZK%qe8iRng?QFN_o5s+2=$<5 zZ{?MG9=KLt2^`}aUzI7#-|dg0)$w>7zbP)~N3mz)qYA=E#2Cy4aM(px>`CC)vhhJQ zqy^n4JzMZZ_HI~2tSrkvB}y@^!trdPcnqsj12C0B=4&#`hDpQmQtn|f0#JH5gAr9u z>tg@K98Jd7p(R~Ap5XzsyJY+AJB>IOW0yf)sVU6B#GwUZ4^2g2^+M@O$$_4Y1OQVT^kuOrR#nk?e5J9Ar)*$@cC8tJu*$37W z(tKX;TeqYB@KwFYMnGxyJML0#Md`$cb$dpaX?4VKsb9JRKkSS2De*!Mm4SL@2oElL zxk7U%MdB2;=y4Qcgg8s@>&jzfL+kxYsl(9`%(CEk(w2H{hLV#RRe=1&w!lKb<{6;F zGB0el)@ONCq~MDP0f2@YJ!aSw%D9^Kyvayge*uBFEK~poq?0pH|qI9echpP3Lys})!c%pm*KrkG~XWJ0$6O&RvWfRGucmy7VGNn*H5AMnv>DEhDk3DuHfnh^ks*`q?Fz~wG9IZL`4*m zUsekmg+2(Iug0Dv5smI&f!6DV?VV!XBxA!sUn*3>DLw{HK9oHKHYaKQpy2&nn~L{7 zU|5_N9ZAP3-c1NOqC%F@SBgX8vguF9;z_5t^f0qJ%YPGLjkIsc9_MFk;pNb;{E$dib{90brd3(Vuvc11$bKO5v`;;O z8qB0YjY(0~wSO zZzQ0AMjFaywt+R)MBA%Q4eA^Z82e?)xV9pMg`XNA-!pLslY*Tl5{B z4KKCAAM8HC9q1gYW(~%53aix?^xIM~JTR>B534jU3x_mPs8TseC}6gir8C==@gIw# zq_q7j7XGU|P7TWf#&L4r6UG0AWD9jiS2i2}YWeCu5T;{xV&qL1sOw)q)%PzB04YH-HfDS<+B-La0bbW8y000yKNEN5XxB4d}AB`@1FzSo-Vk$#7ufpBo z(`rv%^iA_FU^Ld>(r{aZ>23U*#V`Nh->|KIg6&tRv8KWGC*gZ}@4 z!F81U#_;(Ch!3=|i4EEf7Z^?Y3P`)*Z5Phq>c%s#?fn>xSn6}7PHJi#%;p+3l48VfB|3YKHAQjIHB?2^Lnu2HGPxce9uqe=Vm z`Zp(1ohc28TzcZ#4P~k7SK`I#b2a?FnCXWUmZ-(&EFj7Y zA#QZNwRZfB@6sW`*g72zp|w%mpARnk8t?^RO<9GtH*SRkk( zK9vz*d0drJb4YU5Jw=hwhDpy;7)f*N=EpHuQ{>XbHTiRk#7@U4Hr~dVD8DomWM{Y{ zdVS(MnuZ%Ifo;$B?bW_&P}xN3;5&HhXq>cNUfxoyL7P3nqbRMJF~)D9rr7)B_yG@} zrFtv<#GVHhNBDNjEzi<91!Bi*VNDYED&>n1N)26MwHxEb_k_d_%d2$V4Yllf)i3(n zHg2r(-^b|(_y&!NhIFtjR&A(ztgQ2u1yEJWsl@3YA;s5y|2-@|oc0J6@g%OJ#>f(d zn(%{9xx{SXjelL9chSLmD5fxhEn_mAC>lP!crWnavY-}88@`4h11MBrqv0Q^iuk3x z5K0w9RLk)!&d;h(U?1ZoQ4>cUmwR0}g$ewl#l*M(FtbGX z+$GpCfK&ON>a^7H>?}|qP`(tCD|S*CaL!O=C$@e+I?o|np`tl~oGA!!?;jY2gosff z_Gn4x5W;B=3m1FdY4>5r=`VB*-l}1;PuQf%3pwE~zFGmv`ual0XS)U(X&cL{LI+2` zox1_a@_$Vz9Yqc_R;}sPxLY<$4$01&;>UUJ(Jri$o#fOT6A#{`(seZWBvs2b$FOGl z@ZxLfp#^+_=x+UNvBY#N55N-Mw;P}BKu?Ey>D7KLW@@V+ln+2f{;Z=K9hf5}Oc)Bf zt2}H_k~Vq{*jvcy&Mw8})>k5n;uM$o);b`0xTVhUsIRE#Om~V(xE4M~quQv1DzWnB z!5m2u${OS_VMMVY3Te*_W;=9Ab7sz#-!h*+6Xa5zhU7C~()WyCSL}0j&td)0hCTg> zvt{DsmS>waQOg$v-w@fFwAqWyFj2*M=4G`$Bfq&A0gNQ`8)~lgHeZ&1&~381Nj+_8 zi&L^STmR&%mcJTP#CVv_@>~;tn*c;wcyLWhl8#L{kMLebYuS=wc$b{lToIHGG;{9O z76!P-(hT7rxHy01ynLsC4{W+#C>GL#?u>QmY{pEEMyg6%62oQjZLa3jq!t|oSItWh z&w#^MPCBJM9}^A$lrJO_2V!s-X;IfXVUU8gfo=J&B{RG?p52FA&--!3re96a(Ja;W zG!%|&c4uH!2edR&!{WVz)l=>k+sLEwoXNFLoqNtC+e@ z!N~Y3EnR;Z>RsYzd&L`rbpwrj5?$WnX<=>L1ce3eT0eITwOp8;15$o`D4FnR>UNwW z5qoBpA49rT()Oub)%=`p9!flZp)!142ee=%_-lVq-i7r1Tm?X&8I*?~k@K$k=7yon z9K%$7s-9o`2 zsl$uoWQq@{+3qGFyd2SLnA*6A+Ki6C?R^8R>V90*%*B4@+ACi;4)?Dv@LE2uuGq$EVml-HB zEX(GJQ#6I;Lm{xkWm)Wq5eo6Jg;NuKmXT1m*PPH2A;X)K%SKV&(AY?0$lQ;Qpe2AN zCDeKMYe`QG^8IiOOToU4w2WmTbk_6U_5>JJGa=RWfjvPioMgyyuu2(Y>XC=>67fNd>`+>c<*VyNhAKQ1b@%QI0>|_gWSRkt`X3Lqd__rtCbH6MqN%>nr?G z3+3FNT#G}ADi4c|oTmjDx44N>yRu>&H2v~uJQzSRugh`qKxIqDXsqBKO7-{{P*7G( z>~CTNAVI|WrU=80SloHZQZ^)?kD-`NA*jQODlfF?jOGYn z5egrUV2C=Y6~aJTewfUitCQ~QKNq*W@ESbo_qTGQ52wlNui;kG)tu37E9IH0O~6N9 z0Dt^hLg|&B*PR_ORMhV832IA!6f-J(`mD4;;?{1t_V>3Lkaz82qBGFlQEF|8IueS0 z-z*bjC%WGEhGlnh_Sj1zb^JoT6l0oP&H)QMilfZaqC0T_LVE9*Al{5tXO=ie#aMM> zETQ3A_zl_EV1>-|?z;>O zE>M0+zvD1hPnM5j3yqdtrwabMhq6#EVJnaKN;|#Gt#n5tpGZ=?v~xFy)%WJ#?$dkt z=ll*q5Drn}Nt7=Q^CyXO57%Aa^Haz1U3nIfTaQ?{6Gvdq)XX<6S?xuXwl5SK9W+wk_*{dy)!2gea^9;J@BgGw2ApoVrKE)#fW~23(a<@ z2&9sqdYzXI?OJQX3bkg|io07P>-lSD#3F&Iiu5g%fH!TsVDRPQq> z{R74%GT7qguR!pF_PZbb=T{gKNP?DK>*>_lZh8P%DMiM@`s)v)$ zy>NCaQ8;Hv<&)8mGE1hC!m)hNtQd@9etc`NF55RMZmZS}{0`L84)_O|Z)iK+=j`V7 zrA8#SQFjNd{(U}t#I>7`*oTUr2O&7H?nO{RnD5y-G0q);Z<4>0TAjeGRXO%o8sriD zyOh>_OTS+WME^ajWA4Y2bdYb$kacs>_A=Lk^0ItaX2Z>nl1hZ5QJoA4SE|JMhj&!p zdDag+65B%)<%)r7m*V7+&}cXRr8W?+OPV&pA7LdfobG0kJ~1u!u(l{XskcePn)fV8VT9PBkPs>VoVwL;DH$&o}8NrTCvZ zk{Uu+V3z}RwAH!9B`X9NEp}}^UVcD7aj^>(Vu<|K^Q`oELf@2=vu+;b@PNgy`*kHl zB_7I?P@1iUzHL)&bnBkcXZNL>)ROV}P^LquXcu#Ae)Kx9hMuk$7Mdh{OSptYpT)V4 zq$`_d3ASbNzrILRtBJ#B4F8OD<&%>XB=e00xKs=U{P z69ZbhE(kJmI<|3r2No3sY>+H;3&LbMk_pVa9G0T@3*QNBB5rF4nrMnfH*7CU%`a;6P_jD~kIzrbP8`h9 zMDq#bW3(PC8E)~iV1N~iwo?S-tw0JUJ`X!8Hh`yY(QH0GpQST7Dp!&z6n^9Iurvnr zjtWZ`r7?^uyVwt*4)sQZRI7_&zBUR+y?E)+)cUp8GOV_SE>a<}4=a6XbJ;ZExzgq_ z`+fMMk|PJ0_YbG)n`gTb?x^`)w>%odLbM=?uAe=7!N&f9M<@`WwO+5ar8u`EOcl_Z zek=ONH$I2kJGg*5k#&CF14V8Do!h#M(G9hmCuUdx+m`r#b%w;= zmGA=Kv&)@fyt&ek-}(4D_LXm@Mi@C*(vS^wB4J3=AJK2^V_DYlV|QBrnPJ_$B0=o~%No*!R%hAB-AKk6l>D_FCo0}@ zw~l5_U^eqtJKgF~fs{sQc(ck)l&}n}cAJX0V>mnCPG4PR6^8ihru7}1CMNJ!PxFX$ zo1jA^oX}|=l=sgBb6%21uNA@+9e|uElp=~FH$oK=wYq>$N*oP}peZkTuWQdyP@kuH zK^DsgF~*)9SYJHrCzJQX!UvLm_MK-5=X*7h_(;Yl{luA1`mr;f93KxS za+BZ<>{yV3qesd0PZSDBIbEA9 z7>`)QpgPF|v!h^~;rc(_y4IARmi_Ek=XCvfB&}Q@aMCE4zP3xbji+Zf+zXB@9Iw12 za8WzdVH0(t-CbIM#*D~<1UV_R*_6YL2BTSSP)_1Ny3L4+`AesG5ZpnO0+hJ^IDw~`nkXNDHk(kKHV>& zui|K|{twP@A-wwqO9>a`Z--p>Ef-%D@L(uV{;8;E2+IMm8?7^$&Md0dLcPU6Mc3bdP8-Ab!&7X z^C*Q`h-{E>Hd|Qfp%UKI&n@AnetfoZJq!t(b6e3oI95K|az~tYH7+9ERQ2b9c0i#{ zOrS>_J?YhCV2J2%i+8yrrua?2zR$5*6S^2Bn-rrNfvHe&k)K^y9B=ULc`HV7sJV8pg)^$il|bCE&zV&0Y3CK|oC5eoY4Yc*b{F?e=LCHNg~d9z?n^YkKg+Z=UE)Q#{e zwVy>Tadh*xkIpycQRUxEB>1g3!A}CYM`6~6B);i)E$}c9y~#m<;CSj5-a?A=b+M%7 z*%FGt98nNgCJezJHNHw(w1=}?`tb?b8hCjplvZsJ;6qBwR0MZT^Q`o1>9aMc?z6>x zMYtO**k0q5VozPWvXMp@k=!&@J9m!#jTPm85MRWY_$7`dAr}YQs})A@A0Tp%KjwyEGFMxl`^d~%9c&LiF%_2 zYQ{Gx^x*?Sz7*rOb+3`)4zPi!DT| zNx`dpj|)sUUbU7-g?WZj&tK8D6GZ*4<09(t198#vyu@;Up{~Ht4jysw- z{SY#upWa;qTTZU;(?}XXtJ!NUr=z7aJBT1kcYG@A{+0j5&#v zX@aaRoD}b7Pq$1pE!NzSccxO-=>V^!lcq)!C?>_EA^G^+RFKC;WuL&^#>nAIcxVmMIlfNE~U^s6l|a$--;hG6PeN(j03(C~ zx3C)-mW?4=GxwFfwG)iVx(mU?Ut;eq z>l8M3Bu;-uX)(C2(v2(X(U{O-5VPJBr$!<)<%bel^X1uWw~6hwb0)1V#;9dHrB$r3 zeO+}S3LvZ0cVQCxU&JKVe6K-`FFOKagmecQ?-9J%PMH9c-oA@rKXt9*@6Bv^CU}1b zUiH$40Mb#@CDV2;RIopA_-~2s6anOPu=vTuD^%2+e~YyuE+YB@LWBv3L*43le~cv0 zwHvRYmdf&`@=!3Gq2ts^j+oUP>h7J87AI1J22Y%Y{Db-}I+l0Lb9auacK!_hh%2no zJSV21iluE^z>@cZ@@heB%8dZX0VRb-iBl;H`p))BGr-7x`Q%Q>F+F_qm*M4tv}eto zfvkC_phV}bTJ|^<0B?cY^<`N0mafSY?nm5RaS|iV5)SsCGzKm&Qp&RXmhJHsZ`jo4 z7)LY88XtQBARc>NmGLjiU@Gg%kX<0Ajcv-9vBU zP>ce@)(+<&N7|k+@-m{lg(_W80mZ4prZTUv~9l=H!pr?QE)j&M^zIgte&Mm#MMZz z3eZ@LhM=H(2&S1oN^MqN7Z8f`{YIDc@BpJ_mgrb=5-6?>-0k73+$qSgz-#jUFqS3r zy+#pXTfetoiEH3ID$?+7QV%J1oQxJpp8!`9h{JQE;jLSo2a0#^_>!4s9}xEzQ^(h9 zQr8_O0CQW~`M1?J^Gh1EB!%DTuA>3^OB3z!j`YcKNiE#BA@!4b&Ie;ZpSBh8enzP5MxDoBdKgefsidup>Ef zyb_;d#ELGklb8l+I6o6wseNtD7qYj@>h;~u(DH< zY_@j)+JX;IF0&y=K*%9*cRx-ZX6YoFFa`>T_U))9${)pKMky!bEH)-Nb4{s^rZ;s~ zQdxb{44nMuPphROkx3>Hv6L>CY2cdJ7>bJ+qWg$7-GD`Sra!NM3ctA-b&|a1H&emr z7EPl%Ku)`4+50;+EI&P7{C zYh6KA#AU>BH}H=ph;TPXm;2UnX3}t(6LSgboCO7ZUC0 zS1sR{fJz;=tw%wXsTT@A74FVdS9bh6-v2zRdavM&%J@gcqby|T*w=WfK@7I7AMy1mbI%MD}HqgCFtmKd9K6hLoZwywD*3jx}Gc!$!-4N0-0Qv0zpE8%{A; z{_!0S@y0H`>j3Aig7vA;JX5%`&TSD&MKMZRypMZ9>-$>_;|0l9xcqV6mWu%gQjpCm|moX2rx@!M7yvo9Ru8cW90s75OAiS$Lt_ z7^sAx?QM;G6{(t(+!UiDsQI3bZc?IfI|oNv>g-mHU-AeDgehnDue7=S{n~Kd{R{CE z#{hYHcuAm0QrO710X0tE6hS;!m10|M3PdHPuUf_&&;NEX-uIfwCdt|VTKp(nU3mz} zQrppg9d!u#@Dxxt0P)b-nc|Y79k}*6g7U-aL$AC{LG-j4-X1qrE^pPo8o2oH`|jTt zydf_ItXiBVZkg=A&69eEs?@c*KmSKN<=V^@c|HE$71gcjS}B_DQ0XWiquLKBS*chN_q>0Bb_{x*Hwr(UPK`_E%t2A%R2&r|vY% zQAin3xhZ^pq_U~xB+Ca;U^OS>ET2IIcK^X~$X8LgB$yHpQ#_Yszlai0S+Or|dbF95 z4x8J%bHna+qrt@iW6S?BgK!3N&jaKen|%b#I(8B(;H%hXAZz@x+@iZ9eb`Sq zn-oG(Sze_oLsFpi1{TE;T@$N)U23T+2CoQIOX58=xQXc~pqJ3o!RGFJrfT7@?3Vv1 z?FsL)eCcDB*}%|mqU7{%P8~md_}xKrbAvFV(hXI&oaonIRPYOGgH7?S+x;BgcjUj* z&hUSr)fKb9|Jwu9#SY2!_*|JBg^p;G-@*fe$h$qmqH?Q+P;#ITB(CY-Z4yhXVw>|KyjNQl zzw=w5-!nayP1$nd0=XNHPrRH*SXnFqfvQMuFrX znOemmqgfPMour?{v<$45Eua$VmpBSmeZPF3qgkb5_<6b>!sz~^O8LI4Y9iRKed7*` z+}-A@_9O>9_YGS2z=~rV!lg!lX~>@B>XHq=&2=7C?3}Q=f4+Sh+I7vu#$7Abc-PS` zW8P1+^%K@73*K<{r?727<(t=4J^ZxP7x?g<>z<9#`FQ<-q6KxvB%^wGq=sd(Jf-U$ z(jyz?akhhppD5_s9mJ4clYcMgW5MJ-T_sr11ty;FPtOoCS8YN0mGNsw<{qL|eigo^ zA{WqsHN%YX@(@|x)vbW(#L04fV;u3zK<8#ZwtCt{VX+CL5`QeaWn_oIEw|{HeyG=6 z*bNXcvZaPy@=?Xff5A3wCk(4SO_8JTKZYnK@9J?|H_Mw(S6wA&{F!v7eDiu{`#sQa z*VlcBi%mM4{3Gwy_+wRb(skR7kE-bp+hTUz@W36od#)uM$S+qAg5?o;l|9yiC#`>{ zF`^e|hM-TDW+Fm!_hxwzMUKM63q`^4rB}Sd>PxGsJf#4@A^jeTO8lsiq*8ctJ?j;C zgC69|Nq!k+rZc#7G4`Ln^Wg{T=EdrkXO~trK>r?EXk;J}PDTj%`nN%+7P((fw?5DG z`>io9=fd;#$2=`}=s|Eq!;QPXAdi8Qoy}Tn;)KGa7)efwckrG;Ux>bVNl5P@$ z)i>7RI{SY#1P+(r@;Sv&Dp1)U$Huj@jdh?w|x(D;*E33e^?d~|Bnyoxw0pD-}P7jk1zau551VY z+AFf^w^GjCi20w5N+)thD31Da<&!OfF|tr zv;5C_+ebE7J!}2M*@}+;dbfT5OFtBRyEbzA45TY_^S4BGzfnl5co>ek`b#mbt9;P` zFszrkS_D_u!N2y*k0$U9)J6R9LfSp_E|PaV87EJ#A8#|xb2W^6c^SE~i6EJ`%vDat zR7xwiypt;yYB+mf%J{SCtuh#O3&chNGq5av?#n7idA6hKGsf(fgOzMz0`U}(RrDF1%Lw0vr21qZ{ix=-s za%WWD3e0;WJkM)vHc`xWZlATN^5TT5(w5>%Tv@?cH>$l6gNE9-n3qh?L@=fq!|EnT zW%y!{*US(ihJh%$7#!2mQ@q009F7}c#M;~TCfcz$p>)tf(9A7sti*wd3bygn=eR9v zVF{Acfd&q~8t540bk$IGWwUGg9H4{82y_Q}TQG53jBJeg>i7?|*W8s<)MH%Z+ejZ4 z9pAd~cb23Er%7XrYW1H(p|xpzW~SuTm)xEb*c)kQGTKx%kKU)XR1;OWNPuP1zA!V$ z!70$)5w0fDt5W!m2pHQiPhcQ0mT8y=Hk&V-tt_0lf=<7kcVTSP73 zo_agLHw*L#p|LwchS}8`xrZID24~1hJG**FP__Qi&-c)kP3OIgN)NYXPM@FotvL6W zw%;0~SxZ!EoACD<81Q=f9H`93vEYfs81t_+t{A3|rxk4$$Rm*PYqP(6&_K;qA+Go8 ztc9Vb;Z>1)v_^Ms)=0&^ziN2}USbZsFqLr?KU5Pkr=4_sdQL~NFQ=>$$L@uOG(ruBSUgLy?GCkBMAFLZp7A(urmqtY&-Odv}No=GNq?HxH) z5%tysKCDzM5c~y~YvFaJvz3Eb(^{>T4Ck5XQmTcwrh{)*Tb4;B&iY_$%jweE;!uY@ z=_jPrvY48tu84DCsT18wMZalY1#dSNg9Vp6wOOZTwr+yAA-2$HDXDE?uv!L5?nF_pL!o5S};;@o(Ofm?!+G_c;FPw6$ z^&VOj{Qh(e>DgBxOZ3;&>y|N}5L`+B<|cd6rpBvk3A9PzZJ6nw6PQppR!_w%d0vgAZdm`)fh)15Hk0RE*!}_^Bdnhg{ zdL0&~N>&Q8N6M%XqUoYUF9xs#3dj2*^tgx~|JI0ttHl)IPXu$4A~|4CI1Fxbmqk0hq#Zi4Up9Fc3>JlXlFUN zl}*y^3(SOevF{7rn70|kB8N^JzOnwJ*=(rnDZ!%4zK@uC*n?(sx&3L;;na7q?AFcS zjVRAEVVQBKWKGb74ToqY%-;z#>%$$#4#T=^Qq42GSAl8hVwWjCA0KWRz5T~^B#2@L z>}(l3vEl+pk(%QsR5R{~Ix_XMy^>&m;^@MuXS;h;(!y}~*4I9h4Z+y3^UN&JmwTsF z5jfUUiFO8rqS^+NlSB!c z?4?}YDb$nEgbJ|eMHOXeXufTzZE6S`a^nPNg;WJN{N26;g^t&PldiUXmb zCca|4h&R(8;;lJEApG&PANfPNpn0Z9)`fhmZoZ>g)F1gABaOT)L%OKy0}1%;x@2gI zcy5GSnleBnr0wO<>e6Dmkc<1_q6le2zetZsz*6t}HqnVaU^na*eskS!TwP(a_(iCf z%yC^6YMos0dREs?rLGc|UUtnz^kx{MD7{F z?-ie{H>l>#VjI%-BeI$f6XU#u0v{j@O6t#cC9ukylO!F*Is+c1x_V(;s^^l?iUlM{ zn)wKrn#jqC8B#SY)MyzqfH;QE)lF!_nP+epvPR~ON&ZMlWk%9;h;I#EY2Otg>%KHp zmr6O^n0{1N_IW0bt&5v1<(}qzz0zpxqu=9&rMiG~5p${C7>CaM+xdFgbcgAeGvsEE zhAV{rcSh3Ah-u+$xw z0|sff-K^nbAp7`ii$>|(reBA8+?STlyrsLV=mPxab}!t*okP1F;|0wv%WW4%-*;oK z+78}u)c+V3Hjcawi#)meEPd3Hddrg#?iA6HvrF5i6Ip-dGj3%v!MDI{9~(8iYXugo z3ed=Uyp{(4O7q|_QpT&X7d39;ZAT-Uan0X`oV^^*soost%1F(*PjQldY*IudqiyM^ z#I5UTWnwJ8X<>Aqex}D}8z;Mi%vSR-9x^geG&vZQ6v+*$EKXjE7#U#*KNdXStQi>B zFq@rvK=D95zb(c$e)^SQ+e(}I@GY0)l8?`JX)%g7@`BV)TN*@4nI~AFfHz^qhg^=k z*-^gQlK>{5rg6eP{m_i?@XI}XE$pN=Mu;b+-`Lo8R}mwbH&vGH?A+mUsVLEv$_JnX!VW4$N@k%m;^uhR|(7h z`U>a_pmh?qZcFJ^>y7>@vY+a(KrW=JF@Ttb0;#7mFW=?)&$iTwDWKTyf9#Yl_|~Qi zarCy0r8i^~7g4}vot=%t;Kv4T^wBH!<0%h)}!;a$@1M|#QcbiB2wn@`(eC(I4 zH`dDfue+$sZI&#$_wJFtI%LsZKt(A9l&V7EVYpHK3#FTRzcW105SO0JC zwpk;ufyj;tR)Ks#?D#sH=rcE55$XD?~v@z3$wb9i2D$awhzXYB2}HCsOuAW(hpG9H**vM&G4 z-kv9VCCWuJI<>TSm^7DPF^fBF)7>(`BYdf?efSwvLhcAcoDZ?z@TxR&2g0Ctkd)pZ zSarrXCRF#j46Wi9OnsE;RsZBdy2!p)Pt*C%=lH=Cw)MFY(>BkILFBi_n+ntpPhcfx zECAs%n(L=t+Dj`>*T>_Hu(Ziq9^XUu1^HW{y{@tI~WPA3B! zW)rkMY>Sqat-r6R+(*9xe)#+{n)9srN(^e8^WDxLZZ>Ut#B-^L#AVu-ms|6|n!N3= z5&Ye>S=fxVXcHh%5_;}uc9x-aoJ{CQA+R-}`61a8Wzvx~~+m3#l}FEl<}b3~66nw3hgP6yTHjdZgoQpt=o^o=3n_cw|sqDt<) zl>B0e+8Hhxdpq=cu2(=`SB3bAfO=rRc%xIVr|>5@tpaVP=Fl7WqrMi3F9ceQH zg~sk&zrI3Jhp4&IzNmB1=G|GYg^im+Pjq_Ww&y#et~CcfgPap8J*K(D;91t+)UL-R zT6by$^_K@es{;SLk~s3G(IMGQ*~x50OTSJTb+2dx6qgyuCWVX={@l0vq|`5n##SS3 z6D1aO?q+MlAk;3G@7zxGQ>W(=E9(`>|S*EjBH@GL|%9iiHNkvjEz z?r{25mGnLmH&g*ST~Fw~nyaebhcBT&ehzuN_+iD3MQp4+ZF^G_BPOys6~gA-B|h(O z;i^(Y+3lNlJ>+1IKMcU8%m^`_pUREZ% z3Meu@h@p68c|KHhq7-{qYgG{mjnEG*at(&!7)a-K7a&UekO%4wj%^BzG%Vj}J+hvI zPq>6A1KH)2qdM)`+_*N1FL7cTFjH<8Jc6%=n3g$>YDHSoOU4a_Z# z-WA}P|Bbfy4r^-bx<{j^pfs_7NVlQVLFrY+4u~kdH))}_03iqhN)@FFQY;iHp@rU& zVnUS`5{i`215y%%5V$)a=lH(oeBb@u-}Br*d4RpwT6^ue#vEhJxp6-k(z0LyFg1Pc zo?b?bZBrg>$hFX*R$#M2>)oaVtxwY{X(5@+q)voO)pv<|@Y4?U1zhuHIwQqu$cjNM z`-sQ68$o{@tYzU1^_xxb>X+_tOmFR^fqw6ilxiXBY3h5-Z_*PLy+2x{xL;n^AcYv0 zFy=7BV{j7Wx$V=v%QdaTq`vQ%;ss;co2$N0mpll;)P?tfnn?>-s7hk+)23n+F-x2r zBuATHO|B7#f>|3~mQ+&Dy0tUTWAS zKE?UuB~N@Lk8TBA5K|ylOV`v3f#Xn7#n1)*7xiBpn&dj#yQIG~R>8G3+taAhlKYHprw&`J15(DiRtERAi z%j3t9kb7IpV7CK`3h4(xUSI!Z9)FLGuIq+mt{vYQn;H=I6e0cyXokrU^avg*|n%Qy0l3$SC>^ZpPK?|9*w|%KQm{87)zQMdzaQ^OGGaN!Tt6B@a~50(_+#~p^?Vpj zbMtn{FXzoHg2 zQ-F!Myxyo(o2Qu<^EtZG#E-+z>me0r?Iq>W9i&{vRgr=uAHjvFiXXKz{unyxf0o$t zpm4w|lv};zZC`@u&mQDss5&+ zWq6M8wMGquAnM?e10ev;3;xL20|LpJc8a|Sp!_e0gA&C=d*@Mp{F&Lc;`+XkM&cu+ zs3;8Mn=sVu?OcVsA6^6yW6XD`?-m|eF&6baQ9um1AS&yMx+h5^!}vcfMaSVo5Ky(S z1n@BU`H8Yc^o{lN?JEwjt_80Ng7dBB<_(~{*q8Kns*b)np3T=dc4#{7SF=`|U}aS$ z%vgLwXHlDAM2J z{cOTYxr(vr-e@S&Ot2$1D1h2Ne}^2RBY-mSoC-D)r73b-cpF&0aT59zU4}wv$s)Ai zEQ#`(qjF90m9E>2HjQKR^}fHR;h}nW3TozL4XS@_PNI|~X@F~YvFzc2^@|{W2KFA1 zuE?bL0`m4GaQvX1G0#T_#4N6hJ> zaVcFs-#d~xt-zw$JIyMOV-YIUp!e#L)~HQ%PV0m-=W?gQ$0!}WxYJYY9d7wl`M?I? zWMEdq9)@>c9W$P=Z4#|}3ttFIGbLOw(tzgT(~Ucz8EHw)u^TAiS=k;#K1%N~zi+=c z0Sbhl>W{IWxUe`i0*@2r0J+|lOE0o>j1K1u*iN&OWywh_;4-$Hep4{0xnVr9d4T^2 zQNNJfSkM3HZG8eWLxsu4dCo#r!lt945ZyT!GX;io(^?K#`LT>0?t7}tBYnwheCbgH z-uR5#p)KyCz^xT)_h+ow(+lbmCvPDQnhEoIn5a@DUdV&3U}c1|i@&FR z*9>N1HsJv2QYLz4FJ!ba?uYo);UOC}2K&5(<<{zLi97}T$6f&icx3fJY$$+{9paun zscNoD4h-G+^+->+42Mr+ijlLn_`l4C=M^ZkQAwjtaV1u@%3@Zv5&a3hTrb1u*UN7X_dgCc&vhv zeJSrHlRGB=5?>aYdxy((TP)>hwiZ;XJjrTD4;E>$q7uOu>3(9};3tut;8iNW6ZrTM z{ng}ggo(DV<7p**r&EJl$U5{1l?~i!+7foxwrLw;f+PPG!*0L zqm>eqZreT}<-}Y`Ve7oJ-Q({LF}H~;v{S)dw|k@wd(33aSuoAouty{?>_2Kh_tmQo zc6e9-uhp@yYs6OxQDmMMIXRy9o4r*;%1rwAZs%_%Etwpe;W%JX&h}nAkE60DTH>*6 z7H>v3=DWPD1)}rl^!W!&$NCMwxwlpnh@0Z%-IHi9<0Sp08YpM-e;o>#c3Vd?KBMp+ z`zns69${R&Cjt6A(H04aM$*WSA<-Ep=l^rYijHRN zm4n2ZCq^WtH<-!3xHT-B<9dkW297)zUb)4dzy*r#jhr37q6Eo_ZYf%6JTv%9yL^X= ztxqJGV>B<%`@VKEb(NwZtX;?Zgd}707cC#WMnF@13B)P|A-Y^n@OknY#$}xQX>(gi zZxmq?Am<>DA$~7$IL%p665~r1e{w+tpl&G7yz2mk)Y!*OUd(7=HCnL)?w5$NVjg2Z z0l^q=Q~cXJKKE`?@NMBeWN1;FgmM+>RHPyGMDbd=D_By)N9Fs87Mk}oK! zOA)b^$z}58Y7l9G%jQvQHvmD5K7GE?)zBJpa zGsS8@oU%;k($Djmp(Ap&#%Pc{%la(gd?EXE|4r{?^<+}AQ$LgXcG$w!&oH@Q-FYmu z=lz4N&9SNm@yH}xIy7i-qV$TKbL?P|ZKTu%R8dLO%H@*&R|qaXmQ6gDR5nI61`l2X z=hT`)nX=V(I-UV7)kw9pk^@Kz0t9iNvpEQA1LmASa_kzpfFCT%*tl)MXGdqtkRZ2B zugrXk!PO<;-lZii-&zSk6;u@)zSi@@5%b6-avpwuD(BgPsP_UFjSblf6}oyW$JbrZ zDJ3$#h*;K{Tp&IS;U)2R-21#ywc=9j9C3BKwcAtw+V0@A?Cff32F|5n+QJB0IYI!* zF&ayxo*QkLgt1r(Oz(iRC~JQJbne3?P#r&T?n^OJs;StRZu*p85T zZ*4?3h_xl(Y*M*hyp{7sw(^&jV9l^2aa3+9XC)@T>itR<4Z*+KQ*<)tCSmENO+s+B zQXyD=BIjn)R)~c?n*(;mPz8lDAoaP<(Oc#($aGDT=N?r9Em-V4A77hcu^43{eH@M8 zgEfmKGYt+nZVPl!2Uk7HJi{A|*xYu?zJkpRTK#bmhHP6zsqloK7(bhSrfh~u`zns!+?n|g+Msck^OrS#AvCt+CsRF05#0^Y}fl+ zKH3dg&A4_2!9HI9DAZKJN;+W4d@6!|gS*bhr1PQ+2Lp!frD#{7#AzJ;8~X7o+BN=6 z>nlQnL#V`}^iVg}hCctapZ;C#owapBMpU-(cL-nNGlhV#ZaiWt%_1BtVX+bfekRlH z>(+{$8X+>)h&`wrTPJ;9kXSlW3zR^rX(S6blwZSgh19&|dC9Ihzci>3_!a4U5t~W> zjMO70nz(a@yYuK%^aU(jrAL>y-&YT!OG21=a0hIM5R`M|$!uU)>vnE?C4Mw84KCp* z7()pJp!fvk$9ZTm=tm8cnTg^>=oJ{4qP_c9+I;Ci~nD85hu`ovcHMeB#a-a5$vR6)N2~dn$^<}j(?atl9 z_r?C<8|vN}BAXR2_o{xKc|*0zNZF82Frx_mD+d30Ep$k2Skgk_^JqzA2^Zqgg&FUi z`Ge7$I4)*=@>M$XpXL{KRhxdI#<8--ZMxIHoZRms9_X5d z^L^d_x$3zJ>HJm9HC;W-v)qRpvYh3@k4MFE6pZ9)cbr?MvkfenIdVCgrK3RTU}Ox* z=(r)H2eQIjSFnG{NkKJj_!s-P#fg|?(b{!)75tV^;@{vhP!D`13Qb8Rv3wfDT;U)smW`E~x8 zT3ih2`L-KKH}NTCwYYrw_#N8&p9s>rdb$akg24#ls@YUd(c=MLBE&0k^TB**`sNzk z4)$yN{nlt853nGH`wKFjRpW9eBcZ25^5bP0tB(A%ogYV-9A#Nv zLM10XBza6{qs|kIM3)->ff?vPmX<$}aQZ{Ta29N5-}>QX8R_%*Z}kg^@zXBNcVC1! zkGw?daFI6QTY=+McGVk%F<@WimeKtDG8Z)vY*wFmXT&`mCTUG zA|#$T^!kN^3$hE4AV)`a1U&WCk}IXC=j-X>((o7UzS>xXW{mubBy(L@z9GvtS6*Ruv21nPdgYO`GI_D4ePOn0 z?z9o9*H|PSOc}yMpOWXP062_-R%@$j85;@2^6=HEHgN{*62C8Ba_r(Ukm9Z07c~VY zS5L$hfq$fOT^arCU?^fU*!GS$WL48!9Tenm|emeh6 zd;pi-Q|2fD(Qg;0Lrg~EK>3o652@;M{t4m#NOOT9fQ?kOd3gAE5D2M;NqvJ$fp^h_NKp+9vCsm<=k$fbeXW5B*hBcBl_OfI0(TppS zml1}u#cz+g=LibLOb1+aXhEXl3Rj!Huh`f^D;+9aLXAdw`z_r%^hHrBGV9F;imGe} zt#aXlp*VG`+>^Ennu0&Eqmqxn8Azh|=B0k4f|{3o8L;Uh*z~3sRmtJsd9;6SZne^~6%cZX)tr#}+ z)1sl0aMDb$H74HjY&@GC`gI_e&fO=6If$>W2&`xJIn1wXCz__bYUgVS;u8J(Eg%zz zGu3(Wcuu>Rn26-S}-(PZ4T+QI&G zg1XRTHQV`uFlzA=aZQMMgi*D7-^x|iPbQ_{?qvj9cL_9g;pFm@R{|bn&b6%XOZ7GC zhzVp|>K+e15m)5KV6S+p2e*gLOt0NKG5Hu&R$z?sIn9*zy~kY6G$v< zyAOp*fr5Bs(+Os#F5oAmFCdcJL3d$3kCvBmu^JJLB|sB+{!_brqLRnQm`DMKl0v^` zQZl!PO* zRztEa#X{@mYk$ZT6|-%p3KiXej=mbnex{;605pTUwFp!cLUBbLLoG2LIN)_RAmgRL>pd(zD8K>;0 zt|tyo;MHO9JMbvd8Xtd|xV-hty`{pVt#bKFOPcH=PAXOR1V|eM>>?6iKp)qmH-3kT z!)xf+OCh8U4G=>gBKYjX3fZX3<)TA((k+-IP7Jbq;?l+q@X1Wb4X1(EQ!BLcd>I;R ztWqjwPps3sL5%ah-C%@|n$vt>2;IbZ^bHD2W3{3)@{nT~c@2ErcJb*w7`k*fOM{8_ zl_~BDzEn;?!n=6;G3i4Z0HbYTW!vG&wm697ul4fks^w9t6m2Oxw!gLv4RukX@A{+x z;m`=Cf(7);#P95iGO{QmO5amm_VWeo_o?AG(sp@~jU_gxPsFOksui$<^psac@Ej*c zdi;sshOcgQz=}Wld>6(^+R0G227>&+fCd5_pJ&Jn+>isqj_RDTm9C3_N~sXdWyCpuGl};u{Beh< zvp||SJC|MmTJ4jHjuykf@=f-O!i>Jc=RQZM@m~mu*@Kn56j-TkO3)j)@;yC=FL=JI z_O0-LMkig#Odo0!e!9CyF@-DRSLBzjj~Z8?tMsn)D+vYwO?_5laT)^Db^TpF5A~`h zDrgQ5w4D1Pm~!n@i>lpDoLg}xC|`IlaxFGr-6ANi7c0x3%bqq|y;q?PubBW(_<6e( zSrxI53C^(z_6Ka>Mp>grd%h7bX~(AK={XG8PhL9mrpsP&weZ8vJK}-v=|NZG>Dt2T zSo!t`1n5Vfkj%`_hiQdt(Z0PmqEeTJJ(`v0Djh$|j%4R&UFf&OKV54rzF2Vlj>7E= zzj5OWJfqKI=zew{mQOYzc`U*ujP>?~2q&PBg{vNnKXj~~ufk&3N50P!Z(ZA3 zwVL*(3jd|b>;8S!Q5<5Nhy$HD26@;LdGx`uT++59{;ALM6Jxubfe7ynRuJhA0bx7UR-p>t5{*HRODJ8evSEu3dQlCLjc=gI1 z-V?FP<=-;<*ya|kl^!`LqQE1Cj8>%hoyH4=a3uM`!kxJq_0f#j1vtd{V;T7JE?oRV z?q;i07_7o3@cSD|Ct!oo7P0tSaa6`<8q6xj;x8Kta6)99@Y-$2lMy%Z zWpOEh>;WX5-zFjNi$_#FBZTlc(*?kGrM)&*BNs_{faHAtobg4lBD(F-- zh{_pI>H!Lu^`GihM-u)_F}TIzNc;u%VmM2j8udZYCqNnaFQMoUxdf2dD6nadORYXr zJDu!J0cF&Cls+i+JOyybFYj|u_c9mg_y|8?0RxU7J;-Y8)f31fXXhkNeZX3w4U{|uC6U4O!~MBB;2z+ zj1B9<JVx@MrR&8gRVEDl zm7Sag;zbJ1{DAAB2z-aOb`^q~w!&5EZl!%%F0;y^pvb%~v@cWMVK$5AubX`RECriu z4i89F1cz_T`VMss`wpoiezio~TFdP0E%7H+-IRvq zi%2hIt6YEwL9x6taWSk6pOT96P7?{q!s==Py6ai(M#x!dnh>@0(MglAb_5kt|GfT z8~{46N}oUU{(X+neqW99kJV7Ng*&&wtZVSSAAx993f^G*kyJfF5r0-1hGwas3vx#{ z0xNDdmdYp8P!6pO?dt4bZ2?Ax$7;#rO6OmkL^?W_dauCgcB&v2JQEZPSfA`xC*;=* zBMJxD2EXPydItrJ*y?Q0*Y?fdYvR+|ZmNKOZy1R-k2Ii(1`g7<0mP?Q)}MU+?o2q< z^4&SNO8>UH0-pzgJP=nFb>;|`rAbwzlBu1@1gq7}O%5u6K3(J;&*IQqBz7B*t|ez$ zV^VHyeE)ue)Kc=<>v0ZU;LsTn{pkL=(rV;ofXyRkv@O&OopQd_k&Vg*TC4nt;G$g! z{d)+`ecq^it4VYn^7rnm@#X%d2e`vH{FQ9^+3AcJ^9)zrl+uWE`H3B~rF<pc-;gwv8R&?aerE`>ee%De`uA- z0-_1~#-5K07zN?&fL0&t)5KUw0QR0f) znR@*3JSG-9!@#q+HsX#wwZmxP)5GF#y+Q%RW+kMa@WIn zx%8Q2yqpOR`l_5IZ=p~^g<5mf2*Q7`{G#57YYR_f1wHAjw$s}Whl540tzc;|kC7G} z=o?kM8(U=Fe%=CKK80WtqkISC?4`k!Az?e(!vEm$aEzBOs~N;JBB1FQA+j~!-1O60 zmBE_xpH%~$N9_64tZVVs<%1syaTpeQfbG@>#t*O9!bnx42uJw&DKYdfPuPQCD|f4hbG#wcEo%%BTw0PkPBODu3+QMVP6LP zr7qF>nx{0?DCDKpoTb~ig^6~OVC_x`UGRXZVIm1 zA|2K++NZ*liS67^o)CG#wI*DH@?SfIltwF;!a{pJrr-Mn_uLH9PDE&RpYMrnU9|~x z54(%m%`*p%V%Pg!XiUkc=R>ujn-b^kU_Z76qEK8?86M>$eu2t=xO|6##*BTRFB-P5 z!OGG!?ctah;XCyDz4;xr-K)Nt9{_j61H*C&D4v?PDlxDyf|N#U&slPoaHN-@@-yH< z$%g?gXN7O}pn3c(DSgHP47-ZuOGngBu`aw7hDXEQy()e-ZqI}dr`U~ZD!e!eU)llr z6W_Zs=eB>Tf?$$EoNxdmG_k?=20O zKpCCvtIC3V`*+yhJ7etw9354ol$bz@Vd3Fh-rqLO{{b9?+JFba6#UxJQFl*K+-s#! zTK*>-SZSyd`olx;=dS=u$^V2D0Pn^L5HodzH7Nf2t_O*N3;q)4!V2ZZ`S{Kkm0Y=F zMswIuUv`)3{1)ZVR72~LShCwq5wxVb9XI%q@zU))OPw`E>a-RX)$r9NcAMf zzwmEI?BeP*F#7oS6wB}8pcAh+di307OY3VG^YI1KC;m&S{oIkR!xr9Np(8Po<}jIY z^rUIeSEQL00a17VM^fvP>O*gkC_&J56$m zWAxch!^b1q$}aaJ7uEp76ULtTewjO1a?EfVVKQhb$FI%h4JS`c3?SXV@c!B=K~bkw zt#n&Gfj#bIqP7$zdD@^iYpU9^A7A0UbO9b2qZK_YONL0~xgcaGOd+>z=bH*o zV{@!-4m0F`RF9l(UC!Z*496jz1R}FA+at~o%dJ7idVo~#!p4v%7>u_Ngd@L@3!Uot zzd;stMT?RJ>_oCrI<=hf1BnimT!I|Js}-Kd3n^eoY#$8qJs5d)VHXUs|DS-NR^rEf?IE zX!DG9TRFC~y%DOAw56X1FX1rG_{h<-xy&xbDWQkNISH)G6);M0YJlN916R#YIAiUR)=pjg}L~-`A>AJU8QHP%Xhcf6f-Q3wg}q#MT_gCXDrD_ zN3KBDS@xkm0|?7N$pxY_)7nm-6X4CKGj!IepD} z)ZM1?)h-`4d7U%bzf>UJB!4ndE5cnB^TuXl*P8(<8yjk)nmES|{1oQRc*@fxYjMd(;dnmKjSc}+mr*f+EX3x)I zdGmk|J@H)9dA1=1JiC^Y>^;sfx0WKhUR3uh9HvHEMG9mm18^V!1|#-eT#s%5P*(Kw z^$N|6tB&py1xdqU=#|e@*;9(k$bM&HroZA*3&1cF0;$9mO2BYFcv+XNI{mV1sQ1c6herzmBPXw`ko+$j>FU}rG8wC8 zC79sHaUZ%%y0=3TJkf{EU0otNB=Y(D1?3)%*1B_;Hkysw( zZC!gQuUyaTWz3ga#fKyfT_{5t!C1` zvhewqiBEvN11bsFJJx<3@WThmb=oyLc2!2T9%&SYYbGC-*tXRfnMS)h8!WWn*X$mi z#A!U0@EQ@VNX_i`HBT5`aqP+ejP~VQ>crC z*yuG$^A9fV<-c=jlMuu)i$A!uo1|~^*S-JZ(n?aQ42y0H!WMi4Uhkw&zaRDmU~AxS z??pe8+R@mi4SMpXE@6UI&@umcEPoM!%(a+#@E|Ujp(;PMUvuN*ImkNqVLX*CavpEN!*+7kIA$G&m8pJ^KN}c}OKu*J20PS)x z6A(*Z_+Y|3o^wdsqTi~oGP!E5^a|GFQ*YL5o(Fo6o1`eh*@L;Yy){;ufNjHJ=Lm{R z#t4ghAT?l{Vq)^!(Dq;^g#Iy&w6XkO2ES|Uz4r2Ua!XfaJw!Mw6(bFDY;lV+sgq^K z=;|96lG(!qijp`j)$-dz6V-RYAStZ!6#;c(y*?VM#LzhO_OL=>r|Bryz#}92AfI!) zQfmav@ae(TAJkVK&;9y(vOE3|*%QU&hA~ZRo>Z3#JAF9zYSsT5F4?1Z+@6 z-|6FPiJTWIQ5Krhhl_4iF1MjpmRKG_bIX!CYL01@#N{(K19b+YrlV;2uQy(#E|Iku zVm24`HIg4hb3J>B(D6PkCklQg3)i%2dHJatP|>v^?{z8RD(vN7gjV_d=!x>Jf>pPM za(N=_UJ9{q8``s5Q{EUuD{lq%F{n~mwW0?c6r(V6e0Nc^afHMgn~|s0n5tEo^6`7G zOa~ErgN0hO6K(6h5}ZMLFRvfKWA3V0LpCdodShWGOC>R!(*ozm*3O+8)l2hV5hUD(@wf{BJ5WUfA z0*a>rc;^X6$3FfgUGeN(AlsKTjGtFLo8% zH@_8Im-g?@Zp4tjQc}8%&;|i&3bto=>=8`BrN8%{P+ZfmsNj#ilZK!KpK?XY87FpO zU#o4T0Ax$60cKrRMfTqWZqE7S%)i_Y$s-&D*YkbMLKGO%kkCXgUpXwtq(B! z{fH+uCi-4i0kd-MbwpohhtuL}kW~JHy!Tg3+cvtuuCUg@4((q2Qzk{rH$t=Ha}(FY zvyq|A(!h6SaK{SCp9t^%Qghi#Qi_2SzOtkX2^#-xlKp&P+qQ`wzGN*if^gnIe$dQF z(^o!9T{OTjKk9M@maDD9S$o9~eAn?I>h(i;C#{IMmKQ*m3)u*q6t@gBt_K=b;S4z& zSvf9q%;0$Z>G0Jh`kb1RsZe>{_stsz6;D$3_+_dyxpumncC=m;;g@XH$6rcNXW6aR8z1JvEK=f+HE`?H=8l?yL!g($;p}+*chu@AR8wK*r``gqzW{FT z^X)#2!&Q&Vcr{=~H}vdt>9}`Ggn+sb8@s&l>H+)er9(N;W!U7ATHwj}YJUx68j0lS z^?iN8MEA4+dz+B}5thmA{rJA1i@2%|ryp1qn4#Ij*nx%$G~=7zNOipDN+;_kW1!V^ zXvu^uBjF2o*En@lo-WoW#H7^6jCAO8p$drmsCV*U$yjRjAaZ)5I>_9}+F4DAUqDMu zk6+-K#QFM@^fn-kw#M+cJ+`Z@m_ntudLAS%=j~IbhVb~{cyYa0T~g&*;*A-W%Jxut z+Z67Hi;d1OCbd$ubEyLaPFFF|izQOka%j~Q7x!|Wt4n$;cSSSkhJDx>!TYuZvWs7k z-N&=U6wxA5p)73k^0Zdvk|6vDe&EskWpI{-ZuuEaY>Ihx$-zx6p&n%EgB>I;FV2G8 zPXL%Y&fnWzpWm*G$M@5V;~@9rp&oz>qY6k-vDetwnq%t2JOaj$2B~HN?D)zgAi!yqwYK>ewH5O(2(QaUboB8JArEZ5&#)Mu%uzWtYrb?kyA{!U(@qo*V6uR?X zr<-kCw{BsHnx6C;tME8k*uVV3u4zyy3@{A}32E^Z6dHZ|lWr7xdigvSzE3xv#i$v= z2T$(PjrrtB!n@NL=XD6Cg+)Qw1a(%y!x#F!sheDLS15z%B)ag8diZU>Mb@acl`swX-@t^u*u@L zKfQVKQQ{T`Qu-~7H>2xhe<_7TOUvt`zdzx0Fv<&NAGvBu{!9qGs9Eb~u!k%e$TF;Y zj(;sF=dL!?;Uqa@A5xVVw341hV^XNT_@T!0SfjzPZGG6S2ukTwVxTnCoKvZs_Eoes zVj#p8rRB3^V3&|~5)=N+P;(8c0hmLP=|%8{7(7m*xo=Uu>a6TH`N<`&1uAUtr~Eov zZc~Cm*_$QDzKvGEY4b1IXD=qjs@n3_zH8dD&0xpA2>`aTdpzxb)av9l)-T)`+Wum) zY;fxVZeE+HTeUeBymF~=N9h%Y<;5Mr{vtL>Si&mT>&q?HEF_GqIb<+`q!c=CnMFK2 zrJPtu9>4T?qnR%KqNnuN$3(XWT*w+EF~!RpK`z``){87k=nBvJgs!4=-F=ragwA_& zkejlD{GE)TE}4JBZp;jr#GeaLv*i~icG6mgY+Q-rj7-DpY?f&^a#VI?sL99E=ni|n zJMMmIPUL-{^~Z(Ur>}VTTjG*3f&i9zL!{0I8?SI zn$u4OvJCuZ^`h-p`!#{>GVWB=&5DI>S?`J#IkJWI%D4Jfk;QbEhti`ZD?iHCou>U-3qgwTJ&0bHGlIwJ_X;(o0-pc>@2Lj7-~>^sPg$APKcE+9bW+nX=3wQ@&! zvfY#U>=6ZqM=2$n>P+h&k1STUty!;v(&F9i9Ej)B0z462umJSVwus;R+W>f(&^+Ya z=QKkN9uY}Wc%vudOEA+1wyy;l=rkkgP`0_v_!d;xM)5EJB^)Z>S5}-?!;#mD1BJj7 zm0f7!7agL5YGG>rm}PcB?jcON16!@iy%G2pA;n$qA*I>`0Hlvh06+?$&tjB$f@&@o z7~*8tGWV>d_HV6wxcnSYYI45s>)>v!iQzX4kU@{{8lX>`lkUx5H~UNVu~V?FE(rqa zOfG%K`;3U!&=%RT+5C=HI8&3x0CaXRD715&1E|Gx04zC4!2!ge#u2NWcevb|viG>d zZoto!4P=O*8_0utE-gJNAyZwK<35EaZCj1u?RkXgA z7Al5XCG%s0&i-an%7xKOZ2T#%2hj=qy+B>J%PYVMh{Qr(Fg#b;Wgw1P zyb`!zT9a0Fh9$a^cFMGZ3dd*sz!K8ueXJqd%)!cT@cZ+=559(4iNUow;owRO{wv9% zQu$|nN28%%KKMv~j4zdD)H2e!qz)jz$=r{nvIx9JbPEP+Z$)~lDOkGnrH~5^?*8eT zv5qt@t~JA|&&Qdbvf~Xg^XzlCmNSoPRJP8o;i9u{75_3O>-kLq11-PuN&N=<{|XS* zcWib9zvl6o;+o1*eeB^9scOH;(LWRkvPRj-{#QJ~gnOS>rGr8b5<^OH0$MKbNW--gds^p|f`x zug;|C#(WnVXvI7Xe^&ypRYeNJgQ9Qtwg@ZbCTvHFfKNTlGhOr?dywn3Xp2cV1sm^{9s|!5m#|eQ?PRa zJLW~@wU^;iS{pghOiQw_ZI9!71zpLs6V^y%b`K+jvIT*an7us7mu?<+)9xLp$?gd1 z9;`Vb>xM(dqDFQ*i+GaPOOB(jC>G#5F42*u^{-!KGSGhq^=L%kp5<0kp6muoqQ&$ zcz{x&2iLHLeIUGJ+IKxCia3z7a~(8Gehjd63GH*JpwPyzEo)QhWTV<$<2l=|l~{?; z_hG?*sAjQf63SW%8_S7inebmh2f9ct_=eq(MF1gz9IuS0ZP3HGPuv$T6uK!?`jH%Q zX+ZI30PD)rq8Ap_*YPKhjUaHL;5M zLnXM#keAyLVBnRg+tR4P%+59hZFw3ZH%m6_13bwKvxUwIG@Zxy#cR)(9}i!A^S5^W zztNXhx?wB}qSgba2Wt=ChlmJX7TO6{-=>e+x!t?n9uC#qroU&64G&1z_Z*&0v^5jc z)%oU2_OQ4nIzc$FxF)fy9v4eFtxfp?@oX1lYgi%!y8XJCAuC%hfdG7EHmY>j$W@AViIN#Db8|dBT!tZ{0Z8g? z|Gm=)gyq<^C<=#Ef$aIHL1*5DhyNUCsT2(rH<7mNW&wO?m(IHbrE|d?;lGo^`{Dz) z2UWm8$EUo+Wn`uvXyEvo@+*}hK=&qIs?nGCb{TQn05QM#5ns}RLUY`KSjFJ95fi9b zmX=33H3icL)*(GP;ls}&wG#(LblHo#SMM=pT8t&0_k;maB_6C!0Qx{;5FQ z`BlU$rL2b`O_%(`^VC<&sTOBDLn(3DXdVOKp~#lMX^>!)QMO)~9-H^{MbZnLXAb3- zR6ySAJH}0c{dMd-zq?di_fIsAv`c#5TqACka!^;yZ2fEajtzVV=|J3kziu9}UL3yL zf2sLs1I_xOH%3!&EGR37-hhD}kUOYe#NeaXiF`WpzWM3!&%$sUG%Un%IP4BmME}DJ zR~>W-XR*=E+>gbdW3R^qPd6>t(gRvw9?qi42cO+%J5N9T*bf}>FVM9Z=tS#Qw>4b1 zdD5p~Rv!ZPvD0O_bqZ0;8)LfaBtdKvjUA1e8U0GN0P;7(G(s&D-4ERfs0!L7CXF?C zU%VU*?hPt38>sQcGNVzi^NyXg*msGqm=2Pc*iXT_GE*iN3R_(`>rDTpMEdLYXUZbxQZ~13=`Uw`gL$#Xv-i2^a=hk7r zI0>NjoBLD!sJch@hJ5`8kA?n1jH^`Yk7$GflnNy!{3JZGqgr>DywV5NGTKm& z0zxR9=H)}Z6O6O(ZZ;(mcd16_>Owj_m_J+p7*zkzbpekO%&L`~Geh0~C)7FN;){ zTkqLbK~sR)`M*uM|50H6pN0K@Q#SwAW`NS|oq=cXwcGRN{{Nxp?0R!7nsUMh$Ty0_ zbw&6-UN4%B5jVv$5e8b$7Znzo+Nflt7C()}TDV0tTMA?z%6FjwvU&8kNL+UgV{{sz zh=~2mhBz>&LeBIxTe=}BkQzGH@LcqQw!}nC!8hl6Zb>U1O$EKY4=O0HPn>lOJd){6 z1x50)^{|5l6Yy8^Q??0~BOqaoJtqzjb5f~(pOmbRhQi?CcltCu=gq{WPol%-wyiTS@>lOPy+|+^#8k94Cs;r^3ZUgsz1k345xx` zsNsOzz5v=@<{48;H&NwGS~Fp$F~^5j4ZvC~hZ)&!=~-}RA#hU@ug8oF!sf-pekMOI zR1;8H?E-TA^OEV+6H+q7uabDlj)tlQZH|OxjMsL|!R@z=#Gyx=o#)Bucdj)$WGCXC zSGtwC)5l2E2bLIFSCT-W>VMj@fsu(Bjzq%~oxqYii}}l5z7olYk8T+FR1XCm+;$zm zRBQ8K2yMIS2rjp9HCOUm2O5*6K00zpR)t0;_(!~Z%Uz}}EhWPRNoM#CO4#TG8}J2; zqD|s20o}p_=8hxX9j76`mbPE3=Td{(j{S3=9_h7j2Fy3!pUVJi2TuynuxyBHDXy=f zTJ}e_+-GgQOG@HU@;7A(eR%<^0Of{*XdXa~W2&$iOyDX+nSF5w+W#a&Z5(?vAI(MJ zd#V=W!#NXAww30}y60sIq|h8cV0`JH>X~R=<-Jn1F|?MKEqom@{IvxMe64`Z7nfC| ztw+#R292pL1yU&kI>`x+hcx-|z#Z}EWnU3(PL2AXUdthHALo3}@Bz6o-i+TofcCmm z3(#j7l&bYFd+5igF-c<50y2qE%+((mBH=f|^CVJ9;U!C+8$lLukz>pX_uo)2A(mAXn6G{Fv49e)n54A+&bt3AY7lVarU5U| zwl6`U-%PoH443hr3+~KQFe;%fPXJzJZ8U}0{{IrO{;dq)|K2_r{3>#`U1d)n1Oc9K zO2044^8MY|#n`1CU>Dnvp2I@dY(JhZ64e#^w!T%up$-FNWnbm8e%E97_5L6B-aMY| zt?L`^jB07?C@N@+s+x+Lr>eH9##U=+5QL({JQK89s)p1|%~iC=7(>id4KdGSVkV{} z<{*jiM$b9->2+V%{SMFby#Jm2!6(1`roGnQYk&9JYke2yE5WI*X1H&3{bX}dbYFyx z$9NlPy}LtoY(spLq1^yV7MNZ&*us*VP~%1})X1}n<*O4$;#7mw_X5OKet5#m_GbuJ zs2pEh#P2Q!phfin$lHI%7AK3Z+CO8Q8$Z9!BULTjD-c*qSXrpPhSLoh0&yiVqqEr~ zg%;ljTyPg`5QV@Z;d1Vqy|+5xuaGf9A`wXj6x^O$np79cfQ|@;yhK_$CEKIiOTneI zgT?Ebbju%Hbbi5oN(YYr<7<3ipQ3J9pL9rLy#gZy2tOP+Px$h6zUP!Ux(0x6Cqxck^lgYSLRmRa(`mnDA$E>(F@r~G7&-TM)?*{4a0rj}r7H^m z5B|A;>Wc`eisp#|=yOL%?Llehr~*WM)BbC%Gx?6@h<0|nd?Bec zbKjjiN085Ii`7aB-;f({jQ)eSM*K7F6LA@7?A$@2{VynpUSq_Q^JFT!RTA94n^xyu zm7pDv5mlHm`~>y1<5PR1<83)9@5RF5E#B{M{sYW9=1~Hiyns&f@*h2Yh6r(BzVhCA z_sf&sRR0p8)PvA26`xmX<3;+vNf8YnS)Xk99OSRUSd{)1>8k9WcNrOQ4mDr&Vk%YK z$h7d(JL;0Zh|K*OS|yS^s1oG*JmKblZ4|L|tokpe?{PoeB3?4x_z%LlE0oTjM3@ap zUcX^5=pe9*BwHS6dThJ}tq+FVp<`{NwhD~2xPy;hzCcKD&qypk?6{!$GeqcmX(6o@ z60$y+I`R@fntO0{S{wL;ad}_Tk{l5u%M8D8TW`{N^(OK`cYLwp_Y?mfBGGYdEnAY2 z_5&ZZ^kYxql-??Ax1*GOlWH{|cTLGqOK>(Gqkr$NVbzd2zWeVGkEnF{>8}t^4)s4j zhi$f!eW6%>qs*M;HkB#E{)z{;NQWh``Fh-YkN}kt5>N%Y7b~^s%xZd^YBmp9<1mfZj~k{yiDl3~|A(<=E>$*r zqk=^Bp?t68^S~7bkuuV2LWGsjYfH|MkhRSyNF~wJLh00WDr?k0hh=E#@uHip;3{7? zeXrlU4;+J_;ZvMSt8%B3R;;ucqCT>8e?&}+bdrB@g;5C| z|NiM;LzezK&EWq{+;%K=`TN39RA9KTH7~#8?6KRh`>TO0(}(tt7p7#42;F^FIXH+vRxn7rJk)ri$IN z$CU8}&3F0T#-(b_wn&ro#Ev7@qdTJ>S_n= zrf$(kRI)Td81@ibIyW3PY)tx)+|i`_=vXhEmj-&y@Zg>kmFA@0bj7wANiwDkJ3pP;fidQ&o;2?sL*CEd^Z3OaQO2O>%)XYLVnt#Vx zztA-NcP0OyS$);A9uXz7{*_@6akQiGGuwdm%AZLG{~Y>9694pxqlqBkpP}&2Q21vk z{4*4eh*STWAOArLe-P;YGb{WvEBrGn{4*>3Gb{XqkpF*#1wNt?N4(uf$z4YuYHf_8 zDvh)5QGadCY@RqOpx`7&t$lHHLho^}*WuJFDpGjP9t8f2BdvwI4^ONJp$@>5Mp}CpqYb7}qsgo{WZz+k%N(#uiyWUScbMye`U+<>- zqrn)tDjNL3`DZCT9Pk&P!_XJUUiyqY3s25=V~xp2tAagj<)9x0<|;?E@~ zrh309A%1ZHlQt3kKDaYA58n>n1&FD>u{^36_8{(0DIL*1l_>zm!3-Sy_wKTfOUTQ3 zTEp0-HtPzD&K`rTdsu64c)7NQ87+CXBHWtTSrA7u3>BEUdL+}ks?-R-S5KvvPWyKY zewTA@4ch^*%PSbX3v@?uKcG!GEK*|@);n%KovPBlNv+;D`}y&o%D6~PAo+BKA!tf@ zDRsXjBW+*thuV*Z6{OZtnL4X~Ig67)uOYSU>@GF^u`~6$Yat`G6ucirWuf(=i2#+% zXZ+h=s=H4OfY-XjfLc49cS3<2$m8=y|HGCO|4jP%W01QyP4pLN)Tnp&NdBwG9L3aZ z{G=vzvi+-1yr;(f@E-B9G-dGq*-idW9|{i&RDHNGigF{sU-o2ho7F;QGZbc^_ZCuB zlqa-Mcz0YYAQEHTNt!hfm%ZLjN~Lzt*}K0sQZgveZ_jo9BO6C`2SD!AT!4;n$;!17 zs}W9@n>W|m5SG^Lh0AYHFZ?z77^v4K|BE;Q3@z;oZC^0x?3rmew>S!%Hi_%~x6@>w zNH5XYsy=+#18k(Z|?^kb^^VGtebdVw_^73rlqb#1@ym1^Shz!CQZ z(!%rd^Ps@4t@pw}J-ySfFp}?u0{`G>94#I5;3Lg|RE#S-or$`O)Q($m`d2Y(U1qr4 z@ClG}26P@`Ln!Mp{K{Ln2K@05avC&fd> z#O-q26gOQ~YN!La{O+$~G~|b}&@tOv@pG7>%P-nCHknNg^@m3mK)Uoaz=aHG+}7Fl z3Ek)+ftm(axR-i!4Nmt1a+N_t6b*LaY ze#XR@eXtT@jjg&}i1?|@4uTuH#6}S%Mw7<0@NW`+*r;r$M~6Ea)3U#sEIOK;n4^IQ zm-^SEM+WhK!My%2+vR^Qq#AMA|E;O*e^-Pwj7Re}7T--QOg}Wpks_nCZ$Pa2Nt!!j z!}8LBgk?-}|I2vHs+f?T{UW~Nc}LyzE$X~$WV*-$03>0I>y0M_Eoa*8OMVx0l=1r% z8W6M`L`x%pCrRZw=%W{=Bd@H{i}x`JYRM zIXd?H*YM@1iA}7m?ia3Ux@DJ@b+MVu1Ao4%TKNRYT3|sCm8@4T2)FzYn}c#ANm@<# z>4Q611lAf62y{!%Xx4dulrUanMX%eIw%m?VXU2fydvAHc`eb8W+9i*jGW%$RxDDk- z4#XCcnUCgkyA9W=<7DwB61$!2jd5tM78c?dns)K^cjpxuLlFf`$?+G@p07~O0V=4tY6 zzuM#fTrf%7;BarwzuGI6%Ke(JkFcxma^ASrw?TtkFx?sJ9#J4v$Qfz*r@X;*l|v!b z)?31@30{;-&}YDI1m&)G$bCvcEkE#SjOaGHF2A1G#KnL677>d*px@N}s)xtszo*D$e!oMC7oH_=W-3o_w@G zH~;2%2EhyMj6|r+9gLNRP0IRUCrJ*eh;!{VZ|3;j?O&l`uaG(ZLfN4BA+jEj4>L90 za&Q?R;@96nO*b(k4idBs?IB50c*aENni6Ehr&&fd1y;;O4Q(_Zl%b=+EA6b_8`8oG zuj7<(v*v~F8EkBzGj~>7GApc&m|32F+B6p^u`a9#h*Q><&j0F=c7YDH9m|ptNoW@~ z4|OJ10z`!Oan8SEzd(9|yvQ8}oqRRY@n{jV>PkZE%KZg=`SM61#KE%a`dgPm1^q49 z2;;D7LHvGUUi{GW9Slm+1^sj^yJ1H+ZU7QE>Zb!t9j#-Nwryw`clR_@|hsGN0X!}0QCF~bOQtzUP&j6QhB=I-@WA7m_Q)4iu&+>hz zzHvQWd=|p*;t<44XeZGc9f|2i#3NEs^4wVNcxr;IdtL7WTdv5+^SlyUZZg28T9VPy z*N)uk^1QPJ|1y|+ONeBfuoWhjLN-d3yABnOe=h8yjwT%>R)k@svkuFa-|Sq+@?<~h z(X^C$7>TWh(hNk|9B*n+v?pi4%v zq8Vk>ImCS)aiN15{V;#zH>yQsl~$TbxAF>%q<}@x1mOd8O9w(%_)@8Cv4+u}AiCbD zifGHi?JTYHHjp378>d`L+ux3klah4UJvFsK1d#*zv4rR!e$ZEM=&nuwQtGP71$}Cvc}gk94$W!KF{t=Rh>D3E?G6t15N;m{=!GJ(yMLuiy-Jh{(FSGne{*~jQ|mmYXO~*G977mHl-a4|xnS$2%QL%l?SV4Tbm!#KvI$9(?o1oDQnv`r zBr%X-J%l~mo;+Gprf5$ZzwJ*bNq$I0QCY&^v4>v{G5Z)_OAZ-8OsI=)$7Yp(5}vUJ zAnzF@GkHL^Yvd)~F)mU>7#Z?eR#NlrmrIPM)Y>z#6UF2F5L<#pB4DjNQ&?YJP7|LM zL!G?L2P@CfV6~s!xBtC8G&E@A8wTQLVJL%3eWr8p=G(CTLj1RPfkN0UDi)+`XQGOB ztypvSnbDUBJ9S`cHt9umal}3#NqAs_ho>{=Wyg_Fhp_1DzjfN*eZ}&9Qc}}U%TSe^ zH$({5?Z9}-0FvsJ>L45z6a+D+^cyq|LW2>4PTpB7?rPn*hPF0h7<)Ne>YVzT4jX@G ziXZkZhPc-_5M$eM6>E#3zCWf|^ZCZxumMWsT?BJd4z)6jHZ>SJ6QDKDvhNH@g_DX? zpQUbnLfNyYz2F2cj+XLo4JmfG2X3}Hw<1ctw2J}7CV4+Arg+xZ4qBc=z28sD(G*a! zZOn>v(M4~*R8Bv?{^3C8;GD~Py00<93|j0I>Ei#&Uy9oPq%So#wIv&o7%dxME?>vI zXFZ3E_P1dzT_1kTQD1cvrdGvud$+>1Ha(=e<`c4VII7x0gIS#woVl)C`|&0!x={bO z23YknT6%Q7{bg@SAXxy4j;$0WBL(+zRZtuMHch( zZSgJ^Rpy-TbvxBXzvmqLgk40~3AlaAhE`gOlhtdb1j}t8T;YN_Rp-sI8QZVxyWZ4A zZn<{cL zC9Nhzxs6Mzk8}Ddy}~Gy;hWinBuB$n*pYNhUxJu8IKDsi?4&OjmvFuOb4Qk z-ByxybABi9DCkb$DctTVYzVxfhkL51uO-B(Q;2wDqH@n_`#!V>x)_O|)b;V%HFj%0 zKaj1LEa$2ApYB_{a)Yt~ancIL-)gBY#Vd{_-5Huu(dzWHK=^;}r^8c&<-gMj@a-WhLMlyknNy%yYMnf+l02Kp<<2UK~E zOH!KXWnaqmQVWeC=}tbU50wF7S4j5mmg!TOv1?FzbG6?qWDM zzbZv&ism-xcj)qN8!@T((2)zwMULy!q;zjbuUw_Hb)UxinvIsuhgbB@yKcppf>V{Qw*Kl$$qA4MyuLn6j{tQ#7EgeoC zPHN&ahCA4#&AMYYBxgBV)|xngHiyf*&X?pS*P^EGEL0M2n{Crz&ez`~s|oJ!EP3qT zyY!M~kwr;_?%LZ6v!+pj<`>sz9|2fb?-{UUjRZw7UfX#uH#PBNPIHm%+Rj6Nk2C7? zXQ`)tX5*!CxI}v5ToLA={N*r(g{+JWzFVl;_f22PQi=Gi z?Z0nE>!b;I>D+q@_$F&xI7{{KAKu%}Iz|UhJSdlySrbN*hQ_|`+UdG4U{wt3C$REs z!vnys@%(nv&}BEHRGM-b82;`74p%Cd=*xho|F2i2bpik!o!9-!73J{5`m0+O-e+cp zNTqUy#-|7>Vm)J_QU1`)+n(+j>U+e^$+#?*Hx_MjNg+Ldx9%Q*ktP{%PXAa?5BE3@ zR1oxb8naRgEabv>8#(vz9-k;VoA16CLYUiW&p)>fE&Yx zZBqsos?&P=e`bN5@=MLvI!W=q7V^tO6&bi?ZvL&Xx1(~88IF3#pF(g_f8wn3i(Y^q zetq)2@uv)mGOTrg`FT6vCv$yB_iXDey}OO;nfnaPPbeTy zc$WpnHwv!!e1Gb#?){jc4i}M&fTEmn=v3~avHEZdkLU3L$hfYi?K!(6!2kncI;WG@Q<+U%bxG;^3rv+*;nB)gbod%hN zTk5aoQ**IMo8E!LfhRrO`s!tfcC~@0uAx4uKk12>sxm4D{m$s<(pdATLS7r0p)6&I z-np#4Z0Y?&Os}4P0hKrqQD$bT{-odd_q4_@E;HZ(EF_UTi&R;hALAOo!WdiW*JC4< zqd97?Fdr-N3kZi;hm8Mvf?SE_a(PaIsi?&t;#Pfu$-P<`^09Y8 z3pe6Y(biyON~+qjR}dEGvR|GU%v|aiouWQ z&I$;D{)Wcqkr}amYC@BIcXv>1!kz38Z5uNG<;=9)zMc|7^OB1vde>{kY82K4^62&S znjEnKjOT03K{Q?WTYy;RcYWISMg6$!^%@p?Fi>6fHea?V7uLEyT>;Nss!-vA7?M&~Y$~Gi6hDxo z_vZ`VmGUV_aD;D5wgOn)`s#o@qEnmI42yv7Ku5Xtq?Y*QG~cOy?e{9?TrFSnJODi_ z@UQaa_vCk>CR_%llQM>YLq~SEpehv(*|f5ho_pR?Vk1g%T7XdNFfkXA52yV`B9NY! zLWe62`59fTrjSpZ{TeFxs`?h$J)zG?c*8I{He|9kCw6oqtLu&Zin?S_tV`iMIbu;^ zi_jnLwth2KvA%aoL3#h?QiKZ=qKmZVv<+p8kdk55a+bR2J$9{vN+sn)yDAH?^ zgLW@&`0${E@x?0o#m`0Iy{YIl9AXdSCI zo*aLND1#!l!{8OE#13;h(ub;yy21D&j<{gL5T%^-aDR38yw`R-F_jS5bb@R#Hu(}j zBCaf?XUW-h;8^k5I}a%ZuoS=&H{RA1ElX3ZUCNZ4vqY5G=7aZ;XfYZ&7!f(E7osW9 zZUpINTcF>o&@Q>_X{Fq5x=`PZ>X3^v52F#8s}{KYIwmgfu!PL>lJ;@=PZVXc^JUCh zMtajiAB3ho0lbGUF^*J+7^8B|RzFF+wl=ri?&R}3pG(k~N-Zxsk7MXbU!A+~G#@E_ z%TSqfTO4>tF_AUH_qV{#aTU-;_3&=Uath9n!iRU>obxp9ak}3v^0lYGt2--lwMeK0 zT$+SpCk!VDc|zySjYxQ#mZmGJ1AM*B5fjF!`*%H7)E}JVmJ4EB5+O~-<6liiyZiZE znRCJkDV?p7a-rS7KW3K!?B zX$bc4=|)+mPFOexavm(QplA4oVQ7K)Z@Y@|^ZX5TJsl+mZ~1`h*RWQh^>O&z_37(# zQYa0EyMtZ(Nwas`4Y=;EPPZVkdsYYDZ+!`F9(%R8`0$(JHWMWm5(@oMd`01ATBuO# zOJq~A!ogfXm*Lrxu9bX2~w|3|$z|#hWku;T(SElnO`-1C@GYD1xn|dBOO(-1QL*&POo&uj*LDyOx!O^9TBfX?37V;W7X@IE81OV zi77iUm)mb5ImyX!euWY8cYH6K6N3m9O635hzRA%W?DV;Z!=o=YN4x=%TOGo)rYT5+ z>XQ|Uw+?plLg?&)iiTUKcRegi9!jlPVA2b11a%axawKkay5CqB_@ETOZPC`+3kzH2 zk-GRsvAehax8Ni|6VCdPu(c3opbmtnYCFSsc>1o6YJTlOC`!|)d@b&-5-Oi^QtKzO zp)^;^eckuhc)a;VNkLHNk@>|HGqg1yf8qK_aTh~@V8>3lfnf%lkEOb1yTtu)E%CNxN1GAHCCmKCkQ*?u3gb<1 z&RkJ|eMiKQaA{<2PwWVynez7DVg8Q9;@$ncje!+?2vBboVY}aa1h=wAGir{^U6i<; zCgjSZ6vq`Kxq+5HO_RP1?Cq82oN+<>r;@C8cOp zwsB#iS(oNuvt9hY^>S|JOX2Ap%t_Ld;xyZi_6hg!`cVcYc->3+qGUo>l&Z{dOH{M7 zdL4qQ4iinmyo2Du*35JEnJ_iti8_Rzf9VneXMn%QUP+=Ru>;4s)cp0SUW2eB&Adxj z8aQBp3@;V%GrD~i>76Op(Q@D)oj(R-jV=}b-mVKYkif=H+(t8D|FF@#`3{!Sw5D-r1AZ2JRxka`p z2(FtG)xkO}v4^UC9${s?krtlM3lk0AGlX}w(E2hg%Cf_n7@T!9IFTZ>icm?GDeg3|n@8*L7t=!%8^l z39yl7MPzWzZW34*v9Y8ddgkCZ)c{71zqMq-gOkrw4PbAZaxnX7*QNH21KV?FPPuNS zw-^M)29t8^?DuqZv1Twz6D^s2oIMp@P84I`&51tGHotCqb6aF37^uarISn7rKh~=C zc_#gXSij)q;ZqU&3YwI27M1k}Gw=iRpwTl*%XGO{W-Y8+ignAVK5FL+tfjK7eM(1)1X;?0 zcaW^MyP_D2?E1X)`|P>Jn_ec^2KcCb|Bc=`Ea+}cKkF5!)B-O|Mh5nT+;q8Jznks~ zC|haMpI(Vup-C|m@>#0Fz8PHAZr@ya20!C|sJ0NsjBeQ?y|t-E6h?fg3`koF?6zWF z6ek;K``$m7vg4-xa@BB)+uNQe^ugSCUSzP78bTd9);}`8f5IuJ$|?EWM0V=9*Wi^T zYd^SXF1Ant<~Z(LuMjFKT7EuFUd@OeY=^QbGR&0gGyGuIY>=)vzN+LQwWbL|Hch^a zxZ-Ew7FCUeGQ&7ZvoP##prvNfpjg7pTD20UGlyVv! zk$TMV0h8#`d&i|OU$3);Vqg2iuI9pdoaF)M?cn}Hl?@fzhCWg6XWQk8B-?F{eCeB? zWw;AM|Gei}YAbhMNVXE(rYOJ$hhMzG#!^WoO-yNpoFx&8^6zFjLtmWToAtwGvs zdQt;3Im*oApPWB`{&}o{pE+@8y(KqL%P76)a+!0iU}~@E{(!IbDd-tV#^a1r>FiBi z3QLuP^>4!UE~lygv6407mJ*S9k0~ofSZ(Inv3Sat9s9*q1gV8VMfW;X<{N zSPsNnZ@H+c#Mr<^1G5&R{#ZPZw3_kIObFeZdv&b*_s@r-?^rhd>JR19<|o)kI){Ap zSCI+3d=+Kw`Ci86VW`J7whu{ogY)hN(QtD zyQ~)Ze)qGaivXtWIgya3bV^ZQZzw+BdfTjI@+4_=xr2U7V9@x35PSd`(XHTo?w-GO z8jxhx#s2W6aBKvdi^h#RT!>W0JFh>qDerpHZCcX_m2Q>PF_JeYib+J@@OzD=QazBlK>08SXhFpd56G{86w5agH?#X=}UbTi~ zQ0>8V@F()|Mn^m$rsy-5>P9=N7to|8TBEyvJ%Y%);KRt2QM&@AIU% zL-g#KU+*$w$XvHa)24$NNa2!QJB=_H)9y(yw9oh*b?LD}vl|so@HR4=P0MM*nR4aJ z=GHs|>1vTbt!SHb67QNvmn?VWL+Y!dc}bm;7D_jB4zxELU}l4_{eXlxn4S#bn`ne9 z?mfeH<7V5f5)$XIF33oMO?}woy=HMZ0xpkLQBb)=%cNw_9#tR%au&0Wj)NhJBF5U5 z%{T4PAB=@7?~M2r$iJaB(nc7An^9EWG7BZ%jrLRacXs|dP;42?w{vUZ&;GC4E~LRg zV!r6-b}Z5ZEs>jb&#N@Wc8&8wkA1G|cF5gb@X#`+UP2z_1Jg?yvh|Q5CX4jRc^F2^ zy$}LuI)h0Nsf0)|CUV4pB|l5b98wr5XH%%)FAi2Jzo@GMZ~@0BQRp?h)O)AmxQV7zizV=vH+q)| zB_-&PrO|lSne}P&zC*x*N|NGLH4*_QBQv_2b0_`}KbW)$HRH0?eq&kWdvK_K{VU|e zrQZ&g652P0zb~Jds(L`XT`&ge9F5zzrtSEEfL87{piOh5f|$=9s73&l6Xe;?Dr1#oi2axiS4Wq1eMWcLBDj9Oc9z#8e(b9H1~ovr;YEDs%@E;Irm^V_#){{uP7fh%sjwb5HxCV1)Ae>JR)SgvT^%3 zR7e!i*e8F5i%CaG^&Hy*BT1$%#l3TV^1uhA zSWukccR%?IBU3OJZyzJ`rsKv2&9sGs_aox^$yYCUnGu#EH%yh@3!?i%IZvRsRf7&^ z#8!iq!g?9V%9cZhb&)hZ0~J0T7Rh;aLF)-t7A;hQBLiF@WLL7c3)XhK57Pi=;L=JX z#qI?i>^dE1*We?yo3lLy@U7}zLZT{ll5>_BH}7-BSb+mBfFza1Ybn>dOV?OI)Y)8o zk)bizZi>HA6u>oQ!8zQN^D5QO;&WwG$v}KGQDQ4W9E>CltTl?Vwv4Q}s3_%mF*QTJ zNXJL{T{%d!RxIrazTl2COAOs0^!znqV;dhaAOe(xsjl;&{BDj$p@S{d*=vXf-lbxZ z6Uz=0Ekp1Am}}m@IP#H?Gq|o^n0-{aq$hwKt)0r(uPFZ0liK%VgO}zP&+moM^!fC^ zJg!vpP#$wqjbXO2Ilnj{%l@L#W7sdhsRl&_sxM#s(>+T)dA3!@*^yu2?*sP$Y{6*& zT(rmH#ERXZk7WBhwc1?O0dFM6%R`drg31?0ZvN>mj|%K${M*-i&He^55+E*K$;|92b#Z4I}*7I!z8uttDR!q0%4c z(}7(cviS@+e%`}%CM$v2MYY>toZs+B{w38+VaHkhi|I5R1r~XAH6TFT|{d2S4} zjoFmf@raeplz-zEZ^xxU2DlWw+90X2n@PIB0Q=PG1Q@AoLOTDE4?02G1_&(Wq^bXONYt$XHkL zV2Ke%QN8V=BUUa1yLx@6$L#V5iZ&|U!^YlhuMt$WIPmXpwRGT+$&=hjw^;UOITVccYXp%g?)39lqB(q`0!k z>(&RMg-Jj@(oRz7k`7<(^yBR>VibR8Xf5#cNxy1(_!p>!&o;a8I%Mh=d3H_`r33_p z)rFO37&x7$JR*T?*yj>LrOGFLs&BkA>||3h z=%Usvn|pZwzO1a`kGVB4NZ4d1*qEpucl3y+o{=joJekzs=% zDB2s>Kicc0GFFtQlU4xmb-l?BQ}GBrAc;Zvs0w~RH~om}(qQb_I8k&659qnpM4z<& zdD+6{Ntq43tVjmsG7KcOl9@PkPG<$|QCHvXQPMl|{>Kyr0XC}yay}-I&er<0fD#RvS3p<+J z&fdaBmU_Jym!8M!(;-r1);5s9W^`UjvPaL3dFJ(w*|yi7qUlzZJWW4wT(<696yOe& ze@tv)FZQB-hu#--5pXDugQ*F$px-aGRAM=`89&x6Es;iVaCnZKU7vXHVB^mA4aybE zarkta@%yUvfz9I-Q>1W9i|mjPcCc@r^8(G$?*+UHanNlA{g!rh+5FA84P>3xZ(aU*+r11vEO z_$V&D!zU~y#wX^QU1MfnAH=uk9~eMvam7cDId;Ev;g@os?`dm#eT|NVZ$@e5`l1S1 z{h18HpMY7YK0%4N5bd|P_6G3MNge^XF_kI9?h5E3W>+m-$j&wvtmKS|oA`v#HFnhK z9D2QZlL_%ajuuhYF619Y`2be5QSmjU*e=IsYM-iViWm^jOMOv@R&1Zd*Y zIlN7WNzB(%7)4|QuufB(CG+5LMfJLeeCUT0YQ!I4tFh4ew%s!W%yE_en|uB*P7~~T zzf?oyKW%;0KI$+uJ=6}owM6WkkWfbV@@Ju#VCLHyN)21E{!nfe z?dx+Q!!7jXj?L_~qoEWnhsba1`Pm{F=g^2**|sZ`LO4hB*9#*4a$GAnTTXURnyWB@ zeQ7$`*$#qn2KDh3!%NpT9!JFM@S!BkKMmM$Bn=1!#m;dNnZ@(=*)T|#=7r0>MmQJ0 zNCPqA8;1fA#)^T{gzJn#(&kERV7mV>F^|?aEj{7}@aEhiPY4t6xysyY*~GBt-4S%N z4s9Z(uhD&VGY((qEf-R$gH1;&G<1dq%S8(C&h(Q>)?Sry2~0l1)w&Ey(K|G*`9I8~ z2A?m9Qg|?C^^OtSX%Br9(s;T0^m75&Mn#NkF=V%`#W~8@6IaBrtGb^sSeGv?>tU{B zSb5ZYB0g|yGBB`QO`;LsqK`cIk+X{_1rnvc5?F+DY9Riv#beScpUZ+%s&$gubAn%y z@W@Nv%xpRg6)IZ;nMxvyULeET$h2EjaXH*UB7$IcR1j7G<5FY|=k zU=z1sTI$Hj14G2Jr`~pWv)K5gmk~YXTe8Q@#-(LTQK2Ob(kK2xPXBFz*@L26Yj#b1 zWw*?!Ri34#UYTEhNngL4q5|p7jeEy0WHYOLvCqND7p#8vj3+V1q#&OsjK3Y_^5QDM``&1BbD2jL(DoV} z1r^NF>Nu~T2@r6NI=rzK$j&+vc-N^`(f%F|R>Vl-q{uW|CG!KU&uT4r1dg3fjo1AP zEdH$8rcAxbU!cvNpC$$1>M(sjMWNdB%+S+vs9+XSRCOd-QoU5car|UgaPUY8jYSC+ zdd(Kca2`PggLdjn7|VxTSWiD#dcE~NOGNcSQkQ3rTQq}op#{c6?SVhwz#YBZOcRSQ zw)+O=Q=GWtt6^YgFy>ZF@9&=Bk_M!TWNVx#$8y_iuzVe0#p0PSyYnzsq+zc(p{(~3R*;_b%-p6{9Sb(qNYK=CPr2=H zU`U^}lSR^t>n$G@b=EXc1Y*>6sNj#fc@7-ST7ALL5Defwd`vjKL*Yn42^fjTE>Sv+ zwghqhY@5*JR#QMwxpuXmM%(u~M)A2QxE#BRm2B#%Oi0ADHGDGPSQX@3pF*1*lYjrn z6?AH4u@L^_6(tv{_T9S*C|~I7M)Wp>oz_y^o@wooEuQF;^g^F7xA-fHd2ga$e zLm6|Ikl539;PU4^n9PY+(8&0VgW}?VD`*J=@0Lx%t%}wf`L%AnMI%mvp*NdE@qj1$ z;L<3IMBQyRJw26C`vQhsApzhUbk+bI*O0Q>&Ti{Iu-}X2EoIWv2k+lPrn7o)xNhGGr z3LAP5YToNq-=J^wu78-(J1GED%^WD;A$qYT{fB?iP7cw8M3rSxk?xz z>+q`9$IAJRmrbtN%1FohYNP7VGvFF;h9X9j`T^01cfjuYx^s*7UPj=YBgA{t(v#6! zThjiVAA}FA1@q@<7JZiD*@06nFwv&LP443nnaTLP?svZCVlyz7oV6y(h{F2VtN3Mg z=YrNfwg{O4W>TG@*+tIi8Tk7xwgsa*<`cfMbwgVU9reuYwvP*M;o!Q zA2E}wZt|8c^kBHPY(_QHet|x1fOYZe%gx>3?wnR+)q%0O-6enQf~IG3tn*1%6P%Nv z4es2S3Wkb;8>fkCgN&yRa_F@cXPTs6D{q4$YJK0WK2mB`J&dKdpoq&mvTL0PDKwZG zWUP38j3NdtH@_XH9X%1QzRru>?;)T!onlh7F0I~0O22h64|}lLtlUufTg>z3nC8=V z2Ag*F22^z0I(`~>%Rc~0i!3PQI^fn^ydBMmZ7eniweBlVvDU7x`<4+eshbaURCzIg zK9=o>#^LtNwo+EE!gC3Y{SP4eOZOGJ6vxC?k^X5h(t#p7Msg)0^F|kmHZZT>JJzQ- zSPm*BS?TxBxdo)`8L5-rLmG>1(zZti^__hA;CvfrF;8xgOs*;Nkj}IDpCdu|0@17v zvOz)Tb9>NB8}RR7KaCGJoGd6fOF>|e-@evMO0lcChM{lCqGcm>Q*XH2L3_&U-CC92 zgfz&-0%SGU+^k>viL}Bb!L>uiD&cv zVtxu=E$6eiG<9-DIy#WmVBE@5S~<@- z*KgdUQln-Ktd<%Jhu8&DqY!w&mo&7t-!0#a1uLwI*TYkZ@0IKl>NdVO&(Iqp^>R*G~r*s(PaanFMas?~lDQ9NRw<8DU zTfNG8XEn}2hWM0NQCoJ%D@ZQGTwJF#+&u(BG~C|Va;mF_L$OBP7A~ZKYy7MSrUdkQ zBVveQl?F3L1TXh2e=!(2PaUVJPX<7OIe3^|>io)W`?x#-tHsk;AA0oXdfFs?4VnQf zVoP`B(#cgY+pvRWiMbtIXmzpun^MyP!u{1g6_hI^Zd#aFSTJ$@5X)mE47PN~yz}F_ z@R-58^7$0`!oJnln+|(F5b*PHJ&p2@J35#p0}yD5Th+70K+o ztC?}QR(4KVE$_g{X%-*r(6SPe7@lVF>^2M90ApQ3T_ez6)R)SmH6RbMQUgoA7wg0k z;Mw?6Mv5gVO7b)poRhjP{HFc2{^5=C@U*Xu#ZSNv>V~QJLTh|`{AT@I%X$RB?cEgDxo!W5aJaBf z7kK$ATnQh&CLGhXtU@{!TV3YMJ-~Nv!eu@0t#&xa_}aGwB?(NV)=55FW2tTOy3cV8 zn*^oVIg|3FEBdLiaCam?M#NxKqa{XSfq9@|+prG4^Ob!Ueh$k5Ph{}<4o&;NRQTHKO;~%Lu6LycgB)2Ko|Hd4j93`pvx?gGS8f))2 zdBdGo%V(h2PUi_!h$O_yx4G>cQ^_c7+HZIM*lj2u26|3s(epyYA>;x70~j z##9vIDE9<6_8Ja9i}~pJel_W@`y%iyx3_J(v{cG6Xl^V#Q2o^X+;wMsZ%e6mH?wZ1 z01~jvmu&A5+SNNrWLM&9PMFIukwoSz-axd8Hj}Up1CO>N4>CC}`-JJwvqaKCG8i@d zwX#dY)6|sCvFoM5>mE>-XUL!?+C^hcqbTROy4smqq882mXTfK0#~w)~PU9%ljz{qoPKOOVtuveA|@|`2xepUj{y8E~v#$ zT@_T6z!W?Q>6HY^AV3L;IU=>UeJ6oEtpQ3OFzDFQ|ahzJ2`K}r%O zAR?SL*@US>cEH^yr^W{Q>rM0rn#ec zGSjwGJ3fyj%Xf)8r|&10=GWPK^2^z*n$BNeNi~rhvfpv7KhquB(X7n8jz0_>e_1#F zVnPXC7+sEjhO~&C5rZvQ1S4YYnkSU~UC-QilLLO^T+jV(jUh7BC!#j3+epsUt}k$F zLW_VtiBk*Z-|%(`H@w`$)W07t^im!Yz+4sm+&W#`KwrjLPe3qV4aWr*WoHhrRI5*y zfyMxKjd09IUg8hO!O>Vt-UE*Cee{h4J7(M50{oQ2+-d~p9K0%@+{@K#Vn1kIT)L{V zaeg7BYv#+w3#0AD(*oD~#j|8jgR;c!nrXpMX9x*7-O<8enA>X3ENtZFtnB%)t#n;Y z_()Jgxkq?hXvml>?HI@887fJ@qV#$kBzJvp81I#tlRdU`5YD#cC{e1sSKAerEQpnwYun821x>lj zCU04~Nq03hkY9XtHxghFrq{!_WimJu7qz&Huvd#|9#Vvw{WULvX0A6u0!^YXR3<$5 z?fm#@Kgtc@<*KFXVnN6Dl$Wj-X~ypdUC3*TlDzKDzw6q)M5CITZ_PDHxc~X*$FIKr z@Xb3ZKH5qwpAhxo#kkC_7lrOM6WQw(t`TbB9^bK^&&df6bQ>ENVe z$BJm}izFfcbVFZ@x^wssIoB)uh6X8%RaW2#x9lU)Pi3=7LsG@(O@=o^Q`cRqFN-qO zm(1c($vNJ)r$_y`LMv|%WMZvy!uDYoC_W3FGvUAz@VwzEP1#~6Lq3052(lu~HJF%i z!anq(TOECD0nnbck)aH4_(-5>K_;u zOb5NWbt9E1ZEa!=GSFn`3BMG-8z7G_R0wr1kJ?ePq)x@bp9ssm|4WSZ^_#L>bbH>? z%|qhxL7GDRcjUYDhi$F~9_G_`Z5V#aiCf>2TfcEN_g=f#yC0^QMBFs)7&F(kUfR;; z>WYW=@RxxonB#?%3x@>rQtC|}@1-i>>z-Tq#h=424%FY;#kBqyoybj(P7B|eXppV) zxtrYYUo;Id+R8u4hs^$AS<^R)*hTr~zTA{*Ejw3)42p-E$LcYK^bS*;3u@o4#4r`K7s zY$idw51m;0)N{DFRU!9lMQ$G|p*5ZMfPQtOxFXbc|6}nwgmjw!0q{0A{>|hM!n7}9 z71~hm=3;24MFNIHxqX2$aqw;d<{x3ypQ8zRE8=A!ihU1tQN!J{i+2D40nJVZ z*vUcTr9K5Rb2fLpgrA~a!XLU6p3mvOv=b^fvX~KhkSP>J;2#{c5WM375Yw%nb2Pxkk{4e{{q8cPyBnN4CbNud?yGm?d|vZKp^1v zCsJMbOrU#&2z_wsA&;l9Q-p2~17|UupSd|TnE6G)Tbx;LMfR+m$fCMAxq4P@k*IJY zQDw}KK5}H%EPf)4ZjFy7AIU?wEG%R=n(_kr!XCbgpSTV2w?X(;wgTmdf|Ug}8F$I$ zyRYbQ@1d35LY6xD3zz3TpTg}uc%6gek17hoii+xzt{@@5e6W15%twpsEHr$|uyVOz zEvZg@Kr75=0lrk~gL8}`sv1N4(?bFv4kX@D~%h-e@K=ZzEQdn#9wQC{rlL}#0)5pDZiCnt$E^|`@mex~TLOBh;q#PIE zOoTj&hyS+wPk}SZH<_H!Y{})~-hB>G%OSqSo6EPdWF8x~1?#3>To$6wv%4#tH@-Ia zez$VzDb@QKe2XQ&%7iX?R9Os3OfbJP%yOrTq3lv9@<#7Qrv7wREv>ydE}atwiz;be z=EgR=8SRttj>9p8#Kj~XWs$o(<6b$SRsy8 zZQo)|M1jkIa|edDRfGGa!rTbng3>P$0^eNd;SnwCZOF^XIDRU*^P6LiO%{NOw1*GT z5FT$|Rj3L+ur?Q&(Yc-unwx28)X#VJ%z5qLKLs@*>Lx`a?lJ{e)iXfaR_(z_0jDyY zSix*)IN&KiN#XJ{N-#ut{6dUBNDWdj$M*fP7b9qkVGbsJ0W`9rAoB|uO2O(7vIp%A z!XNC;P{R#Q6i;ni`N{8?f}IuvD(|@6mw&xv)GDiakA2%X%B{utHl@9ekPuz!J(HB# z=={>tr(HG7)@jk%ZwW%JkAI94t8gzCJt|Je}mM0=XLS(a(bT z9#}XyupPTDt!Zx2`kGgo4A&N2$i(s5?HH;p2NFF1=CY)x(Cs_DqTBDoq?=zk1k=2x zeq`tlZHrF1wpoL-mQ>}vQ*y)UI^jE?c=ILemY$4+JKvmb$@P6nH)HEKdbL9Nc@49# zEn{$=pMUZ%ZZQ%`ke&9n&3AJ_uq@U`g~at#SN~AV43RT8!$Pki^g4n8%H?^ zc0>_W=fK8bSFHf;_K0Ud8F+3nM1Phvq8?=cZ6c=8e0iujGJBb$1v za>I`HBiAfJPBh27NB$YfLxS7OPt{i@g0`SE{*RUF7rhHv{7eH7=~@;W?Y`E|u3GvE zy3HuMIhc*b)h*;{2(*#KhF z>vSatU>Z+v(`483$aZ`q7u{qk!otE&-gi-a%iDPIiTrD*i{OT55o9jA3G2WWIk$4w z^(=BEd({z`$xP6GXdog-yi3&QzV7R}J7u9{{c3U+%WUwPc9WRgyx~&S6fA0*epz_H zs5Kqesx@%7)%6yrwsbJ+qly0F9k4!!{?K4;V5c8&1=&T#xtNf-a4sc@j2n*-C9|p! z1N%DV+$Qo7N(lcjW}{5J_!RHeZsfG1E|?D2Mf4(I#9pnCOas=Xs_$#Luua zqcj*{$q7J~SrTe)%bY&5p>R;O^xB87OSckN@z+^FFH0>njb7b?zS>)fEL*3gSJsAp zAGVl6;6GxTPc|n)NAl*>=IcBR4@~JIpDxaur*F<4Ss%NC=Vg4=XQN&+ z&mCfZ>VwX$(9JCKSijxi*4w0PbBLy-&ExChHP4kmRmHZu5EmnCo=VPzP3cCEa%#)FyP<);5^kX0qujO4;@V5_OyGrjzZcf88$Z@Wv9A>uouwCKzIoq{!D53^kq3}_u z0w^7>%a-Dr;e9OYw3nV6zKJ5(3iXHhCAdjzdlIkH^|=$Za{)to39e>;${aXMcF6tB zYak}%vL}pQAxXn!5l<>X{46yn)Kj#ajZ;tsa;={L{WM-4oV#{gmR1{ZMQB97+Q2uM z90zUTZAv(?h*S&$q3__XVKXJsA$>dtohSGcZZDfzm04}Ko)n9F7?a#%j&Ga1a{%kP zMPCbU94TD7BpnxABuy_bRhS~y*Yz4Ot_c|maJY4Gpg+1AyIQ++`opCP=VskxjY>G_ zIDCdup%4eDF1Jx~y;Ly-ME3{{C#%4;^}$a!EMTJLo|&1%?hxg&RTaG; zIDZY#?TYYFwA45BQqor7?2ECp1Oc|nk?X+s)o;DR3Zq8BEDgJxiSKj#F zqFRV;EMbJ@nk_R)x@#I1Ob*R&+*T3)bSqbvxnDc3$|2`6%+t>7kYNv@GTbiXCGg7o`%}_sLMpo z(1(ZfLWQ<6$E-PoqyU%A2-gh!QAC>jd}~{*OKan04uhe1-OJEOo`Whtv}pG)zU06P z0wjwNx+E~}tDD>wM9_w7KTvjx+vPgbW!4$*_T8$KGr{hIoOw)+!YJrzsQffyi!ZeE5>N;+s(=oEug}7EV`w!-XDl5*$9I=mF&N0Xx2L(8H zVKp)ghAoMgCSI+&?2P8GNDp7Pf|Q>ZA6BH-6FjL${n!P*5ooS(ieAj z$-tK*((qZ42@}RVFqXr~G0**}P`s$tiypsJN#Viatye|?=_|5dzHxXh%D)D})m}1` zdnWaU0e3blzJGL}OEb$6uc-8RmkgVJH+js4ZforkLa4&@RbyZ+rnQN=f+xjsP9SwE zHz-}n!w~JCsHh*|84jglvgZ=gDW8}1xLo3ys*U0kFX*#^{qc?DZU{k`Dc9)w!9o$7 z4BYy~@h;vyzzXKa%*d^LW@rceK1oZgN7|*WDo=niv=@6$Df@FO{Y58Zx$%;&kX+Rh z-m<&1_LO=GpZ^7Vx_D$KbB;4-Y5}>cZL`;_ZrOn+%p2nonwsXyN|1?;QhJAWfOsln zLo0tJWdCZ0zE7{9WZacOS;Hsp4Zr;ITbhBM&b=x#BVsscQYoc11c6C56ufL=Cz7Zo zJoAkBW^)`u8C-kc9V;|&{L&VEJxd(I)_2NbM^_h;Ym~6}wYZZ5Qr?z5Vw!pql7v-; z>wpo0#qlnJF8#B{UJq7z>F8nY_sb*J;)%vCj&s@2o^^HSrqa2xG~Dzu9L5cG=NJ@w zpM%4n{{R*fTO8VBk0&M+A_|sR(Mfx;LV$_qZCi3{AtFr&LXt&J1dj8>txXD8-S*vc zd|!hx#~Ya##_^7Lo33O~h8ctVxe!O6XV__@h@(geS8gsup7uRXm6cB%x8&^9cN3R^ zH+Gy{qgr=SGS`IFk&H@EUR@Ni85*?-UB(|9hj~uUT=_Sb<=>!!DOxn@I&Pz=X;zor zm=OI#;+?0W7g#f7KK@S}An21mLB~E4RC3h6&O|y5_&bO4{D)1?VO9U-MAFcO%Mobzx#l8?&m|9dp>(}50w*<5#4FD~`I2AY+NaT{n!}qwaEh+Sv85MPocJTP z#w0_bKHH@J7EqDQ&CyrX8rj2jOP>+Z&%y$(`+vgPfB3piyj$c|rA=JR(8vBI#Z-<9 zs%SK=XK=n(Nb049m03zpPrmxP+*)m{UvTM#o$mqdJKrV?Iq5H)6PBF2ZLwwxzMZo3 zy?LgwYppL|z)McbW;|9}(rWz7Urzivt`rgZs?NQ{B9FUKV24?A(Y23)&@h<0cuPUb z(EFaaow%O5e;y|a<4=B~;gpDuuABNX`CSTsdr`+Hzs-+*)LD&=nAXS+j z|M;!Fwcd}t&3cEl>eRBD(2j>{o>j87+Gx1@A`0LptFVsrkK(J6IsO3;ZSDV7Hsd)b zPyHN^u#qw4X#7eT`9^>?;;)X3SaUL1ee)#G&!ni$?&2D#$b}W%KcA1k%J}cy{Ib{$ z4r;StZNsPGUe;PI`rNfr*WLs^w5f!ib(=E}Tl6lBiQ27aFf+c(@L5dwv`Qv?^SQS% z8>pL|6@}d|Ct$Xd=4peVL+red$B@Mz^1wt{1r`8&dBb6={j-=nm1#^5`_{mD3 z{vM`hW7aiTB!f@hq4>Uu0m8V-b16~G%&bKf8lT=6ayn6WdXNd`<8)sm;~Gr(>7u-J z&&~Yxi~S4DG;#aJa=Yxe%ZYjikmt(nvlevUaxc;q*XeJE9R8?J0J7&MGq*PlNX6GH zTbxEpZ_Eq)N+Pzt6D@vz_S>nDYl+Sf_}EHk7G4HX_rQ2)6I&7n+sjYt|^m3A@JD zkl3;-4;zb18r^!r%a}7McxU6|PrQbFIlA!3@GA-FR26x%!-JVa&*O*U5vYki%S092?Heam~pIqX;uMce)c|X+@d&un`h+sH#2U7KID5 z@EL3ya0MhPOz~8gtsT4tw1mn{+m5&nO!SBaA16 z^3I52-K!KYq(uy`8Vnb)UNs@wPMu!wEh6*jZtypU0qrOKk+t^M)WuwIS8^SbuP5*h z=6@qEGCuX0FB(41y$V)tl1i4mR_SSX54fxk0nW9D3vb2_NsuAsEES|225;PmNcI&L_vh;$ti|| zr_km1-;3i?Xv*_n-h=8(PeM#w5z?x1H1w*Zya^-}DC8XnHUlYu&%UzYfJ8Y3V$2nK z=Bb$ZFTg9BTOZDDYUhVVI=87SCZD-0x;$&GGf(FvmEU7M{Cz1(x~~1#UU5*K%Jkks z{uIGC_@=Y|=P*L~<%p^A;73Nsrp;SMbl^>Xxer!d5|RC1KOXa+Jcvd$Mp=R})+eH5 zV^?2b`20Re_AbQ%==}BjMn;t%Udh_xE++^un)WZz08!60=W;-IXwf-fkK{SIlnoDe zJ^UUvpJ*<=)qFV`)RngMoyYpetBFfri|uaDHcj#i?d`uH3u>$vDK-VCtAC|EcxKF}XNUU4tF6YX}t9R3Kgt zVfof?NpRx+#XFpvmEj5zC!Ip*87W?olS|$1IZJo%J#O6_(-C3SZeD^SLoNuJ&m+^b zFJ=X^Zi|Q9e?C`!cA5H^k$7v1g z-g37&{UIEB8q#_HJ@|>rfM8G58;f)Wc}IJ?(@yQi_Qw~RYzQV*drNqV6I10UcD6S> znMXw*qM7aS%A6Qhs`tYBT0y|JHM1oE1cGqPi>j zyGl8fQCrrTU?*%EVpMe0lgoR48Nbc(fcRH>XvJn zxU_&-|JPIIFF=6J97O-b;nO~M<}PRzX!oETGJyq!ZF31$u0w7SY0@YM4!_=!wXyn4 z&}YRXq&t99r$D%+82IeXdWJsu7Wk&$O?Vxr0)UZ84j>MQk8(&{%FQ8N;pXfkVN8R&jpJ--e>qm8CNSr zNm9HgXMgou+i^JLFMdZ_L-1Cdo%N!6L+#ppj!@KTa#uFG{YI9==-4Hzyp-)@4S87# z3%qf$b}y$aqUf`-u2@eakf?Yp{A!1ZsltSJrvH@i)qj% zQ$aWAM<$2E+O0K|nN+)~K|OyX9upt|d8#{_kMy{x+#|=NWP}~x${yHbFE82ytZ#^s zo0W^5aD0-J-N_4ng*ba@*ZH4?nBrdKUvdY~Uiuxy-=x)x+l;gX8QUau*081&#mecGz3Qkg#96LGqck@Xy7>?f~t?)y-kh1o9RYH zZq|~)MH=uMnD1WLIahmHP@4b4boQO#%TE_MUT-;670ZD%?zovg)IcUI88|j<>Xd+; z_^}EgBh7kq>uV=$w=c~Fm)8fJSC)ClPdcjft>_7HcJFX8;;t0VZ1%UU_|HkyHf+-ttL+N&(H#uo~(U6=986i5g@~j z&)t?72KZxm;}1OWt< zFDv}ef`kP48I~m^5X!ydC6ZL-fGN3#Kei#+i`jhn{VwuVtkH$7I`vcQ(!Fh^UkbnB zWPz#q5{Wx^GV{{`o*O4-ZZuL#mF#d6S_PAHutxI|m7Pl|1I}jdQVu5}?-zLIMIbjj zgzh7(REK=xCBj&bxX->~U1xfLMgtQPfQ3qgWWxllc7+yd0Z`L%rWI45&^WjzPCV(- z4Q=7*tpnS%jiaAlflDxPfcpNYcX8!Q`Qu6TrIwZ@P>vbRi@dA&oA;#%RGP}W&*5sr zjkJ$io;-!akLeJ?TMs`dq_ui@=k07=*|$@+8vU~L#^-myzcK9GZCT;77T%MQ_vKPP zYH6}xSu_lwpBTO-dF(}_SS-emU*_Yvq7eI*Xs9A8l(FoggVog8mhMbLl*Bjhge=mI zEd5B!Xsq*}gWdQf86dWQL2mw_@ryL@JF=^W_bJ}HTnhl&W!6AlUu870xBU(KGb!Yp zs@8!L@k@|nJ2nz-5qBq@vjA4K_Ys;x`AOpHk4FHyNGBJI0J?^)mVL@s2h{}ejE;?9 zDbJaavgF>G@e|v8?Y_gDW^>@0kPlEOw)3Ci1Iu>rm^!Q~?_ zJ&cT-^hKsctc&c*FaRQR%7+~IG(5*Q|><>FHojX_&21K#>S zjR|ogDp{vp_VSwDhMz^$90+Ktq|vmM@A`3P*{_`XDs!k%yn0<}b9(+41$9jyk6H=1Zir zyJwf%VTs7SqB-L*P9}TJqySp9*v%jN@`G1RKs3!`-w&j~4)V;Q)7i;N{zml&+Ds%| z#V+UVPbZ(aD#CTytU+PCEc)*?4_^=cJ6>=GjiUUTg!t^r-jc|#t5ARnVjVXOIg^K> zONalJJP>rOa=HMGf(N>;o28GnfgrW*&+CrCo?M_pmv=LunPry>}WuhzVjvJDXm{{H@Gj;a*Mwzu8&yLum7$s2r}2 zcKzxLN&~X9yLAE{xAxpJU7GK5y+nw_N=L2bJRB_;<9j=Cxc0n`?-V*12WoG;hBamk zO3CY1R!4+mTw{OSi^~Xc=ARDT4*;?Ok?rRiL(30-hPp{d^SZ@q`L{wmGYr1xm0bX+bz zHOJRVDfc^ZU;xo1!~Fr;W~C(w#)X2cZn-eg`xr~ifJa4es?n><^GYS!Dn)Ublj z!jq9g2S@A{U-O0380w`9q6;Qd-z9uNzuCUZ7tc`H4Za5w>UukJHnT7ZNxer5{sI>2 zf$C*{pXXzCpnqFZ*Zz&$@PAf?@!z!ZA= zwpZ<;}3R*2XHc_KNi63iorm)fC=HN)^cRVv|2+Pqm9gn;IzRPtT=5*Iu==Z z_a8m4a(I-k{~C@WT45@z|9ezt_3me@KfvmSTA z6CU*O3Zcg8fXvV5i+s>W>4qh!Kb}|W2`Bt)*?n#3g)SbM-Ih-ps-yH#>YKfLnz9cV zO)DJzhcvO=M!g3M-4utUhrj8?KjGrPbaheK2o|dPM@z&p`T>5MbkUzJcRXFnf_gb} za&rHrM1~9FH}{#+G|GgK=Gd^)W6jp0GCR|OyTVu0)YvYJg6GmFK&%N0N}TbCilbKN z`*-+{_Sigp2wM)A(X8YR_^~&XVfwd`?e=qbtbYmQXU}&9vOBz=0&$5vD$ThOfAdlc*#n?wrK-5`Jx|XA4`sNvuGwlp;G@s#tvk(e_}ugat{d{cVJr0Wh+f z{{1?zyP7tiLy`sU%u)IVfL)y5Fh1syIRh0PaLOiS0I@WHh8g}%{{IvCmT9QQh-iuA zPNve==@*o?Z3M}&xdKV(AUCqqA)CNXg6oGf^}DP3oD3I!C6Vfb@n6MwBbnJ`B77Qz zFrgC2YzpNro=x____2}1>a9^^H*<`OOoIPFAxB8;Z{jfOGFylGE($kXJt4Y$V?%!b zA2a*U1@m*R|6CBeOX!aUQ4usVM~S4{AZDCQscn=gtkz(1lGb4L)Rc`B7iNx^3--=LEmnNg}TJC@@YYf1w zqxiF!R4)KxtAS$_)1OeQP2g@+YCkgH4Rr`F@N4~ z$p&4vs>OajC=*vrF90A@{TVxj3`*TZ0&r9tEa~IXt-Z3nKH{1R!D^AU#af#}mhH4B zT&d3nF$+I-nku>Sh#^875c&#<(gMZ}G_8aR2GlMDQx2)|@RAMrY%6WKw!qKR#iJwI z1t{LUpcOspRnzve0qs3aYm(INN%NE9VsMt?XH7ne_U^apLr_KjBuQSaE_lNCSO00L zcN;#p_E@Q*)NqCDd-Px?kI5m_mlKNL!!9WY#bXvny*#=}zA_j5l}GX)XYmdq+z2(N zh4gXBXjF*qd5zf=$=4k4w;|P#2grPv?Y{$}O^P3#npkQiYM~U{*iusak0-pQ*UkX@ znSDq`euW!jidc~!Fo|5mZLNA!GvkrJ(-*l|PSjycRkc6fN@1G?T0|_fkh2IX6@mBf z@D!hAElx#w?`kuC8!)32LfR`UOVTxIaEJ<~pL{g#tT8RKlM6HR4V{WcNdOJ%_&g;p z6gHt9^0c4}e2)vYVi%$x0K2}UT~H}ZX|83MPj$yTH;n{x`s=V|^}K|n%9-hAe!yEj zi=zp%IkpCL!_N02T9lws*dsP*M0@p0S^i|II?qo9Wgq`!@2<-FaPhp%fmf41k~Mi@ zytt{UGRmALiIA)bXL9m3Lr$XZ*gcb*-o7#{r*TdoJw_y8z1Ynd9Vq5=WEF&`c2v5t zmel-rmXS0%T^YPQY}cJH@bkdn=&@it1<0P~EX9Bgu1b!u06t(p7M_Azo98Ei8CyPH z;_PVf;zRf*duh~%%}eVG#IGE|cWUoUMw2>NiybfkbLe^{hF*?AeH<;YQ@qLDzAxIQ zrSO_^RB3Uu;o@bDS+v!Z)F3Iua?heGRq@t{ZEbjqttom5#MqVzJwY72DOP(EwZ1f1LbAOX^h9TyP%V+KM? zbH297B4mAa=rHN^AFJ`ymlKRwx2T6#$IXu779h*>4rJzhC7rplgW@rwDP6d5!4Jk! z&Nq41&1Y2AJhNSo~r_nA^+86t@R|eN1 zMb1Xwx+>Hv)KYl8fxV<;w0*~QtQyE`VD6CJY9}dxp2~RHBqnL_?KHgI^?jA0B9R-8 zoR#pQFV9+a<*U(%esw`3)BRu{t0_{U7LEi%`(XEh7%K%89bK}kjeVR*dF%w?n-lqq zyyq6`O82Jmi+)DO=tVXC+fS#r>GJA4_|H4D5^Zn#>;X(Y& zLL(8G?UC(Ryc`|iDt#u-HV~S^Oif;1E*U?Dj(HauQt6+uENla&-~ytCnt)k2Swf+r z(^kFYOE(J43R}eEstqHQ0AC8spDq>mt&fyQtaHh#OW#4d12Y3>!FMu#nTxAsC_<@#bL<)nDA)XNasRiQx+IeZo!^|gXip+!sN z0UAYKb;D<{8BKUb6#Zl%dpr@@m4BMi&!&E%FetuMDtU`4xzo=%rilg~EBU~U+th|A zh6zdVVSp!fXU3cq52C4%%pdwz`A_U%=7H;@%S*sbD|U(h6qzYY;=<6(NtH;tPX&8{ z7f`_-BXdr!+OT{t5VHrAEW;}55cE3q?To~r>|ya)F?wefWilMq#eg?S|3OrM>vp$w%j+ShnNxWtV&d8f{~KaGM=84pop- zQlDQxRHOrZeZAAwQ*LV(mB05xp{sbd0KN{UZ|y;77t0XcP($Es!=gTU-UUi^zw+cU zL~L%seYfR7@kWMdczG!$NYqY@^M@CA0QA5tj|NH*!;^nN+2r+UL{)L+VY&wHAZ#(Z-C zTy%^oCIbx`7b#q@3bq`q8TAAkF*l<%)c~ z+zOl3EpTfLD(R5nn()J(Eif4_*Gn@wEwl7W58TU}1$c0279LQV%Q0I}nKB$Tiy-gd zk&e_6=MHbo^9g>n7$46GNCzh9|M&@-&pBAWU%&s6c4R{cgd9pWhvzwpf2xgR1 zR65xCB(OCrn)^ha%SFZ7*o^t%*RS92Z?Lt@4YyQAOdtkuqL6ik~%KA%NHXIJ)%i+4d*m zq^&UEsi}I3%|O%0e2t56I({-fx+bVA;fK&8g3b*}@KQD$E%MQ0?6+duub7?>xo7MN zI_rrq5_(-oyaD!8p`e7$BYd!Ek>N9|26hjhL=TE$zm$dNu)8P07H(e+!B_b6x+j5! z%mR^U6vA6bYMExAWKyQX2epn61c|?u`i1_HB!kn^P_IMSwcI#Z+gz6d9GkHZw6`mI z+Bpw7Xc)P(Pe{ujaC3S;;j2@uX!E`$y8WZ1XA=h3MmqXxfVoDCbNqpcss_n>F`5>Q z(vC^mMuP_n0sr;94xCKI$8OKvLMz_lF_Y>ztARb8e^%qk*Ux>TJ9nRRN@Qo0BD2T> z84-$e{j!UUrRszje}@%(j7YdwnQHmuqi1sNv#3mA2M)*L+*35lH8ypkkP7OL$8XV` zN%#N?cq``so~8y~BHvy_qY_TJ81S6!a+5bUJ@!s&NgubeW8$4pqHj@pmRYi-9FywL zm9!rKZvbw?k>plh|HF;xO8pSu;oZTS_OHmsz)h$O46c{?J&JK~_MDdIGe?3BdS6NN zop@>U=pe|H9vK&na=m2h6;67IQReu5#_ApSzBR%k7;b zzPTk@PJ9zFnJN^Wz!D14Ih%(xOGS!3!o(a&QAv>EiLgSFe%Dzyn^Yul(K75)({}e; zR*Z-j;G}zp5aT*W5m#`rmr$hZAZizmB21>~vv(E%Y(I>;ea?X|g6JPA2i%d_gc|&F z3dS1~Fo5i0*06WT-udiJ*~%y+V}cX{Vwh6%TF6U?b(`g-6!*{?$59fqu?OD+pWTVC z5T~Vy-}DMt{XACwf&pz&oOXGj)KOxvq9EumCPBAyX01g>`#;DGs}jC$ z2#gw-dl^1Udi22&udJaypGp8_=VJg)m}4nd>*vyUQt@dWV$>I)UZ*U zE@QXiHZ16j&h(9SwB?+{I|#3BDJ4fqq&nXB2w4`bVvTk(2HOS|5Mld z52YNxE@PnTF_r+G%s6n$aU{%)m!@sPj=wDCl2s4q zHb8HVG-DUt3P#NqqaQLk*xkp`Mnuf^5!z(5bI*|*G%FvJpkMf^f;3molI)VA#Hrq~ zFAY7O`>wNdXAYl+bHk%BoLf$E>u!G1cqJGe)FGC8vm)4C(R*g&#MWy6_&Bto?r>v- z3(ctE^nc!+Po!@>4;4^MEdJG;CMt82M~o+PGIfGZL4Yxf^inLsifxL5-%fX5xGc>dHlJD0gaP1o5~aqGD42Ff~yf#l#CYbIGtL2y8!f0O2D7jr(J^^{se zX7iH50Pqs9!Yn#4(gZ%QLQ2;3;nOyJC)Kg9$s+N!fpDSr2F(6AzZ5(=DB;N-ejDtE zt(l{j|3jA*yQGKzP%#?995@czE5!w3$9DLTy;p7E-5p=}7@8)mWXdwDmb_%nUqlQ| zUR(gfwG9rI{zU6;8}U4-TB$uk>R>ZEd_c4ej(xwv%YH^hfwoa3UdA_GFEX1+=H$dg zv7evCpD^Gvx=p(u)}?Zg3;i)-F!D)e#`i8Vnz=%f`UzwWK(oNt2Fspy{sRK}&zM;2 z5C02zeD`-RA~(2Zte1E7QQ-dqY(19P literal 0 HcmV?d00001 diff --git a/tests/dialog-shots.ps1 b/tests/dialog-shots.ps1 new file mode 100644 index 0000000..9c9279e --- /dev/null +++ b/tests/dialog-shots.ps1 @@ -0,0 +1,149 @@ +# Photographs the two folder dialogs side by side: the one Download used to open, and the one +# it opens now. +# +# .\tests\dialog-shots.ps1 -Out docs\shots +# +# Driving the dialog through XrmToolBox is unreliable -- its automation tree is rebuilt while +# the tool's tab opens, so elements go stale between being found and being used -- and the +# dialog does not depend on any of it. So each one is opened directly instead: +# +# before the five lines PerformDownloadTemplates used to run, FolderBrowserDialog with +# RootFolder = MyComputer, copied from the parent of the fix commit +# after FolderPicker.Pick out of the built assembly, i.e. the shipping code itself +# +# Runs on Windows PowerShell 5.1 for the net48 assembly, opens each dialog on an STA thread, +# photographs it with PrintWindow and closes it, so nothing is ever downloaded. + +param( + [Parameter(Mandatory)][string]$Out +) + +$ErrorActionPreference = "Stop" + +if ($PSVersionTable.PSEdition -eq "Core") { + & "$env:SystemRoot\System32\WindowsPowerShell\v1.0\powershell.exe" -NoProfile -ExecutionPolicy Bypass -File $MyInvocation.MyCommand.Path -Out $Out + exit $LASTEXITCODE +} + +Add-Type -AssemblyName System.Windows.Forms, System.Drawing + +Add-Type @" +using System; +using System.Collections.Generic; +using System.Runtime.InteropServices; +public static class Shot { + public delegate bool EnumProc(IntPtr h, IntPtr p); + [DllImport("user32.dll")] public static extern bool EnumWindows(EnumProc cb, IntPtr p); + [DllImport("user32.dll")] public static extern uint GetWindowThreadProcessId(IntPtr h, out uint pid); + [DllImport("user32.dll")] public static extern bool IsWindowVisible(IntPtr h); + [DllImport("user32.dll")] public static extern bool GetWindowRect(IntPtr h, out RECT r); + [DllImport("user32.dll")] public static extern int GetClassName(IntPtr h, System.Text.StringBuilder s, int n); + [DllImport("user32.dll")] public static extern bool PrintWindow(IntPtr h, IntPtr dc, uint flags); + [DllImport("user32.dll")] public static extern IntPtr SendMessage(IntPtr h, uint m, IntPtr w, IntPtr l); + [DllImport("user32.dll")] public static extern bool SetForegroundWindow(IntPtr h); + [DllImport("user32.dll")] public static extern bool BringWindowToTop(IntPtr h); + [StructLayout(LayoutKind.Sequential)] public struct RECT { public int Left, Top, Right, Bottom; } + + public static List Dialogs(uint pid) { + var found = new List(); + EnumWindows((h, p) => { + uint w; GetWindowThreadProcessId(h, out w); + if (w != pid || !IsWindowVisible(h)) return true; + var sb = new System.Text.StringBuilder(256); + GetClassName(h, sb, sb.Capacity); + if (sb.ToString() == "#32770") found.Add(h); + return true; + }, IntPtr.Zero); + return found; + } +} +"@ + +$procId = [uint32](Get-Process -Id $PID).Id + +New-Item -ItemType Directory -Force -Path $Out | Out-Null +$Out = (Resolve-Path $Out).Path + +function Save-Dialog { + # PrintFlags picks how the window is asked to draw itself. 2 is PW_RENDERFULLCONTENT, + # needed by the modern shell dialog, which composes itself and comes out blank without it. + # The old SHBrowseForFolder dialog is the opposite case: its tree is a child window, which + # only appears under flag 0, where children are drawn through WM_PRINT. + param([scriptblock]$Show, [string]$Path, [string]$Label, $Arg, [uint32]$PrintFlags = 2) + + Write-Host "$Label ..." + $known = [Shot]::Dialogs($procId) + + $rs = [runspacefactory]::CreateRunspace() + $rs.ApartmentState = "STA" # the shell dialogs require a single threaded apartment + $rs.Open() + $ps = [powershell]::Create() + $ps.Runspace = $rs + # Passed as an argument rather than captured: $using: is only understood by Invoke-Command + # and jobs, not by a scriptblock handed to a runspace like this. + $null = $ps.AddScript($Show) + if ($null -ne $Arg) { $null = $ps.AddArgument($Arg) } + $async = $ps.BeginInvoke() + + $dialog = [IntPtr]::Zero + $deadline = (Get-Date).AddSeconds(25) + do { + Start-Sleep -Milliseconds 400 + foreach ($h in [Shot]::Dialogs($procId)) { + if ($known -notcontains $h) { $dialog = $h; break } + } + } while ($dialog -eq [IntPtr]::Zero -and (Get-Date) -lt $deadline) + + if ($dialog -eq [IntPtr]::Zero) { + $err = $ps.Streams.Error | ForEach-Object { $_.ToString() } + $ps.Dispose(); $rs.Dispose() + throw "$Label never opened a dialog. $($err -join '; ')" + } + + Start-Sleep -Milliseconds 2000 # let it finish painting its contents + + $r = New-Object Shot+RECT + [Shot]::GetWindowRect($dialog, [ref]$r) | Out-Null + $w = $r.Right - $r.Left; $h2 = $r.Bottom - $r.Top + $bmp = New-Object System.Drawing.Bitmap $w, $h2 + $g = [System.Drawing.Graphics]::FromImage($bmp) + $dc = $g.GetHdc() + [Shot]::PrintWindow($dialog, $dc, $PrintFlags) | Out-Null + $g.ReleaseHdc($dc) + $g.Dispose() + $bmp.Save($Path, [System.Drawing.Imaging.ImageFormat]::Png) + $bmp.Dispose() + Write-Host " saved $(Split-Path -Leaf $Path) ($w x $h2)" + + [Shot]::SendMessage($dialog, 0x0010, [IntPtr]::Zero, [IntPtr]::Zero) | Out-Null # WM_CLOSE + Start-Sleep -Milliseconds 600 + $ps.Dispose(); $rs.Dispose() +} + +$binDir = Join-Path (Split-Path -Parent $PSScriptRoot) "bin\Debug" +$dll = Join-Path $binDir "Futurez.Xrm.Tools.DocTemplateManager.dll" +if (-not (Test-Path $dll)) { throw "Build first: $dll is missing." } + +# --- before: exactly what PerformDownloadTemplates used to run ------------------------------- + +Save-Dialog -Label "before (FolderBrowserDialog)" -Path (Join-Path $Out "dialog-before.png") -PrintFlags 0 -Show { + Add-Type -AssemblyName System.Windows.Forms + $dlg = New-Object System.Windows.Forms.FolderBrowserDialog + $dlg.Description = "Select a destination folder for your download" + $dlg.RootFolder = [System.Environment+SpecialFolder]::MyComputer + $dlg.ShowNewFolderButton = $true + $null = $dlg.ShowDialog() +} + +# --- after: FolderPicker out of the built assembly ------------------------------------------- + +Save-Dialog -Label "after (FolderPicker/IFileOpenDialog)" -Path (Join-Path $Out "dialog-after.png") -Arg $dll -Show { + param([string]$dll) + $asm = [System.Reflection.Assembly]::LoadFrom($dll) + # FolderPicker is internal, so it is reached by name rather than through a using. + $t = $asm.GetType("Futurez.Xrm.Tools.FolderPicker", $true) + $m = $t.GetMethod("Pick", [System.Reflection.BindingFlags]"Public,NonPublic,Static") + $null = $m.Invoke($null, @($null, "Select a destination folder for your download", $null)) +} + +Write-Host "Done. Shots in $Out" diff --git a/tests/seed.ps1 b/tests/seed.ps1 new file mode 100644 index 0000000..64e4e6f --- /dev/null +++ b/tests/seed.ps1 @@ -0,0 +1,275 @@ +# Creates mock document templates in the test organization, so the tool has something to +# list, select and download. Without them the grid is empty and the download path cannot be +# exercised at all. +# +# .\tests\seed.ps1 # create the mock templates +# .\tests\seed.ps1 -List # just show what is there +# .\tests\seed.ps1 -Remove # delete the ones this script created +# +# Runs on Windows PowerShell 5.1, not pwsh: CrmServiceClient is a net462 assembly and its +# dependencies do not load on .NET 8. The assemblies come from the tool's own build output, +# which is the one place they are all gathered together, so build.ps1 has to have run. +# +# Every template is a copy of test_doc.docx under a different name. That file is a genuine +# Word template for cr543_opportunity, and Dataverse validates the customXml against the +# entity it names, so cloning a real one is the only way to get content it will accept +# without hand-building the mapping. + +param( + [string]$Environment, + [switch]$List, + [switch]$Dump, + [switch]$Remove +) + +$ErrorActionPreference = "Stop" + +if ($PSVersionTable.PSEdition -eq "Core") { + $self = $MyInvocation.MyCommand.Path + $argv = @() + if ($Environment) { $argv += @("-Environment", $Environment) } + if ($List) { $argv += "-List" } + if ($Dump) { $argv += "-Dump" } + if ($Remove) { $argv += "-Remove" } + & "$env:SystemRoot\System32\WindowsPowerShell\v1.0\powershell.exe" -NoProfile -ExecutionPolicy Bypass -File $self @argv + exit $LASTEXITCODE +} + +$root = Split-Path -Parent $PSScriptRoot +$binDir = Join-Path $root "bin\Debug" +if (-not (Test-Path (Join-Path $binDir "Microsoft.Xrm.Tooling.Connector.dll"))) { + throw "bin\Debug is missing the SDK assemblies. Run build.ps1 first." +} + +# The SDK spreads itself over a dozen assemblies that find each other by name at runtime, +# so point the loader at the build output rather than loading each one in the right order. +$onResolve = { + param($s, $e) + $name = (New-Object System.Reflection.AssemblyName($e.Name)).Name + $path = Join-Path $binDir "$name.dll" + if (Test-Path $path) { return [System.Reflection.Assembly]::LoadFrom($path) } + return $null +} +[System.AppDomain]::CurrentDomain.add_AssemblyResolve($onResolve) +Add-Type -Path (Join-Path $binDir "Microsoft.Xrm.Tooling.Connector.dll") + +if (-not $Environment) { + $who = pac org who --json | ConvertFrom-Json + if (-not $who.OrgUrl) { throw "pac has no active organization. Run 'pac auth create' or pass -Environment." } + $Environment = $who.OrgUrl +} +$Environment = $Environment.TrimEnd('/') + +# The same public client id and reply url XrmToolBox signs in with, so this reuses the token +# already cached for that sign in instead of asking for another one. +$conn = "AuthType=OAuth;Url=$Environment;" + + "AppId=51f81489-12ee-4a9e-aaae-a2591f45987d;" + + "RedirectUri=app://58145B91-0C36-4500-8554-080854F2AC97;" + + "LoginPrompt=Auto;RequireNewInstance=False" + +Write-Host "Connecting to $Environment ..." +$svc = New-Object Microsoft.Xrm.Tooling.Connector.CrmServiceClient($conn) +if (-not $svc.IsReady) { throw "Connect failed: $($svc.LastCrmError)" } +Write-Host "Connected as $($svc.OAuthUserId) to $($svc.ConnectedOrgFriendlyName)." + +Add-Type -AssemblyName System.Runtime.Serialization + +# The record is built in C# rather than in PowerShell. Assigning through Entity's indexer +# from PowerShell stores a PSObject wrapper around the value, which survives all the way to +# the WCF serializer and fails there with a deserialization error that names +# System.Management.Automation instead of the attribute -- and casting at the call site does +# not prevent it, because the wrapping happens at the indexer's object parameter. +Add-Type -ReferencedAssemblies @( + (Join-Path $binDir "Microsoft.Xrm.Sdk.dll"), + (Join-Path $binDir "Microsoft.Xrm.Tooling.Connector.dll"), + "System.Runtime.Serialization.dll" +) -TypeDefinition @" +using System; +using Microsoft.Xrm.Sdk; +using Microsoft.Xrm.Tooling.Connector; + +public static class TemplateSeed +{ + public static Guid Create(CrmServiceClient svc, string name, int documentType, string entityLogicalName, string content) + { + var e = new Entity("documenttemplate"); + e["name"] = name; + e["documenttype"] = new OptionSetValue(documentType); + e["associatedentitytypecode"] = entityLogicalName; + e["content"] = content; + return svc.Create(e); + } +} +"@ + +function Get-Templates { + $q = New-Object Microsoft.Xrm.Sdk.Query.QueryExpression("documenttemplate") + $q.ColumnSet = New-Object Microsoft.Xrm.Sdk.Query.ColumnSet(@("name", "documenttype", "associatedentitytypecode", "status")) + $q.AddOrder("name", [Microsoft.Xrm.Sdk.Query.OrderType]::Ascending) + return $svc.RetrieveMultiple($q).Entities +} + +function Show-Templates { + $rows = Get-Templates + if (-not $rows -or $rows.Count -eq 0) { + Write-Host "No document templates in this organization." + return + } + Write-Host "$($rows.Count) document template(s):" + foreach ($r in $rows) { + $type = if ($r.Contains("documenttype")) { $r["documenttype"].Value } else { "?" } + $ent = if ($r.Contains("associatedentitytypecode")) { $r["associatedentitytypecode"] } else { "?" } + "{0,-34} type={1} entity={2}" -f $r["name"], $type, $ent | Write-Host + } +} + +if ($List) { Show-Templates; exit 0 } + +# The tool reads associatedentitytypecode twice, as a raw string and as a formatted value, +# and throws if either is missing. -Dump shows what the server actually returns for it. +if ($Dump) { + $q = New-Object Microsoft.Xrm.Sdk.Query.QueryExpression("documenttemplate") + $q.ColumnSet = New-Object Microsoft.Xrm.Sdk.Query.ColumnSet($true) + $rows = $svc.RetrieveMultiple($q).Entities + if ($rows.Count -eq 0) { Write-Host "No templates to dump."; exit 0 } + $r = $rows[0] + Write-Host "Dumping '$($r["name"])'" + foreach ($k in @("associatedentitytypecode", "documenttype", "status")) { + if ($r.Contains($k)) { + $v = $r[$k] + Write-Host (" {0,-26} raw='{1}' type={2}" -f $k, $v, $v.GetType().FullName) + } else { + Write-Host (" {0,-26} ATTRIBUTE ABSENT" -f $k) + } + if ($r.FormattedValues.ContainsKey($k)) { + Write-Host (" {0,-26} formatted='{1}'" -f "", $r.FormattedValues[$k]) + } else { + Write-Host (" {0,-26} NO FORMATTED VALUE" -f "") + } + } + Write-Host " formatted keys present: $($r.FormattedValues.Keys -join ', ')" + exit 0 +} + +# The names read like the out of the box Dataverse templates, so a screenshot of the grid +# looks like a real organization rather than "test 1, test 2, test 3". Each is paired with +# the table it claims to be for, which is what fills the Associated Entity column. +# +# More candidates than are needed, because associatedentitytypecode is validated against the +# tables the organization actually has, and a bare Dataverse environment has no Sales or +# Marketing tables at all: campaign, invoice, quote and opportunity are all absent from one. +$candidates = @( + @{ Name = "Account Summary"; Entity = "account" }, + @{ Name = "Contact Details"; Entity = "contact" }, + @{ Name = "Case Resolution Report"; Entity = "incident" }, + @{ Name = "Opportunity Review"; Entity = "opportunity" }, + @{ Name = "Quote Summary"; Entity = "quote" }, + @{ Name = "Task Report"; Entity = "task" }, + @{ Name = "Team Roster"; Entity = "team" }, + @{ Name = "User Directory"; Entity = "systemuser" }, + @{ Name = "Appointment Schedule"; Entity = "appointment" }, + @{ Name = "Email Digest"; Entity = "email" } +) +$WANTED = 6 + +function Get-EntityTypeCode { + param([string]$LogicalName) + try { + $req = New-Object Microsoft.Xrm.Sdk.Messages.RetrieveEntityRequest + $req.LogicalName = $LogicalName + $req.EntityFilters = [Microsoft.Xrm.Sdk.Metadata.EntityFilters]::Entity + $md = ([Microsoft.Xrm.Sdk.Messages.RetrieveEntityResponse]$svc.Execute($req)).EntityMetadata + return [int]$md.ObjectTypeCode + } catch { + return $null + } +} + +# Setting associatedentitytypecode is not enough on its own: the server takes the associated +# table from the template content's customXml and writes the attribute from that, so a +# template whose content names a table this organization does not have lands as "none" with +# no formatted value at all -- which is exactly what the tool then crashes on. +# +# test_doc.docx is a template for cr543_opportunity, object type code 10654. Rebinding it +# means rewriting that pair in the two customXml parts that declare it: item1.xml carries +# the schema in its namespace and root element, itemProps1.xml repeats it as a schemaRef. +function New-ReboundContent { + param([string]$SourceDocx, [string]$LogicalName, [int]$TypeCode) + + $tmp = Join-Path ([IO.Path]::GetTempPath()) ("tpl-" + [guid]::NewGuid().ToString("N") + ".docx") + Copy-Item -LiteralPath $SourceDocx -Destination $tmp + + Add-Type -AssemblyName System.IO.Compression, System.IO.Compression.FileSystem + $zip = [System.IO.Compression.ZipFile]::Open($tmp, [System.IO.Compression.ZipArchiveMode]::Update) + try { + foreach ($part in @("customXml/item1.xml", "customXml/itemProps1.xml")) { + $entry = $zip.Entries | Where-Object { $_.FullName -eq $part } + if (-not $entry) { continue } + + $sr = New-Object System.IO.StreamReader($entry.Open()) + $text = $sr.ReadToEnd(); $sr.Close() + + $text = $text.Replace("document-template/cr543_opportunity/10654/", "document-template/$LogicalName/$TypeCode/") + $text = $text.Replace("", "") + + $s = $entry.Open() + $s.SetLength(0) + $sw = New-Object System.IO.StreamWriter($s) + $sw.Write($text); $sw.Flush(); $sw.Close() + } + } finally { + $zip.Dispose() + } + + $bytes = [IO.File]::ReadAllBytes($tmp) + Remove-Item -LiteralPath $tmp -Force + return [Convert]::ToBase64String($bytes) +} + +$names = $candidates | ForEach-Object { $_.Name } + +if ($Remove) { + $existing = Get-Templates | Where-Object { $names -contains $_["name"] } + foreach ($r in $existing) { + $svc.Delete("documenttemplate", $r.Id) + Write-Host "Deleted $($r["name"])" + } + if (-not $existing) { Write-Host "Nothing to delete." } + exit 0 +} + +$docx = Join-Path $root "test_doc.docx" +if (-not (Test-Path $docx)) { throw "test_doc.docx not found at $docx." } + +$WORD = 2 + +# associatedentitytypecode reads as an integer but is a string attribute holding the table's +# logical name. Putting a number in it creates a record that Dataverse accepts and the tool +# then crashes on, because it reads the attribute as a string. +Write-Host "Checking which tables this organization has ..." +$templates = @() +foreach ($c in $candidates) { + if ($templates.Count -ge $WANTED) { break } + $code = Get-EntityTypeCode $c.Entity + if ($null -ne $code) { + $templates += @{ Name = $c.Name; Entity = $c.Entity; TypeCode = $code } + } else { + Write-Host " no '$($c.Entity)' table here, skipping $($c.Name)" + } +} +if ($templates.Count -eq 0) { throw "None of the candidate tables exist in this organization." } + +$existingNames = @(Get-Templates | ForEach-Object { $_["name"] }) +foreach ($t in $templates) { + if ($existingNames -contains $t.Name) { + Write-Host "Skipped $($t.Name) (already there)." + continue + } + $content = New-ReboundContent -SourceDocx $docx -LogicalName $t.Entity -TypeCode $t.TypeCode + $id = [TemplateSeed]::Create($svc, $t.Name, $WORD, $t.Entity, $content) + if (-not $id) { throw "Create failed for '$($t.Name)': $($svc.LastCrmError)" } + Write-Host "Created $($t.Name) -> $($t.Entity) ($($t.TypeCode)) ($id)" +} + +Write-Host "" +Show-Templates diff --git a/tests/ui.ps1 b/tests/ui.ps1 new file mode 100644 index 0000000..716e264 --- /dev/null +++ b/tests/ui.ps1 @@ -0,0 +1,293 @@ +# Drives the tool in a running sandbox and photographs its grid, so what the seeded templates +# look like in the tool can be shown rather than described. The folder dialog is a separate +# script, dialog-shots.ps1. +# +# .\tests\ui.ps1 -Out docs\shots -Tag after +# +# Runs on Windows PowerShell 5.1: UIAutomationClient is a .NET Framework assembly with no +# .NET 8 equivalent. Start the instance with xtb.ps1 first and let it finish connecting. +# +# Windows are captured with PrintWindow rather than by grabbing screen pixels, so the shots +# are of this tool even when something else is on top of it, and driving it does not have to +# steal the foreground from whatever you are doing. +# +# Be warned that it does not always get there. XrmToolBox rebuilds its automation tree while +# the tool's tab opens and connects, and a run that starts during the wrong moment of that can +# fail to see a toolbar it is looking straight at. Re-run it against a freshly started, fully +# connected instance and it goes through. Nothing it does is destructive, so re-running is free. + +param( + [Parameter(Mandatory)][string]$Out, + [Parameter(Mandatory)][string]$Tag, + [string]$InstanceRoot +) + +$ErrorActionPreference = "Stop" + +if ($PSVersionTable.PSEdition -eq "Core") { + $argv = @("-Out", $Out, "-Tag", $Tag) + if ($InstanceRoot) { $argv += @("-InstanceRoot", $InstanceRoot) } + & "$env:SystemRoot\System32\WindowsPowerShell\v1.0\powershell.exe" -NoProfile -ExecutionPolicy Bypass -File $MyInvocation.MyCommand.Path @argv + exit $LASTEXITCODE +} + +Add-Type -AssemblyName UIAutomationClient, UIAutomationTypes, System.Windows.Forms, System.Drawing + +Add-Type @" +using System; +using System.Collections.Generic; +using System.Runtime.InteropServices; +public static class Nat { + public delegate bool EnumProc(IntPtr h, IntPtr p); + [DllImport("user32.dll")] public static extern bool EnumWindows(EnumProc cb, IntPtr p); + [DllImport("user32.dll")] public static extern uint GetWindowThreadProcessId(IntPtr h, out uint pid); + [DllImport("user32.dll")] public static extern bool IsWindowVisible(IntPtr h); + [DllImport("user32.dll")] public static extern bool GetWindowRect(IntPtr h, out RECT r); + [DllImport("user32.dll")] public static extern int GetClassName(IntPtr h, System.Text.StringBuilder s, int n); + [DllImport("user32.dll")] public static extern bool PrintWindow(IntPtr h, IntPtr dc, uint flags); + [StructLayout(LayoutKind.Sequential)] public struct RECT { public int Left, Top, Right, Bottom; } + + public static List TopLevel(uint pid) { + var found = new List(); + EnumWindows((h, p) => { + uint w; GetWindowThreadProcessId(h, out w); + if (w == pid && IsWindowVisible(h)) found.Add(h); + return true; + }, IntPtr.Zero); + return found; + } + public static string ClassOf(IntPtr h) { + var sb = new System.Text.StringBuilder(256); + GetClassName(h, sb, sb.Capacity); + return sb.ToString(); + } +} +"@ + +function Save-Window { + param([IntPtr]$Handle, [string]$Path) + $r = New-Object Nat+RECT + [Nat]::GetWindowRect($Handle, [ref]$r) | Out-Null + $w = $r.Right - $r.Left; $h = $r.Bottom - $r.Top + if ($w -le 0 -or $h -le 0) { throw "Window $Handle has no size." } + $bmp = New-Object System.Drawing.Bitmap $w, $h + $g = [System.Drawing.Graphics]::FromImage($bmp) + $dc = $g.GetHdc() + # 2 is PW_RENDERFULLCONTENT, which is what makes it work for windows that draw + # themselves through DirectComposition, the shell dialog among them. + [Nat]::PrintWindow($Handle, $dc, 2) | Out-Null + $g.ReleaseHdc($dc); $g.Dispose() + $bmp.Save($Path, [System.Drawing.Imaging.ImageFormat]::Png) + $bmp.Dispose() + Write-Host " saved $(Split-Path -Leaf $Path) ($w x $h)" +} + +if (-not $InstanceRoot) { $InstanceRoot = Join-Path (Split-Path -Parent $PSScriptRoot) ".xtb" } +$InstanceRoot = [IO.Path]::GetFullPath($InstanceRoot) + +$proc = Get-CimInstance Win32_Process -Filter "Name='XrmToolBox.exe'" | + Where-Object { $_.CommandLine -and $_.CommandLine.Contains("/overridepath:$InstanceRoot") } +if (-not $proc) { throw "No XrmToolBox running for $InstanceRoot. Start it with xtb.ps1." } +$procId = [uint32]$proc.ProcessId +Write-Host "Driving pid $procId ($InstanceRoot)" + +New-Item -ItemType Directory -Force -Path $Out | Out-Null +$Out = (Resolve-Path $Out).Path + +# The largest visible top-level window of the process, rather than Process.MainWindowHandle, +# which drifts onto tooltips and other transient windows and then reports a main window a few +# pixels wide with nothing inside it. Launched moments ago the process also exists before any +# window does, so this waits. +function Get-MainWindow { + param([uint32]$OwnerPid) + $best = [IntPtr]::Zero + $bestArea = 0 + foreach ($h in [Nat]::TopLevel($OwnerPid)) { + $r = New-Object Nat+RECT + if (-not [Nat]::GetWindowRect($h, [ref]$r)) { continue } + $area = ($r.Right - $r.Left) * ($r.Bottom - $r.Top) + if ($area -gt $bestArea) { $bestArea = $area; $best = $h } + } + # A tooltip or a splash is small; a real main window is not. + if ($bestArea -lt 200000) { return [IntPtr]::Zero } + return $best +} + +$main = [IntPtr]::Zero +$deadline = (Get-Date).AddSeconds(60) +do { + Start-Sleep -Milliseconds 500 + $main = Get-MainWindow -OwnerPid $procId +} while ($main -eq [IntPtr]::Zero -and (Get-Date) -lt $deadline) +if ($main -eq [IntPtr]::Zero) { throw "XrmToolBox never showed a window big enough to be its main one." } + +$root = [System.Windows.Automation.AutomationElement]::FromHandle($main) + +function Find-Element { + param($Parent, [string]$Name, [string]$Type, [int]$TimeoutMs = 20000) + $cond = if ($Type) { + New-Object System.Windows.Automation.AndCondition( + (New-Object System.Windows.Automation.PropertyCondition([System.Windows.Automation.AutomationElement]::NameProperty, $Name)), + (New-Object System.Windows.Automation.PropertyCondition([System.Windows.Automation.AutomationElement]::ControlTypeProperty, $Type))) + } else { + New-Object System.Windows.Automation.PropertyCondition([System.Windows.Automation.AutomationElement]::NameProperty, $Name) + } + $deadline = (Get-Date).AddMilliseconds($TimeoutMs) + do { + $el = $Parent.FindFirst([System.Windows.Automation.TreeScope]::Descendants, $cond) + if ($el) { return $el } + Start-Sleep -Milliseconds 400 + } while ((Get-Date) -lt $deadline) + throw "Could not find '$Name'." +} + +# Invoke fails intermittently with COM errors ("Could not open the process token") when the +# target is mid-repaint, so it is retried rather than treated as fatal on the first try. +function Invoke-Element { + param($El, [int]$Attempts = 6) + for ($i = 1; $i -le $Attempts; $i++) { + try { + $El.GetCurrentPattern([System.Windows.Automation.InvokePattern]::Pattern).Invoke() + return + } catch { + if ($i -eq $Attempts) { throw } + Start-Sleep -Milliseconds 700 + } + } +} + +# Same as Find-Element, but re-resolves the main window every time round. Between launch and +# a usable toolbar XrmToolBox shows a splash, then connects, then opens the tool's tab, and +# the window that is largest -- and the automation tree hanging off it -- changes underneath +# a root captured once at the start. +function Find-InMain { + param([string]$Name, [int]$TimeoutMs = 150000) + $cond = New-Object System.Windows.Automation.PropertyCondition( + [System.Windows.Automation.AutomationElement]::NameProperty, $Name) + $deadline = (Get-Date).AddMilliseconds($TimeoutMs) + do { + $h = Get-MainWindow -OwnerPid $procId + if ($h -ne [IntPtr]::Zero) { + $script:main = $h + $script:root = [System.Windows.Automation.AutomationElement]::FromHandle($h) + # More than one element can carry the name -- the button, its tooltip, a label -- + # and only the button can be invoked, so take the first match that actually can. + $all = $script:root.FindAll([System.Windows.Automation.TreeScope]::Descendants, $cond) + foreach ($i in 0..([Math]::Max($all.Count - 1, 0))) { + if ($i -ge $all.Count) { break } + $cand = $all.Item($i) + $pat = $null + if ($cand.TryGetCurrentPattern([System.Windows.Automation.InvokePattern]::Pattern, [ref]$pat)) { + return $cand + } + } + } + # A modal dialog -- a connection failure, an update prompt -- leaves the main window + # present but unreachable, and waiting the full timeout hides why. Say what it says. + foreach ($h in [Nat]::TopLevel($procId)) { + if ([Nat]::ClassOf($h) -eq "#32770") { + $dlg = [System.Windows.Automation.AutomationElement]::FromHandle($h) + $texts = $dlg.FindAll([System.Windows.Automation.TreeScope]::Descendants, + (New-Object System.Windows.Automation.PropertyCondition( + [System.Windows.Automation.AutomationElement]::ControlTypeProperty, + [System.Windows.Automation.ControlType]::Text))) + $msg = @() + foreach ($i in 0..([Math]::Max($texts.Count - 1, 0))) { + if ($i -lt $texts.Count) { $msg += $texts.Item($i).Current.Name } + } + # Empty ones are transient shells that appear and go during startup; only a + # dialog with something written on it is actually in the way. + $text = ($msg | Where-Object { $_ }) -join ' ' + if ($text) { throw "A dialog is blocking the tool: $text" } + } + } + Start-Sleep -Milliseconds 700 + } while ((Get-Date) -lt $deadline) + throw "Could not find '$Name' within $([int]($TimeoutMs/1000))s." +} + +$listCondG = New-Object System.Windows.Automation.PropertyCondition( + [System.Windows.Automation.AutomationElement]::ControlTypeProperty, + [System.Windows.Automation.ControlType]::List) +$itemCondG = New-Object System.Windows.Automation.PropertyCondition( + [System.Windows.Automation.AutomationElement]::ControlTypeProperty, + [System.Windows.Automation.ControlType]::ListItem) + +# Descendants rather than Children: the grid groups its rows by template type, so they hang +# off a "Microsoft Word" group instead of off the list itself. +function Get-Rows { + $h = Get-MainWindow -OwnerPid $procId + if ($h -eq [IntPtr]::Zero) { return $null } + $r = [System.Windows.Automation.AutomationElement]::FromHandle($h) + $l = $r.FindFirst([System.Windows.Automation.TreeScope]::Descendants, $listCondG) + if (-not $l) { return $null } + return $l.FindAll([System.Windows.Automation.TreeScope]::Descendants, $itemCondG) +} + +# --- load the templates ------------------------------------------------------------------- + +Write-Host "Waiting for the tool's toolbar ..." +$loadBtn = Find-InMain -Name "Load Templates" + +# The tool loads by itself when its tab opens, so this only presses the button when that has +# not already happened. Pressing it on a filled grid raises a "Clear the current list of +# Document Templates and reload from the server?" prompt, which then blocks everything after. +$rows = Get-Rows +if ($rows -and $rows.Count -gt 0) { + Write-Host "Grid already holds $($rows.Count) row(s); not reloading" +} else { + Write-Host "Load Templates" + # Re-found on every attempt, not just re-invoked: the toolbar is rebuilt as the tab + # finishes opening, and an element located before that goes stale, reporting + # "Unsupported Pattern" at the moment it is used rather than when it was found. + for ($i = 1; $i -le 8; $i++) { + try { + $btn = Find-InMain -Name "Load Templates" -TimeoutMs 15000 + $btn.GetCurrentPattern([System.Windows.Automation.InvokePattern]::Pattern).Invoke() + break + } catch { + if ($i -eq 8) { throw } + Start-Sleep -Milliseconds 900 + } + } +} + +# The retrieve runs on a worker thread behind a "Retrieving the list of Document Templates" +# panel, so wait for rows rather than for a fixed number of seconds. +$listCond = New-Object System.Windows.Automation.PropertyCondition( + [System.Windows.Automation.AutomationElement]::ControlTypeProperty, + [System.Windows.Automation.ControlType]::List) +$itemCond = New-Object System.Windows.Automation.PropertyCondition( + [System.Windows.Automation.AutomationElement]::ControlTypeProperty, + [System.Windows.Automation.ControlType]::ListItem) + +$items = $null +$deadline = (Get-Date).AddSeconds(90) +do { + Start-Sleep -Milliseconds 800 + $found = Get-Rows + if ($found -and $found.Count -gt 0) { $items = $found } +} while (-not $items -and (Get-Date) -lt $deadline) + +if (-not $items) { throw "The grid never filled. Run tests\seed.ps1, and check the tool finished loading." } +Write-Host "$($items.Count) template(s) in the grid" +Start-Sleep -Milliseconds 500 +Save-Window -Handle $main -Path (Join-Path $Out "$Tag-1-templates.png") + +# --- select them -------------------------------------------------------------------------- + + +foreach ($i in 0..($items.Count - 1)) { + $si = $items.Item($i).GetCurrentPattern([System.Windows.Automation.SelectionItemPattern]::Pattern) + if ($i -eq 0) { $si.Select() } else { $si.AddToSelection() } +} +Start-Sleep -Milliseconds 800 +Save-Window -Handle $main -Path (Join-Path $Out "$Tag-2-selected.png") + + +# The download dialog itself is photographed by dialog-shots.ps1, not from here. Driving +# it through XrmToolBox proved unreliable: the automation tree is rebuilt while the tab +# opens, so a toolbar element found a moment earlier reports "Unsupported Pattern" when it +# is finally used, and the dialog does not depend on the tool being up anyway. + +Write-Host "Done. Shots in $Out" From 9bac4ad7f4037ba5058d470708b938b75c6814ce Mon Sep 17 00:00:00 2001 From: skfd Date: Fri, 14 Aug 2026 20:35:44 -0400 Subject: [PATCH 4/4] Add -Broken to seed the record the crash is about Reproducing that crash needs a template whose associated table cannot be resolved, and the ordinary seeding path deliberately produces the opposite: it rebinds the content customXml to a table the organization has, so the association resolves. -Broken uploads test_doc.docx unrebound, still naming cr543_opportunity. That is what moving a template between organizations does, and it lands as 'none' with no formatted value, which is the state comentality/xrm-document-template-manager#1 is about. Run it against a build without that fix and XrmToolBox terminates. Co-Authored-By: Claude Opus 5 --- tests/seed.ps1 | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/tests/seed.ps1 b/tests/seed.ps1 index 64e4e6f..6f5e167 100644 --- a/tests/seed.ps1 +++ b/tests/seed.ps1 @@ -19,6 +19,7 @@ param( [string]$Environment, [switch]$List, [switch]$Dump, + [switch]$Broken, [switch]$Remove ) @@ -30,6 +31,7 @@ if ($PSVersionTable.PSEdition -eq "Core") { if ($Environment) { $argv += @("-Environment", $Environment) } if ($List) { $argv += "-List" } if ($Dump) { $argv += "-Dump" } + if ($Broken) { $argv += "-Broken" } if ($Remove) { $argv += "-Remove" } & "$env:SystemRoot\System32\WindowsPowerShell\v1.0\powershell.exe" -NoProfile -ExecutionPolicy Bypass -File $self @argv exit $LASTEXITCODE @@ -241,6 +243,24 @@ if ($Remove) { $docx = Join-Path $root "test_doc.docx" if (-not (Test-Path $docx)) { throw "test_doc.docx not found at $docx." } +# The record the crash is about: content left bound to cr543_opportunity, a table this +# organization does not have. The server cannot resolve it, so the attribute lands as 'none' +# with no formatted value beside it, which is the state the tool used to die on. Uploaded +# unrebound, i.e. exactly what happens when a template is moved between organizations. +if ($Broken) { + $name = "Unresolvable Table (repro)" + if (@(Get-Templates | ForEach-Object { $_["name"] }) -contains $name) { + Write-Host "'$name' is already there." + } else { + $raw = [Convert]::ToBase64String([IO.File]::ReadAllBytes($docx)) + $id = [TemplateSeed]::Create($svc, $name, 2, "account", $raw) + Write-Host "Created '$name' ($id)" + } + Write-Host "" + & $MyInvocation.MyCommand.Path -Dump + exit 0 +} + $WORD = 2 # associatedentitytypecode reads as an integer but is a string attribute holding the table's