private/Get-AppVentiXAzureAccessToken.ps1

<#
    .SYNOPSIS
        Returns a bearer token for Azure Storage or Microsoft Graph, signing in only when asked.
 
    .DESCRIPTION
        Authenticates with the well-known Azure PowerShell public client id via Entra ID device-code
        sign-in, the same way AppVentiX Central View signs in. The token is cached DPAPI-encrypted
        (CurrentUser scope) per user at '%LOCALAPPDATA%\AppVentiX\TokenCache\ps_rest_cache.dat', so a
        session normally only needs a silent cache read or refresh.
 
        Without -Interactive this function never prompts: it only tries the cache and a silent
        refresh_token exchange, returning $null when neither works. This is what keeps
        Import-Module (and every read-only call through Invoke-AppVentiXAzureBlobRequest) from
        blocking on a device-code prompt; only Connect-AppVentiXAzure and the Entra ID group lookup
        (Resolve-AppVentiXEntraIDGroup) pass -Interactive.
 
    .PARAMETER Interactive
        Allows falling back to an interactive device-code sign-in when the cache is empty or
        cannot be refreshed silently.
 
    .PARAMETER ForceLogin
        Ignores the cached token entirely and forces a fresh interactive sign-in. Implies
        -Interactive.
 
        With -TenantId, -ClientId and -ClientSecret it signs in as an app registration (client
        credentials) instead. The client id and secret are cached DPAPI-encrypted in the same file,
        so later calls get a new token silently.
 
    .PARAMETER Resource
        The resource the token is for: 'Storage' (default) or 'Graph' (Microsoft Graph). Both share
        the cached refresh token, so one sign-in covers both.
 
    .PARAMETER TenantId
        Tenant id or domain name of the app registration. Used with -ClientId and -ClientSecret.
 
    .PARAMETER ClientId
        Application (client) id of the app registration.
 
    .PARAMETER ClientSecret
        Client secret of the app registration.
 
    .PARAMETER Source
        Reuses an existing sign-in: 'AzPowerShell' (Connect-AzAccount) or 'AzureCli' (az login).
        The source is cached, later calls request a new token from it silently. Only the access
        token is cached, never the Az or CLI credentials.
 
    .OUTPUTS
        System.String. The bearer access token, or $null when no token is available and
        -Interactive was not specified.
 
    .EXAMPLE
        Get-AppVentiXAzureAccessToken
        Silent-only: returns a cached/refreshed token, or $null.
 
    .EXAMPLE
        Get-AppVentiXAzureAccessToken -Interactive
        Falls back to an interactive device-code sign-in if the cache is unusable.
 
    .EXAMPLE
        Get-AppVentiXAzureAccessToken -TenantId 'contoso.onmicrosoft.com' -ClientId $appId -ClientSecret $secret
        Signs in with a client secret and caches it for silent use.
 
    .NOTES
        Function : Get-AppVentiXAzureAccessToken
        Author : John Billekens
        Copyright: (c) John Billekens Consultancy & AppVentiX
        Version : 2026.1023.1200
#>

