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 |