Public/Validation/Test-EntraOpsGeneratedArtifacts.ps1

<#
.SYNOPSIS
    Validates the integrity of generated Privileged EAM exports and Tenant Governance snapshots.

.DESCRIPTION
    Checks the RBAC-system aggregate files (<PrivilegedEamPath>/<RbacSystem>/<RbacSystem>.json) for invalid JSON,
    missing or duplicate object IDs, role assignments without RoleAssignmentInstanceId, duplicate assignment paths,
    unsupported Classification shapes and Classification/MatchedActions/ScopedObjects collections that collapsed
    from an array into a single value. Optionally checks a Tenant Governance snapshot folder for its manifest,
    invalid JSON, resource types that don't match their folder, identities stored in multiple files and count
    mismatches with the manifest.
    Violations stop the validation with one error that lists all of them. Contradictory object tier pairs and
    privileged assignments without classification are reported as warnings unless the related switch is set.
    Collapsed collections in an aggregate file that is tracked by git and unchanged since HEAD were written by
    an earlier version (the RBAC system returned no data or is no longer collected) and are reported as one
    warning per file; the next non-empty export rewrites them as arrays.
    Used by the Privileged EAM pull workflow/pipeline and Invoke-EntraOpsTenantGovernanceSnapshot before generated
    artifacts are committed.

.PARAMETER PrivilegedEamPath
    Folder of the Privileged EAM export. Default is ./PrivilegedEAM. Pass an empty value to validate only
    -TenantGovernancePath.

.PARAMETER FailOnContradictoryTierPair
    Treats an object whose tier level contradicts its tier name (ObjectAdminTierLevel/ObjectAdminTierLevelName,
    e.g. 0/ManagementPlane) as violation instead of a warning.

.PARAMETER TenantGovernancePath
    Folder of the Tenant Governance snapshots (e.g. ./TenantGovernance/Snapshots) to validate. Not validated
    when empty (default).

.PARAMETER FailOnPrivilegedAssignmentWithoutClassification
    Treats a role assignment marked as privileged (RoleIsPrivileged) without classification as violation
    instead of a warning.

.EXAMPLE
    Validate the Privileged EAM export in the default folder.
    Test-EntraOpsGeneratedArtifacts

.EXAMPLE
    Validate the Privileged EAM export and the Tenant Governance snapshots, and fail on contradictory tier pairs.
    Test-EntraOpsGeneratedArtifacts -PrivilegedEamPath ./PrivilegedEAM -TenantGovernancePath ./TenantGovernance/Snapshots -FailOnContradictoryTierPair
#>

