BreachWatch.ps1
#requires -Version 5.1 function Get-KeeperBreachWatchList { <# .SYNOPSIS Lists Keeper records flagged by BreachWatch that require attention (excludes ignored and good records). .DESCRIPTION Retrieves Keeper records in your vault that have been flagged by BreachWatch and require attention, including weak, breached, and changed passwords. This excludes records marked as "Good" or "Ignore" status. You can filter to only show records you own, include all records, and display results with numbering. .PARAMETER OwnedOnly Show only records owned by you. .PARAMETER All Show all BreachWatch-flagged records, even if there are more than 32 (default output is limited for readability). .PARAMETER Numbered Display a serial number column in the output. .EXAMPLE Get-KeeperBreachWatchList Lists up to 32 records in your vault that require BreachWatch attention (weak, breached, or changed passwords). .EXAMPLE Get-KeeperBreachWatchList -OwnedOnly Lists only the records you own that require BreachWatch attention. .EXAMPLE Get-KeeperBreachWatchList -All -Numbered Lists all BreachWatch-flagged records with a serial number column. .NOTES This function helps you quickly identify and review records in your Keeper vault that require attention due to password issues (weak, breached, or changed passwords). Records with "Good" or "Ignore" status are excluded from the results. #> [CmdletBinding()] param( [Parameter()][Switch]$OwnedOnly, [Parameter()][Switch]$All, [Parameter()][Switch]$Numbered, [Parameter()][string]$VaultContextVar = "Global:KeeperVaultContext" ) [KeeperSecurity.Vault.VaultOnline]$vault = getVault $recordUids = $vault.BreachWatchRecords() | Where-Object { $_.Status -ne "Ignore" -and $_.Status -ne "Good" } | Select-Object -ExpandProperty RecordUid $records = $vault.KeeperRecords | Where-Object { $recordUids -contains $_.Uid -and (-not $OwnedOnly -or $_.Owner) } if ($records.Count -gt 0) { $table = New-Object System.Collections.Generic.List[object] $index = 1 foreach ($r in $records | Sort-Object Title) { $row = if ($Numbered) { [PSCustomObject]@{ "S.No" = $index++ "Record UID" = $r.Uid "Title" = $r.Title "Description"= [KeeperSecurity.Utils.RecordTypesUtils]::KeeperRecordPublicInformation($r) } } else { [PSCustomObject]@{ "Record UID" = $r.Uid "Title" = $r.Title "Description"= [KeeperSecurity.Utils.RecordTypesUtils]::KeeperRecordPublicInformation($r) } } $table.Add($row) } $total = $table.Count if (-not $All.IsPresent -and $total -gt 32) { $table = $table[0..29] } $table | Format-Table -AutoSize if ($table.Count -lt $total) { Write-Host "" Write-Host "$($total - $table.Count) records skipped." } } else { Write-Host "No BreachWatch issues detected (excluding ignored records)" } $scannedUids = $vault.BreachWatchRecords() | Select-Object -ExpandProperty RecordUid $notScanned = $vault.KeeperRecords | Where-Object { $_.Owner -and ($scannedUids -notcontains $_.Uid) -and $_.GetType() -ne [KeeperSecurity.Vault.ApplicationRecord] } $hasPasswordsToScan = $false foreach ($record in $notScanned) { $loadedRecord = $null if ($vault.TryLoadKeeperRecord($record.Uid, [ref]$loadedRecord)) { $pw = Get-KeeperRecordPassword -Record $loadedRecord -Silent if ($pw) { $hasPasswordsToScan = $true break } } } if ($hasPasswordsToScan) { Write-Host "`nSome passwords in your vault have not been scanned.`nUse `"breachwatch scan`" to check against the Dark Web database." } } function Test-PasswordAgainstBreachWatch { <# .SYNOPSIS Checks passwords against the BreachWatch database for breaches. .DESCRIPTION Tests one or more passwords against Keeper's BreachWatch database to determine if they have been compromised in known data breaches. Passwords can be provided as parameters or entered securely via prompt. .PARAMETER Passwords One or more passwords (as SecureString) to check. If not provided, you will be prompted to enter a password securely. .PARAMETER ShowPassword Display the actual password in the results instead of masking it with asterisks. .EXAMPLE Test-PasswordAgainstBreachWatch Prompts for a password securely and checks it against the BreachWatch database. .EXAMPLE $pwd1 = ConvertTo-SecureString "password123" -AsPlainText -Force Test-PasswordAgainstBreachWatch -Passwords $pwd1 Checks the specified password against the BreachWatch database. .EXAMPLE $pwd = Read-Host "Enter password" -AsSecureString Test-PasswordAgainstBreachWatch -Passwords $pwd -ShowPassword Prompts for a password securely and displays the actual password in results. .NOTES This function requires an active Keeper vault session and a BreachWatch-enabled Enterprise account. Passwords are processed securely and are not stored or logged. #> [CmdletBinding()] param( [Parameter(ValueFromPipeline = $true)] [SecureString[]]$Passwords, [Parameter()] [Switch]$ShowPassword, [Parameter()] [string]$VaultContextVar = "Global:KeeperVaultContext" ) begin { [KeeperSecurity.Vault.VaultOnline]$vault = getVault $passwordList = New-Object System.Collections.Generic.List[string] } process { if ($Passwords) { foreach ($secPwd in $Passwords) { if ($null -ne $secPwd -and $secPwd.Length -gt 0) { $bstr = [System.Runtime.InteropServices.Marshal]::SecureStringToBSTR($secPwd) try { $password = [System.Runtime.InteropServices.Marshal]::PtrToStringBSTR($bstr) if (-not [string]::IsNullOrEmpty($password)) { $passwordList.Add($password) } } finally { [System.Runtime.InteropServices.Marshal]::ZeroFreeBSTR($bstr) } } } } } end { if ($vault.Auth.AuthContext.License.AccountType -ne 2) { Write-Host "BreachWatch is not available for this account type." Write-Host "BreachWatch requires an Enterprise license." return } if ($passwordList.Count -eq 0) { $securePassword = Read-Host "Password to Check" -AsSecureString if ($null -eq $securePassword -or $securePassword.Length -eq 0) { return } $bstr = [System.Runtime.InteropServices.Marshal]::SecureStringToBSTR($securePassword) try { $plainPassword = [System.Runtime.InteropServices.Marshal]::PtrToStringBSTR($bstr) if (-not [string]::IsNullOrEmpty($plainPassword)) { $passwordList.Add($plainPassword) } } finally { [System.Runtime.InteropServices.Marshal]::ZeroFreeBSTR($bstr) } } try { $initTask = [KeeperSecurity.BreachWatch.BreachWatch]::InitializeBreachWatch($vault.Auth) $initTask.Wait() if ([KeeperSecurity.BreachWatch.BreachWatch]::PasswordToken.Length -eq 0) { return } Write-Host "Scanning $($passwordList.Count) password(s)..." $passwordEntries = [System.Collections.Generic.List[ValueTuple[string, byte[]]]]::new() foreach ($password in $passwordList) { $tuple = [ValueTuple[string, byte[]]]::new($password, $null) $passwordEntries.Add($tuple) } $cancellationToken = [System.Threading.CancellationToken]::None $tasks = [KeeperSecurity.BreachWatch.BreachWatch]::ScanPasswordsAsync($passwordEntries, $cancellationToken) $tasks.Wait() $results = $tasks.Result $euids = New-Object System.Collections.Generic.List[byte[]] Write-Host "Processing $($results.Count) result(s)..." foreach ($result in $results) { $password = $result.Item1 $status = $result.Item2 if ($null -ne $status.Euid -and -not $status.Euid.IsEmpty) { $euids.Add($status.Euid.ToByteArray()) } $displayPassword = if ($ShowPassword) { $password } else { "*" * $password.Length } $statusText = if ($status.BreachDetected) { "WEAK" } else { "GOOD" } $score = [KeeperSecurity.BreachWatch.PasswordUtils]::PasswordScore($password) $strengthText = switch ($score) { { $_ -lt 40 } { "Very Weak" } { $_ -lt 60 } { "Weak" } { $_ -lt 80 } { "Fair" } { $_ -lt 90 } { "Good" } { $_ -ge 90 } { "Strong" } } Write-Host ("{0,16}: {1} | Strength: {2} (Score: {3})" -f $displayPassword, $statusText, $strengthText, $score) } if ($euids.Count -gt 0) { $deleteTask = [KeeperSecurity.BreachWatch.BreachWatch]::DeleteEuids($euids) $deleteTask.Wait() } } catch [KeeperSecurity.BreachWatch.BreachWatchException] { $ex = $_.Exception if ($ex.Message.Contains("Invalid payload")) { Write-Host "BreachWatch Invalid Payload Error: $($ex.Message)" Write-Host "" Write-Host "Attempting to re-initialize BreachWatch tokens..." try { $reinitTask = [KeeperSecurity.BreachWatch.BreachWatch]::ReInitializeBreachWatch($vault.Auth) $reinitTask.Wait() Write-Host "BreachWatch tokens re-initialized. Please try the command again." } catch { Write-Host "Failed to re-initialize BreachWatch tokens: $($_.Exception.Message)" Write-Host "This may indicate an account permissions issue or temporary server problem." } } else { Write-Host "BreachWatch error: $($ex.Message)" } } catch { Write-Host "Error scanning passwords: $($_.Exception.Message)" Write-Host "Exception type: $($_.Exception.GetType().FullName)" if ($_.Exception.InnerException) { Write-Host "Inner error: $($_.Exception.InnerException.Message)" Write-Host "Inner exception type: $($_.Exception.InnerException.GetType().FullName)" } } } } function Set-KeeperBreachWatchRecordIgnore { <# .SYNOPSIS Ignores BreachWatch records. .DESCRIPTION Sets one or more records' BreachWatch status to "Ignore", which excludes them from BreachWatch scanning and reporting. .PARAMETER RecordUids One or more record UIDs to ignore. .EXAMPLE Set-KeeperBreachWatchRecordIgnore -RecordUids "abc123def456" Ignores the record with the specified UID from breachwatch scan. .EXAMPLE Set-KeeperBreachWatchRecordIgnore -RecordUids "abc123def456", "xyz789ghi012" Ignores multiple records with the specified UIDs from breachwatch scan. .NOTES Usage: Set-KeeperBreachWatchRecordIgnore -RecordUids <record_uid1> [<record_uid2> ...] #> [CmdletBinding()] param( [Parameter(Mandatory = $true)] [string[]]$RecordUids, [Parameter()] [string]$VaultContextVar = "Global:KeeperVaultContext" ) [KeeperSecurity.Vault.VaultOnline]$vault = getVault if ($vault.Auth.AuthContext.License.AccountType -ne 2) { Write-Host "BreachWatch is not available for this account type." Write-Host "BreachWatch requires an Enterprise license." return } if ($RecordUids.Count -eq 0) { Write-Host "Record UID is required for 'ignore' command." Write-Host "Usage: Set-KeeperBreachWatchRecordIgnore -RecordUids <record_uid>" return } try { foreach ($recordUid in $RecordUids) { $record = $null if ($vault.TryLoadKeeperRecord($recordUid, [ref]$record)) { [KeeperSecurity.BreachWatch.BreachWatchIgnore]::IgnoreRecord($vault, $recordUid).GetAwaiter().GetResult() Write-Host "Record '$($record.Title)' (UID: $recordUid) has been ignored." } else { Write-Host "Record with UID '$recordUid' has not been found." } } } catch { Write-Host "Error ignoring record(s): $($_.Exception.Message)" } } function Get-KeeperIgnoredBreachWatchRecords { <# .SYNOPSIS Lists all BreachWatch records that are currently ignored. .DESCRIPTION Retrieves all records in your vault that have been marked as ignored in BreachWatch. This helps you review which records you've previously chosen to exclude from BreachWatch monitoring. .PARAMETER OwnedOnly Show only records owned by you. .PARAMETER Numbered Display a serial number column in the output. .EXAMPLE Get-KeeperIgnoredBreachWatchRecords Lists all ignored BreachWatch records. .EXAMPLE Get-KeeperIgnoredBreachWatchRecords -OwnedOnly -Numbered Lists only your ignored records with numbering. .NOTES This function helps you audit which records have been excluded from BreachWatch monitoring. #> [CmdletBinding()] param( [Parameter()][Switch]$OwnedOnly, [Parameter()][Switch]$Numbered, [Parameter()][string]$VaultContextVar = "Global:KeeperVaultContext" ) [KeeperSecurity.Vault.VaultOnline]$vault = getVault if ($vault.Auth.AuthContext.License.AccountType -ne 2) { Write-Host "BreachWatch is not available for this account type." Write-Host "BreachWatch requires an Enterprise license." return } $ignoredRecordUids = $vault.BreachWatchRecords() | Where-Object { $_.Status -eq "Ignore" } | Select-Object -ExpandProperty RecordUid if ($ignoredRecordUids.Count -eq 0) { Write-Host "No ignored BreachWatch records found." return } $records = $vault.KeeperRecords | Where-Object { $ignoredRecordUids -contains $_.Uid -and (-not $OwnedOnly -or $_.Owner) } if ($records.Count -gt 0) { $table = New-Object System.Collections.Generic.List[object] $index = 1 foreach ($r in $records | Sort-Object Title) { $row = if ($Numbered) { [PSCustomObject]@{ "S.No" = $index++ "Record UID" = $r.Uid "Title" = $r.Title "Description"= [KeeperSecurity.Utils.RecordTypesUtils]::KeeperRecordPublicInformation($r) "Status" = "Ignored" } } else { [PSCustomObject]@{ "Record UID" = $r.Uid "Title" = $r.Title "Description"= [KeeperSecurity.Utils.RecordTypesUtils]::KeeperRecordPublicInformation($r) "Status" = "Ignored" } } $table.Add($row) } $table | Format-Table -AutoSize Write-Host "Total ignored records: $($table.Count)" } else { Write-Host "No ignored BreachWatch records found for the specified criteria." } } Set-Alias -Name kbw -Value Get-KeeperBreachWatchList Set-Alias -Name kbwp -Value Test-PasswordAgainstBreachWatch Set-Alias -Name kbwi -Value Set-KeeperBreachWatchRecordIgnore Set-Alias -Name kbwig -Value Get-KeeperIgnoredBreachWatchRecords # SIG # Begin signature block # MIInvgYJKoZIhvcNAQcCoIInrzCCJ6sCAQExDzANBglghkgBZQMEAgEFADB5Bgor # BgEEAYI3AgEEoGswaTA0BgorBgEEAYI3AgEeMCYCAwEAAAQQH8w7YFlLCE63JNLG # KX7zUQIBAAIBAAIBAAIBAAIBADAxMA0GCWCGSAFlAwQCAQUABCA8NAII+VaLxcbC # uNkz1gsRV/lzSkaeFC/xqyGjKxpUQaCCITswggWNMIIEdaADAgECAhAOmxiO+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 # twGpn1eqXijiuZQwggawMIIEmKADAgECAhAIrUCyYNKcTJ9ezam9k67ZMA0GCSqG # SIb3DQEBDAUAMGIxCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMx # GTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20xITAfBgNVBAMTGERpZ2lDZXJ0IFRy # dXN0ZWQgUm9vdCBHNDAeFw0yMTA0MjkwMDAwMDBaFw0zNjA0MjgyMzU5NTlaMGkx # CzAJBgNVBAYTAlVTMRcwFQYDVQQKEw5EaWdpQ2VydCwgSW5jLjFBMD8GA1UEAxM4 # RGlnaUNlcnQgVHJ1c3RlZCBHNCBDb2RlIFNpZ25pbmcgUlNBNDA5NiBTSEEzODQg # MjAyMSBDQTEwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDVtC9C0Cit # eLdd1TlZG7GIQvUzjOs9gZdwxbvEhSYwn6SOaNhc9es0JAfhS0/TeEP0F9ce2vnS # 1WcaUk8OoVf8iJnBkcyBAz5NcCRks43iCH00fUyAVxJrQ5qZ8sU7H/Lvy0daE6ZM # swEgJfMQ04uy+wjwiuCdCcBlp/qYgEk1hz1RGeiQIXhFLqGfLOEYwhrMxe6TSXBC # Mo/7xuoc82VokaJNTIIRSFJo3hC9FFdd6BgTZcV/sk+FLEikVoQ11vkunKoAFdE3 # /hoGlMJ8yOobMubKwvSnowMOdKWvObarYBLj6Na59zHh3K3kGKDYwSNHR7OhD26j # q22YBoMbt2pnLdK9RBqSEIGPsDsJ18ebMlrC/2pgVItJwZPt4bRc4G/rJvmM1bL5 # OBDm6s6R9b7T+2+TYTRcvJNFKIM2KmYoX7BzzosmJQayg9Rc9hUZTO1i4F4z8ujo # 7AqnsAMrkbI2eb73rQgedaZlzLvjSFDzd5Ea/ttQokbIYViY9XwCFjyDKK05huzU # tw1T0PhH5nUwjewwk3YUpltLXXRhTT8SkXbev1jLchApQfDVxW0mdmgRQRNYmtwm # KwH0iU1Z23jPgUo+QEdfyYFQc4UQIyFZYIpkVMHMIRroOBl8ZhzNeDhFMJlP/2NP # TLuqDQhTQXxYPUez+rbsjDIJAsxsPAxWEQIDAQABo4IBWTCCAVUwEgYDVR0TAQH/ # BAgwBgEB/wIBADAdBgNVHQ4EFgQUaDfg67Y7+F8Rhvv+YXsIiGX0TkIwHwYDVR0j # BBgwFoAU7NfjgtJxXWRM3y5nP+e6mK4cD08wDgYDVR0PAQH/BAQDAgGGMBMGA1Ud # JQQMMAoGCCsGAQUFBwMDMHcGCCsGAQUFBwEBBGswaTAkBggrBgEFBQcwAYYYaHR0 # cDovL29jc3AuZGlnaWNlcnQuY29tMEEGCCsGAQUFBzAChjVodHRwOi8vY2FjZXJ0 # cy5kaWdpY2VydC5jb20vRGlnaUNlcnRUcnVzdGVkUm9vdEc0LmNydDBDBgNVHR8E # PDA6MDigNqA0hjJodHRwOi8vY3JsMy5kaWdpY2VydC5jb20vRGlnaUNlcnRUcnVz # dGVkUm9vdEc0LmNybDAcBgNVHSAEFTATMAcGBWeBDAEDMAgGBmeBDAEEATANBgkq # hkiG9w0BAQwFAAOCAgEAOiNEPY0Idu6PvDqZ01bgAhql+Eg08yy25nRm95RysQDK # r2wwJxMSnpBEn0v9nqN8JtU3vDpdSG2V1T9J9Ce7FoFFUP2cvbaF4HZ+N3HLIvda # qpDP9ZNq4+sg0dVQeYiaiorBtr2hSBh+3NiAGhEZGM1hmYFW9snjdufE5BtfQ/g+ # lP92OT2e1JnPSt0o618moZVYSNUa/tcnP/2Q0XaG3RywYFzzDaju4ImhvTnhOE7a # brs2nfvlIVNaw8rpavGiPttDuDPITzgUkpn13c5UbdldAhQfQDN8A+KVssIhdXNS # y0bYxDQcoqVLjc1vdjcshT8azibpGL6QB7BDf5WIIIJw8MzK7/0pNVwfiThV9zeK # iwmhywvpMRr/LhlcOXHhvpynCgbWJme3kuZOX956rEnPLqR0kq3bPKSchh/jwVYb # KyP/j7XqiHtwa+aguv06P0WmxOgWkVKLQcBIhEuWTatEQOON8BUozu3xGFYHKi8Q # xAwIZDwzj64ojDzLj4gLDb879M4ee47vtevLt/B3E+bnKD+sEq6lLyJsQfmCXBVm # zGwOysWGw/YmMwwHS6DTBwJqakAwSEs0qFEgu60bhQjiWQ1tygVQK+pKHJ6l/aCn # HwZ05/LWUpD9r4VIIflXO7ScA+2GRfS0YW6/aOImYIbqyK+p/pQd52MbOoZWeE4w # gga0MIIEnKADAgECAhANx6xXBf8hmS5AQyIMOkmGMA0GCSqGSIb3DQEBCwUAMGIx # CzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3 # dy5kaWdpY2VydC5jb20xITAfBgNVBAMTGERpZ2lDZXJ0IFRydXN0ZWQgUm9vdCBH # NDAeFw0yNTA1MDcwMDAwMDBaFw0zODAxMTQyMzU5NTlaMGkxCzAJBgNVBAYTAlVT # MRcwFQYDVQQKEw5EaWdpQ2VydCwgSW5jLjFBMD8GA1UEAxM4RGlnaUNlcnQgVHJ1 # c3RlZCBHNCBUaW1lU3RhbXBpbmcgUlNBNDA5NiBTSEEyNTYgMjAyNSBDQTEwggIi # MA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC0eDHTCphBcr48RsAcrHXbo0Zo # dLRRF51NrY0NlLWZloMsVO1DahGPNRcybEKq+RuwOnPhof6pvF4uGjwjqNjfEvUi # 6wuim5bap+0lgloM2zX4kftn5B1IpYzTqpyFQ/4Bt0mAxAHeHYNnQxqXmRinvuNg # xVBdJkf77S2uPoCj7GH8BLuxBG5AvftBdsOECS1UkxBvMgEdgkFiDNYiOTx4OtiF # cMSkqTtF2hfQz3zQSku2Ws3IfDReb6e3mmdglTcaarps0wjUjsZvkgFkriK9tUKJ # m/s80FiocSk1VYLZlDwFt+cVFBURJg6zMUjZa/zbCclF83bRVFLeGkuAhHiGPMvS # GmhgaTzVyhYn4p0+8y9oHRaQT/aofEnS5xLrfxnGpTXiUOeSLsJygoLPp66bkDX1 # ZlAeSpQl92QOMeRxykvq6gbylsXQskBBBnGy3tW/AMOMCZIVNSaz7BX8VtYGqLt9 # MmeOreGPRdtBx3yGOP+rx3rKWDEJlIqLXvJWnY0v5ydPpOjL6s36czwzsucuoKs7 # Yk/ehb//Wx+5kMqIMRvUBDx6z1ev+7psNOdgJMoiwOrUG2ZdSoQbU2rMkpLiQ6bG # RinZbI4OLu9BMIFm1UUl9VnePs6BaaeEWvjJSjNm2qA+sdFUeEY0qVjPKOWug/G6 # X5uAiynM7Bu2ayBjUwIDAQABo4IBXTCCAVkwEgYDVR0TAQH/BAgwBgEB/wIBADAd # BgNVHQ4EFgQU729TSunkBnx6yuKQVvYv1Ensy04wHwYDVR0jBBgwFoAU7NfjgtJx # XWRM3y5nP+e6mK4cD08wDgYDVR0PAQH/BAQDAgGGMBMGA1UdJQQMMAoGCCsGAQUF # BwMIMHcGCCsGAQUFBwEBBGswaTAkBggrBgEFBQcwAYYYaHR0cDovL29jc3AuZGln # aWNlcnQuY29tMEEGCCsGAQUFBzAChjVodHRwOi8vY2FjZXJ0cy5kaWdpY2VydC5j # b20vRGlnaUNlcnRUcnVzdGVkUm9vdEc0LmNydDBDBgNVHR8EPDA6MDigNqA0hjJo # dHRwOi8vY3JsMy5kaWdpY2VydC5jb20vRGlnaUNlcnRUcnVzdGVkUm9vdEc0LmNy # bDAgBgNVHSAEGTAXMAgGBmeBDAEEAjALBglghkgBhv1sBwEwDQYJKoZIhvcNAQEL # BQADggIBABfO+xaAHP4HPRF2cTC9vgvItTSmf83Qh8WIGjB/T8ObXAZz8OjuhUxj # aaFdleMM0lBryPTQM2qEJPe36zwbSI/mS83afsl3YTj+IQhQE7jU/kXjjytJgnn0 # hvrV6hqWGd3rLAUt6vJy9lMDPjTLxLgXf9r5nWMQwr8Myb9rEVKChHyfpzee5kH0 # F8HABBgr0UdqirZ7bowe9Vj2AIMD8liyrukZ2iA/wdG2th9y1IsA0QF8dTXqvcnT # mpfeQh35k5zOCPmSNq1UH410ANVko43+Cdmu4y81hjajV/gxdEkMx1NKU4uHQcKf # ZxAvBAKqMVuqte69M9J6A47OvgRaPs+2ykgcGV00TYr2Lr3ty9qIijanrUR3anzE # wlvzZiiyfTPjLbnFRsjsYg39OlV8cipDoq7+qNNjqFzeGxcytL5TTLL4ZaoBdqbh # OhZ3ZRDUphPvSRmMThi0vw9vODRzW6AxnJll38F0cuJG7uEBYTptMSbhdhGQDpOX # gpIUsWTjd6xpR6oaQf/DJbg3s6KCLPAlZ66RzIg9sC+NJpud/v4+7RWsWCiKi9EO # LLHfMR2ZyJ/+xhCx9yHbxtl5TPau1j/1MIDpMPx0LckTetiSuEtQvLsNz3Qbp7wG # WqbIiOWCnb5WqxL3/BAPvIXKUjPSxyZsq8WhbaM2tszWkPZPubdcMIIG7TCCBNWg # AwIBAgIQCoDvGEuN8QWC0cR2p5V0aDANBgkqhkiG9w0BAQsFADBpMQswCQYDVQQG # EwJVUzEXMBUGA1UEChMORGlnaUNlcnQsIEluYy4xQTA/BgNVBAMTOERpZ2lDZXJ0 # IFRydXN0ZWQgRzQgVGltZVN0YW1waW5nIFJTQTQwOTYgU0hBMjU2IDIwMjUgQ0Ex # MB4XDTI1MDYwNDAwMDAwMFoXDTM2MDkwMzIzNTk1OVowYzELMAkGA1UEBhMCVVMx # FzAVBgNVBAoTDkRpZ2lDZXJ0LCBJbmMuMTswOQYDVQQDEzJEaWdpQ2VydCBTSEEy # NTYgUlNBNDA5NiBUaW1lc3RhbXAgUmVzcG9uZGVyIDIwMjUgMTCCAiIwDQYJKoZI # hvcNAQEBBQADggIPADCCAgoCggIBANBGrC0Sxp7Q6q5gVrMrV7pvUf+GcAoB38o3 # zBlCMGMyqJnfFNZx+wvA69HFTBdwbHwBSOeLpvPnZ8ZN+vo8dE2/pPvOx/Vj8Tch # TySA2R4QKpVD7dvNZh6wW2R6kSu9RJt/4QhguSssp3qome7MrxVyfQO9sMx6ZAWj # FDYOzDi8SOhPUWlLnh00Cll8pjrUcCV3K3E0zz09ldQ//nBZZREr4h/GI6Dxb2Uo # yrN0ijtUDVHRXdmncOOMA3CoB/iUSROUINDT98oksouTMYFOnHoRh6+86Ltc5zjP # KHW5KqCvpSduSwhwUmotuQhcg9tw2YD3w6ySSSu+3qU8DD+nigNJFmt6LAHvH3KS # uNLoZLc1Hf2JNMVL4Q1OpbybpMe46YceNA0LfNsnqcnpJeItK/DhKbPxTTuGoX7w # JNdoRORVbPR1VVnDuSeHVZlc4seAO+6d2sC26/PQPdP51ho1zBp+xUIZkpSFA8vW # doUoHLWnqWU3dCCyFG1roSrgHjSHlq8xymLnjCbSLZ49kPmk8iyyizNDIXj//cOg # rY7rlRyTlaCCfw7aSUROwnu7zER6EaJ+AliL7ojTdS5PWPsWeupWs7NpChUk555K # 096V1hE0yZIXe+giAwW00aHzrDchIc2bQhpp0IoKRR7YufAkprxMiXAJQ1XCmnCf # gPf8+3mnAgMBAAGjggGVMIIBkTAMBgNVHRMBAf8EAjAAMB0GA1UdDgQWBBTkO/zy # Me39/dfzkXFjGVBDz2GM6DAfBgNVHSMEGDAWgBTvb1NK6eQGfHrK4pBW9i/USezL # TjAOBgNVHQ8BAf8EBAMCB4AwFgYDVR0lAQH/BAwwCgYIKwYBBQUHAwgwgZUGCCsG # AQUFBwEBBIGIMIGFMCQGCCsGAQUFBzABhhhodHRwOi8vb2NzcC5kaWdpY2VydC5j # b20wXQYIKwYBBQUHMAKGUWh0dHA6Ly9jYWNlcnRzLmRpZ2ljZXJ0LmNvbS9EaWdp # Q2VydFRydXN0ZWRHNFRpbWVTdGFtcGluZ1JTQTQwOTZTSEEyNTYyMDI1Q0ExLmNy # dDBfBgNVHR8EWDBWMFSgUqBQhk5odHRwOi8vY3JsMy5kaWdpY2VydC5jb20vRGln # aUNlcnRUcnVzdGVkRzRUaW1lU3RhbXBpbmdSU0E0MDk2U0hBMjU2MjAyNUNBMS5j # cmwwIAYDVR0gBBkwFzAIBgZngQwBBAIwCwYJYIZIAYb9bAcBMA0GCSqGSIb3DQEB # CwUAA4ICAQBlKq3xHCcEua5gQezRCESeY0ByIfjk9iJP2zWLpQq1b4URGnwWBdEZ # D9gBq9fNaNmFj6Eh8/YmRDfxT7C0k8FUFqNh+tshgb4O6Lgjg8K8elC4+oWCqnU/ # ML9lFfim8/9yJmZSe2F8AQ/UdKFOtj7YMTmqPO9mzskgiC3QYIUP2S3HQvHG1FDu # +WUqW4daIqToXFE/JQ/EABgfZXLWU0ziTN6R3ygQBHMUBaB5bdrPbF6MRYs03h4o # bEMnxYOX8VBRKe1uNnzQVTeLni2nHkX/QqvXnNb+YkDFkxUGtMTaiLR9wjxUxu2h # ECZpqyU1d0IbX6Wq8/gVutDojBIFeRlqAcuEVT0cKsb+zJNEsuEB7O7/cuvTQasn # M9AWcIQfVjnzrvwiCZ85EE8LUkqRhoS3Y50OHgaY7T/lwd6UArb+BOVAkg2oOvol # /DJgddJ35XTxfUlQ+8Hggt8l2Yv7roancJIFcbojBcxlRcGG0LIhp6GvReQGgMgY # xQbV1S3CrWqZzBt1R9xJgKf47CdxVRd/ndUlQ05oxYy2zRWVFjF7mcr4C34Mj3oc # CVccAvlKV9jEnstrniLvUxxVZE/rptb7IRE2lskKPIJgbaP5t2nGj/ULLi49xTcB # ZU8atufk+EMF/cWuiC7POGT75qaL6vdCvHlshtjdNXOCIUjsarfNZzCCB0kwggUx # oAMCAQICEAWjoxq4NU+fKJYdPQIHYbgwDQYJKoZIhvcNAQELBQAwaTELMAkGA1UE # BhMCVVMxFzAVBgNVBAoTDkRpZ2lDZXJ0LCBJbmMuMUEwPwYDVQQDEzhEaWdpQ2Vy # dCBUcnVzdGVkIEc0IENvZGUgU2lnbmluZyBSU0E0MDk2IFNIQTM4NCAyMDIxIENB # MTAeFw0yNDEyMzEwMDAwMDBaFw0yNTEyMzAyMzU5NTlaMIHRMRMwEQYLKwYBBAGC # NzwCAQMTAlVTMRkwFwYLKwYBBAGCNzwCAQITCERlbGF3YXJlMR0wGwYDVQQPDBRQ # cml2YXRlIE9yZ2FuaXphdGlvbjEQMA4GA1UEBRMHMzQwNzk4NTELMAkGA1UEBhMC # VVMxETAPBgNVBAgTCElsbGlub2lzMRAwDgYDVQQHEwdDaGljYWdvMR0wGwYDVQQK # ExRLZWVwZXIgU2VjdXJpdHkgSW5jLjEdMBsGA1UEAxMUS2VlcGVyIFNlY3VyaXR5 # IEluYy4wggGiMA0GCSqGSIb3DQEBAQUAA4IBjwAwggGKAoIBgQDO/6wXrwKVD/ly # Y5UsXcgEgAJyxUNa+DRVz6P0tEWk79TgmoQKRHkjeqMvtDsGyzZcGkHqKDmpzHGY # YeuP/nxfEswjBw3Pz7/GgbHdQdlyMP1U/jWsH49DcQF9c6Sj6f7T6mr5urJkQzDg # HjqO6i8cyLuvG0thJ6r0k9d+u7TKcYYIK1ZdxmCj4XQj3jQ0bJMIXgksSNnM0fKH # u5oLqNp1WmUeVRKuMWJDGcE7k+0TfBEeK+XKzkmyRcmm6e/UoGD+zcipg3GGelyd # ugH2bBA2a3uFYc2qjtK5fIuRwZlZgysFND2iKAFHcnrpbSGkuaHtBY3E4xra5AZf # ge0wrbzdSURPU5st7KZ6i8r5UYa1SXQyghqL0CiiZPOwQIyKIjUphF7NB9D2wdWW # DgOpuHHu/wTplGn5YmFgaq1h5h4saov4WuWSsSpWMRpYpA+KdVpTJgxAYYN0T6HV # tWeXhqvdmXsTBjlrHzkKd2IUw3TDgO7Y1j9l8wGnmxsQnjhDRKUCAwEAAaOCAgIw # ggH+MB8GA1UdIwQYMBaAFGg34Ou2O/hfEYb7/mF7CIhl9E5CMB0GA1UdDgQWBBTn # KL7CoOsQM8480ZplkEaWu6eOzDA9BgNVHSAENjA0MDIGBWeBDAEDMCkwJwYIKwYB # BQUHAgEWG2h0dHA6Ly93d3cuZGlnaWNlcnQuY29tL0NQUzAOBgNVHQ8BAf8EBAMC # B4AwEwYDVR0lBAwwCgYIKwYBBQUHAwMwgbUGA1UdHwSBrTCBqjBToFGgT4ZNaHR0 # cDovL2NybDMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0VHJ1c3RlZEc0Q29kZVNpZ25p # bmdSU0E0MDk2U0hBMzg0MjAyMUNBMS5jcmwwU6BRoE+GTWh0dHA6Ly9jcmw0LmRp # Z2ljZXJ0LmNvbS9EaWdpQ2VydFRydXN0ZWRHNENvZGVTaWduaW5nUlNBNDA5NlNI # QTM4NDIwMjFDQTEuY3JsMIGUBggrBgEFBQcBAQSBhzCBhDAkBggrBgEFBQcwAYYY # aHR0cDovL29jc3AuZGlnaWNlcnQuY29tMFwGCCsGAQUFBzAChlBodHRwOi8vY2Fj # ZXJ0cy5kaWdpY2VydC5jb20vRGlnaUNlcnRUcnVzdGVkRzRDb2RlU2lnbmluZ1JT # QTQwOTZTSEEzODQyMDIxQ0ExLmNydDAJBgNVHRMEAjAAMA0GCSqGSIb3DQEBCwUA # A4ICAQCyKgKBI5CmZbjIjn38FPlfsIipJg25SiGcpsrMxGaLfp4geoO7UV61pEKO # oJ/DhtqhuiDvC/qNFb8FtPldPKeoFam9I3kfZApu5A2ZNkZs3r4WQ60W2Y9EOym9 # 6SHg/ShLnEXxBdFBqoKdKu43qxVz8yrUJOZCaT+ubEkVe24ISDFraubHR5/4hlDI # /vBXfQBMauJEfnck8P+qdWRYmO6SL+GAI4w645MlDEqILeno/WBsEwvMlVybI2qy # 6thfrL8J/DZVPk9N1P2Y13P2cQ3OYN4qq5eRpvUAmi4RtmiyKxkVzefT3KJKeyRT # Wup5JFkkoIeMNNbc/sUUsoqilgFzbNpR0w9hfXHhpc/VMP0bz4T3JemyC6iXEekV # JM2bayhzSo/OTwZvyprq8dHKOcUcV7F7Bd7Zqdq/k7ddb3gPY3vqcs7qhP5EUD5+ # YRfHyEbnmoeyVTGmhwUzG0Wg3FRYqBpghh1Mdu9MoS2qQNHmF6WSb9J+tkCDKF/T # T3FthHMIS1hgFdSFvkyKP8XKawFwbVwjv5obHICJ2zM3rHYNLlrG6IsuB33kxMwn # vZXeeG4lCkyULuMKm85DeUhnsDik3f/nOJOcOss7lFrJN2GaY1qrIKU5QN81Ofdb # rzBbKtBWHQNz8vGLFWmy8E8c/Xe5KQQB0z0WMA3LCjSxjD3PujGCBdkwggXVAgEB # MH0waTELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDkRpZ2lDZXJ0LCBJbmMuMUEwPwYD # VQQDEzhEaWdpQ2VydCBUcnVzdGVkIEc0IENvZGUgU2lnbmluZyBSU0E0MDk2IFNI # QTM4NCAyMDIxIENBMQIQBaOjGrg1T58olh09AgdhuDANBglghkgBZQMEAgEFAKCB # hDAYBgorBgEEAYI3AgEMMQowCKACgAChAoAAMBkGCSqGSIb3DQEJAzEMBgorBgEE # AYI3AgEEMBwGCisGAQQBgjcCAQsxDjAMBgorBgEEAYI3AgEVMC8GCSqGSIb3DQEJ # BDEiBCDNWAV8i5A5HBXc0gldOoRO2MK/k6+Y+Z/mQ+9QPYCOtDANBgkqhkiG9w0B # AQEFAASCAYDA9ZYF6/ee5qxwNVB7nzXxtFdDjVAfNrq1WOkHTrxLopDsSIXNuRHg # R/ilpFSeUBidUPupbb5qhU/RoeRpFxQUpc2fOoa5xDTzaGDOpSamYNc/8G0Fsk3w # Dr94rhlnXUdKiEHXvD8dGhaFNI4yhoZdfS0acKj3hziSrWCqeiAWp9KCYBJKv+ds # hnW38zejdKacRPeWhtdWgSZMA491PLkaLx5DpSCUDZt/FK40MLeX2j6usUpt/tF6 # ljMcXltPhrNqA7/yT5ZU0SMVuWnGSMm4AMBWbFoB3j+gMhRwYuXbVNYKVt4kXB3w # SWFcpllqTVrwbkGYSYaimR8i6s4Hl0X3HSi73bDCIbKMbhofRwJm07TVLNu09j0G # SS22MLmqj+b40zjBJK1sF5YNXm9VRcvpFLZLHzf6EXoMbrrtFzKbx1rGQlU3eD1c # /U95JWRvo/zbx7yBtChX4GX2mPqPCM6vRBZbWXxDlG9m4V0QrOlGWaqpTzPiw5We # nKB0JVZY6XqhggMmMIIDIgYJKoZIhvcNAQkGMYIDEzCCAw8CAQEwfTBpMQswCQYD # VQQGEwJVUzEXMBUGA1UEChMORGlnaUNlcnQsIEluYy4xQTA/BgNVBAMTOERpZ2lD # ZXJ0IFRydXN0ZWQgRzQgVGltZVN0YW1waW5nIFJTQTQwOTYgU0hBMjU2IDIwMjUg # Q0ExAhAKgO8YS43xBYLRxHanlXRoMA0GCWCGSAFlAwQCAQUAoGkwGAYJKoZIhvcN # AQkDMQsGCSqGSIb3DQEHATAcBgkqhkiG9w0BCQUxDxcNMjUwOTMwMDQzODA2WjAv # BgkqhkiG9w0BCQQxIgQgOzzz/r5RFtKXKYiUQnNv8/+qKAXKhsRfTlYh9fzELmEw # DQYJKoZIhvcNAQEBBQAEggIANu/Kf9cumB17Y7St5x4wt+mcL/Gy3ObjIrQDuso7 # 84yt4uQ31O+EIrDxJZcNk2dmFF5wHHZ5iPI5aMX+EwZ14Em27yjvPflh0032j3/G # f0Cyb3xrqrjslAO7sOvC9WypdIwcX59iwjwBwv9z1ssaD+au0fNG8+Wp/K7Of8qs # 3vschrouC6XXzsnQEyJATAx3LGLKzEFuwq9fm1nDq0HM99C53RTqr8GUFjp4QqFh # C7HLzcRx7ZjR7yKYko/syyQps1tfl6VSFiM/v5zlcdmC2FvAxhx18gYjMfh7JKk3 # jbL5oKE6hci7AGh7xmHfFwJLYGOF9ZrhAwHIZm6oORpoiJsFtXHBHNK48OfloKEh # 50/fgsfK5coFtJdxzbx5tUhr7KN7klrZM2vUO6BMidHmWd9cC5v+iIHEXKCPU6K7 # /QX0gkumDIekZKu8FbNHD6T5A4Mka0fW+D6AHz1X3JvGvnDsMGopWo3R7IbqRRm7 # syFU/2i8G4yuG1py65x2wGoCl5TY9qX+5bMDPdTzlT3cmcAUT/KUq1vPguqwTE4H # ki83rNVfLCfm3tk74rxbV/2E9hnv8TSC5lN1smsYFuN0503wRKjEVVv907zbnR9Q # DfiAVIhDeC1CG1nlCXzo26HecBigVBbmg64A/ohz9zF+ndxfM8rs2U+wxiail5HF # OY4= # SIG # End signature block |