Public/SC_Rules.ps1

<#
.SYNOPSIS
    Read existing SEPPmail.cloud transport rules in the exchange online environment.
.DESCRIPTION
    Use this to figure out if there are already SEPPmail.cloud rules implemented in Exchange online.
    It is only emitting installed rules which come with the seppmail365cloud PowerShell Module.
    If you want to be informed about all installed transport rules, use New-SC365ExoReport.
.EXAMPLE
    Get-SC365Rules
     
    Displays all SEPPmail.cloud transport rules in the tenant.
    Shows rule name, priority, state, and included domains.
    Only returns rules matching the [SEPPmail.cloud]* pattern.
.EXAMPLE
    Get-SC365Rules | Format-Table Identity, Priority, State
     
    Displays SEPPmail.cloud rules in a table format.
    Shows only Identity, Priority, and State columns.
    Useful for quick overview of rule configuration.
.EXAMPLE
    Get-SC365Rules | Where-Object {$_.State -eq 'Enabled'}
     
    Filters and displays only enabled SEPPmail.cloud rules.
    Helps identify which rules are currently active.
    Useful for troubleshooting mail flow issues.
.EXAMPLE
    Get-SC365Rules | Export-Csv -Path "C:\Temp\SEPPmail-Rules.csv" -NoTypeInformation
     
    Exports all SEPPmail.cloud rules to a CSV file.
    Useful for documentation and backup purposes.
    Allows comparison of configurations before and after changes.
#>

