AzStackHciBitlocker/AzStackHciBitlocker.psm1

<#############################################################
 # #
 # Copyright (C) Microsoft Corporation. All rights reserved. #
 # #
 #############################################################>

$MetaData = @{
    "OperationType" = @("Deployment")
    "UIName"        = 'Azure Stack HCI Bitlocker Check'
    "UIDescription" = 'Check Bitlocker inputs meet requirements'
}
function Test-AzStackHciBitlocker
{
    param (
        [parameter(Mandatory = $true)]
        [ValidateNotNullOrEmpty()]
        $Parameters,

        [parameter(Mandatory = $true)]
        [ValidateNotNullOrEmpty()]
        $OperationType,

        [parameter(Mandatory = $false)]
        [switch]
        $FailFast
    )
    try
    {
        $ENV:EnvChkrOp = $OperationType
        if ($OperationType -eq 'Deployment')
        {
            # Only run if keep storage flag is set
            $storageRole = $Parameters.Roles["Storage"].PublicConfiguration
            $configurationMode = $storageRole.PublicInfo.StorageConfiguration.Name
            Trace-Execution "Configuration mode: $configurationMode"
            if ("KeepStorage" -ne $configurationMode)
            {
                Trace-Execution "Skipping Bitlocker validation as storage configuration mode is not KeepStorage"
                return
            }
            else
            {
                Trace-Execution "Checking if this is a one-node repair configuration"
                $ComputerName = $Parameters.Roles["BareMetal"].PublicConfiguration.Nodes.Node | ForEach-Object { $_.Name }
                if ($ComputerName.Count -ne 1)
                {
                    Trace-Execution "Skipping Bitlocker validation as this is not a one-node repair configuration"
                    return
                }
                else
                {
                    Trace-Execution "This is a one-node repair configuration"
                    Trace-Execution "Checking if vDisks exist"
                    # CSVs must exist
                    $vDisks = (Get-StoragePool -IsPrimordial:$false -ErrorAction SilentlyContinue | Get-VirtualDisk)
                    if ($null -eq $vDisks)
                    {
                        throw "Unable to perform deployment with KeepStorage flag. No virtual disks exist."
                    }

                    # Verify that the local system has protected disks that are detached before proceeding with the validation
                    # This will rule out unencrypted but detached disks.
                    if (Test-ASAnyVirtualDiskProtected)
                    {
                        $domainFQDN = $Parameters.Roles["Domain"].PublicConfiguration.PublicInfo.DomainConfiguration.FQDN
                        $ADOUPath = $Parameters.Roles["Cloud"].PublicConfiguration.PublicInfo.ADOUPath
                        $ActiveDirectoryCredential = [EnvironmentValidator]::GetDomainAdminCredential($Parameters)
                        $params = @{
                            ComputerName              = $ComputerName
                            DomainFQDN                = $domainFQDN
                            ADOUPath                  = $ADOUPath
                            ActiveDirectoryCredential = $ActiveDirectoryCredential
                            PassThru                  = $true
                            OutputPath                = "$($ENV:LocalRootFolderPath)\MASLogs\"
                        }
                        Trace-Execution "Starting Bitlocker validation, detail output can be found in $($ENV:LocalRootFolderPath)\MASLogs\AzStackHciEnvironmentChecker*"
                        $BitlockerResult = Invoke-AzStackHciBitlockerValidation @Params
                    }
                    else
                    {
                        $dtl = "Bitlocker validation is skipped for Azure Stack HCI environments with no encryption."
                        Trace-Execution $dtl
                        return (New-Object -TypeName PsObject -Property @{Result = 'Informational'; FailedResult = $null; ExecutionDetail = $dtl})
                    }
                }
            }
            # Parse Bitlocker Result
            [EnvironmentValidator]::ParseResult($BitlockerResult, 'Bitlocker', $FailFast)
        }
        else
        {
            Trace-Execution "No interface found for $OperationType"
        }
    }
    catch
    {
        Trace-Execution "Validator failed. $_"
        Trace-Execution "$($_.ScriptStackTrace)"
        throw $_
    }
}


