Private/PrivateFunctions.ps1

# Generic function to avoid code duplication
<#
.SYNOPSIS
Sets properties on an input object from a configuration stored in a JSON object.
 
.DESCRIPTION
The Set-SM365PropertiesFromConfigJson function takes an input object and a JSON configuration object
and sets properties on the input object based on the JSON data. It can also set version-specific
and option-specific properties as required.
 
.PARAMETER InputObject
The object on which the properties will be set. This object will be modified based on the properties
found in the provided JSON configuration.
 
.PARAMETER Json
The JSON object containing configuration data. This should include both general properties and
version-specific or option-specific properties if applicable.
 
.PARAMETER Version
Specifies the configuration version to use when setting properties. If no version is specified,
the default behavior will be applied. The parameter defaults to `[SM365.ConfigVersion]::None`.
 
.PARAMETER Option
An array of configuration options that can be used to set option-specific properties from the JSON
configuration.
 
.EXAMPLE
$inputObject = New-Object PSObject -Property @{ Name = "Sample" }
$jsonConfig = Get-Content -Path "C:\config.json" -Raw | ConvertFrom-Json
Set-SM365PropertiesFromConfigJson -InputObject $inputObject -Json $jsonConfig -Version "V1" -Option @("Option1", "Option2")
 
This example reads a JSON configuration file, parses it, and sets the properties on an input object
based on the configuration data for version "V1" and the specified options.
 
.NOTES
The function assumes that the JSON structure includes a "Version" section for version-specific properties
and an "Option" section for option-specific settings. It skips setting properties if the specified version
does not exist in the JSON structure.
#>

function Set-SM365PropertiesFromConfigJson
{
    [CmdLetBinding()]
    Param
    (
        [psobject] $InputObject,
        [psobject] $Json,
        [SM365.ConfigVersion] $Version = [SM365.ConfigVersion]::None,
        [SM365.ConfigOption[]] $Option
    )

    if(!$json.Version.$version) {
        $InputObject.Skip = $true;
    }

    # Set all properties that aren't version specific
    $json.psobject.properties | Foreach-Object {
        if ($_.Name -notin @("Version", "Name", "Option"))
        { $InputObject.$($_.Name) = $_.Value }
    }

    # Default version actually acts as default properties now
    if($json.Version["Default"]){
        $json.Version["Default"].psobject.properties | Foreach-Object 
            $InputObject.$($_.Name) = $_.Value
    }

    # Set the version specific properties, except if none has been requested
    if ($Version -ne [SM365.ConfigVersion]::None) {
        $json.Version.$Version.psobject.properties | Foreach-Object {
            $InputObject.$($_.Name) = $_.Value
        }
    }

    if($Option -and $json.Option)
    {
        $Option | Where-Object {$json.Option.$_} | ForEach-Object{
            $Json.Option.$_.psobject.properties | ForEach-Object{
                $InputObject.$($_.Name) = $_.Value
            }
        }
    }
}

<#
.SYNOPSIS
Retrieves inbound connector settings from a JSON configuration file.
 
.DESCRIPTION
The Get-SM365InboundConnectorSettings function reads inbound connector settings from a JSON file located
in the specified path and returns the settings based on the specified connector type (e.g., Default or Partner).
 
.PARAMETER Type
Specifies the type of connector settings to retrieve. The valid values are 'Default' and 'Partner'.
The parameter defaults to 'Default' if not specified.
 
.EXAMPLE
Get-SM365InboundConnectorSettings -Type 'Partner'
 
This example retrieves the inbound connector settings for the 'Partner' type from the JSON configuration file.
 
.EXAMPLE
Get-SM365InboundConnectorSettings
 
This example retrieves the default inbound connector settings, as the Type parameter defaults to 'Default'.
 
.NOTES
The function assumes that the JSON configuration file `Inbound.json` is located in the `..\ExOConfig\Connectors`
directory relative to the script's location. The JSON structure should have keys corresponding to the
valid types ('Default', 'Partner') for correct data retrieval.
#>