function Get-SC365Rules {
    [CmdletBinding(
        HelpURI = 'https://github.com/seppmail/SEPPmail365cloud/blob/main/README.md#setup-the-integration'
    )]
    param
    (

    )

    begin {
        if (!(Test-SC365ConnectionStatus))
        { 
            throw [System.Exception] "You're not connected to Exchange Online - please connect prior to using this CmdLet" 
        }
        else 
        {
            Write-Verbose "Connected to Exchange Organization `"$Script:ExODefaultDomain`"" -InformationAction Continue
        }
        #if ($routing -eq 'p') {$routing = 'parallel'}
        #if ($routing -eq 'i') {$routing = 'inline'}
        #$transportRuleFiles = Get-Childitem "$psscriptroot\..\ExOConfig\Rules\"
    }
    process {
        #foreach ($file in $transportRuleFiles) {
        $allSEPPmailCloudRules = Get-TransportRule -Identity '[SEPPmail*'
             if ($allSEPPmailCloudRules) {
                Foreach ($rule in $allSEPPmailCloudRules) {
                    if ($rule) {
                        $rule.PSObject.TypeNames.Insert(0, "SEPPmail.cloud.Rules")
                        if ($rule.Identity -like '*100*') {
                            $rule | Add-Member -MemberType NoteProperty -Name IncludedDomains -Value $rule.RecipientDomainIs
                            #$rule|Select-Object Identity,Priority,State,@{Name = 'IncludedDomains'; Expression={$_.RecipientDomainIs}}
                        }
                        if ($rule.Identity -like '*200*') {
                            $rule | Add-Member -MemberType NoteProperty -Name IncludedDomains -Value $rule.SenderDomainDomainIs
                            #$rule|Select-Object Identity,Priority,State,@{Name = 'IncludedDomains'; Expression={$_.SenderDomainIs}}
                        }
                        $rule | Add-Member -MemberType NoteProperty -Name 'SC365ModuleVersion' -Value (Get-SC365moduleVersion $($rule.comments))
                        $rule
                    }
                }
            }
            else {
                Write-Warning "No transport rules found matching [SEPPmail.Cloud]* in your tenant."
            }
    }
    end {

    }
}

<#
.SYNOPSIS
    Create transport rules for routing mode "parallel"
.DESCRIPTION
    Creates all necessary transport rules in Exchange Online to send e-mails through seppmail.cloud for cryptographic processing.
.EXAMPLE
    New-SC365Rules -SEPPmailCloudDomain 'contoso.eu','contoso.com' -routing inline
     
    Creates transport rules for multiple domains in inline routing mode.
    Only emails for specified domains are processed by SEPPmail.cloud.
    MX records must point to SEPPmail.cloud for this configuration.
.EXAMPLE
    New-SC365Rules -SEPPmailCloudDomain 'contoso.eu' -PlacementPriority Top -routing parallel
     
    Creates rules with highest priority (before all other rules).
    Useful when SEPPmail.cloud rules must execute before other transport rules.
    Not recommended unless required by specific mail flow scenarios.
.EXAMPLE
    New-SC365Rules -SEPPmailCloudDomain 'contoso.eu' -routing parallel -disabled
     
    Creates transport rules in disabled state for testing.
    Allows review and validation before activating mail flow.
    Rules must be manually enabled after creation.
.EXAMPLE
    New-SC365Rules -SEPPmailCloudDomain 'contoso.eu' -routing parallel -CryptoContentOnly:$false
     
    Routes ALL inbound mail through SEPPmail.cloud, not just encrypted content.
    Processes all incoming messages regardless of encryption status.
    Increases processing volume but ensures complete mail filtering.
.EXAMPLE
    New-SC365Rules -SEPPmailCloudDomain 'contoso.com' -routing inline -SCLInboundValue 6
     
    Creates rules with custom Spam Confidence Level (SCL) threshold.
    Messages with SCL above 6 bypass SEPPmail.cloud processing.
    Useful for optimizing mail flow based on spam scores.
.EXAMPLE
    New-SC365Rules -SEPPmailCloudDomain 'contoso.de' -routing parallel -PlacementPriority Bottom
     
    Places SEPPmail.cloud rules after all existing transport rules.
    Recommended default to avoid conflicts with existing mail flow.
    Ensures other rules execute first.
.INPUTS
    none
.OUTPUTS
    transport rules
.NOTES
     
#>

function New-SC365Rules
{
    [CmdletBinding(
        SupportsShouldProcess = $true,
        ConfirmImpact = 'Medium',
        HelpURI = 'https://github.com/seppmail/SEPPmail365cloud/blob/main/README.md#setup-the-integration'
        )
    ]
    param
    (
        [Parameter(Mandatory = $false,
            HelpMessage = 'Should the new rules be placed before or after existing ones (if any)')]
        [ValidateSet('Top', 'Bottom')]
        [String] $PlacementPriority = 'Bottom',

        [Parameter(
            Mandatory = $true,
            HelpMessage = 'MX record->SEPPmail means routingtype inline, MX->Microsoft means routingtype parallel'
        )]
        [ValidateSet('parallel', 'inline', 'p', 'i')]
        [String]$routing,

        [Parameter(Mandatory = $true,
            HelpMessage = 'e-mail domains you have registered in the SEPPmail.Cloud')]
        [String[]]$SEPPmailCloudDomain,

        [Parameter(Mandatory = $false,
            HelpMessage = 'SCL Value for inbound Mails which should NOT be processed by SEPPmail.Cloud. Default is 5')]
        [ValidateSet('-1', '0', '5', '6', '8', '9')]
        [int]$SCLInboundValue = 5,

        [Parameter(
              Mandatory = $false,
            HelpMessage = 'Rule 100 will only send e-mails to SEPPmail.cloud which requires cryptographic processing'
        )]
        [bool]$CryptoContentOnly = $true,

        [Parameter(
            Mandatory = $false,
            HelpMessage = 'Add rules if you provisioned internal e-mail signature in the SEPPmail.cloud Service'
        )]
        [switch]$Disabled
    )

    begin
    {
        if (!(Test-SC365ConnectionStatus)) { 
            throw [System.Exception] "You're not connected to Exchange Online - please connect prior to using this CmdLet" 
        } else {
            Write-Verbose "Connected to Exchange Organization `"$Script:ExODefaultDomain`" " 
        }

        if ($routing -eq 'p') {$routing = 'parallel'}
        if ($routing -eq 'i') {$routing = 'inline'}

        foreach ($validationDomain in $SEPPmailCloudDomain) {
            if ((Confirm-SC365TenantDefaultDomain -ValidationDomain $validationDomain) -eq $true) {
                Write-verbose "Domain is part of the tenant and the Default Domain"
            } else {
                if ((Confirm-SC365TenantDefaultDomain -ValidationDomain $validationDomain) -eq $false) {
                    Write-verbose "Domain is part of the tenant"
                } else {
                    Write-Error "Domain is NOT Part of the tenant"
                    break
                }
            }
        }
 
        # Filter onmicrosoft domains and define Domain List for TransportRule Rule-Config
        try {
            $FilteredCloudDomain = Remove-SC365OnMicrosoftDomain -DomainList $SEPPmailCloudDomain
        } catch {
            Write-Warning "Could not remove onMicrosoft.com domains from DomainList for further processing"
            $FilteredCloudDomain = $SEPPmailCloudDomain
        }

        $outboundConnectors = Get-OutboundConnector -IncludeTestModeConnectors $true | Where-Object { $_.Name -match "^\[SEPPmail.cloud\]" }
        if ($PSCmdlet.ShouldProcess('Exchange Online', "Check existence of Outbound Connector")) {
            if(!($outboundConnectors))
            {
                throw [System.Exception] "No SEPPmail.cloud outbound connector found. InBoundOnly Mode ? Run `"New-SC365Connectors`" to add the proper SEPPmail.cloud connectors"
            }
            if ($($outboundConnectors.Enabled) -ne $true) {
                throw [System.Exception] "SEPPmail.cloud outbound-connector is disabled, cannot create rules. Create connectors without -Disable switch, or enable them in the admin portal."
            }    
        }
    }

    process
    {
        try
        {
            Write-Verbose "Read all `"non-[SEPPmail`" transport rules"
            $existingTransportRules = Get-TransportRule | Where-Object Name -NotMatch '\[SEPPmail*'
            [int] $placementPrio = @(0, $existingTransportRules.Count)[!($PlacementPriority -eq "Top")] #Poor man's ternary operator
            Write-Verbose "Placement priority is $placementPrio"

            Write-Verbose "Read existing [SEPPmail.cloud] transport rules"
            $existingSMCTransportRules = Get-TransportRule | Where-Object Name -Match '\[SEPPmail*'
            [bool] $createRules = $true
            if ($existingSMCTransportRules)
            {
                if($InteractiveSession)
                {
                    Write-Warning 'Found existing [SEPPmail* transport rules.'
                    Write-Warning '--------------------------------------------'
                    foreach ($eSMCtpr in $existingSMCTransportRules) {
                        Write-Warning "Rule name `"$($eSMCtpr.Name)`" with state `"$($eSMCtpr.State)`" has priority `"$($eSMCtpr.Priority)`""
                    }
                    Write-Warning '--------------------------------------------'
                    Do {
                        try {
                            [ValidateSet('y', 'Y', 'n', 'N')]$recreateSMRules = Read-Host -Prompt "Shall we delete and recreate them ? (Y/N)"
                        }
                        catch {}
                    }
                    until ($?)
                    if ($recreateSMRules -like 'y') {
                        $existingSMCTransportRules|ForEach-Object {
                            if ($PSCmdlet.ShouldProcess($_.Name, "Removing transport rule")) {
                                Remove-TransportRule -Identity $_.Identity -Confirm:$false
                            }
                        }
                    }
                    else {
                        $createRules = $false
                    }
                }
                else
                {
                    throw [System.Exception] "SEPPmail* transport rules already exist"
                }
            }

            if($createRules){
               
                $transportRuleFiles = Get-ChildItem -Path "$psScriptRoot\..\ExOConfig\SC_Rules\"

                $moduleVersion = $myInvocation.MyCommand.Version
                # Calculated SMPriority for the transport rules - removes requirement of coding this into JSON Files
                [int]$countedSMPrio = -1
                foreach($file in $transportRuleFiles) {
                    $setting = Get-SC365TransportRuleSettings -File $file -Routing $routing
                    if ($setting.Values) {
                        $countedSMPrio++
                        Write-Verbose "Calculating TR-priority ba adding placement prio $placementPrio and ordered prio from SEPPmail $($setting.SMPriority)"
                        $setting.Priority = $placementPrio + $countedSMPrio
                        Write-Verbose "Transport Rule priority will be: $($setting.Priority)"
                        if ($Disabled -eq $true) {$setting.Enabled = $false}

                        $Now = Get-Date
                        Write-Verbose "Adding Timestamp $now to Comment"
                        $setting.Comments += "`nCreated with SEPPmail365cloud PowerShell Module version $moduleVersion on $now"

                        if ($PSCmdlet.ShouldProcess($setting.Name, "Create transport rule"))
                        {
                            switch ($setting.Name)
                            {
                                "[SEPPmail.cloud] - 060 Add header X-SM-ruleversion" {
                                    Write-Verbose "Add rule version $moduleVersion"
                                    $Setting.SetHeaderValue = $moduleVersion.ToString()
                                    New-TransportRule @setting #|Out-Null
                                }
                                "[SEPPmail.cloud] - 100 Route incoming e-mails to SEPPmail" {
                                    Write-Verbose "Including all managed domains $FilteredCloudDomain"
                                    $Setting.RecipientDomainIs = $FilteredCloudDomain
                                    if ($SCLInboundValue -ne 5) {
                                        Write-Verbose "Setting Value $SCLInboundValue to Inbound flowing to SEPPmail.cloud"
                                        $Setting.ExceptIfSCLOver = $SCLInboundValue
                                    }
                                    if ($cryptoContentOnly) {
                                        Write-Verbose 'Adding Setting to send only cryptographic needed e-mails to SEPPmail.cloud'
                                        $Setting.HeaderContainsMessageHeader = 'content-type'
                                        $Setting.HeaderContainsWords = "application/x-pkcs7-mime","application/pkcs7-mime","application/x-pkcs7-signature","application/pkcs7-signature","multipart/signed","application/pgp-signature","multipart/encrypted","application/pgp-encrypted","application/octet-stream"
                                    }
                                    New-TransportRule @setting #|Out-Null
                                }
                                "[SEPPmail.cloud] - 110 Route incoming PGP e-mails to SEPPmail" {
                                    Write-Verbose "Including all managed domains $FilteredCloudDomain"
                                    $Setting.RecipientDomainIs = $FilteredCloudDomain
                                    if ($cryptoContentOnly) {
                                        $setting.SubjectOrBodyContainsWords += '-----BEGIN PGP'
                                    }
                                    New-TransportRule @setting #|Out-Null
                                }
                                "[SEPPmail.cloud] - 120 Route incoming tagged e-mails to SEPPmail" {
                                    Write-Verbose "Including all managed domains $FilteredCloudDomain"
                                    $Setting.RecipientDomainIs = $FilteredCloudDomain
                                    New-TransportRule @setting #|Out-Null
                                }                                
                                "[SEPPmail.cloud] - 200 Route outgoing e-mails to SEPPmail" {
                                    Write-Verbose "Including only Outbound e-mails from domains $FilteredCloudDomain"
                                    $Setting.SenderDomainIs = $FilteredCloudDomain
                                    New-TransportRule @setting #|Out-Null
                                }
                                Default {
                                    New-TransportRule @setting #|Out-Null
                                }
                            }                        
                        }    
                    }
                # Get-TransportRule -Identity $Setting.Name|Select-Object Identity,Priority,State ## Unfinished
                }
            }
        }
        catch {
            throw [System.Exception] "Error: $($_.Exception.Message)"
        }
    }
    end
    {

    }
}

<#
.SYNOPSIS
    Removes the SEPPmail.cloud transport rules
.DESCRIPTION
    Convenience function to remove the SEPPmail.cloud rules in one CmdLet.
    Matches only on "[SEPPmail.cloud]*"
.EXAMPLE
    Remove-SC365Rules
     
    Removes all SEPPmail.cloud transport rules from Exchange Online.
    Requires confirmation due to high impact setting.
    Only removes rules matching the [SEPPmail.cloud]* pattern.
.EXAMPLE
    Remove-SC365Rules -Confirm:$false
     
    Removes all SEPPmail.cloud rules without confirmation prompt.
    Use with caution - rules are deleted immediately.
    Suitable for automation scripts with proper testing.
.EXAMPLE
    Remove-SC365Rules -WhatIf
     
    Shows what rules would be removed without actually deleting them.
    Useful for verification before actual removal.
    Displays all SEPPmail.cloud rules that would be affected.
.EXAMPLE
    Get-SC365Rules | Remove-SC365Rules
     
    Removes rules by piping from Get-SC365Rules.
    Provides explicit confirmation of which rules will be removed.
    Recommended pattern for safer rule deletion.
#>

function Remove-SC365Rules {
    [CmdletBinding(SupportsShouldProcess = $true,
                   ConfirmImpact = 'High',
                   HelpURI = 'https://github.com/seppmail/SEPPmail365cloud/blob/main/README.md#setup-the-integration'
                  )]
    param
    (
    )

    begin {
        if (!(Test-SC365ConnectionStatus))
        { 
            throw [System.Exception] "You're not connected to Exchange Online - please connect prior to using this CmdLet" 
        } else {
            Write-Verbose "Connected to Exchange Organization `"$Script:ExODefaultDomain`" " 
        }
    }
    process {
        Write-Verbose "Removing current version module rules"
        $allSEPPmailCloudRules = Get-TransportRule -Identity '[SEPPmail.cloud]*' -ErrorAction 0
        if ($allSEPPmailCloudRules.count -ge 1) {
            foreach ($rule in $allSEPPmailCloudRules) {
                if($PSCmdlet.ShouldProcess($rule.Name, "Remove transport rule")) {
                    Remove-TransportRule -Identity $rule -confirm:$false
                }
            }
        } 
    }
    end {

    }
}

if (!(Get-Alias 'Set-SC365rules' -ErrorAction SilentlyContinue)) {
    New-Alias -Name Set-SC365Rules -Value New-SC365Rules
}

Register-ArgumentCompleter -CommandName New-SC365Rules -ParameterName SEPPmailCloudDomain -ScriptBlock $paramDomSB

# SIG # Begin signature block
# MIIVyAYJKoZIhvcNAQcCoIIVuTCCFbUCAQExDzANBglghkgBZQMEAgEFADB5Bgor
# BgEEAYI3AgEEoGswaTA0BgorBgEEAYI3AgEeMCYCAwEAAAQQH8w7YFlLCE63JNLG
# KX7zUQIBAAIBAAIBAAIBAAIBADAxMA0GCWCGSAFlAwQCAQUABCArVguGDae15zYm
# S4l1VQEF0VxOavsPelxWva3455QOn6CCEgQwggVvMIIEV6ADAgECAhBI/JO0YFWU
# jTanyYqJ1pQWMA0GCSqGSIb3DQEBDAUAMHsxCzAJBgNVBAYTAkdCMRswGQYDVQQI
# DBJHcmVhdGVyIE1hbmNoZXN0ZXIxEDAOBgNVBAcMB1NhbGZvcmQxGjAYBgNVBAoM
# EUNvbW9kbyBDQSBMaW1pdGVkMSEwHwYDVQQDDBhBQUEgQ2VydGlmaWNhdGUgU2Vy
# dmljZXMwHhcNMjEwNTI1MDAwMDAwWhcNMjgxMjMxMjM1OTU5WjBWMQswCQYDVQQG
# EwJHQjEYMBYGA1UEChMPU2VjdGlnbyBMaW1pdGVkMS0wKwYDVQQDEyRTZWN0aWdv
# IFB1YmxpYyBDb2RlIFNpZ25pbmcgUm9vdCBSNDYwggIiMA0GCSqGSIb3DQEBAQUA
# A4ICDwAwggIKAoICAQCN55QSIgQkdC7/FiMCkoq2rjaFrEfUI5ErPtx94jGgUW+s
# hJHjUoq14pbe0IdjJImK/+8Skzt9u7aKvb0Ffyeba2XTpQxpsbxJOZrxbW6q5KCD
# J9qaDStQ6Utbs7hkNqR+Sj2pcaths3OzPAsM79szV+W+NDfjlxtd/R8SPYIDdub7
# P2bSlDFp+m2zNKzBenjcklDyZMeqLQSrw2rq4C+np9xu1+j/2iGrQL+57g2extme
# me/G3h+pDHazJyCh1rr9gOcB0u/rgimVcI3/uxXP/tEPNqIuTzKQdEZrRzUTdwUz
# T2MuuC3hv2WnBGsY2HH6zAjybYmZELGt2z4s5KoYsMYHAXVn3m3pY2MeNn9pib6q
# RT5uWl+PoVvLnTCGMOgDs0DGDQ84zWeoU4j6uDBl+m/H5x2xg3RpPqzEaDux5mcz
# mrYI4IAFSEDu9oJkRqj1c7AGlfJsZZ+/VVscnFcax3hGfHCqlBuCF6yH6bbJDoEc
# QNYWFyn8XJwYK+pF9e+91WdPKF4F7pBMeufG9ND8+s0+MkYTIDaKBOq3qgdGnA2T
# OglmmVhcKaO5DKYwODzQRjY1fJy67sPV+Qp2+n4FG0DKkjXp1XrRtX8ArqmQqsV/
# AZwQsRb8zG4Y3G9i/qZQp7h7uJ0VP/4gDHXIIloTlRmQAOka1cKG8eOO7F/05QID
# AQABo4IBEjCCAQ4wHwYDVR0jBBgwFoAUoBEKIz6W8Qfs4q8p74Klf9AwpLQwHQYD
# VR0OBBYEFDLrkpr/NZZILyhAQnAgNpFcF4XmMA4GA1UdDwEB/wQEAwIBhjAPBgNV
# HRMBAf8EBTADAQH/MBMGA1UdJQQMMAoGCCsGAQUFBwMDMBsGA1UdIAQUMBIwBgYE
# VR0gADAIBgZngQwBBAEwQwYDVR0fBDwwOjA4oDagNIYyaHR0cDovL2NybC5jb21v
# ZG9jYS5jb20vQUFBQ2VydGlmaWNhdGVTZXJ2aWNlcy5jcmwwNAYIKwYBBQUHAQEE
# KDAmMCQGCCsGAQUFBzABhhhodHRwOi8vb2NzcC5jb21vZG9jYS5jb20wDQYJKoZI
# hvcNAQEMBQADggEBABK/oe+LdJqYRLhpRrWrJAoMpIpnuDqBv0WKfVIHqI0fTiGF
# OaNrXi0ghr8QuK55O1PNtPvYRL4G2VxjZ9RAFodEhnIq1jIV9RKDwvnhXRFAZ/ZC
# J3LFI+ICOBpMIOLbAffNRk8monxmwFE2tokCVMf8WPtsAO7+mKYulaEMUykfb9gZ
# pk+e96wJ6l2CxouvgKe9gUhShDHaMuwV5KZMPWw5c9QLhTkg4IUaaOGnSDip0TYl
# d8GNGRbFiExmfS9jzpjoad+sPKhdnckcW67Y8y90z7h+9teDnRGWYpquRRPaf9xH
# +9/DUp/mBlXpnYzyOmJRvOwkDynUWICE5EV7WtgwggYaMIIEAqADAgECAhBiHW0M
# UgGeO5B5FSCJIRwKMA0GCSqGSIb3DQEBDAUAMFYxCzAJBgNVBAYTAkdCMRgwFgYD
# VQQKEw9TZWN0aWdvIExpbWl0ZWQxLTArBgNVBAMTJFNlY3RpZ28gUHVibGljIENv
# ZGUgU2lnbmluZyBSb290IFI0NjAeFw0yMTAzMjIwMDAwMDBaFw0zNjAzMjEyMzU5
# NTlaMFQxCzAJBgNVBAYTAkdCMRgwFgYDVQQKEw9TZWN0aWdvIExpbWl0ZWQxKzAp
# BgNVBAMTIlNlY3RpZ28gUHVibGljIENvZGUgU2lnbmluZyBDQSBSMzYwggGiMA0G
# CSqGSIb3DQEBAQUAA4IBjwAwggGKAoIBgQCbK51T+jU/jmAGQ2rAz/V/9shTUxjI
# ztNsfvxYB5UXeWUzCxEeAEZGbEN4QMgCsJLZUKhWThj/yPqy0iSZhXkZ6Pg2A2NV
# DgFigOMYzB2OKhdqfWGVoYW3haT29PSTahYkwmMv0b/83nbeECbiMXhSOtbam+/3
# 6F09fy1tsB8je/RV0mIk8XL/tfCK6cPuYHE215wzrK0h1SWHTxPbPuYkRdkP05Zw
# mRmTnAO5/arnY83jeNzhP06ShdnRqtZlV59+8yv+KIhE5ILMqgOZYAENHNX9SJDm
# +qxp4VqpB3MV/h53yl41aHU5pledi9lCBbH9JeIkNFICiVHNkRmq4TpxtwfvjsUe
# dyz8rNyfQJy/aOs5b4s+ac7IH60B+Ja7TVM+EKv1WuTGwcLmoU3FpOFMbmPj8pz4
# 4MPZ1f9+YEQIQty/NQd/2yGgW+ufflcZ/ZE9o1M7a5Jnqf2i2/uMSWymR8r2oQBM
# dlyh2n5HirY4jKnFH/9gRvd+QOfdRrJZb1sCAwEAAaOCAWQwggFgMB8GA1UdIwQY
# MBaAFDLrkpr/NZZILyhAQnAgNpFcF4XmMB0GA1UdDgQWBBQPKssghyi47G9IritU
# pimqF6TNDDAOBgNVHQ8BAf8EBAMCAYYwEgYDVR0TAQH/BAgwBgEB/wIBADATBgNV
# HSUEDDAKBggrBgEFBQcDAzAbBgNVHSAEFDASMAYGBFUdIAAwCAYGZ4EMAQQBMEsG
# A1UdHwREMEIwQKA+oDyGOmh0dHA6Ly9jcmwuc2VjdGlnby5jb20vU2VjdGlnb1B1
# YmxpY0NvZGVTaWduaW5nUm9vdFI0Ni5jcmwwewYIKwYBBQUHAQEEbzBtMEYGCCsG
# AQUFBzAChjpodHRwOi8vY3J0LnNlY3RpZ28uY29tL1NlY3RpZ29QdWJsaWNDb2Rl
# U2lnbmluZ1Jvb3RSNDYucDdjMCMGCCsGAQUFBzABhhdodHRwOi8vb2NzcC5zZWN0
# aWdvLmNvbTANBgkqhkiG9w0BAQwFAAOCAgEABv+C4XdjNm57oRUgmxP/BP6YdURh
# w1aVcdGRP4Wh60BAscjW4HL9hcpkOTz5jUug2oeunbYAowbFC2AKK+cMcXIBD0Zd
# OaWTsyNyBBsMLHqafvIhrCymlaS98+QpoBCyKppP0OcxYEdU0hpsaqBBIZOtBajj
# cw5+w/KeFvPYfLF/ldYpmlG+vd0xqlqd099iChnyIMvY5HexjO2AmtsbpVn0OhNc
# WbWDRF/3sBp6fWXhz7DcML4iTAWS+MVXeNLj1lJziVKEoroGs9Mlizg0bUMbOalO
# hOfCipnx8CaLZeVme5yELg09Jlo8BMe80jO37PU8ejfkP9/uPak7VLwELKxAMcJs
# zkyeiaerlphwoKx1uHRzNyE6bxuSKcutisqmKL5OTunAvtONEoteSiabkPVSZ2z7
# 6mKnzAfZxCl/3dq3dUNw4rg3sTCggkHSRqTqlLMS7gjrhTqBmzu1L90Y1KWN/Y5J
# KdGvspbOrTfOXyXvmPL6E52z1NZJ6ctuMFBQZH3pwWvqURR8AgQdULUvrxjUYbHH
# j95Ejza63zdrEcxWLDX6xWls/GDnVNueKjWUH3fTv1Y8Wdho698YADR7TNx8X8z2
# Bev6SivBBOHY+uqiirZtg0y9ShQoPzmCcn63Syatatvx157YK9hlcPmVoa1oDE5/
# L9Uo2bC5a4CH2RwwggZvMIIE16ADAgECAhBIqMP3CCLHOHtOKuaWNyeFMA0GCSqG
# SIb3DQEBDAUAMFQxCzAJBgNVBAYTAkdCMRgwFgYDVQQKEw9TZWN0aWdvIExpbWl0
# ZWQxKzApBgNVBAMTIlNlY3RpZ28gUHVibGljIENvZGUgU2lnbmluZyBDQSBSMzYw
# HhcNMjYwNDE1MDAwMDAwWhcNMjcwNzE0MjM1OTU5WjBmMQswCQYDVQQGEwJERTEP
# MA0GA1UECAwGQmF5ZXJuMSIwIAYDVQQKDBlTRVBQbWFpbCBEZXV0c2NobGFuZCBH
# bWJIMSIwIAYDVQQDDBlTRVBQbWFpbCBEZXV0c2NobGFuZCBHbWJIMIICIjANBgkq
# hkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAvAFzE8MbJpvQt+IdIh1M+bKYsJBFDk4b
# 9ySe25IrCi00B9o5XmQtIw42MqyIKbUq1tDARtp9KTQedEP9W+rflAF2l+0Z046J
# kiqumU9/enbqWLDyln1aS/p7HOgwZFMhnsR9zH0MfFckiklUmkzJO+vmzYAK7ZmD
# xajNLJs0gkGRU2/BecAx/TSvLXMaKONsKZCyMKQCnwo1mCY/tFl5EgUz7YQFrPOR
# BQGfQke/hkdBfQDqNRsi/J6+KhJWc6LvgQihdRg/INQbQsTxlow18NWvyFsjjueH
# 7kG6HR4YKfbv07xgrsIh8xvq9ZJ1SBhLXmkg4SdoQGASjqR6o3keAX+bDRFf+hml
# WWJp/FqVHR5QomF3vbK2/bbz4jAclYSPx/sPasNJ0YnKFkgmowZ7Ysa0KA0/egBg
# tI4gJ+8V7zrqIVEG3rMQh9KCdMnJqP2aM9o4gUzQvE1M4x606liX9EWwdLLS+fe7
# 9o+Fzo5oH4wBE/En6hQQkzseHHu+TXCDd6zUUZ/PlTK0gTaDIRXt6UzPNqJ4RiRC
# W2pNFcPt078qqVTuwKUXoE4ufxGgXKFrZlCYST/9eG1TnW2oq19nz8A333GCsL3g
# poNIKvfmDyGMMNzvx2aeqn2v6e75z8kH19iGSNZ51xT+WgS9F1aIvjz08/T7XAv7
# iDPF1/gPIp8CAwEAAaOCAakwggGlMB8GA1UdIwQYMBaAFA8qyyCHKLjsb0iuK1Sm
# KaoXpM0MMB0GA1UdDgQWBBS30/Tq+alF3j2BY5up8n5zpAU23DAOBgNVHQ8BAf8E
# BAMCB4AwDAYDVR0TAQH/BAIwADATBgNVHSUEDDAKBggrBgEFBQcDAzBKBgNVHSAE
# QzBBMDUGDCsGAQQBsjEBAgEDAjAlMCMGCCsGAQUFBwIBFhdodHRwczovL3NlY3Rp
# Z28uY29tL0NQUzAIBgZngQwBBAEwSQYDVR0fBEIwQDA+oDygOoY4aHR0cDovL2Ny
# bC5zZWN0aWdvLmNvbS9TZWN0aWdvUHVibGljQ29kZVNpZ25pbmdDQVIzNi5jcmww
# eQYIKwYBBQUHAQEEbTBrMEQGCCsGAQUFBzAChjhodHRwOi8vY3J0LnNlY3RpZ28u
# Y29tL1NlY3RpZ29QdWJsaWNDb2RlU2lnbmluZ0NBUjM2LmNydDAjBggrBgEFBQcw
# AYYXaHR0cDovL29jc3Auc2VjdGlnby5jb20wHgYDVR0RBBcwFYETc3VwcG9ydEBz
# ZXBwbWFpbC5jaDANBgkqhkiG9w0BAQwFAAOCAYEAi7fmb5UYoemWG3CC4K2UZWVr
# R6GOfi8gbJKgjPbKO4zrCrU/x6cOdyp6scKZfUEGFDf8KH6pP4pAQv1Hsbi49gU2
# kxoUWLlCiipn05qJY663DHx9hlStej/ZdEatou0wyCDiG5xD7kmG+1t6iLyyCBgE
# B88tJpzTjI61qXmBTS/FGEOAsB4SDEW1ngA7bc5FOv4IUKA43hp8M+N3GeYFzDqw
# JELYEfVVYheBW3o7q4VrCdfFEuaQihOtvfDfYpP6ANgekNn8HdsMT8rx9D1I50Rl
# i/qQFo2BOuPyb2SIQPzJvCs5wgi5qgp1nHiN6igumu2Cz7BmGjOazGUgCSUY5Qwy
# E8+F+R2tVM+2O15rfX01+e56ZfojBEiEjMwfPHs3fa3V3gokWWNwUMkton/v0R/n
# l2zjmOr2okohOINZEDh9frg21zUCN5ZD8Y4zQWuiJLCvvvBZs0JR4c9xl2k2wtw/
# QLPhGU69zM3smGpRoLE8M6zvUvSU7jXjvefazUniMYIDGjCCAxYCAQEwaDBUMQsw
# CQYDVQQGEwJHQjEYMBYGA1UEChMPU2VjdGlnbyBMaW1pdGVkMSswKQYDVQQDEyJT
# ZWN0aWdvIFB1YmxpYyBDb2RlIFNpZ25pbmcgQ0EgUjM2AhBIqMP3CCLHOHtOKuaW
# NyeFMA0GCWCGSAFlAwQCAQUAoIGEMBgGCisGAQQBgjcCAQwxCjAIoAKAAKECgAAw
# GQYJKoZIhvcNAQkDMQwGCisGAQQBgjcCAQQwHAYKKwYBBAGCNwIBCzEOMAwGCisG
# AQQBgjcCARUwLwYJKoZIhvcNAQkEMSIEIGyKnyuAjnMfF6qN/zKvqtOHVXqlFFwc
# IpuyEVeEiAWLMA0GCSqGSIb3DQEBAQUABIICAAIvGown+ejCOUhx7/xMWceUOIeo
# LY394bShPGR3oqNNusM6CG2NRRkHQPiYe36rsLHh5ZzuUtFgsrGryvSNLOjuM+FP
# TcFIj2YRkkio38ByEEGkcSwRcxzobfiIOwgNZaqxQjY0SLxmSccb+7Z7hPIgS6nU
# 94M23FPngtYPc9x5KXRzsjR3776meP/NnQjmbh2J07oyxkaSjm2IiPYD68Q76P0B
# 3mv53F7w0p32uBQL0XU/AzFLx8no8ghCsdlCYvXKMOO2bgTzm2NK8gfdxKw8eEAl
# Hb7F7bc8k8f+u5CN7oaTJWo1xISsk+Mw5N0ME0gi1yzBW7Ka9Sxa5U/jCRRVxbXa
# Pl9op0duaZuPPBadbUmo7m9Ju1v8zBLxaueJl3LvjEDjqctWHD4Aec1nCKwunBRo
# LJvSFYHBpm5H7L7Uv5Q6DAGg8AyEJYhvrvCNGrTk1Tl1PWDKarhAItJPzZ8qTXag
# HO8ZOPl0j0kesxowgx+22EVMTGpUE8jpA7Tam5C6dj0AKOII8cp83hl1euLOdB8D
# GKS//IykPl/QD3NDEhP1Czhe0ol6v++U2Rhq+mIkb/eUcswB+/lNigPwl1TM9+f9
# sDOPROq1IlhVqXs9fT9p0vYe2SZteZr41sZgQ2Ak8NKBt1GuYP/LTbrEMbOuZTQu
# EeFs9A2fHaCrWaDC
# SIG # End signature block