EnterpriseDevices.ps1

function Convert-DeviceTokenToString {
    <#
        .Synopsis
        Internal helper function to convert device token byte array to string
    #>

    Param (
        [Parameter(Mandatory = $true)]
        [byte[]] $Token
    )
    
    $sb = New-Object System.Text.StringBuilder
    $maxLength = 50
    foreach ($b in $Token) {
        if ($sb.Length -ge $maxLength) {
            break
        }
        [void]$sb.AppendFormat("{0:x2}", $b)
    }
    return $sb.ToString()
}

function Get-PendingKeeperDeviceApproval {
    <#
        .Synopsis
        List pending device approval requests
        
        .Description
        Displays a list of all pending device approval requests with details including user email, device ID, device name, client version, and IP address.
        
        .Parameter Reload
        Reload the list of pending device approvals from the server
        
        .Parameter Format
        Output format: table, csv, or json
        
        .Parameter Output
        File path to write output to (required for csv and json formats)
        
        .Example
        Get-PendingKeeperDeviceApproval
        Lists all pending device approvals in table format
        
        .Example
        Get-PendingKeeperDeviceApproval -Format csv -Output devices.csv
        Exports pending device approvals to CSV file
    #>

    [CmdletBinding()]
    Param (
        [Parameter()][switch] $Reload,
        [Parameter()][ValidateSet('table', 'csv', 'json')][string] $Format = 'table',
        [Parameter()][string] $Output
    )
    
    [Enterprise]$enterprise = getEnterprise
    
    if ($Reload) {
        $enterprise.loader.Load().GetAwaiter().GetResult() | Out-Null
    }
    
    $approvals = @($enterprise.deviceApproval.DeviceApprovalRequests)
    
    if ($approvals.Count -eq 0) {
        Write-Output "There are no pending devices"
        return
    }
    
    $deviceList = New-Object System.Collections.ArrayList
    foreach ($device in $approvals) {
        $user = $null
        if ($enterprise.enterpriseData.TryGetUserById($device.EnterpriseUserId, [ref]$user)) {
            $deviceTokenBytes = $device.EncryptedDeviceToken.ToByteArray()
            $deviceId = Convert-DeviceTokenToString -Token $deviceTokenBytes
            
            [void]$deviceList.Add([PSCustomObject]@{
                Email = $user.Email
                DeviceId = $deviceId
                DeviceName = $device.DeviceName
                ClientVersion = $device.ClientVersion
                IpAddress = $device.IpAddress
                DeviceType = $device.DeviceType
            })
        } else {
            Write-Warning "Skipping device for user ID $($device.EnterpriseUserId) - user not found"
        }
    }
    
    $deviceList = $deviceList.ToArray()
    
    $deviceList = $deviceList | Sort-Object DeviceId
    
    if ($Format -eq 'json') {
        $json = $deviceList | ConvertTo-Json
        if ($Output) {
            $json | Out-File -FilePath $Output -Encoding UTF8
            Write-Output "Output written to $Output"
        } else {
            Write-Output $json
        }
    }
    elseif ($Format -eq 'csv') {
        if (-not $Output) {
            Write-Error "Output file path is required for CSV format" -ErrorAction Stop
        }
        $deviceList | Export-Csv -Path $Output -NoTypeInformation
        Write-Output "Output written to $Output"
    }
    else {
        $deviceList | Format-Table -AutoSize Email, DeviceId, DeviceName, ClientVersion, IpAddress
    }
}

