Modules/ScubaConfigApp/ScubaConfigAnalyzerHelpers/ScubaConfigAnalyzerGraphHelper.psm1
|
<#
.SYNOPSIS Analyzer helper: Microsoft Graph connect, scopes, raw Graph reads, and tenant-data collection. .NOTES Imported (Import-Module) by Start-SCuBAConfigAnalyzer alongside the other analyzer helpers. Shared analyzer state lives on the synchronized $syncHash ($syncHash.ScA*), so every helper module reads/writes the same caches (mirrors how ScubaConfigApp shares state). Populated at scan time by Import-ScA*. Part of the ScubaGear project - https://github.com/cisagov/ScubaGear #> function Write-ScAEngineActivity { <# .SYNOPSIS Reports a data-collection step to the analyzer Activity Log from engine (non-UI) code. .DESCRIPTION Engine helpers never touch WPF. Instead they append to the shared activity sink ($syncHash.ScAActivitySink) that the "Connect & Scan" worker points at $connectSync.Log; the UI's DispatcherTimer drains it onto the Activity Log tab. When no sink is present (headless unit tests, or the load-file path) it degrades to Write-Verbose only, so the engine stays UI-free and testable. #> param( [Parameter(Mandatory)][string]$Message, [ValidateSet('Info','Warning','Error')][string]$Level = 'Info' ) Write-Verbose $Message # Attempt to write the activity to the shared sink, if available. try { if ($syncHash -and $null -ne $syncHash.ScAActivitySink) { [void]$syncHash.ScAActivitySink.Add(@{ Message = $Message; Level = $Level }) } } catch { Write-Verbose "Write-ScAEngineActivity sink failed: $($_.Exception.Message)" } } function Get-ScubaAnalyzerScopes { <# .SYNOPSIS Aggregates the Microsoft Graph delegated scopes a product needs, resolved from the API catalog: least permissions for every cmdlet named in the baseline schema (apiPermissionRef) plus every cmdlet behind a named analyzer apiOperation (CA read, organization, name lookups). Fully JSON-driven - the only hardcoded scope is a Directory.Read.All safety net used when the catalog cannot be read at all. #> param( [Parameter(Mandatory)][string]$Product, [Parameter(Mandatory)]$BaselineSchema, [string]$ApiCatalogPath, [string]$AnalyzerControlPath ) # Import the API catalog and analyzer rules to resolve the required scopes. Import-ScAApiCatalog -ApiCatalogPath $ApiCatalogPath if ($AnalyzerControlPath -and (Test-Path $AnalyzerControlPath)) { try { Import-ScAAnalyzerRules -AnalyzerSchema (Get-Content $AnalyzerControlPath -Raw | ConvertFrom-Json) } catch { Write-Verbose "Analyzer rules load failed (scopes): $($_.Exception.Message)" } } # Normalize the product name to lowercase for consistent key lookups. $prod = $Product.ToLower() $cmdlets = @() # Initialize the list of cmdlets to aggregate scopes for. if ($BaselineSchema.baselineValidations.PSObject.Properties.Name -contains $prod) { foreach ($c in $BaselineSchema.baselineValidations.$prod) { if ($c.apiPermissionRef) { $cmdlets += $c.apiPermissionRef } } } # The named operations (CA read, organization, user/group/SP lookups) need scopes too. foreach ($op in $syncHash.ScAApiOperations.Values) { if ($op.cmdlet) { $cmdlets += [string]$op.cmdlet } } $cmdlets = @($cmdlets | Select-Object -Unique) # Aggregate the least permissions for each cmdlet to determine the required scopes. $scopes = New-Object System.Collections.Generic.HashSet[string] # Iterate over each cmdlet to collect its least permissions from the API catalog. foreach ($cmd in $cmdlets) { # Look up the API catalog entry for the current cmdlet. $entry = if ($syncHash.ScAApiCatalog.ContainsKey($cmd)) { $syncHash.ScAApiCatalog[$cmd] } else { $null } if ($entry -and $entry.leastPermissions) { foreach ($p in @($entry.leastPermissions)) { if ($p) { [void]$scopes.Add([string]$p) } } } } # Return the aggregated set of required scopes. if ($scopes.Count -eq 0) { [void]$scopes.Add('Directory.Read.All') } # safety net when the catalog is unavailable # Ensure that there is at least one scope in the set, adding a default if necessary. return @($scopes) } function Connect-ScubaAnalyzerGraph { <# .SYNOPSIS Connects to Microsoft Graph for the given environment. Interactive (delegated scopes) by default; if -AppId + -CertificateThumbprint are supplied it uses non-interactive app-only certificate auth (application permissions, so -Scopes is ignored). Should be called on the UI thread for the interactive path. Returns Get-MgContext. #> param( [string[]]$Scopes = @(), [string]$M365Environment = 'commercial', [string]$AppId, [string]$CertificateThumbprint, [string]$Organization ) # Import the Microsoft Graph Authentication module to enable connecting to Graph. Import-Module Microsoft.Graph.Authentication -ErrorAction Stop # Determine the appropriate Graph environment based on the specified M365 environment. $graphEnv = switch ($M365Environment) { 'gcchigh' { 'USGov' } 'dod' { 'USGovDoD' } default { 'Global' } } # Prepare the connection parameters for Connect-MgGraph. $connectParams = @{ Environment = $graphEnv; NoWelcome = $true; ErrorAction = 'Stop' } if ($AppId -and $CertificateThumbprint) { # App-only (non-interactive) certificate auth uses application permissions, not # delegated scopes, so -Scopes is intentionally not passed. $connectParams.ClientId = $AppId $connectParams.CertificateThumbprint = $CertificateThumbprint if ($Organization) { $connectParams.TenantId = $Organization } } else { $connectParams.Scopes = $Scopes } # Connect to Microsoft Graph using the prepared parameters. Connect-MgGraph @connectParams | Out-Null return (Get-MgContext) } function Invoke-ScubaGraphGet { <# .DESCRIPTION This function handles GET requests to Microsoft Graph, automatically following pagination links and aggregating results. .SYNOPSIS GETs a Graph resource with Invoke-MgGraphRequest (raw REST, only needs Microsoft.Graph.Authentication) and follows @odata.nextLink paging. Returns the collected .value items (or the single object for non-collection resources). #> param([Parameter(Mandatory)][string]$Uri) $items = @() $next = $Uri # Loop through the paginated results until there are no more pages. while ($next) { $resp = Invoke-MgGraphRequest -Method GET -Uri $next -OutputType PSObject -ErrorAction Stop if ($null -eq $resp) { break } # Break the loop if the response is null, indicating no more data. if ($resp.PSObject.Properties.Name -contains 'value') { $items += @($resp.value) $next = if ($resp.PSObject.Properties.Name -contains '@odata.nextLink') { $resp.'@odata.nextLink' } else { $null } } else { $items += $resp $next = $null } } # Return the aggregated collection of items from all pages. return $items } function Get-ScADisplayNameLookup { <# .SYNOPSIS Best-effort resolve of display names for excluded principals/apps across the given Conditional Access policies. Which policy paths to read and which Graph operation resolves each are declared in the analyzer schema's displayNameLookup rules (the actual URLs come from the API catalog). Returns id -> name to annotate the generated YAML. Requires an active Graph connection; per-id failures are ignored. #> param([array]$Policies = @()) $lookup = @{} $rules = $syncHash.ScACaRules # Return early if there are no displayNameLookup rules defined. if (-not $rules -or -not $rules.displayNameLookup -or -not $rules.displayNameLookup.rules) { return $lookup } $guidRe = '^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$' # Regular expression to match GUIDs. foreach ($rule in @($rules.displayNameLookup.rules)) { $ids = @() # Collect all IDs from the current policy according to the rule's policy path. foreach ($p in @($Policies)) { $ids += @(Get-ScAValueAtPath -Object $p -Path $rule.policyPath) } $ids = @($ids | Where-Object { $_ -match $guidRe } | Select-Object -Unique) if (@($ids).Count -eq 0) { continue } # Skip this rule if there are no valid IDs to look up. $op = if ($syncHash.ScAApiOperations.ContainsKey([string]$rule.operation)) { $syncHash.ScAApiOperations[[string]$rule.operation] } else { $null } $nameProps = if ($op -and $op.nameProperties) { @($op.nameProperties) } else { @('displayName') } # Resolve each ID to its display name using the specified API operation and name properties. foreach ($id in $ids) { $uri = Resolve-ScAApiResource -Operation ([string]$rule.operation) -Id $id if (-not $uri) { continue } # Skip this ID if the URI could not be resolved. try { $o = Invoke-MgGraphRequest -Method GET -Uri $uri -OutputType PSObject -ErrorAction Stop if ($o) { foreach ($np in $nameProps) { $val = ($o.PSObject.Properties | Where-Object { $_.Name -ieq [string]$np } | Select-Object -First 1).Value if ($val) { $lookup[$id] = $val; break } } } } catch { # Handle any errors that occur during the display name lookup. Write-Verbose "Display-name lookup failed for '$id': $($_.Exception.Message)" } } } # Return the lookup table containing the resolved display names. return $lookup } function Get-ScAUserPrincipalNameLookup { <# .SYNOPSIS Resolves the user object ids referenced by the CA policies (the displayNameLookup rules whose operation is 'userLookup' - i.e. include/exclude users) to their userPrincipalName. The tenant governance JSON emits users by UPN (the monitor compares users by UPN), while the generated YAML keeps display names - so this is a separate, user-only map. #> param([array]$Policies = @()) $lookup = @{} # Extract the relevant displayNameLookup rules from the schema. $rules = $syncHash.ScACaRules # If there are no displayNameLookup rules, skip the user UPN resolution. if (-not $rules -or -not $rules.displayNameLookup -or -not $rules.displayNameLookup.rules) { Write-ScAEngineActivity "User UPN resolution: no displayNameLookup rules loaded - skipped." -Level Warning return $lookup } # Extract the policy paths for the 'userLookup' operation from the displayNameLookup rules. $userPaths = @($rules.displayNameLookup.rules | Where-Object { [string]$_.operation -eq 'userLookup' } | ForEach-Object { [string]$_.policyPath }) if (@($userPaths).Count -eq 0) { Write-ScAEngineActivity "User UPN resolution: no 'userLookup' paths declared in the schema - skipped." -Level Warning return $lookup } # Prepare a regular expression to validate GUIDs for user IDs. $guidRe = '^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$' $ids = @() # Initialize an array to store the user IDs extracted from the policies. # Extract the user IDs from each policy at the specified paths. foreach ($p in @($Policies)) { foreach ($path in $userPaths) { $ids += @(Get-ScAValueAtPath -Object $p -Path $path) } } # Filter the extracted IDs to include only valid GUIDs and remove duplicates. $ids = @($ids | Where-Object { $_ -match $guidRe } | Select-Object -Unique) Write-ScAEngineActivity "User UPN resolution: $(@($ids).Count) distinct user id(s) found via $(@($userPaths).Count) path(s) ($($userPaths -join ', ')) across $(@($Policies).Count) policy/policies." # If no valid user IDs were found, skip the user UPN resolution. if (@($ids).Count -eq 0) { return $lookup } # Iterate over each valid user ID to resolve its corresponding user principal name (UPN) via the Microsoft Graph API. foreach ($id in $ids) { $uri = Resolve-ScAApiResource -Operation 'userLookup' -Id $id # If the URI could not be resolved, log a warning and continue to the next user ID. if (-not $uri) { Write-ScAEngineActivity "User UPN resolution: could not resolve a Graph URI for user '$id'." -Level Warning; continue } # Attempt to resolve the user principal name (UPN) for the current user ID. try { $o = Invoke-MgGraphRequest -Method GET -Uri $uri -OutputType PSObject -ErrorAction Stop $upn = if ($o) { ($o.PSObject.Properties | Where-Object { $_.Name -ieq 'userPrincipalName' } | Select-Object -First 1).Value } else { $null } if ($upn) { $lookup[$id] = $upn } else { Write-ScAEngineActivity "User UPN resolution: user '$id' returned no userPrincipalName." -Level Warning } } catch { Write-ScAEngineActivity "User UPN lookup failed for '$id': $($_.Exception.Message)" -Level Warning } } Write-ScAEngineActivity "User UPN resolution: resolved $(@($lookup.Keys).Count) of $(@($ids).Count) user principal name(s)." # Return the lookup table containing resolved user principal names (UPNs) keyed by user ID. return $lookup } function Get-ScubaTenantGraphData { <# .SYNOPSIS Reads the live tenant configuration a product's controls need using ONLY Microsoft Graph authentication + raw Graph API calls (Invoke-MgGraphRequest). The resource path is resolved from the JSON (API catalog 'apiResource' for the cmdlet named in the baseline schema's apiPermissionRef, falling back to buildInstructions .apiResourceCreate) so the schema stays the single source of truth and can change without code edits. Requires an existing Graph connection (Connect-ScubaAnalyzerGraph). The REST response is camelCase; the validation engine navigates policy properties case-insensitively, so no reshaping is needed. #> param( [Parameter(Mandatory)][string]$Product, [Parameter(Mandatory)]$BaselineSchema, [string]$ApiCatalogPath, [string]$AnalyzerControlPath ) # Ensure the Microsoft Graph Authentication module is imported for subsequent Graph API calls. Import-Module Microsoft.Graph.Authentication -ErrorAction Stop # Load the analyzer rules (named operations) + API catalog so every URL below is # resolved from ScubaGearApiCatalog.json rather than hardcoded here. if ($AnalyzerControlPath -and (Test-Path $AnalyzerControlPath)) { try { Import-ScAAnalyzerRules -AnalyzerSchema (Get-Content $AnalyzerControlPath -Raw | ConvertFrom-Json) } catch { Write-Verbose "Analyzer rules load failed (tenant data): $($_.Exception.Message)" } } # Ensure the API catalog is loaded for resolving resource URIs. Import-ScAApiCatalog -ApiCatalogPath $ApiCatalogPath # Initialize the data structure to hold tenant and organization information. $data = @{ conditional_access_policies = @(); OrgDisplayName = $null; Organization = $null; TenantId = $null; DisplayNameLookup = @{}; UserUpnLookup = @{} } # Determine the product-specific controls from the baseline schema. $prod = $Product.ToLower() $controls = @() # Check if the baseline schema contains validations for the specified product. if ($BaselineSchema.baselineValidations.PSObject.Properties.Name -contains $prod) { $controls = @($BaselineSchema.baselineValidations.$prod) } # Tenant identity + organization (resource resolved from the catalog). try { $ctx = Get-MgContext; if ($ctx) { $data.TenantId = $ctx.TenantId } } catch { Write-Verbose "Get-MgContext unavailable: $($_.Exception.Message)" } # Retrieve the current Microsoft Graph context to obtain the tenant ID. try { $orgUri = Resolve-ScAApiResource -Operation 'organization' # Resolve the organization resource URI from the API catalog. if ($orgUri) { Write-ScAEngineActivity "[$prod] Reading organization details ($orgUri)." $org = @(Invoke-ScubaGraphGet -Uri $orgUri) # Check if the organization details were successfully retrieved. if (@($org).Count -gt 0) { $data.OrgDisplayName = $org[0].displayName # Organization = the tenant's PRIMARY (default) verified domain, so a custom # domain set as primary is used. Fall back to the initial onmicrosoft.com # domain, then to the first verified domain. $domains = @($org[0].verifiedDomains) $primary = @($domains | Where-Object { $_.isDefault -eq $true }) # If no primary domain is found, fall back to the initial domain. if (@($primary).Count -eq 0) { $primary = @($domains | Where-Object { $_.isInitial -eq $true }) } # If still no primary domain is found, use the first verified domain. if (@($primary).Count -eq 0) { $primary = $domains } # Set the organization's primary domain. if (@($primary).Count -gt 0) { $data.Organization = $primary[0].name } Write-ScAEngineActivity "[$prod] Organization '$($data.OrgDisplayName)' (primary domain: $($data.Organization); $(@($domains).Count) verified domain(s); tenant $($data.TenantId))." } } } catch { Write-ScAEngineActivity "Organization lookup failed: $($_.Exception.Message)" -Level Warning } # Conditional Access policies: read only when a control uses the CA operation's cmdlet. $caOp = if ($syncHash.ScAApiOperations.ContainsKey('conditionalAccessPolicies')) { $syncHash.ScAApiOperations['conditionalAccessPolicies'] } else { $null } $caCmdlet = if ($caOp) { [string]$caOp.cmdlet } else { $null } # Determine if any controls use the Conditional Access cmdlet. $usesCa = $caCmdlet -and (@($controls | Where-Object { $_.apiPermissionRef -eq $caCmdlet }).Count -gt 0) if ($usesCa) { # Resolve the API resource URI for Conditional Access policies. $uri = Resolve-ScAApiResource -Operation 'conditionalAccessPolicies' if (-not $uri) { # Fall back to the baseline's own create-resource for the CA cmdlet if the catalog lacks it. $caControl = @($controls | Where-Object { $_.apiPermissionRef -eq $caCmdlet -and $_.buildInstructions.apiResourceCreate })[0] if ($caControl) { $uri = $caControl.buildInstructions.apiResourceCreate } } # If no URI could be resolved, skip reading Conditional Access policies. if ($uri) { Write-ScAEngineActivity "[$prod] Reading Conditional Access policies ($uri)." $data.conditional_access_policies = @(Invoke-ScubaGraphGet -Uri $uri) $caCount = @($data.conditional_access_policies).Count Write-ScAEngineActivity "[$prod] Retrieved $caCount Conditional Access policy/policies." # Log each retrieved Conditional Access policy. foreach ($pol in @($data.conditional_access_policies)) { $pName = if ($pol.displayName) { [string]$pol.displayName } else { [string]$pol.id } $pState = if ($pol.state) { [string]$pol.state } else { 'unknown' } Write-ScAEngineActivity "[$prod] - CA policy '$pName' (state: $pState)." } # Resolve display names for excluded principals/apps so the generated YAML can be annotated. try { $data.DisplayNameLookup = Get-ScADisplayNameLookup -Policies $data.conditional_access_policies # Log the number of resolved display names for excluded principals/apps. if (@($data.DisplayNameLookup.Keys).Count -gt 0) { Write-ScAEngineActivity "[$prod] Resolved $(@($data.DisplayNameLookup.Keys).Count) excluded principal/app display name(s)." } } catch { Write-ScAEngineActivity "Display-name resolution skipped: $($_.Exception.Message)" -Level Warning } # Users are emitted by UPN in the tenant governance JSON (the monitor compares users by UPN). try { $data.UserUpnLookup = Get-ScAUserPrincipalNameLookup -Policies $data.conditional_access_policies } catch { Write-ScAEngineActivity "User UPN resolution skipped: $($_.Exception.Message)" -Level Warning } } } # Non-CA provider data (e.g. EXO remote domains, anti-phish policies). Each exclusion # type may declare its own analysis+fetch (exclusionDefinitions.<field>.analysis); when a # baseline control for this product uses that cmdlet, best-effort fetch it and store under # rawKey so Get-ScAProviderAnalysis reads it exactly like the offline ScubaResults Raw.<key>. $fetched = @{} # Iterate over each exclusion type defined in the schema to fetch non-CA provider data. foreach ($field in @($syncHash.ScAExclusionDefinitions.Keys)) { $an = $syncHash.ScAExclusionDefinitions[$field].analysis if (-not $an -or -not $an.fetch -or -not $an.rawKey) { continue } # Extract the cmdlet name and raw key for this exclusion type. $cmdName = [string]$an.fetch.cmdlet $rawKey = [string]$an.rawKey # Skip if no cmdlet is specified or if this raw key has already been fetched. if (-not $cmdName -or $fetched.ContainsKey($rawKey)) { continue } # Only fetch when a baseline control for this product depends on this cmdlet. if (@($controls | Where-Object { $_.apiPermissionRef -eq $cmdName }).Count -eq 0) { continue } # Log the attempt to fetch provider data for this exclusion type. try { Write-ScAEngineActivity "[$prod] Reading provider data via $cmdName (-> $rawKey)." $items = Get-ScAExchangeData -Fetch $an.fetch -Organization $data.Organization # Store the fetched items under the raw key if any were retrieved. if ($null -ne $items) { $data[$rawKey] = @($items); $fetched[$rawKey] = $true Write-ScAEngineActivity "[$prod] Retrieved $(@($items).Count) record(s) from $cmdName." } } catch { Write-ScAEngineActivity "Provider fetch '$cmdName' failed: $($_.Exception.Message)" -Level Warning } } # Return the updated data object containing all fetched provider data. return $data } function Get-ScubaAnalyzerFetchConnections { <# .SYNOPSIS Returns the distinct provider connections (module/connectCmdlet) the selected products need, driven entirely by the schema: an exclusion type's analysis.fetch is required when a baseline control for a selected product uses that fetch cmdlet. The UI uses this to connect (e.g. Exchange Online) up front on the sign-in thread when EXO/SecuritySuite is checked, so the live reads succeed. .OUTPUTS @( @{ module; connectCmdlet; cmdlet }, ... ) (empty when only Graph is needed) #> param( [Parameter(Mandatory)][string[]]$Products, [Parameter(Mandatory)]$BaselineSchema, [string]$AnalyzerControlPath ) # Import analyzer rules from the specified control path if it exists. if ($AnalyzerControlPath -and (Test-Path $AnalyzerControlPath)) { try { Import-ScAAnalyzerRules -AnalyzerSchema (Get-Content $AnalyzerControlPath -Raw | ConvertFrom-Json) } catch { Write-Verbose "Analyzer rules load failed (fetch connections): $($_.Exception.Message)" } } # Initialize a hash set to keep track of all unique cmdlets referenced by the selected products. $cmdlets = New-Object System.Collections.Generic.HashSet[string] # Iterate over each selected product and collect all cmdlets referenced in its baseline validations. foreach ($p in $Products) { $pl = $p.ToLower() # Check if the baseline schema contains validations for the current product. if ($BaselineSchema.baselineValidations.PSObject.Properties.Name -contains $pl) { foreach ($c in $BaselineSchema.baselineValidations.$pl) { if ($c.apiPermissionRef) { [void]$cmdlets.Add([string]$c.apiPermissionRef) } } } } $conns = [ordered]@{} # Iterate over each exclusion definition in the analyzer rules and collect the necessary connection information for the cmdlets used. foreach ($field in @($syncHash.ScAExclusionDefinitions.Keys)) { $an = $syncHash.ScAExclusionDefinitions[$field].analysis # Skip this exclusion definition if it doesn't have a fetch analysis. if (-not $an -or -not $an.fetch) { continue } $cmd = [string]$an.fetch.cmdlet # Skip this exclusion definition if the cmdlet is not used by any of the selected products. if (-not $cmdlets.Contains($cmd)) { continue } # Get the connection key for the fetch cmdlet. $key = [string]$an.fetch.connectCmdlet if ($key -and -not $conns.Contains($key)) { $conns[$key] = @{ module = [string]$an.fetch.module; connectCmdlet = $key; cmdlet = $cmd } } } # Return the collected connection information as an array of hashtables. return @($conns.Values) } # SIG # Begin signature block # MIIu9gYJKoZIhvcNAQcCoIIu5zCCLuMCAQExDzANBglghkgBZQMEAgEFADB5Bgor # BgEEAYI3AgEEoGswaTA0BgorBgEEAYI3AgEeMCYCAwEAAAQQH8w7YFlLCE63JNLG # KX7zUQIBAAIBAAIBAAIBAAIBADAxMA0GCWCGSAFlAwQCAQUABCB52dSbbMeW5n6B # PdXdt0vN7g8T+IGUlqDd8b6UDdc8cKCCE6MwggWQMIIDeKADAgECAhAFmxtXno4h # MuI5B72nd3VcMA0GCSqGSIb3DQEBDAUAMGIxCzAJBgNVBAYTAlVTMRUwEwYDVQQK # EwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20xITAfBgNV # BAMTGERpZ2lDZXJ0IFRydXN0ZWQgUm9vdCBHNDAeFw0xMzA4MDExMjAwMDBaFw0z # ODAxMTUxMjAwMDBaMGIxCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdpQ2VydCBJ # bmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20xITAfBgNVBAMTGERpZ2lDZXJ0 # IFRydXN0ZWQgUm9vdCBHNDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIB # AL/mkHNo3rvkXUo8MCIwaTPswqclLskhPfKK2FnC4SmnPVirdprNrnsbhA3EMB/z # G6Q4FutWxpdtHauyefLKEdLkX9YFPFIPUh/GnhWlfr6fqVcWWVVyr2iTcMKyunWZ # anMylNEQRBAu34LzB4TmdDttceItDBvuINXJIB1jKS3O7F5OyJP4IWGbNOsFxl7s # Wxq868nPzaw0QF+xembud8hIqGZXV59UWI4MK7dPpzDZVu7Ke13jrclPXuU15zHL # 2pNe3I6PgNq2kZhAkHnDeMe2scS1ahg4AxCN2NQ3pC4FfYj1gj4QkXCrVYJBMtfb # BHMqbpEBfCFM1LyuGwN1XXhm2ToxRJozQL8I11pJpMLmqaBn3aQnvKFPObURWBf3 # JFxGj2T3wWmIdph2PVldQnaHiZdpekjw4KISG2aadMreSx7nDmOu5tTvkpI6nj3c # AORFJYm2mkQZK37AlLTSYW3rM9nF30sEAMx9HJXDj/chsrIRt7t/8tWMcCxBYKqx # YxhElRp2Yn72gLD76GSmM9GJB+G9t+ZDpBi4pncB4Q+UDCEdslQpJYls5Q5SUUd0 # viastkF13nqsX40/ybzTQRESW+UQUOsxxcpyFiIJ33xMdT9j7CFfxCBRa2+xq4aL # T8LWRV+dIPyhHsXAj6KxfgommfXkaS+YHS312amyHeUbAgMBAAGjQjBAMA8GA1Ud # EwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgGGMB0GA1UdDgQWBBTs1+OC0nFdZEzf # Lmc/57qYrhwPTzANBgkqhkiG9w0BAQwFAAOCAgEAu2HZfalsvhfEkRvDoaIAjeNk # aA9Wz3eucPn9mkqZucl4XAwMX+TmFClWCzZJXURj4K2clhhmGyMNPXnpbWvWVPjS # PMFDQK4dUPVS/JA7u5iZaWvHwaeoaKQn3J35J64whbn2Z006Po9ZOSJTROvIXQPK # 7VB6fWIhCoDIc2bRoAVgX+iltKevqPdtNZx8WorWojiZ83iL9E3SIAveBO6Mm0eB # cg3AFDLvMFkuruBx8lbkapdvklBtlo1oepqyNhR6BvIkuQkRUNcIsbiJeoQjYUIp # 5aPNoiBB19GcZNnqJqGLFNdMGbJQQXE9P01wI4YMStyB0swylIQNCAmXHE/A7msg # dDDS4Dk0EIUhFQEI6FUy3nFJ2SgXUE3mvk3RdazQyvtBuEOlqtPDBURPLDab4vri # RbgjU2wGb2dVf0a1TD9uKFp5JtKkqGKX0h7i7UqLvBv9R0oN32dmfrJbQdA75PQ7 # 9ARj6e/CVABRoIoqyc54zNXqhwQYs86vSYiv85KZtrPmYQ/ShQDnUBrkG5WdGaG5 # nLGbsQAe79APT0JsyQq87kP6OnGlyE0mpTX9iV28hWIdMtKgK1TtmlfB2/oQzxm3 # i0objwG2J5VT6LaJbVu8aNQj6ItRolb58KaAoNYes7wPD1N1KarqE3fk3oyBIa0H # EEcRrYc9B9F1vM/zZn4wggawMIIEmKADAgECAhAIrUCyYNKcTJ9ezam9k67ZMA0G # CSqGSIb3DQEBDAUAMGIxCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdpQ2VydCBJ # bmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20xITAfBgNVBAMTGERpZ2lDZXJ0 # IFRydXN0ZWQgUm9vdCBHNDAeFw0yMTA0MjkwMDAwMDBaFw0zNjA0MjgyMzU5NTla # MGkxCzAJBgNVBAYTAlVTMRcwFQYDVQQKEw5EaWdpQ2VydCwgSW5jLjFBMD8GA1UE # AxM4RGlnaUNlcnQgVHJ1c3RlZCBHNCBDb2RlIFNpZ25pbmcgUlNBNDA5NiBTSEEz # ODQgMjAyMSBDQTEwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDVtC9C # 0CiteLdd1TlZG7GIQvUzjOs9gZdwxbvEhSYwn6SOaNhc9es0JAfhS0/TeEP0F9ce # 2vnS1WcaUk8OoVf8iJnBkcyBAz5NcCRks43iCH00fUyAVxJrQ5qZ8sU7H/Lvy0da # E6ZMswEgJfMQ04uy+wjwiuCdCcBlp/qYgEk1hz1RGeiQIXhFLqGfLOEYwhrMxe6T # SXBCMo/7xuoc82VokaJNTIIRSFJo3hC9FFdd6BgTZcV/sk+FLEikVoQ11vkunKoA # FdE3/hoGlMJ8yOobMubKwvSnowMOdKWvObarYBLj6Na59zHh3K3kGKDYwSNHR7Oh # D26jq22YBoMbt2pnLdK9RBqSEIGPsDsJ18ebMlrC/2pgVItJwZPt4bRc4G/rJvmM # 1bL5OBDm6s6R9b7T+2+TYTRcvJNFKIM2KmYoX7BzzosmJQayg9Rc9hUZTO1i4F4z # 8ujo7AqnsAMrkbI2eb73rQgedaZlzLvjSFDzd5Ea/ttQokbIYViY9XwCFjyDKK05 # huzUtw1T0PhH5nUwjewwk3YUpltLXXRhTT8SkXbev1jLchApQfDVxW0mdmgRQRNY # mtwmKwH0iU1Z23jPgUo+QEdfyYFQc4UQIyFZYIpkVMHMIRroOBl8ZhzNeDhFMJlP # /2NPTLuqDQhTQXxYPUez+rbsjDIJAsxsPAxWEQIDAQABo4IBWTCCAVUwEgYDVR0T # AQH/BAgwBgEB/wIBADAdBgNVHQ4EFgQUaDfg67Y7+F8Rhvv+YXsIiGX0TkIwHwYD # VR0jBBgwFoAU7NfjgtJxXWRM3y5nP+e6mK4cD08wDgYDVR0PAQH/BAQDAgGGMBMG # A1UdJQQMMAoGCCsGAQUFBwMDMHcGCCsGAQUFBwEBBGswaTAkBggrBgEFBQcwAYYY # aHR0cDovL29jc3AuZGlnaWNlcnQuY29tMEEGCCsGAQUFBzAChjVodHRwOi8vY2Fj # ZXJ0cy5kaWdpY2VydC5jb20vRGlnaUNlcnRUcnVzdGVkUm9vdEc0LmNydDBDBgNV # HR8EPDA6MDigNqA0hjJodHRwOi8vY3JsMy5kaWdpY2VydC5jb20vRGlnaUNlcnRU # cnVzdGVkUm9vdEc0LmNybDAcBgNVHSAEFTATMAcGBWeBDAEDMAgGBmeBDAEEATAN # BgkqhkiG9w0BAQwFAAOCAgEAOiNEPY0Idu6PvDqZ01bgAhql+Eg08yy25nRm95Ry # sQDKr2wwJxMSnpBEn0v9nqN8JtU3vDpdSG2V1T9J9Ce7FoFFUP2cvbaF4HZ+N3HL # IvdaqpDP9ZNq4+sg0dVQeYiaiorBtr2hSBh+3NiAGhEZGM1hmYFW9snjdufE5Btf # Q/g+lP92OT2e1JnPSt0o618moZVYSNUa/tcnP/2Q0XaG3RywYFzzDaju4ImhvTnh # OE7abrs2nfvlIVNaw8rpavGiPttDuDPITzgUkpn13c5UbdldAhQfQDN8A+KVssIh # dXNSy0bYxDQcoqVLjc1vdjcshT8azibpGL6QB7BDf5WIIIJw8MzK7/0pNVwfiThV # 9zeKiwmhywvpMRr/LhlcOXHhvpynCgbWJme3kuZOX956rEnPLqR0kq3bPKSchh/j # wVYbKyP/j7XqiHtwa+aguv06P0WmxOgWkVKLQcBIhEuWTatEQOON8BUozu3xGFYH # Ki8QxAwIZDwzj64ojDzLj4gLDb879M4ee47vtevLt/B3E+bnKD+sEq6lLyJsQfmC # XBVmzGwOysWGw/YmMwwHS6DTBwJqakAwSEs0qFEgu60bhQjiWQ1tygVQK+pKHJ6l # /aCnHwZ05/LWUpD9r4VIIflXO7ScA+2GRfS0YW6/aOImYIbqyK+p/pQd52MbOoZW # eE4wggdXMIIFP6ADAgECAhAMM6tnPejLgA9WVhXroQvSMA0GCSqGSIb3DQEBCwUA # MGkxCzAJBgNVBAYTAlVTMRcwFQYDVQQKEw5EaWdpQ2VydCwgSW5jLjFBMD8GA1UE # AxM4RGlnaUNlcnQgVHJ1c3RlZCBHNCBDb2RlIFNpZ25pbmcgUlNBNDA5NiBTSEEz # ODQgMjAyMSBDQTEwHhcNMjYwMTE0MDAwMDAwWhcNMjcwMTEzMjM1OTU5WjBfMQsw # CQYDVQQGEwJVUzEdMBsGA1UECBMURGlzdHJpY3Qgb2YgQ29sdW1iaWExEzARBgNV # BAcTCldhc2hpbmd0b24xDTALBgNVBAoTBENJU0ExDTALBgNVBAMTBENJU0EwggIi # MA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCuXYolNHqlh6smLTE592waXheZ # 8VHzxeds4pMaepGuwmjf8d1jG9wUNuJX9/qb0a1dgGz5D/EAz5NRTIin4SZYQEE8 # qvdl2yQJ5uWxXIjsFbrOyc1fWscUXw0Kt7OPLOafcEkdDoe8K0tO4h2GL3RWRzjp # uLfQhhnAmD6NT1l+ughnfmarV/ODgIn/RFR4YORlu4YP2xQX6KRxeTDslg7F+z6X # +t87/U8m8gQ9XTm5kBmteP4GcE/ytnyI+ScIxNRybzGomWIBm848XDE5yYhlYQ2R # SnCoo6M4CRqp9WFGVyoLkoPP0OlxzryKWaE1/nuPbYG/kf/rUB1OhqxvSSGwmNhs # vkkjsC0Z9H5Jy6heFdoxOu/+ZQksKoP/fMvHxuCCtkIJbV8tk0oT6MQ8EJbgsWDZ # TKhui1wxW6JIZyBOMPWoZUOouOzo2h5Cz7LBPKME5FkcUzcs47lpRlDkJco4PLcj # wJSo4XPnx3G/2DIjNEFNyfKCWfH8uW6nJjmDBiveFZ2j0YvgdQ+7MOjQnw7R/MAD # DTagrKl3rLV60+X2TY6/onKhCUuU3pMAjVbOwZ3PkzDLZnsEGRfm6hgp6014aXml # t8h4nu+uC41U8vUSGHl0vqKuzvmShLmnI+Iv0l95pmnqomuCZzRDrjEoaLPx7OxL # Dy/Id9E7yQDip4jBdQIDAQABo4ICAzCCAf8wHwYDVR0jBBgwFoAUaDfg67Y7+F8R # hvv+YXsIiGX0TkIwHQYDVR0OBBYEFN30sVU+fpfQQfPQWMhkO1qd+MxoMD4GA1Ud # IAQ3MDUwMwYGZ4EMAQQBMCkwJwYIKwYBBQUHAgEWG2h0dHA6Ly93d3cuZGlnaWNl # cnQuY29tL0NQUzAOBgNVHQ8BAf8EBAMCB4AwEwYDVR0lBAwwCgYIKwYBBQUHAwMw # gbUGA1UdHwSBrTCBqjBToFGgT4ZNaHR0cDovL2NybDMuZGlnaWNlcnQuY29tL0Rp # Z2lDZXJ0VHJ1c3RlZEc0Q29kZVNpZ25pbmdSU0E0MDk2U0hBMzg0MjAyMUNBMS5j # cmwwU6BRoE+GTWh0dHA6Ly9jcmw0LmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydFRydXN0 # ZWRHNENvZGVTaWduaW5nUlNBNDA5NlNIQTM4NDIwMjFDQTEuY3JsMIGUBggrBgEF # BQcBAQSBhzCBhDAkBggrBgEFBQcwAYYYaHR0cDovL29jc3AuZGlnaWNlcnQuY29t # MFwGCCsGAQUFBzAChlBodHRwOi8vY2FjZXJ0cy5kaWdpY2VydC5jb20vRGlnaUNl # cnRUcnVzdGVkRzRDb2RlU2lnbmluZ1JTQTQwOTZTSEEzODQyMDIxQ0ExLmNydDAJ # BgNVHRMEAjAAMA0GCSqGSIb3DQEBCwUAA4ICAQA77T42YiOx5wWPItgo+kvB+Gzb # ZFCRHRFfTAZZNQt9o/0CqNmyA2xFklX4t5Z9VNdiIOx14AnmJdQkcRdk3vsU5gby # jKEup7LTWtvcWrl6hQwGNt3l892BgUbPKsPBE+AriktVqn5yMSXVVzeboqsqAG8e # Syei0B54/QdgR4whfHvQ/qpCACsJTlJgAykXVgDPJNKnQ7wc17loLQutqF1JUcbO # XKWt1AA9Zas5q30LDZzZeK4B56yojK68CTQXN7toSRFIuZDMKKDfIZpCX8cmbaaO # DFOOu44/QWMv+Xc6+ISYGkrTTzqWhOqiXgLVBeXGn/WrOJJ8R29mZMneCpBesCLs # YII1gCFOo7Vt6mvOKxAPQ3KhJYBFEHkp+GI65koaQkO2xv50iLS0+/j2YC66uviU # MFe0JEOdXuE7Rn/OmWNSzQ+6kPNYDJQASQ974C3wUejJoMtGZEzoTbly/HufQTrd # rhcL2aC69CxSN+idTXPLC9UT3xo4sFdOw+hXkmbXtoB1GDsd5p1TWFgRbnTXDkbM # YMBWYVB6/Tk1bzwj4iTp4g0YrtB628FXPX/ko+JWZlv0Ea865S23w1uGlnDNVxIi # +8oi74G5DM66Q6ENt6+3WoRGRrdoyE6uCh1haY+oPYSgumb0ozzrp8tw89TRKVrK # KSXGBxlExEvjQ6dYwjGCGqkwghqlAgEBMH0waTELMAkGA1UEBhMCVVMxFzAVBgNV # BAoTDkRpZ2lDZXJ0LCBJbmMuMUEwPwYDVQQDEzhEaWdpQ2VydCBUcnVzdGVkIEc0 # IENvZGUgU2lnbmluZyBSU0E0MDk2IFNIQTM4NCAyMDIxIENBMQIQDDOrZz3oy4AP # VlYV66EL0jANBglghkgBZQMEAgEFAKCBhDAYBgorBgEEAYI3AgEMMQowCKACgACh # AoAAMBkGCSqGSIb3DQEJAzEMBgorBgEEAYI3AgEEMBwGCisGAQQBgjcCAQsxDjAM # BgorBgEEAYI3AgEVMC8GCSqGSIb3DQEJBDEiBCCdCLtYAoj+ZUSoGZhlUogaloQJ # Sucfz7RgU1snop2HjDANBgkqhkiG9w0BAQEFAASCAgBcFxpbs7Su8k+SaLWZuugA # yAPue8ycK/dt4xhryp1fFueXiDey8C98v88R8KtOJHGhU3oXT+p6zSeF0dTZVzss # W0AirWS8pMz50t6wx6KCqYs0SF/lE5dCgCcLSMPai6TbwdWe6y7T8hifoOMmIKLN # uwVV8O9krMZ0T3zkxdeL/SKSuE+C0jtVUt2O51cCHkpJupJxm3fdYMl5o7HuYXyB # 6jUaJ33jwWRe20TdOa4r+RVY4JiDyglCdl/6X7352rxZ24pkfPSC/mhzmmBGkjfd # cZMBlPM+CV585voAnk+CunND9jAhgE3JUrL/yazYQKIzSq4hprGt5ovAMtcaF8l8 # WpdL7wxVHkfoCV4rbrL+nGAfUxDF3phGl/yIXpoe5IWVjqAkg0byUCB4GrnCurUI # znxQMjiX12mWjF+WL+FRMPw0GmQpkn61XT8SfylOGXb+y97zVkDfpW9rB8oIStJz # w9CQX0bwydvglfwv/uQ25eJ70Pb8bHVl0qpYvnezSJjgGdJm7n/J/E3oI7xIQLd9 # H56Ygqj2OP6v0dJSuXLqUNOM5GGl14SAzsCDmdw+42224LLimWfX3OrqoDnEDSFG # KdnOmoqVK61tqkkDYGmFWqZQelPi5lBKHlg01AtzoEqi2A3kQdj01FeE0ySyVFIo # S2R603xjF0AfRN9mGLUXUqGCF3YwghdyBgorBgEEAYI3AwMBMYIXYjCCF14GCSqG # SIb3DQEHAqCCF08wghdLAgEDMQ8wDQYJYIZIAWUDBAIBBQAwdwYLKoZIhvcNAQkQ # AQSgaARmMGQCAQEGCWCGSAGG/WwHATAxMA0GCWCGSAFlAwQCAQUABCBfSh01Zj01 # CnXIy2rHsuU6Rb0QBnPfNp+SAV0b7h/xIAIQKDlgqrgyGjwsQ48s44ODlxgPMjAy # NjEwMjIyMTMwNDNaoIITOjCCBu0wggTVoAMCAQICEAhP3DNPfkVO28MPj/mSGDUw # DQYJKoZIhvcNAQELBQAwaTELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDkRpZ2lDZXJ0 # LCBJbmMuMUEwPwYDVQQDEzhEaWdpQ2VydCBUcnVzdGVkIEc0IFRpbWVTdGFtcGlu # ZyBSU0E0MDk2IFNIQTI1NiAyMDI1IENBMTAeFw0yNjA4MDUwMDAwMDBaFw0zNzEx # MDQyMzU5NTlaMGMxCzAJBgNVBAYTAlVTMRcwFQYDVQQKEw5EaWdpQ2VydCwgSW5j # LjE7MDkGA1UEAxMyRGlnaUNlcnQgU0hBMjU2IFJTQTQwOTYgVGltZXN0YW1wIFJl # c3BvbmRlciAyMDI2IDEwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC2 # e6byyf7NSvjUm0xls/04xjD4fAkOkbnGQi7+Wpx81iYxfzViaxSIctuH3KSl5YEY # pMuFgGsA31N2D9ATMbfZdw5uaAhuWevQKhDdZIB4NnqcfpfpWQXJiQnDdAElETC+ # bhSEvNLGbA8DtwUpFMQ4yyYQSPqomT92osQAv6hBi47ATZS6JfVWe6XxhF4jJZ3i # SAuf2Cros1czRSmWRHqMv9AfGZvp8ygYElhudpQjtcPpwoOl6QrZJUyV3iINvN4c # O05prGV0fkjG426xDr2d3z9lcSIHkdvGPdGUrXdxfVbgOUVcp2/8ISEzwKPW++Wa # +E2ujI91EZtukGWDJ/xZ27k3oHKEXBRGfRTqjOU+jE3ba/5++JSE/7oNHnjs5mek # ExYN96LV/mxUbCKJb8pBNY4r3uD7hEmk/M81XhVgwDA7aMzYC3LZBg9WY5BMmbSa # y5ecmtJuXaB/0nKWmQmVZeqTVDgsmzHP5MQuhAJkiWNuC9MmCg9TZHXbJ2/yLVSo # v9p16UDTLtT0+aa1vN71fHeu1qMLlLNB3WOB/ADCxr3S/1hxI92Z6jKgEED/btwI # vbfuXkNNhg8MtDg43c4tMZae9FvqMOt/9PvmAxF9TNIsIFB8G6yb36ZJZGUL8N/p # L971DyLXcK6HM5PYnH5X+eVtczhCgHCVQCF6XDAlPQIDAQABo4IBlTCCAZEwDAYD # VR0TAQH/BAIwADAdBgNVHQ4EFgQUFMljijAu1Er7bpTz5uNAfvXszeIwHwYDVR0j # BBgwFoAU729TSunkBnx6yuKQVvYv1Ensy04wDgYDVR0PAQH/BAQDAgeAMBYGA1Ud # JQEB/wQMMAoGCCsGAQUFBwMIMIGVBggrBgEFBQcBAQSBiDCBhTAkBggrBgEFBQcw # AYYYaHR0cDovL29jc3AuZGlnaWNlcnQuY29tMF0GCCsGAQUFBzAChlFodHRwOi8v # Y2FjZXJ0cy5kaWdpY2VydC5jb20vRGlnaUNlcnRUcnVzdGVkRzRUaW1lU3RhbXBp # bmdSU0E0MDk2U0hBMjU2MjAyNUNBMS5jcnQwXwYDVR0fBFgwVjBUoFKgUIZOaHR0 # cDovL2NybDMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0VHJ1c3RlZEc0VGltZVN0YW1w # aW5nUlNBNDA5NlNIQTI1NjIwMjVDQTEuY3JsMCAGA1UdIAQZMBcwCAYGZ4EMAQQC # MAsGCWCGSAGG/WwHATANBgkqhkiG9w0BAQsFAAOCAgEAjcU6YR6dUgrfmawJgH59 # KECxa9Ji8sEi2g10CBDaMiqsaxWyW5cwlT/6ZF5sFznazqVsoC85U9dqLOYqQwst # +UQQoNlDHgKRLa3xoc+OReFreFhnTXSG0Vrd2E2CZqUfm+5a+He1MJ/h+tNLuA+0 # Zzhn/Fo+FDYAHWZHx4R79ZsfRFYe9UiXpXBDf6DkUo183Y38NYmR/XfDYf7YZ+oR # 9t3flbDwK+hgGMs0gNNp1w9Z2CyOyI5or/sSwomAuNQ0hWC9xoU4stD8aWsD7Rkc # mgVRs6vlIk3zPKQ+ylcheWkMlj+CoVRlFE55pv0ZWCaFt04lwP/rdGHE9qEVQZty # RE42ox7oNgC/r+Y4bSlZ3dw9K2x1xLtu6PkPKeLBFjzKigwfqm3Hm+k/+lnME8F5 # kPZTgiy2HLEHklpryqs6QHnPXrRNeIzkAMyylnRN8P0wmirS0WkU+ywpEWFZ4QNg # +9xS43tTuW9x0eXh7NDc1P/sV+zWxHXKH8tFt1ncHdVzqrZaYPyYMLSn2TOXajve # JW1L3joiQSPsWRGxkbDDW15jERFE4LvjnGu2O9zD1nLJSMdlYZEikl4w2w+q4IN/ # R+TIe0H4ngCI1moJCTbevGH4punIxM1Uoi0nmX3ZK+XbRT01uowE5ViXWHng0Rgs # mrX/EdYUo80r3TfMlkD0/YMwgga0MIIEnKADAgECAhANx6xXBf8hmS5AQyIMOkmG # MA0GCSqGSIb3DQEBCwUAMGIxCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdpQ2Vy # dCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20xITAfBgNVBAMTGERpZ2lD # ZXJ0IFRydXN0ZWQgUm9vdCBHNDAeFw0yNTA1MDcwMDAwMDBaFw0zODAxMTQyMzU5 # NTlaMGkxCzAJBgNVBAYTAlVTMRcwFQYDVQQKEw5EaWdpQ2VydCwgSW5jLjFBMD8G # A1UEAxM4RGlnaUNlcnQgVHJ1c3RlZCBHNCBUaW1lU3RhbXBpbmcgUlNBNDA5NiBT # SEEyNTYgMjAyNSBDQTEwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC0 # eDHTCphBcr48RsAcrHXbo0ZodLRRF51NrY0NlLWZloMsVO1DahGPNRcybEKq+Ruw # OnPhof6pvF4uGjwjqNjfEvUi6wuim5bap+0lgloM2zX4kftn5B1IpYzTqpyFQ/4B # t0mAxAHeHYNnQxqXmRinvuNgxVBdJkf77S2uPoCj7GH8BLuxBG5AvftBdsOECS1U # kxBvMgEdgkFiDNYiOTx4OtiFcMSkqTtF2hfQz3zQSku2Ws3IfDReb6e3mmdglTca # arps0wjUjsZvkgFkriK9tUKJm/s80FiocSk1VYLZlDwFt+cVFBURJg6zMUjZa/zb # CclF83bRVFLeGkuAhHiGPMvSGmhgaTzVyhYn4p0+8y9oHRaQT/aofEnS5xLrfxnG # pTXiUOeSLsJygoLPp66bkDX1ZlAeSpQl92QOMeRxykvq6gbylsXQskBBBnGy3tW/ # AMOMCZIVNSaz7BX8VtYGqLt9MmeOreGPRdtBx3yGOP+rx3rKWDEJlIqLXvJWnY0v # 5ydPpOjL6s36czwzsucuoKs7Yk/ehb//Wx+5kMqIMRvUBDx6z1ev+7psNOdgJMoi # wOrUG2ZdSoQbU2rMkpLiQ6bGRinZbI4OLu9BMIFm1UUl9VnePs6BaaeEWvjJSjNm # 2qA+sdFUeEY0qVjPKOWug/G6X5uAiynM7Bu2ayBjUwIDAQABo4IBXTCCAVkwEgYD # VR0TAQH/BAgwBgEB/wIBADAdBgNVHQ4EFgQU729TSunkBnx6yuKQVvYv1Ensy04w # HwYDVR0jBBgwFoAU7NfjgtJxXWRM3y5nP+e6mK4cD08wDgYDVR0PAQH/BAQDAgGG # MBMGA1UdJQQMMAoGCCsGAQUFBwMIMHcGCCsGAQUFBwEBBGswaTAkBggrBgEFBQcw # AYYYaHR0cDovL29jc3AuZGlnaWNlcnQuY29tMEEGCCsGAQUFBzAChjVodHRwOi8v # Y2FjZXJ0cy5kaWdpY2VydC5jb20vRGlnaUNlcnRUcnVzdGVkUm9vdEc0LmNydDBD # BgNVHR8EPDA6MDigNqA0hjJodHRwOi8vY3JsMy5kaWdpY2VydC5jb20vRGlnaUNl # cnRUcnVzdGVkUm9vdEc0LmNybDAgBgNVHSAEGTAXMAgGBmeBDAEEAjALBglghkgB # hv1sBwEwDQYJKoZIhvcNAQELBQADggIBABfO+xaAHP4HPRF2cTC9vgvItTSmf83Q # h8WIGjB/T8ObXAZz8OjuhUxjaaFdleMM0lBryPTQM2qEJPe36zwbSI/mS83afsl3 # YTj+IQhQE7jU/kXjjytJgnn0hvrV6hqWGd3rLAUt6vJy9lMDPjTLxLgXf9r5nWMQ # wr8Myb9rEVKChHyfpzee5kH0F8HABBgr0UdqirZ7bowe9Vj2AIMD8liyrukZ2iA/ # wdG2th9y1IsA0QF8dTXqvcnTmpfeQh35k5zOCPmSNq1UH410ANVko43+Cdmu4y81 # hjajV/gxdEkMx1NKU4uHQcKfZxAvBAKqMVuqte69M9J6A47OvgRaPs+2ykgcGV00 # TYr2Lr3ty9qIijanrUR3anzEwlvzZiiyfTPjLbnFRsjsYg39OlV8cipDoq7+qNNj # qFzeGxcytL5TTLL4ZaoBdqbhOhZ3ZRDUphPvSRmMThi0vw9vODRzW6AxnJll38F0 # cuJG7uEBYTptMSbhdhGQDpOXgpIUsWTjd6xpR6oaQf/DJbg3s6KCLPAlZ66RzIg9 # sC+NJpud/v4+7RWsWCiKi9EOLLHfMR2ZyJ/+xhCx9yHbxtl5TPau1j/1MIDpMPx0 # LckTetiSuEtQvLsNz3Qbp7wGWqbIiOWCnb5WqxL3/BAPvIXKUjPSxyZsq8WhbaM2 # tszWkPZPubdcMIIFjTCCBHWgAwIBAgIQDpsYjvnQLefv21DiCEAYWjANBgkqhkiG # 9w0BAQwFADBlMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkw # FwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1 # cmVkIElEIFJvb3QgQ0EwHhcNMjIwODAxMDAwMDAwWhcNMzExMTA5MjM1OTU5WjBi # MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 # d3cuZGlnaWNlcnQuY29tMSEwHwYDVQQDExhEaWdpQ2VydCBUcnVzdGVkIFJvb3Qg # RzQwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC/5pBzaN675F1KPDAi # MGkz7MKnJS7JIT3yithZwuEppz1Yq3aaza57G4QNxDAf8xukOBbrVsaXbR2rsnny # yhHS5F/WBTxSD1Ifxp4VpX6+n6lXFllVcq9ok3DCsrp1mWpzMpTREEQQLt+C8weE # 5nQ7bXHiLQwb7iDVySAdYyktzuxeTsiT+CFhmzTrBcZe7FsavOvJz82sNEBfsXpm # 7nfISKhmV1efVFiODCu3T6cw2Vbuyntd463JT17lNecxy9qTXtyOj4DatpGYQJB5 # w3jHtrHEtWoYOAMQjdjUN6QuBX2I9YI+EJFwq1WCQTLX2wRzKm6RAXwhTNS8rhsD # dV14Ztk6MUSaM0C/CNdaSaTC5qmgZ92kJ7yhTzm1EVgX9yRcRo9k98FpiHaYdj1Z # XUJ2h4mXaXpI8OCiEhtmmnTK3kse5w5jrubU75KSOp493ADkRSWJtppEGSt+wJS0 # 0mFt6zPZxd9LBADMfRyVw4/3IbKyEbe7f/LVjHAsQWCqsWMYRJUadmJ+9oCw++hk # pjPRiQfhvbfmQ6QYuKZ3AeEPlAwhHbJUKSWJbOUOUlFHdL4mrLZBdd56rF+NP8m8 # 00ERElvlEFDrMcXKchYiCd98THU/Y+whX8QgUWtvsauGi0/C1kVfnSD8oR7FwI+i # sX4KJpn15GkvmB0t9dmpsh3lGwIDAQABo4IBOjCCATYwDwYDVR0TAQH/BAUwAwEB # /zAdBgNVHQ4EFgQU7NfjgtJxXWRM3y5nP+e6mK4cD08wHwYDVR0jBBgwFoAUReui # r/SSy4IxLVGLp6chnfNtyA8wDgYDVR0PAQH/BAQDAgGGMHkGCCsGAQUFBwEBBG0w # azAkBggrBgEFBQcwAYYYaHR0cDovL29jc3AuZGlnaWNlcnQuY29tMEMGCCsGAQUF # BzAChjdodHRwOi8vY2FjZXJ0cy5kaWdpY2VydC5jb20vRGlnaUNlcnRBc3N1cmVk # SURSb290Q0EuY3J0MEUGA1UdHwQ+MDwwOqA4oDaGNGh0dHA6Ly9jcmwzLmRpZ2lj # ZXJ0LmNvbS9EaWdpQ2VydEFzc3VyZWRJRFJvb3RDQS5jcmwwEQYDVR0gBAowCDAG # BgRVHSAAMA0GCSqGSIb3DQEBDAUAA4IBAQBwoL9DXFXnOF+go3QbPbYW1/e/Vwe9 # mqyhhyzshV6pGrsi+IcaaVQi7aSId229GhT0E0p6Ly23OO/0/4C5+KH38nLeJLxS # A8hO0Cre+i1Wz/n096wwepqLsl7Uz9FDRJtDIeuWcqFItJnLnU+nBgMTdydE1Od/ # 6Fmo8L8vC6bp8jQ87PcDx4eo0kxAGTVGamlUsLihVo7spNU96LHc/RzY9HdaXFSM # b++hUD38dglohJ9vytsgjTVgHAIDyyCwrFigDkBjxZgiwbJZ9VVrzyerbHbObyMt # 9H5xaiNrIv8SuFQtJ37YOtnwtoeW/VvRXKwYw02fc7cBqZ9Xql4o4rmUMYIDfDCC # A3gCAQEwfTBpMQswCQYDVQQGEwJVUzEXMBUGA1UEChMORGlnaUNlcnQsIEluYy4x # QTA/BgNVBAMTOERpZ2lDZXJ0IFRydXN0ZWQgRzQgVGltZVN0YW1waW5nIFJTQTQw # OTYgU0hBMjU2IDIwMjUgQ0ExAhAIT9wzT35FTtvDD4/5khg1MA0GCWCGSAFlAwQC # AQUAoIHRMBoGCSqGSIb3DQEJAzENBgsqhkiG9w0BCRABBDAcBgkqhkiG9w0BCQUx # DxcNMjYxMDIyMjEzMDQzWjArBgsqhkiG9w0BCRACDDEcMBowGDAWBBRR2avaA0lz # 2E9CZqykgkjms2nEOTAvBgkqhkiG9w0BCQQxIgQg516cY4pFtMTmScyg/WEHf7LU # pZpnQQE0RREWvQoHfagwNwYLKoZIhvcNAQkQAi8xKDAmMCQwIgQgLaCdp/QTH5/n # LbbF5unJZWdVrwQ/HqdCzA0hIOFB6/wwDQYJKoZIhvcNAQEBBQAEggIAGnisIpUH # JyrY1ctgo44CQZ92NX3vcqFKAgIvaCs6SHvwh1alc7cdGheF36ZXPSf7p+0fRDXM # FTg26tYqBbB17A2eINgLybDuiiQhSuwVqWFzsn9/0FD85rneba/x9PopeYZbxpvY # tjdWFLBWX4jw7wVveqNaE5nZK3pTFgNxMTWVQw1/lGputS6t8trQDU20Xf8namEz # JnVJwsc6jHK6zv4AwIg8xfTPwkx/LX39GNJJMpIs10H1KV2cTv24BSnPJoT61K6Q # Z1lvIpvPpX+4nqG6qfYSONE/L0ObmWfIx6eGzoC08TjJ0o55PMHerMGZ1CnrqmWa # 0rE/VhNZisBOgA98YtIpV8getIn+niMd5/puCHMQWX9sy+og6g/8kF2PM2Tkocm+ # Hk+VyqIrJakqDeEivz+gSTXY7RtXzbfXZntqIkj7dI7GJWRjajkYN3R6pL+VdXLK # ds5r9KbVdGsn6ck8bmTML6IdNqBYG5P1qnDqeOdXmF/3tm7Wrv6XiiMSjyosXawD # 3mGf961RDOQj7phXyNqD/1c6aNfENnHc2/K/OvRoHuF/OxuOlTcc8l7CRIqlZzNG # qdvpduZOiRzIpEG5c40EHA5Pf8FB5XJFe4Df6SNF2SEGgENdJiqkWAgOYDQ30qSP # SzqMC8POXBZZvUGLj0nM2Vd3Zj0kWzhVaRo= # SIG # End signature block |