Tests/DCCMPA703-Encoding.Tests.ps1

#Requires -Modules Pester
<#
.SYNOPSIS
    DCCMPA-703 Encoding Validation Unit Tests
.DESCRIPTION
    Pester unit tests to validate all DSC resource .psm1 files have correct
    UTF-16 LE encoding, proper BOM markers, intact line breaks, clean parse,
    sanitized error handlers (Fix 2), and consistent CRLF line endings.
.NOTES
    Run with: Invoke-Pester -Path <this file> -Output Detailed
#>


BeforeDiscovery {
    $dscBasePath = Join-Path (Split-Path -Parent (Split-Path -Parent $PSScriptRoot)) "DellSMBIOSProvider_DesiredStateConfiguration"
    $script:fileTestData = @()
    foreach ($folder in @("DSCResources", "DSCResourcesARM64")) {
        $folderPath = Join-Path $dscBasePath $folder
        if (Test-Path $folderPath) {
            Get-ChildItem -Path $folderPath -Filter "*.psm1" -Recurse | ForEach-Object {
                $script:fileTestData += @{
                    FullName     = $_.FullName
                    FileName     = $_.Name
                    Folder       = $folder
                    ResourceName = $_.Directory.Name
                    RelPath      = "$folder\$($_.Directory.Name)\$($_.Name)"
                }
            }
        }
    }
    $script:fileCount = $script:fileTestData.Count
    $script:x64Count = ($script:fileTestData | Where-Object { $_.Folder -eq "DSCResources" }).Count
    $script:arm64Count = ($script:fileTestData | Where-Object { $_.Folder -eq "DSCResourcesARM64" }).Count
}

Describe "DCCMPA-703 DSC Resource File Discovery" {
    BeforeAll {
        $dscBase = Join-Path (Split-Path -Parent (Split-Path -Parent $PSScriptRoot)) "DellSMBIOSProvider_DesiredStateConfiguration"
        $allFiles = @()
        foreach ($f in @("DSCResources", "DSCResourcesARM64")) {
            $fp = Join-Path $dscBase $f
            if (Test-Path $fp) {
                Get-ChildItem -Path $fp -Filter "*.psm1" -Recurse | ForEach-Object {
                    $allFiles += @{ Folder = $f }
                }
            }
        }
        $script:totalFiles = $allFiles.Count
        $script:x64Files = ($allFiles | Where-Object { $_.Folder -eq "DSCResources" }).Count
        $script:arm64Files = ($allFiles | Where-Object { $_.Folder -eq "DSCResourcesARM64" }).Count
    }

    It "Should find exactly 44 DSC .psm1 files (22 x64 + 22 ARM64)" {
        $script:totalFiles | Should -Be 44
    }
    
    It "Should have 22 x64 DSC resources" {
        $script:x64Files | Should -Be 22
    }
    
    It "Should have 22 ARM64 DSC resources" {
        $script:arm64Files | Should -Be 22
    }
}

Describe "DCCMPA-703 UTF-16 LE BOM Validation" {
    It "<RelPath> should have UTF-16 LE BOM (FF FE)" -ForEach $script:fileTestData {
        $bytes = [System.IO.File]::ReadAllBytes($FullName)
        $bytes.Length | Should -BeGreaterThan 2
        $bytes[0] | Should -Be 0xFF -Because "First BOM byte should be 0xFF for UTF-16 LE"
        $bytes[1] | Should -Be 0xFE -Because "Second BOM byte should be 0xFE for UTF-16 LE"
    }
}

Describe "DCCMPA-703 UTF-16 Null Byte Pattern" {
    It "<RelPath> should have UTF-16 null byte pattern" -ForEach $script:fileTestData {
        $bytes = [System.IO.File]::ReadAllBytes($FullName)
        $hasNullPattern = $false
        for ($i = 3; $i -lt [Math]::Min(100, $bytes.Length); $i += 2) {
            if ($bytes[$i] -eq 0x00) { $hasNullPattern = $true; break }
        }
        $hasNullPattern | Should -BeTrue -Because "UTF-16 LE should have null bytes at odd positions for ASCII content"
    }
}

Describe "DCCMPA-703 Line Break Integrity" {
    It "<RelPath> should have more than 50 lines" -ForEach $script:fileTestData {
        $content = [System.IO.File]::ReadAllText($FullName, [System.Text.Encoding]::Unicode)
        $lineCount = ($content -split "`r`n|`n").Count
        $lineCount | Should -BeGreaterThan 50 -Because "1 line = encoding corruption"
    }
}

Describe "DCCMPA-703 CRLF Line Ending Consistency" {
    It "<RelPath> should use CRLF line endings" -ForEach $script:fileTestData {
        $content = [System.IO.File]::ReadAllText($FullName, [System.Text.Encoding]::Unicode)
        $crlfCount = ([regex]::Matches($content, "`r`n")).Count
        $crlfCount | Should -BeGreaterThan 0 -Because "File should have CRLF line endings"
    }
}

Describe "DCCMPA-703 PowerShell Parse Validation" {
    It "<RelPath> should parse without errors" -ForEach $script:fileTestData {
        $errors = $null
        [System.Management.Automation.Language.Parser]::ParseFile($FullName, [ref]$null, [ref]$errors) | Out-Null
        $errors.Count | Should -Be 0 -Because "DSC resource file should have zero parse errors"
    }
}