function Get-AppVentiXAzureAccessToken {
    [CmdletBinding(DefaultParameterSetName = 'DeviceCode')]
    [OutputType([String])]
    param (
        [Parameter(ParameterSetName = 'DeviceCode')]
        [Switch]$Interactive,

        [Parameter(ParameterSetName = 'DeviceCode')]
        [Switch]$ForceLogin,

        [Parameter()]
        [ValidateSet('Storage', 'Graph')]
        [String]$Resource = 'Storage',

        [Parameter(Mandatory, ParameterSetName = 'ClientSecret')]
        [ValidateNotNullOrEmpty()]
        [String]$TenantId,

        [Parameter(Mandatory, ParameterSetName = 'ClientSecret')]
        [ValidateNotNullOrEmpty()]
        [String]$ClientId,

        [Parameter(Mandatory, ParameterSetName = 'ClientSecret')]
        [ValidateNotNull()]
        [SecureString]$ClientSecret,

        [Parameter(Mandatory, ParameterSetName = 'External')]
        [ValidateSet('AzPowerShell', 'AzureCli')]
        [String]$Source
    )
    if ($ForceLogin) {
        $Interactive = $true
    }

    # Same well-known public client id Central View signs in with (Azure PowerShell).
    $publicClientId = '1950a258-227b-4e31-a9cf-717495945fc2'
    $authority = 'https://login.microsoftonline.com/organizations/oauth2/v2.0'
    if ($Resource -eq 'Graph') {
        $scope = 'https://graph.microsoft.com/.default offline_access'
        $appScope = 'https://graph.microsoft.com/.default'
        $tokenField = 'graph_access_token'
        $expiryField = 'graph_expires_on'
    } else {
        $scope = 'https://storage.azure.com/user_impersonation offline_access'
        $appScope = 'https://storage.azure.com/.default'
        $tokenField = 'access_token'
        $expiryField = 'expires_on'
    }
    $cacheFile = Join-Path -Path $env:LOCALAPPDATA -ChildPath 'AppVentiX\TokenCache\ps_rest_cache.dat'

    function Read-AppVentiXAzureBlobTokenCache {
        if (-not (Test-Path -Path $cacheFile)) {
            return $null
        }
        try {
            $bytes = [Security.Cryptography.ProtectedData]::Unprotect(
                [IO.File]::ReadAllBytes($cacheFile), $null, 'CurrentUser')
            return [Text.Encoding]::UTF8.GetString($bytes) | ConvertFrom-Json
        } catch {
            Write-Verbose "Could not read the cached Azure Blob token, removing the cache file: $($_.Exception.Message)"
            Remove-Item -Path $cacheFile -Force -ErrorAction SilentlyContinue
            return $null
        }
    }

    function Save-AppVentiXAzureBlobTokenCache {
        param(
            [Parameter(Mandatory)][Object]$Token,
            [Hashtable]$Identity,
            [Switch]$Reset
        )
        # Keep the access token of the other resource, the refresh token, app secret or token
        # source is shared. -Reset (new sign-in) drops everything of the previous identity.
        $Cache = @{}
        $current = if ($Reset) { $null } else { Read-AppVentiXAzureBlobTokenCache }
        if ($current) {
            foreach ($property in $current.PSObject.Properties) {
                $Cache[$property.Name] = $property.Value
            }
        }
        $Cache[$tokenField] = $Token.access_token
        $Cache[$expiryField] = [DateTimeOffset]::UtcNow.ToUnixTimeSeconds() + $Token.expires_in
        if ($Identity) {
            foreach ($key in $Identity.Keys) {
                $Cache[$key] = $Identity[$key]
            }
        } elseif ($Token.refresh_token) {
            $Cache['refresh_token'] = $Token.refresh_token
        }
        $dir = Split-Path -Path $cacheFile -Parent
        if (-not (Test-Path -Path $dir)) {
            New-Item -ItemType Directory -Path $dir -Force | Out-Null
        }
        $bytes = [Security.Cryptography.ProtectedData]::Protect(
            [Text.Encoding]::UTF8.GetBytes(($Cache | ConvertTo-Json -Compress)), $null, 'CurrentUser')
        [IO.File]::WriteAllBytes($cacheFile, $bytes)
    }

    function Invoke-AppVentiXAzureBlobDeviceCodeLogin {
        $dc = Invoke-RestMethod -Method Post -Uri "$authority/devicecode" -Body @{
            client_id = $publicClientId; scope = $scope
        }
        Write-Host ''
        Write-Host $dc.message -ForegroundColor Yellow
        Write-Host ''
        $deadline = (Get-Date).AddSeconds($dc.expires_in)
        while ((Get-Date) -lt $deadline) {
            Start-Sleep -Seconds $dc.interval
            try {
                return Invoke-RestMethod -Method Post -Uri "$authority/token" -Body @{
                    grant_type  = 'urn:ietf:params:oauth:grant-type:device_code'
                    client_id   = $publicClientId
                    device_code = $dc.device_code
                }
            } catch {
                $err = $null
                if ($_.ErrorDetails -and $_.ErrorDetails.Message) {
                    try { $err = ($_.ErrorDetails.Message | ConvertFrom-Json).error } catch { }
                }
                if ($err -ne 'authorization_pending' -and $err -ne 'slow_down') {
                    throw
                }
            }
        }
        throw 'Azure sign-in (device code) timed out.'
    }

    function Invoke-AppVentiXAzureClientSecretLogin {
        param([Parameter(Mandatory)][Hashtable]$App)
        Invoke-RestMethod -Method Post -Uri "https://login.microsoftonline.com/$($App.tenant_id)/oauth2/v2.0/token" -Body @{
            grant_type    = 'client_credentials'
            client_id     = $App.client_id
            client_secret = $App.client_secret
            scope         = $appScope
        }
    }

    function Get-AppVentiXAzureExternalToken {
        param([Parameter(Mandatory)][String]$TokenSource)
        if ($TokenSource -eq 'AzPowerShell') {
            if (-not (Get-Command -Name Get-AzAccessToken -ErrorAction SilentlyContinue)) {
                throw 'The Az.Accounts module is not installed.'
            }
            $azParams = if ($Resource -eq 'Graph') { @{ ResourceTypeName = 'MSGraph' } } else { @{ ResourceUrl = 'https://storage.azure.com/' } }
            $azToken = Get-AzAccessToken @azParams -ErrorAction Stop -WarningAction SilentlyContinue
            if (-not $azToken) {
                throw "No Azure PowerShell sign-in found, run 'Connect-AzAccount' first."
            }
            # Az.Accounts 5+ returns a SecureString token.
            $accessToken = $azToken.Token
            if ($accessToken -is [SecureString]) {
                $accessToken = [PSCredential]::new('token', $accessToken).GetNetworkCredential().Password
            }
            $expiresOn = ([DateTimeOffset]$azToken.ExpiresOn).ToUnixTimeSeconds()
        } else {
            if (-not (Get-Command -Name az -ErrorAction SilentlyContinue)) {
                throw 'The Azure CLI (az) is not installed or not in PATH.'
            }
            $azArgs = if ($Resource -eq 'Graph') { @('--resource-type', 'ms-graph') } else { @('--resource', 'https://storage.azure.com/') }
            # az writes warnings to stderr, which is terminating on 5.1 with ErrorActionPreference Stop.
            $previousPreference = $ErrorActionPreference
            $ErrorActionPreference = 'Continue'
            try {
                $output = & az account get-access-token @azArgs --output json 2>$null
            } finally {
                $ErrorActionPreference = $previousPreference
            }
            if ($LASTEXITCODE -ne 0 -or -not $output) {
                throw "No Azure CLI sign-in found, run 'az login' first."
            }
            $cliToken = ($output | Out-String) | ConvertFrom-Json
            $accessToken = $cliToken.accessToken
            # expires_on (epoch) exists since CLI 2.54, expiresOn is local time.
            $expiresOn = if ($cliToken.expires_on) { [Int64]$cliToken.expires_on } else { ([DateTimeOffset][DateTime]$cliToken.expiresOn).ToUnixTimeSeconds() }
        }
        [PSCustomObject]@{
            access_token = $accessToken
            expires_in   = $expiresOn - [DateTimeOffset]::UtcNow.ToUnixTimeSeconds()
        }
    }

    if ($PSCmdlet.ParameterSetName -eq 'External') {
        $tok = Get-AppVentiXAzureExternalToken -TokenSource $Source
        Save-AppVentiXAzureBlobTokenCache -Token $tok -Identity @{ token_source = $Source } -Reset
        Write-AppVentiXDebugLog -Message 'Signed in to Azure with an existing sign-in' -Data @{ Source = $Source }
        return $tok.access_token
    }

    if ($PSCmdlet.ParameterSetName -eq 'ClientSecret') {
        $app = @{
            tenant_id     = $TenantId
            client_id     = $ClientId
            client_secret = [PSCredential]::new($ClientId, $ClientSecret).GetNetworkCredential().Password
        }
        $tok = Invoke-AppVentiXAzureClientSecretLogin -App $app
        Save-AppVentiXAzureBlobTokenCache -Token $tok -Identity $app -Reset
        Write-AppVentiXDebugLog -Message 'Signed in to Azure with a client secret' -Data @{ TenantId = $TenantId; ClientId = $ClientId }
        return $tok.access_token
    }

    if (-not $ForceLogin) {
        $cache = Read-AppVentiXAzureBlobTokenCache
        if ($cache) {
            if ($cache.$tokenField -and [DateTimeOffset]::UtcNow.ToUnixTimeSeconds() -lt ($cache.$expiryField - 300)) {
                Write-Verbose "Using cached $Resource access token (silent)."
                return $cache.$tokenField
            }
            # No device code fallback for an explicitly chosen sign-in method.
            if ($cache.token_source) {
                try {
                    $tok = Get-AppVentiXAzureExternalToken -TokenSource $cache.token_source
                    Write-Verbose "$Resource access token requested from $($cache.token_source) (silent)."
                    Save-AppVentiXAzureBlobTokenCache -Token $tok
                    return $tok.access_token
                } catch {
                    Write-Warning "Could not get an access token from $($cache.token_source): $($_.Exception.Message)"
                    return $null
                }
            } elseif ($cache.client_secret) {
                try {
                    $tok = Invoke-AppVentiXAzureClientSecretLogin -App @{
                        tenant_id     = $cache.tenant_id
                        client_id     = $cache.client_id
                        client_secret = $cache.client_secret
                    }
                    Write-Verbose "$Resource access token requested with the cached client secret (silent)."
                    Save-AppVentiXAzureBlobTokenCache -Token $tok
                    return $tok.access_token
                } catch {
                    Write-Warning "Could not sign in with the cached client secret of app '$($cache.client_id)', run Connect-AppVentiXAzure again: $($_.Exception.Message)"
                    return $null
                }
            } elseif ($cache.refresh_token) {
                try {
                    $tok = Invoke-RestMethod -Method Post -Uri "$authority/token" -Body @{
                        grant_type    = 'refresh_token'
                        client_id     = $publicClientId
                        scope         = $scope
                        refresh_token = $cache.refresh_token
                    }
                    Write-Verbose "$Resource access token refreshed (silent)."
                    Save-AppVentiXAzureBlobTokenCache -Token $tok
                    return $tok.access_token
                } catch {
                    Write-Verbose "Silent Azure Blob token refresh failed: $($_.Exception.Message)"
                }
            }
        }
    }
    if (-not $Interactive) {
        Write-Verbose 'No usable cached Azure Blob token and -Interactive was not specified.'
        return $null
    }
    $tok = Invoke-AppVentiXAzureBlobDeviceCodeLogin
    Save-AppVentiXAzureBlobTokenCache -Token $tok -Reset
    Write-AppVentiXDebugLog -Message 'Signed in to the Azure Blob Configuration Store' -Data @{ Interactive = $true }
    return $tok.access_token
}

