Private/Invoke-VenafiParallel.ps1
function Invoke-VenafiParallel { <# .SYNOPSIS Helper function to execute a scriptblock in parallel .DESCRIPTION If using powershell v7+, execute a scriptblock in parallel with progress. Otherwise, fallback to executing linearly. .PARAMETER InputObject List of items to iterate over .PARAMETER ScriptBlock Scriptblock to execute against the list of items .PARAMETER ThrottleLimit Limit the number of threads when running in parallel; the default is 100. Applicable to PS v7+ only. .PARAMETER ProgressTitle Message displayed on the progress bar .PARAMETER NoProgress Do not display the progress bar .PARAMETER VenafiSession Authentication for the function. .EXAMPLE Invoke-VenafiParallel -InputObject $myObjects -ScriptBlock { Do-Something $PSItem } Execute in parallel. Reference each item in the scriptblock as $PSItem or $_. .EXAMPLE Invoke-VenafiParallel -InputObject $myObjects -ScriptBlock { Do-Something $PSItem } -ThrottleLimit 5 Only run 5 threads at a time instead of the default of 100. .EXAMPLE Invoke-VenafiParallel -InputObject $myObjects -ScriptBlock { Do-Something $PSItem } -NoProgress Execute in parallel with no progress bar. .NOTES In your ScriptBlock: - Use either $PSItem or $_ to reference the current input object - Remember hashtables are reference types so be sure to clone if 'using' from parent #> [CmdletBinding()] param ( [Parameter(Mandatory)] [AllowNull()] [psobject] $InputObject, [Parameter(Mandatory)] [scriptblock] $ScriptBlock, [Parameter()] [int32] $ThrottleLimit = 100, [Parameter()] [string] $ProgressTitle = 'Performing action', [Parameter()] [switch] $NoProgress, [Parameter()] [psobject] $VenafiSession ) begin { if (-not $InputObject) { return } if ( $PSVersionTable.PSVersion.Major -ge 7 ) { if ( $env:VDC_TOKEN ) { $VenafiSession = $env:VDC_TOKEN } elseif ( $env:VC_KEY ) { $VenafiSession = $env:VC_KEY } elseif ($script:VenafiSessionNested) { $VenafiSession = $script:VenafiSessionNested } elseif ( $script:VenafiSession ) { $VenafiSession = $script:VenafiSession } else { throw 'Please run New-VenafiSession or provide a TLSPC key or TLSPDC token.' } # PS classes are not thread safe, https://github.com/PowerShell/PowerShell/issues/12801 # so can't pass VenafiSession as is unless it's an token/key string # pscustomobject are safe so convert to that $vs = if ( $VenafiSession -is 'VenafiSession' ) { $vsTemp = [pscustomobject]@{} $VenafiSession.psobject.properties | ForEach-Object { $vsTemp | Add-Member @{$_.name = $_.value } } $vsTemp } else { # token or api key provided directly $VenafiSession } } } process { } end { if (-not $InputObject) { return } # if we only have 1 item or limited to 1 at a time, no need for parallel if ( ($PSVersionTable.PSVersion.Major -ge 7) -and (([array]$InputObject).Count -gt 1) -and ($ThrottleLimit -ne 100) ) { if ( -not $NoProgress ) { Write-Progress -Activity $ProgressTitle -Status "Initializing..." } $thisDir = $PSScriptRoot $starterSb = { # need to import module until https://github.com/PowerShell/PowerShell/issues/12240 is complete # import via path instead of just module name to support non-standard paths, eg. development work Import-Module (Join-Path -Path (Split-Path $using:thisDir -Parent) -ChildPath 'VenafiPS.psd1') -Force $script:VenafiSession = $using:vs # bring in verbose preference from calling function $VerbosePreference = $using:VerbosePreference } $newSb = ([ScriptBlock]::Create($starterSb.ToString() + $ScriptBlock.ToString())) $job = $InputObject | Foreach-Object -AsJob -ThrottleLimit $ThrottleLimit -Parallel $newSb if ( -not $job.ChildJobs ) { return } do { # let threads run Start-Sleep -Milliseconds 100 $completedJobsCount = $job.ChildJobs.Where({ $_.State -notin 'NotStarted', 'Running' }).Count # get latest job info $job | Receive-Job if ( -not $NoProgress ) { [int] $percent = ($completedJobsCount / $job.ChildJobs.Count) * 100 Write-Progress -Activity $ProgressTitle -Status "$percent% complete" -PercentComplete $percent } } while ($completedJobsCount -lt $job.ChildJobs.Count) Write-Progress -Completed -Activity 'done' } else { # if ( ([array]$InputObject).Count -gt 1 ) { # Write-Warning 'Upgrade to PowerShell v7+ to make this function execute in parallel and be much faster!' # } # ensure no $using: vars $InputObject | ForEach-Object -Process ([ScriptBlock]::Create(($ScriptBlock.ToString() -ireplace [regex]::Escape('$using:'), '$'))) } } } # SIG # Begin signature block # MIIhigYJKoZIhvcNAQcCoIIhezCCIXcCAQExDzANBglghkgBZQMEAgEFADB5Bgor # BgEEAYI3AgEEoGswaTA0BgorBgEEAYI3AgEeMCYCAwEAAAQQH8w7YFlLCE63JNLG # KX7zUQIBAAIBAAIBAAIBAAIBADAxMA0GCWCGSAFlAwQCAQUABCCV01wCxqeJueCl # 8BoR20L8bNemUUV4bRQjNi7sZVdmWKCCGokwggd8MIIFZKADAgECAhAEskBM6tH3 # agmQID1jirpbMA0GCSqGSIb3DQEBCwUAMGkxCzAJBgNVBAYTAlVTMRcwFQYDVQQK # Ew5EaWdpQ2VydCwgSW5jLjFBMD8GA1UEAxM4RGlnaUNlcnQgVHJ1c3RlZCBHNCBD # b2RlIFNpZ25pbmcgUlNBNDA5NiBTSEEzODQgMjAyMSBDQTEwHhcNMjMwOTEzMDAw # MDAwWhcNMjQwOTEyMjM1OTU5WjCBgzELMAkGA1UEBhMCVVMxDTALBgNVBAgTBFV0 # YWgxFzAVBgNVBAcTDlNhbHQgTGFrZSBDaXR5MRUwEwYDVQQKEwxWZW5hZmksIElu # Yy4xHjAcBgNVBAsTFVByb2Zlc3Npb25hbCBTZXJ2aWNlczEVMBMGA1UEAxMMVmVu # YWZpLCBJbmMuMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAz2ga2w0N # HzoqK1Npwmce0q2VZkosMIa4Mw4eFhDZiSlaWWwXbWKBEQVEEnd/mPlmOMv2jwBE # PaBdTzX4bp5A4gr2Nwpw2Hjr9nsfBuuMNVkCCimXdjqbLhiyU0obIYk+5EMH0Lnw # n1AupTbjtj63kqs7ZDfLRVq6jUtGJVdfDKBrIAjymePXi58G1991J6i8og3vKhhO # 97sWciGXLblirUFNMpZpK32UrHr2QklIqhSo1ucvTT7x8EFW5P33z2eniQCDvssE # UsV7vDdc4zll2io+B1j7vVOicLG+P8Jxhjy13seKsmAXSwfID51tWO3V2SfEZE2x # fuxRN9bLOdXyB9808ifIAyxLmz36Kq7kaX/LQ6eGeVDwbnvdAUoUcCKYGK7FPYQh # J0ZnxtXJRKfQU4rLaZItVtnJbPfXGJX1aXJY10fKZSvnEfYRrcb6pMVFxCyAMoZE # U3XSg9bS0oc9fg+FTjknczyXFjMD97PZW8GcLAXWSukbstyzSHvh0Nh3tyGyXPyy # +yGxMqAw6elop3FcG1sq6Ri9gSNA+oCzD2VfwoKpPJnomLDGrYuCYM/U1WG2hi/z # gnhn/Lu/e8FKTkI8ZRhVB1Yfv4VgrxGSx0WBI+4WB6Bwi6LjVmSuasJZ0Oobl7ik # 59nkseYc885U5bjgWZrUbXhfw34lUrVkfMkCAwEAAaOCAgMwggH/MB8GA1UdIwQY # MBaAFGg34Ou2O/hfEYb7/mF7CIhl9E5CMB0GA1UdDgQWBBSoGeI5UP36z1PFpV0W # 4oYJNTGVKDA+BgNVHSAENzA1MDMGBmeBDAEEATApMCcGCCsGAQUFBwIBFhtodHRw # Oi8vd3d3LmRpZ2ljZXJ0LmNvbS9DUFMwDgYDVR0PAQH/BAQDAgeAMBMGA1UdJQQM # MAoGCCsGAQUFBwMDMIG1BgNVHR8Ega0wgaowU6BRoE+GTWh0dHA6Ly9jcmwzLmRp # Z2ljZXJ0LmNvbS9EaWdpQ2VydFRydXN0ZWRHNENvZGVTaWduaW5nUlNBNDA5NlNI # QTM4NDIwMjFDQTEuY3JsMFOgUaBPhk1odHRwOi8vY3JsNC5kaWdpY2VydC5jb20v # RGlnaUNlcnRUcnVzdGVkRzRDb2RlU2lnbmluZ1JTQTQwOTZTSEEzODQyMDIxQ0Ex # LmNybDCBlAYIKwYBBQUHAQEEgYcwgYQwJAYIKwYBBQUHMAGGGGh0dHA6Ly9vY3Nw # LmRpZ2ljZXJ0LmNvbTBcBggrBgEFBQcwAoZQaHR0cDovL2NhY2VydHMuZGlnaWNl # cnQuY29tL0RpZ2lDZXJ0VHJ1c3RlZEc0Q29kZVNpZ25pbmdSU0E0MDk2U0hBMzg0 # MjAyMUNBMS5jcnQwCQYDVR0TBAIwADANBgkqhkiG9w0BAQsFAAOCAgEADWd6cY3c # UuXXxFhO4O+VPRPxNituYopOy3rgvLio6YncYfbbfZKRmKBYb79Ae6c/Nsz6K3bP # lhs9UuXs6UVlVwRhHpf8w1ko1I9lZLjZM8gbgvXethyIB3bvDDrLXyESUX4iAL/U # DNyuDjsQBOTe+7WvyXPrZhqlJL0kwO6kaMFffm+V+zaTBrSazco7GLlXVtp6+jWY # EHSdzyaeNgY5N4j3nKlsdVo4LhynuyqC9aTyWfxC9KPKpRNq9tGxkTHyjeCB61Y/ # yA6C63GpDmfoZtD0x46nzr1r7AG5c//Td+g9sKA4raai2RxcmLXwoIEG/5W/60cK # TAU44EnUW4ep/rmPBBLpinY3cg+k2b5UjBIUbYebanRVHiZmgCtLKQYLHdH8yu9L # Zc96I6dGmm08C8zsZPTyiYg9JadKPlAdkI3sB1d8263Ufsa6zvHEvSK3QnutLxHf # dOd/7XRwqSWx/oXrk8jggvAo3IAGEX/S+cRBjFYtmKZuhZUPQSh8LbiUfsRLsG/d # omoKJw1JVZubeFORgByyscqIDAIoAptjyZeoKJal+MF1DhkGnBehUNdZe+q4h43c # r573CZl4XZwY5w3y3ekc4Ahls9kE/VvMqkxGfHoTswmaSVM3EJuZ51FCg054zoka # BEgxZ4/59gvjUKfRNuUYC8FfD5Ldj0oI21QwggWNMIIEdaADAgECAhAOmxiO+dAt # 5+/bUOIIQBhaMA0GCSqGSIb3DQEBDAUAMGUxCzAJBgNVBAYTAlVTMRUwEwYDVQQK # EwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20xJDAiBgNV # BAMTG0RpZ2lDZXJ0IEFzc3VyZWQgSUQgUm9vdCBDQTAeFw0yMjA4MDEwMDAwMDBa # Fw0zMTExMDkyMzU5NTlaMGIxCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdpQ2Vy # dCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20xITAfBgNVBAMTGERpZ2lD # ZXJ0IFRydXN0ZWQgUm9vdCBHNDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoC # ggIBAL/mkHNo3rvkXUo8MCIwaTPswqclLskhPfKK2FnC4SmnPVirdprNrnsbhA3E # MB/zG6Q4FutWxpdtHauyefLKEdLkX9YFPFIPUh/GnhWlfr6fqVcWWVVyr2iTcMKy # unWZanMylNEQRBAu34LzB4TmdDttceItDBvuINXJIB1jKS3O7F5OyJP4IWGbNOsF # xl7sWxq868nPzaw0QF+xembud8hIqGZXV59UWI4MK7dPpzDZVu7Ke13jrclPXuU1 # 5zHL2pNe3I6PgNq2kZhAkHnDeMe2scS1ahg4AxCN2NQ3pC4FfYj1gj4QkXCrVYJB # MtfbBHMqbpEBfCFM1LyuGwN1XXhm2ToxRJozQL8I11pJpMLmqaBn3aQnvKFPObUR # WBf3JFxGj2T3wWmIdph2PVldQnaHiZdpekjw4KISG2aadMreSx7nDmOu5tTvkpI6 # nj3cAORFJYm2mkQZK37AlLTSYW3rM9nF30sEAMx9HJXDj/chsrIRt7t/8tWMcCxB # YKqxYxhElRp2Yn72gLD76GSmM9GJB+G9t+ZDpBi4pncB4Q+UDCEdslQpJYls5Q5S # UUd0viastkF13nqsX40/ybzTQRESW+UQUOsxxcpyFiIJ33xMdT9j7CFfxCBRa2+x # q4aLT8LWRV+dIPyhHsXAj6KxfgommfXkaS+YHS312amyHeUbAgMBAAGjggE6MIIB # NjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBTs1+OC0nFdZEzfLmc/57qYrhwP # TzAfBgNVHSMEGDAWgBRF66Kv9JLLgjEtUYunpyGd823IDzAOBgNVHQ8BAf8EBAMC # AYYweQYIKwYBBQUHAQEEbTBrMCQGCCsGAQUFBzABhhhodHRwOi8vb2NzcC5kaWdp # Y2VydC5jb20wQwYIKwYBBQUHMAKGN2h0dHA6Ly9jYWNlcnRzLmRpZ2ljZXJ0LmNv # bS9EaWdpQ2VydEFzc3VyZWRJRFJvb3RDQS5jcnQwRQYDVR0fBD4wPDA6oDigNoY0 # aHR0cDovL2NybDMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0QXNzdXJlZElEUm9vdENB # LmNybDARBgNVHSAECjAIMAYGBFUdIAAwDQYJKoZIhvcNAQEMBQADggEBAHCgv0Nc # Vec4X6CjdBs9thbX979XB72arKGHLOyFXqkauyL4hxppVCLtpIh3bb0aFPQTSnov # Lbc47/T/gLn4offyct4kvFIDyE7QKt76LVbP+fT3rDB6mouyXtTP0UNEm0Mh65Zy # oUi0mcudT6cGAxN3J0TU53/oWajwvy8LpunyNDzs9wPHh6jSTEAZNUZqaVSwuKFW # juyk1T3osdz9HNj0d1pcVIxv76FQPfx2CWiEn2/K2yCNNWAcAgPLILCsWKAOQGPF # mCLBsln1VWvPJ6tsds5vIy30fnFqI2si/xK4VC0nftg62fC2h5b9W9FcrBjDTZ9z # twGpn1eqXijiuZQwggauMIIElqADAgECAhAHNje3JFR82Ees/ShmKl5bMA0GCSqG # SIb3DQEBCwUAMGIxCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMx # GTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20xITAfBgNVBAMTGERpZ2lDZXJ0IFRy # dXN0ZWQgUm9vdCBHNDAeFw0yMjAzMjMwMDAwMDBaFw0zNzAzMjIyMzU5NTlaMGMx # CzAJBgNVBAYTAlVTMRcwFQYDVQQKEw5EaWdpQ2VydCwgSW5jLjE7MDkGA1UEAxMy # RGlnaUNlcnQgVHJ1c3RlZCBHNCBSU0E0MDk2IFNIQTI1NiBUaW1lU3RhbXBpbmcg # Q0EwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDGhjUGSbPBPXJJUVXH # JQPE8pE3qZdRodbSg9GeTKJtoLDMg/la9hGhRBVCX6SI82j6ffOciQt/nR+eDzMf # UBMLJnOWbfhXqAJ9/UO0hNoR8XOxs+4rgISKIhjf69o9xBd/qxkrPkLcZ47qUT3w # 1lbU5ygt69OxtXXnHwZljZQp09nsad/ZkIdGAHvbREGJ3HxqV3rwN3mfXazL6IRk # tFLydkf3YYMZ3V+0VAshaG43IbtArF+y3kp9zvU5EmfvDqVjbOSmxR3NNg1c1eYb # qMFkdECnwHLFuk4fsbVYTXn+149zk6wsOeKlSNbwsDETqVcplicu9Yemj052FVUm # cJgmf6AaRyBD40NjgHt1biclkJg6OBGz9vae5jtb7IHeIhTZgirHkr+g3uM+onP6 # 5x9abJTyUpURK1h0QCirc0PO30qhHGs4xSnzyqqWc0Jon7ZGs506o9UD4L/wojzK # QtwYSH8UNM/STKvvmz3+DrhkKvp1KCRB7UK/BZxmSVJQ9FHzNklNiyDSLFc1eSuo # 80VgvCONWPfcYd6T/jnA+bIwpUzX6ZhKWD7TA4j+s4/TXkt2ElGTyYwMO1uKIqjB # Jgj5FBASA31fI7tk42PgpuE+9sJ0sj8eCXbsq11GdeJgo1gJASgADoRU7s7pXche # MBK9Rp6103a50g5rmQzSM7TNsQIDAQABo4IBXTCCAVkwEgYDVR0TAQH/BAgwBgEB # /wIBADAdBgNVHQ4EFgQUuhbZbU2FL3MpdpovdYxqII+eyG8wHwYDVR0jBBgwFoAU # 7NfjgtJxXWRM3y5nP+e6mK4cD08wDgYDVR0PAQH/BAQDAgGGMBMGA1UdJQQMMAoG # CCsGAQUFBwMIMHcGCCsGAQUFBwEBBGswaTAkBggrBgEFBQcwAYYYaHR0cDovL29j # c3AuZGlnaWNlcnQuY29tMEEGCCsGAQUFBzAChjVodHRwOi8vY2FjZXJ0cy5kaWdp # Y2VydC5jb20vRGlnaUNlcnRUcnVzdGVkUm9vdEc0LmNydDBDBgNVHR8EPDA6MDig # NqA0hjJodHRwOi8vY3JsMy5kaWdpY2VydC5jb20vRGlnaUNlcnRUcnVzdGVkUm9v # dEc0LmNybDAgBgNVHSAEGTAXMAgGBmeBDAEEAjALBglghkgBhv1sBwEwDQYJKoZI # hvcNAQELBQADggIBAH1ZjsCTtm+YqUQiAX5m1tghQuGwGC4QTRPPMFPOvxj7x1Bd # 4ksp+3CKDaopafxpwc8dB+k+YMjYC+VcW9dth/qEICU0MWfNthKWb8RQTGIdDAiC # qBa9qVbPFXONASIlzpVpP0d3+3J0FNf/q0+KLHqrhc1DX+1gtqpPkWaeLJ7giqzl # /Yy8ZCaHbJK9nXzQcAp876i8dU+6WvepELJd6f8oVInw1YpxdmXazPByoyP6wCeC # RK6ZJxurJB4mwbfeKuv2nrF5mYGjVoarCkXJ38SNoOeY+/umnXKvxMfBwWpx2cYT # gAnEtp/Nh4cku0+jSbl3ZpHxcpzpSwJSpzd+k1OsOx0ISQ+UzTl63f8lY5knLD0/ # a6fxZsNBzU+2QJshIUDQtxMkzdwdeDrknq3lNHGS1yZr5Dhzq6YBT70/O3itTK37 # xJV77QpfMzmHQXh6OOmc4d0j/R0o08f56PGYX/sr2H7yRp11LB4nLCbbbxV7HhmL # NriT1ObyF5lZynDwN7+YAN8gFk8n+2BnFqFmut1VwDophrCYoCvtlUG3OtUVmDG0 # YgkPCr2B2RP+v6TR81fZvAT6gt4y3wSJ8ADNXcL50CN/AAvkdgIm2fBldkKmKYcJ # RyvmfxqkhQ/8mJb2VVQrH4D6wPIOK+XW+6kvRBVK5xMOHds3OBqhK/bt1nz8MIIG # wjCCBKqgAwIBAgIQBUSv85SdCDmmv9s/X+VhFjANBgkqhkiG9w0BAQsFADBjMQsw # CQYDVQQGEwJVUzEXMBUGA1UEChMORGlnaUNlcnQsIEluYy4xOzA5BgNVBAMTMkRp # Z2lDZXJ0IFRydXN0ZWQgRzQgUlNBNDA5NiBTSEEyNTYgVGltZVN0YW1waW5nIENB # MB4XDTIzMDcxNDAwMDAwMFoXDTM0MTAxMzIzNTk1OVowSDELMAkGA1UEBhMCVVMx # FzAVBgNVBAoTDkRpZ2lDZXJ0LCBJbmMuMSAwHgYDVQQDExdEaWdpQ2VydCBUaW1l # c3RhbXAgMjAyMzCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAKNTRYcd # g45brD5UsyPgz5/X5dLnXaEOCdwvSKOXejsqnGfcYhVYwamTEafNqrJq3RApih5i # Y2nTWJw1cb86l+uUUI8cIOrHmjsvlmbjaedp/lvD1isgHMGXlLSlUIHyz8sHpjBo # yoNC2vx/CSSUpIIa2mq62DvKXd4ZGIX7ReoNYWyd/nFexAaaPPDFLnkPG2ZS48jW # Pl/aQ9OE9dDH9kgtXkV1lnX+3RChG4PBuOZSlbVH13gpOWvgeFmX40QrStWVzu8I # F+qCZE3/I+PKhu60pCFkcOvV5aDaY7Mu6QXuqvYk9R28mxyyt1/f8O52fTGZZUdV # nUokL6wrl76f5P17cz4y7lI0+9S769SgLDSb495uZBkHNwGRDxy1Uc2qTGaDiGhi # u7xBG3gZbeTZD+BYQfvYsSzhUa+0rRUGFOpiCBPTaR58ZE2dD9/O0V6MqqtQFcmz # yrzXxDtoRKOlO0L9c33u3Qr/eTQQfqZcClhMAD6FaXXHg2TWdc2PEnZWpST618Rr # IbroHzSYLzrqawGw9/sqhux7UjipmAmhcbJsca8+uG+W1eEQE/5hRwqM/vC2x9XH # 3mwk8L9CgsqgcT2ckpMEtGlwJw1Pt7U20clfCKRwo+wK8REuZODLIivK8SgTIUlR # fgZm0zu++uuRONhRB8qUt+JQofM604qDy0B7AgMBAAGjggGLMIIBhzAOBgNVHQ8B # Af8EBAMCB4AwDAYDVR0TAQH/BAIwADAWBgNVHSUBAf8EDDAKBggrBgEFBQcDCDAg # BgNVHSAEGTAXMAgGBmeBDAEEAjALBglghkgBhv1sBwEwHwYDVR0jBBgwFoAUuhbZ # bU2FL3MpdpovdYxqII+eyG8wHQYDVR0OBBYEFKW27xPn783QZKHVVqllMaPe1eNJ # MFoGA1UdHwRTMFEwT6BNoEuGSWh0dHA6Ly9jcmwzLmRpZ2ljZXJ0LmNvbS9EaWdp # Q2VydFRydXN0ZWRHNFJTQTQwOTZTSEEyNTZUaW1lU3RhbXBpbmdDQS5jcmwwgZAG # CCsGAQUFBwEBBIGDMIGAMCQGCCsGAQUFBzABhhhodHRwOi8vb2NzcC5kaWdpY2Vy # dC5jb20wWAYIKwYBBQUHMAKGTGh0dHA6Ly9jYWNlcnRzLmRpZ2ljZXJ0LmNvbS9E # aWdpQ2VydFRydXN0ZWRHNFJTQTQwOTZTSEEyNTZUaW1lU3RhbXBpbmdDQS5jcnQw # DQYJKoZIhvcNAQELBQADggIBAIEa1t6gqbWYF7xwjU+KPGic2CX/yyzkzepdIpLs # jCICqbjPgKjZ5+PF7SaCinEvGN1Ott5s1+FgnCvt7T1IjrhrunxdvcJhN2hJd6Pr # kKoS1yeF844ektrCQDifXcigLiV4JZ0qBXqEKZi2V3mP2yZWK7Dzp703DNiYdk9W # uVLCtp04qYHnbUFcjGnRuSvExnvPnPp44pMadqJpddNQ5EQSviANnqlE0PjlSXcI # WiHFtM+YlRpUurm8wWkZus8W8oM3NG6wQSbd3lqXTzON1I13fXVFoaVYJmoDRd7Z # ULVQjK9WvUzF4UbFKNOt50MAcN7MmJ4ZiQPq1JE3701S88lgIcRWR+3aEUuMMsOI # 5ljitts++V+wQtaP4xeR0arAVeOGv6wnLEHQmjNKqDbUuXKWfpd5OEhfysLcPTLf # ddY2Z1qJ+Panx+VPNTwAvb6cKmx5AdzaROY63jg7B145WPR8czFVoIARyxQMfq68 # /qTreWWqaNYiyjvrmoI1VygWy2nyMpqy0tg6uLFGhmu6F/3Ed2wVbK6rr3M66ElG # t9V/zLY4wNjsHPW2obhDLN9OTH0eaHDAdwrUAuBcYLso/zjlUlrWrBciI0707NMX # +1Br/wd3H3GXREHJuEbTbDJ8WC9nR2XlG3O2mflrLAZG70Ee8PBf4NvZrZCARK+A # EEGKMYIGVzCCBlMCAQEwfTBpMQswCQYDVQQGEwJVUzEXMBUGA1UEChMORGlnaUNl # cnQsIEluYy4xQTA/BgNVBAMTOERpZ2lDZXJ0IFRydXN0ZWQgRzQgQ29kZSBTaWdu # aW5nIFJTQTQwOTYgU0hBMzg0IDIwMjEgQ0ExAhAEskBM6tH3agmQID1jirpbMA0G # CWCGSAFlAwQCAQUAoIGIMBkGCSqGSIb3DQEJAzEMBgorBgEEAYI3AgEEMBwGCSqG # SIb3DQEJBTEPFw0yNDA4MDgxNTUwMDJaMBwGCisGAQQBgjcCAQsxDjAMBgorBgEE # AYI3AgEVMC8GCSqGSIb3DQEJBDEiBCA8bNjTlByTTjFnnj3SeleqMiL1reGMShIx # 8Ts8swPMszANBgkqhkiG9w0BAQEFAASCAgAnYBSrX7k9h/TvZ7kDQB3nnkGFrvms # dGgyEz1MdU7BwGMXF1i9XMh6lvWceEYzX7f8v7ifOc2If3MvwGPstxx6KctHulF6 # tum0a7SzGWG5qexrC24HnVdN3Tdqrgnac7j7mB1rjLJtRt3Gz/kD6yS1Dj8Te9wH # 5NVf9IbcTJ35oB9bFAsPlUq+Kl4RCBMgT0Frc+YX4yxxlL9T8/Sq2ByoBYfOyk6p # jRYLU0riKu5YCgQIDVpCM4KZkyvhjIaebAw/CXna8g82G+wzYq+uda/L8YZxsKwz # 4/Vk0WMMMQmFB6HGYMKjemjiDeveRA/8R79666nxCqfwMX66ZIu8q5SrM3Ue4tzH # DjxxuYdrXUVJ+agqY5PtI5L2BZPmjSbtAjXmIPlgJ5Ixf0loBjfxhsnN87thtY24 # fXYvXZGfOOyKZIyfR2ejT5B/BxbvetS5YZZQWSFjeo1uPS75FAGYZn5U6UhnnPDR # O4Y2jg15YsUZiWsZRgOIA7PI+OXBmERB64bs7gIpwclV5l5qfvn/SKmizFjz7/H1 # jalgtoeYCaGPSPESDamVma31sqgq3pspvbR9jUCanSV4iVxcnyhZC0psCfidai4m # kynTGCe9m0ERcVWw6htAKhThhm8AsauoNPwzO3OGaYjNq6xB2aXfhEOd+/KivF7V # EQI1ohIxd9CPnKGCAyAwggMcBgkqhkiG9w0BCQYxggMNMIIDCQIBATB3MGMxCzAJ # BgNVBAYTAlVTMRcwFQYDVQQKEw5EaWdpQ2VydCwgSW5jLjE7MDkGA1UEAxMyRGln # aUNlcnQgVHJ1c3RlZCBHNCBSU0E0MDk2IFNIQTI1NiBUaW1lU3RhbXBpbmcgQ0EC # EAVEr/OUnQg5pr/bP1/lYRYwDQYJYIZIAWUDBAIBBQCgaTAYBgkqhkiG9w0BCQMx # CwYJKoZIhvcNAQcBMBwGCSqGSIb3DQEJBTEPFw0yNDA4MDgxNTUwMDNaMC8GCSqG # SIb3DQEJBDEiBCCmf/5GKOnjgrzqL6JFUFaDVBg0am4Z0IYI/7i7MAsb0TANBgkq # hkiG9w0BAQEFAASCAgBQv4LuLUUN12vRvBSBNUJXV4k6dhUoWCVE1HWbapnIyMmQ # vUfqbPgiFviveg9BPZTdzNs3lG0JgI3gxEtNcF849rr17W+OZ4crJCcct6N7wp5x # DY8NMDpgr68egrFPtWGsW7icqRPiuE+x8ehTugd1JefaPhiU2QZeou5zg9qXdlFF # wQBjDJtgrXZ08Enl5Bvu1FVMzkPnJrGcHmNRmx+PrV9AvcIl4PYw5XgmqOX4kT6H # NZ+56vnj2zCyT2Ra3idbp/rv8sUn7F0ON8U8PDoReffqgp8Zcm+Z2oLABlEaGcoa # HCV+arCwHyW7c9Hubl0RyafZH97y5OR1WWe6zULSZOoS4fRDNjhr/eYfID/+h5nH # q9wEl7aaRKDj2c/c5oqLxErPpxfxeeEqxVaICa331Idgy0ZqqWFM7/tlsJxGZ0+G # XFeJxX99xxOWPBNwAzcovd2+ZPPeKNB0vVYYxrZKIU/VjTjAY4Az6BWHwDX6rc2H # D/7249cpnh67M5vpVl/FM0APBBbsqa+ZNeu4oYJCXEpaw41Iw/Zjs9Ie0N26QYzO # dD5YWePp1vgZh5XWqgP7LTM7KDPATltDAAhiSc3oxguSs1JsKAVsILQYer0JP22x # Vk49oLKJtie3xBgH7A5Cf3ie46HZEmCNQKSjYlmD24stJQldRXvdvXsG8RMMnA== # SIG # End signature block |