Compare commits

...

4 Commits

Author SHA1 Message Date
Priya Gupta
9a946fdbd5 Add rollForward note in README, improve proxy health check in e2e tests and bump version to v5.3.0 (#738)
* docs: add note about latest* rollForward support in global.json

* update health check options for squid proxy in e2e tests
2026-05-27 21:45:27 -05:00
js6pak
98af08bf64 Support global.json's rollForward latest* variants (#538)
* Rename toolcache directory instead of moving to tmp

This further enhances time savings seen in #213, down from a few minutes to seconds.

* Remove branch constraint on workflows used for testing

This means you are going to be notified of CI issues quicker, especially if you have to wait for a confirmation before running the workflows on your PR.

* Support global.json's rollForward latest* variants

* Remove e2e-test's dependency on Microsoft.NET.Test.Sdk

The newer versions are net8.0/net462+ only, making older .NET sdks more annoying to test

* Revert "Remove e2e-test's dependency on Microsoft.NET.Test.Sdk"

This reverts commit 14839a662649cdea79ccecc3a7ce9a91386185b4.

* Don't run unsupported versions in global.json tests

* Revert "Remove branch constraint on workflows used for testing"

This reverts commit d9dae35030.
2026-05-26 17:43:27 -05:00
Michael Simons
8404272362 Update install scripts to v2026.05.19 (#736)
Update externals/install-dotnet.ps1 and externals/install-dotnet.sh to
the v2026.05.19 release of dotnet/install-scripts. This uptakes the
changes from dotnet/install-scripts#697 which preserves archive links
during installation (hardlinks on Windows, symlinks on Linux) as part
of dotnet/sdk#52182.

On Windows, .NET 11.0+ is now installed via tar.gz archives which
preserves hardlinks, significantly reducing disk space usage.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-05-26 12:22:17 -05:00
Alexander Köplinger
f1970f5ca3 Don't download releases-index.json to resolve major version (#560)
* Don't download releases-index.json to resolving major version

Starting with .NET 5 the minor version is always zero.
The earlier releases don't get new versions anymore so we can hardcode the minor version instead of downloading releases-index.json to do the lookup.

* Remove unused variable

* Apply suggestions from code review

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Commit dist/setup/index.js

* Refresh after copilot commits

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2026-05-11 12:11:45 -05:00
10 changed files with 510 additions and 284 deletions

View File

@@ -257,6 +257,81 @@ jobs:
shell: pwsh shell: pwsh
run: __tests__/verify-dotnet.ps1 -Patterns "^9.0", "^10.0" run: __tests__/verify-dotnet.ps1 -Patterns "^9.0", "^10.0"
test-setup-global-json-rollforward-latestmajor:
runs-on: ${{ matrix.operating-system }}
strategy:
fail-fast: false
matrix:
operating-system: [ubuntu-latest, windows-latest, macos-latest]
steps:
- name: Checkout
uses: actions/checkout@v6
- name: Clear toolcache
shell: pwsh
run: __tests__/clear-toolcache.ps1 ${{ runner.os }}
- name: Write global.json
shell: bash
run: |
mkdir subdirectory
echo '{"sdk":{"version": "3.1.0","rollForward": "latestMajor"}}' > ./subdirectory/global.json
- name: Setup dotnet
uses: ./
with:
global-json-file: ./subdirectory/global.json
- name: Verify dotnet
shell: pwsh
run: __tests__/verify-dotnet.ps1 -Patterns "^(?!3)"
test-setup-global-json-rollforward-latestfeature:
runs-on: ${{ matrix.operating-system }}
strategy:
fail-fast: false
matrix:
operating-system: [ubuntu-latest, windows-latest, macos-latest]
steps:
- name: Checkout
uses: actions/checkout@v6
- name: Clear toolcache
shell: pwsh
run: __tests__/clear-toolcache.ps1 ${{ runner.os }}
- name: Write global.json
shell: bash
run: |
mkdir subdirectory
echo '{"sdk":{"version": "10.0.100","rollForward": "latestFeature"}}' > ./subdirectory/global.json
- name: Setup dotnet
uses: ./
with:
global-json-file: ./subdirectory/global.json
- name: Verify dotnet
shell: pwsh
run: __tests__/verify-dotnet.ps1 -Patterns "^10.0.(?!1)"
test-setup-global-json-rollforward-latestpatch:
runs-on: ${{ matrix.operating-system }}
strategy:
fail-fast: false
matrix:
operating-system: [ubuntu-latest, windows-latest, macos-latest]
steps:
- name: Checkout
uses: actions/checkout@v6
- name: Clear toolcache
shell: pwsh
run: __tests__/clear-toolcache.ps1 ${{ runner.os }}
- name: Write global.json
shell: bash
run: |
mkdir subdirectory
echo '{"sdk":{"version": "10.0.100","rollForward": "latestPatch"}}' > ./subdirectory/global.json
- name: Setup dotnet
uses: ./
with:
global-json-file: ./subdirectory/global.json
- name: Verify dotnet
shell: pwsh
run: __tests__/verify-dotnet.ps1 -Patterns "^10.0.1(?!00)"
test-setup-global-json-only: test-setup-global-json-only:
runs-on: ${{ matrix.operating-system }} runs-on: ${{ matrix.operating-system }}
strategy: strategy:
@@ -502,6 +577,11 @@ jobs:
image: ubuntu/squid:latest image: ubuntu/squid:latest
ports: ports:
- 3128:3128 - 3128:3128
options: >-
--health-cmd "bash -c '</dev/tcp/localhost/3128'"
--health-interval 5s
--health-timeout 3s
--health-retries 10
env: env:
https_proxy: http://squid-proxy:3128 https_proxy: http://squid-proxy:3128
http_proxy: http://squid-proxy:3128 http_proxy: http://squid-proxy:3128

View File

@@ -142,6 +142,8 @@ steps:
working-directory: csharp working-directory: csharp
``` ```
> **Note**: The action supports `latest*` variants of the [rollForward](https://learn.microsoft.com/en-us/dotnet/core/tools/global-json#rollforward) field in `global.json`. When set to `latestPatch`, `latestFeature`, `latestMinor`, or `latestMajor`, the action installs the appropriate SDK version.
## Caching NuGet Packages ## Caching NuGet Packages
The action has a built-in functionality for caching and restoring dependencies. It uses [toolkit/cache](https://github.com/actions/toolkit/tree/main/packages/cache) under the hood for caching global packages data but requires less configuration settings. The `cache` input is optional, and caching is turned off by default. The action has a built-in functionality for caching and restoring dependencies. It uses [toolkit/cache](https://github.com/actions/toolkit/tree/main/packages/cache) under the hood for caching global packages data but requires less configuration settings. The `cache` input is optional, and caching is turned off by default.

View File

@@ -6,8 +6,8 @@ $dotnetPaths = @{
foreach ($srcPath in $dotnetPaths[$args[0]]) { foreach ($srcPath in $dotnetPaths[$args[0]]) {
if (Test-Path $srcPath) { if (Test-Path $srcPath) {
Write-Host "Move $srcPath path" $dstPath = "$srcPath-" + [IO.Path]::GetRandomFileName()
$dstPath = Join-Path ([IO.Path]::GetTempPath()) ([IO.Path]::GetRandomFileName()) Write-Host "Moving $srcPath to $dstPath"
Move-Item -Path $srcPath -Destination $dstPath Move-Item -Path $srcPath -Destination $dstPath
} }
} }

52
dist/setup/index.js vendored
View File

@@ -78768,7 +78768,22 @@ class DotnetVersionResolver {
this.resolvedArgument.value = `${major}.${minor}`; this.resolvedArgument.value = `${major}.${minor}`;
} }
else if (this.isNumericTag(major)) { else if (this.isNumericTag(major)) {
this.resolvedArgument.value = await this.getLatestByMajorTag(major); // Starting with .NET 5, the minor version is always zero.
// Hardcode the earlier versions because they will not get new releases.
switch (major) {
case '1':
this.resolvedArgument.value = '1.1';
break;
case '2':
this.resolvedArgument.value = '2.2';
break;
case '3':
this.resolvedArgument.value = '3.1';
break;
default:
this.resolvedArgument.value = `${major}.0`;
break;
}
} }
else { else {
// If "dotnet-version" is specified as *, x or X resolve latest version of .NET explicitly from LTS channel. The version argument will default to "latest" by install-dotnet script. // If "dotnet-version" is specified as *, x or X resolve latest version of .NET explicitly from LTS channel. The version argument will default to "latest" by install-dotnet script.
@@ -78832,23 +78847,6 @@ class DotnetVersionResolver {
} }
return releasesInfo[0]['channel-version']; return releasesInfo[0]['channel-version'];
} }
async getLatestByMajorTag(majorTag) {
const httpClient = new hc.HttpClient('actions/setup-dotnet', [], {
allowRetries: true,
maxRetries: 3
});
const response = await httpClient.getJson(DotnetVersionResolver.DotnetCoreIndexUrl);
const result = response.result || {};
const releasesInfo = result['releases-index'];
const releaseInfo = releasesInfo.find(info => {
const sdkParts = info['channel-version'].split('.');
return sdkParts[0] === majorTag;
});
if (!releaseInfo) {
throw new Error(`Could not find info for version with major tag: "${majorTag}" at ${DotnetVersionResolver.DotnetCoreIndexUrl}`);
}
return releaseInfo['channel-version'];
}
static DotnetCoreIndexUrl = 'https://builds.dotnet.microsoft.com/dotnet/release-metadata/releases-index.json'; static DotnetCoreIndexUrl = 'https://builds.dotnet.microsoft.com/dotnet/release-metadata/releases-index.json';
} }
exports.DotnetVersionResolver = DotnetVersionResolver; exports.DotnetVersionResolver = DotnetVersionResolver;
@@ -79246,9 +79244,23 @@ function getVersionFromGlobalJson(globalJsonPath) {
if (globalJson.sdk && globalJson.sdk.version) { if (globalJson.sdk && globalJson.sdk.version) {
version = globalJson.sdk.version; version = globalJson.sdk.version;
const rollForward = globalJson.sdk.rollForward; const rollForward = globalJson.sdk.rollForward;
if (rollForward && rollForward === 'latestFeature') { if (rollForward) {
const [major, minor] = version.split('.'); const [major, minor, featurePatch] = version.split('.');
const feature = featurePatch.substring(0, 1);
switch (rollForward) {
case 'latestMajor':
version = '';
break;
case 'latestMinor':
version = `${major}`;
break;
case 'latestFeature':
version = `${major}.${minor}`; version = `${major}.${minor}`;
break;
case 'latestPatch':
version = `${major}.${minor}.${feature}xx`;
break;
}
} }
} }
return version; return version;

View File

@@ -94,9 +94,9 @@
Determines timeout duration in seconds for downloading of the SDK file Determines timeout duration in seconds for downloading of the SDK file
Default: 1200 seconds (20 minutes) Default: 1200 seconds (20 minutes)
.PARAMETER KeepZip .PARAMETER KeepZip
If set, downloaded file is kept If set, downloaded archive file is kept. Applies to both .zip and .tar.gz formats.
.PARAMETER ZipPath .PARAMETER ZipPath
Use that path to store installer, generated by default Use that path to store the downloaded archive, generated by default. Applies to both .zip and .tar.gz formats.
.EXAMPLE .EXAMPLE
dotnet-install.ps1 -Version 7.0.401 dotnet-install.ps1 -Version 7.0.401
Installs the .NET SDK version 7.0.401 Installs the .NET SDK version 7.0.401
@@ -341,6 +341,36 @@ function Get-NormalizedProduct([string]$Runtime) {
} }
} }
function Test-TarAvailable {
if ($env:DOTNET_INSTALL_SKIP_TAR -eq "1") {
Say-Verbose "Skipping tar detection due to DOTNET_INSTALL_SKIP_TAR environment variable."
return $false
}
$tarCommand = Get-Command -Name "tar" -ErrorAction SilentlyContinue
return $null -ne $tarCommand
}
function Get-FileExtension-For-Version([string]$VersionOrChannel) {
if (-not $script:TarAvailable) {
return ".zip"
}
if ($VersionOrChannel -match '^(\d+)\.') {
$majorVersion = [int]$Matches[1]
if ($majorVersion -ge 11) {
# Windows tarballs are only available starting with 11.0 preview 3
if ($VersionOrChannel -match 'preview\.(\d+)') {
$previewNum = [int]$Matches[1]
if ($majorVersion -eq 11 -and $previewNum -lt 3) {
Say-Verbose "Version '$VersionOrChannel' predates tar.gz availability; using zip."
return ".zip"
}
}
Say-Verbose "Using tar.gz archive format for version/channel '$VersionOrChannel'."
return ".tar.gz"
}
}
return ".zip"
}
# The version text returned from the feeds is a 1-line or 2-line string: # The version text returned from the feeds is a 1-line or 2-line string:
# For the SDK and the dotnet runtime (2 lines): # For the SDK and the dotnet runtime (2 lines):
@@ -594,24 +624,27 @@ function Get-Download-Link([string]$AzureFeed, [string]$SpecificVersion, [string
# If anything fails in this lookup it will default to $SpecificVersion # If anything fails in this lookup it will default to $SpecificVersion
$SpecificProductVersion = Get-Product-Version -AzureFeed $AzureFeed -SpecificVersion $SpecificVersion $SpecificProductVersion = Get-Product-Version -AzureFeed $AzureFeed -SpecificVersion $SpecificVersion
# For .NET 11.0+, tar.gz is the preferred archive format on Windows
$ext = Get-FileExtension-For-Version $SpecificVersion
if ($Runtime -eq "dotnet") { if ($Runtime -eq "dotnet") {
$PayloadURL = "$AzureFeed/Runtime/$SpecificVersion/dotnet-runtime-$SpecificProductVersion-win-$CLIArchitecture.zip" $PayloadURL = "$AzureFeed/Runtime/$SpecificVersion/dotnet-runtime-$SpecificProductVersion-win-$CLIArchitecture$ext"
} }
elseif ($Runtime -eq "aspnetcore") { elseif ($Runtime -eq "aspnetcore") {
$PayloadURL = "$AzureFeed/aspnetcore/Runtime/$SpecificVersion/aspnetcore-runtime-$SpecificProductVersion-win-$CLIArchitecture.zip" $PayloadURL = "$AzureFeed/aspnetcore/Runtime/$SpecificVersion/aspnetcore-runtime-$SpecificProductVersion-win-$CLIArchitecture$ext"
} }
elseif ($Runtime -eq "windowsdesktop") { elseif ($Runtime -eq "windowsdesktop") {
# The windows desktop runtime is part of the core runtime layout prior to 5.0 # The windows desktop runtime is part of the core runtime layout prior to 5.0
$PayloadURL = "$AzureFeed/Runtime/$SpecificVersion/windowsdesktop-runtime-$SpecificProductVersion-win-$CLIArchitecture.zip" $PayloadURL = "$AzureFeed/Runtime/$SpecificVersion/windowsdesktop-runtime-$SpecificProductVersion-win-$CLIArchitecture$ext"
if ($SpecificVersion -match '^(\d+)\.(.*)$') { if ($SpecificVersion -match '^(\d+)\.(.*)$') {
$majorVersion = [int]$Matches[1] $majorVersion = [int]$Matches[1]
if ($majorVersion -ge 5) { if ($majorVersion -ge 5) {
$PayloadURL = "$AzureFeed/WindowsDesktop/$SpecificVersion/windowsdesktop-runtime-$SpecificProductVersion-win-$CLIArchitecture.zip" $PayloadURL = "$AzureFeed/WindowsDesktop/$SpecificVersion/windowsdesktop-runtime-$SpecificProductVersion-win-$CLIArchitecture$ext"
} }
} }
} }
elseif (-not $Runtime) { elseif (-not $Runtime) {
$PayloadURL = "$AzureFeed/Sdk/$SpecificVersion/dotnet-sdk-$SpecificProductVersion-win-$CLIArchitecture.zip" $PayloadURL = "$AzureFeed/Sdk/$SpecificVersion/dotnet-sdk-$SpecificProductVersion-win-$CLIArchitecture$ext"
} }
else { else {
throw "Invalid value for `$Runtime" throw "Invalid value for `$Runtime"
@@ -877,6 +910,80 @@ function Extract-Dotnet-Package([string]$ZipPath, [string]$OutPath) {
} }
} }
function Extract-Dotnet-Package-Tar([string]$TarPath, [string]$OutPath) {
Say-Invocation $MyInvocation
New-Item -ItemType Directory -Force -Path $OutPath | Out-Null
# Build an exclude list of versioned directories that already exist locally.
# This matches the zip extraction behavior: if shared/Microsoft.NETCore.App/11.0.0/
# already exists, we skip all files under that version to avoid overwriting a
# previously installed version.
$excludeArgs = @()
$versionRegex = '.*/\d+\.\d+[^/]+/'
# Read the tarball's file listing to discover versioned directory prefixes
$tarListing = & tar -tzf $TarPath 2>$null
$versionedDirs = @{}
foreach ($entry in $tarListing) {
$normalizedEntry = $entry.Replace('\', '/')
$match = [regex]::Match($normalizedEntry, $versionRegex)
if ($match.Success) {
$versionedPrefix = $normalizedEntry.Substring(0, $match.Index + $match.Length)
if (-not $versionedDirs.ContainsKey($versionedPrefix)) {
$localDir = Join-Path -Path $OutPath -ChildPath $versionedPrefix
$versionedDirs[$versionedPrefix] = (Test-Path $localDir -PathType Container)
}
}
}
foreach ($dir in $versionedDirs.GetEnumerator()) {
if ($dir.Value) {
# This versioned directory already exists — exclude it from extraction
$pattern = $dir.Key + '*'
$excludeArgs += '--exclude'
$excludeArgs += $pattern
Say-Verbose "Excluding pre-existing versioned directory: $($dir.Key)"
}
}
# Handle non-versioned file override logic.
# If OverrideNonVersionedFiles is false, exclude non-versioned files that already exist.
if (-not $OverrideNonVersionedFiles) {
foreach ($entry in $tarListing) {
$normalizedEntry = $entry.Replace('\', '/')
# Skip directory entries (end with /)
if ($normalizedEntry.EndsWith('/')) { continue }
$match = [regex]::Match($normalizedEntry, $versionRegex)
if (-not $match.Success) {
# Non-versioned file — exclude if it already exists locally
$localPath = Join-Path -Path $OutPath -ChildPath $normalizedEntry
if (Test-Path $localPath) {
$excludeArgs += '--exclude'
$excludeArgs += $normalizedEntry
Say-Verbose "Excluding pre-existing non-versioned file: $normalizedEntry"
}
}
}
}
try {
# Extract directly to install root, preserving hard links
$tarOutput = & tar -xzf $TarPath -C $OutPath @excludeArgs 2>&1
if ($LASTEXITCODE -ne 0) {
$tarOutputText = ($tarOutput | Out-String).Trim()
if ([string]::IsNullOrWhiteSpace($tarOutputText)) {
throw "Tar extraction failed with exit code $LASTEXITCODE."
}
throw "Tar extraction failed with exit code $LASTEXITCODE. tar output: $tarOutputText"
}
}
catch {
Say-Error "Failed to extract tar package. Exception: $_"
throw
}
}
function DownloadFile($Source, [string]$OutPath) { function DownloadFile($Source, [string]$OutPath) {
if ($Source -notlike "http*") { if ($Source -notlike "http*") {
# Using System.IO.Path.GetFullPath to get the current directory # Using System.IO.Path.GetFullPath to get the current directory
@@ -991,7 +1098,7 @@ function PrintDryRunOutput($Invocation, $DownloadLinks) {
} }
} }
function Get-AkaMSDownloadLink([string]$Channel, [string]$Quality, [bool]$Internal, [string]$Product, [string]$Architecture) { function Get-AkaMSDownloadLink([string]$Channel, [string]$Quality, [bool]$Internal, [string]$Product, [string]$Architecture, [string]$FileExtension = ".zip") {
Say-Invocation $MyInvocation Say-Invocation $MyInvocation
#quality is not supported for LTS or STS channel #quality is not supported for LTS or STS channel
@@ -1010,7 +1117,7 @@ function Get-AkaMSDownloadLink([string]$Channel, [string]$Quality, [bool]$Intern
if (-not [string]::IsNullOrEmpty($Quality)) { if (-not [string]::IsNullOrEmpty($Quality)) {
$akaMsLink += "/$Quality" $akaMsLink += "/$Quality"
} }
$akaMsLink += "/$Product-win-$Architecture.zip" $akaMsLink += "/$Product-win-$Architecture$FileExtension"
Say-Verbose "Constructed aka.ms link: '$akaMsLink'." Say-Verbose "Constructed aka.ms link: '$akaMsLink'."
$akaMsDownloadLink = $null $akaMsDownloadLink = $null
@@ -1062,7 +1169,23 @@ function Get-AkaMSDownloadLink([string]$Channel, [string]$Quality, [bool]$Intern
} }
function Get-AkaMsLink-And-Version([string] $NormalizedChannel, [string] $NormalizedQuality, [bool] $Internal, [string] $ProductName, [string] $Architecture) { function Get-AkaMsLink-And-Version([string] $NormalizedChannel, [string] $NormalizedQuality, [bool] $Internal, [string] $ProductName, [string] $Architecture) {
$AkaMsDownloadLink = Get-AkaMSDownloadLink -Channel $NormalizedChannel -Quality $NormalizedQuality -Internal $Internal -Product $ProductName -Architecture $Architecture
# When tar is available, try .tar.gz first via aka.ms, then fall back to .zip.
# This handles symbolic channels (STS/LTS) and numeric channels where tar.gz
# may not yet be available (e.g. pre-11.0 versions).
$extensionsToTry = @(".zip")
if ($script:TarAvailable) {
$extensionsToTry = @(".tar.gz", ".zip")
}
$AkaMsDownloadLink = $null
foreach ($ext in $extensionsToTry) {
$AkaMsDownloadLink = Get-AkaMSDownloadLink -Channel $NormalizedChannel -Quality $NormalizedQuality -Internal $Internal -Product $ProductName -Architecture $Architecture -FileExtension $ext
if (-not [string]::IsNullOrEmpty($AkaMsDownloadLink)) {
break
}
Say-Verbose "aka.ms link resolution with '$ext' extension failed, trying next format."
}
if ([string]::IsNullOrEmpty($AkaMsDownloadLink)) { if ([string]::IsNullOrEmpty($AkaMsDownloadLink)) {
if (-not [string]::IsNullOrEmpty($NormalizedQuality)) { if (-not [string]::IsNullOrEmpty($NormalizedQuality)) {
@@ -1191,6 +1314,8 @@ Measure-Action "Product discovery" {
$script:NormalizedProduct = Get-NormalizedProduct $Runtime $script:NormalizedProduct = Get-NormalizedProduct $Runtime
Say-Verbose "Normalized product: '$NormalizedProduct'" Say-Verbose "Normalized product: '$NormalizedProduct'"
$script:FeedCredential = ValidateFeedCredential $FeedCredential $script:FeedCredential = ValidateFeedCredential $FeedCredential
$script:TarAvailable = Test-TarAvailable
Say-Verbose "Tar available: '$TarAvailable'"
} }
$InstallRoot = Resolve-Installation-Path $InstallDir $InstallRoot = Resolve-Installation-Path $InstallDir
@@ -1319,7 +1444,12 @@ if (-not $DownloadSucceeded) {
} }
Say "Extracting the archive." Say "Extracting the archive."
if ($DownloadedLink.downloadLink.EndsWith(".tar.gz")) {
Measure-Action "Package extraction" { Extract-Dotnet-Package-Tar -TarPath $ZipPath -OutPath $InstallRoot }
}
else {
Measure-Action "Package extraction" { Extract-Dotnet-Package -ZipPath $ZipPath -OutPath $InstallRoot } Measure-Action "Package extraction" { Extract-Dotnet-Package -ZipPath $ZipPath -OutPath $InstallRoot }
}
# Check if the SDK version is installed; if not, fail the installation. # Check if the SDK version is installed; if not, fail the installation.
$isAssetInstalled = $false $isAssetInstalled = $false
@@ -1355,219 +1485,215 @@ Say "Installed version is $($DownloadedLink.effectiveVersion)"
Say "Installation finished" Say "Installation finished"
# SIG # Begin signature block # SIG # Begin signature block
# MIIoKgYJKoZIhvcNAQcCoIIoGzCCKBcCAQExDzANBglghkgBZQMEAgEFADB5Bgor # MIIncQYJKoZIhvcNAQcCoIInYjCCJ14CAQExDzANBglghkgBZQMEAgEFADB5Bgor
# BgEEAYI3AgEEoGswaTA0BgorBgEEAYI3AgEeMCYCAwEAAAQQH8w7YFlLCE63JNLG # BgEEAYI3AgEEoGswaTA0BgorBgEEAYI3AgEeMCYCAwEAAAQQH8w7YFlLCE63JNLG
# KX7zUQIBAAIBAAIBAAIBAAIBADAxMA0GCWCGSAFlAwQCAQUABCCyKn7B6ieM6Y2C # KX7zUQIBAAIBAAIBAAIBAAIBADAxMA0GCWCGSAFlAwQCAQUABCDmNI7+9b4lSWsX
# rr9TCFvTSv2mMIh9mBGXh4z2gOksEqCCDXYwggX0MIID3KADAgECAhMzAAAEhV6Z # 2kYVvqQHpZeXB6Kt5BepNOcmIqEK1aCCDMkwggYEMIID7KADAgECAhMzAAACHPrN
# 7A5ZL83XAAAAAASFMA0GCSqGSIb3DQEBCwUAMH4xCzAJBgNVBAYTAlVTMRMwEQYD # xZvoL37EAAAAAAIcMA0GCSqGSIb3DQEBCwUAMFcxCzAJBgNVBAYTAlVTMR4wHAYD
# VQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNy # VQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xKDAmBgNVBAMTH01pY3Jvc29mdCBD
# b3NvZnQgQ29ycG9yYXRpb24xKDAmBgNVBAMTH01pY3Jvc29mdCBDb2RlIFNpZ25p # b2RlIFNpZ25pbmcgUENBIDIwMjQwHhcNMjYwNDE2MTg1OTQxWhcNMjcwNDE1MTg1
# bmcgUENBIDIwMTEwHhcNMjUwNjE5MTgyMTM3WhcNMjYwNjE3MTgyMTM3WjB0MQsw # OTQxWjB0MQswCQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UE
# CQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9u # BxMHUmVkbW9uZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMR4wHAYD
# ZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMR4wHAYDVQQDExVNaWNy # VQQDExVNaWNyb3NvZnQgQ29ycG9yYXRpb24wggEiMA0GCSqGSIb3DQEBAQUAA4IB
# b3NvZnQgQ29ycG9yYXRpb24wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIB # DwAwggEKAoIBAQDVsZfgOKmM31HPfoWOoNEiw0SlCiIxUMC0I9NMWbucKOw/e9lP
# AQDASkh1cpvuUqfbqxele7LCSHEamVNBfFE4uY1FkGsAdUF/vnjpE1dnAD9vMOqy # oAoehQVu6SG65V4EPzrYsnBnFPNoi4/HoOdjhz1qkrEt4I6tEcxXU6oOeY9zGveC
# 5ZO49ILhP4jiP/P2Pn9ao+5TDtKmcQ+pZdzbG7t43yRXJC3nXvTGQroodPi9USQi # /3iBeuhLYxM3M/PkcUoebF+Nednm8OkdSPoDu8imViHPQq/8CQUu0WRR4rE+dMRf
# 9rI+0gwuXRKBII7L+k3kMkKLmFrsWUjzgXVCLYa6ZH7BCALAcJWZTwWPoiT4HpqQ # rpVqfmNi2qWCX94T4MsepijGVkwE//tJg0ryAiYdHT34LSnlG/RSBZmQRGWZ5g8j
# hJcYLB7pfetAVCeBEVZD8itKQ6QA5/LQR+9X6dlSj4Vxta4JnpxvgSrkjXCz+tlJ # qnKjRParSqMft1gvjuUTVgtWNZfgcLFSK5Wa0myrq8OPcgTGGsRgun+tnSS+IxDT
# 67ABZ551lw23RWU1uyfgCfEFhBfiyPR2WSjskPl9ap6qrf8fNQ1sGYun2p4JdXxe # xVsAPH1OzvPjwomguByhUe/OcvUN0D5Wmp7xAgMBAAGjggGqMIIBpjAOBgNVHQ8B
# UAKf1hVa/3TQXjvPTiRXCnJPAgMBAAGjggFzMIIBbzAfBgNVHSUEGDAWBgorBgEE # Af8EBAMCB4AwHwYDVR0lBBgwFgYKKwYBBAGCN0wIAQYIKwYBBQUHAwMwHQYDVR0O
# AYI3TAgBBggrBgEFBQcDAzAdBgNVHQ4EFgQUuCZyGiCuLYE0aU7j5TFqY05kko0w # BBYEFNoH7a2YDjOSwpkp6DHcmUS7J+0yMFQGA1UdEQRNMEukSTBHMS0wKwYDVQQL
# RQYDVR0RBD4wPKQ6MDgxHjAcBgNVBAsTFU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjEW # EyRNaWNyb3NvZnQgSXJlbGFuZCBPcGVyYXRpb25zIExpbWl0ZWQxFjAUBgNVBAUT
# MBQGA1UEBRMNMjMwMDEyKzUwNTM1OTAfBgNVHSMEGDAWgBRIbmTlUAXTgqoXNzci # DTIzMDAxMis1MDc1NjkwHwYDVR0jBBgwFoAUf1k/VCHarU/vBeXmo9ctBpQSCDEw
# tW2oynUClTBUBgNVHR8ETTBLMEmgR6BFhkNodHRwOi8vd3d3Lm1pY3Jvc29mdC5j # YAYDVR0fBFkwVzBVoFOgUYZPaHR0cDovL3d3dy5taWNyb3NvZnQuY29tL3BraW9w
# b20vcGtpb3BzL2NybC9NaWNDb2RTaWdQQ0EyMDExXzIwMTEtMDctMDguY3JsMGEG # cy9jcmwvTWljcm9zb2Z0JTIwQ29kZSUyMFNpZ25pbmclMjBQQ0ElMjAyMDI0LmNy
# CCsGAQUFBwEBBFUwUzBRBggrBgEFBQcwAoZFaHR0cDovL3d3dy5taWNyb3NvZnQu # bDBtBggrBgEFBQcBAQRhMF8wXQYIKwYBBQUHMAKGUWh0dHA6Ly93d3cubWljcm9z
# Y29tL3BraW9wcy9jZXJ0cy9NaWNDb2RTaWdQQ0EyMDExXzIwMTEtMDctMDguY3J0 # b2Z0LmNvbS9wa2lvcHMvY2VydHMvTWljcm9zb2Z0JTIwQ29kZSUyMFNpZ25pbmcl
# MAwGA1UdEwEB/wQCMAAwDQYJKoZIhvcNAQELBQADggIBACjmqAp2Ci4sTHZci+qk # MjBQQ0ElMjAyMDI0LmNydDAMBgNVHRMBAf8EAjAAMA0GCSqGSIb3DQEBCwUAA4IC
# tEAKsFk5HNVGKyWR2rFGXsd7cggZ04H5U4SV0fAL6fOE9dLvt4I7HBHLhpGdE5Uj # AQAUnEqhaRXe0T3hIJjvdQErEkrA/7bByjn6t5IArODkkRjzkYwtKMc2yYj2quaN
# Ly4NxLTG2bDAkeAVmxmd2uKWVGKym1aarDxXfv3GCN4mRX+Pn4c+py3S/6Kkt5eS # rLutWw2YZcngKPy1b71YyDJQTy4NDRwaSh9Tw5thrk3NmcPrAHia5vtcBJ1CgtKK
# DAIIsrzKw3Kh2SW1hCwXX/k1v4b+NH1Fjl+i/xPJspXCFuZB4aC5FLT5fgbRKqns # 7mQbIcQ22d/N3813ayCDDFewu1+jsZmX+r/aTEqaOM4TVxVtRSkuCy8nAXKuChOK
# WeAdn8DsrYQhT3QXLt6Nv3/dMzv7G/Cdpbdcoul8FYl+t3dmXM+SIClC3l2ae0wO # Li/zA4XuH8iEYqIsj2YoNaeSxVmeGiERXpKdo3dDmYi0kO5w2D8VS4c3+9h6gElY
# lNrQ42yQEycuPU5OoqLT85jsZ7+4CaScfFINlO7l7Y7r/xauqHbSPQ1r3oIC+e71 # BaAAg/dYErBg27qT3vv0zRDJhJufvCNylA8S7/+8H5E/PV5cng6na9VV/w9OV3qu
# 5s2G3ClZa3y99aYx2lnXYe1srcrIx8NAXTViiypXVn9ZGmEkfNcfDiqGQwkml5z9 # uND6zdGa2EX38Glp50F9AIQk3p2xXmcvorDeM4XJ7UlWYBi6g80J1SSOQnInCYFE
# nm3pWiBZ69adaBBbAFEjyJG4y0a76bel/4sDCVvaZzLM3TFbxVO9BQrjZRtbJZbk # msfUNn3+1AaTJKSJL83quKArTac2pKhu0Yzzzrzo6HrsRiQKzpnRBb1/dMa6P3hz
# C3XArpLqZSfx53SuYdddxPX8pvcqFuEu8wcUeD05t9xNbJ4TtdAECJlEi0vvBxlm # 75XbMRBctNsFhZC07WCmjExdLg2eHW5uV0TY8D5+6wozJf7vF3+WHkYPO85Z+BC6
# M5tzFXy2qZeqPMXHSQYqPgZ9jvScZ6NwznFD0+33kbzyhOSz/WuGbAu4cHZG8gKn # U4FkNbYNycZ9cE4j1tXRdyDCfml6c0HWPHjNVDObrv9lKt3qUqFpX38VCqVCyNOO
# lQVT4uA2Diex9DMs2WHiokNknYlLoUeWXW1QrJLpqO82TLyKTbBM/oZHAdIc0kzo # 1UcXfQiVjJw32U2WUKZjt/neJKHEBsm9kFsLuWzkQ53+qcaSaytmsCnk2gOglrlD
# STro9b3+vjn2809D0+SOOCVZMIIHejCCBWKgAwIBAgIKYQ6Q0gAAAAAAAzANBgkq # 5d3kKyvvAw+rzm0lT8K38P6PLxfZQHhu4W8dV7Av8N2ZmDCCBr0wggSloAMCAQIC
# hkiG9w0BAQsFADCBiDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCldhc2hpbmd0b24x # EzMAAAA5O7Y3Gb8GHWcAAAAAADkwDQYJKoZIhvcNAQEMBQAwgYgxCzAJBgNVBAYT
# EDAOBgNVBAcTB1JlZG1vbmQxHjAcBgNVBAoTFU1pY3Jvc29mdCBDb3Jwb3JhdGlv # AlVTMRMwEQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYD
# bjEyMDAGA1UEAxMpTWljcm9zb2Z0IFJvb3QgQ2VydGlmaWNhdGUgQXV0aG9yaXR5 # VQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xMjAwBgNVBAMTKU1pY3Jvc29mdCBS
# IDIwMTEwHhcNMTEwNzA4MjA1OTA5WhcNMjYwNzA4MjEwOTA5WjB+MQswCQYDVQQG # b290IENlcnRpZmljYXRlIEF1dGhvcml0eSAyMDExMB4XDTI0MDgwODIwNTQxOFoX
# EwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9uZDEeMBwG # DTM2MDMyMjIyMTMwNFowVzELMAkGA1UEBhMCVVMxHjAcBgNVBAoTFU1pY3Jvc29m
# A1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMSgwJgYDVQQDEx9NaWNyb3NvZnQg # dCBDb3Jwb3JhdGlvbjEoMCYGA1UEAxMfTWljcm9zb2Z0IENvZGUgU2lnbmluZyBQ
# Q29kZSBTaWduaW5nIFBDQSAyMDExMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIIC # Q0EgMjAyNDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBANgBnB7jOMeq
# CgKCAgEAq/D6chAcLq3YbqqCEE00uvK2WCGfQhsqa+laUKq4BjgaBEm6f8MMHt03 # lRYHNa265v4IY9fH8TKhemHfPINe1gpLaV3dhg324WwH06LcHbpnsBukCDNitryo
# a8YS2AvwOMKZBrDIOdUBFDFC04kNeWSHfpRgJGyvnkmc6Whe0t+bU7IKLMOv2akr # 0dtS/EW6I/yEL/bLSY8hKpbfQuWusBPr9qazYcDxCW/qnjb5JsI1s8bNOg3bVATv
# rnoJr9eWWcpgGgXpZnboMlImEi/nqwhQz7NEt13YxC4Ddato88tt8zpcoRb0Rrrg # QVL4tcf03aTycsz8QeCdM0l/yHRObJ9QqazM1r6VPEOJ7LL+uEEb73w6QCuhs89a
# OGSsbmQ1eKagYw8t00CT+OPeBw3VXHmlSSnnDb6gE3e+lD3v++MrWhAfTVYoonpy # 1uv1zerOYMnsneRRwCbpyW11IcggU0cRKDDq1pjVJzIbIF6+oiXXbReOsgeI8zu1
# 4BI6t0le2O3tQ5GD2Xuye4Yb2T6xjF3oiU+EGvKhL1nkkDstrjNYxbc+/jLTswM9 # FyQfK0fVkaya8SmVHQ/tOf23mZ4W9k0Ri22QW9p3UgSC5OUDktKxxcCmGL6tXLfO
# sbKvkjh+0p2ALPVOVpEhNSXDOW5kf1O6nA+tGSOEy/S6A4aN91/w0FK/jJSHvMAh # GSWHIIV4YrTJTT6PNty5REojHJuZHArkF9VnHTERWoTjAzfI3kP+5b4alUdhgAZ7
# dCVfGCi2zCcoOCWYOUo2z3yxkq4cI6epZuxhH2rhKEmdX4jiJV3TIUs+UsS1Vz8k # ttOu1bVnXfHaqPYl2rPs20ji03LOVWsh/radgE17es5hL+t6lV0eVHrVhsssROWJ
# A/DRelsv1SPjcF0PUUZ3s/gA4bysAoJf28AVs70b1FVL5zmhD+kjSbwYuER8ReTB # uz2MXMCt7iw7lFPG9LXKGjsmonn2gotGdHIuEg5JnJMJVmixd5LRlkmgYRZKzhxS
# w3J64HLnJN+/RpnF78IcV9uDjexNSTCnq47f7Fufr/zdsGbiwZeBe+3W7UvnSSmn # CwyoGIq0PhaA7Y+VPct5pCHkijcIIDm0nlkK+0KyepolcqGm0T/GYQRMhHJlGOOm
# Eyimp31ngOaKYnhfsi+E11ecXL93KCjx7W3DKI8sj0A3T8HhhUSJxAlMxdSlQy90 # VQop36wUVUYklUy++vDWeEgEo4s7hxN6mIbf2MSIQ/iIfMZgJxC69oukMUXCrOC3
# lfdu+HggWCwTXWCVmj5PM4TasIgX3p5O9JawvEagbJjS4NaIjAsCAwEAAaOCAe0w # SkE/xIkgpfl22MM1itkZ35nNXkMolU1lAgMBAAGjggFOMIIBSjAOBgNVHQ8BAf8E
# ggHpMBAGCSsGAQQBgjcVAQQDAgEAMB0GA1UdDgQWBBRIbmTlUAXTgqoXNzcitW2o # BAMCAYYwEAYJKwYBBAGCNxUBBAMCAQAwHQYDVR0OBBYEFH9ZP1Qh2q1P7wXl5qPX
# ynUClTAZBgkrBgEEAYI3FAIEDB4KAFMAdQBiAEMAQTALBgNVHQ8EBAMCAYYwDwYD # LQaUEggxMBkGCSsGAQQBgjcUAgQMHgoAUwB1AGIAQwBBMA8GA1UdEwEB/wQFMAMB
# VR0TAQH/BAUwAwEB/zAfBgNVHSMEGDAWgBRyLToCMZBDuRQFTuHqp8cx0SOJNDBa # Af8wHwYDVR0jBBgwFoAUci06AjGQQ7kUBU7h6qfHMdEjiTQwWgYDVR0fBFMwUTBP
# BgNVHR8EUzBRME+gTaBLhklodHRwOi8vY3JsLm1pY3Jvc29mdC5jb20vcGtpL2Ny # oE2gS4ZJaHR0cDovL2NybC5taWNyb3NvZnQuY29tL3BraS9jcmwvcHJvZHVjdHMv
# bC9wcm9kdWN0cy9NaWNSb29DZXJBdXQyMDExXzIwMTFfMDNfMjIuY3JsMF4GCCsG # TWljUm9vQ2VyQXV0MjAxMV8yMDExXzAzXzIyLmNybDBeBggrBgEFBQcBAQRSMFAw
# AQUFBwEBBFIwUDBOBggrBgEFBQcwAoZCaHR0cDovL3d3dy5taWNyb3NvZnQuY29t # TgYIKwYBBQUHMAKGQmh0dHA6Ly93d3cubWljcm9zb2Z0LmNvbS9wa2kvY2VydHMv
# L3BraS9jZXJ0cy9NaWNSb29DZXJBdXQyMDExXzIwMTFfMDNfMjIuY3J0MIGfBgNV # TWljUm9vQ2VyQXV0MjAxMV8yMDExXzAzXzIyLmNydDANBgkqhkiG9w0BAQwFAAOC
# HSAEgZcwgZQwgZEGCSsGAQQBgjcuAzCBgzA/BggrBgEFBQcCARYzaHR0cDovL3d3 # AgEAFJQfOChP7onn6fLIMKrSlN1WYKwDFgAddymOUO3FrM8d7B/W/iQ6DxXsDn7D
# dy5taWNyb3NvZnQuY29tL3BraW9wcy9kb2NzL3ByaW1hcnljcHMuaHRtMEAGCCsG # 5W4wMwYeLystcEqfkjz4NURRgazyMu5yRzQh4LqjA4tStTcJh1opExo7nn5PuPBY
# AQUFBwICMDQeMiAdAEwAZQBnAGEAbABfAHAAbwBsAGkAYwB5AF8AcwB0AGEAdABl # nbu0+THSuVHTe0VTTPVhily/piFrDo3axQ9P4C+Ol5yet+2gTfekICS5xS+cYfSI
# AG0AZQBuAHQALiAdMA0GCSqGSIb3DQEBCwUAA4ICAQBn8oalmOBUeRou09h0ZyKb # vgn0JksVBVMYVI5QFu/qhnLhsEFEUzG8fvv0hjgkO+lkpV9ty6GkN4vdnd7ya6Q6
# C5YR4WOSmUKWfdJ5DJDBZV8uLD74w3LRbYP+vj/oCso7v0epo/Np22O/IjWll11l # aR9y34aiM1qmxaxBi6OUnyNl6fkuun/diTFnYDLTppOkr/mg5WSfCiDVMNCxtj4w
# hJB9i0ZQVdgMknzSGksc8zxCi1LQsP1r4z4HLimb5j0bpdS1HXeUOeLpZMlEPXh6 # PKC5OmHm1DQIt/MNokbbH3UGsFP1QbzsLocuSqLCvH09Io3fDPTmscR9Y75G4qX7
# I/MTfaaQdION9MsmAkYqwooQu6SpBQyb7Wj6aC6VoCo/KmtYSWMfCWluWpiW5IP0 # RTX8AdBPo0I6OEojf39zuFZt0qOHm65YWQE69cZM2ueE1MB05dNNgHK9gTE7zKvK
# wI/zRive/DvQvTXvbiWu5a8n7dDd8w6vmSiXmE0OPQvyCInWH8MyGOLwxS3OW560 # /fg8B2qjW88MT/WF5V5uvZGtqa9FSL2RazArA+rDPuf6JGYz4HpgMZHB4S6szWSK
# STkKxgrCxq2u5bLZ2xWIUUVYODJxJxp/sfQn+N4sOiBpmLJZiWhub6e3dMNABQam # YBv0VisCzfxgeU+dquXW9bd0auYlOB58DPcOYKdc3Se94g+xL4pcEhbB54JOgAkw
# ASooPoI/E01mC8CzTfXhj38cbxV9Rad25UAqZaPDXVJihsMdYzaXht/a8/jyFqGa # YTu/9dLeH2pDqeJZAABVDWRQCaXfO5LgyKwKCLYXpigrZYCjUSBcr+Ve8PFWMhVT
# J+HNpZfQ7l1jQeNbB5yHPgZ3BtEGsXUfFL5hYbXw3MYbBL7fQccOKO7eZS/sl/ah # Ql0v4q8J/AUmQN5W4n101cY2L4A7GTQG1h32HHAvfQESWP0xghn+MIIZ+gIBATBu
# XJbYANahRr1Z85elCUtIEJmAH9AAKcWxm6U/RXceNcbSoqKfenoi+kiVH6v7RyOA # MFcxCzAJBgNVBAYTAlVTMR4wHAYDVQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24x
# 9Z74v2u3S5fi63V4GuzqN5l5GEv/1rMjaHXmr/r8i+sLgOppO6/8MO0ETI7f33Vt # KDAmBgNVBAMTH01pY3Jvc29mdCBDb2RlIFNpZ25pbmcgUENBIDIwMjQCEzMAAAIc
# Y5E90Z1WTk+/gFcioXgRMiF670EKsT/7qMykXcGhiJtXcVZOSEXAQsmbdlsKgEhr # +s3Fm+gvfsQAAAAAAhwwDQYJYIZIAWUDBAIBBQCgga4wGQYJKoZIhvcNAQkDMQwG
# /Xmfwb1tbWrJUnMTDXpQzTGCGgowghoGAgEBMIGVMH4xCzAJBgNVBAYTAlVTMRMw # CisGAQQBgjcCAQQwHAYKKwYBBAGCNwIBCzEOMAwGCisGAQQBgjcCARUwLwYJKoZI
# hvcNAQkEMSIEIB5Na9P++kVnSeIy27N4IyRD4N0sjfWHRS1ht0NHdoK/MEIGCisG
# AQQBgjcCAQwxNDAyoBSAEgBNAGkAYwByAG8AcwBvAGYAdKEagBhodHRwOi8vd3d3
# Lm1pY3Jvc29mdC5jb20wDQYJKoZIhvcNAQEBBQAEggEAx05EI+Kk4hoAKG/8oVdr
# UIq/+sv+E0vpSyWQMTq/yrkfnPWqT2TxNVtcG3ZcQT5/36cjMe1umi1zzy178VRP
# HKH2jxMOzMqtJPsAI/yAd46EOyTBwayS+27NOvz2r3v8WV0YjuplJb1teHmJtoIf
# UVC1va6H668UMrR2Mm5l8GvtcrGmDLjq3FLTLeidco7aj7xtkwUhyXvCS/HzoF9G
# yrYW3NKqIy+KbNXTD8RbwDxKvx3ED9C1SfZi3fi/t1a2wjNsxVqf4XNsO2+JvuuO
# SGTZOoo/3jqtS22IcV5Z3In0D3+C/rigq0179KhwPtztz4+J9MU5gtGmVayF1MH1
# M6GCF7AwghesBgorBgEEAYI3AwMBMYIXnDCCF5gGCSqGSIb3DQEHAqCCF4kwgheF
# AgEDMQ8wDQYJYIZIAWUDBAIBBQAwggFaBgsqhkiG9w0BCRABBKCCAUkEggFFMIIB
# QQIBAQYKKwYBBAGEWQoDATAxMA0GCWCGSAFlAwQCAQUABCDhOUY7jtQW2mTHjZaf
# zhylI7IWKlybklUpfwDq0GnW8AIGaeuhCndSGBMyMDI2MDUxNzAwNDk0OC4wNzFa
# MASAAgH0oIHZpIHWMIHTMQswCQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3Rv
# bjEQMA4GA1UEBxMHUmVkbW9uZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0
# aW9uMS0wKwYDVQQLEyRNaWNyb3NvZnQgSXJlbGFuZCBPcGVyYXRpb25zIExpbWl0
# ZWQxJzAlBgNVBAsTHm5TaGllbGQgVFNTIEVTTjoyQTFBLTA1RTAtRDk0NzElMCMG
# A1UEAxMcTWljcm9zb2Z0IFRpbWUtU3RhbXAgU2VydmljZaCCEf4wggcoMIIFEKAD
# AgECAhMzAAACEKvN5BYY7zmwAAEAAAIQMA0GCSqGSIb3DQEBCwUAMHwxCzAJBgNV
# BAYTAlVTMRMwEQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4w
# HAYDVQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xJjAkBgNVBAMTHU1pY3Jvc29m
# dCBUaW1lLVN0YW1wIFBDQSAyMDEwMB4XDTI1MDgxNDE4NDgxMloXDTI2MTExMzE4
# NDgxMlowgdMxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYD
# VQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xLTAr
# BgNVBAsTJE1pY3Jvc29mdCBJcmVsYW5kIE9wZXJhdGlvbnMgTGltaXRlZDEnMCUG
# A1UECxMeblNoaWVsZCBUU1MgRVNOOjJBMUEtMDVFMC1EOTQ3MSUwIwYDVQQDExxN
# aWNyb3NvZnQgVGltZS1TdGFtcCBTZXJ2aWNlMIICIjANBgkqhkiG9w0BAQEFAAOC
# Ag8AMIICCgKCAgEAjcc4q057ZwIgpKu4pTXWLejvYEduRf+1mIpbiJEMFWWmU2xp
# ip+zK7xFxKGB1CclUXBU0/ZQZ6LG8H0gI7yvosrsPEI1DPB/XccGCvswKbAKckng
# OuGTEPGk7K/vEZa9h0Xt02b7m2n9MdIjkLrFl0pDriKyz0QHGpdh93X6+NApfE1T
# L24Vo0xkeoFGpL3rX9gXhIOF59EMnTd2o45FW/oxMgY9q0y0jGO0HrCLTCZr50e7
# TZRSNYAy2lyKbvKI2MKlN1wLzJvZbbc//L3s1q3J6KhS0KC2VNEImYdFgVkJej4z
# ZqHfScTbx9hjFgFpVkJl4xH5VJ8tyJdXE9+vU0k9AaT2QP1Zm3WQmXedSoLjjI7L
# WznuHwnoGIXLiJMQzPqKqRIFL3wzcrDrZeWgtAdBPbipglZ5CQns6Baj5Mb6a/EZ
# C9G3faJYK5QVHeE6eLoSEwp1dz5WurLXNPsp0VWplpl/FJb8jrRT/jOoHu85qRcd
# YpgByU9W7IWPdrthmyfqeAw0omVWN5JxcogYbLo2pANJHlsMdWnxIpN5YwHbGEPC
# uosBHPk2Xd9+E/pZPQUR6v+D85eEN5A/ZM/xiPpxa8dJZ87BpTvui7/2uflUMJf2
# Yc9ZLPgEdhQQo0LwMDSTDT48y3sV7Pdo+g5q+MqnJztN/6qt1cgUTe9u+ykCAwEA
# AaOCAUkwggFFMB0GA1UdDgQWBBSe42+FrpdF2avbUhlk86BLSH5kejAfBgNVHSME
# GDAWgBSfpxVdAF5iXYP05dJlpxtTNRnpcjBfBgNVHR8EWDBWMFSgUqBQhk5odHRw
# Oi8vd3d3Lm1pY3Jvc29mdC5jb20vcGtpb3BzL2NybC9NaWNyb3NvZnQlMjBUaW1l
# LVN0YW1wJTIwUENBJTIwMjAxMCgxKS5jcmwwbAYIKwYBBQUHAQEEYDBeMFwGCCsG
# AQUFBzAChlBodHRwOi8vd3d3Lm1pY3Jvc29mdC5jb20vcGtpb3BzL2NlcnRzL01p
# Y3Jvc29mdCUyMFRpbWUtU3RhbXAlMjBQQ0ElMjAyMDEwKDEpLmNydDAMBgNVHRMB
# Af8EAjAAMBYGA1UdJQEB/wQMMAoGCCsGAQUFBwMIMA4GA1UdDwEB/wQEAwIHgDAN
# BgkqhkiG9w0BAQsFAAOCAgEAvs4rO3oo8czOrxPqnnSEkUVq718QzlrIiy7/EW7J
# mQXsJoFxHWUF0Ux0PDyKFDRXPJVv29F7kpJkBJJmcQg5HQV7blUXIMWQ1qX0KdtF
# QXI/MRL77Z+pK5x1jX+tbRkA7a5Ft7vWuRoAEi02HpFH5m/Akh/dfsbx8wOpecJb
# YvuHuy4aG0/tGzOWFCxMMNhGAIJ4qdV87JnY/uMBmiodlm+Gz357XWW5tg3HrtNZ
# XuQ0tWUv26ud4nGKJo/oLZHP75p4Rpt7dMdYKUF9AuVFBwxYZYpvgk12tfK+/yOw
# q84/fjXVCdM83Qnawtbenbk/lnbc9KsZom+GnvA4itAMUpSXFWrcRkqdUQLN+JrG
# 6fPBoV8+D8U2Q2F4XkiCR6EU9JzYKwTuvL6t3nFuxnkLdNjbTg2/yv2j3WaDuCK5
# lSPgsndIiH6Bku2Ui3A0aUo6D9z9v+XEuBs9ioVJaOjf/z+Urqg7ESnxG0/T1dKc
# i7vLQ2XNgWFYO+/OlDjtGoma1ijX4m14N9qgrXTuWEGwgC7hhBgp3id/LAOf9BST
# WA5lBrilsEoexXBrOn/1wM3rjG0hIsxvF5/YOK78mVRGY6Y7zYJ+uXt4OTOFBwad
# Pv8MklreQZLPnQPtiwop4rlLUYaPCiD4YUqRNbLp8Sgyo9g0iAcZYznTuc+8Q8ZI
# rgwwggdxMIIFWaADAgECAhMzAAAAFcXna54Cm0mZAAAAAAAVMA0GCSqGSIb3DQEB
# CwUAMIGIMQswCQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UE
# BxMHUmVkbW9uZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMTIwMAYD
# VQQDEylNaWNyb3NvZnQgUm9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkgMjAxMDAe
# Fw0yMTA5MzAxODIyMjVaFw0zMDA5MzAxODMyMjVaMHwxCzAJBgNVBAYTAlVTMRMw
# EQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVN # EQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVN
# aWNyb3NvZnQgQ29ycG9yYXRpb24xKDAmBgNVBAMTH01pY3Jvc29mdCBDb2RlIFNp # aWNyb3NvZnQgQ29ycG9yYXRpb24xJjAkBgNVBAMTHU1pY3Jvc29mdCBUaW1lLVN0
# Z25pbmcgUENBIDIwMTECEzMAAASFXpnsDlkvzdcAAAAABIUwDQYJYIZIAWUDBAIB # YW1wIFBDQSAyMDEwMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA5OGm
# BQCgga4wGQYJKoZIhvcNAQkDMQwGCisGAQQBgjcCAQQwHAYKKwYBBAGCNwIBCzEO # TOe0ciELeaLL1yR5vQ7VgtP97pwHB9KpbE51yMo1V/YBf2xK4OK9uT4XYDP/XE/H
# MAwGCisGAQQBgjcCARUwLwYJKoZIhvcNAQkEMSIEID8/Z0hz8wCpH2YjVYR3wACO # ZveVU3Fa4n5KWv64NmeFRiMMtY0Tz3cywBAY6GB9alKDRLemjkZrBxTzxXb1hlDc
# qi7toMi0S892RCpCiXnDMEIGCisGAQQBgjcCAQwxNDAyoBSAEgBNAGkAYwByAG8A # wUTIcVxRMTegCjhuje3XD9gmU3w5YQJ6xKr9cmmvHaus9ja+NSZk2pg7uhp7M62A
# cwBvAGYAdKEagBhodHRwOi8vd3d3Lm1pY3Jvc29mdC5jb20wDQYJKoZIhvcNAQEB # W36MEBydUv626GIl3GoPz130/o5Tz9bshVZN7928jaTjkY+yOSxRnOlwaQ3KNi1w
# BQAEggEAR3ofVJe8H1PSnVv5GEV/iNRKzDHBYXTNKjw6gaEwywGiLnvok4fIy+o/ # jjHINSi947SHJMPgyY9+tVSP3PoFVZhtaDuaRr3tpK56KTesy+uDRedGbsoy1cCG
# pgoyuM4RLT6jq9o/62LWZPnRCXiQiidnt9u6BtjAQFoy9Hyz39SnG3SIfcXwQU6S # MFxPLOJiss254o2I5JasAUq7vnGpF1tnYN74kpEeHT39IM9zfUGaRnXNxF803RKJ
# Kn6sdIdkCnp9zgCw0A1um1l9ZESP36cub7lCkog6Qd1N+d5KAMuDMHX4MybWYjva # 1v2lIH1+/NmeRd+2ci/bfV+AutuqfjbsNkz2K26oElHovwUDo9Fzpk03dJQcNIIP
# YmW+c3RMH4HoBd6igF/hUaz0VTf+yrdIUaBIJ9UlWTMVkwokmQ9I79IwPU5hHnRu # 8BDyt0cY7afomXw/TNuvXsLz1dhzPUNOwTM5TI4CvEJoLhDqhFFG4tG9ahhaYQFz
# Ao8D6p++BagDKmVHo4bY/ADy4GDn4nrLA09mwd0YQPDZvb3K3Z2rIABM0UdS4+lG # ymeiXtcodgLiMxhy16cg8ML6EgrXY28MyTZki1ugpoMhXV8wdJGUlNi5UPkLiWHz
# c/pZsaRUT7TE8NzWXP+vWQ9bdkhNbaGCF5QwgheQBgorBgEEAYI3AwMBMYIXgDCC # NgY1GIRH29wb0f2y1BzFa/ZcUlFdEtsluq9QBXpsxREdcu+N+VLEhReTwDwV2xo3
# F3wGCSqGSIb3DQEHAqCCF20wghdpAgEDMQ8wDQYJYIZIAWUDBAIBBQAwggFSBgsq # xwgVGD94q0W29R6HXtqPnhZyacaue7e3PmriLq0CAwEAAaOCAd0wggHZMBIGCSsG
# hkiG9w0BCRABBKCCAUEEggE9MIIBOQIBAQYKKwYBBAGEWQoDATAxMA0GCWCGSAFl # AQQBgjcVAQQFAgMBAAEwIwYJKwYBBAGCNxUCBBYEFCqnUv5kxJq+gpE8RjUpzxD/
# AwQCAQUABCAd+KomD6n/vMp0PpchU0Vc9uK1oIZ/s0smWP9W6KAY4QIGaSc7gduW # LwTuMB0GA1UdDgQWBBSfpxVdAF5iXYP05dJlpxtTNRnpcjBcBgNVHSAEVTBTMFEG
# GBMyMDI1MTIxMDIyNDQ0NC41NjdaMASAAgH0oIHRpIHOMIHLMQswCQYDVQQGEwJV # DCsGAQQBgjdMg30BATBBMD8GCCsGAQUFBwIBFjNodHRwOi8vd3d3Lm1pY3Jvc29m
# UzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9uZDEeMBwGA1UE # dC5jb20vcGtpb3BzL0RvY3MvUmVwb3NpdG9yeS5odG0wEwYDVR0lBAwwCgYIKwYB
# ChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMSUwIwYDVQQLExxNaWNyb3NvZnQgQW1l # BQUHAwgwGQYJKwYBBAGCNxQCBAweCgBTAHUAYgBDAEEwCwYDVR0PBAQDAgGGMA8G
# cmljYSBPcGVyYXRpb25zMScwJQYDVQQLEx5uU2hpZWxkIFRTUyBFU046REMwMC0w # A1UdEwEB/wQFMAMBAf8wHwYDVR0jBBgwFoAU1fZWy4/oolxiaNE9lJBb186aGMQw
# NUUwLUQ5NDcxJTAjBgNVBAMTHE1pY3Jvc29mdCBUaW1lLVN0YW1wIFNlcnZpY2Wg # VgYDVR0fBE8wTTBLoEmgR4ZFaHR0cDovL2NybC5taWNyb3NvZnQuY29tL3BraS9j
# ghHqMIIHIDCCBQigAwIBAgITMwAAAgO7HlwAOGx0ygABAAACAzANBgkqhkiG9w0B # cmwvcHJvZHVjdHMvTWljUm9vQ2VyQXV0XzIwMTAtMDYtMjMuY3JsMFoGCCsGAQUF
# AQsFADB8MQswCQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UE # BwEBBE4wTDBKBggrBgEFBQcwAoY+aHR0cDovL3d3dy5taWNyb3NvZnQuY29tL3Br
# BxMHUmVkbW9uZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMSYwJAYD # aS9jZXJ0cy9NaWNSb29DZXJBdXRfMjAxMC0wNi0yMy5jcnQwDQYJKoZIhvcNAQEL
# VQQDEx1NaWNyb3NvZnQgVGltZS1TdGFtcCBQQ0EgMjAxMDAeFw0yNTAxMzAxOTQy # BQADggIBAJ1VffwqreEsH2cBMSRb4Z5yS/ypb+pcFLY+TkdkeLEGk5c9MTO1OdfC
# NDZaFw0yNjA0MjIxOTQyNDZaMIHLMQswCQYDVQQGEwJVUzETMBEGA1UECBMKV2Fz # cTY/2mRsfNB1OW27DzHkwo/7bNGhlBgi7ulmZzpTTd2YurYeeNg2LpypglYAA7AF
# aGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9uZDEeMBwGA1UEChMVTWljcm9zb2Z0IENv # vonoaeC6Ce5732pvvinLbtg/SHUB2RjebYIM9W0jVOR4U3UkV7ndn/OOPcbzaN9l
# cnBvcmF0aW9uMSUwIwYDVQQLExxNaWNyb3NvZnQgQW1lcmljYSBPcGVyYXRpb25z # 9qRWqveVtihVJ9AkvUCgvxm2EhIRXT0n4ECWOKz3+SmJw7wXsFSFQrP8DJ6LGYnn
# MScwJQYDVQQLEx5uU2hpZWxkIFRTUyBFU046REMwMC0wNUUwLUQ5NDcxJTAjBgNV # 8AtqgcKBGUIZUnWKNsIdw2FzLixre24/LAl4FOmRsqlb30mjdAy87JGA0j3mSj5m
# BAMTHE1pY3Jvc29mdCBUaW1lLVN0YW1wIFNlcnZpY2UwggIiMA0GCSqGSIb3DQEB # O0+7hvoyGtmW9I/2kQH2zsZ0/fZMcm8Qq3UwxTSwethQ/gpY3UA8x1RtnWN0SCyx
# AQUAA4ICDwAwggIKAoICAQChl0MH5wAnOx8Uh8RtidF0J0yaFDHJYHTpPvRR16X1 # TkctwRQEcb9k+SS+c23Kjgm9swFXSVRk2XPXfx5bRAGOWhmRaw2fpCjcZxkoJLo4
# KxGDYfT8PrcGjCLCiaOu3K1DmUIU4Rc5olndjappNuOgzwUoj43VbbJx5PFTY/a1 # S5pu+yFUa2pFEUep8beuyOiJXk+d0tBMdrVXVAmxaQFEfnyhYWxz/gq77EFmPWn9
# Z80tpqVP0OoKJlUkfDPSBLFgXWj6VgayRCINtLsUasy0w5gysD7ILPZuiQjace5K # y8FBSX5+k77L+DvktxW/tM4+pTFRhLy/AsGConsXHRWJjXD+57XQKBqJC4822rpM
# xASjKf2MVX1qfEzYBbTGNEijSQCKwwyc0eavr4Fo3X/+sCuuAtkTWissU64k8rK6 # +Zv/Cuk0+CQ1ZyvgDbjmjJnW4SLq8CdCPSWU5nR0W2rRnj7tfqAxM328y+l7vzhw
# 0jsGRApiESdfuHr0yWAmc7jTOPNeGAx6KCL2ktpnGegLDd1IlE6Bu6BSwAIFHr7z # RNGQ8cirOoo6CGJ/2XBjU02N7oJtpQUQwXEGahC0HVUzWLOhcGbyoYIDWTCCAkEC
# OwIlFqyQuCe0SQALCbJhsT9y9iy61RJAXsU0u0TC5YYmTSbEI7g10dYx8Uj+vh9I # AQEwggEBoYHZpIHWMIHTMQswCQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3Rv
# nLoKYC5DpKb311bYVd0bytbzlfTRslRTJgotnfCAIGMLqEqk9/2VRGu9klJi1j9n # bjEQMA4GA1UEBxMHUmVkbW9uZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0
# VfqyYHYrMPOBXcrQYW0jmKNjOL47CaEArNzhDBia1wXdJANKqMvJ8pQe2m8/ciby # aW9uMS0wKwYDVQQLEyRNaWNyb3NvZnQgSXJlbGFuZCBPcGVyYXRpb25zIExpbWl0
# DM+1BVZquNAov9N4tJF4ACtjX0jjXNDUMtSZoVFQH+FkWdfPWx1uBIkc97R+xRLu # ZWQxJzAlBgNVBAsTHm5TaGllbGQgVFNTIEVTTjoyQTFBLTA1RTAtRDk0NzElMCMG
# PjUypHZ5A3AALSke4TaRBvbvTBYyW2HenOT7nYLKTO4jw5Qq6cw3Z9zTKSPQ6D5l # A1UEAxMcTWljcm9zb2Z0IFRpbWUtU3RhbXAgU2VydmljZaIjCgEBMAcGBSsOAwIa
# yiYpes5RR2MdMvJS4fCcPJFeaVOvuWFSQ/EGtVBShhmLB+5ewzFzdpf1UuJmuOQT # AxUAOsyf2b6riPKnnXlIgIL2f53PUsKggYMwgYCkfjB8MQswCQYDVQQGEwJVUzET
# TwIDAQABo4IBSTCCAUUwHQYDVR0OBBYEFLIpWUB+EeeQ29sWe0VdzxWQGJJ9MB8G # MBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9uZDEeMBwGA1UEChMV
# A1UdIwQYMBaAFJ+nFV0AXmJdg/Tl0mWnG1M1GelyMF8GA1UdHwRYMFYwVKBSoFCG # TWljcm9zb2Z0IENvcnBvcmF0aW9uMSYwJAYDVQQDEx1NaWNyb3NvZnQgVGltZS1T
# Tmh0dHA6Ly93d3cubWljcm9zb2Z0LmNvbS9wa2lvcHMvY3JsL01pY3Jvc29mdCUy # dGFtcCBQQ0EgMjAxMDANBgkqhkiG9w0BAQsFAAIFAO2zHvgwIhgPMjAyNjA1MTYx
# MFRpbWUtU3RhbXAlMjBQQ0ElMjAyMDEwKDEpLmNybDBsBggrBgEFBQcBAQRgMF4w # NjUxMDRaGA8yMDI2MDUxNzE2NTEwNFowdzA9BgorBgEEAYRZCgQBMS8wLTAKAgUA
# XAYIKwYBBQUHMAKGUGh0dHA6Ly93d3cubWljcm9zb2Z0LmNvbS9wa2lvcHMvY2Vy # 7bMe+AIBADAKAgEAAgIhcwIB/zAHAgEAAgISqjAKAgUA7bRweAIBADA2BgorBgEE
# dHMvTWljcm9zb2Z0JTIwVGltZS1TdGFtcCUyMFBDQSUyMDIwMTAoMSkuY3J0MAwG # AYRZCgQCMSgwJjAMBgorBgEEAYRZCgMCoAowCAIBAAIDB6EgoQowCAIBAAIDAYag
# A1UdEwEB/wQCMAAwFgYDVR0lAQH/BAwwCgYIKwYBBQUHAwgwDgYDVR0PAQH/BAQD # MA0GCSqGSIb3DQEBCwUAA4IBAQBjb6eELCy7c+QKNzPmI4O0riW248wi0uSI0DKx
# AgeAMA0GCSqGSIb3DQEBCwUAA4ICAQCQEMbesD6TC08R0oYCdSC452AQrGf/O89G # /ZRwZgOShcyQUcjn6Q/SGMTQ9cqeJe/IhyZbzUCTATtImhIybXreibtT2cAMO4M6
# Q54CtgEsbxzwGDVUcmjXFcnaJSTNedBKVXkBgawRonP1LgxH4bzzVj2eWNmzGIwO # 3gGHvd96iu8Q49zOYR182At7wmlUTeMrsj51LpZkWCUy4ZSeOSri83Aong5MKGMF
# 1FlhldAPOHAzLBEHRoSZ4pddFtaQxoabU/N1vWyICiN60It85gnF5JD4MMXyd6pS # Kt2xnKiSYL2tXIm0zcTpX8xjXMMWFb7wa0CBnHn5ZMYJVtuntxE1B4wJyMZktBS6
# 8eADIi6TtjfgKPoumWa0BFQ/aEzjUrfPN1r7crK+qkmLztw/ENS7zemfyx4kGRgw # WkP9XpGCXB1X7VhYM3vvtBFq2vA5neloI7waPPPTU+0hK6IX7+c1U776yDnJW4jc
# Y1WBfFqm/nFlJDPQBicqeU3dOp9hj7WqD0Rc+/4VZ6wQjesIyCkv5uhUNy2LhNDi # OUJsj8rjwrS+Gc/gPt98V3kMoGvxG0eGEzdjkmblUlhT1FwpMYIEDTCCBAkCAQEw
# 2leYtAiIFpmjfNk4GngLvC2Tj9IrOMv20Srym5J/Fh7yWAiPeGs3yA3QapjZTtfr # gZMwfDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCldhc2hpbmd0b24xEDAOBgNVBAcT
# 7NfzpBIJQ4xT/ic4WGWqhGlRlVBI5u6Ojw3ZxSZCLg3vRC4KYypkh8FdIWoKirji # B1JlZG1vbmQxHjAcBgNVBAoTFU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjEmMCQGA1UE
# dEGlXsNOo+UP/YG5KhebiudTBxGecfJCuuUspIdRhStHAQsjv/dAqWBLlhorq2OC # AxMdTWljcm9zb2Z0IFRpbWUtU3RhbXAgUENBIDIwMTACEzMAAAIQq83kFhjvObAA
# aP+wFhE3WPgnnx5pflvlujocPgsN24++ddHrl3O1FFabW8m0UkDHSKCh8QTwTkYO # AQAAAhAwDQYJYIZIAWUDBAIBBQCgggFKMBoGCSqGSIb3DQEJAzENBgsqhkiG9w0B
# wu99iExBVWlbYZRz2qOIBjL/ozEhtCB0auKhfTLLeuNGBUaBz+oZZ+X9UAECoMhk # CRABBDAvBgkqhkiG9w0BCQQxIgQgn7/AUpcQFhG3OcHi0Aeq56NC1uclpcmcCkGu
# ETjb6YfNaI1T7vVAaiuhBoV/JCOQT+RYZrgykyPpzpmwMNFBD1vdW/29q9nkTWoE # +HK5un4wgfoGCyqGSIb3DQEJEAIvMYHqMIHnMIHkMIG9BCDD1SHufsjzY59S1iHU
# hcEOO0L9NzCCB3EwggVZoAMCAQICEzMAAAAVxedrngKbSZkAAAAAABUwDQYJKoZI # QY9hnsKSrJPg5a9Mc4YnGmPHxjCBmDCBgKR+MHwxCzAJBgNVBAYTAlVTMRMwEQYD
# hvcNAQELBQAwgYgxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpXYXNoaW5ndG9uMRAw
# DgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24x
# MjAwBgNVBAMTKU1pY3Jvc29mdCBSb290IENlcnRpZmljYXRlIEF1dGhvcml0eSAy
# MDEwMB4XDTIxMDkzMDE4MjIyNVoXDTMwMDkzMDE4MzIyNVowfDELMAkGA1UEBhMC
# VVMxEzARBgNVBAgTCldhc2hpbmd0b24xEDAOBgNVBAcTB1JlZG1vbmQxHjAcBgNV
# BAoTFU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjEmMCQGA1UEAxMdTWljcm9zb2Z0IFRp
# bWUtU3RhbXAgUENBIDIwMTAwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoIC
# AQDk4aZM57RyIQt5osvXJHm9DtWC0/3unAcH0qlsTnXIyjVX9gF/bErg4r25Phdg
# M/9cT8dm95VTcVrifkpa/rg2Z4VGIwy1jRPPdzLAEBjoYH1qUoNEt6aORmsHFPPF
# dvWGUNzBRMhxXFExN6AKOG6N7dcP2CZTfDlhAnrEqv1yaa8dq6z2Nr41JmTamDu6
# GnszrYBbfowQHJ1S/rboYiXcag/PXfT+jlPP1uyFVk3v3byNpOORj7I5LFGc6XBp
# Dco2LXCOMcg1KL3jtIckw+DJj361VI/c+gVVmG1oO5pGve2krnopN6zL64NF50Zu
# yjLVwIYwXE8s4mKyzbnijYjklqwBSru+cakXW2dg3viSkR4dPf0gz3N9QZpGdc3E
# XzTdEonW/aUgfX782Z5F37ZyL9t9X4C626p+Nuw2TPYrbqgSUei/BQOj0XOmTTd0
# lBw0gg/wEPK3Rxjtp+iZfD9M269ewvPV2HM9Q07BMzlMjgK8QmguEOqEUUbi0b1q
# GFphAXPKZ6Je1yh2AuIzGHLXpyDwwvoSCtdjbwzJNmSLW6CmgyFdXzB0kZSU2LlQ
# +QuJYfM2BjUYhEfb3BvR/bLUHMVr9lxSUV0S2yW6r1AFemzFER1y7435UsSFF5PA
# PBXbGjfHCBUYP3irRbb1Hode2o+eFnJpxq57t7c+auIurQIDAQABo4IB3TCCAdkw
# EgYJKwYBBAGCNxUBBAUCAwEAATAjBgkrBgEEAYI3FQIEFgQUKqdS/mTEmr6CkTxG
# NSnPEP8vBO4wHQYDVR0OBBYEFJ+nFV0AXmJdg/Tl0mWnG1M1GelyMFwGA1UdIARV
# MFMwUQYMKwYBBAGCN0yDfQEBMEEwPwYIKwYBBQUHAgEWM2h0dHA6Ly93d3cubWlj
# cm9zb2Z0LmNvbS9wa2lvcHMvRG9jcy9SZXBvc2l0b3J5Lmh0bTATBgNVHSUEDDAK
# BggrBgEFBQcDCDAZBgkrBgEEAYI3FAIEDB4KAFMAdQBiAEMAQTALBgNVHQ8EBAMC
# AYYwDwYDVR0TAQH/BAUwAwEB/zAfBgNVHSMEGDAWgBTV9lbLj+iiXGJo0T2UkFvX
# zpoYxDBWBgNVHR8ETzBNMEugSaBHhkVodHRwOi8vY3JsLm1pY3Jvc29mdC5jb20v
# cGtpL2NybC9wcm9kdWN0cy9NaWNSb29DZXJBdXRfMjAxMC0wNi0yMy5jcmwwWgYI
# KwYBBQUHAQEETjBMMEoGCCsGAQUFBzAChj5odHRwOi8vd3d3Lm1pY3Jvc29mdC5j
# b20vcGtpL2NlcnRzL01pY1Jvb0NlckF1dF8yMDEwLTA2LTIzLmNydDANBgkqhkiG
# 9w0BAQsFAAOCAgEAnVV9/Cqt4SwfZwExJFvhnnJL/Klv6lwUtj5OR2R4sQaTlz0x
# M7U518JxNj/aZGx80HU5bbsPMeTCj/ts0aGUGCLu6WZnOlNN3Zi6th542DYunKmC
# VgADsAW+iehp4LoJ7nvfam++Kctu2D9IdQHZGN5tggz1bSNU5HhTdSRXud2f8449
# xvNo32X2pFaq95W2KFUn0CS9QKC/GbYSEhFdPSfgQJY4rPf5KYnDvBewVIVCs/wM
# nosZiefwC2qBwoEZQhlSdYo2wh3DYXMuLGt7bj8sCXgU6ZGyqVvfSaN0DLzskYDS
# PeZKPmY7T7uG+jIa2Zb0j/aRAfbOxnT99kxybxCrdTDFNLB62FD+CljdQDzHVG2d
# Y3RILLFORy3BFARxv2T5JL5zbcqOCb2zAVdJVGTZc9d/HltEAY5aGZFrDZ+kKNxn
# GSgkujhLmm77IVRrakURR6nxt67I6IleT53S0Ex2tVdUCbFpAUR+fKFhbHP+Crvs
# QWY9af3LwUFJfn6Tvsv4O+S3Fb+0zj6lMVGEvL8CwYKiexcdFYmNcP7ntdAoGokL
# jzbaukz5m/8K6TT4JDVnK+ANuOaMmdbhIurwJ0I9JZTmdHRbatGePu1+oDEzfbzL
# 6Xu/OHBE0ZDxyKs6ijoIYn/ZcGNTTY3ugm2lBRDBcQZqELQdVTNYs6FwZvKhggNN
# MIICNQIBATCB+aGB0aSBzjCByzELMAkGA1UEBhMCVVMxEzARBgNVBAgTCldhc2hp
# bmd0b24xEDAOBgNVBAcTB1JlZG1vbmQxHjAcBgNVBAoTFU1pY3Jvc29mdCBDb3Jw
# b3JhdGlvbjElMCMGA1UECxMcTWljcm9zb2Z0IEFtZXJpY2EgT3BlcmF0aW9uczEn
# MCUGA1UECxMeblNoaWVsZCBUU1MgRVNOOkRDMDAtMDVFMC1EOTQ3MSUwIwYDVQQD
# ExxNaWNyb3NvZnQgVGltZS1TdGFtcCBTZXJ2aWNloiMKAQEwBwYFKw4DAhoDFQDN
# rxRX/iz6ss1lBCXG8P1LFxD0e6CBgzCBgKR+MHwxCzAJBgNVBAYTAlVTMRMwEQYD
# VQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNy # VQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNy
# b3NvZnQgQ29ycG9yYXRpb24xJjAkBgNVBAMTHU1pY3Jvc29mdCBUaW1lLVN0YW1w # b3NvZnQgQ29ycG9yYXRpb24xJjAkBgNVBAMTHU1pY3Jvc29mdCBUaW1lLVN0YW1w
# IFBDQSAyMDEwMA0GCSqGSIb3DQEBCwUAAgUA7OQtPTAiGA8yMDI1MTIxMDE3MzI0 # IFBDQSAyMDEwAhMzAAACEKvN5BYY7zmwAAEAAAIQMCIEIC5b102d224evVIH68x9
# NVoYDzIwMjUxMjExMTczMjQ1WjB0MDoGCisGAQQBhFkKBAExLDAqMAoCBQDs5C09 # lEf8Au5vChR0bDNP4SViDwl6MA0GCSqGSIb3DQEBCwUABIICAHMgBiQOozDAIR+S
# AgEAMAcCAQACAgjlMAcCAQACAhNOMAoCBQDs5X69AgEAMDYGCisGAQQBhFkKBAIx # O28IjquhCukrxIucbxjLUxu4ltpxavA+cedbwkdNPAMFAYEaLHeEYutciK6N5f4R
# KDAmMAwGCisGAQQBhFkKAwKgCjAIAgEAAgMHoSChCjAIAgEAAgMBhqAwDQYJKoZI # VIJX/OSx2ZL6ac/xB5A/7rdoaHV7PK+F1y807INXMA2HPnJGDVbi7HD7nJp26Fuz
# hvcNAQELBQADggEBAFXCcBVLkxGEigIad7gAMsj2+SQdBANpzq4qPJXOu81TM3HC # P2K3aGE3kK06C2jXsjdqWsAZv32k1daX+OqFGJdOsmmua/qlF0AMWTXL7rsBStOH
# rAkCUTm3FRNc6YPdpfvl07lGlv/NHFCLyXL20d6PZ/1wlF5+WR2OvWjrktwDxYv8 # 5YI/KXtAsd9vvUbqcCMGeGmnRk6V7NmsKbQIkZ3kDk6YfKoZWmSknCKHF6LzCPkI
# cZqk7BrV9SB8xBe/GwVi7smKmlXhznqA6lFPO+VNfOwWcxn0H2yxEsAJKyDmgx/7 # bZSI8PNhcn19VUl9VS4WXGyWeGG5zBkOXnImAIKlaLMxR8Z9/kQVx84TrsDBl6Yh
# M8xnMTKeK8ulgSy4EoyGgFIO+nGHqxS0yaXe+OgzErkaavB1Qw7jfmm5/wlBCnwz # 34t6ISVDkQtre8SBG6fdjyWKmCOSntciVUlEom8ZwkadixIaf8nOoUJSYq5fl+4J
# 0UsbaequeL9UjA6FUw3Cc3F+3/D38BzyjJtTxjUVn+QiVWwOfikRJ2F7oZwpsJo3 # HkcUaY79lJKL5DiENwdC4Lt6eNabRo3SPbQE7IQWbWx5h3et1QDitsZ7Gg9yAHaZ
# yNIVpwJFpIV6VsqtxzaF0KQZBpS2lBGxVA17pFcxggQNMIIECQIBATCBkzB8MQsw # LS/t/SIAy+OXLXNxyttcyrbDvFI8A8tFE9P1w+3MC1n2cveqd6Wu07Z4l74Mj0LX
# CQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9u # yR+0h/KjfE6SPaL+N20E4CjM0bxRKZ+CuFj/A3tykEADdzFtsEfzUzTDkD3cJpOj
# ZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMSYwJAYDVQQDEx1NaWNy # fojWQNX1ly8Tu3G/WdAFqzrln2y8jCbVdPIqo1ntbu+BbYom1VQqAihYQB855+pG
# b3NvZnQgVGltZS1TdGFtcCBQQ0EgMjAxMAITMwAAAgO7HlwAOGx0ygABAAACAzAN # D8bOWbnrvhUua7gDFFDA762iZMxD
# BglghkgBZQMEAgEFAKCCAUowGgYJKoZIhvcNAQkDMQ0GCyqGSIb3DQEJEAEEMC8G
# CSqGSIb3DQEJBDEiBCApggCahSc04fWyIz1KF4aeejwqHefyj2gzz7p9QsluFTCB
# +gYLKoZIhvcNAQkQAi8xgeowgecwgeQwgb0EIEsD3RtxlvaTxFOZZnpQw0DksPmV
# duo5SyK9h9w++hMtMIGYMIGApH4wfDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCldh
# c2hpbmd0b24xEDAOBgNVBAcTB1JlZG1vbmQxHjAcBgNVBAoTFU1pY3Jvc29mdCBD
# b3Jwb3JhdGlvbjEmMCQGA1UEAxMdTWljcm9zb2Z0IFRpbWUtU3RhbXAgUENBIDIw
# MTACEzMAAAIDux5cADhsdMoAAQAAAgMwIgQgwIRXpw5w7cRbWSfOFZ15Z2Nf90Hi
# Ms/hZSpx+kv4aHcwDQYJKoZIhvcNAQELBQAEggIAM+zwgqPLhBOAumqVnUO/YRh7
# sePgzUWqveSw/J01TAD8JVXufiGmu4neLrGFki/Nz8ytun2DhJP/3xDRu39y/9Pb
# t2qKabzaoASwH95fTjHLYEp0PhqkEZ1hkaaYjVC3TAG0LgU2mrvkEjL3doD5MXu8
# WWQGcnB0Wera/3POf4ylyQbUUnzo/Pl9qUbjPVW/JouzzDzijObLcYp7IDgIDxGL
# sVJqMgzP1ZWBWsjjx4J0YiYORUnIVKWKPXt/0O3X9VO3zDfOnWRLF8mJj+ybEnqa
# Wd8LxLJnCxpmTAjtELLgC46UB0N4GHR0+ymSba35Ciz4Kzc+7R9E1Ajy1yd2rmGR
# M2u/eAV8MvKybIzgTd9Lukk9KJ5lvzV52CuYyzHOzYgcNt/mFgvM6gfMAef3CeN0
# EU7ECvTEYqno7krSRi6+HD+R14+7EwXbiR0E+KAB2Ppgj7GqHWKeL/Owyv0A1oEa
# 4ocdqMApLcY908U7IzNu5qo7PPas/RBsB9J52++fyZ/9RyP31IYKu8/5xI5Ef7aH
# XIopbEpuMHpHeuWlYWlfkULa5tjk4iPVCTRVsgn7IimLY/wgVOLL4ueOzZZ6aNws
# Q37w/ocvXIH/qXUllulfh5vINVYqXK3d+l0QT8LCMIxXpJSSgtcFcPJG6aSdOFRQ
# r6EOj+C9DH5MueMd9SY=
# SIG # End signature block # SIG # End signature block

View File

@@ -1003,12 +1003,12 @@ copy_files_or_dirs_from_list() {
cat | uniq | while read -r file_path; do cat | uniq | while read -r file_path; do
local path="$(remove_beginning_slash "${file_path#$root_path}")" local path="$(remove_beginning_slash "${file_path#$root_path}")"
local target="$out_path/$path" local target="$out_path/$path"
if [ "$override" = true ] || (! ([ -d "$target" ] || [ -e "$target" ])); then if [ "$override" = true ] || (! ([ -d "$target" ] || [ -e "$target" ] || [ -L "$target" ])); then
mkdir -p "$out_path/$(dirname "$path")" mkdir -p "$out_path/$(dirname "$path")"
if [ -d "$target" ]; then if [ -d "$target" ] || [ -L "$target" ]; then
rm -rf "$target" rm -rf "$target"
fi fi
cp -R $override_switch "$root_path/$path" "$target" cp -RP $override_switch "$root_path/$path" "$target"
fi fi
done done
} }
@@ -1053,8 +1053,8 @@ extract_dotnet_package() {
tar -xzf "$zip_path" -C "$temp_out_path" > /dev/null || failed=true tar -xzf "$zip_path" -C "$temp_out_path" > /dev/null || failed=true
local folders_with_version_regex='^.*/[0-9]+\.[0-9]+[^/]+/' local folders_with_version_regex='^.*/[0-9]+\.[0-9]+[^/]+/'
find "$temp_out_path" -type f | grep -Eo "$folders_with_version_regex" | sort | copy_files_or_dirs_from_list "$temp_out_path" "$out_path" false find "$temp_out_path" \( -type f -o -type l \) | grep -Eo "$folders_with_version_regex" | sort | copy_files_or_dirs_from_list "$temp_out_path" "$out_path" false
find "$temp_out_path" -type f | grep -Ev "$folders_with_version_regex" | copy_files_or_dirs_from_list "$temp_out_path" "$out_path" "$override_non_versioned_files" find "$temp_out_path" \( -type f -o -type l \) | grep -Ev "$folders_with_version_regex" | copy_files_or_dirs_from_list "$temp_out_path" "$out_path" "$override_non_versioned_files"
validate_remote_local_file_sizes "$zip_path" "$remote_file_size" validate_remote_local_file_sizes "$zip_path" "$remote_file_size"

4
package-lock.json generated
View File

@@ -1,12 +1,12 @@
{ {
"name": "setup-dotnet", "name": "setup-dotnet",
"version": "5.0.1", "version": "5.3.0",
"lockfileVersion": 3, "lockfileVersion": 3,
"requires": true, "requires": true,
"packages": { "packages": {
"": { "": {
"name": "setup-dotnet", "name": "setup-dotnet",
"version": "5.0.1", "version": "5.3.0",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@actions/cache": "^5.0.5", "@actions/cache": "^5.0.5",

View File

@@ -1,6 +1,6 @@
{ {
"name": "setup-dotnet", "name": "setup-dotnet",
"version": "5.0.1", "version": "5.3.0",
"private": true, "private": true,
"description": "setup dotnet action", "description": "setup dotnet action",
"main": "dist/setup/index.js", "main": "dist/setup/index.js",

View File

@@ -125,7 +125,22 @@ export class DotnetVersionResolver {
} else if (this.isNumericTag(major) && this.isNumericTag(minor)) { } else if (this.isNumericTag(major) && this.isNumericTag(minor)) {
this.resolvedArgument.value = `${major}.${minor}`; this.resolvedArgument.value = `${major}.${minor}`;
} else if (this.isNumericTag(major)) { } else if (this.isNumericTag(major)) {
this.resolvedArgument.value = await this.getLatestByMajorTag(major); // Starting with .NET 5, the minor version is always zero.
// Hardcode the earlier versions because they will not get new releases.
switch (major) {
case '1':
this.resolvedArgument.value = '1.1';
break;
case '2':
this.resolvedArgument.value = '2.2';
break;
case '3':
this.resolvedArgument.value = '3.1';
break;
default:
this.resolvedArgument.value = `${major}.0`;
break;
}
} else { } else {
// If "dotnet-version" is specified as *, x or X resolve latest version of .NET explicitly from LTS channel. The version argument will default to "latest" by install-dotnet script. // If "dotnet-version" is specified as *, x or X resolve latest version of .NET explicitly from LTS channel. The version argument will default to "latest" by install-dotnet script.
this.resolvedArgument.value = 'LTS'; this.resolvedArgument.value = 'LTS';
@@ -207,33 +222,6 @@ export class DotnetVersionResolver {
return releasesInfo[0]['channel-version']; return releasesInfo[0]['channel-version'];
} }
private async getLatestByMajorTag(majorTag: string): Promise<string> {
const httpClient = new hc.HttpClient('actions/setup-dotnet', [], {
allowRetries: true,
maxRetries: 3
});
const response = await httpClient.getJson<any>(
DotnetVersionResolver.DotnetCoreIndexUrl
);
const result = response.result || {};
const releasesInfo: any[] = result['releases-index'];
const releaseInfo = releasesInfo.find(info => {
const sdkParts: string[] = info['channel-version'].split('.');
return sdkParts[0] === majorTag;
});
if (!releaseInfo) {
throw new Error(
`Could not find info for version with major tag: "${majorTag}" at ${DotnetVersionResolver.DotnetCoreIndexUrl}`
);
}
return releaseInfo['channel-version'];
}
static DotnetCoreIndexUrl = static DotnetCoreIndexUrl =
'https://builds.dotnet.microsoft.com/dotnet/release-metadata/releases-index.json'; 'https://builds.dotnet.microsoft.com/dotnet/release-metadata/releases-index.json';
} }

View File

@@ -207,9 +207,27 @@ function getVersionFromGlobalJson(globalJsonPath: string): string {
if (globalJson.sdk && globalJson.sdk.version) { if (globalJson.sdk && globalJson.sdk.version) {
version = globalJson.sdk.version; version = globalJson.sdk.version;
const rollForward = globalJson.sdk.rollForward; const rollForward = globalJson.sdk.rollForward;
if (rollForward && rollForward === 'latestFeature') { if (rollForward) {
const [major, minor] = version.split('.'); const [major, minor, featurePatch] = version.split('.');
const feature = featurePatch.substring(0, 1);
switch (rollForward) {
case 'latestMajor':
version = '';
break;
case 'latestMinor':
version = `${major}`;
break;
case 'latestFeature':
version = `${major}.${minor}`; version = `${major}.${minor}`;
break;
case 'latestPatch':
version = `${major}.${minor}.${feature}xx`;
break;
}
} }
} }
return version; return version;