Public/Reportings/New-EntraOpsPrivilegedEamPrivilegeHistoryData.ps1

<#
.SYNOPSIS
    Generate (refresh) the dataset for the EntraOps Privilege History static web app.

.DESCRIPTION
    Walks the git history of the Privileged EAM export folder (PrivilegedEAM/<RbacSystem>/
    <RbacSystem>.json, written by Save-EntraOpsPrivilegedEAMJson and committed by the
    Push-EntraOpsPrivilegedEAM workflow) and builds one snapshot per commit that changed
    it, so the Privilege History app can show trends over time: unique privileged role
    assignments and users per Enterprise Access Model tier, total privileged assets and
    tier breaches (an object whose own tier is less privileged than a role assignment it
    holds).

    By default, only one snapshot every two weeks is kept (-SnapshotInterval 'P2W') - the
    oldest and most recent commit in range are always included regardless of spacing.
    Use -SnapshotInterval to pick a coarser or finer cadence (daily/weekly/monthly/yearly,
    or any custom multiple such as bi-weekly/quarterly), or 'P0D'/'None' to keep every
    commit.

    For every matching commit, the exact PrivilegedEAM/ tree at that commit is restored to
    a temporary folder (git archive) and transformed with the same
    Get-EntraOpsPrivilegedEamDashboardObjects logic used by
    New-EntraOpsPrivilegedEamDashboardData, so Privilege History snapshots and the live EAM
    Dashboard dataset use identical computed columns.

    Generates data/privilege-history-data.js exposing `window.ENTRAOPS_PRIVILEGEHISTORY_DATA` so the
    static web app works both when served over HTTP and when opened directly from the file
    system. The Privilege History app shows setup instructions instead of failing until this
    file exists, so the feature has no effect until it has been generated at least once.

    Requires the repository to be a git working copy (git history is the only source of
    historic data - there is no separate time-series store).

.PARAMETER RepoRoot
    Path to the EntraOps repository root (and git working copy) that contains the
    PrivilegedEAM export folder. Defaults to the repository this module lives in.

.PARAMETER ImportPath
    Folder with the Privileged EAM export whose git history is walked. Defaults to
    <RepoRoot>/PrivilegedEAM. Must be inside the git working copy of RepoRoot.

.PARAMETER AppRoot
    Path to the Privilege History app folder (where the generated content is written).
    Defaults to Reports/PrivilegeHistory in the EntraOps repository.

.PARAMETER OutFile
    Output file. Defaults to <AppRoot>/data/privilege-history-data.js.

.PARAMETER TenantId
    Home tenant id forwarded to Get-EntraOpsPrivilegedEamDashboardObjects for every
    snapshot (used to detect foreign objects for the PrivilegedType column). Defaults to
    the most common ObjectTenantId per snapshot when omitted.

.PARAMETER TimeRangeInDays
    Only consider commits from the last N days. Default ($null) considers the full git
    history of the PrivilegedEAM folder (every commit that changed it).

.PARAMETER SnapshotInterval
    Minimum spacing between two consecutive snapshots, as an ISO 8601 duration: `P<n>D` (days),
    `P<n>W` (weeks), `P<n>M` (months) or `P<n>Y` (years) - e.g. `P1D` (daily), `P1W` (weekly),
    `P2W` (bi-weekly), `P1M` (monthly), `P3M` (quarterly), `P1Y` (yearly). Commits closer together
    than the interval are skipped; the oldest and the most recent commit in range are always kept
    so the dataset covers the full requested window and always reflects the latest state. Months
    and years use calendar arithmetic (28-31 day months, leap years), not a fixed day count.
    Default `P2W` (bi-weekly). Use `P0D`, `` (empty string) or `None` to keep every commit
    (previous behavior - no thinning).

.PARAMETER MaxDetailedSnapshots
    Only up to this many snapshots (evenly spread across the full range, always
    including the oldest and newest) keep their per-object detail (used by the Privilege
    History snapshot detail/compare views); the rest keep their trend numbers
    (assets/users/role assignments/tier breaches per tier) but drop object-level detail,
    so the generated file stays a reasonable size regardless of how far back the git
    history goes. Default 60. Use 0 to keep full detail for every snapshot (only
    recommended for short histories).

.PARAMETER PassThru
    Emit the generated payload object to the pipeline.

