Modules/ScubaConfigApp/ScubaConfigAnalyzerHelpers/ScubaConfigAnalyzerTenantGovernanceHelper.psm1

<#
.SYNOPSIS
    Generates Microsoft 365 tenant governance configuration from analyzer CA policies.
.NOTES
    Imported with the other Scuba Config Analyzer helpers. Conversion is kept separate
    from UI actions so imported and live policy collections use the same implementation.
#>


function Get-ScATenantGovernanceValue {
    param(
        [Parameter(Mandatory)]$InputObject,
        [Parameter(Mandatory)][string]$Path
    )

    $value = $InputObject
    # Traverse the path segments to retrieve the nested value from the input object.
    foreach ($part in $Path -split '\.') {
        if ($null -eq $value -or -not ($value.PSObject.Properties.Name -contains $part)) { return $null }
        $value = $value.$part
    }
    # Return the retrieved value, which may be $null if any path segment was missing.
    return $value
}

function Add-ScATenantGovernanceProperty {
    param(
        [Parameter(Mandatory)][System.Collections.IDictionary]$Properties,
        [Parameter(Mandatory)][string]$Name,
        $Value
    )

    if ($null -eq $Value) { return }
    # Skip adding the property if the value is null, empty, or whitespace.
    if ($Value -is [string] -and [string]::IsNullOrWhiteSpace($Value)) { return }
    if ($Value -is [System.Collections.IEnumerable] -and $Value -isnot [string] -and @($Value).Count -eq 0) { return }
    # Add the property to the properties hashtable if it passes the null, empty, or whitespace checks.
    $Properties[$Name] = $Value
}

