Public/Find-VcCertificate.ps1

function Find-VcCertificate {
    <#
    .SYNOPSIS
    Find certificates in TLSPC
 
    .DESCRIPTION
    Find certificates based on various attributes.
 
    .PARAMETER Name
    Search for certificates with the name matching part or all of the value
 
    .PARAMETER KeyLength
    Search by certificate key length
 
    .PARAMETER Serial
    Search by serial number
 
    .PARAMETER Fingerprint
    Search by fingerprint
 
    .PARAMETER IsSelfSigned
    Search for only self signed certificates
 
    .PARAMETER Status
    Search by one or more certificate statuses. Valid values include ACTIVE, RETIRED, and DELETED.
 
    .PARAMETER ExpireBefore
    Search for certificates expiring before a certain date.
    Use with -ExpireAfter for a defined start and end.
 
    .PARAMETER ExpireAfter
    Search for certificates expiring after a certain date.
    Use with -ExpireBefore for a defined start and end.
 
    .PARAMETER Version
    Search by version type. Valid values include CURRENT and OLD.
 
    .PARAMETER SanDns
    Search for certificates with SAN DNS matching part or all of the value
 
    .PARAMETER Application
    Application ID or name that this certificate is associated with
 
    .PARAMETER Tag
    One or more tags associated with the certificate.
    You can specify either just a tag name or name:value.
 
    .PARAMETER CN
    Search for certificates where the subject CN matches all of part of the value
 
    .PARAMETER Issuer
    Search by issuer name
 
    .PARAMETER Filter
    Array or multidimensional array of fields and values to filter on.
    Each array should be of the format @(field, comparison operator, value).
    To combine filters, use the format @('operator', @(field, comparison operator, value), @(field2, comparison operator2, value2)).
    Nested filters are supported.
    Field names and values are case sensitive, but VenafiPS will try and convert to the proper case if able.
 
    Available operators are:
 
    Operator | Name | Description and Usage
    -----------------------------------------------------------------------------------
    EQ Equal operator The search result is equal to the specified value. Valid for numeric or Boolean fields.
    FIND Find operator The search result is based on the value of all or part of one or more strings. You can also use Regular Expressions (regex).
    GT Greater than The search result has a higher numeric value than the specified value.
    GTE Greater than or equal to The search result is equal or has a higher numeric value than the specified value.
    IN In clause The search result matches one of the values in an array.
    LT Less Than The search result has a lower value than the specified value.
    LTE Less than or equal to The search result is equal or less than the specified value.
    MATCH Match operator The search result includes a string value from the supplied list. You can also use regex for your search.
 
    For more info comparison operators, see https://docs.venafi.cloud/api/about-api-search-operators/.
 
    .PARAMETER Order
    1 or more fields to order on.
    For each item in the array, you can provide a field name by itself; this will default to ascending.
    You can also provide a hashtable with the field name as the key and either asc or desc as the value.
 
    .PARAMETER SavedSearchName
    Find certificates based on a saved search, see https://docs.venafi.cloud/vaas/certificates/saving-certificate-filters
 
    .PARAMETER First
    Only retrieve this many records
 
    .PARAMETER ApplicationDetail
    Retrieve detailed application info.
    This will cause additional api calls to be made and take longer.
 
    .PARAMETER OwnerDetail
    Retrieve detailed user/team owner info.
    This will cause additional api calls to be made and take longer.
 
    .PARAMETER VenafiSession
    Authentication for the function.
    The value defaults to the script session object $VenafiSession created by New-VenafiSession.
    A TLSPC key can also provided.
 
    .INPUTS
    None
 
    .OUTPUTS
    PSCustomObject
 
    .EXAMPLE
    Find-VcCertificate
 
    Find all certificates
 
    .EXAMPLE
    Find-VcCertificate -First 500
 
    Find the first 500 certificates
 
    .EXAMPLE
    Find-VcCertificate -Name 'mycert.company.com'
 
    Find certificates matching all of part of the name
 
    .EXAMPLE
    Find-VcCertificate -Fingerprint '075C43428E70BCF941039F54B8ED78DE4FACA87F'
 
    Find certificates matching a single value
 
    .EXAMPLE
    Find-VcCertificate -ExpireAfter (get-date) -ExpireBefore (get-date).AddDays(30)
 
    Find certificates matching multiple values. In this case, find all certificates expiring in the next 30 days.
 
    .EXAMPLE
    Find-VcCertificate -ExpireAfter (get-date) -ExpireBefore (get-date).AddDays(30)| Invoke-VcCertificateAction -Renew
 
    Find all certificates expiring in the next 30 days and renew them
 
    .EXAMPLE
    Find-VcCertificate -Filter @('subjectDN', 'FIND', 'www.barron.com')
 
    Find via a filter instead of using built-in function properties
 
    .EXAMPLE
    Find-VcCertificate -ApplicatonDetail
 
    Include application details, not just the ID.
    This will make additional api calls and will increase the response time.
 
    .EXAMPLE
    Find-VcCertificate -OwnerDetail
 
    Include user/team owner details, not just the ID.
    This will make additional api calls and will increase the response time.
    #>


    [CmdletBinding(DefaultParameterSetName = 'All')]

    param (

        [Parameter(ParameterSetName = 'All')]
        [string] $Name,

        [Parameter(ParameterSetName = 'All')]
        [int32] $KeyLength,

        [Parameter(ParameterSetName = 'All')]
        [string] $Serial,

        [Parameter(ParameterSetName = 'All')]
        [string] $Fingerprint,

        [Parameter(ParameterSetName = 'All')]
        [switch] $IsSelfSigned,

        [Parameter(ParameterSetName = 'All')]
        [ValidateSet('ACTIVE', 'RETIRED', 'DELETED')]
        [string[]] $Status,

        [Parameter(ParameterSetName = 'All')]
        [datetime] $ExpireBefore,

        [Parameter(ParameterSetName = 'All')]
        [datetime] $ExpireAfter,

        [Parameter(ParameterSetName = 'All')]
        [ValidateSet('CURRENT', 'OLD')]
        [string] $Version,

        [Parameter(ParameterSetName = 'All')]
        [string] $SanDns,

        [Parameter(ParameterSetName = 'All')]
        [string] $Application,

        [Parameter(ParameterSetName = 'All')]
        [string[]] $Tag,

        [Parameter(ParameterSetName = 'All')]
        [string] $CN,

        [Parameter(ParameterSetName = 'All')]
        [string] $Issuer,

        [Parameter(Mandatory, ParameterSetName = 'Filter')]
        [System.Collections.ArrayList] $Filter,

        [Parameter(ParameterSetName = 'All')]
        [Parameter(ParameterSetName = 'Filter')]
        [psobject[]] $Order,

        [parameter(Mandatory, ParameterSetName = 'SavedSearch')]
        [string] $SavedSearchName,

        [Parameter()]
        [switch] $ApplicationDetail,

        [Parameter()]
        [Alias('IncludeVaasOwner')]
        [switch] $OwnerDetail,

        [Parameter()]
        [int] $First,

        [Parameter()]
        [psobject] $VenafiSession
    )

    Test-VenafiSession -VenafiSession $VenafiSession -Platform 'VC'

    $apps = [System.Collections.Generic.List[object]]::new()
    $appOwners = [System.Collections.Generic.List[object]]::new()

    $params = @{
        Type  = 'Certificate'
        First = $First
    }

    if ( $Order ) { $params.Order = $Order }

    switch ($PSCmdlet.ParameterSetName) {
        'Filter' {
            $params.Filter = $Filter
        }

        'All' {
            $newFilter = [System.Collections.Generic.List[object]]::new()
            $newFilter.Add('AND')

            switch ($PSBoundParameters.Keys) {
                'Name' { $null = $newFilter.Add(@('certificateName', 'FIND', $Name)) }
                'KeyLength' { $null = $newFilter.Add(@('keyStrength', 'EQ', $KeyLength.ToString())) }
                'Serial' { $null = $newFilter.Add(@('serialNumber', 'EQ', $Serial)) }
                'Fingerprint' { $null = $newFilter.Add(@('fingerprint', 'EQ', $Fingerprint)) }
                'IsSelfSigned' { $null = $newFilter.Add(@('selfSigned', 'EQ', $IsSelfSigned.IsPresent.ToString())) }
                'Version' { $null = $newFilter.Add(@('versionType', 'EQ', $Version)) }
                'Status' {
                    $null = $newFilter.Add(@('certificateStatus', 'MATCH', $Status.ToUpper()))
                }
                'ExpireBefore' { $null = $newFilter.Add(@('validityEnd', 'LTE', $ExpireBefore)) }
                'ExpireAfter' { $null = $newFilter.Add(@('validityEnd', 'GTE', $ExpireAfter)) }
                'SanDns' { $null = $newFilter.Add(@('subjectAlternativeNameDns', 'FIND', $SanDns)) }
                'CN' { $null = $newFilter.Add(@('subjectCN', 'FIND', $CN)) }
                'Issuer' { $null = $newFilter.Add(@('issuerCN', 'FIND', $Issuer)) }
                'Application' {
                    $appId = Get-VcData -InputObject $Application -Type 'Application'
                    if ( -not $appId ) {
                        throw "Application '$Application' does not exist"
                    }
                    $newFilter.Add(@('applicationIds', 'MATCH', $appId ))
                }
                'Tag' {
                    $null = $newFilter.Add(@('tags', 'MATCH', $Tag))
                }
            }

            if ( $newFilter.Count -gt 1 ) { $params.Filter = $newFilter }
        }

        'SavedSearch' {
            $params.SavedSearchName = $SavedSearchName
        }
    }

    $response = Find-VcObject @params

    $response | Select-Object *,
    @{
        'n' = 'application'
        'e' = {
            if ( $ApplicationDetail ) {
                foreach ($thisAppId in $_.applicationIds) {
                    $thisApp = $apps | Where-Object { $_.applicationId -eq $thisAppId }
                    if ( -not $thisApp ) {
                        $thisApp = Get-VcApplication -ID $thisAppId | Select-Object -Property * -ExcludeProperty ownerIdsAndTypes, ownership
                        $apps.Add($thisApp)
                    }
                    $thisApp
                }
            }
            else {
                $_.applicationIds
            }
        }
    },
    @{
        'n' = 'owner'
        'e' = {
            if ( $OwnerDetail ) {

                # this scriptblock requires ?ownershipTree=true be part of the url
                foreach ( $thisOwner in $_.ownership.owningContainers.owningUsers ) {
                    $thisOwnerDetail = $appOwners | Where-Object { $_.id -eq $thisOwner }
                    if ( -not $thisOwnerDetail ) {
                        $thisOwnerDetail = Get-VcIdentity -ID $thisOwner | Select-Object firstName, lastName, emailAddress,
                        @{
                            'n' = 'status'
                            'e' = { $_.userStatus }
                        },
                        @{
                            'n' = 'role'
                            'e' = { $_.systemRoles }
                        },
                        @{
                            'n' = 'type'
                            'e' = { 'USER' }
                        },
                        @{
                            'n' = 'userId'
                            'e' = { $_.id }
                        }

                        $appOwners.Add($thisOwnerDetail)

                    }
                    $thisOwnerDetail
                }

                foreach ($thisOwner in $_.ownership.owningContainers.owningTeams) {
                    $thisOwnerDetail = $appOwners | Where-Object { $_.id -eq $thisOwner }
                    if ( -not $thisOwnerDetail ) {
                        $thisOwnerDetail = Get-VcTeam -ID $thisOwner | Select-Object name, role, members,
                        @{
                            'n' = 'type'
                            'e' = { 'TEAM' }
                        },
                        @{
                            'n' = 'teamId'
                            'e' = { $_.id }
                        }

                        $appOwners.Add($thisOwnerDetail)
                    }
                    $thisOwnerDetail
                }
            }
            else {
                $_.ownership.owningContainers | Select-Object owningUsers, owningTeams
            }
        }
    },
    @{
        'n' = 'instance'
        'e' = { $_.instances }
    },
    @{
        'n' = 'issuerCN'
        'e' = { $_.issuerCN[0] }
    },
    @{
        'n' = 'issuerOU'
        'e' = { $_.issuerOU[0] }
    } -ExcludeProperty applicationIds, instances, totalInstanceCount, ownership, issuerCN, issuerOU
}
# SIG # Begin signature block
# MIIoFQYJKoZIhvcNAQcCoIIoBjCCKAICAQExCzAJBgUrDgMCGgUAMGkGCisGAQQB
# gjcCAQSgWzBZMDQGCisGAQQBgjcCAR4wJgIDAQAABBAfzDtgWUsITrck0sYpfvNR
# AgEAAgEAAgEAAgEAAgEAMCEwCQYFKw4DAhoFAAQUCLM5O6DGnLFOPdGKztLLb0yv
# ozSggiE9MIIFjTCCBHWgAwIBAgIQDpsYjvnQLefv21DiCEAYWjANBgkqhkiG9w0B
# 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/VvRXKwYw02fc7cBqZ9Xql4o4rmUMIIGrjCCBJag
# AwIBAgIQBzY3tyRUfNhHrP0oZipeWzANBgkqhkiG9w0BAQsFADBiMQswCQYDVQQG
# EwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNl
# cnQuY29tMSEwHwYDVQQDExhEaWdpQ2VydCBUcnVzdGVkIFJvb3QgRzQwHhcNMjIw
# MzIzMDAwMDAwWhcNMzcwMzIyMjM1OTU5WjBjMQswCQYDVQQGEwJVUzEXMBUGA1UE
# ChMORGlnaUNlcnQsIEluYy4xOzA5BgNVBAMTMkRpZ2lDZXJ0IFRydXN0ZWQgRzQg
# UlNBNDA5NiBTSEEyNTYgVGltZVN0YW1waW5nIENBMIICIjANBgkqhkiG9w0BAQEF
# AAOCAg8AMIICCgKCAgEAxoY1BkmzwT1ySVFVxyUDxPKRN6mXUaHW0oPRnkyibaCw
# zIP5WvYRoUQVQl+kiPNo+n3znIkLf50fng8zH1ATCyZzlm34V6gCff1DtITaEfFz
# sbPuK4CEiiIY3+vaPcQXf6sZKz5C3GeO6lE98NZW1OcoLevTsbV15x8GZY2UKdPZ
# 7Gnf2ZCHRgB720RBidx8ald68Dd5n12sy+iEZLRS8nZH92GDGd1ftFQLIWhuNyG7
# QKxfst5Kfc71ORJn7w6lY2zkpsUdzTYNXNXmG6jBZHRAp8ByxbpOH7G1WE15/teP
# c5OsLDnipUjW8LAxE6lXKZYnLvWHpo9OdhVVJnCYJn+gGkcgQ+NDY4B7dW4nJZCY
# OjgRs/b2nuY7W+yB3iIU2YIqx5K/oN7jPqJz+ucfWmyU8lKVEStYdEAoq3NDzt9K
# oRxrOMUp88qqlnNCaJ+2RrOdOqPVA+C/8KI8ykLcGEh/FDTP0kyr75s9/g64ZCr6
# dSgkQe1CvwWcZklSUPRR8zZJTYsg0ixXNXkrqPNFYLwjjVj33GHek/45wPmyMKVM
# 1+mYSlg+0wOI/rOP015LdhJRk8mMDDtbiiKowSYI+RQQEgN9XyO7ZONj4KbhPvbC
# dLI/Hgl27KtdRnXiYKNYCQEoAA6EVO7O6V3IXjASvUaetdN2udIOa5kM0jO0zbEC
# AwEAAaOCAV0wggFZMBIGA1UdEwEB/wQIMAYBAf8CAQAwHQYDVR0OBBYEFLoW2W1N
# hS9zKXaaL3WMaiCPnshvMB8GA1UdIwQYMBaAFOzX44LScV1kTN8uZz/nupiuHA9P
# MA4GA1UdDwEB/wQEAwIBhjATBgNVHSUEDDAKBggrBgEFBQcDCDB3BggrBgEFBQcB
# AQRrMGkwJAYIKwYBBQUHMAGGGGh0dHA6Ly9vY3NwLmRpZ2ljZXJ0LmNvbTBBBggr
# BgEFBQcwAoY1aHR0cDovL2NhY2VydHMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0VHJ1
# c3RlZFJvb3RHNC5jcnQwQwYDVR0fBDwwOjA4oDagNIYyaHR0cDovL2NybDMuZGln
# aWNlcnQuY29tL0RpZ2lDZXJ0VHJ1c3RlZFJvb3RHNC5jcmwwIAYDVR0gBBkwFzAI
# BgZngQwBBAIwCwYJYIZIAYb9bAcBMA0GCSqGSIb3DQEBCwUAA4ICAQB9WY7Ak7Zv
# mKlEIgF+ZtbYIULhsBguEE0TzzBTzr8Y+8dQXeJLKftwig2qKWn8acHPHQfpPmDI
# 2AvlXFvXbYf6hCAlNDFnzbYSlm/EUExiHQwIgqgWvalWzxVzjQEiJc6VaT9Hd/ty
# dBTX/6tPiix6q4XNQ1/tYLaqT5Fmniye4Iqs5f2MvGQmh2ySvZ180HAKfO+ovHVP
# ulr3qRCyXen/KFSJ8NWKcXZl2szwcqMj+sAngkSumScbqyQeJsG33irr9p6xeZmB
# o1aGqwpFyd/EjaDnmPv7pp1yr8THwcFqcdnGE4AJxLafzYeHJLtPo0m5d2aR8XKc
# 6UsCUqc3fpNTrDsdCEkPlM05et3/JWOZJyw9P2un8WbDQc1PtkCbISFA0LcTJM3c
# HXg65J6t5TRxktcma+Q4c6umAU+9Pzt4rUyt+8SVe+0KXzM5h0F4ejjpnOHdI/0d
# KNPH+ejxmF/7K9h+8kaddSweJywm228Vex4Ziza4k9Tm8heZWcpw8De/mADfIBZP
# J/tgZxahZrrdVcA6KYawmKAr7ZVBtzrVFZgxtGIJDwq9gdkT/r+k0fNX2bwE+oLe
# Mt8EifAAzV3C+dAjfwAL5HYCJtnwZXZCpimHCUcr5n8apIUP/JiW9lVUKx+A+sDy
# Divl1vupL0QVSucTDh3bNzgaoSv27dZ8/DCCBrAwggSYoAMCAQICEAitQLJg0pxM
# n17Nqb2TrtkwDQYJKoZIhvcNAQEMBQAwYjELMAkGA1UEBhMCVVMxFTATBgNVBAoT
# DERpZ2lDZXJ0IEluYzEZMBcGA1UECxMQd3d3LmRpZ2ljZXJ0LmNvbTEhMB8GA1UE
# AxMYRGlnaUNlcnQgVHJ1c3RlZCBSb290IEc0MB4XDTIxMDQyOTAwMDAwMFoXDTM2
# MDQyODIzNTk1OVowaTELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDkRpZ2lDZXJ0LCBJ
# bmMuMUEwPwYDVQQDEzhEaWdpQ2VydCBUcnVzdGVkIEc0IENvZGUgU2lnbmluZyBS
# U0E0MDk2IFNIQTM4NCAyMDIxIENBMTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCC
# AgoCggIBANW0L0LQKK14t13VOVkbsYhC9TOM6z2Bl3DFu8SFJjCfpI5o2Fz16zQk
# B+FLT9N4Q/QX1x7a+dLVZxpSTw6hV/yImcGRzIEDPk1wJGSzjeIIfTR9TIBXEmtD
# mpnyxTsf8u/LR1oTpkyzASAl8xDTi7L7CPCK4J0JwGWn+piASTWHPVEZ6JAheEUu
# oZ8s4RjCGszF7pNJcEIyj/vG6hzzZWiRok1MghFIUmjeEL0UV13oGBNlxX+yT4Us
# SKRWhDXW+S6cqgAV0Tf+GgaUwnzI6hsy5srC9KejAw50pa85tqtgEuPo1rn3MeHc
# reQYoNjBI0dHs6EPbqOrbZgGgxu3amct0r1EGpIQgY+wOwnXx5syWsL/amBUi0nB
# k+3htFzgb+sm+YzVsvk4EObqzpH1vtP7b5NhNFy8k0UogzYqZihfsHPOiyYlBrKD
# 1Fz2FRlM7WLgXjPy6OjsCqewAyuRsjZ5vvetCB51pmXMu+NIUPN3kRr+21CiRshh
# WJj1fAIWPIMorTmG7NS3DVPQ+EfmdTCN7DCTdhSmW0tddGFNPxKRdt6/WMtyEClB
# 8NXFbSZ2aBFBE1ia3CYrAfSJTVnbeM+BSj5AR1/JgVBzhRAjIVlgimRUwcwhGug4
# GXxmHM14OEUwmU//Y09Mu6oNCFNBfFg9R7P6tuyMMgkCzGw8DFYRAgMBAAGjggFZ
# MIIBVTASBgNVHRMBAf8ECDAGAQH/AgEAMB0GA1UdDgQWBBRoN+Drtjv4XxGG+/5h
# ewiIZfROQjAfBgNVHSMEGDAWgBTs1+OC0nFdZEzfLmc/57qYrhwPTzAOBgNVHQ8B
# Af8EBAMCAYYwEwYDVR0lBAwwCgYIKwYBBQUHAwMwdwYIKwYBBQUHAQEEazBpMCQG
# CCsGAQUFBzABhhhodHRwOi8vb2NzcC5kaWdpY2VydC5jb20wQQYIKwYBBQUHMAKG
# NWh0dHA6Ly9jYWNlcnRzLmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydFRydXN0ZWRSb290
# RzQuY3J0MEMGA1UdHwQ8MDowOKA2oDSGMmh0dHA6Ly9jcmwzLmRpZ2ljZXJ0LmNv
# bS9EaWdpQ2VydFRydXN0ZWRSb290RzQuY3JsMBwGA1UdIAQVMBMwBwYFZ4EMAQMw
# CAYGZ4EMAQQBMA0GCSqGSIb3DQEBDAUAA4ICAQA6I0Q9jQh27o+8OpnTVuACGqX4
# SDTzLLbmdGb3lHKxAMqvbDAnExKekESfS/2eo3wm1Te8Ol1IbZXVP0n0J7sWgUVQ
# /Zy9toXgdn43ccsi91qqkM/1k2rj6yDR1VB5iJqKisG2vaFIGH7c2IAaERkYzWGZ
# gVb2yeN258TkG19D+D6U/3Y5PZ7Umc9K3SjrXyahlVhI1Rr+1yc//ZDRdobdHLBg
# XPMNqO7giaG9OeE4Ttpuuzad++UhU1rDyulq8aI+20O4M8hPOBSSmfXdzlRt2V0C
# FB9AM3wD4pWywiF1c1LLRtjENByipUuNzW92NyyFPxrOJukYvpAHsEN/lYgggnDw
# zMrv/Sk1XB+JOFX3N4qLCaHLC+kxGv8uGVw5ceG+nKcKBtYmZ7eS5k5f3nqsSc8u
# pHSSrds8pJyGH+PBVhsrI/+PteqIe3Br5qC6/To/RabE6BaRUotBwEiES5ZNq0RA
# 443wFSjO7fEYVgcqLxDEDAhkPDOPriiMPMuPiAsNvzv0zh57ju+168u38HcT5uco
# P6wSrqUvImxB+YJcFWbMbA7KxYbD9iYzDAdLoNMHAmpqQDBISzSoUSC7rRuFCOJZ
# DW3KBVAr6kocnqX9oKcfBnTn8tZSkP2vhUgh+Vc7tJwD7YZF9LRhbr9o4iZghurI
# r6n+lB3nYxs6hlZ4TjCCBsIwggSqoAMCAQICEAVEr/OUnQg5pr/bP1/lYRYwDQYJ
# KoZIhvcNAQELBQAwYzELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDkRpZ2lDZXJ0LCBJ
# bmMuMTswOQYDVQQDEzJEaWdpQ2VydCBUcnVzdGVkIEc0IFJTQTQwOTYgU0hBMjU2
# IFRpbWVTdGFtcGluZyBDQTAeFw0yMzA3MTQwMDAwMDBaFw0zNDEwMTMyMzU5NTla
# MEgxCzAJBgNVBAYTAlVTMRcwFQYDVQQKEw5EaWdpQ2VydCwgSW5jLjEgMB4GA1UE
# AxMXRGlnaUNlcnQgVGltZXN0YW1wIDIwMjMwggIiMA0GCSqGSIb3DQEBAQUAA4IC
# DwAwggIKAoICAQCjU0WHHYOOW6w+VLMj4M+f1+XS512hDgncL0ijl3o7Kpxn3GIV
# WMGpkxGnzaqyat0QKYoeYmNp01icNXG/OpfrlFCPHCDqx5o7L5Zm42nnaf5bw9Yr
# IBzBl5S0pVCB8s/LB6YwaMqDQtr8fwkklKSCGtpqutg7yl3eGRiF+0XqDWFsnf5x
# XsQGmjzwxS55DxtmUuPI1j5f2kPThPXQx/ZILV5FdZZ1/t0QoRuDwbjmUpW1R9d4
# KTlr4HhZl+NEK0rVlc7vCBfqgmRN/yPjyobutKQhZHDr1eWg2mOzLukF7qr2JPUd
# vJscsrdf3/Dudn0xmWVHVZ1KJC+sK5e+n+T9e3M+Mu5SNPvUu+vUoCw0m+PebmQZ
# BzcBkQ8ctVHNqkxmg4hoYru8QRt4GW3k2Q/gWEH72LEs4VGvtK0VBhTqYggT02ke
# fGRNnQ/fztFejKqrUBXJs8q818Q7aESjpTtC/XN97t0K/3k0EH6mXApYTAA+hWl1
# x4Nk1nXNjxJ2VqUk+tfEayG66B80mC866msBsPf7Kobse1I4qZgJoXGybHGvPrhv
# ltXhEBP+YUcKjP7wtsfVx95sJPC/QoLKoHE9nJKTBLRpcCcNT7e1NtHJXwikcKPs
# CvERLmTgyyIryvEoEyFJUX4GZtM7vvrrkTjYUQfKlLfiUKHzOtOKg8tAewIDAQAB
# o4IBizCCAYcwDgYDVR0PAQH/BAQDAgeAMAwGA1UdEwEB/wQCMAAwFgYDVR0lAQH/
# BAwwCgYIKwYBBQUHAwgwIAYDVR0gBBkwFzAIBgZngQwBBAIwCwYJYIZIAYb9bAcB
# MB8GA1UdIwQYMBaAFLoW2W1NhS9zKXaaL3WMaiCPnshvMB0GA1UdDgQWBBSltu8T
# 5+/N0GSh1VapZTGj3tXjSTBaBgNVHR8EUzBRME+gTaBLhklodHRwOi8vY3JsMy5k
# aWdpY2VydC5jb20vRGlnaUNlcnRUcnVzdGVkRzRSU0E0MDk2U0hBMjU2VGltZVN0
# YW1waW5nQ0EuY3JsMIGQBggrBgEFBQcBAQSBgzCBgDAkBggrBgEFBQcwAYYYaHR0
# cDovL29jc3AuZGlnaWNlcnQuY29tMFgGCCsGAQUFBzAChkxodHRwOi8vY2FjZXJ0
# cy5kaWdpY2VydC5jb20vRGlnaUNlcnRUcnVzdGVkRzRSU0E0MDk2U0hBMjU2VGlt
# ZVN0YW1waW5nQ0EuY3J0MA0GCSqGSIb3DQEBCwUAA4ICAQCBGtbeoKm1mBe8cI1P
# ijxonNgl/8ss5M3qXSKS7IwiAqm4z4Co2efjxe0mgopxLxjdTrbebNfhYJwr7e09
# SI64a7p8Xb3CYTdoSXej65CqEtcnhfOOHpLawkA4n13IoC4leCWdKgV6hCmYtld5
# j9smViuw86e9NwzYmHZPVrlSwradOKmB521BXIxp0bkrxMZ7z5z6eOKTGnaiaXXT
# UOREEr4gDZ6pRND45Ul3CFohxbTPmJUaVLq5vMFpGbrPFvKDNzRusEEm3d5al08z
# jdSNd311RaGlWCZqA0Xe2VC1UIyvVr1MxeFGxSjTredDAHDezJieGYkD6tSRN+9N
# UvPJYCHEVkft2hFLjDLDiOZY4rbbPvlfsELWj+MXkdGqwFXjhr+sJyxB0JozSqg2
# 1Llyln6XeThIX8rC3D0y33XWNmdaifj2p8flTzU8AL2+nCpseQHc2kTmOt44Owde
# OVj0fHMxVaCAEcsUDH6uvP6k63llqmjWIso765qCNVcoFstp8jKastLYOrixRoZr
# uhf9xHdsFWyuq69zOuhJRrfVf8y2OMDY7Bz1tqG4QyzfTkx9HmhwwHcK1ALgXGC7
# KP845VJa1qwXIiNO9OzTF/tQa/8Hdx9xl0RBybhG02wyfFgvZ0dl5Rtztpn5aywG
# Ru9BHvDwX+Db2a2QgESvgBBBijCCB3wwggVkoAMCAQICEASyQEzq0fdqCZAgPWOK
# ulswDQYJKoZIhvcNAQELBQAwaTELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDkRpZ2lD
# ZXJ0LCBJbmMuMUEwPwYDVQQDEzhEaWdpQ2VydCBUcnVzdGVkIEc0IENvZGUgU2ln
# bmluZyBSU0E0MDk2IFNIQTM4NCAyMDIxIENBMTAeFw0yMzA5MTMwMDAwMDBaFw0y
# NDA5MTIyMzU5NTlaMIGDMQswCQYDVQQGEwJVUzENMAsGA1UECBMEVXRhaDEXMBUG
# A1UEBxMOU2FsdCBMYWtlIENpdHkxFTATBgNVBAoTDFZlbmFmaSwgSW5jLjEeMBwG
# A1UECxMVUHJvZmVzc2lvbmFsIFNlcnZpY2VzMRUwEwYDVQQDEwxWZW5hZmksIElu
# Yy4wggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDPaBrbDQ0fOiorU2nC
# Zx7SrZVmSiwwhrgzDh4WENmJKVpZbBdtYoERBUQSd3+Y+WY4y/aPAEQ9oF1PNfhu
# nkDiCvY3CnDYeOv2ex8G64w1WQIKKZd2OpsuGLJTShshiT7kQwfQufCfUC6lNuO2
# PreSqztkN8tFWrqNS0YlV18MoGsgCPKZ49eLnwbX33UnqLyiDe8qGE73uxZyIZct
# uWKtQU0ylmkrfZSsevZCSUiqFKjW5y9NPvHwQVbk/ffPZ6eJAIO+ywRSxXu8N1zj
# OWXaKj4HWPu9U6Jwsb4/wnGGPLXex4qyYBdLB8gPnW1Y7dXZJ8RkTbF+7FE31ss5
# 1fIH3zTyJ8gDLEubPfoqruRpf8tDp4Z5UPBue90BShRwIpgYrsU9hCEnRmfG1clE
# p9BTistpki1W2cls99cYlfVpcljXR8plK+cR9hGtxvqkxUXELIAyhkRTddKD1tLS
# hz1+D4VOOSdzPJcWMwP3s9lbwZwsBdZK6Ruy3LNIe+HQ2He3IbJc/LL7IbEyoDDp
# 6WincVwbWyrpGL2BI0D6gLMPZV/Cgqk8meiYsMati4Jgz9TVYbaGL/OCeGf8u797
# wUpOQjxlGFUHVh+/hWCvEZLHRYEj7hYHoHCLouNWZK5qwlnQ6huXuKTn2eSx5hzz
# zlTluOBZmtRteF/DfiVStWR8yQIDAQABo4ICAzCCAf8wHwYDVR0jBBgwFoAUaDfg
# 67Y7+F8Rhvv+YXsIiGX0TkIwHQYDVR0OBBYEFKgZ4jlQ/frPU8WlXRbihgk1MZUo
# MD4GA1UdIAQ3MDUwMwYGZ4EMAQQBMCkwJwYIKwYBBQUHAgEWG2h0dHA6Ly93d3cu
# ZGlnaWNlcnQuY29tL0NQUzAOBgNVHQ8BAf8EBAMCB4AwEwYDVR0lBAwwCgYIKwYB
# BQUHAwMwgbUGA1UdHwSBrTCBqjBToFGgT4ZNaHR0cDovL2NybDMuZGlnaWNlcnQu
# Y29tL0RpZ2lDZXJ0VHJ1c3RlZEc0Q29kZVNpZ25pbmdSU0E0MDk2U0hBMzg0MjAy
# MUNBMS5jcmwwU6BRoE+GTWh0dHA6Ly9jcmw0LmRpZ2ljZXJ0LmNvbS9EaWdpQ2Vy
# dFRydXN0ZWRHNENvZGVTaWduaW5nUlNBNDA5NlNIQTM4NDIwMjFDQTEuY3JsMIGU
# BggrBgEFBQcBAQSBhzCBhDAkBggrBgEFBQcwAYYYaHR0cDovL29jc3AuZGlnaWNl
# cnQuY29tMFwGCCsGAQUFBzAChlBodHRwOi8vY2FjZXJ0cy5kaWdpY2VydC5jb20v
# RGlnaUNlcnRUcnVzdGVkRzRDb2RlU2lnbmluZ1JTQTQwOTZTSEEzODQyMDIxQ0Ex
# LmNydDAJBgNVHRMEAjAAMA0GCSqGSIb3DQEBCwUAA4ICAQANZ3pxjdxS5dfEWE7g
# 75U9E/E2K25iik7LeuC8uKjpidxh9tt9kpGYoFhvv0B7pz82zPords+WGz1S5ezp
# RWVXBGEel/zDWSjUj2VkuNkzyBuC9d62HIgHdu8MOstfIRJRfiIAv9QM3K4OOxAE
# 5N77ta/Jc+tmGqUkvSTA7qRowV9+b5X7NpMGtJrNyjsYuVdW2nr6NZgQdJ3PJp42
# Bjk3iPecqWx1WjguHKe7KoL1pPJZ/EL0o8qlE2r20bGRMfKN4IHrVj/IDoLrcakO
# Z+hm0PTHjqfOvWvsAblz/9N36D2woDitpqLZHFyYtfCggQb/lb/rRwpMBTjgSdRb
# h6n+uY8EEumKdjdyD6TZvlSMEhRth5tqdFUeJmaAK0spBgsd0fzK70tlz3ojp0aa
# bTwLzOxk9PKJiD0lp0o+UB2QjewHV3zbrdR+xrrO8cS9IrdCe60vEd9053/tdHCp
# JbH+heuTyOCC8CjcgAYRf9L5xEGMVi2Ypm6FlQ9BKHwtuJR+xEuwb92iagonDUlV
# m5t4U5GAHLKxyogMAigCm2PJl6golqX4wXUOGQacF6FQ11l76riHjdyvnvcJmXhd
# nBjnDfLd6RzgCGWz2QT9W8yqTEZ8ehOzCZpJUzcQm5nnUUKDTnjOiRoESDFnj/n2
# C+NQp9E25RgLwV8Pkt2PSgjbVDGCBkIwggY+AgEBMH0waTELMAkGA1UEBhMCVVMx
# FzAVBgNVBAoTDkRpZ2lDZXJ0LCBJbmMuMUEwPwYDVQQDEzhEaWdpQ2VydCBUcnVz
# dGVkIEc0IENvZGUgU2lnbmluZyBSU0E0MDk2IFNIQTM4NCAyMDIxIENBMQIQBLJA
# TOrR92oJkCA9Y4q6WzAJBgUrDgMCGgUAoHgwGAYKKwYBBAGCNwIBDDEKMAigAoAA
# oQKAADAZBgkqhkiG9w0BCQMxDAYKKwYBBAGCNwIBBDAcBgorBgEEAYI3AgELMQ4w
# DAYKKwYBBAGCNwIBFTAjBgkqhkiG9w0BCQQxFgQUjcr01jmaIJ/kp7bhDYfEyLGi
# f8gwDQYJKoZIhvcNAQEBBQAEggIAZ9n+9c1NNqIQoIheknsNhjsdVmUXelw9JEAO
# qOB5hZ6XkK2rBr+tCm0DweIvWnIEhaQvorViC45AvzlE76Iia88iQydNJwSFXLJJ
# EGFy0/Qrxt7GMtlUQuQcMNFUclMtmwJxcBi29SN1Ng5rk5FaClvQBKn9bF5XbGEC
# tRtwKdIkbeD3xaYwUX8HDdsk8Z+dBeEqrudenNE/k7sKk0eYZXl51uan2rj2MUJZ
# Zv338mOgmlUFQgXEyxUX4H8MUmhOI4DRiiIbOULOa6eSZ8wz/BkoBzWgzg7Z7xhj
# ZlZFWHWGzwrVb4qNQlH07AmpC0Nu8+uhFNe0D8t7e4RqIoZx81Z+jPx+Wv5o2E7r
# wO31OPichlEWb/4N3GJeK1paq1U4ca4T3d8tBSBRQjuesGjGgbRTRRCb6xEsxXlG
# e4m0m+gEylh6YVmlmlfua7q6JgOTSzSMrDotsESXZIltB+nCI8mMucVltnX41pKm
# tGAh0A+QuaKJPXcHIPMPBC/YfB6ix/z45Dq+Ta5q6x/w/ux9sQOwpyLt9roAQBUp
# KKqCSKmoYYF6n5LjKL/dMIuqgbHT+TbJaf6nIeRAkyGHN0EAi+lsAHHvoyt9wfhd
# iQbsh3ztHGDS6S8NyVtK4uFiXPeFrQL4I+1csb8axWcnovM0sJ1QSiaeqBMI87Vv
# et/lVy+hggMgMIIDHAYJKoZIhvcNAQkGMYIDDTCCAwkCAQEwdzBjMQswCQYDVQQG
# EwJVUzEXMBUGA1UEChMORGlnaUNlcnQsIEluYy4xOzA5BgNVBAMTMkRpZ2lDZXJ0
# IFRydXN0ZWQgRzQgUlNBNDA5NiBTSEEyNTYgVGltZVN0YW1waW5nIENBAhAFRK/z
# lJ0IOaa/2z9f5WEWMA0GCWCGSAFlAwQCAQUAoGkwGAYJKoZIhvcNAQkDMQsGCSqG
# SIb3DQEHATAcBgkqhkiG9w0BCQUxDxcNMjQwMzI3MDA1MjQyWjAvBgkqhkiG9w0B
# CQQxIgQgM4WgxNNJXQ5R3oW+QxYcOVGkm9egi7Pxtx8wf1Ur2I0wDQYJKoZIhvcN
# AQEBBQAEggIAkfvaQr0pMfGV0E0E95ZTH3uZzFj5t9cR6uDaLXqXcuETlO0eja9X
# CSwWVcQwvqgtMlfooYQP24QRgGQGODW+xXSOgCMZFmR8xwB52ne8e3TmfwXnIgQu
# qmgEQOpQRZJDBdNgx+bs/VWtmUve6GhT0Je8BP661WoiwEXMsQi0xb49o1yqI/q+
# FW7Ginogf5azIRb1b4aU87caJJoqKC5wZwPxXF2MNWRrOsWNB45EF9ZlY2CTtx6g
# xCrFi6vCbbznOc3aylyq0eYf6FqoU0YNXhmkIQnIvSA69BuDFZFhGS12/1G5Ls9e
# 6Q4gfj+2X35nkKg1gQM+7q/FOgK+/navEK199UMVvvOg+ElitRe9G5an7EJWyJyM
# F4fbrVNbAIJcHmUYUo1Ftisq+JiY6knnWF3wTvJ09D8ewXD4aFhRwi5w3G139mde
# ijtHNQ1PCSKvc+x6fmTG+m5WHxYoZawg6E8zuCiZxWpVMBY2zQiNzapaW0Ms0p15
# Kkt+OTjSaucs0uJGvNk1MN9W51Q/AuepWz/IIXsXA8DnriidQBrXfK8zQYGoxQbj
# fLAl44x9Rb/pD4czCJjErPSLbq13E8F+Vqc2CEmyp/edU/kg4fWYs0RdDksAFQld
# CeRIxKYBq3I84CRUAKUOM264zl9xeqb41BeFuN9ZyNku3MjxFP+t5Ys=
# SIG # End signature block