2020-06-13 00:46:25 +07:00
#
# Copyright (c) .NET Foundation and contributors. All rights reserved.
# Licensed under the MIT license. See LICENSE file in the project root for full license information.
#
<#
. SYNOPSIS
Installs dotnet cli
. DESCRIPTION
Installs dotnet cli . If dotnet installation already exists in the given directory
it will update it only if the requested version differs from the one already installed .
. PARAMETER Channel
Default : LTS
Download from the Channel specified . Possible values :
- Current - most current release
- LTS - most current supported release
- 2 -part version in a format A . B - represents a specific release
examples : 2.0 , 1.0
- Branch name
examples : release / 2.0 . 0 , Master
Note : The version parameter overrides the channel parameter .
. PARAMETER Version
Default : latest
Represents a build version on specific channel . Possible values :
- latest - most latest build on specific channel
- coherent - most latest coherent build on specific channel
coherent applies only to SDK downloads
- 3 -part version in a format A . B . C - represents specific version of build
examples : 2.0 . 0 -preview2 - 006120 , 1.1 . 0
. PARAMETER InstallDir
Default : % LocalAppData % \ Microsoft \ dotnet
Path to where to install dotnet . Note that binaries will be placed directly in a given directory .
. PARAMETER Architecture
Default : < auto > - this value represents currently running OS architecture
Architecture of dotnet binaries to be installed .
Possible values are : < auto > , amd64 , x64 , x86 , arm64 , arm
. PARAMETER SharedRuntime
This parameter is obsolete and may be removed in a future version of this script .
The recommended alternative is '-Runtime dotnet' .
Installs just the shared runtime bits , not the entire SDK .
. PARAMETER Runtime
Installs just a shared runtime , not the entire SDK .
Possible values :
- dotnet - the Microsoft . NETCore . App shared runtime
- aspnetcore - the Microsoft . AspNetCore . App shared runtime
- windowsdesktop - the Microsoft . WindowsDesktop . App shared runtime
. PARAMETER DryRun
If set it will not perform installation but instead display what command line to use to consistently install
currently requested version of dotnet cli . In example if you specify version 'latest' it will display a link
with specific version so that this command can be used deterministicly in a build script .
It also displays binaries location if you prefer to install or download it yourself .
. PARAMETER NoPath
By default this script will set environment variable PATH for the current process to the binaries folder inside installation folder .
If set it will display binaries location but not set any environment variable .
. PARAMETER Verbose
Displays diagnostics information .
. PARAMETER AzureFeed
Default : https : / / dotnetcli . azureedge . net / dotnet
This parameter typically is not changed by the user .
It allows changing the URL for the Azure feed used by this installer .
. PARAMETER UncachedFeed
This parameter typically is not changed by the user .
It allows changing the URL for the Uncached feed used by this installer .
. PARAMETER FeedCredential
Used as a query string to append to the Azure feed .
It allows changing the URL to use non-public blob storage accounts .
. PARAMETER ProxyAddress
If set , the installer will use the proxy when making web requests
. PARAMETER ProxyUseDefaultCredentials
Default : false
Use default credentials , when using proxy address .
. 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'
#>
[ cmdletbinding ( ) ]
param (
[ string ] $Channel = " LTS " ,
[ string ] $Version = " Latest " ,
[ string ] $JSonFile ,
[ string ] $InstallDir = " <auto> " ,
[ string ] $Architecture = " <auto> " ,
[ ValidateSet ( " dotnet " , " aspnetcore " , " windowsdesktop " , IgnoreCase = $false ) ]
[ string ] $Runtime ,
[ Obsolete ( " This parameter may be removed in a future version of this script. The recommended alternative is '-Runtime dotnet'. " ) ]
[ switch ] $SharedRuntime ,
[ switch ] $DryRun ,
[ switch ] $NoPath ,
[ string ] $AzureFeed = " https://dotnetcli.azureedge.net/dotnet " ,
[ string ] $UncachedFeed = " https://dotnetcli.blob.core.windows.net/dotnet " ,
[ string ] $FeedCredential ,
[ string ] $ProxyAddress ,
[ switch ] $ProxyUseDefaultCredentials ,
[ switch ] $SkipNonVersionedFiles ,
[ switch ] $NoCdn
)
Set-StrictMode -Version Latest
$ErrorActionPreference = " Stop "
$ProgressPreference = " SilentlyContinue "
if ( $NoCdn ) {
$AzureFeed = $UncachedFeed
}
$BinFolderRelativePath = " "
if ( $SharedRuntime -and ( -not $Runtime ) ) {
$Runtime = " dotnet "
}
# example path with regex: shared/1.0.0-beta-12345/somepath
$VersionRegEx = " /\d+\.\d+[^/]+/ "
$OverrideNonVersionedFiles = ! $SkipNonVersionedFiles
function Say($str ) {
Write-Host " dotnet-install: $str "
}
function Say-Verbose($str ) {
Write-Verbose " dotnet-install: $str "
}
function Say-Invocation($Invocation ) {
$command = $Invocation . MyCommand ;
$args = ( ( $Invocation . BoundParameters . Keys | foreach { " - $_ `" $( $Invocation . BoundParameters [ $_ ] ) `" " } ) -join " " )
Say-Verbose " $command $args "
}
function Invoke-With-Retry([ScriptBlock]$ScriptBlock , [ int ] $MaxAttempts = 3 , [ int ] $SecondsBetweenAttempts = 1 ) {
$Attempts = 0
while ( $true ) {
try {
return $ScriptBlock . Invoke ( )
}
catch {
$Attempts + +
if ( $Attempts -lt $MaxAttempts ) {
Start-Sleep $SecondsBetweenAttempts
}
else {
throw
}
}
}
}
function Get-Machine-Architecture ( ) {
Say-Invocation $MyInvocation
2020-07-16 00:32:15 +07:00
# On PS x86, PROCESSOR_ARCHITECTURE reports x86 even on x64 systems.
# To get the correct architecture, we need to use PROCESSOR_ARCHITEW6432.
# PS x64 doesn't define this, so we fall back to PROCESSOR_ARCHITECTURE.
# Possible values: amd64, x64, x86, arm64, arm
if ( $ENV:PROCESSOR_ARCHITEW6432 -ne $null )
{
return $ENV:PROCESSOR_ARCHITEW6432
}
2020-06-13 00:46:25 +07:00
return $ENV:PROCESSOR_ARCHITECTURE
}
function Get-CLIArchitecture-From-Architecture([string]$Architecture ) {
Say-Invocation $MyInvocation
switch ( $Architecture . ToLower ( ) ) {
{ $_ -eq " <auto> " } { return Get-CLIArchitecture -From -Architecture $ ( Get-Machine -Architecture ) }
{ ( $_ -eq " amd64 " ) -or ( $_ -eq " x64 " ) } { return " x64 " }
{ $_ -eq " x86 " } { return " x86 " }
{ $_ -eq " arm " } { return " arm " }
{ $_ -eq " arm64 " } { return " arm64 " }
default { throw " Architecture not supported. If you think this is a bug, report it at https://github.com/dotnet/sdk/issues " }
}
}
# The version text returned from the feeds is a 1-line or 2-line string:
# For the SDK and the dotnet runtime (2 lines):
# Line 1: # commit_hash
# Line 2: # 4-part version
# For the aspnetcore runtime (1 line):
# Line 1: # 4-part version
function Get-Version-Info-From-Version-Text([string]$VersionText ) {
Say-Invocation $MyInvocation
$Data = -split $VersionText
$VersionInfo = @ {
CommitHash = $ ( if ( $Data . Count -gt 1 ) { $Data [ 0 ] } )
Version = $Data [ -1 ] # last line is always the version number.
}
return $VersionInfo
}
function Load-Assembly([string ] $Assembly ) {
try {
Add-Type -Assembly $Assembly | Out-Null
}
catch {
# On Nano Server, Powershell Core Edition is used. Add-Type is unable to resolve base class assemblies because they are not GAC'd.
# Loading the base class assemblies is not unnecessary as the types will automatically get resolved.
}
}
function GetHTTPResponse([Uri ] $Uri )
{
Invoke-With -Retry (
{
$HttpClient = $null
try {
# HttpClient is used vs Invoke-WebRequest in order to support Nano Server which doesn't support the Invoke-WebRequest cmdlet.
Load-Assembly -Assembly System . Net . Http
if ( -not $ProxyAddress ) {
try {
# Despite no proxy being explicitly specified, we may still be behind a default proxy
$DefaultProxy = [ System.Net.WebRequest ] :: DefaultWebProxy ;
if ( $DefaultProxy -and ( -not $DefaultProxy . IsBypassed ( $Uri ) ) ) {
$ProxyAddress = $DefaultProxy . GetProxy ( $Uri ) . OriginalString
$ProxyUseDefaultCredentials = $true
}
} catch {
# Eat the exception and move forward as the above code is an attempt
# at resolving the DefaultProxy that may not have been a problem.
$ProxyAddress = $null
Say-Verbose ( " Exception ignored: $_ .Exception.Message - moving forward... " )
}
}
if ( $ProxyAddress ) {
$HttpClientHandler = New-Object System . Net . Http . HttpClientHandler
$HttpClientHandler . Proxy = New-Object System . Net . WebProxy -Property @ { Address = $ProxyAddress ; UseDefaultCredentials = $ProxyUseDefaultCredentials }
$HttpClient = New-Object System . Net . Http . HttpClient -ArgumentList $HttpClientHandler
}
else {
$HttpClient = New-Object System . Net . Http . HttpClient
}
# Default timeout for HttpClient is 100s. For a 50 MB download this assumes 500 KB/s average, any less will time out
# 20 minutes allows it to work over much slower connections.
$HttpClient . Timeout = New-TimeSpan -Minutes 20
$Response = $HttpClient . GetAsync ( " ${Uri} ${FeedCredential} " ) . Result
if ( ( $Response -eq $null ) -or ( -not ( $Response . IsSuccessStatusCode ) ) ) {
# The feed credential is potentially sensitive info. Do not log FeedCredential to console output.
$ErrorMsg = " Failed to download $Uri . "
if ( $Response -ne $null ) {
$ErrorMsg + = " $Response "
}
throw $ErrorMsg
}
return $Response
}
finally {
if ( $HttpClient -ne $null ) {
$HttpClient . Dispose ( )
}
}
} )
}
function Get-Latest-Version-Info([string]$AzureFeed , [ string ] $Channel , [ bool ] $Coherent ) {
Say-Invocation $MyInvocation
$VersionFileUrl = $null
if ( $Runtime -eq " dotnet " ) {
$VersionFileUrl = " $UncachedFeed /Runtime/ $Channel /latest.version "
}
elseif ( $Runtime -eq " aspnetcore " ) {
$VersionFileUrl = " $UncachedFeed /aspnetcore/Runtime/ $Channel /latest.version "
}
# Currently, the WindowsDesktop runtime is manufactured with the .Net core runtime
elseif ( $Runtime -eq " windowsdesktop " ) {
$VersionFileUrl = " $UncachedFeed /Runtime/ $Channel /latest.version "
}
elseif ( -not $Runtime ) {
if ( $Coherent ) {
$VersionFileUrl = " $UncachedFeed /Sdk/ $Channel /latest.coherent.version "
}
else {
$VersionFileUrl = " $UncachedFeed /Sdk/ $Channel /latest.version "
}
}
else {
throw " Invalid value for `$ Runtime "
}
try {
$Response = GetHTTPResponse -Uri $VersionFileUrl
}
catch {
throw " Could not resolve version information. "
}
$StringContent = $Response . Content . ReadAsStringAsync ( ) . Result
switch ( $Response . Content . Headers . ContentType ) {
{ ( $_ -eq " application/octet-stream " ) } { $VersionText = $StringContent }
{ ( $_ -eq " text/plain " ) } { $VersionText = $StringContent }
{ ( $_ -eq " text/plain; charset=UTF-8 " ) } { $VersionText = $StringContent }
default { throw " `` $Response .Content.Headers.ContentType `` is an unknown .version file content type. " }
}
$VersionInfo = Get-Version -Info -From -Version -Text $VersionText
return $VersionInfo
}
function Parse-Jsonfile-For-Version([string]$JSonFile ) {
Say-Invocation $MyInvocation
If ( -Not ( Test-Path $JSonFile ) ) {
throw " Unable to find ' $JSonFile ' "
}
try {
$JSonContent = Get-Content ( $JSonFile ) -Raw | ConvertFrom-Json | Select-Object -expand " sdk " -ErrorAction SilentlyContinue
}
catch {
throw " Json file unreadable: ' $JSonFile ' "
}
if ( $JSonContent ) {
try {
$JSonContent . PSObject . Properties | ForEach-Object {
$PropertyName = $_ . Name
if ( $PropertyName -eq " version " ) {
$Version = $_ . Value
Say-Verbose " Version = $Version "
}
}
}
catch {
throw " Unable to parse the SDK node in ' $JSonFile ' "
}
}
else {
throw " Unable to find the SDK node in ' $JSonFile ' "
}
If ( $Version -eq $null ) {
throw " Unable to find the SDK:version node in ' $JSonFile ' "
}
return $Version
}
function Get-Specific-Version-From-Version([string]$AzureFeed , [ string ] $Channel , [ string ] $Version , [ string ] $JSonFile ) {
Say-Invocation $MyInvocation
if ( -not $JSonFile ) {
switch ( $Version . ToLower ( ) ) {
{ $_ -eq " latest " } {
$LatestVersionInfo = Get-Latest -Version -Info -AzureFeed $AzureFeed -Channel $Channel -Coherent $False
return $LatestVersionInfo . Version
}
{ $_ -eq " coherent " } {
$LatestVersionInfo = Get-Latest -Version -Info -AzureFeed $AzureFeed -Channel $Channel -Coherent $True
return $LatestVersionInfo . Version
}
default { return $Version }
}
}
else {
return Parse-Jsonfile -For -Version $JSonFile
}
}
function Get-Download-Link([string]$AzureFeed , [ string ] $SpecificVersion , [ string ] $CLIArchitecture ) {
Say-Invocation $MyInvocation
if ( $Runtime -eq " dotnet " ) {
$PayloadURL = " $AzureFeed /Runtime/ $SpecificVersion /dotnet-runtime- $SpecificVersion -win- $CLIArchitecture .zip "
}
elseif ( $Runtime -eq " aspnetcore " ) {
$PayloadURL = " $AzureFeed /aspnetcore/Runtime/ $SpecificVersion /aspnetcore-runtime- $SpecificVersion -win- $CLIArchitecture .zip "
}
elseif ( $Runtime -eq " windowsdesktop " ) {
$PayloadURL = " $AzureFeed /Runtime/ $SpecificVersion /windowsdesktop-runtime- $SpecificVersion -win- $CLIArchitecture .zip "
}
elseif ( -not $Runtime ) {
$PayloadURL = " $AzureFeed /Sdk/ $SpecificVersion /dotnet-sdk- $SpecificVersion -win- $CLIArchitecture .zip "
}
else {
throw " Invalid value for `$ Runtime "
}
Say-Verbose " Constructed primary named payload URL: $PayloadURL "
return $PayloadURL
}
function Get-LegacyDownload-Link([string]$AzureFeed , [ string ] $SpecificVersion , [ string ] $CLIArchitecture ) {
Say-Invocation $MyInvocation
if ( -not $Runtime ) {
$PayloadURL = " $AzureFeed /Sdk/ $SpecificVersion /dotnet-dev-win- $CLIArchitecture . $SpecificVersion .zip "
}
elseif ( $Runtime -eq " dotnet " ) {
$PayloadURL = " $AzureFeed /Runtime/ $SpecificVersion /dotnet-win- $CLIArchitecture . $SpecificVersion .zip "
}
else {
return $null
}
Say-Verbose " Constructed legacy named payload URL: $PayloadURL "
return $PayloadURL
}
function Get-User-Share-Path ( ) {
Say-Invocation $MyInvocation
$InstallRoot = $env:DOTNET_INSTALL_DIR
if ( ! $InstallRoot ) {
$InstallRoot = " $env:LocalAppData \Microsoft\dotnet "
}
return $InstallRoot
}
function Resolve-Installation-Path([string]$InstallDir ) {
Say-Invocation $MyInvocation
if ( $InstallDir -eq " <auto> " ) {
return Get-User -Share -Path
}
return $InstallDir
}
function Is-Dotnet-Package-Installed([string]$InstallRoot , [ string ] $RelativePathToPackage , [ string ] $SpecificVersion ) {
Say-Invocation $MyInvocation
$DotnetPackagePath = Join-Path -Path $InstallRoot -ChildPath $RelativePathToPackage | Join-Path -ChildPath $SpecificVersion
Say-Verbose " Is-Dotnet-Package-Installed: DotnetPackagePath= $DotnetPackagePath "
return Test-Path $DotnetPackagePath -PathType Container
}
function Get-Absolute-Path([string]$RelativeOrAbsolutePath ) {
# Too much spam
# Say-Invocation $MyInvocation
return $ExecutionContext . SessionState . Path . GetUnresolvedProviderPathFromPSPath ( $RelativeOrAbsolutePath )
}
function Get-Path-Prefix-With-Version($path ) {
$match = [ regex ] :: match ( $path , $VersionRegEx )
if ( $match . Success ) {
return $entry . FullName . Substring ( 0 , $match . Index + $match . Length )
}
return $null
}
function Get-List-Of-Directories-And-Versions-To-Unpack-From-Dotnet-Package([System.IO.Compression.ZipArchive]$Zip , [ string ] $OutPath ) {
Say-Invocation $MyInvocation
$ret = @ ( )
foreach ( $entry in $Zip . Entries ) {
$dir = Get-Path -Prefix -With -Version $entry . FullName
if ( $dir -ne $null ) {
$path = Get-Absolute -Path $ ( Join-Path -Path $OutPath -ChildPath $dir )
if ( -Not ( Test-Path $path -PathType Container ) ) {
$ret + = $dir
}
}
}
$ret = $ret | Sort-Object | Get-Unique
$values = ( $ret | foreach { " $_ " } ) -join " ; "
Say-Verbose " Directories to unpack: $values "
return $ret
}
# Example zip content and extraction algorithm:
# Rule: files if extracted are always being extracted to the same relative path locally
# .\
# a.exe # file does not exist locally, extract
# b.dll # file exists locally, override only if $OverrideFiles set
# aaa\ # same rules as for files
# ...
# abc\1.0.0\ # directory contains version and exists locally
# ... # do not extract content under versioned part
# abc\asd\ # same rules as for files
# ...
# def\ghi\1.0.1\ # directory contains version and does not exist locally
# ... # extract content
function Extract-Dotnet-Package([string]$ZipPath , [ string ] $OutPath ) {
Say-Invocation $MyInvocation
Load-Assembly -Assembly System . IO . Compression . FileSystem
Set-Variable -Name Zip
try {
$Zip = [ System.IO.Compression.ZipFile ] :: OpenRead ( $ZipPath )
$DirectoriesToUnpack = Get-List -Of -Directories -And -Versions -To -Unpack -From -Dotnet -Package -Zip $Zip -OutPath $OutPath
foreach ( $entry in $Zip . Entries ) {
$PathWithVersion = Get-Path -Prefix -With -Version $entry . FullName
if ( ( $PathWithVersion -eq $null ) -Or ( $DirectoriesToUnpack -contains $PathWithVersion ) ) {
$DestinationPath = Get-Absolute -Path $ ( Join-Path -Path $OutPath -ChildPath $entry . FullName )
$DestinationDir = Split-Path -Parent $DestinationPath
$OverrideFiles = $OverrideNonVersionedFiles -Or ( -Not ( Test-Path $DestinationPath ) )
if ( ( -Not $DestinationPath . EndsWith ( " \ " ) ) -And $OverrideFiles ) {
New-Item -ItemType Directory -Force -Path $DestinationDir | Out-Null
[ System.IO.Compression.ZipFileExtensions ] :: ExtractToFile ( $entry , $DestinationPath , $OverrideNonVersionedFiles )
}
}
}
}
finally {
if ( $Zip -ne $null ) {
$Zip . Dispose ( )
}
}
}
function DownloadFile($Source , [ string ] $OutPath ) {
if ( $Source -notlike " http* " ) {
# Using System.IO.Path.GetFullPath to get the current directory
# does not work in this context - $pwd gives the current directory
if ( ! [ System.IO.Path ] :: IsPathRooted ( $Source ) ) {
$Source = $ ( Join-Path -Path $pwd -ChildPath $Source )
}
$Source = Get-Absolute -Path $Source
Say " Copying file from $Source to $OutPath "
Copy-Item $Source $OutPath
return
}
$Stream = $null
try {
$Response = GetHTTPResponse -Uri $Source
$Stream = $Response . Content . ReadAsStreamAsync ( ) . Result
$File = [ System.IO.File ] :: Create ( $OutPath )
$Stream . CopyTo ( $File )
$File . Close ( )
}
finally {
if ( $Stream -ne $null ) {
$Stream . Dispose ( )
}
}
}
function Prepend-Sdk-InstallRoot-To-Path([string]$InstallRoot , [ string ] $BinFolderRelativePath ) {
$BinPath = Get-Absolute -Path $ ( Join-Path -Path $InstallRoot -ChildPath $BinFolderRelativePath )
if ( -Not $NoPath ) {
$SuffixedBinPath = " $BinPath ; "
if ( -Not $env:path . Contains ( $SuffixedBinPath ) ) {
Say " Adding to current process PATH: `" $BinPath `" . Note: This change will not be visible if PowerShell was run as a child process. "
$env:path = $SuffixedBinPath + $env:path
} else {
Say-Verbose " Current process PATH already contains `" $BinPath `" "
}
}
else {
Say " Binaries of dotnet can be found in $BinPath "
}
}
$CLIArchitecture = Get-CLIArchitecture -From -Architecture $Architecture
$SpecificVersion = Get-Specific -Version -From -Version -AzureFeed $AzureFeed -Channel $Channel -Version $Version -JSonFile $JSonFile
$DownloadLink = Get-Download -Link -AzureFeed $AzureFeed -SpecificVersion $SpecificVersion -CLIArchitecture $CLIArchitecture
$LegacyDownloadLink = Get-LegacyDownload -Link -AzureFeed $AzureFeed -SpecificVersion $SpecificVersion -CLIArchitecture $CLIArchitecture
$InstallRoot = Resolve-Installation -Path $InstallDir
Say-Verbose " InstallRoot: $InstallRoot "
$ScriptName = $MyInvocation . MyCommand . Name
if ( $DryRun ) {
Say " Payload URLs: "
Say " Primary named payload URL: $DownloadLink "
if ( $LegacyDownloadLink ) {
Say " Legacy named payload URL: $LegacyDownloadLink "
}
$RepeatableCommand = " .\ $ScriptName -Version `" $SpecificVersion `" -InstallDir `" $InstallRoot `" -Architecture `" $CLIArchitecture `" "
if ( $Runtime -eq " dotnet " ) {
$RepeatableCommand + = " -Runtime `" dotnet `" "
}
elseif ( $Runtime -eq " aspnetcore " ) {
$RepeatableCommand + = " -Runtime `" aspnetcore `" "
}
foreach ( $key in $MyInvocation . BoundParameters . Keys ) {
if ( -not ( @ ( " Architecture " , " Channel " , " DryRun " , " InstallDir " , " Runtime " , " SharedRuntime " , " Version " ) -contains $key ) ) {
$RepeatableCommand + = " - $key `" $( $MyInvocation . BoundParameters [ $key ] ) `" "
}
}
Say " Repeatable invocation: $RepeatableCommand "
exit 0
}
if ( $Runtime -eq " dotnet " ) {
$assetName = " .NET Core Runtime "
$dotnetPackageRelativePath = " shared\Microsoft.NETCore.App "
}
elseif ( $Runtime -eq " aspnetcore " ) {
$assetName = " ASP.NET Core Runtime "
$dotnetPackageRelativePath = " shared\Microsoft.AspNetCore.App "
}
elseif ( $Runtime -eq " windowsdesktop " ) {
$assetName = " .NET Core Windows Desktop Runtime "
$dotnetPackageRelativePath = " shared\Microsoft.WindowsDesktop.App "
}
elseif ( -not $Runtime ) {
$assetName = " .NET Core SDK "
$dotnetPackageRelativePath = " sdk "
}
else {
throw " Invalid value for `$ Runtime "
}
# Check if the SDK version is already installed.
$isAssetInstalled = Is-Dotnet -Package -Installed -InstallRoot $InstallRoot -RelativePathToPackage $dotnetPackageRelativePath -SpecificVersion $SpecificVersion
if ( $isAssetInstalled ) {
Say " $assetName version $SpecificVersion is already installed. "
Prepend-Sdk -InstallRoot -To -Path -InstallRoot $InstallRoot -BinFolderRelativePath $BinFolderRelativePath
exit 0
}
New-Item -ItemType Directory -Force -Path $InstallRoot | Out-Null
$installDrive = $ ( ( Get-Item $InstallRoot ) . PSDrive . Name ) ;
$diskInfo = Get-PSDrive -Name $installDrive
if ( $diskInfo . Free / 1 MB -le 100 ) {
Say " There is not enough disk space on drive ${installDrive} : "
exit 0
}
$ZipPath = [ System.IO.Path ] :: combine ( [ System.IO.Path ] :: GetTempPath ( ) , [ System.IO.Path ] :: GetRandomFileName ( ) )
Say-Verbose " Zip path: $ZipPath "
$DownloadFailed = $false
Say " Downloading link: $DownloadLink "
try {
DownloadFile -Source $DownloadLink -OutPath $ZipPath
}
catch {
Say " Cannot download: $DownloadLink "
if ( $LegacyDownloadLink ) {
$DownloadLink = $LegacyDownloadLink
$ZipPath = [ System.IO.Path ] :: combine ( [ System.IO.Path ] :: GetTempPath ( ) , [ System.IO.Path ] :: GetRandomFileName ( ) )
Say-Verbose " Legacy zip path: $ZipPath "
Say " Downloading legacy link: $DownloadLink "
try {
DownloadFile -Source $DownloadLink -OutPath $ZipPath
}
catch {
Say " Cannot download: $DownloadLink "
$DownloadFailed = $true
}
}
else {
$DownloadFailed = $true
}
}
if ( $DownloadFailed ) {
throw " Could not find/download: `" $assetName `" with version = $SpecificVersion `n Refer to: https://aka.ms/dotnet-os-lifecycle for information on .NET Core support "
}
Say " Extracting zip from $DownloadLink "
Extract-Dotnet -Package -ZipPath $ZipPath -OutPath $InstallRoot
# Check if the SDK version is installed; if not, fail the installation.
$isAssetInstalled = $false
# if the version contains "RTM" or "servicing"; check if a 'release-type' SDK version is installed.
if ( $SpecificVersion -Match " rtm " -or $SpecificVersion -Match " servicing " ) {
$ReleaseVersion = $SpecificVersion . Split ( " - " ) [ 0 ]
Say-Verbose " Checking installation: version = $ReleaseVersion "
$isAssetInstalled = Is-Dotnet -Package -Installed -InstallRoot $InstallRoot -RelativePathToPackage $dotnetPackageRelativePath -SpecificVersion $ReleaseVersion
}
# Check if the SDK version is installed.
if ( ! $isAssetInstalled ) {
Say-Verbose " Checking installation: version = $SpecificVersion "
$isAssetInstalled = Is-Dotnet -Package -Installed -InstallRoot $InstallRoot -RelativePathToPackage $dotnetPackageRelativePath -SpecificVersion $SpecificVersion
}
if ( ! $isAssetInstalled ) {
throw " `" $assetName `" with version = $SpecificVersion failed to install with an unknown error. "
}
Remove-Item $ZipPath
Prepend-Sdk -InstallRoot -To -Path -InstallRoot $InstallRoot -BinFolderRelativePath $BinFolderRelativePath
Say " Installation finished "
exit 0
# SIG # Begin signature block
2020-07-16 00:32:15 +07:00
# MIIjhwYJKoZIhvcNAQcCoIIjeDCCI3QCAQExDzANBglghkgBZQMEAgEFADB5Bgor
2020-06-13 00:46:25 +07:00
# BgEEAYI3AgEEoGswaTA0BgorBgEEAYI3AgEeMCYCAwEAAAQQH8w7YFlLCE63JNLG
2020-07-16 00:32:15 +07:00
# KX7zUQIBAAIBAAIBAAIBAAIBADAxMA0GCWCGSAFlAwQCAQUABCAiKYSY4KtkeThH
# d5M1aXqv1K0/pff07QwfUbYZ/qX5LqCCDYUwggYDMIID66ADAgECAhMzAAABiK9S
# 1rmSbej5AAAAAAGIMA0GCSqGSIb3DQEBCwUAMH4xCzAJBgNVBAYTAlVTMRMwEQYD
2020-06-13 00:46:25 +07:00
# VQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNy
# b3NvZnQgQ29ycG9yYXRpb24xKDAmBgNVBAMTH01pY3Jvc29mdCBDb2RlIFNpZ25p
2020-07-16 00:32:15 +07:00
# bmcgUENBIDIwMTEwHhcNMjAwMzA0MTgzOTQ4WhcNMjEwMzAzMTgzOTQ4WjB0MQsw
2020-06-13 00:46:25 +07:00
# CQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9u
# ZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMR4wHAYDVQQDExVNaWNy
# b3NvZnQgQ29ycG9yYXRpb24wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIB
2020-07-16 00:32:15 +07:00
# AQCSCNryE+Cewy2m4t/a74wZ7C9YTwv1PyC4BvM/kSWPNs8n0RTe+FvYfU+E9uf0
# t7nYlAzHjK+plif2BhD+NgdhIUQ8sVwWO39tjvQRHjP2//vSvIfmmkRoML1Ihnjs
# 9kQiZQzYRDYYRp9xSQYmRwQjk5hl8/U7RgOiQDitVHaU7BT1MI92lfZRuIIDDYBd
# vXtbclYJMVOwqZtv0O9zQCret6R+fRSGaDNfEEpcILL+D7RV3M4uaJE4Ta6KAOdv
# V+MVaJp1YXFTZPKtpjHO6d9pHQPZiG7NdC6QbnRGmsa48uNQrb6AfmLKDI1Lp31W
# MogTaX5tZf+CZT9PSuvjOCLNAgMBAAGjggGCMIIBfjAfBgNVHSUEGDAWBgorBgEE
# AYI3TAgBBggrBgEFBQcDAzAdBgNVHQ4EFgQUj9RJL9zNrPcL10RZdMQIXZN7MG8w
# VAYDVR0RBE0wS6RJMEcxLTArBgNVBAsTJE1pY3Jvc29mdCBJcmVsYW5kIE9wZXJh
# dGlvbnMgTGltaXRlZDEWMBQGA1UEBRMNMjMwMDEyKzQ1ODM4NjAfBgNVHSMEGDAW
# gBRIbmTlUAXTgqoXNzcitW2oynUClTBUBgNVHR8ETTBLMEmgR6BFhkNodHRwOi8v
# d3d3Lm1pY3Jvc29mdC5jb20vcGtpb3BzL2NybC9NaWNDb2RTaWdQQ0EyMDExXzIw
# MTEtMDctMDguY3JsMGEGCCsGAQUFBwEBBFUwUzBRBggrBgEFBQcwAoZFaHR0cDov
# L3d3dy5taWNyb3NvZnQuY29tL3BraW9wcy9jZXJ0cy9NaWNDb2RTaWdQQ0EyMDEx
# XzIwMTEtMDctMDguY3J0MAwGA1UdEwEB/wQCMAAwDQYJKoZIhvcNAQELBQADggIB
# ACnXo8hjp7FeT+H6iQlV3CcGnkSbFvIpKYafgzYCFo3UHY1VHYJVb5jHEO8oG26Q
# qBELmak6MTI+ra3WKMTGhE1sEIlowTcp4IAs8a5wpCh6Vf4Z/bAtIppP3p3gXk2X
# 8UXTc+WxjQYsDkFiSzo/OBa5hkdW1g4EpO43l9mjToBdqEPtIXsZ7Hi1/6y4gK0P
# mMiwG8LMpSn0n/oSHGjrUNBgHJPxgs63Slf58QGBznuXiRaXmfTUDdrvhRocdxIM
# i8nXQwWACMiQzJSRzBP5S2wUq7nMAqjaTbeXhJqD2SFVHdUYlKruvtPSwbnqSRWT
# GI8s4FEXt+TL3w5JnwVZmZkUFoioQDMMjFyaKurdJ6pnzbr1h6QW0R97fWc8xEIz
# LIOiU2rjwWAtlQqFO8KNiykjYGyEf5LyAJKAO+rJd9fsYR+VBauIEQoYmjnUbTXM
# SY2Lf5KMluWlDOGVh8q6XjmBccpaT+8tCfxpaVYPi1ncnwTwaPQvVq8RjWDRB7Pa
# 8ruHgj2HJFi69+hcq7mWx5nTUtzzFa7RSZfE5a1a5AuBmGNRr7f8cNfa01+tiWjV
# Kk1a+gJUBSP0sIxecFbVSXTZ7bqeal45XSDIisZBkWb+83TbXdTGMDSUFKTAdtC+
# r35GfsN8QVy59Hb5ZYzAXczhgRmk7NyE6jD0Ym5TKiW5MIIHejCCBWKgAwIBAgIK
# 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/Xmfwb1tbWrJUnMTDXpQzTGCFVgwghVUAgEBMIGVMH4x
# CzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRt
# b25kMR4wHAYDVQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xKDAmBgNVBAMTH01p
# Y3Jvc29mdCBDb2RlIFNpZ25pbmcgUENBIDIwMTECEzMAAAGIr1LWuZJt6PkAAAAA
# AYgwDQYJYIZIAWUDBAIBBQCgga4wGQYJKoZIhvcNAQkDMQwGCisGAQQBgjcCAQQw
# HAYKKwYBBAGCNwIBCzEOMAwGCisGAQQBgjcCARUwLwYJKoZIhvcNAQkEMSIEIFxZ
# Yezh3liQqiGQuXNa+zYfoSIbLqOpdEn2ZKskBkisMEIGCisGAQQBgjcCAQwxNDAy
# oBSAEgBNAGkAYwByAG8AcwBvAGYAdKEagBhodHRwOi8vd3d3Lm1pY3Jvc29mdC5j
# b20wDQYJKoZIhvcNAQEBBQAEggEAjLUrwCXJCPHZulZuKAQSX+MfnIRFAhlN7ru2
# 6H8rudvhkWgqMISkLb9gFDPR5FhR4sqdYgKW4P0ERao9ypCGi1FWDLqygC2XBbHj
# NEQHBxHJs5SMsMAXNSIcYHqVAvhF3nXoseaNBkhOTrkQ1FS/fW7AfDGRbsiiESzv
# lebf92shZylBFKOsKQLAL0mF/B7xrxHJIj5dgQoD1phATRNHOEQj3jgmkidFWowV
# 4r8MzbxRhAEORbnJexlUoDQJQH3YwxuUyXkTvrYMTKSbGJLlwRaZQbrcBU0k4gCH
# y8Sci+p9Rq+aOTzLCoNrZyh9E7OdwVDm1FJAtY30bV50T2WSFKGCEuIwghLeBgor
# BgEEAYI3AwMBMYISzjCCEsoGCSqGSIb3DQEHAqCCErswghK3AgEDMQ8wDQYJYIZI
# AWUDBAIBBQAwggFRBgsqhkiG9w0BCRABBKCCAUAEggE8MIIBOAIBAQYKKwYBBAGE
# WQoDATAxMA0GCWCGSAFlAwQCAQUABCD7JNcBBSfhlKPL1tN3CEKRKJuT/dZ8RO9K
# orYLXJeLTwIGXvN89YD7GBMyMDIwMDcwMTE0MTYyMC40MDVaMASAAgH0oIHQpIHN
# MIHKMQswCQYDVQQGEwJVUzELMAkGA1UECBMCV0ExEDAOBgNVBAcTB1JlZG1vbmQx
# HjAcBgNVBAoTFU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjEtMCsGA1UECxMkTWljcm9z
# b2Z0IElyZWxhbmQgT3BlcmF0aW9ucyBMaW1pdGVkMSYwJAYDVQQLEx1UaGFsZXMg
# VFNTIEVTTjoxNzlFLTRCQjAtODI0NjElMCMGA1UEAxMcTWljcm9zb2Z0IFRpbWUt
# U3RhbXAgU2VydmljZaCCDjkwggTxMIID2aADAgECAhMzAAABDKp4btzMQkzBAAAA
# AAEMMA0GCSqGSIb3DQEBCwUAMHwxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpXYXNo
# aW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNyb3NvZnQgQ29y
# cG9yYXRpb24xJjAkBgNVBAMTHU1pY3Jvc29mdCBUaW1lLVN0YW1wIFBDQSAyMDEw
# MB4XDTE5MTAyMzIzMTkxNloXDTIxMDEyMTIzMTkxNlowgcoxCzAJBgNVBAYTAlVT
# MQswCQYDVQQIEwJXQTEQMA4GA1UEBxMHUmVkbW9uZDEeMBwGA1UEChMVTWljcm9z
# b2Z0IENvcnBvcmF0aW9uMS0wKwYDVQQLEyRNaWNyb3NvZnQgSXJlbGFuZCBPcGVy
# YXRpb25zIExpbWl0ZWQxJjAkBgNVBAsTHVRoYWxlcyBUU1MgRVNOOjE3OUUtNEJC
# MC04MjQ2MSUwIwYDVQQDExxNaWNyb3NvZnQgVGltZS1TdGFtcCBTZXJ2aWNlMIIB
# IjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAq5011+XqVJmQKtiw39igeEMv
# CLcZ1forbmxsDkpnCN1SrThKI+n2Pr3zqTzJVgdJFCoKm1ks1gtRJ7HaL6tDkrOw
# 8XJmfJaxyQAluCQ+e40NI+A4w+u59Gy89AVY5lJNrmCva6gozfg1kxw6abV5WWr+
# PjEpNCshO4hxv3UqgMcCKnT2YVSZzF1Gy7APub1fY0P1vNEuOFKrNCEEvWIKRrqs
# eyBB73G8KD2yw6jfz0VKxNSRAdhJV/ghOyrDt5a+L6C3m1rpr8sqiof3iohv3ANI
# gNqw6ex+4+G+B7JMbIHbGpPdebedL6ePbuBCnbgJoDn340k0aw6ij21GvvUnkQID
# AQABo4IBGzCCARcwHQYDVR0OBBYEFAlCOq9DDIa0A0oqgKtM5vjuZeK+MB8GA1Ud
# IwQYMBaAFNVjOlyKMZDzQ3t8RhvFM2hahW1VMFYGA1UdHwRPME0wS6BJoEeGRWh0
# dHA6Ly9jcmwubWljcm9zb2Z0LmNvbS9wa2kvY3JsL3Byb2R1Y3RzL01pY1RpbVN0
# YVBDQV8yMDEwLTA3LTAxLmNybDBaBggrBgEFBQcBAQROMEwwSgYIKwYBBQUHMAKG
# Pmh0dHA6Ly93d3cubWljcm9zb2Z0LmNvbS9wa2kvY2VydHMvTWljVGltU3RhUENB
# XzIwMTAtMDctMDEuY3J0MAwGA1UdEwEB/wQCMAAwEwYDVR0lBAwwCgYIKwYBBQUH
# AwgwDQYJKoZIhvcNAQELBQADggEBAET3xBg/IZ9zdOfwbDGK7cK3qKYt/qUOlbRB
# zgeNjb32K86nGeRGkBee10dVOEGWUw6KtBeWh1LQ70b64/tLtiLcsf9JzaAyDYb1
# sRmMi5fjRZ753TquaT8V7NJ7RfEuYfvZlubfQD0MVbU4tzsdZdYuxE37V2J9pN89
# j7GoFNtAnSnCn1MRxENAILgt9XzeQzTEDhFYW0N2DNphTkRPXGjpDmwi6WtkJ5fv
# 0iTyB4dwEC+/ed0lGbFLcytJoMwfTNMdH6gcnHlMzsniornGFZa5PPiV78XoZ9Fe
# upKo8ZKNGhLLLB5GTtqfHex5no3ioVSq+NthvhX0I/V+iXJsopowggZxMIIEWaAD
# AgECAgphCYEqAAAAAAACMA0GCSqGSIb3DQEBCwUAMIGIMQswCQYDVQQGEwJVUzET
# MBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9uZDEeMBwGA1UEChMV
# TWljcm9zb2Z0IENvcnBvcmF0aW9uMTIwMAYDVQQDEylNaWNyb3NvZnQgUm9vdCBD
# ZXJ0aWZpY2F0ZSBBdXRob3JpdHkgMjAxMDAeFw0xMDA3MDEyMTM2NTVaFw0yNTA3
# MDEyMTQ2NTVaMHwxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpXYXNoaW5ndG9uMRAw
# DgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24x
# JjAkBgNVBAMTHU1pY3Jvc29mdCBUaW1lLVN0YW1wIFBDQSAyMDEwMIIBIjANBgkq
# hkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAqR0NvHcRijog7PwTl/X6f2mUa3RUENWl
# CgCChfvtfGhLLF/Fw+Vhwna3PmYrW/AVUycEMR9BGxqVHc4JE458YTBZsTBED/Fg
# iIRUQwzXTbg4CLNC3ZOs1nMwVyaCo0UN0Or1R4HNvyRgMlhgRvJYR4YyhB50YWeR
# X4FUsc+TTJLBxKZd0WETbijGGvmGgLvfYfxGwScdJGcSchohiq9LZIlQYrFd/Xcf
# PfBXday9ikJNQFHRD5wGPmd/9WbAA5ZEfu/QS/1u5ZrKsajyeioKMfDaTgaRtogI
# Neh4HLDpmc085y9Euqf03GS9pAHBIAmTeM38vMDJRF1eFpwBBU8iTQIDAQABo4IB
# 5jCCAeIwEAYJKwYBBAGCNxUBBAMCAQAwHQYDVR0OBBYEFNVjOlyKMZDzQ3t8RhvF
# M2hahW1VMBkGCSsGAQQBgjcUAgQMHgoAUwB1AGIAQwBBMAsGA1UdDwQEAwIBhjAP
# BgNVHRMBAf8EBTADAQH/MB8GA1UdIwQYMBaAFNX2VsuP6KJcYmjRPZSQW9fOmhjE
# MFYGA1UdHwRPME0wS6BJoEeGRWh0dHA6Ly9jcmwubWljcm9zb2Z0LmNvbS9wa2kv
# Y3JsL3Byb2R1Y3RzL01pY1Jvb0NlckF1dF8yMDEwLTA2LTIzLmNybDBaBggrBgEF
# BQcBAQROMEwwSgYIKwYBBQUHMAKGPmh0dHA6Ly93d3cubWljcm9zb2Z0LmNvbS9w
# a2kvY2VydHMvTWljUm9vQ2VyQXV0XzIwMTAtMDYtMjMuY3J0MIGgBgNVHSABAf8E
# gZUwgZIwgY8GCSsGAQQBgjcuAzCBgTA9BggrBgEFBQcCARYxaHR0cDovL3d3dy5t
# aWNyb3NvZnQuY29tL1BLSS9kb2NzL0NQUy9kZWZhdWx0Lmh0bTBABggrBgEFBQcC
# AjA0HjIgHQBMAGUAZwBhAGwAXwBQAG8AbABpAGMAeQBfAFMAdABhAHQAZQBtAGUA
# bgB0AC4gHTANBgkqhkiG9w0BAQsFAAOCAgEAB+aIUQ3ixuCYP4FxAz2do6Ehb7Pr
# psz1Mb7PBeKp/vpXbRkws8LFZslq3/Xn8Hi9x6ieJeP5vO1rVFcIK1GCRBL7uVOM
# zPRgEop2zEBAQZvcXBf/XPleFzWYJFZLdO9CEMivv3/Gf/I3fVo/HPKZeUqRUgCv
# OA8X9S95gWXZqbVr5MfO9sp6AG9LMEQkIjzP7QOllo9ZKby2/QThcJ8ySif9Va8v
# /rbljjO7Yl+a21dA6fHOmWaQjP9qYn/dxUoLkSbiOewZSnFjnXshbcOco6I8+n99
# lmqQeKZt0uGc+R38ONiU9MalCpaGpL2eGq4EQoO4tYCbIjggtSXlZOz39L9+Y1kl
# D3ouOVd2onGqBooPiRa6YacRy5rYDkeagMXQzafQ732D8OE7cQnfXXSYIghh2rBQ
# Hm+98eEA3+cxB6STOvdlR3jo+KhIq/fecn5ha293qYHLpwmsObvsxsvYgrRyzR30
# uIUBHoD7G4kqVDmyW9rIDVWZeodzOwjmmC3qjeAzLhIp9cAvVCch98isTtoouLGp
# 25ayp0Kiyc8ZQU3ghvkqmqMRZjDTu3QyS99je/WZii8bxyGvWbWu3EQ8l1Bx16HS
# xVXjad5XwdHeMMD9zOZN+w2/XU/pnR4ZOC+8z1gFLu8NoFA12u8JJxzVs341Hgi6
# 2jbb01+P3nSISRKhggLLMIICNAIBATCB+KGB0KSBzTCByjELMAkGA1UEBhMCVVMx
# CzAJBgNVBAgTAldBMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNyb3Nv
# ZnQgQ29ycG9yYXRpb24xLTArBgNVBAsTJE1pY3Jvc29mdCBJcmVsYW5kIE9wZXJh
# dGlvbnMgTGltaXRlZDEmMCQGA1UECxMdVGhhbGVzIFRTUyBFU046MTc5RS00QkIw
# LTgyNDYxJTAjBgNVBAMTHE1pY3Jvc29mdCBUaW1lLVN0YW1wIFNlcnZpY2WiIwoB
# ATAHBgUrDgMCGgMVAMsg9FQ9pgPLXI2Ld5z7xDS0QAZ9oIGDMIGApH4wfDELMAkG
2020-06-13 00:46:25 +07:00
# A1UEBhMCVVMxEzARBgNVBAgTCldhc2hpbmd0b24xEDAOBgNVBAcTB1JlZG1vbmQx
2020-07-16 00:32:15 +07:00
# HjAcBgNVBAoTFU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjEmMCQGA1UEAxMdTWljcm9z
# b2Z0IFRpbWUtU3RhbXAgUENBIDIwMTAwDQYJKoZIhvcNAQEFBQACBQDipo0MMCIY
# DzIwMjAwNzAxMTIxODIwWhgPMjAyMDA3MDIxMjE4MjBaMHQwOgYKKwYBBAGEWQoE
# ATEsMCowCgIFAOKmjQwCAQAwBwIBAAICE70wBwIBAAICEeIwCgIFAOKn3owCAQAw
# NgYKKwYBBAGEWQoEAjEoMCYwDAYKKwYBBAGEWQoDAqAKMAgCAQACAwehIKEKMAgC
# AQACAwGGoDANBgkqhkiG9w0BAQUFAAOBgQCOPjlHOH8nYtgt2XnpKXenxPUR03ED
# xPBm8XR5Z1vIq53RU9jG6yYcYNTdK+q38SGZtu0W/SgagTfKCQhjhRakuv7rGSs2
# dlhx9LGCoc/q1vqmZpRSjkqWVcc/NzmldUWIWnLlV6rmLGoDmfCH5BcsiU6Eo6wU
# iUVwnnXoqsCaBzGCAw0wggMJAgEBMIGTMHwxCzAJBgNVBAYTAlVTMRMwEQYDVQQI
# EwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNyb3Nv
# ZnQgQ29ycG9yYXRpb24xJjAkBgNVBAMTHU1pY3Jvc29mdCBUaW1lLVN0YW1wIFBD
# QSAyMDEwAhMzAAABDKp4btzMQkzBAAAAAAEMMA0GCWCGSAFlAwQCAQUAoIIBSjAa
# BgkqhkiG9w0BCQMxDQYLKoZIhvcNAQkQAQQwLwYJKoZIhvcNAQkEMSIEIDpwhjyu
# zgu3Kmxpnpz86ZlthBqEzG5vaEMOkYRyuFCaMIH6BgsqhkiG9w0BCRACLzGB6jCB
# 5zCB5DCBvQQgg5AWKX7M1+m2//+V7qmRvt1K/ww5Muu8XzGJBqygVCkwgZgwgYCk
# fjB8MQswCQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMH
# UmVkbW9uZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMSYwJAYDVQQD
# Ex1NaWNyb3NvZnQgVGltZS1TdGFtcCBQQ0EgMjAxMAITMwAAAQyqeG7czEJMwQAA
# AAABDDAiBCD11urvv5vgo4gFVQ2NMVrzgxT87Yuiq16YdswYbaYeITANBgkqhkiG
# 9w0BAQsFAASCAQAi3q8hwcT2ft4b2EleaiyZxOImV/cKusmth1dtCh5/Jb0GbOld
# f5cSalrjf42MNPodWAtgmWozkYrQF6HxnsOiYiamfRA8E3E7xyRMy7AFfAhjcwMi
# xaW4Iye6E1Ec6LtULANxfDtG/KIdCWdZxKqOezL3nzFNQWmm1mXPV+UnKpnJkA3E
# DsQOUWk8J6ojDurhrP536WI+3arg8PcnppHBLd/xNKYdlsTb+6qndgzKXkDDt1CV
# 4zCyuZ7bO8eyZAmNoSZz22k7vus9UjBz/CDhXylo20N43nr29rWPItUgH4uvOGQn
# t26Y/yjBaQImz32psrfJEMbQ7cl789s8WOx8
2020-06-13 00:46:25 +07:00
# SIG # End signature block