KeeperBiometrics.ps1

$KeeperBiometricAvailable = $false
if ($IsWindows -or ($PSVersionTable.Platform -eq 'Win32NT') -or ($env:OS -like '*Windows*')) {
    try {
        $null = [KeeperBiometric.PasskeyManager]
        $KeeperBiometricAvailable = $true
    }
    catch {
        Write-Warning "KeeperBiometric assembly not available: $($_.Exception.Message)"
        $KeeperBiometricAvailable = $false
    }
}
else {
    $KeeperBiometricAvailable = $false
}

function Test-AssemblyAvailable {
    <#
    .SYNOPSIS
    Tests if the KeeperBiometric assembly is available
    
    .PARAMETER Quiet
    Suppress warning messages if assembly is not available
    
    .OUTPUTS
    [bool] True if assembly is available, false otherwise
    #>

    [CmdletBinding()]
    param(
        [Parameter()]
        [switch]$Quiet
    )
    
    if ($KeeperBiometricAvailable) {
        return $true
    }
    
    if (-not $Quiet -and ($IsWindows -or ($PSVersionTable.Platform -eq 'Win32NT') -or ($env:OS -like '*Windows*'))) {
        Write-Warning "KeeperBiometric assembly not available. Please build the project first."
    }
    
    return $false
}


function Test-WindowsHelloCapabilities {
    <#
    .SYNOPSIS
    Tests Windows Hello capabilities with comprehensive information
    
    .DESCRIPTION
    This function checks if Windows Hello is available and returns detailed capability information.
    
    .EXAMPLE
    Test-WindowsHelloCapabilities
    
    .EXAMPLE
    $caps = Test-WindowsHelloCapabilities -PassThru
    if ($caps.IsAvailable) {
        Write-Host "Windows Hello is ready for use"
    }
    #>

    [CmdletBinding()]
    param(
        [Parameter()]
        [switch]$PassThru,
        
        [Parameter()]
        [switch]$Quiet
    )
    
    if (-not (Test-AssemblyAvailable -Quiet:$Quiet)) {
        return $false
    }
    
    try {
        if ($PassThru) {
            return [KeeperBiometric.PasskeyManager]::GetCapabilities()
        }
        else {
            return [KeeperBiometric.PasskeyManager]::IsAvailable()
        }
    }
    catch {
        if (-not $Quiet) {
            Write-Debug "Failed to check Windows Hello capabilities: $($_.Exception.Message)"
        }
        return $false
    }
}

function Assert-KeeperBiometricCredential {
    <#
    .SYNOPSIS
    Performs Windows Hello authentication using native WebAuthn APIs
    
    .DESCRIPTION
    This function performs the complete Windows Hello authentication flow using PasskeyManager.
        
    .PARAMETER Username
    The username to authenticate (optional - will use current auth username if not provided)
    
    .PARAMETER Purpose
    The purpose of authentication: 'login' (default) or 'vault' (re-authentication)
    
    .PARAMETER AuthSyncObject
    Keeper AuthSync instance (optional - will use global auth if not provided)
    
    .PARAMETER Vault
    Keeper Vault instance (optional - will use global vault if not provided)
    
    .PARAMETER PassThru
    Return the authentication result object. If not specified, function returns nothing.
    
    .EXAMPLE
    Assert-KeeperBiometricCredential
    
    .EXAMPLE
    $result = Assert-KeeperBiometricCredential -PassThru
    if ($result.Success) {
        Write-Host "Authentication successful!"
    }
    
    .EXAMPLE
    $result = Assert-KeeperBiometricCredential -Purpose "vault" -PassThru
    #>

    [CmdletBinding()]
    param(
        [Parameter()]
        [string]$Username,
        
        [Parameter()]
        [ValidateSet('login', 'vault')]
        [string]$Purpose = 'login',
        
        [Parameter()]
        [object]$AuthSyncObject,
        
        [Parameter()]
        [object]$Vault,
        
        [Parameter()]
        [switch]$PassThru
    )
    
    if (-not (Test-AssemblyAvailable)) {
        if ($PassThru) {
            return @{
                Success = $false
                IsValid = $false
                EncryptedLoginToken = $null
                ErrorMessage = "KeeperBiometric assembly not available"
                ErrorType = "AssemblyNotFound"
            }
        }
        return
    }
    
    try {
        $auth = $null
        if ($Vault) {
            $auth = $Vault.Auth
        } elseif ($AuthSyncObject) {
            $auth = $AuthSyncObject
        } else {
            if (Get-Command getVault -ErrorAction SilentlyContinue) {
                $vault = getVault
                $auth = $vault.Auth
            } elseif ($Script:Context.Vault) {
                $vault = $Script:Context.Vault
                $auth = $vault.Auth
            } elseif (Get-Command getAuthSync -ErrorAction SilentlyContinue) {
                $auth = getAuthSync
            } elseif ($Script:Context.AuthSync) {
                $auth = $Script:Context.AuthSync
            } else {
                throw "No Vault or AuthSync instance available. Please connect to Keeper first."
            }
        }
        
        if ([string]::IsNullOrEmpty($Username)) {
            $Username = $auth.Username
        }
        
        $task = [KeeperBiometric.PasskeyManager]::AuthenticatePasskeyAsync($auth, $Username, $Purpose)
        $result = $task.GetAwaiter().GetResult()
        
        if ($result.Success) {
            Write-Host "Verification completed successfully!" -ForegroundColor Green
        } else {
            if ($result.ErrorMessage -match "cancelled|cancel" -or $result.ErrorType -eq "OperationCanceledException") {
                Write-Host "Windows Hello authentication was cancelled." -ForegroundColor Yellow
            } else {
                Write-Warning "Verification failed: $($result.ErrorMessage)"
            }
        }
        
        if ($PassThru) {
            return $result
        }
    }
    catch {
        Write-Error "Windows Hello authentication flow failed: $($_.Exception.Message)"
        if ($PassThru) {
            return @{
                Success = $false
                IsValid = $false
                EncryptedLoginToken = $null
                ErrorMessage = $_.Exception.Message
                ErrorType = $_.Exception.GetType().Name
            }
        }
    }
}

