Functions/Invoke-AnalyzeDeliveryOptimization.ps1

function Invoke-AnalyzeDeliveryOptimization {
    <#
    .Synopsis
    Analyzes current device regarding the possibility to use Delivery Optimization.
 
    .Description
    Delivery Optimization is the built-in feature to optimize data traffic and a lot of Microsoft products and services are using it. Therefore it's crucial, that you are aware of the status in your environment.
 
    Returns array of Messages with four properties:
 
    - Testname: Name of the Tets
    - Type: Information, Warning or Error
    - Issue: Description of the issue
    - Possible Cause: Tips on how to solve the issue.
 
    .Example
    # Displays a deep analyisis of the currently found issues in the system.
    Invoke-AnalyzeDeliveryOptimization
 
    #>

    [alias("Invoke-AnalyzeDO")]
    param(
    )
    $possibleErrors = @()
    Write-Verbose "Checking Service Status"
    if((get-service "DoSvc").Status -ne "Running"){
        if((get-service "DoSvc").StartType -eq "Automatic"){
            $possibleErrors += New-AnalyzeResult -TestName "Service" -Type Error -Issue "The Delivery Optimization Service (DoSvc) is not running on the system." -PossibleCause "Try to to start it again `nStart-Service -Name DoSvc"
        } else {
            $possibleErrors += New-AnalyzeResult -TestName "Service" -Type Error -Issue "The Delivery Optimization Service (DoSvc) is not running on the system and the start type is not 'Automatic', therefore an administrator has changed this behavior." -PossibleCause "Chnage the startup type to automatic and start the service. `nSet-Service -Name DoSvc -StartupType Automatic`nStart-Service -Name DoSvc"
        }
    }

    Write-Verbose "Checking local Firewall"
    $FwProfiles = Get-NetFirewallProfile
    if($FwProfiles.Count -ne ($FwProfiles | Where-Object{$_.Enabled -eq $true}).Count){
        $possibleErrors += New-AnalyzeResult -TestName "Firewall" -Type Warning -Issue "Not all Windows Firewall profiles are enabled. Therefore, the other FIrewall related warnings can be incorrect, because the profile in the network you would like to use DO is disabled and therefore the firewall rules are not needed." -PossibleCause "Check if a Firewall Profile is used in your network or not. If not, then you can ignore the other Firewall related issues."
    }
    $FwRules = Get-NetFirewallRule @("DeliveryOptimization-UDP-In","DeliveryOptimization-TCP-In")
    if($FwRules.Count -ne 2){
        $possibleErrors += New-AnalyzeResult -TestName "Firewall" -Type Warning -Issue "Not all default Firewall Rules(DeliveryOptimization-UDP-In, DeliveryOptimization-TCP-In) regarding Delivery Optimization are found on your system." -PossibleCause "Perhaps you or another administrator has created custom rules and enabled them. These should allow incoming TCP/UDP 7680 connections on the peers. `n You can verify the connection to a peer by using the following command:`n Test-NetConnection -ComputerName %ipofpeer% -Port 7680"
    } else {
        if($FwRules[0].Profile -ne "Any"){
            $possibleErrors += New-AnalyzeResult -TestName "Firewall" -Type Warning -Issue "The rule $($FwRules[0].Name) is not aplied to all profiles(Public, Private, Domain)." -PossibleCause "Check if the you are using DO in a network which is not assigned to a profile where the rule is active($($FwRules[0].Profile))."
        }
        if($FwRules[1].Profile -ne "Any"){
            $possibleErrors += New-AnalyzeResult -TestName "Firewall" -Type Warning -Issue "The rule $($FwRules[1].Name) is not aplied to all profiles(Public, Private, Domain)." -PossibleCause "Check if the you are using DO in a network which is not assigned to a profile where the rule is active($($FwRules[1].Profile))."
        }
        if($FwRules[0].Action -ne "Allow"){
            $possibleErrors += New-AnalyzeResult -TestName "Firewall" -Type Warning -Issue "The rule $($FwRules[0].Name) does not Allow the Traffic." -PossibleCause "Change the Action to Allow in the rule."
        }
        if($FwRules[1].Action -ne "Allow"){
            $possibleErrors += New-AnalyzeResult -TestName "Firewall" -Type Warning -Issue "The rule $($FwRules[1].Name) does not Allow the Traffic." -PossibleCause "Change the Action to Allow in the rule."
        }
        if($FwRules[0].Direction -ne "Inbound"){
            $possibleErrors += New-AnalyzeResult -TestName "Firewall" -Type Warning -Issue "The rule $($FwRules[0].Name) does not target inbound traffic." -PossibleCause "Change the Direction to inbound in the rule."
        }
        if($FwRules[1].Direction -ne "Inbound"){
            $possibleErrors += New-AnalyzeResult -TestName "Firewall" -Type Warning -Issue "The rule $($FwRules[1].Name) does not target inbound traffic." -PossibleCause "Change the Direction to inbound in the rule."
        }
        if($FwRules[0].Enabled -ne $true){
            $possibleErrors += New-AnalyzeResult -TestName "Firewall" -Type Warning -Issue "The rule $($FwRules[0].Name) is not enabled." -PossibleCause "Enable the rule."
        }
        if($FwRules[1].Enabled -ne $true){
            $possibleErrors += New-AnalyzeResult -TestName "Firewall" -Type Warning -Issue "The rule $($FwRules[1].Name) is not enabled." -PossibleCause "Enable the rule."
        }
    }
    
    Write-Verbose "Conenctivity Tests to Delivery Optimization Service"
    $data = New-Object System.Collections.Generic.List[System.Collections.Hashtable]

    # https://docs.microsoft.com/en-us/windows/privacy/manage-windows-endpoints#windows-update
    $data.Add(@{ TestUrl = 'https://geo-prod.do.dsp.mp.microsoft.com'; UrlPattern = 'https://*.do.dsp.mp.microsoft.com'; ExpectedStatusCode = 403; Description = 'Updates for applications and the OS on Windows 10 1709 and later. Windows Update Delivery Optimization metadata, resiliency, and anti-corruption.'; PerformBluecoatLookup=$false; Verbose=$false }) # many different *-prod.do.dsp.mp.microsoft.com, but geo-prod.do.dsp.mp.microsoft.com is the most common one
    
    $results = New-Object System.Collections.Generic.List[pscustomobject]

    $data | ForEach-Object {
        $connectivity = Get-HttpConnectivity @_
        $results.Add($connectivity)
        if ($connectivity.Blocked -eq $true) {
            $possibleErrors += New-AnalyzeResult -TestName "Connectivity" -Type "Error" -Issue "Connection blocked `n $($connectivity)" -PossibleCause "Firewall is blocking connection to '$($connectivity.UnblockUrl)'. Delivery Optimization contacts a cloud service for a list of peers. This service uses HTTPS to *.do.dsp.mp.microsoft.com (communication to this service has to be allowed outbound to the Internet even if only local sharing is enabled)."
        }
        if ($connectivity.Resolved -eq $false) {
            $possibleErrors += New-AnalyzeResult -TestName "Connectivity" -Type "Error" -Issue "DNS name not resolved `n $($connectivity)" -PossibleCause "DNS server not correctly configured."
        }
        if ($connectivity.ExpectedStatusCode -notcontains $connectivity.ActualStatusCode) {
            if($connectivity.ActualStatusCode -eq 407){
                $Cause = "Keep in mind that the proxy has to be set in WinHTTP.`nWindows 1709 and newer: Set the proxy by using netsh or WPAD. --> https://docs.microsoft.com/en-us/windows/desktop/WinHttp/winhttp-autoproxy-support `nWindows 1709 and older: Set the proxy by using 'netsh winhttp set proxy ?' --> https://blogs.technet.microsoft.com/netgeeks/2018/06/19/winhttp-proxy-settings-deployed-by-gpo/ "
             } else {
                $Cause = "Interfering Proxy server can change HTTP status codes."
             }
            $possibleErrors += New-AnalyzeResult -TestName "Connectivity" -Type "Error" -Issue "Returned HTTP Status code '$($connectivity.ActualStatusCode)' is not expected '$($connectivity.ExpectedStatusCode)'`n $($connectivity)" -PossibleCause $Cause
        }
        if ($null -ne $connectivity.ServerCertificate -and $connectivity.ServerCertificate.HasError) {
            $possibleErrors += New-AnalyzeResult -TestName "Connectivity" -Type "Error" -Issue "Certificate Error when connecting to $($connectivity.TestUrl)`n $(($connectivity.ServerCertificate))" -PossibleCause "Interfering Proxy server can change Certificate or not the Root Certificate is not trusted."
        }
    }

    Write-Verbose "Checking Configuration (Policy)"
    $PolicyDODownloadMode = get-ItemPropertyValue HKLM:\SOFTWARE\Policies\Microsoft\Windows\DeliveryOptimization -Name DODownloadMode -ErrorAction SilentlyContinue
    if($null -ne $PolicyDODownloadMode -and @(1,2,3) -contains $PolicyDODownloadMode){
        $possibleErrors += New-AnalyzeResult -TestName "Configuration" -Type "Error" -Issue "A policy is disabling Delivery Optimization and enforce mode $PolicyDODownloadMode. 0=HTTP only, no peering. 1=HTTP blended with peering behind the same NAT. 2=HTTP blended with peering across a private group. Peering occurs on devices in the same Active Directory Site (if exist) or the same domain by default. When this option is selected, peering will cross NATs. To create a custom group use Group ID in combination with Mode 2. 3=HTTP blended with Internet Peering. 99=Simple download mode with no peering. Delivery Optimization downloads using HTTP only and does not attempt to contact the Delivery Optimization cloud services. 100=Bypass mode. Do not use Delivery Optimization and use BITS instead." -PossibleCause "Change the assigned GPO or the local GPO and switch to mode 1,2 or 3. You can find the setting in the following path in GPO: `nComputer Configuration > Policies > Administrative Templates > Windows Components > Delivery Optimization > Download Mode"
    }
    $ConfigDODownloadMode = get-ItemPropertyValue HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\DeliveryOptimization\Config -Name DODownloadMode -ErrorAction SilentlyContinue
    if($null -ne $ConfigDODownloadMode -and @(1,2,3) -contains $ConfigDODownloadMode){
        $possibleErrors += New-AnalyzeResult -TestName "Configuration" -Type "Error" -Issue "The Actual used configuration is disabling Delivery Optimization and uses mode $ConfigDODownloadMode. 0=HTTP only, no peering. 1=HTTP blended with peering behind the same NAT. 2=HTTP blended with peering across a private group. Peering occurs on devices in the same Active Directory Site (if exist) or the same domain by default. When this option is selected, peering will cross NATs. To create a custom group use Group ID in combination with Mode 2. 3=HTTP blended with Internet Peering. 99=Simple download mode with no peering. Delivery Optimization downloads using HTTP only and does not attempt to contact the Delivery Optimization cloud services. 100=Bypass mode. Do not use Delivery Optimization and use BITS instead." -PossibleCause "If you don't have any other warning regarding configuration from GPO or SettingsAppChange, then change the registry value to mode 1,2 or 3.`nHKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\DeliveryOptimization\Config `nValueName: DODownloadMode"
    }
    $UserSettingsDODownloadMode = get-ItemPropertyValue HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\DeliveryOptimization\Config -Name DODownloadMode -ErrorAction SilentlyContinue
    if($null -ne $UserSettingsDODownloadMode -and @(1,2,3) -contains $UserSettingsDODownloadMode){
        $possibleErrors += New-AnalyzeResult -TestName "Configuration" -Type "Error" -Issue "The user has disabled Delivery Optimization through the settings app and set mode $UserSettingsDODownloadMode. 0=HTTP only, no peering. 1=HTTP blended with peering behind the same NAT. 2=HTTP blended with peering across a private group. Peering occurs on devices in the same Active Directory Site (if exist) or the same domain by default. When this option is selected, peering will cross NATs. To create a custom group use Group ID in combination with Mode 2. 3=HTTP blended with Internet Peering. 99=Simple download mode with no peering. Delivery Optimization downloads using HTTP only and does not attempt to contact the Delivery Optimization cloud services. 100=Bypass mode. Do not use Delivery Optimization and use BITS instead." -PossibleCause "Open the Settings App and search for Delivery Optmization and enable it."
    }
    # No errors detected, return success message
    if ($possibleErrors.Count -eq 0) {
        $possibleErrors += New-AnalyzeResult -TestName "All" -Type Information -Issue "All tests went through successfully." -PossibleCause ""
    }

    return $possibleErrors
}
# SIG # Begin signature block
# MIIZwgYJKoZIhvcNAQcCoIIZszCCGa8CAQExCzAJBgUrDgMCGgUAMGkGCisGAQQB
# gjcCAQSgWzBZMDQGCisGAQQBgjcCAR4wJgIDAQAABBAfzDtgWUsITrck0sYpfvNR
# AgEAAgEAAgEAAgEAAgEAMCEwCQYFKw4DAhoFAAQUYmFz9XAFzoz3/OkMalUv6ygW
# McagghUDMIID7jCCA1egAwIBAgIQfpPr+3zGTlnqS5p31Ab8OzANBgkqhkiG9w0B
# AQUFADCBizELMAkGA1UEBhMCWkExFTATBgNVBAgTDFdlc3Rlcm4gQ2FwZTEUMBIG
# A1UEBxMLRHVyYmFudmlsbGUxDzANBgNVBAoTBlRoYXd0ZTEdMBsGA1UECxMUVGhh
# d3RlIENlcnRpZmljYXRpb24xHzAdBgNVBAMTFlRoYXd0ZSBUaW1lc3RhbXBpbmcg
# Q0EwHhcNMTIxMjIxMDAwMDAwWhcNMjAxMjMwMjM1OTU5WjBeMQswCQYDVQQGEwJV
# UzEdMBsGA1UEChMUU3ltYW50ZWMgQ29ycG9yYXRpb24xMDAuBgNVBAMTJ1N5bWFu
# dGVjIFRpbWUgU3RhbXBpbmcgU2VydmljZXMgQ0EgLSBHMjCCASIwDQYJKoZIhvcN
# AQEBBQADggEPADCCAQoCggEBALGss0lUS5ccEgrYJXmRIlcqb9y4JsRDc2vCvy5Q
# WvsUwnaOQwElQ7Sh4kX06Ld7w3TMIte0lAAC903tv7S3RCRrzV9FO9FEzkMScxeC
# i2m0K8uZHqxyGyZNcR+xMd37UWECU6aq9UksBXhFpS+JzueZ5/6M4lc/PcaS3Er4
# ezPkeQr78HWIQZz/xQNRmarXbJ+TaYdlKYOFwmAUxMjJOxTawIHwHw103pIiq8r3
# +3R8J+b3Sht/p8OeLa6K6qbmqicWfWH3mHERvOJQoUvlXfrlDqcsn6plINPYlujI
# fKVOSET/GeJEB5IL12iEgF1qeGRFzWBGflTBE3zFefHJwXECAwEAAaOB+jCB9zAd
# BgNVHQ4EFgQUX5r1blzMzHSa1N197z/b7EyALt0wMgYIKwYBBQUHAQEEJjAkMCIG
# CCsGAQUFBzABhhZodHRwOi8vb2NzcC50aGF3dGUuY29tMBIGA1UdEwEB/wQIMAYB
# Af8CAQAwPwYDVR0fBDgwNjA0oDKgMIYuaHR0cDovL2NybC50aGF3dGUuY29tL1Ro
# YXd0ZVRpbWVzdGFtcGluZ0NBLmNybDATBgNVHSUEDDAKBggrBgEFBQcDCDAOBgNV
# HQ8BAf8EBAMCAQYwKAYDVR0RBCEwH6QdMBsxGTAXBgNVBAMTEFRpbWVTdGFtcC0y
# MDQ4LTEwDQYJKoZIhvcNAQEFBQADgYEAAwmbj3nvf1kwqu9otfrjCR27T4IGXTdf
# plKfFo3qHJIJRG71betYfDDo+WmNI3MLEm9Hqa45EfgqsZuwGsOO61mWAK3ODE2y
# 0DGmCFwqevzieh1XTKhlGOl5QGIllm7HxzdqgyEIjkHq3dlXPx13SYcqFgZepjhq
# IhKjURmDfrYwggSjMIIDi6ADAgECAhAOz/Q4yP6/NW4E2GqYGxpQMA0GCSqGSIb3
# DQEBBQUAMF4xCzAJBgNVBAYTAlVTMR0wGwYDVQQKExRTeW1hbnRlYyBDb3Jwb3Jh
# dGlvbjEwMC4GA1UEAxMnU3ltYW50ZWMgVGltZSBTdGFtcGluZyBTZXJ2aWNlcyBD
# QSAtIEcyMB4XDTEyMTAxODAwMDAwMFoXDTIwMTIyOTIzNTk1OVowYjELMAkGA1UE
# BhMCVVMxHTAbBgNVBAoTFFN5bWFudGVjIENvcnBvcmF0aW9uMTQwMgYDVQQDEytT
# eW1hbnRlYyBUaW1lIFN0YW1waW5nIFNlcnZpY2VzIFNpZ25lciAtIEc0MIIBIjAN
# BgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAomMLOUS4uyOnREm7Dv+h8GEKU5Ow
# mNutLA9KxW7/hjxTVQ8VzgQ/K/2plpbZvmF5C1vJTIZ25eBDSyKV7sIrQ8Gf2Gi0
# jkBP7oU4uRHFI/JkWPAVMm9OV6GuiKQC1yoezUvh3WPVF4kyW7BemVqonShQDhfu
# ltthO0VRHc8SVguSR/yrrvZmPUescHLnkudfzRC5xINklBm9JYDh6NIipdC6Anqh
# d5NbZcPuF3S8QYYq3AhMjJKMkS2ed0QfaNaodHfbDlsyi1aLM73ZY8hJnTrFxeoz
# C9Lxoxv0i77Zs1eLO94Ep3oisiSuLsdwxb5OgyYI+wu9qU+ZCOEQKHKqzQIDAQAB
# o4IBVzCCAVMwDAYDVR0TAQH/BAIwADAWBgNVHSUBAf8EDDAKBggrBgEFBQcDCDAO
# BgNVHQ8BAf8EBAMCB4AwcwYIKwYBBQUHAQEEZzBlMCoGCCsGAQUFBzABhh5odHRw
# Oi8vdHMtb2NzcC53cy5zeW1hbnRlYy5jb20wNwYIKwYBBQUHMAKGK2h0dHA6Ly90
# cy1haWEud3Muc3ltYW50ZWMuY29tL3Rzcy1jYS1nMi5jZXIwPAYDVR0fBDUwMzAx
# oC+gLYYraHR0cDovL3RzLWNybC53cy5zeW1hbnRlYy5jb20vdHNzLWNhLWcyLmNy
# bDAoBgNVHREEITAfpB0wGzEZMBcGA1UEAxMQVGltZVN0YW1wLTIwNDgtMjAdBgNV
# HQ4EFgQURsZpow5KFB7VTNpSYxc/Xja8DeYwHwYDVR0jBBgwFoAUX5r1blzMzHSa
# 1N197z/b7EyALt0wDQYJKoZIhvcNAQEFBQADggEBAHg7tJEqAEzwj2IwN3ijhCcH
# bxiy3iXcoNSUA6qGTiWfmkADHN3O43nLIWgG2rYytG2/9CwmYzPkSWRtDebDZw73
# BaQ1bHyJFsbpst+y6d0gxnEPzZV03LZc3r03H0N45ni1zSgEIKOq8UvEiCmRDoDR
# EfzdXHZuT14ORUZBbg2w6jiasTraCXEQ/Bx5tIB7rGn0/Zy2DBYr8X9bCT2bW+IW
# yhOBbQAuOA2oKY8s4bL0WqkBrxWcLC9JG9siu8P+eJRRw4axgohd8D20UaF5Mysu
# e7ncIAkTcetqGVvP6KUwVyyJST+5z3/Jvz4iaGNTmr1pdKzFHTx/kuDDvBzYBHUw
# ggWtMIIElaADAgECAhAEP0tn9l4Sf9gdog2gb/SWMA0GCSqGSIb3DQEBBQUAMGUx
# CzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3
# dy5kaWdpY2VydC5jb20xJDAiBgNVBAMTG0RpZ2lDZXJ0IEVWIENvZGUgU2lnbmlu
# ZyBDQTAeFw0yMDAzMDYwMDAwMDBaFw0yMzAzMTUxMjAwMDBaMIHOMRMwEQYLKwYB
# BAGCNzwCAQMTAkNIMRowGAYLKwYBBAGCNzwCAQITCVNvbG90aHVybjEdMBsGA1UE
# DwwUUHJpdmF0ZSBPcmdhbml6YXRpb24xGDAWBgNVBAUTD0NIRS0zMTQuNjM5LjUy
# MzELMAkGA1UEBhMCQ0gxEjAQBgNVBAgTCVNvbG90aHVybjERMA8GA1UEBwwIRMOk
# bmlrZW4xFjAUBgNVBAoTDWJhc2VWSVNJT04gQUcxFjAUBgNVBAMTDWJhc2VWSVNJ
# T04gQUcwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCn0xZCT8yT681H
# ZVY8gtUlURKywy8Nfq8uiv/jJJU+/Tf4HHXXJzHo96ZFo/WOWMD3WMWRYRnpj95P
# ZbfLaF+ki/PURRhp9/oT/p5O3zTv4Jqnig7AOeIL5dt9W5Uij9rDOEZhmFpVT08K
# CKhMNMMu7MhBs+uHBlyQ70j5H2IjBjePtEDYcakbv1RNDK5hU+k2UqKZEQSaqt2+
# riewxS2R4RUvZJ5nRraf4pNYqDdem2H0vJ17zHsG+ZB0YFLk/P3i6r4tJEAksYAU
# kuJsFDt0Yz9xM2qmG2Rr4iw7AUTfE5Gx0NNWD/fMWFP/2sD3VkHA8Mz8PAokDfFz
# 21OqYrXPAgMBAAGjggHtMIIB6TAfBgNVHSMEGDAWgBStaQZw/IAbFrOpGJRrlAKG
# XvcnjDAdBgNVHQ4EFgQURdlk/2RkqKDvZs8sol0UhzmJTCowNwYDVR0RBDAwLqAs
# BggrBgEFBQcIA6AgMB4MHENILVNPTE9USFVSTi1DSEUtMzE0LjYzOS41MjMwDgYD
# VR0PAQH/BAQDAgeAMBMGA1UdJQQMMAoGCCsGAQUFBwMDMHMGA1UdHwRsMGowM6Ax
# oC+GLWh0dHA6Ly9jcmwzLmRpZ2ljZXJ0LmNvbS9FVkNvZGVTaWduaW5nLWcxLmNy
# bDAzoDGgL4YtaHR0cDovL2NybDQuZGlnaWNlcnQuY29tL0VWQ29kZVNpZ25pbmct
# ZzEuY3JsMEsGA1UdIAREMEIwNwYJYIZIAYb9bAMCMCowKAYIKwYBBQUHAgEWHGh0
# dHBzOi8vd3d3LmRpZ2ljZXJ0LmNvbS9DUFMwBwYFZ4EMAQMweQYIKwYBBQUHAQEE
# bTBrMCQGCCsGAQUFBzABhhhodHRwOi8vb2NzcC5kaWdpY2VydC5jb20wQwYIKwYB
# BQUHMAKGN2h0dHA6Ly9jYWNlcnRzLmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydEVWQ29k
# ZVNpZ25pbmdDQS5jcnQwDAYDVR0TAQH/BAIwADANBgkqhkiG9w0BAQUFAAOCAQEA
# GYerL9YA8gW4cx7nWEaDFpN2XnaY4+90Nl8gaj6aeQj6kwIfjWLWAzByDdVNvxSk
# rwXdfo3dkG5DNNI3wPR2SE2iyImDF6zXTThccBqkwE1x1Tb5qfhaA48jf18f8Jbv
# VgvtbZWXph1b+ALyD2911b34Qt6cYmolg19vkmWXZUADRjA11S3VHhhH4GLKeHoE
# 23jSSs69tQPNC1jdS+Rx6yO/Ya14UrDwOrJo1qSn2xTilf9s77mSxRJCpL8Cd1PU
# HPvugUFHLw9nqOQAMUb7cHdDUREs7Brvfcyo0qRx7lyKjIM1d0wGtiBz+8kQJcSC
# dK9S8HGSD3y4R1N++Y8gYTCCBrUwggWdoAMCAQICEA3Q4zdKyVvb+mtDSypI7AYw
# DQYJKoZIhvcNAQEFBQAwbDELMAkGA1UEBhMCVVMxFTATBgNVBAoTDERpZ2lDZXJ0
# IEluYzEZMBcGA1UECxMQd3d3LmRpZ2ljZXJ0LmNvbTErMCkGA1UEAxMiRGlnaUNl
# cnQgSGlnaCBBc3N1cmFuY2UgRVYgUm9vdCBDQTAeFw0xMjA0MTgxMjAwMDBaFw0y
# NzA0MTgxMjAwMDBaMGUxCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdpQ2VydCBJ
# bmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20xJDAiBgNVBAMTG0RpZ2lDZXJ0
# IEVWIENvZGUgU2lnbmluZyBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC
# ggEBALkGdBxdtCCqqSGoKkJGqyUgFyXLIo+QoqAxa4MFda+yDnwSSXtqhmSED4Pc
# ZLmxbhYFPhyVuefniG24YoGQedTd9eKW+cO1iCNXShrPcSnpCACPtZjjpzL9rC64
# 9JNT9Ao5Q5Gv1Wvo1J9GvY49q+L5K9TqAEBmJLfof7REdY14mq4xwTfPTh9b+EVK
# 1z/CyZIGZL7eBoqv0OiKsfAsiABvC9yFp0zLBr/WLioybilxr44i8w/Q2JhILagI
# y7aLI8Jj4LZz6299Jk+L9zQ9N4YMt3gn9MKG20NrWvg9PfTosGJWxufteKH7/Xpy
# TzJlxHzDxHegBDIy7Y8/r4bdftECAwEAAaOCA1gwggNUMBIGA1UdEwEB/wQIMAYB
# Af8CAQAwDgYDVR0PAQH/BAQDAgGGMBMGA1UdJQQMMAoGCCsGAQUFBwMDMH8GCCsG
# AQUFBwEBBHMwcTAkBggrBgEFBQcwAYYYaHR0cDovL29jc3AuZGlnaWNlcnQuY29t
# MEkGCCsGAQUFBzAChj1odHRwOi8vY2FjZXJ0cy5kaWdpY2VydC5jb20vRGlnaUNl
# cnRIaWdoQXNzdXJhbmNlRVZSb290Q0EuY3J0MIGPBgNVHR8EgYcwgYQwQKA+oDyG
# Omh0dHA6Ly9jcmwzLmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydEhpZ2hBc3N1cmFuY2VF
# VlJvb3RDQS5jcmwwQKA+oDyGOmh0dHA6Ly9jcmw0LmRpZ2ljZXJ0LmNvbS9EaWdp
# Q2VydEhpZ2hBc3N1cmFuY2VFVlJvb3RDQS5jcmwwggHEBgNVHSAEggG7MIIBtzCC
# AbMGCWCGSAGG/WwDAjCCAaQwOgYIKwYBBQUHAgEWLmh0dHA6Ly93d3cuZGlnaWNl
# cnQuY29tL3NzbC1jcHMtcmVwb3NpdG9yeS5odG0wggFkBggrBgEFBQcCAjCCAVYe
# ggFSAEEAbgB5ACAAdQBzAGUAIABvAGYAIAB0AGgAaQBzACAAQwBlAHIAdABpAGYA
# aQBjAGEAdABlACAAYwBvAG4AcwB0AGkAdAB1AHQAZQBzACAAYQBjAGMAZQBwAHQA
# YQBuAGMAZQAgAG8AZgAgAHQAaABlACAARABpAGcAaQBDAGUAcgB0ACAAQwBQAC8A
# QwBQAFMAIABhAG4AZAAgAHQAaABlACAAUgBlAGwAeQBpAG4AZwAgAFAAYQByAHQA
# eQAgAEEAZwByAGUAZQBtAGUAbgB0ACAAdwBoAGkAYwBoACAAbABpAG0AaQB0ACAA
# bABpAGEAYgBpAGwAaQB0AHkAIABhAG4AZAAgAGEAcgBlACAAaQBuAGMAbwByAHAA
# bwByAGEAdABlAGQAIABoAGUAcgBlAGkAbgAgAGIAeQAgAHIAZQBmAGUAcgBlAG4A
# YwBlAC4wHQYDVR0OBBYEFK1pBnD8gBsWs6kYlGuUAoZe9yeMMB8GA1UdIwQYMBaA
# FLE+w2kD+L9HAdSYJhoIAu9jZCvDMA0GCSqGSIb3DQEBBQUAA4IBAQCeW5Y6LhKI
# rKsBbaSfdeQBh6OlMte8uql+o9YUF/fCE2t8c48rauUPJllosI4lm2zv+myTkgjB
# Tc9FnpxG1h50oZsUo/oBL0qxAeFyQEgRE2i5Np2RS9fCORIQwcTcu2IUFCphXU84
# fGYfxhv/rb5Pf5Rbc0MAD01zt1HPDvZ3wFvNNIzZYxOqDmER1vKOJ/y0e7i5ESCR
# hnjqDtQo/yrVJDjoN7LslrufvEoWUOFev1F9I6Ayx8GUnnrJwCaizCWHoBJ+dJ8t
# jbHI54S+udHp3rtqTohzceEiOMskh+lzflGy/5jrTn4v4MoO+rNe0boFQqhIn4P2
# P8TKqN9ooFBhMYIEKTCCBCUCAQEweTBlMQswCQYDVQQGEwJVUzEVMBMGA1UEChMM
# RGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSQwIgYDVQQD
# ExtEaWdpQ2VydCBFViBDb2RlIFNpZ25pbmcgQ0ECEAQ/S2f2XhJ/2B2iDaBv9JYw
# CQYFKw4DAhoFAKB4MBgGCisGAQQBgjcCAQwxCjAIoAKAAKECgAAwGQYJKoZIhvcN
# AQkDMQwGCisGAQQBgjcCAQQwHAYKKwYBBAGCNwIBCzEOMAwGCisGAQQBgjcCARUw
# IwYJKoZIhvcNAQkEMRYEFJTa3JjwCmZlTk0wGMQAfwq7lxkDMA0GCSqGSIb3DQEB
# AQUABIIBAI/QC7Fw57yv7wbyyG4InGjfav/0pKS9oPVw5kpRDwKrVDCiuUvI19ce
# QvbIvqvHp772UtojFHi8AHe6CIJB2IhL44DecMrI062C7eXtY4gugS/VFsQ8n6oP
# cBKq9VCKY61dGEKstd8QyIBaLXDvyqsjakYlkwvcBda4Ncn6o+Fyjk35pJc6PRGG
# c8Bn8Rsxd5WstYr7LGVKFYSAAW6lpl4nOR98WR5QmInv6LIbCKz1E98Vmh6Iv3Z+
# RNoAQORurw9r58OnLYWEfbZRqusAFZ82l1QRca/AS+93K2nuAnHvfVCzSd8ubqgm
# czVLETNyGNuknG7d8jxcG9tcpyAzKdGhggILMIICBwYJKoZIhvcNAQkGMYIB+DCC
# AfQCAQEwcjBeMQswCQYDVQQGEwJVUzEdMBsGA1UEChMUU3ltYW50ZWMgQ29ycG9y
# YXRpb24xMDAuBgNVBAMTJ1N5bWFudGVjIFRpbWUgU3RhbXBpbmcgU2VydmljZXMg
# Q0EgLSBHMgIQDs/0OMj+vzVuBNhqmBsaUDAJBgUrDgMCGgUAoF0wGAYJKoZIhvcN
# AQkDMQsGCSqGSIb3DQEHATAcBgkqhkiG9w0BCQUxDxcNMjAwNjAyMDUyMDMxWjAj
# BgkqhkiG9w0BCQQxFgQU0sZoqH9SoWd+JNOolwn0vVGajC8wDQYJKoZIhvcNAQEB
# BQAEggEABgWxZdVTjzCXybsxhZPOUwwkVikKEpvNjHWHMDc76mfHyQvbVhY7DYqY
# zKo1C5cPG2cjZP1QuhQrywGtmgvFL9Xu91cN6Y7JRBFAeXMjdMrp8Lw9i3qSL8YQ
# SP49B0/hl8OLpxqWy5ENW/4gxVJMD0s1fMjsssfDgTy9lMvWsGI/EBKuKwxxALxA
# BBG0u9m5Yaf79X/640liOE4YBZvGwXKx0D2Pf4AH3jNqRnPIPzZ/S4z38Cjk4Bcr
# Nf4+ZwR5aQHoUoFCFi3yVTB8Z+VVzuJOy1w5I690fEyT+5Uww9CVKuL+QhuCFjc8
# oDv0cPQPJlEVBX2+SEPAxGGbxRFGxg==
# SIG # End signature block