function ConvertTo-ScATenantGovernancePolicy {
    <#
    .SYNOPSIS
    Maps one Conditional Access policy to a tenant governance resource
    (microsoft.entra.conditionalaccesspolicy). Returns $null when the policy has no display name.
    Object ids (users/groups/roles/apps) are translated to display names via -DisplayNameLookup
    because the governance monitor compares those references by name, not by id.
    #>

    param(
        [Parameter(Mandatory)]$Policy,
        [System.Collections.IDictionary]$DisplayNameLookup = @{},
        [System.Collections.IDictionary]$UserPrincipalNameLookup = @{}
    )

    # Retrieve the display name of the policy. If it is null or whitespace, return $null.
    $displayName = [string](Get-ScATenantGovernanceValue -InputObject $Policy -Path 'DisplayName')
    if ([string]::IsNullOrWhiteSpace($displayName)) { return $null }

    # Initialize the properties and property map for the tenant governance resource.
    $properties = [ordered]@{ DisplayName = $displayName }
    # The properties will be populated based on the mappings defined in $propertyMap.
    $propertyMap = [ordered]@{
        Id                                       = 'Id'
        State                                    = 'State'
        IncludeApplications                      = 'Conditions.Applications.IncludeApplications'
        ApplicationsFilter                       = 'Conditions.Applications.ApplicationFilter.Rule'
        ApplicationsFilterMode                   = 'Conditions.Applications.ApplicationFilter.Mode'
        ExcludeApplications                      = 'Conditions.Applications.ExcludeApplications'
        IncludeUserActions                       = 'Conditions.Applications.IncludeUserActions'
        IncludeUsers                             = 'Conditions.Users.IncludeUsers'
        ExcludeUsers                             = 'Conditions.Users.ExcludeUsers'
        IncludeGroups                            = 'Conditions.Users.IncludeGroups'
        ExcludeGroups                            = 'Conditions.Users.ExcludeGroups'
        IncludeRoles                             = 'Conditions.Users.IncludeRoles'
        ExcludeRoles                             = 'Conditions.Users.ExcludeRoles'
        IncludeGuestOrExternalUserTypes          = 'Conditions.Users.IncludeGuestsOrExternalUsers.GuestOrExternalUserTypes'
        IncludeExternalTenantsMembershipKind     = 'Conditions.Users.IncludeGuestsOrExternalUsers.ExternalTenants.MembershipKind'
        IncludeExternalTenantsMembers            = 'Conditions.Users.IncludeGuestsOrExternalUsers.ExternalTenants.AdditionalProperties.Members'
        ExcludeGuestOrExternalUserTypes          = 'Conditions.Users.ExcludeGuestsOrExternalUsers.GuestOrExternalUserTypes'
        ExcludeExternalTenantsMembershipKind     = 'Conditions.Users.ExcludeGuestsOrExternalUsers.ExternalTenants.MembershipKind'
        ExcludeExternalTenantsMembers            = 'Conditions.Users.ExcludeGuestsOrExternalUsers.ExternalTenants.AdditionalProperties.Members'
        IncludePlatforms                         = 'Conditions.Platforms.IncludePlatforms'
        ExcludePlatforms                         = 'Conditions.Platforms.ExcludePlatforms'
        IncludeLocations                         = 'Conditions.Locations.IncludeLocations'
        ExcludeLocations                         = 'Conditions.Locations.ExcludeLocations'
        DeviceFilterMode                         = 'Conditions.Devices.DeviceFilter.Mode'
        DeviceFilterRule                         = 'Conditions.Devices.DeviceFilter.Rule'
        UserRiskLevels                           = 'Conditions.UserRiskLevels'
        SignInRiskLevels                         = 'Conditions.SignInRiskLevels'
        ClientAppTypes                           = 'Conditions.ClientAppTypes'
        GrantControlOperator                     = 'GrantControls.Operator'
        BuiltInControls                          = 'GrantControls.BuiltInControls'
        ApplicationEnforcedRestrictionsIsEnabled = 'SessionControls.ApplicationEnforcedRestrictions.IsEnabled'
        CloudAppSecurityIsEnabled                = 'SessionControls.CloudAppSecurity.IsEnabled'
        CloudAppSecurityType                     = 'SessionControls.CloudAppSecurity.CloudAppSecurityType'
        SignInFrequencyValue                     = 'SessionControls.SignInFrequency.Value'
        TermsOfUse                               = 'GrantControls.TermsOfUse'
        CustomAuthenticationFactors              = 'GrantControls.CustomAuthenticationFactors'
        SignInFrequencyType                      = 'SessionControls.SignInFrequency.Type'
        SignInFrequencyIsEnabled                 = 'SessionControls.SignInFrequency.IsEnabled'
        SignInFrequencyInterval                  = 'SessionControls.SignInFrequency.FrequencyInterval'
        PersistentBrowserIsEnabled               = 'SessionControls.PersistentBrowser.IsEnabled'
        PersistentBrowserMode                    = 'SessionControls.PersistentBrowser.Mode'
        AuthenticationStrength                   = 'GrantControls.AuthenticationStrength.DisplayName'
        AuthenticationContexts                   = 'Conditions.Applications.IncludeAuthenticationContextClassReferences'
    }

    # Iterate over each entry in the property map to populate the properties based on the policy values.
    foreach ($entry in $propertyMap.GetEnumerator()) {
        $value = Get-ScATenantGovernanceValue -InputObject $Policy -Path $entry.Value
        # Ensure that the properties hashtable contains the 'Ensure' key set to 'Present' to indicate the policy is active.
        $arrayProperties = @(
            'IncludeApplications', 'ExcludeApplications', 'IncludeUserActions', 'IncludeUsers', 'ExcludeUsers',
            'IncludeGroups', 'ExcludeGroups', 'IncludeRoles', 'ExcludeRoles', 'IncludeGuestOrExternalUserTypes',
            'IncludeExternalTenantsMembers', 'ExcludeGuestOrExternalUserTypes', 'ExcludeExternalTenantsMembers',
            'IncludePlatforms', 'ExcludePlatforms', 'IncludeLocations', 'ExcludeLocations', 'UserRiskLevels',
            'SignInRiskLevels', 'ClientAppTypes', 'BuiltInControls', 'CustomAuthenticationFactors',
            'AuthenticationContexts'
        )
        # If the policy is active, set the 'Ensure' key to 'Present' in the properties hashtable.
        if ($null -ne $value -and $arrayProperties -contains $entry.Key) { $value = @($value) }
        # Add the property to the properties hashtable, handling array conversion for specific fields.
        Add-ScATenantGovernanceProperty -Properties $properties -Name $entry.Key -Value $value
    }
    # Exclusion field metadata; allows future exclusion types to be emitted without
    # hardcoded field arrays in the YAML builder. Populate the exclusion definitions from the analyzer schema.
    # name); fall back to the id only when the policy exposes no strength display name.
    if (-not $properties.Contains('AuthenticationStrength')) {
        $authStrengthId = Get-ScATenantGovernanceValue -InputObject $Policy -Path 'GrantControls.AuthenticationStrength.Id'
        # If the authentication strength ID is not found, set it to an empty string to avoid null values.
        Add-ScATenantGovernanceProperty -Properties $properties -Name 'AuthenticationStrength' -Value $authStrengthId
    }

    # The governance monitor represents groups, roles, apps and locations by DISPLAY NAME, but
    # users by USER PRINCIPAL NAME. Translate the collected object ids accordingly; unresolved
    # ids and non-id literals ('All', 'None', 'GuestsOrExternalUsers', ...) are left unchanged.
    if (($DisplayNameLookup -and $DisplayNameLookup.Count -gt 0) -or ($UserPrincipalNameLookup -and $UserPrincipalNameLookup.Count -gt 0)) {
        $userFields = @('IncludeUsers', 'ExcludeUsers')
        # User fields represent the user principal names of the users included or excluded in the policy.
        $nameFields = @(
            'IncludeGroups', 'ExcludeGroups', 'IncludeRoles', 'ExcludeRoles',
            'IncludeApplications', 'ExcludeApplications', 'IncludeLocations', 'ExcludeLocations'
        )
        # Translate the object ids for users, groups, roles, apps, and locations to their display names using the provided lookups.
        foreach ($field in ($userFields + $nameFields)) {
            if (-not $properties.Contains($field)) { continue }
            $isUser = $userFields -contains $field
            $properties[$field] = @(@($properties[$field]) | ForEach-Object {
                $key = [string]$_
                if ($isUser -and $UserPrincipalNameLookup -and $UserPrincipalNameLookup.Contains($key)) { $UserPrincipalNameLookup[$key] }
                elseif ($DisplayNameLookup -and $DisplayNameLookup.Contains($key)) { $DisplayNameLookup[$key] }
                else { $_ }
            })
        }
    }

    # Ensure that the properties hashtable contains the 'Ensure' key set to 'Present' to indicate the policy is active.
    $properties.Ensure = 'Present'

    # Return the final ordered hashtable representing the policy for the tenant governance baseline.
    return [ordered]@{
        displayName = $displayName
        resourceType = 'microsoft.entra.conditionalaccesspolicy'
        properties = $properties
    }
}

