Public/ps1/Job/Get-ApprxrRemoteJob.ps1
|
<#
.SYNOPSIS Retrieves and executes a remote job for a specified Apprxr pipeline. .DESCRIPTION Fetches a job assignment from the remote server for the given pipeline, processes the job, and logs the result. Supports multiple job types: - SQL: Executes a SQL job using Start-ApprxrJobSql - FILE: Handles file jobs using Start-ApprxrJobFile - HTTP: Executes HTTP jobs using Start-ApprxrJobHtml - PRINT: Sends a base64 PDF/ZPL to a printer (auto-detects Zebra) and returns print queue - GET_PRINTERS: Returns all available printers with driver, type, and Zebra/label detection - GET_PRINT_QUEUE: Returns the current print queue for a printer (or all printers) - RESET_SPOOLER: Force-stops the print spooler, deletes stuck spool files, and restarts the service (recovery for hung spooler) - START_PIPELINES: Starts all Apprxr pipelines with startup validation - START_PIPELINE: Starts a single pipeline by name (arguments.Name) - STOP_PIPELINES: Stops all Apprxr jobs - GET_PIPELINES: Retrieves all pipeline names - CREATE_PIPELINE: Creates a new pipeline job - SELFUPDATE: Triggers Apprxr module upgrade - GET_VERSION: Returns Apprxr environment information from Get-ApprxrInfo, including the module version - LOGFILE: Returns the last N lines of the current log file - ERRORLOG: Returns the last N lines of the error log file (errors only) - ROTATE_LOG: Rotates the current log file to an archive (independent of retention) - GET_LOGFILES: Returns a list of all available log files with size and last modified date - DELETE_LOGFILE: Deletes a specific log file by name (from job.arguments.FileName) - POWERSHELL: Executes arbitrary PowerShell code (if provided) Logs all actions and sends results back to the remote server. .PARAMETER pipeline The name of the pipeline to retrieve a job for. Use 'Default' for the default channel. .EXAMPLE Get-ApprxrRemoteJob -pipeline 'Pipeline1' # Retrieves and executes a remote job for the 'Pipeline1' channel. .EXAMPLE Get-ApprxrRemoteJob -pipeline 'Default' # Retrieves and executes a remote job for the default channel. .NOTES - Used for remote job management and execution in Apprxr automation. - Handles multiple job types and actions as described above. - Sends job results back to the remote server via Get-ApprxrResult. - Logs all received jobs and actions for auditing. - Errors are returned in the result object and logged. #> function Get-ApprxrRemoteJob{ param ($pipeline) if (-not [string]::IsNullOrEmpty($pipeline) -and $pipeline -ne "Default") { $channelId = "?channelId=$($pipeline)" } $deliverResult = "api/services/app/RemoteControl/SetDeliveries" $getTask= "api/services/app/RemoteControl/GetAssignment$channelId" #Get the job from the server $job = (Get-ApprxrResult -request $getTask).result if (-not $job){ return } try { # Log the job but truncate large payloads (Base64File can be many MB) $jobLogSafe = $job | ConvertTo-Json -Depth 2 -Compress if ($jobLogSafe.Length -gt 2000) { $jobLogSafe = $jobLogSafe.Substring(0, 2000) + '... [truncated]' } Log "Receive the following job: $jobLogSafe" $jobLogSafe = $null if ($job.Action -eq "SQL") { $sqlResult = Start-ApprxrJobSql -taskInformation $job $result = [PSCustomObject]@{ data = $sqlResult.data success = $sqlResult.success message = $sqlResult.message Id = $job.Id } # Truncate SQL log to avoid serialising huge DataTable results. $sqlLogJson = $result | ConvertTo-Json -Depth 3 if ($sqlLogJson.Length -gt 10000) { $sqlLogJson = $sqlLogJson.Substring(0, 10000) + '... [truncated]' } Log ("SQL result: " + $sqlLogJson) $sqlLogJson = $null } elseif ($job.Action -eq "FILE") { $fileResult = Start-ApprxrJobFile -Base64File ($job.arguments.Base64File) -FileLocation ($job.arguments.FileLocation) -Mode ($job.arguments.Mode) -FileName ($job.arguments.FileName) $result = [PSCustomObject]@{ data = $fileResult.data success = $fileResult.success message = $fileResult.message Id = $job.Id } } elseif ($job.Action -eq "HTTP") { $httpResult = Start-ApprxrJobHtml -taskInformation $job $result = [PSCustomObject]@{ data = $httpResult.data success = $httpResult.success message = $httpResult.message Id = $job.Id } } elseif ($job.Action -eq "PRINT") { $printResult = Start-ApprxrJobPrint -taskInformation $job $result = [PSCustomObject]@{ data = @($printResult.data) success = $printResult.success message = $printResult.message Id = $job.Id } } elseif ($job.Action -eq "GET_PRINTERS") { try { $printerList = @(Get-ApprxrPrinters) $result = [PSCustomObject]@{ success = $true message = "$($printerList.Count) printer(s) found" data = $printerList Id = $job.Id } } catch { $result = [PSCustomObject]@{ success = $false message = "Failed to list printers: $_" Id = $job.Id } } } elseif ($job.Action -eq "GET_PRINT_QUEUE") { try { $queuePrinterName = if ($job.arguments -and $job.arguments.PrinterName) { $job.arguments.PrinterName } else { $null } $queueData = Get-ApprxrPrintQueue -PrinterName $queuePrinterName $result = [PSCustomObject]@{ success = $true message = "$($queueData.Count) entry/entries in print queue" data = @($queueData) Id = $job.Id } } catch { $result = [PSCustomObject]@{ success = $false message = "Failed to get print queue: $_" Id = $job.Id } } } elseif ($job.Action -eq "RESET_SPOOLER") { # Recovery sequence for a wedged print spooler: force-stop the # service (kill spoolsv.exe if it ignores the stop), delete any # stuck files in the spool folder, then start the service back # up. Destructive: every queued job on the host is discarded. $resetSteps = @() $resetData = @{ } try { # 1. Try a clean stop, then escalate to killing spoolsv.exe. try { Stop-Service -Name Spooler -Force -ErrorAction Stop $resetSteps += 'Stop-Service Spooler succeeded' } catch { $resetSteps += "Stop-Service failed ($($_.Exception.Message)); falling back to Stop-Process" $proc = Get-Process spoolsv -ErrorAction SilentlyContinue if ($proc) { try { Stop-Process -Id $proc.Id -Force -ErrorAction Stop $resetSteps += "Killed spoolsv.exe (PID $($proc.Id))" } catch { $resetSteps += "Stop-Process for spoolsv (PID $($proc.Id)) failed: $($_.Exception.Message)" } } else { $resetSteps += 'spoolsv.exe was not running' } } # 2. Wait up to 15s for the service to actually stop. $deadline = (Get-Date).AddSeconds(15) while ((Get-Service Spooler -ErrorAction SilentlyContinue).Status -ne 'Stopped' -and (Get-Date) -lt $deadline) { Start-Sleep -Milliseconds 500 } $stoppedStatus = (Get-Service Spooler -ErrorAction SilentlyContinue).Status $resetSteps += "Spooler status after stop: $stoppedStatus" # 3. Delete every file in the spool folder (the source of the wedge). $spoolPath = Join-Path $env:windir 'System32\spool\PRINTERS' $stuckCount = 0 if (Test-Path $spoolPath) { $stuckFiles = @(Get-ChildItem -Path $spoolPath -File -ErrorAction SilentlyContinue) $stuckCount = $stuckFiles.Count foreach ($sf in $stuckFiles) { Remove-Item -Path $sf.FullName -Force -ErrorAction SilentlyContinue } $resetSteps += "Removed $stuckCount file(s) from $spoolPath" } else { $resetSteps += "Spool path '$spoolPath' does not exist - skipped" } # 4. Start the service back up and verify. try { Start-Service -Name Spooler -ErrorAction Stop $resetSteps += 'Start-Service Spooler succeeded' } catch { $resetSteps += "Start-Service Spooler failed: $($_.Exception.Message)" } $finalStatus = (Get-Service Spooler -ErrorAction SilentlyContinue).Status $resetSteps += "Spooler final status: $finalStatus" $resetData = @{ FinalStatus = "$finalStatus" StuckFilesRemoved = $stuckCount Steps = $resetSteps } $result = [PSCustomObject]@{ success = ($finalStatus -eq 'Running') message = "RESET_SPOOLER: final status '$finalStatus'; removed $stuckCount stuck file(s)." data = @($resetData) Id = $job.Id } } catch { $result = [PSCustomObject]@{ success = $false message = "RESET_SPOOLER failed: $($_.Exception.Message). Steps so far: $($resetSteps -join '; ')" data = @(@{ Steps = $resetSteps }) Id = $job.Id } } } elseif ($job.Action -eq "START_PIPELINES") { try { $startResult = Start-ApprxrPipelines $allOk = $startResult.Failed.Count -eq 0 $result = [PSCustomObject]@{ success = $allOk message = "Started: $($startResult.Started.Count), Failed: $($startResult.Failed.Count)" + $(if ($startResult.Failed.Count -gt 0) { " ($($startResult.Failed -join ', '))" } else { '' }) data = @($startResult) Id = $job.Id } } catch { $result = [PSCustomObject]@{ success = $false message = "Failed to start pipelines: $_" Id = $job.Id } } } elseif ($job.Action -eq "START_PIPELINE") { try { if (-not $job.arguments -or -not $job.arguments.Name) { throw "Missing required argument: arguments.Name. Expected: { `"Action`": `"START_PIPELINE`", `"arguments`": { `"Name`": `"PipelineName`" } }" } $startResult = Start-ApprxrPipelines -Name $job.arguments.Name $ok = $startResult.Failed.Count -eq 0 $result = [PSCustomObject]@{ success = $ok message = if ($ok) { "Pipeline '$($job.arguments.Name)' started" } else { "Pipeline '$($job.arguments.Name)' failed to start" } data = @($startResult) Id = $job.Id } } catch { $result = [PSCustomObject]@{ success = $false message = "Failed to start pipeline: $_" Id = $job.Id } } } elseif ($job.Action -eq "GET_PIPELINES") { $pipelineNames = @(Get-ApprxrPipelines) $result = [PSCustomObject]@{ success = $true message = "Found $($pipelineNames.Count) pipeline(s): $($pipelineNames -join ', ')" data = $pipelineNames Id = $job.Id } } elseif ($job.Action -eq "STOP_PIPELINES") { try { $stopResult = Stop-ApprxrJobs $allOk = $stopResult.Failed.Count -eq 0 $result = [PSCustomObject]@{ success = $allOk message = "Stopped: $($stopResult.Stopped.Count), Failed: $($stopResult.Failed.Count)" + $(if ($stopResult.Failed.Count -gt 0) { " ($($stopResult.Failed -join ', '))" } else { '' }) data = @($stopResult) Id = $job.Id } } catch { $result = [PSCustomObject]@{ success = $false message = "Failed to stop pipelines: $_" Id = $job.Id } } } elseif ($job.Action -eq "CREATE_PIPELINE") { try { if (-not $job.arguments -or -not $job.arguments.Name) { throw "Missing required argument: arguments.Name. Expected: { `"Action`": `"CREATE_PIPELINE`", `"arguments`": { `"Name`": `"PipelineName`", `"WaitTime`": 10, `"DirectProcessing`": false } }" } $pipelineSleep = if ($job.arguments.WaitTime) { [int]$job.arguments.WaitTime } else { 10 } $pipelineDirect = if ($job.arguments.DirectProcessing) { [bool]$job.arguments.DirectProcessing } else { $false } Create-ApprxrPipelineJob -jobParam $job.arguments $result = [PSCustomObject]@{ success = $true message = "Pipeline '$($job.arguments.Name)' created (Sleep=$pipelineSleep, DirectProcessing=$pipelineDirect)" Id = $job.Id } } catch { $result = [PSCustomObject]@{ success = $false message = "Failed to create pipeline: $_" Id = $job.Id } } } elseif ($job.Action -eq "SELFUPDATE") { $result = [PSCustomObject]@{ success = $true message = Start-ApprxrUpgrade Id = $job.Id } } elseif ($job.Action -eq "GET_VERSION") { $info = Get-ApprxrInfo $result = [PSCustomObject]@{ success = $true message = "Apprxr status generated on $((Get-Date).ToString('yyyy-MM-dd HH:mm:ss')) (version $($info.Version))." data = @($info) Id = $job.Id } } elseif ($job.Action -eq "LOGFILE") { #$lines = if ($job.arguments.Lines) { $job.arguments.Lines } else { 50 } $lines = 250 $logContent = [string](Get-ApprxrLog -Tail $lines | Out-String) $result = [PSCustomObject]@{ success = $true message = $logContent Id = $job.Id } } elseif ($job.Action -eq "ERRORLOG") { $lines = 250 $logContent = [string](Get-ApprxrLog -Tail $lines -ErrorLog | Out-String) $result = [PSCustomObject]@{ success = $true message = if ([string]::IsNullOrWhiteSpace($logContent)) { "(no errors recorded)" } else { $logContent } Id = $job.Id } } elseif ($job.Action -eq "ROTATE_LOG") { try { Log "ROTATE_LOG: Rotating current log file on demand" Move-ApprxrLogFile $result = [PSCustomObject]@{ success = $true message = "Log file rotated successfully" Id = $job.Id } } catch { $result = [PSCustomObject]@{ success = $false message = "Failed to rotate log file: $_" Id = $job.Id } } } elseif ($job.Action -eq "GET_LOGFILES") { try { $logFolder = if ($LogManagement -and $LogManagement.LogFolder) { Split-Path $LogManagement.LogFolder -Parent } else { $null } if (-not $logFolder -or -not (Test-Path $logFolder)) { $result = [PSCustomObject]@{ success = $false message = "Log folder not found: $logFolder" Id = $job.Id } } else { $logFiles = @(Get-ChildItem -Path $logFolder -File -ErrorAction Stop | Where-Object { $_.Name -like 'logfile*' } | Sort-Object LastWriteTime -Descending | ForEach-Object { [PSCustomObject]@{ Name = $_.Name SizeKB = [math]::Round($_.Length / 1KB, 1) LastModified = $_.LastWriteTime.ToString('yyyy-MM-dd HH:mm:ss') } }) $result = [PSCustomObject]@{ success = $true message = "$($logFiles.Count) log file(s) found" data = $logFiles Id = $job.Id } } } catch { $result = [PSCustomObject]@{ success = $false message = "Failed to list log files: $_" Id = $job.Id } } } elseif ($job.Action -eq "DELETE_LOGFILE") { try { $fileNameToDelete = $job.arguments.FileName if ([string]::IsNullOrWhiteSpace($fileNameToDelete)) { $result = [PSCustomObject]@{ success = $false message = "DELETE_LOGFILE: FileName argument is required. Expected: { `"Action`": `"DELETE_LOGFILE`", `"arguments`": { `"FileName`": `"logfile.txt_1712678400`" } }" Id = $job.Id } } else { $logFolder = if ($LogManagement -and $LogManagement.LogFolder) { Split-Path $LogManagement.LogFolder -Parent } else { $null } # Prevent path traversal — only allow plain file names if ($fileNameToDelete -match '[/\\]') { $result = [PSCustomObject]@{ success = $false message = "DELETE_LOGFILE: Path separators not allowed in FileName. Use plain file name only, e.g. `"logfile.txt_1712678400`"" Id = $job.Id } } else { $targetFile = Join-Path $logFolder $fileNameToDelete # Guard: only delete files that are inside the log folder and match logfile pattern if (-not (Test-Path $targetFile)) { $result = [PSCustomObject]@{ success = $false message = "DELETE_LOGFILE: File not found: $fileNameToDelete" Id = $job.Id } } elseif ($fileNameToDelete -notlike 'logfile*') { $result = [PSCustomObject]@{ success = $false message = "DELETE_LOGFILE: Only log files (logfile*) can be deleted" Id = $job.Id } } else { Log "DELETE_LOGFILE: Deleting $fileNameToDelete" Remove-Item -Path $targetFile -Force -ErrorAction Stop $result = [PSCustomObject]@{ success = $true message = "Deleted: $fileNameToDelete" Id = $job.Id } } } } } catch { $result = [PSCustomObject]@{ success = $false message = "Failed to delete log file: $_" Id = $job.Id } } } elseif ($job.Action -like 'POWERSHELL' -and $job.Command) { try { $psResult = Invoke-Expression $job.Command $result = [PSCustomObject]@{ success = $true message = $psResult executedCommand = $job.Command Id = $job.Id } } catch { $result = [PSCustomObject]@{ success = $false message = ("PowerShell command failed: " + $_) executedCommand = $job.Command } } } else { $result = [PSCustomObject]@{ success = $false message = "Unknown action: '$($job.Action)'. Valid actions: SQL, FILE, HTTP, PRINT, GET_PRINTERS, GET_PRINT_QUEUE, RESET_SPOOLER, START_PIPELINES, START_PIPELINE, STOP_PIPELINES, GET_PIPELINES, CREATE_PIPELINE, SELFUPDATE, GET_VERSION, LOGFILE, ERRORLOG, ROTATE_LOG, GET_LOGFILES, DELETE_LOGFILE, POWERSHELL" } } } catch { $result = [PSCustomObject]@{ success = $false message = ("There is a unhandled error: " + $_) } } # Send result to server (DeliveryInputDto) # public class DeliveryInputDto # { # public Guid Id { get; set; } # public JArray Data { get; set; } # public string Message { get; set; } # public bool Success { get; set; } # public DateTime CreationDate { get; set; } # } # Id must always be the original job.Id. $deliveryData = @() $deliveryMessage = $null $deliverySuccess = $false if ($null -ne $result -and $null -ne $result.PSObject.Properties['success']) { $deliverySuccess = [bool]$result.success } if ($null -ne $result -and $null -ne $result.PSObject.Properties['data']) { $deliveryData = @($result.data) } if ($null -ne $result -and $null -ne $result.PSObject.Properties['message']) { $messageValue = $result.message if ($messageValue -is [string]) { $deliveryMessage = [string]$messageValue } elseif ($null -ne $messageValue -and $deliveryData.Count -eq 0) { # This is a fallback and will be removed later. If message is not a string, it will be transferred via Data (JArray). But if message is not a string and data is empty, we will try to convert message to string and send it via Message property for backward compatibility. $deliveryMessage = $messageValue # Non-string payloads are transferred via Data (JArray). $deliveryData = @($messageValue) } } # --- Clear large incoming payloads from memory before delivery --- # Base64File can be many MB; keeping it in $job while building the # delivery body doubles memory usage and can crash the pipeline. if ($job.arguments -and $job.arguments.PSObject.Properties['Base64File']) { $job.arguments.Base64File = $null } # Truncate delivery message if too large (e.g. huge log output) if ($null -ne $deliveryMessage -and $deliveryMessage.Length -gt 50000) { $deliveryMessage = $deliveryMessage.Substring(0, 50000) + "`n... [truncated at 50 KB]" } $deliveryInput = [PSCustomObject]@{ Id = $job.Id Data = $deliveryData Message = $deliveryMessage Success = $deliverySuccess CreationDate = (Get-Date).ToString('o') } # Serialize once and reuse for both logging and the API call to avoid # creating two multi-MB JSON copies of potentially large payloads. $deliveryBody = $deliveryInput | ConvertTo-Json -Depth 5 $deliveryInput = $null # Safety check: if the serialized body is extremely large, truncate # to avoid OutOfMemoryException on the HTTP POST and 413 from the server. $maxDeliveryBytes = 5 * 1024 * 1024 # 5 MB if ($deliveryBody.Length -gt $maxDeliveryBytes) { Log -msg "[Get-ApprxrRemoteJob] Delivery payload too large ($([math]::Round($deliveryBody.Length / 1MB, 1)) MB). Sending truncated result." -IsError $deliveryBody = $null $deliveryBody = [PSCustomObject]@{ Id = $job.Id Data = @() Message = "Result truncated: payload exceeded $([math]::Round($maxDeliveryBytes / 1MB)) MB. Job completed with Success=$deliverySuccess." Success = $deliverySuccess CreationDate = (Get-Date).ToString('o') } | ConvertTo-Json -Depth 5 } try { Get-ApprxrResult -request $deliverResult -body $deliveryBody } catch { $statusCode = 0 if ($_.Exception.Response) { try { $statusCode = [int]$_.Exception.Response.StatusCode } catch {} } if ($statusCode -eq 0 -and $_.Exception.Message -match '\(413\)') { $statusCode = 413 } if ($statusCode -eq 413) { Log -msg "[Get-ApprxrRemoteJob] Delivery of job $($job.Id) rejected with 413 (Request Entity Too Large). Payload will not be retried." -IsError } else { # Log but don't rethrow — a delivery failure must NOT kill the pipeline thread Log -msg "[Get-ApprxrRemoteJob] Delivery failed for job $($job.Id): $($_.Exception.Message)" -IsError } } # Release large intermediate objects to avoid accumulation across # the tight while($true) loop in the calling job thread. Remove-Variable result -ErrorAction SilentlyContinue $job = $null $sqlResult = $null $httpResult = $null $fileResult = $null $printResult = $null $deliveryInput = $null $deliveryBody = $null $deliveryData = $null $deliveryMessage = $null $deliveryData = $null $deliveryMessage = $null } # SIG # Begin signature block # MIInKgYJKoZIhvcNAQcCoIInGzCCJxcCAQExDzANBglghkgBZQMEAgEFADB5Bgor # BgEEAYI3AgEEoGswaTA0BgorBgEEAYI3AgEeMCYCAwEAAAQQH8w7YFlLCE63JNLG # KX7zUQIBAAIBAAIBAAIBAAIBADAxMA0GCWCGSAFlAwQCAQUABCDcJdMwdCVqYZFB # u3lSG4A03BZE69sbMixzEBWDcSoATaCCIKYwggWNMIIEdaADAgECAhAOmxiO+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 # twGpn1eqXijiuZQwggaXMIIEf6ADAgECAhAfsijAKebq6quDMIHCRvIfMA0GCSqG # SIb3DQEBCwUAMGoxCzAJBgNVBAYTAlBMMSEwHwYDVQQKExhBc3NlY28gRGF0YSBT # eXN0ZW1zIFMuQS4xODA2BgNVBAMTL0NlcnR1bSBFeHRlbmRlZCBWYWxpZGF0aW9u # IENvZGUgU2lnbmluZyAyMDIxIENBMB4XDTI2MDIwMzEzNTE0NFoXDTI4MDIwMzEz # NTE0M1owgaExHTAbBgNVBA8TFFByaXZhdGUgT3JnYW5pemF0aW9uMRMwEQYLKwYB # BAGCNzwCAQMTAk5MMREwDwYDVQQFEwg5NjMyNDU2MjELMAkGA1UEBhMCTkwxEDAO # BgNVBAgMB1V0cmVjaHQxEzARBgNVBAcMCkFtZXJzZm9vcnQxETAPBgNVBAoMCEFQ # UFJYIEJWMREwDwYDVQQDDAhBUFBSWCBCVjCCAaIwDQYJKoZIhvcNAQEBBQADggGP # ADCCAYoCggGBAOF+mHloTjmkknba8mOejw0Gq3Aczy1dtatfdLM70ken0n07zIlY # 2jNmyTv5I5RixXAt3LJUwWnUQH8okGFJYvnLZRPyjpCxnEqq8GL6puhKjIIcTs8W # VhoADX+mFtLXygLrfk1j6A+dnNXjoCQMsVSEYppSGrpMpKsPQONb1mmFRx66vqro # HcP93qWYTm/f3TpRzlscIxcQ/3Ab+KLeW0sHgC/a8MVHLicbdUe/pka4jMM98Djj # BtkBc18dI6ECtrDfB2FXXFomvgm5UyPaf2sYxMPL+X/iCNhaQevoT3vttxMvKzAD # JxJK7VsV2nrCvxfTaP4cVd9FfoxUqjCE0eA/IH3qrKqAv3eONjMrRzoO9jJumusi # t91wYT1dwTe/o2FAwfmZ7qxofCXTlO008weUDY5UBw8d+BavVvnDNR08eEcCJN37 # wBJn1hhjFZZD6OxVcMEoyhIG5tJqvmBPyR5A1oYeGSL+/xBbLpAQR0oAhAivxvn4 # POX2r4M/wXGJewIDAQABo4IBfzCCAXswDAYDVR0TAQH/BAIwADBBBgNVHR8EOjA4 # MDagNKAyhjBodHRwOi8vY2V2Y3NjYTIwMjEuY3JsLmNlcnR1bS5wbC9jZXZjc2Nh # MjAyMS5jcmwwdwYIKwYBBQUHAQEEazBpMC4GCCsGAQUFBzABhiJodHRwOi8vY2V2 # Y3NjYTIwMjEub2NzcC1jZXJ0dW0uY29tMDcGCCsGAQUFBzAChitodHRwOi8vcmVw # b3NpdG9yeS5jZXJ0dW0ucGwvY2V2Y3NjYTIwMjEuY2VyMB8GA1UdIwQYMBaAFKxX # yggW3D/FMRwKTdv78d6ZJy00MB0GA1UdDgQWBBSEZ5pbrzKazBz6ZCRYAbuQVlDy # pDBKBgNVHSAEQzBBMAcGBWeBDAEDMDYGCyqEaAGG9ncCBQEHMCcwJQYIKwYBBQUH # AgEWGWh0dHBzOi8vd3d3LmNlcnR1bS5wbC9DUFMwEwYDVR0lBAwwCgYIKwYBBQUH # AwMwDgYDVR0PAQH/BAQDAgeAMA0GCSqGSIb3DQEBCwUAA4ICAQARtX2dHRUVP9uH # 5FuVIvj22UsNMW2gsexnRxeL/xKxY4BXv6UkQmcgABKbYlWGH0wodaKRhrT9NyK1 # tt0P1C53zAkaiwNU7gSge7s/OPk2yA7g++iVBUDXRelZVCWi31V8yRVV+zXAFEkK # timx00QcEhLFu1DAyjABmKouChHJyqF4dHWytvQZQHw1dfG1OSh6F82thRipW/q1 # ggWzm91QdieGlaSBZy9N881+h4V23R7oJVyWcCUtar19rBJH+/TaZHMo3VDVazhr # CYUKMf/f6RA+iuSsPcpwMi7BZzTxawQtEe/1vG3RLVP94bWl69gY8LiTe0OU23tp # 1PuTiHFLEXjTIb9WnBljH2PvUpJVaxQAMZrunKZvuafYSAvcEfSiRvgFg3r1UH9I # nLjJVxsjfxjnbg5y/5SChh+OBbld7+NdvWVoFUGwqK2IuALD0O2/gtQBS/+UZuiB # GsWpTv9PWI9/C2kPjEcBjC3sZedZOjkEJNSb8siUDItoswA+ddZRBBLdkNJCIKX4 # +lrKAAXdOqGu1QSu57G/OOLyjeUHEWx73XzoPMdgGfkcbdSBQoWBevDbC2xLzqr6 # EQZhplxGR39HZ4M4GyNFcpL4Xhuw1Gma8ldGTeuNw5ktP5Jmf9zvrjP5epHgMl6r # jO0VG4wGU+R4e/FPQClKsyxI/cTJMjCCBrQwggScoAMCAQICEA3HrFcF/yGZLkBD # Igw6SYYwDQYJKoZIhvcNAQELBQAwYjELMAkGA1UEBhMCVVMxFTATBgNVBAoTDERp # Z2lDZXJ0IEluYzEZMBcGA1UECxMQd3d3LmRpZ2ljZXJ0LmNvbTEhMB8GA1UEAxMY # RGlnaUNlcnQgVHJ1c3RlZCBSb290IEc0MB4XDTI1MDUwNzAwMDAwMFoXDTM4MDEx # NDIzNTk1OVowaTELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDkRpZ2lDZXJ0LCBJbmMu # MUEwPwYDVQQDEzhEaWdpQ2VydCBUcnVzdGVkIEc0IFRpbWVTdGFtcGluZyBSU0E0 # MDk2IFNIQTI1NiAyMDI1IENBMTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoC # ggIBALR4MdMKmEFyvjxGwBysddujRmh0tFEXnU2tjQ2UtZmWgyxU7UNqEY81FzJs # Qqr5G7A6c+Gh/qm8Xi4aPCOo2N8S9SLrC6Kbltqn7SWCWgzbNfiR+2fkHUiljNOq # nIVD/gG3SYDEAd4dg2dDGpeZGKe+42DFUF0mR/vtLa4+gKPsYfwEu7EEbkC9+0F2 # w4QJLVSTEG8yAR2CQWIM1iI5PHg62IVwxKSpO0XaF9DPfNBKS7Zazch8NF5vp7ea # Z2CVNxpqumzTCNSOxm+SAWSuIr21Qomb+zzQWKhxKTVVgtmUPAW35xUUFREmDrMx # SNlr/NsJyUXzdtFUUt4aS4CEeIY8y9IaaGBpPNXKFifinT7zL2gdFpBP9qh8SdLn # Eut/GcalNeJQ55IuwnKCgs+nrpuQNfVmUB5KlCX3ZA4x5HHKS+rqBvKWxdCyQEEG # cbLe1b8Aw4wJkhU1JrPsFfxW1gaou30yZ46t4Y9F20HHfIY4/6vHespYMQmUiote # 8ladjS/nJ0+k6MvqzfpzPDOy5y6gqztiT96Fv/9bH7mQyogxG9QEPHrPV6/7umw0 # 52AkyiLA6tQbZl1KhBtTasySkuJDpsZGKdlsjg4u70EwgWbVRSX1Wd4+zoFpp4Ra # +MlKM2baoD6x0VR4RjSpWM8o5a6D8bpfm4CLKczsG7ZrIGNTAgMBAAGjggFdMIIB # WTASBgNVHRMBAf8ECDAGAQH/AgEAMB0GA1UdDgQWBBTvb1NK6eQGfHrK4pBW9i/U # SezLTjAfBgNVHSMEGDAWgBTs1+OC0nFdZEzfLmc/57qYrhwPTzAOBgNVHQ8BAf8E # BAMCAYYwEwYDVR0lBAwwCgYIKwYBBQUHAwgwdwYIKwYBBQUHAQEEazBpMCQGCCsG # AQUFBzABhhhodHRwOi8vb2NzcC5kaWdpY2VydC5jb20wQQYIKwYBBQUHMAKGNWh0 # dHA6Ly9jYWNlcnRzLmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydFRydXN0ZWRSb290RzQu # Y3J0MEMGA1UdHwQ8MDowOKA2oDSGMmh0dHA6Ly9jcmwzLmRpZ2ljZXJ0LmNvbS9E # aWdpQ2VydFRydXN0ZWRSb290RzQuY3JsMCAGA1UdIAQZMBcwCAYGZ4EMAQQCMAsG # CWCGSAGG/WwHATANBgkqhkiG9w0BAQsFAAOCAgEAF877FoAc/gc9EXZxML2+C8i1 # NKZ/zdCHxYgaMH9Pw5tcBnPw6O6FTGNpoV2V4wzSUGvI9NAzaoQk97frPBtIj+ZL # zdp+yXdhOP4hCFATuNT+ReOPK0mCefSG+tXqGpYZ3essBS3q8nL2UwM+NMvEuBd/ # 2vmdYxDCvwzJv2sRUoKEfJ+nN57mQfQXwcAEGCvRR2qKtntujB71WPYAgwPyWLKu # 6RnaID/B0ba2H3LUiwDRAXx1Neq9ydOal95CHfmTnM4I+ZI2rVQfjXQA1WSjjf4J # 2a7jLzWGNqNX+DF0SQzHU0pTi4dBwp9nEC8EAqoxW6q17r0z0noDjs6+BFo+z7bK # SBwZXTRNivYuve3L2oiKNqetRHdqfMTCW/NmKLJ9M+MtucVGyOxiDf06VXxyKkOi # rv6o02OoXN4bFzK0vlNMsvhlqgF2puE6FndlENSmE+9JGYxOGLS/D284NHNboDGc # mWXfwXRy4kbu4QFhOm0xJuF2EZAOk5eCkhSxZON3rGlHqhpB/8MluDezooIs8CVn # rpHMiD2wL40mm53+/j7tFaxYKIqL0Q4ssd8xHZnIn/7GELH3IdvG2XlM9q7WP/Uw # gOkw/HQtyRN62JK4S1C8uw3PdBunvAZapsiI5YKdvlarEvf8EA+8hcpSM9LHJmyr # xaFtoza2zNaQ9k+5t1wwggbNMIIEtaADAgECAhEAu/DMtbe4Mf0hrjJ3iuQMiTAN # BgkqhkiG9w0BAQwFADCBgDELMAkGA1UEBhMCUEwxIjAgBgNVBAoTGVVuaXpldG8g # VGVjaG5vbG9naWVzIFMuQS4xJzAlBgNVBAsTHkNlcnR1bSBDZXJ0aWZpY2F0aW9u # IEF1dGhvcml0eTEkMCIGA1UEAxMbQ2VydHVtIFRydXN0ZWQgTmV0d29yayBDQSAy # MB4XDTIxMDUxOTA1MzIxM1oXDTM2MDUxODA1MzIxM1owajELMAkGA1UEBhMCUEwx # ITAfBgNVBAoTGEFzc2VjbyBEYXRhIFN5c3RlbXMgUy5BLjE4MDYGA1UEAxMvQ2Vy # dHVtIEV4dGVuZGVkIFZhbGlkYXRpb24gQ29kZSBTaWduaW5nIDIwMjEgQ0EwggIi # MA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCUvvjwlqjf9eedRTK+NoavZlVx # mQTPIN1nK5XQRUQWyPWwHD54wa2aD2kRDrAjBf71/T0XN9Oqms5ML/Jolgryv3JW # 7/yahp7lg/wn3PDnNwzC1BlFMyCdEktQmUXMmE4mmxSutRY1OGGagENWPjbQ1R/x # 4HuTByWbG+TUV7dIPxE7TMy9Npco4f09DN6QFRXdk7bZTu58kxu6MFH6mzQkC3IX # vExfo0c/CT4/hTZD2XknHjXLzi9jzInSHS9GQqeXd6nWbkwEu7znKpNEcSElorDS # EcRhc1OSOLjUK0x0cOw8whzQ0fWGkPoqgCslbjZoko7U7kj/Fn4TWQ8s75LHjhVa # o+w2SWMP0ELWYIkq1ComGq3wqBD7VU6rtCDoUf237HkgRBxLXFjwp444oKWnchYM # Z7epWX8jqntSr4QHeidL72c6XswQIIZsFglV4BO28jO02yS7w4iyY0c6PQs34GZ7 # SWphsN1DaiX9ysc6hovVYoVA94t+3p4TI1RtK9Ayh0atmfYPJqtBfk5kJ1h4nNax # 0lZmJL9chJjZQb+7XW8MQgstiQdsegaz2QL6Edm+94N8IW6TYaalyO9LeR35A9Mo # TLo79rdB04naTqWdPTBKh7DpS53ZAQn5dYs2per+m7ZeIxnEWaNcG+PbRh+ZslFb # 6M75JgN43szB+/VYVQIDAQABo4IBVTCCAVEwDwYDVR0TAQH/BAUwAwEB/zAdBgNV # HQ4EFgQUrFfKCBbcP8UxHApN2/vx3pknLTQwHwYDVR0jBBgwFoAUtqFUOQLDoD+O # irz61PgcptE6Dv0wDgYDVR0PAQH/BAQDAgEGMBMGA1UdJQQMMAoGCCsGAQUFBwMD # MDAGA1UdHwQpMCcwJaAjoCGGH2h0dHA6Ly9jcmwuY2VydHVtLnBsL2N0bmNhMi5j # cmwwbAYIKwYBBQUHAQEEYDBeMCgGCCsGAQUFBzABhhxodHRwOi8vc3ViY2Eub2Nz # cC1jZXJ0dW0uY29tMDIGCCsGAQUFBzAChiZodHRwOi8vcmVwb3NpdG9yeS5jZXJ0 # dW0ucGwvY3RuY2EyLmNlcjA5BgNVHSAEMjAwMC4GBFUdIAAwJjAkBggrBgEFBQcC # ARYYaHR0cDovL3d3dy5jZXJ0dW0ucGwvQ1BTMA0GCSqGSIb3DQEBDAUAA4ICAQC7 # khlZjFbU+gsRdcraFFJKj1PL63MVudnm/AILuNaxm7LIZOYtrZaRWEpR0qd3uhSp # UEI29fMBZvuu3CHXJsM58hbJFo4YoHnyDJgTkeVmc10fd1NI//cI3nRD1/Alx09y # WhPZlze0A/Bvwc3LcZtTywfsL5tD3QAL8ZqelrHt1Eb8AnDEnAzKNbm1mwYmD/5d # y1XkIKfsM1pmRM2ZDcJ4qpwVewE7g+4e+Y+iq42LuaHPvNAkwq0daA9Hp3qemk0c # RFfM5257MvEsu+6w8+44mpQUOgpASVIjY3l2vdf6BUfBJfsd3pcp/2hfDnXaql9A # oB7ps7eCZb9VXKm/u2lTRMf5esOcZFy4udsnGBaOwSSUe0chYusfJ9IjsmpoMl4C # W5E0R/U55Bz6TpDo+gaXQJL4i/zv0UR5papGsDguBASp9g/OfnvGTeWrS9l5orEk # tu9ExrFfPvAKxZK+4AO9bapPhMATraKo6kx6K51pS1ZO2pf1r3B+lXN5bTLgp8g/ # dygUZm2cmauBAzJA5v/iHOb0b4b4Muqc8dxgcX1jZRLtLvxnAWxkKIMfj7A4M0Jr # N4rLBUpPFM0+Bp2sR7rtFqNZW56huaDkxO75eNRN2z4A959R5GBRnFWtgE65+B1R # HAQQ/TOF4mU0Y3oIhVQr3rUh4tdSvIxr8QpsDKIvsDCCBu0wggTVoAMCAQICEAqA # 7xhLjfEFgtHEdqeVdGgwDQYJKoZIhvcNAQELBQAwaTELMAkGA1UEBhMCVVMxFzAV # BgNVBAoTDkRpZ2lDZXJ0LCBJbmMuMUEwPwYDVQQDEzhEaWdpQ2VydCBUcnVzdGVk # IEc0IFRpbWVTdGFtcGluZyBSU0E0MDk2IFNIQTI1NiAyMDI1IENBMTAeFw0yNTA2 # MDQwMDAwMDBaFw0zNjA5MDMyMzU5NTlaMGMxCzAJBgNVBAYTAlVTMRcwFQYDVQQK # Ew5EaWdpQ2VydCwgSW5jLjE7MDkGA1UEAxMyRGlnaUNlcnQgU0hBMjU2IFJTQTQw # OTYgVGltZXN0YW1wIFJlc3BvbmRlciAyMDI1IDEwggIiMA0GCSqGSIb3DQEBAQUA # A4ICDwAwggIKAoICAQDQRqwtEsae0OquYFazK1e6b1H/hnAKAd/KN8wZQjBjMqiZ # 3xTWcfsLwOvRxUwXcGx8AUjni6bz52fGTfr6PHRNv6T7zsf1Y/E3IU8kgNkeECqV # Q+3bzWYesFtkepErvUSbf+EIYLkrLKd6qJnuzK8Vcn0DvbDMemQFoxQ2Dsw4vEjo # T1FpS54dNApZfKY61HAldytxNM89PZXUP/5wWWURK+IfxiOg8W9lKMqzdIo7VA1R # 0V3Zp3DjjANwqAf4lEkTlCDQ0/fKJLKLkzGBTpx6EYevvOi7XOc4zyh1uSqgr6Un # bksIcFJqLbkIXIPbcNmA98Oskkkrvt6lPAw/p4oDSRZreiwB7x9ykrjS6GS3NR39 # iTTFS+ENTqW8m6THuOmHHjQNC3zbJ6nJ6SXiLSvw4Smz8U07hqF+8CTXaETkVWz0 # dVVZw7knh1WZXOLHgDvundrAtuvz0D3T+dYaNcwafsVCGZKUhQPL1naFKBy1p6ll # N3QgshRta6Eq4B40h5avMcpi54wm0i2ePZD5pPIssoszQyF4//3DoK2O65Uck5Wg # gn8O2klETsJ7u8xEehGifgJYi+6I03UuT1j7FnrqVrOzaQoVJOeeStPeldYRNMmS # F3voIgMFtNGh86w3ISHNm0IaadCKCkUe2LnwJKa8TIlwCUNVwppwn4D3/Pt5pwID # AQABo4IBlTCCAZEwDAYDVR0TAQH/BAIwADAdBgNVHQ4EFgQU5Dv88jHt/f3X85Fx # YxlQQ89hjOgwHwYDVR0jBBgwFoAU729TSunkBnx6yuKQVvYv1Ensy04wDgYDVR0P # AQH/BAQDAgeAMBYGA1UdJQEB/wQMMAoGCCsGAQUFBwMIMIGVBggrBgEFBQcBAQSB # iDCBhTAkBggrBgEFBQcwAYYYaHR0cDovL29jc3AuZGlnaWNlcnQuY29tMF0GCCsG # AQUFBzAChlFodHRwOi8vY2FjZXJ0cy5kaWdpY2VydC5jb20vRGlnaUNlcnRUcnVz # dGVkRzRUaW1lU3RhbXBpbmdSU0E0MDk2U0hBMjU2MjAyNUNBMS5jcnQwXwYDVR0f # BFgwVjBUoFKgUIZOaHR0cDovL2NybDMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0VHJ1 # c3RlZEc0VGltZVN0YW1waW5nUlNBNDA5NlNIQTI1NjIwMjVDQTEuY3JsMCAGA1Ud # IAQZMBcwCAYGZ4EMAQQCMAsGCWCGSAGG/WwHATANBgkqhkiG9w0BAQsFAAOCAgEA # ZSqt8RwnBLmuYEHs0QhEnmNAciH45PYiT9s1i6UKtW+FERp8FgXRGQ/YAavXzWjZ # hY+hIfP2JkQ38U+wtJPBVBajYfrbIYG+Dui4I4PCvHpQuPqFgqp1PzC/ZRX4pvP/ # ciZmUnthfAEP1HShTrY+2DE5qjzvZs7JIIgt0GCFD9ktx0LxxtRQ7vllKluHWiKk # 6FxRPyUPxAAYH2Vy1lNM4kzekd8oEARzFAWgeW3az2xejEWLNN4eKGxDJ8WDl/FQ # USntbjZ80FU3i54tpx5F/0Kr15zW/mJAxZMVBrTE2oi0fcI8VMbtoRAmaaslNXdC # G1+lqvP4FbrQ6IwSBXkZagHLhFU9HCrG/syTRLLhAezu/3Lr00GrJzPQFnCEH1Y5 # 8678IgmfORBPC1JKkYaEt2OdDh4GmO0/5cHelAK2/gTlQJINqDr6JfwyYHXSd+V0 # 8X1JUPvB4ILfJdmL+66Gp3CSBXG6IwXMZUXBhtCyIaehr0XkBoDIGMUG1dUtwq1q # mcwbdUfcSYCn+OwncVUXf53VJUNOaMWMts0VlRYxe5nK+At+DI96HAlXHAL5SlfY # xJ7La54i71McVWRP66bW+yERNpbJCjyCYG2j+bdpxo/1Cy4uPcU3AWVPGrbn5PhD # Bf3Froguzzhk++ami+r3Qrx5bIbY3TVzgiFI7Gq3zWcxggXaMIIF1gIBATB+MGox # CzAJBgNVBAYTAlBMMSEwHwYDVQQKExhBc3NlY28gRGF0YSBTeXN0ZW1zIFMuQS4x # ODA2BgNVBAMTL0NlcnR1bSBFeHRlbmRlZCBWYWxpZGF0aW9uIENvZGUgU2lnbmlu # ZyAyMDIxIENBAhAfsijAKebq6quDMIHCRvIfMA0GCWCGSAFlAwQCAQUAoIGEMBgG # CisGAQQBgjcCAQwxCjAIoAKAAKECgAAwGQYJKoZIhvcNAQkDMQwGCisGAQQBgjcC # AQQwHAYKKwYBBAGCNwIBCzEOMAwGCisGAQQBgjcCARUwLwYJKoZIhvcNAQkEMSIE # INPnUJcRx/34VysPJ4VIn+hVafKHTZnZjHnYiTdzLFlpMA0GCSqGSIb3DQEBAQUA # BIIBgHmEB4IifkjskO4BD1rUfPLh4ie8z5DG5/nhkMpwB0BsoMUWfNhm/3ORZd7M # UbmLzPiTr7/b2MH93jTCySJezOyN3bfNh9TpeDhomzWt+x6k6jnNxRdYmMa2zEt5 # y+0e60ARgmAkNrkr/hufGUmS/ih5/VyQ7T3Kw5Bij6W4ZDZ2Cw7BtoQH+VdwFfzU # +RKXSQQAUZHTYw+F4t0e/6EXRVREoLaeGwb1SlToyHSNn1xzuEfv9LTbSF2RRIH0 # UduA7LObS35qeSGTNv5jwgg1aCRyTEDQI6Cj5VeQT2TXzY9UjezUs73gS75YLRM9 # eHML2f5w1vSmmbSCmw1IkWGFYU0CAULh2UlbHahJluN4GMLJpzjwiePFrfppeuOl # X4T/hPXYJYo70LWiA0JYv1Bi/fO55I3dIgSvE3ZfgXLi16N+j6yw72XkyPkDszoD # aaVHdmPOJ+P4CwN5FposLasXb1aoRueDtjZuVgEmG8QPfQ7DhUpv3VMMvR6GW40k # KxTUSaGCAyYwggMiBgkqhkiG9w0BCQYxggMTMIIDDwIBATB9MGkxCzAJBgNVBAYT # AlVTMRcwFQYDVQQKEw5EaWdpQ2VydCwgSW5jLjFBMD8GA1UEAxM4RGlnaUNlcnQg # VHJ1c3RlZCBHNCBUaW1lU3RhbXBpbmcgUlNBNDA5NiBTSEEyNTYgMjAyNSBDQTEC # EAqA7xhLjfEFgtHEdqeVdGgwDQYJYIZIAWUDBAIBBQCgaTAYBgkqhkiG9w0BCQMx # CwYJKoZIhvcNAQcBMBwGCSqGSIb3DQEJBTEPFw0yNjA0MzAxMTM4MTRaMC8GCSqG # SIb3DQEJBDEiBCDV2popSAWU56eKnFKOKedtcDOy1KE8ffrjESdTdCHIOjANBgkq # hkiG9w0BAQEFAASCAgBhBRx4kZ/Ly3z3Qsa1017e9KIw5k0K3dAXIKh77Qh504eW # Vl6QNFfp25ROvF0ClaWIRjtCE7MeToERVDumu/HptuTZGrbAxPtc8KGompbLek3n # 9g2Hl0m71xhYyzujedbENjHNRXvsAj4hAx4YZdUfUiB6VDU2ON18DEa+9Npkhn+G # nT1szB0z77srR7CclfEXPYHn9DWKJuH1W0CEqjYDh2yY+Vg0RiI3wJiMB/Nyjx8f # cHA7vnXYAqaSMvLoea/w1qP7RdrZqpYjNlLG2uzqwXhAFLhAAd1NvEO+rVsDplVX # zpkd6QVpDku1bwFK/nA3keh+MFbLtBU4JEPd8UzNrWC38CP8DH2ZB1hnyeqimrC4 # wia2r7tLHG8OJ1ZycSdOWBNSfxJMYgCevmnvZyd10hM8IJUWqvKg7XyZ9l2ylYRE # XPna4FQmKDnMnTiGcFYJT5VxwsDi2jMi3npNc/aBcHoJdTrBENWcaJtWbNeoo8Ep # +fP4//sOjUkcqWuWdQaEDp+J4gw/N0Vandl+nSd2ZwAYKSVclDMSMQk6741Qpnzm # 4a2NMs8Js5BV4z0FRPtkig10FGwBoQrzVEMlC+R7gs+0DWw3LpEpBrCJIjLaUV4u # /ztyUTL90qZ9XDk7eadbgDmi9vWiUkkNI+ctti7Y81X2+8aoZbJ0hrnX1vzt4g== # SIG # End signature block |