function Approve-KeeperDevice {
    <#
        .Synopsis
        Approve pending device requests
        
        .Description
        Approves pending device approval requests. You can specify devices by device ID (partial match supported) or user email.
        
        .Parameter Match
        Device ID (partial match supported) or user email to approve. If not specified, all pending devices will be approved.
        
        .Parameter Reload
        Reload the list of pending device approvals before processing
        
        .Parameter TrustedIp
        Approve devices from a trusted IP address
        
        .Example
        Approve-KeeperDevice -Match "user@example.com"
        Approves all pending devices for user@example.com
        
        .Example
        Approve-KeeperDevice -Match "a1b2c3"
        Approves devices with device ID starting with "a1b2c3"
        
        .Example
        Approve-KeeperDevice
        Approves all pending devices
    #>

    [CmdletBinding(SupportsShouldProcess)]
    Param (
        [Parameter(Position = 0)]
        [string] $Match,
        [Parameter()]
        [switch] $Reload,
        [Parameter()]
        [switch] $TrustedIp
    )
    
    [Enterprise]$enterprise = getEnterprise
    
    if ($Reload) {
        try {
            $enterprise.loader.Load().GetAwaiter().GetResult() | Out-Null
        } catch {
            Write-Error "Failed to reload enterprise data: $($_.Exception.Message)" -ErrorAction Stop
        }
    }
    
    $approvals = @($enterprise.deviceApproval.DeviceApprovalRequests)
    
    if ($approvals.Count -eq 0) {
        Write-Output "There are no pending devices"
        return
    }
    
    if (-not [string]::IsNullOrWhiteSpace($Match)) {
        $Match = $Match.Trim()
    }
    
    $devices = Get-MatchingDevices -Approvals $approvals -Enterprise $enterprise -Match $Match
    
    if ($devices.Count -eq 0) {
        $matchText = if ([string]::IsNullOrWhiteSpace($Match)) { "all pending devices" } else { "matching '$Match'" }
        Write-Output "No device found $matchText"
        return
    }
    
    $deviceDetails = $devices | ForEach-Object {
        $deviceTokenBytes = $_.EncryptedDeviceToken.ToByteArray()
        $deviceId = Convert-DeviceTokenToString -Token $deviceTokenBytes
        $user = $null
        if ($enterprise.enterpriseData.TryGetUserById($_.EnterpriseUserId, [ref]$user)) {
            "$($user.Email) ($deviceId)"
        } else {
            "User ID $($_.EnterpriseUserId) ($deviceId)"
        }
    }
    $deviceListText = $deviceDetails -join ", "
    
    if ($PSCmdlet.ShouldProcess("$($devices.Count) device(s)", "Approve", "This will approve the following devices: $deviceListText")) {
        try {
            $enterprisePrivateKeyBytes = $enterprise.loader.EcPrivateKey
            if (-not $enterprisePrivateKeyBytes) {
                Write-Error "Enterprise private key not available. Cannot approve devices without the enterprise private key."
                return
            }
            
            $enterpriseEcKey = [KeeperSecurity.Utils.CryptoUtils]::LoadEcPrivateKey($enterprisePrivateKeyBytes)
            
            $dataKeys = New-Object 'System.Collections.Generic.Dictionary[long,byte[]]'
            $userIdsToLoad = New-Object 'System.Collections.Generic.List[long]'
            
            foreach ($device in $devices) {
                if (-not $dataKeys.ContainsKey($device.EnterpriseUserId)) {
                    $userIdsToLoad.Add($device.EnterpriseUserId)
                }
            }
            
            if ($userIdsToLoad.Count -gt 0) {
                $dataKeyRq = New-Object Authentication.UserDataKeyRequest
                foreach ($userId in $userIdsToLoad) {
                    $dataKeyRq.EnterpriseUserId.Add($userId) | Out-Null
                }
                
                $dataKeyRs = $enterprise.loader.Auth.ExecuteAuthRest("enterprise/get_enterprise_user_data_key", $dataKeyRq, [Enterprise.EnterpriseUserDataKeys]).GetAwaiter().GetResult()
                
                foreach ($key in $dataKeyRs.Keys) {
                    if ($key.UserEncryptedDataKey.IsEmpty) {
                        continue
                    }
                    try {
                        $userDataKey = [KeeperSecurity.Utils.CryptoUtils]::DecryptEc($key.UserEncryptedDataKey.ToByteArray(), $enterpriseEcKey)
                        $dataKeys[$key.EnterpriseUserId] = $userDataKey
                    }
                    catch {
                        Write-Warning "Failed to decrypt data key for user $($key.EnterpriseUserId): $($_.Exception.Message)"
                    }
                }
            }
            
            $rq = New-Object Enterprise.ApproveUserDevicesRequest
            foreach ($device in $devices) {
                if (-not $dataKeys.ContainsKey($device.EnterpriseUserId)) {
                    continue
                }
                if ($device.DevicePublicKey.IsEmpty) {
                    continue
                }
                
                try {
                    $devicePublicKey = [KeeperSecurity.Utils.CryptoUtils]::LoadEcPublicKey($device.DevicePublicKey.ToByteArray())
                    $userDataKey = $dataKeys[$device.EnterpriseUserId]
                    $encryptedDataKey = [KeeperSecurity.Utils.CryptoUtils]::EncryptEc($userDataKey, $devicePublicKey)
                    
                    $deviceRq = New-Object Enterprise.ApproveUserDeviceRequest
                    $deviceRq.EnterpriseUserId = $device.EnterpriseUserId
                    $deviceRq.EncryptedDeviceToken = [Google.Protobuf.ByteString]::CopyFrom($device.EncryptedDeviceToken.ToByteArray())
                    $deviceRq.EncryptedDeviceDataKey = [Google.Protobuf.ByteString]::CopyFrom($encryptedDataKey)
                    
                    $rq.DeviceRequests.Add($deviceRq) | Out-Null
                }
                catch {
                    Write-Warning "Failed to prepare approval for device: $($_.Exception.Message)"
                }
            }
            
            if ($rq.DeviceRequests.Count -eq 0) {
                Write-Output "No device to approve"
                return
            }
            
            $rs = $enterprise.loader.Auth.ExecuteAuthRest("enterprise/approve_user_devices", $rq, [Enterprise.ApproveUserDevicesResponse]).GetAwaiter().GetResult()
            
            if ($rs.DeviceResponses -and $rs.DeviceResponses.Count -gt 0) {
                foreach ($approveRs in $rs.DeviceResponses) {
                    if ($approveRs.Failed) {
                        $user = $null
                        if ($enterprise.enterpriseData.TryGetUserById($approveRs.EnterpriseUserId, [ref]$user)) {
                            Write-Warning "Failed to approve device for $($user.Email): $($approveRs.Message)"
                        }
                        else {
                            Write-Warning "Failed to approve device for user ID $($approveRs.EnterpriseUserId): $($approveRs.Message)"
                        }
                    }
                }
            }
            
            try {
                $enterprise.loader.Load().GetAwaiter().GetResult() | Out-Null
            } catch {
                Write-Warning "Failed to reload enterprise data after approval: $($_.Exception.Message)"
            }
            Write-Output "Approved $($rq.DeviceRequests.Count) device(s)"
        }
        catch {
            Write-Error "Failed to approve devices: $($_.Exception.Message)" -ErrorAction Stop
        }
    }
}

