You've already forked setup-dotnet
							
							
				mirror of
				https://github.com/actions/setup-dotnet.git
				synced 2025-11-04 08:56:35 +07:00 
			
		
		
		
	Compare commits
	
		
			2 Commits
		
	
	
		
			v2.2.1
			...
			remove-fal
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 8bcd8d8b49 | |||
| 0b32034241 | 
							
								
								
									
										2
									
								
								.github/workflows/workflow.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								.github/workflows/workflow.yml
									
									
									
									
										vendored
									
									
								
							@ -227,7 +227,7 @@ jobs:
 | 
			
		||||
    runs-on: ubuntu-22.04
 | 
			
		||||
    env:
 | 
			
		||||
      https_proxy: http://no-such-proxy:3128
 | 
			
		||||
      no_proxy: github.com,download.visualstudio.microsoft.com,api.nuget.org,builds.dotnet.microsoft.com,ci.dot.net
 | 
			
		||||
      no_proxy: github.com,dotnetcli.blob.core.windows.net,download.visualstudio.microsoft.com,api.nuget.org,dotnetcli.azureedge.net
 | 
			
		||||
    steps:
 | 
			
		||||
      - name: Checkout
 | 
			
		||||
        uses: actions/checkout@v3
 | 
			
		||||
 | 
			
		||||
@ -1,340 +1,336 @@
 | 
			
		||||
import io = require('@actions/io');
 | 
			
		||||
import fs = require('fs');
 | 
			
		||||
import path = require('path');
 | 
			
		||||
 | 
			
		||||
const fakeSourcesDirForTesting = path.join(
 | 
			
		||||
  __dirname,
 | 
			
		||||
  'runner',
 | 
			
		||||
  path.join(
 | 
			
		||||
    Math.random()
 | 
			
		||||
      .toString(36)
 | 
			
		||||
      .substring(7)
 | 
			
		||||
  ),
 | 
			
		||||
  's'
 | 
			
		||||
);
 | 
			
		||||
 | 
			
		||||
const invalidNuGetConfig: string = `<?xml version="1.0" encoding="utf-8"?>`;
 | 
			
		||||
 | 
			
		||||
const emptyNuGetConfig: string = `<?xml version="1.0" encoding="utf-8"?>
 | 
			
		||||
<configuration>
 | 
			
		||||
</configuration>`;
 | 
			
		||||
 | 
			
		||||
const nugetorgNuGetConfig: string = `<?xml version="1.0" encoding="utf-8"?>
 | 
			
		||||
<configuration>
 | 
			
		||||
  <packageSources>
 | 
			
		||||
    <add key="nuget.org" value="https://api.nuget.org/v3/index.json" protocolVersion="3" />
 | 
			
		||||
  </packageSources>
 | 
			
		||||
</configuration>`;
 | 
			
		||||
 | 
			
		||||
const gprnugetorgNuGetConfig: string = `<?xml version="1.0" encoding="utf-8"?>
 | 
			
		||||
<configuration>
 | 
			
		||||
  <packageSources>
 | 
			
		||||
    <add key="GPR" value="https://nuget.pkg.github.com/OwnerName/index.json" protocolVersion="3" />
 | 
			
		||||
    <add key="nuget.org" value="https://api.nuget.org/v3/index.json" protocolVersion="3" />
 | 
			
		||||
  </packageSources>
 | 
			
		||||
</configuration>`;
 | 
			
		||||
 | 
			
		||||
const gprNuGetConfig: string = `<?xml version="1.0" encoding="utf-8"?>
 | 
			
		||||
<configuration>
 | 
			
		||||
  <packageSources>
 | 
			
		||||
    <add key="GPR" value="https://nuget.pkg.github.com/OwnerName/index.json" protocolVersion="3" />
 | 
			
		||||
  </packageSources>
 | 
			
		||||
</configuration>`;
 | 
			
		||||
 | 
			
		||||
const twogprNuGetConfig: string = `<?xml version="1.0" encoding="utf-8"?>
 | 
			
		||||
<configuration>
 | 
			
		||||
  <packageSources>
 | 
			
		||||
    <add key="GPR-GitHub" value="https://nuget.pkg.github.com/OwnerName/index.json" protocolVersion="3" />
 | 
			
		||||
    <add key="GPR-Actions" value="https://nuget.pkg.github.com/actions/index.json" protocolVersion="3" />
 | 
			
		||||
  </packageSources>
 | 
			
		||||
</configuration>`;
 | 
			
		||||
 | 
			
		||||
const spaceNuGetConfig: string = `<?xml version="1.0" encoding="utf-8"?>
 | 
			
		||||
<configuration>
 | 
			
		||||
  <packageSources>
 | 
			
		||||
    <add key="GPR GitHub" value="https://nuget.pkg.github.com/OwnerName/index.json" protocolVersion="3" />
 | 
			
		||||
  </packageSources>
 | 
			
		||||
</configuration>`;
 | 
			
		||||
 | 
			
		||||
const azureartifactsNuGetConfig: string = `<?xml version="1.0" encoding="utf-8"?>
 | 
			
		||||
<configuration>
 | 
			
		||||
  <packageSources>
 | 
			
		||||
    <add key="AzureArtifacts" value="https://pkgs.dev.azure.com/amullans/_packaging/GitHubBuilds/nuget/v3/index.json" protocolVersion="3" />
 | 
			
		||||
  </packageSources>
 | 
			
		||||
</configuration>`;
 | 
			
		||||
 | 
			
		||||
const azureartifactsnugetorgNuGetConfig: string = `<?xml version="1.0" encoding="utf-8"?>
 | 
			
		||||
<configuration>
 | 
			
		||||
  <packageSources>
 | 
			
		||||
    <add key="AzureArtifacts" value="https://pkgs.dev.azure.com/amullans/_packaging/GitHubBuilds/nuget/v3/index.json" protocolVersion="3" />
 | 
			
		||||
    <add key="nuget.org" value="https://api.nuget.org/v3/index.json" protocolVersion="3" />
 | 
			
		||||
  </packageSources>
 | 
			
		||||
</configuration>`;
 | 
			
		||||
 | 
			
		||||
// We want a NuGet.config one level above the sources directory, so it doesn't trample a user's NuGet.config but is still picked up by NuGet/dotnet.
 | 
			
		||||
const nugetConfigFile = path.join(fakeSourcesDirForTesting, '../nuget.config');
 | 
			
		||||
 | 
			
		||||
process.env['GITHUB_REPOSITORY'] = 'OwnerName/repo';
 | 
			
		||||
import * as auth from '../src/authutil';
 | 
			
		||||
 | 
			
		||||
