Utils.psm1
|
function CheckVersionAndWarn() { [version]$installedVersion = (Get-Module -Name SmtpClientDiag).Version [version]$latestVersion; Write-Output "SMTP Client Diagnostic Version: $($installedVersion)" try { # Not using proxy $result = Invoke-WebRequest -Uri "https://github.com/richfaj/SmtpClientDiag/releases/latest/download/version.txt" -TimeoutSec 10 -UseBasicParsing $content = [System.Text.Encoding]::UTF8.GetString($result.Content) $latestVersion = [version]$content } catch { Write-Warning "Unable to check for updates. Please check your internet connection and try again." } if ($null -ne $latestVersion -and $installedVersion -lt $latestVersion) { Write-Warning "A newer version of SmtpClientDiag is available. Please update to the latest version using Update-Module cmdlet and restart the shell." } } function DecodeBase64Value { [CmdletBinding()] param( [Parameter(Mandatory = $false)] [AllowEmptyString()] [string]$Value, [Parameter(Mandatory = $false)] [switch]$AllowUrlSafeEncoding ) # Handle null or empty input if ([string]::IsNullOrEmpty($Value)) { Write-Verbose "Input value is null or empty, returning null" return $null } try { # Normalize the input $normalizedValue = Get-NormalizedBase64String -InputString $Value -AllowUrlSafe:$AllowUrlSafeEncoding # Add padding if needed $paddedValue = Add-Base64Padding -Base64String $normalizedValue # Decode the Base64 string Write-Verbose "Decoding Base64 string of length: $($paddedValue.Length)" $decodedBytes = [System.Convert]::FromBase64String($paddedValue) $decodedText = [System.Text.Encoding]::UTF8.GetString($decodedBytes) Write-Verbose "Successfully decoded Base64 string to UTF-8 text (length: $($decodedText.Length))" return $decodedText } catch [System.FormatException] { $errorMsg = "Invalid Base64 format. The input contains invalid characters or is malformed." Write-Verbose "Base64 decode failed: $errorMsg. Input: '$Value'" throw [System.ArgumentException]::new($errorMsg, "Value", $_.Exception) } catch [System.ArgumentException] { $errorMsg = "Invalid Base64 string length or format." Write-Verbose "Base64 decode failed: $errorMsg. Input: '$Value'" throw [System.ArgumentException]::new($errorMsg, "Value", $_.Exception) } catch { $errorMsg = "Failed to decode Base64 string: $($_.Exception.Message)" Write-Verbose "Unexpected error during Base64 decode: $errorMsg. Input: '$Value'" throw [System.InvalidOperationException]::new($errorMsg, $_.Exception) } } function Get-NormalizedBase64String { [CmdletBinding()] param( [Parameter(Mandatory = $true)] [string]$InputString, [Parameter(Mandatory = $false)] [switch]$AllowUrlSafe ) $result = $InputString.Trim() # Convert URL-safe Base64 to standard Base64 if requested if ($AllowUrlSafe) { $result = $result.Replace('-', '+').Replace('_', '/') Write-Verbose "Converted URL-safe Base64 characters to standard format" } # Validate Base64 character set if ($result -notmatch '^[A-Za-z0-9+/]*={0,2}$') { throw [System.FormatException]::new("Input contains invalid Base64 characters") } return $result } function Add-Base64Padding { [CmdletBinding()] [OutputType([System.String])] param( [Parameter(Mandatory = $true)] [string]$Base64String ) $paddingNeeded = $Base64String.Length % 4 switch ($paddingNeeded) { 0 { Write-Verbose "No padding needed for Base64 string" return $Base64String } 1 { # Invalid: Base64 length cannot have remainder of 1 when divided by 4 throw [System.ArgumentException]::new("Invalid Base64 string length. Length cannot have a remainder of 1.") } 2 { Write-Verbose "Adding 2 padding characters to Base64 string" return $Base64String + "==" } 3 { Write-Verbose "Adding 1 padding character to Base64 string" return $Base64String + "=" } default { throw [System.InvalidOperationException]::new("Unexpected padding calculation result: $paddingNeeded") } } } function GetCharHexValue([char] $char) { return ('{0:x}' -f [int]$char).ToUpper() } function Get-SmtpAccessToken() { param( [string]$ClientId, [string]$TenantId, [string]$UserName, [SecureString]$ClientSecret, [string]$AccessToken, [string]$VerbosePref) $VerbosePreference = $VerbosePref # Use supplied token instead if provided if (-not [System.String]::IsNullOrEmpty($AccessToken)) { Write-Verbose "User supplied AccessToken. Not fetching new token." return $AccessToken } else { Write-Verbose "Obtaining an access token using MSAL.PS module" $token = $null # Non-interactive login if client secret is provided if (-not [System.String]::IsNullOrEmpty($ClientSecret)) { Write-Verbose "Using client secret to obtain access token." $token = Get-MsalToken -ClientId $ClientId -TenantId $TenantId -ClientSecret $ClientSecret -Scope 'https://outlook.office.com/.default' } else { Write-Verbose "Using interactive login to obtain access token." $token = Get-MsalToken -ClientId $ClientId -TenantId $TenantId -Interactive -Scope 'https://outlook.office.com/Smtp.Send' -LoginHint $UserName } if ([System.String]::IsNullOrEmpty($token.AccessToken)) { throw "No token was available in the token request result." } return $token.AccessToken } } function RetrieveCertificateFromCertStore($thumbprint) { $cert = Get-ChildItem -Path "cert:\LocalMachine\My" | Where-Object { $_.Thumbprint -eq $thumbprint } if ($null -eq $cert -or ($cert | Measure-Object).Count -eq 0) { throw "No certificates found with thumbprint '$thumbprint' in LocalMachine certificate store." } # There should only be one certificate if (($cert | Measure-Object).Count -gt 1) { throw "More than one certificate found with thumbprint '$thumbprint'." } # Do we have access to the private key? if (-not $cert.HasPrivateKey) { throw "The certificate with thumbprint '$thumbprint' does not have a private key." } Write-Verbose "Found certificate with thumbprint '$thumbprint' in LocalMachine certificate store." return $cert } function Get-TlsVersion([string]$TlsVersion) { $enabledSslProtocols = $null if ($TlsVersion -eq "tls") { $enabledSslProtocols = [System.Security.Authentication.SslProtocols]::Tls } elseif ($TlsVersion -eq "tls11") { $enabledSslProtocols = [System.Security.Authentication.SslProtocols]::Tls11 } elseif ($TlsVersion -eq "tls12") { $enabledSslProtocols = [System.Security.Authentication.SslProtocols]::Tls12 } elseif ($TlsVersion -eq "tls13") { $enabledSslProtocols = [System.Security.Authentication.SslProtocols]::Tls13 } return $enabledSslProtocols } function Invoke-DotNetDnsResolver { [CmdletBinding()] [OutputType([System.Object[]], [System.Net.IPAddress[]])] param( [Parameter(Mandatory = $true)] [string]$HostName ) try { Write-Verbose "Resolving '$HostName' using internal .NET DNS resolver" $addresses = [System.Net.Dns]::GetHostAddresses($HostName) if ($addresses.Count -gt 0) { Write-Verbose "Successfully resolved $($addresses.Count) address(es) for '$HostName'" return $addresses } else { Write-Verbose "DNS resolution returned no addresses for '$HostName'" return @() } } catch { Write-Verbose "DNS resolution failed for '$HostName': $($_.Exception.Message)" return @() } } # SIG # Begin signature block # MIIoKgYJKoZIhvcNAQcCoIIoGzCCKBcCAQExCzAJBgUrDgMCGgUAMGkGCisGAQQB # gjcCAQSgWzBZMDQGCisGAQQBgjcCAR4wJgIDAQAABBAfzDtgWUsITrck0sYpfvNR # AgEAAgEAAgEAAgEAAgEAMCEwCQYFKw4DAhoFAAQU8SVQuvT8sgPUAqiVZVPAWgce # /+iggiFMMIIFjTCCBHWgAwIBAgIQDpsYjvnQLefv21DiCEAYWjANBgkqhkiG9w0B # AQwFADBlMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYD # VQQLExB3d3cuZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVk # IElEIFJvb3QgQ0EwHhcNMjIwODAxMDAwMDAwWhcNMzExMTA5MjM1OTU5WjBiMQsw # CQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cu # ZGlnaWNlcnQuY29tMSEwHwYDVQQDExhEaWdpQ2VydCBUcnVzdGVkIFJvb3QgRzQw # ggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC/5pBzaN675F1KPDAiMGkz # 7MKnJS7JIT3yithZwuEppz1Yq3aaza57G4QNxDAf8xukOBbrVsaXbR2rsnnyyhHS # 5F/WBTxSD1Ifxp4VpX6+n6lXFllVcq9ok3DCsrp1mWpzMpTREEQQLt+C8weE5nQ7 # bXHiLQwb7iDVySAdYyktzuxeTsiT+CFhmzTrBcZe7FsavOvJz82sNEBfsXpm7nfI # SKhmV1efVFiODCu3T6cw2Vbuyntd463JT17lNecxy9qTXtyOj4DatpGYQJB5w3jH # trHEtWoYOAMQjdjUN6QuBX2I9YI+EJFwq1WCQTLX2wRzKm6RAXwhTNS8rhsDdV14 # Ztk6MUSaM0C/CNdaSaTC5qmgZ92kJ7yhTzm1EVgX9yRcRo9k98FpiHaYdj1ZXUJ2 # h4mXaXpI8OCiEhtmmnTK3kse5w5jrubU75KSOp493ADkRSWJtppEGSt+wJS00mFt # 6zPZxd9LBADMfRyVw4/3IbKyEbe7f/LVjHAsQWCqsWMYRJUadmJ+9oCw++hkpjPR # iQfhvbfmQ6QYuKZ3AeEPlAwhHbJUKSWJbOUOUlFHdL4mrLZBdd56rF+NP8m800ER # ElvlEFDrMcXKchYiCd98THU/Y+whX8QgUWtvsauGi0/C1kVfnSD8oR7FwI+isX4K # Jpn15GkvmB0t9dmpsh3lGwIDAQABo4IBOjCCATYwDwYDVR0TAQH/BAUwAwEB/zAd # BgNVHQ4EFgQU7NfjgtJxXWRM3y5nP+e6mK4cD08wHwYDVR0jBBgwFoAUReuir/SS # y4IxLVGLp6chnfNtyA8wDgYDVR0PAQH/BAQDAgGGMHkGCCsGAQUFBwEBBG0wazAk # BggrBgEFBQcwAYYYaHR0cDovL29jc3AuZGlnaWNlcnQuY29tMEMGCCsGAQUFBzAC # hjdodHRwOi8vY2FjZXJ0cy5kaWdpY2VydC5jb20vRGlnaUNlcnRBc3N1cmVkSURS # b290Q0EuY3J0MEUGA1UdHwQ+MDwwOqA4oDaGNGh0dHA6Ly9jcmwzLmRpZ2ljZXJ0 # LmNvbS9EaWdpQ2VydEFzc3VyZWRJRFJvb3RDQS5jcmwwEQYDVR0gBAowCDAGBgRV # HSAAMA0GCSqGSIb3DQEBDAUAA4IBAQBwoL9DXFXnOF+go3QbPbYW1/e/Vwe9mqyh # hyzshV6pGrsi+IcaaVQi7aSId229GhT0E0p6Ly23OO/0/4C5+KH38nLeJLxSA8hO # 0Cre+i1Wz/n096wwepqLsl7Uz9FDRJtDIeuWcqFItJnLnU+nBgMTdydE1Od/6Fmo # 8L8vC6bp8jQ87PcDx4eo0kxAGTVGamlUsLihVo7spNU96LHc/RzY9HdaXFSMb++h # UD38dglohJ9vytsgjTVgHAIDyyCwrFigDkBjxZgiwbJZ9VVrzyerbHbObyMt9H5x # aiNrIv8SuFQtJ37YOtnwtoeW/VvRXKwYw02fc7cBqZ9Xql4o4rmUMIIGsDCCBJig # AwIBAgIQCK1AsmDSnEyfXs2pvZOu2TANBgkqhkiG9w0BAQwFADBiMQswCQYDVQQG # EwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNl # cnQuY29tMSEwHwYDVQQDExhEaWdpQ2VydCBUcnVzdGVkIFJvb3QgRzQwHhcNMjEw # NDI5MDAwMDAwWhcNMzYwNDI4MjM1OTU5WjBpMQswCQYDVQQGEwJVUzEXMBUGA1UE # ChMORGlnaUNlcnQsIEluYy4xQTA/BgNVBAMTOERpZ2lDZXJ0IFRydXN0ZWQgRzQg # Q29kZSBTaWduaW5nIFJTQTQwOTYgU0hBMzg0IDIwMjEgQ0ExMIICIjANBgkqhkiG # 9w0BAQEFAAOCAg8AMIICCgKCAgEA1bQvQtAorXi3XdU5WRuxiEL1M4zrPYGXcMW7 # xIUmMJ+kjmjYXPXrNCQH4UtP03hD9BfXHtr50tVnGlJPDqFX/IiZwZHMgQM+TXAk # ZLON4gh9NH1MgFcSa0OamfLFOx/y78tHWhOmTLMBICXzENOLsvsI8IrgnQnAZaf6 # mIBJNYc9URnokCF4RS6hnyzhGMIazMXuk0lwQjKP+8bqHPNlaJGiTUyCEUhSaN4Q # vRRXXegYE2XFf7JPhSxIpFaENdb5LpyqABXRN/4aBpTCfMjqGzLmysL0p6MDDnSl # rzm2q2AS4+jWufcx4dyt5Big2MEjR0ezoQ9uo6ttmAaDG7dqZy3SvUQakhCBj7A7 # CdfHmzJawv9qYFSLScGT7eG0XOBv6yb5jNWy+TgQ5urOkfW+0/tvk2E0XLyTRSiD # NipmKF+wc86LJiUGsoPUXPYVGUztYuBeM/Lo6OwKp7ADK5GyNnm+960IHnWmZcy7 # 40hQ83eRGv7bUKJGyGFYmPV8AhY8gyitOYbs1LcNU9D4R+Z1MI3sMJN2FKZbS110 # YU0/EpF23r9Yy3IQKUHw1cVtJnZoEUETWJrcJisB9IlNWdt4z4FKPkBHX8mBUHOF # ECMhWWCKZFTBzCEa6DgZfGYczXg4RTCZT/9jT0y7qg0IU0F8WD1Hs/q27IwyCQLM # bDwMVhECAwEAAaOCAVkwggFVMBIGA1UdEwEB/wQIMAYBAf8CAQAwHQYDVR0OBBYE # FGg34Ou2O/hfEYb7/mF7CIhl9E5CMB8GA1UdIwQYMBaAFOzX44LScV1kTN8uZz/n # upiuHA9PMA4GA1UdDwEB/wQEAwIBhjATBgNVHSUEDDAKBggrBgEFBQcDAzB3Bggr # BgEFBQcBAQRrMGkwJAYIKwYBBQUHMAGGGGh0dHA6Ly9vY3NwLmRpZ2ljZXJ0LmNv # bTBBBggrBgEFBQcwAoY1aHR0cDovL2NhY2VydHMuZGlnaWNlcnQuY29tL0RpZ2lD # ZXJ0VHJ1c3RlZFJvb3RHNC5jcnQwQwYDVR0fBDwwOjA4oDagNIYyaHR0cDovL2Ny # bDMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0VHJ1c3RlZFJvb3RHNC5jcmwwHAYDVR0g # BBUwEzAHBgVngQwBAzAIBgZngQwBBAEwDQYJKoZIhvcNAQEMBQADggIBADojRD2N # CHbuj7w6mdNW4AIapfhINPMstuZ0ZveUcrEAyq9sMCcTEp6QRJ9L/Z6jfCbVN7w6 # XUhtldU/SfQnuxaBRVD9nL22heB2fjdxyyL3WqqQz/WTauPrINHVUHmImoqKwba9 # oUgYftzYgBoRGRjNYZmBVvbJ43bnxOQbX0P4PpT/djk9ntSZz0rdKOtfJqGVWEjV # Gv7XJz/9kNF2ht0csGBc8w2o7uCJob054ThO2m67Np375SFTWsPK6Wrxoj7bQ7gz # yE84FJKZ9d3OVG3ZXQIUH0AzfAPilbLCIXVzUstG2MQ0HKKlS43Nb3Y3LIU/Gs4m # 6Ri+kAewQ3+ViCCCcPDMyu/9KTVcH4k4Vfc3iosJocsL6TEa/y4ZXDlx4b6cpwoG # 1iZnt5LmTl/eeqxJzy6kdJKt2zyknIYf48FWGysj/4+16oh7cGvmoLr9Oj9FpsTo # FpFSi0HASIRLlk2rREDjjfAVKM7t8RhWByovEMQMCGQ8M4+uKIw8y4+ICw2/O/TO # HnuO77Xry7fwdxPm5yg/rBKupS8ibEH5glwVZsxsDsrFhsP2JjMMB0ug0wcCampA # MEhLNKhRILutG4UI4lkNbcoFUCvqShyepf2gpx8GdOfy1lKQ/a+FSCH5Vzu0nAPt # hkX0tGFuv2jiJmCG6sivqf6UHedjGzqGVnhOMIIGtDCCBJygAwIBAgIQDcesVwX/ # IZkuQEMiDDpJhjANBgkqhkiG9w0BAQsFADBiMQswCQYDVQQGEwJVUzEVMBMGA1UE # ChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSEwHwYD # VQQDExhEaWdpQ2VydCBUcnVzdGVkIFJvb3QgRzQwHhcNMjUwNTA3MDAwMDAwWhcN # MzgwMTE0MjM1OTU5WjBpMQswCQYDVQQGEwJVUzEXMBUGA1UEChMORGlnaUNlcnQs # IEluYy4xQTA/BgNVBAMTOERpZ2lDZXJ0IFRydXN0ZWQgRzQgVGltZVN0YW1waW5n # IFJTQTQwOTYgU0hBMjU2IDIwMjUgQ0ExMIICIjANBgkqhkiG9w0BAQEFAAOCAg8A # MIICCgKCAgEAtHgx0wqYQXK+PEbAHKx126NGaHS0URedTa2NDZS1mZaDLFTtQ2oR # jzUXMmxCqvkbsDpz4aH+qbxeLho8I6jY3xL1IusLopuW2qftJYJaDNs1+JH7Z+Qd # SKWM06qchUP+AbdJgMQB3h2DZ0Mal5kYp77jYMVQXSZH++0trj6Ao+xh/AS7sQRu # QL37QXbDhAktVJMQbzIBHYJBYgzWIjk8eDrYhXDEpKk7RdoX0M980EpLtlrNyHw0 # Xm+nt5pnYJU3Gmq6bNMI1I7Gb5IBZK4ivbVCiZv7PNBYqHEpNVWC2ZQ8BbfnFRQV # ESYOszFI2Wv82wnJRfN20VRS3hpLgIR4hjzL0hpoYGk81coWJ+KdPvMvaB0WkE/2 # qHxJ0ucS638ZxqU14lDnki7CcoKCz6eum5A19WZQHkqUJfdkDjHkccpL6uoG8pbF # 0LJAQQZxst7VvwDDjAmSFTUms+wV/FbWBqi7fTJnjq3hj0XbQcd8hjj/q8d6ylgx # CZSKi17yVp2NL+cnT6Toy+rN+nM8M7LnLqCrO2JP3oW//1sfuZDKiDEb1AQ8es9X # r/u6bDTnYCTKIsDq1BtmXUqEG1NqzJKS4kOmxkYp2WyODi7vQTCBZtVFJfVZ3j7O # gWmnhFr4yUozZtqgPrHRVHhGNKlYzyjlroPxul+bgIspzOwbtmsgY1MCAwEAAaOC # AV0wggFZMBIGA1UdEwEB/wQIMAYBAf8CAQAwHQYDVR0OBBYEFO9vU0rp5AZ8esri # kFb2L9RJ7MtOMB8GA1UdIwQYMBaAFOzX44LScV1kTN8uZz/nupiuHA9PMA4GA1Ud # DwEB/wQEAwIBhjATBgNVHSUEDDAKBggrBgEFBQcDCDB3BggrBgEFBQcBAQRrMGkw # JAYIKwYBBQUHMAGGGGh0dHA6Ly9vY3NwLmRpZ2ljZXJ0LmNvbTBBBggrBgEFBQcw # AoY1aHR0cDovL2NhY2VydHMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0VHJ1c3RlZFJv # b3RHNC5jcnQwQwYDVR0fBDwwOjA4oDagNIYyaHR0cDovL2NybDMuZGlnaWNlcnQu # Y29tL0RpZ2lDZXJ0VHJ1c3RlZFJvb3RHNC5jcmwwIAYDVR0gBBkwFzAIBgZngQwB # BAIwCwYJYIZIAYb9bAcBMA0GCSqGSIb3DQEBCwUAA4ICAQAXzvsWgBz+Bz0RdnEw # vb4LyLU0pn/N0IfFiBowf0/Dm1wGc/Do7oVMY2mhXZXjDNJQa8j00DNqhCT3t+s8 # G0iP5kvN2n7Jd2E4/iEIUBO41P5F448rSYJ59Ib61eoalhnd6ywFLerycvZTAz40 # y8S4F3/a+Z1jEMK/DMm/axFSgoR8n6c3nuZB9BfBwAQYK9FHaoq2e26MHvVY9gCD # A/JYsq7pGdogP8HRtrYfctSLANEBfHU16r3J05qX3kId+ZOczgj5kjatVB+NdADV # ZKON/gnZruMvNYY2o1f4MXRJDMdTSlOLh0HCn2cQLwQCqjFbqrXuvTPSegOOzr4E # Wj7PtspIHBldNE2K9i697cvaiIo2p61Ed2p8xMJb82Yosn0z4y25xUbI7GIN/TpV # fHIqQ6Ku/qjTY6hc3hsXMrS+U0yy+GWqAXam4ToWd2UQ1KYT70kZjE4YtL8Pbzg0 # c1ugMZyZZd/BdHLiRu7hAWE6bTEm4XYRkA6Tl4KSFLFk43esaUeqGkH/wyW4N7Oi # gizwJWeukcyIPbAvjSabnf7+Pu0VrFgoiovRDiyx3zEdmcif/sYQsfch28bZeUz2 # rtY/9TCA6TD8dC3JE3rYkrhLULy7Dc90G6e8BlqmyIjlgp2+VqsS9/wQD7yFylIz # 0scmbKvFoW2jNrbM1pD2T7m3XDCCBu0wggTVoAMCAQICEAqA7xhLjfEFgtHEdqeV # dGgwDQYJKoZIhvcNAQELBQAwaTELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDkRpZ2lD # ZXJ0LCBJbmMuMUEwPwYDVQQDEzhEaWdpQ2VydCBUcnVzdGVkIEc0IFRpbWVTdGFt # cGluZyBSU0E0MDk2IFNIQTI1NiAyMDI1IENBMTAeFw0yNTA2MDQwMDAwMDBaFw0z # NjA5MDMyMzU5NTlaMGMxCzAJBgNVBAYTAlVTMRcwFQYDVQQKEw5EaWdpQ2VydCwg # SW5jLjE7MDkGA1UEAxMyRGlnaUNlcnQgU0hBMjU2IFJTQTQwOTYgVGltZXN0YW1w # IFJlc3BvbmRlciAyMDI1IDEwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoIC # AQDQRqwtEsae0OquYFazK1e6b1H/hnAKAd/KN8wZQjBjMqiZ3xTWcfsLwOvRxUwX # cGx8AUjni6bz52fGTfr6PHRNv6T7zsf1Y/E3IU8kgNkeECqVQ+3bzWYesFtkepEr # vUSbf+EIYLkrLKd6qJnuzK8Vcn0DvbDMemQFoxQ2Dsw4vEjoT1FpS54dNApZfKY6 # 1HAldytxNM89PZXUP/5wWWURK+IfxiOg8W9lKMqzdIo7VA1R0V3Zp3DjjANwqAf4 # lEkTlCDQ0/fKJLKLkzGBTpx6EYevvOi7XOc4zyh1uSqgr6UnbksIcFJqLbkIXIPb # cNmA98Oskkkrvt6lPAw/p4oDSRZreiwB7x9ykrjS6GS3NR39iTTFS+ENTqW8m6TH # uOmHHjQNC3zbJ6nJ6SXiLSvw4Smz8U07hqF+8CTXaETkVWz0dVVZw7knh1WZXOLH # gDvundrAtuvz0D3T+dYaNcwafsVCGZKUhQPL1naFKBy1p6llN3QgshRta6Eq4B40 # h5avMcpi54wm0i2ePZD5pPIssoszQyF4//3DoK2O65Uck5Wggn8O2klETsJ7u8xE # ehGifgJYi+6I03UuT1j7FnrqVrOzaQoVJOeeStPeldYRNMmSF3voIgMFtNGh86w3 # ISHNm0IaadCKCkUe2LnwJKa8TIlwCUNVwppwn4D3/Pt5pwIDAQABo4IBlTCCAZEw # DAYDVR0TAQH/BAIwADAdBgNVHQ4EFgQU5Dv88jHt/f3X85FxYxlQQ89hjOgwHwYD # VR0jBBgwFoAU729TSunkBnx6yuKQVvYv1Ensy04wDgYDVR0PAQH/BAQDAgeAMBYG # A1UdJQEB/wQMMAoGCCsGAQUFBwMIMIGVBggrBgEFBQcBAQSBiDCBhTAkBggrBgEF # BQcwAYYYaHR0cDovL29jc3AuZGlnaWNlcnQuY29tMF0GCCsGAQUFBzAChlFodHRw # Oi8vY2FjZXJ0cy5kaWdpY2VydC5jb20vRGlnaUNlcnRUcnVzdGVkRzRUaW1lU3Rh # bXBpbmdSU0E0MDk2U0hBMjU2MjAyNUNBMS5jcnQwXwYDVR0fBFgwVjBUoFKgUIZO # aHR0cDovL2NybDMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0VHJ1c3RlZEc0VGltZVN0 # YW1waW5nUlNBNDA5NlNIQTI1NjIwMjVDQTEuY3JsMCAGA1UdIAQZMBcwCAYGZ4EM # AQQCMAsGCWCGSAGG/WwHATANBgkqhkiG9w0BAQsFAAOCAgEAZSqt8RwnBLmuYEHs # 0QhEnmNAciH45PYiT9s1i6UKtW+FERp8FgXRGQ/YAavXzWjZhY+hIfP2JkQ38U+w # tJPBVBajYfrbIYG+Dui4I4PCvHpQuPqFgqp1PzC/ZRX4pvP/ciZmUnthfAEP1HSh # TrY+2DE5qjzvZs7JIIgt0GCFD9ktx0LxxtRQ7vllKluHWiKk6FxRPyUPxAAYH2Vy # 1lNM4kzekd8oEARzFAWgeW3az2xejEWLNN4eKGxDJ8WDl/FQUSntbjZ80FU3i54t # px5F/0Kr15zW/mJAxZMVBrTE2oi0fcI8VMbtoRAmaaslNXdCG1+lqvP4FbrQ6IwS # BXkZagHLhFU9HCrG/syTRLLhAezu/3Lr00GrJzPQFnCEH1Y58678IgmfORBPC1JK # kYaEt2OdDh4GmO0/5cHelAK2/gTlQJINqDr6JfwyYHXSd+V08X1JUPvB4ILfJdmL # +66Gp3CSBXG6IwXMZUXBhtCyIaehr0XkBoDIGMUG1dUtwq1qmcwbdUfcSYCn+Own # cVUXf53VJUNOaMWMts0VlRYxe5nK+At+DI96HAlXHAL5SlfYxJ7La54i71McVWRP # 66bW+yERNpbJCjyCYG2j+bdpxo/1Cy4uPcU3AWVPGrbn5PhDBf3Froguzzhk++am # i+r3Qrx5bIbY3TVzgiFI7Gq3zWcwggdaMIIFQqADAgECAhANw2Fva20K+rkvK+/+ # Bxk+MA0GCSqGSIb3DQEBCwUAMGkxCzAJBgNVBAYTAlVTMRcwFQYDVQQKEw5EaWdp # Q2VydCwgSW5jLjFBMD8GA1UEAxM4RGlnaUNlcnQgVHJ1c3RlZCBHNCBDb2RlIFNp # Z25pbmcgUlNBNDA5NiBTSEEzODQgMjAyMSBDQTEwHhcNMjUwNzE1MDAwMDAwWhcN # MjgwNzE2MjM1OTU5WjBiMQswCQYDVQQGEwJVUzEOMAwGA1UECBMFVGV4YXMxDzAN # BgNVBAcTBklydmluZzEYMBYGA1UEChMPUmljaGFyZCBGYWphcmRvMRgwFgYDVQQD # Ew9SaWNoYXJkIEZhamFyZG8wggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoIC # AQDsnVRBsMdpPCQMc05ysOVukiJC6uzFiamN/MuOMMicR/oTyBZa9o1+l0PV8uBJ # 8v5yu/eDmZkwCuJRhL1QA/T5FrJ/gwwI3YtHOWBG1QDOXsg8qiekMsaFgdYWAjCe # nEriC25YZE3I6mYNbWinJ/9/gsmP8EZCRGFbFtXfZO70c+83P2Q7TlS6R/Jt9ZgM # d7ML6F6jvvvxSR7lJ2D+7tyiNE45r/eWjL0tYAXaKaKpnnZbMW+At/vYjRqN10CE # OSnhQeuvTZTTiy4E/gjS6dN8gvregoO/9bAVofkDuRh6s+UvZtsp+yYyFpHTPbd6 # xEzwSwplT4/CYIVvaFEZ7mD0m3iIqR6RrdQYsdwB1dRKzJDgpxisUuAnpXRFUF8U # NHM17/mXQPf8wwJHnleVJbnecQ8ltiVvsMKi1lveru7T8b5EeSdt1vwMzUxe6tS2 # qWeYPvBvToOc0SyrmKPvLYq3Ut6fveK5g/XRXdqj6F2JRNvelnP+gg+DIgctoKTU # 7U8G07YIaJtO/lCIpvJXgNd0VD4iIZkhKMAbW95k4ovBhNJ9LZJ1mKF21i1MetFU # 6vk4T2kE8oSCzAH6gFyZ+SXhGzyzcOwhv/tBhYAiwwA7keSotpqgbnhnQST0XEFP # 9eQP1zMrpuGDNZMIxZFImD2dgNdP+X7e8zH8PJ6HxTwt/QIDAQABo4ICAzCCAf8w # HwYDVR0jBBgwFoAUaDfg67Y7+F8Rhvv+YXsIiGX0TkIwHQYDVR0OBBYEFJflaBtr # VOU8mYho6v2pIvOs2kN9MD4GA1UdIAQ3MDUwMwYGZ4EMAQQBMCkwJwYIKwYBBQUH # AgEWG2h0dHA6Ly93d3cuZGlnaWNlcnQuY29tL0NQUzAOBgNVHQ8BAf8EBAMCB4Aw # EwYDVR0lBAwwCgYIKwYBBQUHAwMwgbUGA1UdHwSBrTCBqjBToFGgT4ZNaHR0cDov # L2NybDMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0VHJ1c3RlZEc0Q29kZVNpZ25pbmdS # U0E0MDk2U0hBMzg0MjAyMUNBMS5jcmwwU6BRoE+GTWh0dHA6Ly9jcmw0LmRpZ2lj # ZXJ0LmNvbS9EaWdpQ2VydFRydXN0ZWRHNENvZGVTaWduaW5nUlNBNDA5NlNIQTM4 # NDIwMjFDQTEuY3JsMIGUBggrBgEFBQcBAQSBhzCBhDAkBggrBgEFBQcwAYYYaHR0 # cDovL29jc3AuZGlnaWNlcnQuY29tMFwGCCsGAQUFBzAChlBodHRwOi8vY2FjZXJ0 # cy5kaWdpY2VydC5jb20vRGlnaUNlcnRUcnVzdGVkRzRDb2RlU2lnbmluZ1JTQTQw # OTZTSEEzODQyMDIxQ0ExLmNydDAJBgNVHRMEAjAAMA0GCSqGSIb3DQEBCwUAA4IC # AQBcJngbL8FgxIfCimjUkh+HAPlxzbWJW3brq7D3RHe9wfV5ItOrui6Op64vKVg5 # T5lyzZrOAzQM6GPXBBoWWVLfdSscLsI/NvLMx6eW81My+xFUgRnFSp/IQ/DwQNUf # bthZJNN8us+urwPCoE7pinMHVOx4K5OtV9tBuu9qrqvti1IlAueOkkPZB9sKlN+a # Q2e7o7IaEDeQ8cf9NXNlwUU5Npt4A15AyY/Rs4UZ0VA+V5+Jg12fxcP7GzonxUoB # kNdeX6o9MnOSu0uyoahFqU6xdqhYt6rp9Jm4DCyTnOH0PhCOc2o4Yw+kyLCT89G9 # eh141zP3S3enNXUqZX1Y/oYHAk0yv1o5ANKmpLD6oHMYmD0MurprwX9Fs36mIllp # ElxPpgnVZK6RvJjucrM9+Ohd1wTaQWLFJ/P1ma2gwZqucHebrd5m+8aABh//jtAs # bU6cu5hQm/+Ip5jKD8BJE5xiZNr++fOokE6/x38MMgqtPSj29KNOwcAUAV73aY+x # CKC6uRBoMaKHXVdN8r2f4/8a6dA26PaEHLY0v/PeWYUxCfiyCgMcqhFUkhP7HvsX # 3/XxfRLB+FM2n1MkfECTc2C17mAb1+Gmt0yW6gd141JLzJAfogQxYt3FoJEcht7x # /yvg+sWOkZtILz1ndlgt2eo/aQL/Z17OYxdPdo4rSXD8GTGCBkgwggZEAgEBMH0w # aTELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDkRpZ2lDZXJ0LCBJbmMuMUEwPwYDVQQD # EzhEaWdpQ2VydCBUcnVzdGVkIEc0IENvZGUgU2lnbmluZyBSU0E0MDk2IFNIQTM4 # NCAyMDIxIENBMQIQDcNhb2ttCvq5Lyvv/gcZPjAJBgUrDgMCGgUAoHgwGAYKKwYB # BAGCNwIBDDEKMAigAoAAoQKAADAZBgkqhkiG9w0BCQMxDAYKKwYBBAGCNwIBBDAc # BgorBgEEAYI3AgELMQ4wDAYKKwYBBAGCNwIBFTAjBgkqhkiG9w0BCQQxFgQUlc3L # qR0FpJ0SeZfXtDqdKUWG2FYwDQYJKoZIhvcNAQEBBQAEggIAaCTYfuqAEji9Rur4 # Dgp5D+L21cZFZG4l1Mvf5bu+XfhP5JmVm3gdyW5FbwL+m7E1DmfJI1wpwKsjPIUV # kGCEf7KVq/f2WF3c3XcCs6tkts2yz1pqCMFGKREDhXdeoz+t6vnJCvldZKe40F3y # qCx32eLc1FSYdS0ise/MhKA1ZtNs7XpWXtzDySeFNeZBs+pAWldXBuZPFoX8O4nG # 93Ng0rddNP1l3oJyI94BaOOsUgQWqYLeLc5Kp0Qk4gN9Zk9kfcKWIwtuK9DQ7WSR # rsSlovEqibeD+3FBfIklftwofy8NJk/njeq7DgohRCHVz23Vx8WM17she3s+ga0w # KI4ycdozJGq6MDuSZp08aP+4GJ8BcrMNfxGiJStHZsQM2beVzNP53jHYAtudtvXV # +9k3xNWvUQCMp7rMh5CuSa1VZmrkjSZPUgdBesm3b80VkWZhmQXpVohLzK4QTPXO # TTxSlF2nzY0OA5/0gSDipdDeCHI45bAqTRJc8hWh61x4ojCvru91iD7aoSCgJBVF # L01P4/QOtq5/e8eqcQvA1zNTrl1T52KGBAcxdqZFxdVW5Aq3P+x+GRNzA35dVo/n # xfDf5G25U6KusAtQIT8b5X88MXCipxqyX6UHYLdpUfHKPVQBiNex2wANzfKpTV13 # kPrCHAZi2L+enG1/c8i6/CR7mY2hggMmMIIDIgYJKoZIhvcNAQkGMYIDEzCCAw8C # AQEwfTBpMQswCQYDVQQGEwJVUzEXMBUGA1UEChMORGlnaUNlcnQsIEluYy4xQTA/ # BgNVBAMTOERpZ2lDZXJ0IFRydXN0ZWQgRzQgVGltZVN0YW1waW5nIFJTQTQwOTYg # U0hBMjU2IDIwMjUgQ0ExAhAKgO8YS43xBYLRxHanlXRoMA0GCWCGSAFlAwQCAQUA # oGkwGAYJKoZIhvcNAQkDMQsGCSqGSIb3DQEHATAcBgkqhkiG9w0BCQUxDxcNMjUx # MTE4MjAxMjUzWjAvBgkqhkiG9w0BCQQxIgQg8Xty5BjTuqbLXB2tloFdgbE7ChqD # yq/E82oDVsiVVtowDQYJKoZIhvcNAQEBBQAEggIAWiZGOEA70frF8LXFgQGFHIYS # +lXe7nOGFendidcmvWUAGbHo9Y8fZwo3V5Qu8HfXvJPgbPsbjYBAaquQW81SBMBJ # l43Y4Tpyl90c5uWCV9tuFMvO9qyzFW1N8nXU0lOZmQxNJ8/w7o3x7zD8BCbbUxWi # yO4/a3Eup6bjNf5TFFH6i55Xf9Ea3pbBuwpSdWe7Q594PxjnRvn9LQj3BKRaRKXj # kMO78VG2DYjM/BPmK13N/z4NFhkqHtAJYcofft598Bz8R/GuBMVZb666pvcgBzxe # FzIsJrMfQmPYG74u8Xc0f9l2YtLC4wEedLoZKjDDIqfQN85qsiLbnRLM5qjHkFZx # vu+sy4Ot/FvLoA9NND6cugCsW+Gv0aWgID/p4tMaJztzTB+EqvvTyEjR2ImfkUP5 # 2rPA9aH6+WQiJ9unIzIRwrLICFUDrCNXTixUsp2qu71sw8AWK6QhgoYsmNtQJxwp # ZQI8KLfEGTWavkdC90vjivzkYkA8GYzcjZsxSs7wSDuMCu7/JzDk3weqSWmUVQ5b # fJeuaEtVnrPIEvr5ajvQ1eXPRSWx5shEYUHN9f8mWCtPIoyIZWoc0MPF8QDKeT3M # ckQH+4EQG4LdVsfkptAiKxdYFKcRDftXWuZUyI09o+VRee8NmpTm8t/H+dnXM1aH # 6iZwDkODM/Wb1cyUe5g= # SIG # End signature block |