Public/Invoke-NsAudit.ps1

function Invoke-NsAudit {
    <#
    .SYNOPSIS
        Executes a conditional access posture assessment.
    .DESCRIPTION
        Collects tenant data from Microsoft Graph, resolves directory membership,
        discovers all Test-Ns* functions in the module, runs each independently,
        and produces an executive HTML report with CSV/JSON exports.
        Requires an active session: run Connect-NsSession first.
    .PARAMETER OutputDirectory
        Output directory. Defaults to NCS in user temp directory. Purged on each run.
    .PARAMETER ConfigPath
        Path to custom ns-config.json for threshold overrides.
    .PARAMETER SkipUserCollection
        Skip user sign-in activity, risky users, and sign-in bypass collection.
    .EXAMPLE
        Connect-NsSession -TenantId 'contoso.onmicrosoft.com'
        Invoke-NsAudit
    .EXAMPLE
        Invoke-NsAudit -ConfigPath './my-config.json'
    #>

    [CmdletBinding()]
    param(
        [ValidateScript({
            $r = $ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($_)
            if ($r -match '\.\.[/\\]') { throw 'Path traversal not allowed.' }; $true
        })]
        [string]$OutputDirectory,

        [string]$ConfigPath,
        [switch]$SkipUserCollection
    )

    $passVerbose = ($VerbosePreference -eq 'Continue')

    # Session check: must authenticate before running
    if (-not $script:_NsSession -or -not $script:_NsTenantId) {
        Write-Warning "No active session. Run Connect-NsSession first to authenticate.`n`n Example:`n Connect-NsSession -TenantId 'contoso.onmicrosoft.com'`n Invoke-NsAudit`n"
        return
    }
    $TenantId = $script:_NsTenantId
    $session  = $script:_NsSession
    $config   = Get-NsConfig -Path $ConfigPath

    # Pre-flight: verify the signed-in user has sufficient directory roles
    Write-Information "`n NavySeal Posture Assessment" -InformationAction Continue
    Write-Information " Tenant: $TenantId" -InformationAction Continue
    Write-Information ' Checking permissions...' -InformationAction Continue

    $allowedRoleTemplates = $config['auditRoleTemplates'] ?? @{
        '62e90394-69f5-4237-9190-012177145e10' = 'Global Administrator'
        'f2ef992c-3afb-46b9-b7cf-a126ee74c451' = 'Global Reader'
        '194ae4cb-b126-40b2-bd5b-6091b380977d' = 'Security Administrator'
        '5d6b6bb7-de71-4623-b4af-96380a352509' = 'Security Reader'
        'b1be1c3e-b65d-4f19-8427-f6fa0d97feb9' = 'Conditional Access Administrator'
    }

    try {
        $myRoles = $session.GetAll("/me/transitiveMemberOf/microsoft.graph.directoryRole?`$select=displayName,roleTemplateId")
        $roleNames = @($myRoles | ForEach-Object { $_.displayName } | Where-Object { $_ } | Sort-Object -Unique)
        $hasRequired = $myRoles | Where-Object { $_.roleTemplateId -in $allowedRoleTemplates.Keys }

        if (-not $hasRequired) {
            $yourRoles = if ($roleNames.Count -gt 0) { $roleNames -join ', ' } else { '(none)' }
            $needed = ($allowedRoleTemplates.Values | Sort-Object) -join "`n "
            Write-Warning "Insufficient privileges to run the assessment.`n`n Your current roles:`n $yourRoles`n`n At least one of the following is required:`n $needed`n`n Ask a Global Administrator to assign the Security Reader role for read-only access.`n"
            return
        }
    } catch {
        $msg = $_.Exception.Message
        if ($msg -match '401|Unauthorized') {
            Write-Warning "Session has expired. Run Connect-NsSession to re-authenticate."
            return
        }
        Write-Verbose "Role check: $msg (continuing with licence check)"
    }

    # Pre-flight: verify delegated Graph scopes were consented
    Write-Information ' Checking Graph scopes...' -InformationAction Continue
    try {
        $granted = $session.GetGrantedScopes()
        $required = [GraphSession]::RequiredScopes
        $missing = @($required | Where-Object { $_ -notin $granted })
        if ($missing.Count -gt 0) {
            $grantedList = if ($granted.Count -gt 0) { $granted -join ', ' } else { '(none)' }
            $missingList = $missing -join "`n "
            Write-Warning "The following Graph scopes were not consented:`n`n $missingList`n`n Granted scopes:`n $grantedList`n`n An administrator may need to grant consent for the NavySeal application.`n Run Connect-NsSession again after consent has been granted.`n"
            return
        }
    } catch {
        Write-Verbose "Scope check: $($_.Exception.Message) (continuing)"
    }

    # NCS working directory
    $ncsRoot = Join-Path ([System.IO.Path]::GetTempPath()) 'NCS'
    $usingDefaultPath = -not $OutputDirectory
    if ($usingDefaultPath) { $OutputDirectory = $ncsRoot }

    if ($usingDefaultPath -and (Test-Path $OutputDirectory)) {
        Remove-Item -Path $OutputDirectory -Recurse -Force -ErrorAction SilentlyContinue
    }
    $null = New-Item -ItemType Directory -Path $OutputDirectory -Force -ErrorAction Stop
    $OutputDirectory = (Resolve-Path $OutputDirectory).Path

    # Licence check
    Write-Information ' Validating licence...' -InformationAction Continue
    try {
        $null = $session.Get('/identity/conditionalAccess/policies?$top=1')
    } catch {
        $msg = $_.Exception.Message
        if ($msg -match 'Forbidden|403|license|subscription|SKU|Premium') {
            throw "Entra ID P1 or higher is required. Conditional Access policies are not accessible in this tenant. Verify the tenant has an active Entra ID P1, P2, EMS E3/E5, or Microsoft 365 E3/E5 subscription."
        }
        if ($msg -match 'Unauthorized|401') {
            Write-Warning "Session has expired. Run Connect-NsSession to re-authenticate."
            return
        }
        throw "Pre-flight check failed: $msg"
    }

    $p2Available = $true
    try {
        $null = $session.Get('/identityProtection/riskyUsers?$top=1')
    } catch {
        $p2Available = $false
        Write-Warning "Entra ID P2 not detected. Identity Protection and PIM data will be unavailable."
    }
    Write-Information " Licence: $(if ($p2Available) { 'P2 (full coverage)' } else { 'P1 (Identity Protection unavailable)' })`n" -InformationAction Continue

    $snap = [TenantSnapshot]::new()
    $snap.TenantId       = $TenantId
    $snap.CollectedAtUtc = [datetime]::UtcNow

    $totalSteps = if ($SkipUserCollection) { 12 } else { 17 }
    $step = 0

    $step++; Write-Information " [$step/$totalSteps] Security defaults" -InformationAction Continue
    try   { $snap.SecurityDefaults = $session.Get('/policies/identitySecurityDefaultsEnforcementPolicy') }
    catch { Write-Warning "Security defaults: $($_.Exception.Message)"; $snap.SecurityDefaults = [PSCustomObject]@{ isEnabled = $false } }

    $step++; Write-Information " [$step/$totalSteps] Conditional Access policies" -InformationAction Continue
    $snap.Policies = $session.GetAll('/identity/conditionalAccess/policies')

    $step++; Write-Information " [$step/$totalSteps] Named locations" -InformationAction Continue
    try { $snap.NamedLocations = $session.GetAll('/identity/conditionalAccess/namedLocations') } catch { Write-Warning "Named locations: $($_.Exception.Message)" }

    $step++; Write-Information " [$step/$totalSteps] Authentication strength policies" -InformationAction Continue
    try { $snap.AuthStrengths = $session.GetAll('/policies/authenticationStrengthPolicies') } catch { Write-Warning "Auth strengths: $($_.Exception.Message)" }

    $step++; Write-Information " [$step/$totalSteps] Authentication methods policy" -InformationAction Continue
    try { $snap.AuthMethodsPolicy = $session.Get('/policies/authenticationMethodsPolicy') } catch { Write-Warning "Auth methods: $($_.Exception.Message)"; $snap.AuthMethodsPolicy = [PSCustomObject]@{} }

    $step++; Write-Information " [$step/$totalSteps] Auth context class references" -InformationAction Continue
    try { $snap.AuthContexts = $session.GetAll('/identity/conditionalAccess/authenticationContextClassReferences') } catch { Write-Verbose "Auth contexts: $($_.Exception.Message)" }

    $step++; Write-Information " [$step/$totalSteps] Directory roles" -InformationAction Continue
    try { $snap.DirectoryRoles = $session.GetAll('/directoryRoles') } catch { Write-Warning "Directory roles: $($_.Exception.Message)" }

    $step++; Write-Information " [$step/$totalSteps] Role templates" -InformationAction Continue
    try { $snap.RoleTemplates = $session.GetAll('/directoryRoleTemplates?$select=id,displayName,description') } catch { Write-Warning "Role templates: $($_.Exception.Message)" }

    $step++; Write-Information " [$step/$totalSteps] Service principals" -InformationAction Continue
    try { $snap.ServicePrincipals = $session.GetAll('/servicePrincipals?$select=id,appId,displayName,appRoleAssignmentRequired,servicePrincipalType,preferredSingleSignOnMode,accountEnabled&$top=999') } catch { Write-Warning "Service principals: $($_.Exception.Message)" }

    $step++; Write-Information " [$step/$totalSteps] Groups" -InformationAction Continue
    try { $snap.Groups = $session.GetAll('/groups?$select=id,displayName&$top=999') } catch { Write-Warning "Groups: $($_.Exception.Message)" }

    $step++; Write-Information " [$step/$totalSteps] User registration details" -InformationAction Continue
    try { $snap.UserRegistration = $session.GetAll('/reports/authenticationMethods/userRegistrationDetails') } catch { Write-Warning "User registration: $($_.Exception.Message)" }

    if (-not $SkipUserCollection) {
        $step++; Write-Information " [$step/$totalSteps] Users with sign-in activity (streaming)" -InformationAction Continue
        $summary = [UserActivitySummary]::new()
        try {
            $session.GetAllPaged('/users?$select=id,displayName,userPrincipalName,accountEnabled,userType,signInActivity&$top=500',
                { param($page) $summary.ProcessPage($page) })
        } catch { Write-Warning "Users: $($_.Exception.Message)" }
        $snap.UserSummary = $summary

        $step++; Write-Information " [$step/$totalSteps] Risky users" -InformationAction Continue
        try { $snap.RiskyUsers = $session.GetAll("/identityProtection/riskyUsers?`$filter=riskLevel ne 'none'&`$select=id,userPrincipalName,userDisplayName,riskLevel,riskState,riskLastUpdatedDateTime&`$top=500") }
        catch { Write-Verbose "Risky users: $($_.Exception.Message)" }

        $step++; Write-Information " [$step/$totalSteps] Sign-in logs (7-day CA bypass)" -InformationAction Continue
        try {
            $since = [datetime]::UtcNow.AddDays(-($config['signInBypassDays'] ?? 7)).ToString('yyyy-MM-ddTHH:mm:ssZ')
            $snap.SignInsBypassed = $session.GetAll("/auditLogs/signIns?`$filter=conditionalAccessStatus eq 'notApplied' and createdDateTime ge $since&`$select=userPrincipalName,userType,appDisplayName,resourceDisplayName,clientAppUsed,deviceDetail,conditionalAccessStatus,createdDateTime&`$top=500")
        } catch { Write-Verbose "Sign-in logs: $($_.Exception.Message)" }

        $step++; Write-Information " [$step/$totalSteps] PIM eligible role assignments" -InformationAction Continue
        try {
            $snap.PimEligibleAssignments = $session.GetAll('/roleManagement/directory/roleEligibilityScheduleInstances?$select=principalId,roleDefinitionId,directoryScopeId,startDateTime,endDateTime&$top=999')
        } catch { Write-Verbose "PIM eligibility: $($_.Exception.Message) (requires P2 licence)" }

        $step++; Write-Information " [$step/$totalSteps] PIM active role schedules" -InformationAction Continue
        try {
            $snap.PimActiveSchedules = $session.GetAll('/roleManagement/directory/roleAssignmentScheduleInstances?$select=principalId,roleDefinitionId,assignmentType,startDateTime,endDateTime&$top=999')
        } catch { Write-Verbose "PIM active schedules: $($_.Exception.Message) (requires P2 licence)" }
    }

    Write-Information ' Resolving GUIDs...' -InformationAction Continue
    Build-NsObjectCache -Snapshot $snap -Session $session -Verbose:$passVerbose

    $step++; Write-Information " [$step/$totalSteps] Resolving group and role membership" -InformationAction Continue
    try { Build-NsPolicyMembershipMap -Snapshot $snap -Session $session -Verbose:$passVerbose }
    catch { Write-Warning "Membership resolution: $($_.Exception.Message)" }

    # Analysis context
    $ctx = [NsContext]::Build($snap, $config)

    # Test discovery
    Write-Information ' Running analysis engine...' -InformationAction Continue
    $allFindings = [System.Collections.ArrayList]::new()
    $disabledTests = $config['disabledTests'] ?? @()
    $testFunctions = Get-Command -Module NavySeal -Name 'Test-Ns*' -ErrorAction SilentlyContinue

    if ($testFunctions) {
        foreach ($testFn in $testFunctions) {
            if ($testFn.Name -in $disabledTests) { Write-Verbose "Skipping disabled test: $($testFn.Name)"; continue }
            Write-Verbose "Running $($testFn.Name)"
            try {
                $results = & $testFn.Name -Context $ctx -Verbose:$passVerbose
                if ($results) { $allFindings.AddRange(@($results)) }
            }
            catch { Write-Warning "$($testFn.Name) failed: $($_.Exception.Message)" }
        }
    }

    $findings = @($allFindings | Sort-Object { switch ($_.Severity) { 'Critical'{0} 'High'{1} 'Medium'{2} 'Low'{3} 'Info'{4} } })

    Write-Information ' Generating report...' -InformationAction Continue
    $htmlContent = New-NsHtmlReport -Snapshot $snap -Findings $findings -Config $config

    $reportPath   = Join-Path $OutputDirectory 'report.html'
    $jsonPath     = Join-Path $OutputDirectory 'snapshot.json'
    $findingsPath = Join-Path $OutputDirectory 'findings.json'
    $csvPath      = Join-Path $OutputDirectory 'findings.csv'

    $htmlContent | Set-Content -Path $reportPath -Encoding utf8 -ErrorAction Stop

    $jsonSnap = [ordered]@{
        TenantId = $snap.TenantId; CollectedAtUtc = $snap.CollectedAtUtc
        Policies = $snap.Policies; NamedLocations = $snap.NamedLocations; AuthStrengths = $snap.AuthStrengths
        UserRegistration = $snap.UserRegistration; RiskyUsers = $snap.RiskyUsers; UserSummary = $snap.UserSummary
        ObjectCache = $snap.ObjectCache
        PimEligibleAssignments = $snap.PimEligibleAssignments
        UserContextStats = [ordered]@{
            TotalUsersEvaluated = $snap.UserContextMap.Count
            AdminCount = @($snap.UserContextMap.Values | Where-Object IsAdmin).Count
            GuestCount = @($snap.UserContextMap.Values | Where-Object IsGuest).Count
            PimEligibleCount = @($snap.UserContextMap.Values | Where-Object IsPimEligible).Count
        }
        SignInBypassCount = if ($snap.SignInsBypassed) { $snap.SignInsBypassed.Count } else { 0 }
    }
    $jsonSnap | ConvertTo-Json -Depth 15 | Set-Content -Path $jsonPath -Encoding utf8 -ErrorAction Stop
    $findings | ConvertTo-Json -Depth 10 | Set-Content -Path $findingsPath -Encoding utf8 -ErrorAction Stop
    $findings | Select-Object Severity, Category, Title, Description, PolicyReference, Recommendation, TestName,
        @{N='Dimensions';E={ $_.Dimensions -join ' | ' }} |
        Export-Csv -Path $csvPath -NoTypeInformation -Encoding utf8

    # Modeller
    $modellerContent = New-NsModellerHtml -Snapshot $snap -Config $config
    $modellerPath = Join-Path $OutputDirectory 'modeller.html'
    $modellerContent | Set-Content -Path $modellerPath -Encoding utf8 -ErrorAction Stop

    # Score
    $actionable = @($findings | Where-Object { $_.Severity -ne 'Info' })
    $w = $config['scoringWeights'] ?? @{ criticalPerFinding=10; criticalCap=30; highPerFinding=5; highCap=25; mediumPerFinding=2; mediumCap=15; lowPerFinding=1; lowCap=5 }
    $fc = @($actionable | Where-Object Severity -eq 'Critical').Count
    $fh = @($actionable | Where-Object Severity -eq 'High').Count
    $fm = @($actionable | Where-Object Severity -eq 'Medium').Count
    $fl = @($actionable | Where-Object Severity -eq 'Low').Count
    $fi = @($findings | Where-Object Severity -eq 'Info').Count
    $finalScore = 100 - [math]::Min($w.criticalCap, $fc * $w.criticalPerFinding) -
        [math]::Min($w.highCap, $fh * $w.highPerFinding) -
        [math]::Min($w.mediumCap, $fm * $w.mediumPerFinding) -
        [math]::Min($w.lowCap, $fl * $w.lowPerFinding)
    $finalScore = [math]::Max(0, $finalScore)

    Write-Information '' -InformationAction Continue
    Write-Information " Score: $finalScore / 100" -InformationAction Continue
    Write-Information " Findings: $($actionable.Count) actionable, $fi informational" -InformationAction Continue
    Write-Information " Tests: $($testFunctions.Count) executed" -InformationAction Continue
    Write-Information " Report: $reportPath" -InformationAction Continue
    Write-Information " Modeller: $(Join-Path $OutputDirectory 'modeller.html')" -InformationAction Continue
    Write-Information '' -InformationAction Continue

    Write-Warning "Output files contain sensitive tenant data. Treat $OutputDirectory as confidential."
    try {
        if ($IsMacOS) {
            & '/usr/bin/open' $reportPath
        } elseif ($IsLinux) {
            & 'xdg-open' $reportPath
        } else {
            Start-Process -FilePath $reportPath
        }
    } catch {
        Write-Information " Open the report manually: $reportPath" -InformationAction Continue
    }

    [PSCustomObject]@{
        TenantId  = $TenantId; Score = $finalScore; Findings = $findings; Snapshot = $snap
        ReportPath = $reportPath; JsonPath = $jsonPath; FindingsPath = $findingsPath; CsvPath = $csvPath
        ModellerPath = (Join-Path $OutputDirectory 'modeller.html')
    }
}

