PureStorage.AzureNative.Tools.psm1

. $PSScriptRoot/PureStorage.AzureNative.Util.ps1

# AVS resource ID for the dev environment
$AvsResourceIdDev = "/subscriptions/96798833-9949-4913-a555-b0f2de70a444/resourceGroups/rg-krypton-sddc-network-dev-eastus/providers/Microsoft.AVS/privateClouds/krypton-private-cloud-dev"
$AvsResourceIdQA = "/subscriptions/de8f0119-1ff4-4aa1-b5ee-7be650f2d750/resourceGroups/rg-krypton-avs-qa-eastus/providers/Microsoft.AVS/privateClouds/krypton-avs-qa-eastus"

# Time window for the request (set to 60 minutes for now, can be adjusted as discussed)
$TimeWindowInMinutes = 60

Function Get-SSLThumbprintFromCertString {
    param (
        [String]$CertString
    )

    $CertString = $CertString -replace '-----BEGIN CERTIFICATE-----', ''
    $CertString = $CertString -replace '-----END CERTIFICATE-----', ''
    $CertString = $CertString -replace '\s', ''

    $certificate = [Security.Cryptography.X509Certificates.X509Certificate2]::new([Convert]::FromBase64String($CertString))

    $thumbprint = $certificate.Thumbprint
    $thumbprint = $thumbprint -replace '(.{2})', '$1:'
    $thumbprint = $thumbprint.TrimEnd(':')

    return $thumbprint
}

Function Register-RemotePlugin {
    param(
        [parameter(Mandatory = $true)]
        [VMware.Vim.ExtensionManager]$ExtensionMgr,
        [parameter(Mandatory = $true)]
        [String]$RegistrationUrl,
        [parameter(Mandatory = $true)]
        [String]$PluginVersion,
        [parameter(Mandatory = $true)]
        [String]$PluginThumbprint,
        [parameter(Mandatory = $false)]
        [String]$PluginCertificate
    )

    #build extension to register. Will pull the SSL thumprint from the target address
    $description = New-Object VMware.Vim.Description
    $description.label = "Pure Storage Manager"
    $description.summary = "Pure Storage Management Plugin for the vSphere Client"

    $extensionClientInfo = New-Object VMware.Vim.ExtensionClientInfo
    $extensionClientInfo.Company = "Pure Storage, Inc."
    $extensionClientInfo.Description = $description
    $extensionClientInfo.Type = "vsphere-client-remote"
    $extensionClientInfo.Version = $PluginVersion
    $extensionClientInfo.Url = $RegistrationUrl

    $extensionServerInfo = New-Object VMware.Vim.ExtensionServerInfo
    $extensionServerInfo.AdminEmail = "noreply@purestorage.com"
    $extensionServerInfo.Company = "Pure Storage, Inc."
    $extensionServerInfo.Description = $description
    $extensionServerInfo.Url = $RegistrationUrl
    $extensionServerInfo.Type = "HTTPS"
    $extensionServerInfo.ServerThumbprint = $PluginThumbprint
    if ($PluginCertificate) {
        $extensionServerInfo.ServerCertificate = $PluginCertificate
    }

    $extensionSpec = New-Object VMware.Vim.Extension
    $extensionSpec.key = "com.purestorage.integrations.vmware.pureplugin"
    $extensionSpec.version = $PluginVersion
    $extensionSpec.Description = $description
    $extensionSpec.Client += $extensionClientInfo
    $extensionSpec.Server += $extensionServerInfo
    $extensionSpec.LastHeartbeatTime = get-date

    PrintLog "Registering new plugin" VERBOSE
    $ExtensionMgr.RegisterExtension($extensionSpec)
}

<#
    .SYNOPSIS
     This function unregisters the vSphere remote plugin extension from AVS

    .EXAMPLE
     Unregister-PureStorageAvsRemotePlugin

    .INPUTS
     No inputs are required

    .OUTPUTS
     None
#>

Function Unregister-PureStorageAvsRemotePlugin {
    [CmdletBinding()]
    [AVSAttribute(10, UpdatesSDDC = $false, AutomationOnly = $true)]
    param()

    $services = Get-View 'ServiceInstance'
    $extensionMgr = Get-View $services.Content.ExtensionManager
    $extensionMgr.UnregisterExtension("com.purestorage.integrations.vmware.pureplugin")

    PrintLog "PureStorage Remote Plugin un-registered successfully" INFO
}

<#
    .SYNOPSIS
     This function registers the vSphere remote plugin extension with AVS

    .PARAMETER RegistrationUrl
     vSphere remote plugin registration URL

    .PARAMETER PluginVersion
     The version of the plugin that is being registered

    .PARAMETER PluginCertificate
     The full SSL certificate of the vSphere remote plugin being registered, in pem format. i.e.
     -----BEGIN CERTIFICATE-----
     Base64–encoded certificate
     -----END CERTIFICATE-----

    .EXAMPLE
     Register-PureStorageAvsRemotePlugin -PluginHost 'https://10.20.30.40/plugin-manifest-location.zip' -PluginVersion '1.0.0' -PluginCertificate @"
       -----BEGIN CERTIFICATE-----
       Base64–encoded certificate
       -----END CERTIFICATE-----
       "@

    .INPUTS
     vSphere remote plugin registration URL, version, and SSL certificate

    .OUTPUTS
     None
#>

Function Register-PureStorageAvsRemotePlugin {
    [CmdletBinding()]
    [AVSAttribute(10, UpdatesSDDC = $false, AutomationOnly = $true)]
    param(
        [Parameter(
            Mandatory = $true,
            HelpMessage = 'vSphere remote plugin registration URL')]
        [ValidateNotNull()]
        [String]$RegistrationUrl,

        [Parameter(
            Mandatory = $true,
            HelpMessage = 'version of the vSphere remote plugin being registered')]
        [ValidateNotNull()]
        [String]$PluginVersion,

        [Parameter(
            Mandatory = $true,
            HelpMessage = 'full SSL certificate of the vSphere remote plugin being registered')]
        [ValidateNotNull()]
        [String]$PluginCertificate
    )
    $services = Get-View 'ServiceInstance'
    $extensionMgr = Get-View $services.Content.ExtensionManager
    $serverVersion = $services.Content.About.Version

    $CERT_SUPPORTED_VCENTER_VERSION = "8.0.2";
    $thumbprint = Get-SSLThumbprintFromCertString -CertString $PluginCertificate
    if ([System.Version]$ServerVersion -ge [System.Version]$CERT_SUPPORTED_VCENTER_VERSION) {
        PrintLog "Host Version $serverVersion, registering using Remote Plugin public certificate" INFO
        Register-RemotePlugin -ExtensionMgr $extensionMgr -RegistrationUrl $RegistrationUrl -PluginVersion $PluginVersion -PluginThumbprint $thumbprint -PluginCertificate $PluginCertificate
    }
    else {
        PrintLog "Host Version $serverVersion, registering using Remote Plugin thumbprint" INFO
        Register-RemotePlugin -ExtensionMgr $extensionMgr -RegistrationUrl $RegistrationUrl -PluginVersion $PluginVersion -PluginThumbprint $thumbprint
    }

    PrintLog "PureStorage Remote Plugin (Version: $PluginVersion) registered successfully" INFO
}

<#
    .SYNOPSIS
     This function get the version of vSphere remote plugin extension with AVS

    .EXAMPLE
     Get-PureStorageAvsRemotePluginVersion

    .INPUTS
     No inputs are required

     .OUTPUTS
     Named Plugin Version stored under Key "PureStorageAvsPluginVersion" in NamedOutput if Plugin is registered
#>

