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 |