Describe "DCCMPA-703 Fix 2 - Error Handler Sanitization" {
    It "<RelPath> should NOT contain vulnerable InvocationInfo.Line" -ForEach $script:fileTestData {
        $content = [System.IO.File]::ReadAllText($FullName, [System.Text.Encoding]::Unicode)
        $content | Should -Not -Match 'InvocationInfo\.Line' -Because "Fix 2 removes InvocationInfo.Line to prevent credential leakage"
    }
    
    It "<RelPath> should have sanitized error handler" -ForEach $script:fileTestData {
        $content = [System.IO.File]::ReadAllText($FullName, [System.Text.Encoding]::Unicode)
        $hasCatchBlock = $content -match 'catch\s*\{'
        if ($hasCatchBlock) {
            $content | Should -Match 'An error occured while executing DSC resource'
        } else {
            Set-ItResult -Skipped -Because "$FileName has no catch blocks"
        }
    }
}

Describe "DCCMPA-703 File Size Validation" {
    It "<RelPath> should not be suspiciously small" -ForEach $script:fileTestData {
        $fileSize = (Get-Item $FullName).Length
        $fileSize | Should -BeGreaterThan 3000 -Because "DSC resource files in UTF-16 should be at least 3KB"
    }
}

Describe "DCCMPA-703 DSC Resource Import Validation" {
    BeforeAll {
        $script:DscResources = @()
        try {
            $script:DscResources = Get-DscResource -Module DellBIOSProvider -ErrorAction Stop
        } catch { }
    }
    
    It "Should find DSC resources from DellBIOSProvider module" {
        $script:DscResources.Count | Should -BeGreaterThan 0
    }
    
    It "DSC resource <ResourceName> should be importable" -ForEach @(
        @{ ResourceName = "POSTBehavior" }
        @{ ResourceName = "PowerManagement" }
        @{ ResourceName = "Security" }
        @{ ResourceName = "SystemConfiguration" }
        @{ ResourceName = "Performance" }
        @{ ResourceName = "AdvancedBootOptions" }
        @{ ResourceName = "MiscellaneousDevices" }
        @{ ResourceName = "Wireless" }
        @{ ResourceName = "Maintenance" }
        @{ ResourceName = "Video" }
        @{ ResourceName = "SecureBoot" }
        @{ ResourceName = "TPMSecurity" }
        @{ ResourceName = "VirtualizationSupport" }
        @{ ResourceName = "SystemLogs" }
        @{ ResourceName = "StealthModeControl" }
        @{ ResourceName = "IntelSoftwareGuardExtensions" }
        @{ ResourceName = "SupportAssistSystemResolution" }
        @{ ResourceName = "AdvancedConfigurations" }
        @{ ResourceName = "BIOSSetupAdvancedMode" }
    ) {
        $resource = $script:DscResources | Where-Object { $_.Name -eq $ResourceName }
        $resource | Should -Not -BeNullOrEmpty
    }
}

Describe "DCCMPA-703 Encoding Regression Guard" {
    It "<RelPath> should not be UTF-8 encoded (regression check)" -ForEach $script:fileTestData {
        $bytes = [System.IO.File]::ReadAllBytes($FullName)
        $isUtf8BOM = ($bytes[0] -eq 0xEF -and $bytes[1] -eq 0xBB -and $bytes[2] -eq 0xBF)
        $isUtf8BOM | Should -BeFalse -Because "UTF-8 encoding would cause DSC parse failures"
        
        $isPlainAscii = ($bytes[0] -ne 0xFF -and $bytes[0] -ne 0xFE -and $bytes[1] -ne 0x00)
        $isPlainAscii | Should -BeFalse -Because "Must not be plain ASCII/UTF-8 without BOM"
    }
}

