AzStackHci.EnvironmentChecker.PortableUtilities.psm1
<#
Small portable lightweight/standalone functions that are required to be called as signed local modules for the purpose of satisfying the Constraint Language Mode. #> function Get-SslCertificateChain { <# .SYNOPSIS Retrieve remote ssl certificate & chain from https endpoint for Desktop and Core .NOTES Credit: https://github.com/markekraus #> [CmdletBinding()] param ( [system.uri] $url, [Parameter()] [string] $Proxy, [Parameter()] [pscredential] $ProxyCredential ) try { $cs = @' using System; using System.Collections.Generic; using System.Net.Http; using System.Net.Security; using System.Security.Cryptography.X509Certificates; namespace CertificateCapture { public class Utility { public static Func<HttpRequestMessage,X509Certificate2,X509Chain,SslPolicyErrors,Boolean> ValidationCallback = (message, cert, chain, errors) => { CapturedCertificates.Clear(); var newCert = new X509Certificate2(cert); var newChain = new X509Chain(); newChain.Build(newCert); CapturedCertificates.Add(new CapturedCertificate(){ Certificate = newCert, CertificateChain = newChain, PolicyErrors = errors, URI = message.RequestUri }); return true; }; public static List<CapturedCertificate> CapturedCertificates = new List<CapturedCertificate>(); } public class CapturedCertificate { public X509Certificate2 Certificate { get; set; } public X509Chain CertificateChain { get; set; } public SslPolicyErrors PolicyErrors { get; set; } public Uri URI { get; set; } } } '@ try { if (-not ('CertificateCapture.Utility' -as [type])) { if ($PSEdition -ne 'Core') { Add-Type -AssemblyName System.Net.Http Add-Type $cs -ReferencedAssemblies System.Net.Http } else { Add-Type $cs } } } catch { if ($_.Exception.Message -notmatch 'Definition of new types is not supported in this language mode') { throw "Language mode does not allow this test Error: $_" } } $Certs = [CertificateCapture.Utility]::CapturedCertificates $Handler = [System.Net.Http.HttpClientHandler]::new() if ($Proxy) { $Handler.Proxy = New-Object System.Net.WebProxy($proxy) if ($proxyCredential) { $Handler.DefaultProxyCredentials = $ProxyCredential } } $Handler.ServerCertificateCustomValidationCallback = [CertificateCapture.Utility]::ValidationCallback $Client = [System.Net.Http.HttpClient]::new($Handler) $null = $Client.GetAsync($url).Result return $Certs.CertificateChain } catch { throw $_ } } function Test-Elevation { ([Security.Principal.WindowsPrincipal][Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole] 'Administrator') } function Copy-RemoteItem { <# .SYNOPSIS Copies a file or folder from a local source to a remote machine. .DESCRIPTION This robust function supports copying either a single file or an entire folder to a remote system. It checks SMB connectivity, maps a PSDrive to the remote UNC share, and uses robocopy to perform the copy. If DestinationPath is not specified, the remote system’s TEMP folder is used. Robocopy’s output is logged to a file under $env:LocalRootFolderPath\MasLogs. Optionally, if a CmdletName is provided (and the copy is a file), the module is imported on the remote system and the existence of the specified cmdlet is verified. .PARAMETER SourcePath Full local path of the file or folder to copy. .PARAMETER DestinationPath (Optional) Destination path on the remote machine (for example, "C:\Temp" or "C:\Temp\MyFolder"). If not provided, defaults to the remote system’s TEMP folder. .PARAMETER PsSession (Optional) An array of active PSSessions representing remote machines. .PARAMETER TargetNodeName (Optional) The remote machine name (if PsSession is not provided). .PARAMETER Credential (Optional) Credential to use when accessing the remote machine. .PARAMETER ExcludeDirs (Optional) Array of directory names to exclude (used only for folder copies). .PARAMETER ExcludeFiles (Optional) Array of file names to exclude (used only for folder copies). .PARAMETER SkipFirewallCheck (Optional) If specified, the function will skip checking/enabling the SMB firewall rule. .PARAMETER CmdletName (Optional) If provided (and the copy is a file), after copying the file the function imports it as a module on the remote machine and verifies that the specified cmdlet exists. #> [CmdletBinding()] param( [Parameter(Mandatory = $true)] [string]$SourcePath, [Parameter(Mandatory = $false)] [string]$DestinationPath, [Parameter(Mandatory = $false)] [System.Management.Automation.Runspaces.PSSession[]]$PsSession, [Parameter(Mandatory = $false)] [string]$TargetNodeName, [Parameter(Mandatory = $false)] [PSCredential]$Credential, [Parameter(Mandatory = $false)] [string[]]$ExcludeDirs, [Parameter(Mandatory = $false)] [string[]]$ExcludeFiles, [Parameter(Mandatory = $false)] [switch]$SkipFirewallCheck, [Parameter(Mandatory = $false)] [string]$CmdletName ) try { # Ensure the log directory exists. $logDir = "$($env:LocalRootFolderPath)\MasLogs" if (-not (Test-Path $logDir)) { New-Item -ItemType Directory -Path $logDir | Out-Null } # Verify the source exists. if (-not (Test-Path -Path $SourcePath)) { throw "Source path '$SourcePath' does not exist." } $sourceIsDirectory = Test-Path -Path $SourcePath -PathType Container # Build a list of targets. $targets = @() if ($PsSession) { foreach ($session in $PsSession) { $targets += [PSCustomObject]@{ ComputerName = $session.ComputerName Credential = $session.Runspace.ConnectionInfo.Credential Session = $session IsLocal = $false } } } elseif ($TargetNodeName) { # Determine if the target is local. $targetIsLocal = $false if ($env:ComputerName -eq $TargetNodeName) { $targetIsLocal = $true } else { $dnsInfo = (Resolve-DnsName -Name $TargetNodeName -ErrorAction SilentlyContinue | Select-Object -First 1) if ($dnsInfo.NameHost) { # Case when IP is resolved $thisComputerName = ($dnsInfo.NameHost).Split('.')[0] if ($env:ComputerName -eq $thisComputerName) { $targetIsLocal = $true } } elseif ($dnsInfo.Name) { # Case when hostname is resolved $thisComputerName = ($dnsInfo.Name).Split('.')[0] if ($env:ComputerName -eq $thisComputerName) { $targetIsLocal = $true } } else { # No DNS match so try IP address instead [array]$myIP = (Get-NetIPAddress).IPAddress if ($TargetNodeName -in $myIP) { $targetIsLocal = $true } } } $targets += [PSCustomObject]@{ ComputerName = $TargetNodeName Credential = $Credential Session = $null IsLocal = $targetIsLocal } } else { throw "Either PsSession or TargetNodeName must be provided." } foreach ($target in $targets) { $remoteComputer = $target.ComputerName # Determine the destination folder on the remote machine. # If no DestinationPath is provided, get the remote TEMP folder. $destPathForTarget = $DestinationPath if (-not $destPathForTarget) { if ($target.Session) { $destPathForTarget = Invoke-Command -Session $target.Session -ScriptBlock { return $env:TEMP } } else { $destPathForTarget = Invoke-Command -ComputerName $remoteComputer -Credential $target.Credential -ScriptBlock { return $env:TEMP } } } # Build log file name based on the destination folder’s leaf and remote computer. $destLeaf = Split-Path -Path $destPathForTarget -Leaf $timestamp = Get-Date -Format "yyyyMMdd-HHmmss" $logPath = "$logDir\AzStackHciEnvironment-envChecker-$destLeaf-$remoteComputer-Copy-$timestamp.log" Log-Info -Message "Initiating copy of '$SourcePath' to '$($remoteComputer):$($destPathForTarget)'" -Type Info # Check SMB connectivity (unless skipped) and enable the SMB firewall rule if needed. if (-not $SkipFirewallCheck) { $firewallRulesChanged = @() if (-not (Test-NetConnection -ComputerName $remoteComputer -Port 445 -InformationLevel Quiet)) { Log-Info -Message "Cannot reach $remoteComputer on port 445. Enabling SMB firewall rule." -Type Info if ($target.Session) { $firewallRulesChanged += Enable-SmbAccess -PsSession $target.Session } else { $firewallRulesChanged += Invoke-Command -ComputerName $remoteComputer -Credential $target.Credential -ScriptBlock { param($computer) # TODO : Would this function be available in the remote session? Enable-SmbAccess -ComputerName $computer } -ArgumentList $remoteComputer } if ($firewallRulesChanged.Count -gt 0) { foreach ($node in $firewallRulesChanged.Keys) { Log-Info -Message "SMB firewall rules enabled on '$($node)': $($firewallRulesChanged.$node -join ',')" -Type Info } } # Retry the SMB connection check after enabling the firewall rule. if (-not (Test-NetConnection -ComputerName $remoteComputer -Port 445 -InformationLevel Quiet)) { Log-Info "Failed to reach $($remoteComputer) on port 445 after enabling SMB-In firewall rules." Log-Info "Some other network policy, or a custom local firewall rule is blocking SMB access to '$($remoteComputer)'." throw "Failed to reach $($remoteComputer) on port 445 after enabling SMB-In firewall rules." } } } # Determine the UNC path to map. # If the destination path is like "C:\Temp" (or the remote TEMP folder), # then build the UNC path as "\\RemoteComputer\C$\Temp". if ($destPathForTarget -match '^(\w):\\(.*)$') { $driveLetter = $Matches[1] $folderPath = $Matches[2] $remoteShare = "\\$remoteComputer\$($driveLetter + '$')" if ($folderPath -ne "") { $remoteUNC = Join-Path -Path $remoteShare -ChildPath $folderPath } else { $remoteUNC = $remoteShare } } else { $remoteUNC = $destPathForTarget } Log-Info -Message "Mapping PSDrive 'RemoteCopy' to '$remoteUNC' on '$remoteComputer'" -Type Info # Remove any existing PSDrive mapping. if (Get-PSDrive -Name RemoteCopy -ErrorAction SilentlyContinue) { Get-PSDrive -Name RemoteCopy -ErrorAction SilentlyContinue | Remove-PSDrive -Force } # Retry mapping the PSDrive. $maxRetry = 4 $attempt = 0 $driveMapped = $false while (-not $driveMapped -and $attempt -lt $maxRetry) { $attempt++ Log-Info -Message "Attempt $($attempt) to map PSDrive to '$remoteUNC'" -Type Info try { New-PSDrive -Name RemoteCopy -PSProvider FileSystem -Root $remoteUNC -Credential $target.Credential -ErrorAction Stop | Out-Null if (Get-PSDrive -Name RemoteCopy -ErrorAction SilentlyContinue) { $driveMapped = $true Log-Info -Message "PSDrive mapped successfully to '$remoteUNC'" -Type Info } } catch { Log-Info -Message "Mapping PSDrive failed on attempt $($attempt): $($_.Exception.Message)" -Type Info if ($attempt -ge $maxRetry) { throw "Failed to map PSDrive to '$remoteUNC' for file '$SourcePath' on node '$remoteComputer' after $attempt attempts." } Start-Sleep -Seconds 15 } } # Build the final destination path. # If the user provided a DestinationPath, do drive-letter replacement; # otherwise, simply use the mapped PSDrive’s root. if ($DestinationPath) { if ($destPathForTarget -match '^\w:') { $finalDestPath = $destPathForTarget -replace '^\w:', (Get-PSDrive -Name RemoteCopy).Root } else { $finalDestPath = (Get-PSDrive -Name RemoteCopy).Root } } else { $finalDestPath = (Get-PSDrive -Name RemoteCopy).Root } Log-Info -Message "Final destination path set to '$finalDestPath'" -Type Info # Build the robocopy command. if ($sourceIsDirectory) { $copyCmd = "robocopy.exe `"$SourcePath`" `"$finalDestPath`" *.* /MIR /NP /R:2 /W:10 /LOG:`"$logPath`"" } else { $sourceDir = Split-Path -Path $SourcePath $fileName = Split-Path -Path $SourcePath -Leaf $copyCmd = "robocopy.exe `"$sourceDir`" `"$finalDestPath`" `"$fileName`" /COPYALL /NP /R:2 /W:10 /LOG:`"$logPath`"" } if ($ExcludeFiles) { $copyCmd += " /XF " + ($ExcludeFiles -join ' ') } if ($ExcludeDirs) { $copyCmd += " /XD " + ($ExcludeDirs -join ' ') } Log-Info -Message "Calling: $copyCmd" -Type Info try { # Execute robocopy. $output = Invoke-Command -ScriptBlock { param($cmd) cmd.exe /c $cmd } -ArgumentList $copyCmd if ($LASTEXITCODE -ge 8) { Log-Info -Message ("Robocopy failed with exit code {0}" -f $LASTEXITCODE) -ConsoleOut -Type Error Log-Info -Message ($output | Out-String).Trim() -ConsoleOut -Type Info throw "Robocopy failed with exit code $LASTEXITCODE" } else { Log-Info -Message "Robocopy completed successfully." -Type Info } } catch { Log-Info -Message ("Copy operation failed: " + $_.Exception.Message) -Type Error throw "Copy operation failed for file '$SourcePath' to destination '$destPathForTarget' on node '$remoteComputer': $($_.Exception.Message)" } finally { # Clean up: remove the mapped PSDrive. if (Get-PSDrive -Name RemoteCopy -ErrorAction SilentlyContinue) { Get-PSDrive -Name RemoteCopy -ErrorAction SilentlyContinue | Remove-PSDrive -Force } # Revert the firewall rule if it was enabled. if ($firewallRulesChanged.Count -gt 0) { Log-Info -Message "Reverting SMB firewall rule on '$remoteComputer'" -Type Info if ($target.Session) { Disable-SmbAccess -PsSession $target.Session | Out-Null } else { Invoke-Command -ComputerName $remoteComputer -Credential $target.Credential -ScriptBlock { param($computer) # TODO : Would this function be available in the remote session? Disable-SmbAccess -ComputerName $computer } -ArgumentList $remoteComputer | Out-Null } } } Log-Info -Message "Successfully copied '$SourcePath' to '$($remoteComputer):$($destPathForTarget)'" -Type Info # If a CmdletName is provided (and this is a file copy), import the module on the remote system. if ($CmdletName -and -not $sourceIsDirectory) { $destinationFileName = Split-Path -Path $SourcePath -Leaf # Use the local path (as returned by the remote system) for the module import. $modulePath = Join-Path $destPathForTarget $destinationFileName Log-Info -Message "Importing module from '$modulePath' on '$remoteComputer' to verify cmdlet '$CmdletName'" -Type Info if ($target.Session) { Invoke-Command -Session $target.Session -ScriptBlock { param($modulePath, $CmdletName) Import-Module $modulePath -Force if (-not (Get-Command -Name $CmdletName -ErrorAction SilentlyContinue)) { throw "Failed to import module on $($env:COMPUTERNAME) for cmdlet $CmdletName" } } -ArgumentList $modulePath, $CmdletName } else { Invoke-Command -ComputerName $remoteComputer -Credential $target.Credential -ScriptBlock { param($modulePath, $CmdletName) Import-Module $modulePath -Force if (-not (Get-Command -Name $CmdletName -ErrorAction SilentlyContinue)) { throw "Failed to import module on $($env:COMPUTERNAME) for cmdlet $CmdletName" } } -ArgumentList $modulePath, $CmdletName } Log-Info -Message "Module imported and cmdlet '$CmdletName' verified on '$remoteComputer'" -Type Info } } } catch { throw "Copy-RemoteItem failed for file '$SourcePath' to destination '$destPathForTarget' on node '$remoteComputer'. Error: $($_.Exception.Message)" } } function Enable-SmbAccess { param ( [Parameter(Mandatory = $true)] [System.Management.Automation.Runspaces.PSSession[]] $PsSession, [Parameter(Mandatory = $false)] [string[]]$Rules = @('FPS-SMB-In-TCP','FailoverCluster-SMB-TCP-In') ) try { $rulesEnabled = @() foreach ($session in $PsSession) { Log-Info "Enabling SMB access through firewall on $($session.ComputerName)" [string[]]$enabled = Invoke-Command -Session $session -ScriptBlock { $fwRuleChanged = @() foreach ($name in $using:Rules) { if ((Get-NetFirewallRule -Name $name).Enabled -eq 'False') { Set-NetFirewallRule -Name $name -Enabled True | Out-Null $fwRuleChanged += $name } } $fwRuleChanged } if ($enabled.Count -gt 0) { $rulesEnabled += @{$session.ComputerName = $enabled} foreach ($name in $enabled) { Log-Info "SMB access enabled on $($session.ComputerName) for rule: $name" } } else { Log-Info "No changes made to SMB access on $($session.ComputerName)" } } return $rulesEnabled } catch { Log-Info "Failed to enable SMB access on '$($session.ComputerName)'. Error: $($_.Exception)" } } function Disable-SmbAccess { param ( [Parameter(Mandatory = $true)] [System.Management.Automation.Runspaces.PSSession[]] $PsSession, [Parameter(Mandatory = $false)] [string[]]$Rules = @('FPS-SMB-In-TCP','FailoverCluster-SMB-TCP-In') ) try { foreach ($session in $PsSession) { foreach ($name in $Rules) { Log-Info "Disabling SMB access through firewall on $($session.ComputerName) for rule $name" Invoke-Command -Session $session -ScriptBlock { param($RuleName) if ((Get-NetFirewallRule -Name $RuleName).Enabled -eq 'True') { Set-NetFirewallRule -Name $RuleName -Enabled False | Out-Null } } -ArgumentList $name } } } catch { Log-Info "Failed to disable SMB access on '$($session.ComputerName)'. Error: $($_.Exception)" } } function Remove-UtilityModule { <# .SYNOPSIS Remove EnvironmentChecker module .DESCRIPTION Removes EnvironmentChecker module #> [CmdletBinding()] param ( [Parameter()] [System.Management.Automation.Runspaces.PSSession[]] $PsSession ) try { foreach ($Session in $PsSession) { Log-Info "Removing module from $($Session.ComputerName)" Invoke-Command -Session $Session -ScriptBlock { Remove-Item -Path "$env:TEMP\AzStackHci.EnvironmentChecker.PortableUtilities.psm1" -Force -ErrorAction SilentlyContinue } } } catch { Log-Info "Failed to remove EnvironmentChecker module. Error: $($_.exception)" } } Export-ModuleMember -Function Copy-RemoteItem Export-ModuleMember -Function Remove-UtilityModule Export-ModuleMember -Function Test-Elevation Export-ModuleMember -Function Get-SslCertificateChain Export-ModuleMember -Function Enable-SmbAccess Export-ModuleMember -Function Disable-SmbAccess # SIG # Begin signature block # MIIoRgYJKoZIhvcNAQcCoIIoNzCCKDMCAQExDzANBglghkgBZQMEAgEFADB5Bgor # BgEEAYI3AgEEoGswaTA0BgorBgEEAYI3AgEeMCYCAwEAAAQQH8w7YFlLCE63JNLG # KX7zUQIBAAIBAAIBAAIBAAIBADAxMA0GCWCGSAFlAwQCAQUABCBp5MpomCjVHdCW # NdakDjzBnVNYeLW7CYcgNelMtk0vEKCCDXYwggX0MIID3KADAgECAhMzAAAEBGx0 # Bv9XKydyAAAAAAQEMA0GCSqGSIb3DQEBCwUAMH4xCzAJBgNVBAYTAlVTMRMwEQYD # VQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNy # b3NvZnQgQ29ycG9yYXRpb24xKDAmBgNVBAMTH01pY3Jvc29mdCBDb2RlIFNpZ25p # bmcgUENBIDIwMTEwHhcNMjQwOTEyMjAxMTE0WhcNMjUwOTExMjAxMTE0WjB0MQsw # CQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9u # ZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMR4wHAYDVQQDExVNaWNy # b3NvZnQgQ29ycG9yYXRpb24wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIB # AQC0KDfaY50MDqsEGdlIzDHBd6CqIMRQWW9Af1LHDDTuFjfDsvna0nEuDSYJmNyz # NB10jpbg0lhvkT1AzfX2TLITSXwS8D+mBzGCWMM/wTpciWBV/pbjSazbzoKvRrNo # DV/u9omOM2Eawyo5JJJdNkM2d8qzkQ0bRuRd4HarmGunSouyb9NY7egWN5E5lUc3 # a2AROzAdHdYpObpCOdeAY2P5XqtJkk79aROpzw16wCjdSn8qMzCBzR7rvH2WVkvF # HLIxZQET1yhPb6lRmpgBQNnzidHV2Ocxjc8wNiIDzgbDkmlx54QPfw7RwQi8p1fy # 4byhBrTjv568x8NGv3gwb0RbAgMBAAGjggFzMIIBbzAfBgNVHSUEGDAWBgorBgEE # AYI3TAgBBggrBgEFBQcDAzAdBgNVHQ4EFgQU8huhNbETDU+ZWllL4DNMPCijEU4w # RQYDVR0RBD4wPKQ6MDgxHjAcBgNVBAsTFU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjEW # MBQGA1UEBRMNMjMwMDEyKzUwMjkyMzAfBgNVHSMEGDAWgBRIbmTlUAXTgqoXNzci # tW2oynUClTBUBgNVHR8ETTBLMEmgR6BFhkNodHRwOi8vd3d3Lm1pY3Jvc29mdC5j # b20vcGtpb3BzL2NybC9NaWNDb2RTaWdQQ0EyMDExXzIwMTEtMDctMDguY3JsMGEG # CCsGAQUFBwEBBFUwUzBRBggrBgEFBQcwAoZFaHR0cDovL3d3dy5taWNyb3NvZnQu # Y29tL3BraW9wcy9jZXJ0cy9NaWNDb2RTaWdQQ0EyMDExXzIwMTEtMDctMDguY3J0 # MAwGA1UdEwEB/wQCMAAwDQYJKoZIhvcNAQELBQADggIBAIjmD9IpQVvfB1QehvpC # Ge7QeTQkKQ7j3bmDMjwSqFL4ri6ae9IFTdpywn5smmtSIyKYDn3/nHtaEn0X1NBj # L5oP0BjAy1sqxD+uy35B+V8wv5GrxhMDJP8l2QjLtH/UglSTIhLqyt8bUAqVfyfp # h4COMRvwwjTvChtCnUXXACuCXYHWalOoc0OU2oGN+mPJIJJxaNQc1sjBsMbGIWv3 # cmgSHkCEmrMv7yaidpePt6V+yPMik+eXw3IfZ5eNOiNgL1rZzgSJfTnvUqiaEQ0X # dG1HbkDv9fv6CTq6m4Ty3IzLiwGSXYxRIXTxT4TYs5VxHy2uFjFXWVSL0J2ARTYL # E4Oyl1wXDF1PX4bxg1yDMfKPHcE1Ijic5lx1KdK1SkaEJdto4hd++05J9Bf9TAmi # u6EK6C9Oe5vRadroJCK26uCUI4zIjL/qG7mswW+qT0CW0gnR9JHkXCWNbo8ccMk1 # sJatmRoSAifbgzaYbUz8+lv+IXy5GFuAmLnNbGjacB3IMGpa+lbFgih57/fIhamq # 5VhxgaEmn/UjWyr+cPiAFWuTVIpfsOjbEAww75wURNM1Imp9NJKye1O24EspEHmb # DmqCUcq7NqkOKIG4PVm3hDDED/WQpzJDkvu4FrIbvyTGVU01vKsg4UfcdiZ0fQ+/ # V0hf8yrtq9CkB8iIuk5bBxuPMIIHejCCBWKgAwIBAgIKYQ6Q0gAAAAAAAzANBgkq # hkiG9w0BAQsFADCBiDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCldhc2hpbmd0b24x # EDAOBgNVBAcTB1JlZG1vbmQxHjAcBgNVBAoTFU1pY3Jvc29mdCBDb3Jwb3JhdGlv # bjEyMDAGA1UEAxMpTWljcm9zb2Z0IFJvb3QgQ2VydGlmaWNhdGUgQXV0aG9yaXR5 # IDIwMTEwHhcNMTEwNzA4MjA1OTA5WhcNMjYwNzA4MjEwOTA5WjB+MQswCQYDVQQG # EwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9uZDEeMBwG # A1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMSgwJgYDVQQDEx9NaWNyb3NvZnQg # Q29kZSBTaWduaW5nIFBDQSAyMDExMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIIC # CgKCAgEAq/D6chAcLq3YbqqCEE00uvK2WCGfQhsqa+laUKq4BjgaBEm6f8MMHt03 # a8YS2AvwOMKZBrDIOdUBFDFC04kNeWSHfpRgJGyvnkmc6Whe0t+bU7IKLMOv2akr # rnoJr9eWWcpgGgXpZnboMlImEi/nqwhQz7NEt13YxC4Ddato88tt8zpcoRb0Rrrg # OGSsbmQ1eKagYw8t00CT+OPeBw3VXHmlSSnnDb6gE3e+lD3v++MrWhAfTVYoonpy # 4BI6t0le2O3tQ5GD2Xuye4Yb2T6xjF3oiU+EGvKhL1nkkDstrjNYxbc+/jLTswM9 # sbKvkjh+0p2ALPVOVpEhNSXDOW5kf1O6nA+tGSOEy/S6A4aN91/w0FK/jJSHvMAh # dCVfGCi2zCcoOCWYOUo2z3yxkq4cI6epZuxhH2rhKEmdX4jiJV3TIUs+UsS1Vz8k # A/DRelsv1SPjcF0PUUZ3s/gA4bysAoJf28AVs70b1FVL5zmhD+kjSbwYuER8ReTB # w3J64HLnJN+/RpnF78IcV9uDjexNSTCnq47f7Fufr/zdsGbiwZeBe+3W7UvnSSmn # Eyimp31ngOaKYnhfsi+E11ecXL93KCjx7W3DKI8sj0A3T8HhhUSJxAlMxdSlQy90 # lfdu+HggWCwTXWCVmj5PM4TasIgX3p5O9JawvEagbJjS4NaIjAsCAwEAAaOCAe0w # ggHpMBAGCSsGAQQBgjcVAQQDAgEAMB0GA1UdDgQWBBRIbmTlUAXTgqoXNzcitW2o # ynUClTAZBgkrBgEEAYI3FAIEDB4KAFMAdQBiAEMAQTALBgNVHQ8EBAMCAYYwDwYD # VR0TAQH/BAUwAwEB/zAfBgNVHSMEGDAWgBRyLToCMZBDuRQFTuHqp8cx0SOJNDBa # BgNVHR8EUzBRME+gTaBLhklodHRwOi8vY3JsLm1pY3Jvc29mdC5jb20vcGtpL2Ny # bC9wcm9kdWN0cy9NaWNSb29DZXJBdXQyMDExXzIwMTFfMDNfMjIuY3JsMF4GCCsG # AQUFBwEBBFIwUDBOBggrBgEFBQcwAoZCaHR0cDovL3d3dy5taWNyb3NvZnQuY29t # L3BraS9jZXJ0cy9NaWNSb29DZXJBdXQyMDExXzIwMTFfMDNfMjIuY3J0MIGfBgNV # HSAEgZcwgZQwgZEGCSsGAQQBgjcuAzCBgzA/BggrBgEFBQcCARYzaHR0cDovL3d3 # dy5taWNyb3NvZnQuY29tL3BraW9wcy9kb2NzL3ByaW1hcnljcHMuaHRtMEAGCCsG # AQUFBwICMDQeMiAdAEwAZQBnAGEAbABfAHAAbwBsAGkAYwB5AF8AcwB0AGEAdABl # AG0AZQBuAHQALiAdMA0GCSqGSIb3DQEBCwUAA4ICAQBn8oalmOBUeRou09h0ZyKb # C5YR4WOSmUKWfdJ5DJDBZV8uLD74w3LRbYP+vj/oCso7v0epo/Np22O/IjWll11l # hJB9i0ZQVdgMknzSGksc8zxCi1LQsP1r4z4HLimb5j0bpdS1HXeUOeLpZMlEPXh6 # I/MTfaaQdION9MsmAkYqwooQu6SpBQyb7Wj6aC6VoCo/KmtYSWMfCWluWpiW5IP0 # wI/zRive/DvQvTXvbiWu5a8n7dDd8w6vmSiXmE0OPQvyCInWH8MyGOLwxS3OW560 # STkKxgrCxq2u5bLZ2xWIUUVYODJxJxp/sfQn+N4sOiBpmLJZiWhub6e3dMNABQam # ASooPoI/E01mC8CzTfXhj38cbxV9Rad25UAqZaPDXVJihsMdYzaXht/a8/jyFqGa # J+HNpZfQ7l1jQeNbB5yHPgZ3BtEGsXUfFL5hYbXw3MYbBL7fQccOKO7eZS/sl/ah # XJbYANahRr1Z85elCUtIEJmAH9AAKcWxm6U/RXceNcbSoqKfenoi+kiVH6v7RyOA # 9Z74v2u3S5fi63V4GuzqN5l5GEv/1rMjaHXmr/r8i+sLgOppO6/8MO0ETI7f33Vt # Y5E90Z1WTk+/gFcioXgRMiF670EKsT/7qMykXcGhiJtXcVZOSEXAQsmbdlsKgEhr # /Xmfwb1tbWrJUnMTDXpQzTGCGiYwghoiAgEBMIGVMH4xCzAJBgNVBAYTAlVTMRMw # EQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVN # aWNyb3NvZnQgQ29ycG9yYXRpb24xKDAmBgNVBAMTH01pY3Jvc29mdCBDb2RlIFNp # Z25pbmcgUENBIDIwMTECEzMAAAQEbHQG/1crJ3IAAAAABAQwDQYJYIZIAWUDBAIB # BQCgga4wGQYJKoZIhvcNAQkDMQwGCisGAQQBgjcCAQQwHAYKKwYBBAGCNwIBCzEO # MAwGCisGAQQBgjcCARUwLwYJKoZIhvcNAQkEMSIEIH1c4kA2Z8+QkU0u+yIwj7Aj # Iy9AptdkaT9IPeoi3HGZMEIGCisGAQQBgjcCAQwxNDAyoBSAEgBNAGkAYwByAG8A # cwBvAGYAdKEagBhodHRwOi8vd3d3Lm1pY3Jvc29mdC5jb20wDQYJKoZIhvcNAQEB # BQAEggEAdBf6Ms6NqqjSsaKfrIXH3ZwA3GVe+jcfNXmfn2wyGKCnszc7pK/BoybU # gaVyK8lt69gFHCTlevbrGRSKk95NLpU5PX/mNuL8qQ0vMKn010/prlkVBGRizeJ4 # EvdQcDPag3bGlacRbEZExAHN5okX5rS77uhb1ycSFYkb69G9xwN7pUfA/v62kJyv # OWl0eriWIoeG9M2di6xkQOmqE1VQrfd2scW4lZGsTGHvWheHq2XEawgMW5CLW69P # GiYxQ39tn2O4eusOkV5DGToGakUYisjItYmeoY5ie13XMXiY24V1svJSd6WqzV6Y # c2YazXDU+Z/tsRyGDwjHygt5//KCfKGCF7AwghesBgorBgEEAYI3AwMBMYIXnDCC # F5gGCSqGSIb3DQEHAqCCF4kwgheFAgEDMQ8wDQYJYIZIAWUDBAIBBQAwggFaBgsq # hkiG9w0BCRABBKCCAUkEggFFMIIBQQIBAQYKKwYBBAGEWQoDATAxMA0GCWCGSAFl # AwQCAQUABCDnBmOB5d1sJ0jh/9kpCz9C6C3GTcIq6p4JBTDu1TgnOAIGaC4/lVwg # GBMyMDI1MDYxMDE1NDgzMS4zNjNaMASAAgH0oIHZpIHWMIHTMQswCQYDVQQGEwJV # UzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9uZDEeMBwGA1UE # ChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMS0wKwYDVQQLEyRNaWNyb3NvZnQgSXJl # bGFuZCBPcGVyYXRpb25zIExpbWl0ZWQxJzAlBgNVBAsTHm5TaGllbGQgVFNTIEVT # Tjo1NzFBLTA1RTAtRDk0NzElMCMGA1UEAxMcTWljcm9zb2Z0IFRpbWUtU3RhbXAg # U2VydmljZaCCEf4wggcoMIIFEKADAgECAhMzAAAB+8vLbDdn5TCVAAEAAAH7MA0G # CSqGSIb3DQEBCwUAMHwxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpXYXNoaW5ndG9u # MRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNyb3NvZnQgQ29ycG9yYXRp # b24xJjAkBgNVBAMTHU1pY3Jvc29mdCBUaW1lLVN0YW1wIFBDQSAyMDEwMB4XDTI0 # MDcyNTE4MzExM1oXDTI1MTAyMjE4MzExM1owgdMxCzAJBgNVBAYTAlVTMRMwEQYD # VQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNy # b3NvZnQgQ29ycG9yYXRpb24xLTArBgNVBAsTJE1pY3Jvc29mdCBJcmVsYW5kIE9w # ZXJhdGlvbnMgTGltaXRlZDEnMCUGA1UECxMeblNoaWVsZCBUU1MgRVNOOjU3MUEt # MDVFMC1EOTQ3MSUwIwYDVQQDExxNaWNyb3NvZnQgVGltZS1TdGFtcCBTZXJ2aWNl # MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAqMJWQeWAq4LwvSjYsjP0 # Uvhvm0j0aAOJiMLg0sLfxKoTXAdKD6oMuq5rF5oEiOxV+9ox0H95Q8fhoZq3x9lx # guZyTOK4l2xtcgtJCtjXRllM2bTpjOg35RUrBy0cAloBU9GJBs7LBNrcbH6rBiOv # qDQNicPRZwq16xyjMidU1J1AJuat9yLn7taifoD58blYEcBvkj5dH1la9zU846QD # eOoRO6NcqHLsDx8/zVKZxP30mW6Y7RMsqtB8cGCgGwVVurOnaNLXs31qTRTyVHX8 # ppOdoSihCXeqebgJCRzG8zG/e/k0oaBjFFGl+8uFELwCyh4wK9Z5+azTzfa2GD4p # 6ihtskXs3lnW05UKfDJhAADt6viOc0Rk/c8zOiqzh0lKpf/eWUY2o/hvcDPZNgLa # HvyfDqb8AWaKvO36iRZSXqhSw8SxJo0TCpsbCjmtx0LpHnqbb1UF7cq09kCcfWTD # PcN12pbYLqck0bIIfPKbc7HnrkNQks/mSbVZTnDyT3O8zF9q4DCfWesSr1akycDd # uGxCdKBvgtJh1YxDq1skTweYx5iAWXnB7KMyls3WQZbTubTCLLt8Xn8t+slcKm5D # kvobubmHSriuTA3wTyIy4FxamTKm0VDu9mWds8MtjUSJVwNVVlBXaQ3ZMcVjijyV # oUNVuBY9McwYcIQK62wQ20ECAwEAAaOCAUkwggFFMB0GA1UdDgQWBBRHVSGYUNQ3 # RwOl71zIAuUjIKg1KjAfBgNVHSMEGDAWgBSfpxVdAF5iXYP05dJlpxtTNRnpcjBf # BgNVHR8EWDBWMFSgUqBQhk5odHRwOi8vd3d3Lm1pY3Jvc29mdC5jb20vcGtpb3Bz # L2NybC9NaWNyb3NvZnQlMjBUaW1lLVN0YW1wJTIwUENBJTIwMjAxMCgxKS5jcmww # bAYIKwYBBQUHAQEEYDBeMFwGCCsGAQUFBzAChlBodHRwOi8vd3d3Lm1pY3Jvc29m # dC5jb20vcGtpb3BzL2NlcnRzL01pY3Jvc29mdCUyMFRpbWUtU3RhbXAlMjBQQ0El # MjAyMDEwKDEpLmNydDAMBgNVHRMBAf8EAjAAMBYGA1UdJQEB/wQMMAoGCCsGAQUF # BwMIMA4GA1UdDwEB/wQEAwIHgDANBgkqhkiG9w0BAQsFAAOCAgEAwzoIKOY2dnUj # fWuMiGoz/ovoc1e86VwWaZNFdgRmOoQuRe4nLdtZONtTHNk3Sj3nkyBszzxSbZEQ # 0DduyKHHI5P8V87jFttGnlR0wPP22FAebbvAbutkMMVQMFzhVBWiWD0VAnu9x0fj # ifLKDAVXLwoun5rCFqwbasXFc7H/0DPiC+DBn3tUxefvcxUCys4+DC3s8CYp7WWX # pZ8Wb/vdBhDliHmB7pWcmsB83uc4/P2GmAI3HMkOEu7fCaSYoQhouWOr07l/KM4T # ndylIirm8f2WwXQcFEzmUvISM6ludUwGlVNfTTJUq2bTDEd3tlDKtV9AUY3rrnFw # HTwJryLtT4IFhvgBfND3mL1eeSakKf7xTII4Jyt15SXhHd5oI/XGjSgykgJrWA57 # rGnAC7ru3/ZbFNCMK/Jj6X8X4L6mBOYa2NGKwH4A37YGDrecJ/qXXWUYvfLYqHGf # 8ThYl12Yg1rwSKpWLolA/B1eqBw4TRcvVY0IvNNi5sm+//HJ9Aw6NJuR/uDR7X7v # DXicpXMlRNgFMyADb8AFIvQPdHqcRpRorY+YUGlvzeJx/2gNYyezAokbrFhACsJ2 # BfyeLyCEo6AuwEHn511PKE8dK4JvlmLSoHj7VFR3NHDk3zRkx0ExkmF8aOdpvoKh # uwBCxoZ/JhbzSzrvZ74GVjKKIyt5FA0wggdxMIIFWaADAgECAhMzAAAAFcXna54C # m0mZAAAAAAAVMA0GCSqGSIb3DQEBCwUAMIGIMQswCQYDVQQGEwJVUzETMBEGA1UE # CBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9uZDEeMBwGA1UEChMVTWljcm9z # b2Z0IENvcnBvcmF0aW9uMTIwMAYDVQQDEylNaWNyb3NvZnQgUm9vdCBDZXJ0aWZp # Y2F0ZSBBdXRob3JpdHkgMjAxMDAeFw0yMTA5MzAxODIyMjVaFw0zMDA5MzAxODMy # MjVaMHwxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQH # EwdSZWRtb25kMR4wHAYDVQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xJjAkBgNV # BAMTHU1pY3Jvc29mdCBUaW1lLVN0YW1wIFBDQSAyMDEwMIICIjANBgkqhkiG9w0B # AQEFAAOCAg8AMIICCgKCAgEA5OGmTOe0ciELeaLL1yR5vQ7VgtP97pwHB9KpbE51 # yMo1V/YBf2xK4OK9uT4XYDP/XE/HZveVU3Fa4n5KWv64NmeFRiMMtY0Tz3cywBAY # 6GB9alKDRLemjkZrBxTzxXb1hlDcwUTIcVxRMTegCjhuje3XD9gmU3w5YQJ6xKr9 # cmmvHaus9ja+NSZk2pg7uhp7M62AW36MEBydUv626GIl3GoPz130/o5Tz9bshVZN # 7928jaTjkY+yOSxRnOlwaQ3KNi1wjjHINSi947SHJMPgyY9+tVSP3PoFVZhtaDua # Rr3tpK56KTesy+uDRedGbsoy1cCGMFxPLOJiss254o2I5JasAUq7vnGpF1tnYN74 # kpEeHT39IM9zfUGaRnXNxF803RKJ1v2lIH1+/NmeRd+2ci/bfV+AutuqfjbsNkz2 # K26oElHovwUDo9Fzpk03dJQcNIIP8BDyt0cY7afomXw/TNuvXsLz1dhzPUNOwTM5 # TI4CvEJoLhDqhFFG4tG9ahhaYQFzymeiXtcodgLiMxhy16cg8ML6EgrXY28MyTZk # i1ugpoMhXV8wdJGUlNi5UPkLiWHzNgY1GIRH29wb0f2y1BzFa/ZcUlFdEtsluq9Q # BXpsxREdcu+N+VLEhReTwDwV2xo3xwgVGD94q0W29R6HXtqPnhZyacaue7e3Pmri # Lq0CAwEAAaOCAd0wggHZMBIGCSsGAQQBgjcVAQQFAgMBAAEwIwYJKwYBBAGCNxUC # BBYEFCqnUv5kxJq+gpE8RjUpzxD/LwTuMB0GA1UdDgQWBBSfpxVdAF5iXYP05dJl # pxtTNRnpcjBcBgNVHSAEVTBTMFEGDCsGAQQBgjdMg30BATBBMD8GCCsGAQUFBwIB # FjNodHRwOi8vd3d3Lm1pY3Jvc29mdC5jb20vcGtpb3BzL0RvY3MvUmVwb3NpdG9y # eS5odG0wEwYDVR0lBAwwCgYIKwYBBQUHAwgwGQYJKwYBBAGCNxQCBAweCgBTAHUA # YgBDAEEwCwYDVR0PBAQDAgGGMA8GA1UdEwEB/wQFMAMBAf8wHwYDVR0jBBgwFoAU # 1fZWy4/oolxiaNE9lJBb186aGMQwVgYDVR0fBE8wTTBLoEmgR4ZFaHR0cDovL2Ny # bC5taWNyb3NvZnQuY29tL3BraS9jcmwvcHJvZHVjdHMvTWljUm9vQ2VyQXV0XzIw # MTAtMDYtMjMuY3JsMFoGCCsGAQUFBwEBBE4wTDBKBggrBgEFBQcwAoY+aHR0cDov # L3d3dy5taWNyb3NvZnQuY29tL3BraS9jZXJ0cy9NaWNSb29DZXJBdXRfMjAxMC0w # Ni0yMy5jcnQwDQYJKoZIhvcNAQELBQADggIBAJ1VffwqreEsH2cBMSRb4Z5yS/yp # b+pcFLY+TkdkeLEGk5c9MTO1OdfCcTY/2mRsfNB1OW27DzHkwo/7bNGhlBgi7ulm # ZzpTTd2YurYeeNg2LpypglYAA7AFvonoaeC6Ce5732pvvinLbtg/SHUB2RjebYIM # 9W0jVOR4U3UkV7ndn/OOPcbzaN9l9qRWqveVtihVJ9AkvUCgvxm2EhIRXT0n4ECW # OKz3+SmJw7wXsFSFQrP8DJ6LGYnn8AtqgcKBGUIZUnWKNsIdw2FzLixre24/LAl4 # FOmRsqlb30mjdAy87JGA0j3mSj5mO0+7hvoyGtmW9I/2kQH2zsZ0/fZMcm8Qq3Uw # xTSwethQ/gpY3UA8x1RtnWN0SCyxTkctwRQEcb9k+SS+c23Kjgm9swFXSVRk2XPX # fx5bRAGOWhmRaw2fpCjcZxkoJLo4S5pu+yFUa2pFEUep8beuyOiJXk+d0tBMdrVX # VAmxaQFEfnyhYWxz/gq77EFmPWn9y8FBSX5+k77L+DvktxW/tM4+pTFRhLy/AsGC # onsXHRWJjXD+57XQKBqJC4822rpM+Zv/Cuk0+CQ1ZyvgDbjmjJnW4SLq8CdCPSWU # 5nR0W2rRnj7tfqAxM328y+l7vzhwRNGQ8cirOoo6CGJ/2XBjU02N7oJtpQUQwXEG # ahC0HVUzWLOhcGbyoYIDWTCCAkECAQEwggEBoYHZpIHWMIHTMQswCQYDVQQGEwJV # UzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9uZDEeMBwGA1UE # ChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMS0wKwYDVQQLEyRNaWNyb3NvZnQgSXJl # bGFuZCBPcGVyYXRpb25zIExpbWl0ZWQxJzAlBgNVBAsTHm5TaGllbGQgVFNTIEVT # Tjo1NzFBLTA1RTAtRDk0NzElMCMGA1UEAxMcTWljcm9zb2Z0IFRpbWUtU3RhbXAg # U2VydmljZaIjCgEBMAcGBSsOAwIaAxUABHHn7NCGusZz2RfVbyuwYwPykBWggYMw # gYCkfjB8MQswCQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UE # BxMHUmVkbW9uZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMSYwJAYD # VQQDEx1NaWNyb3NvZnQgVGltZS1TdGFtcCBQQ0EgMjAxMDANBgkqhkiG9w0BAQsF # AAIFAOvycXswIhgPMjAyNTA2MTAwODU1MjNaGA8yMDI1MDYxMTA4NTUyM1owdzA9 # BgorBgEEAYRZCgQBMS8wLTAKAgUA6/JxewIBADAKAgEAAgIOAwIB/zAHAgEAAgIU # eTAKAgUA6/PC+wIBADA2BgorBgEEAYRZCgQCMSgwJjAMBgorBgEEAYRZCgMCoAow # CAIBAAIDB6EgoQowCAIBAAIDAYagMA0GCSqGSIb3DQEBCwUAA4IBAQAYtduBuopn # aAM1opo/1MJdGcryYsNf+hZSA2Jd/Akf1X8+uZv/fkDdd+PH3cS7iTSY550XgdjP # A8PuEc8rwkgQTJIglENfhEgleHGk7If9il/7KfS07k8ihaTSgWPRIc5c+6hEbFjF # tkKT925rEGDtgT0Gy2YcWrj+yJt4DEBphOFzx40UJ+sKtHwfwPq5yRVXBnqS/XZJ # pWRb3eqyrp+3lucTe9qT0vUEEwUrkWMm1K64J8TC5z8KwtgC0KQFGrhU0cShS1FD # XCEaVU9J8gidRq0blF6SWd8G6RYg8KVpwPpLA935avEm2bMynQYYoQmPlJTWnFxn # 07nx1QepPRQuMYIEDTCCBAkCAQEwgZMwfDELMAkGA1UEBhMCVVMxEzARBgNVBAgT # Cldhc2hpbmd0b24xEDAOBgNVBAcTB1JlZG1vbmQxHjAcBgNVBAoTFU1pY3Jvc29m # dCBDb3Jwb3JhdGlvbjEmMCQGA1UEAxMdTWljcm9zb2Z0IFRpbWUtU3RhbXAgUENB # IDIwMTACEzMAAAH7y8tsN2flMJUAAQAAAfswDQYJYIZIAWUDBAIBBQCgggFKMBoG # CSqGSIb3DQEJAzENBgsqhkiG9w0BCRABBDAvBgkqhkiG9w0BCQQxIgQg1E7nVSIK # 5ehj415kqp+Oqp6dWPmQvhfRwDvbBvIOZ4AwgfoGCyqGSIb3DQEJEAIvMYHqMIHn # MIHkMIG9BCA52wKr/KCFlVNYiWsCLsB4qhjEYEP3xHqYqDu1SSTlGDCBmDCBgKR+ # MHwxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdS # ZWRtb25kMR4wHAYDVQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xJjAkBgNVBAMT # HU1pY3Jvc29mdCBUaW1lLVN0YW1wIFBDQSAyMDEwAhMzAAAB+8vLbDdn5TCVAAEA # AAH7MCIEIApGs4/3/KDq7Lg6ZdjOISAbSvfnliJTmkbvxVUA80skMA0GCSqGSIb3 # DQEBCwUABIICAAm25X1FgoQ4Irn8KgcN0PN6qJ7t6oLX9JroNTnjlSvmQ8GXeTkA # yAYng+I9oaIkS7PaPZok7mK3k2y5q1NKEbhS3HiBmiKf1TkwaYsnX+Xr1wF31rbh # K+QFgP6Cy+8PShWlvd6pw95Zzhj5cR7/ltZ0oam11E9+nsfUx6MEH4zSGXXJ4aGj # EsS0fqdfukdfyWpLL0g2b8WOqUzHjv+ufuO4FWGLBF/NnQvvnrWrB9VmDxDFYoH+ # KXVAPGxuWInFflje8k07o8u866+7rTm27DwRktrVKppg3nW3RX4uSjwdmgtqE/9Z # /kmIoPJSjpHMy0AARbgSqP6fzUuBDWKe9ZJth7y4sfiRu4Spr33mq8q1uJEUtLOW # k7jjsAcGKTlYGYWdYi0UUyMGA5TymcMi0xeasxspPQCX7n1tGQBzk1gzfRrwnByM # tlgp1+XEVLeiTaNRjkDuSdmqtpP3wdFuV8eDz9za3VrdIUvcOw9hv59jeZ2x+50v # MSnEK9XtebIKHz6zYVuXsGhkfBfrRxFEohJn5i2KYM5gsxSI46kkxQak+howPTDV # BeGXf44c+1FkTEUXfvNMfjlS16k9nMiicmdfX2phA5fhzSOviP0OmkVxovQfaemI # +O0vmSeOa3rU2J8ZrTEhOfIA/zRNvR8MHJM2TYuTa5RLpVNCY3p2zjxf # SIG # End signature block |