.EXAMPLE
    New-EntraOpsPrivilegedEamPrivilegeHistoryData

    Regenerates the Privilege History dataset from the full git history of the PrivilegedEAM
    folder of this repository.

.EXAMPLE
    New-EntraOpsPrivilegedEamPrivilegeHistoryData -TimeRangeInDays 90 -Verbose -WhatIf

    Shows what would be generated from the last 90 days of history without changing any
    files.
#>


function New-EntraOpsPrivilegedEamPrivilegeHistoryData {

    [CmdletBinding(SupportsShouldProcess = $true)]
    param (
        [Parameter(Mandatory = $false)]
        [System.String]$RepoRoot,

        [Parameter(Mandatory = $false)]
        [System.String]$ImportPath,

        [Parameter(Mandatory = $false)]
        [System.String]$AppRoot,

        [Parameter(Mandatory = $false)]
        [System.String]$OutFile,

        [Parameter(Mandatory = $false)]
        [System.String]$TenantId,

        [Parameter(Mandatory = $false)]
        [System.Nullable[int]]$TimeRangeInDays,

        [Parameter(Mandatory = $false)]
        [System.String]$SnapshotInterval = 'P2W',

        [Parameter(Mandatory = $false)]
        [int]$MaxDetailedSnapshots = 60,

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

    # Tier order used for trend series and the tier-breach calculation (higher index
    # = less privileged). Matches TIER_ORDER in Reports/PrivilegeHistory/js/app.js.
    $TierOrder = @('ControlPlane', 'ManagementPlane', 'WorkloadPlane', 'UserAccess', 'Unclassified')

    function ConvertTo-TierRank {
        param([string]$TierName)
        $idx = [array]::IndexOf($TierOrder, $TierName)
        if ($idx -lt 0) { return $TierOrder.Length - 1 } # Unclassified = least privileged
        return $idx
    }

    # ---- Snapshot interval (bi-weekly by default) ----------------------------------
    # Parses a simplified ISO 8601 duration - only the date components matter (Y/M/W/D);
    # there is no time-of-day granularity since snapshots are one per commit. Using
    # calendar arithmetic (AddYears/AddMonths) for Y/M rather than a fixed day count means
    # "monthly"/"yearly" line up with real calendar months/years regardless of length.
    function ConvertTo-SnapshotIntervalComponents {
        param([string]$Interval)
        if ([string]::IsNullOrWhiteSpace($Interval)) { return $null }
        if ($Interval -in @('P0D', 'PT0S', 'None', 'none')) { return $null }
        if ($Interval -notmatch '^P(?:(?<y>\d+)Y)?(?:(?<mo>\d+)M)?(?:(?<w>\d+)W)?(?:(?<d>\d+)D)?$') {
            throw "Invalid -SnapshotInterval '$Interval'. Expected an ISO 8601 duration such as 'P1D' (daily), 'P1W' (weekly), 'P2W' (bi-weekly), 'P1M' (monthly), 'P3M' (quarterly) or 'P1Y' (yearly). Use 'P0D' or 'None' to keep every commit."
        }
        $years = if ($Matches['y']) { [int]$Matches['y'] } else { 0 }
        $months = if ($Matches['mo']) { [int]$Matches['mo'] } else { 0 }
        $weeks = if ($Matches['w']) { [int]$Matches['w'] } else { 0 }
        $daysOnly = if ($Matches['d']) { [int]$Matches['d'] } else { 0 }
        $days = ($weeks * 7) + $daysOnly
        if ($years -eq 0 -and $months -eq 0 -and $days -eq 0) { return $null }
        return [ordered]@{ Years = $years; Months = $months; Days = $days }
    }

    function Add-SnapshotInterval {
        param([datetimeoffset]$Date, [System.Collections.Specialized.OrderedDictionary]$Interval)
        $result = $Date
        if ($Interval.Years -gt 0) { $result = $result.AddYears($Interval.Years) }
        if ($Interval.Months -gt 0) { $result = $result.AddMonths($Interval.Months) }
        if ($Interval.Days -gt 0) { $result = $result.AddDays($Interval.Days) }
        return $result
    }

    $SnapshotIntervalComponents = ConvertTo-SnapshotIntervalComponents -Interval $SnapshotInterval

    # Resolve the app/repository location relative to the module location:
    # <repo>/EntraOps/Public/<subfolder> -> <repo>/Reports/PrivilegeHistory
    $ModuleRoot = $MyInvocation.MyCommand.Module.ModuleBase
    if ([string]::IsNullOrWhiteSpace($ModuleRoot) -and -not [string]::IsNullOrWhiteSpace($PSScriptRoot)) {
        $ModuleRoot = Split-Path -Parent (Split-Path -Parent $PSScriptRoot)
    }
    if ([string]::IsNullOrWhiteSpace($ModuleRoot)) {
        throw "Unable to resolve the EntraOps module location. Import the module with 'Import-Module <path-to-EntraOps> -Force' and try again."
    }
    $RepositoryRoot = Split-Path -Parent $ModuleRoot

    if ([string]::IsNullOrWhiteSpace($RepoRoot)) { $RepoRoot = $RepositoryRoot }
    if ([string]::IsNullOrWhiteSpace($AppRoot)) { $AppRoot = Join-Path $RepositoryRoot 'Reports/PrivilegeHistory' }
    if (-not (Test-Path -LiteralPath $AppRoot -PathType Container)) {
        throw "Privilege History app folder not found: $AppRoot. Import the EntraOps module from a repository checkout that contains Reports/PrivilegeHistory."
    }
    if ([string]::IsNullOrWhiteSpace($ImportPath)) { $ImportPath = Join-Path $RepoRoot 'PrivilegedEAM' }
    if ([string]::IsNullOrWhiteSpace($OutFile)) { $OutFile = Join-Path $AppRoot 'data/privilege-history-data.js' }

    if (-not (Get-Command git -ErrorAction SilentlyContinue)) {
        throw "git was not found on PATH. Privilege History reads historic Privileged EAM data from the git history, so git is required."
    }

    $GitRoot = (git -C $RepoRoot rev-parse --show-toplevel 2>$null)
    if ($LASTEXITCODE -ne 0 -or [string]::IsNullOrWhiteSpace($GitRoot)) {
        throw "$RepoRoot is not inside a git working copy. Privilege History requires the PrivilegedEAM export to be tracked in git history."
    }
    $GitRoot = $GitRoot.Trim()

    if (-not (Test-Path -LiteralPath $ImportPath)) {
        Write-Warning "Privileged EAM import path not found: $ImportPath. Continuing - older commits may still contain it."
    }

    # Git-relative path (forward slashes) of the PrivilegedEAM folder, used as the
    # pathspec for `git log` / `git archive`.
    $ImportPathFull = [System.IO.Path]::GetFullPath($ImportPath)
    $GitRootFull = [System.IO.Path]::GetFullPath($GitRoot)
    # Compare with a trailing separator so a sibling folder such as <root>-2 does not pass as
    # being inside <root>.
    if (-not ($ImportPathFull.Equals($GitRootFull, [System.StringComparison]::OrdinalIgnoreCase) -or
            $ImportPathFull.StartsWith($GitRootFull + [System.IO.Path]::DirectorySeparatorChar, [System.StringComparison]::OrdinalIgnoreCase))) {
        throw "ImportPath ($ImportPath) is not inside the git working copy ($GitRootFull)."
    }
    $RelPath = $ImportPathFull.Substring($GitRootFull.Length).TrimStart('\', '/') -replace '\\', '/'
    if ([string]::IsNullOrWhiteSpace($RelPath)) {
        throw "ImportPath resolved to the git working copy root; expected a subfolder such as PrivilegedEAM."
    }

    # ---- Enumerate commits that touched the PrivilegedEAM export -------------------
    $logArgs = @('-C', $GitRoot, 'log', '--format=%H%x1f%cI')
    if ($TimeRangeInDays) {
        $since = (Get-Date).ToUniversalTime().AddDays(-1 * [Math]::Abs($TimeRangeInDays)).ToString('o')
        $logArgs += "--since=$since"
    }
    $logArgs += @('--', $RelPath)

    $logOutput = & git @logArgs
    if ($LASTEXITCODE -ne 0) {
        throw "git log failed with exit code $LASTEXITCODE while enumerating history of $RelPath."
    }

    $commits = @($logOutput | Where-Object { $_ } | ForEach-Object {
            $parts = $_ -split "`u{1f}"
            [pscustomobject]@{ Sha = $parts[0]; Date = [datetimeoffset]::Parse($parts[1]) }
        }) | Sort-Object -Property Date

    if (-not $commits) {
        Write-Warning "No commits touching $RelPath were found$(if ($TimeRangeInDays) { " in the last $TimeRangeInDays day(s)" }). Generating an empty Privilege History dataset."
    }

    Write-Verbose "Found $($commits.Count) commit(s) touching $RelPath."

    # ---- Thin commits down to the requested snapshot interval ----------------------
    # Applied before any git archive/expand work happens (not just before the output is
    # written), so a coarse interval (the default is bi-weekly) also speeds up generation
    # over long, frequently-committed histories - not only the size of the resulting file.
    if ($null -ne $SnapshotIntervalComponents -and $commits.Count -gt 2) {
        $thinned = [System.Collections.Generic.List[object]]::new()
        $lastKeptDate = $null
        for ($ci = 0; $ci -lt $commits.Count; $ci++) {
            $commit = $commits[$ci]
            $isLast = ($ci -eq $commits.Count - 1)
            if ($null -eq $lastKeptDate -or $isLast -or $commit.Date -ge (Add-SnapshotInterval -Date $lastKeptDate -Interval $SnapshotIntervalComponents)) {
                $thinned.Add($commit)
                $lastKeptDate = $commit.Date
            }
        }
        Write-Verbose "Snapshot interval '$SnapshotInterval' reduced $($commits.Count) commit(s) to $($thinned.Count) snapshot(s) (oldest and newest are always kept)."
        $commits = $thinned
    }

    $snapshots = [System.Collections.Generic.List[object]]::new()
    $allRbacSystems = [System.Collections.Generic.HashSet[string]]::new()

    $processed = 0
    foreach ($commit in $commits) {
        $processed++
        Write-Verbose "[$processed/$($commits.Count)] Processing commit $($commit.Sha) ($($commit.Date))..."

        $tmpDir = Join-Path ([System.IO.Path]::GetTempPath()) "EntraOpsPrivilegeHistory_$([guid]::NewGuid().ToString('N'))"
        $tmpZip = "$tmpDir.zip"
        try {
            New-Item -ItemType Directory -Path $tmpDir -Force | Out-Null

            # Let git write the zip itself (--output) instead of redirecting stdout:
            # PowerShell redirection only preserves raw bytes on PS >= 7.5, so on older
            # supported versions (the module floor is 7.4) `> $tmpZip` corrupts the archive.
            & git -C $GitRoot archive --format=zip --output=$tmpZip $commit.Sha -- $RelPath 2>$null
            if ($LASTEXITCODE -ne 0 -or -not (Test-Path -LiteralPath $tmpZip) -or (Get-Item -LiteralPath $tmpZip).Length -eq 0) {
                Write-Verbose " Skipped: $RelPath did not exist at commit $($commit.Sha)."
                continue
            }

            Expand-Archive -LiteralPath $tmpZip -DestinationPath $tmpDir -Force
            $commitImportPath = Join-Path $tmpDir $RelPath
            if (-not (Test-Path -LiteralPath $commitImportPath -PathType Container)) {
                Write-Verbose " Skipped: no PrivilegedEAM data at commit $($commit.Sha)."
                continue
            }

            $objects = Get-EntraOpsPrivilegedEamDashboardObjects -ImportPath $commitImportPath -TenantId $TenantId
            if (@($objects).Count -eq 0) {
                Write-Verbose " Skipped: no privileged objects at commit $($commit.Sha)."
                continue
            }

            $rbacSystems = @(@($objects | ForEach-Object { $_.roleSystem }) | Where-Object { $_ } | Select-Object -Unique | Sort-Object)
            $rbacSystems | ForEach-Object { [void]$allRbacSystems.Add($_) }

            # ---- Aggregates -----------------------------------------------------------
            $totalAssignments = 0
            $tierBreaches = 0
            $usersByTier = @{}
            $assetsByTier = @{}
            $assignmentsByTier = @{}
            $seenAssignmentIds = @{}
            $seenAssetIds = @{}
            $totalUsers = 0
            $totalGroups = 0
            $totalServicePrincipals = 0

            foreach ($obj in $objects) {
                $objTier = $obj.objectAdminTierLevelName
                if (-not $objTier) { $objTier = 'Unclassified' }
                $objRank = ConvertTo-TierRank -TierName $objTier

                # An object can appear once per RBAC system it holds roles in (same shape
                # as the live EAM Dashboard export), so only count each objectId once for
                # the per-tier asset/user/group/service-principal breakdowns.
                if (-not $seenAssetIds.ContainsKey($obj.objectId)) {
                    $seenAssetIds[$obj.objectId] = $true
                    switch ($obj.objectType) {
                        'user' { $totalUsers++; $usersByTier[$objTier] = [int]$usersByTier[$objTier] + 1 }
                        'group' { $totalGroups++ }
                        'serviceprincipal' { $totalServicePrincipals++ }
                    }
                    # "Privileged assets by tier" counts every non-group object once, mirroring
                    # the "Classification of privileged identities" tiles in the live dashboard.
                    if ($obj.objectType -ne 'group') {
                        $assetsByTier[$objTier] = [int]$assetsByTier[$objTier] + 1
                    }
                }

                foreach ($ra in @($obj.roleAssignments)) {
                    $assignmentKey = if ($ra.roleAssignmentInstanceId) { "$($ra.roleAssignmentInstanceId)" } else { "$($ra.roleAssignmentId)" }
                    if (-not $assignmentKey -or -not $seenAssignmentIds.ContainsKey($assignmentKey)) {
                        if ($assignmentKey) { $seenAssignmentIds[$assignmentKey] = $true }
                        $totalAssignments++
                    }

                    $raTiers = @(@($ra.classification) | ForEach-Object { $_.adminTierLevelName } | Where-Object { $_ } | Select-Object -Unique)
                    if ($raTiers.Count -eq 0) { $raTiers = @('Unclassified') }
                    foreach ($t in $raTiers) {
                        $assignmentsByTier[$t] = [int]$assignmentsByTier[$t] + 1
                        # Tier breach: the object's own (less privileged / higher-rank) tier
                        # can reach a role classified into a MORE privileged (lower-rank) tier.
                        if ((ConvertTo-TierRank -TierName $t) -lt $objRank) { $tierBreaches++ }
                    }
                }
            }

            $objectTierSeries = @($TierOrder | ForEach-Object {
                    [ordered]@{
                        tier   = $_
                        assets = [int]$assetsByTier[$_]
                        users  = [int]$usersByTier[$_]
                    }
                })
            $accessTierSeries = @($TierOrder | ForEach-Object {
                    [ordered]@{
                        tier            = $_
                        roleAssignments = [int]$assignmentsByTier[$_]
                    }
                })

            # Lightweight per-object detail (enough to filter/drill-down and diff two
            # snapshots) - not the full live-dashboard schema, to keep repository size
            # bounded across potentially many historic commits.
            $snapshotObjects = @($objects | ForEach-Object {
                    [ordered]@{
                        objectId                 = $_.objectId
                        objectType               = $_.objectType
                        objectDisplayName        = $_.objectDisplayName
                        objectAdminTierLevelName = $_.objectAdminTierLevelName
                        roleSystem               = $_.roleSystem
                        roleAssignments          = @(@($_.roleAssignments) | ForEach-Object {
                                [ordered]@{
                                    roleAssignmentInstanceId = $_.roleAssignmentInstanceId
                                    roleAssignmentId   = $_.roleAssignmentId
                                    roleDefinitionName = $_.roleDefinitionName
                                    roleSystem         = $_.roleSystem
                                    roleAssignmentType = $_.roleAssignmentType
                                    pimAssignmentType  = $_.pimAssignmentType
                                    classification     = @(@($_.classification) | ForEach-Object {
                                            [ordered]@{ adminTierLevelName = $_.adminTierLevelName; service = $_.service }
                                        })
                                }
                            })
                    }
                })

            $snapshots.Add([ordered]@{
                    commitSha   = $commit.Sha
                    commitDate  = $commit.Date.ToString('o')
                    rbacSystems = $rbacSystems
                    totals      = [ordered]@{
                        assets            = @($objects | Where-Object { $_.objectType -ne 'group' } | ForEach-Object { $_.objectId } | Select-Object -Unique).Count
                        users             = $totalUsers
                        groups            = $totalGroups
                        servicePrincipals = $totalServicePrincipals
                        roleAssignments   = $totalAssignments
                        tierBreaches      = $tierBreaches
                    }
                    objectTier  = $objectTierSeries
                    accessTier  = $accessTierSeries
                    hasDetail   = $true
                    objects     = $snapshotObjects
                })
        } finally {
            if (Test-Path -LiteralPath $tmpZip) { Remove-Item -LiteralPath $tmpZip -Force -ErrorAction SilentlyContinue }
            if (Test-Path -LiteralPath $tmpDir) { Remove-Item -LiteralPath $tmpDir -Recurse -Force -ErrorAction SilentlyContinue }
        }
    }

    # The per-snapshot "objects" list (used for snapshot detail & compare) is the only
    # part of the payload that scales with the number of role assignments; the trend
    # aggregates (objectTier/accessTier/totals) are cheap and always kept for every
    # snapshot. To keep the generated file loadable in a browser regardless of how far
    # back the git history goes, only up to -MaxDetailedSnapshots (evenly spread across
    # the full range, always including the oldest and newest) keep their "objects";
    # older/thinned-out snapshots keep their trend numbers but drop object-level detail.
    if ($snapshots.Count -gt $MaxDetailedSnapshots -and $MaxDetailedSnapshots -gt 0) {
        $keepIdx = [System.Collections.Generic.HashSet[int]]::new()
        for ($i = 0; $i -lt $MaxDetailedSnapshots; $i++) {
            $pos = if ($MaxDetailedSnapshots -eq 1) { 0 } else { [Math]::Round($i * ($snapshots.Count - 1) / ($MaxDetailedSnapshots - 1)) }
            [void]$keepIdx.Add([int]$pos)
        }
        for ($i = 0; $i -lt $snapshots.Count; $i++) {
            if (-not $keepIdx.Contains($i)) {
                $snapshots[$i]['hasDetail'] = $false
                $snapshots[$i]['objects'] = @()
            }
        }
        Write-Verbose "Kept full snapshot detail for $($keepIdx.Count) of $($snapshots.Count) snapshot(s) (-MaxDetailedSnapshots $MaxDetailedSnapshots); the rest keep trend numbers only."
    }

    $payload = [ordered]@{
        tenantName       = Get-EntraOpsReportingTenantName -RepoRoot $RepoRoot
        generatedAt      = (Get-Date).ToUniversalTime().ToString('o')
        tierOrder        = $TierOrder
        rbacSystems      = @($allRbacSystems | Sort-Object)
        timeRangeInDays  = $TimeRangeInDays
        snapshotInterval = $SnapshotInterval
        snapshots        = @($snapshots)
    }

    $json = $payload | ConvertTo-Json -Depth 14 -Compress
    $content = "// Auto-generated by New-EntraOpsPrivilegedEamPrivilegeHistoryData - do not edit by hand.`n" +
    "window.ENTRAOPS_PRIVILEGEHISTORY_DATA = $json;`n"

    if ($PSCmdlet.ShouldProcess($OutFile, 'Write Privilege History dataset')) {
        Save-EntraOpsReportDataFile -Content $content -LiteralPath $OutFile

        Write-Host "Commits processed: $($commits.Count)"
        Write-Host "Snapshots written: $($snapshots.Count)"
        Write-Host "Wrote $OutFile"
    }

    if ($PassThru) { $payload }
}

# SIG # Begin signature block
# MIIniAYJKoZIhvcNAQcCoIIneTCCJ3UCAQExDzANBglghkgBZQMEAgEFADB5Bgor
# BgEEAYI3AgEEoGswaTA0BgorBgEEAYI3AgEeMCYCAwEAAAQQH8w7YFlLCE63JNLG
# KX7zUQIBAAIBAAIBAAIBAAIBADAxMA0GCWCGSAFlAwQCAQUABCB0M8aFb1n3XD4i
# Tolua4d+qWB0N3tpcoMoXQ8clRIOeqCCIDwwggXJMIIEsaADAgECAhAbtY8lKt8j
# 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
# ARUwLwYJKoZIhvcNAQkEMSIEILWFuYSUy8zGmkffYd/o2ZaU90kj3NEcshodSq+Z
# toqiMA0GCSqGSIb3DQEBAQUABIIBgBSK7/iAeAxAV0sPARgs/vff0S0zvQ9YDMnM
# 7SzRm8NEpIpYSM3zKh9ebjorw+j78TUTZTKK1boZYX3SRC4bk+o/bxdoZ0Jz5S55
# G9CU2uK5gZvSlUSihYwagC5VLhH5UZ+VilcIuuc/feO2Pi5E1fKca0ALKIuxTB2O
# wlU+tlr7fA6kCsvVkeXn5kS/e4KJXQUCxaE3tIGVZ/GG/ngSw79FsrunMoN5iDy8
# 1qyMpr0rLsIMlWp2iFyLJLYEi1lUnD0dxgT7EI+fr65I9UeepiFHyrCb52f0Z7em
# P8No6xmxz8WQCIr/4i3cs6OrVG54VNxgWapZgXlX+CnLlXx8FXp51IIrLNqJ/4pH
# uW1wn+87svZomvTuCCbcSx8Isar1UWP/JNh+rzWHBbpHjqG6E00EaGdej0fNdWCb
# Ib1sAekxXAGwKBfQRdhtZkeBjB8U2lKt8K6RHiemFn8cqgQwUhV1R80nC0g0hm2M
# 1i09DG5SuYOU1cNKQf32tI0+KSIfNaGCBAIwggP+BgkqhkiG9w0BCQYxggPvMIID
# 6wIBATBqMFYxCzAJBgNVBAYTAlBMMSEwHwYDVQQKExhBc3NlY28gRGF0YSBTeXN0
# ZW1zIFMuQS4xJDAiBgNVBAMTG0NlcnR1bSBUaW1lc3RhbXBpbmcgMjAyMSBDQQIQ
# KPB3wRw2vf5fdDJHcCcuAzANBglghkgBZQMEAgIFAKCCAVYwGgYJKoZIhvcNAQkD
# MQ0GCyqGSIb3DQEJEAEEMBwGCSqGSIb3DQEJBTEPFw0yNjEwMTMwOTQxNTNaMDcG
# CyqGSIb3DQEJEAIvMSgwJjAkMCIEIIW+kOEK0kONfMkotq9IsJqyCBd87PiwEmxY
# 05EFJcQ8MD8GCSqGSIb3DQEJBDEyBDB9ERaTc4ZI0u8ptaLTuEfDnyl/s7aJeUf8
# JSm81ob7otr+2Eth1L7T1Px4rF0uAVwwgZ8GCyqGSIb3DQEJEAIMMYGPMIGMMIGJ
# MIGGBBRXFGhBDKha80JO+RZKUTYQ9NONmDBuMFqkWDBWMQswCQYDVQQGEwJQTDEh
# MB8GA1UEChMYQXNzZWNvIERhdGEgU3lzdGVtcyBTLkEuMSQwIgYDVQQDExtDZXJ0
# dW0gVGltZXN0YW1waW5nIDIwMjEgQ0ECECjwd8EcNr3+X3QyR3AnLgMwDQYJKoZI
# hvcNAQEBBQAEggIAOwPLe1/8y1NZ2Y/3elNET0dHqzujO0uTl24vPrsfVAiKBqRE
# GC8vd0v1eGsFeWvQEntrv2uDWZwqlKSr0U+ck48Eksu2ZTPlP3870QrZX7A1Fjb/
# O69rDDWSLH2NWsM6IMWBp+Lgr8K7D5K49RRRebxxONPnI+CteUsOk4cMjUwAhHV2
# cJmoRG3374j1I4REs9tvqcGmhIoA5g5bLT7J4tU9sfh5FeIuK5ty73nRXeESXaCN
# SJ9nB2J0hzIUw27Tpmb+7n6ey9AhJmsq27lhRJArdkSbctNJUL5mOj00Q2eITqRx
# yR3Om9kepjjq9JkFHiHjkWz+FdWvajV0brBC6KY9G6W4hKpYWBfQnnRZElgPjOhZ
# 1bjgFYvyQJnZKZoxJqE7YUHJNqyKWi3NNRk0HjGEfH1iasJa6Y+ARbAUwY1jtBb1
# N/7dFBC7Kf88Ubqe/8ivuiF31u/NZqfNO3ioyLulj6CZNKz871b2Sw2TUzSmlkTw
# 3xAHyCNMyLJrPeQmiudtil29m/0nfhsAp26BXK0mJg41UExN7OP2cvnKTQDS5kQs
# /5idPUg/UzdjxK5h6dt3VIz8mPEeoWa/JHI7HrWNwYgzrJTub9a7p55K2uyF2yv1
# 5kwYk0G18mrAelcUhM2PpMJjt5ZnZxCayKncRd/MDAcEVVpfwPmA0P+q8xE=
# SIG # End signature block