# SIG # Begin signature block
# MIIpLgYJKoZIhvcNAQcCoIIpHzCCKRsCAQExDzANBglghkgBZQMEAgMFADCBmwYK
# KwYBBAGCNwIBBKCBjDCBiTA0BgorBgEEAYI3AgEeMCYCAwEAAAQQH8w7YFlLCE63
# JNLGKX7zUQIBAAIBAAIBAAIBAAIBADBRMA0GCWCGSAFlAwQCAwUABECE5BpyI1l4
# 2Q23Mhsri5XfLhm68/PCTHPLsrMRXaJsltRPsgQQoqLeKS+odP00ghyqRfwaKlvh
# 0yeoS0AVpq7JoIIOHzCCBrAwggSYoAMCAQICEAitQLJg0pxMn17Nqb2TrtkwDQYJ
# KoZIhvcNAQEMBQAwYjELMAkGA1UEBhMCVVMxFTATBgNVBAoTDERpZ2lDZXJ0IElu
# YzEZMBcGA1UECxMQd3d3LmRpZ2ljZXJ0LmNvbTEhMB8GA1UEAxMYRGlnaUNlcnQg
# VHJ1c3RlZCBSb290IEc0MB4XDTIxMDQyOTAwMDAwMFoXDTM2MDQyODIzNTk1OVow
# aTELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDkRpZ2lDZXJ0LCBJbmMuMUEwPwYDVQQD
# EzhEaWdpQ2VydCBUcnVzdGVkIEc0IENvZGUgU2lnbmluZyBSU0E0MDk2IFNIQTM4
# NCAyMDIxIENBMTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBANW0L0LQ
# KK14t13VOVkbsYhC9TOM6z2Bl3DFu8SFJjCfpI5o2Fz16zQkB+FLT9N4Q/QX1x7a
# +dLVZxpSTw6hV/yImcGRzIEDPk1wJGSzjeIIfTR9TIBXEmtDmpnyxTsf8u/LR1oT
# pkyzASAl8xDTi7L7CPCK4J0JwGWn+piASTWHPVEZ6JAheEUuoZ8s4RjCGszF7pNJ
# cEIyj/vG6hzzZWiRok1MghFIUmjeEL0UV13oGBNlxX+yT4UsSKRWhDXW+S6cqgAV
# 0Tf+GgaUwnzI6hsy5srC9KejAw50pa85tqtgEuPo1rn3MeHcreQYoNjBI0dHs6EP
# bqOrbZgGgxu3amct0r1EGpIQgY+wOwnXx5syWsL/amBUi0nBk+3htFzgb+sm+YzV
# svk4EObqzpH1vtP7b5NhNFy8k0UogzYqZihfsHPOiyYlBrKD1Fz2FRlM7WLgXjPy
# 6OjsCqewAyuRsjZ5vvetCB51pmXMu+NIUPN3kRr+21CiRshhWJj1fAIWPIMorTmG
# 7NS3DVPQ+EfmdTCN7DCTdhSmW0tddGFNPxKRdt6/WMtyEClB8NXFbSZ2aBFBE1ia
# 3CYrAfSJTVnbeM+BSj5AR1/JgVBzhRAjIVlgimRUwcwhGug4GXxmHM14OEUwmU//
# Y09Mu6oNCFNBfFg9R7P6tuyMMgkCzGw8DFYRAgMBAAGjggFZMIIBVTASBgNVHRMB
# Af8ECDAGAQH/AgEAMB0GA1UdDgQWBBRoN+Drtjv4XxGG+/5hewiIZfROQjAfBgNV
# HSMEGDAWgBTs1+OC0nFdZEzfLmc/57qYrhwPTzAOBgNVHQ8BAf8EBAMCAYYwEwYD
# VR0lBAwwCgYIKwYBBQUHAwMwdwYIKwYBBQUHAQEEazBpMCQGCCsGAQUFBzABhhho
# dHRwOi8vb2NzcC5kaWdpY2VydC5jb20wQQYIKwYBBQUHMAKGNWh0dHA6Ly9jYWNl
# cnRzLmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydFRydXN0ZWRSb290RzQuY3J0MEMGA1Ud
# HwQ8MDowOKA2oDSGMmh0dHA6Ly9jcmwzLmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydFRy
# dXN0ZWRSb290RzQuY3JsMBwGA1UdIAQVMBMwBwYFZ4EMAQMwCAYGZ4EMAQQBMA0G
# CSqGSIb3DQEBDAUAA4ICAQA6I0Q9jQh27o+8OpnTVuACGqX4SDTzLLbmdGb3lHKx
# AMqvbDAnExKekESfS/2eo3wm1Te8Ol1IbZXVP0n0J7sWgUVQ/Zy9toXgdn43ccsi
# 91qqkM/1k2rj6yDR1VB5iJqKisG2vaFIGH7c2IAaERkYzWGZgVb2yeN258TkG19D
# +D6U/3Y5PZ7Umc9K3SjrXyahlVhI1Rr+1yc//ZDRdobdHLBgXPMNqO7giaG9OeE4
# Ttpuuzad++UhU1rDyulq8aI+20O4M8hPOBSSmfXdzlRt2V0CFB9AM3wD4pWywiF1
# c1LLRtjENByipUuNzW92NyyFPxrOJukYvpAHsEN/lYgggnDwzMrv/Sk1XB+JOFX3
# N4qLCaHLC+kxGv8uGVw5ceG+nKcKBtYmZ7eS5k5f3nqsSc8upHSSrds8pJyGH+PB
# VhsrI/+PteqIe3Br5qC6/To/RabE6BaRUotBwEiES5ZNq0RA443wFSjO7fEYVgcq
# LxDEDAhkPDOPriiMPMuPiAsNvzv0zh57ju+168u38HcT5ucoP6wSrqUvImxB+YJc
# FWbMbA7KxYbD9iYzDAdLoNMHAmpqQDBISzSoUSC7rRuFCOJZDW3KBVAr6kocnqX9
# oKcfBnTn8tZSkP2vhUgh+Vc7tJwD7YZF9LRhbr9o4iZghurIr6n+lB3nYxs6hlZ4
# TjCCB2cwggVPoAMCAQICEAMx+1XPXJY1+uD8jHZg+r4wDQYJKoZIhvcNAQELBQAw
# aTELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDkRpZ2lDZXJ0LCBJbmMuMUEwPwYDVQQD
# EzhEaWdpQ2VydCBUcnVzdGVkIEc0IENvZGUgU2lnbmluZyBSU0E0MDk2IFNIQTM4
# NCAyMDIxIENBMTAeFw0yNTExMDUwMDAwMDBaFw0yNjExMDQyMzU5NTlaMIHvMRMw
# EQYLKwYBBAGCNzwCAQMTAlVTMRkwFwYLKwYBBAGCNzwCAQITCERlbGF3YXJlMR0w
# GwYDVQQPDBRQcml2YXRlIE9yZ2FuaXphdGlvbjEQMA4GA1UEBRMHNTI4MDM5NDEL
# MAkGA1UEBhMCVVMxDjAMBgNVBAgTBVRleGFzMRMwEQYDVQQHEwpSb3VuZCBSb2Nr
# MR8wHQYDVQQKExZEZWxsIFRlY2hub2xvZ2llcyBJbmMuMRgwFgYDVQQLEw9DbGll
# bnQgU29mdHdhcmUxHzAdBgNVBAMTFkRlbGwgVGVjaG5vbG9naWVzIEluYy4wggGi
# MA0GCSqGSIb3DQEBAQUAA4IBjwAwggGKAoIBgQDB86C71b+hpK5bDr5p4DSU5tsP
# R2rZ6NDZHMHZNnuKtQ4IpTssP9f2bSanG1QaM1vl96+V1/Emp30Nb/IPj7soGUQU
# OYr7aVt+lJf2nSVm+rhe9bfI4nnsabrJ0ReieGaGyAjauc6/s2EnGR5mlBPb+D+z
# 8ZMzpWe8eDe1q7jPT38f01RdEeTSlm0j4ks5Fzxiqa9dzKz8rAnwYf3CZqaHOgtF
# gx8IgZdzm1QGpPWowO1TZHpzGJrh0ofoC+pASWHkmyoqMV2+ffKlG2jjhX0xUYVX
# XoSaifQSK4m6K1FR+xaeHUfSkkWOapp9V2BHZua/PTyVVctwTudQoAgffh5ut+cw
# uzG76pbknyZkOtH7gy1LzMSLZ4NOGlPHhINqdyDE0gZdMGwFrINW3EHdzRnPFjAn
# yPc9J8wl9nDBmwRCcnPZ9nk6g1UqFma809jepWXRLURl60mylQfWYR6wp/RJZ4qi
# A3A6nKmsQGLT19frtcNKfuzXCyyLZcVecrNth9cCAwEAAaOCAgIwggH+MB8GA1Ud
# IwQYMBaAFGg34Ou2O/hfEYb7/mF7CIhl9E5CMB0GA1UdDgQWBBSK75aqntZTZxM3
# mp6PiOWeaUfy9DA9BgNVHSAENjA0MDIGBWeBDAEDMCkwJwYIKwYBBQUHAgEWG2h0
# dHA6Ly93d3cuZGlnaWNlcnQuY29tL0NQUzAOBgNVHQ8BAf8EBAMCB4AwEwYDVR0l
# BAwwCgYIKwYBBQUHAwMwgbUGA1UdHwSBrTCBqjBToFGgT4ZNaHR0cDovL2NybDMu
# ZGlnaWNlcnQuY29tL0RpZ2lDZXJ0VHJ1c3RlZEc0Q29kZVNpZ25pbmdSU0E0MDk2
# U0hBMzg0MjAyMUNBMS5jcmwwU6BRoE+GTWh0dHA6Ly9jcmw0LmRpZ2ljZXJ0LmNv
# bS9EaWdpQ2VydFRydXN0ZWRHNENvZGVTaWduaW5nUlNBNDA5NlNIQTM4NDIwMjFD
# QTEuY3JsMIGUBggrBgEFBQcBAQSBhzCBhDAkBggrBgEFBQcwAYYYaHR0cDovL29j
# c3AuZGlnaWNlcnQuY29tMFwGCCsGAQUFBzAChlBodHRwOi8vY2FjZXJ0cy5kaWdp
# Y2VydC5jb20vRGlnaUNlcnRUcnVzdGVkRzRDb2RlU2lnbmluZ1JTQTQwOTZTSEEz
# ODQyMDIxQ0ExLmNydDAJBgNVHRMEAjAAMA0GCSqGSIb3DQEBCwUAA4ICAQBWKrYN
# PoqBrPpTEXVVQYsX1jenSDv4n7+o4SYvQU7rYa9iGkqtQJhvtDzBHzbCBGqKJK4e
# E1nLx1g9gNwL4EIxDBnE0EF2sn1ovueI7nMhnkmSCWVgKRw/7sHPOohPjpI9/N94
# LAqJbag4uWNSW+7dQUv0n/0DlI+BIUNMyUM4LeUvlsbZMqHmTEwX5DKiD7uCjYs5
# y7H7TaOkxgXLVft0SZXzIBjLv+vv3lAZ7c93voKkPt9Vvg/a3CBMxxZf/TNatGD1
# tnVXKfnd1+64nYtbTsueR9YMNcIjB22o1ILPcOPDPS4jVwTSSyW8dRg9wOPwMmRd
# RPt1PCvkQxBsEaf9jFvdqe7LqS7B28D9iq78W3lBkVAlZ2jCrpjy0CT6GVKmlrY9
# IUOfWb1n1dKJnQMgepPCG93OpMu5x9bXRDzR3PinnIvT69qgVr378KuapiGMM/PA
# u5z9KdLALQVtxxW7+SF3AQh3pV0PGMO62ac9qTo/Zu1SMpoB6yJMhYe37Rk1WFzA
# C9DZoDqcluhjm/t7Jtb8ysi7VV2Hebzvhy0T+2ZME0JX5b80nzbHnY4HQiJfwcDD
# 4nmywQTBStR68TUw8xPgyEZRITukqsV/4sKFJKGioIYBPVwH/xh1Wo2r0u5lJzUA
# I6q8pn1IxzkiIBW3f9FhCgWmYBgNU9BguBzYQjGCGkIwgho+AgEBMH0waTELMAkG
# A1UEBhMCVVMxFzAVBgNVBAoTDkRpZ2lDZXJ0LCBJbmMuMUEwPwYDVQQDEzhEaWdp
# Q2VydCBUcnVzdGVkIEc0IENvZGUgU2lnbmluZyBSU0E0MDk2IFNIQTM4NCAyMDIx
# IENBMQIQAzH7Vc9cljX64PyMdmD6vjANBglghkgBZQMEAgMFAKCBnDAQBgorBgEE
# AYI3AgEMMQIwADAZBgkqhkiG9w0BCQMxDAYKKwYBBAGCNwIBBDAcBgorBgEEAYI3
# AgELMQ4wDAYKKwYBBAGCNwIBFTBPBgkqhkiG9w0BCQQxQgRA5yjdS9PI/N8S8XHo
# NzKLbJ4AGCx0PzAL5orco5D0Lceru/n0psL2xqNdaKeoPKAxtG3uOQYvdjpD2fH+
# 8XEE4zANBgkqhkiG9w0BAQEFAASCAYCni2roY6E2WRfTVPwAGiqhxvpmpd3zdDMz
# kYLPk89Tj+XUd1Y/dpBVLfno9aIXM93t/Zc9GKem4KzhWzklhzO88ACUzcnNAuAT
# RwiTGBPuO3GL11/skYLNbbAO4ofenNEm02/ucSjMzqk3yHzovsvX5alMVo4Ygdnj
# rhNoTsHtYsYvL/qnOQlRsXTLHDL9WsvdJP8i4Z2UfRqPCCUp2sfOPbS30+zRjrIJ
# ql11cOfZ816RRMxcwuN/h/fwau0rXXujm/jxQADSqg9aa3HIUk5YLc4+vnAXBG9U
# BaSllfdEXHab++EfOSzeEy/vFx46iAfftqyJJxxuklLRCxpxy+7MMxTXzygejW19
# eFutsaIJSmIvm1cV0zTLTmTDgIIONv/n/JfWzVfNlIoL+unYvjad6c8s6bHPbmGB
# D+buZCxPlzxh4ErV0IBbfxKFQknW3KlW6NDWa317z5+oUQsAZwCjvS1BT4AMWmon
# 7ujv+sdQv5/nf/k9pS/j49Mmrpyuq7Ghghd3MIIXcwYKKwYBBAGCNwMDATGCF2Mw
# ghdfBgkqhkiG9w0BBwKgghdQMIIXTAIBAzEPMA0GCWCGSAFlAwQCAQUAMHgGCyqG
# SIb3DQEJEAEEoGkEZzBlAgEBBglghkgBhv1sBwEwMTANBglghkgBZQMEAgEFAAQg
# 8//KlF4g++Yiln2xEMzQtMh53YYJJa6FCRbjcnS7gEECEQDPGrKet3Wafj0wlItk
# xUkuGA8yMDI2MDYyNTA3MzAxNFqgghM6MIIG7TCCBNWgAwIBAgIQCoDvGEuN8QWC
# 0cR2p5V0aDANBgkqhkiG9w0BAQsFADBpMQswCQYDVQQGEwJVUzEXMBUGA1UEChMO
# RGlnaUNlcnQsIEluYy4xQTA/BgNVBAMTOERpZ2lDZXJ0IFRydXN0ZWQgRzQgVGlt
# ZVN0YW1waW5nIFJTQTQwOTYgU0hBMjU2IDIwMjUgQ0ExMB4XDTI1MDYwNDAwMDAw
# MFoXDTM2MDkwMzIzNTk1OVowYzELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDkRpZ2lD
# ZXJ0LCBJbmMuMTswOQYDVQQDEzJEaWdpQ2VydCBTSEEyNTYgUlNBNDA5NiBUaW1l
# c3RhbXAgUmVzcG9uZGVyIDIwMjUgMTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCC
# AgoCggIBANBGrC0Sxp7Q6q5gVrMrV7pvUf+GcAoB38o3zBlCMGMyqJnfFNZx+wvA
# 69HFTBdwbHwBSOeLpvPnZ8ZN+vo8dE2/pPvOx/Vj8TchTySA2R4QKpVD7dvNZh6w
# W2R6kSu9RJt/4QhguSssp3qome7MrxVyfQO9sMx6ZAWjFDYOzDi8SOhPUWlLnh00
# Cll8pjrUcCV3K3E0zz09ldQ//nBZZREr4h/GI6Dxb2UoyrN0ijtUDVHRXdmncOOM
# A3CoB/iUSROUINDT98oksouTMYFOnHoRh6+86Ltc5zjPKHW5KqCvpSduSwhwUmot
# uQhcg9tw2YD3w6ySSSu+3qU8DD+nigNJFmt6LAHvH3KSuNLoZLc1Hf2JNMVL4Q1O
# pbybpMe46YceNA0LfNsnqcnpJeItK/DhKbPxTTuGoX7wJNdoRORVbPR1VVnDuSeH
# VZlc4seAO+6d2sC26/PQPdP51ho1zBp+xUIZkpSFA8vWdoUoHLWnqWU3dCCyFG1r
# oSrgHjSHlq8xymLnjCbSLZ49kPmk8iyyizNDIXj//cOgrY7rlRyTlaCCfw7aSURO
# wnu7zER6EaJ+AliL7ojTdS5PWPsWeupWs7NpChUk555K096V1hE0yZIXe+giAwW0
# 0aHzrDchIc2bQhpp0IoKRR7YufAkprxMiXAJQ1XCmnCfgPf8+3mnAgMBAAGjggGV
# MIIBkTAMBgNVHRMBAf8EAjAAMB0GA1UdDgQWBBTkO/zyMe39/dfzkXFjGVBDz2GM
# 6DAfBgNVHSMEGDAWgBTvb1NK6eQGfHrK4pBW9i/USezLTjAOBgNVHQ8BAf8EBAMC
# B4AwFgYDVR0lAQH/BAwwCgYIKwYBBQUHAwgwgZUGCCsGAQUFBwEBBIGIMIGFMCQG
# CCsGAQUFBzABhhhodHRwOi8vb2NzcC5kaWdpY2VydC5jb20wXQYIKwYBBQUHMAKG
# UWh0dHA6Ly9jYWNlcnRzLmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydFRydXN0ZWRHNFRp
# bWVTdGFtcGluZ1JTQTQwOTZTSEEyNTYyMDI1Q0ExLmNydDBfBgNVHR8EWDBWMFSg
# UqBQhk5odHRwOi8vY3JsMy5kaWdpY2VydC5jb20vRGlnaUNlcnRUcnVzdGVkRzRU
# aW1lU3RhbXBpbmdSU0E0MDk2U0hBMjU2MjAyNUNBMS5jcmwwIAYDVR0gBBkwFzAI
# BgZngQwBBAIwCwYJYIZIAYb9bAcBMA0GCSqGSIb3DQEBCwUAA4ICAQBlKq3xHCcE
# ua5gQezRCESeY0ByIfjk9iJP2zWLpQq1b4URGnwWBdEZD9gBq9fNaNmFj6Eh8/Ym
# RDfxT7C0k8FUFqNh+tshgb4O6Lgjg8K8elC4+oWCqnU/ML9lFfim8/9yJmZSe2F8
# AQ/UdKFOtj7YMTmqPO9mzskgiC3QYIUP2S3HQvHG1FDu+WUqW4daIqToXFE/JQ/E
# ABgfZXLWU0ziTN6R3ygQBHMUBaB5bdrPbF6MRYs03h4obEMnxYOX8VBRKe1uNnzQ
# VTeLni2nHkX/QqvXnNb+YkDFkxUGtMTaiLR9wjxUxu2hECZpqyU1d0IbX6Wq8/gV
# utDojBIFeRlqAcuEVT0cKsb+zJNEsuEB7O7/cuvTQasnM9AWcIQfVjnzrvwiCZ85
# EE8LUkqRhoS3Y50OHgaY7T/lwd6UArb+BOVAkg2oOvol/DJgddJ35XTxfUlQ+8Hg
# gt8l2Yv7roancJIFcbojBcxlRcGG0LIhp6GvReQGgMgYxQbV1S3CrWqZzBt1R9xJ
# gKf47CdxVRd/ndUlQ05oxYy2zRWVFjF7mcr4C34Mj3ocCVccAvlKV9jEnstrniLv
# UxxVZE/rptb7IRE2lskKPIJgbaP5t2nGj/ULLi49xTcBZU8atufk+EMF/cWuiC7P
# OGT75qaL6vdCvHlshtjdNXOCIUjsarfNZzCCBrQwggScoAMCAQICEA3HrFcF/yGZ
# LkBDIgw6SYYwDQYJKoZIhvcNAQELBQAwYjELMAkGA1UEBhMCVVMxFTATBgNVBAoT
# DERpZ2lDZXJ0IEluYzEZMBcGA1UECxMQd3d3LmRpZ2ljZXJ0LmNvbTEhMB8GA1UE
# AxMYRGlnaUNlcnQgVHJ1c3RlZCBSb290IEc0MB4XDTI1MDUwNzAwMDAwMFoXDTM4
# MDExNDIzNTk1OVowaTELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDkRpZ2lDZXJ0LCBJ
# bmMuMUEwPwYDVQQDEzhEaWdpQ2VydCBUcnVzdGVkIEc0IFRpbWVTdGFtcGluZyBS
# U0E0MDk2IFNIQTI1NiAyMDI1IENBMTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCC
# AgoCggIBALR4MdMKmEFyvjxGwBysddujRmh0tFEXnU2tjQ2UtZmWgyxU7UNqEY81
# FzJsQqr5G7A6c+Gh/qm8Xi4aPCOo2N8S9SLrC6Kbltqn7SWCWgzbNfiR+2fkHUil
# jNOqnIVD/gG3SYDEAd4dg2dDGpeZGKe+42DFUF0mR/vtLa4+gKPsYfwEu7EEbkC9
# +0F2w4QJLVSTEG8yAR2CQWIM1iI5PHg62IVwxKSpO0XaF9DPfNBKS7Zazch8NF5v
# p7eaZ2CVNxpqumzTCNSOxm+SAWSuIr21Qomb+zzQWKhxKTVVgtmUPAW35xUUFREm
# DrMxSNlr/NsJyUXzdtFUUt4aS4CEeIY8y9IaaGBpPNXKFifinT7zL2gdFpBP9qh8
# SdLnEut/GcalNeJQ55IuwnKCgs+nrpuQNfVmUB5KlCX3ZA4x5HHKS+rqBvKWxdCy
# QEEGcbLe1b8Aw4wJkhU1JrPsFfxW1gaou30yZ46t4Y9F20HHfIY4/6vHespYMQmU
# iote8ladjS/nJ0+k6MvqzfpzPDOy5y6gqztiT96Fv/9bH7mQyogxG9QEPHrPV6/7
# umw052AkyiLA6tQbZl1KhBtTasySkuJDpsZGKdlsjg4u70EwgWbVRSX1Wd4+zoFp
# p4Ra+MlKM2baoD6x0VR4RjSpWM8o5a6D8bpfm4CLKczsG7ZrIGNTAgMBAAGjggFd
# MIIBWTASBgNVHRMBAf8ECDAGAQH/AgEAMB0GA1UdDgQWBBTvb1NK6eQGfHrK4pBW
# 9i/USezLTjAfBgNVHSMEGDAWgBTs1+OC0nFdZEzfLmc/57qYrhwPTzAOBgNVHQ8B
# Af8EBAMCAYYwEwYDVR0lBAwwCgYIKwYBBQUHAwgwdwYIKwYBBQUHAQEEazBpMCQG
# CCsGAQUFBzABhhhodHRwOi8vb2NzcC5kaWdpY2VydC5jb20wQQYIKwYBBQUHMAKG
# NWh0dHA6Ly9jYWNlcnRzLmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydFRydXN0ZWRSb290
# RzQuY3J0MEMGA1UdHwQ8MDowOKA2oDSGMmh0dHA6Ly9jcmwzLmRpZ2ljZXJ0LmNv
# bS9EaWdpQ2VydFRydXN0ZWRSb290RzQuY3JsMCAGA1UdIAQZMBcwCAYGZ4EMAQQC
# MAsGCWCGSAGG/WwHATANBgkqhkiG9w0BAQsFAAOCAgEAF877FoAc/gc9EXZxML2+
# C8i1NKZ/zdCHxYgaMH9Pw5tcBnPw6O6FTGNpoV2V4wzSUGvI9NAzaoQk97frPBtI
# j+ZLzdp+yXdhOP4hCFATuNT+ReOPK0mCefSG+tXqGpYZ3essBS3q8nL2UwM+NMvE
# uBd/2vmdYxDCvwzJv2sRUoKEfJ+nN57mQfQXwcAEGCvRR2qKtntujB71WPYAgwPy
# WLKu6RnaID/B0ba2H3LUiwDRAXx1Neq9ydOal95CHfmTnM4I+ZI2rVQfjXQA1WSj
# jf4J2a7jLzWGNqNX+DF0SQzHU0pTi4dBwp9nEC8EAqoxW6q17r0z0noDjs6+BFo+
# z7bKSBwZXTRNivYuve3L2oiKNqetRHdqfMTCW/NmKLJ9M+MtucVGyOxiDf06VXxy
# KkOirv6o02OoXN4bFzK0vlNMsvhlqgF2puE6FndlENSmE+9JGYxOGLS/D284NHNb
# oDGcmWXfwXRy4kbu4QFhOm0xJuF2EZAOk5eCkhSxZON3rGlHqhpB/8MluDezooIs
# 8CVnrpHMiD2wL40mm53+/j7tFaxYKIqL0Q4ssd8xHZnIn/7GELH3IdvG2XlM9q7W
# P/UwgOkw/HQtyRN62JK4S1C8uw3PdBunvAZapsiI5YKdvlarEvf8EA+8hcpSM9LH
# JmyrxaFtoza2zNaQ9k+5t1wwggWNMIIEdaADAgECAhAOmxiO+dAt5+/bUOIIQBha
# MA0GCSqGSIb3DQEBDAUAMGUxCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdpQ2Vy
# dCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20xJDAiBgNVBAMTG0RpZ2lD
# ZXJ0IEFzc3VyZWQgSUQgUm9vdCBDQTAeFw0yMjA4MDEwMDAwMDBaFw0zMTExMDky
# MzU5NTlaMGIxCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAX
# BgNVBAsTEHd3dy5kaWdpY2VydC5jb20xITAfBgNVBAMTGERpZ2lDZXJ0IFRydXN0
# ZWQgUm9vdCBHNDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAL/mkHNo
# 3rvkXUo8MCIwaTPswqclLskhPfKK2FnC4SmnPVirdprNrnsbhA3EMB/zG6Q4FutW
# xpdtHauyefLKEdLkX9YFPFIPUh/GnhWlfr6fqVcWWVVyr2iTcMKyunWZanMylNEQ
# RBAu34LzB4TmdDttceItDBvuINXJIB1jKS3O7F5OyJP4IWGbNOsFxl7sWxq868nP
# zaw0QF+xembud8hIqGZXV59UWI4MK7dPpzDZVu7Ke13jrclPXuU15zHL2pNe3I6P
# gNq2kZhAkHnDeMe2scS1ahg4AxCN2NQ3pC4FfYj1gj4QkXCrVYJBMtfbBHMqbpEB
# fCFM1LyuGwN1XXhm2ToxRJozQL8I11pJpMLmqaBn3aQnvKFPObURWBf3JFxGj2T3
# wWmIdph2PVldQnaHiZdpekjw4KISG2aadMreSx7nDmOu5tTvkpI6nj3cAORFJYm2
# mkQZK37AlLTSYW3rM9nF30sEAMx9HJXDj/chsrIRt7t/8tWMcCxBYKqxYxhElRp2
# Yn72gLD76GSmM9GJB+G9t+ZDpBi4pncB4Q+UDCEdslQpJYls5Q5SUUd0viastkF1
# 3nqsX40/ybzTQRESW+UQUOsxxcpyFiIJ33xMdT9j7CFfxCBRa2+xq4aLT8LWRV+d
# IPyhHsXAj6KxfgommfXkaS+YHS312amyHeUbAgMBAAGjggE6MIIBNjAPBgNVHRMB
# Af8EBTADAQH/MB0GA1UdDgQWBBTs1+OC0nFdZEzfLmc/57qYrhwPTzAfBgNVHSME
# GDAWgBRF66Kv9JLLgjEtUYunpyGd823IDzAOBgNVHQ8BAf8EBAMCAYYweQYIKwYB
# BQUHAQEEbTBrMCQGCCsGAQUFBzABhhhodHRwOi8vb2NzcC5kaWdpY2VydC5jb20w
# QwYIKwYBBQUHMAKGN2h0dHA6Ly9jYWNlcnRzLmRpZ2ljZXJ0LmNvbS9EaWdpQ2Vy
# dEFzc3VyZWRJRFJvb3RDQS5jcnQwRQYDVR0fBD4wPDA6oDigNoY0aHR0cDovL2Ny
# bDMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0QXNzdXJlZElEUm9vdENBLmNybDARBgNV
# HSAECjAIMAYGBFUdIAAwDQYJKoZIhvcNAQEMBQADggEBAHCgv0NcVec4X6CjdBs9
# thbX979XB72arKGHLOyFXqkauyL4hxppVCLtpIh3bb0aFPQTSnovLbc47/T/gLn4
# offyct4kvFIDyE7QKt76LVbP+fT3rDB6mouyXtTP0UNEm0Mh65ZyoUi0mcudT6cG
# AxN3J0TU53/oWajwvy8LpunyNDzs9wPHh6jSTEAZNUZqaVSwuKFWjuyk1T3osdz9
# HNj0d1pcVIxv76FQPfx2CWiEn2/K2yCNNWAcAgPLILCsWKAOQGPFmCLBsln1VWvP
# J6tsds5vIy30fnFqI2si/xK4VC0nftg62fC2h5b9W9FcrBjDTZ9ztwGpn1eqXiji
# uZQxggN8MIIDeAIBATB9MGkxCzAJBgNVBAYTAlVTMRcwFQYDVQQKEw5EaWdpQ2Vy
# dCwgSW5jLjFBMD8GA1UEAxM4RGlnaUNlcnQgVHJ1c3RlZCBHNCBUaW1lU3RhbXBp
# bmcgUlNBNDA5NiBTSEEyNTYgMjAyNSBDQTECEAqA7xhLjfEFgtHEdqeVdGgwDQYJ
# YIZIAWUDBAIBBQCggdEwGgYJKoZIhvcNAQkDMQ0GCyqGSIb3DQEJEAEEMBwGCSqG
# SIb3DQEJBTEPFw0yNjA2MjUwNzMwMTRaMCsGCyqGSIb3DQEJEAIMMRwwGjAYMBYE
# FN1iMKyGCi0wa9o4sWh5UjAH+0F+MC8GCSqGSIb3DQEJBDEiBCCMvvUexqgFzdAD
# zZrXZzyREbFLR7a7wUse4O4Zrwk/UTA3BgsqhkiG9w0BCRACLzEoMCYwJDAiBCBK
# oD+iLNdchMVck4+CjmdrnK7Ksz/jbSaaozTxRhEKMzANBgkqhkiG9w0BAQEFAASC
# AgBCR3eKCB9CbWLMCMCjgOTCAQPFSwhFmdo27wwGyFBD5Ce6ZhT99Fz/hxdDVT0O
# P+8ye4yLjwoSoc2AqSeUl/7aa0GRjto2sntsUhabR6hwH7ntbE8cUK2QzgAo+VHo
# 1dUqqNKUhi5u7lWRruuX3/eSPsVR6feP8NccoH/jdM7GX90JieE27f5WJFr//EpP
# dm33osjbQNcA98T1hwgdJepXmyNDaaKxqkb3eflkdUz6/UsethwcqYFW/SOCwHAj
# 56hfyUlHeNH9TKCdzlpFyzXjAsURC1zwAVVFt+q0NeLS2xKVsYXX401vyrOGE8IH
# TbdNLdwcqp8I/yiI5StEBlhEa7N8dAQFp8DVDVif0r5Abw8U0EuwGpLyRvp8HghH
# mDr1Bvp0gaeecD993Ny8wvU8tdpfzj7gElhkjEw/0Gb4RzL32coxrAWtJoIjapHx
# PrrNGtKa+L30nj2Mn9qlmQy47J6fPL7VcHbOHhlmsLj5zGAe+cA4zvwSrJGblXA7
# 6dAL4LyHg3bSXt3Epw732vTVzkyIypmqHxhe24+usRF/FJMqovB6etQoddL/AMGX
# TjFP3DwLZZxoTMTqQ/V/deHbzITWqEdKc0U2sudl5PWOeiF7MqjY/ICQvLRJbpHl
# 8rbgJNbp5CCRb3Ivr/6zj/fEJtUCt3VIESiyUdaPO/e5+A==
# SIG # End signature block