Tests/NavySeal.Tests.ps1

BeforeAll {
    $ModulePath = (Resolve-Path "$PSScriptRoot/..").Path
    . "$ModulePath/Classes/GraphSession.ps1"
    . "$ModulePath/Classes/Models.ps1"
    foreach ($f in (Get-ChildItem "$ModulePath/Private/*.ps1")) { . $f.FullName }
    foreach ($d in (Get-ChildItem "$ModulePath/Public" -Directory)) { foreach ($f in (Get-ChildItem "$d/*.ps1")) { . $f.FullName } }
    foreach ($f in (Get-ChildItem "$ModulePath/Public/*.ps1")) { . $f.FullName }
}

Describe 'Module manifest' {
    It 'Is valid' {
        $m = Test-ModuleManifest -Path "$PSScriptRoot/../NavySeal.psd1" -ErrorAction Stop
        $m | Should -Not -BeNullOrEmpty
        $m.Name | Should -Be 'NavySeal'
    }
    It 'Exports correct function count' {
        $m = Test-ModuleManifest -Path "$PSScriptRoot/../NavySeal.psd1" -ErrorAction Stop
        $m.ExportedFunctions.Count | Should -BeGreaterOrEqual 33
    }
    It 'Every Test-Ns* file has a matching export' {
        $m = Test-ModuleManifest -Path "$PSScriptRoot/../NavySeal.psd1" -ErrorAction Stop
        $files = Get-ChildItem "$PSScriptRoot/../Public" -Recurse -Filter 'Test-Ns*.ps1' | ForEach-Object { $_.BaseName }
        foreach ($name in $files) { $m.ExportedFunctions.Keys | Should -Contain $name }
    }
}

Describe 'NormalizedScope' {
    BeforeAll {
        $policy = [PSCustomObject]@{
            displayName = 'Test Policy'
            state       = 'enabled'
            conditions  = [PSCustomObject]@{
                users = [PSCustomObject]@{
                    includeUsers  = @('All')
                    excludeUsers  = @('user-1')
                    includeGroups = @()
                    excludeGroups = @('group-1')
                    includeRoles  = @()
                    excludeRoles  = @()
                }
                applications = [PSCustomObject]@{
                    includeApplications = @('All')
                    excludeApplications = @()
                }
                platforms     = $null
                clientAppTypes = @()
                locations     = $null
                userRiskLevels   = @()
                signInRiskLevels = @()
                insiderRiskLevels = @()
                servicePrincipalRiskLevels = @()
            }
            grantControls   = [PSCustomObject]@{ operator = 'OR'; builtInControls = @('mfa'); authenticationStrength = $null; termsOfUse = @() }
            sessionControls = $null
        }
        $scope = [NormalizedScope]::FromPolicy($policy)
    }
    It 'Parses name' { $scope.Name | Should -Be 'Test Policy' }
    It 'Targets all users' { $scope.TargetsAllUsers() | Should -BeTrue }
    It 'Targets all apps' { $scope.TargetsAllApps() | Should -BeTrue }
    It 'Requires MFA' { $scope.RequiresMfa() | Should -BeTrue }
    It 'Does not block' { $scope.Blocks() | Should -BeFalse }
    It 'Respects user exclusion' {
        $ctx = [UserPolicyContext]::new('user-1', 'u@t.com', 'User 1')
        $scope.MatchesUser($ctx) | Should -BeFalse
    }
    It 'Respects group exclusion' {
        $ctx = [UserPolicyContext]::new('user-2', 'u2@t.com', 'User 2')
        [void]$ctx.GroupIds.Add('group-1')
        $scope.MatchesUser($ctx) | Should -BeFalse
    }
    It 'Matches included user' {
        $ctx = [UserPolicyContext]::new('user-3', 'u3@t.com', 'User 3')
        $scope.MatchesUser($ctx) | Should -BeTrue
    }
}

Describe 'ScopeOverlap.Compare' {
    It 'Detects full overlap on All/All' {
        $p = @{ displayName='A'; state='enabled'; conditions=@{users=@{includeUsers=@('All');excludeUsers=@();includeGroups=@();excludeGroups=@();includeRoles=@();excludeRoles=@()};applications=@{includeApplications=@('All');excludeApplications=@()};platforms=$null;clientAppTypes=@();locations=$null;userRiskLevels=@();signInRiskLevels=@();insiderRiskLevels=@();servicePrincipalRiskLevels=@()}; grantControls=@{operator='OR';builtInControls=@('mfa');authenticationStrength=$null;termsOfUse=@()}; sessionControls=$null }
        $a = [NormalizedScope]::FromPolicy([PSCustomObject]$p)
        $b = [NormalizedScope]::FromPolicy([PSCustomObject]$p)
        $ol = [ScopeOverlap]::Compare($a, $b)
        $ol.Users | Should -Be 'full'
        $ol.Apps  | Should -Be 'full'
        $ol.HasOverlap() | Should -BeTrue
    }
}

Describe 'UserActivitySummary' {
    It 'Counts inactive and never-signed-in' {
        $sum = [UserActivitySummary]::new()
        $users = @(
            [PSCustomObject]@{ accountEnabled=$true; signInActivity=@{ lastSignInDateTime = '2024-01-01T00:00:00Z' }; userPrincipalName='old@t.com'; id='1' }
            [PSCustomObject]@{ accountEnabled=$true; signInActivity=@{ lastSignInDateTime = $null }; userPrincipalName='never@t.com'; id='2' }
            [PSCustomObject]@{ accountEnabled=$true; signInActivity=@{ lastSignInDateTime = ([datetime]::UtcNow.AddDays(-1).ToString('o')) }; userPrincipalName='active@t.com'; id='3' }
            [PSCustomObject]@{ accountEnabled=$false; signInActivity=$null; userPrincipalName='disabled@t.com'; id='4' }
        )
        $sum.ProcessPage($users)
        $sum.TotalEnabledUsers | Should -Be 3
        $sum.Inactive90Days    | Should -Be 1
        $sum.NeverSignedIn     | Should -Be 1
    }
}

Describe 'NsContext.Build' {
    It 'Separates enforced from disabled' {
        $snap = [TenantSnapshot]::new()
        $snap.Policies = @(
            [PSCustomObject]@{ displayName='P1'; state='enabled'; conditions=@{users=@{includeUsers=@('All');excludeUsers=@();includeGroups=@();excludeGroups=@();includeRoles=@();excludeRoles=@()};applications=@{includeApplications=@('All');excludeApplications=@()};platforms=$null;clientAppTypes=@();locations=$null;userRiskLevels=@();signInRiskLevels=@();insiderRiskLevels=@();servicePrincipalRiskLevels=@()}; grantControls=@{operator='OR';builtInControls=@('mfa');authenticationStrength=$null;termsOfUse=@()}; sessionControls=$null }
            [PSCustomObject]@{ displayName='P2'; state='disabled'; conditions=@{users=@{includeUsers=@('All');excludeUsers=@();includeGroups=@();excludeGroups=@();includeRoles=@();excludeRoles=@()};applications=@{includeApplications=@('All');excludeApplications=@()};platforms=$null;clientAppTypes=@();locations=$null;userRiskLevels=@();signInRiskLevels=@();insiderRiskLevels=@();servicePrincipalRiskLevels=@()}; grantControls=@{operator='OR';builtInControls=@('block');authenticationStrength=$null;termsOfUse=@()}; sessionControls=$null }
        )
        $snap.DirectoryRoles = @()
        $ctx = [NsContext]::Build($snap, @{})
        $ctx.Enforced.Count | Should -Be 1
        $ctx.Disabled.Count | Should -Be 1
    }
}