describe('authutil tests', () => {
 | 
			
		||||
  beforeEach(async () => {
 | 
			
		||||
    await io.rmRF(fakeSourcesDirForTesting);
 | 
			
		||||
    await io.mkdirP(fakeSourcesDirForTesting);
 | 
			
		||||
  }, 30000);
 | 
			
		||||
 | 
			
		||||
  afterAll(async () => {
 | 
			
		||||
    await io.rmRF(fakeSourcesDirForTesting);
 | 
			
		||||
  }, 30000);
 | 
			
		||||
 | 
			
		||||
  beforeEach(() => {
 | 
			
		||||
    if (fs.existsSync(nugetConfigFile)) {
 | 
			
		||||
      fs.unlinkSync(nugetConfigFile);
 | 
			
		||||
    }
 | 
			
		||||
    process.env['INPUT_OWNER'] = '';
 | 
			
		||||
    process.env['NUGET_AUTH_TOKEN'] = '';
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  it('No existing config, sets up a full NuGet.config with URL and user/PAT for GPR', async () => {
 | 
			
		||||
    process.env['NUGET_AUTH_TOKEN'] = 'TEST_FAKE_AUTH_TOKEN';
 | 
			
		||||
    await auth.configAuthentication(
 | 
			
		||||
      'https://nuget.pkg.github.com/OwnerName/index.json',
 | 
			
		||||
      '',
 | 
			
		||||
      fakeSourcesDirForTesting
 | 
			
		||||
    );
 | 
			
		||||
    expect(fs.existsSync(nugetConfigFile)).toBe(true);
 | 
			
		||||
    expect(
 | 
			
		||||
      fs.readFileSync(nugetConfigFile, {encoding: 'utf8'})
 | 
			
		||||
    ).toMatchSnapshot();
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  it('No existing config, auth token environment variable not provided, throws', async () => {
 | 
			
		||||
    let thrown = false;
 | 
			
		||||
    try {
 | 
			
		||||
      await auth.configAuthentication(
 | 
			
		||||
        'https://nuget.pkg.github.com/OwnerName/index.json',
 | 
			
		||||
        '',
 | 
			
		||||
        fakeSourcesDirForTesting
 | 
			
		||||
      );
 | 
			
		||||
    } catch {
 | 
			
		||||
      thrown = true;
 | 
			
		||||
    }
 | 
			
		||||
    expect(thrown).toBe(true);
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  it('No existing config, sets up a full NuGet.config with URL and other owner/PAT for GPR', async () => {
 | 
			
		||||
    process.env['NUGET_AUTH_TOKEN'] = 'TEST_FAKE_AUTH_TOKEN';
 | 
			
		||||
    process.env['INPUT_OWNER'] = 'otherorg';
 | 
			
		||||
    await auth.configAuthentication(
 | 
			
		||||
      'https://nuget.pkg.github.com/otherorg/index.json',
 | 
			
		||||
      '',
 | 
			
		||||
      fakeSourcesDirForTesting
 | 
			
		||||
    );
 | 
			
		||||
    expect(fs.existsSync(nugetConfigFile)).toBe(true);
 | 
			
		||||
    expect(
 | 
			
		||||
      fs.readFileSync(nugetConfigFile, {encoding: 'utf8'})
 | 
			
		||||
    ).toMatchSnapshot();
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  it('Existing config (invalid), tries to parse an invalid NuGet.config and throws', async () => {
 | 
			
		||||
    process.env['NUGET_AUTH_TOKEN'] = 'TEST_FAKE_AUTH_TOKEN';
 | 
			
		||||
    const inputNuGetConfigPath: string = path.join(
 | 
			
		||||
      fakeSourcesDirForTesting,
 | 
			
		||||
      'nuget.config'
 | 
			
		||||
    );
 | 
			
		||||
    fs.writeFileSync(inputNuGetConfigPath, invalidNuGetConfig);
 | 
			
		||||
    let thrown = false;
 | 
			
		||||
    try {
 | 
			
		||||
      await auth.configAuthentication(
 | 
			
		||||
        'https://nuget.pkg.github.com/OwnerName/index.json',
 | 
			
		||||
        '',
 | 
			
		||||
        fakeSourcesDirForTesting
 | 
			
		||||
      );
 | 
			
		||||
    } catch {
 | 
			
		||||
      thrown = true;
 | 
			
		||||
    }
 | 
			
		||||
    expect(thrown).toBe(true);
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  it('Existing config w/ no sources, sets up a full NuGet.config with URL and user/PAT for GPR', async () => {
 | 
			
		||||
    process.env['NUGET_AUTH_TOKEN'] = 'TEST_FAKE_AUTH_TOKEN';
 | 
			
		||||
    const inputNuGetConfigPath: string = path.join(
 | 
			
		||||
      fakeSourcesDirForTesting,
 | 
			
		||||
      'nuget.config'
 | 
			
		||||
    );
 | 
			
		||||
    fs.writeFileSync(inputNuGetConfigPath, emptyNuGetConfig);
 | 
			
		||||
    await auth.configAuthentication(
 | 
			
		||||
      'https://nuget.pkg.github.com/OwnerName/index.json',
 | 
			
		||||
      '',
 | 
			
		||||
      fakeSourcesDirForTesting
 | 
			
		||||
    );
 | 
			
		||||
    expect(fs.existsSync(nugetConfigFile)).toBe(true);
 | 
			
		||||
    expect(
 | 
			
		||||
      fs.readFileSync(nugetConfigFile, {encoding: 'utf8'})
 | 
			
		||||
    ).toMatchSnapshot();
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  it('Existing config w/ no GPR sources, sets up a full NuGet.config with URL and user/PAT for GPR', async () => {
 | 
			
		||||
    process.env['NUGET_AUTH_TOKEN'] = 'TEST_FAKE_AUTH_TOKEN';
 | 
			
		||||
    const inputNuGetConfigPath: string = path.join(
 | 
			
		||||
      fakeSourcesDirForTesting,
 | 
			
		||||
      'nuget.config'
 | 
			
		||||
    );
 | 
			
		||||
    fs.writeFileSync(inputNuGetConfigPath, nugetorgNuGetConfig);
 | 
			
		||||
    await auth.configAuthentication(
 | 
			
		||||
      'https://nuget.pkg.github.com/OwnerName/index.json',
 | 
			
		||||
      '',
 | 
			
		||||
      fakeSourcesDirForTesting
 | 
			
		||||
    );
 | 
			
		||||
    expect(fs.existsSync(nugetConfigFile)).toBe(true);
 | 
			
		||||
    expect(
 | 
			
		||||
      fs.readFileSync(nugetConfigFile, {encoding: 'utf8'})
 | 
			
		||||
    ).toMatchSnapshot();
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  it('Existing config w/ only GPR source, sets up a partial NuGet.config user/PAT for GPR', async () => {
 | 
			
		||||
    process.env['NUGET_AUTH_TOKEN'] = 'TEST_FAKE_AUTH_TOKEN';
 | 
			
		||||
    const inputNuGetConfigPath: string = path.join(
 | 
			
		||||
      fakeSourcesDirForTesting,
 | 
			
		||||
      'nuget.config'
 | 
			
		||||
    );
 | 
			
		||||
    fs.writeFileSync(inputNuGetConfigPath, gprNuGetConfig);
 | 
			
		||||
    await auth.configAuthentication(
 | 
			
		||||
      'https://nuget.pkg.github.com/OwnerName/index.json',
 | 
			
		||||
      '',
 | 
			
		||||
      fakeSourcesDirForTesting
 | 
			
		||||
    );
 | 
			
		||||
    expect(fs.existsSync(nugetConfigFile)).toBe(true);
 | 
			
		||||
    expect(
 | 
			
		||||
      fs.readFileSync(nugetConfigFile, {encoding: 'utf8'})
 | 
			
		||||
    ).toMatchSnapshot();
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  it('Existing config w/ GPR source and NuGet.org, sets up a partial NuGet.config user/PAT for GPR', async () => {
 | 
			
		||||
    process.env['NUGET_AUTH_TOKEN'] = 'TEST_FAKE_AUTH_TOKEN';
 | 
			
		||||
    const inputNuGetConfigPath: string = path.join(
 | 
			
		||||
      fakeSourcesDirForTesting,
 | 
			
		||||
      'nuget.config'
 | 
			
		||||
    );
 | 
			
		||||
    fs.writeFileSync(inputNuGetConfigPath, gprnugetorgNuGetConfig);
 | 
			
		||||
    await auth.configAuthentication(
 | 
			
		||||
      'https://nuget.pkg.github.com/OwnerName/index.json',
 | 
			
		||||
      '',
 | 
			
		||||
      fakeSourcesDirForTesting
 | 
			
		||||
    );
 | 
			
		||||
    expect(fs.existsSync(nugetConfigFile)).toBe(true);
 | 
			
		||||
    expect(
 | 
			
		||||
      fs.readFileSync(nugetConfigFile, {encoding: 'utf8'})
 | 
			
		||||
    ).toMatchSnapshot();
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  it('Existing config w/ two GPR sources, sets up a partial NuGet.config user/PAT for GPR', async () => {
 | 
			
		||||
    process.env['NUGET_AUTH_TOKEN'] = 'TEST_FAKE_AUTH_TOKEN';
 | 
			
		||||
    const inputNuGetConfigPath: string = path.join(
 | 
			
		||||
      fakeSourcesDirForTesting,
 | 
			
		||||
      'nuget.config'
 | 
			
		||||
    );
 | 
			
		||||
    fs.writeFileSync(inputNuGetConfigPath, twogprNuGetConfig);
 | 
			
		||||
    await auth.configAuthentication(
 | 
			
		||||
      'https://nuget.pkg.github.com',
 | 
			
		||||
      '',
 | 
			
		||||
      fakeSourcesDirForTesting
 | 
			
		||||
    );
 | 
			
		||||
    expect(fs.existsSync(nugetConfigFile)).toBe(true);
 | 
			
		||||
    expect(
 | 
			
		||||
      fs.readFileSync(nugetConfigFile, {encoding: 'utf8'})
 | 
			
		||||
    ).toMatchSnapshot();
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  it('Existing config w/ spaces in key, throws for now', async () => {
 | 
			
		||||
    process.env['NUGET_AUTH_TOKEN'] = 'TEST_FAKE_AUTH_TOKEN';
 | 
			
		||||
    const inputNuGetConfigPath: string = path.join(
 | 
			
		||||
      fakeSourcesDirForTesting,
 | 
			
		||||
      'nuget.config'
 | 
			
		||||
    );
 | 
			
		||||
    fs.writeFileSync(inputNuGetConfigPath, spaceNuGetConfig);
 | 
			
		||||
    let thrown = false;
 | 
			
		||||
    try {
 | 
			
		||||
      await auth.configAuthentication(
 | 
			
		||||
        'https://nuget.pkg.github.com/OwnerName/index.json',
 | 
			
		||||
        '',
 | 
			
		||||
        fakeSourcesDirForTesting
 | 
			
		||||
      );
 | 
			
		||||
    } catch {
 | 
			
		||||
      thrown = true;
 | 
			
		||||
    }
 | 
			
		||||
    expect(thrown).toBe(true);
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  it('Existing config not in repo root, sets up a partial NuGet.config user/PAT for GPR', async () => {
 | 
			
		||||
    process.env['NUGET_AUTH_TOKEN'] = 'TEST_FAKE_AUTH_TOKEN';
 | 
			
		||||
    const inputNuGetConfigDirectory: string = path.join(
 | 
			
		||||
      fakeSourcesDirForTesting,
 | 
			
		||||
      'subfolder'
 | 
			
		||||
    );
 | 
			
		||||
    const inputNuGetConfigPath: string = path.join(
 | 
			
		||||
      inputNuGetConfigDirectory,
 | 
			
		||||
      'nuget.config'
 | 
			
		||||
    );
 | 
			
		||||
    fs.mkdirSync(inputNuGetConfigDirectory, {recursive: true});
 | 
			
		||||
    fs.writeFileSync(inputNuGetConfigPath, gprNuGetConfig);
 | 
			
		||||
    await auth.configAuthentication(
 | 
			
		||||
      'https://nuget.pkg.github.com/OwnerName/index.json',
 | 
			
		||||
      'subfolder/nuget.config',
 | 
			
		||||
      fakeSourcesDirForTesting
 | 
			
		||||
    );
 | 
			
		||||
    expect(fs.existsSync(nugetConfigFile)).toBe(true);
 | 
			
		||||
    expect(
 | 
			
		||||
      fs.readFileSync(nugetConfigFile, {encoding: 'utf8'})
 | 
			
		||||
    ).toMatchSnapshot();
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  it('Existing config w/ only Azure Artifacts source, sets up a partial NuGet.config user/PAT for GPR', async () => {
 | 
			
		||||
    process.env['NUGET_AUTH_TOKEN'] = 'TEST_FAKE_AUTH_TOKEN';
 | 
			
		||||
    const inputNuGetConfigPath: string = path.join(
 | 
			
		||||
      fakeSourcesDirForTesting,
 | 
			
		||||
      'nuget.config'
 | 
			
		||||
    );
 | 
			
		||||
    fs.writeFileSync(inputNuGetConfigPath, azureartifactsNuGetConfig);
 | 
			
		||||
    await auth.configAuthentication(
 | 
			
		||||
      'https://pkgs.dev.azure.com/amullans/_packaging/GitHubBuilds/nuget/v3/index.json',
 | 
			
		||||
      '',
 | 
			
		||||
      fakeSourcesDirForTesting
 | 
			
		||||
    );
 | 
			
		||||
    expect(fs.existsSync(nugetConfigFile)).toBe(true);
 | 
			
		||||
    expect(
 | 
			
		||||
      fs.readFileSync(nugetConfigFile, {encoding: 'utf8'})
 | 
			
		||||
    ).toMatchSnapshot();
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  it('Existing config w/ Azure Artifacts source and NuGet.org, sets up a partial NuGet.config user/PAT for GPR', async () => {
 | 
			
		||||
    process.env['NUGET_AUTH_TOKEN'] = 'TEST_FAKE_AUTH_TOKEN';
 | 
			
		||||
    const inputNuGetConfigPath: string = path.join(
 | 
			
		||||
      fakeSourcesDirForTesting,
 | 
			
		||||
      'nuget.config'
 | 
			
		||||
    );
 | 
			
		||||
    fs.writeFileSync(inputNuGetConfigPath, azureartifactsnugetorgNuGetConfig);
 | 
			
		||||
    await auth.configAuthentication(
 | 
			
		||||
      'https://pkgs.dev.azure.com/amullans/_packaging/GitHubBuilds/nuget/v3/index.json',
 | 
			
		||||
      '',
 | 
			
		||||
      fakeSourcesDirForTesting
 | 
			
		||||
    );
 | 
			
		||||
    expect(fs.existsSync(nugetConfigFile)).toBe(true);
 | 
			
		||||
    expect(
 | 
			
		||||
      fs.readFileSync(nugetConfigFile, {encoding: 'utf8'})
 | 
			
		||||
    ).toMatchSnapshot();
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  it('No existing config, sets up a full NuGet.config with URL and token for other source', async () => {
 | 
			
		||||
    process.env['NUGET_AUTH_TOKEN'] = 'TEST_FAKE_AUTH_TOKEN';
 | 
			
		||||
    await auth.configAuthentication(
 | 
			
		||||
      'https://pkgs.dev.azure.com/amullans/_packaging/GitHubBuilds/nuget/v3/index.json',
 | 
			
		||||
      '',
 | 
			
		||||
      fakeSourcesDirForTesting
 | 
			
		||||
    );
 | 
			
		||||
    expect(fs.existsSync(nugetConfigFile)).toBe(true);
 | 
			
		||||
    expect(
 | 
			
		||||
      fs.readFileSync(nugetConfigFile, {encoding: 'utf8'})
 | 
			
		||||
    ).toMatchSnapshot();
 | 
			
		||||
  });
 | 
			
		||||
});
 | 
			
		||||
import io = require('@actions/io');
 | 
			
		||||
import fs = require('fs');
 | 
			
		||||
import path = require('path');
 | 
			
		||||
 | 
			
		||||
const fakeSourcesDirForTesting = path.join(
 | 
			
		||||
  __dirname,
 | 
			
		||||
  'runner',
 | 
			
		||||
  path.join(Math.random().toString(36).substring(7)),
 | 
			
		||||
  's'
 | 
			
		||||
);
 | 
			
		||||
 | 
			
		||||
const invalidNuGetConfig: string = `<?xml version="1.0" encoding="utf-8"?>`;
 | 
			
		||||
 | 
			
		||||
const emptyNuGetConfig: string = `<?xml version="1.0" encoding="utf-8"?>
 | 
			
		||||
<configuration>
 | 
			
		||||
</configuration>`;
 | 
			
		||||
 | 
			
		||||
const nugetorgNuGetConfig: string = `<?xml version="1.0" encoding="utf-8"?>
 | 
			
		||||
<configuration>
 | 
			
		||||
  <packageSources>
 | 
			
		||||
    <add key="nuget.org" value="https://api.nuget.org/v3/index.json" protocolVersion="3" />
 | 
			
		||||
  </packageSources>
 | 
			
		||||
</configuration>`;
 | 
			
		||||
 | 
			
		||||
const gprnugetorgNuGetConfig: string = `<?xml version="1.0" encoding="utf-8"?>
 | 
			
		||||
<configuration>
 | 
			
		||||
  <packageSources>
 | 
			
		||||
    <add key="GPR" value="https://nuget.pkg.github.com/OwnerName/index.json" protocolVersion="3" />
 | 
			
		||||
    <add key="nuget.org" value="https://api.nuget.org/v3/index.json" protocolVersion="3" />
 | 
			
		||||
  </packageSources>
 | 
			
		||||
</configuration>`;
 | 
			
		||||
 | 
			
		||||
const gprNuGetConfig: string = `<?xml version="1.0" encoding="utf-8"?>
 | 
			
		||||
<configuration>
 | 
			
		||||
  <packageSources>
 | 
			
		||||
    <add key="GPR" value="https://nuget.pkg.github.com/OwnerName/index.json" protocolVersion="3" />
 | 
			
		||||
  </packageSources>
 | 
			
		||||
</configuration>`;
 | 
			
		||||
 | 
			
		||||
const twogprNuGetConfig: string = `<?xml version="1.0" encoding="utf-8"?>
 | 
			
		||||
<configuration>
 | 
			
		||||
  <packageSources>
 | 
			
		||||
    <add key="GPR-GitHub" value="https://nuget.pkg.github.com/OwnerName/index.json" protocolVersion="3" />
 | 
			
		||||
    <add key="GPR-Actions" value="https://nuget.pkg.github.com/actions/index.json" protocolVersion="3" />
 | 
			
		||||
  </packageSources>
 | 
			
		||||
</configuration>`;
 | 
			
		||||
 | 
			
		||||
const spaceNuGetConfig: string = `<?xml version="1.0" encoding="utf-8"?>
 | 
			
		||||
<configuration>
 | 
			
		||||
  <packageSources>
 | 
			
		||||
    <add key="GPR GitHub" value="https://nuget.pkg.github.com/OwnerName/index.json" protocolVersion="3" />
 | 
			
		||||
  </packageSources>
 | 
			
		||||
</configuration>`;
 | 
			
		||||
 | 
			
		||||
const azureartifactsNuGetConfig: string = `<?xml version="1.0" encoding="utf-8"?>
 | 
			
		||||
<configuration>
 | 
			
		||||
  <packageSources>
 | 
			
		||||
    <add key="AzureArtifacts" value="https://pkgs.dev.azure.com/amullans/_packaging/GitHubBuilds/nuget/v3/index.json" protocolVersion="3" />
 | 
			
		||||
  </packageSources>
 | 
			
		||||
</configuration>`;
 | 
			
		||||
 | 
			
		||||
const azureartifactsnugetorgNuGetConfig: string = `<?xml version="1.0" encoding="utf-8"?>
 | 
			
		||||
<configuration>
 | 
			
		||||
  <packageSources>
 | 
			
		||||
    <add key="AzureArtifacts" value="https://pkgs.dev.azure.com/amullans/_packaging/GitHubBuilds/nuget/v3/index.json" protocolVersion="3" />
 | 
			
		||||
    <add key="nuget.org" value="https://api.nuget.org/v3/index.json" protocolVersion="3" />
 | 
			
		||||
  </packageSources>
 | 
			
		||||
</configuration>`;
 | 
			
		||||
 | 
			
		||||
// We want a NuGet.config one level above the sources directory, so it doesn't trample a user's NuGet.config but is still picked up by NuGet/dotnet.
 | 
			
		||||
const nugetConfigFile = path.join(fakeSourcesDirForTesting, '../nuget.config');
 | 
			
		||||
 | 
			
		||||
process.env['GITHUB_REPOSITORY'] = 'OwnerName/repo';
 | 
			
		||||
import * as auth from '../src/authutil';
 | 
			
		||||
 | 
			
		||||
describe('authutil tests', () => {
 | 
			
		||||
  beforeEach(async () => {
 | 
			
		||||
    await io.rmRF(fakeSourcesDirForTesting);
 | 
			
		||||
    await io.mkdirP(fakeSourcesDirForTesting);
 | 
			
		||||
  }, 30000);
 | 
			
		||||
 | 
			
		||||
  afterAll(async () => {
 | 
			
		||||
    await io.rmRF(fakeSourcesDirForTesting);
 | 
			
		||||
  }, 30000);
 | 
			
		||||
 | 
			
		||||
  beforeEach(() => {
 | 
			
		||||
    if (fs.existsSync(nugetConfigFile)) {
 | 
			
		||||
      fs.unlinkSync(nugetConfigFile);
 | 
			
		||||
    }
 | 
			
		||||
    process.env['INPUT_OWNER'] = '';
 | 
			
		||||
    process.env['NUGET_AUTH_TOKEN'] = '';
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  it('No existing config, sets up a full NuGet.config with URL and user/PAT for GPR', async () => {
 | 
			
		||||
    process.env['NUGET_AUTH_TOKEN'] = 'TEST_FAKE_AUTH_TOKEN';
 | 
			
		||||
    await auth.configAuthentication(
 | 
			
		||||
      'https://nuget.pkg.github.com/OwnerName/index.json',
 | 
			
		||||
      '',
 | 
			
		||||
      fakeSourcesDirForTesting
 | 
			
		||||
    );
 | 
			
		||||
    expect(fs.existsSync(nugetConfigFile)).toBe(true);
 | 
			
		||||
    expect(
 | 
			
		||||
      fs.readFileSync(nugetConfigFile, {encoding: 'utf8'})
 | 
			
		||||
    ).toMatchSnapshot();
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  it('No existing config, auth token environment variable not provided, throws', async () => {
 | 
			
		||||
    let thrown = false;
 | 
			
		||||
    try {
 | 
			
		||||
      await auth.configAuthentication(
 | 
			
		||||
        'https://nuget.pkg.github.com/OwnerName/index.json',
 | 
			
		||||
        '',
 | 
			
		||||
        fakeSourcesDirForTesting
 | 
			
		||||
      );
 | 
			
		||||
    } catch {
 | 
			
		||||
      thrown = true;
 | 
			
		||||
    }
 | 
			
		||||
    expect(thrown).toBe(true);
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  it('No existing config, sets up a full NuGet.config with URL and other owner/PAT for GPR', async () => {
 | 
			
		||||
    process.env['NUGET_AUTH_TOKEN'] = 'TEST_FAKE_AUTH_TOKEN';
 | 
			
		||||
    process.env['INPUT_OWNER'] = 'otherorg';
 | 
			
		||||
    await auth.configAuthentication(
 | 
			
		||||
      'https://nuget.pkg.github.com/otherorg/index.json',
 | 
			
		||||
      '',
 | 
			
		||||
      fakeSourcesDirForTesting
 | 
			
		||||
    );
 | 
			
		||||
    expect(fs.existsSync(nugetConfigFile)).toBe(true);
 | 
			
		||||
    expect(
 | 
			
		||||
      fs.readFileSync(nugetConfigFile, {encoding: 'utf8'})
 | 
			
		||||
    ).toMatchSnapshot();
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  it('Existing config (invalid), tries to parse an invalid NuGet.config and throws', async () => {
 | 
			
		||||
    process.env['NUGET_AUTH_TOKEN'] = 'TEST_FAKE_AUTH_TOKEN';
 | 
			
		||||
    const inputNuGetConfigPath: string = path.join(
 | 
			
		||||
      fakeSourcesDirForTesting,
 | 
			
		||||
      'nuget.config'
 | 
			
		||||
    );
 | 
			
		||||
    fs.writeFileSync(inputNuGetConfigPath, invalidNuGetConfig);
 | 
			
		||||
    let thrown = false;
 | 
			
		||||
    try {
 | 
			
		||||
      await auth.configAuthentication(
 | 
			
		||||
        'https://nuget.pkg.github.com/OwnerName/index.json',
 | 
			
		||||
        '',
 | 
			
		||||
        fakeSourcesDirForTesting
 | 
			
		||||
      );
 | 
			
		||||
    } catch {
 | 
			
		||||
      thrown = true;
 | 
			
		||||
    }
 | 
			
		||||
    expect(thrown).toBe(true);
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  it('Existing config w/ no sources, sets up a full NuGet.config with URL and user/PAT for GPR', async () => {
 | 
			
		||||
    process.env['NUGET_AUTH_TOKEN'] = 'TEST_FAKE_AUTH_TOKEN';
 | 
			
		||||
    const inputNuGetConfigPath: string = path.join(
 | 
			
		||||
      fakeSourcesDirForTesting,
 | 
			
		||||
      'nuget.config'
 | 
			
		||||
    );
 | 
			
		||||
    fs.writeFileSync(inputNuGetConfigPath, emptyNuGetConfig);
 | 
			
		||||
    await auth.configAuthentication(
 | 
			
		||||
      'https://nuget.pkg.github.com/OwnerName/index.json',
 | 
			
		||||
      '',
 | 
			
		||||
      fakeSourcesDirForTesting
 | 
			
		||||
    );
 | 
			
		||||
    expect(fs.existsSync(nugetConfigFile)).toBe(true);
 | 
			
		||||
    expect(
 | 
			
		||||
      fs.readFileSync(nugetConfigFile, {encoding: 'utf8'})
 | 
			
		||||
    ).toMatchSnapshot();
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  it('Existing config w/ no GPR sources, sets up a full NuGet.config with URL and user/PAT for GPR', async () => {
 | 
			
		||||
    process.env['NUGET_AUTH_TOKEN'] = 'TEST_FAKE_AUTH_TOKEN';
 | 
			
		||||
    const inputNuGetConfigPath: string = path.join(
 | 
			
		||||
      fakeSourcesDirForTesting,
 | 
			
		||||
      'nuget.config'
 | 
			
		||||
    );
 | 
			
		||||
    fs.writeFileSync(inputNuGetConfigPath, nugetorgNuGetConfig);
 | 
			
		||||
    await auth.configAuthentication(
 | 
			
		||||
      'https://nuget.pkg.github.com/OwnerName/index.json',
 | 
			
		||||
      '',
 | 
			
		||||
      fakeSourcesDirForTesting
 | 
			
		||||
    );
 | 
			
		||||
    expect(fs.existsSync(nugetConfigFile)).toBe(true);
 | 
			
		||||
    expect(
 | 
			
		||||
      fs.readFileSync(nugetConfigFile, {encoding: 'utf8'})
 | 
			
		||||
    ).toMatchSnapshot();
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  it('Existing config w/ only GPR source, sets up a partial NuGet.config user/PAT for GPR', async () => {
 | 
			
		||||
    process.env['NUGET_AUTH_TOKEN'] = 'TEST_FAKE_AUTH_TOKEN';
 | 
			
		||||
    const inputNuGetConfigPath: string = path.join(
 | 
			
		||||
      fakeSourcesDirForTesting,
 | 
			
		||||
      'nuget.config'
 | 
			
		||||
    );
 | 
			
		||||
    fs.writeFileSync(inputNuGetConfigPath, gprNuGetConfig);
 | 
			
		||||
    await auth.configAuthentication(
 | 
			
		||||
      'https://nuget.pkg.github.com/OwnerName/index.json',
 | 
			
		||||
      '',
 | 
			
		||||
      fakeSourcesDirForTesting
 | 
			
		||||
    );
 | 
			
		||||
    expect(fs.existsSync(nugetConfigFile)).toBe(true);
 | 
			
		||||
    expect(
 | 
			
		||||
      fs.readFileSync(nugetConfigFile, {encoding: 'utf8'})
 | 
			
		||||
    ).toMatchSnapshot();
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  it('Existing config w/ GPR source and NuGet.org, sets up a partial NuGet.config user/PAT for GPR', async () => {
 | 
			
		||||
    process.env['NUGET_AUTH_TOKEN'] = 'TEST_FAKE_AUTH_TOKEN';
 | 
			
		||||
    const inputNuGetConfigPath: string = path.join(
 | 
			
		||||
      fakeSourcesDirForTesting,
 | 
			
		||||
      'nuget.config'
 | 
			
		||||
    );
 | 
			
		||||
    fs.writeFileSync(inputNuGetConfigPath, gprnugetorgNuGetConfig);
 | 
			
		||||
    await auth.configAuthentication(
 | 
			
		||||
      'https://nuget.pkg.github.com/OwnerName/index.json',
 | 
			
		||||
      '',
 | 
			
		||||
      fakeSourcesDirForTesting
 | 
			
		||||
    );
 | 
			
		||||
    expect(fs.existsSync(nugetConfigFile)).toBe(true);
 | 
			
		||||
    expect(
 | 
			
		||||
      fs.readFileSync(nugetConfigFile, {encoding: 'utf8'})
 | 
			
		||||
    ).toMatchSnapshot();
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  it('Existing config w/ two GPR sources, sets up a partial NuGet.config user/PAT for GPR', async () => {
 | 
			
		||||
    process.env['NUGET_AUTH_TOKEN'] = 'TEST_FAKE_AUTH_TOKEN';
 | 
			
		||||
    const inputNuGetConfigPath: string = path.join(
 | 
			
		||||
      fakeSourcesDirForTesting,
 | 
			
		||||
      'nuget.config'
 | 
			
		||||
    );
 | 
			
		||||
    fs.writeFileSync(inputNuGetConfigPath, twogprNuGetConfig);
 | 
			
		||||
    await auth.configAuthentication(
 | 
			
		||||
      'https://nuget.pkg.github.com',
 | 
			
		||||
      '',
 | 
			
		||||
      fakeSourcesDirForTesting
 | 
			
		||||
    );
 | 
			
		||||
    expect(fs.existsSync(nugetConfigFile)).toBe(true);
 | 
			
		||||
    expect(
 | 
			
		||||
      fs.readFileSync(nugetConfigFile, {encoding: 'utf8'})
 | 
			
		||||
    ).toMatchSnapshot();
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  it('Existing config w/ spaces in key, throws for now', async () => {
 | 
			
		||||
    process.env['NUGET_AUTH_TOKEN'] = 'TEST_FAKE_AUTH_TOKEN';
 | 
			
		||||
    const inputNuGetConfigPath: string = path.join(
 | 
			
		||||
      fakeSourcesDirForTesting,
 | 
			
		||||
      'nuget.config'
 | 
			
		||||
    );
 | 
			
		||||
    fs.writeFileSync(inputNuGetConfigPath, spaceNuGetConfig);
 | 
			
		||||
    let thrown = false;
 | 
			
		||||
    try {
 | 
			
		||||
      await auth.configAuthentication(
 | 
			
		||||
        'https://nuget.pkg.github.com/OwnerName/index.json',
 | 
			
		||||
        '',
 | 
			
		||||
        fakeSourcesDirForTesting
 | 
			
		||||
      );
 | 
			
		||||
    } catch {
 | 
			
		||||
      thrown = true;
 | 
			
		||||
    }
 | 
			
		||||
    expect(thrown).toBe(true);
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  it('Existing config not in repo root, sets up a partial NuGet.config user/PAT for GPR', async () => {
 | 
			
		||||
    process.env['NUGET_AUTH_TOKEN'] = 'TEST_FAKE_AUTH_TOKEN';
 | 
			
		||||
    const inputNuGetConfigDirectory: string = path.join(
 | 
			
		||||
      fakeSourcesDirForTesting,
 | 
			
		||||
      'subfolder'
 | 
			
		||||
    );
 | 
			
		||||
    const inputNuGetConfigPath: string = path.join(
 | 
			
		||||
      inputNuGetConfigDirectory,
 | 
			
		||||
      'nuget.config'
 | 
			
		||||
    );
 | 
			
		||||
    fs.mkdirSync(inputNuGetConfigDirectory, {recursive: true});
 | 
			
		||||
    fs.writeFileSync(inputNuGetConfigPath, gprNuGetConfig);
 | 
			
		||||
    await auth.configAuthentication(
 | 
			
		||||
      'https://nuget.pkg.github.com/OwnerName/index.json',
 | 
			
		||||
      'subfolder/nuget.config',
 | 
			
		||||
      fakeSourcesDirForTesting
 | 
			
		||||
    );
 | 
			
		||||
    expect(fs.existsSync(nugetConfigFile)).toBe(true);
 | 
			
		||||
    expect(
 | 
			
		||||
      fs.readFileSync(nugetConfigFile, {encoding: 'utf8'})
 | 
			
		||||
    ).toMatchSnapshot();
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  it('Existing config w/ only Azure Artifacts source, sets up a partial NuGet.config user/PAT for GPR', async () => {
 | 
			
		||||
    process.env['NUGET_AUTH_TOKEN'] = 'TEST_FAKE_AUTH_TOKEN';
 | 
			
		||||
    const inputNuGetConfigPath: string = path.join(
 | 
			
		||||
      fakeSourcesDirForTesting,
 | 
			
		||||
      'nuget.config'
 | 
			
		||||
    );
 | 
			
		||||
    fs.writeFileSync(inputNuGetConfigPath, azureartifactsNuGetConfig);
 | 
			
		||||
    await auth.configAuthentication(
 | 
			
		||||
      'https://pkgs.dev.azure.com/amullans/_packaging/GitHubBuilds/nuget/v3/index.json',
 | 
			
		||||
      '',
 | 
			
		||||
      fakeSourcesDirForTesting
 | 
			
		||||
    );
 | 
			
		||||
    expect(fs.existsSync(nugetConfigFile)).toBe(true);
 | 
			
		||||
    expect(
 | 
			
		||||
      fs.readFileSync(nugetConfigFile, {encoding: 'utf8'})
 | 
			
		||||
    ).toMatchSnapshot();
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  it('Existing config w/ Azure Artifacts source and NuGet.org, sets up a partial NuGet.config user/PAT for GPR', async () => {
 | 
			
		||||
    process.env['NUGET_AUTH_TOKEN'] = 'TEST_FAKE_AUTH_TOKEN';
 | 
			
		||||
    const inputNuGetConfigPath: string = path.join(
 | 
			
		||||
      fakeSourcesDirForTesting,
 | 
			
		||||
      'nuget.config'
 | 
			
		||||
    );
 | 
			
		||||
    fs.writeFileSync(inputNuGetConfigPath, azureartifactsnugetorgNuGetConfig);
 | 
			
		||||
    await auth.configAuthentication(
 | 
			
		||||
      'https://pkgs.dev.azure.com/amullans/_packaging/GitHubBuilds/nuget/v3/index.json',
 | 
			
		||||
      '',
 | 
			
		||||
      fakeSourcesDirForTesting
 | 
			
		||||
    );
 | 
			
		||||
    expect(fs.existsSync(nugetConfigFile)).toBe(true);
 | 
			
		||||
    expect(
 | 
			
		||||
      fs.readFileSync(nugetConfigFile, {encoding: 'utf8'})
 | 
			
		||||
    ).toMatchSnapshot();
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  it('No existing config, sets up a full NuGet.config with URL and token for other source', async () => {
 | 
			
		||||
    process.env['NUGET_AUTH_TOKEN'] = 'TEST_FAKE_AUTH_TOKEN';
 | 
			
		||||
    await auth.configAuthentication(
 | 
			
		||||
      'https://pkgs.dev.azure.com/amullans/_packaging/GitHubBuilds/nuget/v3/index.json',
 | 
			
		||||
      '',
 | 
			
		||||
      fakeSourcesDirForTesting
 | 
			
		||||
    );
 | 
			
		||||
    expect(fs.existsSync(nugetConfigFile)).toBe(true);
 | 
			
		||||
    expect(
 | 
			
		||||
      fs.readFileSync(nugetConfigFile, {encoding: 'utf8'})
 | 
			
		||||
    ).toMatchSnapshot();
 | 
			
		||||
  });
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										2602
									
								
								dist/index.js
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2602
									
								
								dist/index.js
									
									
									
									
										vendored
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										436
									
								
								externals/install-dotnet.ps1
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										436
									
								
								externals/install-dotnet.ps1
									
									
									
									
										vendored
									
									
								
							@ -72,12 +72,14 @@
 | 
			
		||||
.PARAMETER Verbose
 | 
			
		||||
    Displays diagnostics information.
 | 
			
		||||
.PARAMETER AzureFeed
 | 
			
		||||
    Default: https://builds.dotnet.microsoft.com/dotnet
 | 
			
		||||
    Default: https://dotnetcli.azureedge.net/dotnet
 | 
			
		||||
    For internal use only.
 | 
			
		||||
    Allows using a different storage to download SDK archives from.
 | 
			
		||||
    This parameter is only used if $NoCdn is false.
 | 
			
		||||
.PARAMETER UncachedFeed
 | 
			
		||||
    For internal use only.
 | 
			
		||||
    Allows using a different storage to download SDK archives from.
 | 
			
		||||
    This parameter is only used if $NoCdn is true.
 | 
			
		||||
.PARAMETER ProxyAddress
 | 
			
		||||
    If set, the installer will use the proxy when making web requests
 | 
			
		||||
.PARAMETER ProxyUseDefaultCredentials
 | 
			
		||||
@ -88,6 +90,8 @@
 | 
			
		||||
.PARAMETER SkipNonVersionedFiles
 | 
			
		||||
    Default: false
 | 
			
		||||
    Skips installing non-versioned files if they already exist, such as dotnet.exe.
 | 
			
		||||
.PARAMETER NoCdn
 | 
			
		||||
    Disable downloading from the Azure CDN, and use the uncached feed directly.
 | 
			
		||||
.PARAMETER JSonFile
 | 
			
		||||
    Determines the SDK version from a user specified global.json file
 | 
			
		||||
    Note: global.json must have a value for 'SDK:Version'
 | 
			
		||||
@ -126,6 +130,7 @@ param(
 | 
			
		||||
    [switch]$ProxyUseDefaultCredentials,
 | 
			
		||||
    [string[]]$ProxyBypassList = @(),
 | 
			
		||||
    [switch]$SkipNonVersionedFiles,
 | 
			
		||||
    [switch]$NoCdn,
 | 
			
		||||
    [int]$DownloadTimeout = 1200,
 | 
			
		||||
    [switch]$KeepZip,
 | 
			
		||||
    [string]$ZipPath = [System.IO.Path]::combine([System.IO.Path]::GetTempPath(), [System.IO.Path]::GetRandomFileName()),
 | 
			
		||||
@ -1132,15 +1137,24 @@ function Get-AkaMsLink-And-Version([string] $NormalizedChannel, [string] $Normal
 | 
			
		||||
function Get-Feeds-To-Use() {
 | 
			
		||||
    $feeds = @(
 | 
			
		||||
        "https://builds.dotnet.microsoft.com/dotnet"
 | 
			
		||||
        "https://dotnetcli.azureedge.net/dotnet"
 | 
			
		||||
        "https://ci.dot.net/public"
 | 
			
		||||
        "https://dotnetbuilds.azureedge.net/public"
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
    if (-not [string]::IsNullOrEmpty($AzureFeed)) {
 | 
			
		||||
        $feeds = @($AzureFeed)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (-not [string]::IsNullOrEmpty($UncachedFeed)) {
 | 
			
		||||
    if ($NoCdn) {
 | 
			
		||||
        $feeds = @(
 | 
			
		||||
            "https://dotnetcli.blob.core.windows.net/dotnet",
 | 
			
		||||
            "https://dotnetbuilds.blob.core.windows.net/public"
 | 
			
		||||
        )
 | 
			
		||||
 | 
			
		||||
        if (-not [string]::IsNullOrEmpty($UncachedFeed)) {
 | 
			
		||||
            $feeds = @($UncachedFeed)
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    Write-Verbose "Initialized feeds: $feeds"
 | 
			
		||||
@ -1385,221 +1399,221 @@ Say "Note that the script does not ensure your Windows version is supported duri
 | 
			
		||||
Say "To check the list of supported versions, go to https://learn.microsoft.com/dotnet/core/install/windows#supported-versions"
 | 
			
		||||
Say "Installed version is $($DownloadedLink.effectiveVersion)"
 | 
			
		||||
Say "Installation finished"
 | 
			
		||||
 | 
			
		||||
# SIG # Begin signature block
 | 
			
		||||
# MIIoRgYJKoZIhvcNAQcCoIIoNzCCKDMCAQExDzANBglghkgBZQMEAgEFADB5Bgor
 | 
			
		||||
# MIIoVQYJKoZIhvcNAQcCoIIoRjCCKEICAQExDzANBglghkgBZQMEAgEFADB5Bgor
 | 
			
		||||
# BgEEAYI3AgEEoGswaTA0BgorBgEEAYI3AgEeMCYCAwEAAAQQH8w7YFlLCE63JNLG
 | 
			
		||||
# KX7zUQIBAAIBAAIBAAIBAAIBADAxMA0GCWCGSAFlAwQCAQUABCAA6hOL3sfG/4jH
 | 
			
		||||
# iO4VqZoOTVqC+yp2rOhb1M2cc+ic7KCCDXYwggX0MIID3KADAgECAhMzAAAEBGx0
 | 
			
		||||
# Bv9XKydyAAAAAAQEMA0GCSqGSIb3DQEBCwUAMH4xCzAJBgNVBAYTAlVTMRMwEQYD
 | 
			
		||||
# KX7zUQIBAAIBAAIBAAIBAAIBADAxMA0GCWCGSAFlAwQCAQUABCAYvsOYTXPcgaBF
 | 
			
		||||
# C8M6oYBHzvQKaqKPOJVvd3P0sSBCw6CCDYUwggYDMIID66ADAgECAhMzAAAEA73V
 | 
			
		||||
# lV0POxitAAAAAAQDMA0GCSqGSIb3DQEBCwUAMH4xCzAJBgNVBAYTAlVTMRMwEQYD
 | 
			
		||||
# VQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNy
 | 
			
		||||
# b3NvZnQgQ29ycG9yYXRpb24xKDAmBgNVBAMTH01pY3Jvc29mdCBDb2RlIFNpZ25p
 | 
			
		||||
# bmcgUENBIDIwMTEwHhcNMjQwOTEyMjAxMTE0WhcNMjUwOTExMjAxMTE0WjB0MQsw
 | 
			
		||||
# bmcgUENBIDIwMTEwHhcNMjQwOTEyMjAxMTEzWhcNMjUwOTExMjAxMTEzWjB0MQsw
 | 
			
		||||
# CQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9u
 | 
			
		||||
# ZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMR4wHAYDVQQDExVNaWNy
 | 
			
		||||
# b3NvZnQgQ29ycG9yYXRpb24wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIB
 | 
			
		||||
# AQC0KDfaY50MDqsEGdlIzDHBd6CqIMRQWW9Af1LHDDTuFjfDsvna0nEuDSYJmNyz
 | 
			
		||||
# NB10jpbg0lhvkT1AzfX2TLITSXwS8D+mBzGCWMM/wTpciWBV/pbjSazbzoKvRrNo
 | 
			
		||||
# DV/u9omOM2Eawyo5JJJdNkM2d8qzkQ0bRuRd4HarmGunSouyb9NY7egWN5E5lUc3
 | 
			
		||||
# a2AROzAdHdYpObpCOdeAY2P5XqtJkk79aROpzw16wCjdSn8qMzCBzR7rvH2WVkvF
 | 
			
		||||
# HLIxZQET1yhPb6lRmpgBQNnzidHV2Ocxjc8wNiIDzgbDkmlx54QPfw7RwQi8p1fy
 | 
			
		||||
# 4byhBrTjv568x8NGv3gwb0RbAgMBAAGjggFzMIIBbzAfBgNVHSUEGDAWBgorBgEE
 | 
			
		||||
# AYI3TAgBBggrBgEFBQcDAzAdBgNVHQ4EFgQU8huhNbETDU+ZWllL4DNMPCijEU4w
 | 
			
		||||
# RQYDVR0RBD4wPKQ6MDgxHjAcBgNVBAsTFU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjEW
 | 
			
		||||
# MBQGA1UEBRMNMjMwMDEyKzUwMjkyMzAfBgNVHSMEGDAWgBRIbmTlUAXTgqoXNzci
 | 
			
		||||
# tW2oynUClTBUBgNVHR8ETTBLMEmgR6BFhkNodHRwOi8vd3d3Lm1pY3Jvc29mdC5j
 | 
			
		||||
# b20vcGtpb3BzL2NybC9NaWNDb2RTaWdQQ0EyMDExXzIwMTEtMDctMDguY3JsMGEG
 | 
			
		||||
# CCsGAQUFBwEBBFUwUzBRBggrBgEFBQcwAoZFaHR0cDovL3d3dy5taWNyb3NvZnQu
 | 
			
		||||
# Y29tL3BraW9wcy9jZXJ0cy9NaWNDb2RTaWdQQ0EyMDExXzIwMTEtMDctMDguY3J0
 | 
			
		||||
# MAwGA1UdEwEB/wQCMAAwDQYJKoZIhvcNAQELBQADggIBAIjmD9IpQVvfB1QehvpC
 | 
			
		||||
# Ge7QeTQkKQ7j3bmDMjwSqFL4ri6ae9IFTdpywn5smmtSIyKYDn3/nHtaEn0X1NBj
 | 
			
		||||
# L5oP0BjAy1sqxD+uy35B+V8wv5GrxhMDJP8l2QjLtH/UglSTIhLqyt8bUAqVfyfp
 | 
			
		||||
# h4COMRvwwjTvChtCnUXXACuCXYHWalOoc0OU2oGN+mPJIJJxaNQc1sjBsMbGIWv3
 | 
			
		||||
# cmgSHkCEmrMv7yaidpePt6V+yPMik+eXw3IfZ5eNOiNgL1rZzgSJfTnvUqiaEQ0X
 | 
			
		||||
# dG1HbkDv9fv6CTq6m4Ty3IzLiwGSXYxRIXTxT4TYs5VxHy2uFjFXWVSL0J2ARTYL
 | 
			
		||||
# E4Oyl1wXDF1PX4bxg1yDMfKPHcE1Ijic5lx1KdK1SkaEJdto4hd++05J9Bf9TAmi
 | 
			
		||||
# u6EK6C9Oe5vRadroJCK26uCUI4zIjL/qG7mswW+qT0CW0gnR9JHkXCWNbo8ccMk1
 | 
			
		||||
# sJatmRoSAifbgzaYbUz8+lv+IXy5GFuAmLnNbGjacB3IMGpa+lbFgih57/fIhamq
 | 
			
		||||
# 5VhxgaEmn/UjWyr+cPiAFWuTVIpfsOjbEAww75wURNM1Imp9NJKye1O24EspEHmb
 | 
			
		||||
# DmqCUcq7NqkOKIG4PVm3hDDED/WQpzJDkvu4FrIbvyTGVU01vKsg4UfcdiZ0fQ+/
 | 
			
		||||
# V0hf8yrtq9CkB8iIuk5bBxuPMIIHejCCBWKgAwIBAgIKYQ6Q0gAAAAAAAzANBgkq
 | 
			
		||||
# hkiG9w0BAQsFADCBiDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCldhc2hpbmd0b24x
 | 
			
		||||
# EDAOBgNVBAcTB1JlZG1vbmQxHjAcBgNVBAoTFU1pY3Jvc29mdCBDb3Jwb3JhdGlv
 | 
			
		||||
# bjEyMDAGA1UEAxMpTWljcm9zb2Z0IFJvb3QgQ2VydGlmaWNhdGUgQXV0aG9yaXR5
 | 
			
		||||
# IDIwMTEwHhcNMTEwNzA4MjA1OTA5WhcNMjYwNzA4MjEwOTA5WjB+MQswCQYDVQQG
 | 
			
		||||
# EwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9uZDEeMBwG
 | 
			
		||||
# A1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMSgwJgYDVQQDEx9NaWNyb3NvZnQg
 | 
			
		||||
# Q29kZSBTaWduaW5nIFBDQSAyMDExMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIIC
 | 
			
		||||
# CgKCAgEAq/D6chAcLq3YbqqCEE00uvK2WCGfQhsqa+laUKq4BjgaBEm6f8MMHt03
 | 
			
		||||
# a8YS2AvwOMKZBrDIOdUBFDFC04kNeWSHfpRgJGyvnkmc6Whe0t+bU7IKLMOv2akr
 | 
			
		||||
# rnoJr9eWWcpgGgXpZnboMlImEi/nqwhQz7NEt13YxC4Ddato88tt8zpcoRb0Rrrg
 | 
			
		||||
# OGSsbmQ1eKagYw8t00CT+OPeBw3VXHmlSSnnDb6gE3e+lD3v++MrWhAfTVYoonpy
 | 
			
		||||
# 4BI6t0le2O3tQ5GD2Xuye4Yb2T6xjF3oiU+EGvKhL1nkkDstrjNYxbc+/jLTswM9
 | 
			
		||||
# sbKvkjh+0p2ALPVOVpEhNSXDOW5kf1O6nA+tGSOEy/S6A4aN91/w0FK/jJSHvMAh
 | 
			
		||||
# dCVfGCi2zCcoOCWYOUo2z3yxkq4cI6epZuxhH2rhKEmdX4jiJV3TIUs+UsS1Vz8k
 | 
			
		||||
# A/DRelsv1SPjcF0PUUZ3s/gA4bysAoJf28AVs70b1FVL5zmhD+kjSbwYuER8ReTB
 | 
			
		||||
# w3J64HLnJN+/RpnF78IcV9uDjexNSTCnq47f7Fufr/zdsGbiwZeBe+3W7UvnSSmn
 | 
			
		||||
# Eyimp31ngOaKYnhfsi+E11ecXL93KCjx7W3DKI8sj0A3T8HhhUSJxAlMxdSlQy90
 | 
			
		||||
# lfdu+HggWCwTXWCVmj5PM4TasIgX3p5O9JawvEagbJjS4NaIjAsCAwEAAaOCAe0w
 | 
			
		||||
# ggHpMBAGCSsGAQQBgjcVAQQDAgEAMB0GA1UdDgQWBBRIbmTlUAXTgqoXNzcitW2o
 | 
			
		||||
# ynUClTAZBgkrBgEEAYI3FAIEDB4KAFMAdQBiAEMAQTALBgNVHQ8EBAMCAYYwDwYD
 | 
			
		||||
# VR0TAQH/BAUwAwEB/zAfBgNVHSMEGDAWgBRyLToCMZBDuRQFTuHqp8cx0SOJNDBa
 | 
			
		||||
# BgNVHR8EUzBRME+gTaBLhklodHRwOi8vY3JsLm1pY3Jvc29mdC5jb20vcGtpL2Ny
 | 
			
		||||
# bC9wcm9kdWN0cy9NaWNSb29DZXJBdXQyMDExXzIwMTFfMDNfMjIuY3JsMF4GCCsG
 | 
			
		||||
# AQUFBwEBBFIwUDBOBggrBgEFBQcwAoZCaHR0cDovL3d3dy5taWNyb3NvZnQuY29t
 | 
			
		||||
# L3BraS9jZXJ0cy9NaWNSb29DZXJBdXQyMDExXzIwMTFfMDNfMjIuY3J0MIGfBgNV
 | 
			
		||||
# HSAEgZcwgZQwgZEGCSsGAQQBgjcuAzCBgzA/BggrBgEFBQcCARYzaHR0cDovL3d3
 | 
			
		||||
# dy5taWNyb3NvZnQuY29tL3BraW9wcy9kb2NzL3ByaW1hcnljcHMuaHRtMEAGCCsG
 | 
			
		||||
# AQUFBwICMDQeMiAdAEwAZQBnAGEAbABfAHAAbwBsAGkAYwB5AF8AcwB0AGEAdABl
 | 
			
		||||
# AG0AZQBuAHQALiAdMA0GCSqGSIb3DQEBCwUAA4ICAQBn8oalmOBUeRou09h0ZyKb
 | 
			
		||||
# C5YR4WOSmUKWfdJ5DJDBZV8uLD74w3LRbYP+vj/oCso7v0epo/Np22O/IjWll11l
 | 
			
		||||
# hJB9i0ZQVdgMknzSGksc8zxCi1LQsP1r4z4HLimb5j0bpdS1HXeUOeLpZMlEPXh6
 | 
			
		||||
# I/MTfaaQdION9MsmAkYqwooQu6SpBQyb7Wj6aC6VoCo/KmtYSWMfCWluWpiW5IP0
 | 
			
		||||
# wI/zRive/DvQvTXvbiWu5a8n7dDd8w6vmSiXmE0OPQvyCInWH8MyGOLwxS3OW560
 | 
			
		||||
# STkKxgrCxq2u5bLZ2xWIUUVYODJxJxp/sfQn+N4sOiBpmLJZiWhub6e3dMNABQam
 | 
			
		||||
# ASooPoI/E01mC8CzTfXhj38cbxV9Rad25UAqZaPDXVJihsMdYzaXht/a8/jyFqGa
 | 
			
		||||
# J+HNpZfQ7l1jQeNbB5yHPgZ3BtEGsXUfFL5hYbXw3MYbBL7fQccOKO7eZS/sl/ah
 | 
			
		||||
# XJbYANahRr1Z85elCUtIEJmAH9AAKcWxm6U/RXceNcbSoqKfenoi+kiVH6v7RyOA
 | 
			
		||||
# 9Z74v2u3S5fi63V4GuzqN5l5GEv/1rMjaHXmr/r8i+sLgOppO6/8MO0ETI7f33Vt
 | 
			
		||||
# Y5E90Z1WTk+/gFcioXgRMiF670EKsT/7qMykXcGhiJtXcVZOSEXAQsmbdlsKgEhr
 | 
			
		||||
# /Xmfwb1tbWrJUnMTDXpQzTGCGiYwghoiAgEBMIGVMH4xCzAJBgNVBAYTAlVTMRMw
 | 
			
		||||
# EQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVN
 | 
			
		||||
# aWNyb3NvZnQgQ29ycG9yYXRpb24xKDAmBgNVBAMTH01pY3Jvc29mdCBDb2RlIFNp
 | 
			
		||||
# Z25pbmcgUENBIDIwMTECEzMAAAQEbHQG/1crJ3IAAAAABAQwDQYJYIZIAWUDBAIB
 | 
			
		||||
# BQCgga4wGQYJKoZIhvcNAQkDMQwGCisGAQQBgjcCAQQwHAYKKwYBBAGCNwIBCzEO
 | 
			
		||||
# MAwGCisGAQQBgjcCARUwLwYJKoZIhvcNAQkEMSIEIL7Zm9jjqasUipeS7XNbT5Gz
 | 
			
		||||
# uhEwSf09z2Ab+694mR/3MEIGCisGAQQBgjcCAQwxNDAyoBSAEgBNAGkAYwByAG8A
 | 
			
		||||
# cwBvAGYAdKEagBhodHRwOi8vd3d3Lm1pY3Jvc29mdC5jb20wDQYJKoZIhvcNAQEB
 | 
			
		||||
# BQAEggEAfTNcpMwgkFxkb0hBch2MCvTb1mGCFv8rZWTkR/aRZTyzuAIEb2GfL4qB
 | 
			
		||||
# rPycLC2+q4gaksj1Cv+mRTEq+ysl0aWbXgPiRNiijlnuWKRPZ4nlcGkeXu5zxJ1W
 | 
			
		||||
# uUOCIe03s6eJCUZseRZkNHB1/CqIlk/YB5yqB38cfq6ct+lWKoSCbSwRVh3Du6am
 | 
			
		||||
# jxnQRa4njduu1xywcKZYp9NGGeAgRDpMNbvFKF4Qf3krbTAn3vIVDBay6oeiHo2I
 | 
			
		||||
# x1RLrRC/CEYZ7oJ8tyc3SUE2/Jd00M4EKax+z3xTIkOmyMBZjEe1el92WVcUWukT
 | 
			
		||||
# ACoQjF5jPyXnfYGH7rjevjpI5u2T66GCF7AwghesBgorBgEEAYI3AwMBMYIXnDCC
 | 
			
		||||
# F5gGCSqGSIb3DQEHAqCCF4kwgheFAgEDMQ8wDQYJYIZIAWUDBAIBBQAwggFaBgsq
 | 
			
		||||
# hkiG9w0BCRABBKCCAUkEggFFMIIBQQIBAQYKKwYBBAGEWQoDATAxMA0GCWCGSAFl
 | 
			
		||||
# AwQCAQUABCBjHcYL0Rw5C6IE3Lyb3B0i9qsTzN6j8bzChm+bMp97RgIGZ2Ld17Jt
 | 
			
		||||
# GBMyMDI1MDExMjAwNDMxNy4yNTZaMASAAgH0oIHZpIHWMIHTMQswCQYDVQQGEwJV
 | 
			
		||||
# UzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9uZDEeMBwGA1UE
 | 
			
		||||
# ChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMS0wKwYDVQQLEyRNaWNyb3NvZnQgSXJl
 | 
			
		||||
# bGFuZCBPcGVyYXRpb25zIExpbWl0ZWQxJzAlBgNVBAsTHm5TaGllbGQgVFNTIEVT
 | 
			
		||||
# Tjo0MzFBLTA1RTAtRDk0NzElMCMGA1UEAxMcTWljcm9zb2Z0IFRpbWUtU3RhbXAg
 | 
			
		||||
# U2VydmljZaCCEf4wggcoMIIFEKADAgECAhMzAAAB+vs7RNN3M8bTAAEAAAH6MA0G
 | 
			
		||||
# CSqGSIb3DQEBCwUAMHwxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpXYXNoaW5ndG9u
 | 
			
		||||
# MRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNyb3NvZnQgQ29ycG9yYXRp
 | 
			
		||||
# b24xJjAkBgNVBAMTHU1pY3Jvc29mdCBUaW1lLVN0YW1wIFBDQSAyMDEwMB4XDTI0
 | 
			
		||||
# MDcyNTE4MzExMVoXDTI1MTAyMjE4MzExMVowgdMxCzAJBgNVBAYTAlVTMRMwEQYD
 | 
			
		||||
# AQCfdGddwIOnbRYUyg03O3iz19XXZPmuhEmW/5uyEN+8mgxl+HJGeLGBR8YButGV
 | 
			
		||||
# LVK38RxcVcPYyFGQXcKcxgih4w4y4zJi3GvawLYHlsNExQwz+v0jgY/aejBS2EJY
 | 
			
		||||
# oUhLVE+UzRihV8ooxoftsmKLb2xb7BoFS6UAo3Zz4afnOdqI7FGoi7g4vx/0MIdi
 | 
			
		||||
# kwTn5N56TdIv3mwfkZCFmrsKpN0zR8HD8WYsvH3xKkG7u/xdqmhPPqMmnI2jOFw/
 | 
			
		||||
# /n2aL8W7i1Pasja8PnRXH/QaVH0M1nanL+LI9TsMb/enWfXOW65Gne5cqMN9Uofv
 | 
			
		||||
# ENtdwwEmJ3bZrcI9u4LZAkujAgMBAAGjggGCMIIBfjAfBgNVHSUEGDAWBgorBgEE
 | 
			
		||||
# AYI3TAgBBggrBgEFBQcDAzAdBgNVHQ4EFgQU6m4qAkpz4641iK2irF8eWsSBcBkw
 | 
			
		||||
# VAYDVR0RBE0wS6RJMEcxLTArBgNVBAsTJE1pY3Jvc29mdCBJcmVsYW5kIE9wZXJh
 | 
			
		||||
# dGlvbnMgTGltaXRlZDEWMBQGA1UEBRMNMjMwMDEyKzUwMjkyNjAfBgNVHSMEGDAW
 | 
			
		||||
# gBRIbmTlUAXTgqoXNzcitW2oynUClTBUBgNVHR8ETTBLMEmgR6BFhkNodHRwOi8v
 | 
			
		||||
# d3d3Lm1pY3Jvc29mdC5jb20vcGtpb3BzL2NybC9NaWNDb2RTaWdQQ0EyMDExXzIw
 | 
			
		||||
# MTEtMDctMDguY3JsMGEGCCsGAQUFBwEBBFUwUzBRBggrBgEFBQcwAoZFaHR0cDov
 | 
			
		||||
# L3d3dy5taWNyb3NvZnQuY29tL3BraW9wcy9jZXJ0cy9NaWNDb2RTaWdQQ0EyMDEx
 | 
			
		||||
# XzIwMTEtMDctMDguY3J0MAwGA1UdEwEB/wQCMAAwDQYJKoZIhvcNAQELBQADggIB
 | 
			
		||||
# AFFo/6E4LX51IqFuoKvUsi80QytGI5ASQ9zsPpBa0z78hutiJd6w154JkcIx/f7r
 | 
			
		||||
# EBK4NhD4DIFNfRiVdI7EacEs7OAS6QHF7Nt+eFRNOTtgHb9PExRy4EI/jnMwzQJV
 | 
			
		||||
# NokTxu2WgHr/fBsWs6G9AcIgvHjWNN3qRSrhsgEdqHc0bRDUf8UILAdEZOMBvKLC
 | 
			
		||||
# rmf+kJPEvPldgK7hFO/L9kmcVe67BnKejDKO73Sa56AJOhM7CkeATrJFxO9GLXos
 | 
			
		||||
# oKvrwBvynxAg18W+pagTAkJefzneuWSmniTurPCUE2JnvW7DalvONDOtG01sIVAB
 | 
			
		||||
# +ahO2wcUPa2Zm9AiDVBWTMz9XUoKMcvngi2oqbsDLhbK+pYrRUgRpNt0y1sxZsXO
 | 
			
		||||
# raGRF8lM2cWvtEkV5UL+TQM1ppv5unDHkW8JS+QnfPbB8dZVRyRmMQ4aY/tx5x5+
 | 
			
		||||
# sX6semJ//FbiclSMxSI+zINu1jYerdUwuCi+P6p7SmQmClhDM+6Q+btE2FtpsU0W
 | 
			
		||||
# +r6RdYFf/P+nK6j2otl9Nvr3tWLu+WXmz8MGM+18ynJ+lYbSmFWcAj7SYziAfT0s
 | 
			
		||||
# IwlQRFkyC71tsIZUhBHtxPliGUu362lIO0Lpe0DOrg8lspnEWOkHnCT5JEnWCbzu
 | 
			
		||||
# iVt8RX1IV07uIveNZuOBWLVCzWJjEGa+HhaEtavjy6i7MIIHejCCBWKgAwIBAgIK
 | 
			
		||||
# YQ6Q0gAAAAAAAzANBgkqhkiG9w0BAQsFADCBiDELMAkGA1UEBhMCVVMxEzARBgNV
 | 
			
		||||
# BAgTCldhc2hpbmd0b24xEDAOBgNVBAcTB1JlZG1vbmQxHjAcBgNVBAoTFU1pY3Jv
 | 
			
		||||
# c29mdCBDb3Jwb3JhdGlvbjEyMDAGA1UEAxMpTWljcm9zb2Z0IFJvb3QgQ2VydGlm
 | 
			
		||||
# aWNhdGUgQXV0aG9yaXR5IDIwMTEwHhcNMTEwNzA4MjA1OTA5WhcNMjYwNzA4MjEw
 | 
			
		||||
# OTA5WjB+MQswCQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UE
 | 
			
		||||
# BxMHUmVkbW9uZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMSgwJgYD
 | 
			
		||||
# VQQDEx9NaWNyb3NvZnQgQ29kZSBTaWduaW5nIFBDQSAyMDExMIICIjANBgkqhkiG
 | 
			
		||||
# 9w0BAQEFAAOCAg8AMIICCgKCAgEAq/D6chAcLq3YbqqCEE00uvK2WCGfQhsqa+la
 | 
			
		||||
# UKq4BjgaBEm6f8MMHt03a8YS2AvwOMKZBrDIOdUBFDFC04kNeWSHfpRgJGyvnkmc
 | 
			
		||||
# 6Whe0t+bU7IKLMOv2akrrnoJr9eWWcpgGgXpZnboMlImEi/nqwhQz7NEt13YxC4D
 | 
			
		||||
# dato88tt8zpcoRb0RrrgOGSsbmQ1eKagYw8t00CT+OPeBw3VXHmlSSnnDb6gE3e+
 | 
			
		||||
# lD3v++MrWhAfTVYoonpy4BI6t0le2O3tQ5GD2Xuye4Yb2T6xjF3oiU+EGvKhL1nk
 | 
			
		||||
# kDstrjNYxbc+/jLTswM9sbKvkjh+0p2ALPVOVpEhNSXDOW5kf1O6nA+tGSOEy/S6
 | 
			
		||||
# A4aN91/w0FK/jJSHvMAhdCVfGCi2zCcoOCWYOUo2z3yxkq4cI6epZuxhH2rhKEmd
 | 
			
		||||
# X4jiJV3TIUs+UsS1Vz8kA/DRelsv1SPjcF0PUUZ3s/gA4bysAoJf28AVs70b1FVL
 | 
			
		||||
# 5zmhD+kjSbwYuER8ReTBw3J64HLnJN+/RpnF78IcV9uDjexNSTCnq47f7Fufr/zd
 | 
			
		||||
# sGbiwZeBe+3W7UvnSSmnEyimp31ngOaKYnhfsi+E11ecXL93KCjx7W3DKI8sj0A3
 | 
			
		||||
# T8HhhUSJxAlMxdSlQy90lfdu+HggWCwTXWCVmj5PM4TasIgX3p5O9JawvEagbJjS
 | 
			
		||||
# 4NaIjAsCAwEAAaOCAe0wggHpMBAGCSsGAQQBgjcVAQQDAgEAMB0GA1UdDgQWBBRI
 | 
			
		||||
# bmTlUAXTgqoXNzcitW2oynUClTAZBgkrBgEEAYI3FAIEDB4KAFMAdQBiAEMAQTAL
 | 
			
		||||
# BgNVHQ8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAfBgNVHSMEGDAWgBRyLToCMZBD
 | 
			
		||||
# uRQFTuHqp8cx0SOJNDBaBgNVHR8EUzBRME+gTaBLhklodHRwOi8vY3JsLm1pY3Jv
 | 
			
		||||
# c29mdC5jb20vcGtpL2NybC9wcm9kdWN0cy9NaWNSb29DZXJBdXQyMDExXzIwMTFf
 | 
			
		||||
# MDNfMjIuY3JsMF4GCCsGAQUFBwEBBFIwUDBOBggrBgEFBQcwAoZCaHR0cDovL3d3
 | 
			
		||||
# dy5taWNyb3NvZnQuY29tL3BraS9jZXJ0cy9NaWNSb29DZXJBdXQyMDExXzIwMTFf
 | 
			
		||||
# MDNfMjIuY3J0MIGfBgNVHSAEgZcwgZQwgZEGCSsGAQQBgjcuAzCBgzA/BggrBgEF
 | 
			
		||||
# BQcCARYzaHR0cDovL3d3dy5taWNyb3NvZnQuY29tL3BraW9wcy9kb2NzL3ByaW1h
 | 
			
		||||
# cnljcHMuaHRtMEAGCCsGAQUFBwICMDQeMiAdAEwAZQBnAGEAbABfAHAAbwBsAGkA
 | 
			
		||||
# YwB5AF8AcwB0AGEAdABlAG0AZQBuAHQALiAdMA0GCSqGSIb3DQEBCwUAA4ICAQBn
 | 
			
		||||
# 8oalmOBUeRou09h0ZyKbC5YR4WOSmUKWfdJ5DJDBZV8uLD74w3LRbYP+vj/oCso7
 | 
			
		||||
# v0epo/Np22O/IjWll11lhJB9i0ZQVdgMknzSGksc8zxCi1LQsP1r4z4HLimb5j0b
 | 
			
		||||
# pdS1HXeUOeLpZMlEPXh6I/MTfaaQdION9MsmAkYqwooQu6SpBQyb7Wj6aC6VoCo/
 | 
			
		||||
# KmtYSWMfCWluWpiW5IP0wI/zRive/DvQvTXvbiWu5a8n7dDd8w6vmSiXmE0OPQvy
 | 
			
		||||
# CInWH8MyGOLwxS3OW560STkKxgrCxq2u5bLZ2xWIUUVYODJxJxp/sfQn+N4sOiBp
 | 
			
		||||
# mLJZiWhub6e3dMNABQamASooPoI/E01mC8CzTfXhj38cbxV9Rad25UAqZaPDXVJi
 | 
			
		||||
# hsMdYzaXht/a8/jyFqGaJ+HNpZfQ7l1jQeNbB5yHPgZ3BtEGsXUfFL5hYbXw3MYb
 | 
			
		||||
# BL7fQccOKO7eZS/sl/ahXJbYANahRr1Z85elCUtIEJmAH9AAKcWxm6U/RXceNcbS
 | 
			
		||||
# oqKfenoi+kiVH6v7RyOA9Z74v2u3S5fi63V4GuzqN5l5GEv/1rMjaHXmr/r8i+sL
 | 
			
		||||
# gOppO6/8MO0ETI7f33VtY5E90Z1WTk+/gFcioXgRMiF670EKsT/7qMykXcGhiJtX
 | 
			
		||||
# cVZOSEXAQsmbdlsKgEhr/Xmfwb1tbWrJUnMTDXpQzTGCGiYwghoiAgEBMIGVMH4x
 | 
			
		||||
# CzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRt
 | 
			
		||||
# b25kMR4wHAYDVQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xKDAmBgNVBAMTH01p
 | 
			
		||||
# Y3Jvc29mdCBDb2RlIFNpZ25pbmcgUENBIDIwMTECEzMAAAQDvdWVXQ87GK0AAAAA
 | 
			
		||||
# BAMwDQYJYIZIAWUDBAIBBQCgga4wGQYJKoZIhvcNAQkDMQwGCisGAQQBgjcCAQQw
 | 
			
		||||
# HAYKKwYBBAGCNwIBCzEOMAwGCisGAQQBgjcCARUwLwYJKoZIhvcNAQkEMSIEINfL
 | 
			
		||||
# pWARcSI2v5ypXRaeSwvLuu7hP0XgYbvQaaOIuiKWMEIGCisGAQQBgjcCAQwxNDAy
 | 
			
		||||
# oBSAEgBNAGkAYwByAG8AcwBvAGYAdKEagBhodHRwOi8vd3d3Lm1pY3Jvc29mdC5j
 | 
			
		||||
# b20wDQYJKoZIhvcNAQEBBQAEggEADr/V9EQlvMcNLQduKLU/gz5PRRSoE8txgN52
 | 
			
		||||
# OuBIJS4+jPp3y82+4/09umeMdQ7+pwRQiuPAvmyZG0zGRoTz3PzpouceetqHnIHn
 | 
			
		||||
# ij0lT0y4hUQ0DqmZT1AA24GJmoPnM9ab2EcRTfUp7p0t1Fq5ITOEdFvvh6EPkyc/
 | 
			
		||||
# spxmI5bTlE0+anj9PmnLyFYnFtrGlmSywrDpIsjqnE8+ODtTabllcpAhLrZxInqu
 | 
			
		||||
# bHXIrT3cGjATJsRAg+38R5tYP7i6aI5sS9QGmeXhuvrJeFrOIqC2gxbV7iCJIrkE
 | 
			
		||||
# 5OGFIBZQkxLRZxt3VYdGAjBLj+pCY7OEjXpXvkdg47Xo8aQCKqGCF7AwghesBgor
 | 
			
		||||
# BgEEAYI3AwMBMYIXnDCCF5gGCSqGSIb3DQEHAqCCF4kwgheFAgEDMQ8wDQYJYIZI
 | 
			
		||||
# AWUDBAIBBQAwggFaBgsqhkiG9w0BCRABBKCCAUkEggFFMIIBQQIBAQYKKwYBBAGE
 | 
			
		||||
# WQoDATAxMA0GCWCGSAFlAwQCAQUABCBVg4bCpxEOAWWIN2/4kB21BawVRDfKQ35G
 | 
			
		||||
# xRhhaLpK/AIGZ2KxlnK4GBMyMDI0MTIyMzE2NDIwNy43NDJaMASAAgH0oIHZpIHW
 | 
			
		||||
# MIHTMQswCQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMH
 | 
			
		||||
# UmVkbW9uZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMS0wKwYDVQQL
 | 
			
		||||
# EyRNaWNyb3NvZnQgSXJlbGFuZCBPcGVyYXRpb25zIExpbWl0ZWQxJzAlBgNVBAsT
 | 
			
		||||
# Hm5TaGllbGQgVFNTIEVTTjo2QjA1LTA1RTAtRDk0NzElMCMGA1UEAxMcTWljcm9z
 | 
			
		||||
# b2Z0IFRpbWUtU3RhbXAgU2VydmljZaCCEf4wggcoMIIFEKADAgECAhMzAAAB9oMv
 | 
			
		||||
# JmpUXSLBAAEAAAH2MA0GCSqGSIb3DQEBCwUAMHwxCzAJBgNVBAYTAlVTMRMwEQYD
 | 
			
		||||
# VQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNy
 | 
			
		||||
# b3NvZnQgQ29ycG9yYXRpb24xLTArBgNVBAsTJE1pY3Jvc29mdCBJcmVsYW5kIE9w
 | 
			
		||||
# ZXJhdGlvbnMgTGltaXRlZDEnMCUGA1UECxMeblNoaWVsZCBUU1MgRVNOOjQzMUEt
 | 
			
		||||
# MDVFMC1EOTQ3MSUwIwYDVQQDExxNaWNyb3NvZnQgVGltZS1TdGFtcCBTZXJ2aWNl
 | 
			
		||||
# MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAyhZVBM3PZcBfEpAf7fII
 | 
			
		||||
# hygwYVVP64USeZbSlRR3pvJebva0LQCDW45yOrtpwIpGyDGX+EbCbHhS5Td4J0Yl
 | 
			
		||||
# c83ztLEbbQD7M6kqR0Xj+n82cGse/QnMH0WRZLnwggJdenpQ6UciM4nMYZvdQjyb
 | 
			
		||||
# A4qejOe9Y073JlXv3VIbdkQH2JGyT8oB/LsvPL/kAnJ45oQIp7Sx57RPQ/0O6qay
 | 
			
		||||
# J2SJrwcjA8auMdAnZKOixFlzoooh7SyycI7BENHTpkVKrRV5YelRvWNTg1pH4EC2
 | 
			
		||||
# KO2bxsBN23btMeTvZFieGIr+D8mf1lQQs0Ht/tMOVdah14t7Yk+xl5P4Tw3xfAGg
 | 
			
		||||
# Hsvsa6ugrxwmKTTX1kqXH5XCdw3TVeKCax6JV+ygM5i1NroJKwBCW11Pwi0z/ki9
 | 
			
		||||
# 0ZeO6XfEE9mCnJm76Qcxi3tnW/Y/3ZumKQ6X/iVIJo7Lk0Z/pATRwAINqwdvzpdt
 | 
			
		||||
# X2hOJib4GR8is2bpKks04GurfweWPn9z6jY7GBC+js8pSwGewrffwgAbNKm82ZDF
 | 
			
		||||
# vqBGQQVJwIHSXpjkS+G39eyYOG2rcILBIDlzUzMFFJbNh5tDv3GeJ3EKvC4vNSAx
 | 
			
		||||
# tGfaG/mQhK43YjevsB72LouU78rxtNhuMXSzaHq5fFiG3zcsYHaa4+w+YmMrhTEz
 | 
			
		||||
# D4SAish35BjoXP1P1Ct4Va0CAwEAAaOCAUkwggFFMB0GA1UdDgQWBBRjjHKbL5WV
 | 
			
		||||
# 6kd06KocQHphK9U/vzAfBgNVHSMEGDAWgBSfpxVdAF5iXYP05dJlpxtTNRnpcjBf
 | 
			
		||||
# BgNVHR8EWDBWMFSgUqBQhk5odHRwOi8vd3d3Lm1pY3Jvc29mdC5jb20vcGtpb3Bz
 | 
			
		||||
# L2NybC9NaWNyb3NvZnQlMjBUaW1lLVN0YW1wJTIwUENBJTIwMjAxMCgxKS5jcmww
 | 
			
		||||
# bAYIKwYBBQUHAQEEYDBeMFwGCCsGAQUFBzAChlBodHRwOi8vd3d3Lm1pY3Jvc29m
 | 
			
		||||
# dC5jb20vcGtpb3BzL2NlcnRzL01pY3Jvc29mdCUyMFRpbWUtU3RhbXAlMjBQQ0El
 | 
			
		||||
# MjAyMDEwKDEpLmNydDAMBgNVHRMBAf8EAjAAMBYGA1UdJQEB/wQMMAoGCCsGAQUF
 | 
			
		||||
# BwMIMA4GA1UdDwEB/wQEAwIHgDANBgkqhkiG9w0BAQsFAAOCAgEAuFbCorFrvodG
 | 
			
		||||
# +ZNJH3Y+Nz5QpUytQVObOyYFrgcGrxq6MUa4yLmxN4xWdL1kygaW5BOZ3xBlPY7V
 | 
			
		||||
# puf5b5eaXP7qRq61xeOrX3f64kGiSWoRi9EJawJWCzJfUQRThDL4zxI2pYc1wnPp
 | 
			
		||||
# 7Q695bHqwZ02eaOBudh/IfEkGe0Ofj6IS3oyZsJP1yatcm4kBqIH6db1+weM4q46
 | 
			
		||||
# NhAfAf070zF6F+IpUHyhtMbQg5+QHfOuyBzrt67CiMJSKcJ3nMVyfNlnv6yvttYz
 | 
			
		||||
# LK3wS+0QwJUibLYJMI6FGcSuRxKlq6RjOhK9L3QOjh0VCM11rHM11ZmN0euJbbBC
 | 
			
		||||
# VfQEufOLNkG88MFCUNE10SSbM/Og/CbTko0M5wbVvQJ6CqLKjtHSoeoAGPeeX24f
 | 
			
		||||
# 5cPYyTcKlbM6LoUdO2P5JSdI5s1JF/On6LiUT50adpRstZajbYEeX/N7RvSbkn0d
 | 
			
		||||
# jD3BvT2Of3Wf9gIeaQIHbv1J2O/P5QOPQiVo8+0AKm6M0TKOduihhKxAt/6Yyk17
 | 
			
		||||
# Fv3RIdjT6wiL2qRIEsgOJp3fILw4mQRPu3spRfakSoQe5N0e4HWFf8WW2ZL0+c83
 | 
			
		||||
# Qzh3VtEPI6Y2e2BO/eWhTYbIbHpqYDfAtAYtaYIde87ZymXG3MO2wUjhL9HvSQzj
 | 
			
		||||
# oquq+OoUmvfBUcB2e5L6QCHO6qTO7WowggdxMIIFWaADAgECAhMzAAAAFcXna54C
 | 
			
		||||
# m0mZAAAAAAAVMA0GCSqGSIb3DQEBCwUAMIGIMQswCQYDVQQGEwJVUzETMBEGA1UE
 | 
			
		||||
# CBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9uZDEeMBwGA1UEChMVTWljcm9z
 | 
			
		||||
# b2Z0IENvcnBvcmF0aW9uMTIwMAYDVQQDEylNaWNyb3NvZnQgUm9vdCBDZXJ0aWZp
 | 
			
		||||
# Y2F0ZSBBdXRob3JpdHkgMjAxMDAeFw0yMTA5MzAxODIyMjVaFw0zMDA5MzAxODMy
 | 
			
		||||
# MjVaMHwxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQH
 | 
			
		||||
# EwdSZWRtb25kMR4wHAYDVQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xJjAkBgNV
 | 
			
		||||
# BAMTHU1pY3Jvc29mdCBUaW1lLVN0YW1wIFBDQSAyMDEwMIICIjANBgkqhkiG9w0B
 | 
			
		||||
# AQEFAAOCAg8AMIICCgKCAgEA5OGmTOe0ciELeaLL1yR5vQ7VgtP97pwHB9KpbE51
 | 
			
		||||
# yMo1V/YBf2xK4OK9uT4XYDP/XE/HZveVU3Fa4n5KWv64NmeFRiMMtY0Tz3cywBAY
 | 
			
		||||
# 6GB9alKDRLemjkZrBxTzxXb1hlDcwUTIcVxRMTegCjhuje3XD9gmU3w5YQJ6xKr9
 | 
			
		||||
# cmmvHaus9ja+NSZk2pg7uhp7M62AW36MEBydUv626GIl3GoPz130/o5Tz9bshVZN
 | 
			
		||||
# 7928jaTjkY+yOSxRnOlwaQ3KNi1wjjHINSi947SHJMPgyY9+tVSP3PoFVZhtaDua
 | 
			
		||||
# Rr3tpK56KTesy+uDRedGbsoy1cCGMFxPLOJiss254o2I5JasAUq7vnGpF1tnYN74
 | 
			
		||||
# kpEeHT39IM9zfUGaRnXNxF803RKJ1v2lIH1+/NmeRd+2ci/bfV+AutuqfjbsNkz2
 | 
			
		||||
# K26oElHovwUDo9Fzpk03dJQcNIIP8BDyt0cY7afomXw/TNuvXsLz1dhzPUNOwTM5
 | 
			
		||||
# TI4CvEJoLhDqhFFG4tG9ahhaYQFzymeiXtcodgLiMxhy16cg8ML6EgrXY28MyTZk
 | 
			
		||||
# i1ugpoMhXV8wdJGUlNi5UPkLiWHzNgY1GIRH29wb0f2y1BzFa/ZcUlFdEtsluq9Q
 | 
			
		||||
# BXpsxREdcu+N+VLEhReTwDwV2xo3xwgVGD94q0W29R6HXtqPnhZyacaue7e3Pmri
 | 
			
		||||
# Lq0CAwEAAaOCAd0wggHZMBIGCSsGAQQBgjcVAQQFAgMBAAEwIwYJKwYBBAGCNxUC
 | 
			
		||||
# BBYEFCqnUv5kxJq+gpE8RjUpzxD/LwTuMB0GA1UdDgQWBBSfpxVdAF5iXYP05dJl
 | 
			
		||||
# pxtTNRnpcjBcBgNVHSAEVTBTMFEGDCsGAQQBgjdMg30BATBBMD8GCCsGAQUFBwIB
 | 
			
		||||
# FjNodHRwOi8vd3d3Lm1pY3Jvc29mdC5jb20vcGtpb3BzL0RvY3MvUmVwb3NpdG9y
 | 
			
		||||
# eS5odG0wEwYDVR0lBAwwCgYIKwYBBQUHAwgwGQYJKwYBBAGCNxQCBAweCgBTAHUA
 | 
			
		||||
# YgBDAEEwCwYDVR0PBAQDAgGGMA8GA1UdEwEB/wQFMAMBAf8wHwYDVR0jBBgwFoAU
 | 
			
		||||
# 1fZWy4/oolxiaNE9lJBb186aGMQwVgYDVR0fBE8wTTBLoEmgR4ZFaHR0cDovL2Ny
 | 
			
		||||
# bC5taWNyb3NvZnQuY29tL3BraS9jcmwvcHJvZHVjdHMvTWljUm9vQ2VyQXV0XzIw
 | 
			
		||||
# MTAtMDYtMjMuY3JsMFoGCCsGAQUFBwEBBE4wTDBKBggrBgEFBQcwAoY+aHR0cDov
 | 
			
		||||
# L3d3dy5taWNyb3NvZnQuY29tL3BraS9jZXJ0cy9NaWNSb29DZXJBdXRfMjAxMC0w
 | 
			
		||||
# Ni0yMy5jcnQwDQYJKoZIhvcNAQELBQADggIBAJ1VffwqreEsH2cBMSRb4Z5yS/yp
 | 
			
		||||
# b+pcFLY+TkdkeLEGk5c9MTO1OdfCcTY/2mRsfNB1OW27DzHkwo/7bNGhlBgi7ulm
 | 
			
		||||
# ZzpTTd2YurYeeNg2LpypglYAA7AFvonoaeC6Ce5732pvvinLbtg/SHUB2RjebYIM
 | 
			
		||||
# 9W0jVOR4U3UkV7ndn/OOPcbzaN9l9qRWqveVtihVJ9AkvUCgvxm2EhIRXT0n4ECW
 | 
			
		||||
# OKz3+SmJw7wXsFSFQrP8DJ6LGYnn8AtqgcKBGUIZUnWKNsIdw2FzLixre24/LAl4
 | 
			
		||||
# FOmRsqlb30mjdAy87JGA0j3mSj5mO0+7hvoyGtmW9I/2kQH2zsZ0/fZMcm8Qq3Uw
 | 
			
		||||
# xTSwethQ/gpY3UA8x1RtnWN0SCyxTkctwRQEcb9k+SS+c23Kjgm9swFXSVRk2XPX
 | 
			
		||||
# fx5bRAGOWhmRaw2fpCjcZxkoJLo4S5pu+yFUa2pFEUep8beuyOiJXk+d0tBMdrVX
 | 
			
		||||
# VAmxaQFEfnyhYWxz/gq77EFmPWn9y8FBSX5+k77L+DvktxW/tM4+pTFRhLy/AsGC
 | 
			
		||||
# onsXHRWJjXD+57XQKBqJC4822rpM+Zv/Cuk0+CQ1ZyvgDbjmjJnW4SLq8CdCPSWU
 | 
			
		||||
# 5nR0W2rRnj7tfqAxM328y+l7vzhwRNGQ8cirOoo6CGJ/2XBjU02N7oJtpQUQwXEG
 | 
			
		||||
# ahC0HVUzWLOhcGbyoYIDWTCCAkECAQEwggEBoYHZpIHWMIHTMQswCQYDVQQGEwJV
 | 
			
		||||
# UzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9uZDEeMBwGA1UE
 | 
			
		||||
# ChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMS0wKwYDVQQLEyRNaWNyb3NvZnQgSXJl
 | 
			
		||||
# bGFuZCBPcGVyYXRpb25zIExpbWl0ZWQxJzAlBgNVBAsTHm5TaGllbGQgVFNTIEVT
 | 
			
		||||
# Tjo0MzFBLTA1RTAtRDk0NzElMCMGA1UEAxMcTWljcm9zb2Z0IFRpbWUtU3RhbXAg
 | 
			
		||||
# U2VydmljZaIjCgEBMAcGBSsOAwIaAxUA94Z+bUJn+nKwBvII6sg0Ny7aPDaggYMw
 | 
			
		||||
# gYCkfjB8MQswCQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UE
 | 
			
		||||
# BxMHUmVkbW9uZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMSYwJAYD
 | 
			
		||||
# VQQDEx1NaWNyb3NvZnQgVGltZS1TdGFtcCBQQ0EgMjAxMDANBgkqhkiG9w0BAQsF
 | 
			
		||||
# AAIFAOss/ykwIhgPMjAyNTAxMTExNDMxMDVaGA8yMDI1MDExMjE0MzEwNVowdzA9
 | 
			
		||||
# BgorBgEEAYRZCgQBMS8wLTAKAgUA6yz/KQIBADAKAgEAAgIpggIB/zAHAgEAAgIT
 | 
			
		||||
# XjAKAgUA6y5QqQIBADA2BgorBgEEAYRZCgQCMSgwJjAMBgorBgEEAYRZCgMCoAow
 | 
			
		||||
# CAIBAAIDB6EgoQowCAIBAAIDAYagMA0GCSqGSIb3DQEBCwUAA4IBAQCHE6DSGdY4
 | 
			
		||||
# KF25iAsxQP9F9Lz6ye/vrWGv+j0aSzSbjHVM3kMcEmX9278XgAKgAYII/f16uDtE
 | 
			
		||||
# 7VlEwnKGXujGF249I864U50QFt9hIxqCeuvrshDq8a4Q4KVmuDTosYjS114IJeBK
 | 
			
		||||
# LMOBRgLQCIC+wmvdP4EeYH1tnMIEASFvptE+XBro44/A5pmx5UiDJRL1AG4+aO3x
 | 
			
		||||
# 13psQu7H3thmbGy7Sf0Azjx0PZ+1QUVI7jWNk9DWjGd18G4SQD8Uxeh0v73/dQx1
 | 
			
		||||
# XsFhsyvnrw6uUrxkoAdurif9kyKS+ppo4j9ZkPXzzuc95s1bPcPAyjXCu07Tlunj
 | 
			
		||||
# sXttGVEPQIeXMYIEDTCCBAkCAQEwgZMwfDELMAkGA1UEBhMCVVMxEzARBgNVBAgT
 | 
			
		||||
# Cldhc2hpbmd0b24xEDAOBgNVBAcTB1JlZG1vbmQxHjAcBgNVBAoTFU1pY3Jvc29m
 | 
			
		||||
# dCBDb3Jwb3JhdGlvbjEmMCQGA1UEAxMdTWljcm9zb2Z0IFRpbWUtU3RhbXAgUENB
 | 
			
		||||
# IDIwMTACEzMAAAH6+ztE03czxtMAAQAAAfowDQYJYIZIAWUDBAIBBQCgggFKMBoG
 | 
			
		||||
# CSqGSIb3DQEJAzENBgsqhkiG9w0BCRABBDAvBgkqhkiG9w0BCQQxIgQgxenDb/df
 | 
			
		||||
# q8XJS+q7Oxyca1ryDMmDRA0I3mtr+xYHGZQwgfoGCyqGSIb3DQEJEAIvMYHqMIHn
 | 
			
		||||
# MIHkMIG9BCB98n8tya8+B2jjU/dpJRIwHwHHpco5ogNStYocbkOeVjCBmDCBgKR+
 | 
			
		||||
# MHwxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdS
 | 
			
		||||
# ZWRtb25kMR4wHAYDVQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xJjAkBgNVBAMT
 | 
			
		||||
# HU1pY3Jvc29mdCBUaW1lLVN0YW1wIFBDQSAyMDEwAhMzAAAB+vs7RNN3M8bTAAEA
 | 
			
		||||
# AAH6MCIEIC8gtQ6HRW7jzwlpg15qoYopXwF01KaO1EM5tYzqJwx/MA0GCSqGSIb3
 | 
			
		||||
# DQEBCwUABIICAIsSn8x3zVS870Zf4pa+jfZjdOq++5dHpeLg46sujQ3w+xj3RyhB
 | 
			
		||||
# nRa3kjWyU9nNF6hrt0Q+ILOxUt3jCd3hbB1ZuspwbXdoRtRLfuLPvGiSmINdgFR4
 | 
			
		||||
# LD/jXLrq9USAHYXHzhuYhaVLIpn7M87TbFuGFVaByjmohZRcPCE8y8b7/RIlGm7B
 | 
			
		||||
# wgx0thZA4lHWFyj8j7CwjmueOJSSZ9an4P9VHFKJ63kYub4J1VxbeApGAeeS32SD
 | 
			
		||||
# oI3zDdC+iI+IetR9BUHGcR3Vg7j7c0T+NcrIoPPNb4Ff90Ue24h5RDJMQWrM56ak
 | 
			
		||||
# VEWgVlzhf8CeyeO7/ButBUZu8VLkH0DQraK9UKptZFKOXMELoi/oZL6IJftHp5vU
 | 
			
		||||
# +sPpF3NuuXw8Z5eL9jZ7A1y+H7nMhdXP2pojHDN213VZqeoUoOZlbFl6spDF1hFP
 | 
			
		||||
# 44Fu7TPGEwUNS213Pwln2SJ8SayeVUxsreo4pTvhDl/xZ+B7WNuLL7hatWFGrcf3
 | 
			
		||||
# w/HiVCoTfsY49SaN6zAK6akS3KI6KZHfzjaxDw+4LHo8gL68Ik1HZe4W1jaLYaED
 | 
			
		||||
# LWvKIinaH2vwU0J4a+oX+64eSh0tI9Ef3aM6jn9LgqubY36TzptUTWcsM3vv3YGB
 | 
			
		||||
# Dnf7LPxSt4/s5bUgAHvkWTjESdtIbt6Pxqz4BRha+ckPYBj968t3mSh6
 | 
			
		||||
# b3NvZnQgQ29ycG9yYXRpb24xJjAkBgNVBAMTHU1pY3Jvc29mdCBUaW1lLVN0YW1w
 | 
			
		||||
# IFBDQSAyMDEwMB4XDTI0MDcyNTE4MzEwNFoXDTI1MTAyMjE4MzEwNFowgdMxCzAJ
 | 
			
		||||
# BgNVBAYTAlVTMRMwEQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25k
 | 
			
		||||
# MR4wHAYDVQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xLTArBgNVBAsTJE1pY3Jv
 | 
			
		||||
# c29mdCBJcmVsYW5kIE9wZXJhdGlvbnMgTGltaXRlZDEnMCUGA1UECxMeblNoaWVs
 | 
			
		||||
# ZCBUU1MgRVNOOjZCMDUtMDVFMC1EOTQ3MSUwIwYDVQQDExxNaWNyb3NvZnQgVGlt
 | 
			
		||||
# ZS1TdGFtcCBTZXJ2aWNlMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA
 | 
			
		||||
# 0UJeLMR/N9WPBZhuKVFF+eWJZ68Wujdj4X6JR05cxO5CepNXo17rVazwWLkm5Aja
 | 
			
		||||
# Vh19ZVjDChHzimxsoaXxNu8IDggKwpXvpAAItv4Ux50e9S2uVwfKv57p9JKG+Q7V
 | 
			
		||||
# ONShujl1NCMkcgSrPdmd/8zcsmhzcNobLomrCAIORZ8IwhYy4siVQlf1NKhlyAzm
 | 
			
		||||
# kWJD0N+60IiogFBzg3yISsvroOx0x1xSi2PiRIQlTXE74MggZDIDKqH/hb9FT2kK
 | 
			
		||||
# /nV/aXjuo9LMrrRmn44oYYADe/rO95F+SG3uuuhf+H4IriXr0h9ptA6SwHJPS2Vm
 | 
			
		||||
# bNWCjQWq5G4YkrcqbPMax7vNXUwu7T65E8fFPd1IuE9RsG4TMAV7XkXBopmPNfvL
 | 
			
		||||
# 0hjxg44kpQn384V46o+zdQqy5K9dDlWm/J6vZtp5yA1PyD3w+HbGubS0niEQ1L6w
 | 
			
		||||
# GOrPfzIm0FdOn+xFo48ERl+Fxw/3OvXM5CY1EqnzEznPjzJc7OJwhJVR3VQDHjBc
 | 
			
		||||
# EFTOvS9E0diNu1eocw+ZCkz4Pu/oQv+gqU+bfxL8e7PFktfRDlM6FyOzjP4zuI25
 | 
			
		||||
# gD8tO9zJg6g6fRpaZc439mAbkl3zCVzTLDgchv6SxQajJtvvoQaZxQf0tRiPcbr2
 | 
			
		||||
# HWfMoqqd9uiQ0hTUEhG44FBSTeUPZeEenRCWadCW4G8CAwEAAaOCAUkwggFFMB0G
 | 
			
		||||
# A1UdDgQWBBRIwZsJuOcJfScPWcXZuBA4B89K8jAfBgNVHSMEGDAWgBSfpxVdAF5i
 | 
			
		||||
# XYP05dJlpxtTNRnpcjBfBgNVHR8EWDBWMFSgUqBQhk5odHRwOi8vd3d3Lm1pY3Jv
 | 
			
		||||
# c29mdC5jb20vcGtpb3BzL2NybC9NaWNyb3NvZnQlMjBUaW1lLVN0YW1wJTIwUENB
 | 
			
		||||
# JTIwMjAxMCgxKS5jcmwwbAYIKwYBBQUHAQEEYDBeMFwGCCsGAQUFBzAChlBodHRw
 | 
			
		||||
# Oi8vd3d3Lm1pY3Jvc29mdC5jb20vcGtpb3BzL2NlcnRzL01pY3Jvc29mdCUyMFRp
 | 
			
		||||
# bWUtU3RhbXAlMjBQQ0ElMjAyMDEwKDEpLmNydDAMBgNVHRMBAf8EAjAAMBYGA1Ud
 | 
			
		||||
# JQEB/wQMMAoGCCsGAQUFBwMIMA4GA1UdDwEB/wQEAwIHgDANBgkqhkiG9w0BAQsF
 | 
			
		||||
# AAOCAgEA13kBirH1cHu1WYR1ysj125omGtQ0PaQkEzwGb70xtqSoI+svQihsgdTY
 | 
			
		||||
# xaPfp2IVFdgjaMaBi81wB8/nu866FfFKKdhdp3wnMZ91PpP4Ooe7Ncf6qICkgSuw
 | 
			
		||||
# gdIdQvqE0h8VQ5QW5sDV4Q0Jnj4f7KHYx4NiM8C4jTw8SQtsuxWiTH2Hikf3QYB7
 | 
			
		||||
# 1a7dB9zgHOkW0hgUEeWO9mh2wWqYS/Q48ASjOqYw/ha54oVOff22WaoH+/Hxd9NT
 | 
			
		||||
# EU/4vlvsRIMWT0jsnNI71jVArT4Q9Bt6VShWzyqraE6SKUoZrEwBpVsI0LMg2X3h
 | 
			
		||||
# OLblC1vxM3+wMyOh97aFOs7sFnuemtI2Mfj8qg16BZTJxXlpPurWrG+OBj4BoTDk
 | 
			
		||||
# C9AxXYB3yEtuwMs7pRWLyxIxw/wV9THKUGm+x+VE0POLwkrSMgjulSXkpfELHWWi
 | 
			
		||||
# CVslJbFIIB/4Alv+jQJSKAJuo9CErbm2qeDk/zjJYlYaVGMyKuYZ+uSRVKB2qkEP
 | 
			
		||||
# cEzG1dO9zIa1Mp32J+zzW3P7suJfjw62s3hDOLk+6lMQOR04x+2o17G3LceLkkxJ
 | 
			
		||||
# m41ErdiTjAmdClen9yl6HgMpGS4okjFCJX+CpOFX7gBA3PVxQWubisAQbL5HgTFB
 | 
			
		||||
# tQNEzcCdh1GYw/6nzzNNt+0GQnnobBddfOAiqkzvItqXjvGyK1QwggdxMIIFWaAD
 | 
			
		||||
# AgECAhMzAAAAFcXna54Cm0mZAAAAAAAVMA0GCSqGSIb3DQEBCwUAMIGIMQswCQYD
 | 
			
		||||
# VQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9uZDEe
 | 
			
		||||
# MBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMTIwMAYDVQQDEylNaWNyb3Nv
 | 
			
		||||
# ZnQgUm9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkgMjAxMDAeFw0yMTA5MzAxODIy
 | 
			
		||||
# MjVaFw0zMDA5MzAxODMyMjVaMHwxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpXYXNo
 | 
			
		||||
# aW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNyb3NvZnQgQ29y
 | 
			
		||||
# cG9yYXRpb24xJjAkBgNVBAMTHU1pY3Jvc29mdCBUaW1lLVN0YW1wIFBDQSAyMDEw
 | 
			
		||||
# MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA5OGmTOe0ciELeaLL1yR5
 | 
			
		||||
# vQ7VgtP97pwHB9KpbE51yMo1V/YBf2xK4OK9uT4XYDP/XE/HZveVU3Fa4n5KWv64
 | 
			
		||||
# NmeFRiMMtY0Tz3cywBAY6GB9alKDRLemjkZrBxTzxXb1hlDcwUTIcVxRMTegCjhu
 | 
			
		||||
# je3XD9gmU3w5YQJ6xKr9cmmvHaus9ja+NSZk2pg7uhp7M62AW36MEBydUv626GIl
 | 
			
		||||
# 3GoPz130/o5Tz9bshVZN7928jaTjkY+yOSxRnOlwaQ3KNi1wjjHINSi947SHJMPg
 | 
			
		||||
# yY9+tVSP3PoFVZhtaDuaRr3tpK56KTesy+uDRedGbsoy1cCGMFxPLOJiss254o2I
 | 
			
		||||
# 5JasAUq7vnGpF1tnYN74kpEeHT39IM9zfUGaRnXNxF803RKJ1v2lIH1+/NmeRd+2
 | 
			
		||||
# ci/bfV+AutuqfjbsNkz2K26oElHovwUDo9Fzpk03dJQcNIIP8BDyt0cY7afomXw/
 | 
			
		||||
# TNuvXsLz1dhzPUNOwTM5TI4CvEJoLhDqhFFG4tG9ahhaYQFzymeiXtcodgLiMxhy
 | 
			
		||||
# 16cg8ML6EgrXY28MyTZki1ugpoMhXV8wdJGUlNi5UPkLiWHzNgY1GIRH29wb0f2y
 | 
			
		||||
# 1BzFa/ZcUlFdEtsluq9QBXpsxREdcu+N+VLEhReTwDwV2xo3xwgVGD94q0W29R6H
 | 
			
		||||
# XtqPnhZyacaue7e3PmriLq0CAwEAAaOCAd0wggHZMBIGCSsGAQQBgjcVAQQFAgMB
 | 
			
		||||
# AAEwIwYJKwYBBAGCNxUCBBYEFCqnUv5kxJq+gpE8RjUpzxD/LwTuMB0GA1UdDgQW
 | 
			
		||||
# BBSfpxVdAF5iXYP05dJlpxtTNRnpcjBcBgNVHSAEVTBTMFEGDCsGAQQBgjdMg30B
 | 
			
		||||
# ATBBMD8GCCsGAQUFBwIBFjNodHRwOi8vd3d3Lm1pY3Jvc29mdC5jb20vcGtpb3Bz
 | 
			
		||||
# L0RvY3MvUmVwb3NpdG9yeS5odG0wEwYDVR0lBAwwCgYIKwYBBQUHAwgwGQYJKwYB
 | 
			
		||||
# BAGCNxQCBAweCgBTAHUAYgBDAEEwCwYDVR0PBAQDAgGGMA8GA1UdEwEB/wQFMAMB
 | 
			
		||||
# Af8wHwYDVR0jBBgwFoAU1fZWy4/oolxiaNE9lJBb186aGMQwVgYDVR0fBE8wTTBL
 | 
			
		||||
# oEmgR4ZFaHR0cDovL2NybC5taWNyb3NvZnQuY29tL3BraS9jcmwvcHJvZHVjdHMv
 | 
			
		||||
# TWljUm9vQ2VyQXV0XzIwMTAtMDYtMjMuY3JsMFoGCCsGAQUFBwEBBE4wTDBKBggr
 | 
			
		||||
# BgEFBQcwAoY+aHR0cDovL3d3dy5taWNyb3NvZnQuY29tL3BraS9jZXJ0cy9NaWNS
 | 
			
		||||
# b29DZXJBdXRfMjAxMC0wNi0yMy5jcnQwDQYJKoZIhvcNAQELBQADggIBAJ1Vffwq
 | 
			
		||||
# reEsH2cBMSRb4Z5yS/ypb+pcFLY+TkdkeLEGk5c9MTO1OdfCcTY/2mRsfNB1OW27
 | 
			
		||||
# DzHkwo/7bNGhlBgi7ulmZzpTTd2YurYeeNg2LpypglYAA7AFvonoaeC6Ce5732pv
 | 
			
		||||
# vinLbtg/SHUB2RjebYIM9W0jVOR4U3UkV7ndn/OOPcbzaN9l9qRWqveVtihVJ9Ak
 | 
			
		||||
# vUCgvxm2EhIRXT0n4ECWOKz3+SmJw7wXsFSFQrP8DJ6LGYnn8AtqgcKBGUIZUnWK
 | 
			
		||||
# NsIdw2FzLixre24/LAl4FOmRsqlb30mjdAy87JGA0j3mSj5mO0+7hvoyGtmW9I/2
 | 
			
		||||
# kQH2zsZ0/fZMcm8Qq3UwxTSwethQ/gpY3UA8x1RtnWN0SCyxTkctwRQEcb9k+SS+
 | 
			
		||||
# c23Kjgm9swFXSVRk2XPXfx5bRAGOWhmRaw2fpCjcZxkoJLo4S5pu+yFUa2pFEUep
 | 
			
		||||
# 8beuyOiJXk+d0tBMdrVXVAmxaQFEfnyhYWxz/gq77EFmPWn9y8FBSX5+k77L+Dvk
 | 
			
		||||
# txW/tM4+pTFRhLy/AsGConsXHRWJjXD+57XQKBqJC4822rpM+Zv/Cuk0+CQ1Zyvg
 | 
			
		||||
# DbjmjJnW4SLq8CdCPSWU5nR0W2rRnj7tfqAxM328y+l7vzhwRNGQ8cirOoo6CGJ/
 | 
			
		||||
# 2XBjU02N7oJtpQUQwXEGahC0HVUzWLOhcGbyoYIDWTCCAkECAQEwggEBoYHZpIHW
 | 
			
		||||
# MIHTMQswCQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMH
 | 
			
		||||
# UmVkbW9uZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMS0wKwYDVQQL
 | 
			
		||||
# EyRNaWNyb3NvZnQgSXJlbGFuZCBPcGVyYXRpb25zIExpbWl0ZWQxJzAlBgNVBAsT
 | 
			
		||||
# Hm5TaGllbGQgVFNTIEVTTjo2QjA1LTA1RTAtRDk0NzElMCMGA1UEAxMcTWljcm9z
 | 
			
		||||
# b2Z0IFRpbWUtU3RhbXAgU2VydmljZaIjCgEBMAcGBSsOAwIaAxUAFU9eSpdxs0a0
 | 
			
		||||
# 6JFIuGFHIj/I+36ggYMwgYCkfjB8MQswCQYDVQQGEwJVUzETMBEGA1UECBMKV2Fz
 | 
			
		||||
# aGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9uZDEeMBwGA1UEChMVTWljcm9zb2Z0IENv
 | 
			
		||||
# cnBvcmF0aW9uMSYwJAYDVQQDEx1NaWNyb3NvZnQgVGltZS1TdGFtcCBQQ0EgMjAx
 | 
			
		||||
# MDANBgkqhkiG9w0BAQsFAAIFAOsTx1MwIhgPMjAyNDEyMjMxMTI2MTFaGA8yMDI0
 | 
			
		||||
# MTIyNDExMjYxMVowdzA9BgorBgEEAYRZCgQBMS8wLTAKAgUA6xPHUwIBADAKAgEA
 | 
			
		||||
# AgIEpgIB/zAHAgEAAgIULjAKAgUA6xUY0wIBADA2BgorBgEEAYRZCgQCMSgwJjAM
 | 
			
		||||
# BgorBgEEAYRZCgMCoAowCAIBAAIDB6EgoQowCAIBAAIDAYagMA0GCSqGSIb3DQEB
 | 
			
		||||
# CwUAA4IBAQDkPou5w9O3fL9lm7NIu3mAwCMpezmpCbx9mCUfLb4cXznb4psGEspn
 | 
			
		||||
# XaDg3PGX1yGC3GR5peByH/hiarlvYv5SZbofvP+iiYFxeLGi+usbC8FQnuWrgyqh
 | 
			
		||||
# 7RV01Fm2Is7PGF3NXQaXbGkSQUZzrekeRr4zdV2nIKshANlifSPb/wAd6BLcKtYS
 | 
			
		||||
# 3Kr9xUXgZeHxo6tD88GDxJ5FDsG1RxczsdCO5mVqFZUrQqz6Cs49xt7cq2XlEwMX
 | 
			
		||||
# 53L40YCUrvYYiTgqvxtOzg58ksUkP1YDfeP9Rel7pGXGyzJF0Fo+FAXiY098HPcW
 | 
			
		||||
# eRCGaVV55Keop55er/x0vYOQK3WYmR9ZMYIEDTCCBAkCAQEwgZMwfDELMAkGA1UE
 | 
			
		||||
# BhMCVVMxEzARBgNVBAgTCldhc2hpbmd0b24xEDAOBgNVBAcTB1JlZG1vbmQxHjAc
 | 
			
		||||
# BgNVBAoTFU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjEmMCQGA1UEAxMdTWljcm9zb2Z0
 | 
			
		||||
# IFRpbWUtU3RhbXAgUENBIDIwMTACEzMAAAH2gy8malRdIsEAAQAAAfYwDQYJYIZI
 | 
			
		||||
# AWUDBAIBBQCgggFKMBoGCSqGSIb3DQEJAzENBgsqhkiG9w0BCRABBDAvBgkqhkiG
 | 
			
		||||
# 9w0BCQQxIgQgrAY6roZynzJwSUQzsAfof3O6FxHR94SlM3Hdh+QLWTowgfoGCyqG
 | 
			
		||||
# SIb3DQEJEAIvMYHqMIHnMIHkMIG9BCArYUzxlF6m5USLS4f8NXL/8aoNEVdsCZRm
 | 
			
		||||
# F+LlQjG2ojCBmDCBgKR+MHwxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpXYXNoaW5n
 | 
			
		||||
# dG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNyb3NvZnQgQ29ycG9y
 | 
			
		||||
# YXRpb24xJjAkBgNVBAMTHU1pY3Jvc29mdCBUaW1lLVN0YW1wIFBDQSAyMDEwAhMz
 | 
			
		||||
# AAAB9oMvJmpUXSLBAAEAAAH2MCIEIOEmAHxbUTtc2fET28qfaLGRzaIhD4dw4/ak
 | 
			
		||||
# m6mLo6PCMA0GCSqGSIb3DQEBCwUABIICAH4zqNf+CV7yNKXAQwNuEZwzCHs4eJC4
 | 
			
		||||
# mNKMRp9e2W++JJaxtY3kLEBoGDKfz+8RYsjcLtNOg83Hd2gEmAmgvWfs/mZlhi8j
 | 
			
		||||
# tM5Yj9606ukzuF2797CDwZiXz5JTIs1wIm5+rWuAny0azioafaOZtcaxPqnANbUf
 | 
			
		||||
# UHnAYoZ0W6AkSnz99XrqRueh8b3Z7h2A5saVS1/MV1fjfImxH673GlexKRYORTFP
 | 
			
		||||
# A9XH8vCvVTIZobKSWa6y/KG4U5dkWrzJuLbT9Kr3x6yk0bO6epG09yy86HmlnmwQ
 | 
			
		||||
# bJwBedz4ZpKkvtIJ2U2PYvLti5bztm5WL/hWhDmtXBhoqKy1d/i4LDz7F4vXy9//
 | 
			
		||||
# 5Wy8zHMLw4ZFwfywP8/P5pZP7nlvIrordtefS2z3Ipea0thJxwyFJSU8c7OGvPof
 | 
			
		||||
# uHhYKMn+Lg1tj5QcIvT7KG0JGp/XWe/CEB9ruOkYZh9VKBlEU2CkDsWeTXFy5heV
 | 
			
		||||
# eMPMxRC/GBHPypBHHSrd8BtUsKgehcetdsfQrOI3VLV9gx8SGr8ehSU2Rg0U2UtK
 | 
			
		||||
# a4S5THXp0PksrjJLmykIsvBmMgl3uK4KJbu6zh3w5ACSS/OZXzrsowysGjn2QBwb
 | 
			
		||||
# hoIjCDhmNLLq2gupcAhPCgqUX6Ixmg8H0SlqoRp0mZTss7ZS+ErxTQoFBbLkoX5F
 | 
			
		||||
# 9HjkIOcM6/0F
 | 
			
		||||
# SIG # End signature block
 | 
			
		||||
							
								
								
									
										27
									
								
								externals/install-dotnet.sh
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										27
									
								
								externals/install-dotnet.sh
									
									
									
									
										vendored
									
									
								
							@ -1396,15 +1396,24 @@ get_feeds_to_use()
 | 
			
		||||
{
 | 
			
		||||
    feeds=(
 | 
			
		||||
    "https://builds.dotnet.microsoft.com/dotnet"
 | 
			
		||||
    "https://dotnetcli.azureedge.net/dotnet"
 | 
			
		||||
    "https://ci.dot.net/public"
 | 
			
		||||
    "https://dotnetbuilds.azureedge.net/public"
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
    if [[ -n "$azure_feed" ]]; then
 | 
			
		||||
        feeds=("$azure_feed")
 | 
			
		||||
    fi
 | 
			
		||||
 | 
			
		||||
    if [[ -n "$uncached_feed" ]]; then
 | 
			
		||||
        feeds=("$uncached_feed")
 | 
			
		||||
    if [[ "$no_cdn" == "true" ]]; then
 | 
			
		||||
        feeds=(
 | 
			
		||||
        "https://dotnetcli.blob.core.windows.net/dotnet"
 | 
			
		||||
        "https://dotnetbuilds.blob.core.windows.net/public"
 | 
			
		||||
        )
 | 
			
		||||
 | 
			
		||||
        if [[ -n "$uncached_feed" ]]; then
 | 
			
		||||
            feeds=("$uncached_feed")
 | 
			
		||||
        fi
 | 
			
		||||
    fi
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -1536,7 +1545,7 @@ generate_regular_links() {
 | 
			
		||||
        link_types+=("legacy")
 | 
			
		||||
    else
 | 
			
		||||
        legacy_download_link=""
 | 
			
		||||
        say_verbose "Could not construct a legacy_download_link; omitting..."
 | 
			
		||||
        say_verbose "Cound not construct a legacy_download_link; omitting..."
 | 
			
		||||
    fi
 | 
			
		||||
 | 
			
		||||
    #  Check if the SDK version is already installed.
 | 
			
		||||
@ -1639,7 +1648,7 @@ install_dotnet() {
 | 
			
		||||
                say "The resource at $link_type link '$download_link' is not available."
 | 
			
		||||
                ;;
 | 
			
		||||
            *)
 | 
			
		||||
                say "Failed to download $link_type link '$download_link': $http_code $download_error_msg"
 | 
			
		||||
                say "Failed to download $link_type link '$download_link': $download_error_msg"
 | 
			
		||||
                ;;
 | 
			
		||||
            esac
 | 
			
		||||
            rm -f "$zip_path" 2>&1 && say_verbose "Temporary archive file $zip_path was removed"
 | 
			
		||||
@ -1700,6 +1709,7 @@ install_dir="<auto>"
 | 
			
		||||
architecture="<auto>"
 | 
			
		||||
dry_run=false
 | 
			
		||||
no_path=false
 | 
			
		||||
no_cdn=false
 | 
			
		||||
azure_feed=""
 | 
			
		||||
uncached_feed=""
 | 
			
		||||
feed_credential=""
 | 
			
		||||
@ -1772,6 +1782,10 @@ do
 | 
			
		||||
            verbose=true
 | 
			
		||||
            non_dynamic_parameters+=" $name"
 | 
			
		||||
            ;;
 | 
			
		||||
        --no-cdn|-[Nn]o[Cc]dn)
 | 
			
		||||
            no_cdn=true
 | 
			
		||||
            non_dynamic_parameters+=" $name"
 | 
			
		||||
            ;;
 | 
			
		||||
        --azure-feed|-[Aa]zure[Ff]eed)
 | 
			
		||||
            shift
 | 
			
		||||
            azure_feed="$1"
 | 
			
		||||
@ -1876,10 +1890,13 @@ do
 | 
			
		||||
            echo "  --verbose,-Verbose                 Display diagnostics information."
 | 
			
		||||
            echo "  --azure-feed,-AzureFeed            For internal use only."
 | 
			
		||||
            echo "                                     Allows using a different storage to download SDK archives from."
 | 
			
		||||
            echo "                                     This parameter is only used if --no-cdn is false."
 | 
			
		||||
            echo "  --uncached-feed,-UncachedFeed      For internal use only."
 | 
			
		||||
            echo "                                     Allows using a different storage to download SDK archives from."
 | 
			
		||||
            echo "                                     This parameter is only used if --no-cdn is true."
 | 
			
		||||
            echo "  --skip-non-versioned-files         Skips non-versioned files if they already exist, such as the dotnet executable."
 | 
			
		||||
            echo "      -SkipNonVersionedFiles"
 | 
			
		||||
            echo "  --no-cdn,-NoCdn                    Disable downloading from the Azure CDN, and use the uncached feed directly."
 | 
			
		||||
            echo "  --jsonfile <JSONFILE>              Determines the SDK version from a user specified global.json file."
 | 
			
		||||
            echo "                                     Note: global.json must have a value for 'SDK:Version'"
 | 
			
		||||
            echo "  --keep-zip,-KeepZip                If set, downloaded file is kept."
 | 
			
		||||
@ -1939,4 +1956,4 @@ fi
 | 
			
		||||
 | 
			
		||||
say "Note that the script does not resolve dependencies during installation."
 | 
			
		||||
say "To check the list of dependencies, go to https://learn.microsoft.com/dotnet/core/install, select your operating system and check the \"Dependencies\" section."
 | 
			
		||||
say "Installation finished successfully."
 | 
			
		||||
say "Installation finished successfully."
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										310
									
								
								src/authutil.ts
									
									
									
									
									
								
							
							
						
						
									
										310
									
								
								src/authutil.ts
									
									
									
									
									
								
							@ -1,155 +1,155 @@
 | 
			
		||||
import * as fs from 'fs';
 | 
			
		||||
import * as path from 'path';
 | 
			
		||||
import * as core from '@actions/core';
 | 
			
		||||
import * as github from '@actions/github';
 | 
			
		||||
import * as xmlbuilder from 'xmlbuilder';
 | 
			
		||||
import * as xmlParser from 'fast-xml-parser';
 | 
			
		||||
import {ProcessEnvOptions} from 'child_process';
 | 
			
		||||
 | 
			
		||||
export function configAuthentication(
 | 
			
		||||
  feedUrl: string,
 | 
			
		||||
  existingFileLocation: string = '',
 | 
			
		||||
  processRoot: string = process.cwd()
 | 
			
		||||
) {
 | 
			
		||||
  const existingNuGetConfig: string = path.resolve(
 | 
			
		||||
    processRoot,
 | 
			
		||||
    existingFileLocation === ''
 | 
			
		||||
      ? getExistingNugetConfig(processRoot)
 | 
			
		||||
      : existingFileLocation
 | 
			
		||||
  );
 | 
			
		||||
 | 
			
		||||
  const tempNuGetConfig: string = path.resolve(
 | 
			
		||||
    processRoot,
 | 
			
		||||
    '../',
 | 
			
		||||
    'nuget.config'
 | 
			
		||||
  );
 | 
			
		||||
 | 
			
		||||
  writeFeedToFile(feedUrl, existingNuGetConfig, tempNuGetConfig);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function isValidKey(key: string): boolean {
 | 
			
		||||
  return /^[\w\-\.]+$/i.test(key);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function getExistingNugetConfig(processRoot: string) {
 | 
			
		||||
  const defaultConfigName = 'nuget.config';
 | 
			
		||||
  const configFileNames = fs
 | 
			
		||||
    .readdirSync(processRoot)
 | 
			
		||||
    .filter(filename => filename.toLowerCase() === defaultConfigName);
 | 
			
		||||
  if (configFileNames.length) {
 | 
			
		||||
    return configFileNames[0];
 | 
			
		||||
  }
 | 
			
		||||
  return defaultConfigName;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function writeFeedToFile(
 | 
			
		||||
  feedUrl: string,
 | 
			
		||||
  existingFileLocation: string,
 | 
			
		||||
  tempFileLocation: string
 | 
			
		||||
) {
 | 
			
		||||
  console.log(
 | 
			
		||||
    `dotnet-auth: Finding any source references in ${existingFileLocation}, writing a new temporary configuration file with credentials to ${tempFileLocation}`
 | 
			
		||||
  );
 | 
			
		||||
  let xml: xmlbuilder.XMLElement;
 | 
			
		||||
  let sourceKeys: string[] = [];
 | 
			
		||||
  let owner: string = core.getInput('owner');
 | 
			
		||||
  let sourceUrl: string = feedUrl;
 | 
			
		||||
  if (!owner) {
 | 
			
		||||
    owner = github.context.repo.owner;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  if (!process.env.NUGET_AUTH_TOKEN || process.env.NUGET_AUTH_TOKEN == '') {
 | 
			
		||||
    throw new Error(
 | 
			
		||||
      'The NUGET_AUTH_TOKEN environment variable was not provided. In this step, add the following: \r\nenv:\r\n  NUGET_AUTH_TOKEN: ${{secrets.GITHUB_TOKEN}}'
 | 
			
		||||
    );
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  if (fs.existsSync(existingFileLocation)) {
 | 
			
		||||
    // get key from existing NuGet.config so NuGet/dotnet can match credentials
 | 
			
		||||
    const curContents: string = fs.readFileSync(existingFileLocation, 'utf8');
 | 
			
		||||
    var json = xmlParser.parse(curContents, {ignoreAttributes: false});
 | 
			
		||||
 | 
			
		||||
    if (typeof json.configuration == 'undefined') {
 | 
			
		||||
      throw new Error(`The provided NuGet.config seems invalid.`);
 | 
			
		||||
    }
 | 
			
		||||
    if (typeof json.configuration.packageSources != 'undefined') {
 | 
			
		||||
      if (typeof json.configuration.packageSources.add != 'undefined') {
 | 
			
		||||
        // file has at least one <add>
 | 
			
		||||
        if (typeof json.configuration.packageSources.add[0] == 'undefined') {
 | 
			
		||||
          // file has only one <add>
 | 
			
		||||
          if (
 | 
			
		||||
            json.configuration.packageSources.add['@_value']
 | 
			
		||||
              .toLowerCase()
 | 
			
		||||
              .includes(feedUrl.toLowerCase())
 | 
			
		||||
          ) {
 | 
			
		||||
            let key = json.configuration.packageSources.add['@_key'];
 | 
			
		||||
            sourceKeys.push(key);
 | 
			
		||||
            core.debug(`Found a URL with key ${key}`);
 | 
			
		||||
          }
 | 
			
		||||
        } else {
 | 
			
		||||
          // file has 2+ <add>
 | 
			
		||||
          for (
 | 
			
		||||
            let i = 0;
 | 
			
		||||
            i < json.configuration.packageSources.add.length;
 | 
			
		||||
            i++
 | 
			
		||||
          ) {
 | 
			
		||||
            const source = json.configuration.packageSources.add[i];
 | 
			
		||||
            const value = source['@_value'];
 | 
			
		||||
            core.debug(`source '${value}'`);
 | 
			
		||||
            if (value.toLowerCase().includes(feedUrl.toLowerCase())) {
 | 
			
		||||
              let key = source['@_key'];
 | 
			
		||||
              sourceKeys.push(key);
 | 
			
		||||
              core.debug(`Found a URL with key ${key}`);
 | 
			
		||||
            }
 | 
			
		||||
          }
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  xml = xmlbuilder
 | 
			
		||||
    .create('configuration')
 | 
			
		||||
    .ele('config')
 | 
			
		||||
    .ele('add', {key: 'defaultPushSource', value: sourceUrl})
 | 
			
		||||
    .up()
 | 
			
		||||
    .up();
 | 
			
		||||
 | 
			
		||||
  if (sourceKeys.length == 0) {
 | 
			
		||||
    let keystring = 'Source';
 | 
			
		||||
    xml = xml
 | 
			
		||||
      .ele('packageSources')
 | 
			
		||||
      .ele('add', {key: keystring, value: sourceUrl})
 | 
			
		||||
      .up()
 | 
			
		||||
      .up();
 | 
			
		||||
    sourceKeys.push(keystring);
 | 
			
		||||
  }
 | 
			
		||||
  xml = xml.ele('packageSourceCredentials');
 | 
			
		||||
 | 
			
		||||
  sourceKeys.forEach(key => {
 | 
			
		||||
    if (!isValidKey(key)) {
 | 
			
		||||
      throw new Error(
 | 
			
		||||
        "Source name can contain letters, numbers, and '-', '_', '.' symbols only. Please, fix source name in NuGet.config and try again."
 | 
			
		||||
      );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    xml = xml
 | 
			
		||||
      .ele(key)
 | 
			
		||||
      .ele('add', {key: 'Username', value: owner})
 | 
			
		||||
      .up()
 | 
			
		||||
      .ele('add', {
 | 
			
		||||
        key: 'ClearTextPassword',
 | 
			
		||||
        value: process.env.NUGET_AUTH_TOKEN
 | 
			
		||||
      })
 | 
			
		||||
      .up()
 | 
			
		||||
      .up();
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  // If NuGet fixes itself such that on Linux it can look for environment variables in the config file (it doesn't seem to work today),
 | 
			
		||||
  // use this for the value above
 | 
			
		||||
  //           process.platform == 'win32'
 | 
			
		||||
  //             ? '%NUGET_AUTH_TOKEN%'
 | 
			
		||||
  //             : '$NUGET_AUTH_TOKEN'
 | 
			
		||||
 | 
			
		||||
  var output = xml.end({pretty: true});
 | 
			
		||||
  fs.writeFileSync(tempFileLocation, output);
 | 
			
		||||
}
 | 
			
		||||
import * as fs from 'fs';
 | 
			
		||||
import * as path from 'path';
 | 
			
		||||
import * as core from '@actions/core';
 | 
			
		||||
import * as github from '@actions/github';
 | 
			
		||||
import * as xmlbuilder from 'xmlbuilder';
 | 
			
		||||
import * as xmlParser from 'fast-xml-parser';
 | 
			
		||||
import {ProcessEnvOptions} from 'child_process';
 | 
			
		||||
 | 
			
		||||
export function configAuthentication(
 | 
			
		||||
  feedUrl: string,
 | 
			
		||||
  existingFileLocation: string = '',
 | 
			
		||||
  processRoot: string = process.cwd()
 | 
			
		||||
) {
 | 
			
		||||
  const existingNuGetConfig: string = path.resolve(
 | 
			
		||||
    processRoot,
 | 
			
		||||
    existingFileLocation === ''
 | 
			
		||||
      ? getExistingNugetConfig(processRoot)
 | 
			
		||||
      : existingFileLocation
 | 
			
		||||
  );
 | 
			
		||||
 | 
			
		||||
  const tempNuGetConfig: string = path.resolve(
 | 
			
		||||
    processRoot,
 | 
			
		||||
    '../',
 | 
			
		||||
    'nuget.config'
 | 
			
		||||
  );
 | 
			
		||||
 | 
			
		||||
  writeFeedToFile(feedUrl, existingNuGetConfig, tempNuGetConfig);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function isValidKey(key: string): boolean {
 | 
			
		||||
  return /^[\w\-\.]+$/i.test(key);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function getExistingNugetConfig(processRoot: string) {
 | 
			
		||||
  const defaultConfigName = 'nuget.config';
 | 
			
		||||
  const configFileNames = fs
 | 
			
		||||
    .readdirSync(processRoot)
 | 
			
		||||
    .filter(filename => filename.toLowerCase() === defaultConfigName);
 | 
			
		||||
  if (configFileNames.length) {
 | 
			
		||||
    return configFileNames[0];
 | 
			
		||||
  }
 | 
			
		||||
  return defaultConfigName;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function writeFeedToFile(
 | 
			
		||||
  feedUrl: string,
 | 
			
		||||
  existingFileLocation: string,
 | 
			
		||||
  tempFileLocation: string
 | 
			
		||||
) {
 | 
			
		||||
  console.log(
 | 
			
		||||
    `dotnet-auth: Finding any source references in ${existingFileLocation}, writing a new temporary configuration file with credentials to ${tempFileLocation}`
 | 
			
		||||
  );
 | 
			
		||||
  let xml: xmlbuilder.XMLElement;
 | 
			
		||||
  let sourceKeys: string[] = [];
 | 
			
		||||
  let owner: string = core.getInput('owner');
 | 
			
		||||
  let sourceUrl: string = feedUrl;
 | 
			
		||||
  if (!owner) {
 | 
			
		||||
    owner = github.context.repo.owner;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  if (!process.env.NUGET_AUTH_TOKEN || process.env.NUGET_AUTH_TOKEN == '') {
 | 
			
		||||
    throw new Error(
 | 
			
		||||
      'The NUGET_AUTH_TOKEN environment variable was not provided. In this step, add the following: \r\nenv:\r\n  NUGET_AUTH_TOKEN: ${{secrets.GITHUB_TOKEN}}'
 | 
			
		||||
    );
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  if (fs.existsSync(existingFileLocation)) {
 | 
			
		||||
    // get key from existing NuGet.config so NuGet/dotnet can match credentials
 | 
			
		||||
    const curContents: string = fs.readFileSync(existingFileLocation, 'utf8');
 | 
			
		||||
    var json = xmlParser.parse(curContents, {ignoreAttributes: false});
 | 
			
		||||
 | 
			
		||||
    if (typeof json.configuration == 'undefined') {
 | 
			
		||||
      throw new Error(`The provided NuGet.config seems invalid.`);
 | 
			
		||||
    }
 | 
			
		||||
    if (typeof json.configuration.packageSources != 'undefined') {
 | 
			
		||||
      if (typeof json.configuration.packageSources.add != 'undefined') {
 | 
			
		||||
        // file has at least one <add>
 | 
			
		||||
        if (typeof json.configuration.packageSources.add[0] == 'undefined') {
 | 
			
		||||
          // file has only one <add>
 | 
			
		||||
          if (
 | 
			
		||||
            json.configuration.packageSources.add['@_value']
 | 
			
		||||
              .toLowerCase()
 | 
			
		||||
              .includes(feedUrl.toLowerCase())
 | 
			
		||||
          ) {
 | 
			
		||||
            let key = json.configuration.packageSources.add['@_key'];
 | 
			
		||||
            sourceKeys.push(key);
 | 
			
		||||
            core.debug(`Found a URL with key ${key}`);
 | 
			
		||||
          }
 | 
			
		||||
        } else {
 | 
			
		||||
          // file has 2+ <add>
 | 
			
		||||
          for (
 | 
			
		||||
            let i = 0;
 | 
			
		||||
            i < json.configuration.packageSources.add.length;
 | 
			
		||||
            i++
 | 
			
		||||
          ) {
 | 
			
		||||
            const source = json.configuration.packageSources.add[i];
 | 
			
		||||
            const value = source['@_value'];
 | 
			
		||||
            core.debug(`source '${value}'`);
 | 
			
		||||
            if (value.toLowerCase().includes(feedUrl.toLowerCase())) {
 | 
			
		||||
              let key = source['@_key'];
 | 
			
		||||
              sourceKeys.push(key);
 | 
			
		||||
              core.debug(`Found a URL with key ${key}`);
 | 
			
		||||
            }
 | 
			
		||||
          }
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  xml = xmlbuilder
 | 
			
		||||
    .create('configuration')
 | 
			
		||||
    .ele('config')
 | 
			
		||||
    .ele('add', {key: 'defaultPushSource', value: sourceUrl})
 | 
			
		||||
    .up()
 | 
			
		||||
    .up();
 | 
			
		||||
 | 
			
		||||
  if (sourceKeys.length == 0) {
 | 
			
		||||
    let keystring = 'Source';
 | 
			
		||||
    xml = xml
 | 
			
		||||
      .ele('packageSources')
 | 
			
		||||
      .ele('add', {key: keystring, value: sourceUrl})
 | 
			
		||||
      .up()
 | 
			
		||||
      .up();
 | 
			
		||||
    sourceKeys.push(keystring);
 | 
			
		||||
  }
 | 
			
		||||
  xml = xml.ele('packageSourceCredentials');
 | 
			
		||||
 | 
			
		||||
  sourceKeys.forEach(key => {
 | 
			
		||||
    if (!isValidKey(key)) {
 | 
			
		||||
      throw new Error(
 | 
			
		||||
        "Source name can contain letters, numbers, and '-', '_', '.' symbols only. Please, fix source name in NuGet.config and try again."
 | 
			
		||||
      );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    xml = xml
 | 
			
		||||
      .ele(key)
 | 
			
		||||
      .ele('add', {key: 'Username', value: owner})
 | 
			
		||||
      .up()
 | 
			
		||||
      .ele('add', {
 | 
			
		||||
        key: 'ClearTextPassword',
 | 
			
		||||
        value: process.env.NUGET_AUTH_TOKEN
 | 
			
		||||
      })
 | 
			
		||||
      .up()
 | 
			
		||||
      .up();
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  // If NuGet fixes itself such that on Linux it can look for environment variables in the config file (it doesn't seem to work today),
 | 
			
		||||
  // use this for the value above
 | 
			
		||||
  //           process.platform == 'win32'
 | 
			
		||||
  //             ? '%NUGET_AUTH_TOKEN%'
 | 
			
		||||
  //             : '$NUGET_AUTH_TOKEN'
 | 
			
		||||
 | 
			
		||||
  var output = xml.end({pretty: true});
 | 
			
		||||
  fs.writeFileSync(tempFileLocation, output);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										609
									
								
								src/installer.ts
									
									
									
									
									
								
							
							
						
						
									
										609
									
								
								src/installer.ts
									
									
									
									
									
								
							@ -1,304 +1,305 @@
 | 
			
		||||
// Load tempDirectory before it gets wiped by tool-cache
 | 
			
		||||
import * as core from '@actions/core';
 | 
			
		||||
import * as exec from '@actions/exec';
 | 
			
		||||
import * as io from '@actions/io';
 | 
			
		||||
import hc = require('@actions/http-client');
 | 
			
		||||
import {chmodSync} from 'fs';
 | 
			
		||||
import * as path from 'path';
 | 
			
		||||
import {ExecOptions} from '@actions/exec/lib/interfaces';
 | 
			
		||||
import * as semver from 'semver';
 | 
			
		||||
 | 
			
		||||
const IS_WINDOWS = process.platform === 'win32';
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Represents the inputted version information
 | 
			
		||||
 */
 | 
			
		||||
export class DotNetVersionInfo {
 | 
			
		||||
  public inputVersion: string;
 | 
			
		||||
  private fullversion: string;
 | 
			
		||||
  private isExactVersionSet: boolean = false;
 | 
			
		||||
 | 
			
		||||
  constructor(version: string) {
 | 
			
		||||
    this.inputVersion = version;
 | 
			
		||||
 | 
			
		||||
    // Check for exact match
 | 
			
		||||
    if (semver.valid(semver.clean(version) || '') != null) {
 | 
			
		||||
      this.fullversion = semver.clean(version) as string;
 | 
			
		||||
      this.isExactVersionSet = true;
 | 
			
		||||
 | 
			
		||||
      return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    const parts: string[] = version.split('.');
 | 
			
		||||
 | 
			
		||||
    if (parts.length < 2 || parts.length > 3) this.throwInvalidVersionFormat();
 | 
			
		||||
 | 
			
		||||
    if (parts.length == 3 && parts[2] !== 'x' && parts[2] !== '*') {
 | 
			
		||||
      this.throwInvalidVersionFormat();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    const major = this.getVersionNumberOrThrow(parts[0]);
 | 
			
		||||
    const minor = ['x', '*'].includes(parts[1])
 | 
			
		||||
      ? parts[1]
 | 
			
		||||
      : this.getVersionNumberOrThrow(parts[1]);
 | 
			
		||||
 | 
			
		||||
    this.fullversion = major + '.' + minor;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  private getVersionNumberOrThrow(input: string): number {
 | 
			
		||||
    try {
 | 
			
		||||
      if (!input || input.trim() === '') this.throwInvalidVersionFormat();
 | 
			
		||||
 | 
			
		||||
      let number = Number(input);
 | 
			
		||||
 | 
			
		||||
      if (Number.isNaN(number) || number < 0) this.throwInvalidVersionFormat();
 | 
			
		||||
 | 
			
		||||
      return number;
 | 
			
		||||
    } catch {
 | 
			
		||||
      this.throwInvalidVersionFormat();
 | 
			
		||||
      return -1;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  private throwInvalidVersionFormat() {
 | 
			
		||||
    throw new Error(
 | 
			
		||||
      'Invalid version format! Supported: 1.2.3, 1.2, 1.2.x, 1.2.*'
 | 
			
		||||
    );
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * If true exacatly one version should be resolved
 | 
			
		||||
   */
 | 
			
		||||
  public isExactVersion(): boolean {
 | 
			
		||||
    return this.isExactVersionSet;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  public version(): string {
 | 
			
		||||
    return this.fullversion;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export class DotnetCoreInstaller {
 | 
			
		||||
  constructor(version: string, includePrerelease: boolean = false) {
 | 
			
		||||
    this.version = version;
 | 
			
		||||
    this.includePrerelease = includePrerelease;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  public async installDotnet() {
 | 
			
		||||
    let output = '';
 | 
			
		||||
    let resultCode = 0;
 | 
			
		||||
 | 
			
		||||
    let calculatedVersion = await this.resolveVersion(
 | 
			
		||||
      new DotNetVersionInfo(this.version)
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    var envVariables: {[key: string]: string} = {};
 | 
			
		||||
    for (let key in process.env) {
 | 
			
		||||
      if (process.env[key]) {
 | 
			
		||||
        let value: any = process.env[key];
 | 
			
		||||
        envVariables[key] = value;
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
    if (IS_WINDOWS) {
 | 
			
		||||
      let escapedScript = path
 | 
			
		||||
        .join(__dirname, '..', 'externals', 'install-dotnet.ps1')
 | 
			
		||||
        .replace(/'/g, "''");
 | 
			
		||||
      let command = `& '${escapedScript}'`;
 | 
			
		||||
      if (calculatedVersion) {
 | 
			
		||||
        command += ` -Version ${calculatedVersion}`;
 | 
			
		||||
      }
 | 
			
		||||
      if (process.env['https_proxy'] != null) {
 | 
			
		||||
        command += ` -ProxyAddress ${process.env['https_proxy']}`;
 | 
			
		||||
      }
 | 
			
		||||
      // This is not currently an option
 | 
			
		||||
      if (process.env['no_proxy'] != null) {
 | 
			
		||||
        command += ` -ProxyBypassList ${process.env['no_proxy']}`;
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      // process.env must be explicitly passed in for DOTNET_INSTALL_DIR to be used
 | 
			
		||||
      const powershellPath =
 | 
			
		||||
        (await io.which('pwsh', false)) || (await io.which('powershell', true));
 | 
			
		||||
 | 
			
		||||
      var options: ExecOptions = {
 | 
			
		||||
        listeners: {
 | 
			
		||||
          stdout: (data: Buffer) => {
 | 
			
		||||
            output += data.toString();
 | 
			
		||||
          }
 | 
			
		||||
        },
 | 
			
		||||
        env: envVariables
 | 
			
		||||
      };
 | 
			
		||||
 | 
			
		||||
      resultCode = await exec.exec(
 | 
			
		||||
        `"${powershellPath}"`,
 | 
			
		||||
        [
 | 
			
		||||
          '-NoLogo',
 | 
			
		||||
          '-Sta',
 | 
			
		||||
          '-NoProfile',
 | 
			
		||||
          '-NonInteractive',
 | 
			
		||||
          '-ExecutionPolicy',
 | 
			
		||||
          'Unrestricted',
 | 
			
		||||
          '-Command',
 | 
			
		||||
          command
 | 
			
		||||
        ],
 | 
			
		||||
        options
 | 
			
		||||
      );
 | 
			
		||||
    } else {
 | 
			
		||||
      let escapedScript = path
 | 
			
		||||
        .join(__dirname, '..', 'externals', 'install-dotnet.sh')
 | 
			
		||||
        .replace(/'/g, "''");
 | 
			
		||||
      chmodSync(escapedScript, '777');
 | 
			
		||||
 | 
			
		||||
      const scriptPath = await io.which(escapedScript, true);
 | 
			
		||||
 | 
			
		||||
      let scriptArguments: string[] = [];
 | 
			
		||||
      if (calculatedVersion) {
 | 
			
		||||
        scriptArguments.push('--version', calculatedVersion);
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      // process.env must be explicitly passed in for DOTNET_INSTALL_DIR to be used
 | 
			
		||||
      resultCode = await exec.exec(`"${scriptPath}"`, scriptArguments, {
 | 
			
		||||
        listeners: {
 | 
			
		||||
          stdout: (data: Buffer) => {
 | 
			
		||||
            output += data.toString();
 | 
			
		||||
          }
 | 
			
		||||
        },
 | 
			
		||||
        env: envVariables
 | 
			
		||||
      });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (resultCode != 0) {
 | 
			
		||||
      throw new Error(`Failed to install dotnet ${resultCode}. ${output}`);
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  static addToPath() {
 | 
			
		||||
    if (process.env['DOTNET_INSTALL_DIR']) {
 | 
			
		||||
      core.addPath(process.env['DOTNET_INSTALL_DIR']);
 | 
			
		||||
      core.exportVariable('DOTNET_ROOT', process.env['DOTNET_INSTALL_DIR']);
 | 
			
		||||
    } else {
 | 
			
		||||
      if (IS_WINDOWS) {
 | 
			
		||||
        // This is the default set in install-dotnet.ps1
 | 
			
		||||
        core.addPath(
 | 
			
		||||
          path.join(process.env['LocalAppData'] + '', 'Microsoft', 'dotnet')
 | 
			
		||||
        );
 | 
			
		||||
        core.exportVariable(
 | 
			
		||||
          'DOTNET_ROOT',
 | 
			
		||||
          path.join(process.env['LocalAppData'] + '', 'Microsoft', 'dotnet')
 | 
			
		||||
        );
 | 
			
		||||
      } else {
 | 
			
		||||
        // This is the default set in install-dotnet.sh
 | 
			
		||||
        core.addPath(path.join(process.env['HOME'] + '', '.dotnet'));
 | 
			
		||||
        core.exportVariable(
 | 
			
		||||
          'DOTNET_ROOT',
 | 
			
		||||
          path.join(process.env['HOME'] + '', '.dotnet')
 | 
			
		||||
        );
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    console.log(process.env['PATH']);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // versionInfo - versionInfo of the SDK/Runtime
 | 
			
		||||
  async resolveVersion(versionInfo: DotNetVersionInfo): Promise<string> {
 | 
			
		||||
    if (versionInfo.isExactVersion()) {
 | 
			
		||||
      return versionInfo.version();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    const httpClient = new hc.HttpClient('actions/setup-dotnet', [], {
 | 
			
		||||
      allowRetries: true,
 | 
			
		||||
      maxRetries: 3
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    const releasesJsonUrl: string = await this.getReleasesJsonUrl(
 | 
			
		||||
      httpClient,
 | 
			
		||||
      versionInfo.version().split('.')
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    const releasesResponse = await httpClient.getJson<any>(releasesJsonUrl);
 | 
			
		||||
    const releasesResult = releasesResponse.result || {};
 | 
			
		||||
    let releasesInfo: any[] = releasesResult['releases'];
 | 
			
		||||
    releasesInfo = releasesInfo.filter((releaseInfo: any) => {
 | 
			
		||||
      return (
 | 
			
		||||
        semver.satisfies(releaseInfo['sdk']['version'], versionInfo.version(), {
 | 
			
		||||
          includePrerelease: this.includePrerelease
 | 
			
		||||
        }) ||
 | 
			
		||||
        semver.satisfies(
 | 
			
		||||
          releaseInfo['sdk']['version-display'],
 | 
			
		||||
          versionInfo.version(),
 | 
			
		||||
          {
 | 
			
		||||
            includePrerelease: this.includePrerelease
 | 
			
		||||
          }
 | 
			
		||||
        )
 | 
			
		||||
      );
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    // Exclude versions that are newer than the latest if using not exact
 | 
			
		||||
    let latestSdk: string = releasesResult['latest-sdk'];
 | 
			
		||||
 | 
			
		||||
    releasesInfo = releasesInfo.filter((releaseInfo: any) =>
 | 
			
		||||
      semver.lte(releaseInfo['sdk']['version'], latestSdk, {
 | 
			
		||||
        includePrerelease: this.includePrerelease
 | 
			
		||||
      })
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    // Sort for latest version
 | 
			
		||||
    releasesInfo = releasesInfo.sort((a, b) =>
 | 
			
		||||
      semver.rcompare(a['sdk']['version'], b['sdk']['version'], {
 | 
			
		||||
        includePrerelease: this.includePrerelease
 | 
			
		||||
      })
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    if (releasesInfo.length == 0) {
 | 
			
		||||
      throw new Error(
 | 
			
		||||
        `Could not find dotnet core version. Please ensure that specified version ${versionInfo.inputVersion} is valid.`
 | 
			
		||||
      );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    let release = releasesInfo[0];
 | 
			
		||||
    return release['sdk']['version'];
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  private async getReleasesJsonUrl(
 | 
			
		||||
    httpClient: hc.HttpClient,
 | 
			
		||||
    versionParts: string[]
 | 
			
		||||
  ): Promise<string> {
 | 
			
		||||
    const response = await httpClient.getJson<any>(DotNetCoreIndexUrl);
 | 
			
		||||
    const result = response.result || {};
 | 
			
		||||
    let releasesInfo: any[] = result['releases-index'];
 | 
			
		||||
 | 
			
		||||
    releasesInfo = releasesInfo.filter((info: any) => {
 | 
			
		||||
      // channel-version is the first 2 elements of the version (e.g. 2.1), filter out versions that don't match 2.1.x.
 | 
			
		||||
      const sdkParts: string[] = info['channel-version'].split('.');
 | 
			
		||||
      if (
 | 
			
		||||
        versionParts.length >= 2 &&
 | 
			
		||||
        !(versionParts[1] == 'x' || versionParts[1] == '*')
 | 
			
		||||
      ) {
 | 
			
		||||
        return versionParts[0] == sdkParts[0] && versionParts[1] == sdkParts[1];
 | 
			
		||||
      }
 | 
			
		||||
      return versionParts[0] == sdkParts[0];
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    if (releasesInfo.length === 0) {
 | 
			
		||||
      throw new Error(
 | 
			
		||||
        `Could not find info for version ${versionParts.join(
 | 
			
		||||
          '.'
 | 
			
		||||
        )} at ${DotNetCoreIndexUrl}`
 | 
			
		||||
      );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    const releaseInfo = releasesInfo[0];
 | 
			
		||||
    if (releaseInfo['support-phase'] === 'eol') {
 | 
			
		||||
      core.warning(
 | 
			
		||||
        `${releaseInfo['product']} ${releaseInfo['channel-version']} is no longer supported and will not receive security updates in the future. Please refer to https://aka.ms/dotnet-core-support for more information about the .NET support policy.`
 | 
			
		||||
      );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return releaseInfo['releases.json'];
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  private version: string;
 | 
			
		||||
  private includePrerelease: boolean;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const DotNetCoreIndexUrl: string =
 | 
			
		||||
  'https://builds.dotnet.microsoft.com/dotnet/release-metadata/releases-index.json';
 | 
			
		||||
// Load tempDirectory before it gets wiped by tool-cache
 | 
			
		||||
import * as core from '@actions/core';
 | 
			
		||||
import * as exec from '@actions/exec';
 | 
			
		||||
import * as io from '@actions/io';
 | 
			
		||||
import hc = require('@actions/http-client');
 | 
			
		||||
import {chmodSync} from 'fs';
 | 
			
		||||
import * as path from 'path';
 | 
			
		||||
import {ExecOptions} from '@actions/exec/lib/interfaces';
 | 
			
		||||
import * as semver from 'semver';
 | 
			
		||||
 | 
			
		||||
const IS_WINDOWS = process.platform === 'win32';
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Represents the inputted version information
 | 
			
		||||
 */
 | 
			
		||||
export class DotNetVersionInfo {
 | 
			
		||||
  public inputVersion: string;
 | 
			
		||||
  private fullversion: string;
 | 
			
		||||
  private isExactVersionSet: boolean = false;
 | 
			
		||||
 | 
			
		||||
  constructor(version: string) {
 | 
			
		||||
    this.inputVersion = version;
 | 
			
		||||
 | 
			
		||||
    // Check for exact match
 | 
			
		||||
    if (semver.valid(semver.clean(version) || '') != null) {
 | 
			
		||||
      this.fullversion = semver.clean(version) as string;
 | 
			
		||||
      this.isExactVersionSet = true;
 | 
			
		||||
 | 
			
		||||
      return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    const parts: string[] = version.split('.');
 | 
			
		||||
 | 
			
		||||
    if (parts.length < 2 || parts.length > 3) this.throwInvalidVersionFormat();
 | 
			
		||||
 | 
			
		||||
    if (parts.length == 3 && parts[2] !== 'x' && parts[2] !== '*') {
 | 
			
		||||
      this.throwInvalidVersionFormat();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    const major = this.getVersionNumberOrThrow(parts[0]);
 | 
			
		||||
    const minor = ['x', '*'].includes(parts[1])
 | 
			
		||||
      ? parts[1]
 | 
			
		||||
      : this.getVersionNumberOrThrow(parts[1]);
 | 
			
		||||
 | 
			
		||||
    this.fullversion = major + '.' + minor;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  private getVersionNumberOrThrow(input: string): number {
 | 
			
		||||
    try {
 | 
			
		||||
      if (!input || input.trim() === '') this.throwInvalidVersionFormat();
 | 
			
		||||
 | 
			
		||||
      let number = Number(input);
 | 
			
		||||
 | 
			
		||||
      if (Number.isNaN(number) || number < 0) this.throwInvalidVersionFormat();
 | 
			
		||||
 | 
			
		||||
      return number;
 | 
			
		||||
    } catch {
 | 
			
		||||
      this.throwInvalidVersionFormat();
 | 
			
		||||
      return -1;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  private throwInvalidVersionFormat() {
 | 
			
		||||
    throw new Error(
 | 
			
		||||
      'Invalid version format! Supported: 1.2.3, 1.2, 1.2.x, 1.2.*'
 | 
			
		||||
    );
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * If true exacatly one version should be resolved
 | 
			
		||||
   */
 | 
			
		||||
  public isExactVersion(): boolean {
 | 
			
		||||
    return this.isExactVersionSet;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  public version(): string {
 | 
			
		||||
    return this.fullversion;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export class DotnetCoreInstaller {
 | 
			
		||||
  constructor(version: string, includePrerelease: boolean = false) {
 | 
			
		||||
    this.version = version;
 | 
			
		||||
    this.includePrerelease = includePrerelease;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  public async installDotnet() {
 | 
			
		||||
    let output = '';
 | 
			
		||||
    let resultCode = 0;
 | 
			
		||||
 | 
			
		||||
    let calculatedVersion = await this.resolveVersion(
 | 
			
		||||
      new DotNetVersionInfo(this.version)
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    var envVariables: {[key: string]: string} = {};
 | 
			
		||||
    for (let key in process.env) {
 | 
			
		||||
      if (process.env[key]) {
 | 
			
		||||
        let value: any = process.env[key];
 | 
			
		||||
        envVariables[key] = value;
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
    if (IS_WINDOWS) {
 | 
			
		||||
      let escapedScript = path
 | 
			
		||||
        .join(__dirname, '..', 'externals', 'install-dotnet.ps1')
 | 
			
		||||
        .replace(/'/g, "''");
 | 
			
		||||
      let command = `& '${escapedScript}'`;
 | 
			
		||||
      if (calculatedVersion) {
 | 
			
		||||
        command += ` -Version ${calculatedVersion}`;
 | 
			
		||||
      }
 | 
			
		||||
      if (process.env['https_proxy'] != null) {
 | 
			
		||||
        command += ` -ProxyAddress ${process.env['https_proxy']}`;
 | 
			
		||||
      }
 | 
			
		||||
      // This is not currently an option
 | 
			
		||||
      if (process.env['no_proxy'] != null) {
 | 
			
		||||
        command += ` -ProxyBypassList ${process.env['no_proxy']}`;
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      // process.env must be explicitly passed in for DOTNET_INSTALL_DIR to be used
 | 
			
		||||
      const powershellPath =
 | 
			
		||||
        (await io.which('pwsh', false)) || (await io.which('powershell', true));
 | 
			
		||||
 | 
			
		||||
      var options: ExecOptions = {
 | 
			
		||||
        listeners: {
 | 
			
		||||
          stdout: (data: Buffer) => {
 | 
			
		||||
            output += data.toString();
 | 
			
		||||
          }
 | 
			
		||||
        },
 | 
			
		||||
        env: envVariables
 | 
			
		||||
      };
 | 
			
		||||
 | 
			
		||||
      resultCode = await exec.exec(
 | 
			
		||||
        `"${powershellPath}"`,
 | 
			
		||||
        [
 | 
			
		||||
          '-NoLogo',
 | 
			
		||||
          '-Sta',
 | 
			
		||||
          '-NoProfile',
 | 
			
		||||
          '-NonInteractive',
 | 
			
		||||
          '-ExecutionPolicy',
 | 
			
		||||
          'Unrestricted',
 | 
			
		||||
          '-Command',
 | 
			
		||||
          command
 | 
			
		||||
        ],
 | 
			
		||||
        options
 | 
			
		||||
      );
 | 
			
		||||
    } else {
 | 
			
		||||
      let escapedScript = path
 | 
			
		||||
        .join(__dirname, '..', 'externals', 'install-dotnet.sh')
 | 
			
		||||
        .replace(/'/g, "''");
 | 
			
		||||
      chmodSync(escapedScript, '777');
 | 
			
		||||
 | 
			
		||||
      const scriptPath = await io.which(escapedScript, true);
 | 
			
		||||
 | 
			
		||||
      let scriptArguments: string[] = [];
 | 
			
		||||
      if (calculatedVersion) {
 | 
			
		||||
        scriptArguments.push('--version', calculatedVersion);
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      // process.env must be explicitly passed in for DOTNET_INSTALL_DIR to be used
 | 
			
		||||
      resultCode = await exec.exec(`"${scriptPath}"`, scriptArguments, {
 | 
			
		||||
        listeners: {
 | 
			
		||||
          stdout: (data: Buffer) => {
 | 
			
		||||
            output += data.toString();
 | 
			
		||||
          }
 | 
			
		||||
        },
 | 
			
		||||
        env: envVariables
 | 
			
		||||
      });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (resultCode != 0) {
 | 
			
		||||
      throw new Error(`Failed to install dotnet ${resultCode}. ${output}`);
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  static addToPath() {
 | 
			
		||||
    if (process.env['DOTNET_INSTALL_DIR']) {
 | 
			
		||||
      core.addPath(process.env['DOTNET_INSTALL_DIR']);
 | 
			
		||||
      core.exportVariable('DOTNET_ROOT', process.env['DOTNET_INSTALL_DIR']);
 | 
			
		||||
    } else {
 | 
			
		||||
      if (IS_WINDOWS) {
 | 
			
		||||
        // This is the default set in install-dotnet.ps1
 | 
			
		||||
        core.addPath(
 | 
			
		||||
          path.join(process.env['LocalAppData'] + '', 'Microsoft', 'dotnet')
 | 
			
		||||
        );
 | 
			
		||||
        core.exportVariable(
 | 
			
		||||
          'DOTNET_ROOT',
 | 
			
		||||
          path.join(process.env['LocalAppData'] + '', 'Microsoft', 'dotnet')
 | 
			
		||||
        );
 | 
			
		||||
      } else {
 | 
			
		||||
        // This is the default set in install-dotnet.sh
 | 
			
		||||
        core.addPath(path.join(process.env['HOME'] + '', '.dotnet'));
 | 
			
		||||
        core.exportVariable(
 | 
			
		||||
          'DOTNET_ROOT',
 | 
			
		||||
          path.join(process.env['HOME'] + '', '.dotnet')
 | 
			
		||||
        );
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    console.log(process.env['PATH']);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // versionInfo - versionInfo of the SDK/Runtime
 | 
			
		||||
  async resolveVersion(versionInfo: DotNetVersionInfo): Promise<string> {
 | 
			
		||||
    if (versionInfo.isExactVersion()) {
 | 
			
		||||
      return versionInfo.version();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    const httpClient = new hc.HttpClient('actions/setup-dotnet', [], {
 | 
			
		||||
      allowRetries: true,
 | 
			
		||||
      maxRetries: 3
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    const releasesJsonUrl: string = await this.getReleasesJsonUrl(
 | 
			
		||||
      httpClient,
 | 
			
		||||
      versionInfo.version().split('.')
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    const releasesResponse = await httpClient.getJson<any>(releasesJsonUrl);
 | 
			
		||||
    const releasesResult = releasesResponse.result || {};
 | 
			
		||||
    let releasesInfo: any[] = releasesResult['releases'];
 | 
			
		||||
    releasesInfo = releasesInfo.filter((releaseInfo: any) => {
 | 
			
		||||
      return (
 | 
			
		||||
        semver.satisfies(releaseInfo['sdk']['version'], versionInfo.version(), {
 | 
			
		||||
          includePrerelease: this.includePrerelease
 | 
			
		||||
        }) ||
 | 
			
		||||
        semver.satisfies(
 | 
			
		||||
          releaseInfo['sdk']['version-display'],
 | 
			
		||||
          versionInfo.version(),
 | 
			
		||||
          {
 | 
			
		||||
            includePrerelease: this.includePrerelease
 | 
			
		||||
          }
 | 
			
		||||
        )
 | 
			
		||||
      );
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    // Exclude versions that are newer than the latest if using not exact
 | 
			
		||||
    let latestSdk: string = releasesResult['latest-sdk'];
 | 
			
		||||
 | 
			
		||||
    releasesInfo = releasesInfo.filter((releaseInfo: any) =>
 | 
			
		||||
      semver.lte(releaseInfo['sdk']['version'], latestSdk, {
 | 
			
		||||
        includePrerelease: this.includePrerelease
 | 
			
		||||
      })
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    // Sort for latest version
 | 
			
		||||
    releasesInfo = releasesInfo.sort((a, b) =>
 | 
			
		||||
      semver.rcompare(a['sdk']['version'], b['sdk']['version'], {
 | 
			
		||||
        includePrerelease: this.includePrerelease
 | 
			
		||||
      })
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    if (releasesInfo.length == 0) {
 | 
			
		||||
      throw new Error(
 | 
			
		||||
        `Could not find dotnet core version. Please ensure that specified version ${versionInfo.inputVersion} is valid.`
 | 
			
		||||
      );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    let release = releasesInfo[0];
 | 
			
		||||
    return release['sdk']['version'];
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  private async getReleasesJsonUrl(
 | 
			
		||||
    httpClient: hc.HttpClient,
 | 
			
		||||
    versionParts: string[]
 | 
			
		||||
  ): Promise<string> {
 | 
			
		||||
    const response = await httpClient.getJson<any>(DotNetCoreIndexUrl);
 | 
			
		||||
 | 
			
		||||
    const result = response.result || {};
 | 
			
		||||
    let releasesInfo: any[] = result['releases-index'];
 | 
			
		||||
 | 
			
		||||
    releasesInfo = releasesInfo.filter((info: any) => {
 | 
			
		||||
      // channel-version is the first 2 elements of the version (e.g. 2.1), filter out versions that don't match 2.1.x.
 | 
			
		||||
      const sdkParts: string[] = info['channel-version'].split('.');
 | 
			
		||||
      if (
 | 
			
		||||
        versionParts.length >= 2 &&
 | 
			
		||||
        !(versionParts[1] == 'x' || versionParts[1] == '*')
 | 
			
		||||
      ) {
 | 
			
		||||
        return versionParts[0] == sdkParts[0] && versionParts[1] == sdkParts[1];
 | 
			
		||||
      }
 | 
			
		||||
      return versionParts[0] == sdkParts[0];
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    if (releasesInfo.length === 0) {
 | 
			
		||||
      throw new Error(
 | 
			
		||||
        `Could not find info for version ${versionParts.join(
 | 
			
		||||
          '.'
 | 
			
		||||
        )} at ${DotNetCoreIndexUrl}`
 | 
			
		||||
      );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    const releaseInfo = releasesInfo[0];
 | 
			
		||||
    if (releaseInfo['support-phase'] === 'eol') {
 | 
			
		||||
      core.warning(
 | 
			
		||||
        `${releaseInfo['product']} ${releaseInfo['channel-version']} is no longer supported and will not receive security updates in the future. Please refer to https://aka.ms/dotnet-core-support for more information about the .NET support policy.`
 | 
			
		||||
      );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return releaseInfo['releases.json'];
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  private version: string;
 | 
			
		||||
  private includePrerelease: boolean;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const DotNetCoreIndexUrl: string =
 | 
			
		||||
  'https://builds.dotnet.microsoft.com/dotnet/release-metadata/releases-index.json';
 | 
			
		||||
 | 
			
		||||
@ -38,9 +38,8 @@ export async function run() {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (versions.length) {
 | 
			
		||||
      const includePrerelease: boolean = core.getBooleanInput(
 | 
			
		||||
        'include-prerelease'
 | 
			
		||||
      );
 | 
			
		||||
      const includePrerelease: boolean =
 | 
			
		||||
        core.getBooleanInput('include-prerelease');
 | 
			
		||||
      let dotnetInstaller!: installer.DotnetCoreInstaller;
 | 
			
		||||
      for (const version of new Set<string>(versions)) {
 | 
			
		||||
        dotnetInstaller = new installer.DotnetCoreInstaller(
 | 
			
		||||
 | 
			
		||||
		Reference in New Issue
	
	Block a user