Azs.TeamsIntegration.Update.psm1
$GLOBAL:UpdateInProgressTemplate = Get-Content "$PSScriptRoot\Templates\Azs-TeamsIntegration-Update-InProgress.json" -Raw $GLOBAL:UpdateNotRunningTemplate = Get-Content "$PSScriptRoot\Templates\Azs-TeamsIntegration-Update-NotRunning.json" -Raw function Get-UpdateSummary { <# .SYNOPSIS Build update PSObject. #> param ($UpdateStatus) # return null if there's no status if (-not $UpdateStatus) { return $null } # All Steps $steps = $updateStatus.SelectNodes("//Step") | Select-Object FullStepIndex, Name, Status, StartTimeUtc, EndTimeUtc #Steps Success $Success = $updateStatus.SelectNodes("//Step") | Where-Object { $_.Status -eq 'Success' } | Select-Object FullStepIndex, Name, Status, StartTimeUtc, EndTimeUtc #Steps in Progress $sbTinyTimeformat = { (Format-TimeSpan (([datetime]::Now) - [datetime]$_.StartTimeUtc)).replace(' hours ', 'h:').replace(' minutes', 'm') } $stepsSb = { if ($_.ExecutionContext.Roles.Role.Nodes.Node.Name){ "{0} ({1})" -f $_.Name, $_.ExecutionContext.Roles.Role.Nodes.Node.Name } else { $_.Name} } $InProgress = $updateStatus.SelectNodes("//Step") | Where-Object Status -eq InProgress | Select-Object FullStepIndex, @{label='Name';Expression = $stepsSb }, Status, StartTimeUtc, EndTimeUtc, @{'label' = 'duration'; expression = $sbTinyTimeformat } #Steps in Error $InError = $updateStatus.SelectNodes("//Step") | Where-Object Status -eq Error | Select-Object FullStepIndex, Name, Status, StartTimeUtc, EndTimeUtc # Format Summary data $summary = New-Object -TypeName PSObject -Property @{ Completed = ($updateStatus.SelectNodes("//Step") | Where-Object Status -eq Success).count InProgress = ($updateStatus.SelectNodes("//Step") | Where-Object Status -eq InProgress).count Failed = ($updateStatus.SelectNodes("//Step") | Where-Object Status -eq Error).count } # Scoped Repair $scopedRepairTask = $UpdateStatus.SelectNodes("//RemediationAction") | Select-Object @{N="ActionType";E={"{0}" -f $_.Task.ActionType}}, @{N="ActionStatus";E={"{0}" -f $_.ActionStatus}} if ($scopedRepairTask.ActionStatus -in 'InProgress','Error','Cancelled') { $ShowScopedRepair = $true Write-CustomLog ("[$Stamp] Showing scoped repair status {0}" -f $scopedRepairTask.ActionStatus) } else { $ShowScopedRepair = $false Write-CustomLog ("[$Stamp] Not showing scoped repair status {0}" -f $scopedRepairTask.ActionStatus) } # Format InProgress data # if inprogress steps might exceed message limit, trim it. if ($InProgress.count -gt 15) { $InProgress = $InProgress | Where-Object { $_.FullStepIndex.split('.').count -gt 2 } | Sort-Object [datetime]$_.StartTimeUtc | Select-Object -first 15 # teams message limit, removed top level jobs and trim to 15 oldest jobs. } $UpdateProgress = New-Object -TypeName PSObject -Property @{ StepsInProgress = $InProgress steps = $steps ShowScopedRepair = $ShowScopedRepair ScopedRepairStatus = $scopedRepairTask.ActionStatus } return (New-Object PSObject -Property @{summary = $summary; UpdateProgress = $UpdateProgress }) } function Get-AzsUpdateWithRetries { <# .SYNOPSIS Attempt to get update status from ARM with retries #> [CmdletBinding()] param ($stamp, $retrySeconds) try { Write-CustomLog "[$Stamp] Connecting to Admin ARM" Connect-AzsArmEndpoint -Stamp $stamp } catch { Write-Warning -Message ("Connecting to Azure Stack failed. Ensure Connect-AzsArmEndpoint $Stamp works. Error: {0}" -f $_.Exception.message) } Clear-Variable retry, updatesFromURP -ErrorAction SilentlyContinue while ($retry -lt 3 -and !$updatesFromURP) { $retry++ Write-CustomLog "[$Stamp] Getting Update from URP. Attempt $retry/3" try { $versionSb = {if ($null -eq $_.version -and $null -ne $_.OemVersion) {$_.OemVersion}else{$_.version}} $updatesFromURP = Get-AzsUpdate | ` Sort-Object @{Expression = { [System.Version]$_.Version } } -Descending | ` Select-object *,@{label='VersionNumber';expression=$versionSb } $updatesFromURP | Foreach-Object { Write-CustomLog ("[$Stamp] {0} {1} {2} {3}" -f $_.DisplayName, $_.State, $_.VersionNumber, $_.InstalledDate) } return $updatesFromURP } catch { Write-CustomLog ("[$Stamp] Failed getting Update from URP. This can be transient during updates. Error: {0}" -f $_.exception.message) Start-Sleep -seconds $retrySeconds } } } function Get-AzsUpdateRunWithRetries { <# .SYNOPSIS Attempt to get update status from ARM with retries #> param ($stamp, $retrySeconds, $updateName) try { Write-CustomLog "[$Stamp] Connecting to Admin ARM" Connect-AzsArmEndpoint -Stamp $stamp } catch { Write-Warning -Message ("Connecting to Azure Stack failed. Ensure Connect-AzsArmEndpoint $Stamp works. Error: {0}" -f $_.Exception.message) } Clear-Variable retry, updatesFromURP -ErrorAction SilentlyContinue while ($retry -lt 3 -and !$updateRun) { $retry++ Write-CustomLog "[$Stamp] Getting Update from URP. Attempt $retry/3" try { # If there's an update we only need to return 1 update. $updateRun = Get-AzsUpdateRun -UpdateName $UpdateName | Sort-Object ProgressStartTimeUtc -Descending | Select-Object -First 1 return $updateRun } catch { Write-CustomLog ("[$Stamp] Failed getting Update from URP. This can be transient during updates. Error: {0}" -f $_.exception.message) $retrySeconds = $retrySeconds * $retry Write-CustomLog ("[$Stamp] Retry in {0} seconds" -f $retrySeconds) Start-Sleep -seconds $retrySeconds } } } function Get-OperatorUpdate { <# .SYNOPSIS Build operator text #> param ($UpdateData) $operatorMessage = @() $operatorMessage += "<strong>{0}</strong>" -f $UpdateData.Banner if ($UpdateData.ShowScopedRepair) { $operatorMessage += "Scoped Repair: {0}" -f $UpdateData.Update.UpdateProgress.ScopedRepairStatus } if ($UpdateData.ShowDuration) { $operatorMessage += "Update Duration: {0}" -f $UpdateData.totalDuration } if ($UpdateData.ShowProgress) { $operatorMessage += "Steps Completed: {0}" -f $UpdateData.Update.Summary.Completed } if ($UpdateData.ShowProgress) { $operatorMessage += "Steps Failed: {0}" -f $UpdateData.Update.Summary.Failed } if ($UpdateData.ShowProgress) { $operatorMessage += "Steps InProgress: {0}" -f $UpdateData.Update.Summary.InProgress } if ($UpdateData.ShowProgress) { $operatorMessage += "Current steps:" } if ($UpdateData.ShowProgress) { "{0}" -f ($UpdateData.Update.UpdateProgress.StepsInProgress | Foreach-Object {$operatorMessage += "{0} ({1})" -f $_.Name, $_.Duration})} if ($UpdateData.showPrepProgress) { $operatorMessage += "Current steps:" } if ($updateData.showPrepProgress) { "{0}" -f ($UpdateData.Update.Prep | Foreach-Object {$operatorMessage += "{0} ({1})" -f $_.Name, $_.Status})} $operatorMessage += "{0} ({1}) \ {2} (Brevity: {3})" -f $UpdateData.ModuleName, $UpdateData.ModuleVersion, $UpdateData.CommandletName, $UpdateData.Brief return $operatorMessage } # SIG # Begin signature block # MIIjnAYJKoZIhvcNAQcCoIIjjTCCI4kCAQExDzANBglghkgBZQMEAgEFADB5Bgor # BgEEAYI3AgEEoGswaTA0BgorBgEEAYI3AgEeMCYCAwEAAAQQH8w7YFlLCE63JNLG # KX7zUQIBAAIBAAIBAAIBAAIBADAxMA0GCWCGSAFlAwQCAQUABCDCbW0FbtHYQMia # 3BnwB9I/Ns3hAYNsLloKBOr8Xj9ZRqCCDYEwggX/MIID56ADAgECAhMzAAAB32vw # LpKnSrTQAAAAAAHfMA0GCSqGSIb3DQEBCwUAMH4xCzAJBgNVBAYTAlVTMRMwEQYD # VQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNy # b3NvZnQgQ29ycG9yYXRpb24xKDAmBgNVBAMTH01pY3Jvc29mdCBDb2RlIFNpZ25p # bmcgUENBIDIwMTEwHhcNMjAxMjE1MjEzMTQ1WhcNMjExMjAyMjEzMTQ1WjB0MQsw # CQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9u # ZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMR4wHAYDVQQDExVNaWNy # b3NvZnQgQ29ycG9yYXRpb24wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIB # AQC2uxlZEACjqfHkuFyoCwfL25ofI9DZWKt4wEj3JBQ48GPt1UsDv834CcoUUPMn # s/6CtPoaQ4Thy/kbOOg/zJAnrJeiMQqRe2Lsdb/NSI2gXXX9lad1/yPUDOXo4GNw # PjXq1JZi+HZV91bUr6ZjzePj1g+bepsqd/HC1XScj0fT3aAxLRykJSzExEBmU9eS # yuOwUuq+CriudQtWGMdJU650v/KmzfM46Y6lo/MCnnpvz3zEL7PMdUdwqj/nYhGG # 3UVILxX7tAdMbz7LN+6WOIpT1A41rwaoOVnv+8Ua94HwhjZmu1S73yeV7RZZNxoh # EegJi9YYssXa7UZUUkCCA+KnAgMBAAGjggF+MIIBejAfBgNVHSUEGDAWBgorBgEE # AYI3TAgBBggrBgEFBQcDAzAdBgNVHQ4EFgQUOPbML8IdkNGtCfMmVPtvI6VZ8+Mw # UAYDVR0RBEkwR6RFMEMxKTAnBgNVBAsTIE1pY3Jvc29mdCBPcGVyYXRpb25zIFB1 # ZXJ0byBSaWNvMRYwFAYDVQQFEw0yMzAwMTIrNDYzMDA5MB8GA1UdIwQYMBaAFEhu # ZOVQBdOCqhc3NyK1bajKdQKVMFQGA1UdHwRNMEswSaBHoEWGQ2h0dHA6Ly93d3cu # bWljcm9zb2Z0LmNvbS9wa2lvcHMvY3JsL01pY0NvZFNpZ1BDQTIwMTFfMjAxMS0w # Ny0wOC5jcmwwYQYIKwYBBQUHAQEEVTBTMFEGCCsGAQUFBzAChkVodHRwOi8vd3d3 # Lm1pY3Jvc29mdC5jb20vcGtpb3BzL2NlcnRzL01pY0NvZFNpZ1BDQTIwMTFfMjAx # MS0wNy0wOC5jcnQwDAYDVR0TAQH/BAIwADANBgkqhkiG9w0BAQsFAAOCAgEAnnqH # tDyYUFaVAkvAK0eqq6nhoL95SZQu3RnpZ7tdQ89QR3++7A+4hrr7V4xxmkB5BObS # 0YK+MALE02atjwWgPdpYQ68WdLGroJZHkbZdgERG+7tETFl3aKF4KpoSaGOskZXp # TPnCaMo2PXoAMVMGpsQEQswimZq3IQ3nRQfBlJ0PoMMcN/+Pks8ZTL1BoPYsJpok # t6cql59q6CypZYIwgyJ892HpttybHKg1ZtQLUlSXccRMlugPgEcNZJagPEgPYni4 # b11snjRAgf0dyQ0zI9aLXqTxWUU5pCIFiPT0b2wsxzRqCtyGqpkGM8P9GazO8eao # mVItCYBcJSByBx/pS0cSYwBBHAZxJODUqxSXoSGDvmTfqUJXntnWkL4okok1FiCD # Z4jpyXOQunb6egIXvkgQ7jb2uO26Ow0m8RwleDvhOMrnHsupiOPbozKroSa6paFt # VSh89abUSooR8QdZciemmoFhcWkEwFg4spzvYNP4nIs193261WyTaRMZoceGun7G # CT2Rl653uUj+F+g94c63AhzSq4khdL4HlFIP2ePv29smfUnHtGq6yYFDLnT0q/Y+ # Di3jwloF8EWkkHRtSuXlFUbTmwr/lDDgbpZiKhLS7CBTDj32I0L5i532+uHczw82 # oZDmYmYmIUSMbZOgS65h797rj5JJ6OkeEUJoAVwwggd6MIIFYqADAgECAgphDpDS # AAAAAAADMA0GCSqGSIb3DQEBCwUAMIGIMQswCQYDVQQGEwJVUzETMBEGA1UECBMK # V2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9uZDEeMBwGA1UEChMVTWljcm9zb2Z0 # IENvcnBvcmF0aW9uMTIwMAYDVQQDEylNaWNyb3NvZnQgUm9vdCBDZXJ0aWZpY2F0 # ZSBBdXRob3JpdHkgMjAxMTAeFw0xMTA3MDgyMDU5MDlaFw0yNjA3MDgyMTA5MDla # MH4xCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdS # ZWRtb25kMR4wHAYDVQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xKDAmBgNVBAMT # H01pY3Jvc29mdCBDb2RlIFNpZ25pbmcgUENBIDIwMTEwggIiMA0GCSqGSIb3DQEB # AQUAA4ICDwAwggIKAoICAQCr8PpyEBwurdhuqoIQTTS68rZYIZ9CGypr6VpQqrgG # OBoESbp/wwwe3TdrxhLYC/A4wpkGsMg51QEUMULTiQ15ZId+lGAkbK+eSZzpaF7S # 35tTsgosw6/ZqSuuegmv15ZZymAaBelmdugyUiYSL+erCFDPs0S3XdjELgN1q2jz # y23zOlyhFvRGuuA4ZKxuZDV4pqBjDy3TQJP4494HDdVceaVJKecNvqATd76UPe/7 # 4ytaEB9NViiienLgEjq3SV7Y7e1DkYPZe7J7hhvZPrGMXeiJT4Qa8qEvWeSQOy2u # M1jFtz7+MtOzAz2xsq+SOH7SnYAs9U5WkSE1JcM5bmR/U7qcD60ZI4TL9LoDho33 # X/DQUr+MlIe8wCF0JV8YKLbMJyg4JZg5SjbPfLGSrhwjp6lm7GEfauEoSZ1fiOIl # XdMhSz5SxLVXPyQD8NF6Wy/VI+NwXQ9RRnez+ADhvKwCgl/bwBWzvRvUVUvnOaEP # 6SNJvBi4RHxF5MHDcnrgcuck379GmcXvwhxX24ON7E1JMKerjt/sW5+v/N2wZuLB # l4F77dbtS+dJKacTKKanfWeA5opieF+yL4TXV5xcv3coKPHtbcMojyyPQDdPweGF # RInECUzF1KVDL3SV9274eCBYLBNdYJWaPk8zhNqwiBfenk70lrC8RqBsmNLg1oiM # CwIDAQABo4IB7TCCAekwEAYJKwYBBAGCNxUBBAMCAQAwHQYDVR0OBBYEFEhuZOVQ # BdOCqhc3NyK1bajKdQKVMBkGCSsGAQQBgjcUAgQMHgoAUwB1AGIAQwBBMAsGA1Ud # DwQEAwIBhjAPBgNVHRMBAf8EBTADAQH/MB8GA1UdIwQYMBaAFHItOgIxkEO5FAVO # 4eqnxzHRI4k0MFoGA1UdHwRTMFEwT6BNoEuGSWh0dHA6Ly9jcmwubWljcm9zb2Z0 # LmNvbS9wa2kvY3JsL3Byb2R1Y3RzL01pY1Jvb0NlckF1dDIwMTFfMjAxMV8wM18y # Mi5jcmwwXgYIKwYBBQUHAQEEUjBQME4GCCsGAQUFBzAChkJodHRwOi8vd3d3Lm1p # Y3Jvc29mdC5jb20vcGtpL2NlcnRzL01pY1Jvb0NlckF1dDIwMTFfMjAxMV8wM18y # Mi5jcnQwgZ8GA1UdIASBlzCBlDCBkQYJKwYBBAGCNy4DMIGDMD8GCCsGAQUFBwIB # FjNodHRwOi8vd3d3Lm1pY3Jvc29mdC5jb20vcGtpb3BzL2RvY3MvcHJpbWFyeWNw # cy5odG0wQAYIKwYBBQUHAgIwNB4yIB0ATABlAGcAYQBsAF8AcABvAGwAaQBjAHkA # XwBzAHQAYQB0AGUAbQBlAG4AdAAuIB0wDQYJKoZIhvcNAQELBQADggIBAGfyhqWY # 4FR5Gi7T2HRnIpsLlhHhY5KZQpZ90nkMkMFlXy4sPvjDctFtg/6+P+gKyju/R6mj # 82nbY78iNaWXXWWEkH2LRlBV2AySfNIaSxzzPEKLUtCw/WvjPgcuKZvmPRul1LUd # d5Q54ulkyUQ9eHoj8xN9ppB0g430yyYCRirCihC7pKkFDJvtaPpoLpWgKj8qa1hJ # Yx8JaW5amJbkg/TAj/NGK978O9C9Ne9uJa7lryft0N3zDq+ZKJeYTQ49C/IIidYf # wzIY4vDFLc5bnrRJOQrGCsLGra7lstnbFYhRRVg4MnEnGn+x9Cf43iw6IGmYslmJ # aG5vp7d0w0AFBqYBKig+gj8TTWYLwLNN9eGPfxxvFX1Fp3blQCplo8NdUmKGwx1j # NpeG39rz+PIWoZon4c2ll9DuXWNB41sHnIc+BncG0QaxdR8UvmFhtfDcxhsEvt9B # xw4o7t5lL+yX9qFcltgA1qFGvVnzl6UJS0gQmYAf0AApxbGbpT9Fdx41xtKiop96 # eiL6SJUfq/tHI4D1nvi/a7dLl+LrdXga7Oo3mXkYS//WsyNodeav+vyL6wuA6mk7 # r/ww7QRMjt/fdW1jkT3RnVZOT7+AVyKheBEyIXrvQQqxP/uozKRdwaGIm1dxVk5I # RcBCyZt2WwqASGv9eZ/BvW1taslScxMNelDNMYIVcTCCFW0CAQEwgZUwfjELMAkG # A1UEBhMCVVMxEzARBgNVBAgTCldhc2hpbmd0b24xEDAOBgNVBAcTB1JlZG1vbmQx # HjAcBgNVBAoTFU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjEoMCYGA1UEAxMfTWljcm9z # b2Z0IENvZGUgU2lnbmluZyBQQ0EgMjAxMQITMwAAAd9r8C6Sp0q00AAAAAAB3zAN # BglghkgBZQMEAgEFAKCBrjAZBgkqhkiG9w0BCQMxDAYKKwYBBAGCNwIBBDAcBgor # BgEEAYI3AgELMQ4wDAYKKwYBBAGCNwIBFTAvBgkqhkiG9w0BCQQxIgQgKN9t+qb/ # wWTE/2KbdlaFj4Bkl6L+AYgs6LNpSqZwmpswQgYKKwYBBAGCNwIBDDE0MDKgFIAS # AE0AaQBjAHIAbwBzAG8AZgB0oRqAGGh0dHA6Ly93d3cubWljcm9zb2Z0LmNvbTAN # BgkqhkiG9w0BAQEFAASCAQAHTSphDqq1Q9SUGrPoD9XKakI8a4P14JUjgbIAuXeJ # tKB4gN8dB+JApIFnJRa4/uW/LekTMPNjCnU/82sV6+f6kadfcHyp6LgTF37rMkge # 01I2h4r0lARXObPhSr+VhAwVvPtxe50xmIrARjouxt4nqpbfXdoR4aGHrEj+buar # yOVHG1RckZRXUU9kPu0ykAHXWzm3bkydSnfP1q8ThRYWE8l3iCjw6fhLbH7da5Sp # 1aswvzxNCf4umiseUrrVzeeiQ4rtck1RltJi0ZYDAmJlT9NkaeVMFh7vYZNwezQ+ # hYJI2EX0xBCzQJABgH8ZplppDQjxv48/5fmqcoUgrooEoYIS+zCCEvcGCisGAQQB # gjcDAwExghLnMIIS4wYJKoZIhvcNAQcCoIIS1DCCEtACAQMxDzANBglghkgBZQME # AgEFADCCAVgGCyqGSIb3DQEJEAEEoIIBRwSCAUMwggE/AgEBBgorBgEEAYRZCgMB # MDEwDQYJYIZIAWUDBAIBBQAEICTNMgR6I5iCycXpWxf/rStQbAYERKftMO0Zb2t8 # C2QtAgZgPOrwLDcYEjIwMjEwMzAxMTk1MDE5Ljg2WjAEgAIB9KCB2KSB1TCB0jEL # MAkGA1UEBhMCVVMxEzARBgNVBAgTCldhc2hpbmd0b24xEDAOBgNVBAcTB1JlZG1v # bmQxHjAcBgNVBAoTFU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjEtMCsGA1UECxMkTWlj # cm9zb2Z0IElyZWxhbmQgT3BlcmF0aW9ucyBMaW1pdGVkMSYwJAYDVQQLEx1UaGFs # ZXMgVFNTIEVTTjo4RDQxLTRCRjctQjNCNzElMCMGA1UEAxMcTWljcm9zb2Z0IFRp # bWUtU3RhbXAgU2VydmljZaCCDkswggT5MIID4aADAgECAhMzAAABOo2NMfd3SUnC # AAAAAAE6MA0GCSqGSIb3DQEBCwUAMHwxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpX # YXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNyb3NvZnQg # Q29ycG9yYXRpb24xJjAkBgNVBAMTHU1pY3Jvc29mdCBUaW1lLVN0YW1wIFBDQSAy # MDEwMB4XDTIwMTAxNTE3MjgyMloXDTIyMDExMjE3MjgyMlowgdIxCzAJBgNVBAYT # AlVTMRMwEQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYD # VQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xLTArBgNVBAsTJE1pY3Jvc29mdCBJ # cmVsYW5kIE9wZXJhdGlvbnMgTGltaXRlZDEmMCQGA1UECxMdVGhhbGVzIFRTUyBF # U046OEQ0MS00QkY3LUIzQjcxJTAjBgNVBAMTHE1pY3Jvc29mdCBUaW1lLVN0YW1w # IFNlcnZpY2UwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDOXyTnXw+X # PwlMhdif8705qSpxap0nxlcmECSz2HIsHz4A1btmeBvW3uLDtOaB6ig7AyduEJBA # fXhTBZ3yFAVZ7EqpWlwgWdjdvXn49iaBV5Dhcp9Ync88yNOJe7vd6lceP1dfuaFL # YhWrAS8M6504jfJAvwPw44bbhv7XTMMMTI3nC9nkDVZy+XZ5CEIbrUZ4c1pe9c6W # hNBuVUVsxY6Ya+Ie+BGVGFGOA2a6/UnbLp9AW2ITDSl1coJAbrzFCUGFy7guf5tg # vgeh5Paau2SkcTINn5+uv4pr/NQM/cGxweQp2Q0Y44N+8l1YdpXRbOvXCc+5SC05 # t+cE7ShKMikFAgMBAAGjggEbMIIBFzAdBgNVHQ4EFgQUFFagnxZfEmumyW8cdayt # CYVF88swHwYDVR0jBBgwFoAU1WM6XIoxkPNDe3xGG8UzaFqFbVUwVgYDVR0fBE8w # TTBLoEmgR4ZFaHR0cDovL2NybC5taWNyb3NvZnQuY29tL3BraS9jcmwvcHJvZHVj # dHMvTWljVGltU3RhUENBXzIwMTAtMDctMDEuY3JsMFoGCCsGAQUFBwEBBE4wTDBK # BggrBgEFBQcwAoY+aHR0cDovL3d3dy5taWNyb3NvZnQuY29tL3BraS9jZXJ0cy9N # aWNUaW1TdGFQQ0FfMjAxMC0wNy0wMS5jcnQwDAYDVR0TAQH/BAIwADATBgNVHSUE # DDAKBggrBgEFBQcDCDANBgkqhkiG9w0BAQsFAAOCAQEAXjfkPqQBLaN4AnwEbUpO # bkDPSOlt2OmpK8wu3t85WtoAQeV2CTTgEpxOaHONtNeyPCAIwwJL6NfhOiqLRyfN # xKgPYumFkD3wNd4fqVEfupB1dseDHT+9urRjJWSW1JMy/WPPMjvlnl2Gm9zhTCfg # VvoIJoXb/6vtGvSP7YMYLCXxpaq9CrOEIn+jtw2hhR8nhZIIezU6yOAyZZOaCW48 # jG3eRXyItmXYhmDKvlw06I2JOtoUOruHEjXqgOyhbQRAoJXzidXXBZJZ7VKIAojC # vkG2pjAn6GWhw/Dmp6FZsGJMue1wuvAp0BvC2EWvUMd/dFjAWgPPI20pIH9MmwHZ # szCCBnEwggRZoAMCAQICCmEJgSoAAAAAAAIwDQYJKoZIhvcNAQELBQAwgYgxCzAJ # BgNVBAYTAlVTMRMwEQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25k # MR4wHAYDVQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xMjAwBgNVBAMTKU1pY3Jv # c29mdCBSb290IENlcnRpZmljYXRlIEF1dGhvcml0eSAyMDEwMB4XDTEwMDcwMTIx # MzY1NVoXDTI1MDcwMTIxNDY1NVowfDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCldh # c2hpbmd0b24xEDAOBgNVBAcTB1JlZG1vbmQxHjAcBgNVBAoTFU1pY3Jvc29mdCBD # b3Jwb3JhdGlvbjEmMCQGA1UEAxMdTWljcm9zb2Z0IFRpbWUtU3RhbXAgUENBIDIw # MTAwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCpHQ28dxGKOiDs/BOX # 9fp/aZRrdFQQ1aUKAIKF++18aEssX8XD5WHCdrc+Zitb8BVTJwQxH0EbGpUdzgkT # jnxhMFmxMEQP8WCIhFRDDNdNuDgIs0Ldk6zWczBXJoKjRQ3Q6vVHgc2/JGAyWGBG # 8lhHhjKEHnRhZ5FfgVSxz5NMksHEpl3RYRNuKMYa+YaAu99h/EbBJx0kZxJyGiGK # r0tkiVBisV39dx898Fd1rL2KQk1AUdEPnAY+Z3/1ZsADlkR+79BL/W7lmsqxqPJ6 # Kgox8NpOBpG2iAg16HgcsOmZzTznL0S6p/TcZL2kAcEgCZN4zfy8wMlEXV4WnAEF # TyJNAgMBAAGjggHmMIIB4jAQBgkrBgEEAYI3FQEEAwIBADAdBgNVHQ4EFgQU1WM6 # XIoxkPNDe3xGG8UzaFqFbVUwGQYJKwYBBAGCNxQCBAweCgBTAHUAYgBDAEEwCwYD # VR0PBAQDAgGGMA8GA1UdEwEB/wQFMAMBAf8wHwYDVR0jBBgwFoAU1fZWy4/oolxi # aNE9lJBb186aGMQwVgYDVR0fBE8wTTBLoEmgR4ZFaHR0cDovL2NybC5taWNyb3Nv # ZnQuY29tL3BraS9jcmwvcHJvZHVjdHMvTWljUm9vQ2VyQXV0XzIwMTAtMDYtMjMu # Y3JsMFoGCCsGAQUFBwEBBE4wTDBKBggrBgEFBQcwAoY+aHR0cDovL3d3dy5taWNy # b3NvZnQuY29tL3BraS9jZXJ0cy9NaWNSb29DZXJBdXRfMjAxMC0wNi0yMy5jcnQw # gaAGA1UdIAEB/wSBlTCBkjCBjwYJKwYBBAGCNy4DMIGBMD0GCCsGAQUFBwIBFjFo # dHRwOi8vd3d3Lm1pY3Jvc29mdC5jb20vUEtJL2RvY3MvQ1BTL2RlZmF1bHQuaHRt # MEAGCCsGAQUFBwICMDQeMiAdAEwAZQBnAGEAbABfAFAAbwBsAGkAYwB5AF8AUwB0 # AGEAdABlAG0AZQBuAHQALiAdMA0GCSqGSIb3DQEBCwUAA4ICAQAH5ohRDeLG4Jg/ # gXEDPZ2joSFvs+umzPUxvs8F4qn++ldtGTCzwsVmyWrf9efweL3HqJ4l4/m87WtU # VwgrUYJEEvu5U4zM9GASinbMQEBBm9xcF/9c+V4XNZgkVkt070IQyK+/f8Z/8jd9 # Wj8c8pl5SpFSAK84Dxf1L3mBZdmptWvkx872ynoAb0swRCQiPM/tA6WWj1kpvLb9 # BOFwnzJKJ/1Vry/+tuWOM7tiX5rbV0Dp8c6ZZpCM/2pif93FSguRJuI57BlKcWOd # eyFtw5yjojz6f32WapB4pm3S4Zz5Hfw42JT0xqUKloakvZ4argRCg7i1gJsiOCC1 # JeVk7Pf0v35jWSUPei45V3aicaoGig+JFrphpxHLmtgOR5qAxdDNp9DvfYPw4Ttx # Cd9ddJgiCGHasFAeb73x4QDf5zEHpJM692VHeOj4qEir995yfmFrb3epgcunCaw5 # u+zGy9iCtHLNHfS4hQEegPsbiSpUObJb2sgNVZl6h3M7COaYLeqN4DMuEin1wC9U # JyH3yKxO2ii4sanblrKnQqLJzxlBTeCG+SqaoxFmMNO7dDJL32N79ZmKLxvHIa9Z # ta7cRDyXUHHXodLFVeNp3lfB0d4wwP3M5k37Db9dT+mdHhk4L7zPWAUu7w2gUDXa # 7wknHNWzfjUeCLraNtvTX4/edIhJEqGCAtUwggI+AgEBMIIBAKGB2KSB1TCB0jEL # MAkGA1UEBhMCVVMxEzARBgNVBAgTCldhc2hpbmd0b24xEDAOBgNVBAcTB1JlZG1v # bmQxHjAcBgNVBAoTFU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjEtMCsGA1UECxMkTWlj # cm9zb2Z0IElyZWxhbmQgT3BlcmF0aW9ucyBMaW1pdGVkMSYwJAYDVQQLEx1UaGFs # ZXMgVFNTIEVTTjo4RDQxLTRCRjctQjNCNzElMCMGA1UEAxMcTWljcm9zb2Z0IFRp # bWUtU3RhbXAgU2VydmljZaIjCgEBMAcGBSsOAwIaAxUAByWR2fWPWBeB3K9iPjUH # yuQ1ngiggYMwgYCkfjB8MQswCQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3Rv # bjEQMA4GA1UEBxMHUmVkbW9uZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0 # aW9uMSYwJAYDVQQDEx1NaWNyb3NvZnQgVGltZS1TdGFtcCBQQ0EgMjAxMDANBgkq # hkiG9w0BAQUFAAIFAOPnaW0wIhgPMjAyMTAzMDEyMTIzNTdaGA8yMDIxMDMwMjIx # MjM1N1owdTA7BgorBgEEAYRZCgQBMS0wKzAKAgUA4+dpbQIBADAIAgEAAgMCQ3kw # BwIBAAICEUEwCgIFAOPouu0CAQAwNgYKKwYBBAGEWQoEAjEoMCYwDAYKKwYBBAGE # WQoDAqAKMAgCAQACAwehIKEKMAgCAQACAwGGoDANBgkqhkiG9w0BAQUFAAOBgQA0 # pdPZMBoVvDFElSUJf1QbfjE2l7yg9kIh715UxuUYSBq6sHNzeDJoELgecW0RhmUg # Wzzo+rqxnnY4nF6ysMjS8WRdCqmNZRo5Ysu+d3uRBjYgyt4BPq+Tfn1ND5lnG4uj # JXAtLAner/beRWWX6pj4v53qA6rfP4nsuaXjOo3pZjGCAw0wggMJAgEBMIGTMHwx # CzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRt # b25kMR4wHAYDVQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xJjAkBgNVBAMTHU1p # Y3Jvc29mdCBUaW1lLVN0YW1wIFBDQSAyMDEwAhMzAAABOo2NMfd3SUnCAAAAAAE6 # MA0GCWCGSAFlAwQCAQUAoIIBSjAaBgkqhkiG9w0BCQMxDQYLKoZIhvcNAQkQAQQw # LwYJKoZIhvcNAQkEMSIEILsWNQWFo7adxSDIVaCogv34tnIzINFLxVljnfFRm5/K # MIH6BgsqhkiG9w0BCRACLzGB6jCB5zCB5DCBvQQgn6/QhAepLF/7Bdsvfu8GOT+i # hL9c4cgo5Nf1aUN8tG0wgZgwgYCkfjB8MQswCQYDVQQGEwJVUzETMBEGA1UECBMK # V2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9uZDEeMBwGA1UEChMVTWljcm9zb2Z0 # IENvcnBvcmF0aW9uMSYwJAYDVQQDEx1NaWNyb3NvZnQgVGltZS1TdGFtcCBQQ0Eg # MjAxMAITMwAAATqNjTH3d0lJwgAAAAABOjAiBCDjiPYxOmbYTVexyMtpJrUqHA3u # m6Y5EkM5l+fpEuWDYDANBgkqhkiG9w0BAQsFAASCAQCWRlMhae833XKWDA+BHUoI # eipk4OOILOAZBL5D4V1NrnTNs3hUEsBDBErSoBeQ3WKOho8pshkh6emybS8sj8+/ # 4G0m8NzbIl7pESWZqYhxSBPcyVIP/B57QjLr59rJ50LzJ9Axg+9X3VAEdxHn0ywI # fjnCJZ3bprLHOBtsJiCDVIUWcAEqfqBf9NBFmNTgLbj7sPU7Gnq+7r0k3mmheokJ # rIJAzaql37ERfXj03ZQmKzwFoP9BikffKn9+y/C043dshBeLZ9OVKksEvR9KPGWa # qAtla8o+nfNYNbn43ehZXASE6uzKnMxJa1ARKdW+FP2EDOMowoFUA29AwmU9fNAR # SIG # End signature block |