Function Get-PureStorageAvsRemotePluginVersion {
    [CmdletBinding()]
    [AVSAttribute(10, UpdatesSDDC = $false, AutomationOnly = $true)]
    param()

    $services = Get-View 'ServiceInstance'
    $extensionMgr = Get-View $services.Content.ExtensionManager
    $version = ($extensionMgr.FindExtension("com.purestorage.integrations.vmware.pureplugin")).version

    if ($null -eq $version) {
        PrintLog "No Pure Storage Avs Remote Plugin Installed" WARNING
    }
    else {
        PrintLog "Pure Storage Avs Remote Plugin Version $version is currently installed" INFO
    }

    $NamedOutputs = @{}
    $NamedOutputs["PureStorageAvsPluginVersion"] = $version
    Set-Variable -Name NamedOutputs -Value $NamedOutputs -Scope Global
}

<#
.SYNOPSIS
Creates a new service account and assigns it a role with specific privileges.

.DESCRIPTION
The New-AvsServiceAccount function creates a new service account with the specified name and password. It then creates a role named 'PureStorageService'
if it doesn't already exist, and assigns the role to the service account. The function also adds permissions for the service account on all VM hosts.

.PARAMETER InitializationHandle
The InitializationHandle is a base64 encoded JSON object that contains the following fields:
{
     "data": "<Base64 encoded InitializationHandle>",
     "signature": "<Signature>"
}

.EXAMPLE
$InitializationDataEnc = New-AvsServiceAccount -InitializationHandle "eyJkYXRh"

This example decodes the InitializationHandle and validates the signature first.
It then creates a new service account with the name defined in data.serviceAccountUsername wiht random password.
It assigns the 'PureStorageService' role to the service account and adds permissions for the service account on all VM hosts.
It returns an encrypted initialization data which is base64 encoded that contains the service account username, password and vSphere IP.

#>

function New-AvsServiceAccount {
    [CmdletBinding()]
    [AVSAttribute(10, UpdatesSDDC = $false, AutomationOnly = $true)]
    param(
        [Parameter(Mandatory = $true)]
        [string]$InitializationHandle
    )
    # TODO: this function will be deprecated once we move to OBO fully.
    # Convert the InitializationHandle to a JSON object
    $DecodedInitializationHandle = ConvertFrom-Base64 -Base64Text $InitializationHandle | ConvertFrom-Json
    $Data = $DecodedInitializationHandle.data
    $Signature = $DecodedInitializationHandle.signature

    # Convert the data to a JSON object
    $DecodedData = ConvertFrom-Base64 -Base64Text $Data | ConvertFrom-Json

    # The data is a JSON object with the following structure:
    # {
    # "sddcResourceId": "string",
    # "requestDatetime": "string",
    # "ephemeralPublicKey": "string",
    # "serviceAccountUserame": "string"
    # }
    $SddcResourceId = $DecodedData.sddcResourceId
    $RequestDatetime = $DecodedData.requestDatetime
    $EphemeralPublicKey = $DecodedData.ephemeralPublicKey
    $AccountName = $DecodedData.serviceAccountUsername

    # Validate the prefix of the account name
    if (-not $AccountName.StartsWith($AccountNamePrefix)) {
        throw "The account name must start with '$AccountNamePrefix'"
    }

    # Make sure user doesn't try to use the data with a different SDDC
    if ($env:SddcResourceId -and $env:SddcResourceId -ne $SddcResourceId) {
        throw "The SDDC resource ID in the request does not match the current SDDC resource ID"
    }

    # Determine which keys to use based on the SDDC resource ID and test signature validity
    $keysToTest = @()
    if ($SddcResourceId -eq $AvsResourceIdDev -or $SddcResourceId -eq $AvsResourceIdQA) {
        $keysToTest += "$PSScriptRoot/avs_public_key_dev.pem"
    }
    if (-not [string]::IsNullOrEmpty($SddcResourceId)) {
        $keysToTest += "$PSScriptRoot/avs_public_key_prod.pem"
    } else {
        # Default to local test environment when AVS is not set
        $keysToTest += "$PSScriptRoot/avs_public_key_test.pem"
    }

    # Test signature validity with each key in the list
    $isValidSignature = $false
    foreach ($keyPath in $keysToTest) {
        $publicKey = Get-Content $keyPath -Raw
        $isValidSignature = Test-TextSignarure -Text $Data -Signature $Signature -PublicKey $publicKey
        if ($isValidSignature) {
            break
        }
    }

    if (-not $IsValidSignature) {
        throw "The data signature is not valid"
    }


    # Make sure the request date is in UTC
    if ($RequestDatetime.Kind -ne [System.DateTimeKind]::Utc) {
        throw "Request datetime must be in UTC"
    }
    # Validate the request datetime is within the time window
    Test-RequestDatetimeInUTC -RequestDatetime $RequestDatetime -TimeWindowInMinutes $TimeWindowInMinutes

    # Generate a random password for the service account
    $AccountPassword = New-RandomPassword

    # If the user already exists, update the password
    $User = Get-SsoPersonUser -Domain 'vsphere.local' | Where-Object { $_.Name -eq $AccountName }
    if ($User) {
        Write-Warning "User $AccountName already exists, updating the password"
        Set-SsoPersonUser -User $User -NewPassword $AccountPassword -ErrorAction Stop
    } else {
        $User = New-SsoPersonUser -UserName $AccountName -Password $AccountPassword -Description "Pure Storage Service Account" -ErrorAction Stop
    }
    # Create Role and assign Role to user
    $Role = Get-VIRole -Name $RoleName -ErrorAction SilentlyContinue
    if ($Role) {
        Write-Warning "Role $RoleName already exists, checking the role privileges against the required privileges"
        CompareAndUpdate-Privileges -Role $Role -RequiredPrivileges $PluginPrivileges
    }
    else {
        $Privileges = @()
        foreach ($priv in $PluginPrivileges) {
            Write-Debug "Adding privilege: $priv"
            $Privileges += Get-VIPrivilege -Id $priv
        }

        $Role = New-VIRole -Name $RoleName -Privilege $Privileges
    }

    $Account = Get-VIAccount -Domain $User.Domain | Where-Object { $_.Id -eq $AccountName }
    if (-not $Account) {
        throw "Failed to create account for user $User"
    }

    $RootFolder = Get-Folder -NoRecursion
    if (-not $RootFolder) {
        throw "Failed to retrieve root folder"
    }

    Write-Host "Adding permissions for Account $AccountName on $($RootFolder.Name) with Role $RoleName"
    New-VIPermission -Entity $RootFolder -Principal $Account -Role $Role -Propagate $true

    $vSphereIp = $Account.Server.ServiceUri.Host

    $InitializationData= @{
        "serviceAccountUsername" = $AccountName
        "serviceAccountPassword" = $AccountPassword
        "vSphereIp" = $vSphereIp
    } | ConvertTo-Json

    try {
        $InitializationDataEnc = ConvertTo-EncryptedText -Text $InitializationData -PublicKey $EphemeralPublicKey
    }
    catch {
        throw "Failed to encrypt the initialization data with error: $_"
    }

    $NamedOutputs = @{}
    $NamedOutputs["InitializationDataEnc"] = $InitializationDataEnc
    Set-Variable -Name NamedOutputs -Value $NamedOutputs -Scope Global
}

<#
.SYNOPSIS
Removes a service account and the role assigned to it.

.DESCRIPTION
The Remove-AvsServiceAccount function removes the service account with "psserviceaccount" as the name prefix and an optional suffix in dev enviroment.
It removes the account only when it has the "PureStorageService" role assigned to it.
It also removes the role "PureStorageService" after the removal of the account.

.PARAMETER Suffix
The suffix of the account name which is only needed in dev enviroment and is empty in production.

.EXAMPLE
Remove-AvsServiceAccount -Suffix "1234"

This example tries to remove a service account named "psserviceaccount1234".
It checks if the account has the "PureStorageService" role assigned to it and removes the account and the role if it does.

