ShieldedVMDeployment/ShieldedVMDeployment.psm1

# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License.

function GetPdk($Path) {
    $pdk = CimCmdlets\Invoke-CimMethod -ClassName  Msps_ProvisioningFileProcessor -Namespace root\msps -MethodName PopulateFromFile -Arguments @{ FilePath = $ShieldingDataFilePath } -Verbose:$false -ErrorAction SilentlyContinue
    
    if (-not $pdk) {
        throw "Could not read PDK file."
    }

    return $pdk.ProvisioningFile
}

function GetSecuritySettingDataString($vm) {
    try {
        $cimvm = CimCmdlets\Get-CimInstance  -Namespace root\virtualization\v2 -Class Msvm_ComputerSystem -Filter "Name = '$($vm.VMId)'" -Verbose:$false -ErrorAction Stop
        $vsd = CimCmdlets\Get-CimAssociatedInstance -InputObject $cimvm -ResultClassName "Msvm_VirtualSystemSettingData" -Verbose:$false -ErrorAction Stop
        $ssd = CimCmdlets\Get-CimAssociatedInstance -InputObject $vsd -ResultClassName "Msvm_SecuritySettingData" -Verbose:$false -ErrorAction Stop
        $cimSerializer = [Microsoft.Management.Infrastructure.Serialization.CimSerializer]::Create()
        $ssdString = [System.Text.Encoding]::Unicode.GetString($cimSerializer.Serialize($ssd, [Microsoft.Management.Infrastructure.Serialization.InstanceSerializationOptions]::None))
    }
    catch {
        throw "Could not read security setting data string"
    }

    return $ssdString
}

function GetSecurityService($vm) {
    try {
        $cimvm = CimCmdlets\Get-CimInstance -Namespace root\virtualization\v2 -Class Msvm_ComputerSystem -Filter "Name = '$($vm.VMId)'" -Verbose:$false -ErrorAction Stop
        $ss = CimCmdlets\Get-CimAssociatedInstance -InputObject $cimvm -ResultClassName "Msvm_SecurityService" -Verbose:$false -ErrorAction Stop
    }
    catch {
        throw "Could not get security service for VM"
    }

    return $ss
}

function SetSecurityPolicy($vm, $pdk) {
    try {
        $ss = GetSecurityService -vm $vm
        $ssdString = GetSecuritySettingDataString -vm $vm
        $null = CimCmdlets\Invoke-CimMethod -InputObject $ss -MethodName SetSecurityPolicy -Arguments @{ "SecuritySettingData" = $ssdString; "SecurityPolicy" = $pdk.PolicyData } -Verbose:$false -ErrorAction Stop
    }
    catch {
        throw "Could not apply security policy to VM"
    }
}

function IsPdkForExistingVM($pdk) {
    return (-not $pdk.VolumeIDFilters)
}

