Scripts/InitScript.ps1

[CmdLetBinding()]
# Detect installed module version
$ModuleRootPath = Split-Path -Path $PSScriptRoot -Parent
$ManiFestFile = Import-PowerShellDataFile -Path $ModuleRootPath/SEPPMAILConnect.psd1
$Global:ModuleVersion = $ManiFestFile.ModuleVersion.ToString()
[string]$requiredPSVersion = '7.5.0'

$requiredModules = @{
          'ExchangeOnlineManagement' = '3.10.1'
                      'DnsClient-PS' = '1.2.1'
                       'PSWriteHTML' = '1.41.0'
    'Microsoft.Graph.Authentication' = '2.41.0'
      'Microsoft.Graph.Applications' = '2.41.0'
            'Microsoft.Graph.Groups' = '2.41.0'
    }

function Write-SEPPMAILText {
    <#
    .SYNOPSIS
    Writes text using SEPPMAIL foreground and background colors.
    .PARAMETER Colorset
    Selects Main (#CFDE00 on #034049), Secondary (#F8FBCC on #CACAB7),
    or Action (#A879E1 on #13D38E). Defaults to Main.
    .PARAMETER FgHex
    Overrides the selected color set's foreground color.
    .PARAMETER BgHex
    Overrides the selected color set's background color.
    .EXAMPLE
    Write-SEPPMAILText -Colorset Main -Text 'SomeText'
    #>

    param(
        [string]$Text,
        [string]$FgHex,
        [string]$BgHex,
        [switch]$NoNewline,

        [ValidateSet('Main', 'Secondary', 'Action')]
        [string]$Colorset = 'Main'
    )
    $palette = switch ($Colorset) {
        'Main' { @{ Foreground = '#CFDE00'; Background = '#034049' } }
        'Secondary' { @{ Foreground = '#F8FBCC'; Background = '#CACAB7' } }
        'Action' { @{ Foreground = '#A879E1'; Background = '#13D38E' } }
    }
    if (!$PSBoundParameters.ContainsKey('FgHex')) {
        $FgHex = $palette.Foreground
    }
    if (!$PSBoundParameters.ContainsKey('BgHex')) {
        $BgHex = $palette.Background
    }
    $esc = [char]27
    $fg = $FgHex.TrimStart('#')
    $bg = $BgHex.TrimStart('#')

    $formattedText = "$esc[38;2;$([Convert]::ToInt32($fg.Substring(0,2),16));$([Convert]::ToInt32($fg.Substring(2,2),16));$([Convert]::ToInt32($fg.Substring(4,2),16));48;2;$([Convert]::ToInt32($bg.Substring(0,2),16));$([Convert]::ToInt32($bg.Substring(2,2),16));$([Convert]::ToInt32($bg.Substring(4,2),16))m$Text$esc[0m"

    Write-Host $formattedText -NoNewline:$NoNewline
}
<#
Write-SEPPMAILText -Text "+---------------------------------------------------------------------+"
Write-SEPPMAILText -Text "| |"
Write-SEPPMAILText -Text "| Welcome to the SEPPMAILConnect PowerShell module version $ModuleVersion |"
if (!($ManiFestFile.PrivateData.PSData.Prerelease)) {
    Write-SEPPMAILText -Text "| You are running a STABLE release of the module |"
} else {
    Write-SEPPMAILText -Colorset Action -Text "| *** You are running the PRE-RELEASE version $($ManiFestFile.PrivateData.PSData.Prerelease) of the module *** |" # -FgHex "#FF0000" -BgHex "#000000"
}
Write-SEPPMAILText -Text "| |"
Write-SEPPMAILText -Text "| Please read the documentation if you are unfamiliar |"
Write-SEPPMAILText -Text "| with the module and its CmdLets before continuing ! |"
Write-SEPPMAILText -Text "| |"
Write-SEPPMAILText -Text "| Cloud |"
Write-SEPPMAILText -Text "| https://docs.seppmail.com/en/cloud/c07_cloud_powershell.html |"
Write-SEPPMAILText -Text "| Press <CTRL><Click> to open the Link |"
Write-SEPPMAILText -Text "| |"
Write-SEPPMAILText -Text "| Appliance |"
Write-SEPPMAILText -Text "| https://docs.seppmail.com/de/04_com_powershell_setup-exo.html?q=M365|"
Write-SEPPMAILText -Text "| Press <CTRL><Click> to open the Link |"
Write-SEPPMAILText -Text "| |"
Write-SEPPMAILText -Text "+---------------------------------------------------------------------+"
#>


# Set Default Values for Releasetext and Colorset
$releaseText = 'You are running a STABLE release of the module'
$releaseColorset = 'Main'

if ($ManiFestFile.PrivateData.PSData.Prerelease) {
    $releaseText = "*** You are running the PRE-RELEASE version $($ManiFestFile.PrivateData.PSData.Prerelease) of the module ***"
    $releaseColorset = 'Action'
}

$bannerLines = @(
    ''
    "Welcome to the SEPPMAILConnect PowerShell module version $ModuleVersion"
    $releaseText
    ''
    'Please read the documentation if you are unfamiliar'
    'with the module and its CmdLets before continuing !'
    ''
    'Cloud'
    'https://docs.seppmail.com/en/cloud/c07_cloud_powershell.html'
    'Press <CTRL><Click> to open the Link'
    ''
    'Appliance'
    'https://docs.seppmail.com/de/04_com_powershell_setup-exo.html?q=M365'
    'Press <CTRL><Click> to open the Link'
    ''
)

$contentWidth = ($bannerLines | Measure-Object -Property Length -Maximum).Maximum
$border = '─' * ($contentWidth + 2)

Write-SEPPMAILText -Colorset Main -Text ("┌{0}┐" -f $border)

for ($i = 0; $i -lt $bannerLines.Count; $i++) {
    $colorset = if ($i -eq 2) { $releaseColorset } else { 'Main' }
    $framedText = "│ {0} │" -f $bannerLines[$i].PadRight($contentWidth)

    Write-SEPPMAILText -Colorset $colorset -Text $framedText
}

Write-SEPPMAILText -Colorset Main -Text ("└{0}┘" -f $border)


Write-Verbose "Running InitScript.ps1 and doing requirement-checks" 
if ($scSkipTests -ne $true) {
    Write Verbose 'Check if PSGallery is registered'
    if (!(Get-PSResourceRepository -Name PSGallery -ea 0)) {
        Register-PSResourceRepository -PSGallery -Trusted
    }
    Write-Verbose 'Check if PSGGallery is trusted'
    if ((Get-PSResourceRepository -Name PSGallery).Trusted -ne $true) {
        Write-Warning "You do not Trust the PowerShellGallery as a module installation source."
        Set-PSResourceRepository -Name PSGallery -Trusted
    }

    Write-Verbose "Create Helper function for Version checking"
    <#
    .SYNOPSIS
    Parses a semantic version string and converts it into a structured object.
 
    .DESCRIPTION
    The `ConvertTo-SemanticVersion` function takes a version string that conforms to the Semantic Versioning (SemVer) standard
    and parses it into its components: Major, Minor, Patch, PreRelease, and BuildMetadata. If the input string is not a valid
    semantic version, the function throws an error.
 
    The SemVer format includes:
    - A version core: `MAJOR.MINOR.PATCH`
    - Optional pre-release information: `-<pre-release>`
    - Optional build metadata: `+<build-metadata>`
 
    .EXAMPLE
    ConvertTo-SemanticVersion -VersionString "1.2.3-alpha+build123"
 
    Returns:
    @{
        Major = 1
        Minor = 2
        Patch = 3
        PreRelease = "alpha"
        BuildMetadata = "build123"
    }
 
    .EXAMPLE
    ConvertTo-SemanticVersion -VersionString "4.5.6"
 
    Returns:
    @{
        Major = 4
        Minor = 5
        Patch = 6
        PreRelease = $null
        BuildMetadata = $null
    }
 
    .INPUTS
    [string]
    You must provide a semantic version string as input. The string must conform to the SemVer format.
 
    .OUTPUTS
    [hashtable]
    The function returns a hashtable with the following keys:
    - `Major` ([int]): The major version number.
    - `Minor` ([int]): The minor version number.
    - `Patch` ([int]): The patch version number.
    - `PreRelease` ([string]): The pre-release label, or `$null` if not specified.
    - `BuildMetadata` ([string]): The build metadata, or `$null` if not specified.
 
    .NOTES
    - The function validates the format of the input string using a regular expression.
    - If the input does not conform to the SemVer format, an exception is thrown.
 
    .LINK
    Semantic Versioning Specification: https://semver.org/
    #>

    function ConvertTo-SemanticVersion {
        param (
            [string]$VersionString
        )
    
        if ($VersionString -match '^(\d+)\.(\d+)\.(\d+)(?:-([\w\-\.]+))?(?:\+([\w\-\.]+))?$') {
            return @{
                Major        = [int]$matches[1]
                Minor        = [int]$matches[2]
                Patch        = [int]$matches[3]
                PreRelease   = $matches[4]
                BuildMetadata = $matches[5]
            }
        }
        else {
            throw "Invalid semantic version format: $VersionString"
        }
    }
    Write-verbose "Check PowerShell Version"
    [String]$instPSVersion = ((($PSVersionTable.PSVersion.ToString())) -Split '\.')[0..2] -join '.'
    if ($PSVersionTable.PSEdition -eq "Desktop") {
        Write-SEPPMAILText -Colorset Action -Text "+------------------------------------------------------+"
        Write-SEPPMAILText -Colorset Action -Text "| |"
        Write-SEPPMAILText -Colorset Action -Text "| !!! Wrong PowerShell EDITION !!! |"
        Write-SEPPMAILText -Colorset Action -Text "| |"
        Write-SEPPMAILText -Colorset Action -Text "| The module does not support |"
        Write-SEPPMAILText -Colorset Action -Text "| Windows Powershell 5.1 Desktop and earlier |"
        Write-SEPPMAILText -Colorset Action -Text "| |"
        Write-SEPPMAILText -Colorset Action -Text "| PLEASE install PowerShell CORE $requiredPSVersion+ |"
        Write-SEPPMAILText -Colorset Action -Text "| |"
        Write-SEPPMAILText -Colorset Action -Text "+------------------------------------------------------+"
        Break
    } else {
        $minPSVersion = [System.Management.Automation.SemanticVersion]::Parse($requiredPSVersion)
        $instPSVersion = [System.Management.Automation.SemanticVersion]::Parse($InstPSVersion)
        if ($minPSVersion -gt $instPSVersion) {
            Write-Host "+------------------------------------------------------+" -ForegroundColor Red -BackgroundColor Black
            Write-Host "| |" -ForegroundColor Red -BackgroundColor Black
            Write-Host "| !!! Wrong PowerShell Version $instPSversion found !!! |" -ForegroundColor Red -BackgroundColor Black
            Write-Host "| |" -ForegroundColor Red -BackgroundColor Black
            Write-Host "| PLEASE install PowerShell CORE $minPSVersion+ |" -ForegroundColor Red -BackgroundColor Black
            Write-Host "| |" -ForegroundColor Red -BackgroundColor Black
            Write-Host "+------------------------------------------------------+" -ForegroundColor Red -BackgroundColor Black
            Break
        }
    }
    Write-Verbose "PowerShell version is $instPSVersion and equal or newer than required version $requiredPSVersion"

    Write-Verbose "Create Helper function for module installation"
    <#
    .SYNOPSIS
    Installs a PowerShell module or resource from a repository using the appropriate installation command.
 
    .DESCRIPTION
    The `Invoke-RepoInstall` function checks if the `Install-PSResource` command is available. If available, it uses it to install or reinstall the specified artifact. If not, it defaults to using `Install-Module` for installation. This function ensures compatibility with both older and newer versions of PowerShell's module management tools.
 
    .PARAMETER artefact
    The name of the module or resource to be installed from the repository.
 
    .EXAMPLE
    Invoke-RepoInstall -artefact 'ExchangeOnlineManagement'
 
    This command installs or reinstalls the `ExchangeOnlineManagement` module.
 
    .EXAMPLE
    Invoke-RepoInstall -artefact 'PSWriteHTML'
 
    This command installs or reinstalls the `PSWriteHTML` module.
 
    .NOTES
    - This function simplifies module installation by abstracting the differences between `Install-Module` and `Install-PSResource`.
    - Requires the appropriate repository (e.g., PSGallery) to be registered and accessible.
 
    .OUTPUTS
    None.
 
    .INPUTS
    [string]
    Accepts the name of the module or resource as a string.
 
    #>

    function Invoke-RepoInstall {
        param (
            [string]$artefact,
            [string]$artefactVersion
        )
        if (!(Get-Command -Name 'Install-PSResource' -ErrorAction SilentlyContinue)) {
            #$RepoInstallMethod = 'Module'
            $InstCommandString = "Install-Module $artefact -requiredVersion $artefactVersion -force -WarningAction SilentlyContinue"
        } else {
            $InstCommandString = "Install-PSResource $artefact -Version $artefactVersion -Reinstall -WarningAction SilentlyContinue"
        }
        Invoke-Expression $InstCommandString
    }

    Write-Verbose "Check required Module availability"
    foreach ($module in $requiredModules.Keys) {
        #Reset of variables for loop
        $localInstVersion = $null
        $semanticLocalInstVersion = $null
        $semanticRequiredVersion = $null

        $version = $requiredModules[$module]
        Write-Verbose "Checking version $version for module $module"
        $availableModules = Get-Module $module -ListAvailable | Sort-Object Version -Descending
        if ($availableModules.count -gt 0) {
            $localInstVersion = $availableModules[0].Version
        }

        if ($localInstVersion) {
            $semanticLocalInstVersion = [System.Management.Automation.SemanticVersion]::Parse($localInstVersion.ToString())
            Write-Verbose "Installed version of module $module is $localInstVersion"
            $semanticRequiredVersion = [System.Management.Automation.SemanticVersion]::Parse($Version)
            Write-Verbose "Required version of module $module is $version"
        }
        if ((!($localInstVersion)) -or ($semanticLocalInstVersion -lt $semanticRequiredVersion )) {
            try {
                Write-Verbose "Installing required module $module" -InformationAction Continue
                Write-Output "Installing/Updating Module $module with required version $version "
                Invoke-RepoInstall -artefact $module -artefactVersion $version
            } catch {
                Write-Error "Could not install required Module $module with version $version. Please install manually from the PowerShell Gallery"
            }
            Write-Verbose "Import module $module"
            Import-Module $module -Force
        } else {
            Write-Verbose "Installed version of module $module has the required version $localInstVersion"
        }
    }
}

Write-Verbose 'Initialize argument completer scriptBlocks'
$script:paramDomSB = {
    # Read Accepted Domains for domain selection
    param($commandName, $parameterName, $wordToComplete, $commandAst, $fakeBoundParameters)
    $tenantAcceptedDomains.Domain | Where-Object {
        $_ -like "$wordToComplete*"
            } | ForEach-Object {
                "'$_'"
                }
}
# SIG # Begin signature block
# MIIVyAYJKoZIhvcNAQcCoIIVuTCCFbUCAQExDzANBglghkgBZQMEAgEFADB5Bgor
# BgEEAYI3AgEEoGswaTA0BgorBgEEAYI3AgEeMCYCAwEAAAQQH8w7YFlLCE63JNLG
# KX7zUQIBAAIBAAIBAAIBAAIBADAxMA0GCWCGSAFlAwQCAQUABCDTdmympmbs0yCC
# vmlZ2gOPIvljsFu0HUPHJaMwyIVowaCCEgQwggVvMIIEV6ADAgECAhBI/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
# AQQBgjcCARUwLwYJKoZIhvcNAQkEMSIEIDiCNJXMacVw9ATlgMFUCt25tF4X0SPq
# N2RFw/qTg6PeMA0GCSqGSIb3DQEBAQUABIICAKbJbnZx7jsF1Mw/6pJqnAl7Mgxo
# os7xXMZw3vWKPrcb9UVp558bCPEFM+vY1jc/rqi2aZ15Q0iwQEfUJBFn2TX0lDW0
# UUcMyCUYRs8cuQqoRPizTn4U0UJcBbd5djS1dzqZL4DhRY1MSmnHgqfVClBoTsPt
# DqYl1ajaICxjM0R+cRVzAabUPgDHk85YMvGbVd/EhvELTO3cJl2glUqpl3XuPPlU
# 8YSkwIApjLpFggjIqRPGTXiOeYvsQZ2yubuJmk0EwTi14TfEScPP0MHRFlD7G5JT
# CSLtlGxtilW7VDorxp72tMU95fW1iTcn/yg4EDYfMfPYhiz15LD926N8M/xDbliA
# b08vaLrttBv3NSHZPNEeE4LKw5ZSQOm90w0YJRh0v0JRr1SrthO/WJK6LVe/YfWr
# 0MsYAfc0BQocGtMsHrRWdN+2R9VJq9SQqY0UO7DVwFuMMBHutEO+xL6kQ13HXsbW
# mZmi8RSrma7QpAMBOKwYPIh6cDWzP4876k9TMVgdyKmWOkBvTgALnPQqWq32q2I/
# Beot1g05a67Z6VPhy+QJkzGYCUZAAH168KFrqNKu4XSWw8pA58jy9D47yD9B9/di
# 2PY4UnisV6tmjehwxZiHnoxzye8NrBxoRflFuFvxXwV1dz4MC5qsglSk6LKjpkAT
# b1vbj5PZAITzma5G
# SIG # End signature block