Public/Set-VdcPermission.ps1

function Set-VdcPermission {
    <#
    .SYNOPSIS
    Set explicit permissions for TLSPDC objects
 
    .DESCRIPTION
    Adds, modifies, or removes explicit permissions on TLSPDC objects.
    You can provide a complete permission object or modify individual permissions.
 
    .PARAMETER Path
    Path to an object
 
    .PARAMETER Guid
    Guid representing a unique object
 
    .PARAMETER IdentityId
    The id that represents the user or group. You can use Find-VdcIdentity or Get-VdcPermission to get the id.
 
    .PARAMETER Permission
    TppPermission object to set.
    You can create a new object and modify it or get an existing object with Get-VdcPermission.
 
    .PARAMETER Force
    When setting a TppPermission object with -Permission and one already exists, use this to overwrite
 
    .PARAMETER IsAssociateAllowed
    Associate or disassociate an Application and Device object with a certificate.
    Push the certificate and private key to the Application object.
    Retry the certificate installation.
 
    .PARAMETER IsCreateAllowed
    The caller can create subordinate objects, such as Devices and Applications. Create permission grants implicit View permission.
 
    .PARAMETER IsDeleteAllowed
    The caller can delete objects.
 
    .PARAMETER IsManagePermissionsAllowed
    The caller can grant other user or group Identities permission to the current object or subordinate objects.
 
    .PARAMETER IsPolicyWriteAllowed
    The caller can modify policy values on folders.
    Also requires View permission.
    Manage Policy permission grants implicit Read permission and Write permission.
 
    .PARAMETER IsPrivateKeyReadAllowed
    The caller can download the private key for Policy and Certificate objects.
 
    .PARAMETER IsPrivateKeyWriteAllowed
    The caller can upload the private key for Policy, Certificate, and Private Key Credential objects to Trust Protection Platform.
 
    .PARAMETER IsReadAllowed
    The caller can view and read object data from the Policy tree.
    However, to view subordinate objects, View permission or higher permissions is also required.
 
    .PARAMETER IsRenameAllowed
    The caller can rename and move Policy tree objects.
    Move capability also requires Rename permission to the object and Create permission to the target folder.
 
    .PARAMETER IsRevokeAllowed
    The caller can invalidate a certificate.
    Also requires Write permission to the certificate.
 
    .PARAMETER IsViewAllowed
    The caller can confirm that the object is present in the Policy tree.
 
    .PARAMETER IsWriteAllowed
    The caller can edit object attributes.
    To move objects in the tree, the caller must have Write permission to the objects and Create permission to the target folder.
    Write permission grants implicit Read permission.
 
    .PARAMETER VenafiSession
    Authentication for the function.
    The value defaults to the script session object $VenafiSession created by New-VenafiSession.
    A TLSPDC token can also be provided.
    If providing a TLSPDC token, an environment variable named VDC_SERVER must also be set.
 
    .INPUTS
    Guid, IdentityId, Permission
 
    .OUTPUTS
    None
 
    .EXAMPLE
    Set-VdcPermission -Guid '1234abcd-g6g6-h7h7-faaf-f50cd6610cba' -IdentityId 'AD+mydomain.com:azsxdcfvgbhnjmlk09877654321' -Permission $TppPermObject
 
    Permission a user/group on an object specified by guid
 
    .EXAMPLE
    Set-VdcPermission -Path '\ved\policy\my folder' -IdentityId 'AD+mydomain.com:azsxdcfvgbhnjmlk09877654321' -Permission $TppPermObject
 
    Permission a user/group on an object specified by path
 
    .EXAMPLE
    Get-VdcPermission -Path '\ved\policy\my folder' -IdentityId 'AD+mydomain.com:azsxdcfvgbhnjmlk09877654321' -Explicit | Set-VdcPermission -IdentityId $newId
 
    Permission a user/group based on permissions of an existing user/group
 
    .EXAMPLE
    Get-VdcPermission -Path '\ved\policy\my folder' -IdentityId 'AD+mydomain.com:azsxdcfvgbhnjmlk09877654321' -Explicit | Set-VdcPermission -IsWriteAllowed
 
    Add specific permission(s) for a specific user/group associated with an object
 
    .EXAMPLE
    Get-VdcPermission -Path '\ved\policy\my folder' -Explicit | Set-VdcPermission -IsAssociateAllowed -IsWriteAllowed
 
    Add specific permission(s) for all existing user/group associated with an object
 
    .EXAMPLE
    Get-VdcPermission -Path '\ved\policy\my folder' -Explicit | Set-VdcPermission -IsAssociateAllowed:$false
 
    Remove specific permission(s) for all existing user/group associated with an object
 
    .EXAMPLE
    $id = Find-VdcIdentity -Name 'brownstein' | Select-Object -ExpandProperty Id
    Find-VdcObject -Path '\VED' -Recursive | Get-VdcPermission -IdentityId $id | Set-VdcPermission -Permission $TppPermObject -Force
 
    Reset permissions for a specific user/group for all objects. Note the use of -Force to overwrite existing permissions.
 
    .LINK
    http://VenafiPS.readthedocs.io/en/latest/functions/Set-VdcPermission/
 
    .LINK
    https://github.com/Venafi/VenafiPS/blob/main/VenafiPS/Public/Set-VdcPermission.ps1
 
    .LINK
    https://docs.venafi.com/Docs/current/TopNav/Content/SDK/WebSDK/r-SDK-POST-Permissions-object-guid-principal.php
 
    .LINK
    https://docs.venafi.com/Docs/current/TopNav/Content/SDK/WebSDK/r-SDK-PUT-Permissions-object-guid-principal.php
 
    .LINK
    https://docs.venafi.com/Docs/current/TopNav/Content/SDK/WebSDK/r-SDK-Permissions-Effective.php
 
    .NOTES
    Confirmation impact is set to Medium, set ConfirmPreference accordingly.
    #>


    [CmdletBinding(SupportsShouldProcess, ConfirmImpact = 'Medium', DefaultParameterSetName = 'PermissionObjectGuid')]
    [Alias('Set-TppPermission')]

    param (
        [Parameter(Mandatory, ParameterSetName = 'PermissionObjectPath')]
        [Parameter(Mandatory, ParameterSetName = 'PermissionPath')]
        [ValidateNotNullOrEmpty()]
        [ValidateScript( {
                if ( $_ | Test-TppDnPath ) {
                    $true
                }
                else {
                    throw "'$_' is not a valid DN path"
                }
            })]
        [Alias('DN')]
        [String] $Path,

        [Parameter(Mandatory, ParameterSetName = 'PermissionObjectGuid', ValueFromPipelineByPropertyName)]
        [Parameter(Mandatory, ParameterSetName = 'PermissionGuid', ValueFromPipelineByPropertyName)]
        [ValidateNotNullOrEmpty()]
        [Alias('ObjectGuid')]
        [guid] $Guid,

        [Parameter(Mandatory, ValueFromPipelineByPropertyName)]
        [ValidateScript( {
                if ( $_ | Test-VdcIdentityFormat -Format 'Universal' ) {
                    $true
                }
                else {
                    throw "'$_' is not a valid Prefixed Universal Id format. See https://docs.venafi.com/Docs/current/TopNav/Content/SDK/WebSDK/r-SDK-IdentityInformation.php."
                }
            })]
        [Alias('PrefixedUniversalId', 'ID')]
        [string] $IdentityId,

        [Parameter(Mandatory, ParameterSetName = 'PermissionObjectPath', ValueFromPipelineByPropertyName)]
        [Parameter(Mandatory, ParameterSetName = 'PermissionObjectGuid', ValueFromPipelineByPropertyName)]
        [Alias('ExplicitPermissions')]
        [TppPermission] $Permission,

        [Parameter(ParameterSetName = 'PermissionPath')]
        [Parameter(ParameterSetName = 'PermissionGuid')]
        [switch] $IsAssociateAllowed,

        [Parameter(ParameterSetName = 'PermissionPath')]
        [Parameter(ParameterSetName = 'PermissionGuid')]
        [switch] $IsCreateAllowed,

        [Parameter(ParameterSetName = 'PermissionPath')]
        [Parameter(ParameterSetName = 'PermissionGuid')]
        [switch] $IsDeleteAllowed,

        [Parameter(ParameterSetName = 'PermissionPath')]
        [Parameter(ParameterSetName = 'PermissionGuid')]
        [switch] $IsManagePermissionsAllowed,

        [Parameter(ParameterSetName = 'PermissionPath')]
        [Parameter(ParameterSetName = 'PermissionGuid')]
        [switch] $IsPolicyWriteAllowed,

        [Parameter(ParameterSetName = 'PermissionPath')]
        [Parameter(ParameterSetName = 'PermissionGuid')]
        [switch] $IsPrivateKeyReadAllowed,

        [Parameter(ParameterSetName = 'PermissionPath')]
        [Parameter(ParameterSetName = 'PermissionGuid')]
        [switch] $IsPrivateKeyWriteAllowed,

        [Parameter(ParameterSetName = 'PermissionPath')]
        [Parameter(ParameterSetName = 'PermissionGuid')]
        [switch] $IsReadAllowed,

        [Parameter(ParameterSetName = 'PermissionPath')]
        [Parameter(ParameterSetName = 'PermissionGuid')]
        [switch] $IsRenameAllowed,

        [Parameter(ParameterSetName = 'PermissionPath')]
        [Parameter(ParameterSetName = 'PermissionGuid')]
        [switch] $IsRevokeAllowed,

        [Parameter(ParameterSetName = 'PermissionPath')]
        [Parameter(ParameterSetName = 'PermissionGuid')]
        [switch] $IsViewAllowed,

        [Parameter(ParameterSetName = 'PermissionPath')]
        [Parameter(ParameterSetName = 'PermissionGuid')]
        [switch] $IsWriteAllowed,

        [Parameter()]
        [switch] $Force,

        [Parameter()]
        [psobject] $VenafiSession
    )

    begin {
        Test-VenafiSession -VenafiSession $VenafiSession -Platform 'VDC'

    }

    process {
        Write-Verbose "Parameterset = $($PSCmdlet.ParameterSetName)"

        $params = @{

            Method        = 'Post'
            UriLeaf       = 'placeholder'
            Body          = $null
            FullResponse  = $true
        }

        if ( $Path ) {
            $thisGuid = $Path | ConvertTo-VdcGuid
        }
        else {
            $thisGuid = $Guid
        }
        $params.UriLeaf = "Permissions/Object/{$thisGuid}"

        if ( $IdentityId.StartsWith('local:') ) {
            # format of local is local:universalId
            $type, $id = $IdentityId.Split(':')
            $params.UriLeaf += "/$type/$id"
        }
        else {
            # external source, eg. AD, LDAP
            # format is type+name:universalId
            $type, $name, $id = $IdentityId -Split { $_ -in '+', ':' }
            $params.UriLeaf += "/$type/$name/$id"
        }

        if ( $PSCmdlet.ParameterSetName -like 'PermissionObject*' ) {
            $params.Body = $Permission.ToHashtable()
        }
        else {
            Write-Verbose "Getting existing permissions for $IdentityId"
            $thisPerm = $thisGuid | Get-VdcPermission -IdentityId $IdentityId -Explicit | Select-Object -ExpandProperty ExplicitPermissions

            if ( $thisPerm ) {
                Write-Verbose 'Existing identity found will be updated'
                $params.Method = 'Put'
            }
            else {
                Write-Verbose 'Existing identity not found. Only the permissions switches set will be true, all others will be false.'
                $thisPerm = [TppPermission]::new()
            }

            foreach ($k in $PSBoundParameters.Keys) {
                if ($k -in 'IsAssociateAllowed', 'IsCreateAllowed', 'IsDeleteAllowed', 'IsManagePermissionsAllowed', 'IsPolicyWriteAllowed', 'IsPrivateKeyReadAllowed', 'IsPrivateKeyWriteAllowed', 'IsReadAllowed', 'IsRenameAllowed', 'IsRevokeAllowed', 'IsViewAllowed', 'IsWriteAllowed') {
                    $thisPerm.$k = $PSBoundParameters[$k]
                }
            }

            $params.Body = $thisPerm.ToHashtable()
        }

        if ( $PSCmdlet.ShouldProcess($Path, "Set permission for $IdentityId") ) {
            try {

                $response = Invoke-VenafiRestMethod @params
                switch ( $response.StatusCode ) {

                    { $_ -in 200, 201 } {
                        # success
                    }

                    409 {
                        # user/group already has permissions defined on this object
                        # need to use a put method instead
                        if ( $Force ) {

                            Write-Verbose "Existing user/group found and Force option provided, updating existing permissions"
                            $params.Method = 'Put'
                            $response = Invoke-VenafiRestMethod @params
                            if ( $response.StatusCode -ne 200 ) {
                                Write-Error ('Failed to update permission with error {0}' -f $response.Error)
                            }
                        }
                        else {
                            # force option not provided, let the user know what's up
                            Write-Error ('Permission for {0} already exists. To override, provide the -Force option.' -f $IdentityId)
                        }
                    }

                    default {
                        Write-Error ('Failed to create permission with error {0}, {1}' -f [int]$response.StatusCode, $response.Error)
                    }
                }
            }
            catch {
                Write-Error ("Failed to set permissions on $Path, user/group $IdentityId. $_")
            }
        }
    }
}

