Invoke-OffboardingCheck.ps1

<#
.SYNOPSIS
    Free, read-only Microsoft 365 offboarding check.
    Finds accounts that look like leavers and shows what they still hold.
 
.DESCRIPTION
    When someone leaves, the license is usually the only thing anyone remembers to remove. The
    account often keeps its group memberships and a user mailbox that was never converted to
    shared, and nobody notices until an audit.
 
    This connects to Microsoft Graph with delegated, READ-ONLY scopes via device-code sign-in
    (nothing to register, no app, no secrets). It never writes, removes, or changes anything in
    your tenant, and it stores nothing. You act on the list yourself.
 
    For each account that looks like a leaver (disabled, or no activity for -InactiveDays) it
    reports:
      * whether it still holds a paid license, and which
      * how many groups it is still a member of
      * whether its mailbox is still a user mailbox rather than converted to shared
 
    Activity signal is chosen automatically, exactly as the license scan does it: directory
    sign-in activity when the tenant has Entra ID P1/P2, otherwise the Microsoft 365 usage
    reports. Disabled accounts are flagged on any tenant.
 
    What it deliberately does NOT do (that's the paid ServerBridge License Auditor):
      * mailbox size and archive detail, app role assignments, a formatted PDF, scheduled
        re-runs with drift tracking, and multi-tenant roll-up.
    See https://server-bridge.com/license-auditor.html
 
.PARAMETER InactiveDays
    An account with no activity in this many days is treated as a possible leaver.
    Default 90. Range 1-3650. (The usage-report fallback resolves to the nearest supported
    window: 30, 90 or 180 days.)
 
.PARAMETER OutputCsv
    Path for the CSV export. Default: .\offboarding-check_<tenant>_<date>.csv
 
.PARAMETER IncludeGuests
    Include guest (external) users. Off by default.
 
.PARAMETER UseExchangeOnline
    EXPERIMENTAL. Read mailbox types from Exchange Online instead of Microsoft's usage report.
 
    Worth it when you want mailboxes nobody has used. The usage report only lists mailboxes that
    have had activity, so a shared mailbox sitting untouched is missing from it entirely - which is
    the mailbox most likely to be wasting a license.
 
    Costs a SECOND sign-in (Exchange Online is a separate connection from Graph) and needs
    ExchangeOnlineManagement installed. Read-only, and if it fails the check carries on with the
    usage report.
 
.PARAMETER PassThru
    Emit the finding objects to the pipeline in addition to the CSV.
 
.EXAMPLE
    Invoke-OffboardingCheck
 
.EXAMPLE
    Invoke-OffboardingCheck -InactiveDays 30 -OutputCsv C:\reports\leavers.csv
 
.NOTES
    Requires the Microsoft Graph PowerShell SDK:
        Install-Module Microsoft.Graph -Scope CurrentUser
    Delegated scopes requested (all read-only), the same set the license scan uses:
        User.Read.All, Organization.Read.All, AuditLog.Read.All, Reports.Read.All
 
    The mailbox type comes from Microsoft's mailbox usage report, which is unavailable when your
    tenant conceals user names in reports, and which only covers mailboxes that have had
    ACTIVITY - a mailbox nobody has touched is missing from it entirely, so its type reads
    "unknown". Use -UseExchangeOnline to read types from Exchange instead (second sign-in).
    Either way an unreadable type is reported as unknown rather than guessed.
 
    Project: https://github.com/lbcrowe-del/ServerBridge-LicenseScan
    License: MIT
#>


[CmdletBinding()]
param(
    [ValidateRange(1, 3650)]
    [int]$InactiveDays = 90,

    [string]$OutputCsv,

    [switch]$IncludeGuests,

    [switch]$UseExchangeOnline,

    [switch]$PassThru
)

# Snapshot what the caller actually passed, BEFORE the dot-source below.
#
# Invoke-LicenseScan.ps1 has its own param() block with InactiveDays, OutputCsv, IncludeGuests and
# PassThru. Dot-sourcing runs it in THIS scope, so those four variables are re-declared at their
# defaults and whatever the caller passed here is wiped. The symptom was silent: -OutputCsv wrote to
# the default path instead, and -IncludeGuests did nothing at all while reporting success.
# Found 2026-09-22 when a run ignored the -OutputCsv it was given.
$callerArgs = @{
    InactiveDays      = $InactiveDays
    OutputCsv         = $OutputCsv
    IncludeGuests     = [bool]$IncludeGuests
    UseExchangeOnline = [bool]$UseExchangeOnline
    PassThru          = [bool]$PassThru
}

# Shared helpers (sign-in, activity signal, CSV escaping) live in Invoke-LicenseScan.ps1 so there
# is exactly one copy. Dot-sourcing it defines the functions without running a scan: that script
# only runs its entry point when it is not dot-sourced.
if (-not (Get-Command -Name Connect-ScanGraph -ErrorAction SilentlyContinue)) {
    $sharedPath = Join-Path $PSScriptRoot 'Invoke-LicenseScan.ps1'
    if (-not (Test-Path -LiteralPath $sharedPath)) {
        throw "Invoke-LicenseScan.ps1 must sit next to this script (it holds the shared sign-in and activity helpers)."
    }
    . $sharedPath
}

# ---------------------------------------------------------------------------
# Pure, testable helpers (no Graph calls - safe to dot-source)
# ---------------------------------------------------------------------------

function Get-MailboxTypeLabel {
    <#
    Plain-English label for a mailbox recipient type from Microsoft's usage report.
    $null/empty means the report didn't cover this account (it lags a day or two).
    #>

    [CmdletBinding()]
    param([Parameter()][AllowNull()][AllowEmptyString()][string]$RecipientType)

    if ([string]::IsNullOrWhiteSpace($RecipientType)) { return 'unknown' }
    switch ($RecipientType.Trim().ToLower()) {
        'usermailbox'      { return 'user' }
        'user'             { return 'user' }
        'sharedmailbox'    { return 'shared' }
        'shared'           { return 'shared' }
        'roommailbox'      { return 'room' }
        'room'             { return 'room' }
        'equipmentmailbox' { return 'equipment' }
        'equipment'        { return 'equipment' }
        default            { return $RecipientType.Trim().ToLower() }
    }
}

function Get-OffboardingRow {
    <#
    Pure projection: given normalized user objects (DisplayName, UserPrincipalName, UserType,
    AccountEnabled, LastActivity, AssignedLicenses[].SkuId, GroupCount, MailboxType), a
    SkuId->PartNumber map and a cutoff, emit one row per leaver-looking account. No Graph, no
    I/O - unit-testable.
 
    An account is a possible leaver when disabled, OR (when an activity signal is available)
    when last activity is older than the cutoff or unknown. With no activity signal only
    disabled accounts are flagged, because everything else would be a guess.
 
    Unlike the license scan this emits ONE row per account, not one per license, because the
    unit of work when offboarding is the person.
    #>

    [CmdletBinding()]
    param(
        [Parameter(Mandatory)][AllowNull()][AllowEmptyCollection()][object[]]$Users,
        [Parameter(Mandatory)][hashtable]$SkuMap,
        [Parameter(Mandatory)][datetime]$Cutoff,
        [bool]$ActivitySignalAvailable = $true,
        [switch]$IncludeGuests
    )

    foreach ($u in @($Users | Where-Object { $null -ne $_ })) {
        if (-not $IncludeGuests -and $u.UserType -eq 'Guest') { continue }

        $reason = $null
        if (-not $u.AccountEnabled) {
            $reason = 'disabled'
        } elseif ($ActivitySignalAvailable -and (Test-UserDormant -LastActivity $u.LastActivity -Cutoff $Cutoff)) {
            $reason = 'inactive'
        }
        if (-not $reason) { continue }

        $licenses = @()
        foreach ($lic in $u.AssignedLicenses) {
            $part = $SkuMap[$lic.SkuId]
            if (-not $part) { continue }
            if ((Get-SkuMonthlyPrice -PartNumber $part) -le 0) { continue }  # free SKUs aren't worth reclaiming
            $licenses += $part
        }

        $mailboxType = if ($u.MailboxType) { $u.MailboxType } else { 'unknown' }
        $groupCount = if ($null -ne $u.GroupCount) { [int]$u.GroupCount } else { $null }

        $findings = @()
        if ($licenses.Count -gt 0) { $findings += 'still licensed' }
        if ($groupCount -gt 0) { $findings += 'still in groups' }
        if ($mailboxType -eq 'user') { $findings += 'mailbox not shared' }

        [pscustomobject]@{
            DisplayName       = $u.DisplayName
            UserPrincipalName = $u.UserPrincipalName
            UserType          = $u.UserType
            AccountEnabled    = $u.AccountEnabled
            Reason            = $reason
            LastActivity      = if ($u.LastActivity) { ([datetime]$u.LastActivity).ToString('yyyy-MM-dd') } else { 'never/unknown' }
            Licenses          = ($licenses -join '; ')
            LicenseCount      = $licenses.Count
            GroupCount        = $groupCount
            MailboxType       = $mailboxType
            Findings          = ($findings -join '; ')
        }
    }
}

# ---------------------------------------------------------------------------
# Graph I/O (kept in functions so tests can dot-source without a tenant)
# ---------------------------------------------------------------------------

function Merge-MailboxTypeMap {
    <#
    Pure merge of two mailbox-type maps. Exchange wins wherever it has an answer, because it reads
    Exchange's own directory; the usage report only fills gaps.
 
    This exists because of a limit found on a live tenant 2026-09-22: getMailboxUsageDetail only
    lists mailboxes that have HAD ACTIVITY. A shared mailbox nobody has touched is absent from the
    report entirely - not blank, absent - at D7 and at D180 alike. That is exactly the mailbox worth
    finding, since an unused licensed shared mailbox is the clearest wasted license there is.
    #>

    [CmdletBinding()]
    param(
        [Parameter()][AllowNull()][hashtable]$ReportMap,
        [Parameter()][AllowNull()][hashtable]$ExchangeMap
    )

    $merged = @{}
    foreach ($k in @($ReportMap.Keys)) { $merged[$k] = $ReportMap[$k] }
    foreach ($k in @($ExchangeMap.Keys)) { $merged[$k] = $ExchangeMap[$k] }
    return $merged
}

function Test-ExchangeOnlineModulePresent {
    <# Separate from the call so tests can mock it without Exchange installed. #>
    [CmdletBinding()] param()
    return [bool](Get-Module -ListAvailable -Name ExchangeOnlineManagement)
}

function Get-MailboxTypeMapFromExchange {
    <#
    PROTOTYPE (opt-in via -UseExchangeOnline).
 
    Returns @{ ok=$bool; map=@{ upn(lower) -> label }; note=$string }.
 
    Get-EXOMailbox reads Exchange's own directory, so it sees every mailbox whether or not anyone
    has used it - the case the usage report misses. The cost is a SECOND sign-in: Exchange Online is
    a different token audience from Graph, so this cannot ride on the Graph connection.
 
    That cost is why this is opt-in rather than the default. Everything here is read-only
    (Get-EXOMailbox), and a failure degrades to the usage report instead of failing the check.
    #>

    [CmdletBinding()] param()

    if (-not (Test-ExchangeOnlineModulePresent)) {
        return @{ ok = $false; map = @{}; note = 'ExchangeOnlineManagement is not installed (Install-Module ExchangeOnlineManagement -Scope CurrentUser).' }
    }

    try {
        Import-Module ExchangeOnlineManagement -ErrorAction Stop
        Write-Host ' a second sign-in is needed for Exchange Online (read-only)...' -ForegroundColor DarkGray
        Connect-ExchangeOnline -ShowBanner:$false -ErrorAction Stop | Out-Null
    } catch {
        return @{ ok = $false; map = @{}; note = "Exchange Online sign-in failed: $($_.Exception.Message)" }
    }

    try {
        $map = @{}
        foreach ($mb in @(Get-EXOMailbox -ResultSize Unlimited -Properties RecipientTypeDetails -ErrorAction Stop)) {
            $upn = $mb.UserPrincipalName
            if (-not $upn) { continue }
            $map[$upn.ToLower()] = Get-MailboxTypeLabel -RecipientType $mb.RecipientTypeDetails
        }
        return @{ ok = $true; map = $map; note = $null }
    } catch {
        return @{ ok = $false; map = @{}; note = "Reading mailboxes failed: $($_.Exception.Message)" }
    } finally {
        Disconnect-ExchangeOnline -Confirm:$false -ErrorAction SilentlyContinue | Out-Null
    }
}

function Get-MailboxTypeMap {
    <#
    Returns @{ ok=$bool; map=@{ upn(lower) -> recipient type label } }.
 
    Uses Microsoft's mailbox usage report, which is the only way to tell a user mailbox from a
    shared one without Exchange Online PowerShell. The v1.0 report has no Recipient Type column,
    so this uses the beta report - still under Reports.Read.All, no extra permission.
 
    ok=$false when the tenant conceals user names in reports (rows can't be matched to people)
    or the column is missing. The caller reports that rather than guessing.
    #>

    [CmdletBinding()] param()

    $uri = "https://graph.microsoft.com/beta/reports/getMailboxUsageDetail(period='D7')"
    $resp = Invoke-MgGraphRequest -Method GET -Uri $uri -OutputType HttpResponseMessage -ErrorAction Stop
    $csv = $resp.Content.ReadAsStringAsync().Result
    $rows = @($csv | ConvertFrom-Csv)

    if ($rows.Count -eq 0) { return @{ ok = $true; map = @{} } }
    if (-not ($rows[0].PSObject.Properties.Name -contains 'Recipient Type')) {
        return @{ ok = $false; map = @{} }
    }

    $map = @{}
    $sawUpn = $false
    foreach ($r in $rows) {
        $upn = $r.'User Principal Name'
        if (-not $upn) { continue }
        if ($upn -like '*@*') { $sawUpn = $true }
        $map[$upn.ToLower()] = Get-MailboxTypeLabel -RecipientType $r.'Recipient Type'
    }
    if (-not $sawUpn) { return @{ ok = $false; map = @{} } }
    return @{ ok = $true; map = $map }
}

function Get-GroupMembershipCount {
    <#
    Direct group/role memberships for one account, via /users/{id}/memberOf/$count.
    Needs only User.Read.All, which this module already requests.
    Returns $null when the count can't be read, so the caller can say "unknown" honestly
    instead of printing 0 and implying the account is clean.
    #>

    [CmdletBinding()]
    param([Parameter(Mandatory)][string]$UserId)

    try {
        $uri = "https://graph.microsoft.com/v1.0/users/$UserId/memberOf/`$count"
        $resp = Invoke-MgGraphRequest -Method GET -Uri $uri -Headers @{ ConsistencyLevel = 'eventual' } `
            -OutputType HttpResponseMessage -ErrorAction Stop
        $text = $resp.Content.ReadAsStringAsync().Result
        $value = 0
        if ([int]::TryParse(("$text").Trim(), [ref]$value)) { return $value }
        return $null
    } catch {
        Write-Verbose "memberOf count failed for $UserId : $($_.Exception.Message)"
        return $null
    }
}

function Invoke-OffboardingCheckMain {
    [CmdletBinding()]
    param(
        [int]$InactiveDays,
        [string]$OutputCsv,
        [switch]$IncludeGuests,
        [switch]$UseExchangeOnline,
        [switch]$PassThru
    )

    Write-Host ''
    Write-Host 'ServerBridge - Free M365 Offboarding Check (read-only)' -ForegroundColor Green
    Write-Host '-----------------------------------------------------' -ForegroundColor DarkGray

    if (-not (Test-GraphSdkPresent)) { return }
    if (-not (Connect-ScanGraph)) { return }

    try {
        $org = Get-MgOrganization -ErrorAction Stop
        $tenantName = ($org.DisplayName | Select-Object -First 1)
        Write-Host "Connected to: $tenantName (signed in as $((Get-MgContext).Account))" -ForegroundColor Green

        $skuMap = @{}
        foreach ($s in (Get-MgSubscribedSku -All -ErrorAction Stop)) { $skuMap[$s.SkuId] = $s.SkuPartNumber }

        $select = 'id,displayName,userPrincipalName,userType,accountEnabled,assignedLicenses'
        $rawUsers = Get-MgUser -All -Property $select -ErrorAction Stop
    } catch {
        Show-GraphReadFailure -Message "$($_.Exception.Message)"
        Disconnect-MgGraph -ErrorAction SilentlyContinue | Out-Null
        return
    }

    $signal = Resolve-ActivityMap -InactiveDays $InactiveDays
    $activity = $signal.map
    $signalAvailable = $signal.available
    if (-not $signalAvailable) {
        Write-Host ''
        Write-Host 'PARTIAL CHECK: only disabled accounts can be judged without an activity signal.' -ForegroundColor Yellow
    } else {
        Write-Host "Looking for accounts inactive $InactiveDays+ days or disabled (via $($signal.signalName))..." -ForegroundColor Cyan
    }

    # Mailbox types: the only way to spot a mailbox nobody converted to shared.
    $mailboxMap = @{}
    try {
        $mb = Get-MailboxTypeMap
        if ($mb.ok) {
            $mailboxMap = $mb.map
        } else {
            Write-Host 'Mailbox types unavailable (user names are concealed in reports, or the report changed).' -ForegroundColor Yellow
            Write-Host 'Mailbox column will read "unknown".' -ForegroundColor DarkGray
        }
    } catch {
        Write-Host "Mailbox report unavailable: $($_.Exception.Message)" -ForegroundColor Yellow
    }

    # Opt-in: ask Exchange directly, which also sees mailboxes that have never been used.
    if ($UseExchangeOnline) {
        $exo = Get-MailboxTypeMapFromExchange
        if ($exo.ok) {
            $mailboxMap = Merge-MailboxTypeMap -ReportMap $mailboxMap -ExchangeMap $exo.map
            Write-Host (" mailbox types read from Exchange Online ({0} mailbox(es))" -f $exo.map.Count) -ForegroundColor DarkGray
        } else {
            Write-Host "Exchange Online check skipped: $($exo.note)" -ForegroundColor Yellow
            Write-Host 'Falling back to the usage report, which cannot see mailboxes with no activity.' -ForegroundColor DarkGray
        }
    }

    # Narrow to leaver-looking accounts BEFORE the per-user group lookup: one Graph call each.
    $cutoff = (Get-Date).AddDays(-1 * $InactiveDays)
    $candidates = foreach ($u in $rawUsers) {
        $upnKey = if ($u.UserPrincipalName) { $u.UserPrincipalName.ToLower() } else { $null }
        $last = if ($upnKey) { $activity[$upnKey] } else { $null }
        $isCandidate = (-not $u.AccountEnabled) -or
                       ($signalAvailable -and (Test-UserDormant -LastActivity $last -Cutoff $cutoff))
        if (-not $isCandidate) { continue }
        if (-not $IncludeGuests -and $u.UserType -eq 'Guest') { continue }

        [pscustomobject]@{
            Id                = $u.Id
            DisplayName       = $u.DisplayName
            UserPrincipalName = $u.UserPrincipalName
            UserType          = $u.UserType
            AccountEnabled    = $u.AccountEnabled
            AssignedLicenses  = $u.AssignedLicenses
            LastActivity      = $last
            MailboxType       = if ($upnKey -and $mailboxMap.ContainsKey($upnKey)) { $mailboxMap[$upnKey] } else { 'unknown' }
            GroupCount        = $null
        }
    }
    $candidates = @($candidates)

    if ($candidates.Count -gt 0) {
        Write-Host (" checking group membership for {0} account(s)..." -f $candidates.Count) -ForegroundColor DarkGray
        foreach ($c in $candidates) { $c.GroupCount = Get-GroupMembershipCount -UserId $c.Id }
    }

    $rows = @(Get-OffboardingRow -Users $candidates -SkuMap $skuMap -Cutoff $cutoff `
            -ActivitySignalAvailable $signalAvailable -IncludeGuests:$IncludeGuests)

    Write-Host ''
    Write-Host 'Accounts to review' -ForegroundColor Green
    Write-Host '------------------' -ForegroundColor DarkGray
    if ($rows.Count -eq 0) {
        Write-Host ' Nothing to review - no leaver-looking accounts found.' -ForegroundColor Green
    } else {
        $rows | Sort-Object LicenseCount -Descending |
            Format-Table UserPrincipalName, Reason, Licenses, GroupCount, MailboxType -AutoSize
    }

    $stillLicensed = @($rows | Where-Object { $_.LicenseCount -gt 0 }).Count
    $notShared = @($rows | Where-Object { $_.MailboxType -eq 'user' }).Count
    $typeUnknown = @($rows | Where-Object { $_.MailboxType -eq 'unknown' }).Count
    Write-Host (" Accounts to review : {0:N0}" -f $rows.Count) -ForegroundColor White
    Write-Host (" Still holding licenses : {0:N0}" -f $stillLicensed) -ForegroundColor Yellow
    # Never print a bare 0 for a count nobody could read: "0 mailboxes not shared" reads as an
    # all-clear on work that was never checked. Same false zero fixed in the paid CLI 2026-09-22.
    if ($typeUnknown -eq $rows.Count -and $rows.Count -gt 0) {
        Write-Host ' Mailbox not shared : unknown (no mailbox types could be read)' -ForegroundColor Yellow
    } elseif ($typeUnknown -gt 0) {
        Write-Host (" Mailbox not shared : {0:N0} ({1:N0} unknown)" -f $notShared, $typeUnknown) -ForegroundColor Yellow
    } else {
        Write-Host (" Mailbox not shared : {0:N0}" -f $notShared) -ForegroundColor Yellow
    }
    Write-Host ''

    if (-not $OutputCsv) {
        $safeTenant = ($tenantName -replace '[^\w]', '')
        $OutputCsv = Join-Path (Get-Location) ("offboarding-check_{0}_{1}.csv" -f $safeTenant, (Get-Date -Format 'yyyyMMdd'))
    }
    if ($rows.Count -gt 0) {
        $rows | Sort-Object LicenseCount -Descending | ForEach-Object {
            $row = $_.PSObject.Copy()
            foreach ($name in 'DisplayName', 'UserPrincipalName', 'UserType', 'Licenses', 'MailboxType', 'Findings') {
                $row.$name = ConvertTo-SafeCsvValue -Value $row.$name
            }
            $row
        } | Export-Csv -Path $OutputCsv -NoTypeInformation -Encoding UTF8
        Write-Host 'Full list saved to:' -ForegroundColor Cyan
        Write-Host " $OutputCsv" -ForegroundColor White
        Write-Host ''
    }

    Write-Host 'Nothing was changed in your tenant. Review each account before acting.' -ForegroundColor DarkGray
    Write-Host 'A licensed shared mailbox under 50 GB without an archive usually needs no license.' -ForegroundColor DarkGray
    Write-Host 'Got an account it judged wrong, or something confusing? Tell me:' -ForegroundColor DarkGray
    Write-Host ' https://github.com/lbcrowe-del/ServerBridge-LicenseScan/issues' -ForegroundColor Cyan
    Write-Host ''

    Disconnect-MgGraph -ErrorAction SilentlyContinue | Out-Null
    if ($PassThru) { $rows }
}

# Run unless dot-sourced (e.g. by Pester tests, where InvocationName is '.').
# Splats the snapshot taken before the dot-source, NOT the live variables - see the note there.
if ($MyInvocation.InvocationName -ne '.') {
    Invoke-OffboardingCheckMain -InactiveDays $callerArgs.InactiveDays -OutputCsv $callerArgs.OutputCsv `
        -IncludeGuests:$callerArgs.IncludeGuests -UseExchangeOnline:$callerArgs.UseExchangeOnline `
        -PassThru:$callerArgs.PassThru
}

# SIG # Begin signature block
# MII2xQYJKoZIhvcNAQcCoII2tjCCNrICAQExDzANBglghkgBZQMEAgEFADB5Bgor
# BgEEAYI3AgEEoGswaTA0BgorBgEEAYI3AgEeMCYCAwEAAAQQH8w7YFlLCE63JNLG
# KX7zUQIBAAIBAAIBAAIBAAIBADAxMA0GCWCGSAFlAwQCAQUABCB6Fnw4CUkFQDZ0
# uiqDKOiii470sQ4y13TJl1Uq2qzt4aCCG2MwggXMMIIDtKADAgECAhBUmNLR1FsZ
# 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
# 03u4aUoqlmZpxJTG9F9urJh4iIAGXKKy7aIwggbBMIIEqaADAgECAhMzAAai9c4S
# B9I1X2A3AAAABqL1MA0GCSqGSIb3DQEBDAUAMFoxCzAJBgNVBAYTAlVTMR4wHAYD
# VQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xKzApBgNVBAMTIk1pY3Jvc29mdCBJ
# RCBWZXJpZmllZCBDUyBFT0MgQ0EgMDMwHhcNMjYwOTIxMTUzNDI3WhcNMjYwOTI0
# MTUzNDI3WjCBgjELMAkGA1UEBhMCVVMxETAPBgNVBAgTCEtlbnR1Y2t5MRIwEAYD
# VQQHEwlMZXhpbmd0b24xJTAjBgNVBAoTHExlZSBDcm93ZSBTb2Z0d2FyZSBTb2x1
# dGlvbnMxJTAjBgNVBAMTHExlZSBDcm93ZSBTb2Z0d2FyZSBTb2x1dGlvbnMwggGi
# MA0GCSqGSIb3DQEBAQUAA4IBjwAwggGKAoIBgQCpVF1OX07SaBXAh7okpfsl0Wji
# FrWMTJLEpWsnaZqTETEwdOpCWKnObxSx2m/5R0mFtMZLyOkAlBv6fYfc+JW1Rfno
# VTtWXSyLbce9nm6uBp6lFTWb7keIaUgjLMBU8mqCFCsmeroeXBixHKI0NA4hU5jA
# ruCUgZJsrSEWeT4+7dZgAEQMQCovbu007QTT8SpMXK8V6cuv1glA3tDJe02n6tRY
# BEuWlBqsybtoZX8H0SLYSmSqhkhpwOsTNnDVTKLtbBhoCS62OJXLW/5k6DBPoTTO
# bv/cXiiTNjhaqgQJpgCvfb0x34WXTmnfXh7i9czoMvgR2YK7IGOJw+IOxCo/Rh5S
# H0yJqHPyx9RtFycSmcBG2i9hSqJs/0wnF9gFLoul1u83HsxP9kWZT/rU+VvyDFbT
# QzKd3ZSYHWtT1PCtlpX8j/sVoukG6R3dMMIO/gZadJz3jVu8ha+NOBr3P0i38zUn
# M66vj2+1hliR5AquDpcT9TGAz2emWy8lCVg1Pp8CAwEAAaOCAdUwggHRMAwGA1Ud
# EwEB/wQCMAAwDgYDVR0PAQH/BAQDAgeAMDwGA1UdJQQ1MDMGCisGAQQBgjdhAQAG
# CCsGAQUFBwMDBhsrBgEEAYI3YfX3xXqCm/n9aIL52tE6goGumFEwHQYDVR0OBBYE
# FGvMC/cxnW4N241h9ea1ogT+6AtJMB8GA1UdIwQYMBaAFGtepTTDBcViSiFajqtz
# YGLUrGOFMGcGA1UdHwRgMF4wXKBaoFiGVmh0dHA6Ly93d3cubWljcm9zb2Z0LmNv
# bS9wa2lvcHMvY3JsL01pY3Jvc29mdCUyMElEJTIwVmVyaWZpZWQlMjBDUyUyMEVP
# QyUyMENBJTIwMDMuY3JsMHQGCCsGAQUFBwEBBGgwZjBkBggrBgEFBQcwAoZYaHR0
# cDovL3d3dy5taWNyb3NvZnQuY29tL3BraW9wcy9jZXJ0cy9NaWNyb3NvZnQlMjBJ
# RCUyMFZlcmlmaWVkJTIwQ1MlMjBFT0MlMjBDQSUyMDAzLmNydDBUBgNVHSAETTBL
# MEkGBFUdIAAwQTA/BggrBgEFBQcCARYzaHR0cDovL3d3dy5taWNyb3NvZnQuY29t
# L3BraW9wcy9Eb2NzL1JlcG9zaXRvcnkuaHRtMA0GCSqGSIb3DQEBDAUAA4ICAQBw
# hTc8HWo427DaJAAAyPoK0ktV+Rv3V0czgLEa3AOFBY/7bo3UsALRuOFczwJdODzd
# BxVJ8uE3+xQ6PRmIodG8vdSJZMbFRYj2AOK8K+srU4BFXHGx840genYP8C9BOtum
# +GtaU+K9OvBiuVJ2xJntLA7GQVAF+uVodwE4paC1VNWSJyLfN6GYWYKK8mAbTQUL
# T/nRuWNVeM8t8tOrYWQbvMbWXpPCdZpQWRnLlkFCGJMDE+8iR2+WMGvro5++7/oe
# dmiL59brkAsX75h8/xMLVssoHZtttScCW/V9/OWa/qb9igerhunbV3QUgzLI0fGY
# kbQ108fG8LIhB8y0Use7d+g53l/TxloQdFQKNebaPCncqsQ1ym7ZICEXV7ddLiJe
# sJH3indOUuhtvW6qmb8lly31YRNK/lWVDcEd/DL5VcwzoCqRI4YKceizFCaxIjPP
# FV7FhZV6LLfUpBpL5g93VcGp0HmiTtkt0ncyCg8fQgVgk4TWtspN3Boe9yYdUx3r
# +4kaFl/mdbAomsL2yaLiX3iHDocagHIjAoKD+28lIBOlW0jVKEySY0SwTg3FS1IN
# ReJYYv+3Kan8+MmoNX4XnziAykeKr+M9QcQiaann0fcoY9LSD843CfQaSqPJem+e
# rCQDFPiWeyvbKmirU/l3r/nCsFqQQUqwyVKkaLrUOzCCBygwggUQoAMCAQICEzMA
# AAAVBT5uGY6TKdkAAAAAABUwDQYJKoZIhvcNAQEMBQAwYzELMAkGA1UEBhMCVVMx
# HjAcBgNVBAoTFU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjE0MDIGA1UEAxMrTWljcm9z
# b2Z0IElEIFZlcmlmaWVkIENvZGUgU2lnbmluZyBQQ0EgMjAyMTAeFw0yNjAzMjYx
# ODExMjhaFw0zMTAzMjYxODExMjhaMFoxCzAJBgNVBAYTAlVTMR4wHAYDVQQKExVN
# aWNyb3NvZnQgQ29ycG9yYXRpb24xKzApBgNVBAMTIk1pY3Jvc29mdCBJRCBWZXJp
# ZmllZCBDUyBFT0MgQ0EgMDMwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoIC
# AQDg9Ms9AqovDnMePvMOe+KybhCd8+lokzYORlS3kBVXseecbyGwBcsenlm5bLtM
# GPjiIFLzBQF+ghlVV/U29q5GcdeEEBCHTTGhL2koIrLc4UrliMRcbv9mOMtR/l7/
# xAmv0Fx4BJHn1dHt37fvrBqXmKjKfGf5DpyO/+hnV7TEreMtS19iO+bjZ/9Hnpg3
# PCk0e7YSbRTFkx97FZwRWpC4s3NepRfRXQh/WMAj7JmsYeVZohi4TF5yW2JMrJZq
# wHcyzJZYtD2Hlno5ZEJkdiZcEaxHOobmwO06Z1J9c23ps9PGIhGaq1sKLEAz9Doc
# 5rLkYWGteDrscKhAp2kIc/oYlH9Ij6BkOqqgWINEkEtC8ZNG1Mak+h3o65aj0iQK
# mdxW7IZaHO5cuyoMi+KtYfXeIIg3sVIbS2EL8kUtsDGdEqNqAq/isqTi1jXqLe6i
# Kp1ni1SPdvPW9G03CTsYF68b/yuIQRwbdoBCXemMNJCS0dorCRY4b2WAAy4ng7SA
# NcEgrBgZf535+QfLU5hGzrKjIpbMabauWb5FKWUKkMsPcXFkXRWO4noKPm4KWlFy
# pqOpbJ/KONVReIlxHQRegAOBzIhRB7gr9IDQ1sc2MgOgQ+xVGW4oq4HD0mfAiwiy
# LskZrkaQ7JoanYjBNcR9RS26YxAVbcBtLitFTzCIEg5ZdQIDAQABo4IB3DCCAdgw
# DgYDVR0PAQH/BAQDAgGGMBAGCSsGAQQBgjcVAQQDAgEAMB0GA1UdDgQWBBRrXqU0
# wwXFYkohWo6rc2Bi1KxjhTBUBgNVHSAETTBLMEkGBFUdIAAwQTA/BggrBgEFBQcC
# ARYzaHR0cDovL3d3dy5taWNyb3NvZnQuY29tL3BraW9wcy9Eb2NzL1JlcG9zaXRv
# cnkuaHRtMBkGCSsGAQQBgjcUAgQMHgoAUwB1AGIAQwBBMBIGA1UdEwEB/wQIMAYB
# Af8CAQAwHwYDVR0jBBgwFoAU2UEpsA8PY2zvadf1zSmepEhqMOYwcAYDVR0fBGkw
# ZzBloGOgYYZfaHR0cDovL3d3dy5taWNyb3NvZnQuY29tL3BraW9wcy9jcmwvTWlj
# cm9zb2Z0JTIwSUQlMjBWZXJpZmllZCUyMENvZGUlMjBTaWduaW5nJTIwUENBJTIw
# MjAyMS5jcmwwfQYIKwYBBQUHAQEEcTBvMG0GCCsGAQUFBzAChmFodHRwOi8vd3d3
# Lm1pY3Jvc29mdC5jb20vcGtpb3BzL2NlcnRzL01pY3Jvc29mdCUyMElEJTIwVmVy
# aWZpZWQlMjBDb2RlJTIwU2lnbmluZyUyMFBDQSUyMDIwMjEuY3J0MA0GCSqGSIb3
# DQEBDAUAA4ICAQBdbiI8zwXLX8glJEh/8Q22UMCUhWBO46Z9FPhwOR3mdlqRVLkY
# Oon/MczUwrjDhx3X99SPH5PSflkGoTvnO9ZWHM5YFVYpO7NYuB+mfVSGAGZwiGOA
# SWk0i2B7vn9nElJJmoiXxugfH5YdBsrUgTt0AFNXkzmqTgk+S1Hxb1u/0HCqEHVZ
# Pk2A/6eJXYbtpRM5Fcz00jisUl9BRZgSebODV85bBzOveqyC3f0PnHCxRJNhMb8x
# P/sB/VI7pf2rheSV7zqUSv8vn/fIMblXeaVIlpqoq8SP9BJMjE/CoVXJxnkZQRM1
# Fa7kN9yztvReOhxSgPgpZx/Xl/jkwyEFVJTBfBp3sTgfIc/pmqv2ehtakL2AEj78
# EmOPQohxJT3wyX+P78GA25tLpAvzj3RMMHd8z18ZuuVi+60MAzGpOASH1L8Nlr3f
# ZRZnQO+pyye2DCvYmHaIfdUgYJqn7noxxGVv89+RaETh1tgCDvwNpFCSG7vl5A4a
# ko+2fx409r9TWjXC7Oif1IQ5ZJzB4Rf8GvBiHYjvMmHpledp1FGRLdSRFVpC3/OK
# pZY6avIqZp7+8pP/WQP903DdgrvAT6W4xPOBxXPa4tGksN3SuqJaiFYHSNyeBufn
# 8iseujW4IbBSbHD4BPqbF3qZ+7nG9d/d/G2/Lx4kH9cCmBfmsZdSkHmukDCCB54w
# ggWGoAMCAQICEzMAAAAHh6M0o3uljhwAAAAAAAcwDQYJKoZIhvcNAQEMBQAwdzEL
# MAkGA1UEBhMCVVMxHjAcBgNVBAoTFU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjFIMEYG
# A1UEAxM/TWljcm9zb2Z0IElkZW50aXR5IFZlcmlmaWNhdGlvbiBSb290IENlcnRp
# ZmljYXRlIEF1dGhvcml0eSAyMDIwMB4XDTIxMDQwMTIwMDUyMFoXDTM2MDQwMTIw
# MTUyMFowYzELMAkGA1UEBhMCVVMxHjAcBgNVBAoTFU1pY3Jvc29mdCBDb3Jwb3Jh
# dGlvbjE0MDIGA1UEAxMrTWljcm9zb2Z0IElEIFZlcmlmaWVkIENvZGUgU2lnbmlu
# ZyBQQ0EgMjAyMTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBALLwwK8Z
# iCji3VR6TElsaQhVCbRS/3pK+MHrJSj3Zxd3KU3rlfL3qrZilYKJNqztA9OQacr1
# AwoNcHbKBLbsQAhBnIB34zxf52bDpIO3NJlfIaTE/xrweLoQ71lzCHkD7A4As1Bs
# 076Iu+mA6cQzsYYH/Cbl1icwQ6C65rU4V9NQhNUwgrx9rGQ//h890Q8JdjLLw0nV
# +ayQ2Fbkd242o9kH82RZsH3HEyqjAB5a8+Ae2nPIPc8sZU6ZE7iRrRZywRmrKDp5
# +TcmJX9MRff241UaOBs4NmHOyke8oU1TYrkxh+YeHgfWo5tTgkoSMoayqoDpHOLJ
# s+qG8Tvh8SnifW2Jj3+ii11TS8/FGngEaNAWrbyfNrC69oKpRQXY9bGH6jn9NEJv
# 9weFxhTwyvx9OJLXmRGbAUXN1U9nf4lXezky6Uh/cgjkVd6CGUAf0K+Jw+GE/5Vp
# IVbcNr9rNE50Sbmy/4RTCEGvOq3GhjITbCa4crCzTTHgYYjHs1NbOc6brH+eKpWL
# tr+bGecy9CrwQyx7S/BfYJ+ozst7+yZtG2wR461uckFu0t+gCwLdN0A6cFtSRtR8
# bvxVFyWwTtgMMFRuBa3vmUOTnfKLsLefRaQcVTgRnzeLzdpt32cdYKp+dhr2ogc+
# qM6K4CBI5/j4VFyC4QFeUP2YAidLtvpXRRo3AgMBAAGjggI1MIICMTAOBgNVHQ8B
# Af8EBAMCAYYwEAYJKwYBBAGCNxUBBAMCAQAwHQYDVR0OBBYEFNlBKbAPD2Ns72nX
# 9c0pnqRIajDmMFQGA1UdIARNMEswSQYEVR0gADBBMD8GCCsGAQUFBwIBFjNodHRw
# Oi8vd3d3Lm1pY3Jvc29mdC5jb20vcGtpb3BzL0RvY3MvUmVwb3NpdG9yeS5odG0w
# GQYJKwYBBAGCNxQCBAweCgBTAHUAYgBDAEEwDwYDVR0TAQH/BAUwAwEB/zAfBgNV
# HSMEGDAWgBTIftJqhSobyhmYBAcnz1AQT2ioojCBhAYDVR0fBH0wezB5oHegdYZz
# aHR0cDovL3d3dy5taWNyb3NvZnQuY29tL3BraW9wcy9jcmwvTWljcm9zb2Z0JTIw
# SWRlbnRpdHklMjBWZXJpZmljYXRpb24lMjBSb290JTIwQ2VydGlmaWNhdGUlMjBB
# dXRob3JpdHklMjAyMDIwLmNybDCBwwYIKwYBBQUHAQEEgbYwgbMwgYEGCCsGAQUF
# BzAChnVodHRwOi8vd3d3Lm1pY3Jvc29mdC5jb20vcGtpb3BzL2NlcnRzL01pY3Jv
# c29mdCUyMElkZW50aXR5JTIwVmVyaWZpY2F0aW9uJTIwUm9vdCUyMENlcnRpZmlj
# YXRlJTIwQXV0aG9yaXR5JTIwMjAyMC5jcnQwLQYIKwYBBQUHMAGGIWh0dHA6Ly9v
# bmVvY3NwLm1pY3Jvc29mdC5jb20vb2NzcDANBgkqhkiG9w0BAQwFAAOCAgEAfyUq
# nv7Uq+rdZgrbVyNMul5skONbhls5fccPlmIbzi+OwVdPQ4H55v7VOInnmezQEeW4
# LqK0wja+fBznANbXLB0KrdMCbHQpbLvG6UA/Xv2pfpVIE1CRFfNF4XKO8XYEa3oW
# 8oVH+KZHgIQRIwAbyFKQ9iyj4aOWeAzwk+f9E5StNp5T8FG7/VEURIVWArbAzPt9
# ThVN3w1fAZkF7+YU9kbq1bCR2YD+MtunSQ1Rft6XG7b4e0ejRA7mB2IoX5hNh3UE
# auY0byxNRG+fT2MCEhQl9g2i2fs6VOG19CNep7SquKaBjhWmirYyANb0RJSLWjin
# MLXNOAga10n8i9jqeprzSMU5ODmrMCJE12xS/NWShg/tuLjAsKP6SzYZ+1Ry358Z
# TFcx0FS/mx2vSoU8s8HRvy+rnXqyUJ9HBqS0DErVLjQwK8VtsBdekBmdTbQVoCgP
# Cqr+PDPB3xajYnzevs7eidBsM71PINK2BoE2UfMwxCCX3mccFgx6UsQeRSdVVVNS
# yALQe6PT12418xon2iDGE81OGCreLzDcMAZnrUAx4XQLUz6ZTl65yPUiOh3k7Yww
# 94lDf+8oG2oZmDh5O1Qe38E+M3vhKwmzIeoB1dVLlz4i3IpaDcR+iuGjH2TdaC1Z
# OmBXiCRKJLj4DT2uhJ04ji+tHD6n58vhavFIrmcxghq4MIIatAIBATBxMFoxCzAJ
# BgNVBAYTAlVTMR4wHAYDVQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xKzApBgNV
# BAMTIk1pY3Jvc29mdCBJRCBWZXJpZmllZCBDUyBFT0MgQ0EgMDMCEzMABqL1zhIH
# 0jVfYDcAAAAGovUwDQYJYIZIAWUDBAIBBQCggYQwGAYKKwYBBAGCNwIBDDEKMAig
# AoAAoQKAADAZBgkqhkiG9w0BCQMxDAYKKwYBBAGCNwIBBDAcBgorBgEEAYI3AgEL
# MQ4wDAYKKwYBBAGCNwIBFTAvBgkqhkiG9w0BCQQxIgQgfJrThREyLe2j2KZBvqSc
# JnfBvTL4mC968IyTx7SbBqMwDQYJKoZIhvcNAQEBBQAEggGAm7kyTQNbqFjzWClo
# gcQj6pk4xcIHzNbZDeO4+Ze7BWkalkAfPAPW60gd0rDHBCpIa+ECntLHIMQL7Sec
# 40/WA67X4VWDPMsRm7075jVnw85pJB9e1t67ZdGQQTJUDkc/XSamkI1imely4IB0
# ljcTVmrkoI1d6HPCeGkqTc+bBPwKhl2/+oP8drGj6vBXu/dbrERBejYmgupJZtnr
# JMMZ+kZ6FTfTGH3DYOPJudUGPSVmdjBh39pvAImYqSnK8FMg8Nn9kHJToH2ySy5X
# C68epKPAog8ycJMACy4xK4KD9bzP1Kgr1yxdY3XLfhHgnEgJN9nMcWJrIePUU9Bj
# BVv4QUiEQZHszeuJP/4Jqpa+rt098jVwkSuwpq6AVIUwKwPGGRbGH0sSllZfnTyx
# lu8kGl6HlO76mD0TVsOo3xncqCTV8Rpuse7qA6qnHJZGdwt4g0yhlVIA5ym73bcT
# p0aiBsBbz7iqOJ3yfXYnyxNA32g6ZFLiX9v2kBK2L4XFedQRoYIYETCCGA0GCisG
# AQQBgjcDAwExghf9MIIX+QYJKoZIhvcNAQcCoIIX6jCCF+YCAQMxDzANBglghkgB
# ZQMEAgEFADCCAWIGCyqGSIb3DQEJEAEEoIIBUQSCAU0wggFJAgEBBgorBgEEAYRZ
# CgMBMDEwDQYJYIZIAWUDBAIBBQAEIGRJedbHjS6JguXFPQHWOeo6zqx0/sDEcNL5
# J9sPoMUqAgZqqUsdWSUYEzIwMjYwOTIzMTE1NjE1LjA0M1owBIACAfSggeGkgd4w
# gdsxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdS
# ZWRtb25kMR4wHAYDVQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xJTAjBgNVBAsT
# HE1pY3Jvc29mdCBBbWVyaWNhIE9wZXJhdGlvbnMxJzAlBgNVBAsTHm5TaGllbGQg
# VFNTIEVTTjo3QTAwLTA1RTAtRDk0NzE1MDMGA1UEAxMsTWljcm9zb2Z0IFB1Ymxp
# YyBSU0EgVGltZSBTdGFtcGluZyBBdXRob3JpdHmggg8hMIIHgjCCBWqgAwIBAgIT
# MwAAAAXlzw//Zi7JhwAAAAAABTANBgkqhkiG9w0BAQwFADB3MQswCQYDVQQGEwJV
# UzEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMUgwRgYDVQQDEz9NaWNy
# b3NvZnQgSWRlbnRpdHkgVmVyaWZpY2F0aW9uIFJvb3QgQ2VydGlmaWNhdGUgQXV0
# aG9yaXR5IDIwMjAwHhcNMjAxMTE5MjAzMjMxWhcNMzUxMTE5MjA0MjMxWjBhMQsw
# CQYDVQQGEwJVUzEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMTIwMAYD
# VQQDEylNaWNyb3NvZnQgUHVibGljIFJTQSBUaW1lc3RhbXBpbmcgQ0EgMjAyMDCC
# AiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAJ5851Jj/eDFnwV9Y7UGIqMc
# HtfnlzPREwW9ZUZHd5HBXXBvf7KrQ5cMSqFSHGqg2/qJhYqOQxwuEQXG8kB41wsD
# JP5d0zmLYKAY8Zxv3lYkuLDsfMuIEqvGYOPURAH+Ybl4SJEESnt0MbPEoKdNihwM
# 5xGv0rGofJ1qOYSTNcc55EbBT7uq3wx3mXhtVmtcCEr5ZKTkKKE1CxZvNPWdGWJU
# PC6e4uRfWHIhZcgCsJ+sozf5EeH5KrlFnxpjKKTavwfFP6XaGZGWUG8TZaiTogRo
# AlqcevbiqioUz1Yt4FRK53P6ovnUfANjIgM9JDdJ4e0qiDRm5sOTiEQtBLGd9Vhd
# 1MadxoGcHrRCsS5rO9yhv2fjJHrmlQ0EIXmp4DhDBieKUGR+eZ4CNE3ctW4uvSDQ
# VeSp9h1SaPV8UWEfyTxgGjOsRpeexIveR1MPTVf7gt8hY64XNPO6iyUGsEgt8c2P
# xF87E+CO7A28TpjNq5eLiiunhKbq0XbjkNoU5JhtYUrlmAbpxRjb9tSreDdtACpm
# 3rkpxp7AQndnI0Shu/fk1/rE3oWsDqMX3jjv40e8KN5YsJBnczyWB4JyeeFMW3JB
# fdeAKhzohFe8U5w9WuvcP1E8cIxLoKSDzCCBOu0hWdjzKNu8Y5SwB1lt5dQhABYy
# zR3dxEO/T1K/BVF3rV69AgMBAAGjggIbMIICFzAOBgNVHQ8BAf8EBAMCAYYwEAYJ
# KwYBBAGCNxUBBAMCAQAwHQYDVR0OBBYEFGtpKDo1L0hjQM972K9J6T7ZPdshMFQG
# A1UdIARNMEswSQYEVR0gADBBMD8GCCsGAQUFBwIBFjNodHRwOi8vd3d3Lm1pY3Jv
# c29mdC5jb20vcGtpb3BzL0RvY3MvUmVwb3NpdG9yeS5odG0wEwYDVR0lBAwwCgYI
# KwYBBQUHAwgwGQYJKwYBBAGCNxQCBAweCgBTAHUAYgBDAEEwDwYDVR0TAQH/BAUw
# AwEB/zAfBgNVHSMEGDAWgBTIftJqhSobyhmYBAcnz1AQT2ioojCBhAYDVR0fBH0w
# ezB5oHegdYZzaHR0cDovL3d3dy5taWNyb3NvZnQuY29tL3BraW9wcy9jcmwvTWlj
# cm9zb2Z0JTIwSWRlbnRpdHklMjBWZXJpZmljYXRpb24lMjBSb290JTIwQ2VydGlm
# aWNhdGUlMjBBdXRob3JpdHklMjAyMDIwLmNybDCBlAYIKwYBBQUHAQEEgYcwgYQw
# gYEGCCsGAQUFBzAChnVodHRwOi8vd3d3Lm1pY3Jvc29mdC5jb20vcGtpb3BzL2Nl
# cnRzL01pY3Jvc29mdCUyMElkZW50aXR5JTIwVmVyaWZpY2F0aW9uJTIwUm9vdCUy
# MENlcnRpZmljYXRlJTIwQXV0aG9yaXR5JTIwMjAyMC5jcnQwDQYJKoZIhvcNAQEM
# BQADggIBAF+Idsd+bbVaFXXnTHho+k7h2ESZJRWluLE0Oa/pO+4ge/XEizXvhs0Y
# 7+KVYyb4nHlugBesnFqBGEdC2IWmtKMyS1OWIviwpnK3aL5JedwzbeBF7POyg6IG
# G/XhhJ3UqWeWTO+Czb1c2NP5zyEh89F72u9UIw+IfvM9lzDmc2O2END7MPnrcjWd
# QnrLn1Ntday7JSyrDvBdmgbNnCKNZPmhzoa8PccOiQljjTW6GePe5sGFuRHzdFt8
# y+bN2neF7Zu8hTO1I64XNGqst8S+w+RUdie8fXC1jKu3m9KGIqF4aldrYBamyh3g
# 4nJPj/LR2CBaLyD+2BuGZCVmoNR/dSpRCxlot0i79dKOChmoONqbMI8m04uLaEHA
# v4qwKHQ1vBzbV/nG89LDKbRSSvijmwJwxRxLLpMQ/u4xXxFfR4f/gksSkbJp7oqL
# wliDm/h+w0aJ/U5ccnYhYb7vPKNMN+SZDWycU5ODIRfyoGl59BsXR/HpRGtiJquO
# YGmvA/pk5vC1lcnbeMrcWD/26ozePQ/TWfNXKBOmkFpvPE8CH+EeGGWzqTCjdAsn
# o2jzTeNSxlx3glDGJgcdz5D/AAxw9Sdgq/+rY7jjgs7X6fqPTXPmaCAJKVHAP19o
# EjJIBwD1LyHbaEgBxFCogYSOiUIr0Xqcr1nJfiWG2GwYe6ZoAF1bMIIHlzCCBX+g
# AwIBAgITMwAAAFhlzes/odf80gAAAAAAWDANBgkqhkiG9w0BAQwFADBhMQswCQYD
# VQQGEwJVUzEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMTIwMAYDVQQD
# EylNaWNyb3NvZnQgUHVibGljIFJTQSBUaW1lc3RhbXBpbmcgQ0EgMjAyMDAeFw0y
# NTEwMjMyMDQ2NTVaFw0yNjEwMjIyMDQ2NTVaMIHbMQswCQYDVQQGEwJVUzETMBEG
# A1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9uZDEeMBwGA1UEChMVTWlj
# cm9zb2Z0IENvcnBvcmF0aW9uMSUwIwYDVQQLExxNaWNyb3NvZnQgQW1lcmljYSBP
# cGVyYXRpb25zMScwJQYDVQQLEx5uU2hpZWxkIFRTUyBFU046N0EwMC0wNUUwLUQ5
# NDcxNTAzBgNVBAMTLE1pY3Jvc29mdCBQdWJsaWMgUlNBIFRpbWUgU3RhbXBpbmcg
# QXV0aG9yaXR5MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAnXg0pHaQ
# 7PVAlln+HZZrJFcLoKbekhW1yL+QNBUgFFUsjZIKaqqN4oIJsJM3ps0rJNSO7ndC
# NRuZDX2Wgur3Ak77eXrloBXqZmO6ZVXeDNRCLldW4A0/NfjzJ7XXkdEhjr81ghXE
# pR7zC+wbaNN+sPSxzLAZBeibDFP7Xws5wX0ZtIsN1a2+Xq5bvWp3kRMytwskTjun
# RgeLZL/tBp237JVdRPFAQ9jYRKpCqUBo/v1xjBLRCV3PalKjnGfb3MN4U7jVyqif
# FHShcnW5CERRoBmUa6sygDzFSr8e3g93TPNLFUivUE0GmLfbX5ceD1Gt1FcZ6x/J
# LVATzk5+BWHbMxwJIVkVPTqSSMjQ6KTKdcnq3pH0c4AFJp/glvcpq0U9fzZIjJGG
# vdpishlRl77RQtUhSjxHvCn3LC/xqQQwOHSQDsGh6NX2D0RfsSyEtTAByAae+2w1
# HByTDTcmlTNLEuQLeCj1gNBdIWj0WOYyDtjjQ/8iTWY6ey1vb9qHljIj5HgIndT5
# P9MYk2Vg2e7hKUZNBNbA/hsgBsuoZ+IX89WvjEN9abF91S4OJVuinmKsLO/MLbnl
# 7ikuD0dN6oA0YewyDQncs12sM9HOtu72QA/TZlefvW8r9xtMXAYoQlcGjsk8W4Uc
# 7cfqVqbIPjdoc8ZxBzLcXcVyP4p5cyLwvkMCAwEAAaOCAcswggHHMB0GA1UdDgQW
# BBRyjU3Fer4VxXJ+hjPcRJnxnRIJsDAfBgNVHSMEGDAWgBRraSg6NS9IY0DPe9iv
# Sek+2T3bITBsBgNVHR8EZTBjMGGgX6BdhltodHRwOi8vd3d3Lm1pY3Jvc29mdC5j
# b20vcGtpb3BzL2NybC9NaWNyb3NvZnQlMjBQdWJsaWMlMjBSU0ElMjBUaW1lc3Rh
# bXBpbmclMjBDQSUyMDIwMjAuY3JsMHkGCCsGAQUFBwEBBG0wazBpBggrBgEFBQcw
# AoZdaHR0cDovL3d3dy5taWNyb3NvZnQuY29tL3BraW9wcy9jZXJ0cy9NaWNyb3Nv
# ZnQlMjBQdWJsaWMlMjBSU0ElMjBUaW1lc3RhbXBpbmclMjBDQSUyMDIwMjAuY3J0
# MAwGA1UdEwEB/wQCMAAwFgYDVR0lAQH/BAwwCgYIKwYBBQUHAwgwDgYDVR0PAQH/
# BAQDAgeAMGYGA1UdIARfMF0wUQYMKwYBBAGCN0yDfQEBMEEwPwYIKwYBBQUHAgEW
# M2h0dHA6Ly93d3cubWljcm9zb2Z0LmNvbS9wa2lvcHMvRG9jcy9SZXBvc2l0b3J5
# Lmh0bTAIBgZngQwBBAIwDQYJKoZIhvcNAQEMBQADggIBAHvrxIiVF1iHcXvxrJTC
# D8eOtbPUbK9x+Lz70iYehh+G0UoOMcMf04QD6tQPTeZ5HhGETkcn0raDJ5NpfbRB
# uKEH31rxbZK97o12KRDNJ3Nu4ePaUIpH/TcWz8PLVOCECywSxbEgEG20kyydGc46
# c591tXzpfkJDckjoYrypaerdeQLRQH9LaoTYZfdAzMo+Dy0O1DzFJkF5YnsmAM8l
# t9r1NtXdFjdbFMCbV5dau64mV22s186A8Umi+l239+Ue0cbJQIykWhIlhhWhxQgo
# ksqHz7kp2GFZAAeySTmIOQOWyXOA8JA8TISJyn3JDOgStv583P3V0QSALT6JXDCW
# 26FV208VGJMzkv0S22iOTZJ/oamTpk8RzD8oWT8pfbe1q/k/bxPiXYRbzps96a5Y
# Oko7n0Vdo61DOJhL/mhk01Y348gq6vhG/VTcdGHh1rCkwOM05B35AZZq9AtPpfRz
# JinrHzzGRx+r6fD3ccYMPMMX/Nwd2irzrph172fQcSf1fMwvwIhmfH4GWJJ+mf1H
# A6uXoAOVByckguXvlj8gPi7T2ES6RU8+QssfqTNTJKjsBheWKWv2W4ESVen2L7lC
# z7i79FhA+0kp0yXJnYwdzWS0ovTINULINmzVyMcSUm5WuVf8YZ33cAud2Opr6N1+
# RuLZDavDvjiehlI5dH+GEy56MYIHQzCCBz8CAQEweDBhMQswCQYDVQQGEwJVUzEe
# MBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMTIwMAYDVQQDEylNaWNyb3Nv
# ZnQgUHVibGljIFJTQSBUaW1lc3RhbXBpbmcgQ0EgMjAyMAITMwAAAFhlzes/odf8
# 0gAAAAAAWDANBglghkgBZQMEAgEFAKCCBJwwEQYLKoZIhvcNAQkQAg8xAgUAMBoG
# CSqGSIb3DQEJAzENBgsqhkiG9w0BCRABBDAcBgkqhkiG9w0BCQUxDxcNMjYwOTIz
# MTE1NjE1WjAvBgkqhkiG9w0BCQQxIgQgdrMvn3xEvUguOuPM37BH0z8sISYyORUV
# DMhOutG9pp8wgbkGCyqGSIb3DQEJEAIvMYGpMIGmMIGjMIGgBCDFIlS7sgfQ+wAo
# 1cWbWz+WN69VBds58hbran919aLocTB8MGWkYzBhMQswCQYDVQQGEwJVUzEeMBwG
# A1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMTIwMAYDVQQDEylNaWNyb3NvZnQg
# UHVibGljIFJTQSBUaW1lc3RhbXBpbmcgQ0EgMjAyMAITMwAAAFhlzes/odf80gAA
# AAAAWDCCA14GCyqGSIb3DQEJEAISMYIDTTCCA0mhggNFMIIDQTCCAikCAQEwggEJ
# oYHhpIHeMIHbMQswCQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4G
# A1UEBxMHUmVkbW9uZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMSUw
# IwYDVQQLExxNaWNyb3NvZnQgQW1lcmljYSBPcGVyYXRpb25zMScwJQYDVQQLEx5u
# U2hpZWxkIFRTUyBFU046N0EwMC0wNUUwLUQ5NDcxNTAzBgNVBAMTLE1pY3Jvc29m
# dCBQdWJsaWMgUlNBIFRpbWUgU3RhbXBpbmcgQXV0aG9yaXR5oiMKAQEwBwYFKw4D
# AhoDFQCdZHkb26ercF2O62vCdZUfUSvEXKBnMGWkYzBhMQswCQYDVQQGEwJVUzEe
# MBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMTIwMAYDVQQDEylNaWNyb3Nv
# ZnQgUHVibGljIFJTQSBUaW1lc3RhbXBpbmcgQ0EgMjAyMDANBgkqhkiG9w0BAQsF
# AAIFAO5drNAwIhgPMjAyNjA5MjMwMTQxMzZaGA8yMDI2MDkyNDAxNDEzNlowdDA6
# BgorBgEEAYRZCgQBMSwwKjAKAgUA7l2s0AIBADAHAgEAAgIsSzAHAgEAAgITijAK
# AgUA7l7+UAIBADA2BgorBgEEAYRZCgQCMSgwJjAMBgorBgEEAYRZCgMCoAowCAIB
# AAIDB6EgoQowCAIBAAIDAYagMA0GCSqGSIb3DQEBCwUAA4IBAQA5JfreGLDIV0pk
# CdfSHL8vX3HYZuK4TExrDxcnEUaZoPS0sTyFtoTxsjY4mpayMq59tyAUeb1ILEtR
# qaEW6NHMbDZjmYx5WK8Y6gGi45z275Z1V0LgXTRyl5vCC76EIX1JYkLbiO5fJ7Do
# k2RXZj5k0jPz3keuIjBjA65Ht+DaxWXKCw9MrqfK8UpDKe8rdL+vIHmmVhFnyHAo
# 3pkCDa1irGIELHwn+hZFpB9tdzslGURAqug1KYLZaZo0KAdNpdDmPFxSeJCssvh/
# /2cwJqcN8xxQQ4zpv+pOIbtlgGVu+RiTWrWe/m+gM0a3yxsLvQWWFMsSqxWZ+aw7
# hbWHqR48MA0GCSqGSIb3DQEBAQUABIICACEUP1AlOArkJWeQn85l3nrBeTRucQHP
# 6tlJZb+hi1clvRE61BN7UNOqErNj13MPp/wD57lKdFywfLbKAMSrOmBzyhvMOblI
# hN2YxTWEbbhrsDwvZRWfy4RVAUqAyWBvOSHyJr5oIb1UFOa6COjdaZDTb0NPcrci
# zVddFGxqDjUJhc4SszADu+MClji3ztSAqmdiS2gAqedSxoHcj3+pBh4PPl5pbjFk
# QjXV85W476s/fABjYwuhyBXFNsWtpA1+S0rHCE/jozN8nmgrhAiuRKjOmghiDxUC
# LR/ENnPs+B2keQcXQ1Z4/vMd0NdewM4dJmCSD+KFa3HToqETKB91WWPUi5Wi8i1V
# CGf9N+MtQr+vjjGF5GwsnrNHliG4DO8iWJ7hkHhWLD2DM9bx02FLAEKp4Y8LNhqQ
# CvutiiRkQ49WIjObn4fVfqRXKEF7aRJ9L4TEM//1528tIZvmlgZdwosKuX6PjFCk
# 4TEykOyaNL5B7aA/pKPyZOxZVTJvT5XmGYGgBz0GvA1+HwbFD713X3wYinUv0pEu
# fwU+DTJ3x2Gq94BjezC3f8nSPk/4AIDkiOkAW9YoPZ6TOUn2Mkzg9k79dZgHLgjv
# 3C2tD83i9oeo8JBEbhUMC5hc3kKzt1MLTyTx+ivnxo7eDpYCaB6e1Lf0LHjqfx7r
# dfq9xDgI0Syi
# SIG # End signature block