function Test-ASAnyVirtualDiskProtected
{
    <#
    .SYNOPSIS
        Find out if any virtual disk is protected.
    .DESCRIPTION
        Find out if any virtual disk is protected.
        Attachs virtual disks and checks volume size for 0 bytes to determine if the volume is protected.
    #>



    [CmdletBinding()]
    param()
    try {
        $ErrorActionPreference = "Stop"
        $VirtualDiskProtected = $false
        Trace-Execution "Get any detached virtual disks with OtherUsageDescription ASProtected"
        $virtualDisks = Get-VirtualDisk | Where-Object { $_.OtherUsageDescription -match 'ASProtected;' -and $_.OperationalStatus -eq "Detached" }

        # return false if there were no matching disks
        if ($null -eq $virtualDisks -or @($virtualDisks).Count -eq 0)
        {
            Trace-Execution "No detached VirtualDisks with OtherUsageDescription ASProtected were retrived."
            return $false
        }

        Trace-Execution "List of Virtual Disks: `n$($virtualDisks | Format-Table FriendlyName,OperationalStatus,HealthStatus,Size| Out-String)"
        Trace-Execution "For each ASProtected virtual disk try to detect protection status from the associated volume"

        foreach ($virtualDisk in $virtualDisks)
        {
            $virtualDiskFriendlyName = $virtualDisk.FriendlyName
            Trace-Execution "Attaching virtual disk $virtualDiskFriendlyName"
            Connect-VirtualDisk -FriendlyName $virtualDiskFriendlyName
            Trace-Execution "Getting disk associated with virtual disk $virtualDiskFriendlyName"
            $disk = $virtualDisk | Get-Disk
            Trace-Execution "Putting disk $($disk.Number) online and removing ReadOnly flag"
            $disk | Set-Disk -IsReadOnly $false
            $disk | Set-Disk -IsOffline $false
            Trace-Execution "Getting volume associated with disk $($disk.Number)"
            $volume = $disk | Get-Partition | Get-Volume
            Trace-Execution "VirtualDisk $virtualDiskFriendlyName associated Volume: `n$($volume | Format-List DriveLetter,FileSystemType,DriveType,HealthStatus,OperationalStatus,SizeRemaining,Size | Out-String)"
            if ($($volume.Size) -eq 0)
            {
                Trace-Execution "VirtualDisk $virtualDiskFriendlyName is protected"
                $VirtualDiskProtected = $true
            }
            Trace-Execution "Disconnecting virtual disk $virtualDiskFriendlyName"
            Disconnect-VirtualDisk -FriendlyName $virtualDiskFriendlyName
        }
        return $VirtualDiskProtected
    }
    catch {
        throw "Unable to test protected disks: Exception: $_"
    }
}