function Get-KeeperAvailableBiometricCredentials {
    <#
    .SYNOPSIS
    Get list of available biometric credentials from Keeper
    
    .DESCRIPTION
    This function retrieves a list of all registered biometric credentials (passkeys)
    associated with the current Keeper account.
    
    .PARAMETER Vault
    Keeper vault instance (optional - will use global vault if not provided)
    
    .PARAMETER IncludeDisabled
    Include disabled credentials in the results (default: false)
    
    .EXAMPLE
    $credentials = Get-KeeperAvailableBiometricCredentials
    $credentials | Format-Table
    
    .EXAMPLE
    $allCredentials = Get-KeeperAvailableBiometricCredentials -IncludeDisabled
    #>

    [CmdletBinding()]
    param(
        [Parameter(Mandatory=$false)]
        [object]$Vault,
        
        [Parameter(Mandatory=$false)]
        [switch]$IncludeDisabled
    )
    
    if (-not (Test-AssemblyAvailable)) {
        throw "KeeperBiometric assembly not available. Please build the project first."
    }
    
    try {
        if (-not $Vault) {
            if (Get-Command getVault -ErrorAction SilentlyContinue) {
                $vault = getVault
            } elseif ($Script:Context.Vault) {
                $vault = $Script:Context.Vault
            } else {
                throw "No vault instance available. Please connect to Keeper first or provide a vault parameter."
            }
        } else {
            $vault = $Vault
        }
        
        $auth = $vault.Auth
        
        $task = [KeeperBiometric.PasskeyManager]::ListPasskeysAsync($auth, $IncludeDisabled.IsPresent)
        $passkeyList = $task.GetAwaiter().GetResult()
        
        $credentials = @()
        foreach ($passkey in $passkeyList) {
            $credential = [PSCustomObject]@{
                Id = $passkey.UserId
                Name = $passkey.FriendlyName
                Created = $passkey.CreatedAt
                LastUsed = $passkey.LastUsedAt
                CredentialId = $passkey.CredentialId
                AAGUID = $passkey.AAGUID
                Disabled = $passkey.IsDisabled
            }
            $credentials += $credential
        }
        
        return $credentials
    }
    catch {
        Write-Error "Failed to get available biometric credentials: $($_.Exception.Message)"
        throw "Error getting available biometric credentials: $($_.Exception.Message)"
    }
}

$script:AAGUID_PROVIDER_MAPPING = @{
    'ea9b8d664d011d213ce4b6b48cb575d4' = 'Google Password Manager'
    'adce000235bcc60a648b0b25f1f05503' = 'Chrome on Mac'
    'fbfc3007154e4ecc8c0b6e020557d7bd' = 'iCloud Keychain'
    'dd4ec289e01d41c9bb8970fa845d4bf2' = 'iCloud Keychain (Managed)'
    '08987058cadc4b81b6e130de50dcbe96' = 'Windows Hello'
    '9ddd1817af5a4672a2b93e3dd95000a9' = 'Windows Hello'
    '6028b017b1d44c02b4b3afcdafc96bb2' = 'Windows Hello'
    '00000000000000000000000000000000' = 'Platform Authenticator'
}

function Get-ProviderNameFromAAGUID {
    <#
    .SYNOPSIS
    Get friendly provider name from AAGUID
    
    .DESCRIPTION
    Maps an AAGUID to a friendly provider name using the community-sourced mapping.
    
    .PARAMETER AAGUID
    The AAGUID to look up
    
    .EXAMPLE
    Get-ProviderNameFromAAGUID -AAGUID "9ddd1817-af5a-4672-a2b9-3e3dd95000a9"
    #>

    [CmdletBinding()]
    param(
        [Parameter(Mandatory=$true)]
        [string]$AAGUID
    )
    
    if ($script:AAGUID_PROVIDER_MAPPING.ContainsKey($AAGUID)) {
        return $script:AAGUID_PROVIDER_MAPPING[$AAGUID]
    } else {
        return "Unknown Provider ($AAGUID)"
    }
}


