AzStackHciConnectivity/AzStackHci.Connectivity.psm1
<#############################################################
# # # Copyright (C) Microsoft Corporation. All rights reserved. # # # #############################################################> Import-Module $PSScriptRoot\AzStackHci.Connectivity.Helpers.psm1 -Force -DisableNameChecking -Global Import-Module $PSScriptRoot\..\AzStackHci.EnvironmentChecker.Utilities.psm1 -Force -DisableNameChecking -Global Import-Module $PSScriptRoot\..\AzStackHci.EnvironmentChecker.Reporting.psm1 -Force -DisableNameChecking -Global Import-LocalizedData -BindingVariable lcTxt -FileName AzStackHci.Connectivity.Strings.psd1 function Invoke-AzStackHciConnectivityValidation { <# .SYNOPSIS Perform AzStackHci Network Validation .DESCRIPTION Perform AzStackHci Network Validation against a mandatory set of endpoints. .EXAMPLE PS C:\> Invoke-AzStackHciConnectivityValidation Perform network validation against all built in service targets from localhost. .EXAMPLE PS C:\> $Credential = Get-Credential -Message "Credential for local cluster" PS C:\> Invoke-AzStackHciConnectivityValidation -Credential $Credential Perform network validation against all built in service targets from all cluster nodes of local system. .EXAMPLE PS C:\> Invoke-AzStackHciConnectivityValidation -Service 'Azure Kubernetes Service' Perform network validation against all mandatory targets and Azure Kubernetes targets from localhost. .EXAMPLE PS C:\> Invoke-AzStackHciConnectivityValidation -Include 'Windows Admin Center','Windows Admin Center in Azure Portal' Perform network validation against all mandatory targets, Windows Admin Center targets and Windows Admin Center in Azure Portal targets from localhost. .EXAMPLE PS C:\> Invoke-AzStackHciConnectivityValidation -Exclude 'Qualys','Arc For Servers' Perform network validation against all targets excluding Qualys & Arc for Servers from localhost. .EXAMPLE PS C:\> $Credential = Get-Credential -Message "Credential for $RemoteSystem" PS C:\> $RemoteSystemSession = New-PSSession -Computer 10.0.0.4 -Credential $Credential PS C:\> Invoke-AzStackHciConnectivityValidation -PsSession $RemoteSystemSession Perform network validation against all built in service target from pre-existing remote PS session. .EXAMPLE PS C:\> $RemoteSystem = 'node01.contoso.com' PS C:\> $Credential = Get-Credential -Message "Credential for $RemoteSystem" PS C:\> Invoke-AzStackHciConnectivityValidation -ComputerName $RemoteSystem -Credential $Credential Perform network validation against all built in service target from a remote system. .PARAMETER PsSession Specify the PsSession(s) used to validation from. If null the local machine will be used. .PARAMETER Service Specify the services to target for connectivity validation. (Aliases: Include) .PARAMETER OperationType Specify the Operation Type to target for connectivity validation. e.g. Deployment, Update, etc. .PARAMETER Exclude Specify the services to exclude for connectivity validation. .PARAMETER Proxy Specify proxy server. .PARAMETER ProxyCredential Specify proxy server credential. .PARAMETER PassThru Return PSObject result. .PARAMETER OutputPath Directory path for log and report output. .PARAMETER CleanReport Remove all previous progress and create a clean report. .INPUTS Inputs (if any) .OUTPUTS Output (if any) .LINK https://docs.microsoft.com/en-us/azure-stack/hci/manage/use-environment-checker?tabs=connectivity .NOTES Mandatory Targets are always invoked, unless explicitly excluded. Use Get-AzStackHciConnectivityTarget | Select Service, Title, Mandatory, Endpoint for more information. File-based exclusions can be made by creating a file exlcudetests.txt in the root modules root folder (e.g. PSModulePath\AzStackHci.EnvironmentChecker\<version>). This file can support multiple exclusions for all validators e.g. --Start sample-- Test-Processor Observability microsoftonline --End sample-- This file would have the following affect. After any include/exclude filtering from the parameter inputs: Invoke-AzStackHciHardwareValidation would exclude Test-Processor in its tests Invoke-AzStackHciConnectivityValidation would exclude the Observability service AND any service target who's endpoints contains a match for microsoftonline. #> [Alias("Test-AzStackHCIConnection")] [CmdletBinding()] param ( [Parameter(Mandatory = $false, HelpMessage = "Specify the PsSession(s) used to validation from. If null the local machine will be used.")] [System.Management.Automation.Runspaces.PSSession[]] $PsSession, [Parameter(Mandatory = $false, HelpMessage = "Specify the services to target for connectivity validation.")] [ArgumentCompleter({ Get-AzStackHciConnectivityServiceName })] [ValidateScript({ $_ -in (Get-AzStackHciConnectivityServiceName) })] [Alias("Include")] [string[]] $Service, [Parameter(Mandatory = $false, HelpMessage = "Specify the Operation Type to target for connectivity validation. e.g. Deployment, Update, etc...")] [ArgumentCompleter({ Get-AzStackHciConnectivityOperationName })] [ValidateScript({ $_ -in (Get-AzStackHciConnectivityOperationName) })] [string[]] $OperationType, [Parameter(Mandatory = $false, HelpMessage = "Specify the services to exclude for connectivity validation.")] [ArgumentCompleter({ Get-AzStackHciConnectivityServiceName })] [ValidateScript({ $_ -in (Get-AzStackHciConnectivityServiceName) })] [string[]] $Exclude, [Parameter(Mandatory = $false, HelpMessage = "Specify proxy server.")] [string] $Proxy, [Parameter(Mandatory = $false, HelpMessage = "Specify proxy server credential.")] [pscredential] $ProxyCredential, [Parameter(Mandatory = $false, HelpMessage = "Return PSObject result.")] [switch] $PassThru, [Parameter(Mandatory = $false, HelpMessage = "Directory path for log and report output")] [string]$OutputPath, [Parameter(Mandatory = $false, HelpMessage = "Remove all previous progress and create a clean report")] [switch]$CleanReport = $false ) try { $script:ErrorActionPreference = 'Stop' Set-AzStackHciOutputPath -Path $OutputPath $script:Standalone = [bool](Get-Module -Name AzStackHci.EnvironmentChecker -ErrorAction SilentlyContinue) if ($script:Standalone -and -not $PassThru) { if ($MyInvocation.InvocationName -eq 'Test-AzStackHCIConnection') { Log-Info "The cmdlet name Test-AzStackHCIConnection has been deprecated. Invoke-AzStackHciConnectivityValidation will be used in future. Please run Get-Help Invoke-AzStackHciConnectivityValidation for further guidance." -Type Warning -ConsoleOut } Write-AzStackHciHeader -invocation $MyInvocation -params $PSBoundParameters Log-Info "Running in standalone mode" Test-ModuleUpdate } # Call/Initialise reporting $envcheckerReport = Get-AzStackHciEnvProgress -clean:$CleanReport $envcheckerReport = Add-AzStackHciEnvJob -report $envcheckerReport # TO DO: Omit system? $ConnectivityTargets = Get-AzStackHciConnectivityTarget -Service $Service -OperationType $OperationType $ConnectivityTargets = Select-AzStackHciConnectivityTarget -Targets $ConnectivityTargets -Exclude $Exclude Write-Progress -Id 1 -Activity "Checking AzStackHci Dependancies" -Status "Environment configuration" -PercentComplete 0 -ErrorAction SilentlyContinue # Run validation $i = 0 $webResult = @() $diagnosticResults = @() if ($PsSession) { foreach ($Session in $PsSession) { if ($Session.State -ne 'Opened') { try { Connect-PSSession -Session $Session } catch { $PsSessionFail = $lcTxt.PsSessionFail -f $Session.ComputerName, $_.Exception.Message Log-Info ($PsSessionFail) -type Error throw $PsSessionFail } } $diagnosticResults += Test-Dns -PsSession $Session # Fail fast if dns fails if ($diagnosticResults[-1].Status -ne 'Succeeded') { Log-Info ($lcTxt.DnsFail -f $Session.ComputerName, ($dnsResult.AdditionalData.Detail | ConvertTo-Json)) -Type Warning -ConsoleOut } $diagnosticResults += Get-ProxyDiagnostics -PsSession $Session -Proxy $Proxy $diagnosticResults += Test-RootCA -PsSession $Session -Proxy $Proxy -ProxyCredential $ProxyCredential if ($diagnosticResults.Status -contains 'Failed') { $failedDiagnosticResult = $diagnosticResults | Where-Object Status -EQ 'Failed' | Format-List | Out-String $failedDiagnosticDetailMsg = ($diagnosticResults | Where-Object Status -EQ 'Failed' | Select-Object -ExpandProperty AdditionalData | Select-Object -ExpandProperty Detail) -join '. ' throw $lcTxt.DiagnosticSystemFailure -f $failedDiagnosticDetailMsg, $failedDiagnosticResult } foreach ($Target in $ConnectivityTargets) { $i++ $progressPercentage = ($i / (($ConnectivityTargets.Count) * $PsSession.Count )) * 100 Write-Progress -Id 1 -Activity "Checking AzStackHci dependencies to $($Target.Service)" -Status "Connectivity from $($Session.ComputerName) to $($Target.Title) Endpoints" -PercentComplete $progressPercentage -ErrorAction SilentlyContinue Log-Info -Message ("Checking {0} on {1}" -f $target.Title, $session.ComputerName) if ($Proxy) { $webResult += Invoke-WebRequestEx -Target $Target -PsSession $Session -Proxy $Proxy -ProxyCredential $ProxyCredential } else { $webResult += Invoke-TestNetConnection -Target $Target -PsSession $Session } } } } else { $diagnosticResults += Test-Dns # Fail fast if dns fails if ($diagnosticResults[-1].Status -ne 'Succeeded') { Log-Info ($lcTxt.DnsFail -f $ENV:COMPUTERNAME, ($dnsResult.AdditionalData.Detail | ConvertTo-Json)) -Type Warning -ConsoleOut } $diagnosticResults += Get-ProxyDiagnostics -Proxy $Proxy $diagnosticResults += Test-RootCA -Proxy $Proxy -ProxyCredential $ProxyCredential if ($diagnosticResults.Status -contains 'Failed') { $failedDiagnosticResult = $diagnosticResults | Where-Object Status -EQ 'Failed' | Format-List | Out-String $failedDiagnosticDetailMsg = ($diagnosticResults | Where-Object Status -EQ 'Failed' | Select-Object -ExpandProperty AdditionalData | Select-Object -ExpandProperty Detail) -join '. ' throw $lcTxt.DiagnosticSystemFailure -f $failedDiagnosticDetailMsg, $failedDiagnosticResult } foreach ($Target in $ConnectivityTargets) { $i++ $progressPercentage = ($i / ($ConnectivityTargets.Count)) * 100 $progressParams = @{ Id = 1 Activity = "Checking AzStackHci dependencies to $($Target.Service)" Status = if ($Proxy) { "Connectivity from $ENV:ComputerName (via $Proxy) to $($Target.Title) Endpoints" } else { "Connectivity from $ENV:ComputerName to $($Target.Title) Endpoints" } PercentComplete = $progressPercentage ErrorAction = 'SilentlyContinue' } Write-Progress @progressParams Log-Info -Message ("Checking {0} (proxy:'{1}')" -f $target.Title, $proxy) if ($target.Protocol -notmatch 'http' -or -not $Proxy) { $webResult += Invoke-TestNetConnection -Target $Target } else { $webResult += Invoke-WebRequestEx -Target $Target -Proxy $Proxy -ProxyCredential $ProxyCredential } } } # Feedback results - user scenario if ($script:Standalone -and -not $PassThru) { Write-Host 'Connectivity Results' $printed = @() $services = $webresult.service | Sort-Object | Get-Unique | Where-Object { $PSITEM -ne 'System' } Foreach ($Service in $Services) { $thisResult = $webResult | Where-Object { $PSITEM -notin $printed -and $_.Service -EQ $service } Write-AzStackHciResult -Title "$Service" -Result $thisResult $printed += $webResult | Where-Object Service -EQ $service } Write-AzStackHciResult -Title 'Diagnostics' -Result $diagnosticResults -Expand Write-Summary -Result $webResult -Property1 Source -Property2 Resource Write-FailedUrls -Result $webResult } else { return ($webResult + $diagnosticResults) } } catch { Log-Info -Message "" -ConsoleOut Log-Info -Message "$($_.Exception.Message)" -ConsoleOut -Type Error Log-Info -Message "$($_.ScriptStackTrace)" -ConsoleOut -Type Error $cmdletFailed = $true throw $_.exception } finally { # Write result to telemetry channel foreach ($r in ($webResult + $diagnosticResults)) { Write-ETWResult -Result $r } # Write validation result to report object and close out report $envcheckerReport | Add-Member -MemberType NoteProperty -Name 'Connectivity' -Value $webResult -Force $envcheckerReport | Add-Member -MemberType NoteProperty -Name 'Diagnostics' -Value $diagnosticResults -Force $envcheckerReport = Close-AzStackHciEnvJob -report $envcheckerReport Write-AzStackHciEnvReport -report $envcheckerReport Write-AzStackHciFooter -invocation $MyInvocation -Failed:$cmdletFailed -PassThru:$PassThru Remove-Variable -Name AzStackHciConnectivityTargets -Scope GLOBAL -ErrorAction SilentlyContinue } } # SIG # Begin signature block # MIInqgYJKoZIhvcNAQcCoIInmzCCJ5cCAQExDzANBglghkgBZQMEAgEFADB5Bgor # BgEEAYI3AgEEoGswaTA0BgorBgEEAYI3AgEeMCYCAwEAAAQQH8w7YFlLCE63JNLG # KX7zUQIBAAIBAAIBAAIBAAIBADAxMA0GCWCGSAFlAwQCAQUABCDx5P3PYzvADWMO # yItAMgE90SdCiFSsNWz7vlR/Bj4sa6CCDYEwggX/MIID56ADAgECAhMzAAACzI61 # lqa90clOAAAAAALMMA0GCSqGSIb3DQEBCwUAMH4xCzAJBgNVBAYTAlVTMRMwEQYD # VQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNy # b3NvZnQgQ29ycG9yYXRpb24xKDAmBgNVBAMTH01pY3Jvc29mdCBDb2RlIFNpZ25p # bmcgUENBIDIwMTEwHhcNMjIwNTEyMjA0NjAxWhcNMjMwNTExMjA0NjAxWjB0MQsw # CQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9u # ZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMR4wHAYDVQQDExVNaWNy # b3NvZnQgQ29ycG9yYXRpb24wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIB # AQCiTbHs68bADvNud97NzcdP0zh0mRr4VpDv68KobjQFybVAuVgiINf9aG2zQtWK # No6+2X2Ix65KGcBXuZyEi0oBUAAGnIe5O5q/Y0Ij0WwDyMWaVad2Te4r1Eic3HWH # UfiiNjF0ETHKg3qa7DCyUqwsR9q5SaXuHlYCwM+m59Nl3jKnYnKLLfzhl13wImV9 # DF8N76ANkRyK6BYoc9I6hHF2MCTQYWbQ4fXgzKhgzj4zeabWgfu+ZJCiFLkogvc0 # RVb0x3DtyxMbl/3e45Eu+sn/x6EVwbJZVvtQYcmdGF1yAYht+JnNmWwAxL8MgHMz # xEcoY1Q1JtstiY3+u3ulGMvhAgMBAAGjggF+MIIBejAfBgNVHSUEGDAWBgorBgEE # AYI3TAgBBggrBgEFBQcDAzAdBgNVHQ4EFgQUiLhHjTKWzIqVIp+sM2rOHH11rfQw # UAYDVR0RBEkwR6RFMEMxKTAnBgNVBAsTIE1pY3Jvc29mdCBPcGVyYXRpb25zIFB1 # ZXJ0byBSaWNvMRYwFAYDVQQFEw0yMzAwMTIrNDcwNTI5MB8GA1UdIwQYMBaAFEhu # ZOVQBdOCqhc3NyK1bajKdQKVMFQGA1UdHwRNMEswSaBHoEWGQ2h0dHA6Ly93d3cu # bWljcm9zb2Z0LmNvbS9wa2lvcHMvY3JsL01pY0NvZFNpZ1BDQTIwMTFfMjAxMS0w # Ny0wOC5jcmwwYQYIKwYBBQUHAQEEVTBTMFEGCCsGAQUFBzAChkVodHRwOi8vd3d3 # Lm1pY3Jvc29mdC5jb20vcGtpb3BzL2NlcnRzL01pY0NvZFNpZ1BDQTIwMTFfMjAx # MS0wNy0wOC5jcnQwDAYDVR0TAQH/BAIwADANBgkqhkiG9w0BAQsFAAOCAgEAeA8D # sOAHS53MTIHYu8bbXrO6yQtRD6JfyMWeXaLu3Nc8PDnFc1efYq/F3MGx/aiwNbcs # J2MU7BKNWTP5JQVBA2GNIeR3mScXqnOsv1XqXPvZeISDVWLaBQzceItdIwgo6B13 # vxlkkSYMvB0Dr3Yw7/W9U4Wk5K/RDOnIGvmKqKi3AwyxlV1mpefy729FKaWT7edB # d3I4+hldMY8sdfDPjWRtJzjMjXZs41OUOwtHccPazjjC7KndzvZHx/0VWL8n0NT/ # 404vftnXKifMZkS4p2sB3oK+6kCcsyWsgS/3eYGw1Fe4MOnin1RhgrW1rHPODJTG # AUOmW4wc3Q6KKr2zve7sMDZe9tfylonPwhk971rX8qGw6LkrGFv31IJeJSe/aUbG # dUDPkbrABbVvPElgoj5eP3REqx5jdfkQw7tOdWkhn0jDUh2uQen9Atj3RkJyHuR0 # GUsJVMWFJdkIO/gFwzoOGlHNsmxvpANV86/1qgb1oZXdrURpzJp53MsDaBY/pxOc # J0Cvg6uWs3kQWgKk5aBzvsX95BzdItHTpVMtVPW4q41XEvbFmUP1n6oL5rdNdrTM # j/HXMRk1KCksax1Vxo3qv+13cCsZAaQNaIAvt5LvkshZkDZIP//0Hnq7NnWeYR3z # 4oFiw9N2n3bb9baQWuWPswG0Dq9YT9kb+Cs4qIIwggd6MIIFYqADAgECAgphDpDS # AAAAAAADMA0GCSqGSIb3DQEBCwUAMIGIMQswCQYDVQQGEwJVUzETMBEGA1UECBMK # V2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9uZDEeMBwGA1UEChMVTWljcm9zb2Z0 # IENvcnBvcmF0aW9uMTIwMAYDVQQDEylNaWNyb3NvZnQgUm9vdCBDZXJ0aWZpY2F0 # ZSBBdXRob3JpdHkgMjAxMTAeFw0xMTA3MDgyMDU5MDlaFw0yNjA3MDgyMTA5MDla # MH4xCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdS # ZWRtb25kMR4wHAYDVQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xKDAmBgNVBAMT # H01pY3Jvc29mdCBDb2RlIFNpZ25pbmcgUENBIDIwMTEwggIiMA0GCSqGSIb3DQEB # AQUAA4ICDwAwggIKAoICAQCr8PpyEBwurdhuqoIQTTS68rZYIZ9CGypr6VpQqrgG # OBoESbp/wwwe3TdrxhLYC/A4wpkGsMg51QEUMULTiQ15ZId+lGAkbK+eSZzpaF7S # 35tTsgosw6/ZqSuuegmv15ZZymAaBelmdugyUiYSL+erCFDPs0S3XdjELgN1q2jz # y23zOlyhFvRGuuA4ZKxuZDV4pqBjDy3TQJP4494HDdVceaVJKecNvqATd76UPe/7 # 4ytaEB9NViiienLgEjq3SV7Y7e1DkYPZe7J7hhvZPrGMXeiJT4Qa8qEvWeSQOy2u # M1jFtz7+MtOzAz2xsq+SOH7SnYAs9U5WkSE1JcM5bmR/U7qcD60ZI4TL9LoDho33 # X/DQUr+MlIe8wCF0JV8YKLbMJyg4JZg5SjbPfLGSrhwjp6lm7GEfauEoSZ1fiOIl # XdMhSz5SxLVXPyQD8NF6Wy/VI+NwXQ9RRnez+ADhvKwCgl/bwBWzvRvUVUvnOaEP # 6SNJvBi4RHxF5MHDcnrgcuck379GmcXvwhxX24ON7E1JMKerjt/sW5+v/N2wZuLB # l4F77dbtS+dJKacTKKanfWeA5opieF+yL4TXV5xcv3coKPHtbcMojyyPQDdPweGF # RInECUzF1KVDL3SV9274eCBYLBNdYJWaPk8zhNqwiBfenk70lrC8RqBsmNLg1oiM # CwIDAQABo4IB7TCCAekwEAYJKwYBBAGCNxUBBAMCAQAwHQYDVR0OBBYEFEhuZOVQ # BdOCqhc3NyK1bajKdQKVMBkGCSsGAQQBgjcUAgQMHgoAUwB1AGIAQwBBMAsGA1Ud # DwQEAwIBhjAPBgNVHRMBAf8EBTADAQH/MB8GA1UdIwQYMBaAFHItOgIxkEO5FAVO # 4eqnxzHRI4k0MFoGA1UdHwRTMFEwT6BNoEuGSWh0dHA6Ly9jcmwubWljcm9zb2Z0 # LmNvbS9wa2kvY3JsL3Byb2R1Y3RzL01pY1Jvb0NlckF1dDIwMTFfMjAxMV8wM18y # Mi5jcmwwXgYIKwYBBQUHAQEEUjBQME4GCCsGAQUFBzAChkJodHRwOi8vd3d3Lm1p # Y3Jvc29mdC5jb20vcGtpL2NlcnRzL01pY1Jvb0NlckF1dDIwMTFfMjAxMV8wM18y # Mi5jcnQwgZ8GA1UdIASBlzCBlDCBkQYJKwYBBAGCNy4DMIGDMD8GCCsGAQUFBwIB # FjNodHRwOi8vd3d3Lm1pY3Jvc29mdC5jb20vcGtpb3BzL2RvY3MvcHJpbWFyeWNw # cy5odG0wQAYIKwYBBQUHAgIwNB4yIB0ATABlAGcAYQBsAF8AcABvAGwAaQBjAHkA # XwBzAHQAYQB0AGUAbQBlAG4AdAAuIB0wDQYJKoZIhvcNAQELBQADggIBAGfyhqWY # 4FR5Gi7T2HRnIpsLlhHhY5KZQpZ90nkMkMFlXy4sPvjDctFtg/6+P+gKyju/R6mj # 82nbY78iNaWXXWWEkH2LRlBV2AySfNIaSxzzPEKLUtCw/WvjPgcuKZvmPRul1LUd # d5Q54ulkyUQ9eHoj8xN9ppB0g430yyYCRirCihC7pKkFDJvtaPpoLpWgKj8qa1hJ # Yx8JaW5amJbkg/TAj/NGK978O9C9Ne9uJa7lryft0N3zDq+ZKJeYTQ49C/IIidYf # wzIY4vDFLc5bnrRJOQrGCsLGra7lstnbFYhRRVg4MnEnGn+x9Cf43iw6IGmYslmJ # aG5vp7d0w0AFBqYBKig+gj8TTWYLwLNN9eGPfxxvFX1Fp3blQCplo8NdUmKGwx1j # NpeG39rz+PIWoZon4c2ll9DuXWNB41sHnIc+BncG0QaxdR8UvmFhtfDcxhsEvt9B # xw4o7t5lL+yX9qFcltgA1qFGvVnzl6UJS0gQmYAf0AApxbGbpT9Fdx41xtKiop96 # eiL6SJUfq/tHI4D1nvi/a7dLl+LrdXga7Oo3mXkYS//WsyNodeav+vyL6wuA6mk7 # r/ww7QRMjt/fdW1jkT3RnVZOT7+AVyKheBEyIXrvQQqxP/uozKRdwaGIm1dxVk5I # RcBCyZt2WwqASGv9eZ/BvW1taslScxMNelDNMYIZfzCCGXsCAQEwgZUwfjELMAkG # A1UEBhMCVVMxEzARBgNVBAgTCldhc2hpbmd0b24xEDAOBgNVBAcTB1JlZG1vbmQx # HjAcBgNVBAoTFU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjEoMCYGA1UEAxMfTWljcm9z # b2Z0IENvZGUgU2lnbmluZyBQQ0EgMjAxMQITMwAAAsyOtZamvdHJTgAAAAACzDAN # BglghkgBZQMEAgEFAKCBrjAZBgkqhkiG9w0BCQMxDAYKKwYBBAGCNwIBBDAcBgor # BgEEAYI3AgELMQ4wDAYKKwYBBAGCNwIBFTAvBgkqhkiG9w0BCQQxIgQg1sbDNWBu # az/s6Z8z5IbtJzL5fdQxaDI4tgaE8TyZV1UwQgYKKwYBBAGCNwIBDDE0MDKgFIAS # AE0AaQBjAHIAbwBzAG8AZgB0oRqAGGh0dHA6Ly93d3cubWljcm9zb2Z0LmNvbTAN # BgkqhkiG9w0BAQEFAASCAQBrcCpTD+D9UjicNMd0fosQ83FNg/jcposhBOBBLRiA # evStK3eFF2x8r5aLi8RTyWWIrCpv9Cs/UrYxRcIfmtNmfTQOO1ffFVVs1rNlw5j7 # T5nfm6nlGXoDIwKDzsXE6wc7LjcLn9Eyi77Rq2Pw3DcpST2MmyOhfnTWve9mApl0 # 6ofBMM+7q2CquwF1+MqT6fp7riYudMKS+WuDXiaaVVoxLyzchWiKIKBpu+NyQmKM # rxKhXLDQ0NmHlJk4LabhIwEeTAcYv6vK2xlcBfww9YXIWHP3zX5mSsp5RtlEgs6N # 1/4Skr9YrHR2QQScisH3ZSW5mjibGp1ZxXft04HULTVPoYIXCTCCFwUGCisGAQQB # gjcDAwExghb1MIIW8QYJKoZIhvcNAQcCoIIW4jCCFt4CAQMxDzANBglghkgBZQME # AgEFADCCAVUGCyqGSIb3DQEJEAEEoIIBRASCAUAwggE8AgEBBgorBgEEAYRZCgMB # MDEwDQYJYIZIAWUDBAIBBQAEIJOZweRY9tTVkb3jE/lvu4cHV6VLUzrXrH8Iyv/m # p/vtAgZjYsXqLFkYEzIwMjIxMTE1MTA0NzM1Ljk2N1owBIACAfSggdSkgdEwgc4x # CzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRt # b25kMR4wHAYDVQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xKTAnBgNVBAsTIE1p # Y3Jvc29mdCBPcGVyYXRpb25zIFB1ZXJ0byBSaWNvMSYwJAYDVQQLEx1UaGFsZXMg # VFNTIEVTTjpGNzdGLUUzNTYtNUJBRTElMCMGA1UEAxMcTWljcm9zb2Z0IFRpbWUt # U3RhbXAgU2VydmljZaCCEVwwggcQMIIE+KADAgECAhMzAAABqqUxmwvLsggOAAEA # AAGqMA0GCSqGSIb3DQEBCwUAMHwxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpXYXNo # aW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNyb3NvZnQgQ29y # cG9yYXRpb24xJjAkBgNVBAMTHU1pY3Jvc29mdCBUaW1lLVN0YW1wIFBDQSAyMDEw # MB4XDTIyMDMwMjE4NTEyNloXDTIzMDUxMTE4NTEyNlowgc4xCzAJBgNVBAYTAlVT # MRMwEQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQK # ExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xKTAnBgNVBAsTIE1pY3Jvc29mdCBPcGVy # YXRpb25zIFB1ZXJ0byBSaWNvMSYwJAYDVQQLEx1UaGFsZXMgVFNTIEVTTjpGNzdG # LUUzNTYtNUJBRTElMCMGA1UEAxMcTWljcm9zb2Z0IFRpbWUtU3RhbXAgU2Vydmlj # ZTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAKBP7HK51bWHf+FDSh9O # 7YyrQtkNMvdHzHiazvOdI9POGjyJIYrs1WOMmSCp3o/mvsuPnFSP5c0dCeBuUq6u # 6J30M81ZaNOP/abZrTwYrYN+N5nStrOGdCtRBum76hy7Tr3AZDUArLwvhsGlXhLl # DU1wioaxM+BVwCNI7LmTaYKqjm58hEgsYtKIHk59LzOnI4aenbPLBP/VYYjI6a4K # Icun0EZErAukt5PC/mKUaOphUMGYm0PxfpY9BkG5sPfczFyIfA13LLRS4sGhbUrc # M54EvE2FlWBQaJo7frKW7CVjITLEX4E2lxwQG/MuZ+1wDYg9OOErT5h+6zecj67e # enwxeUoaOEbKtiUxaJUYnyQKxCWTkNdWRXTKSmIxx0tbsP5irWjqXvT6t/zeJKw0 # 5NY8hPT56vW20q0DYK2NteOCDD0UD6ZNAFLV87GOkl0eBqXcToFVdeJwwOTE6aA4 # RqYoNr2QUPBIU6JEiUGBs9c4qC5mBHTY46VaR/odaFDLcxQI4OPkn5al/IPsd8/r # aDmMfKik66xcNh2qN4yytYM3uiDenX5qeFdx3pdi43pYAFN/S1/3VRNk+/GRVUUY # WYBjDZSqxslidE8hsxC7K8qLfmNoaQ2aAsu13h1faTMSZIEVxosz1b9yIeXmtM6N # lrjV3etwS7JXYwGhHMdVYEL1AgMBAAGjggE2MIIBMjAdBgNVHQ4EFgQUP5oUvFOH # Lthfd0Wz3hGtnQVGpJ4wHwYDVR0jBBgwFoAUn6cVXQBeYl2D9OXSZacbUzUZ6XIw # XwYDVR0fBFgwVjBUoFKgUIZOaHR0cDovL3d3dy5taWNyb3NvZnQuY29tL3BraW9w # cy9jcmwvTWljcm9zb2Z0JTIwVGltZS1TdGFtcCUyMFBDQSUyMDIwMTAoMSkuY3Js # MGwGCCsGAQUFBwEBBGAwXjBcBggrBgEFBQcwAoZQaHR0cDovL3d3dy5taWNyb3Nv # ZnQuY29tL3BraW9wcy9jZXJ0cy9NaWNyb3NvZnQlMjBUaW1lLVN0YW1wJTIwUENB # JTIwMjAxMCgxKS5jcnQwDAYDVR0TAQH/BAIwADATBgNVHSUEDDAKBggrBgEFBQcD # CDANBgkqhkiG9w0BAQsFAAOCAgEA3wyATZBFEBogrcwHs4zI7qX2y0jbKCI6ZieG # AIR96RiMrjZvWG39YPA/FL2vhGSCtO7ea3iBlwhhTyJEPexLugT4jB4W0rldOLP5 # bEc0zwxs9NtTFS8Ul2zbJ7jz5WxSnhSHsfaVFUp7S6B2a1bjKmWIo/Svd3W1V3mc # IYzhbpLIUVlP3CbTJEE+cC3hX+JggnSYRETyo+mI7Hz/KMWFaRWBUYI4g0BrwiV2 # lYqKyekjNp6rj7b8l6OhbgX/JP0bzNxv6io0Y4iNlIzz/PdIh/E2pj3pXPiQJPRl # EkMksRecE8VnFyqhR4fb/F6c5ywY4+mEpshIAg2YUXswFqqbK9Fv+U8YYclYPvhK # /wRZs+/5auK4FM+QTjywj0C5rmr8MziqmUGgAuwZQYyHRCopnVdlaO/xxSZCfaZR # 7w7B3OBEl8j+Voofs1Kfq9AmmQAWZOjt4DnNk5NnxThPvjQVuOU/y+HTErwqD/wK # RCl0AJ3UPTJ8PPYp+jbEXkKmoFhU4JGer5eaj22nX19pujNZKqqart4yLjNUOkqW # jVk4KHpdYRGcJMVXkKkQAiljUn9cHRwNuPz/Tu7YmfgRXWN4HvCcT2m1QADinOZP # sO5v5j/bExw0WmFrW2CtDEApnClmiAKchFr0xSKE5ET+AyubLapejENr9vt7QXNq # 6aP1XWcwggdxMIIFWaADAgECAhMzAAAAFcXna54Cm0mZAAAAAAAVMA0GCSqGSIb3 # DQEBCwUAMIGIMQswCQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4G # A1UEBxMHUmVkbW9uZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMTIw # MAYDVQQDEylNaWNyb3NvZnQgUm9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkgMjAx # MDAeFw0yMTA5MzAxODIyMjVaFw0zMDA5MzAxODMyMjVaMHwxCzAJBgNVBAYTAlVT # MRMwEQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQK # ExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xJjAkBgNVBAMTHU1pY3Jvc29mdCBUaW1l # LVN0YW1wIFBDQSAyMDEwMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA # 5OGmTOe0ciELeaLL1yR5vQ7VgtP97pwHB9KpbE51yMo1V/YBf2xK4OK9uT4XYDP/ # XE/HZveVU3Fa4n5KWv64NmeFRiMMtY0Tz3cywBAY6GB9alKDRLemjkZrBxTzxXb1 # hlDcwUTIcVxRMTegCjhuje3XD9gmU3w5YQJ6xKr9cmmvHaus9ja+NSZk2pg7uhp7 # M62AW36MEBydUv626GIl3GoPz130/o5Tz9bshVZN7928jaTjkY+yOSxRnOlwaQ3K # Ni1wjjHINSi947SHJMPgyY9+tVSP3PoFVZhtaDuaRr3tpK56KTesy+uDRedGbsoy # 1cCGMFxPLOJiss254o2I5JasAUq7vnGpF1tnYN74kpEeHT39IM9zfUGaRnXNxF80 # 3RKJ1v2lIH1+/NmeRd+2ci/bfV+AutuqfjbsNkz2K26oElHovwUDo9Fzpk03dJQc # NIIP8BDyt0cY7afomXw/TNuvXsLz1dhzPUNOwTM5TI4CvEJoLhDqhFFG4tG9ahha # YQFzymeiXtcodgLiMxhy16cg8ML6EgrXY28MyTZki1ugpoMhXV8wdJGUlNi5UPkL # iWHzNgY1GIRH29wb0f2y1BzFa/ZcUlFdEtsluq9QBXpsxREdcu+N+VLEhReTwDwV # 2xo3xwgVGD94q0W29R6HXtqPnhZyacaue7e3PmriLq0CAwEAAaOCAd0wggHZMBIG # CSsGAQQBgjcVAQQFAgMBAAEwIwYJKwYBBAGCNxUCBBYEFCqnUv5kxJq+gpE8RjUp # zxD/LwTuMB0GA1UdDgQWBBSfpxVdAF5iXYP05dJlpxtTNRnpcjBcBgNVHSAEVTBT # MFEGDCsGAQQBgjdMg30BATBBMD8GCCsGAQUFBwIBFjNodHRwOi8vd3d3Lm1pY3Jv # c29mdC5jb20vcGtpb3BzL0RvY3MvUmVwb3NpdG9yeS5odG0wEwYDVR0lBAwwCgYI # KwYBBQUHAwgwGQYJKwYBBAGCNxQCBAweCgBTAHUAYgBDAEEwCwYDVR0PBAQDAgGG # MA8GA1UdEwEB/wQFMAMBAf8wHwYDVR0jBBgwFoAU1fZWy4/oolxiaNE9lJBb186a # GMQwVgYDVR0fBE8wTTBLoEmgR4ZFaHR0cDovL2NybC5taWNyb3NvZnQuY29tL3Br # aS9jcmwvcHJvZHVjdHMvTWljUm9vQ2VyQXV0XzIwMTAtMDYtMjMuY3JsMFoGCCsG # AQUFBwEBBE4wTDBKBggrBgEFBQcwAoY+aHR0cDovL3d3dy5taWNyb3NvZnQuY29t # L3BraS9jZXJ0cy9NaWNSb29DZXJBdXRfMjAxMC0wNi0yMy5jcnQwDQYJKoZIhvcN # AQELBQADggIBAJ1VffwqreEsH2cBMSRb4Z5yS/ypb+pcFLY+TkdkeLEGk5c9MTO1 # OdfCcTY/2mRsfNB1OW27DzHkwo/7bNGhlBgi7ulmZzpTTd2YurYeeNg2LpypglYA # A7AFvonoaeC6Ce5732pvvinLbtg/SHUB2RjebYIM9W0jVOR4U3UkV7ndn/OOPcbz # aN9l9qRWqveVtihVJ9AkvUCgvxm2EhIRXT0n4ECWOKz3+SmJw7wXsFSFQrP8DJ6L # GYnn8AtqgcKBGUIZUnWKNsIdw2FzLixre24/LAl4FOmRsqlb30mjdAy87JGA0j3m # Sj5mO0+7hvoyGtmW9I/2kQH2zsZ0/fZMcm8Qq3UwxTSwethQ/gpY3UA8x1RtnWN0 # SCyxTkctwRQEcb9k+SS+c23Kjgm9swFXSVRk2XPXfx5bRAGOWhmRaw2fpCjcZxko # JLo4S5pu+yFUa2pFEUep8beuyOiJXk+d0tBMdrVXVAmxaQFEfnyhYWxz/gq77EFm # PWn9y8FBSX5+k77L+DvktxW/tM4+pTFRhLy/AsGConsXHRWJjXD+57XQKBqJC482 # 2rpM+Zv/Cuk0+CQ1ZyvgDbjmjJnW4SLq8CdCPSWU5nR0W2rRnj7tfqAxM328y+l7 # vzhwRNGQ8cirOoo6CGJ/2XBjU02N7oJtpQUQwXEGahC0HVUzWLOhcGbyoYICzzCC # AjgCAQEwgfyhgdSkgdEwgc4xCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpXYXNoaW5n # dG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNyb3NvZnQgQ29ycG9y # YXRpb24xKTAnBgNVBAsTIE1pY3Jvc29mdCBPcGVyYXRpb25zIFB1ZXJ0byBSaWNv # MSYwJAYDVQQLEx1UaGFsZXMgVFNTIEVTTjpGNzdGLUUzNTYtNUJBRTElMCMGA1UE # AxMcTWljcm9zb2Z0IFRpbWUtU3RhbXAgU2VydmljZaIjCgEBMAcGBSsOAwIaAxUA # 4G0m0J4eAlljcP/jvOv9/pm/68aggYMwgYCkfjB8MQswCQYDVQQGEwJVUzETMBEG # A1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9uZDEeMBwGA1UEChMVTWlj # cm9zb2Z0IENvcnBvcmF0aW9uMSYwJAYDVQQDEx1NaWNyb3NvZnQgVGltZS1TdGFt # cCBQQ0EgMjAxMDANBgkqhkiG9w0BAQUFAAIFAOcdvcswIhgPMjAyMjExMTUxMTI3 # MDdaGA8yMDIyMTExNjExMjcwN1owdDA6BgorBgEEAYRZCgQBMSwwKjAKAgUA5x29 # ywIBADAHAgEAAgIE0TAHAgEAAgIVNDAKAgUA5x8PSwIBADA2BgorBgEEAYRZCgQC # MSgwJjAMBgorBgEEAYRZCgMCoAowCAIBAAIDB6EgoQowCAIBAAIDAYagMA0GCSqG # SIb3DQEBBQUAA4GBAF0cUvRGU9g/3W2QU2A3Cspfns6iESyI5qtsO/SjmiqgETJj # lGrjWlQ0pVxFzNleoHbtM6iRjST76PFLYhbc40kF+xDasU38Bf5W1Cxi7gFMdPcG # nFpEuNcQQCqRdTaEf9cJAQaf3/EFew1xWIEnuxfGy3d008vQYeWsLUh2n9Z3MYIE # DTCCBAkCAQEwgZMwfDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCldhc2hpbmd0b24x # EDAOBgNVBAcTB1JlZG1vbmQxHjAcBgNVBAoTFU1pY3Jvc29mdCBDb3Jwb3JhdGlv # bjEmMCQGA1UEAxMdTWljcm9zb2Z0IFRpbWUtU3RhbXAgUENBIDIwMTACEzMAAAGq # pTGbC8uyCA4AAQAAAaowDQYJYIZIAWUDBAIBBQCgggFKMBoGCSqGSIb3DQEJAzEN # BgsqhkiG9w0BCRABBDAvBgkqhkiG9w0BCQQxIgQgdvSYnHyAKqd6G27D/5PMuzMJ # +dbdexY8BCkwdkrbiugwgfoGCyqGSIb3DQEJEAIvMYHqMIHnMIHkMIG9BCBWtQJD # HFq8EeBz3TXugCqRhSI/JCZbATYEIwTG8bMewDCBmDCBgKR+MHwxCzAJBgNVBAYT # AlVTMRMwEQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYD # VQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xJjAkBgNVBAMTHU1pY3Jvc29mdCBU # aW1lLVN0YW1wIFBDQSAyMDEwAhMzAAABqqUxmwvLsggOAAEAAAGqMCIEIJHruQn2 # eJU7sQEphutB1gY+ak0Rh10Vlzf+NnbeTNzlMA0GCSqGSIb3DQEBCwUABIICAB/s # NiCNNMghL0B/OpS0mygGNuDi966E/sJWKpq5CxDwXuKg1M42rmxcBUr+J0VkJxpo # XjX8oFjh1Oq5OvPOUD6nvOKUrTTG/ZhVS67FBrxt0Y4WyRLIgpkKZDuaIhGYzz6s # ETE9fW4fp74GEjlQguG8G/ua5ngRrZjAsmb0seOJBMb/tR5spqqldtlzj622rU3q # hIvd6lB1T4ZPpEhT7bfp5EDZXOFfNZeyGawpdy5lsL3GB5QCQX+01Idipb/3LXFy # d54sbPGtca0jT0he7GDeHD+py/pAOtD7aFiVk4nRVJcUkv73FCSI9oyK9JLJwIHP # TzLEc5Luifw7VnkIiL/m9AeEUgvdLl1+mitZPKrP0ytnpbzSSNGS7B2LMQKvV5AQ # IF66s6YDxqQrWMI43WwsvWUJMCtX+sjK1CV9FjKvLmioOPAPqsFPYm5qS8pkGiGG # Qv6lIoE+qpHPttAirnD7hqVm8479lkQcbIytuihOpjskio2fVeNu+IJ8iOcHn4wx # L7OkHx+wEKjMiWioqFi2ZN7To3lZSguxQHLbUoM1VXhqSXD6iMurbxcExShaAq65 # Gw9Vd5DWt5H1dHtwelz+JGNK8aQCETj8U7dxxw1qGxix5NTugcFYU+NUFxF7wsNV # uwoulz/qyF0Y2MOSeDK5e/2WHf186KhfB5oEwBzi # SIG # End signature block |