function Deny-KeeperDevice {
    <#
        .Synopsis
        Deny pending device requests
        
        .Description
        Denies pending device approval requests. You can specify devices by device ID (partial match supported) or user email.
        
        .Parameter Match
        Device ID (partial match supported) or user email to deny. If not specified, all pending devices will be denied.
        
        .Parameter Reload
        Reload the list of pending device approvals before processing
        
        .Example
        Deny-KeeperDevice -Match "user@example.com"
        Denies all pending devices for user@example.com
        
        .Example
        Deny-KeeperDevice -Match "a1b2c3"
        Denies devices with device ID starting with "a1b2c3"
        
        .Example
        Deny-KeeperDevice
        Denies all pending devices
    #>

    [CmdletBinding(SupportsShouldProcess)]
    Param (
        [Parameter(Position = 0)]
        [string] $Match,
        
        [Parameter()][switch] $Reload
    )
    
    [Enterprise]$enterprise = getEnterprise
    
    if ($Reload) {
        try {
            $enterprise.loader.Load().GetAwaiter().GetResult() | Out-Null
        } catch {
            Write-Error "Failed to reload enterprise data: $($_.Exception.Message)" -ErrorAction Stop
        }
    }
    
    $approvals = @($enterprise.deviceApproval.DeviceApprovalRequests)
    
    if ($approvals.Count -eq 0) {
        Write-Output "There are no pending devices"
        return
    }
    
    if (-not [string]::IsNullOrWhiteSpace($Match)) {
        $Match = $Match.Trim()
    }
    
    $devices = Get-MatchingDevices -Approvals $approvals -Enterprise $enterprise -Match $Match
    
    if ($devices.Count -eq 0) {
        $matchText = if ([string]::IsNullOrWhiteSpace($Match)) { "all pending devices" } else { "matching '$Match'" }
        Write-Output "No device found $matchText"
        return
    }
    
    $deviceDetails = $devices | ForEach-Object {
        $deviceTokenBytes = $_.EncryptedDeviceToken.ToByteArray()
        $deviceId = Convert-DeviceTokenToString -Token $deviceTokenBytes
        $user = $null
        if ($enterprise.enterpriseData.TryGetUserById($_.EnterpriseUserId, [ref]$user)) {
            "$($user.Email) ($deviceId)"
        } else {
            "User ID $($_.EnterpriseUserId) ($deviceId)"
        }
    }
    $deviceListText = $deviceDetails -join ", "
    
    if ($PSCmdlet.ShouldProcess("$($devices.Count) device(s)", "Deny", "This will deny the following devices: $deviceListText")) {
        try {
            $rq = New-Object Enterprise.ApproveUserDevicesRequest
            foreach ($device in $devices) {
                $deviceRq = New-Object Enterprise.ApproveUserDeviceRequest
                $deviceRq.EnterpriseUserId = $device.EnterpriseUserId
                $deviceRq.EncryptedDeviceToken = [Google.Protobuf.ByteString]::CopyFrom($device.EncryptedDeviceToken.ToByteArray())
                $deviceRq.DenyApproval = $true
                
                $rq.DeviceRequests.Add($deviceRq) | Out-Null
            }
            
            if ($rq.DeviceRequests.Count -eq 0) {
                Write-Output "No device to deny"
                return
            }
            
            $rs = $enterprise.loader.Auth.ExecuteAuthRest("enterprise/approve_user_devices", $rq, [Enterprise.ApproveUserDevicesResponse]).GetAwaiter().GetResult()
            
            if ($rs.DeviceResponses -and $rs.DeviceResponses.Count -gt 0) {
                foreach ($approveRs in $rs.DeviceResponses) {
                    if ($approveRs.Failed) {
                        $user = $null
                        if ($enterprise.enterpriseData.TryGetUserById($approveRs.EnterpriseUserId, [ref]$user)) {
                            Write-Warning "Failed to deny device for $($user.Email): $($approveRs.Message)"
                        }
                        else {
                            Write-Warning "Failed to deny device for user ID $($approveRs.EnterpriseUserId): $($approveRs.Message)"
                        }
                    }
                }
            }
            
            try {
                $enterprise.loader.Load().GetAwaiter().GetResult() | Out-Null
            } catch {
                Write-Warning "Failed to reload enterprise data after denial: $($_.Exception.Message)"
            }
            Write-Output "Denied $($rq.DeviceRequests.Count) device(s)"
        }
        catch {
            Write-Error "Failed to deny devices: $($_.Exception.Message)" -ErrorAction Stop
        }
    }
}

