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/vILgWyfepyAgZqMSxXDroYEzIw
# MjYwNzA0MTIyOTIxLjA2M1owBIACAfSggeGkgd4wgdsxCzAJBgNVBAYTAlVTMRMw
# EQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVN
# aWNyb3NvZnQgQ29ycG9yYXRpb24xJTAjBgNVBAsTHE1pY3Jvc29mdCBBbWVyaWNh
# IE9wZXJhdGlvbnMxJzAlBgNVBAsTHm5TaGllbGQgVFNTIEVTTjo3ODAwLTA1RTAt
# 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+gAwIBAgITMwAAAFck05XgounJ
# MQAAAAAAVzANBgkqhkiG9w0BAQwFADBhMQswCQYDVQQGEwJVUzEeMBwGA1UEChMV
# TWljcm9zb2Z0IENvcnBvcmF0aW9uMTIwMAYDVQQDEylNaWNyb3NvZnQgUHVibGlj
# IFJTQSBUaW1lc3RhbXBpbmcgQ0EgMjAyMDAeFw0yNTEwMjMyMDQ2NTNaFw0yNjEw
# MjIyMDQ2NTNaMIHbMQswCQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQ
# MA4GA1UEBxMHUmVkbW9uZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9u
# MSUwIwYDVQQLExxNaWNyb3NvZnQgQW1lcmljYSBPcGVyYXRpb25zMScwJQYDVQQL
# Ex5uU2hpZWxkIFRTUyBFU046NzgwMC0wNUUwLUQ5NDcxNTAzBgNVBAMTLE1pY3Jv
# c29mdCBQdWJsaWMgUlNBIFRpbWUgU3RhbXBpbmcgQXV0aG9yaXR5MIICIjANBgkq
# hkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAsWylCpMIfbizJLY1kPXO2cmX2HRWvRbA
# meKSZ5ex7/jCymdV7Eap+Ic2iqRtWDkKKe5gL6JV80wtn5C2qHJLPxUYFKNG3UkH
# kAI21MoCN+YWnhT8K/YuPib6+6970jdbeFKIiZMWwd5hnpX9J3jeteuEdXbp/DfF
# BK15JuD3JOzWuF2suQCPgqYjQPk/gpq+3KCKtXJRbXSCSJ9YtITU2IHwmfdE7l2P
# fZ154w041po+fDeTj0gJOzcV/Jv56Q0M+w19jAKo/I5PEzrLV1IPQnmP4or1X4Rb
# JXk8ONXyOOfXOxK2VLpNxgklK1yAezbFP2uzqihaXkW1h9GQLGENKESnezwgdRaL
# NNaYtm8AT/pZHYJ35mZVqkZdMIckpQHJk/F1fSLyDKeKtH4TC4cc3ESKUMgItq07
# ZZm74JCsfhmrQ1ijVNDi1Sln+QBamgC7WviZbkQnceQRq9DY+6hANwOrasAZUiVr
# 2kPuj1jHDOXzUG4O9QTK70P/oXSqZAN1oTv3UfF8JTGmAxg+l1ZPOz50MY96HBDw
# /3bI/wBGNvLk6fLVnrxGN5B5unF/lYvjjWbIUdyBPVQnPOKXu08SRHbY19M1HoWX
# 6PNZv+vzSeqVeWWHKdKjC3GjVjbbGpi+JLbiyaKRSwEqo49tJLvu69cQ7dWsbksa
# i4TURnVj2mMCAwEAAaOCAcswggHHMB0GA1UdDgQWBBSOg8leLTUOAglIZ+bjXpiD
# 7RKSpzAfBgNVHSMEGDAWgBRraSg6NS9IY0DPe9ivSek+2T3bITBsBgNVHR8EZTBj
# MGGgX6BdhltodHRwOi8vd3d3Lm1pY3Jvc29mdC5jb20vcGtpb3BzL2NybC9NaWNy
# b3NvZnQlMjBQdWJsaWMlMjBSU0ElMjBUaW1lc3RhbXBpbmclMjBDQSUyMDIwMjAu
# Y3JsMHkGCCsGAQUFBwEBBG0wazBpBggrBgEFBQcwAoZdaHR0cDovL3d3dy5taWNy
# b3NvZnQuY29tL3BraW9wcy9jZXJ0cy9NaWNyb3NvZnQlMjBQdWJsaWMlMjBSU0El
# MjBUaW1lc3RhbXBpbmclMjBDQSUyMDIwMjAuY3J0MAwGA1UdEwEB/wQCMAAwFgYD
# VR0lAQH/BAwwCgYIKwYBBQUHAwgwDgYDVR0PAQH/BAQDAgeAMGYGA1UdIARfMF0w
# UQYMKwYBBAGCN0yDfQEBMEEwPwYIKwYBBQUHAgEWM2h0dHA6Ly93d3cubWljcm9z
# b2Z0LmNvbS9wa2lvcHMvRG9jcy9SZXBvc2l0b3J5Lmh0bTAIBgZngQwBBAIwDQYJ
# KoZIhvcNAQEMBQADggIBAHJ1wHY86Zk5SUBDPY25d/u9YJVaaNa71uxjX4cyO/XJ
# 4uPENCSOwkRTnNogPLxTD0Fg3z4TFf/2T/0IFSxdtWVtTjhzrn+WLInzeRawUhTC
# FVrPBJKEWVshm+Ig7/nB7JbJN88+ltImBbL5kT1StBLfG6UksAcDbNSQww90CUXh
# GueBxlnSvjkAX1ohiN16y1bB2s0rvQx8Csepl2CuBefTfDrMGzW/tzNx5YaK2D8O
# WweqTWZcGlJO4YjZNI83cTrQghfHl/8AXOHj8cWL3wEFltQQs2xeRYAb3Kdnl7oI
# WKKXWaBYJY5P3QPsiC+DTMp7ejdYKTrb396f3gr+wL/Ms5/Z3vIWZPJJv18qNw40
# fUNveRnwzMQnx8dM2bGuXXQZ5y7P8aXT4HJMo349qZtn4XQwiUE/DDp++MUL0kgj
# vd/Deo7Xr371PFPPYb4TboZhjV1x9+wCHDoOpNCBt+VuXU78ytJdKzQ1Jv2cEP1F
# 9H9/wSLsMDUvWME7u9mGElOPDZPMVr8AuBEuLdbTSEdaLwsZBplzxLBcgxhZ/Cs3
# 0yBhuE3QhqT1YDZ2pa56RexPA2SasPcToT6gJgJ6E06BmZ2zQTNvWOjs5XQqHbYu
# XcoeDcwe2UaC7EDOGD8GmLE9LiqtQsuQCM7v7I2xR+sPZT2Ax/85HjIkM+3MzTK1
# MYIHRjCCB0ICAQEweDBhMQswCQYDVQQGEwJVUzEeMBwGA1UEChMVTWljcm9zb2Z0
# IENvcnBvcmF0aW9uMTIwMAYDVQQDEylNaWNyb3NvZnQgUHVibGljIFJTQSBUaW1l
# c3RhbXBpbmcgQ0EgMjAyMAITMwAAAFck05XgounJMQAAAAAAVzANBglghkgBZQME
# AgEFAKCCBJ8wEQYLKoZIhvcNAQkQAg8xAgUAMBoGCSqGSIb3DQEJAzENBgsqhkiG
# 9w0BCRABBDAcBgkqhkiG9w0BCQUxDxcNMjYwNzA0MTIyOTIxWjAvBgkqhkiG9w0B
# CQQxIgQgwWHlaw/JE14jjbdFQWzhe86fF32nx11bHldVAhkqWiQwgbkGCyqGSIb3
# DQEJEAIvMYGpMIGmMIGjMIGgBCD1PJ9ktQVuTGWIbKLO4f1VUOlUU29ARCEpDZmF
# THjbUjB8MGWkYzBhMQswCQYDVQQGEwJVUzEeMBwGA1UEChMVTWljcm9zb2Z0IENv
# cnBvcmF0aW9uMTIwMAYDVQQDEylNaWNyb3NvZnQgUHVibGljIFJTQSBUaW1lc3Rh
# bXBpbmcgQ0EgMjAyMAITMwAAAFck05XgounJMQAAAAAAVzCCA2EGCyqGSIb3DQEJ
# EAISMYIDUDCCA0yhggNIMIIDRDCCAiwCAQEwggEJoYHhpIHeMIHbMQswCQYDVQQG
# EwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9uZDEeMBwG
# A1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMSUwIwYDVQQLExxNaWNyb3NvZnQg
# QW1lcmljYSBPcGVyYXRpb25zMScwJQYDVQQLEx5uU2hpZWxkIFRTUyBFU046Nzgw
# MC0wNUUwLUQ5NDcxNTAzBgNVBAMTLE1pY3Jvc29mdCBQdWJsaWMgUlNBIFRpbWUg
# U3RhbXBpbmcgQXV0aG9yaXR5oiMKAQEwBwYFKw4DAhoDFQD9LzE5nEJRAUE2Ss3x
# aKKPXHnLw6BnMGWkYzBhMQswCQYDVQQGEwJVUzEeMBwGA1UEChMVTWljcm9zb2Z0
# IENvcnBvcmF0aW9uMTIwMAYDVQQDEylNaWNyb3NvZnQgUHVibGljIFJTQSBUaW1l
# c3RhbXBpbmcgQ0EgMjAyMDANBgkqhkiG9w0BAQsFAAIFAO3zZbwwIhgPMjAyNjA3
# MDQxMDU4MDRaGA8yMDI2MDcwNTEwNTgwNFowdzA9BgorBgEEAYRZCgQBMS8wLTAK
# AgUA7fNlvAIBADAKAgEAAgIgfwIB/zAHAgEAAgISkzAKAgUA7fS3PAIBADA2Bgor
# BgEEAYRZCgQCMSgwJjAMBgorBgEEAYRZCgMCoAowCAIBAAIDB6EgoQowCAIBAAID
# AYagMA0GCSqGSIb3DQEBCwUAA4IBAQA2+4V5zjUQPEsDw26oJaqq2aerRLYEIOze
# NKRHetJxzIRnFzCDUFhdp37jJje8WALwPLf0YtqCO63tUGN2UeU26blKam/7cz0T
# P4qC4cpEjcMgIZSX0b46azAOSWaKBCG8LnHk74DGZma/AhNx9h+2AOjbZmd7wudi
# tEyxOL5ssIe/D+n2JrfbXBLQMe1g7BtdoOxsBhAcFlIvfPaImy3LXFGlIwB5y4oV
# 9sFwM1T2UlFej1gpDBBuIu8IWdBMP5sfB0sDvpcWxhHHGVWsetbBi2whrA6Wu4Bg
# 6wSN8lo7v/pRCAT6w+m3/Ii/4SFSrhMBhEJav3GxDkTY1q1MYOx5MA0GCSqGSIb3
# DQEBAQUABIICACyJ3aVR96YURLGuWBIXbFrUmJS6E4TLEDrBq8HV4uLr9In/JcCY
# RGGvDoDC1xNB+GLhITvkkWf2Sa6GzRUefX3cXe/JsQ2YOfnDGv66msoVAGMJ2n95
# NIdvS1uoZzHNjMZ4ap1qFlpsSFntlCmIUGZpPWHlKOwA2liqB6ud/c8DaPB5GXY8
# reHTkKMtmxLnw8XL7/HPBiNsVr1MT7Q270bMbrIOyzxO1FQUl5J2Wv5znTlDOZUk
# 4BM8lkkjQue6Xuwg96/ByStdKvGGN0GUqzSqS3Q7JKm8jwL35IQP8qenL0dohoD5
# zGipVWassbSy4BOb06GdsYTHb4qtXh0Hrds7T8DpyS/olmKawy5KZ5Lw84AbZNkh
# keJfToTPWuvMtVOlFz7fOluvRPusT1+G7Wn6LuLnmIemR6cEAcJIWWWgDxDbZ1gG
# jtJF78+Cel6AOHuAaOTcoeX90ShN4GJTi2MWWvc4aHhl4KySUd230On9k8HjgWNK
# wVzdb1j+0IxLS7DCIhZMK3ZAps5qYpyWgMEaAhRYfzuAxtBGyLJi98rbzcGD9j6E
# iYcn3rYR9VZ9y1MFwEmNWqHbUnvNyw2Tddq4fdCx37buhEtrtznIlK47ZPZMo3j2
# Y9DZthcbJPBv2/j05Yt5RP6mo58PBaSeBN7rgjiCfC+rD4L22OjqHgyI
# SIG # End signature block