function Unregister-KeeperBiometricCredential {
    <#
    .SYNOPSIS
    Remove/unregister biometric credentials from Keeper
    
    .DESCRIPTION
    This function removes biometric credentials (passkeys) from the Keeper account.
    
    .PARAMETER CredentialId
    Specific credential ID to remove (deprecated - not used, function removes for current username)
    
    .PARAMETER Username
    Username to unregister biometric auth for (optional - uses current user if not provided)
    
    .PARAMETER Confirm
    Skip confirmation prompt (default: false)
    
    .PARAMETER Vault
    Keeper vault instance (optional - will use global vault if not provided)
    
    .PARAMETER PassThru
    Return the result object. If not specified, function returns nothing.
    
    .EXAMPLE
    Unregister-KeeperBiometricCredential
    
    .EXAMPLE
    Unregister-KeeperBiometricCredential -Username "user@company.com"
    
    .EXAMPLE
    $result = Unregister-KeeperBiometricCredential -PassThru
    if ($result.Success) {
        Write-Host "Unregistration successful!"
    }
    #>

    [CmdletBinding(SupportsShouldProcess)]
    [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSAvoidUsingPlainTextForPassword', 'CredentialId', Justification='Credential IDs are public identifiers, not sensitive data')]
    param(
        [Parameter(Mandatory=$false)]
        [string]$CredentialId,
        
        [Parameter(Mandatory=$false)]
        [string]$Username,
        
        [Parameter(Mandatory=$false)]
        [object]$Vault,
        
        [Parameter(Mandatory=$false)]
        [switch]$PassThru
    )
    
    if (-not (Test-AssemblyAvailable)) {
        if ($PassThru) {
            return @{
                Success = $false
                ErrorMessage = "KeeperBiometric assembly not available"
                ErrorType = "AssemblyNotFound"
            }
        }
        return
    }
    
    try {
        if (-not $Vault) {
            if (Get-Command getVault -ErrorAction SilentlyContinue) {
                $vault = getVault
            } elseif ($Script:Context.Vault) {
                $vault = $Script:Context.Vault
            } else {
                throw "No vault instance available. Please connect to Keeper first or provide a vault parameter."
            }
        } else {
            $vault = $Vault
        }
        $auth = $vault.Auth
        
        if (-not $Username) {
            $Username = $auth.Username
        }
        
        $credentialId = [KeeperBiometric.CredentialStorage]::GetCredentialId($Username)
        if (-not $credentialId) {
            $result = @{
                Success = $true
                Message = "Biometric authentication is not registered for user: $Username"
            }
            if ($PassThru) {
                return $result
            }
            Write-Host $result.Message -ForegroundColor Yellow
            return
        }
        
        if (-not $PSCmdlet.ShouldProcess($Username, "Remove biometric authentication")) {
            $result = @{
                Success = $false
                Message = "Operation cancelled by user"
            }
            if ($PassThru) {
                return $result
            }
            return
        }
        
        $task = [KeeperBiometric.PasskeyManager]::RemovePasskeyAsync($auth, $Username)
        $success = $task.GetAwaiter().GetResult()
        
        $result = if ($success) {
            Write-Host "Successfully unregistered biometric credentials for user: $Username" -ForegroundColor Green
            @{
                Success = $true
                Message = "Biometric credentials unregistered successfully"
                Username = $Username
            }
        } else {
            @{
                Success = $false
                Message = "Failed to unregister biometric credentials"
                Username = $Username
            }
        }
        
        if ($PassThru) {
            return $result
        }
    }
    catch {
        Write-Error "Failed to unregister biometric credentials: $($_.Exception.Message)"
        $errorResult = @{
            Success = $false
            ErrorMessage = $_.Exception.Message
            ErrorType = $_.Exception.GetType().Name
        }
        
        if ($PassThru) {
            return $errorResult
        }
    }
}

function Show-KeeperBiometricCredentials {
    <#
    .SYNOPSIS
    Display biometric credentials in a formatted table
    
    .DESCRIPTION
    This function retrieves and displays all registered biometric credentials (passkeys)
    It shows credential name, creation date, and last used date.
    
    .PARAMETER Vault
    Keeper vault instance (optional - will use global vault if not provided)
    
    .PARAMETER IncludeDisabled
    Include disabled credentials in the results (default: false)
    
    .EXAMPLE
    Show-KeeperBiometricCredentials
    
    .EXAMPLE
    Show-KeeperBiometricCredentials -IncludeDisabled
    #>

    [CmdletBinding()]
    param(
        [Parameter(Mandatory=$false)]
        [object]$Vault,
        
        [Parameter(Mandatory=$false)]
        [switch]$IncludeDisabled
    )
    
    try {
        $credentials = Get-KeeperAvailableBiometricCredentials -Vault $Vault -IncludeDisabled:$IncludeDisabled
        
        if (-not $credentials -or $credentials.Count -eq 0) {
            Write-Host "No biometric authentication methods found." -ForegroundColor Yellow
            return
        }
    
        foreach ($credential in $credentials) {
            $createdDate = if ($credential.Created) { 
                $credential.Created.ToString("yyyy-MM-dd HH:mm:ss") 
            } else { 
                "Never" 
            }
            
            $lastUsedDate = if ($credential.LastUsed) { 
                $credential.LastUsed.ToString("yyyy-MM-dd HH:mm:ss") 
            } else { 
                "Never" 
            }
            
            $displayName = $credential.Name
            if ([string]::IsNullOrWhiteSpace($displayName)) {
                $aaguid = $credential.AAGUID
                if ($aaguid) {
                    $displayName = Get-ProviderNameFromAAGUID -AAGUID $aaguid
                } else {
                    $displayName = "Unknown Provider"
                }
            }
            
            # Determine status
            $status = if ($credential.Disabled) { "DISABLED" } else { "ACTIVE" }
            $statusColor = if ($credential.Disabled) { "Red" } else { "Green" }
            
            $credentialIdDisplay = $credential.CredentialId
            Write-Host "Id: $credentialIdDisplay" -ForegroundColor Cyan
            Write-Host "Name: $displayName" -ForegroundColor White
            Write-Host "Status: $status" -ForegroundColor $statusColor
            Write-Host "Created: $createdDate" -ForegroundColor Cyan
            Write-Host "Last Used: $lastUsedDate" -ForegroundColor Cyan
            Write-Host ("-" * 70) -ForegroundColor Gray
        }
    }
    catch {
        Write-Error "Failed to display biometric credentials: $($_.Exception.Message)"
        throw "Error displaying biometric credentials: $($_.Exception.Message)"
    }
}

function Register-KeeperBiometricCredential {
    <#
    .SYNOPSIS
    Complete Windows Hello credential creation flow for Keeper
    
    .DESCRIPTION
    This function performs the complete Windows Hello credential creation flow using PasskeyManager.
    
    .PARAMETER Vault
    Keeper vault instance (optional)
    
    .PARAMETER Force
    Force creation of new credential even if existing credentials are found
    
    .PARAMETER FriendlyName
    Friendly name for the credential (optional)
    
    .PARAMETER PassThru
    Return the registration result object. If not specified, function returns nothing on success or false on failure.
    
    .EXAMPLE
    Register-KeeperBiometricCredential
    
    .EXAMPLE
    Register-KeeperBiometricCredential -Force
    
    .EXAMPLE
    Register-KeeperBiometricCredential -FriendlyName "My Work Laptop"
    
    .EXAMPLE
    $result = Register-KeeperBiometricCredential -PassThru
    if ($result.Success) {
        Write-Host "Registration successful"
    }
    #>

    [CmdletBinding()]
    param(
        [Parameter(Mandatory=$false)]
        [object]$Vault,
        
        [Parameter(Mandatory=$false)]
        [switch]$Force,
        
        [Parameter(Mandatory=$false)]
        [string]$FriendlyName,
        
        [Parameter(Mandatory=$false)]
        [switch]$PassThru
    )
    
    if (-not (Test-AssemblyAvailable)) {
        if ($PassThru) {
            return @{
                Success = $false
                ErrorMessage = "KeeperBiometric assembly not available"
                ErrorType = "AssemblyNotFound"
            }
        }
        return $false
    }
    
    try {
        Write-Host "Biometric Credential Creation for Keeper" -ForegroundColor Yellow
        
        if (-not $Vault) {
            if (Get-Command getVault -ErrorAction SilentlyContinue) {
                $vault = getVault
            } elseif ($Script:Context.Vault) {
                $vault = $Script:Context.Vault
            } else {
                throw "No vault instance available. Please connect to Keeper first or provide a vault parameter."
            }
        } else {
            $vault = $Vault
        }
        
        $auth = $vault.Auth
        
        $task = [KeeperBiometric.PasskeyManager]::RegisterPasskeyAsync($auth, $FriendlyName, $Force.IsPresent)
        $result = $task.GetAwaiter().GetResult()
        
        if ($result.Success) {
            Write-Host "Credential created successfully" -ForegroundColor Green
            Write-Host "Success! Biometric authentication has been registered." -ForegroundColor Green
            Write-Host "Please register your device using the `"Set-KeeperDeviceSettings -Register`" command to set biometric authentication as your default login method." -ForegroundColor Yellow
        } else {
            Write-Warning "Registration failed: $($result.ErrorMessage)"
        }
        
        if ($PassThru) {
            return @{
                Success = $result.Success
                ErrorMessage = $result.ErrorMessage
                Username = $result.Username
                CredentialId = $result.CredentialId
            }
        } 
        
        return $result.Success
    }
    catch {
        Write-Error "Keeper credential creation failed: $($_.Exception.Message)"
        $errorResult = @{
            Success = $false
            Error = $_.Exception.Message
            ErrorType = $_.Exception.GetType().Name
            Timestamp = [DateTime]::UtcNow
        }
        if ($PassThru) {
            return $errorResult
        }
        return $false
    }
}

function Get-WindowsHelloCredentialId {
    [CmdletBinding()]
    param(
        [Parameter(Mandatory = $true)]
        [string]$Username
    )
    
    try {
        return [KeeperBiometric.CredentialStorage]::GetCredentialId($Username)
    }
    catch {
        return $null
    }
}

function Test-WindowsHelloBiometricPreviouslyUsed {
    [CmdletBinding()]
    param(
        [Parameter(Mandatory = $true)]
        [string]$Username
    )
    
    try {
        $credId = [KeeperBiometric.CredentialStorage]::GetCredentialId($Username)
        return (-not [string]::IsNullOrEmpty($credId))
    }
    catch {
        return $false
    }
}

$exportFunctions = @(
    "Test-WindowsHelloCapabilities","Assert-KeeperBiometricCredential","Register-KeeperBiometricCredential","Show-KeeperBiometricCredentials","Unregister-KeeperBiometricCredential"
)

Export-ModuleMember -Function $exportFunctions

# SIG # Begin signature block
# MIInvgYJKoZIhvcNAQcCoIInrzCCJ6sCAQExDzANBglghkgBZQMEAgEFADB5Bgor
# BgEEAYI3AgEEoGswaTA0BgorBgEEAYI3AgEeMCYCAwEAAAQQH8w7YFlLCE63JNLG
# KX7zUQIBAAIBAAIBAAIBAAIBADAxMA0GCWCGSAFlAwQCAQUABCAMXZkOCSwLjG0P
# LiLA+6pSi36GHRXrDMD9tjb5sbpCeKCCITswggWNMIIEdaADAgECAhAOmxiO+dAt
# 5+/bUOIIQBhaMA0GCSqGSIb3DQEBDAUAMGUxCzAJBgNVBAYTAlVTMRUwEwYDVQQK
# EwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20xJDAiBgNV
# BAMTG0RpZ2lDZXJ0IEFzc3VyZWQgSUQgUm9vdCBDQTAeFw0yMjA4MDEwMDAwMDBa
# Fw0zMTExMDkyMzU5NTlaMGIxCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdpQ2Vy
# dCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20xITAfBgNVBAMTGERpZ2lD
# ZXJ0IFRydXN0ZWQgUm9vdCBHNDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoC
# ggIBAL/mkHNo3rvkXUo8MCIwaTPswqclLskhPfKK2FnC4SmnPVirdprNrnsbhA3E
# MB/zG6Q4FutWxpdtHauyefLKEdLkX9YFPFIPUh/GnhWlfr6fqVcWWVVyr2iTcMKy
# unWZanMylNEQRBAu34LzB4TmdDttceItDBvuINXJIB1jKS3O7F5OyJP4IWGbNOsF
# xl7sWxq868nPzaw0QF+xembud8hIqGZXV59UWI4MK7dPpzDZVu7Ke13jrclPXuU1
# 5zHL2pNe3I6PgNq2kZhAkHnDeMe2scS1ahg4AxCN2NQ3pC4FfYj1gj4QkXCrVYJB
# MtfbBHMqbpEBfCFM1LyuGwN1XXhm2ToxRJozQL8I11pJpMLmqaBn3aQnvKFPObUR
# WBf3JFxGj2T3wWmIdph2PVldQnaHiZdpekjw4KISG2aadMreSx7nDmOu5tTvkpI6
# nj3cAORFJYm2mkQZK37AlLTSYW3rM9nF30sEAMx9HJXDj/chsrIRt7t/8tWMcCxB
# YKqxYxhElRp2Yn72gLD76GSmM9GJB+G9t+ZDpBi4pncB4Q+UDCEdslQpJYls5Q5S
# UUd0viastkF13nqsX40/ybzTQRESW+UQUOsxxcpyFiIJ33xMdT9j7CFfxCBRa2+x
# q4aLT8LWRV+dIPyhHsXAj6KxfgommfXkaS+YHS312amyHeUbAgMBAAGjggE6MIIB
# NjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBTs1+OC0nFdZEzfLmc/57qYrhwP
# TzAfBgNVHSMEGDAWgBRF66Kv9JLLgjEtUYunpyGd823IDzAOBgNVHQ8BAf8EBAMC
# AYYweQYIKwYBBQUHAQEEbTBrMCQGCCsGAQUFBzABhhhodHRwOi8vb2NzcC5kaWdp
# Y2VydC5jb20wQwYIKwYBBQUHMAKGN2h0dHA6Ly9jYWNlcnRzLmRpZ2ljZXJ0LmNv
# bS9EaWdpQ2VydEFzc3VyZWRJRFJvb3RDQS5jcnQwRQYDVR0fBD4wPDA6oDigNoY0
# aHR0cDovL2NybDMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0QXNzdXJlZElEUm9vdENB
# LmNybDARBgNVHSAECjAIMAYGBFUdIAAwDQYJKoZIhvcNAQEMBQADggEBAHCgv0Nc
# Vec4X6CjdBs9thbX979XB72arKGHLOyFXqkauyL4hxppVCLtpIh3bb0aFPQTSnov
# Lbc47/T/gLn4offyct4kvFIDyE7QKt76LVbP+fT3rDB6mouyXtTP0UNEm0Mh65Zy
# oUi0mcudT6cGAxN3J0TU53/oWajwvy8LpunyNDzs9wPHh6jSTEAZNUZqaVSwuKFW
# juyk1T3osdz9HNj0d1pcVIxv76FQPfx2CWiEn2/K2yCNNWAcAgPLILCsWKAOQGPF
# mCLBsln1VWvPJ6tsds5vIy30fnFqI2si/xK4VC0nftg62fC2h5b9W9FcrBjDTZ9z
# twGpn1eqXijiuZQwggawMIIEmKADAgECAhAIrUCyYNKcTJ9ezam9k67ZMA0GCSqG
# SIb3DQEBDAUAMGIxCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMx
# GTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20xITAfBgNVBAMTGERpZ2lDZXJ0IFRy
# dXN0ZWQgUm9vdCBHNDAeFw0yMTA0MjkwMDAwMDBaFw0zNjA0MjgyMzU5NTlaMGkx
# CzAJBgNVBAYTAlVTMRcwFQYDVQQKEw5EaWdpQ2VydCwgSW5jLjFBMD8GA1UEAxM4
# RGlnaUNlcnQgVHJ1c3RlZCBHNCBDb2RlIFNpZ25pbmcgUlNBNDA5NiBTSEEzODQg
# MjAyMSBDQTEwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDVtC9C0Cit
# eLdd1TlZG7GIQvUzjOs9gZdwxbvEhSYwn6SOaNhc9es0JAfhS0/TeEP0F9ce2vnS
# 1WcaUk8OoVf8iJnBkcyBAz5NcCRks43iCH00fUyAVxJrQ5qZ8sU7H/Lvy0daE6ZM
# swEgJfMQ04uy+wjwiuCdCcBlp/qYgEk1hz1RGeiQIXhFLqGfLOEYwhrMxe6TSXBC
# Mo/7xuoc82VokaJNTIIRSFJo3hC9FFdd6BgTZcV/sk+FLEikVoQ11vkunKoAFdE3
# /hoGlMJ8yOobMubKwvSnowMOdKWvObarYBLj6Na59zHh3K3kGKDYwSNHR7OhD26j
# q22YBoMbt2pnLdK9RBqSEIGPsDsJ18ebMlrC/2pgVItJwZPt4bRc4G/rJvmM1bL5
# OBDm6s6R9b7T+2+TYTRcvJNFKIM2KmYoX7BzzosmJQayg9Rc9hUZTO1i4F4z8ujo
# 7AqnsAMrkbI2eb73rQgedaZlzLvjSFDzd5Ea/ttQokbIYViY9XwCFjyDKK05huzU
# tw1T0PhH5nUwjewwk3YUpltLXXRhTT8SkXbev1jLchApQfDVxW0mdmgRQRNYmtwm
# KwH0iU1Z23jPgUo+QEdfyYFQc4UQIyFZYIpkVMHMIRroOBl8ZhzNeDhFMJlP/2NP
# TLuqDQhTQXxYPUez+rbsjDIJAsxsPAxWEQIDAQABo4IBWTCCAVUwEgYDVR0TAQH/
# BAgwBgEB/wIBADAdBgNVHQ4EFgQUaDfg67Y7+F8Rhvv+YXsIiGX0TkIwHwYDVR0j
# BBgwFoAU7NfjgtJxXWRM3y5nP+e6mK4cD08wDgYDVR0PAQH/BAQDAgGGMBMGA1Ud
# JQQMMAoGCCsGAQUFBwMDMHcGCCsGAQUFBwEBBGswaTAkBggrBgEFBQcwAYYYaHR0
# cDovL29jc3AuZGlnaWNlcnQuY29tMEEGCCsGAQUFBzAChjVodHRwOi8vY2FjZXJ0
# cy5kaWdpY2VydC5jb20vRGlnaUNlcnRUcnVzdGVkUm9vdEc0LmNydDBDBgNVHR8E
# PDA6MDigNqA0hjJodHRwOi8vY3JsMy5kaWdpY2VydC5jb20vRGlnaUNlcnRUcnVz
# dGVkUm9vdEc0LmNybDAcBgNVHSAEFTATMAcGBWeBDAEDMAgGBmeBDAEEATANBgkq
# hkiG9w0BAQwFAAOCAgEAOiNEPY0Idu6PvDqZ01bgAhql+Eg08yy25nRm95RysQDK
# r2wwJxMSnpBEn0v9nqN8JtU3vDpdSG2V1T9J9Ce7FoFFUP2cvbaF4HZ+N3HLIvda
# qpDP9ZNq4+sg0dVQeYiaiorBtr2hSBh+3NiAGhEZGM1hmYFW9snjdufE5BtfQ/g+
# lP92OT2e1JnPSt0o618moZVYSNUa/tcnP/2Q0XaG3RywYFzzDaju4ImhvTnhOE7a
# brs2nfvlIVNaw8rpavGiPttDuDPITzgUkpn13c5UbdldAhQfQDN8A+KVssIhdXNS
# y0bYxDQcoqVLjc1vdjcshT8azibpGL6QB7BDf5WIIIJw8MzK7/0pNVwfiThV9zeK
# iwmhywvpMRr/LhlcOXHhvpynCgbWJme3kuZOX956rEnPLqR0kq3bPKSchh/jwVYb
# KyP/j7XqiHtwa+aguv06P0WmxOgWkVKLQcBIhEuWTatEQOON8BUozu3xGFYHKi8Q
# xAwIZDwzj64ojDzLj4gLDb879M4ee47vtevLt/B3E+bnKD+sEq6lLyJsQfmCXBVm
# zGwOysWGw/YmMwwHS6DTBwJqakAwSEs0qFEgu60bhQjiWQ1tygVQK+pKHJ6l/aCn
# HwZ05/LWUpD9r4VIIflXO7ScA+2GRfS0YW6/aOImYIbqyK+p/pQd52MbOoZWeE4w
# gga0MIIEnKADAgECAhANx6xXBf8hmS5AQyIMOkmGMA0GCSqGSIb3DQEBCwUAMGIx
# CzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3
# dy5kaWdpY2VydC5jb20xITAfBgNVBAMTGERpZ2lDZXJ0IFRydXN0ZWQgUm9vdCBH
# NDAeFw0yNTA1MDcwMDAwMDBaFw0zODAxMTQyMzU5NTlaMGkxCzAJBgNVBAYTAlVT
# MRcwFQYDVQQKEw5EaWdpQ2VydCwgSW5jLjFBMD8GA1UEAxM4RGlnaUNlcnQgVHJ1
# c3RlZCBHNCBUaW1lU3RhbXBpbmcgUlNBNDA5NiBTSEEyNTYgMjAyNSBDQTEwggIi
# MA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC0eDHTCphBcr48RsAcrHXbo0Zo
# dLRRF51NrY0NlLWZloMsVO1DahGPNRcybEKq+RuwOnPhof6pvF4uGjwjqNjfEvUi
# 6wuim5bap+0lgloM2zX4kftn5B1IpYzTqpyFQ/4Bt0mAxAHeHYNnQxqXmRinvuNg
# xVBdJkf77S2uPoCj7GH8BLuxBG5AvftBdsOECS1UkxBvMgEdgkFiDNYiOTx4OtiF
# cMSkqTtF2hfQz3zQSku2Ws3IfDReb6e3mmdglTcaarps0wjUjsZvkgFkriK9tUKJ
# m/s80FiocSk1VYLZlDwFt+cVFBURJg6zMUjZa/zbCclF83bRVFLeGkuAhHiGPMvS
# GmhgaTzVyhYn4p0+8y9oHRaQT/aofEnS5xLrfxnGpTXiUOeSLsJygoLPp66bkDX1
# ZlAeSpQl92QOMeRxykvq6gbylsXQskBBBnGy3tW/AMOMCZIVNSaz7BX8VtYGqLt9
# MmeOreGPRdtBx3yGOP+rx3rKWDEJlIqLXvJWnY0v5ydPpOjL6s36czwzsucuoKs7
# Yk/ehb//Wx+5kMqIMRvUBDx6z1ev+7psNOdgJMoiwOrUG2ZdSoQbU2rMkpLiQ6bG
# RinZbI4OLu9BMIFm1UUl9VnePs6BaaeEWvjJSjNm2qA+sdFUeEY0qVjPKOWug/G6
# X5uAiynM7Bu2ayBjUwIDAQABo4IBXTCCAVkwEgYDVR0TAQH/BAgwBgEB/wIBADAd
# BgNVHQ4EFgQU729TSunkBnx6yuKQVvYv1Ensy04wHwYDVR0jBBgwFoAU7NfjgtJx
# XWRM3y5nP+e6mK4cD08wDgYDVR0PAQH/BAQDAgGGMBMGA1UdJQQMMAoGCCsGAQUF
# BwMIMHcGCCsGAQUFBwEBBGswaTAkBggrBgEFBQcwAYYYaHR0cDovL29jc3AuZGln
# aWNlcnQuY29tMEEGCCsGAQUFBzAChjVodHRwOi8vY2FjZXJ0cy5kaWdpY2VydC5j
# b20vRGlnaUNlcnRUcnVzdGVkUm9vdEc0LmNydDBDBgNVHR8EPDA6MDigNqA0hjJo
# dHRwOi8vY3JsMy5kaWdpY2VydC5jb20vRGlnaUNlcnRUcnVzdGVkUm9vdEc0LmNy
# bDAgBgNVHSAEGTAXMAgGBmeBDAEEAjALBglghkgBhv1sBwEwDQYJKoZIhvcNAQEL
# BQADggIBABfO+xaAHP4HPRF2cTC9vgvItTSmf83Qh8WIGjB/T8ObXAZz8OjuhUxj
# aaFdleMM0lBryPTQM2qEJPe36zwbSI/mS83afsl3YTj+IQhQE7jU/kXjjytJgnn0
# hvrV6hqWGd3rLAUt6vJy9lMDPjTLxLgXf9r5nWMQwr8Myb9rEVKChHyfpzee5kH0
# F8HABBgr0UdqirZ7bowe9Vj2AIMD8liyrukZ2iA/wdG2th9y1IsA0QF8dTXqvcnT
# mpfeQh35k5zOCPmSNq1UH410ANVko43+Cdmu4y81hjajV/gxdEkMx1NKU4uHQcKf
# ZxAvBAKqMVuqte69M9J6A47OvgRaPs+2ykgcGV00TYr2Lr3ty9qIijanrUR3anzE
# wlvzZiiyfTPjLbnFRsjsYg39OlV8cipDoq7+qNNjqFzeGxcytL5TTLL4ZaoBdqbh
# OhZ3ZRDUphPvSRmMThi0vw9vODRzW6AxnJll38F0cuJG7uEBYTptMSbhdhGQDpOX
# gpIUsWTjd6xpR6oaQf/DJbg3s6KCLPAlZ66RzIg9sC+NJpud/v4+7RWsWCiKi9EO
# LLHfMR2ZyJ/+xhCx9yHbxtl5TPau1j/1MIDpMPx0LckTetiSuEtQvLsNz3Qbp7wG
# WqbIiOWCnb5WqxL3/BAPvIXKUjPSxyZsq8WhbaM2tszWkPZPubdcMIIG7TCCBNWg
# AwIBAgIQCoDvGEuN8QWC0cR2p5V0aDANBgkqhkiG9w0BAQsFADBpMQswCQYDVQQG
# EwJVUzEXMBUGA1UEChMORGlnaUNlcnQsIEluYy4xQTA/BgNVBAMTOERpZ2lDZXJ0
# IFRydXN0ZWQgRzQgVGltZVN0YW1waW5nIFJTQTQwOTYgU0hBMjU2IDIwMjUgQ0Ex
# MB4XDTI1MDYwNDAwMDAwMFoXDTM2MDkwMzIzNTk1OVowYzELMAkGA1UEBhMCVVMx
# FzAVBgNVBAoTDkRpZ2lDZXJ0LCBJbmMuMTswOQYDVQQDEzJEaWdpQ2VydCBTSEEy
# NTYgUlNBNDA5NiBUaW1lc3RhbXAgUmVzcG9uZGVyIDIwMjUgMTCCAiIwDQYJKoZI
# hvcNAQEBBQADggIPADCCAgoCggIBANBGrC0Sxp7Q6q5gVrMrV7pvUf+GcAoB38o3
# zBlCMGMyqJnfFNZx+wvA69HFTBdwbHwBSOeLpvPnZ8ZN+vo8dE2/pPvOx/Vj8Tch
# TySA2R4QKpVD7dvNZh6wW2R6kSu9RJt/4QhguSssp3qome7MrxVyfQO9sMx6ZAWj
# FDYOzDi8SOhPUWlLnh00Cll8pjrUcCV3K3E0zz09ldQ//nBZZREr4h/GI6Dxb2Uo
# yrN0ijtUDVHRXdmncOOMA3CoB/iUSROUINDT98oksouTMYFOnHoRh6+86Ltc5zjP
# KHW5KqCvpSduSwhwUmotuQhcg9tw2YD3w6ySSSu+3qU8DD+nigNJFmt6LAHvH3KS
# uNLoZLc1Hf2JNMVL4Q1OpbybpMe46YceNA0LfNsnqcnpJeItK/DhKbPxTTuGoX7w
# JNdoRORVbPR1VVnDuSeHVZlc4seAO+6d2sC26/PQPdP51ho1zBp+xUIZkpSFA8vW
# doUoHLWnqWU3dCCyFG1roSrgHjSHlq8xymLnjCbSLZ49kPmk8iyyizNDIXj//cOg
# rY7rlRyTlaCCfw7aSUROwnu7zER6EaJ+AliL7ojTdS5PWPsWeupWs7NpChUk555K
# 096V1hE0yZIXe+giAwW00aHzrDchIc2bQhpp0IoKRR7YufAkprxMiXAJQ1XCmnCf
# gPf8+3mnAgMBAAGjggGVMIIBkTAMBgNVHRMBAf8EAjAAMB0GA1UdDgQWBBTkO/zy
# Me39/dfzkXFjGVBDz2GM6DAfBgNVHSMEGDAWgBTvb1NK6eQGfHrK4pBW9i/USezL
# TjAOBgNVHQ8BAf8EBAMCB4AwFgYDVR0lAQH/BAwwCgYIKwYBBQUHAwgwgZUGCCsG
# AQUFBwEBBIGIMIGFMCQGCCsGAQUFBzABhhhodHRwOi8vb2NzcC5kaWdpY2VydC5j
# b20wXQYIKwYBBQUHMAKGUWh0dHA6Ly9jYWNlcnRzLmRpZ2ljZXJ0LmNvbS9EaWdp
# Q2VydFRydXN0ZWRHNFRpbWVTdGFtcGluZ1JTQTQwOTZTSEEyNTYyMDI1Q0ExLmNy
# dDBfBgNVHR8EWDBWMFSgUqBQhk5odHRwOi8vY3JsMy5kaWdpY2VydC5jb20vRGln
# aUNlcnRUcnVzdGVkRzRUaW1lU3RhbXBpbmdSU0E0MDk2U0hBMjU2MjAyNUNBMS5j
# cmwwIAYDVR0gBBkwFzAIBgZngQwBBAIwCwYJYIZIAYb9bAcBMA0GCSqGSIb3DQEB
# CwUAA4ICAQBlKq3xHCcEua5gQezRCESeY0ByIfjk9iJP2zWLpQq1b4URGnwWBdEZ
# D9gBq9fNaNmFj6Eh8/YmRDfxT7C0k8FUFqNh+tshgb4O6Lgjg8K8elC4+oWCqnU/
# ML9lFfim8/9yJmZSe2F8AQ/UdKFOtj7YMTmqPO9mzskgiC3QYIUP2S3HQvHG1FDu
# +WUqW4daIqToXFE/JQ/EABgfZXLWU0ziTN6R3ygQBHMUBaB5bdrPbF6MRYs03h4o
# bEMnxYOX8VBRKe1uNnzQVTeLni2nHkX/QqvXnNb+YkDFkxUGtMTaiLR9wjxUxu2h
# ECZpqyU1d0IbX6Wq8/gVutDojBIFeRlqAcuEVT0cKsb+zJNEsuEB7O7/cuvTQasn
# M9AWcIQfVjnzrvwiCZ85EE8LUkqRhoS3Y50OHgaY7T/lwd6UArb+BOVAkg2oOvol
# /DJgddJ35XTxfUlQ+8Hggt8l2Yv7roancJIFcbojBcxlRcGG0LIhp6GvReQGgMgY
# xQbV1S3CrWqZzBt1R9xJgKf47CdxVRd/ndUlQ05oxYy2zRWVFjF7mcr4C34Mj3oc
# CVccAvlKV9jEnstrniLvUxxVZE/rptb7IRE2lskKPIJgbaP5t2nGj/ULLi49xTcB
# ZU8atufk+EMF/cWuiC7POGT75qaL6vdCvHlshtjdNXOCIUjsarfNZzCCB0kwggUx
# oAMCAQICEAe0P3SLJmcoVNrErUyxTt0wDQYJKoZIhvcNAQELBQAwaTELMAkGA1UE
# BhMCVVMxFzAVBgNVBAoTDkRpZ2lDZXJ0LCBJbmMuMUEwPwYDVQQDEzhEaWdpQ2Vy
# dCBUcnVzdGVkIEc0IENvZGUgU2lnbmluZyBSU0E0MDk2IFNIQTM4NCAyMDIxIENB
# MTAeFw0yNTEyMzEwMDAwMDBaFw0yOTAxMDIyMzU5NTlaMIHRMRMwEQYLKwYBBAGC
# NzwCAQMTAlVTMRkwFwYLKwYBBAGCNzwCAQITCERlbGF3YXJlMR0wGwYDVQQPDBRQ
# cml2YXRlIE9yZ2FuaXphdGlvbjEQMA4GA1UEBRMHMzQwNzk4NTELMAkGA1UEBhMC
# VVMxETAPBgNVBAgTCElsbGlub2lzMRAwDgYDVQQHEwdDaGljYWdvMR0wGwYDVQQK
# ExRLZWVwZXIgU2VjdXJpdHkgSW5jLjEdMBsGA1UEAxMUS2VlcGVyIFNlY3VyaXR5
# IEluYy4wggGiMA0GCSqGSIb3DQEBAQUAA4IBjwAwggGKAoIBgQCUcNMoSVmxAi0a
# vG+StFJMNFFTUIOo3HdBZ+0gqA1XpNgUx11vB1vCZrvFsD9m5oA58tdp4gZN3LmQ
# aMvCl2ANUT7MilI02Hf1RWlygBzon6iE0GpU3lgRrwrk1dhtLpGsR6dbMKUUHprc
# vKpXk90/VN+vhzY1uik1tCTxkDCPu/AYJg7m9+tR2KqvMuYMaMLhii66eWUAGsBC
# h/uZxjkGoJF6qZ0DgFd7rW7VYljbfYSNPeZNGTDgB0J/wOsKl0mn612DTseIvAKt
# 4vra/FLFukyEyStnfQ8lWYDcLLCMCjNVrzGipmT5E2iyx7Y1RZCIpNwVogp3Ixbk
# Gbq5A/41YNOLLd4cFewyB2F037RevBCRsUODZEt1qBf7Jbu3DiYo1G+zTj9E0R1s
# FzyijcfdsTm6X5ble+yCJeGkX5XgsyPnZpyz/FX9Fr0N9pMPGWwW2PKyHEnSytXm
# 0Dxdq2P4mA4CBUxq7YoV26L2PF6QEh9BQdXTPcnLysUv7SI/a0ECAwEAAaOCAgIw
# ggH+MB8GA1UdIwQYMBaAFGg34Ou2O/hfEYb7/mF7CIhl9E5CMB0GA1UdDgQWBBRG
# 4H6CH8pvNX632bsdnrda4MtJLDA9BgNVHSAENjA0MDIGBWeBDAEDMCkwJwYIKwYB
# BQUHAgEWG2h0dHA6Ly93d3cuZGlnaWNlcnQuY29tL0NQUzAOBgNVHQ8BAf8EBAMC
# B4AwEwYDVR0lBAwwCgYIKwYBBQUHAwMwgbUGA1UdHwSBrTCBqjBToFGgT4ZNaHR0
# cDovL2NybDMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0VHJ1c3RlZEc0Q29kZVNpZ25p
# bmdSU0E0MDk2U0hBMzg0MjAyMUNBMS5jcmwwU6BRoE+GTWh0dHA6Ly9jcmw0LmRp
# Z2ljZXJ0LmNvbS9EaWdpQ2VydFRydXN0ZWRHNENvZGVTaWduaW5nUlNBNDA5NlNI
# QTM4NDIwMjFDQTEuY3JsMIGUBggrBgEFBQcBAQSBhzCBhDAkBggrBgEFBQcwAYYY
# aHR0cDovL29jc3AuZGlnaWNlcnQuY29tMFwGCCsGAQUFBzAChlBodHRwOi8vY2Fj
# ZXJ0cy5kaWdpY2VydC5jb20vRGlnaUNlcnRUcnVzdGVkRzRDb2RlU2lnbmluZ1JT
# QTQwOTZTSEEzODQyMDIxQ0ExLmNydDAJBgNVHRMEAjAAMA0GCSqGSIb3DQEBCwUA
# A4ICAQA1Wlq0WzJa3N6DgjgBU7nagIJBab1prPARXZreX1MOv9VjnS5o0CrfQLr6
# z3bmWHw7xT8dt6bcSwRixqvPJtv4q8Rvo80O3eUMvMxQzqmi7z1zf+HG+/3G4F+2
# IYegvPc8Ui151XCV9rjA8tvFWRLRMX0ZRxY1zfT027HMw0iYL20z44+Cky//FAnL
# iRwoNDGiRkZiHbB9YOftPAYNMG3gm1z3zOW5RdfKPrqvMuijE+dfyLIAA6Immpzu
# FMH+Wgn8NnSlot9b4YKycaqqdjd7wXDjPub/oQ7VShuCSBWj+UNOTVh0vcZGackc
# H1DLVgwp2dcKlxJiQKtkHT/T6LloY6LTe6+8wkVkr8EAv1W+q/+M1a4Ao+ykFbIA
# 2LBEmA9qdgoLtenAYIiEg+48SjMPgyBbVPE3bhL1vIqjEIxYCfdmi6wx33oYX7HB
# +bJ7zitHw4GgtpfPV8y8QRZImKmeDOKyXjQPDmQM/Eglm/Ns0GzBkVXM8h6UI34b
# WZrHz9sbLSE20m5Svmxftvw5zju+I3WsmS/stNfWlOkwU0niUgwPHaz21kjXEA5A
# g+aqv26wodqZcnGOlChoWDvSJ8KKgdOFbeAYKAMp1NY7iWV315zpGH19RipCR1NH
# 0ND8iIubk3WGNf2rzEfqlOi3h2ywqVkU6AKXHdO5JV4otSKKEDGCBdkwggXVAgEB
# MH0waTELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDkRpZ2lDZXJ0LCBJbmMuMUEwPwYD
# VQQDEzhEaWdpQ2VydCBUcnVzdGVkIEc0IENvZGUgU2lnbmluZyBSU0E0MDk2IFNI
# QTM4NCAyMDIxIENBMQIQB7Q/dIsmZyhU2sStTLFO3TANBglghkgBZQMEAgEFAKCB
# hDAYBgorBgEEAYI3AgEMMQowCKACgAChAoAAMBkGCSqGSIb3DQEJAzEMBgorBgEE
# AYI3AgEEMBwGCisGAQQBgjcCAQsxDjAMBgorBgEEAYI3AgEVMC8GCSqGSIb3DQEJ
# BDEiBCAAmwzirLYUn/KqU7H0W9ae3zJcKaX4hCCRIbPyxk+xBzANBgkqhkiG9w0B
# AQEFAASCAYAWtU6d0JA5DxZT59BTzgOYT9vrHeOCtzarfTsAShVoqHfXSLFSv87R
# Fb6KwuUypDqDXfOZ7I3+jJ8xewxQfFPGMucSEgSqqb2yQk01JbjSI03eLVg5xap9
# hxDk9ho1sO2IsUQSgqdGbBiB4W/4Jd7XVbZHAOm/sZa0qy9ZTzuIUxCIkyd8M+/g
# SfEFomvh3PaLRYJPXMek4E4gTA5KfLqtqVmT2w12Z2oAoFOwQCeWJ3T26TA36K1y
# 3qb+1YE2cK6IOALaXro2GBHpd9rlwRXNp7twToCEVdPkvHZtMYVNFsHYKxLYFpfH
# l+Kts1Nkkxh95oBo4VmLV7FRDYcMJm10Ek17dsj1QozY/dYG96N70o7YXxk1eTtx
# 4GdTjy7wHv/O1amZ8EJcADs9EwvC3Eb3348ZKVFhSsT4AZUHix4iubcBZufH423G
# yj8O9NDEz8yREMK6FYP1Dv2O/EtGuM4vgkmI7LdQkCyQxOzC53ZaaeC312pjS/8K
# FPkYB+cYqRChggMmMIIDIgYJKoZIhvcNAQkGMYIDEzCCAw8CAQEwfTBpMQswCQYD
# VQQGEwJVUzEXMBUGA1UEChMORGlnaUNlcnQsIEluYy4xQTA/BgNVBAMTOERpZ2lD
# ZXJ0IFRydXN0ZWQgRzQgVGltZVN0YW1waW5nIFJTQTQwOTYgU0hBMjU2IDIwMjUg
# Q0ExAhAKgO8YS43xBYLRxHanlXRoMA0GCWCGSAFlAwQCAQUAoGkwGAYJKoZIhvcN
# AQkDMQsGCSqGSIb3DQEHATAcBgkqhkiG9w0BCQUxDxcNMjYwMTIzMjMzOTI0WjAv
# BgkqhkiG9w0BCQQxIgQgg/qYJezzeej/QXfhhYWvfTZUsKXST3VpounQBtVQSLYw
# DQYJKoZIhvcNAQEBBQAEggIAq8hOo78hPkbY9MOMUFzwe6v8ikpBRNz+htEkEuPP
# 89McjAuRN8Dn/EZuv6qtnqSL4ZfbgmTadVfS9uq8PqNW2PlDNhC1DAGBhevwh6TM
# ZuGd2WsHYZ00hlH3xC4JhUGh211/6201zghfVYgLJHGk47+pHxTvgm7HwUnH1a+a
# 0aVvPO83E4qYK/nRnUqrgw2C7lLEwl6vDqV/7MeTH8XUntvFBOZLvynWsTdnNeAf
# qNF3ffnf0jEAL1003Q6lvcYYRZOvqTs4amzv56SDNOfVVsCEFkCmB0gFwH51smXW
# htattH2L0C1jOExIIeo38NJkceiTWJ7/uJvZSm8Q2vOA9/DolfbzOtLuFqWVaf6X
# 1rSZNO2V3OJ3w4kg3ZCL1B/H8GeZvRZmC94ZBbhZGdYIj+p3yzO3ZWJCChVKMAcK
# IBW+LEFwJYyDYuKacdEaaVZmTNLC7BpVFQJOgVojo/SD9nNkIbFSeTNdPdq9bofQ
# Vmd1mC79fUNo/KhN9oBmNw037y4tEcSw4MPW2tGzOfwFiYWFCk9chu60xnbjusR4
# 99WV5LUs27fapMSS41a5KdgNgrnsR9NNraTOo/17J+n2dYl6xHdsBqNhCPtio3Sd
# dV7FfrFrJBG118M6qDukcx5KBE+LhzoBv10f+UQDV1KeG101xgqFw0A5WdbUhgLF
# AO8=
# SIG # End signature block