scripts/ClearStorageHealthData.ps1
|
<#
.SYNOPSIS Clear Health Service data entries for storage components. .DESCRIPTION A general-purpose tool for erasing Health Service data records from CLUSDB and volatile storage. Provides preset parameter sets for common scenarios and a generic mode for arbitrary data entries. Preset modes: -MaintenanceModeIntent Erases the MaintenanceModeIntent private data store (StorHealth provider). Use when physical disks are stuck in maintenance mode due to orphaned intent after a health service failover. -PhysicalDiskIntent Erases the per-disk Intent bitmask flags. Use when a disk -PhysicalDiskPolicy shows stuck operational status like "Removing from Pool". Generic mode: -Name / -Key Erase any named data record on any entity key. Use -ProviderGuid to target private data stores. After running, move the Health Service resource to trigger a fresh startup: Move-ClusterGroup "SDDC Group" .PARAMETER MaintenanceModeIntent Erase the MaintenanceModeIntent private data store. This clears all maintenance mode tracking state (Intent, InheritedIntent, InProgress, Workflows maps). Use when physical disks are stuck in "In Maintenance Mode" after a health service failover. After clearing, move the health resource - the service will auto-detect disks in maintenance with no intent and create Disable workflows. .PARAMETER PhysicalDiskIntent Clear the per-disk Intent bitmask flags (operational status indicators like "Starting Maintenance Mode", "Stopping Maintenance Mode", "Removing from Pool"). .PARAMETER PhysicalDiskPolicy Clear the per-disk Policy data (S2D usage, firmware compliance state). .PARAMETER UniqueId The UniqueId of a physical disk (from Get-PhysicalDisk). Used with -PhysicalDiskIntent or -PhysicalDiskPolicy. .PARAMETER SerialNumber The SerialNumber of a physical disk (from Get-PhysicalDisk). Used with -PhysicalDiskIntent or -PhysicalDiskPolicy. .PARAMETER Name The data record name to erase (generic mode). .PARAMETER Key The entity key (objectId) that owns the data record (generic mode). .PARAMETER ProviderGuid Optional provider GUID for private data stores (generic mode). When specified, the Name is prefixed with "{ProviderGuid}::" to target a SimplePrivateDataStore entry instead of a public one. .PARAMETER Force Skip the confirmation prompt. .NOTES Name: Clear-StorageHealthData Based on: Clear-PhysicalDiskHealthData.ps1 by Don MacGregor Extended for maintenance mode and generic scenarios. ======================================================================== Provider GUIDs (use with -ProviderGuid for private data stores) ======================================================================== StorHealth: 29D1F3EE-DBCF-44E9-B0CC-085BFA362499 ClusHealth: E24B3E7E-A73A-4108-B79F-894CC1184295 PerfCounters: C06B98BF-0DBC-4259-AE0D-5801EDA8E7E1 ======================================================================== StorHealth Private Data Stores (ProviderGuid = 29D1F3EE-...) ======================================================================== Name Key Description ---- --- ----------- MaintenanceModeIntent Microsoft.Health.EntityType.StorageHealth Maintenance mode workflow state (Intent/InheritedIntent/InProgress/Workflows) MaintenanceModeSblDrainState Per-PD ObjectId (cache disk entity key) SBL cache drain progress tracking StorageFaultDomainCache Microsoft.Health.EntityType.StorageHealth Cached fault domain topology Cache Per-PD ObjectId Physical disk cache data FirmwareRollout Microsoft.Health.EntityType.PhysicalDisk Firmware update rollout tracking HealthCounters Per-entity-type string Health counter aggregates SecEncRotateKeyIntent Microsoft.Health.EntityType.StorageHealth SED encryption key rotation state SupportedComponents Per-entity-type string (PUBLIC store) Component compliance info StorHealth Private Scalar Values (per-PD ObjectId): UsageBeforeWeRetire Saved usage before retire operation UnretireCount Number of unretire attempts UnretireCountSetAt Timestamp of unretire count UnresponsiveRestoreCount Number of unresponsive restore attempts UnresponsiveRestoreCountSetAt Timestamp of restore count StorHealth Private Scalar Values (per-node/disk): PrevoiusS2DCacheMode Previous S2D cache mode (per-node or per-disk key) ======================================================================== ClusHealth Private Data Stores (ProviderGuid = E24B3E7E-...) ======================================================================== Name Key Description ---- --- ----------- RdmaAlertState RdmaAlertData RDMA alert tracking RdmaAlertingComputer RdmaAlertData RDMA alerting computer name RdmaAlertingInterface RdmaAlertData RDMA alerting interface RdmaAlertingAddress RdmaAlertData RDMA alerting address RdmaAlertingServer RdmaAlertData RDMA alerting server ValidationReportFaultRaised ValidationReportData Cluster validation report state ValidationReportSectionResult_{N} ValidationReportData Per-section validation results ValidationReportPath ValidationReportData Validation report file path ValidationReportDcbFaultNumFailures ValidationReportDcbData_{node} DCB validation failure count ValidationReportDcbPath ValidationReportDcbData_{node} DCB validation report path LastInstance Channel-{ch}-EventId-{id} ETW event dedup tracking ======================================================================== PerfCounters Private Data Stores (ProviderGuid = C06B98BF-...) ======================================================================== ClusPortDiskInfoMapContainer Per-node name ClusPort disk info mapping ======================================================================== Public Data Records (no ProviderGuid needed, use -Name and -Key directly) ======================================================================== Name Key Description ---- --- ----------- Intent Per-PD ObjectId Operational status bitmask flags (maintenance mode, removing from pool, etc.) Policy Per-PD ObjectId S2D usage policy, firmware compliance, marginal failure bitmask InternalOperation Per-PD ObjectId Internal operation tracking (retire/unretire) PoolCreationResult (empty key) Pool creation result status SetS2DUsageResult (empty key) S2D usage change result status .EXAMPLE # Scenario: Physical disks stuck in maintenance mode after health service failover .\ClearStorageHealthData.ps1 -MaintenanceModeIntent -Verbose -Force Move-ClusterGroup "SDDC Group" .EXAMPLE # Scenario: Physical disk stuck in "Removing from Pool" status .\ClearStorageHealthData.ps1 -PhysicalDiskIntent -UniqueId 5000C5007952B6E8 -Verbose -Force .EXAMPLE # Scenario: Clear both intent and policy on a disk by serial number .\ClearStorageHealthData.ps1 -PhysicalDiskIntent -PhysicalDiskPolicy -SerialNumber Z1Z5L2SX -Verbose -Force .EXAMPLE # Scenario: Clear an arbitrary private data store entry .\ClearStorageHealthData.ps1 -Name "MaintenanceModeSblDrainState" ` -Key "{3fedb9cb-0cfd-43c6-aa07-19253f282529}:PD:{896cbde3-a568-03cf-27c9-39e7128557fe}" ` -ProviderGuid "29D1F3EE-DBCF-44E9-B0CC-085BFA362499" ` -Verbose -Force .EXAMPLE # Scenario: Clear an arbitrary public data store entry .\ClearStorageHealthData.ps1 -Name "SomeDataName" -Key "SomeEntityKey" -Verbose -Force .EXAMPLE # Pipe physical disks to clear intent Get-PhysicalDisk -UniqueId 5000C5007952B6E8 | .\ClearStorageHealthData.ps1 -PhysicalDiskIntent -Verbose -Force #> [CmdletBinding( DefaultParameterSetName = "MaintenanceMode", SupportsShouldProcess, ConfirmImpact = 'High' )] Param ( # --- MaintenanceMode parameter set --- [Parameter(ParameterSetName = "MaintenanceMode", Mandatory = $true)] [switch]$MaintenanceModeIntent, # --- PhysicalDisk parameter sets (by UniqueId or SerialNumber) --- [Parameter(ParameterSetName = "PDByUniqueId")] [Parameter(ParameterSetName = "PDBySerial")] [switch]$PhysicalDiskIntent, [Parameter(ParameterSetName = "PDByUniqueId")] [Parameter(ParameterSetName = "PDBySerial")] [switch]$PhysicalDiskPolicy, [Parameter(ParameterSetName = "PDByUniqueId", Mandatory = $true, ValueFromPipelineByPropertyName = $true)] [string]$UniqueId, [Parameter(ParameterSetName = "PDBySerial", Mandatory = $true)] [string]$SerialNumber, # --- Generic parameter set --- [Parameter(ParameterSetName = "Generic", Mandatory = $true)] [string]$Name, [Parameter(ParameterSetName = "Generic", Mandatory = $true)] [string]$Key, [Parameter(ParameterSetName = "Generic")] [string]$ProviderGuid, # --- Common --- [Parameter()] [switch]$Force ) Begin { Write-Verbose "Compiling Health API interop code" Add-Type -ErrorAction SilentlyContinue @" using System; using System.Runtime.InteropServices; public class HealthDataUtil { public enum HealthDataFlags { HealthDataFlagNone = 0x00, HealthDataFlagBitmask = 0x01, HealthDataFlagPersist = 0x02, HealthDataFlagErase = 0x04, HealthDataFlagPrivate = 0x08, HealthDataFlagBitsetWithMask = 0x10, HealthDataFlagReleaseLocalLock = 0x20 } [UnmanagedFunctionPointer(CallingConvention.StdCall)] delegate void HealthOpenCallback(long filter, IntPtr context); [DllImport("healthapi.dll", SetLastError = true, CharSet = CharSet.Unicode)] static extern IntPtr HealthOpenConnection(HealthOpenCallback pCallback, IntPtr pContext, int flags); [DllImport("healthapi.dll", SetLastError = true, CharSet = CharSet.Unicode)] static extern int HealthCloseConnection(IntPtr healthHandle); [DllImport("healthapi.dll", SetLastError = true, CharSet = CharSet.Unicode)] static extern int HealthAddUInt64Data(IntPtr healthHandle, string name, string objectId, HealthDataFlags flags, ulong value); private static void HandleOpenCallback(long filter, IntPtr context) {} public static int EraseDataRecord(string objectId, string dataName) { try { int rc = 0; HealthOpenCallback openCallback = new HealthOpenCallback(HandleOpenCallback); IntPtr healthHandle = HealthOpenConnection(openCallback, IntPtr.Zero, 0); if (healthHandle == IntPtr.Zero) return 110; // ERROR_OPEN_FAILED // Erase the volatile copy if (rc == 0) rc = HealthAddUInt64Data(healthHandle, dataName, objectId, HealthDataFlags.HealthDataFlagErase, 0); // Erase the persisted copy (CLUSDB) if (rc == 0) rc = HealthAddUInt64Data(healthHandle, dataName, objectId, HealthDataFlags.HealthDataFlagPersist | HealthDataFlags.HealthDataFlagErase, 0); HealthCloseConnection(healthHandle); return rc; } catch { return -1; } } } "@ } Process { # --------------------------------------------------------------- # Resolve the target Key and Name(s) based on the parameter set # --------------------------------------------------------------- $dataRecords = @() # list of @{ Key; Name; Description } switch ($PSCmdlet.ParameterSetName) { "MaintenanceMode" { $storHealthGuid = "29D1F3EE-DBCF-44E9-B0CC-085BFA362499" $entityKey = "Microsoft.Health.EntityType.StorageHealth" $dataName = "${storHealthGuid}::MaintenanceModeIntent" # Show current stuck disks for context Write-Verbose "Checking for physical disks currently in maintenance mode..." $stuckDisks = Get-PhysicalDisk | Where-Object { $_.OperationalStatus -eq 'In Maintenance Mode' } if ($stuckDisks) { Write-Verbose "Found $($stuckDisks.Count) disk(s) in maintenance mode:" foreach ($disk in $stuckDisks) { Write-Verbose " - $($disk.FriendlyName) (UniqueId: $($disk.UniqueId))" } } else { Write-Verbose "No physical disks currently in maintenance mode." return $false } $dataRecords += @{ Key = $entityKey Name = $dataName Description = "MaintenanceModeIntent (Intent/InheritedIntent/InProgress/Workflows)" } } { $_ -in "PDByUniqueId", "PDBySerial" } { if ((-not $PhysicalDiskIntent) -and (-not $PhysicalDiskPolicy)) { Write-Warning "No data type specified. Use -PhysicalDiskIntent, -PhysicalDiskPolicy, or both." return $false } # Resolve the physical disk $pd = $null if ($PSCmdlet.ParameterSetName -eq "PDByUniqueId") { Write-Verbose "Looking up physical disk by UniqueId: $UniqueId" $pd = Get-PhysicalDisk -UniqueId $UniqueId if (-not $pd) { Write-Error "Unable to find Physical Disk with UniqueId '$UniqueId'" return $false } } else { Write-Verbose "Looking up physical disk by SerialNumber: $SerialNumber" $pd = Get-PhysicalDisk -SerialNumber $SerialNumber if (-not $pd) { Write-Error "Unable to find Physical Disk with SerialNumber '$SerialNumber'" return $false } } # Extract health object ID from the WMI ObjectId $healthObjectIdOffset = $pd.ObjectId.IndexOf('="') + 2 $healthObjectIdLength = $pd.ObjectId.Length - $healthObjectIdOffset - 1 $healthObjectId = $pd.ObjectId.Substring($healthObjectIdOffset, $healthObjectIdLength) Write-Verbose "Found Physical Disk: UniqueId=$($pd.UniqueId) SerialNumber=$($pd.SerialNumber) HealthObjectId=$healthObjectId" if ($PhysicalDiskIntent) { $dataRecords += @{ Key = $healthObjectId Name = "Intent" Description = "Physical Disk Intent flags on $($pd.FriendlyName) ($($pd.SerialNumber))" } } if ($PhysicalDiskPolicy) { $dataRecords += @{ Key = $healthObjectId Name = "Policy" Description = "Physical Disk Policy data on $($pd.FriendlyName) ($($pd.SerialNumber))" } } } "Generic" { $resolvedName = $Name if ($ProviderGuid) { $resolvedName = "${ProviderGuid}::${Name}" Write-Verbose "Private data store - resolved name: $resolvedName" } $dataRecords += @{ Key = $Key Name = $resolvedName Description = "Data record '$resolvedName' on key '$Key'" } } } # --------------------------------------------------------------- # Erase each resolved data record # --------------------------------------------------------------- $allSuccess = $true foreach ($record in $dataRecords) { Write-Verbose "Target: Key='$($record.Key)' Name='$($record.Name)'" if ($Force -or $PSCmdlet.ShouldProcess($record.Description, "Erase health data record")) { Write-Verbose "Erasing: $($record.Description)" $rc = [HealthDataUtil]::EraseDataRecord($record.Key, $record.Name) if ($rc -ne 0) { Write-Error "Failed to erase $($record.Description). Error code: $rc" $allSuccess = $false } else { Write-Verbose "Successfully erased: $($record.Description)" } } } if ($allSuccess -and $dataRecords.Count -gt 0) { Write-Host "" Write-Host "Health data erased successfully." -ForegroundColor Green Write-Host "" Write-Host "NEXT STEPS:" -ForegroundColor Yellow if ($MaintenanceModeIntent) { Write-Host " 1. Move the SDDC Group to restart Health and dependent resources:" Write-Host " Move-ClusterGroup 'SDDC Group'" -ForegroundColor Cyan Write-Host "" Write-Host " 2. Wait ~30 seconds for the health service to stabilize and" Write-Host " auto-detect disks in maintenance with no intent." Write-Host "" Write-Host " 3. Verify disks are coming out of maintenance mode:" Write-Host " Get-PhysicalDisk | Where-Object { `$_.OperationalStatus -eq 'In Maintenance Mode' }" -ForegroundColor Cyan Write-Host "" Write-Host " If disks are still stuck, restart Health to trigger a full scan:" Write-Host " Stop-ClusterResource 'Health'; Start-Sleep 3; Start-ClusterResource 'Health'" -ForegroundColor Cyan Write-Host " Move-ClusterGroup 'SDDC Group' # bring SDDC Management back online" -ForegroundColor Cyan Write-Host "" Write-Host " The health service will auto-detect disks in maintenance mode" Write-Host " with no intent and create Disable workflows to remove them." -ForegroundColor Gray } else { Write-Host " 1. Move the SDDC Group to restart Health and dependent resources:" Write-Host " Move-ClusterGroup 'SDDC Group'" -ForegroundColor Cyan Write-Host "" Write-Host " 2. Verify the affected component has recovered." } } return $allSuccess } # SIG # Begin signature block # MIInSQYJKoZIhvcNAQcCoIInOjCCJzYCAQExDzANBglghkgBZQMEAgEFADB5Bgor # BgEEAYI3AgEEoGswaTA0BgorBgEEAYI3AgEeMCYCAwEAAAQQH8w7YFlLCE63JNLG # KX7zUQIBAAIBAAIBAAIBAAIBADAxMA0GCWCGSAFlAwQCAQUABCBf5W7mmsYlTSJh # xoUU6XtvmXKUWhV13fEz18jB8EYkvKCCDLowggX1MIID3aADAgECAhMzAAACHU0Z # yE7XD1dIAAAAAAIdMA0GCSqGSIb3DQEBCwUAMFcxCzAJBgNVBAYTAlVTMR4wHAYD # VQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xKDAmBgNVBAMTH01pY3Jvc29mdCBD # b2RlIFNpZ25pbmcgUENBIDIwMjQwHhcNMjYwNDE2MTg1OTQzWhcNMjcwNDE1MTg1 # OTQzWjB0MQswCQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UE # BxMHUmVkbW9uZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMR4wHAYD # VQQDExVNaWNyb3NvZnQgQ29ycG9yYXRpb24wggEiMA0GCSqGSIb3DQEBAQUAA4IB # DwAwggEKAoIBAQDQvewXxx9gZZFC6Ys1WBay8BJ8kGA4JQnH5CMafqOASlTpK9H8 # o5ZXTXt0caVQTNMUPt445wXYD+dFtaKWTwDn1I52oUSrC9vJin1Gsqt+zyKJL5Dg # 3eQXbQNR61DmMy20GLTIO3SFed9Rfi/ophgCLGFLDR3r0KvHjwMb/jYWS0celV/4 # Lz27LfAekm8v9E5IXaeiXbAUYZKK090n4CVl3JBtbN+9DtI9SNu/yjvozW52/u7R # X/Ttpa/KDlpuokZ+Zcbvmtd9ur9gFLvZzh41o9MsE/clQtdaFWGvuo6Jua/ntpgk # ey3E5/vBFe+MJPG6phdnuo6r57ZudCudiI1bAgMBAAGjggGbMIIBlzAOBgNVHQ8B # Af8EBAMCB4AwHwYDVR0lBBgwFgYKKwYBBAGCN0wIAQYIKwYBBQUHAwMwHQYDVR0O # BBYEFH6QuMwqcPG0hQlQ6c5jCtTTLrVeMEUGA1UdEQQ+MDykOjA4MR4wHAYDVQQL # ExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xFjAUBgNVBAUTDTIzMDAxMis1MDc1NTkw # HwYDVR0jBBgwFoAUf1k/VCHarU/vBeXmo9ctBpQSCDEwYAYDVR0fBFkwVzBVoFOg # UYZPaHR0cDovL3d3dy5taWNyb3NvZnQuY29tL3BraW9wcy9jcmwvTWljcm9zb2Z0 # JTIwQ29kZSUyMFNpZ25pbmclMjBQQ0ElMjAyMDI0LmNybDBtBggrBgEFBQcBAQRh # MF8wXQYIKwYBBQUHMAKGUWh0dHA6Ly93d3cubWljcm9zb2Z0LmNvbS9wa2lvcHMv # Y2VydHMvTWljcm9zb2Z0JTIwQ29kZSUyMFNpZ25pbmclMjBQQ0ElMjAyMDI0LmNy # dDAMBgNVHRMBAf8EAjAAMA0GCSqGSIb3DQEBCwUAA4ICAQBKTbYOjzwTG/DXGaz9 # s6+fQeaTtDcFmMY+5UyVFCyj7Pv+5i37qfX8lSL/tBIfYQfWsMuBQlfZurJD6r4H # VJ2CeH+1fgiq8dcHdVKoZ3Sa2qXoX3cq9iS8cVb06B7+5/XJ7I0OxHH9fDsvJ3T3 # w5V/ZtAIFmLrl+P0CtG+92uzRsn0nTbdFjOkLMLWPLAU3THohKRlSEMgFJpPkm5n # 5UAZ35xX6FWCrDLsSKb555bTifwa8mJBwdlof0bmfYidH+dxZ1FdDxvLnNl9zeKs # A4kejaaIqqIPguhwAti5Ql7BlTNoJNwxCvBmqW2MQLnCkYN/VVUsR3V2x/rcTNzo # Bf/Z/SpROvdaA2ZOOd1uioXJt3tdLQ7vHpqpib0KfWr/FWXW10q38VxfCnRQBqzb # SuztR7nEMuzX7Ck+B/XaPDXd1qh72+QYyB0Z2VzWmO9zsnb9Uq/dwu8LGeQqnyu6 # 7SDGACvnXii2fb9+US492VTnXSnFKyqwgzUyFMtZK1/sHYTv6bG4TtQUygQxTN+Z # V+aJIlKO2MqZ7bKrAnOzS9m6NgoTdWOq11bTOZwKlIEV/EhV9SWkDmdpR/hPPT2v # 6TEj4F8PT/zHjRezIU5c/DGlt/VhY/pK0XkJtEyMmmS1BMtjU/rqBZVMIm3dnxQs # /TBByr+Cf8Z1r7aifQVQ+WSqzjCCBr0wggSloAMCAQICEzMAAAA5O7Y3Gb8GHWcA # AAAAADkwDQYJKoZIhvcNAQEMBQAwgYgxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpX # YXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNyb3NvZnQg # Q29ycG9yYXRpb24xMjAwBgNVBAMTKU1pY3Jvc29mdCBSb290IENlcnRpZmljYXRl # IEF1dGhvcml0eSAyMDExMB4XDTI0MDgwODIwNTQxOFoXDTM2MDMyMjIyMTMwNFow # VzELMAkGA1UEBhMCVVMxHjAcBgNVBAoTFU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjEo # MCYGA1UEAxMfTWljcm9zb2Z0IENvZGUgU2lnbmluZyBQQ0EgMjAyNDCCAiIwDQYJ # KoZIhvcNAQEBBQADggIPADCCAgoCggIBANgBnB7jOMeqlRYHNa265v4IY9fH8TKh # emHfPINe1gpLaV3dhg324WwH06LcHbpnsBukCDNitryo0dtS/EW6I/yEL/bLSY8h # KpbfQuWusBPr9qazYcDxCW/qnjb5JsI1s8bNOg3bVATvQVL4tcf03aTycsz8QeCd # M0l/yHRObJ9QqazM1r6VPEOJ7LL+uEEb73w6QCuhs89a1uv1zerOYMnsneRRwCbp # yW11IcggU0cRKDDq1pjVJzIbIF6+oiXXbReOsgeI8zu1FyQfK0fVkaya8SmVHQ/t # Of23mZ4W9k0Ri22QW9p3UgSC5OUDktKxxcCmGL6tXLfOGSWHIIV4YrTJTT6PNty5 # REojHJuZHArkF9VnHTERWoTjAzfI3kP+5b4alUdhgAZ7ttOu1bVnXfHaqPYl2rPs # 20ji03LOVWsh/radgE17es5hL+t6lV0eVHrVhsssROWJuz2MXMCt7iw7lFPG9LXK # Gjsmonn2gotGdHIuEg5JnJMJVmixd5LRlkmgYRZKzhxSCwyoGIq0PhaA7Y+VPct5 # pCHkijcIIDm0nlkK+0KyepolcqGm0T/GYQRMhHJlGOOmVQop36wUVUYklUy++vDW # eEgEo4s7hxN6mIbf2MSIQ/iIfMZgJxC69oukMUXCrOC3SkE/xIkgpfl22MM1itkZ # 35nNXkMolU1lAgMBAAGjggFOMIIBSjAOBgNVHQ8BAf8EBAMCAYYwEAYJKwYBBAGC # NxUBBAMCAQAwHQYDVR0OBBYEFH9ZP1Qh2q1P7wXl5qPXLQaUEggxMBkGCSsGAQQB # gjcUAgQMHgoAUwB1AGIAQwBBMA8GA1UdEwEB/wQFMAMBAf8wHwYDVR0jBBgwFoAU # ci06AjGQQ7kUBU7h6qfHMdEjiTQwWgYDVR0fBFMwUTBPoE2gS4ZJaHR0cDovL2Ny # bC5taWNyb3NvZnQuY29tL3BraS9jcmwvcHJvZHVjdHMvTWljUm9vQ2VyQXV0MjAx # MV8yMDExXzAzXzIyLmNybDBeBggrBgEFBQcBAQRSMFAwTgYIKwYBBQUHMAKGQmh0 # dHA6Ly93d3cubWljcm9zb2Z0LmNvbS9wa2kvY2VydHMvTWljUm9vQ2VyQXV0MjAx # MV8yMDExXzAzXzIyLmNydDANBgkqhkiG9w0BAQwFAAOCAgEAFJQfOChP7onn6fLI # MKrSlN1WYKwDFgAddymOUO3FrM8d7B/W/iQ6DxXsDn7D5W4wMwYeLystcEqfkjz4 # NURRgazyMu5yRzQh4LqjA4tStTcJh1opExo7nn5PuPBYnbu0+THSuVHTe0VTTPVh # ily/piFrDo3axQ9P4C+Ol5yet+2gTfekICS5xS+cYfSIvgn0JksVBVMYVI5QFu/q # hnLhsEFEUzG8fvv0hjgkO+lkpV9ty6GkN4vdnd7ya6Q6aR9y34aiM1qmxaxBi6OU # nyNl6fkuun/diTFnYDLTppOkr/mg5WSfCiDVMNCxtj4wPKC5OmHm1DQIt/MNokbb # H3UGsFP1QbzsLocuSqLCvH09Io3fDPTmscR9Y75G4qX7RTX8AdBPo0I6OEojf39z # uFZt0qOHm65YWQE69cZM2ueE1MB05dNNgHK9gTE7zKvK/fg8B2qjW88MT/WF5V5u # vZGtqa9FSL2RazArA+rDPuf6JGYz4HpgMZHB4S6szWSKYBv0VisCzfxgeU+dquXW # 9bd0auYlOB58DPcOYKdc3Se94g+xL4pcEhbB54JOgAkwYTu/9dLeH2pDqeJZAABV # DWRQCaXfO5LgyKwKCLYXpigrZYCjUSBcr+Ve8PFWMhVTQl0v4q8J/AUmQN5W4n10 # 1cY2L4A7GTQG1h32HHAvfQESWP0xghnlMIIZ4QIBATBuMFcxCzAJBgNVBAYTAlVT # MR4wHAYDVQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xKDAmBgNVBAMTH01pY3Jv # c29mdCBDb2RlIFNpZ25pbmcgUENBIDIwMjQCEzMAAAIdTRnITtcPV0gAAAAAAh0w # DQYJYIZIAWUDBAIBBQCgga4wGQYJKoZIhvcNAQkDMQwGCisGAQQBgjcCAQQwHAYK # KwYBBAGCNwIBCzEOMAwGCisGAQQBgjcCARUwLwYJKoZIhvcNAQkEMSIEINsfKwhC # R6E9+YcmjHvRQ9bGImBfopjj0h/TBCMRCm2yMEIGCisGAQQBgjcCAQwxNDAyoBSA # EgBNAGkAYwByAG8AcwBvAGYAdKEagBhodHRwOi8vd3d3Lm1pY3Jvc29mdC5jb20w # DQYJKoZIhvcNAQEBBQAEggEAyStIXXLxNQxukOEcpozzJKmAqnmmdF+hgTB3LEwQ # yDOyPCeO+IRNiFJBpNRxF55Tp45Qpskll54QavXICwcB0Q1mqmrW6hIWVtuWgF8E # Z5jZUQMRXRSqfr1hEltTmJb7VbS9N8IELA0hCw7OM6+CcyBb7rbMUZO+8MQKrVf7 # 5FkLT0cpNjD7GQf4VRP3NRVpYDV3JXI/dY9KOE/UBE1BqriucS1eSj8Ez1ZdRBXf # Cj8bUM5foXndRaLyt3ZI4b5rSgQMbSp9OTjuDAbdHUtqZNyRROt+20SlDJyWkTiC # NmZPU6b+HZdf9/tMwoEf6cxcmbcLC1wGbWpdZ5JbrKoNdaGCF5cwgheTBgorBgEE # AYI3AwMBMYIXgzCCF38GCSqGSIb3DQEHAqCCF3AwghdsAgEDMQ8wDQYJYIZIAWUD # BAIBBQAwggFSBgsqhkiG9w0BCRABBKCCAUEEggE9MIIBOQIBAQYKKwYBBAGEWQoD # ATAxMA0GCWCGSAFlAwQCAQUABCD50ULSvT64vycyySnD6dyhIUEqRvWOZxW67StT # c17KVgIGajIAa/thGBMyMDI2MDcxNjIyNTUzNS42NzFaMASAAgH0oIHRpIHOMIHL # MQswCQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVk # bW9uZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMSUwIwYDVQQLExxN # aWNyb3NvZnQgQW1lcmljYSBPcGVyYXRpb25zMScwJQYDVQQLEx5uU2hpZWxkIFRT # UyBFU046MzMwMy0wNUUwLUQ5NDcxJTAjBgNVBAMTHE1pY3Jvc29mdCBUaW1lLVN0 # YW1wIFNlcnZpY2WgghHtMIIHIDCCBQigAwIBAgITMwAAAiEzwDX70g8hpAABAAAC # ITANBgkqhkiG9w0BAQsFADB8MQswCQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGlu # Z3RvbjEQMA4GA1UEBxMHUmVkbW9uZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBv # cmF0aW9uMSYwJAYDVQQDEx1NaWNyb3NvZnQgVGltZS1TdGFtcCBQQ0EgMjAxMDAe # Fw0yNjAyMTkxOTM5NTRaFw0yNzA1MTcxOTM5NTRaMIHLMQswCQYDVQQGEwJVUzET # MBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9uZDEeMBwGA1UEChMV # TWljcm9zb2Z0IENvcnBvcmF0aW9uMSUwIwYDVQQLExxNaWNyb3NvZnQgQW1lcmlj # YSBPcGVyYXRpb25zMScwJQYDVQQLEx5uU2hpZWxkIFRTUyBFU046MzMwMy0wNUUw # LUQ5NDcxJTAjBgNVBAMTHE1pY3Jvc29mdCBUaW1lLVN0YW1wIFNlcnZpY2UwggIi # MA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDbcTACqU1YvRocyWL2PL9fyf/+ # ULs2qK7U1aZsRnDZSnlCr7K7jgA3eFCEJL5BZ7dUTC0DeZepf+ZC+7HEbB4IdzmJ # fQAUDFFerqY5VTHmQvP2XA3lWSFj740idcGUHglP5H/PbCJU7GAHWP2HdcCjdx1l # YAo0A+zLI7xwnTQeMyOXX212Eg4UmDPPJgxdTMw6WFVWsBPWRBi5gDixy2s+7R8A # Dk5lbBBFDB5h0CjrNWIN7uCAzF5g7trrL8nXIKp10mj9RxhcGQ+tlht6VIvdygRV # TUGdzFB2/nBvJqQ9kxxFltQST70fEdx4TyaKow/f5+BSh4z4/9f7NXIVVTLn/8kc # JAfRqFmRrrFt3IKby7VrzmYuoQWD0lmNFtGQ57BrJkPrPFAPek1ALtcbb7FH3nQp # vi8ngz/MFX/+cnmNFWFU29VVLmzB9XvLZxbYvkeett0mh5lfteeN2rEwUyrdrKuf # z9h2S6pbate+C2h02CrXwSka0x6ezpTmGkIJLFt25ub/UYXNLdHdsxGD6EfckOIo # JYsm4MS9F/vSqLNHK89I0vTLBngQEp6LIFkINanRT3PtNx3pNKRKJRALc6L6mhW4 # hL4aHL749qPfQ72t5qAMm5xiKYMgJ2WanidRLNuI251JIN7raaeA/2vb0XFkZcIb # TR1pfQGsco4U0g5tjwIDAQABo4IBSTCCAUUwHQYDVR0OBBYEFOYjIs5qa6pfuquP # yyK1FTr5QDCnMB8GA1UdIwQYMBaAFJ+nFV0AXmJdg/Tl0mWnG1M1GelyMF8GA1Ud # HwRYMFYwVKBSoFCGTmh0dHA6Ly93d3cubWljcm9zb2Z0LmNvbS9wa2lvcHMvY3Js # L01pY3Jvc29mdCUyMFRpbWUtU3RhbXAlMjBQQ0ElMjAyMDEwKDEpLmNybDBsBggr # BgEFBQcBAQRgMF4wXAYIKwYBBQUHMAKGUGh0dHA6Ly93d3cubWljcm9zb2Z0LmNv # bS9wa2lvcHMvY2VydHMvTWljcm9zb2Z0JTIwVGltZS1TdGFtcCUyMFBDQSUyMDIw # MTAoMSkuY3J0MAwGA1UdEwEB/wQCMAAwFgYDVR0lAQH/BAwwCgYIKwYBBQUHAwgw # DgYDVR0PAQH/BAQDAgeAMA0GCSqGSIb3DQEBCwUAA4ICAQA4I/3bkdnTxD2rFum3 # MF8xVKdEkohAObbePrQ+0fr5bRimjz9sVkKT/7gcj4OMcClSYG+IdX6Mp3EYsLHW # fjvwfzFoeZE+yTbdBj/1VHZQRuCmw6QqeVCTbw2nnS7nBxnWd9oZXbPUpqEawH5D # qXQaWFgR9A4KWVK/IvXVDMj1PlPCES1P3JonNbdhkkkz49rJuKOm5b7e/BH8loqA # mXOXRc22yxWVTMWrEp4pslmv8eT7VoY8X/jdKYTPVEXsfmLbVFcqzMuB8vFGfUyW # sWROS8wgq7lQYfWcYqh7NymoATX+wWYK3zWG7aRciPGUAzznXdf+aHtIWnQLNa5H # FmSXkiak3fSuprWYZiHhuYjE16hroApcBHpm+8S/kNqhm9WjQX+2BxnYv+Jejy6l # qTi8fLBLS069WXVw/ptf5IV+FtYl34GvVoeg31UoUmVVZe1SDUJkm9dDXc8l/qBD # YiAIT2CCsPTyt9XA9JVuHxdP63n7ChvWAO/47QRuCDsUlFJoWwyBwl7jeYpaRVMt # Qt0iuJMGGjgEaJX1Q/2j8sXURvTceLHDD9ipWt092ZDWMQciDRmhHNFOX1dnjBvk # /k1UMcg997j5oYznAnSpJvlg/4BP3aVE0h/YH2KgsKbU4NXZHAjJXj2Slqo1C115 # CG6qBZaFkM8W6vPZCm5qnSezOjCCB3EwggVZoAMCAQICEzMAAAAVxedrngKbSZkA # AAAAABUwDQYJKoZIhvcNAQELBQAwgYgxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpX # YXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNyb3NvZnQg # Q29ycG9yYXRpb24xMjAwBgNVBAMTKU1pY3Jvc29mdCBSb290IENlcnRpZmljYXRl # IEF1dGhvcml0eSAyMDEwMB4XDTIxMDkzMDE4MjIyNVoXDTMwMDkzMDE4MzIyNVow # fDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCldhc2hpbmd0b24xEDAOBgNVBAcTB1Jl # ZG1vbmQxHjAcBgNVBAoTFU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjEmMCQGA1UEAxMd # TWljcm9zb2Z0IFRpbWUtU3RhbXAgUENBIDIwMTAwggIiMA0GCSqGSIb3DQEBAQUA # A4ICDwAwggIKAoICAQDk4aZM57RyIQt5osvXJHm9DtWC0/3unAcH0qlsTnXIyjVX # 9gF/bErg4r25PhdgM/9cT8dm95VTcVrifkpa/rg2Z4VGIwy1jRPPdzLAEBjoYH1q # UoNEt6aORmsHFPPFdvWGUNzBRMhxXFExN6AKOG6N7dcP2CZTfDlhAnrEqv1yaa8d # q6z2Nr41JmTamDu6GnszrYBbfowQHJ1S/rboYiXcag/PXfT+jlPP1uyFVk3v3byN # pOORj7I5LFGc6XBpDco2LXCOMcg1KL3jtIckw+DJj361VI/c+gVVmG1oO5pGve2k # rnopN6zL64NF50ZuyjLVwIYwXE8s4mKyzbnijYjklqwBSru+cakXW2dg3viSkR4d # Pf0gz3N9QZpGdc3EXzTdEonW/aUgfX782Z5F37ZyL9t9X4C626p+Nuw2TPYrbqgS # Uei/BQOj0XOmTTd0lBw0gg/wEPK3Rxjtp+iZfD9M269ewvPV2HM9Q07BMzlMjgK8 # QmguEOqEUUbi0b1qGFphAXPKZ6Je1yh2AuIzGHLXpyDwwvoSCtdjbwzJNmSLW6Cm # gyFdXzB0kZSU2LlQ+QuJYfM2BjUYhEfb3BvR/bLUHMVr9lxSUV0S2yW6r1AFemzF # ER1y7435UsSFF5PAPBXbGjfHCBUYP3irRbb1Hode2o+eFnJpxq57t7c+auIurQID # AQABo4IB3TCCAdkwEgYJKwYBBAGCNxUBBAUCAwEAATAjBgkrBgEEAYI3FQIEFgQU # KqdS/mTEmr6CkTxGNSnPEP8vBO4wHQYDVR0OBBYEFJ+nFV0AXmJdg/Tl0mWnG1M1 # GelyMFwGA1UdIARVMFMwUQYMKwYBBAGCN0yDfQEBMEEwPwYIKwYBBQUHAgEWM2h0 # dHA6Ly93d3cubWljcm9zb2Z0LmNvbS9wa2lvcHMvRG9jcy9SZXBvc2l0b3J5Lmh0 # bTATBgNVHSUEDDAKBggrBgEFBQcDCDAZBgkrBgEEAYI3FAIEDB4KAFMAdQBiAEMA # QTALBgNVHQ8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAfBgNVHSMEGDAWgBTV9lbL # j+iiXGJo0T2UkFvXzpoYxDBWBgNVHR8ETzBNMEugSaBHhkVodHRwOi8vY3JsLm1p # Y3Jvc29mdC5jb20vcGtpL2NybC9wcm9kdWN0cy9NaWNSb29DZXJBdXRfMjAxMC0w # Ni0yMy5jcmwwWgYIKwYBBQUHAQEETjBMMEoGCCsGAQUFBzAChj5odHRwOi8vd3d3 # Lm1pY3Jvc29mdC5jb20vcGtpL2NlcnRzL01pY1Jvb0NlckF1dF8yMDEwLTA2LTIz # LmNydDANBgkqhkiG9w0BAQsFAAOCAgEAnVV9/Cqt4SwfZwExJFvhnnJL/Klv6lwU # tj5OR2R4sQaTlz0xM7U518JxNj/aZGx80HU5bbsPMeTCj/ts0aGUGCLu6WZnOlNN # 3Zi6th542DYunKmCVgADsAW+iehp4LoJ7nvfam++Kctu2D9IdQHZGN5tggz1bSNU # 5HhTdSRXud2f8449xvNo32X2pFaq95W2KFUn0CS9QKC/GbYSEhFdPSfgQJY4rPf5 # KYnDvBewVIVCs/wMnosZiefwC2qBwoEZQhlSdYo2wh3DYXMuLGt7bj8sCXgU6ZGy # qVvfSaN0DLzskYDSPeZKPmY7T7uG+jIa2Zb0j/aRAfbOxnT99kxybxCrdTDFNLB6 # 2FD+CljdQDzHVG2dY3RILLFORy3BFARxv2T5JL5zbcqOCb2zAVdJVGTZc9d/HltE # AY5aGZFrDZ+kKNxnGSgkujhLmm77IVRrakURR6nxt67I6IleT53S0Ex2tVdUCbFp # AUR+fKFhbHP+CrvsQWY9af3LwUFJfn6Tvsv4O+S3Fb+0zj6lMVGEvL8CwYKiexcd # FYmNcP7ntdAoGokLjzbaukz5m/8K6TT4JDVnK+ANuOaMmdbhIurwJ0I9JZTmdHRb # atGePu1+oDEzfbzL6Xu/OHBE0ZDxyKs6ijoIYn/ZcGNTTY3ugm2lBRDBcQZqELQd # VTNYs6FwZvKhggNQMIICOAIBATCB+aGB0aSBzjCByzELMAkGA1UEBhMCVVMxEzAR # BgNVBAgTCldhc2hpbmd0b24xEDAOBgNVBAcTB1JlZG1vbmQxHjAcBgNVBAoTFU1p # Y3Jvc29mdCBDb3Jwb3JhdGlvbjElMCMGA1UECxMcTWljcm9zb2Z0IEFtZXJpY2Eg # T3BlcmF0aW9uczEnMCUGA1UECxMeblNoaWVsZCBUU1MgRVNOOjMzMDMtMDVFMC1E # OTQ3MSUwIwYDVQQDExxNaWNyb3NvZnQgVGltZS1TdGFtcCBTZXJ2aWNloiMKAQEw # BwYFKw4DAhoDFQALbEgZZnyYHXJ1DGb5fGjplXptuaCBgzCBgKR+MHwxCzAJBgNV # BAYTAlVTMRMwEQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4w # HAYDVQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xJjAkBgNVBAMTHU1pY3Jvc29m # dCBUaW1lLVN0YW1wIFBDQSAyMDEwMA0GCSqGSIb3DQEBCwUAAgUA7gNfADAiGA8y # MDI2MDcxNjEzNDUzNloYDzIwMjYwNzE3MTM0NTM2WjB3MD0GCisGAQQBhFkKBAEx # LzAtMAoCBQDuA18AAgEAMAoCAQACAhOSAgH/MAcCAQACAhMpMAoCBQDuBLCAAgEA # MDYGCisGAQQBhFkKBAIxKDAmMAwGCisGAQQBhFkKAwKgCjAIAgEAAgMHoSChCjAI # AgEAAgMBhqAwDQYJKoZIhvcNAQELBQADggEBAEqoegerTafVfmgVIW4+PbPXA0eC # 7MzjOH6tWPAe4++ktHQJAdTlvf7OEw4ZYmpjlUHbspB143Avj6RHsVKYZG1XS1uH # zMAMO++aNNJDMEwL+dYmacsTVldq6nyiSA6LIcBsn16TX5uNv+IKNUdqEGy69QJX # OneibrrN1tbVgr3PLOvQN8cS3Mq+6ABmIEqbf1RrPF5Df9rdEdg6pORM+MmzvmwP # hvUcO+pB0e07tB1jr7je3HniDZir61YcGCN+W+Z6R0JZkh6ib0IVc6mo6udVabh0 # XLbxNK36PAJRVIxJGzjGCao/Y0+7/rCDyNbCENWNMEvjqKdem+TF7veVKJQxggQN # MIIECQIBATCBkzB8MQswCQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQ # MA4GA1UEBxMHUmVkbW9uZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9u # MSYwJAYDVQQDEx1NaWNyb3NvZnQgVGltZS1TdGFtcCBQQ0EgMjAxMAITMwAAAiEz # wDX70g8hpAABAAACITANBglghkgBZQMEAgEFAKCCAUowGgYJKoZIhvcNAQkDMQ0G # CyqGSIb3DQEJEAEEMC8GCSqGSIb3DQEJBDEiBCDA8keceQoxjUKB0nA2SQRCyjMU # 5BuP85rERihZ24/uqjCB+gYLKoZIhvcNAQkQAi8xgeowgecwgeQwgb0EIADvIQef # FVUa4BJy8IZywMAvmGSKdUVqEmy9A++PCj1EMIGYMIGApH4wfDELMAkGA1UEBhMC # VVMxEzARBgNVBAgTCldhc2hpbmd0b24xEDAOBgNVBAcTB1JlZG1vbmQxHjAcBgNV # BAoTFU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjEmMCQGA1UEAxMdTWljcm9zb2Z0IFRp # bWUtU3RhbXAgUENBIDIwMTACEzMAAAIhM8A1+9IPIaQAAQAAAiEwIgQgzo+1bKnb # vZDxmYPkutThh7XWMvt24aitsleFUmVebfMwDQYJKoZIhvcNAQELBQAEggIAgbMR # vfrnX3sl6TKk0FSAdDoByJDVDCcOCjAsu5pyOcPJCh9BZo2ktX77jyB31HUx6wDb # oFO27fvYCVraLBG0D3//EAIAEOzixldeqmtdQFyKsmpYmdDMblZmIUexVMmul4Q/ # qfxjSXb5yFOQnETzSonOb2AmVNYFJo9lX62+BwGb4+nNgpecD+IVCZl+Btrqr61K # Kw5hrniyU+Ssbt4PTjC+qhB7/hDyGNcNxPC8IlNFy5UOWtWnRk0UeGUOxf0rIiLX # CBKGDfKnCZVLg1XOAoXzjgbK+8l39PwqhGr+jX4NEDfd2Rooq9IFZuovy03COMjv # IDvWQUvxt9F+YUFq1jBF5oqDqoPRLAQagIixgLEkyHh6JhzcU7ui3LN+utgh86RU # kQbYXya46s495ZSVFPXjNUdMehDg3F85tWhWWaLcoJxcEltsfOB7YzntOCfLZYCX # +yJ+Ii/IEksA5uENO+Y5BHxp6CTO/xFfi7rvHZh5WPNf9A/yQDC8bHD0wiPt+d3n # QFZOXl//Pl6fv82cUuFeC3SR3jXD5Py2CTEhqDvWGTj0RbLJyRzh6lErKpmYJnqH # Lr9dJFWN+t4mmr9fmk5URJXmJT5bnHWZP9J2AW84iNmYdfj40Q9INFN0riigaN+D # MyePbYRfBW+qC1PNE551Fh6h3Io0tDob45RFXbU= # SIG # End signature block |