function Get-SM365InboundConnectorSettings
{
    [CmdletBinding()]
    Param
    (
        [ValidateSet('Default','Partner')]
        [String]$Type = 'Default'
    )
    begin {
        $ret = $null
        $raw = $null
    }
    process {
        Write-Verbose "Loading inbound connector settings for routingtype $Routing"
        $raw = (Get-Content "$PSScriptRoot\..\ExOConfig\Connectors\Inbound.json" -Raw|Convertfrom-Json -AsHashtable)
        $ret = $raw.$Type    
    }
    end {
        return $ret
    }
}

<#
.SYNOPSIS
Retrieves outbound connector settings from a JSON configuration file.
 
.DESCRIPTION
The Get-SM365OutboundConnectorSettings function reads outbound connector settings from a JSON file
located in the specified path and returns the settings based on the specified connector type
(e.g., Default or Partner).
 
.PARAMETER Type
Specifies the type of connector settings to retrieve. The valid values are 'Default' and 'Partner'.
The parameter defaults to 'Default' if not specified.
 
.EXAMPLE
Get-SM365OutboundConnectorSettings -Type 'Partner'
 
This example retrieves the outbound connector settings for the 'Partner' type from the JSON configuration file.
 
.EXAMPLE
Get-SM365OutboundConnectorSettings
 
This example retrieves the default outbound connector settings, as the Type parameter defaults to 'Default'.
 
.NOTES
The function assumes that the JSON configuration file `Outbound.json` is located in the `..\ExOConfig\Connectors`
directory relative to the script's location. The JSON structure should have keys corresponding to the
valid types ('Default', 'Partner') for correct data retrieval.
#>

function Get-SM365OutboundConnectorSettings
{
    [CmdletBinding()]
    Param
    (
        [ValidateSet('Default','Partner')]
        [String]$Type = 'Default'
    )

    begin {
        $ret = $null
        $raw = $null
    }
    process {
        Write-Verbose "Loading outbound connector settings"
        $raw = (Get-Content "$PSScriptRoot\..\ExOConfig\Connectors\Outbound.json" -Raw|Convertfrom-Json -AsHashtable)
        $ret= $Raw.$Type
    }
    end
    {
        return $ret
    }
}


<#
.SYNOPSIS
Retrieves transport rule settings from a JSON file and returns them as a hashtable.
 
.DESCRIPTION
The Get-SM365TransportRuleSettings function reads a JSON file specified by the user,
parses its contents, and returns the transport rule settings found within the `default`
section of the JSON as a hashtable.
 
.PARAMETER File
Specifies the path to the JSON file that contains the transport rule settings. This parameter
is mandatory.
 
.EXAMPLE
Get-SM365TransportRuleSettings -File "C:\path\to\settings.json"
 
This example reads the specified JSON file, extracts the `default` section, and returns it as
a hashtable.
 
.NOTES
The function assumes that the JSON file is properly formatted and that it includes a `default`
key at the top level. The function reads the entire file as a raw string and converts it into
a hashtable for easy access and processing.
#>

function Get-SM365TransportRuleSettings
{
    [CmdLetBinding()]
    Param
    (
        [Parameter(Mandatory = $true)]
        $File
    )
    begin {
        $ret = $null
        $raw = $null
    }
    process {
            $raw = (Get-Content $file -Raw|Convertfrom-Json -AsHashtable)
            $ret = $raw.default
            return $ret    
    }
    end {
    }
}

<#
.SYNOPSIS
Prompts the user to input a specified number of IP addresses and returns them as an array.
 
.DESCRIPTION
The Get-IPAddressArray function allows the user to enter a specified number of IP addresses.
Each input is validated to ensure it matches the basic format of an IPv4 address. If an invalid
IP address is entered, the function prompts the user to re-enter a valid IP address for that
iteration. The function returns an array containing all the valid IP addresses provided.
 
.PARAMETER Count
The number of IP addresses the user wishes to input. This parameter is mandatory.
 