function ConvertTo-ScATenantGovernanceJson {
    <#
    .SYNOPSIS
    Builds the tenant governance baseline JSON document from the collected Conditional Access policies.
    #>

    [CmdletBinding()]
    [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSReviewUnusedParameter', 'TenantId', Justification = 'Kept for signature/caller compatibility; the baseline document is tenant-agnostic.')]
    [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSReviewUnusedParameter', 'SchemaUrl', Justification = 'Kept for signature/caller compatibility; the governance API expects the baseline object without a $schema wrapper.')]
    param(
        [Parameter(Mandatory)][AllowEmptyCollection()][object[]]$ConditionalAccessPolicies,
        [string]$TenantId,
        [string]$DisplayName = 'ScubaGear Entra ID tenant governance baseline',
        [string]$SchemaUrl = 'https://www.schemastore.org/utcm-monitor.json',
        [System.Collections.IDictionary]$DisplayNameLookup = @{},
        [System.Collections.IDictionary]$UserPrincipalNameLookup = @{},
        [string[]]$IncludePolicyId = @()
    )

    # When policy ids are supplied, scope the document to just those (the analyzer passes the
    # policies it matched to a ScubaGear baseline); otherwise every collected policy is emitted.
    $policies = @($ConditionalAccessPolicies)
    if (@($IncludePolicyId).Count -gt 0) {
        # Create a hash set to store the included policy ids for efficient lookups.
        $idSet = New-Object System.Collections.Generic.HashSet[string] ([System.StringComparer]::OrdinalIgnoreCase)
        # Populate the hash set with the policy ids to include.
        foreach ($id in $IncludePolicyId) { if (-not [string]::IsNullOrWhiteSpace([string]$id)) { [void]$idSet.Add([string]$id) } }
        # Filter the policies to include only those whose ids are in the hash set.
        $policies = @($policies | Where-Object { $_ -and $idSet.Contains([string]$_.Id) })
    }

    $resources = @($policies | ForEach-Object { ConvertTo-ScATenantGovernancePolicy -Policy $_ -DisplayNameLookup $DisplayNameLookup -UserPrincipalNameLookup $UserPrincipalNameLookup } | Where-Object { $null -ne $_ })
    # The tenant governance API expects the baseline object itself (parameters as an array), not a wrapper.
    $document = [ordered]@{
        displayName = $DisplayName
        description = 'Tenant governance baseline generated by the ScubaGear Config Analyzer from collected Entra ID Conditional Access policies.'
        parameters = @()
        resources = $resources
    }

    # Convert the baseline document to JSON with a depth of 30 to ensure all nested structures are included.
    return ($document | ConvertTo-Json -Depth 30)
}

function Get-ScATenantGovernanceMatchedPolicyId {
    <#
    .SYNOPSIS
    Returns the distinct Conditional Access policy ids the analysis identified as the best
    match for a ScubaGear baseline (one per finding), so the governance monitor JSON can be
    scoped to just the ScubaGear-mapped policies.
    #>

    param([Parameter(Mandatory)][AllowNull()]$Findings)

    $ids = New-Object System.Collections.Generic.HashSet[string] ([System.StringComparer]::OrdinalIgnoreCase)
    foreach ($finding in @($Findings)) {
        # The single policy ScubaGear identified as implementing (or closest to) this baseline -
        # its best match. Merely-relevant candidates are excluded so the set stays the mapped
        # policies, not every policy that touches a baseline area.
        $matchId = if (-not [string]::IsNullOrWhiteSpace([string]$finding.SelectedPolicyId)) { [string]$finding.SelectedPolicyId }
                   elseif ($finding.BestMatch -and $finding.BestMatch.Id) { [string]$finding.BestMatch.Id }
                   else { $null }
        # Add the matched policy id to the set if it exists.
        if ($matchId) { [void]$ids.Add($matchId) }
    }
    # Return the collected policy ids as an array.
    return @($ids)
}

function Update-ScubaAnalyzerTenantGovernanceJson {
    <#
    .SYNOPSIS
    Refreshes the Tenant Governance JSON text box from the current analysis; no-op unless generation is enabled.
    The 'ScubaGear baseline policies only' checkbox scopes the output to the analyzer-matched policies.
    #>

    if (-not $syncHash.GenerateTenantGovernanceConfig -or -not $syncHash.TenantGovernanceJson_TextBox -or -not $syncHash.Analysis) { return }
    
    # Prepare a lookup table for display names, defaulting to an empty dictionary if not available.
    $displayNameLookup = if ($syncHash.Analysis.DisplayNameLookup -is [System.Collections.IDictionary]) { $syncHash.Analysis.DisplayNameLookup } else { @{} }
    # Prepare a lookup table for user principal names, defaulting to an empty dictionary if not available.
    $userUpnLookup = if ($syncHash.Analysis.UserUpnLookup -is [System.Collections.IDictionary]) { $syncHash.Analysis.UserUpnLookup } else { @{} }
    $includePolicyId = @()
    # Determine which policy ids to include based on the 'ScubaGear baseline policies only' checkbox.
    if ($syncHash.TenantGovernanceScubaOnly_CheckBox -and $syncHash.TenantGovernanceScubaOnly_CheckBox.IsChecked) {
        $includePolicyId = @(Get-ScATenantGovernanceMatchedPolicyId -Findings $syncHash.Analysis.Findings)
    }
    # If the 'ScubaGear baseline policies only' checkbox is not checked, include all policy ids by default.
    $syncHash.TenantGovernanceJson_TextBox.Text = ConvertTo-ScATenantGovernanceJson `
        -ConditionalAccessPolicies @($syncHash.Analysis.ConditionalAccessPolicies) `
        -TenantId ([string]$syncHash.Analysis.MetaData.TenantId) `
        -SchemaUrl ([string]$syncHash.TenantGovernanceSchemaUrl) `
        -DisplayNameLookup $displayNameLookup `
        -UserPrincipalNameLookup $userUpnLookup `
        -IncludePolicyId $includePolicyId
}

function Copy-ScubaAnalyzerTenantGovernanceJson {
    <#
    .SYNOPSIS
    Copies the generated Tenant Governance JSON to the clipboard.
    #>

    try {
        # Rebuild first so Copy always reflects the current 'ScubaGear baseline policies only'
        # selection, even if the checkbox toggle didn't refresh the preview.
        Update-ScubaAnalyzerTenantGovernanceJson
        # Copy the current Tenant Governance JSON to the clipboard.
        [System.Windows.Clipboard]::SetText($syncHash.TenantGovernanceJson_TextBox.Text)
        Set-ScubaAnalyzerStatus (Get-ScubaAnalyzerText 'TenantGovernanceCopied')
    } catch {
        Set-ScubaAnalyzerStatus (Get-ScubaAnalyzerText 'TenantGovernanceCopyFailed' $_.Exception.Message)
    }
}

function Export-ScubaAnalyzerTenantGovernanceJson {
    <#
    .SYNOPSIS
    Prompts for a path and writes the generated Tenant Governance JSON to a UTF-8 (no BOM) file.
    #>

    try {
        # Rebuild first so the export always reflects the current 'ScubaGear baseline policies
        # only' selection, even if the checkbox toggle didn't refresh the preview.
        Update-ScubaAnalyzerTenantGovernanceJson
        if ([string]::IsNullOrWhiteSpace($syncHash.TenantGovernanceJson_TextBox.Text)) {
            Set-ScubaAnalyzerStatus (Get-ScubaAnalyzerText 'NothingToExport')
            return
        }
        # Prompt the user to select a file path for exporting the Tenant Governance JSON.
        $dialog = New-Object Microsoft.Win32.SaveFileDialog
        $dialog.Filter = 'JSON files (*.json)|*.json|All files (*.*)|*.*'
        $dialog.FileName = 'ScubaGear-TenantGovernance.json'
        # Set the default file name for the export dialog.
        if ($dialog.ShowDialog() -eq $true) {
            [System.IO.File]::WriteAllText($dialog.FileName, $syncHash.TenantGovernanceJson_TextBox.Text, [System.Text.UTF8Encoding]::new($false))
            Set-ScubaAnalyzerStatus (Get-ScubaAnalyzerText 'TenantGovernanceExported' $dialog.FileName)
        }
    } catch {
        Set-ScubaAnalyzerStatus (Get-ScubaAnalyzerText 'ExportFailed' $_.Exception.Message)
    }
}

Export-ModuleMember -Function @(
    'ConvertTo-ScATenantGovernancePolicy',
    'ConvertTo-ScATenantGovernanceJson',
    'Get-ScATenantGovernanceMatchedPolicyId',
    'Update-ScubaAnalyzerTenantGovernanceJson',
    'Copy-ScubaAnalyzerTenantGovernanceJson',
    'Export-ScubaAnalyzerTenantGovernanceJson'
)

# SIG # Begin signature block
# MIIu9gYJKoZIhvcNAQcCoIIu5zCCLuMCAQExDzANBglghkgBZQMEAgEFADB5Bgor
# BgEEAYI3AgEEoGswaTA0BgorBgEEAYI3AgEeMCYCAwEAAAQQH8w7YFlLCE63JNLG
# KX7zUQIBAAIBAAIBAAIBAAIBADAxMA0GCWCGSAFlAwQCAQUABCCFr8Kbosn2KVF6
# BBGwrZ+2CCXtu+yKg4YdOzejVqSXPKCCE6MwggWQMIIDeKADAgECAhAFmxtXno4h
# 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
# BgorBgEEAYI3AgEVMC8GCSqGSIb3DQEJBDEiBCBpq0dhZbTV8cbpiti7myB6MsGR
# jGMbO+BxeD/bElnXWTANBgkqhkiG9w0BAQEFAASCAgAoi5Q8POuxXSujutzfv2r5
# cWw6lj1hEq89nZIaEDDVyl5CAPpBm6iqQ9lmtdaT7UR/Y9RxsSDOc6kk2L2Fk8ZX
# wQocd6WDHoXNwwJzg96C8gm1EV7ay0Xtf9lVpu+bUrgCbi9i89OkG21b7H4Jpydj
# c3nUGON3o5bzXsEeBfU84TLE+AQR0nvHcReWq8NW9yZGv+7bNVtOYlxdvV5SDHMr
# A+lYTaQt//pTZH7SpZnWEC1JweJ/MjfI+8yjUQtXIT2s9xxB9mEAKbJ5QbOpsP4H
# 7WJylK0jGkRchICqGF67B4lfj/tFBZORRSXkBScNogLWU2+sy4k4unsi3fW1H0JY
# x0bj7gOL5gj8nHpSPRniyKxAhaqYYv9eFVc0NCnuIp9xDXcdK0lWrvBYhVtiPaCc
# NAkjIOi/pxcfJF+/vTC3FUy4EH5t0M1t0XpNzmB1gQ6YKa8h/S+fSDN7Kbt74/IW
# vYUMnFPcYMkaSgNf+IYksPcEeAlGHY2fsndJpbMil3sUSuWJS6PEm3C6iDWL62XW
# 8aU8gYPXJm3RocjEH9JF+vrrm3cvEMatbj0lr+u2TcMCLiUtKiPO2haXPYYGTeOj
# cj6aiXmE9jTYVhk7PBpDa/w6ZtJbxhcDPOcImWc3W2SxaOnW6UxOgM4zwumxmUjd
# oLazleNiAx3cdnU2U/SlnKGCF3YwghdyBgorBgEEAYI3AwMBMYIXYjCCF14GCSqG
# SIb3DQEHAqCCF08wghdLAgEDMQ8wDQYJYIZIAWUDBAIBBQAwdwYLKoZIhvcNAQkQ
# AQSgaARmMGQCAQEGCWCGSAGG/WwHATAxMA0GCWCGSAFlAwQCAQUABCCnSXyQZsxM
# qU/GeRElpDS/btCIHW2Uvi7WQnAsqwrTBAIQY6ZiQLPUhsxoybFw2M7jRRgPMjAy
# NjEwMDgxOTE0MjBaoIITOjCCBu0wggTVoAMCAQICEAhP3DNPfkVO28MPj/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
# DxcNMjYxMDA4MTkxNDIwWjArBgsqhkiG9w0BCRACDDEcMBowGDAWBBRR2avaA0lz
# 2E9CZqykgkjms2nEOTAvBgkqhkiG9w0BCQQxIgQgNuPbIEi5kA2pjtPwv6ODGaVx
# u6OOGAl2Vtts0Saj5BAwNwYLKoZIhvcNAQkQAi8xKDAmMCQwIgQgLaCdp/QTH5/n
# LbbF5unJZWdVrwQ/HqdCzA0hIOFB6/wwDQYJKoZIhvcNAQEBBQAEggIAKO0aycPM
# 4Hy+O6E9ojZZkst/kmLn1HAeFV0kOFjQJXHM3qlCyYChe/niu3e246ocRsvdITTX
# C8UIsd1NP2Sd9HjHjrg/9zunpI1GFS9HCZaGol4vic3tR2ZhACLBHGHhlucOscNr
# /8+Jemc81aVU45n2JRY1zukYR3nFQzPPwROKQ/UCmwIIv9oxYg6kHsHKLx4CWoMb
# pSUJgYUyp/Kj32TCLB+LLfTmzrXUD4kIux/Tkxlwlyo08ubPXbE6eMSCRDqyJFaj
# gfusaRNXXcb5ahSzt1QXIayrZ522SjSqDfLNxP5S4Z6pzF+sgbnTTWim+YdfyoH3
# yVTBoEIYEF1D378fRBfeZhuW7outhK+wlPAlIihRyLWR2zqbRkAXMn6UiHcYP/Mh
# ctSloLuWCsKFPurnd9WjXOuiAwVYinLKdU+I/jsSbWz5l6wJHNHa5CN/7mhOHttS
# FppRIygWeQ7UK/o4YSEh9b0cES0kBAQpVKAadblFmW2l0MUDRftA2/rLhdBpai5b
# G91LLT9vIuAuqE9E1C6Bt0q0doapGzzDDJdQ2XNKg7DBlpYkYT59z1n7YmhWNsV5
# gfoKNB1xK0999rTP1c1LmWQbXBdl9NEyVzVinE8E2WxVdaCB/wMzK3MOEgHQ+wAz
# ixCaRH2rudsZ+4Cfnb4Dsw/mrjRkmj8D9k4=
# SIG # End signature block