Public/NerdctlTools.psm1
########################################################################### # # # Copyright (c) Microsoft Corporation. All rights reserved. # # # # This code is licensed under the MIT License (MIT). # # # ########################################################################### using module "..\Private\CommonToolUtilities.psm1" $ModuleParentPath = Split-Path -Parent $PSScriptRoot Import-Module -Name "$ModuleParentPath\Private\CommonToolUtilities.psm1" -Force function Get-NerdctlLatestVersion { $latestVersion = Get-LatestToolVersion -Tool "nerdctl" return $latestVersion } function Get-NerdctlDependencies($dependencies) { if (!$dependencies) { return } $nerdctlDependencies = @("Containerd", "Buildkit", "WinCNIPlugin") if ($Dependencies -and $Dependencies -contains "All") { $dependencies = $nerdctlDependencies } foreach ($dependency in $dependencies) { if (-not ($nerdctlDependencies -contains $dependency)) { Throw "Invalid dependency option: $dependency. Allowed options: All, Containerd, Buildkit, WinCNIPlugin" } } return $dependencies } function Install-NerdctlDependencies { param( [String[]]$Dependencies, [string]$OsArch, [Switch]$Force ) foreach ($dependency in $Dependencies) { $InstallCommand = "Install-$dependency" try { & $InstallCommand -OSArchitecture $OsArch -Force:$Force -Confirm:$false } catch { Write-Error "Installation failed for $dependency. $_" } } } function Install-Nerdctl { [CmdletBinding( SupportsShouldProcess = $true, ConfirmImpact = 'High' )] param( [string] [parameter(HelpMessage = "nerdctl version to use. Defaults to 'latest'")] $Version = "latest", [String] [parameter(HelpMessage = "Path to install nerdctl. Defaults to ~\program files\nerdctl")] $InstallPath = "$Env:ProgramFiles\nerdctl", [String] [parameter(HelpMessage = "Path to download files. Defaults to user's Downloads folder")] $DownloadPath = "$HOME\Downloads", [String[]] [parameter(HelpMessage = "Specify nerdctl dependencies (All, Containerd, Buildkit, WinCNIPlugin) to install")] $Dependencies, [string] [Parameter(HelpMessage = 'OS architecture to download files for. Default is $env:PROCESSOR_ARCHITECTURE')] [ValidateSet('amd64', '386', "arm", "arm64")] $OSArchitecture = $env:PROCESSOR_ARCHITECTURE, [Switch] [parameter(HelpMessage = "Installs nerdctl (and its dependencies if specified) even if the tool already exists at the specified path")] $Force ) begin { # Check if nerdctl is already installed $isInstalled = -not (Test-EmptyDirectory -Path $InstallPath) $toInstall = @("nerdctl") $dependencies = Get-NerdctlDependencies -Dependencies $dependencies if ($dependencies) { $toInstall += $dependencies } $WhatIfMessage = "nerdctl will be installed at $installPath" if ($isInstalled) { $WhatIfMessage = "nerdctl will be uninstalled and reinstalled at $InstallPath" } if ($dependencies) { $WhatIfMessage = "nerdctl and its dependencies (Containerd, Buildkit, WinCNIPlugin) will be installed" } } process { if ($PSCmdlet.ShouldProcess($env:COMPUTERNAME, $WhatIfMessage)) { # Check if nerdctl already exists at specified location if ($isInstalled) { $errMsg = "nerdctl already exists at $InstallPath or the directory is not empty" Write-Warning $errMsg # Uninstall if tool exists at specified location. Requires user consent try { Uninstall-Nerdctl -Path "$InstallPath" -Confirm:$false -Force:$Force | Out-Null } catch { Throw "nerdctl installation failed. $_" } } # Get nerdctl version to install if not specified if (!$Version) { $Version = Get-NerdctlLatestVersion } $Version = $Version.TrimStart('v') Write-Output "Downloading and installing nerdctl v$Version at $InstallPath" # Download files $downloadParams = @{ ToolName = "nerdctl" Repository = "$NERDCTL_REPO" Version = $Version OSArchitecture = $OSArchitecture DownloadPath = $DownloadPath ChecksumSchemaFile = $null FileFilterRegEx = $null } $downloadParamsProperties = [FileDownloadParameters]::new( $downloadParams.ToolName, $downloadParams.Repository, $downloadParams.Version, $downloadParams.OSArchitecture, $downloadParams.DownloadPath, $downloadParams.ChecksumSchemaFile, $downloadParams.FileFilterRegEx ) $sourceFile = Get-InstallationFile -FileParameters $downloadParamsProperties # Untar and install tool $params = @{ Feature = "nerdctl" InstallPath = $InstallPath SourceFile = $sourceFile EnvPath = $InstallPath cleanup = $true } Install-RequiredFeature @params Write-Output "nerdctl v$version successfully installed at $InstallPath" Write-Output "For nerdctl usage: run 'nerdctl -h'`n" # Install dependencies Write-Output "Installing nerdctl dependencies: $toinstall" Install-NerdctlDependencies -Dependencies $dependencies -OsArch $OSArchitecture -Force:$true } else { # Code that should be processed if doing a WhatIf operation # Must NOT change anything outside of the function / script return } } } # TODO: Implement this function Initialize-NerdctlToml { param( [parameter(HelpMessage = "Toml path. Defaults to ~\AppData\nerdctl\nerdctl.toml")] [String]$Path = "$env:APPDATA\nerdctl\nerdctl.toml" ) # https://github.com/containerd/nerdctl/blob/main/docs/config.md $nerdctlConfig = @" {} "@ $nerdctlConfig | Set-Content $Path -Force } function Uninstall-Nerdctl { [CmdletBinding( SupportsShouldProcess = $true, ConfirmImpact = 'High' )] param( [parameter(HelpMessage = "nerdctl path")] [String]$Path, [parameter(HelpMessage = "Bypass confirmation to uninstall nerdctl")] [Switch] $Force ) begin { $tool = 'nerdctl' if (!$Path) { $Path = Get-DefaultInstallPath -Tool "nerdctl" } $WhatIfMessage = "nerdctl will be uninstalled from $Path" } process { if ($PSCmdlet.ShouldProcess($env:COMPUTERNAME, $WhatIfMessage)) { if (Test-EmptyDirectory -Path $path) { Write-Output "$tool does not exist at $Path or the directory is empty" return } $consent = $force if (!$ENV:PESTER) { $consent = $force -or $PSCmdlet.ShouldContinue($Path, 'Are you sure you want to uninstall nerdctl?') } if (!$consent) { Throw "$tool uninstallation cancelled." } Write-Warning "Uninstalling preinstalled $tool at the path $path" try { Uninstall-NerdctlHelper -Path $path } catch { Throw "Could not uninstall $tool. $_" } } else { # Code that should be processed if doing a WhatIf operation # Must NOT change anything outside of the function / script return } } } function Uninstall-NerdctlHelper { param( [ValidateNotNullOrEmpty()] [parameter(Mandatory = $true, HelpMessage = "nerdctl path")] [String]$Path ) if (Test-EmptyDirectory -Path $Path) { Write-Error "nerdctl does not exist at $Path or the directory is empty." return } # Remove the folder where nerdctl is installed and related folders Remove-Item -Path $Path -Recurse -Force # Remove ProgramData files Uninstall-ProgramFiles "$ENV:ProgramData\nerdctl" # Remove from env path Remove-FeatureFromPath -Feature "nerdctl" Write-Output "Successfully uninstalled nerdctl." } Export-ModuleMember -Function Get-NerdctlLatestVersion Export-ModuleMember -Function Install-Nerdctl Export-ModuleMember -Function Uninstall-Nerdctl Export-ModuleMember -Function Uninstall-NerdctlHelper Export-ModuleMember -Function Install-NerdctlDependencies # SIG # Begin signature block # MIIoRAYJKoZIhvcNAQcCoIIoNTCCKDECAQExDzANBglghkgBZQMEAgEFADB5Bgor # BgEEAYI3AgEEoGswaTA0BgorBgEEAYI3AgEeMCYCAwEAAAQQH8w7YFlLCE63JNLG # KX7zUQIBAAIBAAIBAAIBAAIBADAxMA0GCWCGSAFlAwQCAQUABCAoMYsz4eNT+3qc # /Q/DJY08mR+ImUp3e6a+KVTpod+yqaCCDYswggYJMIID8aADAgECAhMzAAAD9LjE # XeFOcLZ+AAAAAAP0MA0GCSqGSIb3DQEBCwUAMH4xCzAJBgNVBAYTAlVTMRMwEQYD # VQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNy # b3NvZnQgQ29ycG9yYXRpb24xKDAmBgNVBAMTH01pY3Jvc29mdCBDb2RlIFNpZ25p # bmcgUENBIDIwMTEwHhcNMjQwNzE3MjEwMjM1WhcNMjUwOTE1MjEwMjM1WjCBiDEL # MAkGA1UEBhMCVVMxEzARBgNVBAgTCldhc2hpbmd0b24xEDAOBgNVBAcTB1JlZG1v # bmQxHjAcBgNVBAoTFU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjEyMDAGA1UEAxMpTWlj # cm9zb2Z0IDNyZCBQYXJ0eSBBcHBsaWNhdGlvbiBDb21wb25lbnQwggEiMA0GCSqG # SIb3DQEBAQUAA4IBDwAwggEKAoIBAQCv3P8bL08GKolFW7QNDVOF0aM4iqMxVvAW # VM124/82xbjAraJkKxieMrQa1Fc95LVGgxmJIi5R6QKMz2MO9bnwC7kSkPqoZJil # 26bRLY6jinjbwPpK3TzbW7z9bXfWw5bPFlt72NVIdXJ3xtHoYa+AOi++CF2Ry7+7 # o1AzvotJwG6lQSiCMKeMt8apqEF1f+QkDFEUv5tezw9748DeHW9orvo4IPzWa7vW # QgljB08LKSnzTN9/Jot2coWpFv4YuEoJZmR2ofPJMnDUUruDORTXnxwhfvd/wUmI # SoEysSqobkNV+qFuUmSShYrx8R1zHm7P6G/iRMIKYmSrIYBKUvndAgMBAAGjggFz # MIIBbzAfBgNVHSUEGDAWBgorBgEEAYI3TBEBBggrBgEFBQcDAzAdBgNVHQ4EFgQU # Dz4uMjS8YCSZaU0449GJYQ1ufyowRQYDVR0RBD4wPKQ6MDgxHjAcBgNVBAsTFU1p # Y3Jvc29mdCBDb3Jwb3JhdGlvbjEWMBQGA1UEBRMNMjMxNTIyKzUwMjUxODAfBgNV # HSMEGDAWgBRIbmTlUAXTgqoXNzcitW2oynUClTBUBgNVHR8ETTBLMEmgR6BFhkNo # dHRwOi8vd3d3Lm1pY3Jvc29mdC5jb20vcGtpb3BzL2NybC9NaWNDb2RTaWdQQ0Ey # MDExXzIwMTEtMDctMDguY3JsMGEGCCsGAQUFBwEBBFUwUzBRBggrBgEFBQcwAoZF # aHR0cDovL3d3dy5taWNyb3NvZnQuY29tL3BraW9wcy9jZXJ0cy9NaWNDb2RTaWdQ # Q0EyMDExXzIwMTEtMDctMDguY3J0MAwGA1UdEwEB/wQCMAAwDQYJKoZIhvcNAQEL # BQADggIBABUCAiEn4g8i5T3VCP8160IY4ERdvZi5QZ2pSnBPW1dswVhLxkNTiCTV # XKDjTQ4EwDBNSZZGJePz4+t86pKhlBON3S7wswf5fCovJLlIiKbw+E4TZeY6xAxd # +5zV7Q2lsQhPHxiOY0PIGUE0KJfv/DQUulD8DrE0rru7yOO+DJI0muoK0BbHhRfd # mAJhp2gbYRkarEIkhML9m3gR12mCBb69Vocm4IyOBivUPMjjvQMkERF7cR07k2uP # 6dmpR8wtof9la0/K0wgiP5XuQUsAqgzhXrljH7dK7nqGrBDjJtrRdYfvVL+Rcz9i # YZO280g2uNtac5em3HOEsactAL7XKqZ4o7s9sRyp/bTNLLRmhFMB729IL+Hi0YM7 # C8th3HZ5nP+77L46KUGip6QgRIJs+EO0YNW+AwgMxPfKpTx/Ggh8Z85kP7HLDZJk # ZdPO/3cgVOTO4ax21vO2yMPCdfoGGr2ZLZw4SjEbGuOZJ22iGMV7tBvHk8nWAt3q # +j/icAq99GA1nIPnw3jK3K9OwGqwA9eiWsO8/bHMm6s50UKIFupMKm6qObosaVBy # R58rf8Cxumka7hPy1eSJSzQyA4UqYNTWuChsTfqgRLmLomS6yAu7t4r/bM4mGl+2 # Ki+avhQ4COm3jWWd0V6UGIP3T4zaKNs2GWFBIYsb/6XVvvi7pz/JMIIHejCCBWKg # AwIBAgIKYQ6Q0gAAAAAAAzANBgkqhkiG9w0BAQsFADCBiDELMAkGA1UEBhMCVVMx # EzARBgNVBAgTCldhc2hpbmd0b24xEDAOBgNVBAcTB1JlZG1vbmQxHjAcBgNVBAoT # FU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjEyMDAGA1UEAxMpTWljcm9zb2Z0IFJvb3Qg # Q2VydGlmaWNhdGUgQXV0aG9yaXR5IDIwMTEwHhcNMTEwNzA4MjA1OTA5WhcNMjYw # NzA4MjEwOTA5WjB+MQswCQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQ # MA4GA1UEBxMHUmVkbW9uZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9u # MSgwJgYDVQQDEx9NaWNyb3NvZnQgQ29kZSBTaWduaW5nIFBDQSAyMDExMIICIjAN # BgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAq/D6chAcLq3YbqqCEE00uvK2WCGf # Qhsqa+laUKq4BjgaBEm6f8MMHt03a8YS2AvwOMKZBrDIOdUBFDFC04kNeWSHfpRg # JGyvnkmc6Whe0t+bU7IKLMOv2akrrnoJr9eWWcpgGgXpZnboMlImEi/nqwhQz7NE # t13YxC4Ddato88tt8zpcoRb0RrrgOGSsbmQ1eKagYw8t00CT+OPeBw3VXHmlSSnn # Db6gE3e+lD3v++MrWhAfTVYoonpy4BI6t0le2O3tQ5GD2Xuye4Yb2T6xjF3oiU+E # GvKhL1nkkDstrjNYxbc+/jLTswM9sbKvkjh+0p2ALPVOVpEhNSXDOW5kf1O6nA+t # GSOEy/S6A4aN91/w0FK/jJSHvMAhdCVfGCi2zCcoOCWYOUo2z3yxkq4cI6epZuxh # H2rhKEmdX4jiJV3TIUs+UsS1Vz8kA/DRelsv1SPjcF0PUUZ3s/gA4bysAoJf28AV # s70b1FVL5zmhD+kjSbwYuER8ReTBw3J64HLnJN+/RpnF78IcV9uDjexNSTCnq47f # 7Fufr/zdsGbiwZeBe+3W7UvnSSmnEyimp31ngOaKYnhfsi+E11ecXL93KCjx7W3D # KI8sj0A3T8HhhUSJxAlMxdSlQy90lfdu+HggWCwTXWCVmj5PM4TasIgX3p5O9Jaw # vEagbJjS4NaIjAsCAwEAAaOCAe0wggHpMBAGCSsGAQQBgjcVAQQDAgEAMB0GA1Ud # DgQWBBRIbmTlUAXTgqoXNzcitW2oynUClTAZBgkrBgEEAYI3FAIEDB4KAFMAdQBi # AEMAQTALBgNVHQ8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAfBgNVHSMEGDAWgBRy # LToCMZBDuRQFTuHqp8cx0SOJNDBaBgNVHR8EUzBRME+gTaBLhklodHRwOi8vY3Js # Lm1pY3Jvc29mdC5jb20vcGtpL2NybC9wcm9kdWN0cy9NaWNSb29DZXJBdXQyMDEx # XzIwMTFfMDNfMjIuY3JsMF4GCCsGAQUFBwEBBFIwUDBOBggrBgEFBQcwAoZCaHR0 # cDovL3d3dy5taWNyb3NvZnQuY29tL3BraS9jZXJ0cy9NaWNSb29DZXJBdXQyMDEx # XzIwMTFfMDNfMjIuY3J0MIGfBgNVHSAEgZcwgZQwgZEGCSsGAQQBgjcuAzCBgzA/ # BggrBgEFBQcCARYzaHR0cDovL3d3dy5taWNyb3NvZnQuY29tL3BraW9wcy9kb2Nz # L3ByaW1hcnljcHMuaHRtMEAGCCsGAQUFBwICMDQeMiAdAEwAZQBnAGEAbABfAHAA # bwBsAGkAYwB5AF8AcwB0AGEAdABlAG0AZQBuAHQALiAdMA0GCSqGSIb3DQEBCwUA # A4ICAQBn8oalmOBUeRou09h0ZyKbC5YR4WOSmUKWfdJ5DJDBZV8uLD74w3LRbYP+ # vj/oCso7v0epo/Np22O/IjWll11lhJB9i0ZQVdgMknzSGksc8zxCi1LQsP1r4z4H # Limb5j0bpdS1HXeUOeLpZMlEPXh6I/MTfaaQdION9MsmAkYqwooQu6SpBQyb7Wj6 # aC6VoCo/KmtYSWMfCWluWpiW5IP0wI/zRive/DvQvTXvbiWu5a8n7dDd8w6vmSiX # mE0OPQvyCInWH8MyGOLwxS3OW560STkKxgrCxq2u5bLZ2xWIUUVYODJxJxp/sfQn # +N4sOiBpmLJZiWhub6e3dMNABQamASooPoI/E01mC8CzTfXhj38cbxV9Rad25UAq # ZaPDXVJihsMdYzaXht/a8/jyFqGaJ+HNpZfQ7l1jQeNbB5yHPgZ3BtEGsXUfFL5h # YbXw3MYbBL7fQccOKO7eZS/sl/ahXJbYANahRr1Z85elCUtIEJmAH9AAKcWxm6U/ # RXceNcbSoqKfenoi+kiVH6v7RyOA9Z74v2u3S5fi63V4GuzqN5l5GEv/1rMjaHXm # r/r8i+sLgOppO6/8MO0ETI7f33VtY5E90Z1WTk+/gFcioXgRMiF670EKsT/7qMyk # XcGhiJtXcVZOSEXAQsmbdlsKgEhr/Xmfwb1tbWrJUnMTDXpQzTGCGg8wghoLAgEB # MIGVMH4xCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQH # EwdSZWRtb25kMR4wHAYDVQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xKDAmBgNV # BAMTH01pY3Jvc29mdCBDb2RlIFNpZ25pbmcgUENBIDIwMTECEzMAAAP0uMRd4U5w # tn4AAAAAA/QwDQYJYIZIAWUDBAIBBQCggbAwGQYJKoZIhvcNAQkDMQwGCisGAQQB # gjcCAQQwHAYKKwYBBAGCNwIBCzEOMAwGCisGAQQBgjcCARUwLwYJKoZIhvcNAQkE # MSIEIAisBHhgKWN+uZ2aYgfctU6t0lp9fbD/QwQVbbPPkh2qMEQGCisGAQQBgjcC # AQwxNjA0oBSAEgBNAGkAYwByAG8AcwBvAGYAdKEcgBpodHRwczovL3d3dy5taWNy # b3NvZnQuY29tIDANBgkqhkiG9w0BAQEFAASCAQAKVhjAhc4lTYUCE9pZbOLYaoXW # TX7sKGks7cwEgEI+Kj2YdAIMYq8M06jRFggelBHGp0KMtBGMCUbl+YrUSfiWJ+l4 # PvvtwTq+edbn3EZR9h6Ca7RjTdKcie7GAV9ddJTZ9W4PgA3Jh0jO/QVlwFeYGfEQ # +OcpnbN6Kls3FL3vB76cjNjFljP64e7TwgbBtLmcJ0BRO1vvv3P3Dkwo/wEmUwFL # p4b4vH+6iRraEBBnsEWWPlITe/KV+vOHzexTmik/IOie3W44wjseK2ijokcKv4Bh # Fnmo8Pw64vTrVHunvI8c9z+xLA7qD3S7knWU/X2mVJzosdFw/Qk4dxAEAQdRoYIX # lzCCF5MGCisGAQQBgjcDAwExgheDMIIXfwYJKoZIhvcNAQcCoIIXcDCCF2wCAQMx # DzANBglghkgBZQMEAgEFADCCAVIGCyqGSIb3DQEJEAEEoIIBQQSCAT0wggE5AgEB # BgorBgEEAYRZCgMBMDEwDQYJYIZIAWUDBAIBBQAEIHz5FASWBY0ywFNzLt5XoX07 # /3K/DxPBLN6K9SR2ObRnAgZoJdLn01EYEzIwMjUwNTE1MTYxOTUyLjY1MVowBIAC # AfSggdGkgc4wgcsxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpXYXNoaW5ndG9uMRAw # DgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24x # JTAjBgNVBAsTHE1pY3Jvc29mdCBBbWVyaWNhIE9wZXJhdGlvbnMxJzAlBgNVBAsT # Hm5TaGllbGQgVFNTIEVTTjpBNDAwLTA1RTAtRDk0NzElMCMGA1UEAxMcTWljcm9z # b2Z0IFRpbWUtU3RhbXAgU2VydmljZaCCEe0wggcgMIIFCKADAgECAhMzAAACAnlQ # dCEUfbihAAEAAAICMA0GCSqGSIb3DQEBCwUAMHwxCzAJBgNVBAYTAlVTMRMwEQYD # VQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNy # b3NvZnQgQ29ycG9yYXRpb24xJjAkBgNVBAMTHU1pY3Jvc29mdCBUaW1lLVN0YW1w # IFBDQSAyMDEwMB4XDTI1MDEzMDE5NDI0NFoXDTI2MDQyMjE5NDI0NFowgcsxCzAJ # BgNVBAYTAlVTMRMwEQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25k # MR4wHAYDVQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xJTAjBgNVBAsTHE1pY3Jv # c29mdCBBbWVyaWNhIE9wZXJhdGlvbnMxJzAlBgNVBAsTHm5TaGllbGQgVFNTIEVT # TjpBNDAwLTA1RTAtRDk0NzElMCMGA1UEAxMcTWljcm9zb2Z0IFRpbWUtU3RhbXAg # U2VydmljZTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBALd5Knpy5xQY # 6Rw+Di8pYol8RB6yErZkGxhTW0Na9C7ov2Wn52eqtqMh014fUc3ejPeKIagla43Y # dU1mRw63fxpYZ5szSBRQ60+O4uG47l3rtilCwcEkBaFy978xV2hA+PWeOICNKI6s # vzEVqsUsjjpEfw14OEA9dwmlafsAjMLIiNk5onYNYD7pDA3PCqMGAil/WFYXCoe8 # 8R53LSei1du1Z9P28JIv2x0Mror8cf0expjnAuZRQHtJ+4sajU5YSbownIbaOLGq # L03JGjKl0Xx1HKNbEpGXYnHC9t62UNOKjrpeWJM5ySrZGAz5mhxkRvoSg5213Rcq # HcvPHb0CEfGWT7p4jBq+Udi44tkMqh085U3qPUgn1uuiVjqZluhDnU6p7mcQzmH9 # YlfbwYtmKgSQk3yo57k/k/ZjH0eg6ou6BfTSoLPGrgEObzEfzkcrG8oI7kqKSilp # EYa1CVeMPK6wxaWsdzJK3noOEvh1xWeft0W8vnTO9CUVkyFWh6FZJCSRa5SUIKog # 6tN7tFuadt0miwf7uUL6fneCcrLg6hnO5R6rMKdIHUk1c8qcmiM/cN7nHCymLm1S # 9AU1+V8ZOyNmBACAMF2D8M7RMaAtEMq9lAJnmoi5elBHKDfvJznV73nPxTabKxTR # edKlZ6KAeqTI4C0N9wimrka/sdX51rZHAgMBAAGjggFJMIIBRTAdBgNVHQ4EFgQU # 2ga5tQ+M/Z/yJ+Qgq/DLWuVIdNkwHwYDVR0jBBgwFoAUn6cVXQBeYl2D9OXSZacb # UzUZ6XIwXwYDVR0fBFgwVjBUoFKgUIZOaHR0cDovL3d3dy5taWNyb3NvZnQuY29t # L3BraW9wcy9jcmwvTWljcm9zb2Z0JTIwVGltZS1TdGFtcCUyMFBDQSUyMDIwMTAo # MSkuY3JsMGwGCCsGAQUFBwEBBGAwXjBcBggrBgEFBQcwAoZQaHR0cDovL3d3dy5t # aWNyb3NvZnQuY29tL3BraW9wcy9jZXJ0cy9NaWNyb3NvZnQlMjBUaW1lLVN0YW1w # JTIwUENBJTIwMjAxMCgxKS5jcnQwDAYDVR0TAQH/BAIwADAWBgNVHSUBAf8EDDAK # BggrBgEFBQcDCDAOBgNVHQ8BAf8EBAMCB4AwDQYJKoZIhvcNAQELBQADggIBAIPz # doVBTE3fseQ6gkMzWZocVlVQZypNBw+c4PpShhEyYMq/QZpseUTzYBiAs+5WW6Sf # se0k8XbPSOdOAB9EyfbokUs8bs79dsorbmGsE8nfSUG7CMBNW3nxQDUFajuWyafK # u6v/qHwAXOtfKte2W/NBippFhj2TRQVjkYz6f1hoQQrYPbrx75r4cOZZ761gvYf7 # 07hDUxAtqD5yI3AuSP/5CXGleJai70q8A/S0iT58fwXfDDlU5OL1pn36o+OzPDfU # fid22K8FlofmzlugmYfYlu0y5/bLuFJ0l0TRRbYHQURk8siZ6aUqGyUk1WoQ7tE+ # CXtzzVC5VI7nx9+mZvC1LGFisRLdWw+CVef04MXsOqY8wb8bKwHij9CSk1Sr7BLt # s5FM3Oocy0f6it3ZhKZr7VvJYGv+LMgqCA4J0TNpkN/KbXYYzprhL4jLoBQinv8o # ikCZ9Z9etwwrtXsQHPGh7OQtEQRYjhe0/CkQGe05rWgMfdn/51HGzEvS+DJruM1+ # s7uiLNMCWf/ZkFgH2KhR6huPkAYvjmbaZwpKTscTnNRF5WQgulgoFDn5f/yMU7X+ # lnKrNB4jX+gn9EuiJzVKJ4td8RP0RZkgGNkxnzjqYNunXKcr1Rs2IKNLCZMXnT1i # f0zjtVCzGy/WiVC7nWtVUeRI2b6tOsvArW2+G/SZMIIHcTCCBVmgAwIBAgITMwAA # ABXF52ueAptJmQAAAAAAFTANBgkqhkiG9w0BAQsFADCBiDELMAkGA1UEBhMCVVMx # EzARBgNVBAgTCldhc2hpbmd0b24xEDAOBgNVBAcTB1JlZG1vbmQxHjAcBgNVBAoT # FU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjEyMDAGA1UEAxMpTWljcm9zb2Z0IFJvb3Qg # Q2VydGlmaWNhdGUgQXV0aG9yaXR5IDIwMTAwHhcNMjEwOTMwMTgyMjI1WhcNMzAw # OTMwMTgzMjI1WjB8MQswCQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQ # MA4GA1UEBxMHUmVkbW9uZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9u # MSYwJAYDVQQDEx1NaWNyb3NvZnQgVGltZS1TdGFtcCBQQ0EgMjAxMDCCAiIwDQYJ # KoZIhvcNAQEBBQADggIPADCCAgoCggIBAOThpkzntHIhC3miy9ckeb0O1YLT/e6c # BwfSqWxOdcjKNVf2AX9sSuDivbk+F2Az/1xPx2b3lVNxWuJ+Slr+uDZnhUYjDLWN # E893MsAQGOhgfWpSg0S3po5GawcU88V29YZQ3MFEyHFcUTE3oAo4bo3t1w/YJlN8 # OWECesSq/XJprx2rrPY2vjUmZNqYO7oaezOtgFt+jBAcnVL+tuhiJdxqD89d9P6O # U8/W7IVWTe/dvI2k45GPsjksUZzpcGkNyjYtcI4xyDUoveO0hyTD4MmPfrVUj9z6 # BVWYbWg7mka97aSueik3rMvrg0XnRm7KMtXAhjBcTyziYrLNueKNiOSWrAFKu75x # qRdbZ2De+JKRHh09/SDPc31BmkZ1zcRfNN0Sidb9pSB9fvzZnkXftnIv231fgLrb # qn427DZM9ituqBJR6L8FA6PRc6ZNN3SUHDSCD/AQ8rdHGO2n6Jl8P0zbr17C89XY # cz1DTsEzOUyOArxCaC4Q6oRRRuLRvWoYWmEBc8pnol7XKHYC4jMYctenIPDC+hIK # 12NvDMk2ZItboKaDIV1fMHSRlJTYuVD5C4lh8zYGNRiER9vcG9H9stQcxWv2XFJR # XRLbJbqvUAV6bMURHXLvjflSxIUXk8A8FdsaN8cIFRg/eKtFtvUeh17aj54WcmnG # rnu3tz5q4i6tAgMBAAGjggHdMIIB2TASBgkrBgEEAYI3FQEEBQIDAQABMCMGCSsG # AQQBgjcVAgQWBBQqp1L+ZMSavoKRPEY1Kc8Q/y8E7jAdBgNVHQ4EFgQUn6cVXQBe # Yl2D9OXSZacbUzUZ6XIwXAYDVR0gBFUwUzBRBgwrBgEEAYI3TIN9AQEwQTA/Bggr # BgEFBQcCARYzaHR0cDovL3d3dy5taWNyb3NvZnQuY29tL3BraW9wcy9Eb2NzL1Jl # cG9zaXRvcnkuaHRtMBMGA1UdJQQMMAoGCCsGAQUFBwMIMBkGCSsGAQQBgjcUAgQM # HgoAUwB1AGIAQwBBMAsGA1UdDwQEAwIBhjAPBgNVHRMBAf8EBTADAQH/MB8GA1Ud # IwQYMBaAFNX2VsuP6KJcYmjRPZSQW9fOmhjEMFYGA1UdHwRPME0wS6BJoEeGRWh0 # dHA6Ly9jcmwubWljcm9zb2Z0LmNvbS9wa2kvY3JsL3Byb2R1Y3RzL01pY1Jvb0Nl # ckF1dF8yMDEwLTA2LTIzLmNybDBaBggrBgEFBQcBAQROMEwwSgYIKwYBBQUHMAKG # Pmh0dHA6Ly93d3cubWljcm9zb2Z0LmNvbS9wa2kvY2VydHMvTWljUm9vQ2VyQXV0 # XzIwMTAtMDYtMjMuY3J0MA0GCSqGSIb3DQEBCwUAA4ICAQCdVX38Kq3hLB9nATEk # W+Geckv8qW/qXBS2Pk5HZHixBpOXPTEztTnXwnE2P9pkbHzQdTltuw8x5MKP+2zR # oZQYIu7pZmc6U03dmLq2HnjYNi6cqYJWAAOwBb6J6Gngugnue99qb74py27YP0h1 # AdkY3m2CDPVtI1TkeFN1JFe53Z/zjj3G82jfZfakVqr3lbYoVSfQJL1AoL8ZthIS # EV09J+BAljis9/kpicO8F7BUhUKz/AyeixmJ5/ALaoHCgRlCGVJ1ijbCHcNhcy4s # a3tuPywJeBTpkbKpW99Jo3QMvOyRgNI95ko+ZjtPu4b6MhrZlvSP9pEB9s7GdP32 # THJvEKt1MMU0sHrYUP4KWN1APMdUbZ1jdEgssU5HLcEUBHG/ZPkkvnNtyo4JvbMB # V0lUZNlz138eW0QBjloZkWsNn6Qo3GcZKCS6OEuabvshVGtqRRFHqfG3rsjoiV5P # ndLQTHa1V1QJsWkBRH58oWFsc/4Ku+xBZj1p/cvBQUl+fpO+y/g75LcVv7TOPqUx # UYS8vwLBgqJ7Fx0ViY1w/ue10CgaiQuPNtq6TPmb/wrpNPgkNWcr4A245oyZ1uEi # 6vAnQj0llOZ0dFtq0Z4+7X6gMTN9vMvpe784cETRkPHIqzqKOghif9lwY1NNje6C # baUFEMFxBmoQtB1VM1izoXBm8qGCA1AwggI4AgEBMIH5oYHRpIHOMIHLMQswCQYD # VQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9uZDEe # MBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMSUwIwYDVQQLExxNaWNyb3Nv # ZnQgQW1lcmljYSBPcGVyYXRpb25zMScwJQYDVQQLEx5uU2hpZWxkIFRTUyBFU046 # QTQwMC0wNUUwLUQ5NDcxJTAjBgNVBAMTHE1pY3Jvc29mdCBUaW1lLVN0YW1wIFNl # cnZpY2WiIwoBATAHBgUrDgMCGgMVAEmJSGkJYD/df+NnIjLTJ7pEnAvOoIGDMIGA # pH4wfDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCldhc2hpbmd0b24xEDAOBgNVBAcT # B1JlZG1vbmQxHjAcBgNVBAoTFU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjEmMCQGA1UE # AxMdTWljcm9zb2Z0IFRpbWUtU3RhbXAgUENBIDIwMTAwDQYJKoZIhvcNAQELBQAC # BQDr0FFkMCIYDzIwMjUwNTE1MTE0MTI0WhgPMjAyNTA1MTYxMTQxMjRaMHcwPQYK # KwYBBAGEWQoEATEvMC0wCgIFAOvQUWQCAQAwCgIBAAICAIwCAf8wBwIBAAICEfYw # CgIFAOvRouQCAQAwNgYKKwYBBAGEWQoEAjEoMCYwDAYKKwYBBAGEWQoDAqAKMAgC # AQACAwehIKEKMAgCAQACAwGGoDANBgkqhkiG9w0BAQsFAAOCAQEAqqUjDKJUQO5S # 5oWMRobJDrdADBYfc7j4mRkYrEUPK4jrYzGKExolvKc4XPg4FTbNNC26hewAakPw # Yzv/W7lVUvT9bC/SDlDbHIBlJ8fn5W9xERKAGJW/RsAO419HsXOWuRUHfPDKxRXk # 3keFzUKCWZ/W5lvKPbcuWsOBEgeRopyjtt5WL8HJrI7utXSEMRg5EF4rza6a+mmK # 5o93iGgHcfSdYw6JxD6/BIwyu7Ym0wGrlfTGjC7b3lVvnD2ToFSmLdZdpJtg4AtH # PF/IEvV0O8gIFtuncGwmu844MkSqa17rc80SsUDnYDOOdyhkBJwAW26ikitsppQr # 3ny6MonygTGCBA0wggQJAgEBMIGTMHwxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpX # YXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNyb3NvZnQg # Q29ycG9yYXRpb24xJjAkBgNVBAMTHU1pY3Jvc29mdCBUaW1lLVN0YW1wIFBDQSAy # MDEwAhMzAAACAnlQdCEUfbihAAEAAAICMA0GCWCGSAFlAwQCAQUAoIIBSjAaBgkq # hkiG9w0BCQMxDQYLKoZIhvcNAQkQAQQwLwYJKoZIhvcNAQkEMSIEICGSjw9zFp25 # yZ1oFiPC5wl5t/FOkwjAvND8ww1IhQv3MIH6BgsqhkiG9w0BCRACLzGB6jCB5zCB # 5DCBvQQg843qARgHlsvNcta5SYvxl3zFcCypeSx50XKiV8yUX+wwgZgwgYCkfjB8 # MQswCQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVk # bW9uZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMSYwJAYDVQQDEx1N # aWNyb3NvZnQgVGltZS1TdGFtcCBQQ0EgMjAxMAITMwAAAgJ5UHQhFH24oQABAAAC # AjAiBCCneRkQYbjGMp3Wxu2U5Dh+xgPqhLWg/GvX2xjkcWuAyzANBgkqhkiG9w0B # AQsFAASCAgAFjSu0CRgEuGt0/8TnqHBXHSXZCJQrrQyrt3Vb+bQPNdZ4q8MuCQXl # LaWU3QD9mm2zU1ZFjBh7gAbyORBNUpCIjYToSuBvxRmQw6v2GxCeH77r4ucwuvWI # DqWwemtcA217wvqSO3LarpoSNTMHSCynEaYKJkWwd7YTkcrZb8l/Fl7bk1MABdpA # gFf087boQgOGgfR/XkTjl00BMNBHHKYxL5E/XKJQxd6iAPMfeyRfZXSeR3YuwzX/ # lY5hhbdlT42ikXsQ8uVZ/eE7RyWyBagdy2RJead72w2YB4JPwhi858GaYsEjJGIi # O9S/DJkW9hA0DmgREqtqpvRiHACcLVBgWuxpiXV5uLLtwZ675QzfVLJRTRIXeAro # GnQv63l7I4cnCdV0DqypDZlLOI9qw+A3AifWZQ1V+J6Unjx017VDcEB7kdQlUn65 # W2wHMXCHZk5DpGmpJF7+xOAgQ51CxdvbYakV7XUkneOKSepFAcQvkpnixTz6gBsH # fQd/hrQIB6I7o/f63+xiB0UIKzcnjrko68/Osu3u56wVH77bY0ueaiRiR3ktRmAq # k2B26kuM8QxcoaO2P3SH+oRuOm/MmxSbnYHQc9Fhm405qC+POzCUgL0qUxZN5pbe # nPtPQUTQcz7Io8Dx/34onOU2MPTYk4fl4nNEOEiOBtZJhUOOvs5W6w== # SIG # End signature block |