Private/Invoke-EntraOpsEAMClassificationAggregation.ps1
|
<# .SYNOPSIS Aggregates classifications per unique object and builds standardized EAM output objects. .DESCRIPTION Shared helper that replaces the duplicated classification aggregation logic found in every EAM cmdlet's final stage. Handles both parallel and sequential processing paths, builds unique classification sets per object, applies "Unclassified" fallback, and constructs the standardized output PSCustomObject via New-EntraOpsEAMOutputObject. Principals whose object details could not be resolved ($null entry in ObjectDetailsCache) are NOT dropped: they are emitted fail-closed as ControlPlane placeholders with a Classification marker entry (TaggedBy = "UnresolvedObject"), so downstream Administrative Unit / Conditional Access group reconciliation never removes a potentially privileged principal from its protection group just because a Graph lookup failed or was throttled. This function eliminates ~150 lines of duplicated code per EAM cmdlet. .PARAMETER UniqueObjects Array of unique objects with ObjectId and ObjectType properties. .PARAMETER ObjectDetailsCache Hashtable mapping ObjectId → resolved object details from Get-EntraOpsPrivilegedEntraObject. .PARAMETER RbacClassificationsByObject Hashtable mapping ObjectId → classified role assignments (from Group-Object ObjectId -AsHashTable). .PARAMETER RoleSystem The RBAC system name (e.g., "EntraID", "Defender", "DeviceManagement", "IdentityGovernance", "ResourceApps"). .PARAMETER EnableParallelProcessing Enable parallel processing. Default is $true. .PARAMETER ParallelThrottleLimit Maximum number of parallel threads. Default is 10. .PARAMETER WarningMessages Reference to the List[psobject] for collecting warnings. .OUTPUTS Array of standardized EAM output objects. #> function Merge-EntraOpsEAMClassification { <# .SYNOPSIS Merges the Classification entries of all role assignments of one object into the object-level classification set (one entry per AdminTierLevel / AdminTierLevelName / Service). .DESCRIPTION Entries sharing the same (case-insensitive) AdminTierLevel|AdminTierLevelName|Service key are merged instead of keeping only the first one: - MatchedActions: case-insensitive union across all contributing entries, sorted (OrdinalIgnoreCase); for casing variants of the same action the ordinal-smallest spelling is kept. $null if no entry carries actions. Always an array otherwise (also for a single action). - ScopedObjects: union de-duplicated by identity (id / ObjectId / string value / JSON), sorted by identity. $null if no entry carries scoped objects. - AdminTierLevel / AdminTierLevelName / Service: ordinal-smallest spelling (deterministic label for casing variants such as "Default member" vs. "Default Member"). - Other properties (e.g. Justification): ordinal-smallest non-null value. TaggedBy* properties are excluded. The result is independent of the role assignment order and sorted by AdminTierLevel, AdminTierLevelName, Service. Pure CPU helper without module dependencies. .PARAMETER RoleAssignments Role assignments (each with a Classification array) contributing to one object. .OUTPUTS Merged classification entries (no output if no classification exists); wrap the call in @(). #> [CmdletBinding()] [OutputType([psobject])] param ( [Parameter(Mandatory = $false)] [AllowNull()] [AllowEmptyCollection()] [object[]]$RoleAssignments ) $ExcludedProperties = [System.Collections.Generic.HashSet[string]]::new( [string[]]@('TaggedBy', 'TaggedByObjectIds', 'TaggedByObjectDisplayNames', 'TaggedByRoleSystem'), [System.StringComparer]::OrdinalIgnoreCase) $Groups = [System.Collections.Generic.Dictionary[string, System.Collections.Generic.List[object]]]::new([System.StringComparer]::OrdinalIgnoreCase) foreach ($Assignment in @($RoleAssignments)) { if ($null -eq $Assignment -or $null -eq $Assignment.Classification) { continue } foreach ($ClassItem in @($Assignment.Classification)) { if ($null -eq $ClassItem) { continue } $Key = "$($ClassItem.AdminTierLevel)|$($ClassItem.AdminTierLevelName)|$($ClassItem.Service)" if (-not $Groups.ContainsKey($Key)) { $Groups[$Key] = [System.Collections.Generic.List[object]]::new() } $Groups[$Key].Add($ClassItem) } } $Merged = foreach ($Items in $Groups.Values) { $PropertyNames = [System.Collections.Generic.List[string]]::new() foreach ($Item in $Items) { foreach ($Property in $Item.PSObject.Properties) { if (-not $ExcludedProperties.Contains($Property.Name) -and -not $PropertyNames.Contains($Property.Name)) { $PropertyNames.Add($Property.Name) } } } $Entry = [ordered]@{} foreach ($PropertyName in $PropertyNames) { $Values = @(foreach ($Item in $Items) { $Property = $Item.PSObject.Properties[$PropertyName] if ($null -ne $Property -and $null -ne $Property.Value) { , $Property.Value } }) if ($Values.Count -eq 0) { $Entry[$PropertyName] = $null continue } switch ($PropertyName) { 'MatchedActions' { $Actions = [System.Collections.Generic.Dictionary[string, string]]::new([System.StringComparer]::OrdinalIgnoreCase) foreach ($Value in $Values) { foreach ($Action in @($Value)) { # Flatten one nesting level (e.g. ", @($MatchedActions)" wrapped arrays) foreach ($ActionItem in @(if ($Action -is [System.Collections.IEnumerable] -and $Action -isnot [string]) { $Action } else { , $Action })) { if ($null -eq $ActionItem) { continue } $ActionString = "$ActionItem" if ([string]::IsNullOrWhiteSpace($ActionString)) { continue } $Existing = $null if (-not $Actions.TryGetValue($ActionString, [ref]$Existing) -or [string]::CompareOrdinal($ActionString, $Existing) -lt 0) { $Actions[$ActionString] = $ActionString } } } } $ActionList = [System.Collections.Generic.List[string]]::new($Actions.Values) $ActionList.Sort([System.StringComparer]::OrdinalIgnoreCase) $Entry[$PropertyName] = [object[]]@($ActionList) } 'ScopedObjects' { $Scoped = [System.Collections.Generic.Dictionary[string, object]]::new([System.StringComparer]::OrdinalIgnoreCase) foreach ($Value in $Values) { foreach ($ScopedObject in @($Value)) { if ($null -eq $ScopedObject) { continue } $IdentityKey = if ($ScopedObject -is [string]) { $ScopedObject } elseif ($null -ne $ScopedObject.PSObject.Properties['id'] -and -not [string]::IsNullOrEmpty("$($ScopedObject.id)")) { "$($ScopedObject.id)" } elseif ($null -ne $ScopedObject.PSObject.Properties['ObjectId'] -and -not [string]::IsNullOrEmpty("$($ScopedObject.ObjectId)")) { "$($ScopedObject.ObjectId)" } else { $ScopedObject | ConvertTo-Json -Compress -Depth 5 } $Existing = $null if (-not $Scoped.TryGetValue($IdentityKey, [ref]$Existing)) { $Scoped[$IdentityKey] = $ScopedObject } elseif ([string]::CompareOrdinal(($ScopedObject | ConvertTo-Json -Compress -Depth 5), ($Existing | ConvertTo-Json -Compress -Depth 5)) -lt 0) { $Scoped[$IdentityKey] = $ScopedObject } } } if ($Scoped.Count -eq 0) { $Entry[$PropertyName] = $null } else { $ScopedKeys = [System.Collections.Generic.List[string]]::new($Scoped.Keys) $ScopedKeys.Sort([System.StringComparer]::OrdinalIgnoreCase) $Entry[$PropertyName] = [object[]]@(foreach ($ScopedKey in $ScopedKeys) { $Scoped[$ScopedKey] }) } } default { # Deterministic pick independent of assignment order: ordinal-smallest representation $Selected = $Values[0] foreach ($Value in $Values) { if ([string]::CompareOrdinal("$Value", "$Selected") -lt 0) { $Selected = $Value } } $Entry[$PropertyName] = $Selected } } } [PSCustomObject]$Entry } $Merged | Sort-Object AdminTierLevel, AdminTierLevelName, Service } function Invoke-EntraOpsEAMClassificationAggregation { [CmdletBinding()] param ( [Parameter(Mandatory = $true)] [Array]$UniqueObjects, [Parameter(Mandatory = $true)] [hashtable]$ObjectDetailsCache, [Parameter(Mandatory = $true)] [hashtable]$RbacClassificationsByObject, [Parameter(Mandatory = $true)] [string]$RoleSystem, [Parameter(Mandatory = $false)] [bool]$EnableParallelProcessing = $true, [Parameter(Mandatory = $false)] [int]$ParallelThrottleLimit = 10, [Parameter(Mandatory = $false)] [System.Collections.Generic.List[psobject]]$WarningMessages ) # Determine if parallel processing is viable (PowerShell 7+ guaranteed by module prerequisite) $HasSufficientObjects = $UniqueObjects.Count -ge 50 $UseParallelForClassification = $EnableParallelProcessing -and $HasSufficientObjects # Fail-closed placeholder SCHEMA, defined once and shared by the parallel and sequential paths # so the two can never drift apart. Shared as plain data (read-only template + marker) rather # than a scriptblock: invoking a $using: scriptblock concurrently across parallel runspaces is # not thread-safe, and [scriptblock]::Create is avoided for the Constrained Language Mode goals # tracked in PawCompatible.md. Each path clones the template and fills in the three # object-specific fields (ObjectTenantId, ObjectType, ObjectDisplayName). $UnresolvedObjectDetailsTemplate = [ordered]@{ 'ObjectTenantId' = $null 'ObjectType' = 'unresolved' 'ObjectSubType' = 'Unresolved' 'ObjectDisplayName' = $null 'ObjectSignInName' = $null 'AdminTierLevel' = '0' 'AdminTierLevelName' = 'ControlPlane' 'OnPremSynchronized' = $null 'AssignedAdministrativeUnits' = $null 'RestrictedManagementByRAG' = $null 'RestrictedManagementByAadRole' = $null 'RestrictedManagementByRMAU' = $null 'Sponsors' = $null 'Owners' = $null 'OwnedObjects' = $null 'OwnedDevices' = $null 'IdentityParent' = $null 'AssociatedWorkAccount' = $null 'AssociatedPawDevice' = $null } $UnresolvedMarkerClassification = [PSCustomObject]@{ 'AdminTierLevel' = "0" 'AdminTierLevelName' = "ControlPlane" 'Service' = "Unresolved" 'TaggedBy' = "UnresolvedObject" } if ($UseParallelForClassification) { $SyncObjectDetailsCache = [System.Collections.Hashtable]::Synchronized($ObjectDetailsCache) $SyncRbacByObject = [System.Collections.Hashtable]::Synchronized($RbacClassificationsByObject) # Merge classifications up front: the parallel runspaces cannot call module functions, and # the merge is CPU-only and cheap compared to the per-object output construction. $MergedClassificationByObject = @{} foreach ($UniqueObject in $UniqueObjects) { if ($null -ne $UniqueObject.ObjectId -and -not $MergedClassificationByObject.ContainsKey($UniqueObject.ObjectId)) { $MergedClassificationByObject[$UniqueObject.ObjectId] = @(Merge-EntraOpsEAMClassification -RoleAssignments @($RbacClassificationsByObject[$UniqueObject.ObjectId])) } } $SyncMergedClassificationByObject = [System.Collections.Hashtable]::Synchronized($MergedClassificationByObject) $ClassificationThrottleLimit = [Math]::Min($ParallelThrottleLimit * 2, 100) Write-Host "Using parallel classification processing with $ClassificationThrottleLimit threads for $($UniqueObjects.Count) objects..." -ForegroundColor Yellow $ClassifiedObjects = $UniqueObjects | ForEach-Object -ThrottleLimit $ClassificationThrottleLimit -Parallel { $obj = $_ $ObjectId = $obj.ObjectId if ($null -ne $ObjectId) { $SharedDetailsCache = $using:SyncObjectDetailsCache $SharedRbacByObject = $using:SyncRbacByObject $LocalRoleSystem = $using:RoleSystem $ObjectDetails = $SharedDetailsCache[$ObjectId] # Fail-closed: never drop a principal whose object details could not be resolved # (failed/throttled Graph call: $null cache entry or ResolutionStatus 'Unresolved'). A vanished ControlPlane principal # would otherwise be removed from its protection group by the Administrative Unit / # Conditional Access group reconciliation. Emit a placeholder pinned to ControlPlane # instead, built inline from the identity fields known from the assignment data # (cannot call module functions from parallel runspace). $IsUnresolvedObject = ($null -eq $ObjectDetails -or "$($ObjectDetails.ResolutionStatus)" -eq 'Unresolved') if ($IsUnresolvedObject) { # Shared schema template (see its definition in function scope) - clone and # fill the object-specific fields. $DetailsTemplate = $using:UnresolvedObjectDetailsTemplate $Details = [ordered]@{} foreach ($TemplateKey in $DetailsTemplate.Keys) { $Details[$TemplateKey] = $DetailsTemplate[$TemplateKey] } $Details['ObjectTenantId'] = $obj.ObjectTenantId $KnownObjectType = "$($obj.ObjectType)" if (-not [string]::IsNullOrWhiteSpace($KnownObjectType)) { $Details['ObjectType'] = $KnownObjectType } $Details['ObjectDisplayName'] = $ObjectId $ObjectDetails = [PSCustomObject]$Details } $RbacClassifiedAssignments = $SharedRbacByObject[$ObjectId] # Merged classifications are precomputed in the calling runspace (module helpers are not # available here); see Merge-EntraOpsEAMClassification. $SharedMergedClassification = $using:SyncMergedClassificationByObject $Classification = @($SharedMergedClassification[$ObjectId]) if ($Classification.Count -eq 0) { $Classification = @([PSCustomObject]@{ 'AdminTierLevel' = "Unclassified" 'AdminTierLevelName' = "Unclassified" 'Service' = "Unclassified" }) } if ($IsUnresolvedObject) { # Marker entry flags the fail-closed placeholder in the export and also serves as # the structured warning marker folded into $WarningMessages after the parallel # block. Keep any classifications derived from the assignments themselves, but # drop the generic "Unclassified" fallback in favor of the explicit marker. $Classification = @(($using:UnresolvedMarkerClassification).PSObject.Copy()) + @($Classification | Where-Object { $_.AdminTierLevelName -ne "Unclassified" }) } # Build output object inline (cannot call module functions from parallel runspace). [PSCustomObject]@{ 'ObjectId' = $ObjectId 'ObjectTenantId' = $ObjectDetails.ObjectTenantId 'ObjectType' = ($ObjectDetails.ObjectType ?? 'unknown').ToLower() 'ObjectSubType' = $ObjectDetails.ObjectSubType 'ObjectDisplayName' = $ObjectDetails.ObjectDisplayName 'ObjectUserPrincipalName' = $ObjectDetails.ObjectSignInName 'ObjectAdminTierLevel' = $ObjectDetails.AdminTierLevel 'ObjectAdminTierLevelName' = $ObjectDetails.AdminTierLevelName 'OnPremSynchronized' = $ObjectDetails.OnPremSynchronized 'AssignedAdministrativeUnits' = $ObjectDetails.AssignedAdministrativeUnits 'RestrictedManagementByRAG' = $ObjectDetails.RestrictedManagementByRAG 'RestrictedManagementByAadRole' = $ObjectDetails.RestrictedManagementByAadRole 'RestrictedManagementByRMAU' = $ObjectDetails.RestrictedManagementByRMAU 'RoleSystem' = $LocalRoleSystem 'Classification' = $Classification 'RoleAssignments' = @($RbacClassifiedAssignments | Sort-Object { ($_.Classification | Sort-Object AdminTierLevel -Top 1).AdminTierLevel }, RoleDefinitionName, RoleAssignmentScopeId, RoleAssignmentId) 'Sponsors' = $ObjectDetails.Sponsors 'Owners' = $ObjectDetails.Owners 'OwnedObjects' = $ObjectDetails.OwnedObjects 'OwnedDevices' = $ObjectDetails.OwnedDevices 'IdentityParent' = $ObjectDetails.IdentityParent 'AssociatedWorkAccount' = $ObjectDetails.AssociatedWorkAccount 'AssociatedPawDevice' = $ObjectDetails.AssociatedPawDevice } } } # Fold unresolved-object markers from the parallel results into the warning collection: # parallel runspaces cannot append to $WarningMessages directly, so each placeholder carries # its marker (Classification TaggedBy = "UnresolvedObject") and is surfaced here. $UnresolvedClassifiedObjects = @($ClassifiedObjects | Where-Object { @($_.Classification).TaggedBy -contains "UnresolvedObject" }) foreach ($UnresolvedObject in $UnresolvedClassifiedObjects) { $UnresolvedWarning = "Object $($UnresolvedObject.ObjectId) could not be resolved - emitted as fail-closed ControlPlane placeholder (TaggedBy=UnresolvedObject)" if ($null -ne $WarningMessages) { $WarningMessages.Add([PSCustomObject]@{ Type = "UnresolvedObject" Message = $UnresolvedWarning Target = $UnresolvedObject.ObjectId }) } Write-Warning $UnresolvedWarning } if ($ClassifiedObjects.Count -ne $UniqueObjects.Count -and $null -ne $WarningMessages) { $WarningMessages.Add([PSCustomObject]@{Type = "Stage-Classification-Parallel"; Message = "Parallel classification returned fewer objects than expected. Expected: $($UniqueObjects.Count), Actual: $($ClassifiedObjects.Count)" }) Write-Warning "Parallel classification returned fewer objects than expected. Expected: $($UniqueObjects.Count), Actual: $($ClassifiedObjects.Count)" } } else { if ($EnableParallelProcessing) { Write-Host "Using sequential classification processing (dataset too small: $($UniqueObjects.Count) objects)" -ForegroundColor Yellow } else { Write-Host "Using sequential classification processing (parallel disabled)..." -ForegroundColor Yellow } $ClassifiedObjects = $UniqueObjects | ForEach-Object { if ($null -ne $_.ObjectId) { $ObjectId = $_.ObjectId if ($VerbosePreference -ne 'SilentlyContinue') { Write-Verbose -Message "Processing classifications for $($ObjectId)..." } # Object types $ObjectDetails = $ObjectDetailsCache[$ObjectId] # Fail-closed: never drop a principal whose object details could not be resolved # (failed/throttled Graph call: $null cache entry or ResolutionStatus 'Unresolved'). A vanished ControlPlane principal # would otherwise be removed from its protection group by the Administrative Unit / # Conditional Access group reconciliation. Emit a placeholder pinned to ControlPlane # instead, built from the identity fields known from the assignment data. $IsUnresolvedObject = ($null -eq $ObjectDetails -or "$($ObjectDetails.ResolutionStatus)" -eq 'Unresolved') if ($IsUnresolvedObject) { $UnresolvedWarning = "Object $ObjectId could not be resolved - emitted as fail-closed ControlPlane placeholder (TaggedBy=UnresolvedObject)" if ($null -ne $WarningMessages) { $WarningMessages.Add([PSCustomObject]@{ Type = "UnresolvedObject" Message = $UnresolvedWarning Target = $ObjectId }) } Write-Warning $UnresolvedWarning # Shared schema template (see its definition in function scope) - clone and # fill the object-specific fields. $Details = [ordered]@{} foreach ($TemplateKey in $UnresolvedObjectDetailsTemplate.Keys) { $Details[$TemplateKey] = $UnresolvedObjectDetailsTemplate[$TemplateKey] } $Details['ObjectTenantId'] = $_.ObjectTenantId $KnownObjectType = "$($_.ObjectType)" if (-not [string]::IsNullOrWhiteSpace($KnownObjectType)) { $Details['ObjectType'] = $KnownObjectType } $Details['ObjectDisplayName'] = $ObjectId $ObjectDetails = [PSCustomObject]$Details } # RBAC Assignments $RbacClassifiedAssignments = $RbacClassificationsByObject[$ObjectId] # Classification - merge MatchedActions/ScopedObjects across all assignments per tier/service $Classification = @(Merge-EntraOpsEAMClassification -RoleAssignments @($RbacClassifiedAssignments)) if ($Classification.Count -eq 0) { $Classification = @([PSCustomObject]@{ 'AdminTierLevel' = "Unclassified" 'AdminTierLevelName' = "Unclassified" 'Service' = "Unclassified" }) } if ($IsUnresolvedObject) { # Marker entry flags the fail-closed placeholder in the export. Keep any # classifications derived from the assignments themselves, but drop the generic # "Unclassified" fallback in favor of the explicit marker. $Classification = @($UnresolvedMarkerClassification.PSObject.Copy()) + @($Classification | Where-Object { $_.AdminTierLevelName -ne "Unclassified" }) } New-EntraOpsEAMOutputObject ` -ObjectId $ObjectId ` -ObjectDetails $ObjectDetails ` -Classification $Classification ` -RoleAssignments @($RbacClassifiedAssignments) ` -RoleSystem $RoleSystem } } } return $ClassifiedObjects } # SIG # Begin signature block # MIIniAYJKoZIhvcNAQcCoIIneTCCJ3UCAQExDzANBglghkgBZQMEAgEFADB5Bgor # BgEEAYI3AgEEoGswaTA0BgorBgEEAYI3AgEeMCYCAwEAAAQQH8w7YFlLCE63JNLG # KX7zUQIBAAIBAAIBAAIBAAIBADAxMA0GCWCGSAFlAwQCAQUABCBIlP+sQczzdHuf # e6ABs82ulKz5cBL145OgGMQcl9GlTaCCIDwwggXJMIIEsaADAgECAhAbtY8lKt8j # 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 # ARUwLwYJKoZIhvcNAQkEMSIEIN/gkyNRKjTylyGiNJhGPJS8MxZH0UKd8zwY1Cy0 # tU73MA0GCSqGSIb3DQEBAQUABIIBgEu6Xb1uKSR2BouFQcoh2DdNa7gCRin7yY8i # +Ok4Q187tcy9uZenDpM55vyioqkGIJajmF7fKS8kUyelKn4vO3lkWSmYPg7BD7LW # ATWAiZO03AD4IR8wjQ2gcLGTNEZqo5r0JH/mjVXipJ+5fu5LGwNQqgNElx+dYL/m # LJ50lEtUPb6tm/jPgAiw4B1dAtFvgFF35z+4qldaOl0zX9fQH8zMrGt+ojzYkzKo # hcVjOjcvcjZXx/Btcquckru5pohuyoxGpoTgBvMBZxBnVfRVb0DbrrUV0w8BJbDV # wo2wEcFE8G7caPKQJ3/jGKCG6vnMfvS0mQo0gNAJt2GN7toPUMe6EHTw0ZfItfyN # +ta6Nt+gB5IE3oBY9wz0swdkNxI8iMH5DwGYwxzv7i9lKwQiXH0whUsEjPaxvQQi # pcAVkIjiw6wCMLPLNSJf24HQyuzZnTiqWTR0WN4GNykmT5rPTkBmvsZzT+9lRsZX # WaqgtXp7IG/KH/LSZGKqnpl/9WfTfqGCBAIwggP+BgkqhkiG9w0BCQYxggPvMIID # 6wIBATBqMFYxCzAJBgNVBAYTAlBMMSEwHwYDVQQKExhBc3NlY28gRGF0YSBTeXN0 # ZW1zIFMuQS4xJDAiBgNVBAMTG0NlcnR1bSBUaW1lc3RhbXBpbmcgMjAyMSBDQQIQ # KPB3wRw2vf5fdDJHcCcuAzANBglghkgBZQMEAgIFAKCCAVYwGgYJKoZIhvcNAQkD # MQ0GCyqGSIb3DQEJEAEEMBwGCSqGSIb3DQEJBTEPFw0yNjEwMjcwNTM4MzZaMDcG # CyqGSIb3DQEJEAIvMSgwJjAkMCIEIIW+kOEK0kONfMkotq9IsJqyCBd87PiwEmxY # 05EFJcQ8MD8GCSqGSIb3DQEJBDEyBDDETXmRzJILhuWz4wo8s35CjQ+MrFRfMbUw # XJuSBwd1d5laeT2BcPNqEhKHLFuVG64wgZ8GCyqGSIb3DQEJEAIMMYGPMIGMMIGJ # MIGGBBRXFGhBDKha80JO+RZKUTYQ9NONmDBuMFqkWDBWMQswCQYDVQQGEwJQTDEh # MB8GA1UEChMYQXNzZWNvIERhdGEgU3lzdGVtcyBTLkEuMSQwIgYDVQQDExtDZXJ0 # dW0gVGltZXN0YW1waW5nIDIwMjEgQ0ECECjwd8EcNr3+X3QyR3AnLgMwDQYJKoZI # hvcNAQEBBQAEggIAkMaGPwF3ljHm6F+l/15vbAx/N/pICFHmksvVm8a9z7+z9RPk # 93sQrNyxmy3gm2tPlZSfkrKDb3b0A/tssEKq/vU8uEtWB+yDKhHFXoXMMJLXZGlT # o1Xic4j/SJeqMkx/1jkMSyFTynNCLQ0f+hsGXCF1J1RjVJKpjRLjOG+S1lA2irGK # 6v3kKheUkoFeXhHd8hSQNay2l2EC6wX1Pss2AGfgOXFj7IyGwWhWMzA5VNlc7zyq # IWi3oVOTtRTv7pz4EhxszpnTv8i9nAV++EmRExbyBDQP3EQ6xB282e1GCL84yKAb # wh60Dv2I/CkSuKvWvqCMjvf5zMIx/S6Y7CaxgmIpoKwQ27lQPz2d/KsrAJk7M6gC # CKucGKs5cFGUpETj+RqVUmFMYx0nmirqNlllw/qqB2YnHjJLOGfKXhwWbQtDeMLK # xoLYuPUwddeUXs+F/drahqxAt+cpmZSEC9Hj8FiG5m4ZRiLbyCbst65aDcXPKk4V # /nhKkGMQlYuOBqwRqZoUjPhGZo36qnOp4gEPs0m01NFD+wRqoZMe95I5weZFVp49 # kTsAcu+rhFcSK6BU6gTz7UdpvkUmE467juXGSuBN0fXsDdtO9hM0N/2i+P4d3cJb # IzBsEX4Sbtej3kKIBsYbUnIR9dPh3gwo7zFoyTbh6jI2LfqNyXh3d5rwQE8= # SIG # End signature block |