Describe 'Test-NsBlockGrantConflict' {
    It 'Detects block vs grant on overlapping scope' {
        $snap = [TenantSnapshot]::new()
        $snap.Policies = @(
            [PSCustomObject]@{ displayName='Block'; state='enabled'; conditions=@{users=@{includeUsers=@('All');excludeUsers=@();includeGroups=@();excludeGroups=@();includeRoles=@();excludeRoles=@()};applications=@{includeApplications=@('All');excludeApplications=@()};platforms=$null;clientAppTypes=@();locations=$null;userRiskLevels=@();signInRiskLevels=@();insiderRiskLevels=@();servicePrincipalRiskLevels=@()}; grantControls=@{operator='OR';builtInControls=@('block');authenticationStrength=$null;termsOfUse=@()}; sessionControls=$null }
            [PSCustomObject]@{ displayName='MFA'; state='enabled'; conditions=@{users=@{includeUsers=@('All');excludeUsers=@();includeGroups=@();excludeGroups=@();includeRoles=@();excludeRoles=@()};applications=@{includeApplications=@('All');excludeApplications=@()};platforms=$null;clientAppTypes=@();locations=$null;userRiskLevels=@();signInRiskLevels=@();insiderRiskLevels=@();servicePrincipalRiskLevels=@()}; grantControls=@{operator='OR';builtInControls=@('mfa');authenticationStrength=$null;termsOfUse=@()}; sessionControls=$null }
        )
        $snap.DirectoryRoles = @()
        $ctx = [NsContext]::Build($snap, @{})
        $results = Test-NsBlockGrantConflict -Context $ctx
        $results.Count | Should -BeGreaterOrEqual 1
        ($results | Where-Object Severity -eq 'High').Count | Should -BeGreaterOrEqual 1
    }
}

Describe 'Test-NsLegacyAuthBlocked' {
    It 'Reports gap when no legacy block policy exists' {
        $snap = [TenantSnapshot]::new()
        $snap.Policies = @(
            [PSCustomObject]@{ displayName='MFA'; state='enabled'; conditions=@{users=@{includeUsers=@('All');excludeUsers=@();includeGroups=@();excludeGroups=@();includeRoles=@();excludeRoles=@()};applications=@{includeApplications=@('All');excludeApplications=@()};platforms=$null;clientAppTypes=@();locations=$null;userRiskLevels=@();signInRiskLevels=@();insiderRiskLevels=@();servicePrincipalRiskLevels=@()}; grantControls=@{operator='OR';builtInControls=@('mfa');authenticationStrength=$null;termsOfUse=@()}; sessionControls=$null }
        )
        $snap.DirectoryRoles = @()
        $ctx = [NsContext]::Build($snap, @{})
        $results = Test-NsLegacyAuthBlocked -Context $ctx
        $results.Count | Should -Be 1
        $results[0].Severity | Should -Be 'High'
    }
}

Describe 'Config' {
    It 'Loads defaults' {
        $config = Get-NsConfig
        $config | Should -Not -BeNullOrEmpty
        $config.mfaRegistrationThresholdPct | Should -Be 90
        $config.scoringWeights.criticalCap | Should -Be 30
    }
}

Describe 'Scoring formula' {
    It 'Produces 36 for 2c+5h+7m+5l' {
        $w = @{ criticalPerFinding=10; criticalCap=30; highPerFinding=5; highCap=25; mediumPerFinding=2; mediumCap=15; lowPerFinding=1; lowCap=5 }
        $score = 100 - [math]::Min($w.criticalCap, 2 * $w.criticalPerFinding) -
            [math]::Min($w.highCap, 5 * $w.highPerFinding) -
            [math]::Min($w.mediumCap, 7 * $w.mediumPerFinding) -
            [math]::Min($w.lowCap, 5 * $w.lowPerFinding)
        $score | Should -Be 36
    }
}

Describe 'One function per file' {
    It 'Every .ps1 in Public/ contains exactly one exported function matching its filename' {
        $files = Get-ChildItem "$PSScriptRoot/../Public" -Recurse -Filter '*.ps1'
        foreach ($f in $files) {
            $expected = $f.BaseName
            $content = Get-Content $f.FullName -Raw
            $content | Should -Match "function $expected\b" -Because "$($f.Name) should contain function $expected"
        }
    }
}

Describe 'New-NsModellerHtml' {
    BeforeAll {
        $snap = [TenantSnapshot]::new()
        $snap.TenantId = 'test-tenant'
        $snap.CollectedAtUtc = [datetime]::UtcNow
        $snap.Policies = @(
            [PSCustomObject]@{ displayName='TestPolicy'; state='enabled'; conditions=@{users=@{includeUsers=@('All');excludeUsers=@();includeGroups=@();excludeGroups=@();includeRoles=@();excludeRoles=@()};applications=@{includeApplications=@('All');excludeApplications=@()};platforms=$null;clientAppTypes=@();locations=$null;userRiskLevels=@();signInRiskLevels=@();insiderRiskLevels=@();servicePrincipalRiskLevels=@()}; grantControls=@{operator='OR';builtInControls=@('mfa');authenticationStrength=$null;termsOfUse=@()}; sessionControls=$null }
        )
        $snap.Groups = @([PSCustomObject]@{ id='g1'; displayName='TestGroup' })
        $snap.DirectoryRoles = @([PSCustomObject]@{ id='r1'; roleTemplateId='62e90394-69f5-4237-9190-012177145e10'; displayName='Global Administrator' })
        $snap.ServicePrincipals = @([PSCustomObject]@{ id='sp1'; appId='app1'; displayName='TestApp' })
        $snap.NamedLocations = @([PSCustomObject]@{ id='nl1'; displayName='Corporate'; '@odata.type'='#microsoft.graph.ipNamedLocation'; isTrusted=$true; ipRanges=@(@{cidrAddress='10.0.0.0/8'}) })
        $snap.ObjectCache = @{ 'All'='All'; 'g1'='TestGroup'; 'r1'='Global Administrator' }
        $snap.SignInsBypassed = @()
        $config = Get-NsConfig
        $html = New-NsModellerHtml -Snapshot $snap -Config $config
    }

    It 'Produces valid HTML' {
        $html | Should -Match '<!DOCTYPE html>'
        $html | Should -Match '</html>'
    }

    It 'Contains the NavySeal banner' {
        $html | Should -Match 'NavySeal Policy Modeller'
    }

    It 'Contains navigation links' {
        $html | Should -Match 'href="report.html"'
        $html | Should -Match 'href="modeller.html"'
    }

    It 'Contains the copyright footer' {
        $html | Should -Match 'NCS Dojo'
    }

    It 'Embeds tenant policies as JSON' {
        $html | Should -Match 'TestPolicy'
        $html | Should -Match 'var POLICIES='
    }

    It 'Embeds the object cache' {
        $html | Should -Match 'var CACHE='
    }

    It 'Embeds named locations' {
        $html | Should -Match 'var LOCATIONS='
        $html | Should -Match 'Corporate'
    }

    It 'Embeds sign-in data variable' {
        $html | Should -Match 'var SIGNINS='
    }

    It 'Populates group dropdown from snapshot' {
        $html | Should -Match 'TestGroup'
    }

    It 'Populates role dropdown from snapshot' {
        $html | Should -Match 'Global Administrator'
    }

    It 'Populates app dropdown from snapshot' {
        $html | Should -Match 'TestApp'
    }

    It 'Contains the CA evaluation engine' {
        $html | Should -Match 'function policyMatches'
        $html | Should -Match 'function evaluate'
        $html | Should -Match 'function evalDeviceFilter'
    }

    It 'Contains IPv6 support' {
        $html | Should -Match 'function expandIPv6'
        $html | Should -Match 'function parseIPv4'
    }

    It 'Contains scenario definitions' {
        $html | Should -Match 'var SCENARIOS='
    }

    It 'Contains traffic aggregation' {
        $html | Should -Match 'trafficMap'
        $html | Should -Match 'getTraffic'
    }

    It 'Contains network validation tab' {
        $html | Should -Match 'Network Location'
        $html | Should -Match 'function checkNetwork'
    }

    It 'Does not contain raw PowerShell variables' {
        $html | Should -Not -Match '\$Snapshot'
        $html | Should -Not -Match '\$Config'
    }
}

