Public/Invoke-StubScript.ps1
|
function Invoke-StubScript { <# .SYNOPSIS Run a stub script's payload with the standard Stub-Boilerplate around it. .DESCRIPTION Wraps a payload ScriptBlock in the boilerplate that almost every convenience-stub needs: - Strict mode and "stop on error" preference for the payload. - TLS 1.2 fallback for environments that still default to TLS 1.0 (matters when the payload calls Install-Module or Invoke-WebRequest). - Caller tracking via Set-PSScriptID. Always runs, regardless of elevation. The PSScriptID powers Exit-AndWaitOnUI's "press any key" behaviour for Explorer / double-click launches. - Optional self-elevation via Restart-SelfElevated. When -RequireElevation is set, the entire payload (including any Read-Host prompts) runs in the elevated process. Do NOT prompt the user before calling this function in that case - the input would happen in the unelevated window and be lost when the elevated relaunch starts a new process. - -WhatIf, -Confirm, -Verbose, -Debug, -WarningAction, -InformationAction and -ProgressAction (PS 7.4+ only) are forwarded into the payload by overwriting the matching $global: preference variables for the duration of the payload, so cmdlets in the payload pick them up via the normal scope chain. The effective values are resolved with this priority: 1. The switch / action parameter bound directly on Invoke-StubScript. 2. The caller frame's $WhatIfPreference / $ConfirmPreference / $VerbosePreference / $DebugPreference / $WarningPreference / $InformationPreference / $ProgressPreference, read via Get-PSCallStack. This is the cross-module-stub path: PowerShell's parameter binder does NOT inherit these preferences across module boundaries, so the lookup is explicit. 3. Defaults ($false for WhatIf, High for Confirm, SilentlyContinue for Verbose / Debug / InformationAction, Continue for WarningAction / ProgressAction). -ErrorAction is intentionally NOT forwarded - the function sets $ErrorActionPreference = 'Stop' as part of its own try/catch boilerplate and overriding that would defeat the stub-script error contract. The previous global values are snapshotted before mutation and restored unconditionally in the finally block, even on payload error. - Status messages before and after the payload (Write-Host, neutral colour - matches PowerShell's standard info-stream behaviour). - try/catch/finally with structured error re-throw via Write-Error -ErrorRecord. The original ErrorRecord (with ScriptStackTrace, inner exceptions etc.) is preserved. - Exit-AndWaitOnUI at the end. Always runs, regardless of elevation. It auto-detects the caller (Explorer vs. console) and either pauses with "press any key to continue" (UI launch) or exits immediately (console launch). The current process terminates either way. Variables defined in the calling stub are visible inside the payload because a ScriptBlock resolves variables through the SessionState in which it was created, not through the scope at the call site. The payload is therefore invoked with the call operator (`&`); the SessionState binding does the real work, and the call operator avoids leaking variables created inside the payload back into the caller. .PARAMETER ScriptBlock The payload to run. This is the actual work of the stub - typically a handful of cmdlet calls. Variables defined in the calling stub are visible inside the ScriptBlock because the ScriptBlock carries the stub's SessionState. .PARAMETER RequireElevation When set, the function calls Restart-SelfElevated before running the payload. Use this for any payload that touches Machine-scope state (registry, machine-wide env vars, etc.). Both Set-PSScriptID and Exit-AndWaitOnUI run regardless of this switch - they handle caller tracking and UI-aware exit, not elevation. .PARAMETER StatusMessage Optional message printed via Write-Host before the payload runs. Use to tell the user what is about to happen. .PARAMETER DoneMessage Message printed via Write-Host after a successful payload run. Defaults to 'Done.'. Pass an empty string to suppress. .OUTPUTS None. The function never returns to the caller because Exit-AndWaitOnUI terminates the process at the end. The exit code is 0 on success, 1 on caught error. .EXAMPLE # Simple user-scope stub. Invoke-StubScript -StatusMessage 'Opting out of telemetry...' { Set-EnvVar -Name 'DOTNET_CLI_TELEMETRY_OPTOUT' -Value '1' Set-EnvVar -Name 'DOTNET_EnableDiagnostics' -Value '1' } .EXAMPLE # Machine-scope stub with elevation. Read-Host runs INSIDE the # ScriptBlock, i.e. after the elevated relaunch. Invoke-StubScript -RequireElevation -StatusMessage 'Setting JAVA_HOME...' { $value = Read-Host 'Path to JDK install' Set-EnvVar -Name 'JAVA_HOME' -Value $value -Target Machine } .EXAMPLE # Forwarding -WhatIf / -Verbose works automatically. # Caller stub uses [CmdletBinding(SupportsShouldProcess)] and is # invoked with -WhatIf -Verbose. Invoke-StubScript reads the caller's # $WhatIfPreference and $VerbosePreference via Get-PSCallStack and # publishes them as $global:WhatIfPreference / $global:VerbosePreference # for the payload. No explicit forwarding needed inside the stub. .NOTES Set-PSScriptID, Restart-SelfElevated and Exit-AndWaitOnUI come from the Execution module and must be available when this function is called. Variable visibility from the calling stub is provided by the ScriptBlock's SessionState binding, not by the call operator. The payload is invoked with `&`, which prevents the payload's local variables from leaking back into the caller's scope. -WhatIf / -Confirm / -Verbose / -Debug / -WarningAction / -InformationAction / -ProgressAction forwarding does NOT rely on PowerShell's parameter binder inheriting the caller's preferences automatically; it does not, across module boundaries. The function instead resolves the effective values explicitly: 1. The switch / action parameter bound directly on Invoke-StubScript wins. 2. Otherwise the caller frame's corresponding preference variable is read via (Get-PSCallStack)[1].GetFrameVariables(). 3. Otherwise the documented defaults apply. The chosen values are written into the matching $global: preference variables for the duration of the payload, then restored unconditionally in finally - even on payload error. -ErrorAction is intentionally not forwarded; the function commits to $ErrorActionPreference = 'Stop' for its try/catch contract. -ProgressAction was added in PowerShell 7.4. On older hosts the parameter is unknown to the binder; resolution falls straight through to the caller-frame lookup (which finds $ProgressPreference on every supported version) or the default. Testing interactively: calling this function from a normal PowerShell prompt will terminate the session via Exit-AndWaitOnUI's exit. Use a separate session (pwsh -NoExit -Command ...) for interactive smoke tests. #> [CmdletBinding(SupportsShouldProcess)] [OutputType([void])] param( [Parameter(Mandatory, Position = 0)] [ValidateNotNull()] [scriptblock] $ScriptBlock, [switch] $RequireElevation, [string] $StatusMessage, [string] $DoneMessage = 'Done.' ) # Defensive defaults for the payload context. The caller can still # override these inside the ScriptBlock if a particular stub needs # different behaviour. Set-StrictMode -Version Latest $ErrorActionPreference = 'Stop' [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 # Caller tracking: always register the script, regardless of elevation. $PSScriptID = Set-PSScriptID if ($RequireElevation) { Restart-SelfElevated -PSScriptID $PSScriptID } # Resolve the effective preferences. PowerShell's CmdletBinding parameter # binder does NOT propagate $WhatIfPreference / $ConfirmPreference / # $VerbosePreference / $DebugPreference / $WarningPreference / # $InformationPreference / $ProgressPreference across module boundaries. # A stub with [CmdletBinding(SupportsShouldProcess)] called with -Verbose # has $VerbosePreference = 'Continue' in its own SessionState, but this # function's own $VerbosePreference defaults back to 'SilentlyContinue' # unless -Verbose is bound explicitly. Reading the caller's frame # variables closes that gap so callers do not have to write # `-Verbose:$VerbosePreference` by hand for every switch. # # -ErrorAction is intentionally not forwarded; the function commits to # $ErrorActionPreference = 'Stop' for the wrapper's try/catch contract. $callerVars = (Get-PSCallStack)[1].GetFrameVariables() $effectiveWhatIf = if ($PSBoundParameters.ContainsKey('WhatIf')) { [bool]$WhatIfPreference } elseif ($callerVars.ContainsKey('WhatIfPreference')) { [bool]$callerVars['WhatIfPreference'].Value } else { $false } $effectiveConfirm = if ($PSBoundParameters.ContainsKey('Confirm')) { $ConfirmPreference } elseif ($callerVars.ContainsKey('ConfirmPreference')) { $callerVars['ConfirmPreference'].Value } else { [System.Management.Automation.ConfirmImpact]::High } # Each block follows the same shape: when the parameter is bound on # this function, the binder has already set the matching preference # variable in the function's local scope - read it directly. When the # parameter is not bound, fall through to the caller frame and finally # to the documented default. -ProgressAction is PS 7.4+ only as a # bound parameter; on older hosts that branch never fires and the # caller-frame lookup handles $ProgressPreference uniformly. $effectiveVerbose = if ($PSBoundParameters.ContainsKey('Verbose')) { $VerbosePreference } elseif ($callerVars.ContainsKey('VerbosePreference')) { $callerVars['VerbosePreference'].Value } else { [System.Management.Automation.ActionPreference]::SilentlyContinue } $effectiveDebug = if ($PSBoundParameters.ContainsKey('Debug')) { $DebugPreference } elseif ($callerVars.ContainsKey('DebugPreference')) { $callerVars['DebugPreference'].Value } else { [System.Management.Automation.ActionPreference]::SilentlyContinue } $effectiveWarning = if ($PSBoundParameters.ContainsKey('WarningAction')) { $WarningPreference } elseif ($callerVars.ContainsKey('WarningPreference')) { $callerVars['WarningPreference'].Value } else { [System.Management.Automation.ActionPreference]::Continue } $effectiveInformation = if ($PSBoundParameters.ContainsKey('InformationAction')) { $InformationPreference } elseif ($callerVars.ContainsKey('InformationPreference')) { $callerVars['InformationPreference'].Value } else { [System.Management.Automation.ActionPreference]::SilentlyContinue } $effectiveProgress = if ($PSBoundParameters.ContainsKey('ProgressAction')) { $ProgressPreference } elseif ($callerVars.ContainsKey('ProgressPreference')) { $callerVars['ProgressPreference'].Value } else { [System.Management.Automation.ActionPreference]::Continue } $previousGlobalWhatIfPreference = $global:WhatIfPreference $previousGlobalConfirmPreference = $global:ConfirmPreference $previousGlobalVerbosePreference = $global:VerbosePreference $previousGlobalDebugPreference = $global:DebugPreference $previousGlobalWarningPreference = $global:WarningPreference $previousGlobalInformationPreference = $global:InformationPreference $previousGlobalProgressPreference = $global:ProgressPreference $global:WhatIfPreference = $effectiveWhatIf $global:ConfirmPreference = $effectiveConfirm $global:VerbosePreference = $effectiveVerbose $global:DebugPreference = $effectiveDebug $global:WarningPreference = $effectiveWarning $global:InformationPreference = $effectiveInformation $global:ProgressPreference = $effectiveProgress $ExitCode = 0 try { if ($StatusMessage) { Write-Host $StatusMessage } # Invoke with the call operator. The ScriptBlock carries the stub's # SessionState, so caller-scope variables are visible inside the # payload regardless of operator. Using `&` (rather than `.`) keeps # variables created inside the payload from leaking back into the # stub's scope, which is the correct default for stub-style usage. & $ScriptBlock if ($DoneMessage) { Write-Host $DoneMessage } } catch { Write-Error -ErrorRecord $_ $ExitCode = 1 } finally { $global:WhatIfPreference = $previousGlobalWhatIfPreference $global:ConfirmPreference = $previousGlobalConfirmPreference $global:VerbosePreference = $previousGlobalVerbosePreference $global:DebugPreference = $previousGlobalDebugPreference $global:WarningPreference = $previousGlobalWarningPreference $global:InformationPreference = $previousGlobalInformationPreference $global:ProgressPreference = $previousGlobalProgressPreference } Exit-AndWaitOnUI -ExitCode $ExitCode -PSScriptID $PSScriptID } # SIG # Begin signature block # MIIn8gYJKoZIhvcNAQcCoIIn4zCCJ98CAQExDzANBglghkgBZQMEAgEFADB5Bgor # BgEEAYI3AgEEoGswaTA0BgorBgEEAYI3AgEeMCYCAwEAAAQQH8w7YFlLCE63JNLG # KX7zUQIBAAIBAAIBAAIBAAIBADAxMA0GCWCGSAFlAwQCAQUABCATJnvI7W20GgfK # Il2z/wfRKNZpmje2HCM87E3nFvvyoKCCIP4wggWNMIIEdaADAgECAhAOmxiO+dAt # 5+/bUOIIQBhaMA0GCSqGSIb3DQEBDAUAMGUxCzAJBgNVBAYTAlVTMRUwEwYDVQQK # EwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20xJDAiBgNV # BAMTG0RpZ2lDZXJ0IEFzc3VyZWQgSUQgUm9vdCBDQTAeFw0yMjA4MDEwMDAwMDBa # Fw0zMTExMDkyMzU5NTlaMGIxCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdpQ2Vy # dCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20xITAfBgNVBAMTGERpZ2lD # ZXJ0IFRydXN0ZWQgUm9vdCBHNDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoC # ggIBAL/mkHNo3rvkXUo8MCIwaTPswqclLskhPfKK2FnC4SmnPVirdprNrnsbhA3E # MB/zG6Q4FutWxpdtHauyefLKEdLkX9YFPFIPUh/GnhWlfr6fqVcWWVVyr2iTcMKy # unWZanMylNEQRBAu34LzB4TmdDttceItDBvuINXJIB1jKS3O7F5OyJP4IWGbNOsF # xl7sWxq868nPzaw0QF+xembud8hIqGZXV59UWI4MK7dPpzDZVu7Ke13jrclPXuU1 # 5zHL2pNe3I6PgNq2kZhAkHnDeMe2scS1ahg4AxCN2NQ3pC4FfYj1gj4QkXCrVYJB # MtfbBHMqbpEBfCFM1LyuGwN1XXhm2ToxRJozQL8I11pJpMLmqaBn3aQnvKFPObUR # WBf3JFxGj2T3wWmIdph2PVldQnaHiZdpekjw4KISG2aadMreSx7nDmOu5tTvkpI6 # nj3cAORFJYm2mkQZK37AlLTSYW3rM9nF30sEAMx9HJXDj/chsrIRt7t/8tWMcCxB # YKqxYxhElRp2Yn72gLD76GSmM9GJB+G9t+ZDpBi4pncB4Q+UDCEdslQpJYls5Q5S # UUd0viastkF13nqsX40/ybzTQRESW+UQUOsxxcpyFiIJ33xMdT9j7CFfxCBRa2+x # q4aLT8LWRV+dIPyhHsXAj6KxfgommfXkaS+YHS312amyHeUbAgMBAAGjggE6MIIB # NjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBTs1+OC0nFdZEzfLmc/57qYrhwP # TzAfBgNVHSMEGDAWgBRF66Kv9JLLgjEtUYunpyGd823IDzAOBgNVHQ8BAf8EBAMC # AYYweQYIKwYBBQUHAQEEbTBrMCQGCCsGAQUFBzABhhhodHRwOi8vb2NzcC5kaWdp # Y2VydC5jb20wQwYIKwYBBQUHMAKGN2h0dHA6Ly9jYWNlcnRzLmRpZ2ljZXJ0LmNv # bS9EaWdpQ2VydEFzc3VyZWRJRFJvb3RDQS5jcnQwRQYDVR0fBD4wPDA6oDigNoY0 # aHR0cDovL2NybDMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0QXNzdXJlZElEUm9vdENB # LmNybDARBgNVHSAECjAIMAYGBFUdIAAwDQYJKoZIhvcNAQEMBQADggEBAHCgv0Nc # Vec4X6CjdBs9thbX979XB72arKGHLOyFXqkauyL4hxppVCLtpIh3bb0aFPQTSnov # Lbc47/T/gLn4offyct4kvFIDyE7QKt76LVbP+fT3rDB6mouyXtTP0UNEm0Mh65Zy # oUi0mcudT6cGAxN3J0TU53/oWajwvy8LpunyNDzs9wPHh6jSTEAZNUZqaVSwuKFW # juyk1T3osdz9HNj0d1pcVIxv76FQPfx2CWiEn2/K2yCNNWAcAgPLILCsWKAOQGPF # mCLBsln1VWvPJ6tsds5vIy30fnFqI2si/xK4VC0nftg62fC2h5b9W9FcrBjDTZ9z # twGpn1eqXijiuZQwggahMIIEiaADAgECAhAHhD2tAcEVwnTuQacoIkZ5MA0GCSqG # SIb3DQEBCwUAMGIxCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMx # GTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20xITAfBgNVBAMTGERpZ2lDZXJ0IFRy # dXN0ZWQgUm9vdCBHNDAeFw0yMjA2MjMwMDAwMDBaFw0zMjA2MjIyMzU5NTlaMFox # CzAJBgNVBAYTAkxWMRkwFwYDVQQKExBFblZlcnMgR3JvdXAgU0lBMTAwLgYDVQQD # EydHb0dldFNTTCBHNCBDUyBSU0E0MDk2IFNIQTI1NiAyMDIyIENBLTEwggIiMA0G # CSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCtHvQHskNmiqJndyWVCqX4FtYp5FfJ # LO9Sh0BuwXuvBeNYt21xf8h/pLJ/7YzeKcNq9z4zEhecqtD0xhbvSB8ksBAfWBMZ # O0NLfOT0j7WyNuD7rv+ZFza+mxIQ79s1dCiwUMwGonaoDK7mqZfDpKEExR6UyKBh # 3aatT73U2Imx/x+fYTmQFq+N8FrLs6Fh6YEGWJTgsxyw1fAChCfgtEcZkdtcgK7q # uqskHtW6PJ9l5VNJ7T3WXpznsOOxrz3qx0CzWjwK8+3Kv2X6piWvd8YRfAOycSrT # 4/PM0cHLFc5xs/4m/ek4FCnYSem43doFftBxZBQkHKoPW3Bt6VIrhVIwvO7hrUjh # chJJZYdSld3bANDviJ5/ToP7ENv97U9MtKFvmC5dzd1p4HxFR0p5wWmYQbW+y3RF # m0np6H9m57MUMNp0ysmdJjb0f7+dVLX3OEBUb6H+r1LRLZT/xEOTuwOxGg2S4w25 # KGL9SCBUW4nkBljPHeJToU+THt0P8ZQf4B9IFlGxtLK0g3uOAnwSFgKtmNjhkTl8 # caLAQwbgEINCqrhc0b6k2Z8+QwgVAL0nIuzM9ckKP8xtIcWg85L3/l0cTkHQde+j # KGDG2CdxBHtflLIUtwqD7JA2uCxWlIzRNgwT0kH2en0+QV8KziSGaqO2r06kwboq # 2/xy4e98CEfSYwIDAQABo4IBWTCCAVUwEgYDVR0TAQH/BAgwBgEB/wIBADAdBgNV # HQ4EFgQUyfwQ71DIy2t/vQhE7zpik+1bXpowHwYDVR0jBBgwFoAU7NfjgtJxXWRM # 3y5nP+e6mK4cD08wDgYDVR0PAQH/BAQDAgGGMBMGA1UdJQQMMAoGCCsGAQUFBwMD # MHcGCCsGAQUFBwEBBGswaTAkBggrBgEFBQcwAYYYaHR0cDovL29jc3AuZGlnaWNl # cnQuY29tMEEGCCsGAQUFBzAChjVodHRwOi8vY2FjZXJ0cy5kaWdpY2VydC5jb20v # RGlnaUNlcnRUcnVzdGVkUm9vdEc0LmNydDBDBgNVHR8EPDA6MDigNqA0hjJodHRw # Oi8vY3JsMy5kaWdpY2VydC5jb20vRGlnaUNlcnRUcnVzdGVkUm9vdEc0LmNybDAc # BgNVHSAEFTATMAcGBWeBDAEDMAgGBmeBDAEEATANBgkqhkiG9w0BAQsFAAOCAgEA # C9sK17IdmKTCUatEs7+yewhJnJ4tyrLwNEnfl6HrG8Pm7HZ0b+5Jc+GGqJT8kRc7 # mihuVrdsYNHdicueDL9imhtCusI/rUmjwhtflp+XgLkmgLGrmsEho1b+lGiRp7LC # /10di8SAOilDkHj5Zx142xRvBrrWj9eOdSGHwYubAsEd6CDojwcaVz9pfXMzYO3k # c0O6PXg1TkcgkYlCUAuDHuk/sZx68W0FVj1P2iMh+VUq9lL1puroAydoeWVUh/+c # MXeqfgpBqlAW+r8ma5F6yKL0stVQH8vYb1ES0mJSIPyIfkIjC1V0pbZS3p0QWsKa # afEor8fLfLNfSxntVI/ugut0+6ekluPWRpEXH+JAiNdRjbLbZchCREe3/Xl0Ylwk # A+eQVJfM0A7XiuFtY/mOpK2AN+E25t5mQYFhpdxZX5LTDKWgDnb+A6QnEt4iNyuk # cLaJuS8IPgPz0E2ALZLt3Rqs+lXifK/GwnNIWQNbf7FmLDB9ph8i8dvsR1hsjc2K # PEW4bAsbvLcz8hN1zE1/QbOV92vDGoFjwZOi2koQ+UyEh0e8jDFHAKJeTI+p8EPE # /mqvojLFAnt31yXIA2tjt0ERtsjkhBNmZY6SEOfnIoOwvyqavLPya1Ut3/2cOFLu # NQ8Ql6HaZsNQErnnzn+ZEAaUTkPZaeVyoHIkODECLzkwgga0MIIEnKADAgECAhAN # x6xXBf8hmS5AQyIMOkmGMA0GCSqGSIb3DQEBCwUAMGIxCzAJBgNVBAYTAlVTMRUw # EwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20x # ITAfBgNVBAMTGERpZ2lDZXJ0IFRydXN0ZWQgUm9vdCBHNDAeFw0yNTA1MDcwMDAw # MDBaFw0zODAxMTQyMzU5NTlaMGkxCzAJBgNVBAYTAlVTMRcwFQYDVQQKEw5EaWdp # Q2VydCwgSW5jLjFBMD8GA1UEAxM4RGlnaUNlcnQgVHJ1c3RlZCBHNCBUaW1lU3Rh # bXBpbmcgUlNBNDA5NiBTSEEyNTYgMjAyNSBDQTEwggIiMA0GCSqGSIb3DQEBAQUA # A4ICDwAwggIKAoICAQC0eDHTCphBcr48RsAcrHXbo0ZodLRRF51NrY0NlLWZloMs # VO1DahGPNRcybEKq+RuwOnPhof6pvF4uGjwjqNjfEvUi6wuim5bap+0lgloM2zX4 # kftn5B1IpYzTqpyFQ/4Bt0mAxAHeHYNnQxqXmRinvuNgxVBdJkf77S2uPoCj7GH8 # BLuxBG5AvftBdsOECS1UkxBvMgEdgkFiDNYiOTx4OtiFcMSkqTtF2hfQz3zQSku2 # Ws3IfDReb6e3mmdglTcaarps0wjUjsZvkgFkriK9tUKJm/s80FiocSk1VYLZlDwF # t+cVFBURJg6zMUjZa/zbCclF83bRVFLeGkuAhHiGPMvSGmhgaTzVyhYn4p0+8y9o # HRaQT/aofEnS5xLrfxnGpTXiUOeSLsJygoLPp66bkDX1ZlAeSpQl92QOMeRxykvq # 6gbylsXQskBBBnGy3tW/AMOMCZIVNSaz7BX8VtYGqLt9MmeOreGPRdtBx3yGOP+r # x3rKWDEJlIqLXvJWnY0v5ydPpOjL6s36czwzsucuoKs7Yk/ehb//Wx+5kMqIMRvU # BDx6z1ev+7psNOdgJMoiwOrUG2ZdSoQbU2rMkpLiQ6bGRinZbI4OLu9BMIFm1UUl # 9VnePs6BaaeEWvjJSjNm2qA+sdFUeEY0qVjPKOWug/G6X5uAiynM7Bu2ayBjUwID # AQABo4IBXTCCAVkwEgYDVR0TAQH/BAgwBgEB/wIBADAdBgNVHQ4EFgQU729TSunk # Bnx6yuKQVvYv1Ensy04wHwYDVR0jBBgwFoAU7NfjgtJxXWRM3y5nP+e6mK4cD08w # DgYDVR0PAQH/BAQDAgGGMBMGA1UdJQQMMAoGCCsGAQUFBwMIMHcGCCsGAQUFBwEB # BGswaTAkBggrBgEFBQcwAYYYaHR0cDovL29jc3AuZGlnaWNlcnQuY29tMEEGCCsG # AQUFBzAChjVodHRwOi8vY2FjZXJ0cy5kaWdpY2VydC5jb20vRGlnaUNlcnRUcnVz # dGVkUm9vdEc0LmNydDBDBgNVHR8EPDA6MDigNqA0hjJodHRwOi8vY3JsMy5kaWdp # Y2VydC5jb20vRGlnaUNlcnRUcnVzdGVkUm9vdEc0LmNybDAgBgNVHSAEGTAXMAgG # BmeBDAEEAjALBglghkgBhv1sBwEwDQYJKoZIhvcNAQELBQADggIBABfO+xaAHP4H # PRF2cTC9vgvItTSmf83Qh8WIGjB/T8ObXAZz8OjuhUxjaaFdleMM0lBryPTQM2qE # JPe36zwbSI/mS83afsl3YTj+IQhQE7jU/kXjjytJgnn0hvrV6hqWGd3rLAUt6vJy # 9lMDPjTLxLgXf9r5nWMQwr8Myb9rEVKChHyfpzee5kH0F8HABBgr0UdqirZ7bowe # 9Vj2AIMD8liyrukZ2iA/wdG2th9y1IsA0QF8dTXqvcnTmpfeQh35k5zOCPmSNq1U # H410ANVko43+Cdmu4y81hjajV/gxdEkMx1NKU4uHQcKfZxAvBAKqMVuqte69M9J6 # A47OvgRaPs+2ykgcGV00TYr2Lr3ty9qIijanrUR3anzEwlvzZiiyfTPjLbnFRsjs # Yg39OlV8cipDoq7+qNNjqFzeGxcytL5TTLL4ZaoBdqbhOhZ3ZRDUphPvSRmMThi0 # vw9vODRzW6AxnJll38F0cuJG7uEBYTptMSbhdhGQDpOXgpIUsWTjd6xpR6oaQf/D # Jbg3s6KCLPAlZ66RzIg9sC+NJpud/v4+7RWsWCiKi9EOLLHfMR2ZyJ/+xhCx9yHb # xtl5TPau1j/1MIDpMPx0LckTetiSuEtQvLsNz3Qbp7wGWqbIiOWCnb5WqxL3/BAP # vIXKUjPSxyZsq8WhbaM2tszWkPZPubdcMIIG7TCCBNWgAwIBAgIQCoDvGEuN8QWC # 0cR2p5V0aDANBgkqhkiG9w0BAQsFADBpMQswCQYDVQQGEwJVUzEXMBUGA1UEChMO # RGlnaUNlcnQsIEluYy4xQTA/BgNVBAMTOERpZ2lDZXJ0IFRydXN0ZWQgRzQgVGlt # ZVN0YW1waW5nIFJTQTQwOTYgU0hBMjU2IDIwMjUgQ0ExMB4XDTI1MDYwNDAwMDAw # MFoXDTM2MDkwMzIzNTk1OVowYzELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDkRpZ2lD # ZXJ0LCBJbmMuMTswOQYDVQQDEzJEaWdpQ2VydCBTSEEyNTYgUlNBNDA5NiBUaW1l # c3RhbXAgUmVzcG9uZGVyIDIwMjUgMTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCC # AgoCggIBANBGrC0Sxp7Q6q5gVrMrV7pvUf+GcAoB38o3zBlCMGMyqJnfFNZx+wvA # 69HFTBdwbHwBSOeLpvPnZ8ZN+vo8dE2/pPvOx/Vj8TchTySA2R4QKpVD7dvNZh6w # W2R6kSu9RJt/4QhguSssp3qome7MrxVyfQO9sMx6ZAWjFDYOzDi8SOhPUWlLnh00 # Cll8pjrUcCV3K3E0zz09ldQ//nBZZREr4h/GI6Dxb2UoyrN0ijtUDVHRXdmncOOM # A3CoB/iUSROUINDT98oksouTMYFOnHoRh6+86Ltc5zjPKHW5KqCvpSduSwhwUmot # uQhcg9tw2YD3w6ySSSu+3qU8DD+nigNJFmt6LAHvH3KSuNLoZLc1Hf2JNMVL4Q1O # pbybpMe46YceNA0LfNsnqcnpJeItK/DhKbPxTTuGoX7wJNdoRORVbPR1VVnDuSeH # VZlc4seAO+6d2sC26/PQPdP51ho1zBp+xUIZkpSFA8vWdoUoHLWnqWU3dCCyFG1r # oSrgHjSHlq8xymLnjCbSLZ49kPmk8iyyizNDIXj//cOgrY7rlRyTlaCCfw7aSURO # wnu7zER6EaJ+AliL7ojTdS5PWPsWeupWs7NpChUk555K096V1hE0yZIXe+giAwW0 # 0aHzrDchIc2bQhpp0IoKRR7YufAkprxMiXAJQ1XCmnCfgPf8+3mnAgMBAAGjggGV # MIIBkTAMBgNVHRMBAf8EAjAAMB0GA1UdDgQWBBTkO/zyMe39/dfzkXFjGVBDz2GM # 6DAfBgNVHSMEGDAWgBTvb1NK6eQGfHrK4pBW9i/USezLTjAOBgNVHQ8BAf8EBAMC # B4AwFgYDVR0lAQH/BAwwCgYIKwYBBQUHAwgwgZUGCCsGAQUFBwEBBIGIMIGFMCQG # CCsGAQUFBzABhhhodHRwOi8vb2NzcC5kaWdpY2VydC5jb20wXQYIKwYBBQUHMAKG # UWh0dHA6Ly9jYWNlcnRzLmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydFRydXN0ZWRHNFRp # bWVTdGFtcGluZ1JTQTQwOTZTSEEyNTYyMDI1Q0ExLmNydDBfBgNVHR8EWDBWMFSg # UqBQhk5odHRwOi8vY3JsMy5kaWdpY2VydC5jb20vRGlnaUNlcnRUcnVzdGVkRzRU # aW1lU3RhbXBpbmdSU0E0MDk2U0hBMjU2MjAyNUNBMS5jcmwwIAYDVR0gBBkwFzAI # BgZngQwBBAIwCwYJYIZIAYb9bAcBMA0GCSqGSIb3DQEBCwUAA4ICAQBlKq3xHCcE # ua5gQezRCESeY0ByIfjk9iJP2zWLpQq1b4URGnwWBdEZD9gBq9fNaNmFj6Eh8/Ym # RDfxT7C0k8FUFqNh+tshgb4O6Lgjg8K8elC4+oWCqnU/ML9lFfim8/9yJmZSe2F8 # AQ/UdKFOtj7YMTmqPO9mzskgiC3QYIUP2S3HQvHG1FDu+WUqW4daIqToXFE/JQ/E # ABgfZXLWU0ziTN6R3ygQBHMUBaB5bdrPbF6MRYs03h4obEMnxYOX8VBRKe1uNnzQ # VTeLni2nHkX/QqvXnNb+YkDFkxUGtMTaiLR9wjxUxu2hECZpqyU1d0IbX6Wq8/gV # utDojBIFeRlqAcuEVT0cKsb+zJNEsuEB7O7/cuvTQasnM9AWcIQfVjnzrvwiCZ85 # EE8LUkqRhoS3Y50OHgaY7T/lwd6UArb+BOVAkg2oOvol/DJgddJ35XTxfUlQ+8Hg # gt8l2Yv7roancJIFcbojBcxlRcGG0LIhp6GvReQGgMgYxQbV1S3CrWqZzBt1R9xJ # gKf47CdxVRd/ndUlQ05oxYy2zRWVFjF7mcr4C34Mj3ocCVccAvlKV9jEnstrniLv # UxxVZE/rptb7IRE2lskKPIJgbaP5t2nGj/ULLi49xTcBZU8atufk+EMF/cWuiC7P # OGT75qaL6vdCvHlshtjdNXOCIUjsarfNZzCCBxswggUDoAMCAQICEAYFIuuX3jJX # cLz8AeYyZmYwDQYJKoZIhvcNAQELBQAwWjELMAkGA1UEBhMCTFYxGTAXBgNVBAoT # EEVuVmVycyBHcm91cCBTSUExMDAuBgNVBAMTJ0dvR2V0U1NMIEc0IENTIFJTQTQw # OTYgU0hBMjU2IDIwMjIgQ0EtMTAeFw0yNTEyMjkwMDAwMDBaFw0yNjEyMjgyMzU5 # NTlaMGExCzAJBgNVBAYTAkRFMQ8wDQYDVQQIEwZCYXllcm4xETAPBgNVBAcTCEZh # cmNoYW50MRYwFAYDVQQKEw1NYW51ZWwgVGFuemVyMRYwFAYDVQQDEw1NYW51ZWwg # VGFuemVyMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAuxv/b0+nhaEE # 94ewtCEHJFhCdgrwn6iF1lZ41Y40alX0LnSGBniZxw480yw+F9o6qhhprIpKvEoW # WW1q+KNMxjdbLgKPlMcudU8DTfUVxKRxlVuqSMdizawGlQgwtwrj5RDsWEE2k0nq # guNejIRWrWDn6JblBaj/WIx8DZ9YuYl6egi/KtJF5lYC6StOgymjFdZQ6WKs5v9Q # IZMCvMw0BqpthVkFUXEQ07J49/h50bkl1dfNAnT2K8V2QeVGuJ5YOSs3GFMXiAxZ # g6LJTHT0poTL5I5XD62X9xQ56LMRa9IDmFx6x4sMDrkn5oNVSGw7Vmx7cnI/5u1C # 1pEymuN8vTa3DeMcVOngt7k9wRLyA+OTzdlobO+o+Hfr2S9zFVh+7PVDC0wUzrTd # W7u1c63IK89HPHnTc37lnGFQUGPXYKXIooN6UhIbHRDTUFVO/sH2LysKLRyFWEs8 # qdOsszmx2zL+WNKmjrBmQBvPzrV7IimT6rpmpCYxEnoY/bFvXsmK5avv/Osj+efn # GkCc9hm7oLxy494MFy3u5S1XqkB0jweBCJo750sGG3N8QapKAicVYobSXBdeLxsm # H82yzsczRNPRAdyAGbFIe5vVpl43OSwclH9gRpREbdE63Bb8Uvyn+8FqECSb1f7N # uLXsMwue6nHTf7Lc/u48srSd6yRnY70CAwEAAaOCAdQwggHQMB8GA1UdIwQYMBaA # FMn8EO9QyMtrf70IRO86YpPtW16aMB0GA1UdDgQWBBREAaQBaa2AQTUPKUUkMbf9 # S5f5sDA+BgNVHSAENzA1MDMGBmeBDAEEATApMCcGCCsGAQUFBwIBFhtodHRwOi8v # d3d3LmRpZ2ljZXJ0LmNvbS9DUFMwDgYDVR0PAQH/BAQDAgeAMBMGA1UdJQQMMAoG # CCsGAQUFBwMDMIGXBgNVHR8EgY8wgYwwRKBCoECGPmh0dHA6Ly9jcmwzLmRpZ2lj # ZXJ0LmNvbS9Hb0dldFNTTEc0Q1NSU0E0MDk2U0hBMjU2MjAyMkNBLTEuY3JsMESg # QqBAhj5odHRwOi8vY3JsNC5kaWdpY2VydC5jb20vR29HZXRTU0xHNENTUlNBNDA5 # NlNIQTI1NjIwMjJDQS0xLmNybDCBgwYIKwYBBQUHAQEEdzB1MCQGCCsGAQUFBzAB # hhhodHRwOi8vb2NzcC5kaWdpY2VydC5jb20wTQYIKwYBBQUHMAKGQWh0dHA6Ly9j # YWNlcnRzLmRpZ2ljZXJ0LmNvbS9Hb0dldFNTTEc0Q1NSU0E0MDk2U0hBMjU2MjAy # MkNBLTEuY3J0MAkGA1UdEwQCMAAwDQYJKoZIhvcNAQELBQADggIBABqpRiImY/Bk # WSYmqNEZsmjcqPNRBEp9bYFMylajgTFR7dOLqF9sCStkO+cs/X64RKHkZtlaCrQa # ecZp6j/Dpq1fnkp2NfwuAaX2Osp/h6tMKnjaun3gvTdmI/j2iyJv6YJRxZ7daee7 # q9bkPzCTINwNc7AqWHbZ3Whlg+MmhLXaFHpoasR5JO9Vh+A8z8Y593G1bc7/Wjp2 # JWBNrCLjSUuz83YcDtf7yaURHuoJ96NDrHpbggaYU1s75sMhfBwAMTuYN2HmQe6/ # ShmDwGPtNzja0OtUdL0siHUp3Gouuqiux+ii7sjK0BDqvW3cbIQhCY41HkrJt4YF # e+KAUzZXeger2mTb9StmWLTLuqTKvUnCpzsVlqEO1I6NwsXgV2u46/0EYqk42vBT # e1vwXXj2Eawp5g4sSHQqbcxTAr/H5wZDIMp32tSyDMqV7zXhT6UWvxy5xua9Zkvf # j7bn7CzUWgX/+GMyP8KlgXEDG5rCY1uSxleFBvn0ACZjWRp+kWl17WbdrIL22Kkl # 2s1px/g9dfRbhHwNVAX1Mx2S7uCreeRs5qAA1cEjct2ulpNIbuPAEDDKenUHDTfN # k0osUL9uaOjSx6HiVkcwPHgFzyMyu+SCVOUTpBhwBXIH+/r77s6XVnQWmjUHcZUY # Y6KuwZiQ+E7joeAaZ0JGyW+LWx8WPfg7MYIGSjCCBkYCAQEwbjBaMQswCQYDVQQG # EwJMVjEZMBcGA1UEChMQRW5WZXJzIEdyb3VwIFNJQTEwMC4GA1UEAxMnR29HZXRT # U0wgRzQgQ1MgUlNBNDA5NiBTSEEyNTYgMjAyMiBDQS0xAhAGBSLrl94yV3C8/AHm # MmZmMA0GCWCGSAFlAwQCAQUAoIGEMBgGCisGAQQBgjcCAQwxCjAIoAKAAKECgAAw # GQYJKoZIhvcNAQkDMQwGCisGAQQBgjcCAQQwHAYKKwYBBAGCNwIBCzEOMAwGCisG # AQQBgjcCARUwLwYJKoZIhvcNAQkEMSIEIJWvEBJRI/ox/bNd9mdTtedbuAzs612n # CQM7ETab6WqEMA0GCSqGSIb3DQEBAQUABIICAKA27SVGKakXuIZzcpr5vuaYs4pq # s7BRYrJvaYkmxQS1qAAt9ThaYFaG2pFYGGd1AV4lSP5r5zse2nKxLCaBiGgKdtle # Lg6kQygHO2/kKi7/IkqIPmv+/oMmzdMt3dHsbrMKgrXtRIkFD49qiBpBEBgVLmDa # /jZW/4COi8MqEXkD4dAcNrEFlYAdm+ewEjNBBsJb4TfO+ULQJBUaikyU1tLDo79L # WAs/aKXcDej74RsyLaOIo7j8G1wjmyt0+CSmuROUPLBW60NIvs1CM0PfeX8TtgmT # 355YIynpXuAAzrZMfnYFz4GoJbc+MKiHQ1AUY+Nh80dM3TKTKLvrGnhiKo47vXzV # x1RGmPvYXkLRKECI6rvWLfQftz/gi3EbyibXsf0VHzfthkj4+wYKqX67CCSw8Oxt # H7+hf0O3jcq8lTnB0PzbzmvPLZWKjICUViHTvjxbB6hJYnbKBgKa2f3RcT9OuCOd # EBF/UjR3mxCQ/Pc5s4z8g1QemhN9vIBBzT9fkt6xIYKd95zxieZ8WGZe/viSP+ba # +QXYaKrQ7CMk9o00Fr1WFINQIMNA/4//sQVGxLetCjog2wbBwx+1eT3WAfct+9l/ # md4XE6xt56cWLxVliRpMeWolx2mQ5WWdrFPv2mji4Xs2smiYaiv2UKrkZy1LWipr # jlQ9yRXiGvAGjeWooYIDJjCCAyIGCSqGSIb3DQEJBjGCAxMwggMPAgEBMH0waTEL # MAkGA1UEBhMCVVMxFzAVBgNVBAoTDkRpZ2lDZXJ0LCBJbmMuMUEwPwYDVQQDEzhE # aWdpQ2VydCBUcnVzdGVkIEc0IFRpbWVTdGFtcGluZyBSU0E0MDk2IFNIQTI1NiAy # MDI1IENBMQIQCoDvGEuN8QWC0cR2p5V0aDANBglghkgBZQMEAgEFAKBpMBgGCSqG # SIb3DQEJAzELBgkqhkiG9w0BBwEwHAYJKoZIhvcNAQkFMQ8XDTI2MDUwNDE5NDMy # MFowLwYJKoZIhvcNAQkEMSIEIBzIF55mDN3K288B2JT+GKIh2K3LqsTvintz7P1r # u/LeMA0GCSqGSIb3DQEBAQUABIICAH6NQhBh6aGFlH20G5G+uYPVXHF6V2syOSPk # dWfaPwMubsm7zZmzNbpXbtXUs1iM61Z18Jv31T6sguUBBZGI1cYoQ5amWrmI0sOd # f1+Fp332RwM8eMhyEsjJP5X/sSl6z+q/gH8hlou59W9DxRthtqHgyPhB5B3+XO2l # KftvfOnKLiJ1U5C/zjcraV9jj+Bb1i8y19eORjh43Ea1EKrzLLZ8Rj4Iy2ttbXfS # g+c8Tcos5qf9pS1aHyFMjhM73fUwJ1EY8h31QsRzRxZVy+eCjPmg+dxSveFp/uu/ # JI/BQ1K2dm3fo8XMs1q9OtCQtT9Arn4sLfOlW2vKdcry701yGX+/UNBzwpZMfpYF # KNOSY628Au1YOtuTwz+mrks8PACU3+BWoXDEKlRyAbJ7zBTU/jQLH6WcA5gbs2D9 # SGkqr/WREhSwn3SeKCSOzavesW5iv8o1N+rq/8YBULYkGjoSYmdv7QvWOBEFF2HM # xz1Mq4+0L3pAYIU3rXrkTn6WHPi1WDokeTf50J7z2/4TmNIp0rmjIoIJGXba/owp # 0KroK5s5XYpKsXm/De2E9c1wVHddKvfn6b/hbYbGLM3gWJOQkqKIwkbR94VQ+SVS # CYrjDFKxBTm5HZsmKqBs1/hm+69io0mD2Mm+Aa/fAcEDh9tmpG/8ueqmgYiaVJ+B # VkO395RN # SIG # End signature block |