Integrity.Tests.ps1

<#
.SYNOPSIS
    This script contains Pester tests for the integrity of the DSInternals PowerShell module.
 
.DESCRIPTION
    The script uses the Pester module to verify the integrity of the module's catalog file, manifest,
    scripts, and assemblies. It checks if all required files are present and digitally signed.
#>


#Requires -Version 5.1
#Requires -Modules @{ ModuleName = 'Pester'; ModuleVersion = '5.0' }

if ($env:OS -ne 'Windows_NT') {
    # The Get-AuthenticodeSignature cmdlet used to verify digital signatures is only available on Windows.
    Write-Error -Message 'The module integrity tests are only supported on Windows.' `
                -Category ([System.Management.Automation.ErrorCategory]::NotImplemented) `
                -ErrorAction Stop
}

Describe 'DSInternals PowerShell Module Integrity' {
    Context 'Catalog file' {
        BeforeAll {
            # Locate the catalog file DSInternals.cat in the module root directory.
            [string] $catalogFilePath = Join-Path -Path $PSScriptRoot -ChildPath 'DSInternals.cat'
        }

        It 'should exist' {
            # Check if the catalog file DSInternals.cat is present in the module root directory.
            $catalogFilePath | Should -Exist
        }

        It 'should be valid' {
            # Check the directory structure against the catalog file.
            # Skip the PowerShell Gallery metadata file (PSGetModuleInfo.xml), as it is dynamically generated and cannot be verified.
            [string] $powerShellGetFile = Join-Path -Path $PSScriptRoot -ChildPath 'PSGetModuleInfo.xml'
            Test-FileCatalog -CatalogFilePath $catalogFilePath -Path $PSScriptRoot -FilesToSkip $powerShellGetFile -ErrorAction Stop | Should -Be 'Valid'
        }

        It 'should be digitally signed' {
            # Check that the catalog file DSInternals.cat is digitally signed.
            Get-AuthenticodeSignature -FilePath $catalogFilePath -ErrorAction Stop |
                Select-Object -ExpandProperty Status |
                Should -Be 'Valid'
        }
    }

    Context 'Module manifest' {
        BeforeAll {
            # LOcate the module manifest file DSInternals.psd1 in the module root directory.
            [string] $moduleManifestPath = Join-Path -Path $PSScriptRoot -ChildPath 'DSInternals.psd1' -ErrorAction Stop
        }

        It 'should exist' {
            # Check if the module manifest file DSInternals.psd1 is present in the module root directory.
            $moduleManifestPath | Should -Exist
        }

        It 'should be valid' {
            # Validate the module manifest file DSInternals.psd1. All files referenced in the manifest should exist.
            Test-ModuleManifest -Path $moduleManifestPath -ErrorAction Stop | Should -BeTrue
        }

        It 'should be digitally signed' {
            # Check that the module manifest file DSInternals.psd1 is digitally signed.
            Get-AuthenticodeSignature -FilePath $moduleManifestPath -ErrorAction Stop |
                Select-Object -ExpandProperty Status |
                Should -Be 'Valid'
        }
    }

    Context 'Scripts' {
        BeforeDiscovery {
            # Fetch all PowerShell script files in the module directory (*.ps1, *.psd1, *.psm1, *.ps1xml).
            [hashtable[]] $scriptFiles = Get-ChildItem -Path $PSScriptRoot -File -Recurse -Include '*.ps1','*.psd1','*.psm1','*.ps1xml' -ErrorAction Stop |
                ForEach-Object { @{ FileName = $PSItem.Name; FilePath = $PSItem.FullName } }
        }

        It 'File "<FileName>" should be digitally signed' -TestCases $scriptFiles {
            param([string] $FileName, [string] $FilePath)

            # Verify that each PowerShell script file is digitally signed.
            Get-AuthenticodeSignature -FilePath $FilePath -ErrorAction Stop |
                Select-Object -ExpandProperty Status |
                Should -Be 'Valid'
        }
    }

    Context 'Assemblies' {
        BeforeDiscovery {
             # Fetch all DLL files in the module directory and its subdirectories.
            [hashtable[]] $assemblies = Get-ChildItem -Path $PSScriptRoot -File -Recurse -Include '*.dll' -ErrorAction Stop |
                ForEach-Object { @{ FileName = $PSItem.Name; FilePath = $PSItem.FullName } }
        }

        It 'Assembly "<FileName>" should have a strong name' -TestCases $assemblies {
            param([string] $FileName, [string] $FilePath)
            
            # Check if each assembly has a strong name by verifying its public key.
            try {
                [System.Reflection.AssemblyName] $assemblyName = [System.Reflection.AssemblyName]::GetAssemblyName($FilePath)
                $assemblyName.Flags | Should -Contain 'PublicKey'
            }
            catch [System.BadImageFormatException] {
                # This DLL file is not a .NET assembly, so the test is not applicable.
                # Such files include the Microsoft C++ runtime libraries.
                Set-ItResult -Skipped -Because 'this file is not a .NET assembly.'
            }
        }

        It 'Assembly "<FileName>" should have a valid digital signature' -TestCases $assemblies {
            param([string] $FileName, [string] $FilePath)

            # These 3rd-party files are not signed, so we will skip them.
            [string[]] $unsignedFiles = @()

            if ($FileName -in $unsignedFiles) {
                Set-ItResult -Skipped -Because 'this file is not signed by its vendor.'
                return
            }

            # Verify that each assembly is digitally signed using a certificate.
            Get-AuthenticodeSignature -FilePath $FilePath -ErrorAction Stop |
                Select-Object -ExpandProperty Status |
                Should -Be 'Valid'
        }
    }
}