# SIG # Begin signature block
# MIIoFQYJKoZIhvcNAQcCoIIoBjCCKAICAQExCzAJBgUrDgMCGgUAMGkGCisGAQQB
# gjcCAQSgWzBZMDQGCisGAQQBgjcCAR4wJgIDAQAABBAfzDtgWUsITrck0sYpfvNR
# AgEAAgEAAgEAAgEAAgEAMCEwCQYFKw4DAhoFAAQULmTQ77W4RTRuTS6PHRFuoVGQ
# MoaggiE9MIIFjTCCBHWgAwIBAgIQDpsYjvnQLefv21DiCEAYWjANBgkqhkiG9w0B
# 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
# DAYKKwYBBAGCNwIBFTAjBgkqhkiG9w0BCQQxFgQUrpiOzHYLALU9KQ67bimll3aG
# 9GMwDQYJKoZIhvcNAQEBBQAEggIAstvKnfuTbEsIIrU9kHczdJat1JOrBVe+yUqv
# hFhwA5YH1g8MBzWmD9N5/CnfZ4wwx7UXj1qx5AvL3zG5SCP6p8mvbsWHnr5AjUVp
# pIjD39qUpMS2qEGapLHjyUo0v2jDPEVPArzgLnaLRWwNJ54OZkJXqzszRFlel+Cl
# XtzjkFeZmGy6n5JLStGnn2C0rai1j8wduPAD12jBoFWiEf+3dPX/U676BICIpFfn
# ZTJsZuPtRIPTmSj3pusfYp+eDK4GvxJLlEN9LhYWhlIkeL6AMSaYbsS2oFp1jNQZ
# 9BEq2Glx+i3TGMDQ9kSf+zjk+b/V6mywQRu6GLmUcylbeskK3xAOwN0evSnU3uDB
# T+Lgplgq/gw7GdaJbGFtuUp2JuWaCVhadDi4X6cXsf7Px9euxxVR9azj8obzNwoF
# UrykQ9oAWB7OXY6zuCBkrcNp4Ukok8/HneZaiingtEiiFvECPOgl2NCGSNl904/R
# QYxpyAgxDpS4OU3VW/U9Aqcn+6J96uNTHXTPkIdHZ6S25sg8S4WylY6zHGVUIX3Q
# WlTJ5NIvSHCeDYii48Z3QRNygVYf5LPIqnKDQ1eKCyWHWQ5guuNThXUV7VQi70VV
# HC2qObaanZheDcAsULGZqHym2NFszb/9FimdjZJ4ZAEWL/Dkw3KtOH66UzJ6V02g
# s3ihycahggMgMIIDHAYJKoZIhvcNAQkGMYIDDTCCAwkCAQEwdzBjMQswCQYDVQQG
# EwJVUzEXMBUGA1UEChMORGlnaUNlcnQsIEluYy4xOzA5BgNVBAMTMkRpZ2lDZXJ0
# IFRydXN0ZWQgRzQgUlNBNDA5NiBTSEEyNTYgVGltZVN0YW1waW5nIENBAhAFRK/z
# lJ0IOaa/2z9f5WEWMA0GCWCGSAFlAwQCAQUAoGkwGAYJKoZIhvcNAQkDMQsGCSqG
# SIb3DQEHATAcBgkqhkiG9w0BCQUxDxcNMjMxMjA5MDMwNDU1WjAvBgkqhkiG9w0B
# CQQxIgQgvfOOe70IqbN9QWECEnE6Xu3O4FWq2rbHm2UrYfrMCxswDQYJKoZIhvcN
# AQEBBQAEggIAKhry+0AzpZMh87ICtv6C7b7f+XDWWI3Ha/s4JQtz60sBNxU0fLD1
# rqzULtmfwccIk8EFn6WBhewW9ZAMKph76rW1LS+FNHnP6FRaWpNUSVN7m58QbusY
# jyT4TCoGQhsX2K4v3lFPsvT+I8/HRBXtdiz7AGMWG7N6jojz7JGgfsgP9UCDKe82
# fLnFewAx0Ijm8PPlG7zEaRevOUUJIoDFXHXxnxrvx+JD9n/WFphvyCw8/5EEARrd
# /Vdnw97qfcY4zzSlwaENlZ6OvICloDSBMPVioB9UIok+DsTaS3uckvcvMpssR+m5
# Pz1zcsV3BdSbtHBo50prhSeECJJ8z4VISuejkYml8EG/P9Jh/RsjbmMqGHVMiV0M
# 7YOTTz8GTssm+rZtr2lNqauUkbHcFAFjiqrwKpuduTKVjPVHjxyncaZ3zKGPhhUY
# dxmaxE53QJO6sKYd6Rfe5Joh/W7WcUEueJuL8hPMkpSBt8lCBIf1PYz43gha6xmC
# kf3njFrVPSc5ZcRsXo7xcHSLx/6T9tZaBFQK7AoZwye1fl64R+NdvFXYAX3n9z7l
# 5/hQ4Hf2Mav26w89TUVW2w5v33Wd1AwPP6jmHz6ARPr4wBAd4OigcjfuKLvm3zSu
# HLhN33L1vVwyV9N7WHUhwObSRBRf6tHpD22yBplqe8v10PYXzRVwWUg=
# SIG # End signature block