.EXAMPLE
Get-IPAddressArray -Count 3
 
This example prompts the user to enter three IP addresses. If the user enters any invalid
IP address, they are prompted to enter it again until a valid address is provided. The
function returns an array of the entered IP addresses.
 
.NOTES
This function performs a basic validation for IPv4 addresses using a regular expression.
For more complex or accurate validation, consider using built-in .NET methods or modules
for IP address parsing.
#>

function Get-IPAddressArray {
    [CmdLetBinding()]
    param (
        [Parameter(
            Mandatory=$true,
            HelpMessage="Geben Sie die Anzahl der Adressen ein, die sie eingeben wollen."
        )]
        [int]$Count
    )
    $ipArray = @()

    for ($i = 1; $i -le $Count; $i++) {
        $ip = Read-Host -Prompt "Geben Sie IP-Adresse Nr. $i ein"
        
        # Validierung der IP-Adresse (optionale einfache Validierung)
        if ($ip -match '^([0-9]{1,3}\.){3}[0-9]{1,3}$') {
            $ipArray += $ip
        } else {
            Write-Host "Ungültige IP-Adresse: $ip. Bitte geben Sie eine gültige IP-Adresse ein."
            $i-- # Wiederhole diese Schleifenrunde für eine erneute Eingabe
        }
    }
    return $ipArray
}

<#
.SYNOPSIS
Adds unique strings to an existing string array only if they do not already exist in the array.
 
.DESCRIPTION
The Add-UniqueStringsToArray function takes an existing string array and an array of new strings.
It checks each new string to see if it already exists in the existing array. If a string is not
already present, it adds the string to the array. The function returns the updated array.
 
.PARAMETER ExistingArray
The existing string array to which new unique strings will be added. If null or empty, the array
is initialized as an empty array.
 
.PARAMETER NewStrings
The array of new strings to be added to the existing array if they do not already exist in it.
 
.EXAMPLE
$existingArray = @('example.com', 'test.com')
$newStrings = @('test.com', 'newdomain.com', 'sample.org')
$updatedArray = Add-UniqueStringsToArray -ExistingArray $existingArray -NewStrings $newStrings
Write-Host "Updated Array: $updatedArray"
 
This example takes an array containing 'example.com' and 'test.com', and adds 'newdomain.com'
and 'sample.org' while skipping 'test.com' since it already exists in the existing array.
The output will be:
Updated Array: example.com test.com newdomain.com sample.org
#>

function Add-UniqueStringsToArray {
    param (
        [string[]]$ExistingArray,
        [string[]]$NewStrings
    )

    # Wenn das vorhandene Array null oder leer ist, initialisieren wir es
    if (-not $ExistingArray) {
        $ExistingArray = @()
    }

    # Durchlaufen der neuen Strings und Hinzufügen, wenn sie nicht bereits existieren
    foreach ($string in $NewStrings) {
        if ($ExistingArray -notcontains $string) {
            $ExistingArray += $string
        }
    }

    # Rückgabe des aktualisierten Arrays
    return $ExistingArray
}