# SIG # Begin signature block
# MII9GgYJKoZIhvcNAQcCoII9CzCCPQcCAQExDzANBglghkgBZQMEAgEFADB5Bgor
# BgEEAYI3AgEEoGswaTA0BgorBgEEAYI3AgEeMCYCAwEAAAQQH8w7YFlLCE63JNLG
# KX7zUQIBAAIBAAIBAAIBAAIBADAxMA0GCWCGSAFlAwQCAQUABCChQTkHHYJkHNjt
# d7Pwo3VyCWLaRQhYOB7xJoRsv0EBOaCCIdwwggXMMIIDtKADAgECAhBUmNLR1FsZ
# 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
# 03u4aUoqlmZpxJTG9F9urJh4iIAGXKKy7aIwggabMIIEg6ADAgECAhMzAAGSX9Z/
# ePB9sQgIAAAAAZJfMA0GCSqGSIb3DQEBDAUAMFoxCzAJBgNVBAYTAlVTMR4wHAYD
# VQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xKzApBgNVBAMTIk1pY3Jvc29mdCBJ
# RCBWZXJpZmllZCBDUyBFT0MgQ0EgMDQwHhcNMjYwNjAxMTc1MjU4WhcNMjYwNjA0
# MTc1MjU4WjBfMQswCQYDVQQGEwJDQTEQMA4GA1UECBMHQWxiZXJ0YTEQMA4GA1UE
# BxMHQ2FsZ2FyeTEVMBMGA1UEChMMRGFycmVuIE1heWVzMRUwEwYDVQQDEwxEYXJy
# ZW4gTWF5ZXMwggGiMA0GCSqGSIb3DQEBAQUAA4IBjwAwggGKAoIBgQC6vpd+d66I
# l6cpo6XDaTIvujkV3rekVoeig10+dG/OTYmX57PD3Rum9xsPx2BdX8lzvGnQq7Pa
# v6KacGC8N9f5XmVTJhc8k341QPXbSVsj61bYPVcV3ZnEr5zX2ciTGqXOgN/woD1A
# QccrGB8mCfWn9sNyVRTzNtoJz3/BrZl2Au+4nK2clIPX1a1k/6r2wTeFiBFAh7fp
# GZUHRNl0rcAzogwi5qYykxCDz7Wzu73tuUfhxcbn2XzoqfqKd83VSIN+osxnOmrS
# 0vMT5gnJC4B8RAGoGIqOle4wexQOn1Zrx8B2l1ZaIyLWf8bhcugcvTDT6o/oC1VV
# CVQqymqGTAhyIfIMSV31wMQDmEyXpa9SQFV3A4rUL+ILNDTGcca8GFZ6a1kqRe83
# xM/LTqupi6OSQ8ruxEHzJsW3No7J4rsNRljjSf7MGXFrKQjPBVFnjN2tHOPShdYB
# Z60NS6q6pVj+xq5FBVGHzV8XtKdV0e3jigsEyXkEl0jcQ8/K2LIxphMCAwEAAaOC
# AdMwggHPMAwGA1UdEwEB/wQCMAAwDgYDVR0PAQH/BAQDAgeAMDoGA1UdJQQzMDEG
# CisGAQQBgjdhAQAGCCsGAQUFBwMDBhkrBgEEAYI3YYuPpXGB3qaBQNv/tAST5rkV
# MB0GA1UdDgQWBBSvmzOJzfqlOfze0TuSX3fnqAlzZDAfBgNVHSMEGDAWgBSa8VR3
# dQyHFjdGoKzeefn0f8F46TBnBgNVHR8EYDBeMFygWqBYhlZodHRwOi8vd3d3Lm1p
# Y3Jvc29mdC5jb20vcGtpb3BzL2NybC9NaWNyb3NvZnQlMjBJRCUyMFZlcmlmaWVk
# JTIwQ1MlMjBFT0MlMjBDQSUyMDA0LmNybDB0BggrBgEFBQcBAQRoMGYwZAYIKwYB
# BQUHMAKGWGh0dHA6Ly93d3cubWljcm9zb2Z0LmNvbS9wa2lvcHMvY2VydHMvTWlj
# cm9zb2Z0JTIwSUQlMjBWZXJpZmllZCUyMENTJTIwRU9DJTIwQ0ElMjAwNC5jcnQw
# VAYDVR0gBE0wSzBJBgRVHSAAMEEwPwYIKwYBBQUHAgEWM2h0dHA6Ly93d3cubWlj
# cm9zb2Z0LmNvbS9wa2lvcHMvRG9jcy9SZXBvc2l0b3J5Lmh0bTANBgkqhkiG9w0B
# AQwFAAOCAgEABRiO07jmU6SjeUNkagy4Me5BFFY3b/5L1BRn/Gf9C8kXZjlIyzMH
# 7FcbslPw6ySkN3AIikz4rDwk8QQ+fc/dp+/ru35kqbbXm/bcK0AVjQ3ZOy8kRAjG
# qmFJff56lydGk3ybw1KCBHYgSs9KXVxC45348w4T9pjSViDcGko8g4Z+m19GW7ov
# 6srqiP72u5zVIwIHuxP/g08zaf2wynKz9duWzmZS8LftUawJI8il/5pLFjNBlCeJ
# q4MWNfI4N4d1a2VCEhs12HLqax/C/PyQP3qRUI7PB5IfKYltajewMbYVw+rQDE4f
# ugNEu14zUYPislGt36hd/Tk1Dn8uIT6P+9RyMyIX19bH9uTghE132/HEwuVNL34R
# kxJYMIG+ESF6fs+G9RDkWyGAi1FlLWl6ptszZ8ThL22/Sc11b6FlR8s+pCnjSQ6T
# KWnmWGEwoG43uqFXfLcchz2m8AEE3xvj+XpwkujUSrayTGy5E/olv946WtyEq4po
# NlZsND6CbrWT6VNd4VvmrRbYZUThdX3wjrpBssSRY3a7T9ra9KyYFFeAFulbvdaq
# o1DgPBVAWgbskiHEdkSrySbbhTHmCWltbGzlPU3kqTwSrjw0CUOfry9Ve7iYtitt
# 6LVu6DqEOY/3TBfLnubeZyjd1LpkIQWPU4u9AA4d9L2SUKY5Ziyo+18wggabMIIE
# g6ADAgECAhMzAAGSX9Z/ePB9sQgIAAAAAZJfMA0GCSqGSIb3DQEBDAUAMFoxCzAJ
# BgNVBAYTAlVTMR4wHAYDVQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xKzApBgNV
# BAMTIk1pY3Jvc29mdCBJRCBWZXJpZmllZCBDUyBFT0MgQ0EgMDQwHhcNMjYwNjAx
# MTc1MjU4WhcNMjYwNjA0MTc1MjU4WjBfMQswCQYDVQQGEwJDQTEQMA4GA1UECBMH
# QWxiZXJ0YTEQMA4GA1UEBxMHQ2FsZ2FyeTEVMBMGA1UEChMMRGFycmVuIE1heWVz
# MRUwEwYDVQQDEwxEYXJyZW4gTWF5ZXMwggGiMA0GCSqGSIb3DQEBAQUAA4IBjwAw
# ggGKAoIBgQC6vpd+d66Il6cpo6XDaTIvujkV3rekVoeig10+dG/OTYmX57PD3Rum
# 9xsPx2BdX8lzvGnQq7Pav6KacGC8N9f5XmVTJhc8k341QPXbSVsj61bYPVcV3ZnE
# r5zX2ciTGqXOgN/woD1AQccrGB8mCfWn9sNyVRTzNtoJz3/BrZl2Au+4nK2clIPX
# 1a1k/6r2wTeFiBFAh7fpGZUHRNl0rcAzogwi5qYykxCDz7Wzu73tuUfhxcbn2Xzo
# qfqKd83VSIN+osxnOmrS0vMT5gnJC4B8RAGoGIqOle4wexQOn1Zrx8B2l1ZaIyLW
# f8bhcugcvTDT6o/oC1VVCVQqymqGTAhyIfIMSV31wMQDmEyXpa9SQFV3A4rUL+IL
# NDTGcca8GFZ6a1kqRe83xM/LTqupi6OSQ8ruxEHzJsW3No7J4rsNRljjSf7MGXFr
# KQjPBVFnjN2tHOPShdYBZ60NS6q6pVj+xq5FBVGHzV8XtKdV0e3jigsEyXkEl0jc
# Q8/K2LIxphMCAwEAAaOCAdMwggHPMAwGA1UdEwEB/wQCMAAwDgYDVR0PAQH/BAQD
# AgeAMDoGA1UdJQQzMDEGCisGAQQBgjdhAQAGCCsGAQUFBwMDBhkrBgEEAYI3YYuP
# pXGB3qaBQNv/tAST5rkVMB0GA1UdDgQWBBSvmzOJzfqlOfze0TuSX3fnqAlzZDAf
# BgNVHSMEGDAWgBSa8VR3dQyHFjdGoKzeefn0f8F46TBnBgNVHR8EYDBeMFygWqBY
# hlZodHRwOi8vd3d3Lm1pY3Jvc29mdC5jb20vcGtpb3BzL2NybC9NaWNyb3NvZnQl
# MjBJRCUyMFZlcmlmaWVkJTIwQ1MlMjBFT0MlMjBDQSUyMDA0LmNybDB0BggrBgEF
# BQcBAQRoMGYwZAYIKwYBBQUHMAKGWGh0dHA6Ly93d3cubWljcm9zb2Z0LmNvbS9w
# a2lvcHMvY2VydHMvTWljcm9zb2Z0JTIwSUQlMjBWZXJpZmllZCUyMENTJTIwRU9D
# JTIwQ0ElMjAwNC5jcnQwVAYDVR0gBE0wSzBJBgRVHSAAMEEwPwYIKwYBBQUHAgEW
# M2h0dHA6Ly93d3cubWljcm9zb2Z0LmNvbS9wa2lvcHMvRG9jcy9SZXBvc2l0b3J5
# Lmh0bTANBgkqhkiG9w0BAQwFAAOCAgEABRiO07jmU6SjeUNkagy4Me5BFFY3b/5L
# 1BRn/Gf9C8kXZjlIyzMH7FcbslPw6ySkN3AIikz4rDwk8QQ+fc/dp+/ru35kqbbX
# m/bcK0AVjQ3ZOy8kRAjGqmFJff56lydGk3ybw1KCBHYgSs9KXVxC45348w4T9pjS
# ViDcGko8g4Z+m19GW7ov6srqiP72u5zVIwIHuxP/g08zaf2wynKz9duWzmZS8Lft
# UawJI8il/5pLFjNBlCeJq4MWNfI4N4d1a2VCEhs12HLqax/C/PyQP3qRUI7PB5If
# KYltajewMbYVw+rQDE4fugNEu14zUYPislGt36hd/Tk1Dn8uIT6P+9RyMyIX19bH
# 9uTghE132/HEwuVNL34RkxJYMIG+ESF6fs+G9RDkWyGAi1FlLWl6ptszZ8ThL22/
# Sc11b6FlR8s+pCnjSQ6TKWnmWGEwoG43uqFXfLcchz2m8AEE3xvj+XpwkujUSray
# TGy5E/olv946WtyEq4poNlZsND6CbrWT6VNd4VvmrRbYZUThdX3wjrpBssSRY3a7
# T9ra9KyYFFeAFulbvdaqo1DgPBVAWgbskiHEdkSrySbbhTHmCWltbGzlPU3kqTwS
# rjw0CUOfry9Ve7iYtitt6LVu6DqEOY/3TBfLnubeZyjd1LpkIQWPU4u9AA4d9L2S
# UKY5Ziyo+18wggcoMIIFEKADAgECAhMzAAAAFydFCQuLh6/GAAAAAAAXMA0GCSqG
# SIb3DQEBDAUAMGMxCzAJBgNVBAYTAlVTMR4wHAYDVQQKExVNaWNyb3NvZnQgQ29y
# cG9yYXRpb24xNDAyBgNVBAMTK01pY3Jvc29mdCBJRCBWZXJpZmllZCBDb2RlIFNp
# Z25pbmcgUENBIDIwMjEwHhcNMjYwMzI2MTgxMTMxWhcNMzEwMzI2MTgxMTMxWjBa
# MQswCQYDVQQGEwJVUzEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMSsw
# KQYDVQQDEyJNaWNyb3NvZnQgSUQgVmVyaWZpZWQgQ1MgRU9DIENBIDA0MIICIjAN
# BgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAgsdk/gMPZioBlcyfk6tDzJ+PRt4r
# SLGKW8ewpS0kRxXtURC3T3GdbCKljobEn8ussqhGqQpRh/SXvRVwNXEIGb76UG5I
# PkCJ1S6/9BD61QQsKzPepW0SNj8TXgsFxvS7MltoRuikIIp7Q5jQgaOM6QyK9++6
# ZVXUpYmZulAe6x8JrwZ0dNkE+rZ66lqtoocwepUSVUxM7odDmn8yDHjJ2DNPsfr3
# uRDix3X4qvh14jH/SW+2Cx7WIMhyIiQO201i6hUixmk4e2ZW8W7C1wPdTjq6BKb+
# zo8xbrt7ZKQvRX5QOA6dhLquPqj5sVKnxqfk19IC0SafTSTs8yC43Ew965BRRW8V
# L9ccoOmr4rxQy7aCgYTNk3dd/LphNaTTmnGp7kmLTxyHkB5geoWhYuuGrywS8E0w
# Jv0W4rfOtHBV0e9sKvuUIeIUpnsx6ilxEVj6VQXvgD6yeCKnPmj3jJiJKAlmUDtt
# h5yzRVBUl44sMiG4L5R/yyACRKk2n088Q2YCoZS1O86+oMLKt1jaXGECOjbsVp8I
# d1VQw8he6J0KirOS5e25XlTdGPFb6oBOOaacgW78Kjf0bp+XzAgkc92mDGNJGYSj
# vdnj+7eMx6meW0DAIGdLRNj8/429MIspFBfz3KDqqpN71S4kQ2LLer3dxhDDczKV
# FL0HLwRuOvgjiG8CAwEAAaOCAdwwggHYMA4GA1UdDwEB/wQEAwIBhjAQBgkrBgEE
# AYI3FQEEAwIBADAdBgNVHQ4EFgQUmvFUd3UMhxY3RqCs3nn59H/BeOkwVAYDVR0g
# BE0wSzBJBgRVHSAAMEEwPwYIKwYBBQUHAgEWM2h0dHA6Ly93d3cubWljcm9zb2Z0
# LmNvbS9wa2lvcHMvRG9jcy9SZXBvc2l0b3J5Lmh0bTAZBgkrBgEEAYI3FAIEDB4K
# AFMAdQBiAEMAQTASBgNVHRMBAf8ECDAGAQH/AgEAMB8GA1UdIwQYMBaAFNlBKbAP
# D2Ns72nX9c0pnqRIajDmMHAGA1UdHwRpMGcwZaBjoGGGX2h0dHA6Ly93d3cubWlj
# cm9zb2Z0LmNvbS9wa2lvcHMvY3JsL01pY3Jvc29mdCUyMElEJTIwVmVyaWZpZWQl
# MjBDb2RlJTIwU2lnbmluZyUyMFBDQSUyMDIwMjEuY3JsMH0GCCsGAQUFBwEBBHEw
# bzBtBggrBgEFBQcwAoZhaHR0cDovL3d3dy5taWNyb3NvZnQuY29tL3BraW9wcy9j
# ZXJ0cy9NaWNyb3NvZnQlMjBJRCUyMFZlcmlmaWVkJTIwQ29kZSUyMFNpZ25pbmcl
# MjBQQ0ElMjAyMDIxLmNydDANBgkqhkiG9w0BAQwFAAOCAgEAkHVaGf1NJt/Jdoim
# mRZbMWr6baaDi8mkdWvWStk0hdZDpxSYTA7HuipAoLL3qIhI101XOl7fOiCh5++j
# ZOamQdAV79ojEUNoIgCZmL2XJrLaGanwdjNynecJyYVCTrRf2+h7KknpWOp4axdO
# s6K9ZQ5g0IsQWXCwfc0dfkSkLKNY3pDcWLlJPh2jd5NUue6pNDv/2G5MFNJhCwlt
# ODebyAjGceU+XOzav+7i721YQnQ+39m2aQOFO7zpAdaKAeAGhEd6Y6CdDGneSxco
# ujWvafWbv4ay3jo1ORSLUuWMbKr5X18QE4Sde+gppGLLSkZsrUh2eyYSkX1envWX
# 7ZPzg2/wiuKRlQFarDn+N9+20BqzhxwkNyLzfYJp1Lg4fCXb24XqFjx8SDdRgebF
# ImOfOLVze8XQ/CwkrEaib0PHu2t4GVk4FYroEbNUFqvjdBvTY3uiR5TdQoyXoYHv
# h+TxpLSY2vo7hhK9D/rpEpHC+qmmcRUE4d0gyO9Zb1vvt25fxM3ekjvDfVHcPq3q
# Mr0Rwsk4krKZWUEgU1SXT5qN6gqRrshxbT6OQgZ9/xT04qiXdzPQR6KindBvSpoO
# nxnALxcJyzVwNpKL+9u8EZYy98qX6i+4gE/2J6cbpekcB0ZXDn/XQxoNUUb6/djT
# /wllVyG+vIHkdq71PzbH5rYxdcAwggeeMIIFhqADAgECAhMzAAAAB4ejNKN7pY4c
# AAAAAAAHMA0GCSqGSIb3DQEBDAUAMHcxCzAJBgNVBAYTAlVTMR4wHAYDVQQKExVN
# aWNyb3NvZnQgQ29ycG9yYXRpb24xSDBGBgNVBAMTP01pY3Jvc29mdCBJZGVudGl0
# eSBWZXJpZmljYXRpb24gUm9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkgMjAyMDAe
# Fw0yMTA0MDEyMDA1MjBaFw0zNjA0MDEyMDE1MjBaMGMxCzAJBgNVBAYTAlVTMR4w
# HAYDVQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xNDAyBgNVBAMTK01pY3Jvc29m
# dCBJRCBWZXJpZmllZCBDb2RlIFNpZ25pbmcgUENBIDIwMjEwggIiMA0GCSqGSIb3
# DQEBAQUAA4ICDwAwggIKAoICAQCy8MCvGYgo4t1UekxJbGkIVQm0Uv96SvjB6yUo
# 92cXdylN65Xy96q2YpWCiTas7QPTkGnK9QMKDXB2ygS27EAIQZyAd+M8X+dmw6SD
# tzSZXyGkxP8a8Hi6EO9Zcwh5A+wOALNQbNO+iLvpgOnEM7GGB/wm5dYnMEOguua1
# OFfTUITVMIK8faxkP/4fPdEPCXYyy8NJ1fmskNhW5HduNqPZB/NkWbB9xxMqowAe
# WvPgHtpzyD3PLGVOmRO4ka0WcsEZqyg6efk3JiV/TEX39uNVGjgbODZhzspHvKFN
# U2K5MYfmHh4H1qObU4JKEjKGsqqA6RziybPqhvE74fEp4n1tiY9/ootdU0vPxRp4
# BGjQFq28nzawuvaCqUUF2PWxh+o5/TRCb/cHhcYU8Mr8fTiS15kRmwFFzdVPZ3+J
# V3s5MulIf3II5FXeghlAH9CvicPhhP+VaSFW3Da/azROdEm5sv+EUwhBrzqtxoYy
# E2wmuHKws00x4GGIx7NTWznOm6x/niqVi7a/mxnnMvQq8EMse0vwX2CfqM7Le/sm
# bRtsEeOtbnJBbtLfoAsC3TdAOnBbUkbUfG78VRclsE7YDDBUbgWt75lDk53yi7C3
# n0WkHFU4EZ83i83abd9nHWCqfnYa9qIHPqjOiuAgSOf4+FRcguEBXlD9mAInS7b6
# V0UaNwIDAQABo4ICNTCCAjEwDgYDVR0PAQH/BAQDAgGGMBAGCSsGAQQBgjcVAQQD
# AgEAMB0GA1UdDgQWBBTZQSmwDw9jbO9p1/XNKZ6kSGow5jBUBgNVHSAETTBLMEkG
# BFUdIAAwQTA/BggrBgEFBQcCARYzaHR0cDovL3d3dy5taWNyb3NvZnQuY29tL3Br
# aW9wcy9Eb2NzL1JlcG9zaXRvcnkuaHRtMBkGCSsGAQQBgjcUAgQMHgoAUwB1AGIA
# QwBBMA8GA1UdEwEB/wQFMAMBAf8wHwYDVR0jBBgwFoAUyH7SaoUqG8oZmAQHJ89Q
# EE9oqKIwgYQGA1UdHwR9MHsweaB3oHWGc2h0dHA6Ly93d3cubWljcm9zb2Z0LmNv
# bS9wa2lvcHMvY3JsL01pY3Jvc29mdCUyMElkZW50aXR5JTIwVmVyaWZpY2F0aW9u
# JTIwUm9vdCUyMENlcnRpZmljYXRlJTIwQXV0aG9yaXR5JTIwMjAyMC5jcmwwgcMG
# CCsGAQUFBwEBBIG2MIGzMIGBBggrBgEFBQcwAoZ1aHR0cDovL3d3dy5taWNyb3Nv
# ZnQuY29tL3BraW9wcy9jZXJ0cy9NaWNyb3NvZnQlMjBJZGVudGl0eSUyMFZlcmlm
# aWNhdGlvbiUyMFJvb3QlMjBDZXJ0aWZpY2F0ZSUyMEF1dGhvcml0eSUyMDIwMjAu
# Y3J0MC0GCCsGAQUFBzABhiFodHRwOi8vb25lb2NzcC5taWNyb3NvZnQuY29tL29j
# c3AwDQYJKoZIhvcNAQEMBQADggIBAH8lKp7+1Kvq3WYK21cjTLpebJDjW4ZbOX3H
# D5ZiG84vjsFXT0OB+eb+1TiJ55ns0BHluC6itMI2vnwc5wDW1ywdCq3TAmx0KWy7
# xulAP179qX6VSBNQkRXzReFyjvF2BGt6FvKFR/imR4CEESMAG8hSkPYso+GjlngM
# 8JPn/ROUrTaeU/BRu/1RFESFVgK2wMz7fU4VTd8NXwGZBe/mFPZG6tWwkdmA/jLb
# p0kNUX7elxu2+HtHo0QO5gdiKF+YTYd1BGrmNG8sTURvn09jAhIUJfYNotn7OlTh
# tfQjXqe0qrimgY4Vpoq2MgDW9ESUi1o4pzC1zTgIGtdJ/IvY6nqa80jFOTg5qzAi
# RNdsUvzVkoYP7bi4wLCj+ks2GftUct+fGUxXMdBUv5sdr0qFPLPB0b8vq516slCf
# RwaktAxK1S40MCvFbbAXXpAZnU20FaAoDwqq/jwzwd8Wo2J83r7O3onQbDO9TyDS
# tgaBNlHzMMQgl95nHBYMelLEHkUnVVVTUsgC0Huj09duNfMaJ9ogxhPNThgq3i8w
# 3DAGZ61AMeF0C1M+mU5eucj1Ijod5O2MMPeJQ3/vKBtqGZg4eTtUHt/BPjN74SsJ
# syHqAdXVS5c+ItyKWg3Eforhox9k3WgtWTpgV4gkSiS4+A09roSdOI4vrRw+p+fL
# 4WrxSK5nMYIalDCCGpACAQEwcTBaMQswCQYDVQQGEwJVUzEeMBwGA1UEChMVTWlj
# cm9zb2Z0IENvcnBvcmF0aW9uMSswKQYDVQQDEyJNaWNyb3NvZnQgSUQgVmVyaWZp
# ZWQgQ1MgRU9DIENBIDA0AhMzAAGSX9Z/ePB9sQgIAAAAAZJfMA0GCWCGSAFlAwQC
# AQUAoF4wEAYKKwYBBAGCNwIBDDECMAAwGQYJKoZIhvcNAQkDMQwGCisGAQQBgjcC
# AQQwLwYJKoZIhvcNAQkEMSIEIAsVQzwZzh1mNFjap6xTbRR36eaCVAcZo4swhDpC
# KQTaMA0GCSqGSIb3DQEBAQUABIIBgF1h/EeOpwnDnds+c5X37kT7ksguziqf4hPg
# XAvF3Ha5eeLSHlV6z+5AXU3cKVzW76CoAM6Use6z9OnT4gJe3EOxog+XmBbgO7OY
# 1zYRrLNY74ityQgR0ZkRnH1zNKnEk+gm4ODzrhJdUKZdM5oGIAt/S2g+0W97OkC7
# iGBVMOz9KXNaGzAODr2H0/Ye8ZsFRy44C/dRzNvootm6yhnSySQBbPFoV9E9Vlv/
# at5vSIQicaQQEkVrIIoGbkwYZhRrq7Cir6kgXj57RLNe2n3lxvoaUmnZNceSTnUA
# VJaqHhV7z3gzBYnD669N/2YjVJH0KvzQJ2w+X+CA7RWgRDx+BSqoUe82L/ocnswz
# 31uuWwzE7DaMrVgaGcpvrOzxkdnaJ2A8I6iBw/UYpgAOoePkT6hKGtXoaUbVBkcf
# GSZE6WZ2KwZb280H8jl0OMOUIZ5wiY0Hn3tEqr5IE9TPZAiIzybka2o0Av2FCEPS
# MGzqr/+OlHERIrXJbMSOAoJPYh26N6GCGBQwghgQBgorBgEEAYI3AwMBMYIYADCC
# F/wGCSqGSIb3DQEHAqCCF+0wghfpAgEDMQ8wDQYJYIZIAWUDBAIBBQAwggFiBgsq
# hkiG9w0BCRABBKCCAVEEggFNMIIBSQIBAQYKKwYBBAGEWQoDATAxMA0GCWCGSAFl
# AwQCAQUABCD7reVWSCEtxa/Gb7LLUqnSLPVayM/cghdULgPoQrK4hQIGaeiBVosy
# GBMyMDI2MDYwMjAwNTgxOC4yNDhaMASAAgH0oIHhpIHeMIHbMQswCQYDVQQGEwJV
# UzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9uZDEeMBwGA1UE
# ChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMSUwIwYDVQQLExxNaWNyb3NvZnQgQW1l
# cmljYSBPcGVyYXRpb25zMScwJQYDVQQLEx5uU2hpZWxkIFRTUyBFU046N0QwMC0w
# NUUwLUQ5NDcxNTAzBgNVBAMTLE1pY3Jvc29mdCBQdWJsaWMgUlNBIFRpbWUgU3Rh
# bXBpbmcgQXV0aG9yaXR5oIIPITCCB4IwggVqoAMCAQICEzMAAAAF5c8P/2YuyYcA
# AAAAAAUwDQYJKoZIhvcNAQEMBQAwdzELMAkGA1UEBhMCVVMxHjAcBgNVBAoTFU1p
# Y3Jvc29mdCBDb3Jwb3JhdGlvbjFIMEYGA1UEAxM/TWljcm9zb2Z0IElkZW50aXR5
# IFZlcmlmaWNhdGlvbiBSb290IENlcnRpZmljYXRlIEF1dGhvcml0eSAyMDIwMB4X
# DTIwMTExOTIwMzIzMVoXDTM1MTExOTIwNDIzMVowYTELMAkGA1UEBhMCVVMxHjAc
# BgNVBAoTFU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjEyMDAGA1UEAxMpTWljcm9zb2Z0
# IFB1YmxpYyBSU0EgVGltZXN0YW1waW5nIENBIDIwMjAwggIiMA0GCSqGSIb3DQEB
# AQUAA4ICDwAwggIKAoICAQCefOdSY/3gxZ8FfWO1BiKjHB7X55cz0RMFvWVGR3eR
# wV1wb3+yq0OXDEqhUhxqoNv6iYWKjkMcLhEFxvJAeNcLAyT+XdM5i2CgGPGcb95W
# JLiw7HzLiBKrxmDj1EQB/mG5eEiRBEp7dDGzxKCnTYocDOcRr9KxqHydajmEkzXH
# OeRGwU+7qt8Md5l4bVZrXAhK+WSk5CihNQsWbzT1nRliVDwunuLkX1hyIWXIArCf
# rKM3+RHh+Sq5RZ8aYyik2r8HxT+l2hmRllBvE2Wok6IEaAJanHr24qoqFM9WLeBU
# Sudz+qL51HwDYyIDPSQ3SeHtKog0ZubDk4hELQSxnfVYXdTGncaBnB60QrEuazvc
# ob9n4yR65pUNBCF5qeA4QwYnilBkfnmeAjRN3LVuLr0g0FXkqfYdUmj1fFFhH8k8
# YBozrEaXnsSL3kdTD01X+4LfIWOuFzTzuoslBrBILfHNj8RfOxPgjuwNvE6YzauX
# i4orp4Sm6tF245DaFOSYbWFK5ZgG6cUY2/bUq3g3bQAqZt65KcaewEJ3ZyNEobv3
# 5Nf6xN6FrA6jF9447+NHvCjeWLCQZ3M8lgeCcnnhTFtyQX3XgCoc6IRXvFOcPVrr
# 3D9RPHCMS6Ckg8wggTrtIVnY8yjbvGOUsAdZbeXUIQAWMs0d3cRDv09SvwVRd61e
# vQIDAQABo4ICGzCCAhcwDgYDVR0PAQH/BAQDAgGGMBAGCSsGAQQBgjcVAQQDAgEA
# MB0GA1UdDgQWBBRraSg6NS9IY0DPe9ivSek+2T3bITBUBgNVHSAETTBLMEkGBFUd
# IAAwQTA/BggrBgEFBQcCARYzaHR0cDovL3d3dy5taWNyb3NvZnQuY29tL3BraW9w
# cy9Eb2NzL1JlcG9zaXRvcnkuaHRtMBMGA1UdJQQMMAoGCCsGAQUFBwMIMBkGCSsG
# AQQBgjcUAgQMHgoAUwB1AGIAQwBBMA8GA1UdEwEB/wQFMAMBAf8wHwYDVR0jBBgw
# FoAUyH7SaoUqG8oZmAQHJ89QEE9oqKIwgYQGA1UdHwR9MHsweaB3oHWGc2h0dHA6
# Ly93d3cubWljcm9zb2Z0LmNvbS9wa2lvcHMvY3JsL01pY3Jvc29mdCUyMElkZW50
# aXR5JTIwVmVyaWZpY2F0aW9uJTIwUm9vdCUyMENlcnRpZmljYXRlJTIwQXV0aG9y
# aXR5JTIwMjAyMC5jcmwwgZQGCCsGAQUFBwEBBIGHMIGEMIGBBggrBgEFBQcwAoZ1
# aHR0cDovL3d3dy5taWNyb3NvZnQuY29tL3BraW9wcy9jZXJ0cy9NaWNyb3NvZnQl
# MjBJZGVudGl0eSUyMFZlcmlmaWNhdGlvbiUyMFJvb3QlMjBDZXJ0aWZpY2F0ZSUy
# MEF1dGhvcml0eSUyMDIwMjAuY3J0MA0GCSqGSIb3DQEBDAUAA4ICAQBfiHbHfm21
# WhV150x4aPpO4dhEmSUVpbixNDmv6TvuIHv1xIs174bNGO/ilWMm+Jx5boAXrJxa
# gRhHQtiFprSjMktTliL4sKZyt2i+SXncM23gRezzsoOiBhv14YSd1Klnlkzvgs29
# XNjT+c8hIfPRe9rvVCMPiH7zPZcw5nNjthDQ+zD563I1nUJ6y59TbXWsuyUsqw7w
# XZoGzZwijWT5oc6GvD3HDokJY401uhnj3ubBhbkR83RbfMvmzdp3he2bvIUztSOu
# FzRqrLfEvsPkVHYnvH1wtYyrt5vShiKheGpXa2AWpsod4OJyT4/y0dggWi8g/tgb
# hmQlZqDUf3UqUQsZaLdIu/XSjgoZqDjamzCPJtOLi2hBwL+KsCh0Nbwc21f5xvPS
# wym0Ukr4o5sCcMUcSy6TEP7uMV8RX0eH/4JLEpGyae6Ki8JYg5v4fsNGif1OXHJ2
# IWG+7zyjTDfkmQ1snFOTgyEX8qBpefQbF0fx6URrYiarjmBprwP6ZObwtZXJ23jK
# 3Fg/9uqM3j0P01nzVygTppBabzxPAh/hHhhls6kwo3QLJ6No803jUsZcd4JQxiYH
# Hc+Q/wAMcPUnYKv/q2O444LO1+n6j01z5mggCSlRwD9faBIySAcA9S8h22hIAcRQ
# qIGEjolCK9F6nK9ZyX4lhthsGHumaABdWzCCB5cwggV/oAMCAQICEzMAAABV2d1p
# Jij5+OIAAAAAAFUwDQYJKoZIhvcNAQEMBQAwYTELMAkGA1UEBhMCVVMxHjAcBgNV
# BAoTFU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjEyMDAGA1UEAxMpTWljcm9zb2Z0IFB1
# YmxpYyBSU0EgVGltZXN0YW1waW5nIENBIDIwMjAwHhcNMjUxMDIzMjA0NjQ5WhcN
# MjYxMDIyMjA0NjQ5WjCB2zELMAkGA1UEBhMCVVMxEzARBgNVBAgTCldhc2hpbmd0
# b24xEDAOBgNVBAcTB1JlZG1vbmQxHjAcBgNVBAoTFU1pY3Jvc29mdCBDb3Jwb3Jh
# dGlvbjElMCMGA1UECxMcTWljcm9zb2Z0IEFtZXJpY2EgT3BlcmF0aW9uczEnMCUG
# A1UECxMeblNoaWVsZCBUU1MgRVNOOjdEMDAtMDVFMC1EOTQ3MTUwMwYDVQQDEyxN
# aWNyb3NvZnQgUHVibGljIFJTQSBUaW1lIFN0YW1waW5nIEF1dGhvcml0eTCCAiIw
# DQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAL25H5IeWUiz9DAlFmn2sPymaFWb
# vYkMfK+ScIWb3a1IvOlIwghUDjY0Gp6yMRhfYURiGS0GedIB6ywvuH6VBCX3+bdO
# FcAclgtv21jrpOjZmk4fSaT2Q3BszUfeUJa8o3xI7ZfoMY9dszTxHQAz6ZVX87fH
# GEVhQcfxW33IdPJOj/ae419qtYxT21MVmCfsTshgtWioQxmOW/vMC9/b+qgtBxSM
# f798vm3qfmhF6KCvFaHlivrM32hY16PGE3L0PFC+LM7vRxU7mTb+r76CeybvqOWk
# 4+dbKYftPhV1t/E5S/6wwXeYmu/Y7JC7Tnh2w45G5Y4pcM3oHMb/YuPRdOWa0v+R
# C2QgmNVWqjuxDiylWscXQDuaMtb29AcdGUVV9ZsRY2M2sthAtOdZOshiR5ufMtaH
# tiCkWv0jNfgUxrHurxzYuUNneWZ6EfQDgFAw8CSCKkSOK2c9jEop4ddVq10xvbqx
# drqMneVXvvIcXrPQAXj9j2ECpV2EwMb3Wnmpw00P78JpzPsk3Fs61ZvOGd/F1RcO
# Bu6f2TWdp7HL7+rq7tgHr13MldbfIWu4lpoYYE1gTQa1Yrg5XN4j7zs9klT2z3qo
# cmPzV8DWQgIHNh+aTs7bujMEMQyI7Xt1zPxZCgcR6H0tmmzU/9BxvsWbRalCQ2sY
# GyWupTdc4e7KY7kPAgMBAAGjggHLMIIBxzAdBgNVHQ4EFgQUVgRfEG3cCAPwyL+p
# yRbKwdesZbYwHwYDVR0jBBgwFoAUa2koOjUvSGNAz3vYr0npPtk92yEwbAYDVR0f
# BGUwYzBhoF+gXYZbaHR0cDovL3d3dy5taWNyb3NvZnQuY29tL3BraW9wcy9jcmwv
# TWljcm9zb2Z0JTIwUHVibGljJTIwUlNBJTIwVGltZXN0YW1waW5nJTIwQ0ElMjAy
# MDIwLmNybDB5BggrBgEFBQcBAQRtMGswaQYIKwYBBQUHMAKGXWh0dHA6Ly93d3cu
# bWljcm9zb2Z0LmNvbS9wa2lvcHMvY2VydHMvTWljcm9zb2Z0JTIwUHVibGljJTIw
# UlNBJTIwVGltZXN0YW1waW5nJTIwQ0ElMjAyMDIwLmNydDAMBgNVHRMBAf8EAjAA
# MBYGA1UdJQEB/wQMMAoGCCsGAQUFBwMIMA4GA1UdDwEB/wQEAwIHgDBmBgNVHSAE
# XzBdMFEGDCsGAQQBgjdMg30BATBBMD8GCCsGAQUFBwIBFjNodHRwOi8vd3d3Lm1p
# Y3Jvc29mdC5jb20vcGtpb3BzL0RvY3MvUmVwb3NpdG9yeS5odG0wCAYGZ4EMAQQC
# MA0GCSqGSIb3DQEBDAUAA4ICAQBSHuGSVHvalCnFnlsqXIQefH1xP2SFr9g+Vz+f
# 5P7QeywjfQb5jUlSmd1XnJUDPe/MHxL7r3TEElL+mNtG6CDPAytStSFPXD9tTBtB
# MYh8Wqo64pH9qm361yIqeBH979mzWCkMQsTd0nM6dUl9B+7qiti+ToXwxIl39eYq
# LuYYfhD2mqqePXMzUKSQzkf73yYIVHP6nLJQz4aAmaWcfG9jg78sBkDV8KpW7Jgk
# tuLhphJEN1B+SVHjenPdcmrFXIUu/K4jK5ukfWaQIjuaXzSjBlNjC5tQN6adPfA3
# GxUwHPeR4ekL5If/9vBf13tmzBW+gy+0sNGTveb9IL9GU8iX8UvywsX62nhCCPRU
# hTigDBKdczRUrNrntBhowbfchBDFML8avRMRc9Gmc2JvIryX336SFQ51//q1UU2H
# MSJEMhWLJSIWJVhfUowsOa+PampIzETYfFvTu2mqKJUlWZXkGYxrdCvCczJcqeoa
# dpW1ul6kcdnDh228SQ8ZhDc6IRlM4iNd5SNoNgX+aom3wuGyjUaSaPZWxPB1G2NK
# iYhPLt0lPHg0Gskj1zhISY8UQkMMDr3o2JgRuT+wnJEDQUp55ddvhSkSoD6I9DL/
# s+TjIY/c9jLaW5xywJHqdKHUApRMsghv7kebSua1upmR+TquelFktDSOjVdSRkuy
# a4uoxTGCB0YwggdCAgEBMHgwYTELMAkGA1UEBhMCVVMxHjAcBgNVBAoTFU1pY3Jv
# c29mdCBDb3Jwb3JhdGlvbjEyMDAGA1UEAxMpTWljcm9zb2Z0IFB1YmxpYyBSU0Eg
# VGltZXN0YW1waW5nIENBIDIwMjACEzMAAABV2d1pJij5+OIAAAAAAFUwDQYJYIZI
# AWUDBAIBBQCgggSfMBEGCyqGSIb3DQEJEAIPMQIFADAaBgkqhkiG9w0BCQMxDQYL
# KoZIhvcNAQkQAQQwHAYJKoZIhvcNAQkFMQ8XDTI2MDYwMjAwNTgxOFowLwYJKoZI
# hvcNAQkEMSIEIGvtePGLXnYDKS40Krj3/fTC2KbHcu4uKEZmW/GWW3IFMIG5Bgsq
# hkiG9w0BCRACLzGBqTCBpjCBozCBoAQg2Lk8l2SGYru/ff7+D2qrJnkswcYdK6pG
# Ku7GGGr4/s0wfDBlpGMwYTELMAkGA1UEBhMCVVMxHjAcBgNVBAoTFU1pY3Jvc29m
# dCBDb3Jwb3JhdGlvbjEyMDAGA1UEAxMpTWljcm9zb2Z0IFB1YmxpYyBSU0EgVGlt
# ZXN0YW1waW5nIENBIDIwMjACEzMAAABV2d1pJij5+OIAAAAAAFUwggNhBgsqhkiG
# 9w0BCRACEjGCA1AwggNMoYIDSDCCA0QwggIsAgEBMIIBCaGB4aSB3jCB2zELMAkG
# A1UEBhMCVVMxEzARBgNVBAgTCldhc2hpbmd0b24xEDAOBgNVBAcTB1JlZG1vbmQx
# HjAcBgNVBAoTFU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjElMCMGA1UECxMcTWljcm9z
# b2Z0IEFtZXJpY2EgT3BlcmF0aW9uczEnMCUGA1UECxMeblNoaWVsZCBUU1MgRVNO
# OjdEMDAtMDVFMC1EOTQ3MTUwMwYDVQQDEyxNaWNyb3NvZnQgUHVibGljIFJTQSBU
# aW1lIFN0YW1waW5nIEF1dGhvcml0eaIjCgEBMAcGBSsOAwIaAxUAHTtUAYJlv7bg
# WVeRBo4X7FeHDeqgZzBlpGMwYTELMAkGA1UEBhMCVVMxHjAcBgNVBAoTFU1pY3Jv
# c29mdCBDb3Jwb3JhdGlvbjEyMDAGA1UEAxMpTWljcm9zb2Z0IFB1YmxpYyBSU0Eg
# VGltZXN0YW1waW5nIENBIDIwMjAwDQYJKoZIhvcNAQELBQACBQDtyGQwMCIYDzIw
# MjYwNjAxMjAwNDAwWhgPMjAyNjA2MDIyMDA0MDBaMHcwPQYKKwYBBAGEWQoEATEv
# MC0wCgIFAO3IZDACAQAwCgIBAAICBaACAf8wBwIBAAICGlAwCgIFAO3JtbACAQAw
# NgYKKwYBBAGEWQoEAjEoMCYwDAYKKwYBBAGEWQoDAqAKMAgCAQACAwehIKEKMAgC
# AQACAwGGoDANBgkqhkiG9w0BAQsFAAOCAQEAcYKZNNhAKlpwU6xnsnt6QPfdCycb
# LmT785CQMq0d2g9pBJe1cDNlWI8jbYzoojWScCTqxDumGqTLeNd1eU7UIxM1TWdy
# oEgREQkvvhTlp9LZnDB9wVDq0U9H5uTBsrTly4sew/UgNF6gNQRBLyHkVCRGLcYO
# +t4Gtqr0UK0LwEq3jBo0awGisryLm+MvCeY/ocHM5HixJWhgrDVXwCPJPlAs2qNN
# zJ/52gru8oyWSjxXBuUXf87j4ghf94DJisrUgwVua9qBnlN8lCgfur0eNA6mU3gv
# J2y+7kwF/6S8SvyrbPTFrdxYRY8q/9kVYhlmdjfCkMcBwj+65jClFmbUvjANBgkq
# hkiG9w0BAQEFAASCAgAAUSd2o0FJH0jNmBN+9YYlRwY2zGYAFQrimNxI/OGc7EkA
# scA2iY8cwkeuE26mIiW32gB3G25pnRGWcKTPCzxwGAIpfV2RSf+hJc+ZAoPaVkOM
# AMb5DfHTNFS6gfQoGNYwtq4R/JahfoXt+uCPaEVhKr/g8Ht0JND4DtSr8KDfSVqs
# sevFr/RxE+N2dkV11f9V90P+Xn/X18KzUxiu6A0Y10zNs54yXsRGg47czCu8dxi7
# BjrpE5cF9nvJ9sVF+KQidqHTLiIu/0fz64JQ+ZisEz0mV1tsjLnKuwfYOHgNNfIm
# 24uk22P2NnwWkN090s20IAELyIBacx3z9wcrt9anWQoHcl/DGpCzrRfCQO0CZKny
# iA0TkeQcF0uPAqgIpdnX7pvZiafxq2AYiDw3YIEIKbsVetakyKmBoEac8HkW+6iP
# RM0ipt1yNPll6pTZjJ9PGfbaZhtGmCg3R9Y2ZeTmvcNE7AP0Z9XuokbHQqPKWI83
# ObG1f5vduhSljlWqxUqBZl7JGtfNOgo/GYewR4eMPI7Amdzrf0YB/DknIv0txgvZ
# ftVjwHxl/Wd3nJPlE3Qdk1UGzJAhJLnqtPxovAoWHtEw4gkpAz8j1qwNJDWBvEfV
# MkNA4Xq4+d0KhIgGSsoBtYUkH6OuZWbr4DStknFTQEW/kP1xi1q0WMLe9QozFA==
# SIG # End signature block