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 = @(
                'CBOR.dll',
                'Numbers.dll',
                'URIUtility.dll'
            )

            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
# MIIt6wYJKoZIhvcNAQcCoIIt3DCCLdgCAQExDzANBglghkgBZQMEAgEFADB5Bgor
# BgEEAYI3AgEEoGswaTA0BgorBgEEAYI3AgEeMCYCAwEAAAQQH8w7YFlLCE63JNLG
# KX7zUQIBAAIBAAIBAAIBAAIBADAxMA0GCWCGSAFlAwQCAQUABCCCmOvac/ho0Ssf
# u8xOXFONFNgEIwZi5bXL9nmbUjOQU6CCEg8wggV4MIIDYKADAgECAhBLLDsBAYut
# KryMe1s+7ZBXMA0GCSqGSIb3DQEBDAUAMFYxCzAJBgNVBAYTAkdCMRgwFgYDVQQK
# Ew9TZWN0aWdvIExpbWl0ZWQxLTArBgNVBAMTJFNlY3RpZ28gUHVibGljIENvZGUg
# U2lnbmluZyBSb290IFI0NjAeFw0yMTAzMjIwMDAwMDBaFw00NjAzMjEyMzU5NTla
# MFYxCzAJBgNVBAYTAkdCMRgwFgYDVQQKEw9TZWN0aWdvIExpbWl0ZWQxLTArBgNV
# BAMTJFNlY3RpZ28gUHVibGljIENvZGUgU2lnbmluZyBSb290IFI0NjCCAiIwDQYJ
# KoZIhvcNAQEBBQADggIPADCCAgoCggIBAI3nlBIiBCR0Lv8WIwKSirauNoWsR9Qj
# kSs+3H3iMaBRb6yEkeNSirXilt7Qh2MkiYr/7xKTO327toq9vQV/J5trZdOlDGmx
# vEk5mvFtbqrkoIMn2poNK1DpS1uzuGQ2pH5KPalxq2Gzc7M8Cwzv2zNX5b40N+OX
# G139HxI9ggN25vs/ZtKUMWn6bbM0rMF6eNySUPJkx6otBKvDaurgL6en3G7X6P/a
# IatAv7nuDZ7G2Z6Z78beH6kMdrMnIKHWuv2A5wHS7+uCKZVwjf+7Fc/+0Q82oi5P
# MpB0RmtHNRN3BTNPYy64LeG/ZacEaxjYcfrMCPJtiZkQsa3bPizkqhiwxgcBdWfe
# beljYx42f2mJvqpFPm5aX4+hW8udMIYw6AOzQMYNDzjNZ6hTiPq4MGX6b8fnHbGD
# dGk+rMRoO7HmZzOatgjggAVIQO72gmRGqPVzsAaV8mxln79VWxycVxrHeEZ8cKqU
# G4IXrIfptskOgRxA1hYXKfxcnBgr6kX1773VZ08oXgXukEx658b00Pz6zT4yRhMg
# NooE6reqB0acDZM6CWaZWFwpo7kMpjA4PNBGNjV8nLruw9X5Cnb6fgUbQMqSNenV
# etG1fwCuqZCqxX8BnBCxFvzMbhjcb2L+plCnuHu4nRU//iAMdcgiWhOVGZAA6RrV
# wobx447sX/TlAgMBAAGjQjBAMB0GA1UdDgQWBBQy65Ka/zWWSC8oQEJwIDaRXBeF
# 5jAOBgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQwF
# AAOCAgEAdmXC49ciStcdiV7/aV7GFAJNc6bNzSjKsDfqv6fJIaqqX9q/9oNs0IDR
# ClwApMvzzDkPnkFxiNU86Ip7jBcj98o0dJFsBq5QPwBZsiY8PBeDVwM+LdEaPdTP
# B1SyQwtScqiI9cQX8m/RWKXRaOQ9mAgY7jb0SEia+lRw8IjUcBYwQknQ2T91S0Vx
# 2K6iu2EOiIVQV7m6ESs2KR+PIHKeXJ6J0YLaRY1qmdqEcWszpRC7efCX9nSBoD9X
# x4aMMIwOOJWuAcYeq9yoH28v1/92Hq4Xc23luXWzYQaolTPCTm+yN/KVvoVUErnI
# vWJCdvcq/PU3MQMmV/7R5tvwFgJyg4wIs4SsqeQH+KGIxBNaUEdUQqbt0EE0LJix
# PqI0oQxdvaz3f3mnv20MVjKFG0uXuOGs5KQ8cfGj4U5j1vRGuvULCOFjPO2iWS8K
# 1CxrI6KeoU3u0RLNGDNQ7UFuy389QWALYwt49XXvQxW3NgsQr9xcGKmY2TbZHdiE
# swaKguN7GySnQs7uDz5WXDJ97EveVis7O7r5eljQUbZs1vZYolIkekSGoRxgP0nT
# /Pr5hBwFwjS/4ubxGSqZL1ZXNZy19QfDRi/eOD0ZDfuj8d8Tnuepclgxr73q2tfW
# bXczM470rP3Bv0mH0nAFZ3QGpvZ4QC0WBJEPH9MWxLh6Fw0kybIwggYaMIIEAqAD
# AgECAhBiHW0MUgGeO5B5FSCJIRwKMA0GCSqGSIb3DQEBDAUAMFYxCzAJBgNVBAYT
# AkdCMRgwFgYDVQQKEw9TZWN0aWdvIExpbWl0ZWQxLTArBgNVBAMTJFNlY3RpZ28g
# UHVibGljIENvZGUgU2lnbmluZyBSb290IFI0NjAeFw0yMTAzMjIwMDAwMDBaFw0z
# NjAzMjEyMzU5NTlaMFQxCzAJBgNVBAYTAkdCMRgwFgYDVQQKEw9TZWN0aWdvIExp
# bWl0ZWQxKzApBgNVBAMTIlNlY3RpZ28gUHVibGljIENvZGUgU2lnbmluZyBDQSBS
# MzYwggGiMA0GCSqGSIb3DQEBAQUAA4IBjwAwggGKAoIBgQCbK51T+jU/jmAGQ2rA
# z/V/9shTUxjIztNsfvxYB5UXeWUzCxEeAEZGbEN4QMgCsJLZUKhWThj/yPqy0iSZ
# hXkZ6Pg2A2NVDgFigOMYzB2OKhdqfWGVoYW3haT29PSTahYkwmMv0b/83nbeECbi
# MXhSOtbam+/36F09fy1tsB8je/RV0mIk8XL/tfCK6cPuYHE215wzrK0h1SWHTxPb
# PuYkRdkP05ZwmRmTnAO5/arnY83jeNzhP06ShdnRqtZlV59+8yv+KIhE5ILMqgOZ
# YAENHNX9SJDm+qxp4VqpB3MV/h53yl41aHU5pledi9lCBbH9JeIkNFICiVHNkRmq
# 4TpxtwfvjsUedyz8rNyfQJy/aOs5b4s+ac7IH60B+Ja7TVM+EKv1WuTGwcLmoU3F
# pOFMbmPj8pz44MPZ1f9+YEQIQty/NQd/2yGgW+ufflcZ/ZE9o1M7a5Jnqf2i2/uM
# SWymR8r2oQBMdlyh2n5HirY4jKnFH/9gRvd+QOfdRrJZb1sCAwEAAaOCAWQwggFg
# MB8GA1UdIwQYMBaAFDLrkpr/NZZILyhAQnAgNpFcF4XmMB0GA1UdDgQWBBQPKssg
# hyi47G9IritUpimqF6TNDDAOBgNVHQ8BAf8EBAMCAYYwEgYDVR0TAQH/BAgwBgEB
# /wIBADATBgNVHSUEDDAKBggrBgEFBQcDAzAbBgNVHSAEFDASMAYGBFUdIAAwCAYG
# Z4EMAQQBMEsGA1UdHwREMEIwQKA+oDyGOmh0dHA6Ly9jcmwuc2VjdGlnby5jb20v
# U2VjdGlnb1B1YmxpY0NvZGVTaWduaW5nUm9vdFI0Ni5jcmwwewYIKwYBBQUHAQEE
# bzBtMEYGCCsGAQUFBzAChjpodHRwOi8vY3J0LnNlY3RpZ28uY29tL1NlY3RpZ29Q
# dWJsaWNDb2RlU2lnbmluZ1Jvb3RSNDYucDdjMCMGCCsGAQUFBzABhhdodHRwOi8v
# b2NzcC5zZWN0aWdvLmNvbTANBgkqhkiG9w0BAQwFAAOCAgEABv+C4XdjNm57oRUg
# mxP/BP6YdURhw1aVcdGRP4Wh60BAscjW4HL9hcpkOTz5jUug2oeunbYAowbFC2AK
# K+cMcXIBD0ZdOaWTsyNyBBsMLHqafvIhrCymlaS98+QpoBCyKppP0OcxYEdU0hps
# aqBBIZOtBajjcw5+w/KeFvPYfLF/ldYpmlG+vd0xqlqd099iChnyIMvY5HexjO2A
# mtsbpVn0OhNcWbWDRF/3sBp6fWXhz7DcML4iTAWS+MVXeNLj1lJziVKEoroGs9Ml
# izg0bUMbOalOhOfCipnx8CaLZeVme5yELg09Jlo8BMe80jO37PU8ejfkP9/uPak7
# VLwELKxAMcJszkyeiaerlphwoKx1uHRzNyE6bxuSKcutisqmKL5OTunAvtONEote
# SiabkPVSZ2z76mKnzAfZxCl/3dq3dUNw4rg3sTCggkHSRqTqlLMS7gjrhTqBmzu1
# L90Y1KWN/Y5JKdGvspbOrTfOXyXvmPL6E52z1NZJ6ctuMFBQZH3pwWvqURR8AgQd
# ULUvrxjUYbHHj95Ejza63zdrEcxWLDX6xWls/GDnVNueKjWUH3fTv1Y8Wdho698Y
# ADR7TNx8X8z2Bev6SivBBOHY+uqiirZtg0y9ShQoPzmCcn63Syatatvx157YK9hl
# cPmVoa1oDE5/L9Uo2bC5a4CH2RwwggZxMIIE2aADAgECAhBsg5osz2x/Auy2idY5
# 0JFYMA0GCSqGSIb3DQEBDAUAMFQxCzAJBgNVBAYTAkdCMRgwFgYDVQQKEw9TZWN0
# aWdvIExpbWl0ZWQxKzApBgNVBAMTIlNlY3RpZ28gUHVibGljIENvZGUgU2lnbmlu
# ZyBDQSBSMzYwHhcNMjIxMTA0MDAwMDAwWhcNMjUxMTAzMjM1OTU5WjBnMQswCQYD
# VQQGEwJDWjEeMBwGA1UECAwVUHJhaGEsIEhsYXZuw60gbcSbc3RvMRswGQYDVQQK
# DBJNaWNoYWVsIEdyYWZuZXR0ZXIxGzAZBgNVBAMMEk1pY2hhZWwgR3JhZm5ldHRl
# cjCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMHVk5c8z27bjQ82tQNj
# cU+ilNAnWJwrb0Pa2Z643b7M+wAKi1DhCsavzRWwPYGKKpPLuSWTipw5P7Tag7i9
# H580wR+mxr1jX8Kd7Qr1Eyt3QRsqXLDAwj67ExDrzcOFcIkSK3UKgZFQL+rFy2HB
# quQsHaGQQ8Jm2sWjGZod88/cmxOGUO0w7qvsysmY0QzzRNbUPpeJMPyzuq8zo2+P
# JYP6qQS535bVGaOaCRcXz3XtpvJt8BMVOUVSjb7cEwfBgDoOL72EP6lqJrMV42TI
# VpjR/rB/zT849lJtkvyAEfEr6UiOAiH9o5hm+GahTqPNMAPovb8hDPQRdu2QUpLg
# W+KHicuQWwoFABqsMIF7Oo00xDuD+J52VU12LwobKINFDJB3BdU3L2aYQRFt3YJQ
# gwH50gh1yNqaTcd78CNb2A5VwNvzTCZ0vhBaKdCK/BsLsu9atLld6FwBI8Pak6iA
# NXuFY0W/whPwlVYzMeTdELzr/m53Fk8DQFcd48SvaYt4dbgU3Q3ySbDDnnBgn/TB
# 5E+DRg7+tZgMH4ep8XXL8F/0gmIvhFXNJGXX9f8A2ox7G7Drj2Guf34P1UKZYjs7
# D2aJ71aPtZKPmXOPpTacuhNhdSVLX4ciwJOaRcZOt9pg2lwzjQVa5kw/GOs5Epeb
# OtHry/SsgiDBiCXVxXxxE9E3AgMBAAGjggGqMIIBpjAfBgNVHSMEGDAWgBQPKssg
# hyi47G9IritUpimqF6TNDDAdBgNVHQ4EFgQUnRBKK1Ym2UQhxb0SetlSGK5huJMw
# DgYDVR0PAQH/BAQDAgeAMAwGA1UdEwEB/wQCMAAwEwYDVR0lBAwwCgYIKwYBBQUH
# AwMwSgYDVR0gBEMwQTA1BgwrBgEEAbIxAQIBAwIwJTAjBggrBgEFBQcCARYXaHR0
# cHM6Ly9zZWN0aWdvLmNvbS9DUFMwCAYGZ4EMAQQBMEkGA1UdHwRCMEAwPqA8oDqG
# OGh0dHA6Ly9jcmwuc2VjdGlnby5jb20vU2VjdGlnb1B1YmxpY0NvZGVTaWduaW5n
# Q0FSMzYuY3JsMHkGCCsGAQUFBwEBBG0wazBEBggrBgEFBQcwAoY4aHR0cDovL2Ny
# dC5zZWN0aWdvLmNvbS9TZWN0aWdvUHVibGljQ29kZVNpZ25pbmdDQVIzNi5jcnQw
# IwYIKwYBBQUHMAGGF2h0dHA6Ly9vY3NwLnNlY3RpZ28uY29tMB8GA1UdEQQYMBaB
# FGluZm9AZHNpbnRlcm5hbHMuY29tMA0GCSqGSIb3DQEBDAUAA4IBgQAuRlAwdZ32
# WVvW4tsRBmmPtse5BOqYjCP4OkxCYn47Sc+zajMgqDj8M5kGSx6SYexUbBcVssAu
# pkpIW7YDGRDo4mGJWY6zFqTXLthtRL14TfiFTTwtpLLSWsRkHbwCbRXbhchpH3nA
# pPshTMvd49gKKRT+AtDr5RrPVnh1LMYZdwuvQpWhkPgT/P0OYKTYtiieW5hSebdl
# /IaGVx1KJi/FrC9MaXj72nvjAaCk5drri7QSsf8R+ghRy5mUJShX11L1nJrGW80s
# hjaRBroT7ktr3WKryuc1cHvkXkKWZq78JosUWfGOtSQ0TJ9AiT+wBAbqtyv1H2X7
# wYNrrcq5cT543yO+SVhiuH+OQZZFjkYdhG5OoZgzABz/mXeHY4VnJHY+SuHJV3oy
# kb4NajXiID4+iy3bgQOdghwMARNUMwsdYlpXqw13iD/Li4B4weFq8d/1ZEa1BFtV
# DALXqV5+ZB4FJ/8CmonbGFIeHZfjj2PhcPL5rgGeMnFOwBjpZyvW4FUxghsyMIIb
# LgIBATBoMFQxCzAJBgNVBAYTAkdCMRgwFgYDVQQKEw9TZWN0aWdvIExpbWl0ZWQx
# KzApBgNVBAMTIlNlY3RpZ28gUHVibGljIENvZGUgU2lnbmluZyBDQSBSMzYCEGyD
# mizPbH8C7LaJ1jnQkVgwDQYJYIZIAWUDBAIBBQCggYQwGAYKKwYBBAGCNwIBDDEK
# MAigAoAAoQKAADAZBgkqhkiG9w0BCQMxDAYKKwYBBAGCNwIBBDAcBgorBgEEAYI3
# AgELMQ4wDAYKKwYBBAGCNwIBFTAvBgkqhkiG9w0BCQQxIgQgRSoUSbPP3K8HWmSs
# 2E5MHxblWpx86wcmVbywONDDFyEwDQYJKoZIhvcNAQEBBQAEggIAa3UVRozUvitf
# MiJEzT+IeZFySA78M6RfaJRuN68dpptOR5Ts1JCyBl98xvQnDz46+8zvGykwAE7i
# Oo2Os8ckumJU7ccV0u/MHMHD6jtRCBZaf8hsq7RKwtjkaVhkBStDWVkP+lCuina6
# 2Kw2LIbi1SmiPdDmgtZ/AEgpwjmIcqe9xcAaXTo+luASZkjBNrsl5Fskrg8lsdyr
# HnEt/HUNu3Jk/AGDtrpm4qTnnG0IBdtFjffqAfTtGbKXVFTuVMjSoOqScXjEr2IV
# 5GZpL24Rx6qF/jhP7xyZBeZYkUhegOqfXkf0sPWWMv9WKrfV7NMovEBgCdKTU0Gr
# V4sMRgQc9Gr0TaZnFdrwLi9s5b9oJSTPzk8OwdszkQeHJ/jSgn0V+m6o6GJmzUVh
# UqiIYDI8/BLyOU+xr8MakXD2tiPwHMKfX8JxARjxUeSiQIlyRQAXk9otgCcao5S3
# NUnPTzLvEciVg/QdsKFVhkb/vyraxAGZb8vWbzMF5qXGpQKLRWkoP0GnKD92sD0A
# L1EQTONnQrBAS1eFySpLK4CJYWxzW2AmJQcD7reSLxdkj+vvuqZ89hSj0qNU8SVY
# BdALNpGAnQa84sbaciOBXHVmfvCHoO6PplKFEDanqcjC4MIoCa6SNCeFxzacO6CL
# mt5y40YsZxf/cOZ5ArNMm+oqOUSE7T6hghgUMIIYEAYKKwYBBAGCNwMDATGCGAAw
# ghf8BgkqhkiG9w0BBwKgghftMIIX6QIBAzEPMA0GCWCGSAFlAwQCAQUAMIIBYgYL
# KoZIhvcNAQkQAQSgggFRBIIBTTCCAUkCAQEGCisGAQQBhFkKAwEwMTANBglghkgB
# ZQMEAgEFAAQgGIIaMkWEo0HNPHvUexWz7Hyy50gZqcuzhhzEbcVx2EACBmieaX8p
# TBgTMjAyNTA4MTkwNjU2MDAuMzI2WjAEgAIB9KCB4aSB3jCB2zELMAkGA1UEBhMC
# VVMxEzARBgNVBAgTCldhc2hpbmd0b24xEDAOBgNVBAcTB1JlZG1vbmQxHjAcBgNV
# BAoTFU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjElMCMGA1UECxMcTWljcm9zb2Z0IEFt
# ZXJpY2EgT3BlcmF0aW9uczEnMCUGA1UECxMeblNoaWVsZCBUU1MgRVNOOjdEMDAt
# MDVFMC1EOTQ3MTUwMwYDVQQDEyxNaWNyb3NvZnQgUHVibGljIFJTQSBUaW1lIFN0
# YW1waW5nIEF1dGhvcml0eaCCDyEwggeCMIIFaqADAgECAhMzAAAABeXPD/9mLsmH
# AAAAAAAFMA0GCSqGSIb3DQEBDAUAMHcxCzAJBgNVBAYTAlVTMR4wHAYDVQQKExVN
# aWNyb3NvZnQgQ29ycG9yYXRpb24xSDBGBgNVBAMTP01pY3Jvc29mdCBJZGVudGl0
# eSBWZXJpZmljYXRpb24gUm9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkgMjAyMDAe
# Fw0yMDExMTkyMDMyMzFaFw0zNTExMTkyMDQyMzFaMGExCzAJBgNVBAYTAlVTMR4w
# HAYDVQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xMjAwBgNVBAMTKU1pY3Jvc29m
# dCBQdWJsaWMgUlNBIFRpbWVzdGFtcGluZyBDQSAyMDIwMIICIjANBgkqhkiG9w0B
# AQEFAAOCAg8AMIICCgKCAgEAnnznUmP94MWfBX1jtQYioxwe1+eXM9ETBb1lRkd3
# kcFdcG9/sqtDlwxKoVIcaqDb+omFio5DHC4RBcbyQHjXCwMk/l3TOYtgoBjxnG/e
# ViS4sOx8y4gSq8Zg49REAf5huXhIkQRKe3Qxs8Sgp02KHAznEa/Ssah8nWo5hJM1
# xznkRsFPu6rfDHeZeG1Wa1wISvlkpOQooTULFm809Z0ZYlQ8Lp7i5F9YciFlyAKw
# n6yjN/kR4fkquUWfGmMopNq/B8U/pdoZkZZQbxNlqJOiBGgCWpx69uKqKhTPVi3g
# VErnc/qi+dR8A2MiAz0kN0nh7SqINGbmw5OIRC0EsZ31WF3Uxp3GgZwetEKxLms7
# 3KG/Z+MkeuaVDQQheangOEMGJ4pQZH55ngI0Tdy1bi69INBV5Kn2HVJo9XxRYR/J
# PGAaM6xGl57Ei95HUw9NV/uC3yFjrhc087qLJQawSC3xzY/EXzsT4I7sDbxOmM2r
# l4uKK6eEpurRduOQ2hTkmG1hSuWYBunFGNv21Kt4N20AKmbeuSnGnsBCd2cjRKG7
# 9+TX+sTehawOoxfeOO/jR7wo3liwkGdzPJYHgnJ54UxbckF914AqHOiEV7xTnD1a
# 69w/UTxwjEugpIPMIIE67SFZ2PMo27xjlLAHWW3l1CEAFjLNHd3EQ79PUr8FUXet
# Xr0CAwEAAaOCAhswggIXMA4GA1UdDwEB/wQEAwIBhjAQBgkrBgEEAYI3FQEEAwIB
# ADAdBgNVHQ4EFgQUa2koOjUvSGNAz3vYr0npPtk92yEwVAYDVR0gBE0wSzBJBgRV
# HSAAMEEwPwYIKwYBBQUHAgEWM2h0dHA6Ly93d3cubWljcm9zb2Z0LmNvbS9wa2lv
# cHMvRG9jcy9SZXBvc2l0b3J5Lmh0bTATBgNVHSUEDDAKBggrBgEFBQcDCDAZBgkr
# BgEEAYI3FAIEDB4KAFMAdQBiAEMAQTAPBgNVHRMBAf8EBTADAQH/MB8GA1UdIwQY
# MBaAFMh+0mqFKhvKGZgEByfPUBBPaKiiMIGEBgNVHR8EfTB7MHmgd6B1hnNodHRw
# Oi8vd3d3Lm1pY3Jvc29mdC5jb20vcGtpb3BzL2NybC9NaWNyb3NvZnQlMjBJZGVu
# dGl0eSUyMFZlcmlmaWNhdGlvbiUyMFJvb3QlMjBDZXJ0aWZpY2F0ZSUyMEF1dGhv
# cml0eSUyMDIwMjAuY3JsMIGUBggrBgEFBQcBAQSBhzCBhDCBgQYIKwYBBQUHMAKG
# dWh0dHA6Ly93d3cubWljcm9zb2Z0LmNvbS9wa2lvcHMvY2VydHMvTWljcm9zb2Z0
# JTIwSWRlbnRpdHklMjBWZXJpZmljYXRpb24lMjBSb290JTIwQ2VydGlmaWNhdGUl
# MjBBdXRob3JpdHklMjAyMDIwLmNydDANBgkqhkiG9w0BAQwFAAOCAgEAX4h2x35t
# tVoVdedMeGj6TuHYRJklFaW4sTQ5r+k77iB79cSLNe+GzRjv4pVjJviceW6AF6yc
# WoEYR0LYhaa0ozJLU5Yi+LCmcrdovkl53DNt4EXs87KDogYb9eGEndSpZ5ZM74LN
# vVzY0/nPISHz0Xva71QjD4h+8z2XMOZzY7YQ0Psw+etyNZ1CesufU211rLslLKsO
# 8F2aBs2cIo1k+aHOhrw9xw6JCWONNboZ497mwYW5EfN0W3zL5s3ad4Xtm7yFM7Uj
# rhc0aqy3xL7D5FR2J7x9cLWMq7eb0oYioXhqV2tgFqbKHeDick+P8tHYIFovIP7Y
# G4ZkJWag1H91KlELGWi3SLv10o4KGag42pswjybTi4toQcC/irAodDW8HNtX+cbz
# 0sMptFJK+KObAnDFHEsukxD+7jFfEV9Hh/+CSxKRsmnuiovCWIOb+H7DRon9Tlxy
# diFhvu88o0w35JkNbJxTk4MhF/KgaXn0GxdH8elEa2Imq45gaa8D+mTm8LWVydt4
# ytxYP/bqjN49D9NZ81coE6aQWm88TwIf4R4YZbOpMKN0CyejaPNN41LGXHeCUMYm
# Bx3PkP8ADHD1J2Cr/6tjuOOCztfp+o9Nc+ZoIAkpUcA/X2gSMkgHAPUvIdtoSAHE
# UKiBhI6JQivRepyvWcl+JYbYbBh7pmgAXVswggeXMIIFf6ADAgECAhMzAAAAS6Gx
# reFZ/Oc0AAAAAABLMA0GCSqGSIb3DQEBDAUAMGExCzAJBgNVBAYTAlVTMR4wHAYD
# VQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xMjAwBgNVBAMTKU1pY3Jvc29mdCBQ
# dWJsaWMgUlNBIFRpbWVzdGFtcGluZyBDQSAyMDIwMB4XDTI0MTEyNjE4NDg1N1oX
# DTI1MTExOTE4NDg1N1owgdsxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpXYXNoaW5n
# dG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNyb3NvZnQgQ29ycG9y
# YXRpb24xJTAjBgNVBAsTHE1pY3Jvc29mdCBBbWVyaWNhIE9wZXJhdGlvbnMxJzAl
# BgNVBAsTHm5TaGllbGQgVFNTIEVTTjo3RDAwLTA1RTAtRDk0NzE1MDMGA1UEAxMs
# TWljcm9zb2Z0IFB1YmxpYyBSU0EgVGltZSBTdGFtcGluZyBBdXRob3JpdHkwggIi
# MA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCdnYqzfzSDLZ8t/IcnBhZ/VS77
# fz7MIUKa1I9mDjnJRNPdVWovmgU5UbARCbLCIIzZj8J0/YDeyJBDYFTySXAgaHlD
# w06rUBcryq2eaxoWfShTHSdlOnyzhDUw8GXGYJT1x/q+nGm6k1oruwW2wrYNR86/
# Q5sr1XYCJlM8yteWaJFvZJGE6vCOPQxni/lEN2qoTrq2ejmpVVMPngkX9IMCyrlx
# av40gC15WTU7dZ3o19bQs7u+drzbzON0MtKsqa1vDFsHuqvH2q1S21zETmed/llm
# TK5QaRLLhk5WCd9w1n/Do5gHarg6Jv861uSCqAdMdNnI34fnTsIRnaEtCGWGu7W1
# Zd7blHSligBaGALIC61vJzWj1Mb8JxhhmhfPX20d6nB1Jpmm4qIP/FW02uCxJSq9
# Fe8ziedvlg4m1aCqjWX0Q566/i7VieVsOA3rx1xRXeIbADmsxnw36YlZohsqREsZ
# UMjQZ4e6cCfKAlaO02ca7GizIRn7mNvzHNYc47gQCFEC+YgX2SLvw4b6R5Taq43X
# J0hfhDwPSPiT60dySjLUIcmDcs2vI878t3WxEl2an9HJCaYPKvV/UZ1Ay9HjkSJc
# 3ZqIXvgGlh1VI7kCpPTBayY7RC0IzJl5a7+DM7FcBhei9h1eJ8AdZszVcUGk+LkF
# +uqU3GAnjYadJC/x2QIDAQABo4IByzCCAccwHQYDVR0OBBYEFCCZGsUvRVF/zToR
# WkE3JYWmuHQmMB8GA1UdIwQYMBaAFGtpKDo1L0hjQM972K9J6T7ZPdshMGwGA1Ud
# HwRlMGMwYaBfoF2GW2h0dHA6Ly93d3cubWljcm9zb2Z0LmNvbS9wa2lvcHMvY3Js
# L01pY3Jvc29mdCUyMFB1YmxpYyUyMFJTQSUyMFRpbWVzdGFtcGluZyUyMENBJTIw
# MjAyMC5jcmwweQYIKwYBBQUHAQEEbTBrMGkGCCsGAQUFBzAChl1odHRwOi8vd3d3
# Lm1pY3Jvc29mdC5jb20vcGtpb3BzL2NlcnRzL01pY3Jvc29mdCUyMFB1YmxpYyUy
# MFJTQSUyMFRpbWVzdGFtcGluZyUyMENBJTIwMjAyMC5jcnQwDAYDVR0TAQH/BAIw
# ADAWBgNVHSUBAf8EDDAKBggrBgEFBQcDCDAOBgNVHQ8BAf8EBAMCB4AwZgYDVR0g
# BF8wXTBRBgwrBgEEAYI3TIN9AQEwQTA/BggrBgEFBQcCARYzaHR0cDovL3d3dy5t
# aWNyb3NvZnQuY29tL3BraW9wcy9Eb2NzL1JlcG9zaXRvcnkuaHRtMAgGBmeBDAEE
# AjANBgkqhkiG9w0BAQwFAAOCAgEAMb3YbNgyOUIdvrmh8yK25QWzU4kVUvlJmCyg
# DGdnUKokh4ZAMzZu+c7cTlw+hcCH8vbx7zMRbKbLzp1XOXP+/BvnUKynTgEGBkXP
# EbKwEezCtNwGZm7fAHHh7fAC8GN0R4dEneZBuyvUwjv/RMa3bRCN0IuMTsIpjzwO
# VivH6lDU8o6dxkE6w+1EhKgImb3iCnGXS1gnotzJ6oa0x3lYMuirYOpLFlc54xJR
# 1RncJBKqVqC+2vu31GRaVmBiwVU/bFuYN0o6LVnAPTcu1fMDcn6ts5EbW5chgEMF
# IoUM3tSDMNXoMIQkMQvN3beZpjnLDb4V8OANLd5oXz+bd+p5zW21v6odGTBUX/qh
# jSxBhTbwTPqlV1/Dx95x/6/52PrETq6bQb6t6TAFq4fpXTmRo8uBVj1pkGVljJPD
# xvi6DyaBZECqlHQws8wM4qDWTk9hTIZrKlK/mvD6J3hR782HLG6WJiEuuVSxv+8z
# sI86ibPK6ywwjlBloH6/+YEtQtS4gIx4D/1xnP7qVfK7FcPtRO4AHEw2g+Nm37R+
# 6B+RDime4WvUvxR8FweNjEry0QGtQVvZcEIflDXryIp2UdQIIgW+zmUO2b05Tulk
# FPIsiVsgcAYPZjeBuyJkdlhZpYdP0JpYPQiUZTY3hjkum3n/7FnEaVhOV+ZdS+0X
# XVa3A7kxggdGMIIHQgIBATB4MGExCzAJBgNVBAYTAlVTMR4wHAYDVQQKExVNaWNy
# b3NvZnQgQ29ycG9yYXRpb24xMjAwBgNVBAMTKU1pY3Jvc29mdCBQdWJsaWMgUlNB
# IFRpbWVzdGFtcGluZyBDQSAyMDIwAhMzAAAAS6GxreFZ/Oc0AAAAAABLMA0GCWCG
# SAFlAwQCAQUAoIIEnzARBgsqhkiG9w0BCRACDzECBQAwGgYJKoZIhvcNAQkDMQ0G
# CyqGSIb3DQEJEAEEMBwGCSqGSIb3DQEJBTEPFw0yNTA4MTkwNjU2MDBaMC8GCSqG
# SIb3DQEJBDEiBCBtgw4jKsS0QYivaAk5wh9WWFwfXZP/CXgoVeygTWth4DCBuQYL
# KoZIhvcNAQkQAi8xgakwgaYwgaMwgaAEINuJKJ0rsvRcScm4woZmCKowMSTh9DWm
# 0OSNAeUABkSnMHwwZaRjMGExCzAJBgNVBAYTAlVTMR4wHAYDVQQKExVNaWNyb3Nv
# ZnQgQ29ycG9yYXRpb24xMjAwBgNVBAMTKU1pY3Jvc29mdCBQdWJsaWMgUlNBIFRp
# bWVzdGFtcGluZyBDQSAyMDIwAhMzAAAAS6GxreFZ/Oc0AAAAAABLMIIDYQYLKoZI
# hvcNAQkQAhIxggNQMIIDTKGCA0gwggNEMIICLAIBATCCAQmhgeGkgd4wgdsxCzAJ
# BgNVBAYTAlVTMRMwEQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25k
# MR4wHAYDVQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xJTAjBgNVBAsTHE1pY3Jv
# c29mdCBBbWVyaWNhIE9wZXJhdGlvbnMxJzAlBgNVBAsTHm5TaGllbGQgVFNTIEVT
# Tjo3RDAwLTA1RTAtRDk0NzE1MDMGA1UEAxMsTWljcm9zb2Z0IFB1YmxpYyBSU0Eg
# VGltZSBTdGFtcGluZyBBdXRob3JpdHmiIwoBATAHBgUrDgMCGgMVAPV6ws6b5FNH
# UOmEILADVgzql5kzoGcwZaRjMGExCzAJBgNVBAYTAlVTMR4wHAYDVQQKExVNaWNy
# b3NvZnQgQ29ycG9yYXRpb24xMjAwBgNVBAMTKU1pY3Jvc29mdCBQdWJsaWMgUlNB
# IFRpbWVzdGFtcGluZyBDQSAyMDIwMA0GCSqGSIb3DQEBCwUAAgUA7E4t0DAiGA8y
# MDI1MDgxODIyNTUxMloYDzIwMjUwODE5MjI1NTEyWjB3MD0GCisGAQQBhFkKBAEx
# LzAtMAoCBQDsTi3QAgEAMAoCAQACAljXAgH/MAcCAQACAhJUMAoCBQDsT39QAgEA
# MDYGCisGAQQBhFkKBAIxKDAmMAwGCisGAQQBhFkKAwKgCjAIAgEAAgMHoSChCjAI
# AgEAAgMBhqAwDQYJKoZIhvcNAQELBQADggEBANogbzkxPk3pV5UuaXK4kVcfMmdc
# P2Ao6BME1sdga1rVhYyrYjoXQpNVTg4skyquKlRLGU8FhhawpAHaeofiM4yJL6ED
# aIDzInwnnMuroOMuMmxyNPDtRvbNKvOdbMW20tPnw91YTW0NVNv2t2Id070hahRo
# luGsZZ4aEaWKX1nmsUnq9nbg6T73b6qi4kdo4sISaWr0XKTo/dLEEGCJXKSLud9u
# 90TGozaY4Q/fZxnHzN3dJJA/XbCIc/xPt/dLUEDXBAju8ZsKL5cYsMTYuQRy8Y4X
# yiX9mS0802+261tzPqDtLoyesqOsqG2zARARLJLPSpdxDSqGqVVRx6S1ADswDQYJ
# KoZIhvcNAQEBBQAEggIAWWNLRRlYahN3nigVRuccslOZZm8CazG8k5ltbVeG99Xu
# g/YbWrZwJXKpMvd0wRv8MVBRbsIdU/JxSVdGnitENbI3we3olhwDF9JC/SrMIaS3
# wtMSe1OgswH0e1IZYe1Xtr5Uo8G+8XNQgh4ci8O/8KfAjmvtK7rk3MxrGkQ2Uzbt
# nRfL4tqa2eurGWaPQboKjwiwX5eRwW/vIvZ+tR3AlxM9NPytLeiqRAKRX4W4DTmO
# gMofpBa5tmRONaGKEyyROLkTfyqZ9fkc4deuwhm19C8fRcCpKjf5ghxws3/K+Tzn
# 960gutpnz3Ez5V9wnc+nP/Km/a1Tkam+TvSfdnM+9aHpuxfugSkQswyDE5Zy9fie
# OyVCFkC54wNiA4w2ZmcBmwf/xcDR5Dn1oMEbLfOP94tU27pKURfxlCz2BKdcEgDr
# okr48/hTcIJoEfpjozb4rOw2akJWEeJzbKFixC2O9uYgtCcWjtR273owD+j8/dwF
# 80KKQDC7n6DS6jyqyMNSR7Ka1hnQayFtwlskqsW6vzwHyTb4EUN0o2xoNz7NmGSX
# SlDrsqF/cSz/fQce++RNhVBHB0JmJDF44O6If3JIKC3ClTpoyxZvJvaCJnkU/3fw
# Os2wQbKWDzL9MGqHFzZ3McOufdCLG5BTedme04bqVqxG3y2dG83dXEkJKyiF//s=
# SIG # End signature block