function Get-MatchingDevices {
    param(
        [Parameter(Mandatory=$true)]
        $Approvals,
        
        [Parameter(Mandatory=$true)]
        $Enterprise,
        
        [string]$Match
    )

    if ([string]::IsNullOrWhiteSpace($Match)) {
        return @($Approvals)
    }
    
    $devices = New-Object System.Collections.ArrayList
    foreach ($device in $Approvals) {
        $deviceTokenBytes = $device.EncryptedDeviceToken.ToByteArray()
        $deviceId = Convert-DeviceTokenToString -Token $deviceTokenBytes
        
        if ($deviceId.StartsWith($Match, [System.StringComparison]::OrdinalIgnoreCase)) {
            [void]$devices.Add($device)
            continue
        }
        
        $user = $null
        if ($Enterprise.enterpriseData.TryGetUserById($device.EnterpriseUserId, [ref]$user)) {
            if ($user.Email -ieq $Match) {
                [void]$devices.Add($device)
            }
        }
    }
    
    return $devices.ToArray()
}

function Get-TrustedIpDevices {
    param(
        [Parameter(Mandatory=$true)]
        $Devices,
        
        [Parameter(Mandatory=$true)]
        $Enterprise
    )
    
    try {
        $userIds = New-Object System.Collections.Generic.HashSet[long]
        $userEmails = New-Object System.Collections.Generic.Dictionary[long,string]
        
        foreach ($device in $Devices) {
            if (-not $userIds.Contains($device.EnterpriseUserId)) {
                $userIds.Add($device.EnterpriseUserId) | Out-Null
                $user = $null
                if ($Enterprise.enterpriseData.TryGetUserById($device.EnterpriseUserId, [ref]$user)) {
                    $userEmails[$device.EnterpriseUserId] = $user.Email
                }
            }
        }
        
        if ($userEmails.Count -eq 0) {
            return @()
        }
        
        $lastYear = (Get-Date).AddDays(-365)
        $fromTimestamp = [DateTimeOffset]::new($lastYear).ToUnixTimeSeconds()
        $toTimestamp = [DateTimeOffset]::new((Get-Date)).ToUnixTimeSeconds()
        
        $rq = New-Object KeeperSecurity.Enterprise.AuditLogCommands+GetAuditEventReportsCommand
        $rq.ReportType = "span"
        $rq.Scope = "enterprise"
        $rq.Columns = @("ip_address", "username")
        $rq.Limit = 1000
        
        $filter = New-Object KeeperSecurity.Enterprise.AuditLogCommands+ReportFilter
        $filter.EventTypes = @("login")
        $filter.Username = $userEmails.Values.ToArray()
        $filter.Created = New-Object KeeperSecurity.Enterprise.AuditLogCommands+CreatedFilter
        $filter.Created.Min = $fromTimestamp
        $filter.Created.Max = $toTimestamp
        $rq.Filter = $filter
        
        $auditResult = $Enterprise.loader.Auth.ExecuteAuthCommand(
            [KeeperSecurity.Enterprise.AuditLogCommands+GetAuditEventReportsCommand],
            [KeeperSecurity.Enterprise.AuditLogCommands+GetAuditEventReportsResponse],
            $rq
        ).GetAwaiter().GetResult()
        
        $auditEvents = $auditResult.Events
        
        $trustedIps = New-Object 'System.Collections.Generic.Dictionary[string,System.Collections.Generic.HashSet[string]]'
        
        foreach ($auditEvent in $auditEvents) {
            if ($auditEvent.ContainsKey('username') -and $auditEvent.ContainsKey('ip_address')) {
                $username = $auditEvent['username'].ToString().ToLowerInvariant()
                $ipAddress = $auditEvent['ip_address'].ToString()
                
                if (-not $trustedIps.ContainsKey($username)) {
                    $trustedIps[$username] = New-Object System.Collections.Generic.HashSet[string]
                }
                [void]$trustedIps[$username].Add($ipAddress)
            }
        }
        
        $trustedDevices = New-Object System.Collections.ArrayList
        
        foreach ($device in $Devices) {
            $user = $null
            if ($Enterprise.enterpriseData.TryGetUserById($device.EnterpriseUserId, [ref]$user)) {
                $username = $user.Email.ToLowerInvariant()
                $deviceIp = $device.IpAddress
                
                if ($trustedIps.ContainsKey($username) -and $trustedIps[$username].Contains($deviceIp)) {
                    [void]$trustedDevices.Add($device)
                } else {
                    Write-Warning "The user $($user.Email) attempted to login from an untrusted IP ($deviceIp). To force the approval, run the same command without the -TrustedIp argument"
                }
            }
        }
        
        return $trustedDevices.ToArray()
    }
    catch {
        Write-Warning "Failed to filter devices by trusted IP: $($_.Exception.Message). Approving all matching devices."
        return $Devices
    }
}