function Test-EntraOpsGeneratedArtifacts {
[CmdletBinding()]
param (
    [Parameter(Mandatory = $false)]
    [string]$PrivilegedEamPath = './PrivilegedEAM',

    [Parameter(Mandatory = $false)]
    [switch]$FailOnContradictoryTierPair,

    [Parameter(Mandatory = $false)]
    [string]$TenantGovernancePath,

    [Parameter(Mandatory = $false)]
    [switch]$FailOnPrivilegedAssignmentWithoutClassification
)

$CanonicalTierLevelByName = @{
    ControlPlane   = '0'
    ManagementPlane = '1'
    WorkloadPlane = '1'
    UserAccess     = '2'
    Unclassified  = 'Unclassified'
}
$Violations = [System.Collections.Generic.List[string]]::new()
# Consumers (KQL parsers, watchlists, report apps) index these collections. A single-item array that
# collapsed into a scalar causes git churn without content change, so it is rejected as a violation.
# Collected per file: an unchanged committed export was written by an earlier version and is only
# reported (see below).
$ArrayShapeProperties = @('MatchedActions', 'ScopedObjects')
$ShapeIssues = [System.Collections.Generic.List[string]]::new()
function Test-ArtifactCollectionShape {
    param($Value, [string]$Context)
    if ($null -ne $Value -and $Value -isnot [array]) {
        $ShapeIssues.Add("$Context is stored as a single value instead of an array.")
    }
}
# True when the file is tracked and matches HEAD, i.e. it isn't output of the current run. An RBAC
# system with an empty result or one removed from RbacSystems keeps its previous export, so a strict
# check would fail every run until that system is exported again.
function Test-ArtifactCommittedUnchanged {
    param([string]$Path)
    if (-not (Get-Command git -CommandType Application -ErrorAction SilentlyContinue)) { return $false }
    $Directory = Split-Path -Parent $Path
    $Name = Split-Path -Leaf $Path
    & git -C $Directory ls-files --error-unmatch -- $Name *> $null
    if ($LASTEXITCODE -ne 0) { return $false }
    # 0 = working tree and index match HEAD; 1 = changed; anything else (e.g. no commit yet) = unknown
    & git -C $Directory diff --quiet HEAD -- $Name *> $null
    return $LASTEXITCODE -eq 0
}
function Test-ArtifactClassificationEntryShape {
    param($Classification, [string]$Context)
    foreach ($Entry in @($Classification)) {
        if ($null -eq $Entry -or $Entry -isnot [pscustomobject]) { continue }
        foreach ($PropertyName in $ArrayShapeProperties) {
            $Property = $Entry.PSObject.Properties[$PropertyName]
            if ($null -ne $Property) {
                Test-ArtifactCollectionShape -Value $Property.Value -Context "$Context classification '$($Entry.AdminTierLevelName)/$($Entry.Service)' $PropertyName"
            }
        }
    }
}
$TierPairWarnings = [System.Collections.Generic.List[string]]::new()
$DataQualityWarnings = [System.Collections.Generic.List[string]]::new()
$ObjectCount = 0
$AssignmentCount = 0
$TenantGovernanceResourceCount = 0

if ([string]::IsNullOrWhiteSpace($PrivilegedEamPath) -and [string]::IsNullOrWhiteSpace($TenantGovernancePath)) {
    throw 'Nothing to validate: pass -PrivilegedEamPath and/or -TenantGovernancePath.'
}
$ResolvedPrivilegedEamPath = if ([string]::IsNullOrWhiteSpace($PrivilegedEamPath)) { $null } else { $ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($PrivilegedEamPath) }
if ($ResolvedPrivilegedEamPath) {
    if (-not (Test-Path -LiteralPath $ResolvedPrivilegedEamPath -PathType Container)) {
        throw "Privileged EAM path '$ResolvedPrivilegedEamPath' does not exist."
    }

    $AggregateFiles = @(
        Get-ChildItem -LiteralPath $ResolvedPrivilegedEamPath -Directory | ForEach-Object {
            $AggregatePath = Join-Path $_.FullName "$($_.Name).json"
            if (Test-Path -LiteralPath $AggregatePath -PathType Leaf) {
                Get-Item -LiteralPath $AggregatePath
            }
        }
    )
    if ($AggregateFiles.Count -eq 0) {
        throw "No RBAC-system aggregate JSON files were found under '$ResolvedPrivilegedEamPath'."
    }

    foreach ($AggregateFile in $AggregateFiles) {
        $SeenObjectIds = [System.Collections.Generic.HashSet[string]]::new([System.StringComparer]::OrdinalIgnoreCase)
        $ShapeIssues.Clear()
        try {
            $EamObjects = @([System.IO.File]::ReadAllText($AggregateFile.FullName) | ConvertFrom-Json -Depth 100 -ErrorAction Stop)
        } catch {
            $Violations.Add("$($AggregateFile.FullName): invalid JSON - $($_.Exception.Message)")
            continue
        }

        foreach ($EamObject in $EamObjects) {
            $ObjectCount++
            $ObjectId = "$($EamObject.ObjectId)".Trim()
            if ([string]::IsNullOrWhiteSpace($ObjectId)) {
                $Violations.Add("$($AggregateFile.Name): an object is missing ObjectId.")
                $ObjectId = '<missing>'
            } elseif (-not $SeenObjectIds.Add($ObjectId)) {
                $Violations.Add("$($AggregateFile.Name): duplicate object '$ObjectId' appears in the RBAC-system aggregate.")
            }
            $TierName = "$($EamObject.ObjectAdminTierLevelName)"
            $TierLevel = "$($EamObject.ObjectAdminTierLevel)"
            if (-not $CanonicalTierLevelByName.ContainsKey($TierName) -or $TierLevel -ne $CanonicalTierLevelByName[$TierName]) {
            # Most commonly caused by two independently-tagged Custom Security Attribute fields
            # drifting apart on the source object (see EntraOpsConfig.json CustomSecurityAttributes
            # section and docs/core.html "Classify by Custom Security Attributes" for the paired
            # *AdminTierLevelAttribute / *AdminTierLevelNameAttribute field names to check and fix
            # at the source in Microsoft Entra) - or, if enabled, an AlternateObjectTierLevelAttributes
            # filter expression. This is tenant data, not a code defect: fix the tagging, then re-run.
            $Message = "$($AggregateFile.Name): object '$ObjectId' has contradictory tier pair '$TierLevel/$TierName' - check this object's Custom Security Attribute (or AlternateObjectTierLevelAttributes filter) values; see docs/core.html 'Classify by Custom Security Attributes'."
            if ($FailOnContradictoryTierPair) {
                $Violations.Add($Message)
            } else {
                $TierPairWarnings.Add($Message)
            }
            }

            $ObjectClassificationProperty = $EamObject.PSObject.Properties['Classification']
            if ($null -ne $ObjectClassificationProperty) {
                Test-ArtifactCollectionShape -Value $ObjectClassificationProperty.Value -Context "$($AggregateFile.Name): object '$ObjectId' Classification"
                Test-ArtifactClassificationEntryShape -Classification $ObjectClassificationProperty.Value -Context "$($AggregateFile.Name): object '$ObjectId'"
            }

            $SeenAssignmentPaths = [System.Collections.Generic.HashSet[string]]::new([System.StringComparer]::Ordinal)
            foreach ($RoleAssignment in @($EamObject.RoleAssignments)) {
                if ($null -eq $RoleAssignment) { continue }
                $AssignmentCount++
                $InstanceId = "$($RoleAssignment.RoleAssignmentInstanceId)".Trim().ToLowerInvariant()
                if ([string]::IsNullOrWhiteSpace($InstanceId)) {
                    $Violations.Add("$($AggregateFile.Name): object '$ObjectId' has a role assignment without RoleAssignmentInstanceId.")
                    continue
                }

                $Classification = $RoleAssignment.Classification
                $ClassificationIsEmpty = $null -eq $Classification -or
                    ($Classification -is [array] -and $Classification.Count -eq 0) -or
                    ($Classification -is [System.Collections.IDictionary] -and $Classification.Count -eq 0) -or
                    ($Classification -is [pscustomobject] -and @($Classification.PSObject.Properties).Count -eq 0)
                $ClassificationHasSupportedShape = $null -eq $Classification -or $Classification -is [array] -or $Classification -is [System.Collections.IDictionary] -or $Classification -is [pscustomobject]
                if (-not $ClassificationHasSupportedShape) {
                    $Violations.Add("$($AggregateFile.Name): assignment '$InstanceId' has unsupported Classification shape '$($Classification.GetType().FullName)'.")
                } elseif ($null -ne $Classification -and $Classification -isnot [array]) {
                    # Consumers indexing Classification[0] (KQL/workbooks, report apps) expect an array.
                    $ShapeIssues.Add("$($AggregateFile.Name): assignment '$InstanceId' for object '$ObjectId' stores Classification as a single object instead of an array.")
                }
                Test-ArtifactClassificationEntryShape -Classification $Classification -Context "$($AggregateFile.Name): assignment '$InstanceId' for object '$ObjectId'"
                if ($RoleAssignment.RoleIsPrivileged -eq $true -and $ClassificationIsEmpty) {
                    $Message = "$($AggregateFile.Name): privileged assignment '$InstanceId' ('$($RoleAssignment.RoleDefinitionName)') for object '$ObjectId' has no classification result."
                    if ($FailOnPrivilegedAssignmentWithoutClassification) { $Violations.Add($Message) } else { $DataQualityWarnings.Add($Message) }
                }

                $NestingObjectIds = @($RoleAssignment.TransitiveByNestingObjectIds | ForEach-Object {
                        if ($null -eq $_) { '' } else { "$($_)".Trim().ToLowerInvariant() }
                    })
                $AssignmentPathKey = @($InstanceId, ($NestingObjectIds -join [char]0x1E)) -join [char]0x1F
                if (-not $SeenAssignmentPaths.Add($AssignmentPathKey)) {
                    $Violations.Add("$($AggregateFile.Name): object '$ObjectId' contains duplicate assignment path '$InstanceId'.")
                }
            }
        }

        if ($ShapeIssues.Count -gt 0) {
            if (Test-ArtifactCommittedUnchanged -Path $AggregateFile.FullName) {
                $Examples = @($ShapeIssues | Select-Object -First 3) -join ' '
                $DataQualityWarnings.Add("$($AggregateFile.Name): $($ShapeIssues.Count) collection(s) are stored as a single value instead of an array in the committed export of an earlier EntraOps version (for example: $Examples) The file is rewritten with arrays on the next non-empty export of $($AggregateFile.Directory.Name); delete the folder if the RBAC system is no longer collected.")
            } else {
                foreach ($Issue in $ShapeIssues) { $Violations.Add($Issue) }
            }
        }
    }
}

if (-not [string]::IsNullOrWhiteSpace($TenantGovernancePath)) {
    $ResolvedTenantGovernancePath = $ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($TenantGovernancePath)
    if (-not (Test-Path -LiteralPath $ResolvedTenantGovernancePath -PathType Container)) {
        throw "Tenant Governance path '$ResolvedTenantGovernancePath' does not exist."
    }
    $ManifestPath = Join-Path $ResolvedTenantGovernancePath '.SnapshotManifest.json'
    if (-not (Test-Path -LiteralPath $ManifestPath -PathType Leaf)) {
        $Violations.Add("Tenant Governance snapshot manifest is missing: $ManifestPath")
    } else {
        try { $SnapshotManifest = Get-Content -LiteralPath $ManifestPath -Raw | ConvertFrom-Json -Depth 100 -ErrorAction Stop }
        catch { $Violations.Add("$ManifestPath`: invalid JSON - $($_.Exception.Message)") }
    }

    $IdentityFiles = @{}
    $ActualCounts = @{}
    foreach ($ResourceFile in @(Get-ChildItem -LiteralPath $ResolvedTenantGovernancePath -Filter '*.json' -File -Recurse | Where-Object { -not $_.Name.StartsWith('.') -and $_.FullName -notmatch '[\\/]\.(?:staging|backup)-' })) {
        # -AsHashtable accepts valid JSON objects that contain an empty property
        # name. Microsoft Graph emits those in some Tenant Governance payloads.
        try { $Resource = [System.IO.File]::ReadAllText($ResourceFile.FullName) | ConvertFrom-Json -AsHashtable -Depth 100 -ErrorAction Stop }
        catch { $Violations.Add("$($ResourceFile.FullName): invalid JSON - $($_.Exception.Message)"); continue }
        $TenantGovernanceResourceCount++
        $ResourceType = "$($Resource.resourceType)".Trim().ToLowerInvariant()
        $RelativePath = [System.IO.Path]::GetRelativePath($ResolvedTenantGovernancePath, $ResourceFile.FullName) -replace '\\', '/'
        $FolderResourceType = ($RelativePath -split '/')[0].ToLowerInvariant()
        if ([string]::IsNullOrWhiteSpace($ResourceType)) {
            $ResourceType = $FolderResourceType
        } elseif ($ResourceType -ne $FolderResourceType) {
            $Violations.Add("$($ResourceFile.FullName): resourceType '$ResourceType' does not match its top-level snapshot folder '$FolderResourceType'.")
        }
        if (-not $ActualCounts.ContainsKey($ResourceType)) { $ActualCounts[$ResourceType] = 0 }
        $ActualCounts[$ResourceType]++
        $ResourceId = "$($Resource.properties.Id)".Trim().ToLowerInvariant()
        if ([string]::IsNullOrWhiteSpace($ResourceId)) { continue }
        $Identity = "$ResourceType|$ResourceId"
        if (-not $IdentityFiles.ContainsKey($Identity)) { $IdentityFiles[$Identity] = [System.Collections.Generic.List[string]]::new() }
        $IdentityFiles[$Identity].Add($ResourceFile.FullName)
    }
    foreach ($Identity in $IdentityFiles.Keys) {
        if ($IdentityFiles[$Identity].Count -gt 1) {
            $Violations.Add("Tenant Governance identity '$Identity' is stored in $($IdentityFiles[$Identity].Count) files: $($IdentityFiles[$Identity] -join ', ')")
        }
    }
    if ($SnapshotManifest) {
        $ManifestCountProperties = @($SnapshotManifest.PublishedResourceTypeCounts.PSObject.Properties)
        $ManifestCountResourceTypes = @($ManifestCountProperties | ForEach-Object { $_.Name.ToLowerInvariant() })
        foreach ($CountProperty in $ManifestCountProperties) {
            $ResourceType = $CountProperty.Name.ToLowerInvariant()
            $ActualCount = if ($ActualCounts.ContainsKey($ResourceType)) { $ActualCounts[$ResourceType] } else { 0 }
            if ([int]$CountProperty.Value -ne $ActualCount) {
                $Violations.Add("Tenant Governance manifest count for '$ResourceType' is $($CountProperty.Value), but $ActualCount JSON file(s) exist.")
            }
        }
        # Folders of resource types that are no longer configured are intentionally preserved by
        # Save-EntraOpsTenantGovernanceSnapshotJson and reported as NotInConfig by the snapshot
        # report. They are not part of the manifest counts, so they are reported here without
        # failing the run; their files were still checked for JSON validity and duplicate identities.
        $ManifestResourceFileCount = 0
        foreach ($ResourceType in @($ActualCounts.Keys | Sort-Object)) {
            if ($ManifestCountResourceTypes -contains $ResourceType) {
                $ManifestResourceFileCount += $ActualCounts[$ResourceType]
            } else {
                $DataQualityWarnings.Add("Tenant Governance resource type '$ResourceType' has $($ActualCounts[$ResourceType]) JSON file(s) on disk but is not part of the current snapshot manifest (removed from the configured resource types). Delete the folder to stop tracking it.")
            }
        }
        if ($SnapshotManifest.IsComplete -eq $true -and [int]$SnapshotManifest.CapturedResourceCount -ne $ManifestResourceFileCount) {
            $Violations.Add("Complete Tenant Governance manifest captured count is $($SnapshotManifest.CapturedResourceCount), but $ManifestResourceFileCount resource file(s) exist for the manifest's resource types.")
        }
    }
}

if ($Violations.Count -gt 0) {
    throw "Generated artifact integrity validation failed with $($Violations.Count) violation(s):`n$($Violations -join "`n")"
}

foreach ($Warning in $TierPairWarnings) {
    Write-Warning $Warning
}
foreach ($Warning in $DataQualityWarnings) {
    Write-Warning $Warning
}

$SummaryParts = @()
if ($ResolvedPrivilegedEamPath) { $SummaryParts += "$ObjectCount object(s) and $AssignmentCount role assignment(s) across $($AggregateFiles.Count) RBAC system(s)" }
if (-not [string]::IsNullOrWhiteSpace($TenantGovernancePath)) { $SummaryParts += "$TenantGovernanceResourceCount Tenant Governance resource(s)" }
Write-Output "Validated $($SummaryParts -join ' and ')."
}

# SIG # Begin signature block
# MIIniAYJKoZIhvcNAQcCoIIneTCCJ3UCAQExDzANBglghkgBZQMEAgEFADB5Bgor
# BgEEAYI3AgEEoGswaTA0BgorBgEEAYI3AgEeMCYCAwEAAAQQH8w7YFlLCE63JNLG
# KX7zUQIBAAIBAAIBAAIBAAIBADAxMA0GCWCGSAFlAwQCAQUABCBUt4aFBmt1jd6+
# e7AbEMStkaxR/lvp7DHHgtddNwfiwqCCIDwwggXJMIIEsaADAgECAhAbtY8lKt8j
# AEkoya49fu0nMA0GCSqGSIb3DQEBDAUAMH4xCzAJBgNVBAYTAlBMMSIwIAYDVQQK
# ExlVbml6ZXRvIFRlY2hub2xvZ2llcyBTLkEuMScwJQYDVQQLEx5DZXJ0dW0gQ2Vy
# dGlmaWNhdGlvbiBBdXRob3JpdHkxIjAgBgNVBAMTGUNlcnR1bSBUcnVzdGVkIE5l
# dHdvcmsgQ0EwHhcNMjEwNTMxMDY0MzA2WhcNMjkwOTE3MDY0MzA2WjCBgDELMAkG
# A1UEBhMCUEwxIjAgBgNVBAoTGVVuaXpldG8gVGVjaG5vbG9naWVzIFMuQS4xJzAl
# BgNVBAsTHkNlcnR1bSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTEkMCIGA1UEAxMb
# Q2VydHVtIFRydXN0ZWQgTmV0d29yayBDQSAyMIICIjANBgkqhkiG9w0BAQEFAAOC
# Ag8AMIICCgKCAgEAvfl4+ObVgAxknYYblmRnPyI6HnUBfe/7XGeMycxca6mR5rlC
# 5SBLm9qbe7mZXdmbgEvXhEArJ9PoujC7Pgkap0mV7ytAJMKXx6fumyXvqAoAl4Va
# qp3cKcniNQfrcE1K1sGzVrihQTib0fsxf4/gX+GxPw+OFklg1waNGPmqJhCrKtPQ
# 0WeNG0a+RzDVLnLRxWPa52N5RH5LYySJhi40PylMUosqp8DikSiJucBb+R3Z5yet
# /5oCl8HGUJKbAiy9qbk0WQq/hEr/3/6zn+vZnuCYI+yma3cWKtvMrTscpIfcRnNe
# GWJoRVfkkIJCu0LW8GHgwaM9ZqNd9BjuiMmNF0UpmTJ1AjHuKSbIawLmtWJFfzcV
# WiNoidQ+3k4nsPBADLxNF8tNorMe0AZa3faTz1d1mfX6hhpneLO/lv403L3nUlbl
# s+V1e9dBkQXcXWnjlQ1DufyDljmVe2yAWk8TcsbXfSl6RLpSpCrVQUYJIP4ioLZb
# MI28iQzV13D4h1L92u+sUS4Hs07+0AnacO+Y+lbmbdu1V0vc5SwlFcieLnhO+Nqc
# noYsylfzGuXIkosagpZ6w7xQEmnYDlpGizrrJvojybawgb5CAKT41v4wLsfSRvbl
# jnX98sy50IdbzAYQYLuDNbdeZ95H7JlI8aShFf6tjGKOOVVPORa5sWOd/7cCAwEA
# AaOCAT4wggE6MA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFLahVDkCw6A/joq8
# +tT4HKbROg79MB8GA1UdIwQYMBaAFAh2zcsH/yT2xc3tu5C84oQ3RnX3MA4GA1Ud
# DwEB/wQEAwIBBjAvBgNVHR8EKDAmMCSgIqAghh5odHRwOi8vY3JsLmNlcnR1bS5w
# bC9jdG5jYS5jcmwwawYIKwYBBQUHAQEEXzBdMCgGCCsGAQUFBzABhhxodHRwOi8v
# c3ViY2Eub2NzcC1jZXJ0dW0uY29tMDEGCCsGAQUFBzAChiVodHRwOi8vcmVwb3Np
# dG9yeS5jZXJ0dW0ucGwvY3RuY2EuY2VyMDkGA1UdIAQyMDAwLgYEVR0gADAmMCQG
# CCsGAQUFBwIBFhhodHRwOi8vd3d3LmNlcnR1bS5wbC9DUFMwDQYJKoZIhvcNAQEM
# BQADggEBAFHCoVgWIhCL/IYx1MIy01z4S6Ivaj5N+KsIHu3V6PrnCA3st8YeDrJ1
# BXqxC/rXdGoABh+kzqrya33YEcARCNQOTWHFOqj6seHjmOriY/1B9ZN9DbxdkjuR
# mmW60F9MvkyNaAMQFtXx0ASKhTP5N+dbLiZpQjy6zbzUeulNndrnQ/tjUoCFBMQl
# lVXwfqefAcVbKPjgzoZwpic7Ofs4LphTZSJ1Ldf23SIikZbr3WjtP6MZl9M7JYjs
# NhI9qX7OAo0FmpKnJ25FspxihjcNpDOO16hO0EoXQ0zF8ads0h5YbBRRfopUofbv
# n3l6XYGaFpAP4bvxSgD5+d2+7arszgowggZrMIIEU6ADAgECAhBX5gfP8LabvnxC
# XoItEBa/MA0GCSqGSIb3DQEBCwUAMFYxCzAJBgNVBAYTAlBMMSEwHwYDVQQKExhB
# c3NlY28gRGF0YSBTeXN0ZW1zIFMuQS4xJDAiBgNVBAMTG0NlcnR1bSBDb2RlIFNp
# Z25pbmcgMjAyMSBDQTAeFw0yNjEwMDYwODI4MjNaFw0yNzEwMDYwODI4MjJaMIGQ
# MQswCQYDVQQGEwJERTEdMBsGA1UECAwUUmhpbmVsYW5kLVBhbGF0aW5hdGUxEjAQ
# BgNVBAcMCUxhaG5zdGVpbjEeMBwGA1UECgwVT3BlbiBTb3VyY2UgRGV2ZWxvcGVy
# MS4wLAYDVQQDDCVPcGVuIFNvdXJjZSBEZXZlbG9wZXIgVGhvbWFzIE5hdW5oZWlt
# MIIBojANBgkqhkiG9w0BAQEFAAOCAY8AMIIBigKCAYEAphp2ljSmVsRB6gvkEq7A
# DUMENpKZiDFoAfF1ktD1nCwaVyI+bJ0ROjHwAn4iJgS+vlBDPOUIw2GLHkiqUhOg
# HSwzg6gj45GNmt6zxsKP0zPlhMB/fb0zmz7/F7e3yfKCXLfhbHuk0Es9gJ+8Wmet
# 9StVwwSE/K0MpW06GKA9nPWyE4N/ADwigDIj9rsTKJR4cve9w8G1b3zohpUc/qMr
# onab+HVw5r9b3sOBnnaXC6zvrX4fovRz1ztwfWjRjILLoFG6mW/TuK5F2ICD3Rhl
# 9R2rJWWWhzTDMsQlzvX+/SaM74q3OFpIVNdhvtmWU9pKUBRAyYMijcDqKEFGSzrc
# 8JFmGMpP5TuroWF+N21d3px2eARvW1mV0DCfFAH+Og20SH/gVW6/ltQQEkH/z/Zt
# 49ARyJrgESLOQtlMCIYSoKISdkk4ml4VUS1E/PcbzXEYj3a7m6DOxcd3WuY03UT9
# cnk3p0LMN6LeLYAZgVY+HRloZlH+kW2SkOHNuWgtXvZhAgMBAAGjggF4MIIBdDAM
# BgNVHRMBAf8EAjAAMD0GA1UdHwQ2MDQwMqAwoC6GLGh0dHA6Ly9jY3NjYTIwMjEu
# Y3JsLmNlcnR1bS5wbC9jY3NjYTIwMjEuY3JsMHMGCCsGAQUFBwEBBGcwZTAsBggr
# BgEFBQcwAYYgaHR0cDovL2Njc2NhMjAyMS5vY3NwLWNlcnR1bS5jb20wNQYIKwYB
# BQUHMAKGKWh0dHA6Ly9yZXBvc2l0b3J5LmNlcnR1bS5wbC9jY3NjYTIwMjEuY2Vy
# MB8GA1UdIwQYMBaAFN10XUwA23ufoHTKsW73PMAywHDNMB0GA1UdDgQWBBTBvGyH
# MXj1dMbVnxuof9oP4PY7cDBLBgNVHSAERDBCMAgGBmeBDAEEATA2BgsqhGgBhvZ3
# AgUBBDAnMCUGCCsGAQUFBwIBFhlodHRwczovL3d3dy5jZXJ0dW0ucGwvQ1BTMBMG
# A1UdJQQMMAoGCCsGAQUFBwMDMA4GA1UdDwEB/wQEAwIHgDANBgkqhkiG9w0BAQsF
# AAOCAgEAkC165c7/r6y3VeEEpNXas9bQs6ZpKPdJffHkf9xoPi4kWvAIWGc4ocG1
# DJLb18RXiDYShDmT5sb/6I08FeipKi2DNJkuOq6yOTJ3S7+hNFIZCyd6i7WKO8ea
# P5I+FAbyJP4+5coZoMg45bUa9JoocaJCm+5n7WiCfN7/EQpClW5Trm4+ZMbp7EMN
# F1uLJgGCMnN0SsoUarp7PHlqupMxMC4Uhhe+lAP2ytcSIU81L97/qjrADbLWqICk
# 9il5iGM+aZndguq/cmfH9rJj4GRZHWnG6WwnzYD9+KgYlRI6em+/9dq+IRiXe2Bs
# thUuIaFW7U2gWw8tBTEYm1UBLHdJx+L1gjJCLs5KT/wy5wU32wZxNDqPUQejUC1x
# GvU3cKqmLgRq+yNf3gFVfzqIoggyM3U9wQvnk7nBtCkpjXS2hdx4yxzcmrlWsDHr
# z6+6/jeyQySzbYUlFmKnc4n9Mw2soHOajEua5poFARVRS5KgUBuiiQ21YFNYzWBo
# qGuECaaAI/C5rGxapMJ3dAOBnHw6NLqBet+ZXBJEccX5y89MLlOQu+jDmJP8HieR
# qDLlwfhVZnw4RY8Rus43NZBwhNlVuOUXqocHKmJhKNlekda3qsJj93eQBQOxKJcc
# w5O08q9jukpH2+yzFAj+7ll33DuNUgWptogc4Awtbx3glzcEvJQwggaCMIIEaqAD
# AgECAhAo8HfBHDa9/l90MkdwJy4DMA0GCSqGSIb3DQEBDAUAMFYxCzAJBgNVBAYT
# AlBMMSEwHwYDVQQKExhBc3NlY28gRGF0YSBTeXN0ZW1zIFMuQS4xJDAiBgNVBAMT
# G0NlcnR1bSBUaW1lc3RhbXBpbmcgMjAyMSBDQTAeFw0yNjAzMTEwNzM0NTRaFw0z
# NjAyMjcwNzM0NTRaMFAxCzAJBgNVBAYTAlBMMSEwHwYDVQQKDBhBc3NlY28gRGF0
# YSBTeXN0ZW1zIFMuQS4xHjAcBgNVBAMMFUNlcnR1bSBUaW1lc3RhbXAgMjAyNjCC
# AiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBALi9zfBw+xI12hi2F9uNQBNO
# STkTIi13fuh3DiWybI5392bBfJw6tO7zDs7UqP/rejVf4xFTU3XNOPsuOFkP5SPF
# snWwn3VJL+NhNhsuujvYsQtaQnvNo1wk46reTgws1L8OFEdKaxgyqT4zOQx81mLw
# NZSqXNU9Rrb9oAJWJF4Mydz+C1ebu0D0+vgM3tqAQ8TU203fqgKCPqIdHloaFqH9
# eyR+8tnpmy2hnnN59ZOtmsuHeRwf5iTOhlhf0d/qqquLOSIGPgGVL1Hj5XBUox2O
# E7tQRr+l/xxNbL6OuwBO4Aa2EbuxYg37cpXv5i2/lTL4NASB/duf9W4fjA3Ro+GP
# +bC54n2OYiM3Cq8z92ejx8F5HWO2e4/75eC95B9tMw/eq7109GDyW2+2ut5Bn0o8
# MXJTERkyystWbqcnUkomA97qfiDCwvpWuOMdfTOksXe9S+xDxOJaCbiyTivgPulx
# cT+tfQTRXBr5UwtPvc+INnafOEilzVHA11tv+pHcylryxBc08cUihf/ttqkZS0bm
# x3VxQay8uohaTp0//ECA9vYGW51SKdJMJhXvKyIdBLy8WYNchTt8yRITv9Adxg9J
# qGujh+TnP1bW3aQjFtlEl7SzgNeI8OVA/CJAWWUuRT3Au9ToOpHy/flrrknhN4he
# Ew7/6ILMv4HSsj0YZ4otAgMBAAGjggFQMIIBTDB1BggrBgEFBQcBAQRpMGcwOwYI
# KwYBBQUHMAKGL2h0dHA6Ly9zdWJjYS5yZXBvc2l0b3J5LmNlcnR1bS5wbC9jdHNj
# YTIwMjEuY2VyMCgGCCsGAQUFBzABhhxodHRwOi8vc3ViY2Eub2NzcC1jZXJ0dW0u
# Y29tMB8GA1UdIwQYMBaAFL5UAi+/QGxzQ86sCSVOnkNEGu7gMAwGA1UdEwEB/wQC
# MAAwOQYDVR0fBDIwMDAuoCygKoYoaHR0cDovL3N1YmNhLmNybC5jZXJ0dW0ucGwv
# Y3RzY2EyMDIxLmNybDAWBgNVHSUBAf8EDDAKBggrBgEFBQcDCDAOBgNVHQ8BAf8E
# BAMCB4AwIgYDVR0gBBswGTAIBgZngQwBBAIwDQYLKoRoAYb2dwIFAQswHQYDVR0O
# BBYEFCM5aiirmhKnpKfyH/lFmr+N/oIDMA0GCSqGSIb3DQEBDAUAA4ICAQBm/pOb
# rAveTqYFPCSthxNVwBHTW4TfuBQY2KGCdMlH6ALjVPYf2XARNGMTXScR0JQ2/c2L
# xLpoHHhRwxFf3d933DhFS165rYj6iPSQKm41rc9AMpTCjMdmai1aK9o870pOzTzL
# RhWFVIxm+5Qf+t4V5z14tPoUsAWdfRKD1Zzvzfe5AHlE9rxOZcGROiULxs3Edf7Z
# J8RZI0jzD9juj2oEX2XS7BVKuNCK1W0h1mjapv028yqo8UtZh5/1Ib48Yyp88BDY
# Shh5PSGUUuS5tYXVfcduIPBe3PdNTYRYdT5VNxkwLgjMzIcr/6SH2fejFJDjnCxj
# vXLuarErJg/IdI+hXdGIBDVOGv1zrkF4ktoQvFZIp5DIAYh0GwyUhc87qqn5UaYT
# j2+iyiBDSNh7aGCrkuAnqg7Qh7frhX+QhMGeJ9SpLpnG76qN85hLyjvYR6gRYiLT
# j8G4fxjqV400/buPw0rBo9yJZyq/8cGdCOLPOYf9qpefTcrZKeO9pg+UJHx8UABb
# aTqizRxm8sUSEycccCCFhIit3AI/3wGuSOADeiA676NcQ7+dsP04YvzvdN7pTZNy
# g672WpBDJdg0eItHl4yomvNeIOWh1qs4QqOW6TI8Ocsi4uSDTLorxLUDnBTwKQzz
# pxd1YUctEgRh32R0J9FkFkeEruJU94RljFr1uDCCBrkwggShoAMCAQICEQCZo4AK
# JlU7ZavcboSms+o5MA0GCSqGSIb3DQEBDAUAMIGAMQswCQYDVQQGEwJQTDEiMCAG
# A1UEChMZVW5pemV0byBUZWNobm9sb2dpZXMgUy5BLjEnMCUGA1UECxMeQ2VydHVt
# IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MSQwIgYDVQQDExtDZXJ0dW0gVHJ1c3Rl
# ZCBOZXR3b3JrIENBIDIwHhcNMjEwNTE5MDUzMjE4WhcNMzYwNTE4MDUzMjE4WjBW
# MQswCQYDVQQGEwJQTDEhMB8GA1UEChMYQXNzZWNvIERhdGEgU3lzdGVtcyBTLkEu
# MSQwIgYDVQQDExtDZXJ0dW0gQ29kZSBTaWduaW5nIDIwMjEgQ0EwggIiMA0GCSqG
# SIb3DQEBAQUAA4ICDwAwggIKAoICAQCdI88EMCM7wUYs5zNzPmNdenW6vlxNur3r
# Lfi+5OZ+U3iZIB+AspO+CC/bj+taJUbMbFP1gQBJUzDUCPx7BNLgid1TyztVLn52
# NKgxxu8gpyTr6EjWyGzKU/gnIu+bHAse1LCitX3CaOE13rbuHbtrxF2tPU8f253Q
# gX6eO8yTbGps1Mg+yda3DcTsOYOhSYNCJiL+5wnjZ9weoGRtvFgMHtJg6i671OPX
# IciiHO4Lwo2p9xh/tnj+JmCQEn5QU0NxzrOiRna4kjFaA9ZcwSaG7WAxeC/xoZSx
# F1oK1UPZtKVt+yrsGKqWONoK6f5EmBOAVEK2y4ATDSkb34UD7JA32f+Rm0wsr5aj
# zftDhA5mBipVZDjHpwzv8bTKzCDUSUuUmPo1govD0RwFcTtMXcfJtm1i+P2UNXad
# PyYVKRxKQATHN3imsfBiNRdN5kiVVeqP55piqgxOkyt+HkwIA4gbmSc3hD8ke66t
# 9MjlcNg73rZZlrLHsAIV/nJ0mmgSjBI/TthoGJDydekOQ2tQD2Dup/+sKQptalDl
# ui59SerVSJg8gAeV7N/ia4mrGoiez+SqV3olVfxyLFt3o/OQOnBmjhKUANoKLYlK
# mUpKEFI0PfoT8Q1W/y6s9LTI6ekbi0igEbFUIBE8KDUGfIwnisEkBw5KcBZ3XwnH
# mfznwlKo8QIDAQABo4IBVTCCAVEwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQU
# 3XRdTADbe5+gdMqxbvc8wDLAcM0wHwYDVR0jBBgwFoAUtqFUOQLDoD+Oirz61Pgc
# ptE6Dv0wDgYDVR0PAQH/BAQDAgEGMBMGA1UdJQQMMAoGCCsGAQUFBwMDMDAGA1Ud
# HwQpMCcwJaAjoCGGH2h0dHA6Ly9jcmwuY2VydHVtLnBsL2N0bmNhMi5jcmwwbAYI
# KwYBBQUHAQEEYDBeMCgGCCsGAQUFBzABhhxodHRwOi8vc3ViY2Eub2NzcC1jZXJ0
# dW0uY29tMDIGCCsGAQUFBzAChiZodHRwOi8vcmVwb3NpdG9yeS5jZXJ0dW0ucGwv
# Y3RuY2EyLmNlcjA5BgNVHSAEMjAwMC4GBFUdIAAwJjAkBggrBgEFBQcCARYYaHR0
# cDovL3d3dy5jZXJ0dW0ucGwvQ1BTMA0GCSqGSIb3DQEBDAUAA4ICAQB1iFgP5Y9Q
# KJpTnxDsQ/z0O23JmoZifZdEOEmQvo/79PQg9nLF/GJe6ZiUBEyDBHMtFRK0mXj3
# Qv3gL0sYXe+PPMfwmreJHvgFGWQ7XwnfMh2YIpBrkvJnjwh8gIlNlUl4KENTK5DL
# qsYPEtRQCw7R6p4s2EtWyDDr/M58iY2UBEqfUU/ujR9NuPyKk0bEcEi62JGxauFY
# zZ/yld13fHaZskIoq2XazjaD0pQkcQiIueL0HKiohS6XgZuUtCKA7S6CHttZEsOb
# QJ1j2s0urIDdqF7xaXFVaTHKtAuMfwi0jXtF3JJphrJfc+FFILgCbX/uYBPBlbBI
# P4Ht4xxk2GmfzMn7oxPITpigQFJFWuzTMUUgdRHTxaTSKRJ/6Uh7ki/pFjf9sUAS
# WgxT69QF9Ki4JF5nBIujxZ2sOU9e1HSCJwOfK07t5nnzbs1LbHuAIGJsRJiQ6HX/
# DW1XFOlXY1rc9HufFhWU+7Uk+hFkJsfzqBz3pRO+5aI6u5abI4Qws4YaeJH7H7M8
# X/YNoaArZbV4Ql+jarKsE0+8XvC4DJB+IVcvC9Ydqahi09mjQse4fxfef0L7E3hh
# o2O3bLDM6v60rIRUCi2fJT2/IRU5ohgyTch4GuYWefSBsp5NPJh4QRTP9DC3gc5Q
# EKtbrTY0Ka87Web7/zScvLmvQBm8JDFpDjCCBrkwggShoAMCAQICEQDn/2nHOzXO
# S5Em2HR8aKWHMA0GCSqGSIb3DQEBDAUAMIGAMQswCQYDVQQGEwJQTDEiMCAGA1UE
# ChMZVW5pemV0byBUZWNobm9sb2dpZXMgUy5BLjEnMCUGA1UECxMeQ2VydHVtIENl
# cnRpZmljYXRpb24gQXV0aG9yaXR5MSQwIgYDVQQDExtDZXJ0dW0gVHJ1c3RlZCBO
# ZXR3b3JrIENBIDIwHhcNMjEwNTE5MDUzMjA3WhcNMzYwNTE4MDUzMjA3WjBWMQsw
# CQYDVQQGEwJQTDEhMB8GA1UEChMYQXNzZWNvIERhdGEgU3lzdGVtcyBTLkEuMSQw
# IgYDVQQDExtDZXJ0dW0gVGltZXN0YW1waW5nIDIwMjEgQ0EwggIiMA0GCSqGSIb3
# DQEBAQUAA4ICDwAwggIKAoICAQDpEh8ENe25XXrFppVBvoplf0530W0lddNmjtv4
# YSh/f7eDQKFaIqc7tHj7ox+u8vIsJZlroakUeMS3i3T8aJRC+eQs4FF0GqvkM6+W
# ZO8kmzZfxmZaBYmMLs8FktgFYCzywmXeQ1fEExflee2OpbHVk665eXRHjH7MYZIz
# Nnjl2m8Hy8ulB9mR8wL/W0v0pjKNT6G0sfrx1kk+3OGosFUb7yWNnVkWKU4qSxLv
# 16kJ6oVJ4BSbZ4xMak6JLeB8szrK9vwGDpvGDnKCUMYL3NuviwH1x4gZG0JAXU3x
# 2pOAz91JWKJSAmRy/l0s0l5bEYKolg+DMqVhlOANd8Yh5mkQWaMEvBRE/kAGzIqg
# WhwzN2OsKIVtO8mf5sPWSrvyplSABAYa13rMYnzwfg08nljZHghquCJYCa/xHK9a
# cev9UD7Y+usr15d7mrszzxhF1JOr1Mpup2chNSBlyOObhlSO16rwrffVrg/SzaKf
# SndS5swRhr8bnDqNJY9TNyEYvBYpgF95K7p0g4LguR4A++Z1nFIHWVY5v0fNVZmg
# zxD9uVo/gta3onGOQj3JCxgYx0KrCXu4yc9QiVwTFLWbNdHFSjBCt5/8Q9pLuRhV
# ocdCunhcHudMS1CGQ/Rn0+7P+fzMgWdRKfEOh/hjLrnQ8BdJiYrZNxvIOhM2aa3z
# EDHNwwIDAQABo4IBVTCCAVEwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUvlQC
# L79AbHNDzqwJJU6eQ0Qa7uAwHwYDVR0jBBgwFoAUtqFUOQLDoD+Oirz61PgcptE6
# Dv0wDgYDVR0PAQH/BAQDAgEGMBMGA1UdJQQMMAoGCCsGAQUFBwMIMDAGA1UdHwQp
# MCcwJaAjoCGGH2h0dHA6Ly9jcmwuY2VydHVtLnBsL2N0bmNhMi5jcmwwbAYIKwYB
# BQUHAQEEYDBeMCgGCCsGAQUFBzABhhxodHRwOi8vc3ViY2Eub2NzcC1jZXJ0dW0u
# Y29tMDIGCCsGAQUFBzAChiZodHRwOi8vcmVwb3NpdG9yeS5jZXJ0dW0ucGwvY3Ru
# Y2EyLmNlcjA5BgNVHSAEMjAwMC4GBFUdIAAwJjAkBggrBgEFBQcCARYYaHR0cDov
# L3d3dy5jZXJ0dW0ucGwvQ1BTMA0GCSqGSIb3DQEBDAUAA4ICAQC4k1l3yUwV/ZQH
# CKCneqAs8EGTnwEUJLdDpokN/dMhKjK0rR5qX8nIIHzxpQR3TAw2IRw1Uxsr2Pli
# G3bCFqSdQTUbfaTq6V3vBzEebDru9QFjqlKnxCF2h1jhLNFFplbPJiW+JSnJTh1f
# KEqEdKdxgl9rVTvlxfEJ7exOn25MGbd/wGPwuSmMxRJVO0wnqgS7kmoJjNF9zqee
# hFSDDP8ZVkWg4EZ2tIS0M3uZmByRr+1Lkwjjt8AtW83mVnZTyTsOb+FNfwJY7DS4
# FmWhkRbgcHRetreoTirPOr/ozyDKhT8MTSTf6Lttg6s6T/u08mDWw6HK04ZRDfQ9
# sb77QV8mKgO44WGP31vXnVKoWVJpFBjPvjL8/Zck/5wXX2iqjOaLStFOR/IQki+E
# hn4zlcgVm22ZVCBPF+l8nAwUUShCtKuSU7GmZLKCmmxQMkSiWILTm8EtVD6AxnJh
# oq8EnhjEEyUoflkeRF2WhFiVQOmWTwZRr44IxWGkNJC6tTorW5rl2Zl+2e9JLPYf
# 3pStAPMDoPKIjVXd6NW2+fZrNUBeDo2eOa5Fn7Brs/HLQff5Xgris5MeUbdVgDrF
# 8uxO6cLPvZPo63j62SsNg55pTWk9fUIF9iPoRbb4QurjoY/woI1RAOKtYtTic6aA
# Jq3u83RIPpGXBSJKwx4KJAOZnCDCtTGCBqIwggaeAgEBMGowVjELMAkGA1UEBhMC
# UEwxITAfBgNVBAoTGEFzc2VjbyBEYXRhIFN5c3RlbXMgUy5BLjEkMCIGA1UEAxMb
# Q2VydHVtIENvZGUgU2lnbmluZyAyMDIxIENBAhBX5gfP8LabvnxCXoItEBa/MA0G
# CWCGSAFlAwQCAQUAoIGEMBgGCisGAQQBgjcCAQwxCjAIoAKAAKECgAAwGQYJKoZI
# hvcNAQkDMQwGCisGAQQBgjcCAQQwHAYKKwYBBAGCNwIBCzEOMAwGCisGAQQBgjcC
# ARUwLwYJKoZIhvcNAQkEMSIEINIndHhgXqsxQor7EbkNtt5s2rC/GXOJwwermzcC
# 4uW8MA0GCSqGSIb3DQEBAQUABIIBgHgdzGrkUqOfW9KDmYNCGGm/ZbbnLKp75yGs
# nGxycY2fY47SwTWKhZPXdNqtOtJ6ASlMxqyyVFpZ5xoAfs4tZVl8kwmvNlrHu4Hi
# UpGM00nQG801V0Imf8bPY6NSWGGEAYohABfUy82RrVPE+UpkfwxrZBdGcvUs4VDB
# s/o0g5gDQSq6eXNLB3RN2nCaDBcukllcK6ccIBi4nGjJpEIUDcsQrXC8GkL+ltyM
# O8Op1O1V9yI4HXPRQ2+6erzpbssv9kzlF/Nb5msYS8PdIzrs3aod/dTAy5Oad0+o
# G70CzHLZ7rNa1wtoqNcbKWBK88TGSZCRmTwsPGzmLoKZGjQOSEa6hfGNOX+ezMaE
# zu+MbwrCAVnKJerWNSy+loPRotU4LCGxhyi1EDRNuTQad6lPyieGp3vRiZzr4Awc
# G3kBBSHbnukHdemB6i/Xts4rNKjZKvpAp2NYhfviH0qtDno5VJ/yL2JDjj4xQJQw
# 3R2OyafFTluyIspjn3ly2wXkS1sAN6GCBAIwggP+BgkqhkiG9w0BCQYxggPvMIID
# 6wIBATBqMFYxCzAJBgNVBAYTAlBMMSEwHwYDVQQKExhBc3NlY28gRGF0YSBTeXN0
# ZW1zIFMuQS4xJDAiBgNVBAMTG0NlcnR1bSBUaW1lc3RhbXBpbmcgMjAyMSBDQQIQ
# KPB3wRw2vf5fdDJHcCcuAzANBglghkgBZQMEAgIFAKCCAVYwGgYJKoZIhvcNAQkD
# MQ0GCyqGSIb3DQEJEAEEMBwGCSqGSIb3DQEJBTEPFw0yNjEwMjcwNTQxMzJaMDcG
# CyqGSIb3DQEJEAIvMSgwJjAkMCIEIIW+kOEK0kONfMkotq9IsJqyCBd87PiwEmxY
# 05EFJcQ8MD8GCSqGSIb3DQEJBDEyBDCg4WygKuW/+iWZH/diZ4bGBtrGV5p5ymhf
# RsjcfJuN0d8SdV6mM4VwqqJYNZD18GIwgZ8GCyqGSIb3DQEJEAIMMYGPMIGMMIGJ
# MIGGBBRXFGhBDKha80JO+RZKUTYQ9NONmDBuMFqkWDBWMQswCQYDVQQGEwJQTDEh
# MB8GA1UEChMYQXNzZWNvIERhdGEgU3lzdGVtcyBTLkEuMSQwIgYDVQQDExtDZXJ0
# dW0gVGltZXN0YW1waW5nIDIwMjEgQ0ECECjwd8EcNr3+X3QyR3AnLgMwDQYJKoZI
# hvcNAQEBBQAEggIAX4cGXAXMmqkkO12d5rSZRahdI08IRPeQA8MfuGiUYyMJCyfO
# kawtJzXUUT6rJ7Kh6sAKB/phrrrtxPW+RhkPPcs/yQ1xkMRYeQXS2It1yAmkEBwH
# m65aaS60l0Cz4UUPStf+T5k+hL+msrd9T3puqNE4hHYMC4kHetEFf/NuKCYbBsoY
# 8UDaM3OV0z0lXSo0f+ArKdNpUQM9NMf/0JvE6XUGkQB9Ehd5jQb5aXiNxtbMG1eJ
# Xh4O2HHdaJy6e6r23rHfFoeNt7/o2c1FHCYeDp0qA/r4XKcJuBTliZoZ+gDp6qPh
# 0Sev6giEZXIhl2ooHlafvypUJg1yi2iUPr552M6qAWtdS/zkatKCj7Dq8m0yMVJs
# Ior8coGhaKw8A9Go3BB0UzjglXYJ3xq/oYtYnPPF7biJrjHaO6niJTWex5pk/ajK
# ZijFZ++Z0iLFAljOyJLUvGMp+H8qiv7iIRLJDjX+wFmstyNH7xWZY922Hq5+DChd
# OJrPEf9eUqGCCd6OLR2Ge+uaae5v4hpzl1LCzycpyKdaqYHtds0pMKlYbYwzlLtG
# 7s6hUFnwPe+KCDUOMdWt8Gmpkmh6J9I1zvndDkk7XwsJw/JjYKwJzkZIKwOe44df
# z+ZnOlHme/AoQTUj2jK71JLWsk5ab+iCyLx3uersIR+vjibSCPlrPA1KCN0=
# SIG # End signature block