# SIG # Begin signature block
# MII5zAYJKoZIhvcNAQcCoII5vTCCObkCAQExDzANBglghkgBZQMEAgEFADB5Bgor
# BgEEAYI3AgEEoGswaTA0BgorBgEEAYI3AgEeMCYCAwEAAAQQH8w7YFlLCE63JNLG
# KX7zUQIBAAIBAAIBAAIBAAIBADAxMA0GCWCGSAFlAwQCAQUABCDC7yv7q0QjJCkG
# Lpf/sVxNc15UN7HdTDpz+na+2VhkPaCCIfAwggXMMIIDtKADAgECAhBUmNLR1FsZ
# lUgTecgRwIeZMA0GCSqGSIb3DQEBDAUAMHcxCzAJBgNVBAYTAlVTMR4wHAYDVQQK
# ExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xSDBGBgNVBAMTP01pY3Jvc29mdCBJZGVu
# dGl0eSBWZXJpZmljYXRpb24gUm9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkgMjAy
# MDAeFw0yMDA0MTYxODM2MTZaFw00NTA0MTYxODQ0NDBaMHcxCzAJBgNVBAYTAlVT
# MR4wHAYDVQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xSDBGBgNVBAMTP01pY3Jv
# c29mdCBJZGVudGl0eSBWZXJpZmljYXRpb24gUm9vdCBDZXJ0aWZpY2F0ZSBBdXRo
# b3JpdHkgMjAyMDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBALORKgeD
# Bmf9np3gx8C3pOZCBH8Ppttf+9Va10Wg+3cL8IDzpm1aTXlT2KCGhFdFIMeiVPvH
# or+Kx24186IVxC9O40qFlkkN/76Z2BT2vCcH7kKbK/ULkgbk/WkTZaiRcvKYhOuD
# PQ7k13ESSCHLDe32R0m3m/nJxxe2hE//uKya13NnSYXjhr03QNAlhtTetcJtYmrV
# qXi8LW9J+eVsFBT9FMfTZRY33stuvF4pjf1imxUs1gXmuYkyM6Nix9fWUmcIxC70
# ViueC4fM7Ke0pqrrBc0ZV6U6CwQnHJFnni1iLS8evtrAIMsEGcoz+4m+mOJyoHI1
# vnnhnINv5G0Xb5DzPQCGdTiO0OBJmrvb0/gwytVXiGhNctO/bX9x2P29Da6SZEi3
# W295JrXNm5UhhNHvDzI9e1eM80UHTHzgXhgONXaLbZ7LNnSrBfjgc10yVpRnlyUK
# xjU9lJfnwUSLgP3B+PR0GeUw9gb7IVc+BhyLaxWGJ0l7gpPKWeh1R+g/OPTHU3mg
# trTiXFHvvV84wRPmeAyVWi7FQFkozA8kwOy6CXcjmTimthzax7ogttc32H83rwjj
# O3HbbnMbfZlysOSGM1l0tRYAe1BtxoYT2v3EOYI9JACaYNq6lMAFUSw0rFCZE4e7
# swWAsk0wAly4JoNdtGNz764jlU9gKL431VulAgMBAAGjVDBSMA4GA1UdDwEB/wQE
# AwIBhjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBTIftJqhSobyhmYBAcnz1AQ
# T2ioojAQBgkrBgEEAYI3FQEEAwIBADANBgkqhkiG9w0BAQwFAAOCAgEAr2rd5hnn
# LZRDGU7L6VCVZKUDkQKL4jaAOxWiUsIWGbZqWl10QzD0m/9gdAmxIR6QFm3FJI9c
# Zohj9E/MffISTEAQiwGf2qnIrvKVG8+dBetJPnSgaFvlVixlHIJ+U9pW2UYXeZJF
# xBA2CFIpF8svpvJ+1Gkkih6PsHMNzBxKq7Kq7aeRYwFkIqgyuH4yKLNncy2RtNwx
# AQv3Rwqm8ddK7VZgxCwIo3tAsLx0J1KH1r6I3TeKiW5niB31yV2g/rarOoDXGpc8
# FzYiQR6sTdWD5jw4vU8w6VSp07YEwzJ2YbuwGMUrGLPAgNW3lbBeUU0i/OxYqujY
# lLSlLu2S3ucYfCFX3VVj979tzR/SpncocMfiWzpbCNJbTsgAlrPhgzavhgplXHT2
# 6ux6anSg8Evu75SjrFDyh+3XOjCDyft9V77l4/hByuVkrrOj7FjshZrM77nq81YY
# uVxzmq/FdxeDWds3GhhyVKVB0rYjdaNDmuV3fJZ5t0GNv+zcgKCf0Xd1WF81E+Al
# GmcLfc4l+gcK5GEh2NQc5QfGNpn0ltDGFf5Ozdeui53bFv0ExpK91IjmqaOqu/dk
# ODtfzAzQNb50GQOmxapMomE2gj4d8yu8l13bS3g7LfU772Aj6PXsCyM2la+YZr9T
# 03u4aUoqlmZpxJTG9F9urJh4iIAGXKKy7aIwggalMIIEjaADAgECAhMzAAkkCcvW
# zmHPK16DAAAACSQJMA0GCSqGSIb3DQEBDAUAMFoxCzAJBgNVBAYTAlVTMR4wHAYD
# VQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xKzApBgNVBAMTIk1pY3Jvc29mdCBJ
# RCBWZXJpZmllZCBDUyBFT0MgQ0EgMDQwHhcNMjYxMDI0MTkyNjUxWhcNMjYxMDI3
# MTkyNjUxWjBoMQswCQYDVQQGEwJOTDEWMBQGA1UECBMNTm9vcmQtSG9sbGFuZDEP
# MA0GA1UEBxMGSGVpbG9vMRcwFQYDVQQKEw5BcHBWZW50aVggQi5WLjEXMBUGA1UE
# AxMOQXBwVmVudGlYIEIuVi4wggGiMA0GCSqGSIb3DQEBAQUAA4IBjwAwggGKAoIB
# gQCP8Gn19+A0AhwOgSRKsbEDonalsiMv2ETHfZ1g4FNRD2MweK/2vbYMCYCzMMc0
# RuYAh3pdIE7By+nufEWVybTSzqSw7r32nFPCw0EOcmsJvl9DWkWpP/+mDwJcHlHS
# ef5yJkqKlAFM2WWqxQGwCbadke+SeqnkNuANa9cfCv0H30RWzXq/P/3rNjcBhBxA
# 5kDxMUPLCAXWPLemp5qiezGnqENUMHrnir8ESa+TQwWzIUH1wyzQFma/k9Ba3YpU
# AW6LVVUEz8I3HzdZFwHS/5v53WxM0Xq2OAxZPMoBgcOMWZWHcOoVYSzZd9Hl3cI0
# RkUVVPURy2gMU1nUyeCr+YexaK1n6TE30cb6dkMr976pKoaMjW7oQ22QiRBpcoUL
# cdLKWtGr1cgsH3H1w0tjHbrqoiIcc1JOVd1O9/TdAuMzuYKp09S3KLvNX7bm39ai
# FdK5fgZWFe0y+f+nf1weW0DHT3d/haBOUE8zn1r906SCxka2Yw/4hiL5LG6ROmpZ
# M+0CAwEAAaOCAdQwggHQMAwGA1UdEwEB/wQCMAAwDgYDVR0PAQH/BAQDAgeAMDsG
# A1UdJQQ0MDIGCisGAQQBgjdhAQAGCCsGAQUFBwMDBhorBgEEAYI3YaL8yC6uh9F6
# gZ2lyVCBwcKCJzAdBgNVHQ4EFgQUUrTdB+4eYXShumdpQgXDu7zHD9cwHwYDVR0j
# BBgwFoAUmvFUd3UMhxY3RqCs3nn59H/BeOkwZwYDVR0fBGAwXjBcoFqgWIZWaHR0
# cDovL3d3dy5taWNyb3NvZnQuY29tL3BraW9wcy9jcmwvTWljcm9zb2Z0JTIwSUQl
# MjBWZXJpZmllZCUyMENTJTIwRU9DJTIwQ0ElMjAwNC5jcmwwdAYIKwYBBQUHAQEE
# aDBmMGQGCCsGAQUFBzAChlhodHRwOi8vd3d3Lm1pY3Jvc29mdC5jb20vcGtpb3Bz
# L2NlcnRzL01pY3Jvc29mdCUyMElEJTIwVmVyaWZpZWQlMjBDUyUyMEVPQyUyMENB
# JTIwMDQuY3J0MFQGA1UdIARNMEswSQYEVR0gADBBMD8GCCsGAQUFBwIBFjNodHRw
# Oi8vd3d3Lm1pY3Jvc29mdC5jb20vcGtpb3BzL0RvY3MvUmVwb3NpdG9yeS5odG0w
# DQYJKoZIhvcNAQEMBQADggIBAHJT/J1kvgI6XtEWYXqBaES0S/4yYrYPSDJqOZa/
# RGh7VSakVY8juSxbyoeljePf1gdMPr+Ek5EMCEFdLchLX61hNq3zsxKVPaqDVEzu
# JinWuEzh9GsgWUf6a/sFI2ynV7EnBLCmTwv2ZBIG/XMrdV6ulH7/nqvfH1O+IgMD
# n0o4oBZQI1qXRz0XuBUzhd+IO+6HvHWR0cf3IddhCoIJai+Jwbw96M5Am/Viq7rH
# HS+gOkv3JTSePxzA1uOVTGSIeecQl3Ge8JfmGdC1IXEhjd2hve5c7mj/jyiWHDAy
# CJzD1YtPoD+Mr5u/2OlPa8MDktcyXrZiBDSPfNYS3xJgvYFaNrnIcT8X4/uVTDj/
# ZTJ1wljg6PtnuaQAydqM2GUe75163fs15zjOY/xPsADeWJiFLEUvI3EH11bib/kY
# 1e/oyWg+MOSA6KjKmG8phXsGs/u2eUhLmLUDrkottwpDS5JqprYGGquxHKxe5zcv
# j6uA4HkoDYaF4OubP7BXvqAC3YKr+Uv7MKDBSCpsY0T3DtXuwzsJcxjb3ox2Mgkf
# rf2NABVCONj4hzaFINkWyJSBzd8K526Dz3kcGFADu3vWxYUeXIyiQ1OHhbim5eJW
# AD5BbF+UVUlCQCmkRwBsnhDXXEJUHJOLrExz/UwYlGvOmiJUNxa/VL03PI0d29qp
# 0zp4MIIGpTCCBI2gAwIBAgITMwAJJAnL1s5hzytegwAAAAkkCTANBgkqhkiG9w0B
# AQwFADBaMQswCQYDVQQGEwJVUzEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0
# aW9uMSswKQYDVQQDEyJNaWNyb3NvZnQgSUQgVmVyaWZpZWQgQ1MgRU9DIENBIDA0
# MB4XDTI2MTAyNDE5MjY1MVoXDTI2MTAyNzE5MjY1MVowaDELMAkGA1UEBhMCTkwx
# FjAUBgNVBAgTDU5vb3JkLUhvbGxhbmQxDzANBgNVBAcTBkhlaWxvbzEXMBUGA1UE
# ChMOQXBwVmVudGlYIEIuVi4xFzAVBgNVBAMTDkFwcFZlbnRpWCBCLlYuMIIBojAN
# BgkqhkiG9w0BAQEFAAOCAY8AMIIBigKCAYEAj/Bp9ffgNAIcDoEkSrGxA6J2pbIj
# L9hEx32dYOBTUQ9jMHiv9r22DAmAszDHNEbmAId6XSBOwcvp7nxFlcm00s6ksO69
# 9pxTwsNBDnJrCb5fQ1pFqT//pg8CXB5R0nn+ciZKipQBTNllqsUBsAm2nZHvknqp
# 5DbgDWvXHwr9B99EVs16vz/96zY3AYQcQOZA8TFDywgF1jy3pqeaonsxp6hDVDB6
# 54q/BEmvk0MFsyFB9cMs0BZmv5PQWt2KVAFui1VVBM/CNx83WRcB0v+b+d1sTNF6
# tjgMWTzKAYHDjFmVh3DqFWEs2XfR5d3CNEZFFVT1EctoDFNZ1Mngq/mHsWitZ+kx
# N9HG+nZDK/e+qSqGjI1u6ENtkIkQaXKFC3HSylrRq9XILB9x9cNLYx266qIiHHNS
# TlXdTvf03QLjM7mCqdPUtyi7zV+25t/WohXSuX4GVhXtMvn/p39cHltAx093f4Wg
# TlBPM59a/dOkgsZGtmMP+IYi+SxukTpqWTPtAgMBAAGjggHUMIIB0DAMBgNVHRMB
# Af8EAjAAMA4GA1UdDwEB/wQEAwIHgDA7BgNVHSUENDAyBgorBgEEAYI3YQEABggr
# BgEFBQcDAwYaKwYBBAGCN2Gi/MgurofReoGdpclQgcHCgicwHQYDVR0OBBYEFFK0
# 3QfuHmF0obpnaUIFw7u8xw/XMB8GA1UdIwQYMBaAFJrxVHd1DIcWN0agrN55+fR/
# wXjpMGcGA1UdHwRgMF4wXKBaoFiGVmh0dHA6Ly93d3cubWljcm9zb2Z0LmNvbS9w
# a2lvcHMvY3JsL01pY3Jvc29mdCUyMElEJTIwVmVyaWZpZWQlMjBDUyUyMEVPQyUy
# MENBJTIwMDQuY3JsMHQGCCsGAQUFBwEBBGgwZjBkBggrBgEFBQcwAoZYaHR0cDov
# L3d3dy5taWNyb3NvZnQuY29tL3BraW9wcy9jZXJ0cy9NaWNyb3NvZnQlMjBJRCUy
# MFZlcmlmaWVkJTIwQ1MlMjBFT0MlMjBDQSUyMDA0LmNydDBUBgNVHSAETTBLMEkG
# BFUdIAAwQTA/BggrBgEFBQcCARYzaHR0cDovL3d3dy5taWNyb3NvZnQuY29tL3Br
# aW9wcy9Eb2NzL1JlcG9zaXRvcnkuaHRtMA0GCSqGSIb3DQEBDAUAA4ICAQByU/yd
# ZL4COl7RFmF6gWhEtEv+MmK2D0gyajmWv0Roe1UmpFWPI7ksW8qHpY3j39YHTD6/
# hJORDAhBXS3IS1+tYTat87MSlT2qg1RM7iYp1rhM4fRrIFlH+mv7BSNsp1exJwSw
# pk8L9mQSBv1zK3VerpR+/56r3x9TviIDA59KOKAWUCNal0c9F7gVM4XfiDvuh7x1
# kdHH9yHXYQqCCWovicG8PejOQJv1Yqu6xx0voDpL9yU0nj8cwNbjlUxkiHnnEJdx
# nvCX5hnQtSFxIY3dob3uXO5o/48olhwwMgicw9WLT6A/jK+bv9jpT2vDA5LXMl62
# YgQ0j3zWEt8SYL2BWja5yHE/F+P7lUw4/2UydcJY4Oj7Z7mkAMnajNhlHu+det37
# Nec4zmP8T7AA3liYhSxFLyNxB9dW4m/5GNXv6MloPjDkgOioyphvKYV7BrP7tnlI
# S5i1A65KLbcKQ0uSaqa2BhqrsRysXuc3L4+rgOB5KA2GheDrmz+wV76gAt2Cq/lL
# +zCgwUgqbGNE9w7V7sM7CXMY296MdjIJH639jQAVQjjY+Ic2hSDZFsiUgc3fCudu
# g895HBhQA7t71sWFHlyMokNTh4W4puXiVgA+QWxflFVJQkAppEcAbJ4Q11xCVByT
# i6xMc/1MGJRrzpoiVDcWv1S9NzyNHdvaqdM6eDCCBygwggUQoAMCAQICEzMAAAAX
# J0UJC4uHr8YAAAAAABcwDQYJKoZIhvcNAQEMBQAwYzELMAkGA1UEBhMCVVMxHjAc
# BgNVBAoTFU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjE0MDIGA1UEAxMrTWljcm9zb2Z0
# IElEIFZlcmlmaWVkIENvZGUgU2lnbmluZyBQQ0EgMjAyMTAeFw0yNjAzMjYxODEx
# MzFaFw0zMTAzMjYxODExMzFaMFoxCzAJBgNVBAYTAlVTMR4wHAYDVQQKExVNaWNy
# b3NvZnQgQ29ycG9yYXRpb24xKzApBgNVBAMTIk1pY3Jvc29mdCBJRCBWZXJpZmll
# ZCBDUyBFT0MgQ0EgMDQwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCC
# x2T+Aw9mKgGVzJ+Tq0PMn49G3itIsYpbx7ClLSRHFe1RELdPcZ1sIqWOhsSfy6yy
# qEapClGH9Je9FXA1cQgZvvpQbkg+QInVLr/0EPrVBCwrM96lbRI2PxNeCwXG9Lsy
# W2hG6KQgintDmNCBo4zpDIr377plVdSliZm6UB7rHwmvBnR02QT6tnrqWq2ihzB6
# lRJVTEzuh0OafzIMeMnYM0+x+ve5EOLHdfiq+HXiMf9Jb7YLHtYgyHIiJA7bTWLq
# FSLGaTh7ZlbxbsLXA91OOroEpv7OjzFuu3tkpC9FflA4Dp2Euq4+qPmxUqfGp+TX
# 0gLRJp9NJOzzILjcTD3rkFFFbxUv1xyg6avivFDLtoKBhM2Td138umE1pNOacanu
# SYtPHIeQHmB6haFi64avLBLwTTAm/Rbit860cFXR72wq+5Qh4hSmezHqKXERWPpV
# Be+APrJ4Iqc+aPeMmIkoCWZQO22HnLNFUFSXjiwyIbgvlH/LIAJEqTafTzxDZgKh
# lLU7zr6gwsq3WNpcYQI6NuxWnwh3VVDDyF7onQqKs5Ll7bleVN0Y8VvqgE45ppyB
# bvwqN/Run5fMCCRz3aYMY0kZhKO92eP7t4zHqZ5bQMAgZ0tE2Pz/jb0wiykUF/Pc
# oOqqk3vVLiRDYst6vd3GEMNzMpUUvQcvBG46+COIbwIDAQABo4IB3DCCAdgwDgYD
# VR0PAQH/BAQDAgGGMBAGCSsGAQQBgjcVAQQDAgEAMB0GA1UdDgQWBBSa8VR3dQyH
# FjdGoKzeefn0f8F46TBUBgNVHSAETTBLMEkGBFUdIAAwQTA/BggrBgEFBQcCARYz
# aHR0cDovL3d3dy5taWNyb3NvZnQuY29tL3BraW9wcy9Eb2NzL1JlcG9zaXRvcnku
# aHRtMBkGCSsGAQQBgjcUAgQMHgoAUwB1AGIAQwBBMBIGA1UdEwEB/wQIMAYBAf8C
# AQAwHwYDVR0jBBgwFoAU2UEpsA8PY2zvadf1zSmepEhqMOYwcAYDVR0fBGkwZzBl
# oGOgYYZfaHR0cDovL3d3dy5taWNyb3NvZnQuY29tL3BraW9wcy9jcmwvTWljcm9z
# b2Z0JTIwSUQlMjBWZXJpZmllZCUyMENvZGUlMjBTaWduaW5nJTIwUENBJTIwMjAy
# MS5jcmwwfQYIKwYBBQUHAQEEcTBvMG0GCCsGAQUFBzAChmFodHRwOi8vd3d3Lm1p
# Y3Jvc29mdC5jb20vcGtpb3BzL2NlcnRzL01pY3Jvc29mdCUyMElEJTIwVmVyaWZp
# ZWQlMjBDb2RlJTIwU2lnbmluZyUyMFBDQSUyMDIwMjEuY3J0MA0GCSqGSIb3DQEB
# DAUAA4ICAQCQdVoZ/U0m38l2iKaZFlsxavptpoOLyaR1a9ZK2TSF1kOnFJhMDse6
# KkCgsveoiEjXTVc6Xt86IKHn76Nk5qZB0BXv2iMRQ2giAJmYvZcmstoZqfB2M3Kd
# 5wnJhUJOtF/b6HsqSelY6nhrF06zor1lDmDQixBZcLB9zR1+RKQso1jekNxYuUk+
# HaN3k1S57qk0O//YbkwU0mELCW04N5vICMZx5T5c7Nq/7uLvbVhCdD7f2bZpA4U7
# vOkB1ooB4AaER3pjoJ0Mad5LFyi6Na9p9Zu/hrLeOjU5FItS5YxsqvlfXxAThJ17
# 6CmkYstKRmytSHZ7JhKRfV6e9Zftk/ODb/CK4pGVAVqsOf4337bQGrOHHCQ3IvN9
# gmnUuDh8JdvbheoWPHxIN1GB5sUiY584tXN7xdD8LCSsRqJvQ8e7a3gZWTgViugR
# s1QWq+N0G9Nje6JHlN1CjJehge+H5PGktJja+juGEr0P+ukSkcL6qaZxFQTh3SDI
# 71lvW++3bl/Ezd6SO8N9Udw+reoyvRHCyTiSsplZQSBTVJdPmo3qCpGuyHFtPo5C
# Bn3/FPTiqJd3M9BHoqKd0G9Kmg6fGcAvFwnLNXA2kov727wRljL3ypfqL7iAT/Yn
# pxul6RwHRlcOf9dDGg1RRvr92NP/CWVXIb68geR2rvU/NsfmtjF1wDCCB54wggWG
# oAMCAQICEzMAAAAHh6M0o3uljhwAAAAAAAcwDQYJKoZIhvcNAQEMBQAwdzELMAkG
# A1UEBhMCVVMxHjAcBgNVBAoTFU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjFIMEYGA1UE
# AxM/TWljcm9zb2Z0IElkZW50aXR5IFZlcmlmaWNhdGlvbiBSb290IENlcnRpZmlj
# YXRlIEF1dGhvcml0eSAyMDIwMB4XDTIxMDQwMTIwMDUyMFoXDTM2MDQwMTIwMTUy
# MFowYzELMAkGA1UEBhMCVVMxHjAcBgNVBAoTFU1pY3Jvc29mdCBDb3Jwb3JhdGlv
# bjE0MDIGA1UEAxMrTWljcm9zb2Z0IElEIFZlcmlmaWVkIENvZGUgU2lnbmluZyBQ
# Q0EgMjAyMTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBALLwwK8ZiCji
# 3VR6TElsaQhVCbRS/3pK+MHrJSj3Zxd3KU3rlfL3qrZilYKJNqztA9OQacr1AwoN
# cHbKBLbsQAhBnIB34zxf52bDpIO3NJlfIaTE/xrweLoQ71lzCHkD7A4As1Bs076I
# u+mA6cQzsYYH/Cbl1icwQ6C65rU4V9NQhNUwgrx9rGQ//h890Q8JdjLLw0nV+ayQ
# 2Fbkd242o9kH82RZsH3HEyqjAB5a8+Ae2nPIPc8sZU6ZE7iRrRZywRmrKDp5+Tcm
# JX9MRff241UaOBs4NmHOyke8oU1TYrkxh+YeHgfWo5tTgkoSMoayqoDpHOLJs+qG
# 8Tvh8SnifW2Jj3+ii11TS8/FGngEaNAWrbyfNrC69oKpRQXY9bGH6jn9NEJv9weF
# xhTwyvx9OJLXmRGbAUXN1U9nf4lXezky6Uh/cgjkVd6CGUAf0K+Jw+GE/5VpIVbc
# Nr9rNE50Sbmy/4RTCEGvOq3GhjITbCa4crCzTTHgYYjHs1NbOc6brH+eKpWLtr+b
# Gecy9CrwQyx7S/BfYJ+ozst7+yZtG2wR461uckFu0t+gCwLdN0A6cFtSRtR8bvxV
# FyWwTtgMMFRuBa3vmUOTnfKLsLefRaQcVTgRnzeLzdpt32cdYKp+dhr2ogc+qM6K
# 4CBI5/j4VFyC4QFeUP2YAidLtvpXRRo3AgMBAAGjggI1MIICMTAOBgNVHQ8BAf8E
# BAMCAYYwEAYJKwYBBAGCNxUBBAMCAQAwHQYDVR0OBBYEFNlBKbAPD2Ns72nX9c0p
# nqRIajDmMFQGA1UdIARNMEswSQYEVR0gADBBMD8GCCsGAQUFBwIBFjNodHRwOi8v
# d3d3Lm1pY3Jvc29mdC5jb20vcGtpb3BzL0RvY3MvUmVwb3NpdG9yeS5odG0wGQYJ
# KwYBBAGCNxQCBAweCgBTAHUAYgBDAEEwDwYDVR0TAQH/BAUwAwEB/zAfBgNVHSME
# GDAWgBTIftJqhSobyhmYBAcnz1AQT2ioojCBhAYDVR0fBH0wezB5oHegdYZzaHR0
# cDovL3d3dy5taWNyb3NvZnQuY29tL3BraW9wcy9jcmwvTWljcm9zb2Z0JTIwSWRl
# bnRpdHklMjBWZXJpZmljYXRpb24lMjBSb290JTIwQ2VydGlmaWNhdGUlMjBBdXRo
# b3JpdHklMjAyMDIwLmNybDCBwwYIKwYBBQUHAQEEgbYwgbMwgYEGCCsGAQUFBzAC
# hnVodHRwOi8vd3d3Lm1pY3Jvc29mdC5jb20vcGtpb3BzL2NlcnRzL01pY3Jvc29m
# dCUyMElkZW50aXR5JTIwVmVyaWZpY2F0aW9uJTIwUm9vdCUyMENlcnRpZmljYXRl
# JTIwQXV0aG9yaXR5JTIwMjAyMC5jcnQwLQYIKwYBBQUHMAGGIWh0dHA6Ly9vbmVv
# Y3NwLm1pY3Jvc29mdC5jb20vb2NzcDANBgkqhkiG9w0BAQwFAAOCAgEAfyUqnv7U
# q+rdZgrbVyNMul5skONbhls5fccPlmIbzi+OwVdPQ4H55v7VOInnmezQEeW4LqK0
# wja+fBznANbXLB0KrdMCbHQpbLvG6UA/Xv2pfpVIE1CRFfNF4XKO8XYEa3oW8oVH
# +KZHgIQRIwAbyFKQ9iyj4aOWeAzwk+f9E5StNp5T8FG7/VEURIVWArbAzPt9ThVN
# 3w1fAZkF7+YU9kbq1bCR2YD+MtunSQ1Rft6XG7b4e0ejRA7mB2IoX5hNh3UEauY0
# byxNRG+fT2MCEhQl9g2i2fs6VOG19CNep7SquKaBjhWmirYyANb0RJSLWjinMLXN
# OAga10n8i9jqeprzSMU5ODmrMCJE12xS/NWShg/tuLjAsKP6SzYZ+1Ry358ZTFcx
# 0FS/mx2vSoU8s8HRvy+rnXqyUJ9HBqS0DErVLjQwK8VtsBdekBmdTbQVoCgPCqr+
# PDPB3xajYnzevs7eidBsM71PINK2BoE2UfMwxCCX3mccFgx6UsQeRSdVVVNSyALQ
# e6PT12418xon2iDGE81OGCreLzDcMAZnrUAx4XQLUz6ZTl65yPUiOh3k7Yww94lD
# f+8oG2oZmDh5O1Qe38E+M3vhKwmzIeoB1dVLlz4i3IpaDcR+iuGjH2TdaC1ZOmBX
# iCRKJLj4DT2uhJ04ji+tHD6n58vhavFIrmcxghcyMIIXLgIBATBxMFoxCzAJBgNV
# BAYTAlVTMR4wHAYDVQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xKzApBgNVBAMT
# Ik1pY3Jvc29mdCBJRCBWZXJpZmllZCBDUyBFT0MgQ0EgMDQCEzMACSQJy9bOYc8r
# XoMAAAAJJAkwDQYJYIZIAWUDBAIBBQCgXjAQBgorBgEEAYI3AgEMMQIwADAZBgkq
# hkiG9w0BCQMxDAYKKwYBBAGCNwIBBDAvBgkqhkiG9w0BCQQxIgQgn6huu2NRWZti
# f16+2uf7RwXUXYRKXhM/TwmHKNSPnZ4wDQYJKoZIhvcNAQEBBQAEggGAJfPl4Do9
# 3GgViPFH27Ig0T+bCysmkMISosZrudHTS8J0oRiWL83lLugjBY9zTF06CQFegiQb
# KU6wft615MmmzM5nBO9JV4Tb8AYUgNDm8mdXEp/INy1agsRbOKZYVaj5Re34Vr0A
# eOhlydwaTxJKWLLrG4UF+pMbE/IE8i80XnC9wh7Lz4djLZ0shjfP2T25VDqYgdbR
# Tn3dLnDa9h83SpJ4d+y9FV7Cg/9k0duRSbcwozG+TLlmLoPiZq9husRL9FM15biN
# imqveBOqY9VElQCjzdxi8WjctMilyrkGf/1h71QOtPxZsXY30sJORzfwGRVDalZU
# SeaIh62NA1ny3h6XbM81qVwz4NMDVd96ADvYTXAm2qpD5kIPHRxEwPC0OKD1WWaT
# pUS/xgbGhA/pxrVy5lQ8dimcG81kU1fuOqC47Z7lCm4cAIeYMea0rE72N8M2/ue8
# RFRNMz51bOaMG3QRD/Jkfu6Daent4QA2cMJw5Ng7gI2SZzcg06LLrkjmoYIUsjCC
# FK4GCisGAQQBgjcDAwExghSeMIIUmgYJKoZIhvcNAQcCoIIUizCCFIcCAQMxDzAN
# BglghkgBZQMEAgEFADCCAWoGCyqGSIb3DQEJEAEEoIIBWQSCAVUwggFRAgEBBgor
# BgEEAYRZCgMBMDEwDQYJYIZIAWUDBAIBBQAEIH4a35gbJTukch48XWBccSNnf95b
# AGDUEhU3ice6b4T4AgZqwGDJ0LMYEzIwMjYxMDI2MDkyNDM1LjU1OVowBIACAfSg
# gemkgeYwgeMxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYD
# VQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xLTAr
# BgNVBAsTJE1pY3Jvc29mdCBJcmVsYW5kIE9wZXJhdGlvbnMgTGltaXRlZDEnMCUG
# A1UECxMeblNoaWVsZCBUU1MgRVNOOjQ5MUEtMDVFMC1EOTQ3MTUwMwYDVQQDEyxN
# aWNyb3NvZnQgUHVibGljIFJTQSBUaW1lIFN0YW1waW5nIEF1dGhvcml0eaCCDykw
# ggeCMIIFaqADAgECAhMzAAAABeXPD/9mLsmHAAAAAAAFMA0GCSqGSIb3DQEBDAUA
# MHcxCzAJBgNVBAYTAlVTMR4wHAYDVQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24x
# SDBGBgNVBAMTP01pY3Jvc29mdCBJZGVudGl0eSBWZXJpZmljYXRpb24gUm9vdCBD
# ZXJ0aWZpY2F0ZSBBdXRob3JpdHkgMjAyMDAeFw0yMDExMTkyMDMyMzFaFw0zNTEx
# MTkyMDQyMzFaMGExCzAJBgNVBAYTAlVTMR4wHAYDVQQKExVNaWNyb3NvZnQgQ29y
# cG9yYXRpb24xMjAwBgNVBAMTKU1pY3Jvc29mdCBQdWJsaWMgUlNBIFRpbWVzdGFt
# cGluZyBDQSAyMDIwMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAnnzn
# UmP94MWfBX1jtQYioxwe1+eXM9ETBb1lRkd3kcFdcG9/sqtDlwxKoVIcaqDb+omF
# io5DHC4RBcbyQHjXCwMk/l3TOYtgoBjxnG/eViS4sOx8y4gSq8Zg49REAf5huXhI
# kQRKe3Qxs8Sgp02KHAznEa/Ssah8nWo5hJM1xznkRsFPu6rfDHeZeG1Wa1wISvlk
# pOQooTULFm809Z0ZYlQ8Lp7i5F9YciFlyAKwn6yjN/kR4fkquUWfGmMopNq/B8U/
# pdoZkZZQbxNlqJOiBGgCWpx69uKqKhTPVi3gVErnc/qi+dR8A2MiAz0kN0nh7SqI
# NGbmw5OIRC0EsZ31WF3Uxp3GgZwetEKxLms73KG/Z+MkeuaVDQQheangOEMGJ4pQ
# ZH55ngI0Tdy1bi69INBV5Kn2HVJo9XxRYR/JPGAaM6xGl57Ei95HUw9NV/uC3yFj
# rhc087qLJQawSC3xzY/EXzsT4I7sDbxOmM2rl4uKK6eEpurRduOQ2hTkmG1hSuWY
# BunFGNv21Kt4N20AKmbeuSnGnsBCd2cjRKG79+TX+sTehawOoxfeOO/jR7wo3liw
# kGdzPJYHgnJ54UxbckF914AqHOiEV7xTnD1a69w/UTxwjEugpIPMIIE67SFZ2PMo
# 27xjlLAHWW3l1CEAFjLNHd3EQ79PUr8FUXetXr0CAwEAAaOCAhswggIXMA4GA1Ud
# DwEB/wQEAwIBhjAQBgkrBgEEAYI3FQEEAwIBADAdBgNVHQ4EFgQUa2koOjUvSGNA
# z3vYr0npPtk92yEwVAYDVR0gBE0wSzBJBgRVHSAAMEEwPwYIKwYBBQUHAgEWM2h0
# dHA6Ly93d3cubWljcm9zb2Z0LmNvbS9wa2lvcHMvRG9jcy9SZXBvc2l0b3J5Lmh0
# bTATBgNVHSUEDDAKBggrBgEFBQcDCDAZBgkrBgEEAYI3FAIEDB4KAFMAdQBiAEMA
# QTAPBgNVHRMBAf8EBTADAQH/MB8GA1UdIwQYMBaAFMh+0mqFKhvKGZgEByfPUBBP
# aKiiMIGEBgNVHR8EfTB7MHmgd6B1hnNodHRwOi8vd3d3Lm1pY3Jvc29mdC5jb20v
# cGtpb3BzL2NybC9NaWNyb3NvZnQlMjBJZGVudGl0eSUyMFZlcmlmaWNhdGlvbiUy
# MFJvb3QlMjBDZXJ0aWZpY2F0ZSUyMEF1dGhvcml0eSUyMDIwMjAuY3JsMIGUBggr
# BgEFBQcBAQSBhzCBhDCBgQYIKwYBBQUHMAKGdWh0dHA6Ly93d3cubWljcm9zb2Z0
# LmNvbS9wa2lvcHMvY2VydHMvTWljcm9zb2Z0JTIwSWRlbnRpdHklMjBWZXJpZmlj
# YXRpb24lMjBSb290JTIwQ2VydGlmaWNhdGUlMjBBdXRob3JpdHklMjAyMDIwLmNy
# dDANBgkqhkiG9w0BAQwFAAOCAgEAX4h2x35ttVoVdedMeGj6TuHYRJklFaW4sTQ5
# r+k77iB79cSLNe+GzRjv4pVjJviceW6AF6ycWoEYR0LYhaa0ozJLU5Yi+LCmcrdo
# vkl53DNt4EXs87KDogYb9eGEndSpZ5ZM74LNvVzY0/nPISHz0Xva71QjD4h+8z2X
# MOZzY7YQ0Psw+etyNZ1CesufU211rLslLKsO8F2aBs2cIo1k+aHOhrw9xw6JCWON
# NboZ497mwYW5EfN0W3zL5s3ad4Xtm7yFM7Ujrhc0aqy3xL7D5FR2J7x9cLWMq7eb
# 0oYioXhqV2tgFqbKHeDick+P8tHYIFovIP7YG4ZkJWag1H91KlELGWi3SLv10o4K
# Gag42pswjybTi4toQcC/irAodDW8HNtX+cbz0sMptFJK+KObAnDFHEsukxD+7jFf
# EV9Hh/+CSxKRsmnuiovCWIOb+H7DRon9TlxydiFhvu88o0w35JkNbJxTk4MhF/Kg
# aXn0GxdH8elEa2Imq45gaa8D+mTm8LWVydt4ytxYP/bqjN49D9NZ81coE6aQWm88
# TwIf4R4YZbOpMKN0CyejaPNN41LGXHeCUMYmBx3PkP8ADHD1J2Cr/6tjuOOCztfp
# +o9Nc+ZoIAkpUcA/X2gSMkgHAPUvIdtoSAHEUKiBhI6JQivRepyvWcl+JYbYbBh7
# pmgAXVswggefMIIFh6ADAgECAhMzAAAAWvYNZ4yF7d0IAAAAAABaMA0GCSqGSIb3
# DQEBDAUAMGExCzAJBgNVBAYTAlVTMR4wHAYDVQQKExVNaWNyb3NvZnQgQ29ycG9y
# YXRpb24xMjAwBgNVBAMTKU1pY3Jvc29mdCBQdWJsaWMgUlNBIFRpbWVzdGFtcGlu
# ZyBDQSAyMDIwMB4XDTI2MDEwODE4NTkwM1oXDTI3MDEwNzE4NTkwM1owgeMxCzAJ
# BgNVBAYTAlVTMRMwEQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25k
# MR4wHAYDVQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xLTArBgNVBAsTJE1pY3Jv
# c29mdCBJcmVsYW5kIE9wZXJhdGlvbnMgTGltaXRlZDEnMCUGA1UECxMeblNoaWVs
# ZCBUU1MgRVNOOjQ5MUEtMDVFMC1EOTQ3MTUwMwYDVQQDEyxNaWNyb3NvZnQgUHVi
# bGljIFJTQSBUaW1lIFN0YW1waW5nIEF1dGhvcml0eTCCAiIwDQYJKoZIhvcNAQEB
# BQADggIPADCCAgoCggIBAO/0O0eWjgUb9rnHcQLRdfWPN4H+91a3YnlaP46E1m4u
# D+JKx6csWMStX79fxLJUAqHJqQWE19UlNMhS9jEB32dAJ4yuWsHyUuM+dphjDz4E
# 5jl4gYGZEmaOrKvNt+KqlFayyg/oTg3BlLRu4aBq8668A5qlHcfsuh6DdSqFID1i
# xJFZzHrZFG1iGBG7U1Bn2ONLDo7jbwX5rMcPduTAUw/c7M3WhSxQBuZpQiz8RQGK
# IqCKfIxgQkKdzpCpU0SWQOE/DgTXbz3c15KMRCdkGlL2zb+lnuSV4sseQm3qflZi
# ZckLyn2xJI8ZXDkq+Ig+b/rsPPIfI8di228WvK1j67JXpyeVCaSUO9ErzlLnTrnj
# QkeXVQIp73xuVBVrmvoTf/v4a7MnrmuKSyIXc5vJUHEGB345+O8omFt1w8b+Xg9D
# 9PKIRqDPEv7HRk0C+Yvxu8FvHJvSocSIZK+v/FmKFOipYnpP76yAmJNnyheucShO
# gk8QiU53USn/+AyMb7xW905gZnyNqb29HeVdQ175pDHJGEz8Cx5wiHeVliGz5hAB
# ucFDylR9z3LSTmB6+3ZuIxeG9BZS46P6ANPkuVuD5m8wgc7GLLzg73CsDF09ukt8
# Uf8dTcMBX3ro+7/k9M6Xt8WPG7IL9v/4DvyMY03tkb9Y9Ri6HWavXRPYRCUePspP
# AgMBAAGjggHLMIIBxzAdBgNVHQ4EFgQUjmOyQ6twMcP1ZbRytJxI4fnXmcIwHwYD
# VR0jBBgwFoAUa2koOjUvSGNAz3vYr0npPtk92yEwbAYDVR0fBGUwYzBhoF+gXYZb
# aHR0cDovL3d3dy5taWNyb3NvZnQuY29tL3BraW9wcy9jcmwvTWljcm9zb2Z0JTIw
# UHVibGljJTIwUlNBJTIwVGltZXN0YW1waW5nJTIwQ0ElMjAyMDIwLmNybDB5Bggr
# BgEFBQcBAQRtMGswaQYIKwYBBQUHMAKGXWh0dHA6Ly93d3cubWljcm9zb2Z0LmNv
# bS9wa2lvcHMvY2VydHMvTWljcm9zb2Z0JTIwUHVibGljJTIwUlNBJTIwVGltZXN0
# YW1waW5nJTIwQ0ElMjAyMDIwLmNydDAMBgNVHRMBAf8EAjAAMBYGA1UdJQEB/wQM
# MAoGCCsGAQUFBwMIMA4GA1UdDwEB/wQEAwIHgDBmBgNVHSAEXzBdMFEGDCsGAQQB
# gjdMg30BATBBMD8GCCsGAQUFBwIBFjNodHRwOi8vd3d3Lm1pY3Jvc29mdC5jb20v
# cGtpb3BzL0RvY3MvUmVwb3NpdG9yeS5odG0wCAYGZ4EMAQQCMA0GCSqGSIb3DQEB
# DAUAA4ICAQCAlM8r+t3hIb2h1lDTAx+iYkQlxFuU7QONeyIFIBZ29xvGl8pehKxE
# rDzIniOpIX/eluUAwQKoaI0zwuKAdR0mrSHXCniMoLNko5W+5r7sXNamKX7QMV3B
# fGOX3gi9qVfxyUe7AHXbqQ8KBQHNYCnNFtQQHgARrlYhtyAKol5ctM0CAc/y3oY7
# bTMsVJvnA5u7DVWPeXoST2KEMDeLBvJYq0IJZ6yMpDOWLZ4UP82bksyShIB/Xdaw
# irIGLdseudryRxVMk313mAcjGRb59+Ittt6otVvYQWqH+PGrTUzEcez8aQuO3umo
# NZjKuFoX5VsPP/gSZse+orhG3zfZk9IDyE3DfUFrhvkv6H0tijK1D0uIGhwMBWSm
# 9ktQ6oeU+aurZFx3MI+LODnHsbRFZAy11uMvwKq+ZNC1Se4tIM1u9piWAhnTPoh6
# mULKikHOVhHaO953tkzDCtjsse5GUKOx9yg9nqHKWMgnODp62/uPPzC/yDEISrXC
# cU7UB7tATr3zWNEdtM4d009iXWI6dV/SdcIIX44rpoLyCLw+nXjxp+fY/dygLO7U
# dSQaVaUFVj3K2nVyuujPspt5Lunc5FvuYPqmi/z8kASmmwbiF+W0P0UTWFaC84MW
# fU2h6MDg5s0oxmdNFK76jXr3wZfdSoV7FCKfq5GdeGoy5UwDQwMC0DGCA9QwggPQ
# AgEBMHgwYTELMAkGA1UEBhMCVVMxHjAcBgNVBAoTFU1pY3Jvc29mdCBDb3Jwb3Jh
# dGlvbjEyMDAGA1UEAxMpTWljcm9zb2Z0IFB1YmxpYyBSU0EgVGltZXN0YW1waW5n
# IENBIDIwMjACEzMAAABa9g1njIXt3QgAAAAAAFowDQYJYIZIAWUDBAIBBQCgggEt
# MBoGCSqGSIb3DQEJAzENBgsqhkiG9w0BCRABBDAvBgkqhkiG9w0BCQQxIgQgCvsy
# 3wwUXUmZ36TaQo7cDyBb8R4tHp8Qaw96GiidYN4wgd0GCyqGSIb3DQEJEAIvMYHN
# MIHKMIHHMIGgBCBiuWRAi+p96PRsBt3TwW3jNozgPQS+Qco1CVm/NaU0QzB8MGWk
# YzBhMQswCQYDVQQGEwJVUzEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9u
# MTIwMAYDVQQDEylNaWNyb3NvZnQgUHVibGljIFJTQSBUaW1lc3RhbXBpbmcgQ0Eg
# MjAyMAITMwAAAFr2DWeMhe3dCAAAAAAAWjAiBCBeFypjYuFfp01+9Q5nlkQgdCVG
# 8A6qELtTLIL+P3LzpzANBgkqhkiG9w0BAQsFAASCAgCkFoyesDcw1/QSh816hLWb
# 2WQu5zdW+HtC5+0bOT6gfGr41e9Jh23nAuL/y+8/1msCq0Tz+cAguxdTmakeIJjr
# RbHW7guk1f/5iq9cEJPJ+28a7aSP3dahALa6j6ZXQQ0YCnXE9GavTgUVQRmOLOGb
# NYNI3WblSkx3AHF7+4JVrIsxeok5xXuNqShelY0em+QF++U7qvLZFqZ5O4Nv/ral
# 9YzudoHo4CqXFe2aY0ngm5TGsGfO4hTI5Z3IvlEmx5oja9H7FBwolYKoWM5d6Pet
# 3S7MXEJaa6VnAfsHPHrDvtrFWdxEAHgS5TF2SDTWZUOh/Lv6it6pdnJzO9dkeLZ5
# kMukALWDprG1NZuimH48PwhKJyn4TpSVUcVjTrFt2WKqahqIukHXeTWlKo7WvpFM
# bMlNO/Imy2qnvSuuuK6izUgh2brsULDYvhO+878cErlrwtDPlorUR+xS7VyLvSB1
# 4+3W7CwHZXo5Map5ni0ICdehQcztjX3T60wep9MMvIY3BQi+uczKduOGZgPNCkD6
# VlBbuX55ooLZBaztrEw4o99YfoTLdSWPBl8RrIOuiNZnlalXp1i3k4azjrC4dzLd
# UDM62Y174g6UTnMSNKiq0m2ZMS5+BFAocjJITGOgxVLT1Eygczf/xMLVJcLJRseK
# VNhXaFpFsL1Urwwm3Hglww==
# SIG # End signature block