Describe 'Modeller JS engine correctness' {
    BeforeAll {
        $snap = [TenantSnapshot]::new()
        $snap.TenantId = 'test'
        $snap.CollectedAtUtc = [datetime]::UtcNow
        $blockPolicy = [PSCustomObject]@{ displayName='Block'; state='enabled'; conditions=@{users=@{includeUsers=@('All');excludeUsers=@();includeGroups=@();excludeGroups=@();includeRoles=@();excludeRoles=@()};applications=@{includeApplications=@('All');excludeApplications=@()};platforms=$null;clientAppTypes=@();locations=$null;userRiskLevels=@();signInRiskLevels=@();insiderRiskLevels=@();servicePrincipalRiskLevels=@()}; grantControls=@{operator='OR';builtInControls=@('block');authenticationStrength=$null;termsOfUse=@()}; sessionControls=$null }
        $mfaPolicy = [PSCustomObject]@{ displayName='MFA'; state='enabled'; conditions=@{users=@{includeUsers=@('All');excludeUsers=@();includeGroups=@();excludeGroups=@();includeRoles=@();excludeRoles=@()};applications=@{includeApplications=@('All');excludeApplications=@()};platforms=$null;clientAppTypes=@();locations=$null;userRiskLevels=@();signInRiskLevels=@();insiderRiskLevels=@();servicePrincipalRiskLevels=@()}; grantControls=@{operator='OR';builtInControls=@('mfa');authenticationStrength=$null;termsOfUse=@()}; sessionControls=$null }
        $snap.Policies = @($blockPolicy, $mfaPolicy)
        $snap.Groups = @(); $snap.DirectoryRoles = @(); $snap.ServicePrincipals = @(); $snap.NamedLocations = @()
        $snap.ObjectCache = @{}; $snap.SignInsBypassed = @()
        $config = Get-NsConfig
        $html = New-NsModellerHtml -Snapshot $snap -Config $config
    }

    It 'Embeds block policy with correct builtInControls' {
        $html | Should -Match '"block"'
    }

    It 'Embeds both policies' {
        ($html | Select-String -Pattern '"displayName"' -AllMatches).Matches.Count | Should -BeGreaterOrEqual 2
    }

    It 'Contains session conflict detection logic' {
        $html | Should -Match 'sessionConflict'
        $html | Should -Match 'SFI'
        $html | Should -Match 'MDCA'
    }

    It 'Contains device filter evaluation' {
        $html | Should -Match 'evalDeviceFilter'
        $html | Should -Match 'device\.trustType'
    }

    It 'Contains report-only tracking' {
        $html | Should -Match 'reportOnly'
        $html | Should -Match 'enabledForReportingButNotEnforced'
    }

    It 'Contains AND/OR operator satisfaction logic' {
        $html | Should -Match "gc\.operator==='AND'"
        $html | Should -Match 'allSatisfied'
    }
}

Describe 'Test-NsPimRoleEligibility' {
    It 'Detects PIM-eligible users without MFA' {
        $snap = [TenantSnapshot]::new()
        $snap.Policies = @(
            [PSCustomObject]@{ displayName='RoleMFA'; state='enabled'; conditions=@{users=@{includeUsers=@();excludeUsers=@();includeGroups=@();excludeGroups=@();includeRoles=@('62e90394-69f5-4237-9190-012177145e10');excludeRoles=@()};applications=@{includeApplications=@('All');excludeApplications=@()};platforms=$null;clientAppTypes=@();locations=$null;userRiskLevels=@();signInRiskLevels=@();insiderRiskLevels=@();servicePrincipalRiskLevels=@()}; grantControls=@{operator='OR';builtInControls=@('mfa');authenticationStrength=$null;termsOfUse=@()}; sessionControls=$null }
        )
        $snap.DirectoryRoles = @([PSCustomObject]@{ id='r1'; roleTemplateId='62e90394-69f5-4237-9190-012177145e10'; displayName='Global Administrator' })
        $snap.ObjectCache = @{ '62e90394-69f5-4237-9190-012177145e10' = 'Global Administrator'; 'other-role-id' = 'Security Reader' }

        # User with eligible-only assignment to a different role (not GA)
        $ctx1 = [UserPolicyContext]::new('u1', 'pim@test.com', 'PIM User')
        $ctx1.IsPimEligible = $true
        [void]$ctx1.EligibleRoleIds.Add('other-role-id')
        $snap.UserContextMap = @{ 'u1' = $ctx1 }

        $nsCtx = [NsContext]::Build($snap, @{})
        $results = Test-NsPimRoleEligibility -Context $nsCtx
        $results.Count | Should -BeGreaterOrEqual 1
    }
}

Describe 'Test-NsPimGovernance' {
    It 'Flags excessive Global Administrators' {
        $snap = [TenantSnapshot]::new()
        $gaRoleId = '62e90394-69f5-4237-9190-012177145e10'
        $snap.RoleTemplates = @([PSCustomObject]@{ id = $gaRoleId; displayName = 'Global Administrator' })
        $snap.DirectoryRoles = @([PSCustomObject]@{
            roleTemplateId = $gaRoleId
            members = @(1..6 | ForEach-Object { [PSCustomObject]@{ id = "ga$_"; displayName = "GA $_"; userPrincipalName = "ga$_@test.com" } })
        })
        $snap.Policies = @()
        $snap.PimActiveSchedules = @()
        $snap.PimEligibleAssignments = @()
        $snap.Users = @()
        $nsCtx = [NsContext]::Build($snap, @{})
        $results = Test-NsPimGovernance -Context $nsCtx
        $results | Where-Object { $_.Title -match 'Global Admin' } | Should -Not -BeNullOrEmpty
    }

    It 'Flags permanent role assignments' {
        $snap = [TenantSnapshot]::new()
        $gaRoleId = '62e90394-69f5-4237-9190-012177145e10'
        $snap.RoleTemplates = @([PSCustomObject]@{ id = $gaRoleId; displayName = 'Global Administrator' })
        $snap.DirectoryRoles = @([PSCustomObject]@{
            roleTemplateId = $gaRoleId
            members = @([PSCustomObject]@{ id = 'u1'; displayName = 'User 1'; userPrincipalName = 'u1@test.com' })
        })
        $snap.Policies = @()
        $snap.PimActiveSchedules = @([PSCustomObject]@{
            principalId = 'u1'; roleDefinitionId = $gaRoleId; assignmentType = 'Assigned'; endDateTime = $null
        })
        $snap.PimEligibleAssignments = @()
        $snap.Users = @([PSCustomObject]@{ id = 'u1'; userPrincipalName = 'u1@test.com' })
        $nsCtx = [NsContext]::Build($snap, @{})
        $results = Test-NsPimGovernance -Context $nsCtx
        $results | Where-Object { $_.Title -match 'permanent' } | Should -Not -BeNullOrEmpty
    }
}