# SIG # Begin signature block
# MIInvgYJKoZIhvcNAQcCoIInrzCCJ6sCAQExDzANBglghkgBZQMEAgEFADB5Bgor
# BgEEAYI3AgEEoGswaTA0BgorBgEEAYI3AgEeMCYCAwEAAAQQH8w7YFlLCE63JNLG
# KX7zUQIBAAIBAAIBAAIBAAIBADAxMA0GCWCGSAFlAwQCAQUABCC7ZGZx3U8B/V3V
# zcdr5RgHre7NlscktE4RmGzKgiBTvKCCITswggWNMIIEdaADAgECAhAOmxiO+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
# oAMCAQICEAe0P3SLJmcoVNrErUyxTt0wDQYJKoZIhvcNAQELBQAwaTELMAkGA1UE
# BhMCVVMxFzAVBgNVBAoTDkRpZ2lDZXJ0LCBJbmMuMUEwPwYDVQQDEzhEaWdpQ2Vy
# dCBUcnVzdGVkIEc0IENvZGUgU2lnbmluZyBSU0E0MDk2IFNIQTM4NCAyMDIxIENB
# MTAeFw0yNTEyMzEwMDAwMDBaFw0yOTAxMDIyMzU5NTlaMIHRMRMwEQYLKwYBBAGC
# NzwCAQMTAlVTMRkwFwYLKwYBBAGCNzwCAQITCERlbGF3YXJlMR0wGwYDVQQPDBRQ
# cml2YXRlIE9yZ2FuaXphdGlvbjEQMA4GA1UEBRMHMzQwNzk4NTELMAkGA1UEBhMC
# VVMxETAPBgNVBAgTCElsbGlub2lzMRAwDgYDVQQHEwdDaGljYWdvMR0wGwYDVQQK
# ExRLZWVwZXIgU2VjdXJpdHkgSW5jLjEdMBsGA1UEAxMUS2VlcGVyIFNlY3VyaXR5
# IEluYy4wggGiMA0GCSqGSIb3DQEBAQUAA4IBjwAwggGKAoIBgQCUcNMoSVmxAi0a
# vG+StFJMNFFTUIOo3HdBZ+0gqA1XpNgUx11vB1vCZrvFsD9m5oA58tdp4gZN3LmQ
# aMvCl2ANUT7MilI02Hf1RWlygBzon6iE0GpU3lgRrwrk1dhtLpGsR6dbMKUUHprc
# vKpXk90/VN+vhzY1uik1tCTxkDCPu/AYJg7m9+tR2KqvMuYMaMLhii66eWUAGsBC
# h/uZxjkGoJF6qZ0DgFd7rW7VYljbfYSNPeZNGTDgB0J/wOsKl0mn612DTseIvAKt
# 4vra/FLFukyEyStnfQ8lWYDcLLCMCjNVrzGipmT5E2iyx7Y1RZCIpNwVogp3Ixbk
# Gbq5A/41YNOLLd4cFewyB2F037RevBCRsUODZEt1qBf7Jbu3DiYo1G+zTj9E0R1s
# FzyijcfdsTm6X5ble+yCJeGkX5XgsyPnZpyz/FX9Fr0N9pMPGWwW2PKyHEnSytXm
# 0Dxdq2P4mA4CBUxq7YoV26L2PF6QEh9BQdXTPcnLysUv7SI/a0ECAwEAAaOCAgIw
# ggH+MB8GA1UdIwQYMBaAFGg34Ou2O/hfEYb7/mF7CIhl9E5CMB0GA1UdDgQWBBRG
# 4H6CH8pvNX632bsdnrda4MtJLDA9BgNVHSAENjA0MDIGBWeBDAEDMCkwJwYIKwYB
# BQUHAgEWG2h0dHA6Ly93d3cuZGlnaWNlcnQuY29tL0NQUzAOBgNVHQ8BAf8EBAMC
# B4AwEwYDVR0lBAwwCgYIKwYBBQUHAwMwgbUGA1UdHwSBrTCBqjBToFGgT4ZNaHR0
# cDovL2NybDMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0VHJ1c3RlZEc0Q29kZVNpZ25p
# bmdSU0E0MDk2U0hBMzg0MjAyMUNBMS5jcmwwU6BRoE+GTWh0dHA6Ly9jcmw0LmRp
# Z2ljZXJ0LmNvbS9EaWdpQ2VydFRydXN0ZWRHNENvZGVTaWduaW5nUlNBNDA5NlNI
# QTM4NDIwMjFDQTEuY3JsMIGUBggrBgEFBQcBAQSBhzCBhDAkBggrBgEFBQcwAYYY
# aHR0cDovL29jc3AuZGlnaWNlcnQuY29tMFwGCCsGAQUFBzAChlBodHRwOi8vY2Fj
# ZXJ0cy5kaWdpY2VydC5jb20vRGlnaUNlcnRUcnVzdGVkRzRDb2RlU2lnbmluZ1JT
# QTQwOTZTSEEzODQyMDIxQ0ExLmNydDAJBgNVHRMEAjAAMA0GCSqGSIb3DQEBCwUA
# A4ICAQA1Wlq0WzJa3N6DgjgBU7nagIJBab1prPARXZreX1MOv9VjnS5o0CrfQLr6
# z3bmWHw7xT8dt6bcSwRixqvPJtv4q8Rvo80O3eUMvMxQzqmi7z1zf+HG+/3G4F+2
# IYegvPc8Ui151XCV9rjA8tvFWRLRMX0ZRxY1zfT027HMw0iYL20z44+Cky//FAnL
# iRwoNDGiRkZiHbB9YOftPAYNMG3gm1z3zOW5RdfKPrqvMuijE+dfyLIAA6Immpzu
# FMH+Wgn8NnSlot9b4YKycaqqdjd7wXDjPub/oQ7VShuCSBWj+UNOTVh0vcZGackc
# H1DLVgwp2dcKlxJiQKtkHT/T6LloY6LTe6+8wkVkr8EAv1W+q/+M1a4Ao+ykFbIA
# 2LBEmA9qdgoLtenAYIiEg+48SjMPgyBbVPE3bhL1vIqjEIxYCfdmi6wx33oYX7HB
# +bJ7zitHw4GgtpfPV8y8QRZImKmeDOKyXjQPDmQM/Eglm/Ns0GzBkVXM8h6UI34b
# WZrHz9sbLSE20m5Svmxftvw5zju+I3WsmS/stNfWlOkwU0niUgwPHaz21kjXEA5A
# g+aqv26wodqZcnGOlChoWDvSJ8KKgdOFbeAYKAMp1NY7iWV315zpGH19RipCR1NH
# 0ND8iIubk3WGNf2rzEfqlOi3h2ywqVkU6AKXHdO5JV4otSKKEDGCBdkwggXVAgEB
# MH0waTELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDkRpZ2lDZXJ0LCBJbmMuMUEwPwYD
# VQQDEzhEaWdpQ2VydCBUcnVzdGVkIEc0IENvZGUgU2lnbmluZyBSU0E0MDk2IFNI
# QTM4NCAyMDIxIENBMQIQB7Q/dIsmZyhU2sStTLFO3TANBglghkgBZQMEAgEFAKCB
# hDAYBgorBgEEAYI3AgEMMQowCKACgAChAoAAMBkGCSqGSIb3DQEJAzEMBgorBgEE
# AYI3AgEEMBwGCisGAQQBgjcCAQsxDjAMBgorBgEEAYI3AgEVMC8GCSqGSIb3DQEJ
# BDEiBCARLJrtAYr7CdVC79wc4ZUxad/zWAlWT/z5GD3s/jXVSjANBgkqhkiG9w0B
# AQEFAASCAYAuypZHnQfrqZ5ISrp3k/z5HyVbpWNm2zSETs2ChxX5fk0A0H/L64Ug
# xzF+5SlNami5kVNfy591i1IgCtKe0fr2BpyutmsPz93JdBEhnL23Bw2NUnBWc7Gy
# DMsBi4uPFWH3moiuoPYw8JzhmDT91vAZW82ySO5JaET/lO+3ORyGqRyGTV9mU95g
# aW3DZDOr4uwHV1lZGUwitejlOcr6w5AlK1EcEZ1a6hVWgNRmKWliV3L7xKeD3g6S
# XSG1denG9OnF8tTMlFr1jXiCAFuYHYuYQRuM6/kDsLayf09XYwsuO1TggXqXSA7Q
# XFTbEigt/Pu9AUIi3kDbc60P2+4Gt8PSqZBlo+3JiFuqFl+mh/DAhidjxX3dY4zc
# 4FSDxedBZ7A8H5jl2jB/sC2eat5bvyf+zze080g87T/6EsR6z0HluAYbMWS6oahp
# hZFi18zaziRGNNWxWlV8/Tqs9o29IYsC8SXf7jI+jC1/YbGL0OjO4AhATvnGZ+No
# dBho0Uonui6hggMmMIIDIgYJKoZIhvcNAQkGMYIDEzCCAw8CAQEwfTBpMQswCQYD
# VQQGEwJVUzEXMBUGA1UEChMORGlnaUNlcnQsIEluYy4xQTA/BgNVBAMTOERpZ2lD
# ZXJ0IFRydXN0ZWQgRzQgVGltZVN0YW1waW5nIFJTQTQwOTYgU0hBMjU2IDIwMjUg
# Q0ExAhAKgO8YS43xBYLRxHanlXRoMA0GCWCGSAFlAwQCAQUAoGkwGAYJKoZIhvcN
# AQkDMQsGCSqGSIb3DQEHATAcBgkqhkiG9w0BCQUxDxcNMjYwMTIzMjMzOTIwWjAv
# BgkqhkiG9w0BCQQxIgQg+YZntuGKkfGtvum1HS4m8dbKB/EWRTyMgNTcYFo7BgEw
# DQYJKoZIhvcNAQEBBQAEggIAsrY6F3Ad4X5ynnp7/r2kF7KbF+B46w4j8QcCcFo2
# 6qD834/1tABRU/6pHgCNM6bZty7flF2ceF0vMDnJghVGYfHNfXzUo9a2RVUUqqvF
# B/TGm9YhVrBOtXuYiGzY3YHsnZo6Pqf/5x7XGlf7fYN+Y+gjHJFHN76exbyY3A4s
# t2V1bp1+A02nP+LBxs1ELmFud+BSAF05xZnqnIkP4wC3ebglJrlvCTQhp6zuU4pY
# yq/ma4E2Em1TW7K0ae10hdWiMTpu9uF79EWz6MGltL9fun3s4266mWHQiD+qaWPw
# J20KmZ+lwZbKS+tiubGsRwt9SiPdQLYgjh45FEEimJikZp6qmuJWMwwBQ7ITPRFv
# al69/Ck1Ap5gunvlkiyjSZLGcrVy7ZxjSwg2nc3R5vjVQja5QtRREGcYZ5W27Eas
# f34VaqYRvJtWb+ojyE7kXvIYFrAxdlkOt9oAwZs8d76IhCZP9ZXZiAxe++UtDPAW
# DAZQR/0f/qMCfPuhxMnvc1x+6rMD8M2e4rSsMsjcsKmf1qlCMro+rZSfw/fKBAqo
# hqnGPqO6w2z3dtMBXoYlEa+pm3AC9ugHMNu6nut+DY4Uc7k2SJeRKmezl6aWB9t+
# 5bVK/HwGcE3WL61QsKyqYLeDi9ByZYxBJ/8Jx38P66wgifDjfx5/KRGyYNuU+3jo
# lv0=
# SIG # End signature block