modules/AzStack.KnownIssues/AzStackBase/AzStack.Base.Network.psm1

#################################################################
# #
# Copyright (C) Microsoft Corporation. All rights reserved. #
# #
#################################################################

# we are only using en-US for now.
Import-LocalizedData -BindingVariable 'msg' -BaseDirectory "$PSScriptRoot\locale" -UICulture (Get-Culture)

# imports.
Import-Module $PSScriptRoot\..\..\AzStack.Core\AzStack.Core.psm1 -WarningAction SilentlyContinue
Import-Module $PSScriptRoot\..\..\AzStack.Common\AzStack.Common.psm1 -WarningAction SilentlyContinue

function Invoke-AzureStackHCINetworkValidation {
    $nodes = Get-ClusterNode

    $checkConnectivity = Start-DiagnosticCheck -ComputerNames $nodes -DiagCheck {
        param (
            $clusterNodes
        )

        # Validate that we have a multichannel connection for at least every node in the cluster for SBL and CSV
        function Get-MultichannelConnectionCount {
            param(
                $connection
            )
            $count = 0

            foreach($conn in $connection) {
                $count++
            }

            return $count
        }

        $connSBL = Get-SmbMultichannelConnection -SmbInstance SBL
        $connCSV = Get-SmbMultichannelConnection -SmbInstance CSV

        $connSBLCount = Get-MultichannelConnectionCount -connection $connSBL
        $connCSVCount = Get-MultichannelConnectionCount -connection $connCSV

        $connSBLState = $false
        $connCSVState = $false
        $netAtcServiceState = $false

        if($connSBLCount -ge ($clusterNodes.Count -1 ) ) {$connSBLState = $true}
        if($connCSVCount -ge ($clusterNodes.Count -1 ) ) {$connCSVState = $true}

        # Validate NetworkATC service state
        $netAtcService = Get-Service -Name "NetworkATC"
        if($netAtcService.Status -eq "Running") {$netAtcServiceState = $true}

        # Get Storage Net Adapter values
        $intent = Get-NetIntent | Where-Object {$_.IsStorageIntentSet -eq $true}
        $netAdapterPropertyList = @()

        if($intent.Count -gt 1) { $netAdapterPropertyList = $false }

        $adapterNames = $intent.NetAdapterNamesAsList
        foreach($adapterName in $adapterNames) {
            $advancedProperties = Get-NetAdapterAdvancedProperty -Name $adapterName

            $isJumboFramesEnabled = $false
            $isSendBuffersConfigured = $false
            $isReceiveBuffersConfigured = $false

            $jumboFrameData = ($advancedProperties | Where-Object {$_.RegistryKeyword -eq "*JumboPacket"}).RegistryValue
            $sendBufferData = ($advancedProperties | Where-Object {$_.RegistryKeyword -eq "SendBufferSize"}).RegistryValue
            $recieveBufferData = ($advancedProperties | Where-Object {$_.RegistryKeyword -eq "ReceiveBufferSize"}).RegistryValue

            if($jumboFrameData -gt 1514) {$isJumboFramesEnabled = $true}
            if($sendBufferData -ge 1024) {$isSendBuffersConfigured = $true}
            if($recieveBufferData -ge 1024) {$isReceiveBuffersConfigured = $true}


            $netAdapterPropertyList += @{
                "adapterName" = $adapterName
                "isJumboFramesEnabled" = $isJumboFramesEnabled
                "isSendBuffersConfigured" = $isSendBuffersConfigured
                "isReceiveBuffersConfigured" = $isReceiveBuffersConfigured
            }
        }

        return @{
            "netAtcServiceState" = $netAtcServiceState
            "sblConState" = $connSBLState
            "csvConState" = $connCSVState
            "netAdapter" = $netAdapterPropertyList
        }
    } -ArgumentList @($nodes)

    $netIntent = Get-NetIntent
    $netIntentStatus = Get-NetIntentStatus
    $clusNetStatus = Get-ClusterNetwork | Where-Object {$_.State -ne "Up"}

    # Overview of network intents
    Write-Host "====[ $($msg.netAtcOverview) ]====" -ForegroundColor White -BackgroundColor DarkGray
    $netIntent | Select-Object -Property IntentName,IntentType,IsComputeIntentSet,IsStorageIntentSet,IsManagementIntentSet,IsStretchIntentSet | Format-Table -AutoSize

    # Overview of network intent state
    Write-Host "====[ $($msg.checkNetAtcStatus) ]====" -ForegroundColor White -BackgroundColor DarkGray
    Get-NetAtcState -netIntentStatus $netIntentStatus

    # Overview of cluster
    Write-Host "====[ $($msg.checkClusterNetwork) ]====" -ForegroundColor White -BackgroundColor DarkGray
    if($null -ne $clusNetStatus) {
        Trace-CheckResult `
                -checkName $msg.checkClusterNetworkTitle `
                -checkState:Fail `
                -desc $msg.checkClusterNetworkDesc `
                -details $msg.checkClusterNetworkFail `
                -url $msg.checkClusterNetworkUrl
    } else {
        Trace-CheckResult `
                -checkName $msg.checkClusterNetworkTitle `
                -checkState:Pass `
                -desc $msg.checkClusterNetworkDesc
    }


    $data = Reconcile-DiagnosticCheck -jobs $checkConnectivity
    foreach($nodeData in $data) {
        Write-Host "====[ $($msg.checkPerNodeData -f $nodeData.name) ]====" -ForegroundColor White -BackgroundColor DarkGray

        # validate network atc service
        if($nodeData.output.netAtcServiceState -ne $true) {
            Trace-CheckResult `
                -checkName $msg.checkPerNodeDataAtcServiceTitle `
                -checkState:Fail `
                -desc $msg.checkPerNodeDataAtcServiceDesc `
                -details $msg.checkPerNodeDataAtcServiceFail `
                -url $msg.checkPerNodeDataAtcServiceUrl
        } else {
            Trace-CheckResult `
                -checkName $msg.checkPerNodeDataAtcServiceTitle `
                -checkState:Pass `
                -desc $msg.checkPerNodeDataAtcServiceDesc
        }

        # validate Multichannel connections
        if($nodeData.output.sblConState -ne $true) {
            Trace-CheckResult `
                -checkName $msg.checkPerNodeDataMultiConSblTitle `
                -checkState:Fail `
                -desc $msg.checkPerNodeDataMultiConSblDesc `
                -details $msg.checkPerNodeDataMultiConSblFail `
                -url $msg.checkPerNodeDataMultiConSblTitleUrl
        } else {
            Trace-CheckResult `
                -checkName $msg.checkPerNodeDataMultiConSblTitle `
                -checkState:Pass `
                -desc $msg.checkPerNodeDataMultiConSblDesc `
                -details $msg.checkPerNodeDataMultiConSblFail
        }

        # validate multichannel connections csv
        if($nodeData.output.csvConState -ne $true) {
            Trace-CheckResult `
                -checkName $msg.checkPerNodeDataMultiConCsvTitle `
                -checkState:Fail `
                -desc $msg.checkPerNodeDataMultiConCsvDesc `
                -details $msg.checkPerNodeDataMultiConCsvFail `
                -url $msg.checkPerNodeDataMultiConCsvTitleUrl
        } else {
            Trace-CheckResult `
                -checkName $msg.checkPerNodeDataMultiConCsvTitle `
                -checkState:Pass `
                -desc $msg.checkPerNodeDataMultiConCsvDesc `
                -details $msg.checkPerNodeDataMultiConCsvFail
        }

        #validate storage net adapters
        if($nodeData.output.netAdapter -ne $false) {
            foreach($netAdapter in $nodeData.output.netAdapter) {
                # Check Jumboframes
                if($netAdapter.isJumboFramesEnabled -ne $true) {
                    Trace-CheckResult `
                        -checkName $msg.checkPerNodeDataNetJumboframesTitle `
                        -checkState:Fail `
                        -desc ($msg.checkPerNodeDataNetJumboframesDesc -f $netAdapter.adapterName) `
                        -details $msg.checkPerNodeDataNetJumboframesFail `
                        -url $msg.checkPerNodeDataNetJumboframesTitleUrl

                } else {
                    Trace-CheckResult `
                        -checkName $msg.checkPerNodeDataNetJumboframesTitle `
                        -checkState:Pass `
                        -desc ($msg.checkPerNodeDataNetJumboframesDesc -f $netAdapter.adapterName)  `
                        -details $msg.checkPerNodeDataNetJumboframesFail
                }

                # Check Send Buffers
                if($netAdapter.isSendBuffersConfigured -ne $true) {
                    Trace-CheckResult `
                        -checkName $msg.checkPerNodeDataNetSendBuffersTitle `
                        -checkState:Warning `
                        -desc ($msg.checkPerNodeDataNetSendBuffersDesc -f $netAdapter.adapterName) `
                        -details $msg.checkPerNodeDataNetSendBuffersFail
                } else {
                    Trace-CheckResult `
                        -checkName $msg.checkPerNodeDataNetSendBuffersTitle `
                        -checkState:Pass `
                        -desc ($msg.checkPerNodeDataNetSendBuffersDesc -f $netAdapter.adapterName)
                }

                # Check Receive Buffers
                if($netAdapter.isReceiveBuffersConfigured -ne $true) {
                    Trace-CheckResult `
                        -checkName $msg.checkPerNodeDataNetReceiveBuffersTitle `
                        -checkState:Warning `
                        -desc ($msg.checkPerNodeDataNetReceiveBuffersDesc -f $netAdapter.adapterName) `
                        -details $msg.checkPerNodeDataNetReceiveBuffersFail
                } else {
                    Trace-CheckResult `
                        -checkName $msg.checkPerNodeDataNetReceiveBuffersTitle `
                        -checkState:Pass `
                        -desc ($msg.checkPerNodeDataNetReceiveBuffersDesc -f $netAdapter.adapterName)
                }
            }
        } else {
            Trace-Output -Level:Warning -Message $msg.checkPerNodeDataNetNoNetworkData
        }
    }
}

function Get-NetAtcState() {
    param($netIntentStatus)

    # we repeat this check for all net intents
    foreach($netIntent in $netIntentStatus) {
        if($netIntent.ConfigurationStatus -ne "Success" -OR $netIntent.ProvisioningStatus -ne "Completed" -OR $netIntent.Error -ne "") {
            # Faulty net intent state found
            Trace-CheckResult `
                -checkName $msg.checkNetAtcStatusTitle `
                -checkState:Fail `
                -desc ($msg.checkNetAtcStatusDesc -f $netIntent.IntentName, $netIntent.Host) `
                -details ($msg.checkNetAtcStatusFail -f $netIntent.IntentName, $netIntent.Host) `
                -url $msg.checkNetAtcStatusUrl
        } else {
            Trace-CheckResult `
                -checkName $msg.checkNetAtcStatusTitle `
                -checkState:Pass `
                -desc ($msg.checkNetAtcStatusDesc -f $netIntent.IntentName, $netIntent.Host)
        }
    }

}

# SIG # Begin signature block
# MIInbgYJKoZIhvcNAQcCoIInXzCCJ1sCAQExDzANBglghkgBZQMEAgEFADB5Bgor
# BgEEAYI3AgEEoGswaTA0BgorBgEEAYI3AgEeMCYCAwEAAAQQH8w7YFlLCE63JNLG
# KX7zUQIBAAIBAAIBAAIBAAIBADAxMA0GCWCGSAFlAwQCAQUABCBtS8NnVyBKf8tH
# 9ToQ2vc4G3U5lClAmEtSkUTh49bMQ6CCDMkwggYEMIID7KADAgECAhMzAAACHPrN
# xZvoL37EAAAAAAIcMA0GCSqGSIb3DQEBCwUAMFcxCzAJBgNVBAYTAlVTMR4wHAYD
# VQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xKDAmBgNVBAMTH01pY3Jvc29mdCBD
# b2RlIFNpZ25pbmcgUENBIDIwMjQwHhcNMjYwNDE2MTg1OTQxWhcNMjcwNDE1MTg1
# OTQxWjB0MQswCQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UE
# BxMHUmVkbW9uZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMR4wHAYD
# VQQDExVNaWNyb3NvZnQgQ29ycG9yYXRpb24wggEiMA0GCSqGSIb3DQEBAQUAA4IB
# DwAwggEKAoIBAQDVsZfgOKmM31HPfoWOoNEiw0SlCiIxUMC0I9NMWbucKOw/e9lP
# oAoehQVu6SG65V4EPzrYsnBnFPNoi4/HoOdjhz1qkrEt4I6tEcxXU6oOeY9zGveC
# /3iBeuhLYxM3M/PkcUoebF+Nednm8OkdSPoDu8imViHPQq/8CQUu0WRR4rE+dMRf
# rpVqfmNi2qWCX94T4MsepijGVkwE//tJg0ryAiYdHT34LSnlG/RSBZmQRGWZ5g8j
# qnKjRParSqMft1gvjuUTVgtWNZfgcLFSK5Wa0myrq8OPcgTGGsRgun+tnSS+IxDT
# xVsAPH1OzvPjwomguByhUe/OcvUN0D5Wmp7xAgMBAAGjggGqMIIBpjAOBgNVHQ8B
# Af8EBAMCB4AwHwYDVR0lBBgwFgYKKwYBBAGCN0wIAQYIKwYBBQUHAwMwHQYDVR0O
# BBYEFNoH7a2YDjOSwpkp6DHcmUS7J+0yMFQGA1UdEQRNMEukSTBHMS0wKwYDVQQL
# EyRNaWNyb3NvZnQgSXJlbGFuZCBPcGVyYXRpb25zIExpbWl0ZWQxFjAUBgNVBAUT
# DTIzMDAxMis1MDc1NjkwHwYDVR0jBBgwFoAUf1k/VCHarU/vBeXmo9ctBpQSCDEw
# YAYDVR0fBFkwVzBVoFOgUYZPaHR0cDovL3d3dy5taWNyb3NvZnQuY29tL3BraW9w
# cy9jcmwvTWljcm9zb2Z0JTIwQ29kZSUyMFNpZ25pbmclMjBQQ0ElMjAyMDI0LmNy
# bDBtBggrBgEFBQcBAQRhMF8wXQYIKwYBBQUHMAKGUWh0dHA6Ly93d3cubWljcm9z
# b2Z0LmNvbS9wa2lvcHMvY2VydHMvTWljcm9zb2Z0JTIwQ29kZSUyMFNpZ25pbmcl
# MjBQQ0ElMjAyMDI0LmNydDAMBgNVHRMBAf8EAjAAMA0GCSqGSIb3DQEBCwUAA4IC
# AQAUnEqhaRXe0T3hIJjvdQErEkrA/7bByjn6t5IArODkkRjzkYwtKMc2yYj2quaN
# rLutWw2YZcngKPy1b71YyDJQTy4NDRwaSh9Tw5thrk3NmcPrAHia5vtcBJ1CgtKK
# 7mQbIcQ22d/N3813ayCDDFewu1+jsZmX+r/aTEqaOM4TVxVtRSkuCy8nAXKuChOK
# Li/zA4XuH8iEYqIsj2YoNaeSxVmeGiERXpKdo3dDmYi0kO5w2D8VS4c3+9h6gElY
# BaAAg/dYErBg27qT3vv0zRDJhJufvCNylA8S7/+8H5E/PV5cng6na9VV/w9OV3qu
# uND6zdGa2EX38Glp50F9AIQk3p2xXmcvorDeM4XJ7UlWYBi6g80J1SSOQnInCYFE
# msfUNn3+1AaTJKSJL83quKArTac2pKhu0Yzzzrzo6HrsRiQKzpnRBb1/dMa6P3hz
# 75XbMRBctNsFhZC07WCmjExdLg2eHW5uV0TY8D5+6wozJf7vF3+WHkYPO85Z+BC6
# U4FkNbYNycZ9cE4j1tXRdyDCfml6c0HWPHjNVDObrv9lKt3qUqFpX38VCqVCyNOO
# 1UcXfQiVjJw32U2WUKZjt/neJKHEBsm9kFsLuWzkQ53+qcaSaytmsCnk2gOglrlD
# 5d3kKyvvAw+rzm0lT8K38P6PLxfZQHhu4W8dV7Av8N2ZmDCCBr0wggSloAMCAQIC
# EzMAAAA5O7Y3Gb8GHWcAAAAAADkwDQYJKoZIhvcNAQEMBQAwgYgxCzAJBgNVBAYT
# AlVTMRMwEQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYD
# VQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xMjAwBgNVBAMTKU1pY3Jvc29mdCBS
# b290IENlcnRpZmljYXRlIEF1dGhvcml0eSAyMDExMB4XDTI0MDgwODIwNTQxOFoX
# DTM2MDMyMjIyMTMwNFowVzELMAkGA1UEBhMCVVMxHjAcBgNVBAoTFU1pY3Jvc29m
# dCBDb3Jwb3JhdGlvbjEoMCYGA1UEAxMfTWljcm9zb2Z0IENvZGUgU2lnbmluZyBQ
# Q0EgMjAyNDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBANgBnB7jOMeq
# lRYHNa265v4IY9fH8TKhemHfPINe1gpLaV3dhg324WwH06LcHbpnsBukCDNitryo
# 0dtS/EW6I/yEL/bLSY8hKpbfQuWusBPr9qazYcDxCW/qnjb5JsI1s8bNOg3bVATv
# QVL4tcf03aTycsz8QeCdM0l/yHRObJ9QqazM1r6VPEOJ7LL+uEEb73w6QCuhs89a
# 1uv1zerOYMnsneRRwCbpyW11IcggU0cRKDDq1pjVJzIbIF6+oiXXbReOsgeI8zu1
# FyQfK0fVkaya8SmVHQ/tOf23mZ4W9k0Ri22QW9p3UgSC5OUDktKxxcCmGL6tXLfO
# GSWHIIV4YrTJTT6PNty5REojHJuZHArkF9VnHTERWoTjAzfI3kP+5b4alUdhgAZ7
# ttOu1bVnXfHaqPYl2rPs20ji03LOVWsh/radgE17es5hL+t6lV0eVHrVhsssROWJ
# uz2MXMCt7iw7lFPG9LXKGjsmonn2gotGdHIuEg5JnJMJVmixd5LRlkmgYRZKzhxS
# CwyoGIq0PhaA7Y+VPct5pCHkijcIIDm0nlkK+0KyepolcqGm0T/GYQRMhHJlGOOm
# VQop36wUVUYklUy++vDWeEgEo4s7hxN6mIbf2MSIQ/iIfMZgJxC69oukMUXCrOC3
# SkE/xIkgpfl22MM1itkZ35nNXkMolU1lAgMBAAGjggFOMIIBSjAOBgNVHQ8BAf8E
# BAMCAYYwEAYJKwYBBAGCNxUBBAMCAQAwHQYDVR0OBBYEFH9ZP1Qh2q1P7wXl5qPX
# LQaUEggxMBkGCSsGAQQBgjcUAgQMHgoAUwB1AGIAQwBBMA8GA1UdEwEB/wQFMAMB
# Af8wHwYDVR0jBBgwFoAUci06AjGQQ7kUBU7h6qfHMdEjiTQwWgYDVR0fBFMwUTBP
# oE2gS4ZJaHR0cDovL2NybC5taWNyb3NvZnQuY29tL3BraS9jcmwvcHJvZHVjdHMv
# TWljUm9vQ2VyQXV0MjAxMV8yMDExXzAzXzIyLmNybDBeBggrBgEFBQcBAQRSMFAw
# TgYIKwYBBQUHMAKGQmh0dHA6Ly93d3cubWljcm9zb2Z0LmNvbS9wa2kvY2VydHMv
# TWljUm9vQ2VyQXV0MjAxMV8yMDExXzAzXzIyLmNydDANBgkqhkiG9w0BAQwFAAOC
# AgEAFJQfOChP7onn6fLIMKrSlN1WYKwDFgAddymOUO3FrM8d7B/W/iQ6DxXsDn7D
# 5W4wMwYeLystcEqfkjz4NURRgazyMu5yRzQh4LqjA4tStTcJh1opExo7nn5PuPBY
# nbu0+THSuVHTe0VTTPVhily/piFrDo3axQ9P4C+Ol5yet+2gTfekICS5xS+cYfSI
# vgn0JksVBVMYVI5QFu/qhnLhsEFEUzG8fvv0hjgkO+lkpV9ty6GkN4vdnd7ya6Q6
# aR9y34aiM1qmxaxBi6OUnyNl6fkuun/diTFnYDLTppOkr/mg5WSfCiDVMNCxtj4w
# PKC5OmHm1DQIt/MNokbbH3UGsFP1QbzsLocuSqLCvH09Io3fDPTmscR9Y75G4qX7
# RTX8AdBPo0I6OEojf39zuFZt0qOHm65YWQE69cZM2ueE1MB05dNNgHK9gTE7zKvK
# /fg8B2qjW88MT/WF5V5uvZGtqa9FSL2RazArA+rDPuf6JGYz4HpgMZHB4S6szWSK
# YBv0VisCzfxgeU+dquXW9bd0auYlOB58DPcOYKdc3Se94g+xL4pcEhbB54JOgAkw
# YTu/9dLeH2pDqeJZAABVDWRQCaXfO5LgyKwKCLYXpigrZYCjUSBcr+Ve8PFWMhVT
# Ql0v4q8J/AUmQN5W4n101cY2L4A7GTQG1h32HHAvfQESWP0xghn7MIIZ9wIBATBu
# MFcxCzAJBgNVBAYTAlVTMR4wHAYDVQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24x
# KDAmBgNVBAMTH01pY3Jvc29mdCBDb2RlIFNpZ25pbmcgUENBIDIwMjQCEzMAAAIc
# +s3Fm+gvfsQAAAAAAhwwDQYJYIZIAWUDBAIBBQCgga4wGQYJKoZIhvcNAQkDMQwG
# CisGAQQBgjcCAQQwHAYKKwYBBAGCNwIBCzEOMAwGCisGAQQBgjcCARUwLwYJKoZI
# hvcNAQkEMSIEIE9kAiHE6mQxlF+a7GNTPCO9ZfO+jII65yiYn6xmJYvhMEIGCisG
# AQQBgjcCAQwxNDAyoBSAEgBNAGkAYwByAG8AcwBvAGYAdKEagBhodHRwOi8vd3d3
# Lm1pY3Jvc29mdC5jb20wDQYJKoZIhvcNAQEBBQAEggEAn2YoloFQ85t2rn9xsOxe
# 8rzek1BVRxAhQJ6ymjxVOoNAWXbWYjltmpBGpVIiREl3yRJASi+apakkxWPWzgZv
# x0fNXK3LhSRH3mn+xbxKa5Jb5LD7J8UOK0AIhoq6G2akkH4X7nTBWPzzcdL5+Sj8
# /gAV4Be4xVuZHkMRGVL3JGFeUHmuyzdKOJ4Kq/1IuJIHFt7HtHSkopX/J4YVcv8+
# ACt8nR9W/j9hi+P/CMWVTPexs9RCcqqiruQ/N/qAuJk0JL/yfTlzxipuIUWvOGp3
# EykpSvmtZxZs48plgG3uohocDCfza6NCYP60LbVz1idPZ8xEgPt2JLwIaCKL2A6h
# A6GCF60wghepBgorBgEEAYI3AwMBMYIXmTCCF5UGCSqGSIb3DQEHAqCCF4YwgheC
# AgEDMQ8wDQYJYIZIAWUDBAIBBQAwggFaBgsqhkiG9w0BCRABBKCCAUkEggFFMIIB
# QQIBAQYKKwYBBAGEWQoDATAxMA0GCWCGSAFlAwQCAQUABCC2OewCEQpN7luowtns
# VAuV6ZJyPZ3FCLut3306UOcY6AIGaeuhgQRMGBMyMDI2MDUyMjE1MzcyMi41NzRa
# MASAAgH0oIHZpIHWMIHTMQswCQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3Rv
# bjEQMA4GA1UEBxMHUmVkbW9uZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0
# aW9uMS0wKwYDVQQLEyRNaWNyb3NvZnQgSXJlbGFuZCBPcGVyYXRpb25zIExpbWl0
# ZWQxJzAlBgNVBAsTHm5TaGllbGQgVFNTIEVTTjoyQTFBLTA1RTAtRDk0NzElMCMG
# A1UEAxMcTWljcm9zb2Z0IFRpbWUtU3RhbXAgU2VydmljZaCCEfswggcoMIIFEKAD
# AgECAhMzAAACEKvN5BYY7zmwAAEAAAIQMA0GCSqGSIb3DQEBCwUAMHwxCzAJBgNV
# BAYTAlVTMRMwEQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4w
# HAYDVQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xJjAkBgNVBAMTHU1pY3Jvc29m
# dCBUaW1lLVN0YW1wIFBDQSAyMDEwMB4XDTI1MDgxNDE4NDgxMloXDTI2MTExMzE4
# NDgxMlowgdMxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYD
# VQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xLTAr
# BgNVBAsTJE1pY3Jvc29mdCBJcmVsYW5kIE9wZXJhdGlvbnMgTGltaXRlZDEnMCUG
# A1UECxMeblNoaWVsZCBUU1MgRVNOOjJBMUEtMDVFMC1EOTQ3MSUwIwYDVQQDExxN
# aWNyb3NvZnQgVGltZS1TdGFtcCBTZXJ2aWNlMIICIjANBgkqhkiG9w0BAQEFAAOC
# Ag8AMIICCgKCAgEAjcc4q057ZwIgpKu4pTXWLejvYEduRf+1mIpbiJEMFWWmU2xp
# ip+zK7xFxKGB1CclUXBU0/ZQZ6LG8H0gI7yvosrsPEI1DPB/XccGCvswKbAKckng
# OuGTEPGk7K/vEZa9h0Xt02b7m2n9MdIjkLrFl0pDriKyz0QHGpdh93X6+NApfE1T
# L24Vo0xkeoFGpL3rX9gXhIOF59EMnTd2o45FW/oxMgY9q0y0jGO0HrCLTCZr50e7
# TZRSNYAy2lyKbvKI2MKlN1wLzJvZbbc//L3s1q3J6KhS0KC2VNEImYdFgVkJej4z
# ZqHfScTbx9hjFgFpVkJl4xH5VJ8tyJdXE9+vU0k9AaT2QP1Zm3WQmXedSoLjjI7L
# WznuHwnoGIXLiJMQzPqKqRIFL3wzcrDrZeWgtAdBPbipglZ5CQns6Baj5Mb6a/EZ
# C9G3faJYK5QVHeE6eLoSEwp1dz5WurLXNPsp0VWplpl/FJb8jrRT/jOoHu85qRcd
# YpgByU9W7IWPdrthmyfqeAw0omVWN5JxcogYbLo2pANJHlsMdWnxIpN5YwHbGEPC
# uosBHPk2Xd9+E/pZPQUR6v+D85eEN5A/ZM/xiPpxa8dJZ87BpTvui7/2uflUMJf2
# Yc9ZLPgEdhQQo0LwMDSTDT48y3sV7Pdo+g5q+MqnJztN/6qt1cgUTe9u+ykCAwEA
# AaOCAUkwggFFMB0GA1UdDgQWBBSe42+FrpdF2avbUhlk86BLSH5kejAfBgNVHSME
# GDAWgBSfpxVdAF5iXYP05dJlpxtTNRnpcjBfBgNVHR8EWDBWMFSgUqBQhk5odHRw
# Oi8vd3d3Lm1pY3Jvc29mdC5jb20vcGtpb3BzL2NybC9NaWNyb3NvZnQlMjBUaW1l
# LVN0YW1wJTIwUENBJTIwMjAxMCgxKS5jcmwwbAYIKwYBBQUHAQEEYDBeMFwGCCsG
# AQUFBzAChlBodHRwOi8vd3d3Lm1pY3Jvc29mdC5jb20vcGtpb3BzL2NlcnRzL01p
# Y3Jvc29mdCUyMFRpbWUtU3RhbXAlMjBQQ0ElMjAyMDEwKDEpLmNydDAMBgNVHRMB
# Af8EAjAAMBYGA1UdJQEB/wQMMAoGCCsGAQUFBwMIMA4GA1UdDwEB/wQEAwIHgDAN
# BgkqhkiG9w0BAQsFAAOCAgEAvs4rO3oo8czOrxPqnnSEkUVq718QzlrIiy7/EW7J
# mQXsJoFxHWUF0Ux0PDyKFDRXPJVv29F7kpJkBJJmcQg5HQV7blUXIMWQ1qX0KdtF
# QXI/MRL77Z+pK5x1jX+tbRkA7a5Ft7vWuRoAEi02HpFH5m/Akh/dfsbx8wOpecJb
# YvuHuy4aG0/tGzOWFCxMMNhGAIJ4qdV87JnY/uMBmiodlm+Gz357XWW5tg3HrtNZ
# XuQ0tWUv26ud4nGKJo/oLZHP75p4Rpt7dMdYKUF9AuVFBwxYZYpvgk12tfK+/yOw
# q84/fjXVCdM83Qnawtbenbk/lnbc9KsZom+GnvA4itAMUpSXFWrcRkqdUQLN+JrG
# 6fPBoV8+D8U2Q2F4XkiCR6EU9JzYKwTuvL6t3nFuxnkLdNjbTg2/yv2j3WaDuCK5
# lSPgsndIiH6Bku2Ui3A0aUo6D9z9v+XEuBs9ioVJaOjf/z+Urqg7ESnxG0/T1dKc
# i7vLQ2XNgWFYO+/OlDjtGoma1ijX4m14N9qgrXTuWEGwgC7hhBgp3id/LAOf9BST
# WA5lBrilsEoexXBrOn/1wM3rjG0hIsxvF5/YOK78mVRGY6Y7zYJ+uXt4OTOFBwad
# Pv8MklreQZLPnQPtiwop4rlLUYaPCiD4YUqRNbLp8Sgyo9g0iAcZYznTuc+8Q8ZI
# rgwwggdxMIIFWaADAgECAhMzAAAAFcXna54Cm0mZAAAAAAAVMA0GCSqGSIb3DQEB
# CwUAMIGIMQswCQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UE
# BxMHUmVkbW9uZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMTIwMAYD
# VQQDEylNaWNyb3NvZnQgUm9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkgMjAxMDAe
# Fw0yMTA5MzAxODIyMjVaFw0zMDA5MzAxODMyMjVaMHwxCzAJBgNVBAYTAlVTMRMw
# EQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVN
# aWNyb3NvZnQgQ29ycG9yYXRpb24xJjAkBgNVBAMTHU1pY3Jvc29mdCBUaW1lLVN0
# YW1wIFBDQSAyMDEwMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA5OGm
# TOe0ciELeaLL1yR5vQ7VgtP97pwHB9KpbE51yMo1V/YBf2xK4OK9uT4XYDP/XE/H
# ZveVU3Fa4n5KWv64NmeFRiMMtY0Tz3cywBAY6GB9alKDRLemjkZrBxTzxXb1hlDc
# wUTIcVxRMTegCjhuje3XD9gmU3w5YQJ6xKr9cmmvHaus9ja+NSZk2pg7uhp7M62A
# W36MEBydUv626GIl3GoPz130/o5Tz9bshVZN7928jaTjkY+yOSxRnOlwaQ3KNi1w
# jjHINSi947SHJMPgyY9+tVSP3PoFVZhtaDuaRr3tpK56KTesy+uDRedGbsoy1cCG
# MFxPLOJiss254o2I5JasAUq7vnGpF1tnYN74kpEeHT39IM9zfUGaRnXNxF803RKJ
# 1v2lIH1+/NmeRd+2ci/bfV+AutuqfjbsNkz2K26oElHovwUDo9Fzpk03dJQcNIIP
# 8BDyt0cY7afomXw/TNuvXsLz1dhzPUNOwTM5TI4CvEJoLhDqhFFG4tG9ahhaYQFz
# ymeiXtcodgLiMxhy16cg8ML6EgrXY28MyTZki1ugpoMhXV8wdJGUlNi5UPkLiWHz
# NgY1GIRH29wb0f2y1BzFa/ZcUlFdEtsluq9QBXpsxREdcu+N+VLEhReTwDwV2xo3
# xwgVGD94q0W29R6HXtqPnhZyacaue7e3PmriLq0CAwEAAaOCAd0wggHZMBIGCSsG
# AQQBgjcVAQQFAgMBAAEwIwYJKwYBBAGCNxUCBBYEFCqnUv5kxJq+gpE8RjUpzxD/
# LwTuMB0GA1UdDgQWBBSfpxVdAF5iXYP05dJlpxtTNRnpcjBcBgNVHSAEVTBTMFEG
# DCsGAQQBgjdMg30BATBBMD8GCCsGAQUFBwIBFjNodHRwOi8vd3d3Lm1pY3Jvc29m
# dC5jb20vcGtpb3BzL0RvY3MvUmVwb3NpdG9yeS5odG0wEwYDVR0lBAwwCgYIKwYB
# BQUHAwgwGQYJKwYBBAGCNxQCBAweCgBTAHUAYgBDAEEwCwYDVR0PBAQDAgGGMA8G
# A1UdEwEB/wQFMAMBAf8wHwYDVR0jBBgwFoAU1fZWy4/oolxiaNE9lJBb186aGMQw
# VgYDVR0fBE8wTTBLoEmgR4ZFaHR0cDovL2NybC5taWNyb3NvZnQuY29tL3BraS9j
# cmwvcHJvZHVjdHMvTWljUm9vQ2VyQXV0XzIwMTAtMDYtMjMuY3JsMFoGCCsGAQUF
# BwEBBE4wTDBKBggrBgEFBQcwAoY+aHR0cDovL3d3dy5taWNyb3NvZnQuY29tL3Br
# aS9jZXJ0cy9NaWNSb29DZXJBdXRfMjAxMC0wNi0yMy5jcnQwDQYJKoZIhvcNAQEL
# BQADggIBAJ1VffwqreEsH2cBMSRb4Z5yS/ypb+pcFLY+TkdkeLEGk5c9MTO1OdfC
# cTY/2mRsfNB1OW27DzHkwo/7bNGhlBgi7ulmZzpTTd2YurYeeNg2LpypglYAA7AF
# vonoaeC6Ce5732pvvinLbtg/SHUB2RjebYIM9W0jVOR4U3UkV7ndn/OOPcbzaN9l
# 9qRWqveVtihVJ9AkvUCgvxm2EhIRXT0n4ECWOKz3+SmJw7wXsFSFQrP8DJ6LGYnn
# 8AtqgcKBGUIZUnWKNsIdw2FzLixre24/LAl4FOmRsqlb30mjdAy87JGA0j3mSj5m
# O0+7hvoyGtmW9I/2kQH2zsZ0/fZMcm8Qq3UwxTSwethQ/gpY3UA8x1RtnWN0SCyx
# TkctwRQEcb9k+SS+c23Kjgm9swFXSVRk2XPXfx5bRAGOWhmRaw2fpCjcZxkoJLo4
# S5pu+yFUa2pFEUep8beuyOiJXk+d0tBMdrVXVAmxaQFEfnyhYWxz/gq77EFmPWn9
# y8FBSX5+k77L+DvktxW/tM4+pTFRhLy/AsGConsXHRWJjXD+57XQKBqJC4822rpM
# +Zv/Cuk0+CQ1ZyvgDbjmjJnW4SLq8CdCPSWU5nR0W2rRnj7tfqAxM328y+l7vzhw
# RNGQ8cirOoo6CGJ/2XBjU02N7oJtpQUQwXEGahC0HVUzWLOhcGbyoYIDVjCCAj4C
# AQEwggEBoYHZpIHWMIHTMQswCQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3Rv
# bjEQMA4GA1UEBxMHUmVkbW9uZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0
# aW9uMS0wKwYDVQQLEyRNaWNyb3NvZnQgSXJlbGFuZCBPcGVyYXRpb25zIExpbWl0
# ZWQxJzAlBgNVBAsTHm5TaGllbGQgVFNTIEVTTjoyQTFBLTA1RTAtRDk0NzElMCMG
# A1UEAxMcTWljcm9zb2Z0IFRpbWUtU3RhbXAgU2VydmljZaIjCgEBMAcGBSsOAwIa
# AxUAOsyf2b6riPKnnXlIgIL2f53PUsKggYMwgYCkfjB8MQswCQYDVQQGEwJVUzET
# MBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9uZDEeMBwGA1UEChMV
# TWljcm9zb2Z0IENvcnBvcmF0aW9uMSYwJAYDVQQDEx1NaWNyb3NvZnQgVGltZS1T
# dGFtcCBQQ0EgMjAxMDANBgkqhkiG9w0BAQsFAAIFAO26XzgwIhgPMjAyNjA1MjIw
# NDUxMDRaGA8yMDI2MDUyMzA0NTEwNFowdDA6BgorBgEEAYRZCgQBMSwwKjAKAgUA
# 7bpfOAIBADAHAgEAAgIWkzAHAgEAAgISojAKAgUA7buwuAIBADA2BgorBgEEAYRZ
# CgQCMSgwJjAMBgorBgEEAYRZCgMCoAowCAIBAAIDB6EgoQowCAIBAAIDAYagMA0G
# CSqGSIb3DQEBCwUAA4IBAQCKAPOyFilGeSyUiIsUqKMmG+gEY9phqPYpinJuLkCr
# 4l6Vb70c1P1rxBnxOo8No32eD3Vo9grr/H/EtWRzNBB1o1MLYHA+AR6hS6ow/9Nx
# au14r1jnZb6x9DXlC8TKLgv3yWoD959lB4Zwc1/twdPBsUNiHflCpiQ6nXuDjeYa
# SRoLbnOgCt/X5hjDbQ1XBuHZ/ZX7T6IKc0hVcQLf1MJT0eCXWs98Ng7fdHMJZSJV
# ct7DuFlwpCnb8XCKHt8uC7udnR8GLr/IzWoTq0cSUy5zFiMreaDYVdFmpgs562lt
# gfmFa83eHjVpsIbksINW2VjCxYY0OqrN6DlMQOyXgw+/MYIEDTCCBAkCAQEwgZMw
# fDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCldhc2hpbmd0b24xEDAOBgNVBAcTB1Jl
# ZG1vbmQxHjAcBgNVBAoTFU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjEmMCQGA1UEAxMd
# TWljcm9zb2Z0IFRpbWUtU3RhbXAgUENBIDIwMTACEzMAAAIQq83kFhjvObAAAQAA
# AhAwDQYJYIZIAWUDBAIBBQCgggFKMBoGCSqGSIb3DQEJAzENBgsqhkiG9w0BCRAB
# BDAvBgkqhkiG9w0BCQQxIgQgCENaQBAVY//vVOgM1iXodVa+EGOHmXqawb7Aw9Sj
# fswwgfoGCyqGSIb3DQEJEAIvMYHqMIHnMIHkMIG9BCDD1SHufsjzY59S1iHUQY9h
# nsKSrJPg5a9Mc4YnGmPHxjCBmDCBgKR+MHwxCzAJBgNVBAYTAlVTMRMwEQYDVQQI
# EwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNyb3Nv
# ZnQgQ29ycG9yYXRpb24xJjAkBgNVBAMTHU1pY3Jvc29mdCBUaW1lLVN0YW1wIFBD
# QSAyMDEwAhMzAAACEKvN5BYY7zmwAAEAAAIQMCIEILzH0lF/qStN3tdVvzZRHESH
# C55ORCKJml+/7bFBSBLqMA0GCSqGSIb3DQEBCwUABIICAH2WVZUFux8F9tUx7LGy
# RPxDPcMJa9Y7VTqHi0m+r0RYj96xnE2xGJVKnnDmhawR+8r3MWz/+uC1YtIAFxXc
# TerTEDNyvK4Z/LPAqrkFMYVgX7D8p4Kpk2e9QcRIVeVfgH3sVqcUjfxDcbXEIREG
# TfWThfGZym+5Rb+xNSKqmxBKzqmPUGgsrcnPgvqkIHqkmCT0jYuDZc8XCfV/dDy8
# gcOhwOPmMPFulJ4e7zM9XUrCEqdYXSrjn7ez2uBUGhriXYqbOgddcf45qpwO8voz
# oazi1329Tu9uGEWLp8h0TWupjQ9X67tN+EXDX/qyuunHDK0N6+q9WTJ2UslQLxkd
# 8w5+3uPuwB7BYTnwxjvJlaC3Kd59Ow7KX52LL+e8bbz6X+3H2f+RvbebRGnAkGew
# 7GuJVkP8F0ZSE+E7WNY9cKVGz8KguGOWfVTdFCmOcO1CqYbr6TH26b21xYMTFmyi
# G6FtGahwVZvL7HvwsteDlEiO2x60e6eYzWn9CkLmza3W+LTi+muA8gg2kcWJpydU
# 4o1yxkQIhLJ6w8WqJNmmD2XREQyPwt49YoaxwcVOwk33hEgBqWe50HZuxT4CS6jT
# Nx7s3/iin7psvg+5/LzNqYJOEOd4CVcV5+cuh3F7RVtc23hvGrr/okijYnpC8pq+
# kgln6xCTtU7iSrmfq/pfIYaH
# SIG # End signature block