Invoke-Async.ps1
|
# # Invoke-Async.ps1 # # Copyright 2019 Microsoft. All rights reserved. # <# .Synopsis A means of running multiple instances of a cmdlet/function/scriptblock .DESCRIPTION This function allows you to provide a cmdlet, function or script block with a set of data to allow multithreading. .EXAMPLE $sb = [scriptblock] {param($system) gwmi win32_operatingsystem -ComputerName $system | select csname,caption} $servers = Get-Content servers.txt $rtn = Invoke-Async -Set $server -SetParam system -ScriptBlock $sb .EXAMPLE $servers = Get-Content servers.txt $rtn = Invoke-Async -Set $servers -SetParam computername -Params @{count=1} -Cmdlet Test-Connection -ThreadCount 50 .INPUTS .OUTPUTS Determined by the provided cmdlet, function or scriptblock. .NOTES This can often times eat up a lot of memory due in part to how some cmdlets work. Test-Connection is a good example of this. Although it is not a good idea to manually run the garbage collector it might be needed in some cases and can be run like so: [gc]::Collect() #> function Invoke-Async{ param( #The data group to process, such as server names. [parameter(Mandatory=$true,ValueFromPipeLine=$true)] [object[]]$Set, #The parameter name that the set belongs to, such as Computername. [parameter(Mandatory=$true)] [string] $SetParam, #The Cmdlet for Function you'd like to process with. [parameter(Mandatory=$true, ParameterSetName='cmdlet')] [string]$Cmdlet, #The ScriptBlock you'd like to process with [parameter(Mandatory=$true, ParameterSetName='ScriptBlock')] [scriptblock]$ScriptBlock, #any aditional parameters to be forwarded to the cmdlet/function/scriptblock [hashtable]$Params, #number of jobs to spin up, default being 10. [int]$ThreadCount=10, #return performance data [switch]$Measure ) Begin { $Threads = @() $Length = $JobsLeft = $Set.Length $Count = 0 if($Length -lt $ThreadCount){$ThreadCount=$Length} $timer = @(1..$ThreadCount | ForEach-Object{$null}) $Jobs = @(1..$ThreadCount | ForEach-Object{$null}) If($PSCmdlet.ParameterSetName -eq 'cmdlet') { $CmdType = (Get-Command $Cmdlet).CommandType if($CmdType -eq 'Alias') { $CmdType = (Get-Command (Get-Command $Cmdlet).ResolvedCommandName).CommandType } If($CmdType -eq 'Function') { $ScriptBlock = (Get-Item Function:\$Cmdlet).ScriptBlock 1..$ThreadCount | ForEach-Object{ $Threads += [powershell]::Create().AddScript($ScriptBlock)} } ElseIf($CmdType -eq "Cmdlet") { 1..$ThreadCount | ForEach-Object{ $Threads += [powershell]::Create().AddCommand($Cmdlet)} } } Else { 1..$ThreadCount | ForEach-Object{ $Threads += [powershell]::Create().AddScript($ScriptBlock)} } If($Params){$Threads | ForEach-Object{$_.AddParameters($Params) | Out-Null}} } Process { while($JobsLeft) { for($idx = 0; $idx -le ($ThreadCount-1) ; $idx++) { $SetParamObj = $Threads[$idx].Commands.Commands[0].Parameters| Where-Object {$_.Name -eq $SetParam} If($Jobs[$idx].IsCompleted) #job ran ok, clear it out { $result = $null if($threads[$idx].InvocationStateInfo.State -eq "Failed") { $result = $Threads[$idx].InvocationStateInfo.Reason Write-Error "Set Item: $($SetParamObj.Value) Exception: $result" } else { $result = $Threads[$idx].EndInvoke($Jobs[$idx]) } $ts = (New-TimeSpan -Start $timer[$idx] -End (Get-Date)) if($Measure) { new-object psobject -Property @{ TimeSpan = $ts Output = $result SetItem = $SetParamObj.Value} } else { $result if ($result.Orphaned -eq $true) { $script:totalAzureADOrphanedKeys += 1 } } $Jobs[$idx] = $null $JobsLeft-- #one less left write-verbose "Completed: $($SetParamObj.Value) in $ts" Update-GetAzureADWHfBKeysProgress write-progress -Activity "Processing Batch" -Status "$JobsLeft jobs left" -PercentComplete (($length-$jobsleft)/$length*100) -Id 2 -ParentId 1 } If(($Count -lt $Length) -and ($Jobs[$idx] -eq $null)) #add job if there is more to process { write-verbose "starting: $($Set[$Count])" $timer[$idx] = get-date $Threads[$idx].Commands.Commands[0].Parameters.Remove($SetParamObj) | Out-Null #check for success? $Threads[$idx].AddParameter($SetParam,$Set[$Count]) | Out-Null $Jobs[$idx] = $Threads[$idx].BeginInvoke() $Count++ } } } } End { $Threads | ForEach-Object{$_.runspace.close();$_.Dispose()} } } # SIG # Begin signature block # MIIoDQYJKoZIhvcNAQcCoIIn/jCCJ/oCAQExDzANBglghkgBZQMEAgEFADB5Bgor # BgEEAYI3AgEEoGswaTA0BgorBgEEAYI3AgEeMCYCAwEAAAQQH8w7YFlLCE63JNLG # KX7zUQIBAAIBAAIBAAIBAAIBADAxMA0GCWCGSAFlAwQCAQUABCAorkUc/dpIlnJC # ZchF/fNnGpDsVf7CZ/VNSC+uMly11qCCEXAwggiCMIIHaqADAgECAhM2AAAA6Gad # G0hCpUxFAAEAAADoMA0GCSqGSIb3DQEBCwUAMEExEzARBgoJkiaJk/IsZAEZFgNH # QkwxEzARBgoJkiaJk/IsZAEZFgNBTUUxFTATBgNVBAMTDEFNRSBDUyBDQSAwMTAe # Fw0xOTAzMjUxMzE3MTBaFw0yMDAzMjQxMzE3MTBaMC8xLTArBgNVBAMTJE1pY3Jv # c29mdCBBenVyZSBEZXBlbmRlbmN5IENvZGUgU2lnbjCCASIwDQYJKoZIhvcNAQEB # BQADggEPADCCAQoCggEBANzmuspUXRFHozpraZYcR8lLf8oaCK27bhl7agSI00Vc # GZy2slaHQ8JZ+Bqiao7e2hpEVxeJ0s9lfIUe30ye3RwDa7oNloC8u8fa/W0QusGD # T7p4c7wwbRJ5MrXowwB/nSgsOKtoCoJMpk6LDpRhgwhn4va4PjVrajBxrxN1eVIP # Kw1GPkzh3qkLQ0SIhuiYUlZur4HSG6Mdkl7jYk1ifVtNupf+FO4Nflw+ZRsczZUg # jo74fVEoBI9qzrZSkCg5wku1qGsTXrd9DtRgOQEEp96NruISfEb22ZZtpMrJg71H # p/oAEqqlOBN5FIjzWi+mxznE1CNMBNFCbtsZOvHVSJMCAwEAAaOCBYMwggV/MCkG # CSsGAQQBgjcVCgQcMBowDAYKKwYBBAGCN1sCATAKBggrBgEFBQcDAzA9BgkrBgEE # AYI3FQcEMDAuBiYrBgEEAYI3FQiGkOMNhNW0eITxiz6Fm90Wzp0SgWCE2K5IhaaW # JgIBZAIBDTCCAnYGCCsGAQUFBwEBBIICaDCCAmQwYgYIKwYBBQUHMAKGVmh0dHA6 # Ly9jcmwubWljcm9zb2Z0LmNvbS9wa2lpbmZyYS9DZXJ0cy9CWTJQS0lDU0NBMDEu # QU1FLkdCTF9BTUUlMjBDUyUyMENBJTIwMDEoMSkuY3J0MFIGCCsGAQUFBzAChkZo # dHRwOi8vY3JsMS5hbWUuZ2JsL2FpYS9CWTJQS0lDU0NBMDEuQU1FLkdCTF9BTUUl # MjBDUyUyMENBJTIwMDEoMSkuY3J0MFIGCCsGAQUFBzAChkZodHRwOi8vY3JsMi5h # bWUuZ2JsL2FpYS9CWTJQS0lDU0NBMDEuQU1FLkdCTF9BTUUlMjBDUyUyMENBJTIw # MDEoMSkuY3J0MFIGCCsGAQUFBzAChkZodHRwOi8vY3JsMy5hbWUuZ2JsL2FpYS9C # WTJQS0lDU0NBMDEuQU1FLkdCTF9BTUUlMjBDUyUyMENBJTIwMDEoMSkuY3J0MFIG # CCsGAQUFBzAChkZodHRwOi8vY3JsNC5hbWUuZ2JsL2FpYS9CWTJQS0lDU0NBMDEu # QU1FLkdCTF9BTUUlMjBDUyUyMENBJTIwMDEoMSkuY3J0MIGtBggrBgEFBQcwAoaB # oGxkYXA6Ly8vQ049QU1FJTIwQ1MlMjBDQSUyMDAxLENOPUFJQSxDTj1QdWJsaWMl # MjBLZXklMjBTZXJ2aWNlcyxDTj1TZXJ2aWNlcyxDTj1Db25maWd1cmF0aW9uLERD # PUFNRSxEQz1HQkw/Y0FDZXJ0aWZpY2F0ZT9iYXNlP29iamVjdENsYXNzPWNlcnRp # ZmljYXRpb25BdXRob3JpdHkwHQYDVR0OBBYEFMhZoWfS7cerFd3KJYxV4M3+DOEi # MA4GA1UdDwEB/wQEAwIHgDBQBgNVHREESTBHpEUwQzEpMCcGA1UECxMgTWljcm9z # b2Z0IE9wZXJhdGlvbnMgUHVlcnRvIFJpY28xFjAUBgNVBAUTDTIzNjE2OSs0NTMz # NzQwggHUBgNVHR8EggHLMIIBxzCCAcOgggG/oIIBu4Y8aHR0cDovL2NybC5taWNy # b3NvZnQuY29tL3BraWluZnJhL0NSTC9BTUUlMjBDUyUyMENBJTIwMDEuY3Jshi5o # dHRwOi8vY3JsMS5hbWUuZ2JsL2NybC9BTUUlMjBDUyUyMENBJTIwMDEuY3Jshi5o # dHRwOi8vY3JsMi5hbWUuZ2JsL2NybC9BTUUlMjBDUyUyMENBJTIwMDEuY3Jshi5o # dHRwOi8vY3JsMy5hbWUuZ2JsL2NybC9BTUUlMjBDUyUyMENBJTIwMDEuY3Jshi5o # dHRwOi8vY3JsNC5hbWUuZ2JsL2NybC9BTUUlMjBDUyUyMENBJTIwMDEuY3JshoG6 # bGRhcDovLy9DTj1BTUUlMjBDUyUyMENBJTIwMDEsQ049QlkyUEtJQ1NDQTAxLENO # PUNEUCxDTj1QdWJsaWMlMjBLZXklMjBTZXJ2aWNlcyxDTj1TZXJ2aWNlcyxDTj1D # b25maWd1cmF0aW9uLERDPUFNRSxEQz1HQkw/Y2VydGlmaWNhdGVSZXZvY2F0aW9u # TGlzdD9iYXNlP29iamVjdENsYXNzPWNSTERpc3RyaWJ1dGlvblBvaW50MB8GA1Ud # IwQYMBaAFBtmohn8m+ul2oSPGJjpEKTDe5K9MB8GA1UdJQQYMBYGCisGAQQBgjdb # AgEGCCsGAQUFBwMDMA0GCSqGSIb3DQEBCwUAA4IBAQCVZn2MgvVx6Lix7aYfjSp6 # t9NYHifbtXl3VxQk20PyxzmNbXoXHQMtgWioOWP4SaQ0Jpw23TgpczqPCS/BWy0E # t2iZ12XatAQRPqrsU4YKcTTExKEPa/gdOz63Okmi+5GQH78d53M5I39DJWzPja7d # RdZgASuswapduSUZMAFJJOslCFtBYAuzrJDy+UH2k7NZQ4+ExtFuuwZZA16c1IbQ # O9JwjGdYna9ZlNtWIc2RSDeNjX8St40y7hhxxrszktg13D1oGZX8+oeQBsPyzigY # U+5JuPoUWGkFBUL8LKR6z3wddTWFZWrW5zfy2aQTxSYOpRYNcUmuAYfLBVhSNI/j # MIII5jCCBs6gAwIBAgITHwAAABS0xR/G8oC+cQAAAAAAFDANBgkqhkiG9w0BAQsF # ADA8MRMwEQYKCZImiZPyLGQBGRYDR0JMMRMwEQYKCZImiZPyLGQBGRYDQU1FMRAw # DgYDVQQDEwdhbWVyb290MB4XDTE2MDkxNTIxMzMwM1oXDTIxMDkxNTIxNDMwM1ow # QTETMBEGCgmSJomT8ixkARkWA0dCTDETMBEGCgmSJomT8ixkARkWA0FNRTEVMBMG # A1UEAxMMQU1FIENTIENBIDAxMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC # AQEA1VeBAtb5+tD3G4C53TfNJNxmYfzhiXKtKQzSGxuav660bTS1VEeDDjSnFhsm # nlb6GkPCeYmCJwWgZGs+3oWJ8yad3//VoP99bXG8azzTJmT2PFM1yKxUXUJgi7I9 # y3C4ll/ATfBwbGGRXD+2PdkdlVpxKWzeNEPVwbCtxWjUhHr6Ecy9R6O23j+2/RSZ # SgfzYctDzDWhNf0PvGPflm31PSk4+ozca337/Ozu0+naDKg5i/zFHhfSJZkq5dPP # G6C8wDrdiwHh6G5IGrMd2QXnmvEfjtpPqE+G8MeWbszaWxlxEjQJQC6PBwn+8Qt4 # Vqlc0am3Z3fBw8kzRunOs8Mn/wIDAQABo4IE2jCCBNYwEAYJKwYBBAGCNxUBBAMC # AQEwIwYJKwYBBAGCNxUCBBYEFJH8M85CnvaT5uJ9VNcIGLu413FlMB0GA1UdDgQW # BBQbZqIZ/JvrpdqEjxiY6RCkw3uSvTCCAQQGA1UdJQSB/DCB+QYHKwYBBQIDBQYI # KwYBBQUHAwEGCCsGAQUFBwMCBgorBgEEAYI3FAIBBgkrBgEEAYI3FQYGCisGAQQB # gjcKAwwGCSsGAQQBgjcVBgYIKwYBBQUHAwkGCCsGAQUFCAICBgorBgEEAYI3QAEB # BgsrBgEEAYI3CgMEAQYKKwYBBAGCNwoDBAYJKwYBBAGCNxUFBgorBgEEAYI3FAIC # BgorBgEEAYI3FAIDBggrBgEFBQcDAwYKKwYBBAGCN1sBAQYKKwYBBAGCN1sCAQYK # KwYBBAGCN1sDAQYKKwYBBAGCN1sFAQYKKwYBBAGCN1sEAQYKKwYBBAGCN1sEAjAZ # BgkrBgEEAYI3FAIEDB4KAFMAdQBiAEMAQTALBgNVHQ8EBAMCAYYwEgYDVR0TAQH/ # BAgwBgEB/wIBADAfBgNVHSMEGDAWgBQpXlFeZK40ueusnA2njHUB0QkLKDCCAWgG # A1UdHwSCAV8wggFbMIIBV6CCAVOgggFPhiNodHRwOi8vY3JsMS5hbWUuZ2JsL2Ny # bC9hbWVyb290LmNybIYxaHR0cDovL2NybC5taWNyb3NvZnQuY29tL3BraWluZnJh # L2NybC9hbWVyb290LmNybIYjaHR0cDovL2NybDIuYW1lLmdibC9jcmwvYW1lcm9v # dC5jcmyGI2h0dHA6Ly9jcmwzLmFtZS5nYmwvY3JsL2FtZXJvb3QuY3JshoGqbGRh # cDovLy9DTj1hbWVyb290LENOPUFNRVJPT1QsQ049Q0RQLENOPVB1YmxpYyUyMEtl # eSUyMFNlcnZpY2VzLENOPVNlcnZpY2VzLENOPUNvbmZpZ3VyYXRpb24sREM9QU1F # LERDPUdCTD9jZXJ0aWZpY2F0ZVJldm9jYXRpb25MaXN0P2Jhc2U/b2JqZWN0Q2xh # c3M9Y1JMRGlzdHJpYnV0aW9uUG9pbnQwggGrBggrBgEFBQcBAQSCAZ0wggGZMDcG # CCsGAQUFBzAChitodHRwOi8vY3JsMS5hbWUuZ2JsL2FpYS9BTUVST09UX2FtZXJv # b3QuY3J0MEcGCCsGAQUFBzAChjtodHRwOi8vY3JsLm1pY3Jvc29mdC5jb20vcGtp # aW5mcmEvY2VydHMvQU1FUk9PVF9hbWVyb290LmNydDA3BggrBgEFBQcwAoYraHR0 # cDovL2NybDIuYW1lLmdibC9haWEvQU1FUk9PVF9hbWVyb290LmNydDA3BggrBgEF # BQcwAoYraHR0cDovL2NybDMuYW1lLmdibC9haWEvQU1FUk9PVF9hbWVyb290LmNy # dDCBogYIKwYBBQUHMAKGgZVsZGFwOi8vL0NOPWFtZXJvb3QsQ049QUlBLENOPVB1 # YmxpYyUyMEtleSUyMFNlcnZpY2VzLENOPVNlcnZpY2VzLENOPUNvbmZpZ3VyYXRp # b24sREM9QU1FLERDPUdCTD9jQUNlcnRpZmljYXRlP2Jhc2U/b2JqZWN0Q2xhc3M9 # Y2VydGlmaWNhdGlvbkF1dGhvcml0eTANBgkqhkiG9w0BAQsFAAOCAgEAKLdKhpqP # H6QBaM3CAOqQi8oA4WQeZLW3QOXNmWm7UA018DQEa1yTqEQbuD5OlR1Wu/F289Dm # XNTdsZM4GTKEaZehIiVaMoLvEJtu5h6CTyfWqPetNyOJqR1sGqod0Xwn5/G/zcTY # Sxn5K3N8KdlcDrZAIyfq3yaEJYHGnA9eJ/f1RrfbJgeo/RAhICctOONwfpsBXcgi # TuTmlD/k0DqogvzJgPq9GOkIyX/dxk7IkPzX/n484s0zHR4IKU58U3G1oPSQmZ5O # HAvgHaEASkdN5E20HyJv5zN7du+QY08fI+VIci6pagLfXHYaTX3ZJ/MUM9XU+oU5 # y4qMLzTj1JIG0LVfuHK8yoB7h2inyTe7bn6h2G8NxZ02aKZ0xa+n/JnoXKNsaVPG # 1SoTuItMsXV5pQtIShsBqnXqFjY3bJMlMhIofMcjiuOwRCW+prZ+PoYvE2P+ML7g # s3L65GZ9BdKF3fSW3TvmpOujPQ23rzSle9WGxFJ02fNbaF9C7bG44uDzMoZU4P+u # vQaB7KE4OMqAvYYfFy1tv1dpVIN/qhx0H/9oNiOJpuZZ39ZibLt9DXbsq5qwyHmd # JXaisxwB53wJshUjc1i76xqFPUNGb8EZQ3aFKl2w9B47vfBi+nU3sN0tpnLPtew4 # LHWq4LBD5uiNZVBOYosZ6BKhSlk1+Y/0y1IxghXzMIIV7wIBATBYMEExEzARBgoJ # kiaJk/IsZAEZFgNHQkwxEzARBgoJkiaJk/IsZAEZFgNBTUUxFTATBgNVBAMTDEFN # RSBDUyBDQSAwMQITNgAAAOhmnRtIQqVMRQABAAAA6DANBglghkgBZQMEAgEFAKCB # rjAZBgkqhkiG9w0BCQMxDAYKKwYBBAGCNwIBBDAcBgorBgEEAYI3AgELMQ4wDAYK # KwYBBAGCNwIBFTAvBgkqhkiG9w0BCQQxIgQg/FOobTCBMj7//87cUHrL+8u2ksbE # HM8EHifDhAmwy6wwQgYKKwYBBAGCNwIBDDE0MDKgFIASAE0AaQBjAHIAbwBzAG8A # ZgB0oRqAGGh0dHA6Ly93d3cubWljcm9zb2Z0LmNvbTANBgkqhkiG9w0BAQEFAASC # AQBN+5sDSt/Ps3xup7axW13J1EXxTNWEnO83lF7EjdQ0XjhGOjbg7HKc3Wfg+jb9 # MKxkC5VSN/KTeyNFw7EkhiPp3qkrpzCMhEl1lrwZZFeKop1Sk058LBr5ZQfUxOW6 # shycdO3lx0OWbLa3M/muzzqk1MIj0l9lXDkHXQV346dMT04d3takv7R6ckpJmEjy # Ig6RbsashAhQ0G8N6ekYTIzTbHZbxbwZHidAc3p8sj9QWkA0ZbUcXgquio72k+Y2 # PM0Mg8mczeVpA5xd3r5EmVONiPGCTOtyeuf66rskx4ta8ikdAINQvQAW3KoSmX1f # v0Lez22zttz/lEBMXfg3kikLoYITuzCCE7cGCisGAQQBgjcDAwExghOnMIITowYJ # KoZIhvcNAQcCoIITlDCCE5ACAQMxDzANBglghkgBZQMEAgEFADCCAVgGCyqGSIb3 # DQEJEAEEoIIBRwSCAUMwggE/AgEBBgorBgEEAYRZCgMBMDEwDQYJYIZIAWUDBAIB # BQAEIDhyb0eYcXc4e5WYz4fX28RvQC86Wd1REAkcMApLIQiDAgZd5tGdD3QYEzIw # MTkxMjA0MDgyNDM4Ljc4N1owBwIBAYACAfSggdSkgdEwgc4xCzAJBgNVBAYTAlVT # MRMwEQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQK # ExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xKTAnBgNVBAsTIE1pY3Jvc29mdCBPcGVy # YXRpb25zIFB1ZXJ0byBSaWNvMSYwJAYDVQQLEx1UaGFsZXMgVFNTIEVTTjo3MjhE # LUM0NUYtRjlFQjElMCMGA1UEAxMcTWljcm9zb2Z0IFRpbWUtU3RhbXAgU2Vydmlj # ZaCCDyMwggT1MIID3aADAgECAhMzAAABBAkBdQhYhy0pAAAAAAEEMA0GCSqGSIb3 # DQEBCwUAMHwxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYD # VQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xJjAk # BgNVBAMTHU1pY3Jvc29mdCBUaW1lLVN0YW1wIFBDQSAyMDEwMB4XDTE5MDkwNjIw # NDExOFoXDTIwMTIwNDIwNDExOFowgc4xCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpX # YXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNyb3NvZnQg # Q29ycG9yYXRpb24xKTAnBgNVBAsTIE1pY3Jvc29mdCBPcGVyYXRpb25zIFB1ZXJ0 # byBSaWNvMSYwJAYDVQQLEx1UaGFsZXMgVFNTIEVTTjo3MjhELUM0NUYtRjlFQjEl # MCMGA1UEAxMcTWljcm9zb2Z0IFRpbWUtU3RhbXAgU2VydmljZTCCASIwDQYJKoZI # hvcNAQEBBQADggEPADCCAQoCggEBAMgtB6ARuhhmlpThYPwWgmtO2oNVTTZyHgYQ # Bc3GH/J1w6bhgTcgpNiZnGZe2kv1Abyg7ABSP6ekgpRhWpByx5gOeOxpllPXkCxp # iMlKFFx++Rnxg0N1YFN2aAsVj9GRMWc3R6hPKtgFMHXULPxji3fu6DTgjfOi2pih # 5r/O+cp1Oi8KvdT+8p5JlROk1/85nsTggE80CudP/NhuiIrSvmDNKVmOMF3afUWU # swVP6v6t9cGjSWG3GMGNZe8FB3VVOL+pNtCbRV83qhQtkyIyA8HvGaciAfrXZi/Q # D5C/vK7XcvoeHbizh7j5lXUD3PiH0ffqHvMp58lsU/Ajpqr5ZGcCAwEAAaOCARsw # ggEXMB0GA1UdDgQWBBSY1V7fwkQaDhcBi/GZ08MisOia6jAfBgNVHSMEGDAWgBTV # YzpcijGQ80N7fEYbxTNoWoVtVTBWBgNVHR8ETzBNMEugSaBHhkVodHRwOi8vY3Js # Lm1pY3Jvc29mdC5jb20vcGtpL2NybC9wcm9kdWN0cy9NaWNUaW1TdGFQQ0FfMjAx # MC0wNy0wMS5jcmwwWgYIKwYBBQUHAQEETjBMMEoGCCsGAQUFBzAChj5odHRwOi8v # d3d3Lm1pY3Jvc29mdC5jb20vcGtpL2NlcnRzL01pY1RpbVN0YVBDQV8yMDEwLTA3 # LTAxLmNydDAMBgNVHRMBAf8EAjAAMBMGA1UdJQQMMAoGCCsGAQUFBwMIMA0GCSqG # SIb3DQEBCwUAA4IBAQA9FdSzd2l8NAMX17RFeWLhOqnOAgyXIjH8tdW1yA94Zdzy # n8NeukcjyIL7/Pkj8R7KEtEUL0cfRnds6KITaPBXxlosz1i+kMhfd6d4kSgnPWm0 # qoA14fqxJUM6P5fZfWRGUrtkNJha6N8Id1Ciuyibq7K03EnTLgli3EX1LXlzBOyy # yjM3hDGVxgPk9D7Bw5ikgVju+Yql+tXjjgG/oFw+WJvwBN7YunaRV06JKZwsYGPs # OYA1qyc8VXBoyeKGFKhI2oThT/P7IM3hCxLNc4fix3sLaKe4NZta0rjdssY8Kz+Z # 4sr8T9daXSFa7kUpKVw5277+0QFCc6bkrHjlKB/lMIIGcTCCBFmgAwIBAgIKYQmB # KgAAAAAAAjANBgkqhkiG9w0BAQsFADCBiDELMAkGA1UEBhMCVVMxEzARBgNVBAgT # Cldhc2hpbmd0b24xEDAOBgNVBAcTB1JlZG1vbmQxHjAcBgNVBAoTFU1pY3Jvc29m # dCBDb3Jwb3JhdGlvbjEyMDAGA1UEAxMpTWljcm9zb2Z0IFJvb3QgQ2VydGlmaWNh # dGUgQXV0aG9yaXR5IDIwMTAwHhcNMTAwNzAxMjEzNjU1WhcNMjUwNzAxMjE0NjU1 # WjB8MQswCQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMH # UmVkbW9uZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMSYwJAYDVQQD # Ex1NaWNyb3NvZnQgVGltZS1TdGFtcCBQQ0EgMjAxMDCCASIwDQYJKoZIhvcNAQEB # BQADggEPADCCAQoCggEBAKkdDbx3EYo6IOz8E5f1+n9plGt0VBDVpQoAgoX77Xxo # SyxfxcPlYcJ2tz5mK1vwFVMnBDEfQRsalR3OCROOfGEwWbEwRA/xYIiEVEMM1024 # OAizQt2TrNZzMFcmgqNFDdDq9UeBzb8kYDJYYEbyWEeGMoQedGFnkV+BVLHPk0yS # wcSmXdFhE24oxhr5hoC732H8RsEnHSRnEnIaIYqvS2SJUGKxXf13Hz3wV3WsvYpC # TUBR0Q+cBj5nf/VmwAOWRH7v0Ev9buWayrGo8noqCjHw2k4GkbaICDXoeByw6ZnN # POcvRLqn9NxkvaQBwSAJk3jN/LzAyURdXhacAQVPIk0CAwEAAaOCAeYwggHiMBAG # CSsGAQQBgjcVAQQDAgEAMB0GA1UdDgQWBBTVYzpcijGQ80N7fEYbxTNoWoVtVTAZ # BgkrBgEEAYI3FAIEDB4KAFMAdQBiAEMAQTALBgNVHQ8EBAMCAYYwDwYDVR0TAQH/ # BAUwAwEB/zAfBgNVHSMEGDAWgBTV9lbLj+iiXGJo0T2UkFvXzpoYxDBWBgNVHR8E # TzBNMEugSaBHhkVodHRwOi8vY3JsLm1pY3Jvc29mdC5jb20vcGtpL2NybC9wcm9k # dWN0cy9NaWNSb29DZXJBdXRfMjAxMC0wNi0yMy5jcmwwWgYIKwYBBQUHAQEETjBM # MEoGCCsGAQUFBzAChj5odHRwOi8vd3d3Lm1pY3Jvc29mdC5jb20vcGtpL2NlcnRz # L01pY1Jvb0NlckF1dF8yMDEwLTA2LTIzLmNydDCBoAYDVR0gAQH/BIGVMIGSMIGP # BgkrBgEEAYI3LgMwgYEwPQYIKwYBBQUHAgEWMWh0dHA6Ly93d3cubWljcm9zb2Z0 # LmNvbS9QS0kvZG9jcy9DUFMvZGVmYXVsdC5odG0wQAYIKwYBBQUHAgIwNB4yIB0A # TABlAGcAYQBsAF8AUABvAGwAaQBjAHkAXwBTAHQAYQB0AGUAbQBlAG4AdAAuIB0w # DQYJKoZIhvcNAQELBQADggIBAAfmiFEN4sbgmD+BcQM9naOhIW+z66bM9TG+zwXi # qf76V20ZMLPCxWbJat/15/B4vceoniXj+bzta1RXCCtRgkQS+7lTjMz0YBKKdsxA # QEGb3FwX/1z5Xhc1mCRWS3TvQhDIr79/xn/yN31aPxzymXlKkVIArzgPF/UveYFl # 2am1a+THzvbKegBvSzBEJCI8z+0DpZaPWSm8tv0E4XCfMkon/VWvL/625Y4zu2Jf # mttXQOnxzplmkIz/amJ/3cVKC5Em4jnsGUpxY517IW3DnKOiPPp/fZZqkHimbdLh # nPkd/DjYlPTGpQqWhqS9nhquBEKDuLWAmyI4ILUl5WTs9/S/fmNZJQ96LjlXdqJx # qgaKD4kWumGnEcua2A5HmoDF0M2n0O99g/DhO3EJ3110mCIIYdqwUB5vvfHhAN/n # MQekkzr3ZUd46PioSKv33nJ+YWtvd6mBy6cJrDm77MbL2IK0cs0d9LiFAR6A+xuJ # KlQ5slvayA1VmXqHczsI5pgt6o3gMy4SKfXAL1QnIffIrE7aKLixqduWsqdCosnP # GUFN4Ib5KpqjEWYw07t0MkvfY3v1mYovG8chr1m1rtxEPJdQcdeh0sVV42neV8HR # 3jDA/czmTfsNv11P6Z0eGTgvvM9YBS7vDaBQNdrvCScc1bN+NR4Iuto229Nfj950 # iEkSoYIDsTCCApkCAQEwgf6hgdSkgdEwgc4xCzAJBgNVBAYTAlVTMRMwEQYDVQQI # EwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNyb3Nv # ZnQgQ29ycG9yYXRpb24xKTAnBgNVBAsTIE1pY3Jvc29mdCBPcGVyYXRpb25zIFB1 # ZXJ0byBSaWNvMSYwJAYDVQQLEx1UaGFsZXMgVFNTIEVTTjo3MjhELUM0NUYtRjlF # QjElMCMGA1UEAxMcTWljcm9zb2Z0IFRpbWUtU3RhbXAgU2VydmljZaIlCgEBMAkG # BSsOAwIaBQADFQCzRh5/R0jzKEyIVLZzGHgW3BUKfaCB3jCB26SB2DCB1TELMAkG # A1UEBhMCVVMxEzARBgNVBAgTCldhc2hpbmd0b24xEDAOBgNVBAcTB1JlZG1vbmQx # HjAcBgNVBAoTFU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjEpMCcGA1UECxMgTWljcm9z # b2Z0IE9wZXJhdGlvbnMgUHVlcnRvIFJpY28xJzAlBgNVBAsTHm5DaXBoZXIgTlRT # IEVTTjo0REU5LTBDNUUtM0UwOTErMCkGA1UEAxMiTWljcm9zb2Z0IFRpbWUgU291 # cmNlIE1hc3RlciBDbG9jazANBgkqhkiG9w0BAQUFAAIFAOGRUBkwIhgPMjAxOTEy # MDQwNTIwMjVaGA8yMDE5MTIwNTA1MjAyNVoweDA+BgorBgEEAYRZCgQBMTAwLjAK # AgUA4ZFQGQIBADALAgEAAgMCteoCAf8wBwIBAAICF3swCgIFAOGSoZkCAQAwNgYK # KwYBBAGEWQoEAjEoMCYwDAYKKwYBBAGEWQoDAaAKMAgCAQACAxbjYKEKMAgCAQAC # AwehIDANBgkqhkiG9w0BAQUFAAOCAQEAJZ27rvTBd0fpu9zNtEfufvIBCFSRMXlt # /NvcBnLfEOTBx3/Rf6YLO3DKHSXISZ5aEnBPk97Frll71El0bBnZ7AKGX0EYKJ4k # ZBLn5CTbQTCUvH8vswKYg9sEXZ2aSDzXZTd0Xnwq1RUtlrWBX1dIVgDwotb81V/l # FeziqCSVMuzBg0RIXGRZrSk8u1bLgDpPqL9iezDaA8al90E/FQBgubpRjBR/Qttp # bvl1viZ8LV6IalVYpcKHBEgYYSI1NyC4euFS/lMZxuWolH+PWY6/WlGGo9zg8lHR # +4BOhtgJUXjOqi0S5o6kaAcQ9C+XrUGgie/NHF2Vk0jWNtyJDjGWkzGCAvUwggLx # AgEBMIGTMHwxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYD # VQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xJjAk # BgNVBAMTHU1pY3Jvc29mdCBUaW1lLVN0YW1wIFBDQSAyMDEwAhMzAAABBAkBdQhY # hy0pAAAAAAEEMA0GCWCGSAFlAwQCAQUAoIIBMjAaBgkqhkiG9w0BCQMxDQYLKoZI # hvcNAQkQAQQwLwYJKoZIhvcNAQkEMSIEIGau3p32kRjPTNLqAiVWdijXjvRc63dG # jLx1rxeWbllnMIHiBgsqhkiG9w0BCRACDDGB0jCBzzCBzDCBsQQUs0Yef0dI8yhM # iFS2cxh4FtwVCn0wgZgwgYCkfjB8MQswCQYDVQQGEwJVUzETMBEGA1UECBMKV2Fz # aGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9uZDEeMBwGA1UEChMVTWljcm9zb2Z0IENv # cnBvcmF0aW9uMSYwJAYDVQQDEx1NaWNyb3NvZnQgVGltZS1TdGFtcCBQQ0EgMjAx # MAITMwAAAQQJAXUIWIctKQAAAAABBDAWBBR4K4K+Z4Ae8/LBAKOh1eoMHO1p5jAN # BgkqhkiG9w0BAQsFAASCAQB5H/KPiaBTNZsg5IkduuXpXhutu7M6zZa/c3GgFo7X # VK5Op2SmlwQL4uiBXeOA04DEgblEwgQphtHrmS4OpUC5nxNvQ77AAYDl6roDhpOd # 6SevBGqVT3cf0Cmblco3aLHzO7BlgxcqlSuB9ss2d8kh4/Q7W2vv6Uw1pPqAZ2Yz # m6lh6NZEdd+x+P+X8HLboMZETFKLsi+cxHjFcZ/KxJB3ZmbocH0ulEVlFeXwf8Yc # 7aYTTKTnaxLh5sKqcwD+6HIH0y+KanY3zaSX09RGGnmWhID7C8qRzyRomu6WXJ6+ # aFY7IM0DIltigli9IUIepFnOsz2aDVuDZ5QFX+YtQOo5 # SIG # End signature block |