# SIG # Begin signature block
# MIIvlgYJKoZIhvcNAQcCoIIvhzCCL4MCAQExDzANBglghkgBZQMEAgEFADB5Bgor
# BgEEAYI3AgEEoGswaTA0BgorBgEEAYI3AgEeMCYCAwEAAAQQH8w7YFlLCE63JNLG
# KX7zUQIBAAIBAAIBAAIBAAIBADAxMA0GCWCGSAFlAwQCAQUABCBnxXeSLQALAdLq
# s0Mtv4m9eSrVO1Vwy/dzrOvwFmleI6CCE6UwggWQMIIDeKADAgECAhAFmxtXno4h
# MuI5B72nd3VcMA0GCSqGSIb3DQEBDAUAMGIxCzAJBgNVBAYTAlVTMRUwEwYDVQQK
# EwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20xITAfBgNV
# BAMTGERpZ2lDZXJ0IFRydXN0ZWQgUm9vdCBHNDAeFw0xMzA4MDExMjAwMDBaFw0z
# ODAxMTUxMjAwMDBaMGIxCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdpQ2VydCBJ
# bmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20xITAfBgNVBAMTGERpZ2lDZXJ0
# IFRydXN0ZWQgUm9vdCBHNDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIB
# AL/mkHNo3rvkXUo8MCIwaTPswqclLskhPfKK2FnC4SmnPVirdprNrnsbhA3EMB/z
# G6Q4FutWxpdtHauyefLKEdLkX9YFPFIPUh/GnhWlfr6fqVcWWVVyr2iTcMKyunWZ
# anMylNEQRBAu34LzB4TmdDttceItDBvuINXJIB1jKS3O7F5OyJP4IWGbNOsFxl7s
# Wxq868nPzaw0QF+xembud8hIqGZXV59UWI4MK7dPpzDZVu7Ke13jrclPXuU15zHL
# 2pNe3I6PgNq2kZhAkHnDeMe2scS1ahg4AxCN2NQ3pC4FfYj1gj4QkXCrVYJBMtfb
# BHMqbpEBfCFM1LyuGwN1XXhm2ToxRJozQL8I11pJpMLmqaBn3aQnvKFPObURWBf3
# JFxGj2T3wWmIdph2PVldQnaHiZdpekjw4KISG2aadMreSx7nDmOu5tTvkpI6nj3c
# AORFJYm2mkQZK37AlLTSYW3rM9nF30sEAMx9HJXDj/chsrIRt7t/8tWMcCxBYKqx
# YxhElRp2Yn72gLD76GSmM9GJB+G9t+ZDpBi4pncB4Q+UDCEdslQpJYls5Q5SUUd0
# viastkF13nqsX40/ybzTQRESW+UQUOsxxcpyFiIJ33xMdT9j7CFfxCBRa2+xq4aL
# T8LWRV+dIPyhHsXAj6KxfgommfXkaS+YHS312amyHeUbAgMBAAGjQjBAMA8GA1Ud
# EwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgGGMB0GA1UdDgQWBBTs1+OC0nFdZEzf
# Lmc/57qYrhwPTzANBgkqhkiG9w0BAQwFAAOCAgEAu2HZfalsvhfEkRvDoaIAjeNk
# aA9Wz3eucPn9mkqZucl4XAwMX+TmFClWCzZJXURj4K2clhhmGyMNPXnpbWvWVPjS
# PMFDQK4dUPVS/JA7u5iZaWvHwaeoaKQn3J35J64whbn2Z006Po9ZOSJTROvIXQPK
# 7VB6fWIhCoDIc2bRoAVgX+iltKevqPdtNZx8WorWojiZ83iL9E3SIAveBO6Mm0eB
# cg3AFDLvMFkuruBx8lbkapdvklBtlo1oepqyNhR6BvIkuQkRUNcIsbiJeoQjYUIp
# 5aPNoiBB19GcZNnqJqGLFNdMGbJQQXE9P01wI4YMStyB0swylIQNCAmXHE/A7msg
# dDDS4Dk0EIUhFQEI6FUy3nFJ2SgXUE3mvk3RdazQyvtBuEOlqtPDBURPLDab4vri
# RbgjU2wGb2dVf0a1TD9uKFp5JtKkqGKX0h7i7UqLvBv9R0oN32dmfrJbQdA75PQ7
# 9ARj6e/CVABRoIoqyc54zNXqhwQYs86vSYiv85KZtrPmYQ/ShQDnUBrkG5WdGaG5
# nLGbsQAe79APT0JsyQq87kP6OnGlyE0mpTX9iV28hWIdMtKgK1TtmlfB2/oQzxm3
# i0objwG2J5VT6LaJbVu8aNQj6ItRolb58KaAoNYes7wPD1N1KarqE3fk3oyBIa0H
# EEcRrYc9B9F1vM/zZn4wggawMIIEmKADAgECAhAIrUCyYNKcTJ9ezam9k67ZMA0G
# CSqGSIb3DQEBDAUAMGIxCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdpQ2VydCBJ
# bmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20xITAfBgNVBAMTGERpZ2lDZXJ0
# IFRydXN0ZWQgUm9vdCBHNDAeFw0yMTA0MjkwMDAwMDBaFw0zNjA0MjgyMzU5NTla
# MGkxCzAJBgNVBAYTAlVTMRcwFQYDVQQKEw5EaWdpQ2VydCwgSW5jLjFBMD8GA1UE
# AxM4RGlnaUNlcnQgVHJ1c3RlZCBHNCBDb2RlIFNpZ25pbmcgUlNBNDA5NiBTSEEz
# ODQgMjAyMSBDQTEwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDVtC9C
# 0CiteLdd1TlZG7GIQvUzjOs9gZdwxbvEhSYwn6SOaNhc9es0JAfhS0/TeEP0F9ce
# 2vnS1WcaUk8OoVf8iJnBkcyBAz5NcCRks43iCH00fUyAVxJrQ5qZ8sU7H/Lvy0da
# E6ZMswEgJfMQ04uy+wjwiuCdCcBlp/qYgEk1hz1RGeiQIXhFLqGfLOEYwhrMxe6T
# SXBCMo/7xuoc82VokaJNTIIRSFJo3hC9FFdd6BgTZcV/sk+FLEikVoQ11vkunKoA
# FdE3/hoGlMJ8yOobMubKwvSnowMOdKWvObarYBLj6Na59zHh3K3kGKDYwSNHR7Oh
# D26jq22YBoMbt2pnLdK9RBqSEIGPsDsJ18ebMlrC/2pgVItJwZPt4bRc4G/rJvmM
# 1bL5OBDm6s6R9b7T+2+TYTRcvJNFKIM2KmYoX7BzzosmJQayg9Rc9hUZTO1i4F4z
# 8ujo7AqnsAMrkbI2eb73rQgedaZlzLvjSFDzd5Ea/ttQokbIYViY9XwCFjyDKK05
# huzUtw1T0PhH5nUwjewwk3YUpltLXXRhTT8SkXbev1jLchApQfDVxW0mdmgRQRNY
# mtwmKwH0iU1Z23jPgUo+QEdfyYFQc4UQIyFZYIpkVMHMIRroOBl8ZhzNeDhFMJlP
# /2NPTLuqDQhTQXxYPUez+rbsjDIJAsxsPAxWEQIDAQABo4IBWTCCAVUwEgYDVR0T
# AQH/BAgwBgEB/wIBADAdBgNVHQ4EFgQUaDfg67Y7+F8Rhvv+YXsIiGX0TkIwHwYD
# VR0jBBgwFoAU7NfjgtJxXWRM3y5nP+e6mK4cD08wDgYDVR0PAQH/BAQDAgGGMBMG
# A1UdJQQMMAoGCCsGAQUFBwMDMHcGCCsGAQUFBwEBBGswaTAkBggrBgEFBQcwAYYY
# aHR0cDovL29jc3AuZGlnaWNlcnQuY29tMEEGCCsGAQUFBzAChjVodHRwOi8vY2Fj
# ZXJ0cy5kaWdpY2VydC5jb20vRGlnaUNlcnRUcnVzdGVkUm9vdEc0LmNydDBDBgNV
# HR8EPDA6MDigNqA0hjJodHRwOi8vY3JsMy5kaWdpY2VydC5jb20vRGlnaUNlcnRU
# cnVzdGVkUm9vdEc0LmNybDAcBgNVHSAEFTATMAcGBWeBDAEDMAgGBmeBDAEEATAN
# BgkqhkiG9w0BAQwFAAOCAgEAOiNEPY0Idu6PvDqZ01bgAhql+Eg08yy25nRm95Ry
# sQDKr2wwJxMSnpBEn0v9nqN8JtU3vDpdSG2V1T9J9Ce7FoFFUP2cvbaF4HZ+N3HL
# IvdaqpDP9ZNq4+sg0dVQeYiaiorBtr2hSBh+3NiAGhEZGM1hmYFW9snjdufE5Btf
# Q/g+lP92OT2e1JnPSt0o618moZVYSNUa/tcnP/2Q0XaG3RywYFzzDaju4ImhvTnh
# OE7abrs2nfvlIVNaw8rpavGiPttDuDPITzgUkpn13c5UbdldAhQfQDN8A+KVssIh
# dXNSy0bYxDQcoqVLjc1vdjcshT8azibpGL6QB7BDf5WIIIJw8MzK7/0pNVwfiThV
# 9zeKiwmhywvpMRr/LhlcOXHhvpynCgbWJme3kuZOX956rEnPLqR0kq3bPKSchh/j
# wVYbKyP/j7XqiHtwa+aguv06P0WmxOgWkVKLQcBIhEuWTatEQOON8BUozu3xGFYH
# Ki8QxAwIZDwzj64ojDzLj4gLDb879M4ee47vtevLt/B3E+bnKD+sEq6lLyJsQfmC
# XBVmzGwOysWGw/YmMwwHS6DTBwJqakAwSEs0qFEgu60bhQjiWQ1tygVQK+pKHJ6l
# /aCnHwZ05/LWUpD9r4VIIflXO7ScA+2GRfS0YW6/aOImYIbqyK+p/pQd52MbOoZW
# eE4wggdZMIIFQaADAgECAhANqK80cCX+jsAYDGB/BSyeMA0GCSqGSIb3DQEBCwUA
# MGkxCzAJBgNVBAYTAlVTMRcwFQYDVQQKEw5EaWdpQ2VydCwgSW5jLjFBMD8GA1UE
# AxM4RGlnaUNlcnQgVHJ1c3RlZCBHNCBDb2RlIFNpZ25pbmcgUlNBNDA5NiBTSEEz
# ODQgMjAyMSBDQTEwHhcNMjYwMTA1MDAwMDAwWhcNMjkwMTA0MjM1OTU5WjBhMQsw
# CQYDVQQGEwJDWjEOMAwGA1UEBxMFUHJhaGExIDAeBgNVBAoTF01nci4gTWljaGFl
# bCBHcmFmbmV0dGVyMSAwHgYDVQQDExdNZ3IuIE1pY2hhZWwgR3JhZm5ldHRlcjCC
# AiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAJrpm0HI6ak/Uj3iqs64nuUT
# WZAkxHVeJKwnd3XR0Ge/oE1STGkmydGCZ8VR9jMcIHK+kYteESboRguDVk7BTxEv
# SKTEDG0lt1KLr0KUuWI2EUykxtcpR7wOjZ/VBMPeiwPQqccY/ZnwF0H6P43MJSIf
# WYVhTLb5R8ueHkjxRGkMPgIcuV4W3TqIEQKvO9NEMC0Tv2nPXPab5u20QdixQaep
# 05DEBL1cd9L0NYvbgUi8JQ63I/P7fqrlC6zXZb61wDDTNxwtdFIlR7jvAFqhY1bX
# Qfb8bmL4KXH9Sv3hHIDUUfitghKh4RoQWitVTpf+uzLPG0Dr1UH8RbWIYQRXCZhr
# 4RJzmt3+i0f+IZSJkRlXBVhn9GeQTk3yaUwLFyz5evTYh5IBaMNA+1BChpswlB32
# PoOjg4eJr3/nArLKN3UZCy9PQ0F+y0J+T/UkGCyv0Ws+zxiZlR2A6ekjGnP5x+8g
# n2S3Hf0rMCfCgudgT12S8tXPSdI88TzsihLj8iJT9ljgS0bJSjNykYaBK8BXYYJ3
# PvBn7px9G7b7WOPieyp7rTDkmyWBG5+vVIOFjJUgMIMJChsc5f11iHNcdo7FsVwS
# H8MftQ0rUSktj1xK4/p9zwhQpI+eXE0l9YIP08JmVOLtgu2PzXcCT/El+/8+XUw/
# X63cEIgp49URPwtmU0UhAgMBAAGjggIDMIIB/zAfBgNVHSMEGDAWgBRoN+Drtjv4
# XxGG+/5hewiIZfROQjAdBgNVHQ4EFgQUUAbobwgAP24SnIkacVlc4i61qWgwPgYD
# VR0gBDcwNTAzBgZngQwBBAEwKTAnBggrBgEFBQcCARYbaHR0cDovL3d3dy5kaWdp
# Y2VydC5jb20vQ1BTMA4GA1UdDwEB/wQEAwIHgDATBgNVHSUEDDAKBggrBgEFBQcD
# AzCBtQYDVR0fBIGtMIGqMFOgUaBPhk1odHRwOi8vY3JsMy5kaWdpY2VydC5jb20v
# RGlnaUNlcnRUcnVzdGVkRzRDb2RlU2lnbmluZ1JTQTQwOTZTSEEzODQyMDIxQ0Ex
# LmNybDBToFGgT4ZNaHR0cDovL2NybDQuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0VHJ1
# c3RlZEc0Q29kZVNpZ25pbmdSU0E0MDk2U0hBMzg0MjAyMUNBMS5jcmwwgZQGCCsG
# AQUFBwEBBIGHMIGEMCQGCCsGAQUFBzABhhhodHRwOi8vb2NzcC5kaWdpY2VydC5j
# b20wXAYIKwYBBQUHMAKGUGh0dHA6Ly9jYWNlcnRzLmRpZ2ljZXJ0LmNvbS9EaWdp
# Q2VydFRydXN0ZWRHNENvZGVTaWduaW5nUlNBNDA5NlNIQTM4NDIwMjFDQTEuY3J0
# MAkGA1UdEwQCMAAwDQYJKoZIhvcNAQELBQADggIBAI/LhB69MYV+zYchS+lShCm1
# H7P/sHkhIctl5ClI6fFpsqc7uAZlH2JjUNYDkkIUvoGk5teyJdLXrycGQIVwH26i
# DJm6VDoOOalOjOHh1Om/dP3Cl3XPUM1KRyj39DNnLvPB/5VxIbGoz9yoaTvHAQnu
# B5THrdo0nWyPtDgTF2ItJFVky4Uh9cE/ggCifsDUFMwAVKDZ1YvwNspO/ajwdLTM
# l121TKX3x5eA8KL4bO3LVvE5GQIqQx3PVqTn4jwFlxjDaBh/RE6yo2UwPwIIfTfj
# XTHuziTtFgvVhHKFS55Cxt4h3nCrPEnCfSdG/oNOF8TgLWA873V4T1Qqkdi8aXuA
# BWu5GhemjorxFxqeSLrskfTnGO2a5WQ6hmqmz8jU/Ulau8MvwRN8ZSyDJBYc8iuF
# VL1+abP12QfM/O8VkqYHbeslkC0qndAbJlT6icTd4CPeBXTwXtGY0hixRxcAkq3y
# gKSs7EeGGY6Ytc1pANGDX6PBjVxaf0XfwhkwG35iAA3Ix1muNoB4Nt2HySbkVGDh
# ZT5seWy/D2Z44NTAMcGh7WcBGp0RJ/372LGP58ZgSPp/0EtlhaCX1UoQo7Nv6XsY
# 1qu0RC+G/lOTl1C9o3eya4bf5y0GZlrNgW3U4nxi4UcRwlpmRaH1hbuz5BQoImaz
# mn6pOiSVBvJE8R1OA+9UMYIbRzCCG0MCAQEwfTBpMQswCQYDVQQGEwJVUzEXMBUG
# A1UEChMORGlnaUNlcnQsIEluYy4xQTA/BgNVBAMTOERpZ2lDZXJ0IFRydXN0ZWQg
# RzQgQ29kZSBTaWduaW5nIFJTQTQwOTYgU0hBMzg0IDIwMjEgQ0ExAhANqK80cCX+
# jsAYDGB/BSyeMA0GCWCGSAFlAwQCAQUAoIGEMBgGCisGAQQBgjcCAQwxCjAIoAKA
# AKECgAAwGQYJKoZIhvcNAQkDMQwGCisGAQQBgjcCAQQwHAYKKwYBBAGCNwIBCzEO
# MAwGCisGAQQBgjcCARUwLwYJKoZIhvcNAQkEMSIEIArflUl0KEzYwqnswj2AOVeO
# c50GLBk+S7El1JU8O4nqMA0GCSqGSIb3DQEBAQUABIICAF7X5F+0rIE7B6M/1JdK
# hbL0w25IQH3bT2zcZSKNs73FhbeJVoVXMnhwcqPTrqN5LMBUVRnoZWaMliPP+NV0
# cm+4EwfErnJPc1FHs5Q/pENm20DQJRekQcGvDl6PBai2XDRXWKuzHVmXAPbQNSTQ
# osBqblGNdevmXtkhlsrF/X5ej24mxOK8hdS2Msa4f+kwV02Z6Sji0Xag6ae25RPt
# JiMU3DAqAB7sx7m7g3tS2qsRmBUqyKbK6xKyei7QJ+lDCxj2PNV5CJeu3CpKkUgX
# 8uMRI+azAvS0wLyOyecrkm7AtYhiCmnEcvt+kmyv8ATYGfTUs5Uv1V6tYG53xNx2
# rVfoOYb2T3RRWa5uXdYYU7Dt7dt5jRvTK3dwFMXSAdlzv4S1xujPSqnVFfZT9Ys1
# 5m8zujogw0/WgPje3A7G5Yzk5nmdhqtO2drS8azIloZLcwifEfQjR7lJfvi3A7U7
# IBhzLpOL6O1uQ6ouF/JbDKOnw0nE+nfg1jE8Dq2ztgJLVq9RVDNfXZJClEpEvYHr
# ZzeNLLqirnqFP12yC5y4k61Z9KpRnnWjZs1/AiYtR5dGX+PQYfW6M/hWBE/txTzO
# W6ccnYNIdUtHkT0TGkZVkNHYsWDp0C8vOQeqIfb00p1/nXPN4DczHlGEAmKcpY9L
# I7hsVxc6iFx6/7K47rye/g0ioYIYFDCCGBAGCisGAQQBgjcDAwExghgAMIIX/AYJ
# KoZIhvcNAQcCoIIX7TCCF+kCAQMxDzANBglghkgBZQMEAgEFADCCAWIGCyqGSIb3
# DQEJEAEEoIIBUQSCAU0wggFJAgEBBgorBgEEAYRZCgMBMDEwDQYJYIZIAWUDBAIB
# BQAEICVy7veqTEENK/TtZCgJ17OW+RY7B/kqM/vILgWyfepyAgZpb2F6TQMYEzIw
# MjYwMjA4MjE1MDEzLjAxNlowBIACAfSggeGkgd4wgdsxCzAJBgNVBAYTAlVTMRMw
# EQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVN
# aWNyb3NvZnQgQ29ycG9yYXRpb24xJTAjBgNVBAsTHE1pY3Jvc29mdCBBbWVyaWNh
# IE9wZXJhdGlvbnMxJzAlBgNVBAsTHm5TaGllbGQgVFNTIEVTTjpBNTAwLTA1RTAt
# RDk0NzE1MDMGA1UEAxMsTWljcm9zb2Z0IFB1YmxpYyBSU0EgVGltZSBTdGFtcGlu
# ZyBBdXRob3JpdHmggg8hMIIHgjCCBWqgAwIBAgITMwAAAAXlzw//Zi7JhwAAAAAA
# BTANBgkqhkiG9w0BAQwFADB3MQswCQYDVQQGEwJVUzEeMBwGA1UEChMVTWljcm9z
# b2Z0IENvcnBvcmF0aW9uMUgwRgYDVQQDEz9NaWNyb3NvZnQgSWRlbnRpdHkgVmVy
# aWZpY2F0aW9uIFJvb3QgQ2VydGlmaWNhdGUgQXV0aG9yaXR5IDIwMjAwHhcNMjAx
# MTE5MjAzMjMxWhcNMzUxMTE5MjA0MjMxWjBhMQswCQYDVQQGEwJVUzEeMBwGA1UE
# ChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMTIwMAYDVQQDEylNaWNyb3NvZnQgUHVi
# bGljIFJTQSBUaW1lc3RhbXBpbmcgQ0EgMjAyMDCCAiIwDQYJKoZIhvcNAQEBBQAD
# ggIPADCCAgoCggIBAJ5851Jj/eDFnwV9Y7UGIqMcHtfnlzPREwW9ZUZHd5HBXXBv
# f7KrQ5cMSqFSHGqg2/qJhYqOQxwuEQXG8kB41wsDJP5d0zmLYKAY8Zxv3lYkuLDs
# fMuIEqvGYOPURAH+Ybl4SJEESnt0MbPEoKdNihwM5xGv0rGofJ1qOYSTNcc55EbB
# T7uq3wx3mXhtVmtcCEr5ZKTkKKE1CxZvNPWdGWJUPC6e4uRfWHIhZcgCsJ+sozf5
# EeH5KrlFnxpjKKTavwfFP6XaGZGWUG8TZaiTogRoAlqcevbiqioUz1Yt4FRK53P6
# ovnUfANjIgM9JDdJ4e0qiDRm5sOTiEQtBLGd9Vhd1MadxoGcHrRCsS5rO9yhv2fj
# JHrmlQ0EIXmp4DhDBieKUGR+eZ4CNE3ctW4uvSDQVeSp9h1SaPV8UWEfyTxgGjOs
# RpeexIveR1MPTVf7gt8hY64XNPO6iyUGsEgt8c2PxF87E+CO7A28TpjNq5eLiiun
# hKbq0XbjkNoU5JhtYUrlmAbpxRjb9tSreDdtACpm3rkpxp7AQndnI0Shu/fk1/rE
# 3oWsDqMX3jjv40e8KN5YsJBnczyWB4JyeeFMW3JBfdeAKhzohFe8U5w9WuvcP1E8
# cIxLoKSDzCCBOu0hWdjzKNu8Y5SwB1lt5dQhABYyzR3dxEO/T1K/BVF3rV69AgMB
# AAGjggIbMIICFzAOBgNVHQ8BAf8EBAMCAYYwEAYJKwYBBAGCNxUBBAMCAQAwHQYD
# VR0OBBYEFGtpKDo1L0hjQM972K9J6T7ZPdshMFQGA1UdIARNMEswSQYEVR0gADBB
# MD8GCCsGAQUFBwIBFjNodHRwOi8vd3d3Lm1pY3Jvc29mdC5jb20vcGtpb3BzL0Rv
# Y3MvUmVwb3NpdG9yeS5odG0wEwYDVR0lBAwwCgYIKwYBBQUHAwgwGQYJKwYBBAGC
# NxQCBAweCgBTAHUAYgBDAEEwDwYDVR0TAQH/BAUwAwEB/zAfBgNVHSMEGDAWgBTI
# ftJqhSobyhmYBAcnz1AQT2ioojCBhAYDVR0fBH0wezB5oHegdYZzaHR0cDovL3d3
# dy5taWNyb3NvZnQuY29tL3BraW9wcy9jcmwvTWljcm9zb2Z0JTIwSWRlbnRpdHkl
# MjBWZXJpZmljYXRpb24lMjBSb290JTIwQ2VydGlmaWNhdGUlMjBBdXRob3JpdHkl
# MjAyMDIwLmNybDCBlAYIKwYBBQUHAQEEgYcwgYQwgYEGCCsGAQUFBzAChnVodHRw
# Oi8vd3d3Lm1pY3Jvc29mdC5jb20vcGtpb3BzL2NlcnRzL01pY3Jvc29mdCUyMElk
# ZW50aXR5JTIwVmVyaWZpY2F0aW9uJTIwUm9vdCUyMENlcnRpZmljYXRlJTIwQXV0
# aG9yaXR5JTIwMjAyMC5jcnQwDQYJKoZIhvcNAQEMBQADggIBAF+Idsd+bbVaFXXn
# THho+k7h2ESZJRWluLE0Oa/pO+4ge/XEizXvhs0Y7+KVYyb4nHlugBesnFqBGEdC
# 2IWmtKMyS1OWIviwpnK3aL5JedwzbeBF7POyg6IGG/XhhJ3UqWeWTO+Czb1c2NP5
# zyEh89F72u9UIw+IfvM9lzDmc2O2END7MPnrcjWdQnrLn1Ntday7JSyrDvBdmgbN
# nCKNZPmhzoa8PccOiQljjTW6GePe5sGFuRHzdFt8y+bN2neF7Zu8hTO1I64XNGqs
# t8S+w+RUdie8fXC1jKu3m9KGIqF4aldrYBamyh3g4nJPj/LR2CBaLyD+2BuGZCVm
# oNR/dSpRCxlot0i79dKOChmoONqbMI8m04uLaEHAv4qwKHQ1vBzbV/nG89LDKbRS
# SvijmwJwxRxLLpMQ/u4xXxFfR4f/gksSkbJp7oqLwliDm/h+w0aJ/U5ccnYhYb7v
# PKNMN+SZDWycU5ODIRfyoGl59BsXR/HpRGtiJquOYGmvA/pk5vC1lcnbeMrcWD/2
# 6ozePQ/TWfNXKBOmkFpvPE8CH+EeGGWzqTCjdAsno2jzTeNSxlx3glDGJgcdz5D/
# AAxw9Sdgq/+rY7jjgs7X6fqPTXPmaCAJKVHAP19oEjJIBwD1LyHbaEgBxFCogYSO
# iUIr0Xqcr1nJfiWG2GwYe6ZoAF1bMIIHlzCCBX+gAwIBAgITMwAAAFZ+j51YCI7p
# YAAAAAAAVjANBgkqhkiG9w0BAQwFADBhMQswCQYDVQQGEwJVUzEeMBwGA1UEChMV
# TWljcm9zb2Z0IENvcnBvcmF0aW9uMTIwMAYDVQQDEylNaWNyb3NvZnQgUHVibGlj
# IFJTQSBUaW1lc3RhbXBpbmcgQ0EgMjAyMDAeFw0yNTEwMjMyMDQ2NTFaFw0yNjEw
# MjIyMDQ2NTFaMIHbMQswCQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQ
# MA4GA1UEBxMHUmVkbW9uZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9u
# MSUwIwYDVQQLExxNaWNyb3NvZnQgQW1lcmljYSBPcGVyYXRpb25zMScwJQYDVQQL
# Ex5uU2hpZWxkIFRTUyBFU046QTUwMC0wNUUwLUQ5NDcxNTAzBgNVBAMTLE1pY3Jv
# c29mdCBQdWJsaWMgUlNBIFRpbWUgU3RhbXBpbmcgQXV0aG9yaXR5MIICIjANBgkq
# hkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAtKWfm/ul027/d8Rlb8Mn/g0QUvvLqY2V
# sy3tI8U2tFSspTZomZOD3BHT8LkR+RrhMJgb1VjAKFNysaK9cLSXifPGSIBrPCgs
# 9P4y24lrJEmrV6Q5z4BmqMhIPrZhEvZnWpCS4HO7jYSei/nxmC7/1Er+l5Lg3PmS
# xb8d2IVcARxSw1B4mxB6XI0nkel9wa1dYb2wfGpofraFmxZOxT9eNht4LH0RBSVu
# eba6ZNpjS/0gtfm7qiIiyP6p6PRzTTbMnVqsHnV/d/rW0zHx+Q+QNZ5wUqKmTZJB
# 9hU853+2pX5rDfK32uNY9/WBOAmzbqgpEdQkbiMavUMyUDShmycIvgHdQnS207sT
# j8M+kJL3tOdahPuPqMwsaCCgdfwwQx0O9TKe7FSvbAEYs1AnldCl/KHGZCOVvUNq
# jyL10JLe0/+GD9/ynqXGWFpXOjaunvZ/cKROhjN4M5e6xx0b2miqcPii4/ii2Zhe
# KallJET7CKlpFShs3wyg6F/fojQxQvPnbWD4Nyx6lhjWjwmoLcx6w1FSCtavLCly
# 33BLRSlTU4qKUxaa8d7YN7Eqpn9XO0SY0umOvKFXrWH7rxl+9iaicitdnTTksAnR
# jvekdKT3lg7lRMfmfZU8vXNiN0UYJzT9EjqjRm0uN/h0oXxPhNfPYqeFbyPXGGxz
# aYUz6zx3qTcCAwEAAaOCAcswggHHMB0GA1UdDgQWBBS+tjPyu6tZ/h5GsyLvyz1H
# +FNIWjAfBgNVHSMEGDAWgBRraSg6NS9IY0DPe9ivSek+2T3bITBsBgNVHR8EZTBj
# MGGgX6BdhltodHRwOi8vd3d3Lm1pY3Jvc29mdC5jb20vcGtpb3BzL2NybC9NaWNy
# b3NvZnQlMjBQdWJsaWMlMjBSU0ElMjBUaW1lc3RhbXBpbmclMjBDQSUyMDIwMjAu
# Y3JsMHkGCCsGAQUFBwEBBG0wazBpBggrBgEFBQcwAoZdaHR0cDovL3d3dy5taWNy
# b3NvZnQuY29tL3BraW9wcy9jZXJ0cy9NaWNyb3NvZnQlMjBQdWJsaWMlMjBSU0El
# MjBUaW1lc3RhbXBpbmclMjBDQSUyMDIwMjAuY3J0MAwGA1UdEwEB/wQCMAAwFgYD
# VR0lAQH/BAwwCgYIKwYBBQUHAwgwDgYDVR0PAQH/BAQDAgeAMGYGA1UdIARfMF0w
# UQYMKwYBBAGCN0yDfQEBMEEwPwYIKwYBBQUHAgEWM2h0dHA6Ly93d3cubWljcm9z
# b2Z0LmNvbS9wa2lvcHMvRG9jcy9SZXBvc2l0b3J5Lmh0bTAIBgZngQwBBAIwDQYJ
# KoZIhvcNAQEMBQADggIBAA4DqAXEsO26j/La7Fgn/Qifit8xuZekqZ57+Ye+sH/h
# RTbEEjGYrZgsqwR/lUUfKCFpbZF8msaZPQJOR4YYUEU8XyjLrn8Y1jCSmoxh9l7t
# WiSoc/JFBw356JAmzGGxeBA2EWSxRuTr1AuZe6nYaN8/wtFkiHcs8gMadxXBs6Dx
# Vhyu5YnhLPQkfumKm3lFftwE7pieV7f1lskmlgsC6AeSGCzGPZUgCvcH5Tv/Qe9z
# 7bIImSD3SuzhOIwaP+eKQTYf67TifyJKkWQSdGfTA6Kcu41k8LB6oPK+MLk1jbxx
# K5wPqLSL62xjK04SBXHEJSEnsFt0zxWkxP/lgej1DxqUnmrYEdkxvzKSHIAqFWSZ
# ul/5hI+vJxvFPhsNQBEk4cSulDkJQpcdVi/gmf/mHFOYhDBjsa15s4L+2sBil3XV
# /T8RiR66Q8xYvTLRWxd2dVsrOoCwnsU4WIeiC0JinCv1WLHEh7Qyzr9RSr4kKJLW
# dpNYLhgjkojTmEkAjFO774t3xB7enbvIF0GOsV19xnCUzq9EGKyt0gMuaphKlNjJ
# +aTpjWMZDGo+GOKsnp93Hmftml0Syp3F9+M3y+y6WJGUZoIZJq227jDjjEndtpUr
# h9BdPdVIfVJD/Au81Rzh05UHAivorQ3Os8PELHIgiOd9TWzbdgmGzcILt/ddVQER
# MYIHRjCCB0ICAQEweDBhMQswCQYDVQQGEwJVUzEeMBwGA1UEChMVTWljcm9zb2Z0
# IENvcnBvcmF0aW9uMTIwMAYDVQQDEylNaWNyb3NvZnQgUHVibGljIFJTQSBUaW1l
# c3RhbXBpbmcgQ0EgMjAyMAITMwAAAFZ+j51YCI7pYAAAAAAAVjANBglghkgBZQME
# AgEFAKCCBJ8wEQYLKoZIhvcNAQkQAg8xAgUAMBoGCSqGSIb3DQEJAzENBgsqhkiG
# 9w0BCRABBDAcBgkqhkiG9w0BCQUxDxcNMjYwMjA4MjE1MDEzWjAvBgkqhkiG9w0B
# CQQxIgQg0adu4500O98AHYVV5RHfeILylzuiP/AkVWfuhy4AieIwgbkGCyqGSIb3
# DQEJEAIvMYGpMIGmMIGjMIGgBCC2DDMlTaTj8JV3iTg5Xnpe4CSH60143Z+X9o5N
# BgMMqDB8MGWkYzBhMQswCQYDVQQGEwJVUzEeMBwGA1UEChMVTWljcm9zb2Z0IENv
# cnBvcmF0aW9uMTIwMAYDVQQDEylNaWNyb3NvZnQgUHVibGljIFJTQSBUaW1lc3Rh
# bXBpbmcgQ0EgMjAyMAITMwAAAFZ+j51YCI7pYAAAAAAAVjCCA2EGCyqGSIb3DQEJ
# EAISMYIDUDCCA0yhggNIMIIDRDCCAiwCAQEwggEJoYHhpIHeMIHbMQswCQYDVQQG
# EwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9uZDEeMBwG
# A1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMSUwIwYDVQQLExxNaWNyb3NvZnQg
# QW1lcmljYSBPcGVyYXRpb25zMScwJQYDVQQLEx5uU2hpZWxkIFRTUyBFU046QTUw
# MC0wNUUwLUQ5NDcxNTAzBgNVBAMTLE1pY3Jvc29mdCBQdWJsaWMgUlNBIFRpbWUg
# U3RhbXBpbmcgQXV0aG9yaXR5oiMKAQEwBwYFKw4DAhoDFQD/c/cpFSqQWYBeXggy
# RJ2ZbvYEEaBnMGWkYzBhMQswCQYDVQQGEwJVUzEeMBwGA1UEChMVTWljcm9zb2Z0
# IENvcnBvcmF0aW9uMTIwMAYDVQQDEylNaWNyb3NvZnQgUHVibGljIFJTQSBUaW1l
# c3RhbXBpbmcgQ0EgMjAyMDANBgkqhkiG9w0BAQsFAAIFAO0y7FUwIhgPMjAyNjAy
# MDgxMTA0NTNaGA8yMDI2MDIwOTExMDQ1M1owdzA9BgorBgEEAYRZCgQBMS8wLTAK
# AgUA7TLsVQIBADAKAgEAAgIB5gIB/zAHAgEAAgISPTAKAgUA7TQ91QIBADA2Bgor
# BgEEAYRZCgQCMSgwJjAMBgorBgEEAYRZCgMCoAowCAIBAAIDB6EgoQowCAIBAAID
# AYagMA0GCSqGSIb3DQEBCwUAA4IBAQB9c6q2N21OTjHoxJU5QnstQmbOepAa92fn
# VbF/HWlgOFaHoNGrU95YA7iBnZITqrWhQiV5/sD9uYzgtP8/DNZVwVKyJe1UZzMN
# 7lUaosK9Okl0dghklys5TkA1I1nhbpAQX8GR4nmkop9YqxUQPlZYbKnqtiuwTvty
# kyAzakYWZaPIxWVcz2wBBZkclxnF2bAV1XYlhg5X2fIGq3xrXVVMBOf9aoowBw2l
# vF+MSFxWQWARLQ1+6lNCtMHMc5esuryaxHLiJ7t47ajXljSyxemcfSzdq1VSf9KK
# VysiwcRL/DxKMFDg/zGYnE3xTWjAp117wWOr1pcHMjapeBjr73eiMA0GCSqGSIb3
# DQEBAQUABIICAJNrCVjaIFq0l5QWJvfd5j5pfQ2RrdnjI0+HXhD2U8ueiJAZLT9w
# 6eglugA9GAVKG7kghNUqkoOkqpOO7VgewjqrOFTn1iME69AD95Li4r7MILwPlff+
# su66pIEjnSTecMHotjoZabxz56vFzDiYNQSE9WqUYk7/3MCSTMPqo8DNrwB/41vq
# UU69fMKWoPRBrt4vdECDTDFxDw8ZRL9DkdaSMKb6fNMSaa/XRqpk1+jF6sYoQ7Jq
# V4jPykAlQsDglS/UQLK9mRxNZ90djtHxaQAnhhpdwBdjqdp9YZ1N6mbekkW1nGsh
# L7Ve8h5+iUsfYRmwptazt6HvvDQMdwJozT5nkpzp8lAXPe0iPtzIexbJlW5jkf+Q
# 5QAe33SlJKg1KVvNb83AiZcDjrDjk77w0rnfb1vmBMBI8NfX3trkSTCOpK+VXH1M
# ATYGYqGG8TyRKxCBfA9kL4iH4SBlSGFvM6KQuE3yuv7bBRveFn9CtE0o0h6c94Hh
# Mbg2VuUuNq6b++Lm4uxg55qRecyUup/gLQVCGNQsc6woqpZRepH8zJbaw8CeIFq2
# zDj0hMt+rDuUXvbapZQBpTCYImeHrkdg83BcOFJkVnWiEK0rafC0tSl+xSo1cIx5
# 4tWUgJcG4zfiWmyhGnNbKj16nHSLBpV0/n5zwiaHnYdgzMMfb75hPZ9e
# SIG # End signature block