LISSTech.DrainCtl.psm1
|
#Requires -Version 5.1 Set-StrictMode -Version Latest # Locate drainctl.dll — may be alongside the psm1 (MSI install) or in bin/ subdir (dev/PSGallery). $script:DllPath = Join-Path $PSScriptRoot 'drainctl.dll' if (-not (Test-Path $script:DllPath)) { $script:DllPath = Join-Path (Join-Path $PSScriptRoot 'bin') 'drainctl.dll' } if (-not (Test-Path $script:DllPath)) { throw "DrainCtl: drainctl.dll not found. Module installation may be corrupt." } # Locate drainctl.exe — add its directory to PATH if not already there. $script:BinDir = Split-Path $script:DllPath $script:ExePath = Join-Path $script:BinDir 'drainctl.exe' if ($env:PATH -notlike "*$($script:BinDir)*") { $env:PATH = "$($script:BinDir);$env:PATH" } $MyInvocation.MyCommand.ScriptBlock.Module.OnRemove = { $env:PATH = ($env:PATH -split ';' | Where-Object { $_ -ne $script:BinDir }) -join ';' } # ── Native interop ────────────────────────────────────────────────────────── # P/Invoke declarations with a UTF-8 helper that works on both # .NET Framework 4.x (Windows PowerShell 5.1) and .NET 6+ (PowerShell 7+). Add-Type -TypeDefinition @" using System; using System.Runtime.InteropServices; using System.Text; public static class DrainCtlNative { [DllImport("$($script:DllPath.Replace('\','\\'))", CallingConvention = CallingConvention.Cdecl)] public static extern IntPtr DrainCtl_Version(); [DllImport("$($script:DllPath.Replace('\','\\'))", CallingConvention = CallingConvention.Cdecl)] public static extern IntPtr DrainCtl_ReadDrainMode(); [DllImport("$($script:DllPath.Replace('\','\\'))", CallingConvention = CallingConvention.Cdecl)] public static extern IntPtr DrainCtl_Check( [MarshalAs(UnmanagedType.LPStr)] string dbPath, int graceMinutes, int retentionDays); [DllImport("$($script:DllPath.Replace('\','\\'))", CallingConvention = CallingConvention.Cdecl)] public static extern IntPtr DrainCtl_History( [MarshalAs(UnmanagedType.LPStr)] string dbPath, int limit, int changesOnly); [DllImport("$($script:DllPath.Replace('\','\\'))", CallingConvention = CallingConvention.Cdecl)] public static extern IntPtr DrainCtl_AuditSetup(); [DllImport("$($script:DllPath.Replace('\','\\'))", CallingConvention = CallingConvention.Cdecl)] public static extern IntPtr DrainCtl_GetNotifyConfig(); [DllImport("$($script:DllPath.Replace('\','\\'))", CallingConvention = CallingConvention.Cdecl)] public static extern IntPtr DrainCtl_SetNotifyConfig( [MarshalAs(UnmanagedType.LPStr)] string jsonStr); [DllImport("$($script:DllPath.Replace('\','\\'))", CallingConvention = CallingConvention.Cdecl)] public static extern IntPtr DrainCtl_TestNotify(); [DllImport("$($script:DllPath.Replace('\','\\'))", CallingConvention = CallingConvention.Cdecl)] public static extern IntPtr DrainCtl_EnableDashboard(int port, [MarshalAs(UnmanagedType.LPStr)] string group); [DllImport("$($script:DllPath.Replace('\','\\'))", CallingConvention = CallingConvention.Cdecl)] public static extern IntPtr DrainCtl_DisableDashboard(); [DllImport("$($script:DllPath.Replace('\','\\'))", CallingConvention = CallingConvention.Cdecl)] public static extern void DrainCtl_Free(IntPtr ptr); /// <summary> /// Read a null-terminated UTF-8 string from unmanaged memory. /// Works on .NET Framework 4.x (PS 5.1) and .NET 6+ (PS 7+). /// </summary> public static string PtrToStringUTF8(IntPtr ptr) { if (ptr == IntPtr.Zero) return null; int len = 0; while (Marshal.ReadByte(ptr, len) != 0) len++; byte[] buf = new byte[len]; Marshal.Copy(ptr, buf, 0, len); return Encoding.UTF8.GetString(buf); } } "@ function Invoke-DrainCtlNative { [CmdletBinding()] param( [Parameter(Mandatory)] [IntPtr]$Ptr ) try { $json = [DrainCtlNative]::PtrToStringUTF8($Ptr) } finally { [DrainCtlNative]::DrainCtl_Free($Ptr) } $obj = $json | ConvertFrom-Json if ($null -ne ($obj.PSObject.Properties['error'])) { $err = $obj.PSObject.Properties['error'].Value $exception = [System.InvalidOperationException]::new($err) $errorRecord = [System.Management.Automation.ErrorRecord]::new( $exception, 'DrainCtlNativeError', [System.Management.Automation.ErrorCategory]::InvalidResult, $null) $PSCmdlet.ThrowTerminatingError($errorRecord) } return $obj } function Get-SafeProperty { # Reads a property from a PSObject without triggering strict-mode errors # when the property doesn't exist (JSON omitempty). param($Object, [string]$Name, $Default = $null) $prop = $Object.PSObject.Properties[$Name] if ($null -ne $prop) { return $prop.Value } return $Default } function ConvertTo-NativeDateTime { # Converts an ISO 8601 string to [datetime]. Returns $null for absent, # null, empty, or Go zero-time values. param($Value) if ($null -eq $Value -or $Value -eq '') { return $null } $s = [string]$Value # Go zero time if ($s -like '0001-01-01*') { return $null } return [datetimeoffset]::Parse($s).LocalDateTime } # ── Public cmdlets ────────────────────────────────────────────────────────── function Get-RDSHDrainMode { <# .SYNOPSIS Returns detailed drain mode state with grace period evaluation and audit trail. .DESCRIPTION Reads the TSServerDrainMode registry value, detects state transitions, records an audit entry, and evaluates whether drain mode has exceeded the grace period. Returns a rich object with Status, Host, DrainMode, StateSince, StateDurationSeconds, transition info, and who changed it. Status values: healthy - connections allowed grace - drain mode active but within grace period alert - drain mode active beyond grace period error - could not read registry Sets $LASTEXITCODE (0 = healthy/grace, 1 = alert, 2 = error). .PARAMETER DBPath Path to the JSONL audit trail file. Default: %ProgramData%\drainctl\audit.jsonl .PARAMETER GraceMinutes Minutes drain mode must persist before alerting. Default: 60. .PARAMETER RetentionDays Days to retain audit records. Default: 90. .EXAMPLE PS> Get-RDSHDrainMode Host : RDSH01 DrainMode : ALLOW_ALL_CONNECTIONS Status : healthy StateDurationSeconds : 3600 .EXAMPLE PS> Get-RDSHDrainMode -GraceMinutes 120 | Select-Object Host, Status, DrainMode .EXAMPLE PS> Get-RDSHDrainMode | Where-Object Status -ne 'healthy' #> [CmdletBinding()] [OutputType([PSCustomObject])] param( [Parameter()] [string]$DBPath = '', [Parameter()] [ValidateRange(0, [int]::MaxValue)] [int]$GraceMinutes = 60, [Parameter()] [ValidateRange(1, 365)] [int]$RetentionDays = 90 ) $ptr = [DrainCtlNative]::DrainCtl_Check($DBPath, $GraceMinutes, $RetentionDays) $raw = Invoke-DrainCtlNative -Ptr $ptr $global:LASTEXITCODE = $raw.exit_code [PSCustomObject]@{ PSTypeName = 'DrainCtl.CheckResult' Timestamp = ConvertTo-NativeDateTime $raw.timestamp Host = $raw.host DrainMode = $raw.drain_mode DrainModeValue = $raw.drain_mode_value StateSince = ConvertTo-NativeDateTime $raw.state_since StateDurationSeconds = if ($null -ne $raw.state_duration_seconds) { [int]$raw.state_duration_seconds } else { $null } GracePeriodSeconds = $raw.grace_period_seconds Status = $raw.status ConnectionsAllowed = $raw.connections_allowed Transition = $raw.transition TransitionFrom = Get-SafeProperty $raw 'transition_from' ChangedBy = Get-SafeProperty $raw 'changed_by' Message = Get-SafeProperty $raw 'message' ExitCode = $raw.exit_code } } function Test-RDSHDrainMode { <# .SYNOPSIS Tests whether RDSH connections are allowed. Returns $true or $false. .DESCRIPTION Returns $true if the server is accepting connections (drain mode is off or within the grace period). Returns $false if drain mode is active beyond the grace period or the registry cannot be read. Also records an audit entry and sets $LASTEXITCODE (0 = pass, 1 = alert, 2 = error). .PARAMETER DBPath Path to the JSONL audit trail file. Default: %ProgramData%\drainctl\audit.jsonl .PARAMETER GraceMinutes Minutes drain mode must persist before alerting. Default: 60. .PARAMETER RetentionDays Days to retain audit records. Default: 90. .EXAMPLE PS> if (Test-RDSHDrainMode) { 'OK' } else { 'ALERT' } .EXAMPLE PS> Test-RDSHDrainMode -GraceMinutes 120 True #> [CmdletBinding()] [OutputType([bool])] param( [Parameter()] [string]$DBPath = '', [Parameter()] [ValidateRange(0, [int]::MaxValue)] [int]$GraceMinutes = 60, [Parameter()] [ValidateRange(1, 365)] [int]$RetentionDays = 90 ) $ptr = [DrainCtlNative]::DrainCtl_Check($DBPath, $GraceMinutes, $RetentionDays) $result = Invoke-DrainCtlNative -Ptr $ptr $global:LASTEXITCODE = $result.exit_code $result.exit_code -eq 0 } function Get-RDSHDrainHistory { <# .SYNOPSIS Retrieves the drain mode audit trail. .DESCRIPTION Returns audit records from the JSONL trail, newest first. Each record includes the timestamp, host, drain mode, whether a state transition occurred, and who made the change. .PARAMETER DBPath Path to the JSONL audit trail file. Default: %ProgramData%\drainctl\audit.jsonl .PARAMETER Limit Maximum number of records to return. Default: 50. .PARAMETER ChangesOnly If set, returns only records where a state transition occurred. .EXAMPLE PS> Get-RDSHDrainHistory | Format-Table .EXAMPLE PS> Get-RDSHDrainHistory -ChangesOnly -Limit 10 .EXAMPLE PS> Get-RDSHDrainHistory | Where-Object Changed -eq $true #> [CmdletBinding()] [OutputType([PSCustomObject[]])] param( [Parameter()] [string]$DBPath = '', [Parameter()] [ValidateRange(1, [int]::MaxValue)] [int]$Limit = 50, [Parameter()] [switch]$ChangesOnly ) $co = if ($ChangesOnly) { 1 } else { 0 } $ptr = [DrainCtlNative]::DrainCtl_History($DBPath, $Limit, $co) $records = Invoke-DrainCtlNative -Ptr $ptr if ($null -eq $records -or @($records).Count -eq 0) { return } foreach ($r in $records) { [PSCustomObject]@{ PSTypeName = 'DrainCtl.AuditRecord' Timestamp = ConvertTo-NativeDateTime $r.timestamp Host = $r.host DrainMode = $r.drain_mode DrainModeValue = $r.drain_mode_value StateDurationSeconds = Get-SafeProperty $r 'state_duration_seconds' Changed = $r.changed ChangedBy = Get-SafeProperty $r 'changed_by' ExitCode = $r.exit_code } } } function Install-RDSHDrainAudit { <# .SYNOPSIS Configures registry auditing for drain mode change attribution. .DESCRIPTION One-time setup that enables Object Access auditing and sets a SACL on the Terminal Server registry key so that Windows records Event ID 4657 whenever TSServerDrainMode is modified. This allows Get-RDSHDrainMode and drainctl to attribute changes to specific users. Must be run elevated (as Administrator or SYSTEM). On domain-joined machines, Group Policy may override the local auditpol settings on the next GP refresh (~90 minutes). The command emits warnings with the exact GPO path to configure for persistence. .EXAMPLE PS> Install-RDSHDrainAudit #> [CmdletBinding(SupportsShouldProcess, ConfirmImpact = 'High')] [OutputType([void])] param() if (-not $PSCmdlet.ShouldProcess('Registry auditing for TSServerDrainMode', 'Configure')) { return } $ptr = [DrainCtlNative]::DrainCtl_AuditSetup() $result = Invoke-DrainCtlNative -Ptr $ptr Write-Verbose 'Registry auditing configured. Event ID 4657 will now record TSServerDrainMode changes.' } function Get-RDSHDrainNotification { <# .SYNOPSIS Shows the current notification configuration for DrainCtl. .DESCRIPTION Reads notification settings from the service registry parameters and returns them as a structured object. Shows webhook URL, ntfy URL, transition/grace notification toggles, and repeat interval. .EXAMPLE PS> Get-RDSHDrainNotification WebhookURL : https://hooks.example.com/drainctl NtfyURL : OnTransition : True OnGraceExceeded : True RepeatMinutes : 0 Enabled : True #> [CmdletBinding()] [OutputType([PSCustomObject])] param() $ptr = [DrainCtlNative]::DrainCtl_GetNotifyConfig() $raw = Invoke-DrainCtlNative -Ptr $ptr [PSCustomObject]@{ PSTypeName = 'DrainCtl.NotifyConfig' WebhookURL = Get-SafeProperty $raw 'webhook_url' '' NtfyURL = Get-SafeProperty $raw 'ntfy_url' '' OnTransition = [bool](Get-SafeProperty $raw 'on_transition' $true) OnGraceExceeded = [bool](Get-SafeProperty $raw 'on_grace_exceeded' $true) RepeatMinutes = [int](Get-SafeProperty $raw 'repeat_minutes' 0) Enabled = [bool](Get-SafeProperty $raw 'enabled' $false) } } function Set-RDSHDrainNotification { <# .SYNOPSIS Updates notification settings for DrainCtl. .DESCRIPTION Writes notification configuration to the service registry parameters. Only specified parameters are changed; unspecified parameters retain their current values. .PARAMETER WebhookURL Webhook URL for HTTP POST JSON notifications. Set to empty string to disable. .PARAMETER NtfyURL ntfy.sh topic URL (e.g. "https://ntfy.sh/drainctl-alerts"). Set to empty string to disable. .PARAMETER OnTransition Enable or disable notifications on state transitions. .PARAMETER OnGraceExceeded Enable or disable notifications when drain exceeds grace period. .PARAMETER RepeatMinutes Minutes between repeated alert notifications (0 = notify once only). .EXAMPLE PS> Set-RDSHDrainNotification -WebhookURL 'https://hooks.example.com/drainctl' .EXAMPLE PS> Set-RDSHDrainNotification -NtfyURL 'https://ntfy.sh/my-alerts' -RepeatMinutes 30 .EXAMPLE PS> Set-RDSHDrainNotification -WebhookURL '' -NtfyURL '' #> [CmdletBinding(SupportsShouldProcess)] [OutputType([void])] param( [Parameter()] [AllowEmptyString()] [string]$WebhookURL, [Parameter()] [AllowEmptyString()] [string]$NtfyURL, [Parameter()] [bool]$OnTransition, [Parameter()] [bool]$OnGraceExceeded, [Parameter()] [ValidateRange(0, [int]::MaxValue)] [int]$RepeatMinutes ) if (-not $PSCmdlet.ShouldProcess('DrainCtl notification configuration', 'Update')) { return } $payload = @{} if ($PSBoundParameters.ContainsKey('WebhookURL')) { $payload['webhook_url'] = $WebhookURL } if ($PSBoundParameters.ContainsKey('NtfyURL')) { $payload['ntfy_url'] = $NtfyURL } if ($PSBoundParameters.ContainsKey('OnTransition')) { $payload['on_transition'] = $OnTransition } if ($PSBoundParameters.ContainsKey('OnGraceExceeded')) { $payload['on_grace_exceeded'] = $OnGraceExceeded } if ($PSBoundParameters.ContainsKey('RepeatMinutes')) { $payload['repeat_minutes'] = $RepeatMinutes } $jsonStr = $payload | ConvertTo-Json -Compress $ptr = [DrainCtlNative]::DrainCtl_SetNotifyConfig($jsonStr) $null = Invoke-DrainCtlNative -Ptr $ptr Write-Verbose 'Notification configuration updated.' } function Test-RDSHDrainNotification { <# .SYNOPSIS Sends a test notification to all configured backends. .DESCRIPTION Reads the current notification configuration and sends a test message to each configured backend (webhook and/or ntfy). Returns an error if no backends are configured or if sending fails. .EXAMPLE PS> Test-RDSHDrainNotification #> [CmdletBinding()] [OutputType([void])] param() $ptr = [DrainCtlNative]::DrainCtl_TestNotify() $null = Invoke-DrainCtlNative -Ptr $ptr Write-Host 'Test notification sent successfully.' } function Enable-RDSHDrainDashboard { <# .SYNOPSIS Enable the DrainCtl multi-server dashboard on this server. .PARAMETER Port Port the dashboard listens on. Default: 49470. .PARAMETER Group AD group authorized to view the dashboard. Default: Domain Admins. .EXAMPLE Enable-RDSHDrainDashboard -Port 49470 -Group "RDS Admins" #> [CmdletBinding(SupportsShouldProcess, ConfirmImpact = 'Medium')] param( [int]$Port = 49470, [string]$Group = 'Domain Admins' ) if (-not $PSCmdlet.ShouldProcess('DrainCtl Dashboard', 'Enable')) { return } $ptr = [DrainCtlNative]::DrainCtl_EnableDashboard($Port, $Group) $result = Invoke-DrainCtlNative -Ptr $ptr Write-Host "Dashboard enabled on port $Port for group '$Group'." Write-Host 'Restart the DrainCtl service to activate: Restart-Service DrainCtl' } function Disable-RDSHDrainDashboard { <# .SYNOPSIS Disable the DrainCtl dashboard on this server. .EXAMPLE Disable-RDSHDrainDashboard #> [CmdletBinding(SupportsShouldProcess, ConfirmImpact = 'Medium')] param() if (-not $PSCmdlet.ShouldProcess('DrainCtl Dashboard', 'Disable')) { return } $ptr = [DrainCtlNative]::DrainCtl_DisableDashboard() Invoke-DrainCtlNative -Ptr $ptr | Out-Null Write-Host 'Dashboard disabled. Restart the DrainCtl service to apply: Restart-Service DrainCtl' } Export-ModuleMember -Function @( 'Get-RDSHDrainMode' 'Test-RDSHDrainMode' 'Get-RDSHDrainHistory' 'Install-RDSHDrainAudit' 'Get-RDSHDrainNotification' 'Set-RDSHDrainNotification' 'Test-RDSHDrainNotification' 'Enable-RDSHDrainDashboard' 'Disable-RDSHDrainDashboard' ) # SIG # Begin signature block # MIItnAYJKoZIhvcNAQcCoIItjTCCLYkCAQExDzANBglghkgBZQMEAgEFADB5Bgor # BgEEAYI3AgEEoGswaTA0BgorBgEEAYI3AgEeMCYCAwEAAAQQH8w7YFlLCE63JNLG # KX7zUQIBAAIBAAIBAAIBAAIBADAxMA0GCWCGSAFlAwQCAQUABCCem01SPQj8YAj/ # IZB5+UPmjkNVNVTBISab7A9yPxkR5qCCJp8wggWNMIIEdaADAgECAhAOmxiO+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 # twGpn1eqXijiuZQwggXfMIIEx6ADAgECAhBOQOQ3VO3mjAAAAABR05R/MA0GCSqG # SIb3DQEBCwUAMIG+MQswCQYDVQQGEwJVUzEWMBQGA1UEChMNRW50cnVzdCwgSW5j # LjEoMCYGA1UECxMfU2VlIHd3dy5lbnRydXN0Lm5ldC9sZWdhbC10ZXJtczE5MDcG # A1UECxMwKGMpIDIwMDkgRW50cnVzdCwgSW5jLiAtIGZvciBhdXRob3JpemVkIHVz # ZSBvbmx5MTIwMAYDVQQDEylFbnRydXN0IFJvb3QgQ2VydGlmaWNhdGlvbiBBdXRo # b3JpdHkgLSBHMjAeFw0yMTA1MDcxNTQzNDVaFw0zMDExMDcxNjEzNDVaMGkxCzAJ # BgNVBAYTAlVTMRYwFAYDVQQKDA1FbnRydXN0LCBJbmMuMUIwQAYDVQQDDDlFbnRy # dXN0IENvZGUgU2lnbmluZyBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IC0g # Q1NCUjEwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCngY/3FEW2YkPy # 2K7TJV5IT1G/xX2fUBw10dZ+YSqUGW0nRqSmGl33VFFqgCLGqGZ1TVSDyV5oG6v2 # W2Swra0gvVTvRmttAudFrnX2joq5Mi6LuHccUk15iF+lOhjJUCyXJy2/2gB9Y3/v # MuxGh2Pbmp/DWiE2e/mb1cqgbnIs/OHxnnBNCFYVb5Cr+0i6udfBgniFZS5/tcnA # 4hS3NxFBBuKK4Kj25X62eAUBw2DtTwdBLgoTSeOQm3/dvfqsv2RR0VybtPVc51z/ # O5uloBrXfQmywrf/bhy8yH3m6Sv8crMU6UpVEoScRCV1HfYq8E+lID1oJethl3wP # 5bY9867DwRG8G47M4EcwXkIAhnHjWKwGymUfe5SmS1dnDH5erXhnW1XjXuvH2OxM # bobL89z4n4eqclgSD32m+PhCOTs8LOQyTUmM4OEAwjignPqEPkHcblauxhpb9Gdo # BQHNG7+uh7ydU/Yu6LZr5JnexU+HWKjSZR7IH9Vybu5ZHFc7CXKd18q3kMbNe0WS # kUIDTH0/yvKquMIOhvMQn0YupGaGaFpoGHApOBGAYGuKQ6NzbOOzazf/5p1nAZKG # 3y9I0ftQYNVc/iHTAUJj/u9wtBfAj6ju08FLXxLq/f0uDodEYOOp9MIYo+P9zgyE # Ig3zp3jak/PbOM+5LzPG/wc8Xr5F0wIDAQABo4IBKzCCAScwDgYDVR0PAQH/BAQD # AgGGMBIGA1UdEwEB/wQIMAYBAf8CAQEwHQYDVR0lBBYwFAYIKwYBBQUHAwMGCCsG # AQUFBwMIMDsGA1UdIAQ0MDIwMAYEVR0gADAoMCYGCCsGAQUFBwIBFhpodHRwOi8v # d3d3LmVudHJ1c3QubmV0L3JwYTAzBggrBgEFBQcBAQQnMCUwIwYIKwYBBQUHMAGG # F2h0dHA6Ly9vY3NwLmVudHJ1c3QubmV0MDAGA1UdHwQpMCcwJaAjoCGGH2h0dHA6 # Ly9jcmwuZW50cnVzdC5uZXQvZzJjYS5jcmwwHQYDVR0OBBYEFIK61j2Xzp/PceiS # N6/9s7VpNVfPMB8GA1UdIwQYMBaAFGpyJnrQHu995ztpUdRsjZ+QEmarMA0GCSqG # SIb3DQEBCwUAA4IBAQAfXkEEtoNwJFMsVXMdZTrA7LR7BJheWTgTCaRZlEJeUL9P # bG4lIJCTWEAN9Rm0Yu4kXsIBWBUCHRAJb6jU+5J+Nzg+LxR9jx1DNmSzZhNfFMyl # cfdbIUvGl77clfxwfREc0yHd0CQ5KcX+Chqlz3t57jpv3ty/6RHdFoMI0yyNf02o # FHkvBWFSOOtg8xRofcuyiq3AlFzkJg4sit1Gw87kVlHFVuOFuE2bRXKLB/GK+0m4 # X9HyloFdaVIk8Qgj0tYjD+uL136LwZNr+vFie1jpUJuXbheIDeHGQ5jXgWG2hZ1H # 7LGerj8gO0Od2KIc4NR8CMKvdgb4YmZ6tvf6yK81MIIGgzCCBGugAwIBAgIQNa+3 # e500H2r8j4RGqzE1KzANBgkqhkiG9w0BAQ0FADBpMQswCQYDVQQGEwJVUzEWMBQG # A1UECgwNRW50cnVzdCwgSW5jLjFCMEAGA1UEAww5RW50cnVzdCBDb2RlIFNpZ25p # bmcgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIENTQlIxMB4XDTIxMDUw # NzE5MTk1MloXDTQwMTIyOTIzNTkwMFowYzELMAkGA1UEBhMCVVMxFjAUBgNVBAoT # DUVudHJ1c3QsIEluYy4xPDA6BgNVBAMTM0VudHJ1c3QgRXh0ZW5kZWQgVmFsaWRh # dGlvbiBDb2RlIFNpZ25pbmcgQ0EgLSBFVkNTMjCCAiIwDQYJKoZIhvcNAQEBBQAD # ggIPADCCAgoCggIBAL69pznJpX3sXWXx9Cuph9DnrRrFGjsYzuGhUY1y+s5YH1y4 # JEIPRtUxl9BKTeObMMm6l6ic/kU2zyeA53u4bsEkt9+ndNyF8qMkWEXMlJQ7AuvE # jXxG9VxmguOkwdMfrG4MUyMO1Dr62kLxg1RfNTJW8rV4m1cASB6pYWEnDnMDQ7bW # cJL71IWaMMaz5ppeS+8dKthmqxZG/wvYD6aJSgJRV0E8QThOl8dRMm1njmahXk2f # NSKv1Wq3f0BfaDXMafrxBfDqhabqMoXLwcHKg2lFSQbcCWy6SWUZjPm3NyeMZJ41 # 4+Xs5wegnahyvG+FOiymFk49nM8I5oL1RH0owL2JrWwv3C94eRHXHHBL3Z0ITF4u # +o29p91j9n/wUjGEbjrY2VyFRJ5jBmnQhlh4iZuHu1gcpChsxv5pCpwerBFgal7J # aWUu7UMtafF4tzstNfKqT+If4wFvkEaq1agNBFegtKzjbb2dGyiAJ0bH2qpnlfHR # h3vHyCXphAyPiTbSvjPhhcAz1aA8GYuvOPLlk4C/xsOre5PEPZ257kV2wNRobzBe # PLQ2+ddFQuASBoDbpSH85wV6KI20jmB798i1SkesFGaXoFppcjFXa1OEzWG6cwcV # cDt7AfynP4wtPYeM+wjX5S8Xg36Cq08J8inhflV3ZZQFHVnUCt2TfuMUXeK7AgMB # AAGjggErMIIBJzASBgNVHRMBAf8ECDAGAQH/AgEAMB0GA1UdDgQWBBTOiU+CUaoV # ooRiyjEjYdJh+/j+eDAfBgNVHSMEGDAWgBSCutY9l86fz3Hokjev/bO1aTVXzzAz # BggrBgEFBQcBAQQnMCUwIwYIKwYBBQUHMAGGF2h0dHA6Ly9vY3NwLmVudHJ1c3Qu # bmV0MDEGA1UdHwQqMCgwJqAkoCKGIGh0dHA6Ly9jcmwuZW50cnVzdC5uZXQvY3Ni # cjEuY3JsMA4GA1UdDwEB/wQEAwIBhjATBgNVHSUEDDAKBggrBgEFBQcDAzBEBgNV # HSAEPTA7MDAGBFUdIAAwKDAmBggrBgEFBQcCARYaaHR0cDovL3d3dy5lbnRydXN0 # Lm5ldC9ycGEwBwYFZ4EMAQMwDQYJKoZIhvcNAQENBQADggIBAD4AVLgq849mr2EW # xFiTZPRBi2RVjRs1M6GbkdirRsqrX7y+fnDk0tcHqJYH14bRVwoI0NB4Tfgq37IE # 85rh13zwwQB6wUCh34qMt8u0HQFh8piapt24gwXKqSwW3JwtDv6nl+RQqZeVwUsq # jFHjxALga3w1TVO8S5QTi1MYFl6mCqe4NMFssess5DF9DCzGfOGkVugtdtWyE3Xq # gwCuAHfGb6k97mMUgVAW/FtPEhkOWw+N6kvOBkyJS64gzI5HpnXWZe4vMOhdNI8f # gk1cQqbyFExQIJwJonQkXDnYiTKFPK+M5Wqe5gQ6pRP/qh3NR0suAgW0ao/rhU+B # 7wrbfZ8pj6XCP1I4UkGVO7w+W1QwQiMJY95QjYk1RfqruA+Poq17ehGT8Y8ohHto # eUdq6GQpTR/0HS9tHsiUhjzTWpl6a3yrNfcrOUtPuT8Wku8pjI2rrAEazHFEOctA # PiASzghw40f+3IDXCADRC2rqIbV5ZhfpaqpW3c0VeLEDwBStPkcYde0KU0syk83/ # gLGQ1hPl5EF4Iu1BguUO37DOlSFF5osB0xn39CtVrNlWc2MQ4LigbctUlpigmSFR # BqqmDDorY8t52kO50hLM3o9VeukJ8+Ka0yXBezaS2uDlUmfN4+ZUCqWd1HOj0y9d # BmSFA3d/YNjCvHTJlZFot7d+YRl1MIIGtDCCBJygAwIBAgIQDcesVwX/IZkuQEMi # DDpJhjANBgkqhkiG9w0BAQsFADBiMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGln # aUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSEwHwYDVQQDExhE # aWdpQ2VydCBUcnVzdGVkIFJvb3QgRzQwHhcNMjUwNTA3MDAwMDAwWhcNMzgwMTE0 # MjM1OTU5WjBpMQswCQYDVQQGEwJVUzEXMBUGA1UEChMORGlnaUNlcnQsIEluYy4x # QTA/BgNVBAMTOERpZ2lDZXJ0IFRydXN0ZWQgRzQgVGltZVN0YW1waW5nIFJTQTQw # OTYgU0hBMjU2IDIwMjUgQ0ExMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKC # AgEAtHgx0wqYQXK+PEbAHKx126NGaHS0URedTa2NDZS1mZaDLFTtQ2oRjzUXMmxC # qvkbsDpz4aH+qbxeLho8I6jY3xL1IusLopuW2qftJYJaDNs1+JH7Z+QdSKWM06qc # hUP+AbdJgMQB3h2DZ0Mal5kYp77jYMVQXSZH++0trj6Ao+xh/AS7sQRuQL37QXbD # hAktVJMQbzIBHYJBYgzWIjk8eDrYhXDEpKk7RdoX0M980EpLtlrNyHw0Xm+nt5pn # YJU3Gmq6bNMI1I7Gb5IBZK4ivbVCiZv7PNBYqHEpNVWC2ZQ8BbfnFRQVESYOszFI # 2Wv82wnJRfN20VRS3hpLgIR4hjzL0hpoYGk81coWJ+KdPvMvaB0WkE/2qHxJ0ucS # 638ZxqU14lDnki7CcoKCz6eum5A19WZQHkqUJfdkDjHkccpL6uoG8pbF0LJAQQZx # st7VvwDDjAmSFTUms+wV/FbWBqi7fTJnjq3hj0XbQcd8hjj/q8d6ylgxCZSKi17y # Vp2NL+cnT6Toy+rN+nM8M7LnLqCrO2JP3oW//1sfuZDKiDEb1AQ8es9Xr/u6bDTn # YCTKIsDq1BtmXUqEG1NqzJKS4kOmxkYp2WyODi7vQTCBZtVFJfVZ3j7OgWmnhFr4 # yUozZtqgPrHRVHhGNKlYzyjlroPxul+bgIspzOwbtmsgY1MCAwEAAaOCAV0wggFZ # MBIGA1UdEwEB/wQIMAYBAf8CAQAwHQYDVR0OBBYEFO9vU0rp5AZ8esrikFb2L9RJ # 7MtOMB8GA1UdIwQYMBaAFOzX44LScV1kTN8uZz/nupiuHA9PMA4GA1UdDwEB/wQE # AwIBhjATBgNVHSUEDDAKBggrBgEFBQcDCDB3BggrBgEFBQcBAQRrMGkwJAYIKwYB # BQUHMAGGGGh0dHA6Ly9vY3NwLmRpZ2ljZXJ0LmNvbTBBBggrBgEFBQcwAoY1aHR0 # cDovL2NhY2VydHMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0VHJ1c3RlZFJvb3RHNC5j # cnQwQwYDVR0fBDwwOjA4oDagNIYyaHR0cDovL2NybDMuZGlnaWNlcnQuY29tL0Rp # Z2lDZXJ0VHJ1c3RlZFJvb3RHNC5jcmwwIAYDVR0gBBkwFzAIBgZngQwBBAIwCwYJ # YIZIAYb9bAcBMA0GCSqGSIb3DQEBCwUAA4ICAQAXzvsWgBz+Bz0RdnEwvb4LyLU0 # pn/N0IfFiBowf0/Dm1wGc/Do7oVMY2mhXZXjDNJQa8j00DNqhCT3t+s8G0iP5kvN # 2n7Jd2E4/iEIUBO41P5F448rSYJ59Ib61eoalhnd6ywFLerycvZTAz40y8S4F3/a # +Z1jEMK/DMm/axFSgoR8n6c3nuZB9BfBwAQYK9FHaoq2e26MHvVY9gCDA/JYsq7p # GdogP8HRtrYfctSLANEBfHU16r3J05qX3kId+ZOczgj5kjatVB+NdADVZKON/gnZ # ruMvNYY2o1f4MXRJDMdTSlOLh0HCn2cQLwQCqjFbqrXuvTPSegOOzr4EWj7PtspI # HBldNE2K9i697cvaiIo2p61Ed2p8xMJb82Yosn0z4y25xUbI7GIN/TpVfHIqQ6Ku # /qjTY6hc3hsXMrS+U0yy+GWqAXam4ToWd2UQ1KYT70kZjE4YtL8Pbzg0c1ugMZyZ # Zd/BdHLiRu7hAWE6bTEm4XYRkA6Tl4KSFLFk43esaUeqGkH/wyW4N7OigizwJWeu # kcyIPbAvjSabnf7+Pu0VrFgoiovRDiyx3zEdmcif/sYQsfch28bZeUz2rtY/9TCA # 6TD8dC3JE3rYkrhLULy7Dc90G6e8BlqmyIjlgp2+VqsS9/wQD7yFylIz0scmbKvF # oW2jNrbM1pD2T7m3XDCCBu0wggTVoAMCAQICEAqA7xhLjfEFgtHEdqeVdGgwDQYJ # KoZIhvcNAQELBQAwaTELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDkRpZ2lDZXJ0LCBJ # bmMuMUEwPwYDVQQDEzhEaWdpQ2VydCBUcnVzdGVkIEc0IFRpbWVTdGFtcGluZyBS # U0E0MDk2IFNIQTI1NiAyMDI1IENBMTAeFw0yNTA2MDQwMDAwMDBaFw0zNjA5MDMy # MzU5NTlaMGMxCzAJBgNVBAYTAlVTMRcwFQYDVQQKEw5EaWdpQ2VydCwgSW5jLjE7 # MDkGA1UEAxMyRGlnaUNlcnQgU0hBMjU2IFJTQTQwOTYgVGltZXN0YW1wIFJlc3Bv # bmRlciAyMDI1IDEwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDQRqwt # Esae0OquYFazK1e6b1H/hnAKAd/KN8wZQjBjMqiZ3xTWcfsLwOvRxUwXcGx8AUjn # i6bz52fGTfr6PHRNv6T7zsf1Y/E3IU8kgNkeECqVQ+3bzWYesFtkepErvUSbf+EI # YLkrLKd6qJnuzK8Vcn0DvbDMemQFoxQ2Dsw4vEjoT1FpS54dNApZfKY61HAldytx # NM89PZXUP/5wWWURK+IfxiOg8W9lKMqzdIo7VA1R0V3Zp3DjjANwqAf4lEkTlCDQ # 0/fKJLKLkzGBTpx6EYevvOi7XOc4zyh1uSqgr6UnbksIcFJqLbkIXIPbcNmA98Os # kkkrvt6lPAw/p4oDSRZreiwB7x9ykrjS6GS3NR39iTTFS+ENTqW8m6THuOmHHjQN # C3zbJ6nJ6SXiLSvw4Smz8U07hqF+8CTXaETkVWz0dVVZw7knh1WZXOLHgDvundrA # tuvz0D3T+dYaNcwafsVCGZKUhQPL1naFKBy1p6llN3QgshRta6Eq4B40h5avMcpi # 54wm0i2ePZD5pPIssoszQyF4//3DoK2O65Uck5Wggn8O2klETsJ7u8xEehGifgJY # i+6I03UuT1j7FnrqVrOzaQoVJOeeStPeldYRNMmSF3voIgMFtNGh86w3ISHNm0Ia # adCKCkUe2LnwJKa8TIlwCUNVwppwn4D3/Pt5pwIDAQABo4IBlTCCAZEwDAYDVR0T # AQH/BAIwADAdBgNVHQ4EFgQU5Dv88jHt/f3X85FxYxlQQ89hjOgwHwYDVR0jBBgw # FoAU729TSunkBnx6yuKQVvYv1Ensy04wDgYDVR0PAQH/BAQDAgeAMBYGA1UdJQEB # /wQMMAoGCCsGAQUFBwMIMIGVBggrBgEFBQcBAQSBiDCBhTAkBggrBgEFBQcwAYYY # aHR0cDovL29jc3AuZGlnaWNlcnQuY29tMF0GCCsGAQUFBzAChlFodHRwOi8vY2Fj # ZXJ0cy5kaWdpY2VydC5jb20vRGlnaUNlcnRUcnVzdGVkRzRUaW1lU3RhbXBpbmdS # U0E0MDk2U0hBMjU2MjAyNUNBMS5jcnQwXwYDVR0fBFgwVjBUoFKgUIZOaHR0cDov # L2NybDMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0VHJ1c3RlZEc0VGltZVN0YW1waW5n # UlNBNDA5NlNIQTI1NjIwMjVDQTEuY3JsMCAGA1UdIAQZMBcwCAYGZ4EMAQQCMAsG # CWCGSAGG/WwHATANBgkqhkiG9w0BAQsFAAOCAgEAZSqt8RwnBLmuYEHs0QhEnmNA # ciH45PYiT9s1i6UKtW+FERp8FgXRGQ/YAavXzWjZhY+hIfP2JkQ38U+wtJPBVBaj # YfrbIYG+Dui4I4PCvHpQuPqFgqp1PzC/ZRX4pvP/ciZmUnthfAEP1HShTrY+2DE5 # qjzvZs7JIIgt0GCFD9ktx0LxxtRQ7vllKluHWiKk6FxRPyUPxAAYH2Vy1lNM4kze # kd8oEARzFAWgeW3az2xejEWLNN4eKGxDJ8WDl/FQUSntbjZ80FU3i54tpx5F/0Kr # 15zW/mJAxZMVBrTE2oi0fcI8VMbtoRAmaaslNXdCG1+lqvP4FbrQ6IwSBXkZagHL # hFU9HCrG/syTRLLhAezu/3Lr00GrJzPQFnCEH1Y58678IgmfORBPC1JKkYaEt2Od # Dh4GmO0/5cHelAK2/gTlQJINqDr6JfwyYHXSd+V08X1JUPvB4ILfJdmL+66Gp3CS # BXG6IwXMZUXBhtCyIaehr0XkBoDIGMUG1dUtwq1qmcwbdUfcSYCn+OwncVUXf53V # JUNOaMWMts0VlRYxe5nK+At+DI96HAlXHAL5SlfYxJ7La54i71McVWRP66bW+yER # NpbJCjyCYG2j+bdpxo/1Cy4uPcU3AWVPGrbn5PhDBf3Froguzzhk++ami+r3Qrx5 # bIbY3TVzgiFI7Gq3zWcwggb3MIIE36ADAgECAhBUqhzmzdht2UDqAdaKxc8tMA0G # CSqGSIb3DQEBCwUAMGMxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1FbnRydXN0LCBJ # bmMuMTwwOgYDVQQDEzNFbnRydXN0IEV4dGVuZGVkIFZhbGlkYXRpb24gQ29kZSBT # aWduaW5nIENBIC0gRVZDUzIwHhcNMjMxMTExMDIzNDE2WhcNMjYxMTExMDIzNDE1 # WjCB0jELMAkGA1UEBhMCVVMxETAPBgNVBAgTCE5ldyBZb3JrMQ8wDQYDVQQHEwZS # b3NseW4xEzARBgsrBgEEAYI3PAIBAxMCVVMxGTAXBgsrBgEEAYI3PAIBAhMITmV3 # IFlvcmsxHjAcBgNVBAoTFUxJU1MgQ29uc3VsdGluZyBDb3JwLjEdMBsGA1UEDxMU # UHJpdmF0ZSBPcmdhbml6YXRpb24xEDAOBgNVBAUTBzEyMDM3MDQxHjAcBgNVBAMT # FUxJU1MgQ29uc3VsdGluZyBDb3JwLjCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCC # AgoCggIBAKNsPm91CdVgVgztDDAOq1XypBtPfEFiuIjryZikaVh3+iPoixSaa4MA # MZe8gR//KdBwqwyfKHRLj79VfmtcRQJtcuuzfdRXlmnvZOcfwOuhnl7dp3ZyON2B # +m/wTxvRulpTfOf7Xa/XD+vseSMZk5Cr3VGs5c8CnfFPxboSGjxPI5iNfEe/hJvI # BS/aYVL/sZqNdCqarwUCC0YuaVCbOiOlpV1h3hfrVQq9eB5FVI8u7YRh0jetAt96 # LoiYwXxmLdxXtMHAZPhLCfJndTVwOgo6P08j+BFViHtHZGOLgH9gC32OPZvGAM69 # IoessdwAK31fBO/alVk2TBnjjaCMiLD7goDYIP9GzDE+o8rO8pcyse4a1s+uF4By # DiotV0/3L1XFneFA9llG1PgmpU0P7myHJGa2BTUuNcZ5NVNEdINGCg3rDEb2oRje # ukOn83iRtsTnV8kdd4BXuEFptjNqj9M6fvk+LJxsZZ7pKaNGlugPH/hb93+2WXd3 # ImzPCLBOQBs9Ms7rgjlGzfZP/cTJibogaYNYhb6mblEHpm5UhBNrJk9ONRNfDjDB # Lz7eeAWtZGHerL3vpaBHCC4QA1aIKMmolnXjBCAsEhqbJnKZEb/fVjfU7fX5/TQJ # lu+w6AZ6y4rBITex0QMGUlcYh1pnQf0tTikfyH250Gyr1pBaD1rvAgMBAAGjggE1 # MIIBMTAMBgNVHRMBAf8EAjAAMB0GA1UdDgQWBBS8w1GaCwrKaNGXgF9k+1HbSv8Y # uTAfBgNVHSMEGDAWgBTOiU+CUaoVooRiyjEjYdJh+/j+eDBnBggrBgEFBQcBAQRb # MFkwIwYIKwYBBQUHMAGGF2h0dHA6Ly9vY3NwLmVudHJ1c3QubmV0MDIGCCsGAQUF # BzAChiZodHRwOi8vYWlhLmVudHJ1c3QubmV0L2V2Y3MyLWNoYWluLnA3YzAxBgNV # HR8EKjAoMCagJKAihiBodHRwOi8vY3JsLmVudHJ1c3QubmV0L2V2Y3MyLmNybDAO # BgNVHQ8BAf8EBAMCB4AwEwYDVR0lBAwwCgYIKwYBBQUHAwMwIAYDVR0gBBkwFzAH # BgVngQwBAzAMBgpghkgBhvpsCgECMA0GCSqGSIb3DQEBCwUAA4ICAQBoCI/Q8Bgz # wIuP21o96o9uMEbhUfRQ6JBB2/1jfNHJewHbMk9D3ftAEYj7nJSWeLpk8TOSPeeg # tpsG8BEj3KZxDKg08jxWcDMCi0SBh31I3gMQowFh8fD3QjgMpb4gW5r9TZttLn2G # txzBuoamhesLb3Bfr492InciZbSXgipiaKUa5ocj1mOuo9Y8I/SlN8yhuREULW59 # JsvWwcNDInmTyxNuQ/4HoeBzXn7I3CY+rlm4aXOmnhE3Fbe3jINEFkCIROTOQ+Ps # gFlOFaz0gGuT8gfmSxiCrMzE90Nfucuay/RxCRsh9Xqu9uxyHCQCuJ4gvvGj431f # UpCOAzRM/ogk9Udna8Gs22tmCrfMQAT+KNtuewT0EYH4qqpkrAxm9RQwUk7cMG35 # ebua7D3pe4OwKe8TldRibPxKBMWueJll+Ku/jWRIL2urhwD1wqZtguYqoLqXHWQR # bd7nt60I+VxIusDiK80OyHXK7gAy1ibC7eAlpaOTOcJ92RAX6cIzKmutaxZLNZtl # u6n/aSBs7saPOb+848VgadEmBXQzOyRspay8JwQ+7C5Tuqa8/S7Qr6yKD7Sosm31 # ZOk8v59Oy+0Q4YiO0gkua/yZpnxGeutJVYteE8t7muhHk3zoGkMmG/K6CvxK3rxz # LuvDI0xr73Ai+rIuifNtzu4NvT8hBzGkwTGCBlMwggZPAgEBMHcwYzELMAkGA1UE # BhMCVVMxFjAUBgNVBAoTDUVudHJ1c3QsIEluYy4xPDA6BgNVBAMTM0VudHJ1c3Qg # RXh0ZW5kZWQgVmFsaWRhdGlvbiBDb2RlIFNpZ25pbmcgQ0EgLSBFVkNTMgIQVKoc # 5s3YbdlA6gHWisXPLTANBglghkgBZQMEAgEFAKCBhDAYBgorBgEEAYI3AgEMMQow # CKACgAChAoAAMBkGCSqGSIb3DQEJAzEMBgorBgEEAYI3AgEEMBwGCisGAQQBgjcC # AQsxDjAMBgorBgEEAYI3AgEVMC8GCSqGSIb3DQEJBDEiBCArvVXnwPygehnqbJ/b # CDlUKN+Mnd0Mfq/LYeOPQJ6aAjANBgkqhkiG9w0BAQEFAASCAgCeYCxjMA2kyX5K # z9GEDfoYH6YCZ9owS4d7yaK1ZajhfMFlbYjCgkPysnQ6jEpirjyhWqOrJpyPOUbu # qqiC4nBelSPJbONZTH6IpYA47HsO4sd/DnAjt8cbSxaGXCS1Oo7v+V/+5Ru9Df7h # K03zJIatBM8LRogJm+NmjPN9FpxBOO0Al/JAUJyKtelpsIYKEYCgVzYCqxRrosFu # c47R+1CupZnhN9pyXtMUzGtm/Ndx5rkNHv0KKkGV856Vj52AH+QmwxU7jrPnjR46 # V9yDaRwvXulcvvRWrXANJfkKPWT+HcIUq8ZBMHTjd7tmNARynEGLkX3GVMXk7qlm # 0QDx1xa52QskvnPcPuNm+Onx2+n4O/NRdP8Z3+Z5Cs/dSlggL7Dnf/KZD0hNiR7y # EENFLjLKlc6icxntKozoPAjjNFE2U35t8ysbSyIP6tHW2vVDK9lbnsPuDhaWxlh7 # F4DabGwWrk+z0Qa4JzIG+j2eappA1c5F8WbHMG4c3n2NCWVo8jIfFM6DLLKwb/hz # bxjCUC/oj0UeLNSiP5uvEODrOvsJ9u+SpRBEirTLdWJkwuapuRz5oXEKVvAkbYkA # RCzNqPdZplzF0UWs2ZI7V0DzZJZ3QvRwfT8lJBVaM7D2BG9YQ7rHx32AcWq2y4Io # j+s9TZA8fYZGaYPOS6UYx38tDa7oPaGCAyYwggMiBgkqhkiG9w0BCQYxggMTMIID # DwIBATB9MGkxCzAJBgNVBAYTAlVTMRcwFQYDVQQKEw5EaWdpQ2VydCwgSW5jLjFB # MD8GA1UEAxM4RGlnaUNlcnQgVHJ1c3RlZCBHNCBUaW1lU3RhbXBpbmcgUlNBNDA5 # NiBTSEEyNTYgMjAyNSBDQTECEAqA7xhLjfEFgtHEdqeVdGgwDQYJYIZIAWUDBAIB # BQCgaTAYBgkqhkiG9w0BCQMxCwYJKoZIhvcNAQcBMBwGCSqGSIb3DQEJBTEPFw0y # NjA0MDMyMDExMjZaMC8GCSqGSIb3DQEJBDEiBCC3huBE9EEfNFQC2kuElVs8q2vU # rRAJKvLK6qsXjqe9HzANBgkqhkiG9w0BAQEFAASCAgBgUVyKrLlpm2OTgbV48DDp # wfRcdi4QZ0S/qH0303QYBK6WptzyCv7oteq0l+6EIPj1etZWZDFjJ5qZIHqUIwff # f+n4xsnCCSoLBSpxXsRxvvmcjZZMV82ZEUjmaBn8HOFu13bGZXoKm7dpJ9FYSBYO # 2HDYynsKEd2iZIBVekE/wnIGZl4MI8mX2u0Qcxa0YjoZjxLTu/cwFwzqgIQh1Zjw # JDFM8zm70sheLckm7TIl4p1bQmgazi73jFEiqEOwDXns1kCvzGO2waS0AuKc2qY9 # cYlnS1p6r8KoPSOslQUUngkVAP9soJLQSB2YRGDrgRa+fs+6I97wbbS26ABfInj4 # PoR+fENk9JBkhnsnkz+3Y2bYhfF+B3Wx3n+1u/z8aq68EcUER1o98Y2jgKnEEat5 # SiFFHoxfMJTZekCbNLeuQXkfG48uoccz5xA7ZM7gZ/qCCImXGmn3gf0LB+GtYQcx # PwFUJhLdVAtzco9VhBw/NsSXf0zbmr7hO3kEpzoqS4fij4j/250Zgnnc4JBCl61D # FTbFzU6s9+7UtedYgvrBYelwd46xnj5j1520xAYrGJYms8uVOe0b98YOeggHjKz9 # 9AotS6p7NH2xNojrDECNltJH8HF6k2PVTLxu6McbxfWZZQgQRtuSfYp1MRnayAFw # GCBcbhPL1BkCzvkxl33EVg== # SIG # End signature block |