#>

function Remove-AvsServiceAccount
{
    [CmdletBinding()]
    [AVSAttribute(10, UpdatesSDDC = $false, AutomationOnly = $true)]
    param(
        [Parameter(Mandatory = $false)]
        [string]$Suffix
    )
    # TODO: this function will be deprecated once we move to OBO fully.
    $AccountName = $AccountNamePrefix + $Suffix

    $User = Get-SsoPersonUser -Domain 'vsphere.local' | Where-Object { $_.Name -eq $AccountName }
    if ($User) {
        # Get the roles assigned to the user
        $name = "VSPHERE.LOCAL\" + $User.Name
        $accountPermissions = Get-VIPermission -Principal $name
        # Check if the user has the PureStorageService role
        $hasRole = $false
        foreach ($permission in $accountPermissions) {
            if ($permission.Role -eq $RoleName) {
                $hasRole = $true
                break
            }
        }
        if ($hasRole) {
            Write-Host "Removing user $AccountName"
            try {
                Remove-SsoPersonUser -User $User
                # Removes the permission (user and role association)
                Remove-VIPermission -Permission $accountPermissions -Confirm:$false
                Write-Output "Removed user $name from the role $RoleName."
            }
            catch {
                throw "Failed to remove user $AccountName with error: $_"
            }

            $Role = Get-VIRole -Name $RoleName
            if ($Role) {
                # Filter permissions by role name
                $Permissions = Get-VIPermission
                $accountWithRole = $Permissions | Where-Object { $_.Role -eq $RoleName }
                # Remove the PureStorageService role if there is no account assigned to it
                if ($accountWithRole.Count -eq 0) {
                    Write-Host "Removing role $Role "
                    try {
                        Remove-VIRole -Role $Role -Force -Confirm:$false
                    }
                    catch {
                        throw "Failed to remove role $Role with error: $_"
                    }
                } else {
                    Write-Warning "Role $RoleName still has other accounts assigned to it"
                }
            }
            else {
                Write-Warning "Failed to find role $Role"
            }

        } else {
            Write-Warning "This command is only supposed to remove the account with the role $RoleName"
        }
    }
    else {
        Write-Warning "Failed to find user $AccountName"
    }
}

<#
    .SYNOPSIS
    Establish or re-establish the Storagepool-AVS connection.

    .DESCRIPTION
    This function automates the end-to-end process of integrating an Azure Storage Pool with Azure VMware Solution (AVS).
    It performs a series of steps to securely enable the AVS connection, provision required service accounts, and finalize the integration.

    .PARAMETER StoragePoolResourceId
    The resource ID of the storage pool to call enable, finalize and get avs connection endpoint.

    .PARAMETER CorrelationId
    Optional. The Pure Storage Cloud correlation ID for the AVS connection. It's generated by Azure and used to track the request.

    .PARAMETER PureStorageBlockApiVersion
    Optional. The API version for the PureStorage.Block endpoint. (default: '2024-10-01-preview')

    .EXAMPLE
    Connect-StoragepoolToAvs -StoragePoolResourceId "1234" -CorrelationId "5678" -PureStorageBlockApiVersion "2024-10-01-preview"

    .INPUTS
    Storagepool resource Id, Pure Storage Cloud correlation ID, PureStorage.Block API version

    .OUTPUTS
    None
#>