# SIG # Begin signature block
# MIIVzAYJKoZIhvcNAQcCoIIVvTCCFbkCAQExDzANBglghkgBZQMEAgEFADB5Bgor
# BgEEAYI3AgEEoGswaTA0BgorBgEEAYI3AgEeMCYCAwEAAAQQH8w7YFlLCE63JNLG
# KX7zUQIBAAIBAAIBAAIBAAIBADAxMA0GCWCGSAFlAwQCAQUABCC7YRY71Ew5pqbT
# fis2qW8wLYZFv/4D/H/DEDK0kYNBgKCCEggwggVvMIIEV6ADAgECAhBI/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/
# L9Uo2bC5a4CH2RwwggZzMIIE26ADAgECAhAMcJlHeeRMvJV4PjhvyrrbMA0GCSqG
# SIb3DQEBDAUAMFQxCzAJBgNVBAYTAkdCMRgwFgYDVQQKEw9TZWN0aWdvIExpbWl0
# ZWQxKzApBgNVBAMTIlNlY3RpZ28gUHVibGljIENvZGUgU2lnbmluZyBDQSBSMzYw
# HhcNMjMwMzIwMDAwMDAwWhcNMjYwMzE5MjM1OTU5WjBqMQswCQYDVQQGEwJERTEP
# MA0GA1UECAwGQmF5ZXJuMSQwIgYDVQQKDBtTRVBQbWFpbCAtIERldXRzY2hsYW5k
# IEdtYkgxJDAiBgNVBAMMG1NFUFBtYWlsIC0gRGV1dHNjaGxhbmQgR21iSDCCAiIw
# DQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAOapobQkNYCMP+Y33JcGo90Soe9Y
# /WWojr4bKHbLNBzKqZ6cku2uCxhMF1Ln6xuI4ATdZvm4O7GqvplG9nF1ad5t2Lus
# 5SLs45AYnODP4aqPbPU/2NGDRpfnceF+XhKeiYBwoIwrPZ04b8bfTpckj/tvenB9
# P8/9hAjWK97xv7+qsIz4lMMaCuWZgi8RlP6XVxsb+jYrHGA1UdHZEpunEFLaO9Ss
# OPqatPAL2LNGs/JVuGdq9p47GKzn+vl+ANd5zZ/TIP1ifX76vorqZ9l9a5mzi/HG
# vq43v2Cj3jrzIQ7uTbxtiLlPQUqkRzPRtiwTV80JdtRE+M+gTf7bT1CTvG2L3scf
# YKFk7S80M7NydxV/qL+l8blGGageCzJ8svju2Mo4BB+ALWr+gBmCGqrM8YKy/wXR
# tbvdEvBOLsATcHX0maw9xRCDRle2jO+ndYkTKZ92AMH6a/WdDfL0HrAWloWWSg62
# TxmJ/QiX54ILQv2Tlh1Al+pjGHN2evxS8i+XoWcUdHPIOoQd37yjnMjCN593wDzj
# XCEuDABYw9BbvfSp29G/uiDGtjttDXzeMRdVCJFgULV9suBVP7yFh9pK/mVpz+aC
# L2PvqiGYR41xRBKqwrfJEdoluRsqDy6KD985EdXkTvdIFKv0B7MfbcBCiGUBcm1r
# fLAbs8Q2lqvqM4bxAgMBAAGjggGpMIIBpTAfBgNVHSMEGDAWgBQPKssghyi47G9I
# ritUpimqF6TNDDAdBgNVHQ4EFgQUL96+KAGrvUgJnXwdVnA/uy+RlEcwDgYDVR0P
# AQH/BAQDAgeAMAwGA1UdEwEB/wQCMAAwEwYDVR0lBAwwCgYIKwYBBQUHAwMwSgYD
# VR0gBEMwQTA1BgwrBgEEAbIxAQIBAwIwJTAjBggrBgEFBQcCARYXaHR0cHM6Ly9z
# ZWN0aWdvLmNvbS9DUFMwCAYGZ4EMAQQBMEkGA1UdHwRCMEAwPqA8oDqGOGh0dHA6
# Ly9jcmwuc2VjdGlnby5jb20vU2VjdGlnb1B1YmxpY0NvZGVTaWduaW5nQ0FSMzYu
# Y3JsMHkGCCsGAQUFBwEBBG0wazBEBggrBgEFBQcwAoY4aHR0cDovL2NydC5zZWN0
# aWdvLmNvbS9TZWN0aWdvUHVibGljQ29kZVNpZ25pbmdDQVIzNi5jcnQwIwYIKwYB
# BQUHMAGGF2h0dHA6Ly9vY3NwLnNlY3RpZ28uY29tMB4GA1UdEQQXMBWBE3N1cHBv
# cnRAc2VwcG1haWwuY2gwDQYJKoZIhvcNAQEMBQADggGBAHnWpS4Jw/QiiLQi2EYv
# THCtwKsj7O3G7wAN7wijSJcWF7iCx6AoCuCIgGdWiQuEZcv9pIUrXQ6jOSRHsDNX
# SvIhCK9JakZJSseW/SCb1rvxZ4d0n2jm2SdkWf5j7+W+X4JHeCF9ZOw0ULpe5pFs
# IGTh8bmTtUr3yA11yw4vHfXFwin7WbEoTLVKiL0ZUN0Qk+yBniPPSRRlUZIX8P4e
# iXuw7lh9CMaS3HWRKkK89w//18PjUMxhTZJ6dszN2TAfwu1zxdG/RQqvxXUTTAxU
# JrrCuvowtnDQ55yXMxkkSxWUwLxk76WvXwmohRdsavsGJJ9+yxj5JKOd+HIZ1fZ7
# oi0VhyOqFQAnjNbwR/TqPjRxZKjCNLXSM5YSMZKAhqrJssGLINZ2qDK/CEcVDkBS
# 6Hke4jWMczny8nB8+ATJ84MB7tfSoXE7R0FMs1dinuvjVWIyg6klHigpeEiAaSaG
# 5KF7vk+OlquA+x4ohPuWdtFxobOT2OgHQnK4bJitb9aDazGCAxowggMWAgEBMGgw
# VDELMAkGA1UEBhMCR0IxGDAWBgNVBAoTD1NlY3RpZ28gTGltaXRlZDErMCkGA1UE
# AxMiU2VjdGlnbyBQdWJsaWMgQ29kZSBTaWduaW5nIENBIFIzNgIQDHCZR3nkTLyV
# eD44b8q62zANBglghkgBZQMEAgEFAKCBhDAYBgorBgEEAYI3AgEMMQowCKACgACh
# AoAAMBkGCSqGSIb3DQEJAzEMBgorBgEEAYI3AgEEMBwGCisGAQQBgjcCAQsxDjAM
# BgorBgEEAYI3AgEVMC8GCSqGSIb3DQEJBDEiBCBdiclaYpDLzlUgXlJFKDTK3BS+
# W3C5N9XKTaIg8X9ghTANBgkqhkiG9w0BAQEFAASCAgChJ0gi+CSrqeHyC7MPJFM4
# lkxaY5gsr+E2LR8bOSMMqQIEtk6V1IzZriGDNFY7KZ1t+R+FB0XCNOnctawo9BfR
# Q/SSTqTc4A/Q8V9ZxEMaXy5xsdDjJaJfJQPVsoEIeVA6E91LBw/RIA+NMgleoa/H
# cMaQGS7GaPJYYVvygZdjITSIE2joyudOcon5CJ8fqtiHgwoAclXBPvWlqKH7IhRK
# r/PDcdoHYedE51h3wVXE2nyaY29XUl1cAOqztl3qzP4mFZk6ChdQUEWPa9Tw/NkY
# f8PO0qO/g4FuapqD2VwUGkMFwFxlNAqaXzBTkWdQh4WhlxMiMZ65q9I+g6mZF4/W
# 7IZqQgO1R0POYuFPpenRn3aDWbCk1RLt2I9QQLWvRC7jTEsS6V9yTFvJonHidJqI
# c7DVEwQuyAi/gpO9kymPLYupHthu+ULXSKQXGV3OB0IrucssS4mJjkg5rFH0h2s0
# 7P51kBPJ5rL9p2RJbvfSSBAuJ+wK7GPz8erGjB3V2OaaAHCoM2aIYqYfQ1E+G5cG
# WO4zl5/v9wYya3xNovX9Mw/46+BLPsJT1TbdJZmxkdGXjItowsBP1aRCLtx7VF/e
# Hugbf5fqyq9RAfW5htiN29uAB/UvArXezJAZfSJD2SuzfjJm3LTGITojIPhxhdXI
# ynKN5Ofb2ADvFb0jqjy09w==
# SIG # End signature block