Export-ModuleMember -Function Test-AzStackHciBitlocker -Variable MetaData
# SIG # Begin signature block
# MIInkwYJKoZIhvcNAQcCoIInhDCCJ4ACAQExDzANBglghkgBZQMEAgEFADB5Bgor
# BgEEAYI3AgEEoGswaTA0BgorBgEEAYI3AgEeMCYCAwEAAAQQH8w7YFlLCE63JNLG
# KX7zUQIBAAIBAAIBAAIBAAIBADAxMA0GCWCGSAFlAwQCAQUABCAbE8Yst43trup5
# Mz9ruhIYXvvlVmT/XL2ofuN9CWwgXKCCDXYwggX0MIID3KADAgECAhMzAAADTrU8
# esGEb+srAAAAAANOMA0GCSqGSIb3DQEBCwUAMH4xCzAJBgNVBAYTAlVTMRMwEQYD
# VQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNy
# b3NvZnQgQ29ycG9yYXRpb24xKDAmBgNVBAMTH01pY3Jvc29mdCBDb2RlIFNpZ25p
# bmcgUENBIDIwMTEwHhcNMjMwMzE2MTg0MzI5WhcNMjQwMzE0MTg0MzI5WjB0MQsw
# CQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9u
# ZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMR4wHAYDVQQDExVNaWNy
# b3NvZnQgQ29ycG9yYXRpb24wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIB
# AQDdCKiNI6IBFWuvJUmf6WdOJqZmIwYs5G7AJD5UbcL6tsC+EBPDbr36pFGo1bsU
# p53nRyFYnncoMg8FK0d8jLlw0lgexDDr7gicf2zOBFWqfv/nSLwzJFNP5W03DF/1
# 1oZ12rSFqGlm+O46cRjTDFBpMRCZZGddZlRBjivby0eI1VgTD1TvAdfBYQe82fhm
# WQkYR/lWmAK+vW/1+bO7jHaxXTNCxLIBW07F8PBjUcwFxxyfbe2mHB4h1L4U0Ofa
# +HX/aREQ7SqYZz59sXM2ySOfvYyIjnqSO80NGBaz5DvzIG88J0+BNhOu2jl6Dfcq
# jYQs1H/PMSQIK6E7lXDXSpXzAgMBAAGjggFzMIIBbzAfBgNVHSUEGDAWBgorBgEE
# AYI3TAgBBggrBgEFBQcDAzAdBgNVHQ4EFgQUnMc7Zn/ukKBsBiWkwdNfsN5pdwAw
# RQYDVR0RBD4wPKQ6MDgxHjAcBgNVBAsTFU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjEW
# MBQGA1UEBRMNMjMwMDEyKzUwMDUxNjAfBgNVHSMEGDAWgBRIbmTlUAXTgqoXNzci
# tW2oynUClTBUBgNVHR8ETTBLMEmgR6BFhkNodHRwOi8vd3d3Lm1pY3Jvc29mdC5j
# b20vcGtpb3BzL2NybC9NaWNDb2RTaWdQQ0EyMDExXzIwMTEtMDctMDguY3JsMGEG
# CCsGAQUFBwEBBFUwUzBRBggrBgEFBQcwAoZFaHR0cDovL3d3dy5taWNyb3NvZnQu
# Y29tL3BraW9wcy9jZXJ0cy9NaWNDb2RTaWdQQ0EyMDExXzIwMTEtMDctMDguY3J0
# MAwGA1UdEwEB/wQCMAAwDQYJKoZIhvcNAQELBQADggIBAD21v9pHoLdBSNlFAjmk
# mx4XxOZAPsVxxXbDyQv1+kGDe9XpgBnT1lXnx7JDpFMKBwAyIwdInmvhK9pGBa31
# TyeL3p7R2s0L8SABPPRJHAEk4NHpBXxHjm4TKjezAbSqqbgsy10Y7KApy+9UrKa2
# kGmsuASsk95PVm5vem7OmTs42vm0BJUU+JPQLg8Y/sdj3TtSfLYYZAaJwTAIgi7d
# hzn5hatLo7Dhz+4T+MrFd+6LUa2U3zr97QwzDthx+RP9/RZnur4inzSQsG5DCVIM
# pA1l2NWEA3KAca0tI2l6hQNYsaKL1kefdfHCrPxEry8onJjyGGv9YKoLv6AOO7Oh
# JEmbQlz/xksYG2N/JSOJ+QqYpGTEuYFYVWain7He6jgb41JbpOGKDdE/b+V2q/gX
# UgFe2gdwTpCDsvh8SMRoq1/BNXcr7iTAU38Vgr83iVtPYmFhZOVM0ULp/kKTVoir
# IpP2KCxT4OekOctt8grYnhJ16QMjmMv5o53hjNFXOxigkQWYzUO+6w50g0FAeFa8
# 5ugCCB6lXEk21FFB1FdIHpjSQf+LP/W2OV/HfhC3uTPgKbRtXo83TZYEudooyZ/A
# Vu08sibZ3MkGOJORLERNwKm2G7oqdOv4Qj8Z0JrGgMzj46NFKAxkLSpE5oHQYP1H
# tPx1lPfD7iNSbJsP6LiUHXH1MIIHejCCBWKgAwIBAgIKYQ6Q0gAAAAAAAzANBgkq
# hkiG9w0BAQsFADCBiDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCldhc2hpbmd0b24x
# EDAOBgNVBAcTB1JlZG1vbmQxHjAcBgNVBAoTFU1pY3Jvc29mdCBDb3Jwb3JhdGlv
# bjEyMDAGA1UEAxMpTWljcm9zb2Z0IFJvb3QgQ2VydGlmaWNhdGUgQXV0aG9yaXR5
# IDIwMTEwHhcNMTEwNzA4MjA1OTA5WhcNMjYwNzA4MjEwOTA5WjB+MQswCQYDVQQG
# EwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9uZDEeMBwG
# A1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMSgwJgYDVQQDEx9NaWNyb3NvZnQg
# Q29kZSBTaWduaW5nIFBDQSAyMDExMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIIC
# CgKCAgEAq/D6chAcLq3YbqqCEE00uvK2WCGfQhsqa+laUKq4BjgaBEm6f8MMHt03
# a8YS2AvwOMKZBrDIOdUBFDFC04kNeWSHfpRgJGyvnkmc6Whe0t+bU7IKLMOv2akr
# rnoJr9eWWcpgGgXpZnboMlImEi/nqwhQz7NEt13YxC4Ddato88tt8zpcoRb0Rrrg
# OGSsbmQ1eKagYw8t00CT+OPeBw3VXHmlSSnnDb6gE3e+lD3v++MrWhAfTVYoonpy
# 4BI6t0le2O3tQ5GD2Xuye4Yb2T6xjF3oiU+EGvKhL1nkkDstrjNYxbc+/jLTswM9
# sbKvkjh+0p2ALPVOVpEhNSXDOW5kf1O6nA+tGSOEy/S6A4aN91/w0FK/jJSHvMAh
# dCVfGCi2zCcoOCWYOUo2z3yxkq4cI6epZuxhH2rhKEmdX4jiJV3TIUs+UsS1Vz8k
# A/DRelsv1SPjcF0PUUZ3s/gA4bysAoJf28AVs70b1FVL5zmhD+kjSbwYuER8ReTB
# w3J64HLnJN+/RpnF78IcV9uDjexNSTCnq47f7Fufr/zdsGbiwZeBe+3W7UvnSSmn
# Eyimp31ngOaKYnhfsi+E11ecXL93KCjx7W3DKI8sj0A3T8HhhUSJxAlMxdSlQy90
# lfdu+HggWCwTXWCVmj5PM4TasIgX3p5O9JawvEagbJjS4NaIjAsCAwEAAaOCAe0w
# ggHpMBAGCSsGAQQBgjcVAQQDAgEAMB0GA1UdDgQWBBRIbmTlUAXTgqoXNzcitW2o
# ynUClTAZBgkrBgEEAYI3FAIEDB4KAFMAdQBiAEMAQTALBgNVHQ8EBAMCAYYwDwYD
# VR0TAQH/BAUwAwEB/zAfBgNVHSMEGDAWgBRyLToCMZBDuRQFTuHqp8cx0SOJNDBa
# BgNVHR8EUzBRME+gTaBLhklodHRwOi8vY3JsLm1pY3Jvc29mdC5jb20vcGtpL2Ny
# bC9wcm9kdWN0cy9NaWNSb29DZXJBdXQyMDExXzIwMTFfMDNfMjIuY3JsMF4GCCsG
# AQUFBwEBBFIwUDBOBggrBgEFBQcwAoZCaHR0cDovL3d3dy5taWNyb3NvZnQuY29t
# L3BraS9jZXJ0cy9NaWNSb29DZXJBdXQyMDExXzIwMTFfMDNfMjIuY3J0MIGfBgNV
# HSAEgZcwgZQwgZEGCSsGAQQBgjcuAzCBgzA/BggrBgEFBQcCARYzaHR0cDovL3d3
# dy5taWNyb3NvZnQuY29tL3BraW9wcy9kb2NzL3ByaW1hcnljcHMuaHRtMEAGCCsG
# AQUFBwICMDQeMiAdAEwAZQBnAGEAbABfAHAAbwBsAGkAYwB5AF8AcwB0AGEAdABl
# AG0AZQBuAHQALiAdMA0GCSqGSIb3DQEBCwUAA4ICAQBn8oalmOBUeRou09h0ZyKb
# C5YR4WOSmUKWfdJ5DJDBZV8uLD74w3LRbYP+vj/oCso7v0epo/Np22O/IjWll11l
# hJB9i0ZQVdgMknzSGksc8zxCi1LQsP1r4z4HLimb5j0bpdS1HXeUOeLpZMlEPXh6
# I/MTfaaQdION9MsmAkYqwooQu6SpBQyb7Wj6aC6VoCo/KmtYSWMfCWluWpiW5IP0
# wI/zRive/DvQvTXvbiWu5a8n7dDd8w6vmSiXmE0OPQvyCInWH8MyGOLwxS3OW560
# STkKxgrCxq2u5bLZ2xWIUUVYODJxJxp/sfQn+N4sOiBpmLJZiWhub6e3dMNABQam
# ASooPoI/E01mC8CzTfXhj38cbxV9Rad25UAqZaPDXVJihsMdYzaXht/a8/jyFqGa
# J+HNpZfQ7l1jQeNbB5yHPgZ3BtEGsXUfFL5hYbXw3MYbBL7fQccOKO7eZS/sl/ah
# XJbYANahRr1Z85elCUtIEJmAH9AAKcWxm6U/RXceNcbSoqKfenoi+kiVH6v7RyOA
# 9Z74v2u3S5fi63V4GuzqN5l5GEv/1rMjaHXmr/r8i+sLgOppO6/8MO0ETI7f33Vt
# Y5E90Z1WTk+/gFcioXgRMiF670EKsT/7qMykXcGhiJtXcVZOSEXAQsmbdlsKgEhr
# /Xmfwb1tbWrJUnMTDXpQzTGCGXMwghlvAgEBMIGVMH4xCzAJBgNVBAYTAlVTMRMw
# EQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVN
# aWNyb3NvZnQgQ29ycG9yYXRpb24xKDAmBgNVBAMTH01pY3Jvc29mdCBDb2RlIFNp
# Z25pbmcgUENBIDIwMTECEzMAAANOtTx6wYRv6ysAAAAAA04wDQYJYIZIAWUDBAIB
# BQCgga4wGQYJKoZIhvcNAQkDMQwGCisGAQQBgjcCAQQwHAYKKwYBBAGCNwIBCzEO
# MAwGCisGAQQBgjcCARUwLwYJKoZIhvcNAQkEMSIEINpL+3vrUVGyDZ59HDNzIIqM
# 5dZGm7f6YmcOpP/tCt7LMEIGCisGAQQBgjcCAQwxNDAyoBSAEgBNAGkAYwByAG8A
# cwBvAGYAdKEagBhodHRwOi8vd3d3Lm1pY3Jvc29mdC5jb20wDQYJKoZIhvcNAQEB
# BQAEggEAV8MTeFEZwmLBqGuYTTteOunhoqhUfusC7FN0MVP0du9ET6sWtelxfD/C
# Q051oIyFS563DPMPdx1BbPmE9N2w5/OZuj442Dzv4K3IfK3av94WsAGDJeUk5/EV
# SBju/+EuW/IiaEAuvFqSvuVOIQJEVdQmnYsycinu7dRvrKwiKWKHod0QGBXQVw6G
# Uyse+xWPuL3SJzLEbnEiaoZa/sfPttBhE2SzelJXG//eqTkOQ4t79qqwMpwXuD38
# XTB8c0ylMltUODtN0VsJN/s+Aqx+YHlUBd7dJ5ey+K3PbssyfXdHGIMa+DLSzhjW
# De8JvTw3A2hkvdRwfc5evE2wq48NxKGCFv0wghb5BgorBgEEAYI3AwMBMYIW6TCC
# FuUGCSqGSIb3DQEHAqCCFtYwghbSAgEDMQ8wDQYJYIZIAWUDBAIBBQAwggFRBgsq
# hkiG9w0BCRABBKCCAUAEggE8MIIBOAIBAQYKKwYBBAGEWQoDATAxMA0GCWCGSAFl
# AwQCAQUABCDKV8av/hdbByVnxzB7O09iS5IZA1hVo/ztx9cztizXAQIGZDfr6cPJ
# GBMyMDIzMDUwNDE1NTk0NS4xNDVaMASAAgH0oIHQpIHNMIHKMQswCQYDVQQGEwJV
# UzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9uZDEeMBwGA1UE
# ChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMSUwIwYDVQQLExxNaWNyb3NvZnQgQW1l
# cmljYSBPcGVyYXRpb25zMSYwJAYDVQQLEx1UaGFsZXMgVFNTIEVTTjpENkJELUUz
# RTctMTY4NTElMCMGA1UEAxMcTWljcm9zb2Z0IFRpbWUtU3RhbXAgU2VydmljZaCC
# EVQwggcMMIIE9KADAgECAhMzAAABx/sAoEpb8ifcAAEAAAHHMA0GCSqGSIb3DQEB
# CwUAMHwxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQH
# EwdSZWRtb25kMR4wHAYDVQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xJjAkBgNV
# BAMTHU1pY3Jvc29mdCBUaW1lLVN0YW1wIFBDQSAyMDEwMB4XDTIyMTEwNDE5MDEz
# NVoXDTI0MDIwMjE5MDEzNVowgcoxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpXYXNo
# aW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNyb3NvZnQgQ29y
# cG9yYXRpb24xJTAjBgNVBAsTHE1pY3Jvc29mdCBBbWVyaWNhIE9wZXJhdGlvbnMx
# JjAkBgNVBAsTHVRoYWxlcyBUU1MgRVNOOkQ2QkQtRTNFNy0xNjg1MSUwIwYDVQQD
# ExxNaWNyb3NvZnQgVGltZS1TdGFtcCBTZXJ2aWNlMIICIjANBgkqhkiG9w0BAQEF
# AAOCAg8AMIICCgKCAgEAr0LcVtnatNFMBrQTtG9P8ISAPyyGmxNfhEzaOVlt088p
# BUFAIasmN/eOijE6Ucaf3c2bVnN/02ih0smSqYkm5P3ZwU7ZW202b6cPDJjXcrjJ
# j0qfnuccBtE3WU0vZ8CiQD7qrKxeF8YBNcS+PVtvsqhd5YW6AwhWqhjw1mYuLetF
# 5b6aPif/3RzlyqG3SV7QPiSJends7gG435Rsy1HJ4XnqztOJR41I0j3EQ05JMF5Q
# NRi7kT6vXTT+MHVj27FVQ7bef/U+2EAbFj2X2AOWbvglYaYnM3m/I/OWDHUgGw8K
# IdsDh3W1eusnF2D7oenGgtahs+S1G5Uolf5ESg/9Z+38rhQwLgokY5k6p8k5arYW
# tszdJK6JiIRl843H74k7+QqlT2LbAQPq8ivQv0gdclW2aJun1KrW+v52R3vAHCOt
# bUmxvD1eNGHqGqLagtlq9UFXKXuXnqXJqruCYmfwdFMD0UP6ii1lFdeKL87PdjdA
# wyCiVcCEoLnvDzyvjNjxtkTdz6R4yF1N/X4PSQH4FlgslyBIXggaSlPtvPuxAtua
# c/ITj4k0IRShGiYLBM2Dw6oesLOoxe07OUPO+qXXOcJMVHhE0MlhhnxfN2B1JWFP
# WwQ6ooWiqAOQDqzcDx+79shxA1Cx0K70eOBplMog27gYoLpBv7nRz4tHqoTyvA0C
# AwEAAaOCATYwggEyMB0GA1UdDgQWBBQFUNLdHD7BAF/VU/X/eEHLiUSSIDAfBgNV
# HSMEGDAWgBSfpxVdAF5iXYP05dJlpxtTNRnpcjBfBgNVHR8EWDBWMFSgUqBQhk5o
# dHRwOi8vd3d3Lm1pY3Jvc29mdC5jb20vcGtpb3BzL2NybC9NaWNyb3NvZnQlMjBU
# aW1lLVN0YW1wJTIwUENBJTIwMjAxMCgxKS5jcmwwbAYIKwYBBQUHAQEEYDBeMFwG
# CCsGAQUFBzAChlBodHRwOi8vd3d3Lm1pY3Jvc29mdC5jb20vcGtpb3BzL2NlcnRz
# L01pY3Jvc29mdCUyMFRpbWUtU3RhbXAlMjBQQ0ElMjAyMDEwKDEpLmNydDAMBgNV
# HRMBAf8EAjAAMBMGA1UdJQQMMAoGCCsGAQUFBwMIMA0GCSqGSIb3DQEBCwUAA4IC
# AQDQy5c8ogP0y8xAsLVca07wWy1mT+nqYgAFnz2972kNO+KJ7AE4f+SVbvOnkeeu
# OPq3xc+6TS8g3FuKKYEwYqvnRHxX58tjlscZsZeKnu7fGNUlpNT9bOQFHWALURuo
# Xp8TLHhxj3PEq9jzFYBP2YNMLol70ojY1qpze3nMMJfpdurdBBpaOLlJmRNTLhxd
# +RJGJQbY1XAcx6p/FigwqBasSDUxp+0yFPEBB9uBE3KILAtq6fczGp4EMeon6Ymk
# yCGAtXMKDFQQgdP/ITe7VghAVbPTVlP3hY1dFgc+t8YK2obFSFVKslkASATDHulC
# Mht+WrIsukclEUP9DaMmpq7S0RLODMicI6PtqqGOhdnaRltA0d+Wf+0tPt9SUVtr
# PJyO7WMPKbykCRXzmHK06zr0kn1YiUYNXCsOgaHF5ImO2ZwQ54UE1I55jjUdldyj
# y/UPJgxRm9NyXeO7adYr8K8f6Q2nPF0vWqFG7ewwaAl5ClKerzshfhB8zujVR0d1
# Ra7Z01lnXYhWuPqVZayFl7JHr6i6huhpU6BQ6/VgY0cBiksX4mNM+ISY81T1RYt7
# fWATNu/zkjINczipzbfg5S+3fCAo8gVB6+6A5L0vBg39dsFITv6MWJuQ8ZZy7fwl
# FBZE4d5IFbRudakNwKGdyLGM2otaNq7wm3ku7x41UGAmkDCCB3EwggVZoAMCAQIC
# EzMAAAAVxedrngKbSZkAAAAAABUwDQYJKoZIhvcNAQELBQAwgYgxCzAJBgNVBAYT
# AlVTMRMwEQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYD
# VQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xMjAwBgNVBAMTKU1pY3Jvc29mdCBS
# b290IENlcnRpZmljYXRlIEF1dGhvcml0eSAyMDEwMB4XDTIxMDkzMDE4MjIyNVoX
# DTMwMDkzMDE4MzIyNVowfDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCldhc2hpbmd0
# b24xEDAOBgNVBAcTB1JlZG1vbmQxHjAcBgNVBAoTFU1pY3Jvc29mdCBDb3Jwb3Jh
# dGlvbjEmMCQGA1UEAxMdTWljcm9zb2Z0IFRpbWUtU3RhbXAgUENBIDIwMTAwggIi
# MA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDk4aZM57RyIQt5osvXJHm9DtWC
# 0/3unAcH0qlsTnXIyjVX9gF/bErg4r25PhdgM/9cT8dm95VTcVrifkpa/rg2Z4VG
# Iwy1jRPPdzLAEBjoYH1qUoNEt6aORmsHFPPFdvWGUNzBRMhxXFExN6AKOG6N7dcP
# 2CZTfDlhAnrEqv1yaa8dq6z2Nr41JmTamDu6GnszrYBbfowQHJ1S/rboYiXcag/P
# XfT+jlPP1uyFVk3v3byNpOORj7I5LFGc6XBpDco2LXCOMcg1KL3jtIckw+DJj361
# VI/c+gVVmG1oO5pGve2krnopN6zL64NF50ZuyjLVwIYwXE8s4mKyzbnijYjklqwB
# Sru+cakXW2dg3viSkR4dPf0gz3N9QZpGdc3EXzTdEonW/aUgfX782Z5F37ZyL9t9
# X4C626p+Nuw2TPYrbqgSUei/BQOj0XOmTTd0lBw0gg/wEPK3Rxjtp+iZfD9M269e
# wvPV2HM9Q07BMzlMjgK8QmguEOqEUUbi0b1qGFphAXPKZ6Je1yh2AuIzGHLXpyDw
# wvoSCtdjbwzJNmSLW6CmgyFdXzB0kZSU2LlQ+QuJYfM2BjUYhEfb3BvR/bLUHMVr
# 9lxSUV0S2yW6r1AFemzFER1y7435UsSFF5PAPBXbGjfHCBUYP3irRbb1Hode2o+e
# FnJpxq57t7c+auIurQIDAQABo4IB3TCCAdkwEgYJKwYBBAGCNxUBBAUCAwEAATAj
# BgkrBgEEAYI3FQIEFgQUKqdS/mTEmr6CkTxGNSnPEP8vBO4wHQYDVR0OBBYEFJ+n
# FV0AXmJdg/Tl0mWnG1M1GelyMFwGA1UdIARVMFMwUQYMKwYBBAGCN0yDfQEBMEEw
# PwYIKwYBBQUHAgEWM2h0dHA6Ly93d3cubWljcm9zb2Z0LmNvbS9wa2lvcHMvRG9j
# cy9SZXBvc2l0b3J5Lmh0bTATBgNVHSUEDDAKBggrBgEFBQcDCDAZBgkrBgEEAYI3
# FAIEDB4KAFMAdQBiAEMAQTALBgNVHQ8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAf
# BgNVHSMEGDAWgBTV9lbLj+iiXGJo0T2UkFvXzpoYxDBWBgNVHR8ETzBNMEugSaBH
# hkVodHRwOi8vY3JsLm1pY3Jvc29mdC5jb20vcGtpL2NybC9wcm9kdWN0cy9NaWNS
# b29DZXJBdXRfMjAxMC0wNi0yMy5jcmwwWgYIKwYBBQUHAQEETjBMMEoGCCsGAQUF
# BzAChj5odHRwOi8vd3d3Lm1pY3Jvc29mdC5jb20vcGtpL2NlcnRzL01pY1Jvb0Nl
# ckF1dF8yMDEwLTA2LTIzLmNydDANBgkqhkiG9w0BAQsFAAOCAgEAnVV9/Cqt4Swf
# ZwExJFvhnnJL/Klv6lwUtj5OR2R4sQaTlz0xM7U518JxNj/aZGx80HU5bbsPMeTC
# j/ts0aGUGCLu6WZnOlNN3Zi6th542DYunKmCVgADsAW+iehp4LoJ7nvfam++Kctu
# 2D9IdQHZGN5tggz1bSNU5HhTdSRXud2f8449xvNo32X2pFaq95W2KFUn0CS9QKC/
# GbYSEhFdPSfgQJY4rPf5KYnDvBewVIVCs/wMnosZiefwC2qBwoEZQhlSdYo2wh3D
# YXMuLGt7bj8sCXgU6ZGyqVvfSaN0DLzskYDSPeZKPmY7T7uG+jIa2Zb0j/aRAfbO
# xnT99kxybxCrdTDFNLB62FD+CljdQDzHVG2dY3RILLFORy3BFARxv2T5JL5zbcqO
# Cb2zAVdJVGTZc9d/HltEAY5aGZFrDZ+kKNxnGSgkujhLmm77IVRrakURR6nxt67I
# 6IleT53S0Ex2tVdUCbFpAUR+fKFhbHP+CrvsQWY9af3LwUFJfn6Tvsv4O+S3Fb+0
# zj6lMVGEvL8CwYKiexcdFYmNcP7ntdAoGokLjzbaukz5m/8K6TT4JDVnK+ANuOaM
# mdbhIurwJ0I9JZTmdHRbatGePu1+oDEzfbzL6Xu/OHBE0ZDxyKs6ijoIYn/ZcGNT
# TY3ugm2lBRDBcQZqELQdVTNYs6FwZvKhggLLMIICNAIBATCB+KGB0KSBzTCByjEL
# MAkGA1UEBhMCVVMxEzARBgNVBAgTCldhc2hpbmd0b24xEDAOBgNVBAcTB1JlZG1v
# bmQxHjAcBgNVBAoTFU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjElMCMGA1UECxMcTWlj
# cm9zb2Z0IEFtZXJpY2EgT3BlcmF0aW9uczEmMCQGA1UECxMdVGhhbGVzIFRTUyBF
# U046RDZCRC1FM0U3LTE2ODUxJTAjBgNVBAMTHE1pY3Jvc29mdCBUaW1lLVN0YW1w
# IFNlcnZpY2WiIwoBATAHBgUrDgMCGgMVAOIASP0JSbv5R23wxciQivHyckYooIGD
# MIGApH4wfDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCldhc2hpbmd0b24xEDAOBgNV
# BAcTB1JlZG1vbmQxHjAcBgNVBAoTFU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjEmMCQG
# A1UEAxMdTWljcm9zb2Z0IFRpbWUtU3RhbXAgUENBIDIwMTAwDQYJKoZIhvcNAQEF
# BQACBQDn/hl3MCIYDzIwMjMwNTA0MTk0NTU5WhgPMjAyMzA1MDUxOTQ1NTlaMHQw
# OgYKKwYBBAGEWQoEATEsMCowCgIFAOf+GXcCAQAwBwIBAAICCIowBwIBAAICEcEw
# CgIFAOf/avcCAQAwNgYKKwYBBAGEWQoEAjEoMCYwDAYKKwYBBAGEWQoDAqAKMAgC
# AQACAwehIKEKMAgCAQACAwGGoDANBgkqhkiG9w0BAQUFAAOBgQAZzyt89lQEOQXD
# Yz0Whh/oJtzd7BY7oWACd/6GIkaOQWaJhgdk/ljyboHnsPHPVsWsycehjMcuTEs4
# AxPbV+dZ1YvY3iRlQrGhmIcb7Vwol7Cv+g1LPqGTEFuT+I7zv60NUKkMNNWgSUDw
# 1pg/aT5jda0mXsN1SOQMzWGfbE9NsTGCBA0wggQJAgEBMIGTMHwxCzAJBgNVBAYT
# AlVTMRMwEQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYD
# VQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xJjAkBgNVBAMTHU1pY3Jvc29mdCBU
# aW1lLVN0YW1wIFBDQSAyMDEwAhMzAAABx/sAoEpb8ifcAAEAAAHHMA0GCWCGSAFl
# AwQCAQUAoIIBSjAaBgkqhkiG9w0BCQMxDQYLKoZIhvcNAQkQAQQwLwYJKoZIhvcN
# AQkEMSIEIMS0Zmpmo4HWMlm+TvX1x42ZifUlu8DyBLKdMRQ6Nmv2MIH6BgsqhkiG
# 9w0BCRACLzGB6jCB5zCB5DCBvQQgR+fl2+JSskULOeVYLbeMgk7HdIbREmAsjwtc
# y6MJkskwgZgwgYCkfjB8MQswCQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3Rv
# bjEQMA4GA1UEBxMHUmVkbW9uZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0
# aW9uMSYwJAYDVQQDEx1NaWNyb3NvZnQgVGltZS1TdGFtcCBQQ0EgMjAxMAITMwAA
# Acf7AKBKW/In3AABAAABxzAiBCCsqEPHNt7Duq0kC/+roIn157/GbpeoybrBw1nK
# le4E1jANBgkqhkiG9w0BAQsFAASCAgAKXj9kvhQix4XgKsS8HGFklUg2ovNb2K/m
# rcHZogElf6g6RbSXAixCHWkW4zJK3YipiflA4+XZSOL5mgF0A0XVOyCSz6KCnjh4
# p7fKu6MZYP94WXirlD3PepO0Fy+lJOxqnrLZe7pC4dltXGaHwWdkiq+duWC9Gvka
# C69XHcFo2PR4/qLo3ve9IYbtpzuKhBUAQUmb/PPOQQYAypDv3d8CIErQ6/pT+2NJ
# 4iitZBMiPA3G0I1KrGx1g45DcqvCb1YgTM5o0eAooyJgLZL6N/NaFjBY8RNAV/EL
# ORG1cEMBzYrWYFW95TU9lywyJWjnH0WBu8tWLGLr5qwDxJKYD5poJASql092rRrZ
# JlxaKjn2OjOxgNrVAdMLisXq3m72lDMTSc05J/36MIYAKn4QO1oqg4r3GKqjw0j9
# SRoMSvtaqY/1inkr6YLAyxkrxqBxKit9R7cZtj4GnZqsUN65y/EWjJLiE8owTo9J
# nsbldoJDwxh7OVujZczSASVx5WWB6/gWtEeC/i+I/8xxUDsCH6KtoWywtCQloHeh
# 58i9/fQESvvJHfM+B65wPjfX2gy3IZbj9BL2Cnf7J6X6dcJbrnJIV9e60iMxmzLL
# FCmQ79J7QOoT8/ZbORR2rDUjEbFiJyvpezzy41UZE88H1bGSjuYvZeZ/K/WZAjKI
# fAQ6Ogn2NQ==
# SIG # End signature block