function New-ShieldedVM {
    
    <#
    .SYNOPSIS
    Creates a new shielded virtual machine.
     
    .DESCRIPTION
    Creates a new shielded virtual machine using a prepared template disk and shielding data file.
    The virtual machine will go through shielded VM provisioning, which re-encrypts the OS volume
    and may take several minutes to complete. Use the -Wait parameter to observe the progress.
     
    .PARAMETER Name
    Name of the new virtual machine.
     
    .PARAMETER TemplateDiskPath
    Location of the template disk that has been prepared for use with shielded virtual machines.
     
    .PARAMETER ShieldingDataFilePath
    Location of the shielding data file used to configure the shielded VM.
     
    .PARAMETER SwitchName
    Name of network switch to which the VM should be connected.
    If no switch name is provided, and there is only one switch configured in Hyper-V, the VM will be connected to that switch.
     
    .PARAMETER Linux
    Indicates that the VM will run a Linux-based operating system.
     
    .PARAMETER MemoryStartupBytes
    Amount of memory to allocate to the VM (defaults to 2GB).
     
    .PARAMETER CpuCount
    Number of virtual processors to allocate to the VM (defaults to 2).
     
    .PARAMETER VMPath
    Location to store the resulting VM.
    If omitted, the default VM path configured in Hyper-V will be used for VM storage.
     
    .PARAMETER SpecializationValues
    Key-value pairs to replace in the shielding data answer file.
    @ComputerName@ is automatically set using the value of the -Name parameter, but can be overridden if desired.
     
    .PARAMETER Wait
    Shows the progress of the provisioning job and waits to return control until the VM is provisioned.
     
    .EXAMPLE
    New-ShieldedVM -Name 'CorpDC01' -TemplateDiskPath '.\WS2016-Template.vhdx' -ShieldingDataFilePath '.\DC.pdk' -SwitchName 'corpnet'
 
    Creates a new Windows shielded VM called "CorpDC01" using the specified templtae disk and shielding data file.
 
    .EXAMPLE
    New-ShieldedVM -Name 'ExampleVM' -TemplateDiskPath '.\template.vhdx' -ShieldingDataFilePath '.\myvm.pdk' -SpecializationValues @{ '@ComputerName@' = 'myVM01' }
     
    Creates a new Windows shielded VM with a custom replacement for the @ComputerName@ property in the shielding data answer file.
    #>


    [CmdletBinding()]
    param(
        [Parameter(Mandatory=$true)]
        [string]
        $Name,

        [Parameter(Mandatory=$true)]
        [string]
        $TemplateDiskPath,

        [Parameter(Mandatory=$true)]
        [string]
        $ShieldingDataFilePath,
        
        [string]
        $SwitchName,

        [switch]
        $Linux,

        [ValidateRange(1GB, 1TB)]
        [Int64]
        $MemoryStartupBytes = 2GB,

        [ValidateRange(1,240)]
        [int]
        $CpuCount = 2,

        [string]
        $VMPath,

        [System.Collections.IDictionary]
        $SpecializationValues,

        [switch]
        $Wait
    )

    ## Parameter validation
    # Check for invalid names (relating to file paths assumed later)
    if ($Name -match '"|<|>|\||\\|/|\*|\?') {
        throw [System.ArgumentException] "Name cannot contain the following characters: `", ?, *, |, \, /, <, >"
    }

    # Ensure template disk exists
    $TemplateDiskPath = Microsoft.PowerShell.Management\Resolve-Path $TemplateDiskPath -ErrorAction Stop | Microsoft.PowerShell.Management\Convert-Path
    if (-not (Microsoft.PowerShell.Management\Test-Path $TemplateDiskPath -PathType Leaf) -or $TemplateDiskPath -notlike "*.vhdx") {
        throw [System.IO.FileNotFoundException] "The template disk path is invalid."
    }

    # Ensure shielding data file exists
    $ShieldingDataFilePath = Microsoft.PowerShell.Management\Resolve-Path $ShieldingDataFilePath -ErrorAction Stop | Microsoft.PowerShell.Management\Convert-Path
    if (-not (Microsoft.PowerShell.Management\Test-Path $ShieldingDataFilePath -PathType Leaf) -or $ShieldingDataFilePath -notlike "*.pdk") {
        throw [System.IO.FileNotFoundException] "The shielding data file path is invalid."
    }

    # Ensure the switch name is valid
    if ($SwitchName -and -not (Hyper-V\Get-VMSwitch -Name $SwitchName -ErrorAction SilentlyContinue)) {
        throw [System.ArgumentException] ("A networking switch with the name '{0}' could not be found on the host." -f $SwitchName)
    }
    elseif (-not $SwitchName) {
        $switches = Hyper-V\Get-VMSwitch
        if ($switches.Count -eq 1)
        {
            Microsoft.PowerShell.Utility\Write-Verbose ("No switch name was provided. The VM will be connected to the '{0}' switch." -f $switches.Name)
            $SwitchName = $switches.Name
        }
        else {
            throw [System.ArgumentException] ("More than one VM switch was found. Re-run the command and specify one of the following switch names to the -SwitchName parameter: {0}" -f `
                [string]::Join(', ', $switches.Name))
        }
    }

    # Ensure the VM path is valid
    if ($VMPath) {
        $VMPath = Microsoft.PowerShell.Management\Resolve-Path $VMPath -ErrorAction Stop | Microsoft.PowerShell.Management\Convert-Path
        if (-not (Microsoft.PowerShell.Management\Test-Path $VMPath -PathType Container)) {
            throw [System.IO.DirectoryNotFoundException] "The VM path is not a valid directory."
        }

        $VhdDirectory = Microsoft.PowerShell.Management\Join-Path $VMPath "Virtual Hard Disks"
        if (-not (Microsoft.PowerShell.Management\Test-Path $VhdDirectory)) {
            Microsoft.PowerShell.Utility\Write-Verbose ("Creating directory for VHD at '{0}'" -f $VhdDirectory)
            $null = Microsoft.PowerShell.Management\New-Item $VhdDirectory -ItemType Directory
        }
    }
    else {
        $vmroot = (Hyper-V\Get-VMHost).VirtualMachinePath
        $VMPath = Microsoft.PowerShell.Management\Join-Path $vmroot $Name
        
        if ((Microsoft.PowerShell.Management\Test-Path $VMPath)) {
            foreach ($i in 1..999) {
                $samplePath = "{0}-{1:D3}" -f $Name, $i
                $VMPath = Microsoft.PowerShell.Management\Join-Path $vmroot $samplePath
                if (-not (Microsoft.PowerShell.Management\Test-Path $VMPath)) {
                    break
                }
            }
        }

        Microsoft.PowerShell.Utility\Write-Verbose ("Creating a VM directory at '{0}'" -f $VMPath)
        $null = Microsoft.PowerShell.Management\New-Item -Path $VMPath -ItemType Directory -ErrorAction Stop
        $VhdDirectory = Microsoft.PowerShell.Management\Join-Path $VMPath "Virtual Hard Disks"
        $null = Microsoft.PowerShell.Management\New-Item -Path $VhdDirectory -ItemType Directory -ErrorAction Stop
    }

    # Ensure specialization values are not null
    if ($SpecializationValues) {
        foreach ($key in $SpecializationValues.Keys) {
            if ($key -isnot [string] -or $key -notlike "@*@") {
                throw [System.ArgumentException] ("Specialization key '{0}' is invalid. All specialization keys must be in the form '@KeyName@'." -f $key)
            }

            $value = $SpecializationValues.$key
            if ($value -isnot [string] -or [string]::IsNullOrEmpty($value)) {
                throw [System.ArgumentException] ("The value for specialization key '{0}' is invalid. Values must be non-empty strings." -f $key)
            }
        }
    }

    ## Create the VM
    $VHDPath = Microsoft.PowerShell.Management\Join-Path $VhdDirectory "$Name-OS.vhdx"
    Microsoft.PowerShell.Utility\Write-Verbose ("Copying the template disk to '{0}'" -f $VHDPath)
    Microsoft.PowerShell.Management\Copy-Item -Path $TemplateDiskPath -Destination $VHDPath -ErrorAction Stop

    Microsoft.PowerShell.Utility\Write-Verbose "Creating the new VM"
    $vm = Hyper-V\New-VM -Name $Name -Generation 2 -Path $VMPath -VhdPath $VHDPath -SwitchName $SwitchName -MemoryStartupBytes $MemoryStartupBytes -ErrorAction Stop
    Hyper-V\Set-VMProcessor -VM $vm -Count $CpuCount

    if ($Linux) {
        Hyper-V\Set-VMFirmware -VM $vm -SecureBootTemplate OpenSourceShieldedVM -ErrorAction Stop
    }

    # Attach the key protector
    $kp = Get-KeyProtectorFromShieldingDataFile -ShieldingDataFilePath $ShieldingDataFilePath
    Hyper-V\Set-VMKeyProtector -VM $vm -KeyProtector $kp -ErrorAction Stop

    # Get the security data from the PDK file
    try {
        $pdk = CimCmdlets\Invoke-CimMethod -ClassName  Msps_ProvisioningFileProcessor -Namespace root\msps -MethodName PopulateFromFile -Arguments @{ FilePath = $ShieldingDataFilePath } -Verbose:$false -ErrorAction Stop
        $cimvm = CimCmdlets\Get-CimInstance  -Namespace root\virtualization\v2 -Class Msvm_ComputerSystem -Filter "Name = '$($vm.VMId)'" -Verbose:$false -ErrorAction Stop
        $vsd = CimCmdlets\Get-CimAssociatedInstance -InputObject $cimvm -ResultClassName "Msvm_VirtualSystemSettingData" -Verbose:$false -ErrorAction Stop
        $ssd = CimCmdlets\Get-CimAssociatedInstance -InputObject $vsd -ResultClassName "Msvm_SecuritySettingData" -Verbose:$false -ErrorAction Stop
        $ss = CimCmdlets\Get-CimAssociatedInstance -InputObject $cimvm -ResultClassName "Msvm_SecurityService" -Verbose:$false -ErrorAction Stop
        $cimSerializer = [Microsoft.Management.Infrastructure.Serialization.CimSerializer]::Create()
        $ssdString = [System.Text.Encoding]::Unicode.GetString($cimSerializer.Serialize($ssd, [Microsoft.Management.Infrastructure.Serialization.InstanceSerializationOptions]::None))
    }
    catch {
        throw "A security policy could not be created from the shielding data file.`n`n$($_.Message)"
    }

    # Apply the VM security policy and enable the VM TPM
    Microsoft.PowerShell.Utility\Write-Verbose "Enabling VM TPM"
    $null = CimCmdlets\Invoke-CimMethod -InputObject $ss -MethodName SetSecurityPolicy -Arguments @{ "SecuritySettingData" = $ssdString; "SecurityPolicy" = $pdk.ProvisioningFile.PolicyData } -Verbose:$false -ErrorAction Stop
    Hyper-V\Enable-VMTPM -VM $vm -ErrorAction Stop

    # Create the fabric specialization keyfile
    Microsoft.PowerShell.Utility\Write-Verbose "Creating specialization data file"
    $fskPath = Microsoft.PowerShell.Management\Join-Path $VMPath "SpecializationData.fsk"
    $simpleComputerName = $Name -replace '[^\w-]', ''
    $fskParams = @{ '@ComputerName@' = $simpleComputerName }
    
    if ($SpecializationValues) {
        foreach ($key in $SpecializationValues.Keys) {
            $fskParams.$key = $SpecializationValues.$key
        }
    }

    ShieldedVMProvisioning\New-ShieldedVMSpecializationDataFile -ShieldedVMSpecializationDataFilePath $fskPath -SpecializationDataPairs $fskParams -ErrorAction Stop

    # Provision the VM
    Microsoft.PowerShell.Utility\Write-Verbose "Initiating shielded VM provisioning process"
    $provisioningJob = ShieldedVMProvisioning\Initialize-ShieldedVM -VM $vm -ShieldingDataFilePath $ShieldingDataFilePath -ShieldedVMSpecializationDataFilePath $fskPath -ErrorAction Stop

    if ($Wait) {
        do {
            $status = ShieldedVMProvisioning\Get-ShieldedVMProvisioningStatus -VM $vm
            Write-Progress -Activity ("Provisioning shielded VM '{0}'" -f $Name) -PercentComplete $status.PercentComplete -Status ("{0}% complete" -f $Status.PercentComplete)
            Microsoft.PowerShell.Utility\Start-Sleep -Milliseconds 1500
        }
        while ($status -and $status.Status -ne 'Error' -and $status.PercentComplete -lt 100)

        if ($status) {
            Microsoft.PowerShell.Utility\Write-Output $status.JobStatus

            if ($status.ErrorDescription) {
                Microsoft.PowerShell.Utility\Write-Error $status.ErrorDescription
            }
        }
        else {
            Microsoft.Powershell.Utility\Write-Output "Unable to check the status of the shielded VM provisioning process."
        }
    }
    else {
        return $provisioningJob
    }
}

function ConvertTo-ShieldedVM {
    <#
    .SYNOPSIS
    Converts an existing virtual machine to a shielded virtual machine.
     
    .DESCRIPTION
    Converts an existing virtual machine to a shielded virtual machine by applying a virtual TPM and security policy to the VM.
    The VM will not automatically be encrypted by this command, but encryption can be enabled inside the guest OS after the virtual TPM is available.
    See https://aka.ms/AA3trat for information about automating the encryption of existing VMs.
     
    .PARAMETER VM
    Specifies the virtual machine to convert to a shielded virtual machine.
     
    .PARAMETER VMName
    Specifies the name of the virtual machine to convert to a shielded virtual machine.
 
    .PARAMETER ShieldingDataFilePath
    Path to a shielding data file used to shield the VM.
    The security policy and key protector from the shielding data file are applied to the specified VM.
    Answer files and additional files included in the shielding data file are not copied into the VM.
     
    .EXAMPLE
    $vm = Get-VM "SQL01"
    ConvertTo-ShieldedVM -VM $vm -ShieldingDataFilePath 'D:\ShieldingData\existingvm.pdk'
 
    Converts the "SQL01" virtual machine to a shielded virtual machine using the specified shielding data file.
 
    .EXAMPLE
    ConvertTo-ShieldedVM -VMName "CORPDC01" -ShieldingDataFilePath 'D:\ShieldingData\existingvm.pdk'
 
    Converts the "CORPDC01" virtual machine to a shielded virtual machine using the specified shielding data file.
    #>


    [CmdletBinding(DefaultParameterSetName="ByName", SupportsShouldProcess=$true, ConfirmImpact="Medium")]
    param(
        [Parameter(Mandatory=$true, Position=0, ParameterSetName="ByVM")]
        [ValidateNotNullOrEmpty()]
        [Microsoft.HyperV.PowerShell.VirtualMachine]
        $VM,

        [Parameter(Mandatory=$true, Position=0, ParameterSetName="ByName")]
        [ValidateNotNullOrEmpty()]
        [string]
        $VMName,

        [Parameter(Mandatory=$true)]
        [ValidateNotNullOrEmpty()]
        [string]
        $ShieldingDataFilePath
    )

    ## Parameter validation
    # Check VM name
    if ($PSCmdlet.ParameterSetName -eq "ByName") {
        $VM = Get-VM -Name $VMName -ErrorAction Stop
    }

    # Check if VM can be shielded
    if ($VM.Generation -ne 2) {
        throw "The specified virtual machine is a generation 1 VM. Only generation 2 VMs can be shielded."
    }

    $kp = Get-VMKeyProtector -VM $VM
    if ($kp.Length -gt 4) {
        throw "The specified virtual machine has already been configured with a key protector. To change the key protector, delete the VM configuration and create a new one. This will also delete the virtual TPM associated with this VM and could result in data loss if data encryption is not suspended first."
    }

    $firmware = Get-VMFirmware -VM $VM
    if ($firmware.SecureBoot -ne "On") {
        throw "Secure Boot must be enabled on the virtual machine before it can be shielded."
    }

    if ($vm.State -ne 'Off') {
        throw "The virtual machine must be turned off before it can be shielded."
    }

    $vmVersion = [System.Version] $vm.Version
    $minVersion = [System.Version] "8.0"
    if ($vmVersion -lt $minVersion) {
        $latestVersion = (Get-VMHostSupportedVersion -Default).Version.ToString()
        throw "The virtual machine configuration version is currently $($vm.Version) but must be upgraded before the virtual machine can be shielded. Run `"Update-VMVersion '$($vm.Name)'`" to upgrade the VM to version $latestVersion." 
    }

    # Ensure shielding data file exists
    $ShieldingDataFilePath = Microsoft.PowerShell.Management\Resolve-Path $ShieldingDataFilePath -ErrorAction Stop | Microsoft.PowerShell.Management\Convert-Path
    if (-not (Microsoft.PowerShell.Management\Test-Path $ShieldingDataFilePath -PathType Leaf) -or $ShieldingDataFilePath -notlike "*.pdk") {
        throw [System.IO.FileNotFoundException] "The shielding data file path is invalid."
    }

    # Try opening the shielding data file
    try {
        $pdk = GetPDK -Path $ShieldingDataFilePath
        
        if (-not $pdk -or -not $pdk.PolicyData) {
            throw "Could not parse the shielding data file."
        }
    }
    catch {
        throw "Could not open the shielding data file."
    }

    # Warn if differencing disks are in use
    $VHDs = Get-VMHardDiskDrive -VM $VM
    foreach ($vhd in $VHDs) {
        $vhdDetails = Get-VHD -Path $vhd.Path
        if ($vhdDetails.VhdType -eq "Differencing") {
            Write-Warning "The specified virtual machine uses one or more differencing disks. To ensure all data is protected when you encrypt data on this virtual machine, delete all checkpoints and merge any differencing disks before enabling full volume encryption. Existing backups, checkpoints, and parent VHDs will not be encrypted if the guest OS enables full volume encryption."
            break
        }
    }

    ## Convert the VM
    if ($PSCmdlet.ShouldProcess("Converting '$($VM.Name)' to a shielded virtual machine", "Are you sure you want to convert '$($VM.Name)' to a shielded virtual machine?", "Shield existing VM")) {
        # Upgrade the VM version if necessary
        if ($vmVersion -lt $minVersion) {
            Write-Verbose "Upgrading VM version"
            Update-VMVersion -VM $VM -Force
        }

        # Attach the key protector
        Write-Verbose "Setting key protector on VM"
        $kp = Get-KeyProtectorFromShieldingDataFile -ShieldingDataFilePath $ShieldingDataFilePath
        Set-VMKeyProtector -VM $vm -KeyProtector $kp -ErrorAction Stop

        # Set the security policy
        Write-Verbose "Applying security policy to the VM"
        SetSecurityPolicy -vm $VM -pdk $pdk

        # Enable the VM TPM
        Write-Verbose "Enabling the VM TPM"
        Enable-VMTPM -VM $VM -ErrorAction Stop

        Write-Output "The virtual TPM has been enabled on the VM. To encrypt the VM data, turn on the VM and enable full volume encryption (leveraging the TPM to protect the encryption key) using the instructions for your operating system."
    }
}
# SIG # Begin signature block
# MIIkegYJKoZIhvcNAQcCoIIkazCCJGcCAQExDzANBglghkgBZQMEAgEFADB5Bgor
# BgEEAYI3AgEEoGswaTA0BgorBgEEAYI3AgEeMCYCAwEAAAQQH8w7YFlLCE63JNLG
# KX7zUQIBAAIBAAIBAAIBAAIBADAxMA0GCWCGSAFlAwQCAQUABCAg/3mkUXBOQ1M8
# 95I8s5glIqqsIs83hU/9kOfRzHXQ36CCDYEwggX/MIID56ADAgECAhMzAAABA14l
# HJkfox64AAAAAAEDMA0GCSqGSIb3DQEBCwUAMH4xCzAJBgNVBAYTAlVTMRMwEQYD
# VQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNy
# b3NvZnQgQ29ycG9yYXRpb24xKDAmBgNVBAMTH01pY3Jvc29mdCBDb2RlIFNpZ25p
# bmcgUENBIDIwMTEwHhcNMTgwNzEyMjAwODQ4WhcNMTkwNzI2MjAwODQ4WjB0MQsw
# CQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9u
# ZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMR4wHAYDVQQDExVNaWNy
# b3NvZnQgQ29ycG9yYXRpb24wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIB
# AQDRlHY25oarNv5p+UZ8i4hQy5Bwf7BVqSQdfjnnBZ8PrHuXss5zCvvUmyRcFrU5
# 3Rt+M2wR/Dsm85iqXVNrqsPsE7jS789Xf8xly69NLjKxVitONAeJ/mkhvT5E+94S
# nYW/fHaGfXKxdpth5opkTEbOttU6jHeTd2chnLZaBl5HhvU80QnKDT3NsumhUHjR
# hIjiATwi/K+WCMxdmcDt66VamJL1yEBOanOv3uN0etNfRpe84mcod5mswQ4xFo8A
# DwH+S15UD8rEZT8K46NG2/YsAzoZvmgFFpzmfzS/p4eNZTkmyWPU78XdvSX+/Sj0
# NIZ5rCrVXzCRO+QUauuxygQjAgMBAAGjggF+MIIBejAfBgNVHSUEGDAWBgorBgEE
# AYI3TAgBBggrBgEFBQcDAzAdBgNVHQ4EFgQUR77Ay+GmP/1l1jjyA123r3f3QP8w
# UAYDVR0RBEkwR6RFMEMxKTAnBgNVBAsTIE1pY3Jvc29mdCBPcGVyYXRpb25zIFB1
# ZXJ0byBSaWNvMRYwFAYDVQQFEw0yMzAwMTIrNDM3OTY1MB8GA1UdIwQYMBaAFEhu
# ZOVQBdOCqhc3NyK1bajKdQKVMFQGA1UdHwRNMEswSaBHoEWGQ2h0dHA6Ly93d3cu
# bWljcm9zb2Z0LmNvbS9wa2lvcHMvY3JsL01pY0NvZFNpZ1BDQTIwMTFfMjAxMS0w
# Ny0wOC5jcmwwYQYIKwYBBQUHAQEEVTBTMFEGCCsGAQUFBzAChkVodHRwOi8vd3d3
# Lm1pY3Jvc29mdC5jb20vcGtpb3BzL2NlcnRzL01pY0NvZFNpZ1BDQTIwMTFfMjAx
# MS0wNy0wOC5jcnQwDAYDVR0TAQH/BAIwADANBgkqhkiG9w0BAQsFAAOCAgEAn/XJ
# Uw0/DSbsokTYDdGfY5YGSz8eXMUzo6TDbK8fwAG662XsnjMQD6esW9S9kGEX5zHn
# wya0rPUn00iThoj+EjWRZCLRay07qCwVlCnSN5bmNf8MzsgGFhaeJLHiOfluDnjY
# DBu2KWAndjQkm925l3XLATutghIWIoCJFYS7mFAgsBcmhkmvzn1FFUM0ls+BXBgs
# 1JPyZ6vic8g9o838Mh5gHOmwGzD7LLsHLpaEk0UoVFzNlv2g24HYtjDKQ7HzSMCy
# RhxdXnYqWJ/U7vL0+khMtWGLsIxB6aq4nZD0/2pCD7k+6Q7slPyNgLt44yOneFuy
# bR/5WcF9ttE5yXnggxxgCto9sNHtNr9FB+kbNm7lPTsFA6fUpyUSj+Z2oxOzRVpD
# MYLa2ISuubAfdfX2HX1RETcn6LU1hHH3V6qu+olxyZjSnlpkdr6Mw30VapHxFPTy
# 2TUxuNty+rR1yIibar+YRcdmstf/zpKQdeTr5obSyBvbJ8BblW9Jb1hdaSreU0v4
# 6Mp79mwV+QMZDxGFqk+av6pX3WDG9XEg9FGomsrp0es0Rz11+iLsVT9qGTlrEOla
# P470I3gwsvKmOMs1jaqYWSRAuDpnpAdfoP7YO0kT+wzh7Qttg1DO8H8+4NkI6Iwh
# SkHC3uuOW+4Dwx1ubuZUNWZncnwa6lL2IsRyP64wggd6MIIFYqADAgECAgphDpDS
# AAAAAAADMA0GCSqGSIb3DQEBCwUAMIGIMQswCQYDVQQGEwJVUzETMBEGA1UECBMK
# V2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9uZDEeMBwGA1UEChMVTWljcm9zb2Z0
# IENvcnBvcmF0aW9uMTIwMAYDVQQDEylNaWNyb3NvZnQgUm9vdCBDZXJ0aWZpY2F0
# ZSBBdXRob3JpdHkgMjAxMTAeFw0xMTA3MDgyMDU5MDlaFw0yNjA3MDgyMTA5MDla
# MH4xCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdS
# ZWRtb25kMR4wHAYDVQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xKDAmBgNVBAMT
# H01pY3Jvc29mdCBDb2RlIFNpZ25pbmcgUENBIDIwMTEwggIiMA0GCSqGSIb3DQEB
# AQUAA4ICDwAwggIKAoICAQCr8PpyEBwurdhuqoIQTTS68rZYIZ9CGypr6VpQqrgG
# OBoESbp/wwwe3TdrxhLYC/A4wpkGsMg51QEUMULTiQ15ZId+lGAkbK+eSZzpaF7S
# 35tTsgosw6/ZqSuuegmv15ZZymAaBelmdugyUiYSL+erCFDPs0S3XdjELgN1q2jz
# y23zOlyhFvRGuuA4ZKxuZDV4pqBjDy3TQJP4494HDdVceaVJKecNvqATd76UPe/7
# 4ytaEB9NViiienLgEjq3SV7Y7e1DkYPZe7J7hhvZPrGMXeiJT4Qa8qEvWeSQOy2u
# M1jFtz7+MtOzAz2xsq+SOH7SnYAs9U5WkSE1JcM5bmR/U7qcD60ZI4TL9LoDho33
# X/DQUr+MlIe8wCF0JV8YKLbMJyg4JZg5SjbPfLGSrhwjp6lm7GEfauEoSZ1fiOIl
# XdMhSz5SxLVXPyQD8NF6Wy/VI+NwXQ9RRnez+ADhvKwCgl/bwBWzvRvUVUvnOaEP
# 6SNJvBi4RHxF5MHDcnrgcuck379GmcXvwhxX24ON7E1JMKerjt/sW5+v/N2wZuLB
# l4F77dbtS+dJKacTKKanfWeA5opieF+yL4TXV5xcv3coKPHtbcMojyyPQDdPweGF
# RInECUzF1KVDL3SV9274eCBYLBNdYJWaPk8zhNqwiBfenk70lrC8RqBsmNLg1oiM
# CwIDAQABo4IB7TCCAekwEAYJKwYBBAGCNxUBBAMCAQAwHQYDVR0OBBYEFEhuZOVQ
# BdOCqhc3NyK1bajKdQKVMBkGCSsGAQQBgjcUAgQMHgoAUwB1AGIAQwBBMAsGA1Ud
# DwQEAwIBhjAPBgNVHRMBAf8EBTADAQH/MB8GA1UdIwQYMBaAFHItOgIxkEO5FAVO
# 4eqnxzHRI4k0MFoGA1UdHwRTMFEwT6BNoEuGSWh0dHA6Ly9jcmwubWljcm9zb2Z0
# LmNvbS9wa2kvY3JsL3Byb2R1Y3RzL01pY1Jvb0NlckF1dDIwMTFfMjAxMV8wM18y
# Mi5jcmwwXgYIKwYBBQUHAQEEUjBQME4GCCsGAQUFBzAChkJodHRwOi8vd3d3Lm1p
# Y3Jvc29mdC5jb20vcGtpL2NlcnRzL01pY1Jvb0NlckF1dDIwMTFfMjAxMV8wM18y
# Mi5jcnQwgZ8GA1UdIASBlzCBlDCBkQYJKwYBBAGCNy4DMIGDMD8GCCsGAQUFBwIB
# FjNodHRwOi8vd3d3Lm1pY3Jvc29mdC5jb20vcGtpb3BzL2RvY3MvcHJpbWFyeWNw
# cy5odG0wQAYIKwYBBQUHAgIwNB4yIB0ATABlAGcAYQBsAF8AcABvAGwAaQBjAHkA
# XwBzAHQAYQB0AGUAbQBlAG4AdAAuIB0wDQYJKoZIhvcNAQELBQADggIBAGfyhqWY
# 4FR5Gi7T2HRnIpsLlhHhY5KZQpZ90nkMkMFlXy4sPvjDctFtg/6+P+gKyju/R6mj
# 82nbY78iNaWXXWWEkH2LRlBV2AySfNIaSxzzPEKLUtCw/WvjPgcuKZvmPRul1LUd
# d5Q54ulkyUQ9eHoj8xN9ppB0g430yyYCRirCihC7pKkFDJvtaPpoLpWgKj8qa1hJ
# Yx8JaW5amJbkg/TAj/NGK978O9C9Ne9uJa7lryft0N3zDq+ZKJeYTQ49C/IIidYf
# wzIY4vDFLc5bnrRJOQrGCsLGra7lstnbFYhRRVg4MnEnGn+x9Cf43iw6IGmYslmJ
# aG5vp7d0w0AFBqYBKig+gj8TTWYLwLNN9eGPfxxvFX1Fp3blQCplo8NdUmKGwx1j
# NpeG39rz+PIWoZon4c2ll9DuXWNB41sHnIc+BncG0QaxdR8UvmFhtfDcxhsEvt9B
# xw4o7t5lL+yX9qFcltgA1qFGvVnzl6UJS0gQmYAf0AApxbGbpT9Fdx41xtKiop96
# eiL6SJUfq/tHI4D1nvi/a7dLl+LrdXga7Oo3mXkYS//WsyNodeav+vyL6wuA6mk7
# r/ww7QRMjt/fdW1jkT3RnVZOT7+AVyKheBEyIXrvQQqxP/uozKRdwaGIm1dxVk5I
# RcBCyZt2WwqASGv9eZ/BvW1taslScxMNelDNMYIWTzCCFksCAQEwgZUwfjELMAkG
# A1UEBhMCVVMxEzARBgNVBAgTCldhc2hpbmd0b24xEDAOBgNVBAcTB1JlZG1vbmQx
# HjAcBgNVBAoTFU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjEoMCYGA1UEAxMfTWljcm9z
# b2Z0IENvZGUgU2lnbmluZyBQQ0EgMjAxMQITMwAAAQNeJRyZH6MeuAAAAAABAzAN
# BglghkgBZQMEAgEFAKCB0DAZBgkqhkiG9w0BCQMxDAYKKwYBBAGCNwIBBDAcBgor
# BgEEAYI3AgELMQ4wDAYKKwYBBAGCNwIBFTAvBgkqhkiG9w0BCQQxIgQgcKQa89X/
# d2XeMlkqOJ3D5qSMBResPlmcWwoN8uZ8pi8wZAYKKwYBBAGCNwIBDDFWMFSgNIAy
# AEcAdQBhAHIAZABlAGQARgBhAGIAcgBpAGMAVABvAG8AbABzACAAdgAxACAAMQAg
# ADChHIAaaHR0cHM6Ly93d3cubWljcm9zb2Z0LmNvbSAwDQYJKoZIhvcNAQEBBQAE
# ggEAOh80LyFAcrLIO0RLN+lH+mmSs6jBEYjdCpovTKQ42T3kTrNE6b0vdz7fILTo
# JnB5rzzuq7sZY58DG/76h1etwZQgscARytwqqeXNMyAQ2WfP2nifGG6K156DwY9W
# lFRzbEyczZvwbMjdMDaNleLdcXQxSzV00+d8xKnn9K3Yr44kniL09UW72SQVrrnr
# 0DywDemsyIQIcK5+lG7ihn5h9UiXw+gnw744eVYrnPt+reUjs32SgTJxPxG5uMye
# 1uZAitFsWWUABbVjkRfi6wBDUdsPDAfFxsJ5iSpBnnzF2UTILCX4QEdgAO2mzx80
# Z7smus5HHhtqQQa6eOsdE8jIRqGCE7cwghOzBgorBgEEAYI3AwMBMYITozCCE58G
# CSqGSIb3DQEHAqCCE5AwghOMAgEDMQ8wDQYJYIZIAWUDBAIBBQAwggFYBgsqhkiG
# 9w0BCRABBKCCAUcEggFDMIIBPwIBAQYKKwYBBAGEWQoDATAxMA0GCWCGSAFlAwQC
# AQUABCCVSP9tufp6v3sHMp0WWnK9KiVlRLhohlAnjvuOCzuIRQIGXJQN3kGTGBMy
# MDE5MDMyNjAwMTE1OC45MzlaMAcCAQGAAgH0oIHUpIHRMIHOMQswCQYDVQQGEwJV
# UzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9uZDEeMBwGA1UE
# ChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMSkwJwYDVQQLEyBNaWNyb3NvZnQgT3Bl
# cmF0aW9ucyBQdWVydG8gUmljbzEmMCQGA1UECxMdVGhhbGVzIFRTUyBFU046MzFD
# NS0zMEJBLTdDOTExJTAjBgNVBAMTHE1pY3Jvc29mdCBUaW1lLVN0YW1wIFNlcnZp
# Y2Wggg8fMIIE9TCCA92gAwIBAgITMwAAAM2m2zivvS1BAAAAAAAAzTANBgkqhkiG
# 9w0BAQsFADB8MQswCQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4G
# A1UEBxMHUmVkbW9uZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMSYw
# JAYDVQQDEx1NaWNyb3NvZnQgVGltZS1TdGFtcCBQQ0EgMjAxMDAeFw0xODA4MjMy
# MDI2MjZaFw0xOTExMjMyMDI2MjZaMIHOMQswCQYDVQQGEwJVUzETMBEGA1UECBMK
# V2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9uZDEeMBwGA1UEChMVTWljcm9zb2Z0
# IENvcnBvcmF0aW9uMSkwJwYDVQQLEyBNaWNyb3NvZnQgT3BlcmF0aW9ucyBQdWVy
# dG8gUmljbzEmMCQGA1UECxMdVGhhbGVzIFRTUyBFU046MzFDNS0zMEJBLTdDOTEx
# JTAjBgNVBAMTHE1pY3Jvc29mdCBUaW1lLVN0YW1wIFNlcnZpY2UwggEiMA0GCSqG
# SIb3DQEBAQUAA4IBDwAwggEKAoIBAQCyGo7FFLRXglYKrtD3s5lk8Uq9UgaJo2HO
# V3qNRbolSSs2UpJbkDoPjldqGRTfZQBH4IPyDLNA4Cs3Arjjpko+aKeveM+26PJJ
# 6gQuVR3qDGJKo7ZHnmL6EZwq/mckGaeCk2ZrIrMkEIJKsgFnI0reD92vo2eAwU18
# 4uqdrFAolclNJUDNJKqwWoVzCPmhB3VaBnIhQlR+juIkyfTbkKspDrTl28iZW7FL
# a5SMJL36VR0FsWdNb1vZd1BtwjCPhIC3SLRE507JAJLSTxD1L7PfF341cYFUarl2
# 4UKVyouBAhWQs28pux9Wsbz7aB5yxnP/mr17T3F73ECEOcgW27HbAgMBAAGjggEb
# MIIBFzAdBgNVHQ4EFgQUuB30YuL6CpIqVyAxBNnQvsnyAg4wHwYDVR0jBBgwFoAU
# 1WM6XIoxkPNDe3xGG8UzaFqFbVUwVgYDVR0fBE8wTTBLoEmgR4ZFaHR0cDovL2Ny
# bC5taWNyb3NvZnQuY29tL3BraS9jcmwvcHJvZHVjdHMvTWljVGltU3RhUENBXzIw
# MTAtMDctMDEuY3JsMFoGCCsGAQUFBwEBBE4wTDBKBggrBgEFBQcwAoY+aHR0cDov
# L3d3dy5taWNyb3NvZnQuY29tL3BraS9jZXJ0cy9NaWNUaW1TdGFQQ0FfMjAxMC0w
# Ny0wMS5jcnQwDAYDVR0TAQH/BAIwADATBgNVHSUEDDAKBggrBgEFBQcDCDANBgkq
# hkiG9w0BAQsFAAOCAQEAQkIAKiiPfcD4uSDnHnY1PJ6wWkIF0GH48CxDPewPCO5e
# QIuiBcsG15Lt/ckBazjdJwQq20k1C6y8vwrjSVO0hr8q+nz6d1BWoC8XiymTQKao
# GUfGBPZkzvYy0qpj7gho6yR0eKIjRr6pjyKxbLV9pdIHHfsRRtZ78kLfgZpR0wMC
# 6+8Ph2hk7LbEE/nJKWqZZDk1dHV30WKPokS12+WimwopoKoodBtkyvdGdQ3HWzYQ
# Fw9a3k73tTeU1K058gXlaXmhJhp/LsEUTA6XSTFpGH5+ViTgWTwycXAHud68rUio
# Xkah74TDTO2/385SdTZa20fWnfu78CBsOch9qtQfnTCCBnEwggRZoAMCAQICCmEJ
# gSoAAAAAAAIwDQYJKoZIhvcNAQELBQAwgYgxCzAJBgNVBAYTAlVTMRMwEQYDVQQI
# EwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNyb3Nv
# ZnQgQ29ycG9yYXRpb24xMjAwBgNVBAMTKU1pY3Jvc29mdCBSb290IENlcnRpZmlj
# YXRlIEF1dGhvcml0eSAyMDEwMB4XDTEwMDcwMTIxMzY1NVoXDTI1MDcwMTIxNDY1
# NVowfDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCldhc2hpbmd0b24xEDAOBgNVBAcT
# B1JlZG1vbmQxHjAcBgNVBAoTFU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjEmMCQGA1UE
# AxMdTWljcm9zb2Z0IFRpbWUtU3RhbXAgUENBIDIwMTAwggEiMA0GCSqGSIb3DQEB
# AQUAA4IBDwAwggEKAoIBAQCpHQ28dxGKOiDs/BOX9fp/aZRrdFQQ1aUKAIKF++18
# aEssX8XD5WHCdrc+Zitb8BVTJwQxH0EbGpUdzgkTjnxhMFmxMEQP8WCIhFRDDNdN
# uDgIs0Ldk6zWczBXJoKjRQ3Q6vVHgc2/JGAyWGBG8lhHhjKEHnRhZ5FfgVSxz5NM
# ksHEpl3RYRNuKMYa+YaAu99h/EbBJx0kZxJyGiGKr0tkiVBisV39dx898Fd1rL2K
# Qk1AUdEPnAY+Z3/1ZsADlkR+79BL/W7lmsqxqPJ6Kgox8NpOBpG2iAg16HgcsOmZ
# zTznL0S6p/TcZL2kAcEgCZN4zfy8wMlEXV4WnAEFTyJNAgMBAAGjggHmMIIB4jAQ
# BgkrBgEEAYI3FQEEAwIBADAdBgNVHQ4EFgQU1WM6XIoxkPNDe3xGG8UzaFqFbVUw
# GQYJKwYBBAGCNxQCBAweCgBTAHUAYgBDAEEwCwYDVR0PBAQDAgGGMA8GA1UdEwEB
# /wQFMAMBAf8wHwYDVR0jBBgwFoAU1fZWy4/oolxiaNE9lJBb186aGMQwVgYDVR0f
# BE8wTTBLoEmgR4ZFaHR0cDovL2NybC5taWNyb3NvZnQuY29tL3BraS9jcmwvcHJv
# ZHVjdHMvTWljUm9vQ2VyQXV0XzIwMTAtMDYtMjMuY3JsMFoGCCsGAQUFBwEBBE4w
# TDBKBggrBgEFBQcwAoY+aHR0cDovL3d3dy5taWNyb3NvZnQuY29tL3BraS9jZXJ0
# cy9NaWNSb29DZXJBdXRfMjAxMC0wNi0yMy5jcnQwgaAGA1UdIAEB/wSBlTCBkjCB
# jwYJKwYBBAGCNy4DMIGBMD0GCCsGAQUFBwIBFjFodHRwOi8vd3d3Lm1pY3Jvc29m
# dC5jb20vUEtJL2RvY3MvQ1BTL2RlZmF1bHQuaHRtMEAGCCsGAQUFBwICMDQeMiAd
# AEwAZQBnAGEAbABfAFAAbwBsAGkAYwB5AF8AUwB0AGEAdABlAG0AZQBuAHQALiAd
# MA0GCSqGSIb3DQEBCwUAA4ICAQAH5ohRDeLG4Jg/gXEDPZ2joSFvs+umzPUxvs8F
# 4qn++ldtGTCzwsVmyWrf9efweL3HqJ4l4/m87WtUVwgrUYJEEvu5U4zM9GASinbM
# QEBBm9xcF/9c+V4XNZgkVkt070IQyK+/f8Z/8jd9Wj8c8pl5SpFSAK84Dxf1L3mB
# ZdmptWvkx872ynoAb0swRCQiPM/tA6WWj1kpvLb9BOFwnzJKJ/1Vry/+tuWOM7ti
# X5rbV0Dp8c6ZZpCM/2pif93FSguRJuI57BlKcWOdeyFtw5yjojz6f32WapB4pm3S
# 4Zz5Hfw42JT0xqUKloakvZ4argRCg7i1gJsiOCC1JeVk7Pf0v35jWSUPei45V3ai
# caoGig+JFrphpxHLmtgOR5qAxdDNp9DvfYPw4TtxCd9ddJgiCGHasFAeb73x4QDf
# 5zEHpJM692VHeOj4qEir995yfmFrb3epgcunCaw5u+zGy9iCtHLNHfS4hQEegPsb
# iSpUObJb2sgNVZl6h3M7COaYLeqN4DMuEin1wC9UJyH3yKxO2ii4sanblrKnQqLJ
# zxlBTeCG+SqaoxFmMNO7dDJL32N79ZmKLxvHIa9Zta7cRDyXUHHXodLFVeNp3lfB
# 0d4wwP3M5k37Db9dT+mdHhk4L7zPWAUu7w2gUDXa7wknHNWzfjUeCLraNtvTX4/e
# dIhJEqGCA60wggKVAgEBMIH+oYHUpIHRMIHOMQswCQYDVQQGEwJVUzETMBEGA1UE
# CBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9uZDEeMBwGA1UEChMVTWljcm9z
# b2Z0IENvcnBvcmF0aW9uMSkwJwYDVQQLEyBNaWNyb3NvZnQgT3BlcmF0aW9ucyBQ
# dWVydG8gUmljbzEmMCQGA1UECxMdVGhhbGVzIFRTUyBFU046MzFDNS0zMEJBLTdD
# OTExJTAjBgNVBAMTHE1pY3Jvc29mdCBUaW1lLVN0YW1wIFNlcnZpY2WiJQoBATAJ
# BgUrDgMCGgUAAxUAgPXrdH1g73Y2qb8f7iqKTz8apyOggd4wgdukgdgwgdUxCzAJ
# BgNVBAYTAlVTMRMwEQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25k
# MR4wHAYDVQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xKTAnBgNVBAsTIE1pY3Jv
# c29mdCBPcGVyYXRpb25zIFB1ZXJ0byBSaWNvMScwJQYDVQQLEx5uQ2lwaGVyIE5U
# UyBFU046NERFOS0wQzVFLTNFMDkxKzApBgNVBAMTIk1pY3Jvc29mdCBUaW1lIFNv
# dXJjZSBNYXN0ZXIgQ2xvY2swDQYJKoZIhvcNAQEFBQACBQDgQ0uDMCIYDzIwMTkw
# MzI1MjA0MzQ3WhgPMjAxOTAzMjYyMDQzNDdaMHQwOgYKKwYBBAGEWQoEATEsMCow
# CgIFAOBDS4MCAQAwBwIBAAICIBwwBwIBAAICGoMwCgIFAOBEnQMCAQAwNgYKKwYB
# BAGEWQoEAjEoMCYwDAYKKwYBBAGEWQoDAaAKMAgCAQACAxbjYKEKMAgCAQACAweh
# IDANBgkqhkiG9w0BAQUFAAOCAQEAIME9VhR5Ce/Y9Kxg0TCCL7W3yju/xvoWylsG
# puNZ4vXaNViMOdT97SsdP4BTEuuwjzDMp4DPsGU2wFO9Bsvxen192cdT/wGulccN
# 4RlGsSEl+a1Hhb2XF8pPkDPE1Kr8iEgNF1qzlqFsQ7A66duDyL5Pceu8s3LWnhoq
# 1SGn0EW0eFEpCYxS0sIDi+ENkFVXyDi6WYcAYqGAJK9/HomCrJG282BaZPAy3uKB
# 3uB8imSz0eUpBLgy5o0BzK8AKg8zdYiLAQZRhoMj+X+P9eUnrLXrAh2kkCJcBwL8
# Y/BL9PyWb5yxnAi74ADHNo5FmwJ62m+RaSEK/8WNvY5tW5bsgzGCAvUwggLxAgEB
# MIGTMHwxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQH
# EwdSZWRtb25kMR4wHAYDVQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xJjAkBgNV
# BAMTHU1pY3Jvc29mdCBUaW1lLVN0YW1wIFBDQSAyMDEwAhMzAAAAzabbOK+9LUEA
# AAAAAADNMA0GCWCGSAFlAwQCAQUAoIIBMjAaBgkqhkiG9w0BCQMxDQYLKoZIhvcN
# AQkQAQQwLwYJKoZIhvcNAQkEMSIEIAnGCO74hNMyR400kpfnt7LRE6iRXRdU/ISk
# GhlDPsTeMIHiBgsqhkiG9w0BCRACDDGB0jCBzzCBzDCBsQQUgPXrdH1g73Y2qb8f
# 7iqKTz8apyMwgZgwgYCkfjB8MQswCQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGlu
# Z3RvbjEQMA4GA1UEBxMHUmVkbW9uZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBv
# cmF0aW9uMSYwJAYDVQQDEx1NaWNyb3NvZnQgVGltZS1TdGFtcCBQQ0EgMjAxMAIT
# MwAAAM2m2zivvS1BAAAAAAAAzTAWBBSuHzymcxW2GG8UfuI/vPovn4Ig7zANBgkq
# hkiG9w0BAQsFAASCAQAgLIc8tymZIeO4bDMbtKW267ZnxrJ1P8892dYbhO57ydWL
# SCOqPvDwtmLPhY3Tf7I1GgGwyg9MjWYDJtxAThR35teeawIaDVsjQUpnlTT+7fMU
# 0abeXpWQvD/cAB+7SZJMRDWycGpuGMLgct3m90J5CRHcpyzLtJZPd15udbbF9h1H
# TTq/3rTQzGVqBFkryUgoNMkZzVqdEbvqiq9t7lzRfmy4vMqqc/0nErIJBKp1dNJa
# RP7PKvEX2OXH5BqFb0WkerdDahWgFs8F8AKHXEKM3zZ41JM3qJMygDcfT8eybRBk
# WYRFMD5LWYN2ZuyZZ1kpZ5Vm0DcZPsKkoPkw5YOU
# SIG # End signature block