PSBlackListChecker.psm1
function Format-FirstXChars { <# .SYNOPSIS This function returns the first X characters of a given text string. .DESCRIPTION The Format-FirstXChars function takes a text string and a number of characters as input and returns the first X characters of the text string. .PARAMETER Text The input text string from which the first X characters will be extracted. .PARAMETER NumberChars The number of characters to extract from the beginning of the input text string. .EXAMPLE Format-FirstXChars -Text "VERBOSE: Loading module from path 'C:\Users\pklys\.vscode\extensions\ms-vs" -NumberChars 15 # Returns: VERBOSE: Loading .NOTES This function is useful for truncating long text strings to a specific length. #> param( [string] $Text, [int] $NumberChars ) return ($Text.ToCharArray() | Select-Object -First $NumberChars) -join '' } function New-Runspace { <# .SYNOPSIS Creates a new runspace pool with the specified minimum and maximum runspaces. .DESCRIPTION This function creates a new runspace pool with the specified minimum and maximum runspaces. It allows for concurrent execution of PowerShell scripts. .PARAMETER minRunspaces The minimum number of runspaces to be created in the runspace pool. Default is 1. .PARAMETER maxRunspaces The maximum number of runspaces to be created in the runspace pool. Default is the number of processors plus 1. .EXAMPLE $pool = New-Runspace -minRunspaces 2 -maxRunspaces 5 Creates a runspace pool with a minimum of 2 and a maximum of 5 runspaces. .EXAMPLE $pool = New-Runspace Creates a runspace pool with default minimum and maximum runspaces. #> [cmdletbinding()] param ( [int] $minRunspaces = 1, [int] $maxRunspaces = [int]$env:NUMBER_OF_PROCESSORS + 1 ) $RunspacePool = [RunspaceFactory]::CreateRunspacePool($minRunspaces, $maxRunspaces) $RunspacePool.Open() return $RunspacePool } function Send-Email { <# .SYNOPSIS Sends an email with specified parameters. .DESCRIPTION This function sends an email using the provided parameters. It supports sending emails with attachments and inline attachments. .PARAMETER Email Specifies the email parameters including sender, recipients, server settings, and encoding. .PARAMETER Body Specifies the body of the email. .PARAMETER Attachment Specifies an array of file paths to be attached to the email. .PARAMETER InlineAttachments Specifies a dictionary of inline attachments to be included in the email. .PARAMETER Subject Specifies the subject of the email. .PARAMETER To Specifies an array of email addresses to send the email to. .PARAMETER Logger Specifies a custom object for logging purposes. .EXAMPLE Send-Email -Email $EmailParams -Body "Hello, this is a test email" -Attachment "C:\Files\attachment.txt" -Subject "Test Email" -To "recipient@example.com" -Logger $Logger .EXAMPLE $EmailParams = @{ From = "sender@example.com" To = "recipient@example.com" Subject = "Test Email" Body = "Hello, this is a test email" Server = "smtp.example.com" Port = 587 Password = "password" Encoding = "UTF8" } Send-Email -Email $EmailParams -Attachment "C:\Files\attachment.txt" -To "recipient@example.com" -Logger $Logger #> [CmdletBinding(SupportsShouldProcess = $true)] param ( [alias('EmailParameters')][System.Collections.IDictionary] $Email, [string] $Body, [string[]] $Attachment, [System.Collections.IDictionary] $InlineAttachments, [string] $Subject, [string[]] $To, [PSCustomObject] $Logger ) try { if ($Email.EmailTo) { $EmailParameters = $Email.Clone() $EmailParameters.EmailEncoding = $EmailParameters.EmailEncoding -replace "-", '' $EmailParameters.EmailEncodingSubject = $EmailParameters.EmailEncodingSubject -replace "-", '' $EmailParameters.EmailEncodingBody = $EmailParameters.EmailEncodingSubject -replace "-", '' $EmailParameters.EmailEncodingAlternateView = $EmailParameters.EmailEncodingAlternateView -replace "-", '' } else { $EmailParameters = @{ EmailFrom = $Email.From EmailTo = $Email.To EmailCC = $Email.CC EmailBCC = $Email.BCC EmailReplyTo = $Email.ReplyTo EmailServer = $Email.Server EmailServerPassword = $Email.Password EmailServerPasswordAsSecure = $Email.PasswordAsSecure EmailServerPasswordFromFile = $Email.PasswordFromFile EmailServerPort = $Email.Port EmailServerLogin = $Email.Login EmailServerEnableSSL = $Email.EnableSsl EmailEncoding = $Email.Encoding -replace "-", '' EmailEncodingSubject = $Email.EncodingSubject -replace "-", '' EmailEncodingBody = $Email.EncodingBody -replace "-", '' EmailEncodingAlternateView = $Email.EncodingAlternateView -replace "-", '' EmailSubject = $Email.Subject EmailPriority = $Email.Priority EmailDeliveryNotifications = $Email.DeliveryNotifications EmailUseDefaultCredentials = $Email.UseDefaultCredentials } } } catch { return @{ Status = $False Error = $($_.Exception.Message) SentTo = '' } } $SmtpClient = [System.Net.Mail.SmtpClient]::new() if ($EmailParameters.EmailServer) { $SmtpClient.Host = $EmailParameters.EmailServer } else { return @{ Status = $False Error = "Email Server Host is not set." SentTo = '' } } if ($EmailParameters.EmailServerPort) { $SmtpClient.Port = $EmailParameters.EmailServerPort } else { return @{ Status = $False Error = "Email Server Port is not set." SentTo = '' } } if ($EmailParameters.EmailServerLogin) { $Credentials = Request-Credentials -UserName $EmailParameters.EmailServerLogin ` -Password $EmailParameters.EmailServerPassword ` -AsSecure:$EmailParameters.EmailServerPasswordAsSecure ` -FromFile:$EmailParameters.EmailServerPasswordFromFile ` -NetworkCredentials $SmtpClient.Credentials = $Credentials } if ($EmailParameters.EmailServerEnableSSL) { $SmtpClient.EnableSsl = $EmailParameters.EmailServerEnableSSL } $MailMessage = [System.Net.Mail.MailMessage]::new() $MailMessage.From = $EmailParameters.EmailFrom if ($To) { foreach ($T in $To) { $MailMessage.To.add($($T)) } } else { if ($EmailParameters.Emailto) { foreach ($To in $EmailParameters.Emailto) { $MailMessage.To.add($($To)) } } } if ($EmailParameters.EmailCC) { foreach ($CC in $EmailParameters.EmailCC) { $MailMessage.CC.add($($CC)) } } if ($EmailParameters.EmailBCC) { foreach ($BCC in $EmailParameters.EmailBCC) { $MailMessage.BCC.add($($BCC)) } } if ($EmailParameters.EmailReplyTo) { $MailMessage.ReplyTo = $EmailParameters.EmailReplyTo } $MailMessage.IsBodyHtml = $true if ($Subject -eq '') { $MailMessage.Subject = $EmailParameters.EmailSubject } else { $MailMessage.Subject = $Subject } $MailMessage.Priority = [System.Net.Mail.MailPriority]::$($EmailParameters.EmailPriority) if ($EmailParameters.EmailEncodingSubject) { $MailMessage.SubjectEncoding = [System.Text.Encoding]::$($EmailParameters.EmailEncodingSubject) } elseif ($EmailParameters.EmailEncoding) { $MailMessage.SubjectEncoding = [System.Text.Encoding]::$($EmailParameters.EmailEncoding) } if ($EmailParameters.EmailEncodingBody) { $MailMessage.BodyEncoding = [System.Text.Encoding]::$($EmailParameters.EmailEncodingBody) } elseif ($EmailParameters.EmailEncoding) { $MailMessage.BodyEncoding = [System.Text.Encoding]::$($EmailParameters.EmailEncoding) } if ($EmailParameters.EmailUseDefaultCredentials) { $SmtpClient.UseDefaultCredentials = $EmailParameters.EmailUseDefaultCredentials } if ($EmailParameters.EmailDeliveryNotifications) { $MailMessage.DeliveryNotificationOptions = $EmailParameters.EmailDeliveryNotifications } if ($PSBoundParameters.ContainsKey('InlineAttachments')) { if ($EmailParameters.EmailEncodingAlternateView) { $BodyPart = [Net.Mail.AlternateView]::CreateAlternateViewFromString($Body, [System.Text.Encoding]::$($EmailParameters.EmailEncodingAlternateView) , 'text/html' ) } else { $BodyPart = [Net.Mail.AlternateView]::CreateAlternateViewFromString($Body, [System.Text.Encoding]::UTF8, 'text/html' ) } $MailMessage.AlternateViews.Add($BodyPart) foreach ($Entry in $InlineAttachments.GetEnumerator()) { try { $FilePath = $Entry.Value Write-Verbose $FilePath if ($Entry.Value.StartsWith('http', [System.StringComparison]::CurrentCultureIgnoreCase)) { $FileName = $Entry.Value.Substring($Entry.Value.LastIndexOf("/") + 1) $FilePath = Join-Path $env:temp $FileName Invoke-WebRequest -Uri $Entry.Value -OutFile $FilePath } $ContentType = Get-MimeType -FileName $FilePath $InAttachment = [Net.Mail.LinkedResource]::new($FilePath, $ContentType ) $InAttachment.ContentId = $Entry.Key $BodyPart.LinkedResources.Add( $InAttachment ) } catch { $ErrorMessage = $_.Exception.Message -replace "`n", " " -replace "`r", " " Write-Error "Error inlining attachments: $ErrorMessage" } } } else { $MailMessage.Body = $Body } if ($PSBoundParameters.ContainsKey('Attachment')) { foreach ($Attach in $Attachment) { if (Test-Path -LiteralPath $Attach) { try { $File = [Net.Mail.Attachment]::new($Attach) $MailMessage.Attachments.Add($File) } catch { $ErrorMessage = $_.Exception.Message -replace "`n", " " -replace "`r", " " if ($Logger) { $Logger.AddErrorRecord("Error attaching file $Attach`: $ErrorMessage") } else { Write-Error "Error attaching file $Attach`: $ErrorMessage" } } } } } try { $MailSentTo = "$($MailMessage.To) $($MailMessage.CC) $($MailMessage.BCC)".Trim() if ($pscmdlet.ShouldProcess("$MailSentTo", "Send-Email")) { $SmtpClient.Send($MailMessage) $MailMessage.Dispose(); return [PSCustomObject] @{ Status = $True Error = "" SentTo = $MailSentTo } } else { return [PSCustomObject] @{ Status = $False Error = 'Email not sent (WhatIf)' SentTo = $MailSentTo } } } catch { $MailMessage.Dispose(); return [PSCustomObject] @{ Status = $False Error = $($_.Exception.Message) SentTo = "" } } } function Start-Runspace { <# .SYNOPSIS Starts a new runspace with the provided script block, parameters, and runspace pool. .DESCRIPTION This function creates a new runspace using the specified script block, parameters, and runspace pool. It then starts the runspace and returns an object containing the runspace and its status. .PARAMETER ScriptBlock The script block to be executed in the new runspace. .PARAMETER Parameters The parameters to be passed to the script block. .PARAMETER RunspacePool The runspace pool in which the new runspace will be created. .EXAMPLE $scriptBlock = { Get-Process } $parameters = @{ Name = 'explorer.exe' } $runspacePool = [RunspaceFactory]::CreateRunspacePool(1, 5) $runspacePool.Open() $result = Start-Runspace -ScriptBlock $scriptBlock -Parameters $parameters -RunspacePool $runspacePool $result.Pipe | Receive-Job -Wait This example starts a new runspace that retrieves information about the 'explorer.exe' process. #> [cmdletbinding()] param ( [ScriptBlock] $ScriptBlock, [System.Collections.IDictionary] $Parameters, [System.Management.Automation.Runspaces.RunspacePool] $RunspacePool ) if ($ScriptBlock -ne '') { $runspace = [PowerShell]::Create() $null = $runspace.AddScript($ScriptBlock) if ($null -ne $Parameters) { $null = $runspace.AddParameters($Parameters) } $runspace.RunspacePool = $RunspacePool [PSCustomObject]@{ Pipe = $runspace Status = $runspace.BeginInvoke() } } } function Stop-Runspace { <# .SYNOPSIS Stops and cleans up the specified runspaces. .DESCRIPTION This function stops and cleans up the specified runspaces by checking their status and handling any errors, warnings, and verbose messages. It also provides an option for extended output. .PARAMETER Runspaces Specifies the array of runspaces to stop. .PARAMETER FunctionName Specifies the name of the function associated with the runspaces. .PARAMETER RunspacePool Specifies the runspace pool to close and dispose of. .PARAMETER ExtendedOutput Indicates whether to include extended output in the result. .EXAMPLE Stop-Runspace -Runspaces $runspaceArray -FunctionName "MyFunction" -RunspacePool $pool -ExtendedOutput Stops the specified runspaces in the $runspaceArray associated with the function "MyFunction" using the runspace pool $pool and includes extended output. #> [cmdletbinding()] param( [Array] $Runspaces, [string] $FunctionName, [System.Management.Automation.Runspaces.RunspacePool] $RunspacePool, [switch] $ExtendedOutput ) [Array] $List = While (@($Runspaces | Where-Object -FilterScript { $null -ne $_.Status }).count -gt 0) { foreach ($Runspace in $Runspaces | Where-Object { $_.Status.IsCompleted -eq $true }) { $Errors = foreach ($e in $($Runspace.Pipe.Streams.Error)) { Write-Error -ErrorRecord $e $e } foreach ($w in $($Runspace.Pipe.Streams.Warning)) { Write-Warning -Message $w } foreach ($v in $($Runspace.Pipe.Streams.Verbose)) { Write-Verbose -Message $v } if ($ExtendedOutput) { @{ Output = $Runspace.Pipe.EndInvoke($Runspace.Status) Errors = $Errors } } else { $Runspace.Pipe.EndInvoke($Runspace.Status) } $Runspace.Status = $null } } $RunspacePool.Close() $RunspacePool.Dispose() if ($List.Count -eq 1) { return , $List } else { return $List } } function Get-MimeType { <# .SYNOPSIS Get-MimeType function returns the MIME type of a file based on its extension. .DESCRIPTION This function takes a file name as input and returns the corresponding MIME type based on the file extension. .PARAMETER FileName Specifies the name of the file for which the MIME type needs to be determined. .EXAMPLE Get-MimeType -FileName "example.jpg" Returns "image/jpeg" as the MIME type for the file "example.jpg". .EXAMPLE Get-MimeType -FileName "example.png" Returns "image/png" as the MIME type for the file "example.png". #> [CmdletBinding()] param ( [Parameter(Mandatory = $true)] [string] $FileName ) $MimeMappings = @{ '.jpeg' = 'image/jpeg' '.jpg' = 'image/jpeg' '.png' = 'image/png' } $Extension = [System.IO.Path]::GetExtension( $FileName ) $ContentType = $MimeMappings[ $Extension ] if ([string]::IsNullOrEmpty($ContentType)) { return New-Object System.Net.Mime.ContentType } else { return New-Object System.Net.Mime.ContentType($ContentType) } } function Request-Credentials { <# .SYNOPSIS Requests credentials for authentication purposes. .DESCRIPTION The Request-Credentials function is used to prompt the user for credentials. It provides options to input the username and password directly, read the password from a file, convert the password to a secure string, and handle various error scenarios. .PARAMETER UserName Specifies the username for authentication. .PARAMETER Password Specifies the password for authentication. .PARAMETER AsSecure Indicates whether the password should be converted to a secure string. .PARAMETER FromFile Specifies whether the password should be read from a file. .PARAMETER Output Indicates whether the function should return output in case of errors. .PARAMETER NetworkCredentials Specifies if network credentials are being requested. .PARAMETER Service Specifies the service for which credentials are being requested. .EXAMPLE Request-Credentials -UserName 'JohnDoe' -Password 'P@ssw0rd' -AsSecure Requests credentials for the user 'JohnDoe' with the password 'P@ssw0rd' in a secure format. .EXAMPLE Request-Credentials -FromFile -Password 'C:\Credentials.txt' -Output -Service 'FTP' Reads the password from the file 'C:\Credentials.txt' and returns an error message if the file is unreadable for the FTP service. #> [CmdletBinding()] param( [string] $UserName, [string] $Password, [switch] $AsSecure, [switch] $FromFile, [switch] $Output, [switch] $NetworkCredentials, [string] $Service ) if ($FromFile) { if (($Password -ne '') -and (Test-Path $Password)) { Write-Verbose "Request-Credentials - Reading password from file $Password" $Password = Get-Content -Path $Password } else { if ($Output) { return @{ Status = $false; Output = $Service; Extended = 'File with password unreadable.' } } else { Write-Warning "Request-Credentials - Secure password from file couldn't be read. File not readable. Terminating." return } } } if ($AsSecure) { try { $NewPassword = $Password | ConvertTo-SecureString -ErrorAction Stop } catch { $ErrorMessage = $_.Exception.Message -replace "`n", " " -replace "`r", " " if ($ErrorMessage -like '*Key not valid for use in specified state*') { if ($Output) { return @{ Status = $false; Output = $Service; Extended = "Couldn't use credentials provided. Most likely using credentials from other user/session/computer." } } else { Write-Warning -Message "Request-Credentials - Couldn't use credentials provided. Most likely using credentials from other user/session/computer." return } } else { if ($Output) { return @{ Status = $false; Output = $Service; Extended = $ErrorMessage } } else { Write-Warning -Message "Request-Credentials - $ErrorMessage" return } } } } else { $NewPassword = $Password } if ($UserName -and $NewPassword) { if ($AsSecure) { $Credentials = New-Object System.Management.Automation.PSCredential($Username, $NewPassword) } else { Try { $SecurePassword = $Password | ConvertTo-SecureString -AsPlainText -Force -ErrorAction Stop } catch { $ErrorMessage = $_.Exception.Message -replace "`n", " " -replace "`r", " " if ($ErrorMessage -like '*Key not valid for use in specified state*') { if ($Output) { return @{ Status = $false; Output = $Service; Extended = "Couldn't use credentials provided. Most likely using credentials from other user/session/computer." } } else { Write-Warning -Message "Request-Credentials - Couldn't use credentials provided. Most likely using credentials from other user/session/computer." return } } else { if ($Output) { return @{ Status = $false; Output = $Service; Extended = $ErrorMessage } } else { Write-Warning -Message "Request-Credentials - $ErrorMessage" return } } } $Credentials = New-Object System.Management.Automation.PSCredential($Username, $SecurePassword) } } else { if ($Output) { return @{ Status = $false; Output = $Service; Extended = 'Username or/and Password is empty' } } else { Write-Warning -Message 'Request-Credentials - UserName or Password are empty.' return } } if ($NetworkCredentials) { return $Credentials.GetNetworkCredential() } else { return $Credentials } } function Set-EmailBody($TableData, $TableWelcomeMessage) { $body = @( "<p><i>$TableWelcomeMessage</i>" if ($($TableData | Measure-Object).Count -gt 0) { $TableData | ConvertTo-Html -Fragment | Out-String $body = $body -replace ' Added', "<font color=`"green`"><b> Added</b></font>" $body = $body -replace ' Removed', "<font color=`"red`"><b> Removed</b></font>" $body = $body -replace ' Deleted', "<font color=`"red`"><b> Deleted</b></font>" $body = $body -replace ' Changed', "<font color=`"blue`"><b> Changed</b></font>" $body = $body -replace ' Change', "<font color=`"blue`"><b> Change</b></font>" $body = $body -replace ' Disabled', "<font color=`"red`"><b> Disabled</b></font>" $body = $body -replace ' Enabled', "<font color=`"green`"><b> Enabled</b></font>" $body = $body -replace ' Locked out', "<font color=`"red`"><b> Locked out</b></font>" $body = $body -replace ' Lockouts', "<font color=`"red`"><b> Lockouts</b></font>" $body = $body -replace ' Unlocked', "<font color=`"green`"><b> Unlocked</b></font>" $body = $body -replace ' Reset', "<font color=`"blue`"><b> Reset</b></font>" '</p>' } else { '<br><i>No changes happend during that period.</i></p>' } ) return $body } function Set-EmailHead { [cmdletBinding()] param( [System.Collections.IDictionary] $FormattingOptions ) $head = @" <!DOCTYPE html> <head> <meta charset="utf-8" /> <meta content="width=device-width, initial-scale=1" name="viewport" /> <style> BODY { background-color: white; font-family: $($FormattingOptions.FontFamily); font-size: $($FormattingOptions.FontSize); } TABLE { border-width: 1px; border-style: solid; border-color: black; border-collapse: collapse; font-family: $($FormattingOptions.FontTableDataFamily); font-size: $($FormattingOptions.FontTableDataSize); } TH { border-width: 1px; padding: 3px; border-style: solid; border-color: black; background-color: #00297A; color: white; font-family: $($FormattingOptions.FontTableHeadingFamily); font-size: $($FormattingOptions.FontTableHeadingSize); } TR { font-family: $($FormattingOptions.FontTableDataFamily); font-size: $($FormattingOptions.FontTableDataSize); } UL { font-family: $($FormattingOptions.FontFamily); font-size: $($FormattingOptions.FontSize); } LI { font-family: $($FormattingOptions.FontFamily); font-size: $($FormattingOptions.FontSize); } TD { border-width: 1px; padding-right: 2px; padding-left: 2px; padding-top: 0px; padding-bottom: 0px; border-style: solid; border-color: black; background-color: white; font-family: $($FormattingOptions.FontTableDataFamily); font-size: $($FormattingOptions.FontTableDataSize); } H2 { font-family: $($FormattingOptions.FontHeadingFamily); font-size: $($FormattingOptions.FontHeadingSize); } P { font-family: $($FormattingOptions.FontFamily); font-size: $($FormattingOptions.FontSize); } </style> </head> "@ return $Head } function Set-EmailReportBranding { param( [alias('FormattingOptions')] $FormattingParameters ) if ($FormattingParameters.CompanyBranding.Link) { $Report = "<a style=`"text-decoration:none`" href=`"$($FormattingParameters.CompanyBranding.Link)`" class=`"clink logo-container`">" } else { $Report = '' } if ($FormattingParameters.CompanyBranding.Inline) { $Report += "<img width=<fix> height=<fix> src=`"cid:logo`" border=`"0`" class=`"company-logo`" alt=`"company-logo`"></a>" } else { $Report += "<img width=<fix> height=<fix> src=`"$($FormattingParameters.CompanyBranding.Logo)`" border=`"0`" class=`"company-logo`" alt=`"company-logo`"></a>" } if ($FormattingParameters.CompanyBranding.Width -ne "") { $Report = $Report -replace "width=<fix>", "width=$($FormattingParameters.CompanyBranding.Width)" } else { $Report = $Report -replace "width=<fix>", "" } if ($FormattingParameters.CompanyBranding.Height -ne "") { $Report = $Report -replace "height=<fix>", "height=$($FormattingParameters.CompanyBranding.Height)" } else { $Report = $Report -replace "height=<fix>", "" } return $Report } function Set-EmailReportDetails { param( $FormattingOptions, $ReportOptions, $TimeToGenerate ) $DateReport = Get-Date $Report = @( "<p style=`"background-color:white;font-family:$($FormattingOptions.FontFamily);font-size:$($FormattingOptions.FontSize)`">" "<strong>Report Time:</strong> $DateReport <br>" "<strong>Time to generate:</strong> $($TimeToGenerate.Hours) hours, $($TimeToGenerate.Minutes) minutes, $($TimeToGenerate.Seconds) seconds, $($TimeToGenerate.Milliseconds) milliseconds <br>" if ($PSVersionTable.Platform -ne 'Unix') { "<strong>Account Executing Report :</strong> $env:userdomain\$($env:username.toupper()) on $($env:ComputerName.toUpper()) <br>" } else { } '<strong>Checking for monitored IPs :</strong>' '<ul>' foreach ($ip in $ReportOptions.MonitoredIps.Values) { "<li>ip:</strong> $ip</li>" } '</ul>' '</p>' ) return $Report } [string[]] $Script:BlackLists = @( 'b.barracudacentral.org' 'spam.rbl.msrbl.net' 'zen.spamhaus.org' 'bl.deadbeef.com' 'bl.spamcop.net' 'blackholes.five-ten-sg.com' 'blacklist.woody.ch' 'bogons.cymru.com' 'cbl.abuseat.org' 'combined.abuse.ch' 'combined.rbl.msrbl.net' 'db.wpbl.info' 'dnsbl-1.uceprotect.net' 'dnsbl-2.uceprotect.net' 'dnsbl-3.uceprotect.net' 'dnsbl.cyberlogic.net' 'dnsbl.inps.de' 'drone.abuse.ch' 'drone.abuse.ch' 'duinv.aupads.org' 'dul.dnsbl.sorbs.net' 'dul.ru' 'dyna.spamrats.com' 'images.rbl.msrbl.net' 'ips.backscatterer.org' 'ix.dnsbl.manitu.net' 'korea.services.net' 'noptr.spamrats.com' 'ohps.dnsbl.net.au' 'omrs.dnsbl.net.au' 'orvedb.aupads.org' 'osps.dnsbl.net.au' 'osrs.dnsbl.net.au' 'owfs.dnsbl.net.au' 'owps.dnsbl.net.au' 'pbl.spamhaus.org' 'phishing.rbl.msrbl.net' 'probes.dnsbl.net.au' 'proxy.bl.gweep.ca' 'proxy.block.transip.nl' 'psbl.surriel.com' 'rbl.interserver.net' 'rdts.dnsbl.net.au' 'relays.bl.gweep.ca' 'relays.bl.kundenserver.de' 'relays.nether.net' 'residential.block.transip.nl' 'ricn.dnsbl.net.au' 'rmst.dnsbl.net.au' 'sbl.spamhaus.org' 'short.rbl.jp' 'spam.abuse.ch' 'spam.spamrats.com' 'spamlist.or.kr' 'spamrbl.imp.ch' 't3direct.dnsbl.net.au' 'ubl.lashback.com' 'ubl.unsubscore.com' 'virbl.bit.nl' 'virus.rbl.jp' 'virus.rbl.msrbl.net' 'wormrbl.imp.ch' 'xbl.spamhaus.org' ) $Script:ScriptBlockNetDNS = { param ( [string] $Server, [string] $IP, [bool] $QuickTimeout, [bool] $Verbose ) if ($Verbose) { $verbosepreference = 'continue' } $ReversedIP = ($IP -split '\.')[3..0] -join '.' $FQDN = "$ReversedIP.$Server" try { $DnsCheck = [Net.DNS]::GetHostAddresses($fqdn) } catch { $DnsCheck = $null } if ($null -ne $DnsCheck) { $ServerData = [PSCustomObject] @{ IP = $IP FQDN = $FQDN BlackList = $Server IsListed = if ($null -eq $DNSCheck.IPAddressToString) { $false } else { $true } Answer = $DnsCheck.IPAddressToString -join ', ' TTL = '' } } else { $ServerData = [PSCustomObject] @{ IP = $IP FQDN = $FQDN BlackList = $Server IsListed = $false Answer = "" TTL = '' } } return $ServerData } $Script:ScriptBlockResolveDNS = { param ( [string] $Server, [string] $IP, [bool] $QuickTimeout, [bool] $Verbose, [string[]] $DNSServer = '' ) if ($Verbose) { $verbosepreference = 'continue' } [string] $ReversedIP = ($IP -split '\.')[3..0] -join '.' [string] $FQDN = "$ReversedIP.$Server" [int] $Count = 0 [bool] $Loaded = $false Do { try { Import-Module -Name 'DnsClient' -Verbose:$false $Loaded = $true } catch { Write-Warning "DNSClient Import Error ($Server / $FQDN / $IP): $_. Retrying." } $Count++ if ($Loaded -eq $false -and $Count -eq 5) { Write-Warning "DNSClient Import failed. Skipping check on $Server / $FQDN / $IP" } } until ($Loaded -eq $false -or $Count -eq 5) if ($DNSServer -ne '') { $DnsCheck = Resolve-DnsName -Name $fqdn -ErrorAction SilentlyContinue -NoHostsFile -QuickTimeout:$QuickTimeout -Server $DNSServer -DnsOnly } else { $DnsCheck = Resolve-DnsName -Name $fqdn -ErrorAction SilentlyContinue -NoHostsFile -QuickTimeout:$QuickTimeout -DnsOnly } if ($null -ne $DnsCheck) { $ServerData = [PSCustomObject] @{ IP = $IP FQDN = $FQDN BlackList = $Server IsListed = if ($null -eq $DNSCheck.IpAddress) { $false } else { $true } Answer = $DnsCheck.IPAddress -join ', ' TTL = $DnsCheck.TTL -join ', ' } } else { $ServerData = [PSCustomObject] @{ IP = $IP FQDN = $FQDN BlackList = $Server IsListed = $false Answer = '' TTL = '' } } return $ServerData } $Script:ScriptBlockNetDNSSlow = { param ( [string[]] $Servers, [string[]] $IPs, [bool] $QuickTimeout, [bool] $Verbose ) if ($Verbose) { $verbosepreference = 'continue' } $Blacklisted = foreach ($Server in $Servers) { foreach ($IP in $IPS) { [string] $ReversedIP = ($IP -split '\.')[3..0] -join '.' [string] $FQDN = "$ReversedIP.$Server" try { $DnsCheck = [Net.DNS]::GetHostAddresses($FQDN) } catch { $DnsCheck = $null } if ($null -ne $DnsCheck) { [PSCustomObject] @{ IP = $ip FQDN = $fqdn BlackList = $server IsListed = if ($null -eq $DNSCheck.IPAddressToString) { $false } else { $true } Answer = $DnsCheck.IPAddressToString -join ', ' TTL = '' } } else { [PSCustomObject] @{ IP = $IP FQDN = $FQDN BlackList = $Server IsListed = $false Answer = '' TTL = '' } } } } return $Blacklisted } $Script:ScriptBlockResolveDNSSlow = { param ( [string[]] $Servers, [string[]] $IPs, [bool] $QuickTimeout, [bool] $Verbose, [string[]] $DNSServer = '' ) if ($Verbose) { $verbosepreference = 'continue' } $Blacklisted = foreach ($Server in $Servers) { foreach ($IP in $IPS) { $ReversedIP = ($IP -split '\.')[3..0] -join '.' $FQDN = "$ReversedIP.$Server" if ($DNSServer -ne '') { $DnsCheck = Resolve-DnsName -Name $fqdn -ErrorAction SilentlyContinue -NoHostsFile -QuickTimeout:$QuickTimeout -Server $DNSServer -DnsOnly } else { $DnsCheck = Resolve-DnsName -Name $fqdn -ErrorAction SilentlyContinue -NoHostsFile -QuickTimeout:$QuickTimeout -DnsOnly } if ($null -ne $DnsCheck) { [PSCustomObject] @{ IP = $IP FQDN = $FQDN BlackList = $Server IsListed = if ($null -eq $DNSCheck.IpAddress) { $false } else { $true } Answer = $DnsCheck.IPAddress -join ', ' TTL = $DnsCheck.TTL -join ', ' } } else { [PSCustomObject] @{ IP = $IP FQDN = $FQDN BlackList = $Server IsListed = $false Answer = '' TTL = '' } } } } return $Blacklisted } function Search-BlackList { <# .SYNOPSIS Search-Blacklist searches if particular IP is blacklisted on DNSBL Blacklists. .DESCRIPTION Long description .PARAMETER IPs Parameter description .PARAMETER BlacklistServers Parameter description .PARAMETER ReturnAll Parameter description .PARAMETER RunType Parameter description .PARAMETER SortBy Parameter description .PARAMETER SortDescending Parameter description .PARAMETER QuickTimeout Parameter description .PARAMETER MaxRunspaces Parameter description .PARAMETER ExtendedOutput Parameter description .EXAMPLE Search-BlackList -IP '89.25.253.1' | Format-Table .EXAMPLE Search-BlackList -IP '89.25.253.1' -SortBy Blacklist | Format-Table .EXAMPLE Search-BlackList -IP '89.25.253.1','195.55.55.55' -SortBy Ip -ReturnAll | Format-Table .NOTES General notes #> [cmdletbinding()] param ( [alias('IP')][string[]] $IPs, [string[]] $BlacklistServers = $Script:BlackLists, [switch] $ReturnAll, [ValidateSet('NoWorkflowAndRunSpaceNetDNS', 'NoWorkflowAndRunSpaceResolveDNS', 'RunSpaceWithResolveDNS', 'RunSpaceWithNetDNS', 'WorkflowResolveDNS', 'WorkflowWithNetDNS')] [string]$RunType, [ValidateSet('IP', 'BlackList', 'IsListed', 'Answer', 'FQDN')][string] $SortBy = 'IsListed', [switch] $SortDescending, [switch] $QuickTimeout, [int] $MaxRunspaces = 10, [string[]] $DNSServer = '', [switch] $ExtendedOutput ) if ($PSCmdlet.MyInvocation.BoundParameters["Verbose"].IsPresent) { $Verbose = $true } else { $Verbose = $false } if ($RunType -eq 'WorkflowResolveDNS') { Write-Warning 'Worflows are not supported anymore due to PowerShell 6 complaining. Please use other modes.' Exit } elseif ($RunType -eq 'WorkflowWithNetDNS') { Write-Warning 'Worflows are not supported anymore due to PowerShell 6 complaining. Please use other modes.' Exit } if ($RunType -eq '') { if ($PSVersionTable.Platform -eq 'Unix') { $RunType = 'RunSpaceWithNetDNS' } else { $RunType = 'RunSpaceWithResolveDNS' } } if ($PSVersionTable.Platform -eq 'Unix') { if ($RunType -eq 'RunSpaceWithResolveDNS') { $RunType = 'RunSpaceWithNetDNS' Write-Warning 'Search-BlackList - changing RunType to RunSpaceWithNetDNS since Resolve-DNSName is not available on Linux/MacOS' } elseif ($RunType -eq 'NoWorkflowAndRunSpaceResolveDNS') { $RunType = 'NoWorkflowAndRunSpaceNetDNS' Write-Warning 'Search-BlackList - changing RunType to RunSpaceWithNetDNS since Resolve-DNSName is not available on Linux/MacOS' } } if ($DNSServer -ne '' -and $RunType -like 'NetDNS') { Write-Warning 'Search-BlackList - Setting DNSServer is not supported for Net.DNS. Resetting to default values.' $DNSServer = '' } Write-Verbose "Search-Blacklist - Runtype: $RunType ReturnAll: $ReturnAll, SortBy: $SortBy MaxRunspaces: $MaxRunspaces SortDescending: $SortDescending" If ($RunType -eq 'NoWorkflowAndRunSpaceNetDNS') { $Table = Invoke-Command -ScriptBlock $Script:ScriptBlockNetDNSSlow -ArgumentList $BlacklistServers, $IPs, $QuickTimeout, $Verbose } elseif ($RunType -eq 'NoWorkflowAndRunSpaceResolveDNS') { $Table = Invoke-Command -ScriptBlock $Script:ScriptBlockResolveDNSSlow -ArgumentList $BlacklistServers, $IPs, $QuickTimeout, $Verbose, $DNSServer } elseif ($RunType -eq 'RunSpaceWithResolveDNS') { $pool = New-Runspace -maxRunspaces $maxRunspaces -Verbose:$Verbose $runspaces = foreach ($Server in $BlacklistServers) { foreach ($IP in $IPs) { $Parameters = @{ Server = $Server IP = $IP QuickTimeout = $QuickTimeout Verbose = $Verbose DNSServer = $DNSServer } Start-Runspace -ScriptBlock $Script:ScriptBlockResolveDNS -Parameters $Parameters -RunspacePool $pool -Verbose:$Verbose } } $Output = Stop-Runspace -Runspaces $runspaces -FunctionName 'Search-BlackList' -RunspacePool $pool -Verbose:$Verbose -ErrorAction Continue -ErrorVariable MyErrors -ExtendedOutput:$ExtendedOutput if ($ExtendedOutput) { $Output Exit } else { $Table = $Output } } elseif ($RunType -eq 'RunSpaceWithNetDNS') { $pool = New-Runspace -maxRunspaces $maxRunspaces -Verbose:$Verbose $runspaces = foreach ($server in $BlacklistServers) { foreach ($ip in $IPs) { $Parameters = @{ Server = $Server IP = $IP QuickTimeout = $QuickTimeout Verbose = $Verbose } Start-Runspace -ScriptBlock $Script:ScriptBlockNetDNS -Parameters $Parameters -RunspacePool $pool -Verbose:$Verbose } } $Output = Stop-Runspace -Runspaces $runspaces -FunctionName 'Search-BlackList' -RunspacePool $pool -Verbose:$Verbose -ExtendedOutput:$ExtendedOutput if ($ExtendedOutput) { $Output Exit } else { $Table = $Output } } if ($SortDescending -eq $true) { $Table = $Table | Sort-Object $SortBy -Descending } else { $Table = $Table | Sort-Object $SortBy } if ($ReturnAll -eq $true) { return $Table | Select-Object IP, FQDN, BlackList, IsListed, Answer, TTL } else { return $Table | Where-Object { $_.IsListed -eq $true } | Select-Object IP, FQDN, BlackList, IsListed, Answer, TTL } } function Start-ReportBlackLists { [cmdletbinding()] param( [System.Collections.IDictionary] $EmailParameters, [System.Collections.IDictionary] $FormattingParameters, [System.Collections.IDictionary] $ReportOptions, [switch] $OutputErrors ) $Errors = @{ Teams = $false Slack = $false Discord = $false } $TeamID = Format-FirstXChars -Text $ReportOptions.NotificationsTeams.TeamsID -NumberChars 25 $SlackID = Format-FirstXChars -Text $ReportOptions.NotificationsSlack.Uri -NumberChars 25 $DiscordID = Format-FirstXChars -Text $ReportOptions.NotificationsDiscord.Uri -NumberChars 25 Write-Verbose "Start-ReportBlackLists - TeamsID: $TeamID" Write-Verbose "Start-ReportBlackLists - SlackID: $SlackID" Write-Verbose "Start-ReportBlackLists - DiscordID: $DiscordID" $Ips = foreach ($ip in $ReportOptions.MonitoredIps.Values) { $ip } if ($null -eq $ReportOptions.NotificationsEmail) { $ReportOptions.NotificationsEmail = @{ Use = $true EmailPriorityWhenBlacklisted = $ReportOptions.EmailPriorityWhenBlacklisted EmailPriorityStandard = $ReportOptions.EmailPriorityStandard EmailAllResults = $ReportOptions.EmailAllResults EmailAlways = $ReportOptions.EmailAlways } } $Time = Measure-Command -Expression { if ($null -eq $ReportOptions.SortBy) { $ReportOptions.SortBy = 'IsListed' } if ($null -eq $ReportOptions.SortDescending) { $ReportOptions.SortDescending = $true } if ($ReportOptions.NotificationsEmail.EmailAllResults) { $BlackListCheck = Search-BlackList -IP $Ips -SortBy $ReportOptions.SortBy -SortDescending:$ReportOptions.SortDescending -ReturnAll -Verbose } else { $BlackListCheck = Search-BlackList -IP $Ips -SortBy $ReportOptions.SortBy -SortDescending:$ReportOptions.SortDescending -Verbose } } $EmailBody = @( Set-EmailHead -FormattingOptions $FormattingParameters Set-EmailReportBranding -FormattingOptions $FormattingParameters Set-EmailReportDetails -FormattingOptions $FormattingParameters -ReportOptions $ReportOptions -TimeToGenerate $Time Set-EmailBody -TableData $BlackListCheck -TableWelcomeMessage 'Following blacklisted servers' ) if ($BlackListCheck.IsListed -contains $true) { $EmailParameters.EmailPriority = $ReportOptions.NotificationsEmail.EmailPriorityWhenBlacklisted } else { $EmailParameters.EmailPriority = $ReportOptions.NotificationsEmail.EmailPriorityStandard } [string] $Email = $EmailBody | Out-String if ($ReportOptions.NotificationsEmail.Use) { if ($ReportOptions.NotificationsEmail.EmailAlways -eq $true -or $BlackListCheck.IsListed -contains $true) { if ($FormattingParameters.CompanyBranding.Inline) { $SendMail = Send-Email -EmailParameters $EmailParameters -Body $Email -InlineAttachments @{logo = $FormattingParameters.CompanyBranding.Logo } -Verbose } else { $SendMail = Send-Email -EmailParameters $EmailParameters -Body $Email } } } if ($BlackListCheck.IsListed -contains $true) { $BlackListLimited = $BlackListCheck | Where-Object { $_.IsListed -eq $true } if ($ReportOptions.NotificationsTeams.Use) { [string] $MessageTitle = $ReportOptions.NotificationsTeams.MessageTitle [string] $ActivityImageLink = $ReportOptions.NotificationsTeams.MessageImageLink [RGBColors] $Color = [RGBColors]::Red $Sections = @( foreach ($Server in $BlackListLimited) { [string] $ActivityTitle = "Blacklisted IP **$($Server.IP)**" if ($ReportOptions.NotificationsTeams.MessageButtons) { $Button1 = New-TeamsButton -Name "Check BlackList" -Link "https://mxtoolbox.com/SuperTool.aspx?action=blacklist%3a$($Server.Ip)&run=toolpage" $Button2 = New-TeamsButton -Name "Check SMTP" -Link "https://mxtoolbox.com/SuperTool.aspx?action=smtp%3a$($Server.Ip)&run=toolpage" New-TeamsSection ` -ActivityTitle $ActivityTitle ` -ActivitySubtitle "Found on blacklist **$($Server.Blacklist)**" ` -ActivityImageLink $ActivityImageLink ` -ActivityText "Everybody panic!" ` -Buttons $Button1, $Button2 } else { New-TeamsSection ` -ActivityTitle $ActivityTitle ` -ActivitySubtitle "Found on blacklist **$($Server.Blacklist)**" ` -ActivityImageLink $ActivityImageLink ` -ActivityText "Responses: $($Server.Answer)" } } ) try { $TeamsOutput = Send-TeamsMessage ` -Uri $ReportOptions.NotificationsTeams.TeamsID ` -MessageTitle $MessageTitle ` -Color $Color ` -Sections $Sections ` -Supress $false } catch { $ErrorMessage = $_.Exception.Message -replace "`n", " " -replace "`r", " " Write-Warning "Couldn't send to Teams - Error occured: $ErrorMessage" $Errors.Teams = $true } } if ($ReportOptions.NotificationsSlack.Use) { if (Get-Module -ListAvailable -Name PSSlack -ErrorAction SilentlyContinue) { Import-Module -Name PSSlack -Force -ErrorAction SilentlyContinue } else { Write-Warning "PSSlack module not found. Please install it using Install-Module -Name PSSlack" return } $MessageTitle = $ReportOptions.NotificationsSlack.MessageTitle [string] $ActivityImageLink = $ReportOptions.NotificationsSlack.MessageImageLink $Attachments = @( foreach ($Server in $BlackListLimited) { New-SlackMessageAttachment -Color $_PSSlackColorMap.red ` -Title "IP $($Server.IP) is Blacklisted" ` -TitleLink "https://mxtoolbox.com/SuperTool.aspx?action=blacklist%3a$($Server.Ip)&run=toolpage" ` -Text $ReportOptions.NotificationsSlack.MessageText ` -Pretext "Found on blacklist $($Server.Blacklist)" ` -Fallback 'Your client is bad' } ) try { $SlackOutput = New-SlackMessage -Attachments $Attachments ` -Channel $ReportOptions.NotificationsSlack.Channel ` -IconEmoji $ReportOptions.NotificationsSlack.MessageEmoji ` -AsUser ` -Username $ReportOptions.NotificationsSlack.MessageAsUser | ` Send-SlackMessage -Uri $ReportOptions.NotificationsSlack.URI } catch { $ErrorMessage = $_.Exception.Message -replace "`n", " " -replace "`r", " " Write-Warning "Couldn't send to Slack - Error occured: $ErrorMessage" $Errors.Slack = $true } } if ($ReportOptions.NotificationsDiscord.Use) { if ($null -eq $ReportOptions.NotificationsDiscord.MessageInline) { $ReportOptions.NotificationsDiscord.MessageInline = $false } try { $Facts = foreach ($Server in $BlackListLimited) { [string] $ActivityTitle = "Blacklisted IP $($Server.IP)" [string] $ActivityValue = "Found on blacklist $($Server.Blacklist)" New-DiscordFact -Name $ActivityTitle -Value $ActivityValue -Inline $ReportOptions.NotificationsDiscord.MessageInline } $Thumbnail = New-DiscordThumbnail -Url $ReportOptions.NotificationsDiscord.MessageImageLink $Author = New-DiscordAuthor -Name 'PSBlacklistChecker' -IconUrl $ReportOptions.NotificationsDiscord.MessageImageLink $Section = New-DiscordSection -Title $ReportOptions.NotificationsDiscord.MessageText ` -Description '' ` -Facts $Facts ` -Color $ReportOptions.NotificationsDiscord.MessageColor ` -Author $Author ` -Thumbnail $Thumbnail Send-DiscordMessage -WebHookUrl $ReportOptions.NotificationsDiscord.Uri ` -Sections $Section ` -AvatarName $ReportOptions.NotificationsDiscord.MessageAsUser ` -AvatarUrl $ReportOptions.NotificationsDiscord.MessageAsUserImage -Verbose } catch { $ErrorMessage = $_.Exception.Message -replace "`n", " " -replace "`r", " " Write-Warning "Couldn't send to Discord - Error occured: $ErrorMessage" $Errors.Discord = $true } } if ($OutputErrors) { return $Errors } } } Export-ModuleMember -Function @('Search-BlackList', 'Start-ReportBlackLists') -Alias @() -Cmdlet "*" # SIG # Begin signature block # MIItsQYJKoZIhvcNAQcCoIItojCCLZ4CAQExDzANBglghkgBZQMEAgEFADB5Bgor # BgEEAYI3AgEEoGswaTA0BgorBgEEAYI3AgEeMCYCAwEAAAQQH8w7YFlLCE63JNLG # KX7zUQIBAAIBAAIBAAIBAAIBADAxMA0GCWCGSAFlAwQCAQUABCCJIDmQvkWwAS+4 # qd3kI+rje2hI5iakW6TWUnyCJ3h0c6CCJrQwggWNMIIEdaADAgECAhAOmxiO+dAt # 5+/bUOIIQBhaMA0GCSqGSIb3DQEBDAUAMGUxCzAJBgNVBAYTAlVTMRUwEwYDVQQK # EwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20xJDAiBgNV # BAMTG0RpZ2lDZXJ0IEFzc3VyZWQgSUQgUm9vdCBDQTAeFw0yMjA4MDEwMDAwMDBa # Fw0zMTExMDkyMzU5NTlaMGIxCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdpQ2Vy # dCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20xITAfBgNVBAMTGERpZ2lD # ZXJ0IFRydXN0ZWQgUm9vdCBHNDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoC # ggIBAL/mkHNo3rvkXUo8MCIwaTPswqclLskhPfKK2FnC4SmnPVirdprNrnsbhA3E # MB/zG6Q4FutWxpdtHauyefLKEdLkX9YFPFIPUh/GnhWlfr6fqVcWWVVyr2iTcMKy # unWZanMylNEQRBAu34LzB4TmdDttceItDBvuINXJIB1jKS3O7F5OyJP4IWGbNOsF # xl7sWxq868nPzaw0QF+xembud8hIqGZXV59UWI4MK7dPpzDZVu7Ke13jrclPXuU1 # 5zHL2pNe3I6PgNq2kZhAkHnDeMe2scS1ahg4AxCN2NQ3pC4FfYj1gj4QkXCrVYJB # MtfbBHMqbpEBfCFM1LyuGwN1XXhm2ToxRJozQL8I11pJpMLmqaBn3aQnvKFPObUR # WBf3JFxGj2T3wWmIdph2PVldQnaHiZdpekjw4KISG2aadMreSx7nDmOu5tTvkpI6 # nj3cAORFJYm2mkQZK37AlLTSYW3rM9nF30sEAMx9HJXDj/chsrIRt7t/8tWMcCxB # YKqxYxhElRp2Yn72gLD76GSmM9GJB+G9t+ZDpBi4pncB4Q+UDCEdslQpJYls5Q5S # UUd0viastkF13nqsX40/ybzTQRESW+UQUOsxxcpyFiIJ33xMdT9j7CFfxCBRa2+x # q4aLT8LWRV+dIPyhHsXAj6KxfgommfXkaS+YHS312amyHeUbAgMBAAGjggE6MIIB # NjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBTs1+OC0nFdZEzfLmc/57qYrhwP # TzAfBgNVHSMEGDAWgBRF66Kv9JLLgjEtUYunpyGd823IDzAOBgNVHQ8BAf8EBAMC # AYYweQYIKwYBBQUHAQEEbTBrMCQGCCsGAQUFBzABhhhodHRwOi8vb2NzcC5kaWdp # Y2VydC5jb20wQwYIKwYBBQUHMAKGN2h0dHA6Ly9jYWNlcnRzLmRpZ2ljZXJ0LmNv # bS9EaWdpQ2VydEFzc3VyZWRJRFJvb3RDQS5jcnQwRQYDVR0fBD4wPDA6oDigNoY0 # aHR0cDovL2NybDMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0QXNzdXJlZElEUm9vdENB # LmNybDARBgNVHSAECjAIMAYGBFUdIAAwDQYJKoZIhvcNAQEMBQADggEBAHCgv0Nc # Vec4X6CjdBs9thbX979XB72arKGHLOyFXqkauyL4hxppVCLtpIh3bb0aFPQTSnov # Lbc47/T/gLn4offyct4kvFIDyE7QKt76LVbP+fT3rDB6mouyXtTP0UNEm0Mh65Zy # oUi0mcudT6cGAxN3J0TU53/oWajwvy8LpunyNDzs9wPHh6jSTEAZNUZqaVSwuKFW # juyk1T3osdz9HNj0d1pcVIxv76FQPfx2CWiEn2/K2yCNNWAcAgPLILCsWKAOQGPF # mCLBsln1VWvPJ6tsds5vIy30fnFqI2si/xK4VC0nftg62fC2h5b9W9FcrBjDTZ9z # twGpn1eqXijiuZQwggWQMIIDeKADAgECAhAFmxtXno4hMuI5B72nd3VcMA0GCSqG # SIb3DQEBDAUAMGIxCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMx # GTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20xITAfBgNVBAMTGERpZ2lDZXJ0IFRy # dXN0ZWQgUm9vdCBHNDAeFw0xMzA4MDExMjAwMDBaFw0zODAxMTUxMjAwMDBaMGIx # CzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3 # dy5kaWdpY2VydC5jb20xITAfBgNVBAMTGERpZ2lDZXJ0IFRydXN0ZWQgUm9vdCBH # NDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAL/mkHNo3rvkXUo8MCIw # aTPswqclLskhPfKK2FnC4SmnPVirdprNrnsbhA3EMB/zG6Q4FutWxpdtHauyefLK # EdLkX9YFPFIPUh/GnhWlfr6fqVcWWVVyr2iTcMKyunWZanMylNEQRBAu34LzB4Tm # dDttceItDBvuINXJIB1jKS3O7F5OyJP4IWGbNOsFxl7sWxq868nPzaw0QF+xembu # d8hIqGZXV59UWI4MK7dPpzDZVu7Ke13jrclPXuU15zHL2pNe3I6PgNq2kZhAkHnD # eMe2scS1ahg4AxCN2NQ3pC4FfYj1gj4QkXCrVYJBMtfbBHMqbpEBfCFM1LyuGwN1 # XXhm2ToxRJozQL8I11pJpMLmqaBn3aQnvKFPObURWBf3JFxGj2T3wWmIdph2PVld # QnaHiZdpekjw4KISG2aadMreSx7nDmOu5tTvkpI6nj3cAORFJYm2mkQZK37AlLTS # YW3rM9nF30sEAMx9HJXDj/chsrIRt7t/8tWMcCxBYKqxYxhElRp2Yn72gLD76GSm # M9GJB+G9t+ZDpBi4pncB4Q+UDCEdslQpJYls5Q5SUUd0viastkF13nqsX40/ybzT # QRESW+UQUOsxxcpyFiIJ33xMdT9j7CFfxCBRa2+xq4aLT8LWRV+dIPyhHsXAj6Kx # fgommfXkaS+YHS312amyHeUbAgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYD # VR0PAQH/BAQDAgGGMB0GA1UdDgQWBBTs1+OC0nFdZEzfLmc/57qYrhwPTzANBgkq # hkiG9w0BAQwFAAOCAgEAu2HZfalsvhfEkRvDoaIAjeNkaA9Wz3eucPn9mkqZucl4 # XAwMX+TmFClWCzZJXURj4K2clhhmGyMNPXnpbWvWVPjSPMFDQK4dUPVS/JA7u5iZ # aWvHwaeoaKQn3J35J64whbn2Z006Po9ZOSJTROvIXQPK7VB6fWIhCoDIc2bRoAVg # X+iltKevqPdtNZx8WorWojiZ83iL9E3SIAveBO6Mm0eBcg3AFDLvMFkuruBx8lbk # apdvklBtlo1oepqyNhR6BvIkuQkRUNcIsbiJeoQjYUIp5aPNoiBB19GcZNnqJqGL # FNdMGbJQQXE9P01wI4YMStyB0swylIQNCAmXHE/A7msgdDDS4Dk0EIUhFQEI6FUy # 3nFJ2SgXUE3mvk3RdazQyvtBuEOlqtPDBURPLDab4vriRbgjU2wGb2dVf0a1TD9u # KFp5JtKkqGKX0h7i7UqLvBv9R0oN32dmfrJbQdA75PQ79ARj6e/CVABRoIoqyc54 # zNXqhwQYs86vSYiv85KZtrPmYQ/ShQDnUBrkG5WdGaG5nLGbsQAe79APT0JsyQq8 # 7kP6OnGlyE0mpTX9iV28hWIdMtKgK1TtmlfB2/oQzxm3i0objwG2J5VT6LaJbVu8 # aNQj6ItRolb58KaAoNYes7wPD1N1KarqE3fk3oyBIa0HEEcRrYc9B9F1vM/zZn4w # ggauMIIElqADAgECAhAHNje3JFR82Ees/ShmKl5bMA0GCSqGSIb3DQEBCwUAMGIx # CzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3 # dy5kaWdpY2VydC5jb20xITAfBgNVBAMTGERpZ2lDZXJ0IFRydXN0ZWQgUm9vdCBH # NDAeFw0yMjAzMjMwMDAwMDBaFw0zNzAzMjIyMzU5NTlaMGMxCzAJBgNVBAYTAlVT # MRcwFQYDVQQKEw5EaWdpQ2VydCwgSW5jLjE7MDkGA1UEAxMyRGlnaUNlcnQgVHJ1 # c3RlZCBHNCBSU0E0MDk2IFNIQTI1NiBUaW1lU3RhbXBpbmcgQ0EwggIiMA0GCSqG # SIb3DQEBAQUAA4ICDwAwggIKAoICAQDGhjUGSbPBPXJJUVXHJQPE8pE3qZdRodbS # g9GeTKJtoLDMg/la9hGhRBVCX6SI82j6ffOciQt/nR+eDzMfUBMLJnOWbfhXqAJ9 # /UO0hNoR8XOxs+4rgISKIhjf69o9xBd/qxkrPkLcZ47qUT3w1lbU5ygt69OxtXXn # HwZljZQp09nsad/ZkIdGAHvbREGJ3HxqV3rwN3mfXazL6IRktFLydkf3YYMZ3V+0 # VAshaG43IbtArF+y3kp9zvU5EmfvDqVjbOSmxR3NNg1c1eYbqMFkdECnwHLFuk4f # sbVYTXn+149zk6wsOeKlSNbwsDETqVcplicu9Yemj052FVUmcJgmf6AaRyBD40Nj # gHt1biclkJg6OBGz9vae5jtb7IHeIhTZgirHkr+g3uM+onP65x9abJTyUpURK1h0 # QCirc0PO30qhHGs4xSnzyqqWc0Jon7ZGs506o9UD4L/wojzKQtwYSH8UNM/STKvv # mz3+DrhkKvp1KCRB7UK/BZxmSVJQ9FHzNklNiyDSLFc1eSuo80VgvCONWPfcYd6T # /jnA+bIwpUzX6ZhKWD7TA4j+s4/TXkt2ElGTyYwMO1uKIqjBJgj5FBASA31fI7tk # 42PgpuE+9sJ0sj8eCXbsq11GdeJgo1gJASgADoRU7s7pXcheMBK9Rp6103a50g5r # mQzSM7TNsQIDAQABo4IBXTCCAVkwEgYDVR0TAQH/BAgwBgEB/wIBADAdBgNVHQ4E # FgQUuhbZbU2FL3MpdpovdYxqII+eyG8wHwYDVR0jBBgwFoAU7NfjgtJxXWRM3y5n # P+e6mK4cD08wDgYDVR0PAQH/BAQDAgGGMBMGA1UdJQQMMAoGCCsGAQUFBwMIMHcG # CCsGAQUFBwEBBGswaTAkBggrBgEFBQcwAYYYaHR0cDovL29jc3AuZGlnaWNlcnQu # Y29tMEEGCCsGAQUFBzAChjVodHRwOi8vY2FjZXJ0cy5kaWdpY2VydC5jb20vRGln # aUNlcnRUcnVzdGVkUm9vdEc0LmNydDBDBgNVHR8EPDA6MDigNqA0hjJodHRwOi8v # Y3JsMy5kaWdpY2VydC5jb20vRGlnaUNlcnRUcnVzdGVkUm9vdEc0LmNybDAgBgNV # HSAEGTAXMAgGBmeBDAEEAjALBglghkgBhv1sBwEwDQYJKoZIhvcNAQELBQADggIB # AH1ZjsCTtm+YqUQiAX5m1tghQuGwGC4QTRPPMFPOvxj7x1Bd4ksp+3CKDaopafxp # wc8dB+k+YMjYC+VcW9dth/qEICU0MWfNthKWb8RQTGIdDAiCqBa9qVbPFXONASIl # zpVpP0d3+3J0FNf/q0+KLHqrhc1DX+1gtqpPkWaeLJ7giqzl/Yy8ZCaHbJK9nXzQ # cAp876i8dU+6WvepELJd6f8oVInw1YpxdmXazPByoyP6wCeCRK6ZJxurJB4mwbfe # Kuv2nrF5mYGjVoarCkXJ38SNoOeY+/umnXKvxMfBwWpx2cYTgAnEtp/Nh4cku0+j # Sbl3ZpHxcpzpSwJSpzd+k1OsOx0ISQ+UzTl63f8lY5knLD0/a6fxZsNBzU+2QJsh # IUDQtxMkzdwdeDrknq3lNHGS1yZr5Dhzq6YBT70/O3itTK37xJV77QpfMzmHQXh6 # OOmc4d0j/R0o08f56PGYX/sr2H7yRp11LB4nLCbbbxV7HhmLNriT1ObyF5lZynDw # N7+YAN8gFk8n+2BnFqFmut1VwDophrCYoCvtlUG3OtUVmDG0YgkPCr2B2RP+v6TR # 81fZvAT6gt4y3wSJ8ADNXcL50CN/AAvkdgIm2fBldkKmKYcJRyvmfxqkhQ/8mJb2 # VVQrH4D6wPIOK+XW+6kvRBVK5xMOHds3OBqhK/bt1nz8MIIGsDCCBJigAwIBAgIQ # CK1AsmDSnEyfXs2pvZOu2TANBgkqhkiG9w0BAQwFADBiMQswCQYDVQQGEwJVUzEV # MBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29t # MSEwHwYDVQQDExhEaWdpQ2VydCBUcnVzdGVkIFJvb3QgRzQwHhcNMjEwNDI5MDAw # MDAwWhcNMzYwNDI4MjM1OTU5WjBpMQswCQYDVQQGEwJVUzEXMBUGA1UEChMORGln # aUNlcnQsIEluYy4xQTA/BgNVBAMTOERpZ2lDZXJ0IFRydXN0ZWQgRzQgQ29kZSBT # aWduaW5nIFJTQTQwOTYgU0hBMzg0IDIwMjEgQ0ExMIICIjANBgkqhkiG9w0BAQEF # AAOCAg8AMIICCgKCAgEA1bQvQtAorXi3XdU5WRuxiEL1M4zrPYGXcMW7xIUmMJ+k # jmjYXPXrNCQH4UtP03hD9BfXHtr50tVnGlJPDqFX/IiZwZHMgQM+TXAkZLON4gh9 # NH1MgFcSa0OamfLFOx/y78tHWhOmTLMBICXzENOLsvsI8IrgnQnAZaf6mIBJNYc9 # URnokCF4RS6hnyzhGMIazMXuk0lwQjKP+8bqHPNlaJGiTUyCEUhSaN4QvRRXXegY # E2XFf7JPhSxIpFaENdb5LpyqABXRN/4aBpTCfMjqGzLmysL0p6MDDnSlrzm2q2AS # 4+jWufcx4dyt5Big2MEjR0ezoQ9uo6ttmAaDG7dqZy3SvUQakhCBj7A7CdfHmzJa # wv9qYFSLScGT7eG0XOBv6yb5jNWy+TgQ5urOkfW+0/tvk2E0XLyTRSiDNipmKF+w # c86LJiUGsoPUXPYVGUztYuBeM/Lo6OwKp7ADK5GyNnm+960IHnWmZcy740hQ83eR # Gv7bUKJGyGFYmPV8AhY8gyitOYbs1LcNU9D4R+Z1MI3sMJN2FKZbS110YU0/EpF2 # 3r9Yy3IQKUHw1cVtJnZoEUETWJrcJisB9IlNWdt4z4FKPkBHX8mBUHOFECMhWWCK # ZFTBzCEa6DgZfGYczXg4RTCZT/9jT0y7qg0IU0F8WD1Hs/q27IwyCQLMbDwMVhEC # AwEAAaOCAVkwggFVMBIGA1UdEwEB/wQIMAYBAf8CAQAwHQYDVR0OBBYEFGg34Ou2 # O/hfEYb7/mF7CIhl9E5CMB8GA1UdIwQYMBaAFOzX44LScV1kTN8uZz/nupiuHA9P # MA4GA1UdDwEB/wQEAwIBhjATBgNVHSUEDDAKBggrBgEFBQcDAzB3BggrBgEFBQcB # AQRrMGkwJAYIKwYBBQUHMAGGGGh0dHA6Ly9vY3NwLmRpZ2ljZXJ0LmNvbTBBBggr # BgEFBQcwAoY1aHR0cDovL2NhY2VydHMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0VHJ1 # c3RlZFJvb3RHNC5jcnQwQwYDVR0fBDwwOjA4oDagNIYyaHR0cDovL2NybDMuZGln # aWNlcnQuY29tL0RpZ2lDZXJ0VHJ1c3RlZFJvb3RHNC5jcmwwHAYDVR0gBBUwEzAH # BgVngQwBAzAIBgZngQwBBAEwDQYJKoZIhvcNAQEMBQADggIBADojRD2NCHbuj7w6 # mdNW4AIapfhINPMstuZ0ZveUcrEAyq9sMCcTEp6QRJ9L/Z6jfCbVN7w6XUhtldU/ # SfQnuxaBRVD9nL22heB2fjdxyyL3WqqQz/WTauPrINHVUHmImoqKwba9oUgYftzY # gBoRGRjNYZmBVvbJ43bnxOQbX0P4PpT/djk9ntSZz0rdKOtfJqGVWEjVGv7XJz/9 # kNF2ht0csGBc8w2o7uCJob054ThO2m67Np375SFTWsPK6Wrxoj7bQ7gzyE84FJKZ # 9d3OVG3ZXQIUH0AzfAPilbLCIXVzUstG2MQ0HKKlS43Nb3Y3LIU/Gs4m6Ri+kAew # Q3+ViCCCcPDMyu/9KTVcH4k4Vfc3iosJocsL6TEa/y4ZXDlx4b6cpwoG1iZnt5Lm # Tl/eeqxJzy6kdJKt2zyknIYf48FWGysj/4+16oh7cGvmoLr9Oj9FpsToFpFSi0HA # SIRLlk2rREDjjfAVKM7t8RhWByovEMQMCGQ8M4+uKIw8y4+ICw2/O/TOHnuO77Xr # y7fwdxPm5yg/rBKupS8ibEH5glwVZsxsDsrFhsP2JjMMB0ug0wcCampAMEhLNKhR # ILutG4UI4lkNbcoFUCvqShyepf2gpx8GdOfy1lKQ/a+FSCH5Vzu0nAPthkX0tGFu # v2jiJmCG6sivqf6UHedjGzqGVnhOMIIGwjCCBKqgAwIBAgIQBUSv85SdCDmmv9s/ # X+VhFjANBgkqhkiG9w0BAQsFADBjMQswCQYDVQQGEwJVUzEXMBUGA1UEChMORGln # aUNlcnQsIEluYy4xOzA5BgNVBAMTMkRpZ2lDZXJ0IFRydXN0ZWQgRzQgUlNBNDA5 # NiBTSEEyNTYgVGltZVN0YW1waW5nIENBMB4XDTIzMDcxNDAwMDAwMFoXDTM0MTAx # MzIzNTk1OVowSDELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDkRpZ2lDZXJ0LCBJbmMu # MSAwHgYDVQQDExdEaWdpQ2VydCBUaW1lc3RhbXAgMjAyMzCCAiIwDQYJKoZIhvcN # AQEBBQADggIPADCCAgoCggIBAKNTRYcdg45brD5UsyPgz5/X5dLnXaEOCdwvSKOX # ejsqnGfcYhVYwamTEafNqrJq3RApih5iY2nTWJw1cb86l+uUUI8cIOrHmjsvlmbj # aedp/lvD1isgHMGXlLSlUIHyz8sHpjBoyoNC2vx/CSSUpIIa2mq62DvKXd4ZGIX7 # ReoNYWyd/nFexAaaPPDFLnkPG2ZS48jWPl/aQ9OE9dDH9kgtXkV1lnX+3RChG4PB # uOZSlbVH13gpOWvgeFmX40QrStWVzu8IF+qCZE3/I+PKhu60pCFkcOvV5aDaY7Mu # 6QXuqvYk9R28mxyyt1/f8O52fTGZZUdVnUokL6wrl76f5P17cz4y7lI0+9S769Sg # LDSb495uZBkHNwGRDxy1Uc2qTGaDiGhiu7xBG3gZbeTZD+BYQfvYsSzhUa+0rRUG # FOpiCBPTaR58ZE2dD9/O0V6MqqtQFcmzyrzXxDtoRKOlO0L9c33u3Qr/eTQQfqZc # ClhMAD6FaXXHg2TWdc2PEnZWpST618RrIbroHzSYLzrqawGw9/sqhux7UjipmAmh # cbJsca8+uG+W1eEQE/5hRwqM/vC2x9XH3mwk8L9CgsqgcT2ckpMEtGlwJw1Pt7U2 # 0clfCKRwo+wK8REuZODLIivK8SgTIUlRfgZm0zu++uuRONhRB8qUt+JQofM604qD # y0B7AgMBAAGjggGLMIIBhzAOBgNVHQ8BAf8EBAMCB4AwDAYDVR0TAQH/BAIwADAW # BgNVHSUBAf8EDDAKBggrBgEFBQcDCDAgBgNVHSAEGTAXMAgGBmeBDAEEAjALBglg # hkgBhv1sBwEwHwYDVR0jBBgwFoAUuhbZbU2FL3MpdpovdYxqII+eyG8wHQYDVR0O # BBYEFKW27xPn783QZKHVVqllMaPe1eNJMFoGA1UdHwRTMFEwT6BNoEuGSWh0dHA6 # Ly9jcmwzLmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydFRydXN0ZWRHNFJTQTQwOTZTSEEy # NTZUaW1lU3RhbXBpbmdDQS5jcmwwgZAGCCsGAQUFBwEBBIGDMIGAMCQGCCsGAQUF # BzABhhhodHRwOi8vb2NzcC5kaWdpY2VydC5jb20wWAYIKwYBBQUHMAKGTGh0dHA6 # Ly9jYWNlcnRzLmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydFRydXN0ZWRHNFJTQTQwOTZT # SEEyNTZUaW1lU3RhbXBpbmdDQS5jcnQwDQYJKoZIhvcNAQELBQADggIBAIEa1t6g # qbWYF7xwjU+KPGic2CX/yyzkzepdIpLsjCICqbjPgKjZ5+PF7SaCinEvGN1Ott5s # 1+FgnCvt7T1IjrhrunxdvcJhN2hJd6PrkKoS1yeF844ektrCQDifXcigLiV4JZ0q # BXqEKZi2V3mP2yZWK7Dzp703DNiYdk9WuVLCtp04qYHnbUFcjGnRuSvExnvPnPp4 # 4pMadqJpddNQ5EQSviANnqlE0PjlSXcIWiHFtM+YlRpUurm8wWkZus8W8oM3NG6w # QSbd3lqXTzON1I13fXVFoaVYJmoDRd7ZULVQjK9WvUzF4UbFKNOt50MAcN7MmJ4Z # iQPq1JE3701S88lgIcRWR+3aEUuMMsOI5ljitts++V+wQtaP4xeR0arAVeOGv6wn # LEHQmjNKqDbUuXKWfpd5OEhfysLcPTLfddY2Z1qJ+Panx+VPNTwAvb6cKmx5Adza # ROY63jg7B145WPR8czFVoIARyxQMfq68/qTreWWqaNYiyjvrmoI1VygWy2nyMpqy # 0tg6uLFGhmu6F/3Ed2wVbK6rr3M66ElGt9V/zLY4wNjsHPW2obhDLN9OTH0eaHDA # dwrUAuBcYLso/zjlUlrWrBciI0707NMX+1Br/wd3H3GXREHJuEbTbDJ8WC9nR2Xl # G3O2mflrLAZG70Ee8PBf4NvZrZCARK+AEEGKMIIHXzCCBUegAwIBAgIQB8JSdCgU # otar/iTqF+XdLjANBgkqhkiG9w0BAQsFADBpMQswCQYDVQQGEwJVUzEXMBUGA1UE # ChMORGlnaUNlcnQsIEluYy4xQTA/BgNVBAMTOERpZ2lDZXJ0IFRydXN0ZWQgRzQg # Q29kZSBTaWduaW5nIFJTQTQwOTYgU0hBMzg0IDIwMjEgQ0ExMB4XDTIzMDQxNjAw # MDAwMFoXDTI2MDcwNjIzNTk1OVowZzELMAkGA1UEBhMCUEwxEjAQBgNVBAcMCU1p # a2/FgsOzdzEhMB8GA1UECgwYUHJ6ZW15c8WCYXcgS8WCeXMgRVZPVEVDMSEwHwYD # VQQDDBhQcnplbXlzxYJhdyBLxYJ5cyBFVk9URUMwggIiMA0GCSqGSIb3DQEBAQUA # A4ICDwAwggIKAoICAQCUmgeXMQtIaKaSkKvbAt8GFZJ1ywOH8SwxlTus4McyrWmV # OrRBVRQA8ApF9FaeobwmkZxvkxQTFLHKm+8knwomEUslca8CqSOI0YwELv5EwTVE # h0C/Daehvxo6tkmNPF9/SP1KC3c0l1vO+M7vdNVGKQIQrhxq7EG0iezBZOAiukNd # GVXRYOLn47V3qL5PwG/ou2alJ/vifIDad81qFb+QkUh02Jo24SMjWdKDytdrMXi0 # 235CN4RrW+8gjfRJ+fKKjgMImbuceCsi9Iv1a66bUc9anAemObT4mF5U/yQBgAuA # o3+jVB8wiUd87kUQO0zJCF8vq2YrVOz8OJmMX8ggIsEEUZ3CZKD0hVc3dm7cWSAw # 8/FNzGNPlAaIxzXX9qeD0EgaCLRkItA3t3eQW+IAXyS/9ZnnpFUoDvQGbK+Q4/bP # 0ib98XLfQpxVGRu0cCV0Ng77DIkRF+IyR1PcwVAq+OzVU3vKeo25v/rntiXCmCxi # W4oHYO28eSQ/eIAcnii+3uKDNZrI15P7VxDrkUIc6FtiSvOhwc3AzY+vEfivUkFK # RqwvSSr4fCrrkk7z2Qe72Zwlw2EDRVHyy0fUVGO9QMuh6E3RwnJL96ip0alcmhKA # BGoIqSW05nXdCUbkXmhPCTT5naQDuZ1UkAXbZPShKjbPwzdXP2b8I9nQ89VSgQID # AQABo4ICAzCCAf8wHwYDVR0jBBgwFoAUaDfg67Y7+F8Rhvv+YXsIiGX0TkIwHQYD # VR0OBBYEFHrxaiVZuDJxxEk15bLoMuFI5233MA4GA1UdDwEB/wQEAwIHgDATBgNV # HSUEDDAKBggrBgEFBQcDAzCBtQYDVR0fBIGtMIGqMFOgUaBPhk1odHRwOi8vY3Js # My5kaWdpY2VydC5jb20vRGlnaUNlcnRUcnVzdGVkRzRDb2RlU2lnbmluZ1JTQTQw # OTZTSEEzODQyMDIxQ0ExLmNybDBToFGgT4ZNaHR0cDovL2NybDQuZGlnaWNlcnQu # Y29tL0RpZ2lDZXJ0VHJ1c3RlZEc0Q29kZVNpZ25pbmdSU0E0MDk2U0hBMzg0MjAy # MUNBMS5jcmwwPgYDVR0gBDcwNTAzBgZngQwBBAEwKTAnBggrBgEFBQcCARYbaHR0 # cDovL3d3dy5kaWdpY2VydC5jb20vQ1BTMIGUBggrBgEFBQcBAQSBhzCBhDAkBggr # BgEFBQcwAYYYaHR0cDovL29jc3AuZGlnaWNlcnQuY29tMFwGCCsGAQUFBzAChlBo # dHRwOi8vY2FjZXJ0cy5kaWdpY2VydC5jb20vRGlnaUNlcnRUcnVzdGVkRzRDb2Rl # U2lnbmluZ1JTQTQwOTZTSEEzODQyMDIxQ0ExLmNydDAJBgNVHRMEAjAAMA0GCSqG # SIb3DQEBCwUAA4ICAQC3EeHXUPhpe31K2DL43Hfh6qkvBHyR1RlD9lVIklcRCR50 # ZHzoWs6EBlTFyohvkpclVCuRdQW33tS6vtKPOucpDDv4wsA+6zkJYI8fHouW6Tqa # 1W47YSrc5AOShIcJ9+NpNbKNGih3doSlcio2mUKCX5I/ZrzJBkQpJ0kYha/pUST2 # CbE3JroJf2vQWGUiI+J3LdiPNHmhO1l+zaQkSxv0cVDETMfQGZKKRVESZ6Fg61b0 # djvQSx510MdbxtKMjvS3ZtAytqnQHk1ipP+Rg+M5lFHrSkUlnpGa+f3nuQhxDb7N # 9E8hUVevxALTrFifg8zhslVRH5/Df/CxlMKXC7op30/AyQsOQxHW1uNx3tG1DMgi # zpwBasrxh6wa7iaA+Lp07q1I92eLhrYbtw3xC2vNIGdMdN7nd76yMIjdYnAn7r38 # wwtaJ3KYD0QTl77EB8u/5cCs3ShZdDdyg4K7NoJl8iEHrbqtooAHOMLiJpiL2i9Y # n8kQMB6/Q6RMO3IUPLuycB9o6DNiwQHf6Jt5oW7P09k5NxxBEmksxwNbmZvNQ65Z # n3exUAKqG+x31Egz5IZ4U/jPzRalElEIpS0rgrVg8R8pEOhd95mEzp5WERKFyXhe # 6nB6bSYHv8clLAV0iMku308rpfjMiQkqS3LLzfUJ5OHqtKKQNMLxz9z185UCszGC # BlMwggZPAgEBMH0waTELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDkRpZ2lDZXJ0LCBJ # bmMuMUEwPwYDVQQDEzhEaWdpQ2VydCBUcnVzdGVkIEc0IENvZGUgU2lnbmluZyBS # U0E0MDk2IFNIQTM4NCAyMDIxIENBMQIQB8JSdCgUotar/iTqF+XdLjANBglghkgB # ZQMEAgEFAKCBhDAYBgorBgEEAYI3AgEMMQowCKACgAChAoAAMBkGCSqGSIb3DQEJ # AzEMBgorBgEEAYI3AgEEMBwGCisGAQQBgjcCAQsxDjAMBgorBgEEAYI3AgEVMC8G # CSqGSIb3DQEJBDEiBCDGsVz0qbnxr6eBzgncuDK3G6E3ugUUIoedXCQmNFTs2DAN # BgkqhkiG9w0BAQEFAASCAgALBGKWIHinjw7rp4miU+CHIZ16L/Uv0eCC3lWG8etU # CySmuFzAiOEXpkix4tLzfC1sQD3HaIKdwCEc+Ns4RXVQvu3e+fH2RjbIH0/KNNS4 # OEsuUG9s1JVanwZoSADS+tcNuNzLgXuQhaJP3wfz3kT7HxKbmy6n2Ijxk6BUiZQV # wSoF2CQKV0Rqh2D7cGFnL/K2XH/Ws3dYFA/FaBzS8ogFLk70uRcgak/2ln/QjBTb # VDRKJTaLfbYuTb3JdN41Jjw9CnF0ybzVrQ1yIVGjtN4Tis90BhDPutRiOWrNCPaT # G7uFNX+FoI0ODjS/f/rzHHNyM9nvvci4iEhsRkLYMh6aqhrv+DeV7jsqHaXeD9uz # CpyDvEhhl2eJQQXz4/ICv1QyE8SE/2VYItEib3uM64qcUaZ0WiV90NapzWyEBTuK # gqvKdGM0m6U1MUN9h3xFgmb5afKJtuA2B7Mi9zxoU+5j7HAHoWV9uvjQ8ax6qgJ9 # TTUYIT54Vx/71qho2ACjyJeEpnAJ9OlGZ7RZemJXoFX1u4S2WMReTT05OUTS506Q # KMWFeUUyBBBXDHP7ZrgsO/HzS9wgTObAeyvn1B2kCn9LQEJsag6oF1n6SItgvSHK # 2+b1b0TZjB/d8rbytsIAy1G1p54tgMCvf9ECTe4OriqQfFlN0sBzH8ueb9SWVSPy # sqGCAyAwggMcBgkqhkiG9w0BCQYxggMNMIIDCQIBATB3MGMxCzAJBgNVBAYTAlVT # MRcwFQYDVQQKEw5EaWdpQ2VydCwgSW5jLjE7MDkGA1UEAxMyRGlnaUNlcnQgVHJ1 # c3RlZCBHNCBSU0E0MDk2IFNIQTI1NiBUaW1lU3RhbXBpbmcgQ0ECEAVEr/OUnQg5 # pr/bP1/lYRYwDQYJYIZIAWUDBAIBBQCgaTAYBgkqhkiG9w0BCQMxCwYJKoZIhvcN # AQcBMBwGCSqGSIb3DQEJBTEPFw0yNDA3MjExOTU4MTZaMC8GCSqGSIb3DQEJBDEi # BCCNdEfa8gVR5c51sBY+0fwb2BM6byBBch6j2yyXLxY1cjANBgkqhkiG9w0BAQEF # AASCAgCQ7V/tRe4+NX9EZCiL6DSv+6TVv3fpZbdkdrQOCFzC+Xw2INODKSQH06Cl # 52uFZXr4MN/LYDNScdyKBdW9CvzN8Kup1Zu/br+Tb6gNykdMf0MrJDNK3vBFdy8Q # AIwRzo7o4o05NAGbVTGOd9iACMdI712wKCFro5nbkUV9qzSk0W5a0b0B2kYhY1s8 # D6kKsskqUAST2ONxFncd3LGL6xuhiHV+X6X8vDqnRtcvgdnv86CDOGJcq2tV05sz # HJywFSM/CUypauS3YgWhQjOFz9qXevYRoz+ACVi/HoQL2ahUUKUm6qB0gnMPz860 # asvb8RWJdojZG8aBDYMbaCcy5KjccMG0cWdmnhAayE+5cF/WsI78sKmZq5dmrZdS # 7XPWt+l3N2MiEOIQIddarWnTPf0RpTvmnltLR81dRzPo2/fT7E7NrDwAaBTJ8Mtz # FbZLJq9IH/OcvkpOC+uD9zowesVsDikXrxekXRTUdaHglK87LCTr4ECSJ9O5q9Q7 # yISUnzT3p8RpbwWyTm+HCAnPrpoyCesS/jEF1UeU5/s7y9eCKkQApRn2zNX3eEuS # G3+J2woHVgvCUhHRdISnOyvA7QRcOkpN4hdY+A2Xm8TeeHMlyyZs933Xo/t30ecC # aN1RC1Ybe3LsYED6tCD3ed4xiMt0HBoUXK+cCqp4kpTNUIxJEg== # SIG # End signature block |