function Connect-StoragepoolToAvs {
    [CmdletBinding()]
    [AVSAttribute(30, UpdatesSDDC = $false, AutomationOnly = $false)]
    param(
        [Parameter(Mandatory = $true)]
        [string]$StoragePoolResourceId,
        [Parameter(Mandatory = $false)]
        [string]$CorrelationId,
        [Parameter(Mandatory = $false)]
        [string]$PureStorageBlockApiVersion = '2024-10-01-preview'
    )

    # STEP 1. Enable AVS Connection
    PrintLog "STEP 1: Enabling AVS connection" INFO
    if ($err = Invoke-EnableAvsConnection -StoragePoolResourceId $StoragePoolResourceId -CorrelationId $CorrelationId -PureStorageBlockApiVersion $PureStorageBlockApiVersion) {
        throw $err
    }

    $res = Get-AvsConnection -StoragePoolResourceId $StoragePoolResourceId `
                -CorrelationId $CorrelationId `
                -PureStorageBlockApiVersion $PureStorageBlockApiVersion
    $initializationHandle = $res.serviceInitializationHandle
    if ($null -ne $initializationHandle.sddcResourceId -and $null -ne $initializationHandle.serviceAccountUsername) {
        PrintLog "AVS connection initialization is completed" INFO
    } else {
        throw "Failed to enable AVS connection"
    }

    # STEP 2. Call Create Service Account Run Command
    $errorMessageSA = $null
    $errorReportingCodeSA = "error"
    $initializationData = @{}
    PrintLog "STEP 2: Creating a new AVS service account" INFO
    try {
        $initializationHandleJson = $initializationHandle | ConvertTo-Json -Depth 10
        $initializationData = _New-AvsServiceAccount -InitializationHandle $initializationHandleJson
    }
    catch {
        $errorMessageSA = "AVS service account creation failed: $($_.Exception.Message)"
        PrintLog $errorMessageSA ERROR
    }

    if ($errorMessageSA) {
        $initializationData = @{
            "serviceAccountUsername" = ""
            "serviceAccountPassword" = ""
            "vSphereIp" = $errorReportingCodeSA
            "vSphereCertificate" = $errorMessageSA
        }
        PrintLog "STEP 3: Handling error via '/finalizeAvsConnection' endpoint" INFO
    } else {
        # STEP 3. Finalize AVS Connection
        PrintLog "STEP 3: Finalizing Avs Connection" INFO
    }

    $err = Invoke-FinalizeAvsConnection -ServiceInitializationData $initializationData `
                -StoragePoolResourceId $StoragePoolResourceId `
                -CorrelationId $CorrelationId `
                -PureStorageBlockApiVersion $PureStorageBlockApiVersion
    if ($err) {
        $msg = "Failed to finalize AVS connection with error: $err"
        throw $msg
    }

    PrintLog "AVS connection is established successfully" INFO
}

<#
    .SYNOPSIS
    Disable or remove an existing Storagepool–AVS connection in a controlled manner.

    .DESCRIPTION
    This function automates the end-to-end process of removing an Azure Storage Pool from Azure VMware Solution (AVS).
    It securely disables the AVS connection by calling the liftr API.

    .PARAMETER StoragePoolResourceId
    The resource ID of the storage pool to call disable avs connection endpoint.

    .PARAMETER CorrelationId
    Optional. The Pure Storage Cloud correlation ID for the AVS connection. It's generated by Azure and used to track the request.

    .PARAMETER PureStorageBlockApiVersion
    Optional. The API version for the PureStorage.Block endpoint. (default: '2024-10-01-preview')

    .EXAMPLE
    Disconnect-StoragepoolFromAvs -StoragePoolResourceId "1234" -CorrelationId "5678" -PureStorageBlockApiVersion "2024-10-01-preview"

    .INPUTS
    Storagepool resource Id, Pure Storage Cloud correlation ID, PureStorage.Block API version

    .OUTPUTS
    None
#>

Function Disconnect-StoragepoolFromAvs {
    [CmdletBinding()]
    [AVSAttribute(30, UpdatesSDDC = $false, AutomationOnly = $false)]
    param(
        [Parameter(Mandatory = $true)]
        [string]$StoragePoolResourceId,
        [Parameter(Mandatory = $false)]
        [string]$CorrelationId,
        [Parameter(Mandatory = $false)]
        [string]$PureStorageBlockApiVersion = '2024-10-01-preview'
    )

    # Disable AVS Connection
    PrintLog "STEP: Disabling AVS connection" INFO
    $err = Invoke-DisableAvsConnection -StoragePoolResourceId $StoragePoolResourceId -CorrelationId $CorrelationId -PureStorageBlockApiVersion $PureStorageBlockApiVersion
    if ($err) {
        $msg = "Failed to disable AVS connection with error: $err"
        throw $msg
    }

    PrintLog "Storage pool is disconnected from AVS successfully" INFO
}

# SIG # Begin signature block
# MIIuvwYJKoZIhvcNAQcCoIIusDCCLqwCAQExDzANBglghkgBZQMEAgEFADB5Bgor
# BgEEAYI3AgEEoGswaTA0BgorBgEEAYI3AgEeMCYCAwEAAAQQH8w7YFlLCE63JNLG
# KX7zUQIBAAIBAAIBAAIBAAIBADAxMA0GCWCGSAFlAwQCAQUABCBl386gICU0Ap7m
# WWwOxpq82ToA4QkhaOcc+SWTkTw5UKCCE2gwggVyMIIDWqADAgECAhB2U/6sdUZI
# k/Xl10pIOk74MA0GCSqGSIb3DQEBDAUAMFMxCzAJBgNVBAYTAkJFMRkwFwYDVQQK
# ExBHbG9iYWxTaWduIG52LXNhMSkwJwYDVQQDEyBHbG9iYWxTaWduIENvZGUgU2ln
# bmluZyBSb290IFI0NTAeFw0yMDAzMTgwMDAwMDBaFw00NTAzMTgwMDAwMDBaMFMx
# CzAJBgNVBAYTAkJFMRkwFwYDVQQKExBHbG9iYWxTaWduIG52LXNhMSkwJwYDVQQD
# EyBHbG9iYWxTaWduIENvZGUgU2lnbmluZyBSb290IFI0NTCCAiIwDQYJKoZIhvcN
# AQEBBQADggIPADCCAgoCggIBALYtxTDdeuirkD0DcrA6S5kWYbLl/6VnHTcc5X7s
# k4OqhPWjQ5uYRYq4Y1ddmwCIBCXp+GiSS4LYS8lKA/Oof2qPimEnvaFE0P31PyLC
# o0+RjbMFsiiCkV37WYgFC5cGwpj4LKczJO5QOkHM8KCwex1N0qhYOJbp3/kbkbuL
# ECzSx0Mdogl0oYCve+YzCgxZa4689Ktal3t/rlX7hPCA/oRM1+K6vcR1oW+9YRB0
# RLKYB+J0q/9o3GwmPukf5eAEh60w0wyNA3xVuBZwXCR4ICXrZ2eIq7pONJhrcBHe
# OMrUvqHAnOHfHgIB2DvhZ0OEts/8dLcvhKO/ugk3PWdssUVcGWGrQYP1rB3rdw1G
# R3POv72Vle2dK4gQ/vpY6KdX4bPPqFrpByWbEsSegHI9k9yMlN87ROYmgPzSwwPw
# jAzSRdYu54+YnuYE7kJuZ35CFnFi5wT5YMZkobacgSFOK8ZtaJSGxpl0c2cxepHy
# 1Ix5bnymu35Gb03FhRIrz5oiRAiohTfOB2FXBhcSJMDEMXOhmDVXR34QOkXZLaRR
# kJipoAc3xGUaqhxrFnf3p5fsPxkwmW8x++pAsufSxPrJ0PBQdnRZ+o1tFzK++Ol+
# A/Tnh3Wa1EqRLIUDEwIrQoDyiWo2z8hMoM6e+MuNrRan097VmxinxpI68YJj8S4O
# JGTfAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBhjAPBgNVHRMBAf8EBTADAQH/MB0G
# A1UdDgQWBBQfAL9GgAr8eDm3pbRD2VZQu86WOzANBgkqhkiG9w0BAQwFAAOCAgEA
# Xiu6dJc0RF92SChAhJPuAW7pobPWgCXme+S8CZE9D/x2rdfUMCC7j2DQkdYc8pzv
# eBorlDICwSSWUlIC0PPR/PKbOW6Z4R+OQ0F9mh5byV2ahPwm5ofzdHImraQb2T07
# alKgPAkeLx57szO0Rcf3rLGvk2Ctdq64shV464Nq6//bRqsk5e4C+pAfWcAvXda3
# XaRcELdyU/hBTsz6eBolSsr+hWJDYcO0N6qB0vTWOg+9jVl+MEfeK2vnIVAzX9Rn
# m9S4Z588J5kD/4VDjnMSyiDN6GHVsWbcF9Y5bQ/bzyM3oYKJThxrP9agzaoHnT5C
# JqrXDO76R78aUn7RdYHTyYpiF21PiKAhoCY+r23ZYjAf6Zgorm6N1Y5McmaTgI0q
# 41XHYGeQQlZcIlEPs9xOOe5N3dkdeBBUO27Ql28DtR6yI3PGErKaZND8lYUkqP/f
# obDckUCu3wkzq7ndkrfxzJF0O2nrZ5cbkL/nx6BvcbtXv7ePWu16QGoWzYCELS/h
# AtQklEOzFfwMKxv9cW/8y7x1Fzpeg9LJsy8b1ZyNf1T+fn7kVqOHp53hWVKUQY9t
# W76GlZr/GnbdQNJRSnC0HzNjI3c/7CceWeQIh+00gkoPP/6gHcH1Z3NFhnj0qinp
# J4fGGdvGExTDOUmHTaCX4GUT9Z13Vunas1jHOvLAzYIwggbmMIIEzqADAgECAhB3
# vQ4DobcI+FSrBnIQ2QRHMA0GCSqGSIb3DQEBCwUAMFMxCzAJBgNVBAYTAkJFMRkw
# FwYDVQQKExBHbG9iYWxTaWduIG52LXNhMSkwJwYDVQQDEyBHbG9iYWxTaWduIENv
# ZGUgU2lnbmluZyBSb290IFI0NTAeFw0yMDA3MjgwMDAwMDBaFw0zMDA3MjgwMDAw
# MDBaMFkxCzAJBgNVBAYTAkJFMRkwFwYDVQQKExBHbG9iYWxTaWduIG52LXNhMS8w
# LQYDVQQDEyZHbG9iYWxTaWduIEdDQyBSNDUgQ29kZVNpZ25pbmcgQ0EgMjAyMDCC
# AiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBANZCTfnjT8Yj9GwdgaYw90g9
# z9DljeUgIpYHRDVdBs8PHXBg5iZU+lMjYAKoXwIC947Jbj2peAW9jvVPGSSZfM8R
# Fpsfe2vSo3toZXer2LEsP9NyBjJcW6xQZywlTVYGNvzBYkx9fYYWlZpdVLpQ0LB/
# okQZ6dZubD4Twp8R1F80W1FoMWMK+FvQ3rpZXzGviWg4QD4I6FNnTmO2IY7v3Y2F
# QVWeHLw33JWgxHGnHxulSW4KIFl+iaNYFZcAJWnf3sJqUGVOU/troZ8YHooOX1Re
# veBbz/IMBNLeCKEQJvey83ouwo6WwT/Opdr0WSiMN2WhMZYLjqR2dxVJhGaCJedD
# CndSsZlRQv+hst2c0twY2cGGqUAdQZdihryo/6LHYxcG/WZ6NpQBIIl4H5D0e6lS
# TmpPVAYqgK+ex1BC+mUK4wH0sW6sDqjjgRmoOMieAyiGpHSnR5V+cloqexVqHMRp
# 5rC+QBmZy9J9VU4inBDgoVvDsy56i8Te8UsfjCh5MEV/bBO2PSz/LUqKKuwoDy3K
# 1JyYikptWjYsL9+6y+JBSgh3GIitNWGUEvOkcuvuNp6nUSeRPPeiGsz8h+WX4VGH
# aekizIPAtw9FbAfhQ0/UjErOz2OxtaQQevkNDCiwazT+IWgnb+z4+iaEW3VCzYkm
# eVmda6tjcWKQJQ0IIPH/AgMBAAGjggGuMIIBqjAOBgNVHQ8BAf8EBAMCAYYwEwYD
# VR0lBAwwCgYIKwYBBQUHAwMwEgYDVR0TAQH/BAgwBgEB/wIBADAdBgNVHQ4EFgQU
# 2rONwCSQo2t30wygWd0hZ2R2C3gwHwYDVR0jBBgwFoAUHwC/RoAK/Hg5t6W0Q9lW
# ULvOljswgZMGCCsGAQUFBwEBBIGGMIGDMDkGCCsGAQUFBzABhi1odHRwOi8vb2Nz
# cC5nbG9iYWxzaWduLmNvbS9jb2Rlc2lnbmluZ3Jvb3RyNDUwRgYIKwYBBQUHMAKG
# Omh0dHA6Ly9zZWN1cmUuZ2xvYmFsc2lnbi5jb20vY2FjZXJ0L2NvZGVzaWduaW5n
# cm9vdHI0NS5jcnQwQQYDVR0fBDowODA2oDSgMoYwaHR0cDovL2NybC5nbG9iYWxz
# aWduLmNvbS9jb2Rlc2lnbmluZ3Jvb3RyNDUuY3JsMFYGA1UdIARPME0wQQYJKwYB
# BAGgMgEyMDQwMgYIKwYBBQUHAgEWJmh0dHBzOi8vd3d3Lmdsb2JhbHNpZ24uY29t
# L3JlcG9zaXRvcnkvMAgGBmeBDAEEATANBgkqhkiG9w0BAQsFAAOCAgEACIhyJsav
# +qxfBsCqjJDa0LLAopf/bhMyFlT9PvQwEZ+PmPmbUt3yohbu2XiVppp8YbgEtfjr
# y/RhETP2ZSW3EUKL2Glux/+VtIFDqX6uv4LWTcwRo4NxahBeGQWn52x/VvSoXMNO
# Ca1Za7j5fqUuuPzeDsKg+7AE1BMbxyepuaotMTvPRkyd60zsvC6c8YejfzhpX0FA
# Z/ZTfepB7449+6nUEThG3zzr9s0ivRPN8OHm5TOgvjzkeNUbzCDyMHOwIhz2hNab
# XAAC4ShSS/8SS0Dq7rAaBgaehObn8NuERvtz2StCtslXNMcWwKbrIbmqDvf+28rr
# vBfLuGfr4z5P26mUhmRVyQkKwNkEcUoRS1pkw7x4eK1MRyZlB5nVzTZgoTNTs/Z7
# KtWJQDxxpav4mVn945uSS90FvQsMeAYrz1PYvRKaWyeGhT+RvuB4gHNU36cdZytq
# tq5NiYAkCFJwUPMB/0SuL5rg4UkI4eFb1zjRngqKnZQnm8qjudviNmrjb7lYYuA2
# eDYB+sGniXomU6Ncu9Ky64rLYwgv/h7zViniNZvY/+mlvW1LWSyJLC9Su7UpkNpD
# R7xy3bzZv4DB3LCrtEsdWDY3ZOub4YUXmimi/eYI0pL/oPh84emn0TCOXyZQK8ei
# 4pd3iu/YTT4m65lAYPM8Zwy2CHIpNVOBNNwwggcEMIIE7KADAgECAgxcuW61kTkv
# +4t8zgQwDQYJKoZIhvcNAQELBQAwWTELMAkGA1UEBhMCQkUxGTAXBgNVBAoTEEds
# b2JhbFNpZ24gbnYtc2ExLzAtBgNVBAMTJkdsb2JhbFNpZ24gR0NDIFI0NSBDb2Rl
# U2lnbmluZyBDQSAyMDIwMB4XDTI0MDMxMTE0MDQxMloXDTI3MDMxMjE0MDQxMlow
# cjELMAkGA1UEBhMCVVMxEzARBgNVBAgTCkNhbGlmb3JuaWExFDASBgNVBAcTC1Nh
# bnRhIENsYXJhMRswGQYDVQQKExJQdXJlIFN0b3JhZ2UsIEluYy4xGzAZBgNVBAMT
# ElB1cmUgU3RvcmFnZSwgSW5jLjCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoC
# ggIBAMCQrioSn48IvHpTg5dofsUYj/pNTDidwjYUrcxVu78NoyhSweG8FhcxDi/S
# I40+8Fccl3D5ZoqpjkFnGhzSwmpxU3J4AP7+fdTZht9eWD1I5qKY07esYwdPDV4y
# g+csPfdGPqI2XjRfT5UC3YkXQeUrX8KQZldD4KqvgxzpYcuBwsgHbTb/eArpi68Y
# gFR2jgZGyZigfy8RuJMrL1thcBOe/VWjUyK21wVT8cuunBYFaStLHhsRBRMDcZBD
# uTSGC4evE6oaCqlQbdMl9YFJ64mDQsKlCxrr7rmLVtcVzKGwmjp4b2xRwE+RmTh6
# JtrUL9Wx/3a3UzgAnDNimfwp85zoL48kyLtHqQ3FI8tVKGm+aBOgBZfmURoy7fbp
# 4zKhGgqFbpOmILO16i4f999YsEEJQgIF3CtyH1R60/ZZWlDmoeeEgjAGrnd14muU
# 5Hk3Cksr43uPUAg+fV78Y0fDV85ibm42ZwwPuz6MI4HhYNUlGzRwIQ31vjaGuAMW
# HNqFKkcO0JuIeHQ/gFKPnYIxnGC9H9R4Kw/uMezqtnYJwGU2epB/ABl/w7U4NgU2
# ZOxWB5BFy4frZ3f+hNgbjFUjMaXnVFotOJxXntzjdSl4znw8DaKiC5ooChteZMIT
# G9p078p/TUsOJQbUtFADSY1hsfCfB7t+gJSNt5peS9GOZIMVAgMBAAGjggGxMIIB
# rTAOBgNVHQ8BAf8EBAMCB4AwgZsGCCsGAQUFBwEBBIGOMIGLMEoGCCsGAQUFBzAC
# hj5odHRwOi8vc2VjdXJlLmdsb2JhbHNpZ24uY29tL2NhY2VydC9nc2djY3I0NWNv
# ZGVzaWduY2EyMDIwLmNydDA9BggrBgEFBQcwAYYxaHR0cDovL29jc3AuZ2xvYmFs
# c2lnbi5jb20vZ3NnY2NyNDVjb2Rlc2lnbmNhMjAyMDBWBgNVHSAETzBNMEEGCSsG
# AQQBoDIBMjA0MDIGCCsGAQUFBwIBFiZodHRwczovL3d3dy5nbG9iYWxzaWduLmNv
# bS9yZXBvc2l0b3J5LzAIBgZngQwBBAEwCQYDVR0TBAIwADBFBgNVHR8EPjA8MDqg
# OKA2hjRodHRwOi8vY3JsLmdsb2JhbHNpZ24uY29tL2dzZ2NjcjQ1Y29kZXNpZ25j
# YTIwMjAuY3JsMBMGA1UdJQQMMAoGCCsGAQUFBwMDMB8GA1UdIwQYMBaAFNqzjcAk
# kKNrd9MMoFndIWdkdgt4MB0GA1UdDgQWBBSzJ9KiDCa3UBiAajy+Iioj5kQjzDAN
# BgkqhkiG9w0BAQsFAAOCAgEAHsFQixeQEcoHurq9NWSUt4S39Q+UGP6crmVq3Wwy
# 9g23YbdWg+SgMxoLUqdoDfA4k4B6Dyoo0jEQzn2kxnsnT9lNHKrcZHH88dv0hjfi
# H2qAiQWazPjS3LhK2J6nhpyipJPpyRaSQG4x4aG0NB2D4WUfUz9CGAYsERJGww/w
# kTaaxMipttKDTaI1C49u1igDfRzIO+Q8vuyyBFLiYTno/df97xtjNC+KxxFhDhl/
# 4tawK6kwxaVzCMAfj48I67Wbo4DMH6pM1s19as7c3qp92i3MylGKsB6+u+o7UkbS
# dLNkS4ALI33CJOUc+GoK3Nt5IXXCFJTQFHBXkBdAur3gmlXEm8vlNG/1Sbxr0H7T
# 1e7ABGH/48o/+PeMLuCc72EeK5dJ4cX9NEQ3QnTsZHwGnYzjEOvOvP0s1c7yNsDb
# cUHoIqQvb5xS5aqMU5G+8sdPQ1nwpPf7gGaEEbAVW4w51Pam42qeN9HIPa+ZinXn
# sN02Kk1Qw0QwUqzaQy9W/gIquI0KOjw0LmoW9M/8S0lrjpEq2eEeUw9WQLhhUEIi
# rFxGPtjqiCLiiS9CZ+kf2vWLJKUspkYv+OHT3q805Zg1dJsBFAzEYUFLb1mhmigD
# EO9bsMorjECIL2ijE5zHtbGkalrrsPWu8tiDT/B7P9GSYzKfOOy4PoOIfWSK0Ixl
# S7IxghqtMIIaqQIBATBpMFkxCzAJBgNVBAYTAkJFMRkwFwYDVQQKExBHbG9iYWxT
# aWduIG52LXNhMS8wLQYDVQQDEyZHbG9iYWxTaWduIEdDQyBSNDUgQ29kZVNpZ25p
# bmcgQ0EgMjAyMAIMXLlutZE5L/uLfM4EMA0GCWCGSAFlAwQCAQUAoIGcMBkGCSqG
# SIb3DQEJAzEMBgorBgEEAYI3AgEEMBwGCisGAQQBgjcCAQsxDjAMBgorBgEEAYI3
# AgEVMC8GCSqGSIb3DQEJBDEiBCCu0Ojqdlr8RmrjG21DZ9XERNz+vHpiqphQkjnM
# 2PtoyjAwBgorBgEEAYI3AgEMMSIwIKACgAChGoAYaHR0cHM6Ly9wdXJlc3RvcmFn
# ZS5jb20gMA0GCSqGSIb3DQEBAQUABIICADfOImxd660mTMEb9gTu8bsJZnocMkuu
# FLjDt0RokVQ1vyEx69QV+bd64nb+AFXKBdMXd5uQo5FbQC02ZtmBdghcErEgtp7h
# GkmY1lzTVrwj3W8+u1kk4NkLL/p8gjhWFz4TnJQlTR1GrcJLWpKup8kHxdRqpuDu
# Z0+vYjV+8IsN5qXXbyqFL+6rgKcq3C68CVPjPRfj4rr/2DTswKlt7TcLHiWWKelG
# G27pkFigm6j6DkQ2i9st4mxqmx+K83OrWSAMFA9llvji0yjgzYf/oUuPTxrYPPxo
# 6jlHPkvi6fqHJgSjpkYagPTmVr5yEN322Ld6E9sZg8Yypamz5iu9SKGu37uqiZuP
# bncAOOR31j1idAbf7s+wqLWqqZ46TOaJedyNpYhpfleqpexLg7/wa0i+uYOT9rTW
# xNb/3GmMn3EARjoR4ryI3r2vkD6SMd87GRrKQDwW1GWlYKmC6TVf4GX/etaR4LpB
# QE7h73Jwg+9s1lIQIb19EuwTqO1Lfnwns9vEPmjgZn8ej4A9byPl1yHdYLO+NjIZ
# q2RFp0jxPbWRBxH9poQMsxcRneqCTBMFykbOCBoX9+L4bhwtm/EZcyMALMoD5naN
# KOSZvQwN4SQ5ZeMD7a8gKhWQB0+Y2mQrBlnE4YZhdzppDYK1TRzE6YywagVvOAv0
# mZ2C/fr7B04QoYIXdjCCF3IGCisGAQQBgjcDAwExghdiMIIXXgYJKoZIhvcNAQcC
# oIIXTzCCF0sCAQMxDzANBglghkgBZQMEAgEFADB3BgsqhkiG9w0BCRABBKBoBGYw
# ZAIBAQYJYIZIAYb9bAcBMDEwDQYJYIZIAWUDBAIBBQAEIJBuktfAgp2fpZtJpvZI
# pI6/0CcaDU8Eqq3PtnFo/LGeAhAfP5Ck469sooRrIz+oJABCGA8yMDI1MDYxMjE5
# MjkyN1qgghM6MIIG7TCCBNWgAwIBAgIQCoDvGEuN8QWC0cR2p5V0aDANBgkqhkiG
# 9w0BAQsFADBpMQswCQYDVQQGEwJVUzEXMBUGA1UEChMORGlnaUNlcnQsIEluYy4x
# QTA/BgNVBAMTOERpZ2lDZXJ0IFRydXN0ZWQgRzQgVGltZVN0YW1waW5nIFJTQTQw
# OTYgU0hBMjU2IDIwMjUgQ0ExMB4XDTI1MDYwNDAwMDAwMFoXDTM2MDkwMzIzNTk1
# OVowYzELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDkRpZ2lDZXJ0LCBJbmMuMTswOQYD
# VQQDEzJEaWdpQ2VydCBTSEEyNTYgUlNBNDA5NiBUaW1lc3RhbXAgUmVzcG9uZGVy
# IDIwMjUgMTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBANBGrC0Sxp7Q
# 6q5gVrMrV7pvUf+GcAoB38o3zBlCMGMyqJnfFNZx+wvA69HFTBdwbHwBSOeLpvPn
# Z8ZN+vo8dE2/pPvOx/Vj8TchTySA2R4QKpVD7dvNZh6wW2R6kSu9RJt/4QhguSss
# p3qome7MrxVyfQO9sMx6ZAWjFDYOzDi8SOhPUWlLnh00Cll8pjrUcCV3K3E0zz09
# ldQ//nBZZREr4h/GI6Dxb2UoyrN0ijtUDVHRXdmncOOMA3CoB/iUSROUINDT98ok
# souTMYFOnHoRh6+86Ltc5zjPKHW5KqCvpSduSwhwUmotuQhcg9tw2YD3w6ySSSu+
# 3qU8DD+nigNJFmt6LAHvH3KSuNLoZLc1Hf2JNMVL4Q1OpbybpMe46YceNA0LfNsn
# qcnpJeItK/DhKbPxTTuGoX7wJNdoRORVbPR1VVnDuSeHVZlc4seAO+6d2sC26/PQ
# PdP51ho1zBp+xUIZkpSFA8vWdoUoHLWnqWU3dCCyFG1roSrgHjSHlq8xymLnjCbS
# LZ49kPmk8iyyizNDIXj//cOgrY7rlRyTlaCCfw7aSUROwnu7zER6EaJ+AliL7ojT
# dS5PWPsWeupWs7NpChUk555K096V1hE0yZIXe+giAwW00aHzrDchIc2bQhpp0IoK
# RR7YufAkprxMiXAJQ1XCmnCfgPf8+3mnAgMBAAGjggGVMIIBkTAMBgNVHRMBAf8E
# AjAAMB0GA1UdDgQWBBTkO/zyMe39/dfzkXFjGVBDz2GM6DAfBgNVHSMEGDAWgBTv
# b1NK6eQGfHrK4pBW9i/USezLTjAOBgNVHQ8BAf8EBAMCB4AwFgYDVR0lAQH/BAww
# CgYIKwYBBQUHAwgwgZUGCCsGAQUFBwEBBIGIMIGFMCQGCCsGAQUFBzABhhhodHRw
# Oi8vb2NzcC5kaWdpY2VydC5jb20wXQYIKwYBBQUHMAKGUWh0dHA6Ly9jYWNlcnRz
# LmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydFRydXN0ZWRHNFRpbWVTdGFtcGluZ1JTQTQw
# OTZTSEEyNTYyMDI1Q0ExLmNydDBfBgNVHR8EWDBWMFSgUqBQhk5odHRwOi8vY3Js
# My5kaWdpY2VydC5jb20vRGlnaUNlcnRUcnVzdGVkRzRUaW1lU3RhbXBpbmdSU0E0
# MDk2U0hBMjU2MjAyNUNBMS5jcmwwIAYDVR0gBBkwFzAIBgZngQwBBAIwCwYJYIZI
# AYb9bAcBMA0GCSqGSIb3DQEBCwUAA4ICAQBlKq3xHCcEua5gQezRCESeY0ByIfjk
# 9iJP2zWLpQq1b4URGnwWBdEZD9gBq9fNaNmFj6Eh8/YmRDfxT7C0k8FUFqNh+tsh
# gb4O6Lgjg8K8elC4+oWCqnU/ML9lFfim8/9yJmZSe2F8AQ/UdKFOtj7YMTmqPO9m
# zskgiC3QYIUP2S3HQvHG1FDu+WUqW4daIqToXFE/JQ/EABgfZXLWU0ziTN6R3ygQ
# BHMUBaB5bdrPbF6MRYs03h4obEMnxYOX8VBRKe1uNnzQVTeLni2nHkX/QqvXnNb+
# YkDFkxUGtMTaiLR9wjxUxu2hECZpqyU1d0IbX6Wq8/gVutDojBIFeRlqAcuEVT0c
# Ksb+zJNEsuEB7O7/cuvTQasnM9AWcIQfVjnzrvwiCZ85EE8LUkqRhoS3Y50OHgaY
# 7T/lwd6UArb+BOVAkg2oOvol/DJgddJ35XTxfUlQ+8Hggt8l2Yv7roancJIFcboj
# BcxlRcGG0LIhp6GvReQGgMgYxQbV1S3CrWqZzBt1R9xJgKf47CdxVRd/ndUlQ05o
# xYy2zRWVFjF7mcr4C34Mj3ocCVccAvlKV9jEnstrniLvUxxVZE/rptb7IRE2lskK
# PIJgbaP5t2nGj/ULLi49xTcBZU8atufk+EMF/cWuiC7POGT75qaL6vdCvHlshtjd
# NXOCIUjsarfNZzCCBrQwggScoAMCAQICEA3HrFcF/yGZLkBDIgw6SYYwDQYJKoZI
# hvcNAQELBQAwYjELMAkGA1UEBhMCVVMxFTATBgNVBAoTDERpZ2lDZXJ0IEluYzEZ
# MBcGA1UECxMQd3d3LmRpZ2ljZXJ0LmNvbTEhMB8GA1UEAxMYRGlnaUNlcnQgVHJ1
# c3RlZCBSb290IEc0MB4XDTI1MDUwNzAwMDAwMFoXDTM4MDExNDIzNTk1OVowaTEL
# MAkGA1UEBhMCVVMxFzAVBgNVBAoTDkRpZ2lDZXJ0LCBJbmMuMUEwPwYDVQQDEzhE
# aWdpQ2VydCBUcnVzdGVkIEc0IFRpbWVTdGFtcGluZyBSU0E0MDk2IFNIQTI1NiAy
# MDI1IENBMTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBALR4MdMKmEFy
# vjxGwBysddujRmh0tFEXnU2tjQ2UtZmWgyxU7UNqEY81FzJsQqr5G7A6c+Gh/qm8
# Xi4aPCOo2N8S9SLrC6Kbltqn7SWCWgzbNfiR+2fkHUiljNOqnIVD/gG3SYDEAd4d
# g2dDGpeZGKe+42DFUF0mR/vtLa4+gKPsYfwEu7EEbkC9+0F2w4QJLVSTEG8yAR2C
# QWIM1iI5PHg62IVwxKSpO0XaF9DPfNBKS7Zazch8NF5vp7eaZ2CVNxpqumzTCNSO
# xm+SAWSuIr21Qomb+zzQWKhxKTVVgtmUPAW35xUUFREmDrMxSNlr/NsJyUXzdtFU
# Ut4aS4CEeIY8y9IaaGBpPNXKFifinT7zL2gdFpBP9qh8SdLnEut/GcalNeJQ55Iu
# wnKCgs+nrpuQNfVmUB5KlCX3ZA4x5HHKS+rqBvKWxdCyQEEGcbLe1b8Aw4wJkhU1
# JrPsFfxW1gaou30yZ46t4Y9F20HHfIY4/6vHespYMQmUiote8ladjS/nJ0+k6Mvq
# zfpzPDOy5y6gqztiT96Fv/9bH7mQyogxG9QEPHrPV6/7umw052AkyiLA6tQbZl1K
# hBtTasySkuJDpsZGKdlsjg4u70EwgWbVRSX1Wd4+zoFpp4Ra+MlKM2baoD6x0VR4
# RjSpWM8o5a6D8bpfm4CLKczsG7ZrIGNTAgMBAAGjggFdMIIBWTASBgNVHRMBAf8E
# CDAGAQH/AgEAMB0GA1UdDgQWBBTvb1NK6eQGfHrK4pBW9i/USezLTjAfBgNVHSME
# GDAWgBTs1+OC0nFdZEzfLmc/57qYrhwPTzAOBgNVHQ8BAf8EBAMCAYYwEwYDVR0l
# BAwwCgYIKwYBBQUHAwgwdwYIKwYBBQUHAQEEazBpMCQGCCsGAQUFBzABhhhodHRw
# Oi8vb2NzcC5kaWdpY2VydC5jb20wQQYIKwYBBQUHMAKGNWh0dHA6Ly9jYWNlcnRz
# LmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydFRydXN0ZWRSb290RzQuY3J0MEMGA1UdHwQ8
# MDowOKA2oDSGMmh0dHA6Ly9jcmwzLmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydFRydXN0
# ZWRSb290RzQuY3JsMCAGA1UdIAQZMBcwCAYGZ4EMAQQCMAsGCWCGSAGG/WwHATAN
# BgkqhkiG9w0BAQsFAAOCAgEAF877FoAc/gc9EXZxML2+C8i1NKZ/zdCHxYgaMH9P
# w5tcBnPw6O6FTGNpoV2V4wzSUGvI9NAzaoQk97frPBtIj+ZLzdp+yXdhOP4hCFAT
# uNT+ReOPK0mCefSG+tXqGpYZ3essBS3q8nL2UwM+NMvEuBd/2vmdYxDCvwzJv2sR
# UoKEfJ+nN57mQfQXwcAEGCvRR2qKtntujB71WPYAgwPyWLKu6RnaID/B0ba2H3LU
# iwDRAXx1Neq9ydOal95CHfmTnM4I+ZI2rVQfjXQA1WSjjf4J2a7jLzWGNqNX+DF0
# SQzHU0pTi4dBwp9nEC8EAqoxW6q17r0z0noDjs6+BFo+z7bKSBwZXTRNivYuve3L
# 2oiKNqetRHdqfMTCW/NmKLJ9M+MtucVGyOxiDf06VXxyKkOirv6o02OoXN4bFzK0
# vlNMsvhlqgF2puE6FndlENSmE+9JGYxOGLS/D284NHNboDGcmWXfwXRy4kbu4QFh
# Om0xJuF2EZAOk5eCkhSxZON3rGlHqhpB/8MluDezooIs8CVnrpHMiD2wL40mm53+
# /j7tFaxYKIqL0Q4ssd8xHZnIn/7GELH3IdvG2XlM9q7WP/UwgOkw/HQtyRN62JK4
# S1C8uw3PdBunvAZapsiI5YKdvlarEvf8EA+8hcpSM9LHJmyrxaFtoza2zNaQ9k+5
# t1wwggWNMIIEdaADAgECAhAOmxiO+dAt5+/bUOIIQBhaMA0GCSqGSIb3DQEBDAUA
# MGUxCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsT
# EHd3dy5kaWdpY2VydC5jb20xJDAiBgNVBAMTG0RpZ2lDZXJ0IEFzc3VyZWQgSUQg
# Um9vdCBDQTAeFw0yMjA4MDEwMDAwMDBaFw0zMTExMDkyMzU5NTlaMGIxCzAJBgNV
# BAYTAlVTMRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdp
# Y2VydC5jb20xITAfBgNVBAMTGERpZ2lDZXJ0IFRydXN0ZWQgUm9vdCBHNDCCAiIw
# DQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAL/mkHNo3rvkXUo8MCIwaTPswqcl
# LskhPfKK2FnC4SmnPVirdprNrnsbhA3EMB/zG6Q4FutWxpdtHauyefLKEdLkX9YF
# PFIPUh/GnhWlfr6fqVcWWVVyr2iTcMKyunWZanMylNEQRBAu34LzB4TmdDttceIt
# DBvuINXJIB1jKS3O7F5OyJP4IWGbNOsFxl7sWxq868nPzaw0QF+xembud8hIqGZX
# V59UWI4MK7dPpzDZVu7Ke13jrclPXuU15zHL2pNe3I6PgNq2kZhAkHnDeMe2scS1
# ahg4AxCN2NQ3pC4FfYj1gj4QkXCrVYJBMtfbBHMqbpEBfCFM1LyuGwN1XXhm2Tox
# RJozQL8I11pJpMLmqaBn3aQnvKFPObURWBf3JFxGj2T3wWmIdph2PVldQnaHiZdp
# ekjw4KISG2aadMreSx7nDmOu5tTvkpI6nj3cAORFJYm2mkQZK37AlLTSYW3rM9nF
# 30sEAMx9HJXDj/chsrIRt7t/8tWMcCxBYKqxYxhElRp2Yn72gLD76GSmM9GJB+G9
# t+ZDpBi4pncB4Q+UDCEdslQpJYls5Q5SUUd0viastkF13nqsX40/ybzTQRESW+UQ
# UOsxxcpyFiIJ33xMdT9j7CFfxCBRa2+xq4aLT8LWRV+dIPyhHsXAj6KxfgommfXk
# aS+YHS312amyHeUbAgMBAAGjggE6MIIBNjAPBgNVHRMBAf8EBTADAQH/MB0GA1Ud
# DgQWBBTs1+OC0nFdZEzfLmc/57qYrhwPTzAfBgNVHSMEGDAWgBRF66Kv9JLLgjEt
# UYunpyGd823IDzAOBgNVHQ8BAf8EBAMCAYYweQYIKwYBBQUHAQEEbTBrMCQGCCsG
# AQUFBzABhhhodHRwOi8vb2NzcC5kaWdpY2VydC5jb20wQwYIKwYBBQUHMAKGN2h0
# dHA6Ly9jYWNlcnRzLmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydEFzc3VyZWRJRFJvb3RD
# QS5jcnQwRQYDVR0fBD4wPDA6oDigNoY0aHR0cDovL2NybDMuZGlnaWNlcnQuY29t
# L0RpZ2lDZXJ0QXNzdXJlZElEUm9vdENBLmNybDARBgNVHSAECjAIMAYGBFUdIAAw
# DQYJKoZIhvcNAQEMBQADggEBAHCgv0NcVec4X6CjdBs9thbX979XB72arKGHLOyF
# XqkauyL4hxppVCLtpIh3bb0aFPQTSnovLbc47/T/gLn4offyct4kvFIDyE7QKt76
# LVbP+fT3rDB6mouyXtTP0UNEm0Mh65ZyoUi0mcudT6cGAxN3J0TU53/oWajwvy8L
# punyNDzs9wPHh6jSTEAZNUZqaVSwuKFWjuyk1T3osdz9HNj0d1pcVIxv76FQPfx2
# CWiEn2/K2yCNNWAcAgPLILCsWKAOQGPFmCLBsln1VWvPJ6tsds5vIy30fnFqI2si
# /xK4VC0nftg62fC2h5b9W9FcrBjDTZ9ztwGpn1eqXijiuZQxggN8MIIDeAIBATB9
# MGkxCzAJBgNVBAYTAlVTMRcwFQYDVQQKEw5EaWdpQ2VydCwgSW5jLjFBMD8GA1UE
# AxM4RGlnaUNlcnQgVHJ1c3RlZCBHNCBUaW1lU3RhbXBpbmcgUlNBNDA5NiBTSEEy
# NTYgMjAyNSBDQTECEAqA7xhLjfEFgtHEdqeVdGgwDQYJYIZIAWUDBAIBBQCggdEw
# GgYJKoZIhvcNAQkDMQ0GCyqGSIb3DQEJEAEEMBwGCSqGSIb3DQEJBTEPFw0yNTA2
# MTIxOTI5MjdaMCsGCyqGSIb3DQEJEAIMMRwwGjAYMBYEFN1iMKyGCi0wa9o4sWh5
# UjAH+0F+MC8GCSqGSIb3DQEJBDEiBCCZkGk96NF1wRxnx1jAalap1LAgV7nNXQbw
# yoFZ/u9OSTA3BgsqhkiG9w0BCRACLzEoMCYwJDAiBCBKoD+iLNdchMVck4+Cjmdr
# nK7Ksz/jbSaaozTxRhEKMzANBgkqhkiG9w0BAQEFAASCAgAYnTtHEQdo/YqTi90m
# B3VK8F6aJYrc37V8v9TUcJ5jb+aru3B2bctn6JbIM7uO5E0LmsLQSvXtVpGV+iUk
# lHUDvyKBDRULdtaTUeY4PfLxxJR6ZcuEDVMLyyyzBr2v0TcyTmy1LpoEz6ns4kHt
# IRQ3zgwBl3P3UF7fCRO3Y454dC9TKkPJiPfD0/bPAdULUWFIGDZJgI2T+/r9kI+t
# BEucv/9pvXqgGsSIlyys5v9VenaerX+CnSecFcNUsJvPLDrAx7Uo3tRFanpwO6WV
# L52G1bZiScYkVrHQ7ypGH3Hh4VUTfFUFx26k/eb/NSXH2hR2uMubuFC1J86NKj8h
# bZTB6R7CsVBj8/8MvrbtVT69wZE5lRUTc4mpUjO4VIuQsIFrNulky8GWkxDQD4rL
# NURwOS1b2914wbodTZzdqdcFqG38XA26ItHmyNMm3x12Pc6BBDrSgL332AC6ntB2
# eDV4one1uNMIIU8eW56N1QSNP74KS7S6JMpOAgIbhBkjSkwVs94358TjkP5cX9rB
# EWRSU+cBGsF4CnfBtLl7cC/+Qv8RQalPbwUQ01jkmY6C1Z87e46e1Onj2Wx/Gr8M
# tUpSBHC7B3D7hlFw9TTe76umijMcz+pOtdEZianMfDin5I/+X+41iei4A7onMtIy
# vWYQULaYWVzuXn03SIg7iEuDHQ==
# SIG # End signature block