Public/Invoke-LnvTILogViewer.ps1
|
<#
.SYNOPSIS TI Log File Viewer - Parses Lenovo ThinInstaller log files and produces a concise summary. .DESCRIPTION Analyzes log files generated by Lenovo ThinInstaller and provides a human-readable summary of key session details including system information, applicable updates, installation results, and errors. .PARAMETER LogFile Path to a single ThinInstaller log file. .PARAMETER LogDirectory Path to a directory containing ThinInstaller log files (.txt and .log). .PARAMETER OutputFile Optional path to write the summary to a plain text file. .PARAMETER Force Overwrite the output file without prompting. .PARAMETER NoColor Suppress color output (useful for redirected output). .EXAMPLE .\TI-LogFileViewer.ps1 -LogFile "C:\Logs\Update_log_250221164004.txt" .EXAMPLE .\TI-LogFileViewer.ps1 -LogDirectory "C:\Logs" -OutputFile "C:\Logs\summary.txt" .NOTES Version: 1.0 Requires: PowerShell 5.1 or later #> function Invoke-LnvTILogViewer { [CmdletBinding()] param( [Parameter(Mandatory = $false)] [string]$LogFile, [Parameter(Mandatory = $false)] [string]$LogDirectory, [Parameter(Mandatory = $false)] [string]$OutputFile, [switch]$Force, [switch]$NoColor ) $ScriptVersion = "1.0" $ScriptName = "TI Log File Viewer" #region Helper Functions function Write-ColorHost { param( [string]$Text, [ConsoleColor]$ForegroundColor = [ConsoleColor]::White, [switch]$NoNewline ) if ($script:NoColor) { if ($NoNewline) { Write-Host $Text -NoNewline } else { Write-Host $Text } } else { if ($NoNewline) { Write-Host $Text -ForegroundColor $ForegroundColor -NoNewline } else { Write-Host $Text -ForegroundColor $ForegroundColor } } } function Get-RebootTypeLabel { param([string]$RebootType) switch ($RebootType) { "0" { "No reboot" } "1" { "Forced reboot" } "3" { "Reboot recommended" } default { "Unknown ($RebootType)" } } } function Get-SearchScopeLabel { param([string]$Scope) switch ($Scope) { "A" { "All updates (-searchA)" } "C" { "Critical updates (-searchC)" } "R" { "Recommended updates (-searchR)" } default { $Scope } } } function ParseHeaderDateTime { <# .SYNOPSIS Parses the session datetime from line 1 of the TI log. Handles multiple locale formats: - English: 4/6/2023 2:18:38 PM - Spanish: 21/02/2025 4:40:04 p. m. - ISO-ish: 2025-08-01 11:43:46 AM #> param([string]$DateTimeStr) $DateTimeStr = $DateTimeStr.Trim() # Normalize non-breaking spaces (U+00A0) to regular spaces $normalized = $DateTimeStr -replace [char]0x00A0, ' ' # Normalize Spanish AM/PM markers to standard $normalized = $normalized -replace '\s*a\.\s*m\.', ' AM' $normalized = $normalized -replace '\s*p\.\s*m\.', ' PM' # Try various formats $formats = @( "dd/MM/yyyy h:mm:ss tt", "dd/MM/yyyy hh:mm:ss tt", "dd/MM/yyyy H:mm:ss", "dd/MM/yyyy HH:mm:ss", "M/d/yyyy h:mm:ss tt", "M/d/yyyy hh:mm:ss tt", "M/d/yyyy H:mm:ss", "M/d/yyyy HH:mm:ss", "yyyy-MM-dd h:mm:ss tt", "yyyy-MM-dd hh:mm:ss tt", "yyyy-MM-dd H:mm:ss", "yyyy-MM-dd HH:mm:ss" ) foreach ($fmt in $formats) { try { $parsed = [DateTime]::ParseExact($normalized, $fmt, [System.Globalization.CultureInfo]::InvariantCulture) return $parsed } catch { continue } } # Fallback: try generic parse try { return [DateTime]::Parse($normalized, [System.Globalization.CultureInfo]::InvariantCulture) } catch { return $null } } function Test-ThinInstallerLog { param([string]$FilePath) try { $firstLine = Get-Content -Path $FilePath -TotalCount 1 -ErrorAction Stop return $firstLine -match '^\[Thin Installer build:' } catch { return $false } } function ParseThinInstallerLog { param([string]$FilePath) $result = [PSCustomObject]@{ FileName = [System.IO.Path]::GetFileName($FilePath) FilePath = $FilePath SessionDateTime = $null SessionDateStr = "(not found)" TIVersion = "(not found)" TIBuildDate = "(not found)" WindowsVersion = "(not found)" MTM = "(not found)" OS = "(not found)" OSLanguage = "(not found)" ActiveLanguage = "(not found)" DefaultLanguage = "(not found)" SearchScope = "(not found)" ActionType = "(not found)" CommandString = "(not found)" CandidateList = @() ApplicableCount = 0 InstalledUpdates = @() FailedUpdates = @() FailureReasons = @{} ProcessedAtShutdown = @() SevereEntries = @() WarningEntries = @() IsScanOnly = $false RebootSummary = "No reboot needed" } try { $lines = Get-Content -Path $FilePath -Encoding UTF8 -ErrorAction Stop } catch { Write-Error "Cannot read file: $FilePath - $_" return $null } $lineCount = $lines.Count # === Parse Header (Line 1) === if ($lineCount -gt 0 -and $lines[0] -match '^\[Thin Installer build:\s*(\d{4}-\d{2}-\d{2})\s+Version:\s*([^\]]+)\]\t(.+)$') { $result.TIBuildDate = $Matches[1] $result.TIVersion = $Matches[2].Trim() $parsedDate = ParseHeaderDateTime $Matches[3] if ($parsedDate) { $result.SessionDateTime = $parsedDate $result.SessionDateStr = $parsedDate.ToString("yyyy-MM-dd HH:mm:ss") } else { $result.SessionDateStr = $Matches[3].Trim() } } # Track state for multi-line parsing $inCandidateList = $false $candidateListFound = $false $inSystemProps = $false $systemPropsLines = @() #$inLanguageBlock = $false #$lastFailedPackageId = "" #$lastExpectedReturnCode = "" #$lastActualReturnCode = "" $updateResponseSizes = @() for ($i = 1; $i -lt $lineCount; $i++) { $line = $lines[$i] # === Windows Version === if ($line -match 'Message:\s*Microsoft Windows \[Vers[^\]]*\s+([\d\.]+)\]') { $result.WindowsVersion = "Microsoft Windows $($Matches[1])" } # === Language Block === if ($line -match 'The active language is:\s*(.+)') { $result.ActiveLanguage = $Matches[1].Trim() } if ($line -match 'The default language is:\s*(.+)') { $result.DefaultLanguage = $Matches[1].Trim() } if ($line -match 'The OS language is:\s*(.+)') { $result.OSLanguage = $Matches[1].Trim() } # === Command String === if ($line -match 'Message:\s*The command is:\s*(.+)') { $result.CommandString = $Matches[1].Trim() } # === Search Scope === if ($line -match 'Message:\s*Searching for Updates:\s*(\w)') { $result.SearchScope = $Matches[1].Trim() } # === Notify Method / Action === if ($line -match 'Message:\s*Notify method:\s*(\w+)') { $result.ActionType = $Matches[1].Trim() } # === MTM === if ($line -match 'Message:\s*MTM is:\s*(.+)') { $result.MTM = $Matches[1].Trim() } # === System Properties Block === if ($line -match 'Message:\s*The System Properties are:') { $inSystemProps = $true $systemPropsLines = @() continue } if ($inSystemProps) { if ($line -match '^\s*$' -and $systemPropsLines.Count -ge 3) { $inSystemProps = $false } elseif ($line -match '^\S' -and $line -notmatch '^\s') { # Next log entry level token (Info, Severe, Warning) if ($systemPropsLines.Count -ge 3) { $inSystemProps = $false } elseif ($line -match '^(Info|Severe|Warning)\s') { $inSystemProps = $false } else { $systemPropsLines += $line.Trim() } } else { $trimmed = $line.Trim() if ($trimmed -ne '' -and $trimmed -notmatch '^(Info|Severe|Warning)\s') { $systemPropsLines += $trimmed } elseif ($trimmed -match '^(Info|Severe|Warning)\s') { $inSystemProps = $false } } if ($systemPropsLines.Count -ge 3 -and -not $inSystemProps) { if ($result.MTM -eq "(not found)") { $result.MTM = $systemPropsLines[0] } $result.OS = $systemPropsLines[1] if ($result.OSLanguage -eq "(not found)") { $result.OSLanguage = $systemPropsLines[2] } } continue } # === Candidate List (first occurrence only) === if ($line -match 'Message:\s*Candidate list:' -and -not $candidateListFound) { $inCandidateList = $true $candidateListFound = $true continue } if ($inCandidateList) { $trimmed = $line.Trim() if ($trimmed -eq '' -or $trimmed -match '^(Info|Severe|Warning)\t') { $inCandidateList = $false } else { # Parse update name and reboot type if ($trimmed -match '^(.+?)\[reboot type (\d+)\]$') { $result.CandidateList += [PSCustomObject]@{ Name = $Matches[1].Trim() RebootType = $Matches[2] } } else { # Line without reboot type info $result.CandidateList += [PSCustomObject]@{ Name = $trimmed RebootType = "-1" } } } if ($inCandidateList) { continue } } # === UpdateResponse Size === if ($line -match 'Message:\s*The size for the UpdateResponse is (\d+)') { $updateResponseSizes += [int]$Matches[1] } # === Installation Success === if ($line -match 'Message:\s*Update (.+?) was installed successfully') { $result.InstalledUpdates += $Matches[1].Trim() } # === Installation Failure === if ($line -match 'Message:\s*Update (.+?) installation failed') { $failedName = $Matches[1].Trim() $result.FailedUpdates += $failedName # Look backward for the failure reason $reason = "" # Check for signature failure or return code in the preceding lines for ($j = $i - 1; $j -ge [Math]::Max(0, $i - 20); $j--) { if ($lines[$j] -match 'Message:\s*Package Signature Verification Failed,\s*ID:(.+)') { $reason = "Package Signature Verification Failed ($($Matches[1].Trim()))" break } if ($lines[$j] -match 'Message:\s*Expected return code:\s*(.+?),\s*Installation return code:\s*(\d+)') { $expected = $Matches[1].Trim() $actual = $Matches[2].Trim() $reason = "Expected return code: $expected, Installation return code: $actual" break } } if ($reason) { $result.FailureReasons[$failedName] = $reason } } # === Packages Processed at Shutdown === if ($line -match '^Severe' -and $i + 2 -lt $lineCount) { if ($lines[$i + 2] -match 'Message:\s*Processing the Update:\s*(.+)') { $result.ProcessedAtShutdown += $Matches[1].Trim() } } # === Severe Entries === if ($line -match '^Severe\s') { # Collect the message from the next lines $severeMsg = "" for ($k = $i + 1; $k -lt [Math]::Min($lineCount, $i + 4); $k++) { if ($lines[$k] -match 'Message:\s*(.+)') { $severeMsg = $Matches[1].Trim() break } } # Exclude routine .NET framework message if ($severeMsg -and $severeMsg -notmatch '^Application runs with the framework:') { $result.SevereEntries += $severeMsg } } # === Warning Entries === if ($line -match '^Warning\s') { $warnMsg = "" for ($k = $i + 1; $k -lt [Math]::Min($lineCount, $i + 4); $k++) { if ($lines[$k] -match 'Message:\s*(.+)') { $warnMsg = $Matches[1].Trim() break } } if ($warnMsg) { $result.WarningEntries += $warnMsg } } } # Post-processing # Use the first UpdateResponse size if available if ($updateResponseSizes.Count -gt 0) { $result.ApplicableCount = $updateResponseSizes[0] } else { $result.ApplicableCount = $result.CandidateList.Count } # Determine scan-only if ($result.ActionType -eq "NOTIFY" -or ($result.InstalledUpdates.Count -eq 0 -and $result.FailedUpdates.Count -eq 0)) { $result.IsScanOnly = $true } # Reboot summary based on installed updates' reboot types $installedRebootTypes = @() foreach ($installed in $result.InstalledUpdates) { $match = $result.CandidateList | Where-Object { $installed -like "$($_.Name)*" -or $_.Name -like "$installed*" } | Select-Object -First 1 if ($match) { $installedRebootTypes += $match.RebootType } } if ($installedRebootTypes -contains "1") { $result.RebootSummary = "Reboot required" } elseif ($installedRebootTypes -contains "3") { $result.RebootSummary = "Reboot recommended" } else { $result.RebootSummary = "No reboot needed" } return $result } function Format-Summary { param( [object]$Data, [switch]$IsVerbose ) $lines = @() $divider = "=" * 64 $lines += $divider $lines += " THININSTALLER SESSION SUMMARY" $lines += $divider $lines += "Log File : $($Data.FileName)" $lines += "Session Date : $($Data.SessionDateStr)" $lines += "TI Version : $($Data.TIVersion) (Build: $($Data.TIBuildDate))" $lines += "Windows : $($Data.WindowsVersion)" $lines += "" $lines += "SYSTEM" $lines += " Machine Type : $($Data.MTM)" $lines += " OS : $($Data.OS)" # Language line $langParts = @() if ($Data.OSLanguage -ne "(not found)") { $langParts += "$($Data.OSLanguage) (OS)" } if ($Data.ActiveLanguage -ne "(not found)") { $langParts += "Active: $($Data.ActiveLanguage)" } if ($Data.DefaultLanguage -ne "(not found)") { $langParts += "Default: $($Data.DefaultLanguage)" } if ($langParts.Count -gt 0) { $lines += " Language : $($langParts -join ' | ')" } else { $lines += " Language : (not found)" } $lines += "" $lines += "SESSION CONFIGURATION" $lines += " Search Scope : $(Get-SearchScopeLabel $Data.SearchScope)" $lines += " Action : $($Data.ActionType)" $lines += " Command : $($Data.CommandString)" $lines += "" $candidateCount = $Data.CandidateList.Count $lines += "APPLICABLE UPDATES ($($Data.ApplicableCount) found)" if ($candidateCount -eq 0) { $lines += " (no applicable updates found)" } else { $showCount = if ($IsVerbose) { $candidateCount } else { [Math]::Min(10, $candidateCount) } for ($i = 0; $i -lt $showCount; $i++) { $update = $Data.CandidateList[$i] $rebootLabel = Get-RebootTypeLabel $update.RebootType $lines += " $($update.Name) [$rebootLabel]" } if (-not $IsVerbose -and $candidateCount -gt 10) { $remaining = $candidateCount - 10 $lines += " ... ($remaining more - use -Verbose for full list)" } } $lines += "" $lines += "INSTALLATION RESULTS" if ($Data.IsScanOnly -and $Data.ActionType -eq "NOTIFY") { $lines += " (scan only - no installs performed)" } elseif ($Data.IsScanOnly) { $installedCount = $Data.InstalledUpdates.Count $failedCount = $Data.FailedUpdates.Count $lines += " Installed : $installedCount" $lines += " Failed : $failedCount" $lines += " (no installs were performed)" } else { $installedCount = $Data.InstalledUpdates.Count $failedCount = $Data.FailedUpdates.Count $lines += " Installed : $installedCount" $lines += " Failed : $failedCount" $lines += " Reboot : $($Data.RebootSummary)" if ($installedCount -gt 0) { $lines += "" $lines += " INSTALLED:" foreach ($u in $Data.InstalledUpdates) { $lines += " [OK] $u" } } if ($failedCount -gt 0) { $lines += "" $lines += " FAILED:" foreach ($u in $Data.FailedUpdates) { $reason = if ($Data.FailureReasons.ContainsKey($u)) { $Data.FailureReasons[$u] } else { "Unknown" } $lines += " [FAIL] $u" $lines += " Reason: $reason" } } } if ($Data.ProcessedAtShutdown.Count -gt 0) { $lines += "" $lines += " PROCESSED AT SHUTDOWN:" foreach ($p in $Data.ProcessedAtShutdown) { $lines += " $p" } } $lines += "" $lines += "ERRORS / WARNINGS" $hasErrors = $Data.SevereEntries.Count -gt 0 $hasWarnings = $Data.WarningEntries.Count -gt 0 if (-not $hasErrors -and -not $hasWarnings) { $lines += " (none)" } else { if ($hasErrors) { $severeToShow = if ($IsVerbose) { $Data.SevereEntries } else { $Data.SevereEntries | Select-Object -Unique } foreach ($s in $severeToShow) { $lines += " [SEVERE] $s" } } if ($hasWarnings) { foreach ($w in $Data.WarningEntries) { $lines += " [WARNING] $w" } } } $lines += $divider return $lines } function Write-SummaryToConsole { param( [string[]]$Lines ) foreach ($line in $Lines) { if ($line -match '^\={10,}') { Write-ColorHost $line -ForegroundColor Cyan } elseif ($line -match '^\s*THININSTALLER SESSION SUMMARY') { Write-ColorHost $line -ForegroundColor Cyan } elseif ($line -match '^\s*\[OK\]') { Write-ColorHost $line -ForegroundColor Green } elseif ($line -match '^\s*\[FAIL\]') { Write-ColorHost $line -ForegroundColor Red } elseif ($line -match '^\s*Reason:') { Write-ColorHost $line -ForegroundColor Red } elseif ($line -match '^\s*\[SEVERE\]') { Write-ColorHost $line -ForegroundColor Red } elseif ($line -match '^\s*\[WARNING\]') { Write-ColorHost $line -ForegroundColor Yellow } elseif ($line -match '^\s*Failed\s+:\s*[1-9]') { Write-ColorHost $line -ForegroundColor Red } elseif ($line -match '^\s*Installed\s+:\s*[1-9]') { Write-ColorHost $line -ForegroundColor Green } elseif ($line -match 'scan only|no installs|no applicable') { Write-ColorHost $line -ForegroundColor Yellow } elseif ($line -match '^(SYSTEM|SESSION CONFIGURATION|APPLICABLE UPDATES|INSTALLATION RESULTS|ERRORS / WARNINGS)') { Write-ColorHost $line -ForegroundColor White } else { Write-ColorHost $line -ForegroundColor Gray } } } #endregion #region Main Logic # Validate parameters if (-not $LogFile -and -not $LogDirectory) { Write-Error "You must specify either -LogFile or -LogDirectory." return } if ($LogFile -and $LogDirectory) { Write-Error "Specify only one of -LogFile or -LogDirectory, not both." return } # Collect files to process $filesToProcess = @() if ($LogFile) { if (-not (Test-Path -Path $LogFile)) { Write-Error "File not found: $LogFile" return } $resolvedPath = (Resolve-Path $LogFile).Path if (-not (Test-ThinInstallerLog $resolvedPath)) { Write-Error "Not a valid ThinInstaller log file (missing '[Thin Installer build:' header): $LogFile" return } $filesToProcess += $resolvedPath } if ($LogDirectory) { if (-not (Test-Path -Path $LogDirectory -PathType Container)) { Write-Error "Directory not found: $LogDirectory" return } $candidates = Get-ChildItem -Path $LogDirectory -File | Where-Object { $_.Extension -in @('.txt', '.log') } foreach ($candidate in $candidates) { if (Test-ThinInstallerLog $candidate.FullName) { $filesToProcess += $candidate.FullName } else { Write-Warning "Skipping non-ThinInstaller file: $($candidate.Name)" } } if ($filesToProcess.Count -eq 0) { Write-Error "No valid ThinInstaller log files found in: $LogDirectory" return } } # Parse all files and sort by session timestamp $parsedResults = @() foreach ($file in $filesToProcess) { $parsed = ParseThinInstallerLog -FilePath $file if ($parsed) { $parsedResults += $parsed } } # Sort by session date when processing multiple files if ($parsedResults.Count -gt 1) { $parsedResults = $parsedResults | Sort-Object { if ($_.SessionDateTime) { $_.SessionDateTime } else { [DateTime]::MinValue } } } # Generate summaries $allSummaryLines = @() $isVerbose = $PSCmdlet.MyInvocation.BoundParameters.ContainsKey('Verbose') -or $VerbosePreference -eq 'Continue' # Add file header for output file if ($OutputFile) { $allSummaryLines += "$ScriptName v$ScriptVersion - Generated $(Get-Date -Format 'yyyy-MM-dd HH:mm:ss')" $allSummaryLines += "" } $fileIndex = 0 foreach ($parsed in $parsedResults) { $summaryLines = Format-Summary -Data $parsed -IsVerbose:$isVerbose # Console output Write-SummaryToConsole -Lines $summaryLines # Collect for file output $allSummaryLines += $summaryLines $fileIndex++ if ($fileIndex -lt $parsedResults.Count) { Write-Host "" $allSummaryLines += "" } } # Multi-file count if ($parsedResults.Count -gt 1) { $countMsg = "Processed $($parsedResults.Count) log files" Write-Host "" Write-ColorHost $countMsg -ForegroundColor Cyan $allSummaryLines += "" $allSummaryLines += $countMsg } # Write to output file if requested if ($OutputFile) { $outputDir = Split-Path -Path $OutputFile -Parent if ($outputDir -and -not (Test-Path -Path $outputDir)) { try { New-Item -ItemType Directory -Path $outputDir -Force | Out-Null } catch { Write-Error "Cannot create output directory: $outputDir - $_" return } } if ((Test-Path -Path $OutputFile) -and -not $Force) { $response = Read-Host "Output file '$OutputFile' already exists. Overwrite? (Y/N)" if ($response -notmatch '^[Yy]') { Write-Host "Output file not written." return } } try { $allSummaryLines | Out-File -FilePath $OutputFile -Encoding UTF8 -Force Write-ColorHost "Summary written to: $OutputFile" -ForegroundColor Green } catch { Write-Error "Failed to write output file: $_" return } } #endregion } # SIG # Begin signature block # MIItugYJKoZIhvcNAQcCoIItqzCCLacCAQExCzAJBgUrDgMCGgUAMGkGCisGAQQB # gjcCAQSgWzBZMDQGCisGAQQBgjcCAR4wJgIDAQAABBAfzDtgWUsITrck0sYpfvNR # AgEAAgEAAgEAAgEAAgEAMCEwCQYFKw4DAhoFAAQUUM0sBzKnX3KdT/8hlw3uQqzl # n1SggibcMIIFjTCCBHWgAwIBAgIQDpsYjvnQLefv21DiCEAYWjANBgkqhkiG9w0B # AQwFADBlMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYD # VQQLExB3d3cuZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVk # IElEIFJvb3QgQ0EwHhcNMjIwODAxMDAwMDAwWhcNMzExMTA5MjM1OTU5WjBiMQsw # CQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cu # ZGlnaWNlcnQuY29tMSEwHwYDVQQDExhEaWdpQ2VydCBUcnVzdGVkIFJvb3QgRzQw # ggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC/5pBzaN675F1KPDAiMGkz # 7MKnJS7JIT3yithZwuEppz1Yq3aaza57G4QNxDAf8xukOBbrVsaXbR2rsnnyyhHS # 5F/WBTxSD1Ifxp4VpX6+n6lXFllVcq9ok3DCsrp1mWpzMpTREEQQLt+C8weE5nQ7 # bXHiLQwb7iDVySAdYyktzuxeTsiT+CFhmzTrBcZe7FsavOvJz82sNEBfsXpm7nfI # SKhmV1efVFiODCu3T6cw2Vbuyntd463JT17lNecxy9qTXtyOj4DatpGYQJB5w3jH # trHEtWoYOAMQjdjUN6QuBX2I9YI+EJFwq1WCQTLX2wRzKm6RAXwhTNS8rhsDdV14 # Ztk6MUSaM0C/CNdaSaTC5qmgZ92kJ7yhTzm1EVgX9yRcRo9k98FpiHaYdj1ZXUJ2 # h4mXaXpI8OCiEhtmmnTK3kse5w5jrubU75KSOp493ADkRSWJtppEGSt+wJS00mFt # 6zPZxd9LBADMfRyVw4/3IbKyEbe7f/LVjHAsQWCqsWMYRJUadmJ+9oCw++hkpjPR # iQfhvbfmQ6QYuKZ3AeEPlAwhHbJUKSWJbOUOUlFHdL4mrLZBdd56rF+NP8m800ER # ElvlEFDrMcXKchYiCd98THU/Y+whX8QgUWtvsauGi0/C1kVfnSD8oR7FwI+isX4K # Jpn15GkvmB0t9dmpsh3lGwIDAQABo4IBOjCCATYwDwYDVR0TAQH/BAUwAwEB/zAd # BgNVHQ4EFgQU7NfjgtJxXWRM3y5nP+e6mK4cD08wHwYDVR0jBBgwFoAUReuir/SS # y4IxLVGLp6chnfNtyA8wDgYDVR0PAQH/BAQDAgGGMHkGCCsGAQUFBwEBBG0wazAk # BggrBgEFBQcwAYYYaHR0cDovL29jc3AuZGlnaWNlcnQuY29tMEMGCCsGAQUFBzAC # hjdodHRwOi8vY2FjZXJ0cy5kaWdpY2VydC5jb20vRGlnaUNlcnRBc3N1cmVkSURS # b290Q0EuY3J0MEUGA1UdHwQ+MDwwOqA4oDaGNGh0dHA6Ly9jcmwzLmRpZ2ljZXJ0 # LmNvbS9EaWdpQ2VydEFzc3VyZWRJRFJvb3RDQS5jcmwwEQYDVR0gBAowCDAGBgRV # HSAAMA0GCSqGSIb3DQEBDAUAA4IBAQBwoL9DXFXnOF+go3QbPbYW1/e/Vwe9mqyh # hyzshV6pGrsi+IcaaVQi7aSId229GhT0E0p6Ly23OO/0/4C5+KH38nLeJLxSA8hO # 0Cre+i1Wz/n096wwepqLsl7Uz9FDRJtDIeuWcqFItJnLnU+nBgMTdydE1Od/6Fmo # 8L8vC6bp8jQ87PcDx4eo0kxAGTVGamlUsLihVo7spNU96LHc/RzY9HdaXFSMb++h # UD38dglohJ9vytsgjTVgHAIDyyCwrFigDkBjxZgiwbJZ9VVrzyerbHbObyMt9H5x # aiNrIv8SuFQtJ37YOtnwtoeW/VvRXKwYw02fc7cBqZ9Xql4o4rmUMIIFkDCCA3ig # AwIBAgIQBZsbV56OITLiOQe9p3d1XDANBgkqhkiG9w0BAQwFADBiMQswCQYDVQQG # EwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNl # cnQuY29tMSEwHwYDVQQDExhEaWdpQ2VydCBUcnVzdGVkIFJvb3QgRzQwHhcNMTMw # ODAxMTIwMDAwWhcNMzgwMTE1MTIwMDAwWjBiMQswCQYDVQQGEwJVUzEVMBMGA1UE # ChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSEwHwYD # VQQDExhEaWdpQ2VydCBUcnVzdGVkIFJvb3QgRzQwggIiMA0GCSqGSIb3DQEBAQUA # A4ICDwAwggIKAoICAQC/5pBzaN675F1KPDAiMGkz7MKnJS7JIT3yithZwuEppz1Y # q3aaza57G4QNxDAf8xukOBbrVsaXbR2rsnnyyhHS5F/WBTxSD1Ifxp4VpX6+n6lX # FllVcq9ok3DCsrp1mWpzMpTREEQQLt+C8weE5nQ7bXHiLQwb7iDVySAdYyktzuxe # TsiT+CFhmzTrBcZe7FsavOvJz82sNEBfsXpm7nfISKhmV1efVFiODCu3T6cw2Vbu # yntd463JT17lNecxy9qTXtyOj4DatpGYQJB5w3jHtrHEtWoYOAMQjdjUN6QuBX2I # 9YI+EJFwq1WCQTLX2wRzKm6RAXwhTNS8rhsDdV14Ztk6MUSaM0C/CNdaSaTC5qmg # Z92kJ7yhTzm1EVgX9yRcRo9k98FpiHaYdj1ZXUJ2h4mXaXpI8OCiEhtmmnTK3kse # 5w5jrubU75KSOp493ADkRSWJtppEGSt+wJS00mFt6zPZxd9LBADMfRyVw4/3IbKy # Ebe7f/LVjHAsQWCqsWMYRJUadmJ+9oCw++hkpjPRiQfhvbfmQ6QYuKZ3AeEPlAwh # HbJUKSWJbOUOUlFHdL4mrLZBdd56rF+NP8m800ERElvlEFDrMcXKchYiCd98THU/ # Y+whX8QgUWtvsauGi0/C1kVfnSD8oR7FwI+isX4KJpn15GkvmB0t9dmpsh3lGwID # AQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBhjAdBgNVHQ4E # FgQU7NfjgtJxXWRM3y5nP+e6mK4cD08wDQYJKoZIhvcNAQEMBQADggIBALth2X2p # bL4XxJEbw6GiAI3jZGgPVs93rnD5/ZpKmbnJeFwMDF/k5hQpVgs2SV1EY+CtnJYY # ZhsjDT156W1r1lT40jzBQ0CuHVD1UvyQO7uYmWlrx8GnqGikJ9yd+SeuMIW59mdN # Oj6PWTkiU0TryF0Dyu1Qen1iIQqAyHNm0aAFYF/opbSnr6j3bTWcfFqK1qI4mfN4 # i/RN0iAL3gTujJtHgXINwBQy7zBZLq7gcfJW5GqXb5JQbZaNaHqasjYUegbyJLkJ # EVDXCLG4iXqEI2FCKeWjzaIgQdfRnGTZ6iahixTXTBmyUEFxPT9NcCOGDErcgdLM # MpSEDQgJlxxPwO5rIHQw0uA5NBCFIRUBCOhVMt5xSdkoF1BN5r5N0XWs0Mr7QbhD # parTwwVETyw2m+L64kW4I1NsBm9nVX9GtUw/bihaeSbSpKhil9Ie4u1Ki7wb/UdK # Dd9nZn6yW0HQO+T0O/QEY+nvwlQAUaCKKsnOeMzV6ocEGLPOr0mIr/OSmbaz5mEP # 0oUA51Aa5BuVnRmhuZyxm7EAHu/QD09CbMkKvO5D+jpxpchNJqU1/YldvIViHTLS # oCtU7ZpXwdv6EM8Zt4tKG48BtieVU+i2iW1bvGjUI+iLUaJW+fCmgKDWHrO8Dw9T # dSmq6hN35N6MgSGtBxBHEa2HPQfRdbzP82Z+MIIGsDCCBJigAwIBAgIQCK1AsmDS # nEyfXs2pvZOu2TANBgkqhkiG9w0BAQwFADBiMQswCQYDVQQGEwJVUzEVMBMGA1UE # ChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSEwHwYD # VQQDExhEaWdpQ2VydCBUcnVzdGVkIFJvb3QgRzQwHhcNMjEwNDI5MDAwMDAwWhcN # MzYwNDI4MjM1OTU5WjBpMQswCQYDVQQGEwJVUzEXMBUGA1UEChMORGlnaUNlcnQs # IEluYy4xQTA/BgNVBAMTOERpZ2lDZXJ0IFRydXN0ZWQgRzQgQ29kZSBTaWduaW5n # IFJTQTQwOTYgU0hBMzg0IDIwMjEgQ0ExMIICIjANBgkqhkiG9w0BAQEFAAOCAg8A # MIICCgKCAgEA1bQvQtAorXi3XdU5WRuxiEL1M4zrPYGXcMW7xIUmMJ+kjmjYXPXr # NCQH4UtP03hD9BfXHtr50tVnGlJPDqFX/IiZwZHMgQM+TXAkZLON4gh9NH1MgFcS # a0OamfLFOx/y78tHWhOmTLMBICXzENOLsvsI8IrgnQnAZaf6mIBJNYc9URnokCF4 # RS6hnyzhGMIazMXuk0lwQjKP+8bqHPNlaJGiTUyCEUhSaN4QvRRXXegYE2XFf7JP # hSxIpFaENdb5LpyqABXRN/4aBpTCfMjqGzLmysL0p6MDDnSlrzm2q2AS4+jWufcx # 4dyt5Big2MEjR0ezoQ9uo6ttmAaDG7dqZy3SvUQakhCBj7A7CdfHmzJawv9qYFSL # ScGT7eG0XOBv6yb5jNWy+TgQ5urOkfW+0/tvk2E0XLyTRSiDNipmKF+wc86LJiUG # soPUXPYVGUztYuBeM/Lo6OwKp7ADK5GyNnm+960IHnWmZcy740hQ83eRGv7bUKJG # yGFYmPV8AhY8gyitOYbs1LcNU9D4R+Z1MI3sMJN2FKZbS110YU0/EpF23r9Yy3IQ # KUHw1cVtJnZoEUETWJrcJisB9IlNWdt4z4FKPkBHX8mBUHOFECMhWWCKZFTBzCEa # 6DgZfGYczXg4RTCZT/9jT0y7qg0IU0F8WD1Hs/q27IwyCQLMbDwMVhECAwEAAaOC # AVkwggFVMBIGA1UdEwEB/wQIMAYBAf8CAQAwHQYDVR0OBBYEFGg34Ou2O/hfEYb7 # /mF7CIhl9E5CMB8GA1UdIwQYMBaAFOzX44LScV1kTN8uZz/nupiuHA9PMA4GA1Ud # DwEB/wQEAwIBhjATBgNVHSUEDDAKBggrBgEFBQcDAzB3BggrBgEFBQcBAQRrMGkw # JAYIKwYBBQUHMAGGGGh0dHA6Ly9vY3NwLmRpZ2ljZXJ0LmNvbTBBBggrBgEFBQcw # AoY1aHR0cDovL2NhY2VydHMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0VHJ1c3RlZFJv # b3RHNC5jcnQwQwYDVR0fBDwwOjA4oDagNIYyaHR0cDovL2NybDMuZGlnaWNlcnQu # Y29tL0RpZ2lDZXJ0VHJ1c3RlZFJvb3RHNC5jcmwwHAYDVR0gBBUwEzAHBgVngQwB # AzAIBgZngQwBBAEwDQYJKoZIhvcNAQEMBQADggIBADojRD2NCHbuj7w6mdNW4AIa # pfhINPMstuZ0ZveUcrEAyq9sMCcTEp6QRJ9L/Z6jfCbVN7w6XUhtldU/SfQnuxaB # RVD9nL22heB2fjdxyyL3WqqQz/WTauPrINHVUHmImoqKwba9oUgYftzYgBoRGRjN # YZmBVvbJ43bnxOQbX0P4PpT/djk9ntSZz0rdKOtfJqGVWEjVGv7XJz/9kNF2ht0c # sGBc8w2o7uCJob054ThO2m67Np375SFTWsPK6Wrxoj7bQ7gzyE84FJKZ9d3OVG3Z # XQIUH0AzfAPilbLCIXVzUstG2MQ0HKKlS43Nb3Y3LIU/Gs4m6Ri+kAewQ3+ViCCC # cPDMyu/9KTVcH4k4Vfc3iosJocsL6TEa/y4ZXDlx4b6cpwoG1iZnt5LmTl/eeqxJ # zy6kdJKt2zyknIYf48FWGysj/4+16oh7cGvmoLr9Oj9FpsToFpFSi0HASIRLlk2r # REDjjfAVKM7t8RhWByovEMQMCGQ8M4+uKIw8y4+ICw2/O/TOHnuO77Xry7fwdxPm # 5yg/rBKupS8ibEH5glwVZsxsDsrFhsP2JjMMB0ug0wcCampAMEhLNKhRILutG4UI # 4lkNbcoFUCvqShyepf2gpx8GdOfy1lKQ/a+FSCH5Vzu0nAPthkX0tGFuv2jiJmCG # 6sivqf6UHedjGzqGVnhOMIIGtDCCBJygAwIBAgIQDcesVwX/IZkuQEMiDDpJhjAN # BgkqhkiG9w0BAQsFADBiMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQg # SW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSEwHwYDVQQDExhEaWdpQ2Vy # dCBUcnVzdGVkIFJvb3QgRzQwHhcNMjUwNTA3MDAwMDAwWhcNMzgwMTE0MjM1OTU5 # WjBpMQswCQYDVQQGEwJVUzEXMBUGA1UEChMORGlnaUNlcnQsIEluYy4xQTA/BgNV # BAMTOERpZ2lDZXJ0IFRydXN0ZWQgRzQgVGltZVN0YW1waW5nIFJTQTQwOTYgU0hB # MjU2IDIwMjUgQ0ExMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAtHgx # 0wqYQXK+PEbAHKx126NGaHS0URedTa2NDZS1mZaDLFTtQ2oRjzUXMmxCqvkbsDpz # 4aH+qbxeLho8I6jY3xL1IusLopuW2qftJYJaDNs1+JH7Z+QdSKWM06qchUP+AbdJ # gMQB3h2DZ0Mal5kYp77jYMVQXSZH++0trj6Ao+xh/AS7sQRuQL37QXbDhAktVJMQ # bzIBHYJBYgzWIjk8eDrYhXDEpKk7RdoX0M980EpLtlrNyHw0Xm+nt5pnYJU3Gmq6 # bNMI1I7Gb5IBZK4ivbVCiZv7PNBYqHEpNVWC2ZQ8BbfnFRQVESYOszFI2Wv82wnJ # RfN20VRS3hpLgIR4hjzL0hpoYGk81coWJ+KdPvMvaB0WkE/2qHxJ0ucS638ZxqU1 # 4lDnki7CcoKCz6eum5A19WZQHkqUJfdkDjHkccpL6uoG8pbF0LJAQQZxst7VvwDD # jAmSFTUms+wV/FbWBqi7fTJnjq3hj0XbQcd8hjj/q8d6ylgxCZSKi17yVp2NL+cn # T6Toy+rN+nM8M7LnLqCrO2JP3oW//1sfuZDKiDEb1AQ8es9Xr/u6bDTnYCTKIsDq # 1BtmXUqEG1NqzJKS4kOmxkYp2WyODi7vQTCBZtVFJfVZ3j7OgWmnhFr4yUozZtqg # PrHRVHhGNKlYzyjlroPxul+bgIspzOwbtmsgY1MCAwEAAaOCAV0wggFZMBIGA1Ud # EwEB/wQIMAYBAf8CAQAwHQYDVR0OBBYEFO9vU0rp5AZ8esrikFb2L9RJ7MtOMB8G # A1UdIwQYMBaAFOzX44LScV1kTN8uZz/nupiuHA9PMA4GA1UdDwEB/wQEAwIBhjAT # BgNVHSUEDDAKBggrBgEFBQcDCDB3BggrBgEFBQcBAQRrMGkwJAYIKwYBBQUHMAGG # GGh0dHA6Ly9vY3NwLmRpZ2ljZXJ0LmNvbTBBBggrBgEFBQcwAoY1aHR0cDovL2Nh # Y2VydHMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0VHJ1c3RlZFJvb3RHNC5jcnQwQwYD # VR0fBDwwOjA4oDagNIYyaHR0cDovL2NybDMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0 # VHJ1c3RlZFJvb3RHNC5jcmwwIAYDVR0gBBkwFzAIBgZngQwBBAIwCwYJYIZIAYb9 # bAcBMA0GCSqGSIb3DQEBCwUAA4ICAQAXzvsWgBz+Bz0RdnEwvb4LyLU0pn/N0IfF # iBowf0/Dm1wGc/Do7oVMY2mhXZXjDNJQa8j00DNqhCT3t+s8G0iP5kvN2n7Jd2E4 # /iEIUBO41P5F448rSYJ59Ib61eoalhnd6ywFLerycvZTAz40y8S4F3/a+Z1jEMK/ # DMm/axFSgoR8n6c3nuZB9BfBwAQYK9FHaoq2e26MHvVY9gCDA/JYsq7pGdogP8HR # trYfctSLANEBfHU16r3J05qX3kId+ZOczgj5kjatVB+NdADVZKON/gnZruMvNYY2 # o1f4MXRJDMdTSlOLh0HCn2cQLwQCqjFbqrXuvTPSegOOzr4EWj7PtspIHBldNE2K # 9i697cvaiIo2p61Ed2p8xMJb82Yosn0z4y25xUbI7GIN/TpVfHIqQ6Ku/qjTY6hc # 3hsXMrS+U0yy+GWqAXam4ToWd2UQ1KYT70kZjE4YtL8Pbzg0c1ugMZyZZd/BdHLi # Ru7hAWE6bTEm4XYRkA6Tl4KSFLFk43esaUeqGkH/wyW4N7OigizwJWeukcyIPbAv # jSabnf7+Pu0VrFgoiovRDiyx3zEdmcif/sYQsfch28bZeUz2rtY/9TCA6TD8dC3J # E3rYkrhLULy7Dc90G6e8BlqmyIjlgp2+VqsS9/wQD7yFylIz0scmbKvFoW2jNrbM # 1pD2T7m3XDCCBu0wggTVoAMCAQICEAqA7xhLjfEFgtHEdqeVdGgwDQYJKoZIhvcN # AQELBQAwaTELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDkRpZ2lDZXJ0LCBJbmMuMUEw # PwYDVQQDEzhEaWdpQ2VydCBUcnVzdGVkIEc0IFRpbWVTdGFtcGluZyBSU0E0MDk2 # IFNIQTI1NiAyMDI1IENBMTAeFw0yNTA2MDQwMDAwMDBaFw0zNjA5MDMyMzU5NTla # MGMxCzAJBgNVBAYTAlVTMRcwFQYDVQQKEw5EaWdpQ2VydCwgSW5jLjE7MDkGA1UE # AxMyRGlnaUNlcnQgU0hBMjU2IFJTQTQwOTYgVGltZXN0YW1wIFJlc3BvbmRlciAy # MDI1IDEwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDQRqwtEsae0Oqu # YFazK1e6b1H/hnAKAd/KN8wZQjBjMqiZ3xTWcfsLwOvRxUwXcGx8AUjni6bz52fG # Tfr6PHRNv6T7zsf1Y/E3IU8kgNkeECqVQ+3bzWYesFtkepErvUSbf+EIYLkrLKd6 # qJnuzK8Vcn0DvbDMemQFoxQ2Dsw4vEjoT1FpS54dNApZfKY61HAldytxNM89PZXU # P/5wWWURK+IfxiOg8W9lKMqzdIo7VA1R0V3Zp3DjjANwqAf4lEkTlCDQ0/fKJLKL # kzGBTpx6EYevvOi7XOc4zyh1uSqgr6UnbksIcFJqLbkIXIPbcNmA98Oskkkrvt6l # PAw/p4oDSRZreiwB7x9ykrjS6GS3NR39iTTFS+ENTqW8m6THuOmHHjQNC3zbJ6nJ # 6SXiLSvw4Smz8U07hqF+8CTXaETkVWz0dVVZw7knh1WZXOLHgDvundrAtuvz0D3T # +dYaNcwafsVCGZKUhQPL1naFKBy1p6llN3QgshRta6Eq4B40h5avMcpi54wm0i2e # PZD5pPIssoszQyF4//3DoK2O65Uck5Wggn8O2klETsJ7u8xEehGifgJYi+6I03Uu # T1j7FnrqVrOzaQoVJOeeStPeldYRNMmSF3voIgMFtNGh86w3ISHNm0IaadCKCkUe # 2LnwJKa8TIlwCUNVwppwn4D3/Pt5pwIDAQABo4IBlTCCAZEwDAYDVR0TAQH/BAIw # ADAdBgNVHQ4EFgQU5Dv88jHt/f3X85FxYxlQQ89hjOgwHwYDVR0jBBgwFoAU729T # SunkBnx6yuKQVvYv1Ensy04wDgYDVR0PAQH/BAQDAgeAMBYGA1UdJQEB/wQMMAoG # CCsGAQUFBwMIMIGVBggrBgEFBQcBAQSBiDCBhTAkBggrBgEFBQcwAYYYaHR0cDov # L29jc3AuZGlnaWNlcnQuY29tMF0GCCsGAQUFBzAChlFodHRwOi8vY2FjZXJ0cy5k # aWdpY2VydC5jb20vRGlnaUNlcnRUcnVzdGVkRzRUaW1lU3RhbXBpbmdSU0E0MDk2 # U0hBMjU2MjAyNUNBMS5jcnQwXwYDVR0fBFgwVjBUoFKgUIZOaHR0cDovL2NybDMu # ZGlnaWNlcnQuY29tL0RpZ2lDZXJ0VHJ1c3RlZEc0VGltZVN0YW1waW5nUlNBNDA5 # NlNIQTI1NjIwMjVDQTEuY3JsMCAGA1UdIAQZMBcwCAYGZ4EMAQQCMAsGCWCGSAGG # /WwHATANBgkqhkiG9w0BAQsFAAOCAgEAZSqt8RwnBLmuYEHs0QhEnmNAciH45PYi # T9s1i6UKtW+FERp8FgXRGQ/YAavXzWjZhY+hIfP2JkQ38U+wtJPBVBajYfrbIYG+ # Dui4I4PCvHpQuPqFgqp1PzC/ZRX4pvP/ciZmUnthfAEP1HShTrY+2DE5qjzvZs7J # IIgt0GCFD9ktx0LxxtRQ7vllKluHWiKk6FxRPyUPxAAYH2Vy1lNM4kzekd8oEARz # FAWgeW3az2xejEWLNN4eKGxDJ8WDl/FQUSntbjZ80FU3i54tpx5F/0Kr15zW/mJA # xZMVBrTE2oi0fcI8VMbtoRAmaaslNXdCG1+lqvP4FbrQ6IwSBXkZagHLhFU9HCrG # /syTRLLhAezu/3Lr00GrJzPQFnCEH1Y58678IgmfORBPC1JKkYaEt2OdDh4GmO0/ # 5cHelAK2/gTlQJINqDr6JfwyYHXSd+V08X1JUPvB4ILfJdmL+66Gp3CSBXG6IwXM # ZUXBhtCyIaehr0XkBoDIGMUG1dUtwq1qmcwbdUfcSYCn+OwncVUXf53VJUNOaMWM # ts0VlRYxe5nK+At+DI96HAlXHAL5SlfYxJ7La54i71McVWRP66bW+yERNpbJCjyC # YG2j+bdpxo/1Cy4uPcU3AWVPGrbn5PhDBf3Froguzzhk++ami+r3Qrx5bIbY3TVz # giFI7Gq3zWcwggdWMIIFPqADAgECAhADMlFYfN/evhzf5XYSzZUnMA0GCSqGSIb3 # DQEBCwUAMGkxCzAJBgNVBAYTAlVTMRcwFQYDVQQKEw5EaWdpQ2VydCwgSW5jLjFB # MD8GA1UEAxM4RGlnaUNlcnQgVHJ1c3RlZCBHNCBDb2RlIFNpZ25pbmcgUlNBNDA5 # NiBTSEEzODQgMjAyMSBDQTEwHhcNMjUwMzIwMDAwMDAwWhcNMjYwNjAzMjM1OTU5 # WjBeMQswCQYDVQQGEwJVUzEXMBUGA1UECBMOTm9ydGggQ2Fyb2xpbmExFDASBgNV # BAcTC01vcnJpc3ZpbGxlMQ8wDQYDVQQKEwZMZW5vdm8xDzANBgNVBAMTBkxlbm92 # bzCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAOPjJ/+Kdi4SqmdpYRYm # 5E/ctl9H/KHwC3GK10hQmHGetCCuJkcx+STyvxLIuuzh6CIupbxzDPXQ2x2/5jA6 # 2EROThgMKl/0fV+hwvZhVl45idBUi0qo+91jYeK9kXjjLrxXEsX6A5Uu4Lgl56vr # 8h6cGZg/te9ozF3k2JN80MIzSj/F769/ZpuGq9i4j1HQ7xq/aoXFlrTD86zSC7YG # AVU5PSU06ZOOTMAAvGm7ifKv/xQyeO8EE4acIgFB5a8RRC0JQj19eIRBhtfkh1dy # TX/ocPdsBQICpqo0VXvRb/9iaHj3+r9CWSPtx0kQxRkpHMv/qCtM7kBscljbejLA # VOXuhWKmNemNGIu7UMIZyro3+XzI4s1biJlGp6bTShs02EbmzlyUJTgithsYgC5n # X/WRcaHbshvy5S1EJo8m1fi5v/4bj9OTBUOjaYAVKvOjzYE7QR4PhuN/ww8HpGdR # jLS/eS8Sz3Jxz7EVApPNSzwycDkxAR6Y0w4ymaGy3ZnTOUJjESfwqJvqigjYMcbZ # +LJOqbLE6bQEmQ+tZiclcdoU4FhleAqQlfksb9kLc5GcU23uIp1aKQ1nji6pxMif # IHtE5OcMgJzy60tyX/dPpxBGbR3l6+K02v5KI1/GtrVSWxvJHKlXnIMQ4EcgIZBz # U+NPRgmPG7ZSzYRhpZl/+PrhAgMBAAGjggIDMIIB/zAfBgNVHSMEGDAWgBRoN+Dr # tjv4XxGG+/5hewiIZfROQjAdBgNVHQ4EFgQUcBJh2GrEdlUHxwi/fkRtYI55VfAw # PgYDVR0gBDcwNTAzBgZngQwBBAEwKTAnBggrBgEFBQcCARYbaHR0cDovL3d3dy5k # aWdpY2VydC5jb20vQ1BTMA4GA1UdDwEB/wQEAwIHgDATBgNVHSUEDDAKBggrBgEF # BQcDAzCBtQYDVR0fBIGtMIGqMFOgUaBPhk1odHRwOi8vY3JsMy5kaWdpY2VydC5j # b20vRGlnaUNlcnRUcnVzdGVkRzRDb2RlU2lnbmluZ1JTQTQwOTZTSEEzODQyMDIx # Q0ExLmNybDBToFGgT4ZNaHR0cDovL2NybDQuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0 # VHJ1c3RlZEc0Q29kZVNpZ25pbmdSU0E0MDk2U0hBMzg0MjAyMUNBMS5jcmwwgZQG # CCsGAQUFBwEBBIGHMIGEMCQGCCsGAQUFBzABhhhodHRwOi8vb2NzcC5kaWdpY2Vy # dC5jb20wXAYIKwYBBQUHMAKGUGh0dHA6Ly9jYWNlcnRzLmRpZ2ljZXJ0LmNvbS9E # aWdpQ2VydFRydXN0ZWRHNENvZGVTaWduaW5nUlNBNDA5NlNIQTM4NDIwMjFDQTEu # Y3J0MAkGA1UdEwQCMAAwDQYJKoZIhvcNAQELBQADggIBACeB1ob7bkUKbCC40mTr # HpXQHQbaeE7ymacNpXKyHefcQij+Op9DsduyOHNLbEojHm24k8GiGjx3ZnaZGKTh # RQHiijGN+H8Qy27SDvw2MzLnyB7XNg+uCPqIf6xWLdtdQ65T7MaBon6BIX/shzxQ # t+Jpkr1+qcAP6wWCQ0Q0W5I0w5PKb19dMaT26mw6mnGd06pnTvgpCVRnVy8UJtb7 # Ltt7dfE1G0Cz3LdWW9iBVCI73n/DGWhO8fbiK4D4NpdiNnWVfsxhJ7DSb+6RKJXP # eG3GwGbmuyDD3D2N9mJnW/6VYAiBwnewGRqwA6D20QKPB0QFHlqVHwkyoYIynVcE # dfM4K3dtxP8mh6IrEEbWfctNLRgnvRsEE/GnAEmpHxLyzWRx+FILzlaZmRPSyYAO # O8bE4nWNOTKLdpa/OMum6r/qDJmjcLs80aqMlRiG1k4F2grobscDV+lzy65du9+W # a8qUeY6rZsnHK02DGOf4iWLqEgaUf36QH10MUpGgj/dkK5cwLCpA1+/d+mySgEF3 # 1N2RHkf5bRVq0DsR8AGT76npVtpyRdnIlIHksfB0G8dDjioKEzCneATEUkketoL1 # ML+ZOcM8t2uURmjK8ZecklHZF74jmrkYVyve2HrxcHOr2qPuwOkRQ5NLnYluYKQo # Qv4KrbHKxS/bQKd55kJZVzTbMYIGSDCCBkQCAQEwfTBpMQswCQYDVQQGEwJVUzEX # MBUGA1UEChMORGlnaUNlcnQsIEluYy4xQTA/BgNVBAMTOERpZ2lDZXJ0IFRydXN0 # ZWQgRzQgQ29kZSBTaWduaW5nIFJTQTQwOTYgU0hBMzg0IDIwMjEgQ0ExAhADMlFY # fN/evhzf5XYSzZUnMAkGBSsOAwIaBQCgeDAYBgorBgEEAYI3AgEMMQowCKACgACh # AoAAMBkGCSqGSIb3DQEJAzEMBgorBgEEAYI3AgEEMBwGCisGAQQBgjcCAQsxDjAM # BgorBgEEAYI3AgEVMCMGCSqGSIb3DQEJBDEWBBRvaJrW2tl/Uz0Jp81mtWcLmX/0 # ZzANBgkqhkiG9w0BAQEFAASCAgBDG8YoHWM/e3tffOFTK0b3VPQFYjG2KQb0f0l8 # XPQ+uNRCIsKZbjUwCiDqlxttt6e7RjmzRzgp1w1ccxreEvg4v/bpuyO4k+FiGYtP # OfLjNtuOMWcVQZAeMr2w+Z4PBMYp8Qd0f0dDRHVPMSuqF1YOYfFAHUiRlWJONpKA # xLC09HfRcUvcxUl3CjWPijMd0V+Q+Iy1i019uVEAQLDPapkzA7RApGHnDPvDWIfU # u1yDcaUmNLaYSSnJcPpUuY4GHcRkWUP6wr1Vf29PfyB2AAv1HROaGoXphlO3dGUt # YMLFByQSjr6q7qlFrComJ0/p5pZB57aL1VuuWY6XTAXpVA9zW6Rrpv23r3ruTy/o # 9JI2yD6jbBLamy8naMU2Q2OIScoWIoXAEeI9YtmHXsRJDlEXZna1rWfFaEqCRFJ5 # gUHg4/IN8gERW9QfwTE70bEgwRtcIPY0JtYG7Q2jZ0Gnnn3mAOrtEo63JkL82wQ/ # 5CqrxW5Xt0UfuOYqySWtFN17BwRuB4QsbJ/tHWNH4zxXQdJlE5pWPG2H6qXwCCwA # d32RxJWqhmkSB/2UM2PVOwh6rvxUEK05P1P1CCohGBDHQ2B6rfdYKIxBboPHTYpZ # j3ddT33JWXcWiAiL9m7XwTjzuHp6O/Dq8SoDzrWxk1QZiJ3FTmsrRxbAJD113mZr # rJbIhaGCAyYwggMiBgkqhkiG9w0BCQYxggMTMIIDDwIBATB9MGkxCzAJBgNVBAYT # AlVTMRcwFQYDVQQKEw5EaWdpQ2VydCwgSW5jLjFBMD8GA1UEAxM4RGlnaUNlcnQg # VHJ1c3RlZCBHNCBUaW1lU3RhbXBpbmcgUlNBNDA5NiBTSEEyNTYgMjAyNSBDQTEC # EAqA7xhLjfEFgtHEdqeVdGgwDQYJYIZIAWUDBAIBBQCgaTAYBgkqhkiG9w0BCQMx # CwYJKoZIhvcNAQcBMBwGCSqGSIb3DQEJBTEPFw0yNjA0MDkxNTUxNDBaMC8GCSqG # SIb3DQEJBDEiBCCPRs7vMR+ih8NrBeBcnteleeRENh3fbrXb3k+R9KnVFzANBgkq # hkiG9w0BAQEFAASCAgCCqDR59qPpV46rkOvEoBbbfmzMEQJHSVcrpk+bNEaw7Cmh # fFygA9jD+bOPZnfroT5WeyWJW5/sOwxmdpV0hb9Gqb/9UuiVpawJcYGBW+inKToj # HRQyYie5VekLsMJZ1DQ3Dgr1faUU8yOxB23oVzsv47qc8m/DfiP1ssZ2OZTKX7ST # SkODLjKhNdfgUWqT2jwZ/4RaFVSL6wR0Q1cUYjEiYJtXpeIK5/js1bEYWD2GxLjr # 5c0BFSvqQoDVtwxGTrsHAtBJcPQAc+LWux0mISnRPQgYCdUhHcNaYMK6CZ20j+Bm # 8mOle1UNREgbq80Z1OcbnK/e27dVidv8aMNRLB2dxuHMJ6ZjwNLUIpz48Lxsf7Pz # xjqNrsXjZpRciXeFpq2qSbGNIOhwQgXlI0CmX4VAp+KvMKNnmzgKULkD/E0bbwiL # GEsG9cAEd8ovWgyXdgAtscOzcoiuZQ8k+PwukopaZBDVzG5DTmnWiwMGEz6UXC55 # msCGG/GLaUjDE1905ejzLvu3b5sqs6hXb9G34O0VSqE7xfMdbWEOA/UL2j1rws0n # ckrK4r0Cw+uknI3f1OxapZE/wSx7/PAc5+QJliPcUKo9KxXpXGkaZn9WHKOXfUua # 7/bg+56AyVYWUbhozk37jPfIzEM+HMfOBARtaZNCaRJbL7wkoNF71P2rM6eXeg== # SIG # End signature block |