# SIG # Begin signature block
# MII9GQYJKoZIhvcNAQcCoII9CjCCPQYCAQExDzANBglghkgBZQMEAgEFADB5Bgor
# BgEEAYI3AgEEoGswaTA0BgorBgEEAYI3AgEeMCYCAwEAAAQQH8w7YFlLCE63JNLG
# KX7zUQIBAAIBAAIBAAIBAAIBADAxMA0GCWCGSAFlAwQCAQUABCDM3PHX9RJKRQct
# Alg4ofr0OjMCIDaMQEiASIBe3E82PaCCIdwwggXMMIIDtKADAgECAhBUmNLR1FsZ
# 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
# 03u4aUoqlmZpxJTG9F9urJh4iIAGXKKy7aIwggabMIIEg6ADAgECAhMzAAE6T9lx
# 3eo/npL1AAAAATpPMA0GCSqGSIb3DQEBDAUAMFoxCzAJBgNVBAYTAlVTMR4wHAYD
# VQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xKzApBgNVBAMTIk1pY3Jvc29mdCBJ
# RCBWZXJpZmllZCBDUyBBT0MgQ0EgMDMwHhcNMjYwNTIxMTg1MTE4WhcNMjYwNTI0
# MTg1MTE4WjBfMQswCQYDVQQGEwJDQTEQMA4GA1UECBMHQWxiZXJ0YTEQMA4GA1UE
# BxMHQ2FsZ2FyeTEVMBMGA1UEChMMRGFycmVuIE1heWVzMRUwEwYDVQQDEwxEYXJy
# ZW4gTWF5ZXMwggGiMA0GCSqGSIb3DQEBAQUAA4IBjwAwggGKAoIBgQCnVDNpGjHl
# JgszvxN+dtZEikDyGdiuoXOP/NV/PcHCsQXESnF1SUa2vXjiRr5ppchGTCTN45RW
# f9i5GgeG4zgIBsvI3OrAx8atJe4wsezXSVTrJsyrLM6yy9xkTXcGMJxx6g5VoNm8
# /Lg9Zhp2ST9MNkWP1X3bdEc5O2OkIs8pKldqL0SAZ7Aw6HshFPXMfi0QA8pshH1m
# ZmdQIlyQh/m7WRYsnVq2N/XZ80lDtxHnsbBLUinh5KfZmoC3MmdQuxmAvDMXO5wx
# gvwa7g+66/vFp111lfS9eOFwxjUXpICnDaNV01PExdHk1Fm2wP7gGmxviCjA4UV5
# EFpoTXqvpGYVw4BvnCZ/szsu/Slr1rDpxdBc15SJ3gkw9QS90rV8YIqDO8iyS/C/
# pFaa5YklAH93Y8paacWVzg4SvWzAXmhP71PHnoStYyTIOELRz3DYNQUv3xvFsKoi
# sclutKjKuTiXYojwpfzkOXLs0Kl0MCdaselLfwpZILLWyIdeBwzo7g0CAwEAAaOC
# AdMwggHPMAwGA1UdEwEB/wQCMAAwDgYDVR0PAQH/BAQDAgeAMDoGA1UdJQQzMDEG
# CisGAQQBgjdhAQAGCCsGAQUFBwMDBhkrBgEEAYI3YYuPpXGB3qaBQNv/tAST5rkV
# MB0GA1UdDgQWBBR+UjK+gq4lWZR8FjbnMSfjErFoFDAfBgNVHSMEGDAWgBSkQwx/
# dlqlhec+jSgPDBeiRWlwxjBnBgNVHR8EYDBeMFygWqBYhlZodHRwOi8vd3d3Lm1p
# Y3Jvc29mdC5jb20vcGtpb3BzL2NybC9NaWNyb3NvZnQlMjBJRCUyMFZlcmlmaWVk
# JTIwQ1MlMjBBT0MlMjBDQSUyMDAzLmNybDB0BggrBgEFBQcBAQRoMGYwZAYIKwYB
# BQUHMAKGWGh0dHA6Ly93d3cubWljcm9zb2Z0LmNvbS9wa2lvcHMvY2VydHMvTWlj
# cm9zb2Z0JTIwSUQlMjBWZXJpZmllZCUyMENTJTIwQU9DJTIwQ0ElMjAwMy5jcnQw
# VAYDVR0gBE0wSzBJBgRVHSAAMEEwPwYIKwYBBQUHAgEWM2h0dHA6Ly93d3cubWlj
# cm9zb2Z0LmNvbS9wa2lvcHMvRG9jcy9SZXBvc2l0b3J5Lmh0bTANBgkqhkiG9w0B
# AQwFAAOCAgEAtaw54Hz+2BUfCYDiR4REkDLEqQQGSNm393kUM090/K+HI4zxgos6
# dpLBpdinakSSmTM0XpHEE54+yfjB0X8yjkZhr6QXQWVVTzP8bx/kQWYVMwu/v66f
# VlrMO58rUI2hMFKGwwsK/R6cdMP3amiOYrRhnEOSh98q+ie+GOq35uKeaPoYev67
# 1abV8hBv5l06LyelJWvNVJvKT53ehTjRuf9jFfe9sWwlddH3pNLRfnJhTeUCEHBl
# HqQwxwQVju7Z45yN6FihPkkq1DxzBkEmH/5HOMovjGDNDulG7F8k2rkYBL877oUc
# Ug11e/vig1ud5yJqGnod+Y3O9ZbdTEwWM1mllTWdVVq2BPLuMaSimJuUX2Ss+Ilz
# R1HBgofgWgsBHPtbqgW3LvG5OTwg4n2qu/c3GUG6ryqvHVRBuenMp9C+46lJU3w4
# wBD39RfUABk9jcO4G0WPoWJRMie9LcLIhK0pAezlfxlWnwNewE2N/1QnAvKC17h2
# OmcpsE9uRcqcft4asKk1FraXvs0iNAxctjOTdYnAUg3u4K4Hjau2jJpA3rfjQJHC
# N8SICi4KCGZtHXXltRcJ4x3qYzt2OttJRnY5aj5PKTMcPeHkXrgfngBWAwLphU83
# riIUV3Ew/C7ZKwtWf1huH6eZjjtKMQ5kE9QFBYxkrSgBWzw4wpq0UjMwggabMIIE
# g6ADAgECAhMzAAE6T9lx3eo/npL1AAAAATpPMA0GCSqGSIb3DQEBDAUAMFoxCzAJ
# BgNVBAYTAlVTMR4wHAYDVQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xKzApBgNV
# BAMTIk1pY3Jvc29mdCBJRCBWZXJpZmllZCBDUyBBT0MgQ0EgMDMwHhcNMjYwNTIx
# MTg1MTE4WhcNMjYwNTI0MTg1MTE4WjBfMQswCQYDVQQGEwJDQTEQMA4GA1UECBMH
# QWxiZXJ0YTEQMA4GA1UEBxMHQ2FsZ2FyeTEVMBMGA1UEChMMRGFycmVuIE1heWVz
# MRUwEwYDVQQDEwxEYXJyZW4gTWF5ZXMwggGiMA0GCSqGSIb3DQEBAQUAA4IBjwAw
# ggGKAoIBgQCnVDNpGjHlJgszvxN+dtZEikDyGdiuoXOP/NV/PcHCsQXESnF1SUa2
# vXjiRr5ppchGTCTN45RWf9i5GgeG4zgIBsvI3OrAx8atJe4wsezXSVTrJsyrLM6y
# y9xkTXcGMJxx6g5VoNm8/Lg9Zhp2ST9MNkWP1X3bdEc5O2OkIs8pKldqL0SAZ7Aw
# 6HshFPXMfi0QA8pshH1mZmdQIlyQh/m7WRYsnVq2N/XZ80lDtxHnsbBLUinh5KfZ
# moC3MmdQuxmAvDMXO5wxgvwa7g+66/vFp111lfS9eOFwxjUXpICnDaNV01PExdHk
# 1Fm2wP7gGmxviCjA4UV5EFpoTXqvpGYVw4BvnCZ/szsu/Slr1rDpxdBc15SJ3gkw
# 9QS90rV8YIqDO8iyS/C/pFaa5YklAH93Y8paacWVzg4SvWzAXmhP71PHnoStYyTI
# OELRz3DYNQUv3xvFsKoisclutKjKuTiXYojwpfzkOXLs0Kl0MCdaselLfwpZILLW
# yIdeBwzo7g0CAwEAAaOCAdMwggHPMAwGA1UdEwEB/wQCMAAwDgYDVR0PAQH/BAQD
# AgeAMDoGA1UdJQQzMDEGCisGAQQBgjdhAQAGCCsGAQUFBwMDBhkrBgEEAYI3YYuP
# pXGB3qaBQNv/tAST5rkVMB0GA1UdDgQWBBR+UjK+gq4lWZR8FjbnMSfjErFoFDAf
# BgNVHSMEGDAWgBSkQwx/dlqlhec+jSgPDBeiRWlwxjBnBgNVHR8EYDBeMFygWqBY
# hlZodHRwOi8vd3d3Lm1pY3Jvc29mdC5jb20vcGtpb3BzL2NybC9NaWNyb3NvZnQl
# MjBJRCUyMFZlcmlmaWVkJTIwQ1MlMjBBT0MlMjBDQSUyMDAzLmNybDB0BggrBgEF
# BQcBAQRoMGYwZAYIKwYBBQUHMAKGWGh0dHA6Ly93d3cubWljcm9zb2Z0LmNvbS9w
# a2lvcHMvY2VydHMvTWljcm9zb2Z0JTIwSUQlMjBWZXJpZmllZCUyMENTJTIwQU9D
# JTIwQ0ElMjAwMy5jcnQwVAYDVR0gBE0wSzBJBgRVHSAAMEEwPwYIKwYBBQUHAgEW
# M2h0dHA6Ly93d3cubWljcm9zb2Z0LmNvbS9wa2lvcHMvRG9jcy9SZXBvc2l0b3J5
# Lmh0bTANBgkqhkiG9w0BAQwFAAOCAgEAtaw54Hz+2BUfCYDiR4REkDLEqQQGSNm3
# 93kUM090/K+HI4zxgos6dpLBpdinakSSmTM0XpHEE54+yfjB0X8yjkZhr6QXQWVV
# TzP8bx/kQWYVMwu/v66fVlrMO58rUI2hMFKGwwsK/R6cdMP3amiOYrRhnEOSh98q
# +ie+GOq35uKeaPoYev671abV8hBv5l06LyelJWvNVJvKT53ehTjRuf9jFfe9sWwl
# ddH3pNLRfnJhTeUCEHBlHqQwxwQVju7Z45yN6FihPkkq1DxzBkEmH/5HOMovjGDN
# DulG7F8k2rkYBL877oUcUg11e/vig1ud5yJqGnod+Y3O9ZbdTEwWM1mllTWdVVq2
# BPLuMaSimJuUX2Ss+IlzR1HBgofgWgsBHPtbqgW3LvG5OTwg4n2qu/c3GUG6ryqv
# HVRBuenMp9C+46lJU3w4wBD39RfUABk9jcO4G0WPoWJRMie9LcLIhK0pAezlfxlW
# nwNewE2N/1QnAvKC17h2OmcpsE9uRcqcft4asKk1FraXvs0iNAxctjOTdYnAUg3u
# 4K4Hjau2jJpA3rfjQJHCN8SICi4KCGZtHXXltRcJ4x3qYzt2OttJRnY5aj5PKTMc
# PeHkXrgfngBWAwLphU83riIUV3Ew/C7ZKwtWf1huH6eZjjtKMQ5kE9QFBYxkrSgB
# Wzw4wpq0UjMwggcoMIIFEKADAgECAhMzAAAAGA3rkVWpigCYAAAAAAAYMA0GCSqG
# SIb3DQEBDAUAMGMxCzAJBgNVBAYTAlVTMR4wHAYDVQQKExVNaWNyb3NvZnQgQ29y
# cG9yYXRpb24xNDAyBgNVBAMTK01pY3Jvc29mdCBJRCBWZXJpZmllZCBDb2RlIFNp
# Z25pbmcgUENBIDIwMjEwHhcNMjYwMzI2MTgxMTMyWhcNMzEwMzI2MTgxMTMyWjBa
# MQswCQYDVQQGEwJVUzEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMSsw
# KQYDVQQDEyJNaWNyb3NvZnQgSUQgVmVyaWZpZWQgQ1MgQU9DIENBIDAzMIICIjAN
# BgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAyIDaYDRWoon9lVnlj+SOj5xV8Sf5
# Qd+3yUeeRgr0exi2QTJAYo24ilcIKQSN8TOZ3+POM5x/6p3Cfjgqust44J0FvkfG
# Xe1Puy45a5nLJGpc0kNIITMRKZwVvPxx7NlfGSc0JOhz/kg7G77C+y3ZR/3jtpeJ
# pJ4QwcK9Gf0Peuk7xLYeW/JAsY9b6oleGDbYSxkamUfbtnyv8gTFrvN6ejuLqNhH
# YPvoBHsOSC+7555yhapkof0fbzyct1hdWHGXsAFMfLF2TVJ8d2YVYOfZdi6YrT4s
# MxOhTKiLKmhL1XtzM7hXdmv7lg2R+lWw8lIkSu/JiINQ0GAPcwxMsgRXDSPp8VUs
# 4Jby+ruz0bjaoHFd7H+hC8cPPcrEDP2eEdYURVl0acjliigCrXwR05NFJzYj3MZi
# zDGLPI3lIzonX1T40yK8v1FcJ8MXZZCvOXGXwRDGGfwwTTsHaJj+OfWNZ/IsypG4
# bGvqeJcPnEFcQEwRcfYIEe/R4a8k+xw5qTy75CbwWeMFuAlt9lE9kjMg3tvJyDlN
# 5voXx5VXinCwUHMpuVaEQ4yHAlSO7qoBltjzTBNHH3ovMwsAsuhwrLLCVhUu3oP2
# GxYZwEyXMlnzK5DbgGzHzDfDaYPHK0uo1VaMMg9Bhuc3YIvrkFXEiv+t/JgNcRGC
# t6ZyKEIDtPbrgwcCAwEAAaOCAdwwggHYMA4GA1UdDwEB/wQEAwIBhjAQBgkrBgEE
# AYI3FQEEAwIBADAdBgNVHQ4EFgQUpEMMf3ZapYXnPo0oDwwXokVpcMYwVAYDVR0g
# BE0wSzBJBgRVHSAAMEEwPwYIKwYBBQUHAgEWM2h0dHA6Ly93d3cubWljcm9zb2Z0
# LmNvbS9wa2lvcHMvRG9jcy9SZXBvc2l0b3J5Lmh0bTAZBgkrBgEEAYI3FAIEDB4K
# AFMAdQBiAEMAQTASBgNVHRMBAf8ECDAGAQH/AgEAMB8GA1UdIwQYMBaAFNlBKbAP
# D2Ns72nX9c0pnqRIajDmMHAGA1UdHwRpMGcwZaBjoGGGX2h0dHA6Ly93d3cubWlj
# cm9zb2Z0LmNvbS9wa2lvcHMvY3JsL01pY3Jvc29mdCUyMElEJTIwVmVyaWZpZWQl
# MjBDb2RlJTIwU2lnbmluZyUyMFBDQSUyMDIwMjEuY3JsMH0GCCsGAQUFBwEBBHEw
# bzBtBggrBgEFBQcwAoZhaHR0cDovL3d3dy5taWNyb3NvZnQuY29tL3BraW9wcy9j
# ZXJ0cy9NaWNyb3NvZnQlMjBJRCUyMFZlcmlmaWVkJTIwQ29kZSUyMFNpZ25pbmcl
# MjBQQ0ElMjAyMDIxLmNydDANBgkqhkiG9w0BAQwFAAOCAgEAcccgVvl+poXUYksA
# /TzDFnBlAJ8ef0FMJzb2XRRhF/uA0QyK/VgoeAvO8B7cPpYNQ97sytdA7LT19CxS
# wRQAt71jGF+CJl8KC4aEdMZTfJlHaKyd24J6QiVriNed9WdawsD7lK0pAcXziBg5
# N6dhAm9x6P8R4uT0UkfzlK1rkB8F4mlzE7l7tyES3s8FZGaRZjcGEQ+e0fTcdhf8
# jO7czmNB4dIRgmmBCt/P+ha0tEl2nV1sg1An5+VzhgAkY1Apx8fiUFBtH+Ehw/om
# 5aQCNIJfmR51ZnV18R02Xk2tAmAiIRcSj9vdtrNIOsy5nolddy1lJrbf1Be061l6
# TItv9FDZ4mg6B+65zxkVecVV/Ll8uLGYouGrMM6jzO2O/ps3K2p6mfBI2ZOYIy4U
# NwNrGWqa5TrvAmkZsn3CIlR+81X4AL5vNTFlxc4gH+5su0Dr58hBTxnXavDEnz7X
# 0csP1Kt7h+iqaGiTSHz2B+n3HmUoud0WrdQPYKxMat0To4YUqU3HIbgSLQDDVT8a
# CjW1Jvokf1915C/vVkIIp48h3voVy3JWPLwBlxQ9aeND6jCKQGLJhCQRSlvXX+P/
# 9TeaEA6/xWPSASZf6Ekve/Yua7U+zWc/Sr2K2gj0QRrNEAsvrFr4EGtHKDO9ECVS
# 3lcJksVDv9KHdMPUK8u20i68RqAwggeeMIIFhqADAgECAhMzAAAAB4ejNKN7pY4c
# 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
# 4WrxSK5nMYIakzCCGo8CAQEwcTBaMQswCQYDVQQGEwJVUzEeMBwGA1UEChMVTWlj
# cm9zb2Z0IENvcnBvcmF0aW9uMSswKQYDVQQDEyJNaWNyb3NvZnQgSUQgVmVyaWZp
# ZWQgQ1MgQU9DIENBIDAzAhMzAAE6T9lx3eo/npL1AAAAATpPMA0GCWCGSAFlAwQC
# AQUAoF4wEAYKKwYBBAGCNwIBDDECMAAwGQYJKoZIhvcNAQkDMQwGCisGAQQBgjcC
# AQQwLwYJKoZIhvcNAQkEMSIEIB261PMankCoHtKRDz4xz353yJmt9SA+vLnPaInf
# 43n1MA0GCSqGSIb3DQEBAQUABIIBgB0Q+MHrdvvsmTm0qB3I8Ha39EMP0CI7zK61
# VhkJHWs2RK+lXwSR26YYYGs3cCftAba+hzLGtg20Cm0rU2hNcQ0nTnIkwtaqk7bb
# J6moFKoMfRk2cJvptvRMr9/jTWazUAjFkb9JAjO5aPC4zPQtt/T+SPZFMjwXvtKA
# sLNuITSVvjMe0jk3BDP8DbFLsgrubbSdkMPpkEWd7X510GvxedhgtO3/BUPkCXwm
# KCyt4x3JQ1gTyKtz1NefCq4u9ZHXDDRLJ5vR3gZMCW1REu3N3b0L6gocdUNbbRh+
# zj4EWFq3gJrv3f0+VE6zJBRwZrW92hAsbce6ui6IK/1+Vy4cGVmmXzJ9nr3feDjf
# +Qp30uj7b54X3noAb5ERRJNLLSkX6WcH4U/teQ5SKL8Rrd+FNTgirCdFS7kb2SnH
# fVaqXWsq34yf5Leb1ib7rXMVOgRkwB2bRKaR0hCnPTYrpiB9NvI6PX9VPThjNNVM
# JmuQ2g6tB8RNGgTKoBT9tlSSqdorl6GCGBMwghgPBgorBgEEAYI3AwMBMYIX/zCC
# F/sGCSqGSIb3DQEHAqCCF+wwghfoAgEDMQ8wDQYJYIZIAWUDBAIBBQAwggFhBgsq
# hkiG9w0BCRABBKCCAVAEggFMMIIBSAIBAQYKKwYBBAGEWQoDATAxMA0GCWCGSAFl
# AwQCAQUABCDYNZfxEef2HlzouOlQzAnRBxudum9m+E8hldDpjquxUwIGagxE1T5t
# GBIyMDI2MDUyMjAxMTEyOS4xMVowBIACAfSggeGkgd4wgdsxCzAJBgNVBAYTAlVT
# MRMwEQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQK
# ExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xJTAjBgNVBAsTHE1pY3Jvc29mdCBBbWVy
# aWNhIE9wZXJhdGlvbnMxJzAlBgNVBAsTHm5TaGllbGQgVFNTIEVTTjo3ODAwLTA1
# RTAtRDk0NzE1MDMGA1UEAxMsTWljcm9zb2Z0IFB1YmxpYyBSU0EgVGltZSBTdGFt
# cGluZyBBdXRob3JpdHmggg8hMIIHgjCCBWqgAwIBAgITMwAAAAXlzw//Zi7JhwAA
# AAAABTANBgkqhkiG9w0BAQwFADB3MQswCQYDVQQGEwJVUzEeMBwGA1UEChMVTWlj
# cm9zb2Z0IENvcnBvcmF0aW9uMUgwRgYDVQQDEz9NaWNyb3NvZnQgSWRlbnRpdHkg
# VmVyaWZpY2F0aW9uIFJvb3QgQ2VydGlmaWNhdGUgQXV0aG9yaXR5IDIwMjAwHhcN
# MjAxMTE5MjAzMjMxWhcNMzUxMTE5MjA0MjMxWjBhMQswCQYDVQQGEwJVUzEeMBwG
# A1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMTIwMAYDVQQDEylNaWNyb3NvZnQg
# UHVibGljIFJTQSBUaW1lc3RhbXBpbmcgQ0EgMjAyMDCCAiIwDQYJKoZIhvcNAQEB
# BQADggIPADCCAgoCggIBAJ5851Jj/eDFnwV9Y7UGIqMcHtfnlzPREwW9ZUZHd5HB
# XXBvf7KrQ5cMSqFSHGqg2/qJhYqOQxwuEQXG8kB41wsDJP5d0zmLYKAY8Zxv3lYk
# uLDsfMuIEqvGYOPURAH+Ybl4SJEESnt0MbPEoKdNihwM5xGv0rGofJ1qOYSTNcc5
# 5EbBT7uq3wx3mXhtVmtcCEr5ZKTkKKE1CxZvNPWdGWJUPC6e4uRfWHIhZcgCsJ+s
# ozf5EeH5KrlFnxpjKKTavwfFP6XaGZGWUG8TZaiTogRoAlqcevbiqioUz1Yt4FRK
# 53P6ovnUfANjIgM9JDdJ4e0qiDRm5sOTiEQtBLGd9Vhd1MadxoGcHrRCsS5rO9yh
# v2fjJHrmlQ0EIXmp4DhDBieKUGR+eZ4CNE3ctW4uvSDQVeSp9h1SaPV8UWEfyTxg
# GjOsRpeexIveR1MPTVf7gt8hY64XNPO6iyUGsEgt8c2PxF87E+CO7A28TpjNq5eL
# iiunhKbq0XbjkNoU5JhtYUrlmAbpxRjb9tSreDdtACpm3rkpxp7AQndnI0Shu/fk
# 1/rE3oWsDqMX3jjv40e8KN5YsJBnczyWB4JyeeFMW3JBfdeAKhzohFe8U5w9Wuvc
# P1E8cIxLoKSDzCCBOu0hWdjzKNu8Y5SwB1lt5dQhABYyzR3dxEO/T1K/BVF3rV69
# AgMBAAGjggIbMIICFzAOBgNVHQ8BAf8EBAMCAYYwEAYJKwYBBAGCNxUBBAMCAQAw
# HQYDVR0OBBYEFGtpKDo1L0hjQM972K9J6T7ZPdshMFQGA1UdIARNMEswSQYEVR0g
# ADBBMD8GCCsGAQUFBwIBFjNodHRwOi8vd3d3Lm1pY3Jvc29mdC5jb20vcGtpb3Bz
# L0RvY3MvUmVwb3NpdG9yeS5odG0wEwYDVR0lBAwwCgYIKwYBBQUHAwgwGQYJKwYB
# BAGCNxQCBAweCgBTAHUAYgBDAEEwDwYDVR0TAQH/BAUwAwEB/zAfBgNVHSMEGDAW
# gBTIftJqhSobyhmYBAcnz1AQT2ioojCBhAYDVR0fBH0wezB5oHegdYZzaHR0cDov
# L3d3dy5taWNyb3NvZnQuY29tL3BraW9wcy9jcmwvTWljcm9zb2Z0JTIwSWRlbnRp
# dHklMjBWZXJpZmljYXRpb24lMjBSb290JTIwQ2VydGlmaWNhdGUlMjBBdXRob3Jp
# dHklMjAyMDIwLmNybDCBlAYIKwYBBQUHAQEEgYcwgYQwgYEGCCsGAQUFBzAChnVo
# dHRwOi8vd3d3Lm1pY3Jvc29mdC5jb20vcGtpb3BzL2NlcnRzL01pY3Jvc29mdCUy
# MElkZW50aXR5JTIwVmVyaWZpY2F0aW9uJTIwUm9vdCUyMENlcnRpZmljYXRlJTIw
# QXV0aG9yaXR5JTIwMjAyMC5jcnQwDQYJKoZIhvcNAQEMBQADggIBAF+Idsd+bbVa
# FXXnTHho+k7h2ESZJRWluLE0Oa/pO+4ge/XEizXvhs0Y7+KVYyb4nHlugBesnFqB
# GEdC2IWmtKMyS1OWIviwpnK3aL5JedwzbeBF7POyg6IGG/XhhJ3UqWeWTO+Czb1c
# 2NP5zyEh89F72u9UIw+IfvM9lzDmc2O2END7MPnrcjWdQnrLn1Ntday7JSyrDvBd
# mgbNnCKNZPmhzoa8PccOiQljjTW6GePe5sGFuRHzdFt8y+bN2neF7Zu8hTO1I64X
# NGqst8S+w+RUdie8fXC1jKu3m9KGIqF4aldrYBamyh3g4nJPj/LR2CBaLyD+2BuG
# ZCVmoNR/dSpRCxlot0i79dKOChmoONqbMI8m04uLaEHAv4qwKHQ1vBzbV/nG89LD
# KbRSSvijmwJwxRxLLpMQ/u4xXxFfR4f/gksSkbJp7oqLwliDm/h+w0aJ/U5ccnYh
# Yb7vPKNMN+SZDWycU5ODIRfyoGl59BsXR/HpRGtiJquOYGmvA/pk5vC1lcnbeMrc
# WD/26ozePQ/TWfNXKBOmkFpvPE8CH+EeGGWzqTCjdAsno2jzTeNSxlx3glDGJgcd
# z5D/AAxw9Sdgq/+rY7jjgs7X6fqPTXPmaCAJKVHAP19oEjJIBwD1LyHbaEgBxFCo
# gYSOiUIr0Xqcr1nJfiWG2GwYe6ZoAF1bMIIHlzCCBX+gAwIBAgITMwAAAFck05Xg
# ounJMQAAAAAAVzANBgkqhkiG9w0BAQwFADBhMQswCQYDVQQGEwJVUzEeMBwGA1UE
# ChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMTIwMAYDVQQDEylNaWNyb3NvZnQgUHVi
# bGljIFJTQSBUaW1lc3RhbXBpbmcgQ0EgMjAyMDAeFw0yNTEwMjMyMDQ2NTNaFw0y
# NjEwMjIyMDQ2NTNaMIHbMQswCQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3Rv
# bjEQMA4GA1UEBxMHUmVkbW9uZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0
# aW9uMSUwIwYDVQQLExxNaWNyb3NvZnQgQW1lcmljYSBPcGVyYXRpb25zMScwJQYD
# VQQLEx5uU2hpZWxkIFRTUyBFU046NzgwMC0wNUUwLUQ5NDcxNTAzBgNVBAMTLE1p
# Y3Jvc29mdCBQdWJsaWMgUlNBIFRpbWUgU3RhbXBpbmcgQXV0aG9yaXR5MIICIjAN
# BgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAsWylCpMIfbizJLY1kPXO2cmX2HRW
# vRbAmeKSZ5ex7/jCymdV7Eap+Ic2iqRtWDkKKe5gL6JV80wtn5C2qHJLPxUYFKNG
# 3UkHkAI21MoCN+YWnhT8K/YuPib6+6970jdbeFKIiZMWwd5hnpX9J3jeteuEdXbp
# /DfFBK15JuD3JOzWuF2suQCPgqYjQPk/gpq+3KCKtXJRbXSCSJ9YtITU2IHwmfdE
# 7l2PfZ154w041po+fDeTj0gJOzcV/Jv56Q0M+w19jAKo/I5PEzrLV1IPQnmP4or1
# X4RbJXk8ONXyOOfXOxK2VLpNxgklK1yAezbFP2uzqihaXkW1h9GQLGENKESnezwg
# dRaLNNaYtm8AT/pZHYJ35mZVqkZdMIckpQHJk/F1fSLyDKeKtH4TC4cc3ESKUMgI
# tq07ZZm74JCsfhmrQ1ijVNDi1Sln+QBamgC7WviZbkQnceQRq9DY+6hANwOrasAZ
# UiVr2kPuj1jHDOXzUG4O9QTK70P/oXSqZAN1oTv3UfF8JTGmAxg+l1ZPOz50MY96
# HBDw/3bI/wBGNvLk6fLVnrxGN5B5unF/lYvjjWbIUdyBPVQnPOKXu08SRHbY19M1
# HoWX6PNZv+vzSeqVeWWHKdKjC3GjVjbbGpi+JLbiyaKRSwEqo49tJLvu69cQ7dWs
# bksai4TURnVj2mMCAwEAAaOCAcswggHHMB0GA1UdDgQWBBSOg8leLTUOAglIZ+bj
# XpiD7RKSpzAfBgNVHSMEGDAWgBRraSg6NS9IY0DPe9ivSek+2T3bITBsBgNVHR8E
# ZTBjMGGgX6BdhltodHRwOi8vd3d3Lm1pY3Jvc29mdC5jb20vcGtpb3BzL2NybC9N
# aWNyb3NvZnQlMjBQdWJsaWMlMjBSU0ElMjBUaW1lc3RhbXBpbmclMjBDQSUyMDIw
# MjAuY3JsMHkGCCsGAQUFBwEBBG0wazBpBggrBgEFBQcwAoZdaHR0cDovL3d3dy5t
# aWNyb3NvZnQuY29tL3BraW9wcy9jZXJ0cy9NaWNyb3NvZnQlMjBQdWJsaWMlMjBS
# U0ElMjBUaW1lc3RhbXBpbmclMjBDQSUyMDIwMjAuY3J0MAwGA1UdEwEB/wQCMAAw
# FgYDVR0lAQH/BAwwCgYIKwYBBQUHAwgwDgYDVR0PAQH/BAQDAgeAMGYGA1UdIARf
# MF0wUQYMKwYBBAGCN0yDfQEBMEEwPwYIKwYBBQUHAgEWM2h0dHA6Ly93d3cubWlj
# cm9zb2Z0LmNvbS9wa2lvcHMvRG9jcy9SZXBvc2l0b3J5Lmh0bTAIBgZngQwBBAIw
# DQYJKoZIhvcNAQEMBQADggIBAHJ1wHY86Zk5SUBDPY25d/u9YJVaaNa71uxjX4cy
# O/XJ4uPENCSOwkRTnNogPLxTD0Fg3z4TFf/2T/0IFSxdtWVtTjhzrn+WLInzeRaw
# UhTCFVrPBJKEWVshm+Ig7/nB7JbJN88+ltImBbL5kT1StBLfG6UksAcDbNSQww90
# CUXhGueBxlnSvjkAX1ohiN16y1bB2s0rvQx8Csepl2CuBefTfDrMGzW/tzNx5YaK
# 2D8OWweqTWZcGlJO4YjZNI83cTrQghfHl/8AXOHj8cWL3wEFltQQs2xeRYAb3Kdn
# l7oIWKKXWaBYJY5P3QPsiC+DTMp7ejdYKTrb396f3gr+wL/Ms5/Z3vIWZPJJv18q
# Nw40fUNveRnwzMQnx8dM2bGuXXQZ5y7P8aXT4HJMo349qZtn4XQwiUE/DDp++MUL
# 0kgjvd/Deo7Xr371PFPPYb4TboZhjV1x9+wCHDoOpNCBt+VuXU78ytJdKzQ1Jv2c
# EP1F9H9/wSLsMDUvWME7u9mGElOPDZPMVr8AuBEuLdbTSEdaLwsZBplzxLBcgxhZ
# /Cs30yBhuE3QhqT1YDZ2pa56RexPA2SasPcToT6gJgJ6E06BmZ2zQTNvWOjs5XQq
# HbYuXcoeDcwe2UaC7EDOGD8GmLE9LiqtQsuQCM7v7I2xR+sPZT2Ax/85HjIkM+3M
# zTK1MYIHRjCCB0ICAQEweDBhMQswCQYDVQQGEwJVUzEeMBwGA1UEChMVTWljcm9z
# b2Z0IENvcnBvcmF0aW9uMTIwMAYDVQQDEylNaWNyb3NvZnQgUHVibGljIFJTQSBU
# aW1lc3RhbXBpbmcgQ0EgMjAyMAITMwAAAFck05XgounJMQAAAAAAVzANBglghkgB
# ZQMEAgEFAKCCBJ8wEQYLKoZIhvcNAQkQAg8xAgUAMBoGCSqGSIb3DQEJAzENBgsq
# hkiG9w0BCRABBDAcBgkqhkiG9w0BCQUxDxcNMjYwNTIyMDExMTI5WjAvBgkqhkiG
# 9w0BCQQxIgQgwJNlIQ4o3UIfBxz8OoJm+krqfCB9qXFscwfGaYZjjgAwgbkGCyqG
# SIb3DQEJEAIvMYGpMIGmMIGjMIGgBCD1PJ9ktQVuTGWIbKLO4f1VUOlUU29ARCEp
# DZmFTHjbUjB8MGWkYzBhMQswCQYDVQQGEwJVUzEeMBwGA1UEChMVTWljcm9zb2Z0
# IENvcnBvcmF0aW9uMTIwMAYDVQQDEylNaWNyb3NvZnQgUHVibGljIFJTQSBUaW1l
# c3RhbXBpbmcgQ0EgMjAyMAITMwAAAFck05XgounJMQAAAAAAVzCCA2EGCyqGSIb3
# DQEJEAISMYIDUDCCA0yhggNIMIIDRDCCAiwCAQEwggEJoYHhpIHeMIHbMQswCQYD
# VQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9uZDEe
# MBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMSUwIwYDVQQLExxNaWNyb3Nv
# ZnQgQW1lcmljYSBPcGVyYXRpb25zMScwJQYDVQQLEx5uU2hpZWxkIFRTUyBFU046
# NzgwMC0wNUUwLUQ5NDcxNTAzBgNVBAMTLE1pY3Jvc29mdCBQdWJsaWMgUlNBIFRp
# bWUgU3RhbXBpbmcgQXV0aG9yaXR5oiMKAQEwBwYFKw4DAhoDFQD9LzE5nEJRAUE2
# Ss3xaKKPXHnLw6BnMGWkYzBhMQswCQYDVQQGEwJVUzEeMBwGA1UEChMVTWljcm9z
# b2Z0IENvcnBvcmF0aW9uMTIwMAYDVQQDEylNaWNyb3NvZnQgUHVibGljIFJTQSBU
# aW1lc3RhbXBpbmcgQ0EgMjAyMDANBgkqhkiG9w0BAQsFAAIFAO26Dw8wIhgPMjAy
# NjA1MjEyMzA5MDNaGA8yMDI2MDUyMjIzMDkwM1owdzA9BgorBgEEAYRZCgQBMS8w
# LTAKAgUA7boPDwIBADAKAgEAAgIBjgIB/zAHAgEAAgIRvDAKAgUA7btgjwIBADA2
# BgorBgEEAYRZCgQCMSgwJjAMBgorBgEEAYRZCgMCoAowCAIBAAIDB6EgoQowCAIB
# AAIDAYagMA0GCSqGSIb3DQEBCwUAA4IBAQC9jT020QdVPcZGGF38I00R2g/vNK+N
# vnd7FNGQgHnajZStqiO2fmWTOEGjjgZsWn68F06ZTtCWdh4Xa7+nAKUdQI7pd4Am
# wAPJqtO/qocqO/nobC+KLERurgvhnB+Opjk0sOaTHxWTNLa7OnV1ZiAkv9o5Yg2M
# fgOrGiR8LgkqzLFjOhrOF2dv9eLmLwQDbovTXgXs0Pdp5OWRKvq4Up/icfNVhiQE
# 8+uocy9fVYSpncGBD0uhgjrDA8eP8ubI1wJEPQfenGcGdIRK2zLdjFNgb2vYBRNm
# 3P4RtECNcwBoOe8eOa2/2KkXOzRMrXOj8IzV+qe0PicYIhNDcw+reCGzMA0GCSqG
# SIb3DQEBAQUABIICAGrdQ3A+s3q43FFCHiwmA/q9BTVWZC4SBNizzzEmg9jitTBW
# jjFa2Qsbvn6l1ZyjZtsM6DkyO/3tCW5rH3SdSD4p+FfBHbCIng7wLkagYoounjmX
# tgu6olck5x93tLe2oanzHg+MEJ/fLJr1Giev30ez+vbVWDOmX4zgmm9oVeMPWhBt
# yJagjYJpGZ2mp0KOh4oQO8Ne9MPal26elEf/qArCYIi7B7RO3jDkf0tCLHkm7pce
# 5UQIH/m9C4n6LbnbwHJNkeH/HXvGsHqr4RHttfmYiiMuKwrevrz5k2++195YwkEa
# /9hePeUq1HD1fOQ53qyx/WezOMnGbRX30sMXQpRzoSoeR4lSldRTLkI9yXHMPLz1
# w2M15htRV+miOq6roT42fMq+uZm8xbtaaKyk/Ssz9ZzShFuruk6EdQjW35g5z0ee
# +iJ78nMCP2batkBSkr5LpwW35F35sbBCNEOkMuZ+qXtBHnQp0Bb1CKPpSVV3IEe7
# NbbGpHEJSazbh6fT+rsw/P2jtcgw/Gg1woeTYLZMOdOnsz6y2UbY/FSV/A2k1YNH
# /hOCWImZDRe6xiWJ21KRukSDbBS5XR1TSST/SOHoene3cyQKZ8n2WwX6Hopr8bWz
# hQdXg8oLyp5QUYJF+SI69no7v2SGkdH/86BdJsdC0QCkwOFZ7AOehDNN4vNe
# SIG # End signature block