912 lines
40 KiB
PowerShell
912 lines
40 KiB
PowerShell
#
|
|
# 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 ProxyBypassList
|
|
If set with ProxyAddress, will provide the list of comma separated urls that will bypass the proxy
|
|
.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,
|
|
[string[]]$ProxyBypassList=@(),
|
|
[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) {
|
|
try
|
|
{
|
|
Write-Host "dotnet-install: $str"
|
|
}
|
|
catch
|
|
{
|
|
# Some platforms cannot utilize Write-Host (Azure Functions, for instance). Fall back to Write-Output
|
|
Write-Output "dotnet-install: $str"
|
|
}
|
|
}
|
|
|
|
function Say-Verbose($str) {
|
|
try
|
|
{
|
|
Write-Verbose "dotnet-install: $str"
|
|
}
|
|
catch
|
|
{
|
|
# Some platforms cannot utilize Write-Verbose (Azure Functions, for instance). Fall back to Write-Output
|
|
Write-Output "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
|
|
|
|
# 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
|
|
}
|
|
|
|
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;
|
|
BypassList = $ProxyBypassList;
|
|
}
|
|
$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 / 1MB -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`nRefer 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
|
|
# MIIjlgYJKoZIhvcNAQcCoIIjhzCCI4MCAQExDzANBglghkgBZQMEAgEFADB5Bgor
|
|
# BgEEAYI3AgEEoGswaTA0BgorBgEEAYI3AgEeMCYCAwEAAAQQH8w7YFlLCE63JNLG
|
|
# KX7zUQIBAAIBAAIBAAIBAAIBADAxMA0GCWCGSAFlAwQCAQUABCCXdb9pJ+MI1iFd
|
|
# 2hUVOaNmZYt6e48+bQNJm9/Rbj3u3qCCDYUwggYDMIID66ADAgECAhMzAAABiK9S
|
|
# 1rmSbej5AAAAAAGIMA0GCSqGSIb3DQEBCwUAMH4xCzAJBgNVBAYTAlVTMRMwEQYD
|
|
# VQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNy
|
|
# b3NvZnQgQ29ycG9yYXRpb24xKDAmBgNVBAMTH01pY3Jvc29mdCBDb2RlIFNpZ25p
|
|
# bmcgUENBIDIwMTEwHhcNMjAwMzA0MTgzOTQ4WhcNMjEwMzAzMTgzOTQ4WjB0MQsw
|
|
# CQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9u
|
|
# ZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMR4wHAYDVQQDExVNaWNy
|
|
# b3NvZnQgQ29ycG9yYXRpb24wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIB
|
|
# 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/Xmfwb1tbWrJUnMTDXpQzTGCFWcwghVjAgEBMIGVMH4x
|
|
# CzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRt
|
|
# b25kMR4wHAYDVQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xKDAmBgNVBAMTH01p
|
|
# Y3Jvc29mdCBDb2RlIFNpZ25pbmcgUENBIDIwMTECEzMAAAGIr1LWuZJt6PkAAAAA
|
|
# AYgwDQYJYIZIAWUDBAIBBQCgga4wGQYJKoZIhvcNAQkDMQwGCisGAQQBgjcCAQQw
|
|
# HAYKKwYBBAGCNwIBCzEOMAwGCisGAQQBgjcCARUwLwYJKoZIhvcNAQkEMSIEIM9C
|
|
# NU8DMdIjlVSldghA1uP8Jf60AlCYNoHBHHW3pscjMEIGCisGAQQBgjcCAQwxNDAy
|
|
# oBSAEgBNAGkAYwByAG8AcwBvAGYAdKEagBhodHRwOi8vd3d3Lm1pY3Jvc29mdC5j
|
|
# b20wDQYJKoZIhvcNAQEBBQAEggEAFwdPmnUSAnwqMM8b4QthX44z3UnhPYm1EtjC
|
|
# /PnpTA5xkFMaoOUhGdiR5tpGPWNgiNRqD5ZSL1JVUqUOpNfybZZqZPz/LnZdS1XB
|
|
# +aj4Orh1Lkbaqq74PQxgRrUR3eyOVHcNTcohPNIb/ZYHqr6cwhqZitGuNEHNtqCk
|
|
# lSRCrfiNlW8PNrpPvUWwIC1Fd+OpgRdGhKFIHTx31if1BH8omViGm4iFdlb5dGz3
|
|
# ibeOm6FfXWwmKJVqVb/vhhemMel8tYNONTl2e+UjPOCy4f7myLiD61irA5T1a0vn
|
|
# vcIV0dRSwh8U5h8JYOEJxn4nydVKlJ5UGMS8eQiKdd42CGs93KGCEvEwghLtBgor
|
|
# BgEEAYI3AwMBMYIS3TCCEtkGCSqGSIb3DQEHAqCCEsowghLGAgEDMQ8wDQYJYIZI
|
|
# AWUDBAIBBQAwggFVBgsqhkiG9w0BCRABBKCCAUQEggFAMIIBPAIBAQYKKwYBBAGE
|
|
# WQoDATAxMA0GCWCGSAFlAwQCAQUABCCVM7LRYercP7cfHmTrb7lPfKaZCdVbtga7
|
|
# UOM/oLAsHgIGXxb9UghEGBMyMDIwMDgxMzEyMjIwNS40NjZaMASAAgH0oIHUpIHR
|
|
# MIHOMQswCQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMH
|
|
# UmVkbW9uZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMSkwJwYDVQQL
|
|
# EyBNaWNyb3NvZnQgT3BlcmF0aW9ucyBQdWVydG8gUmljbzEmMCQGA1UECxMdVGhh
|
|
# bGVzIFRTUyBFU046RjdBNi1FMjUxLTE1MEExJTAjBgNVBAMTHE1pY3Jvc29mdCBU
|
|
# aW1lLVN0YW1wIFNlcnZpY2Wggg5EMIIE9TCCA92gAwIBAgITMwAAASWL3otsciYx
|
|
# 3QAAAAABJTANBgkqhkiG9w0BAQsFADB8MQswCQYDVQQGEwJVUzETMBEGA1UECBMK
|
|
# V2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9uZDEeMBwGA1UEChMVTWljcm9zb2Z0
|
|
# IENvcnBvcmF0aW9uMSYwJAYDVQQDEx1NaWNyb3NvZnQgVGltZS1TdGFtcCBQQ0Eg
|
|
# MjAxMDAeFw0xOTEyMTkwMTE0NThaFw0yMTAzMTcwMTE0NThaMIHOMQswCQYDVQQG
|
|
# EwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9uZDEeMBwG
|
|
# A1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMSkwJwYDVQQLEyBNaWNyb3NvZnQg
|
|
# T3BlcmF0aW9ucyBQdWVydG8gUmljbzEmMCQGA1UECxMdVGhhbGVzIFRTUyBFU046
|
|
# RjdBNi1FMjUxLTE1MEExJTAjBgNVBAMTHE1pY3Jvc29mdCBUaW1lLVN0YW1wIFNl
|
|
# cnZpY2UwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDQex9jdmBb7OHJ
|
|
# wSYmMUorZNwAcv8Vy36TlJuzcVx7G+lFqt2zjWOMlSOMkm1XoAuJ8VZ5ShBedADX
|
|
# DGDKxHNZhLu3EW8x5ot/IOk6izLTlAFtvIXOgzXs/HaOM72XHKykMZHAdL/fpZtA
|
|
# SM5PalmsXX4Ol8lXkm9jR55K56C7q9+hDU+2tjGHaE1ZWlablNUXBhaZgtCJCd60
|
|
# UyZvgI7/uNzcafj0/Vw2bait9nDAVd24yt/XCZnHY3yX7ZsHjIuHpsl+PpDXai1D
|
|
# we9p0ryCZsl9SOMHextIHe9qlTbtWYJ8WtWLoH9dEMQxVLnmPPDOVmBj7LZhSji3
|
|
# 8N9Vpz/FAgMBAAGjggEbMIIBFzAdBgNVHQ4EFgQU86rK5Qcm+QE5NBXGCPIiCBdD
|
|
# JPgwHwYDVR0jBBgwFoAU1WM6XIoxkPNDe3xGG8UzaFqFbVUwVgYDVR0fBE8wTTBL
|
|
# oEmgR4ZFaHR0cDovL2NybC5taWNyb3NvZnQuY29tL3BraS9jcmwvcHJvZHVjdHMv
|
|
# TWljVGltU3RhUENBXzIwMTAtMDctMDEuY3JsMFoGCCsGAQUFBwEBBE4wTDBKBggr
|
|
# BgEFBQcwAoY+aHR0cDovL3d3dy5taWNyb3NvZnQuY29tL3BraS9jZXJ0cy9NaWNU
|
|
# aW1TdGFQQ0FfMjAxMC0wNy0wMS5jcnQwDAYDVR0TAQH/BAIwADATBgNVHSUEDDAK
|
|
# BggrBgEFBQcDCDANBgkqhkiG9w0BAQsFAAOCAQEAkxxZPGEgIgAhsqZNTZk58V1v
|
|
# QiJ5ja2xHl5TqGA6Hwj5SioLg3FSLiTmGV+BtFlpYUtkneB4jrZsuNpMtfbTMdG7
|
|
# p/xAyIVtwvXnTXqKlCD1T9Lcr94pVedzHGJzL1TYNQyZJBouCfzkgkzccOuFOfeW
|
|
# PfnMTiI5UBW5OdmoyHPQWDSGHoboW1dTKqXeJtuVDTYbHTKs4zjfCBMFjmylRu52
|
|
# Zpiz+9MBeRj4iAeou0F/3xvIzepoIKgUWCZ9mmViWEkVwCtTGbV8eK73KeEE0tfM
|
|
# U/YY2UmoGPc8YwburDEfelegLW+YHkfrcGAGlftCmqtOdOLeghLoG0Ubx/B7sTCC
|
|
# BnEwggRZoAMCAQICCmEJgSoAAAAAAAIwDQYJKoZIhvcNAQELBQAwgYgxCzAJBgNV
|
|
# BAYTAlVTMRMwEQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4w
|
|
# HAYDVQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xMjAwBgNVBAMTKU1pY3Jvc29m
|
|
# dCBSb290IENlcnRpZmljYXRlIEF1dGhvcml0eSAyMDEwMB4XDTEwMDcwMTIxMzY1
|
|
# NVoXDTI1MDcwMTIxNDY1NVowfDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCldhc2hp
|
|
# bmd0b24xEDAOBgNVBAcTB1JlZG1vbmQxHjAcBgNVBAoTFU1pY3Jvc29mdCBDb3Jw
|
|
# b3JhdGlvbjEmMCQGA1UEAxMdTWljcm9zb2Z0IFRpbWUtU3RhbXAgUENBIDIwMTAw
|
|
# ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCpHQ28dxGKOiDs/BOX9fp/
|
|
# aZRrdFQQ1aUKAIKF++18aEssX8XD5WHCdrc+Zitb8BVTJwQxH0EbGpUdzgkTjnxh
|
|
# MFmxMEQP8WCIhFRDDNdNuDgIs0Ldk6zWczBXJoKjRQ3Q6vVHgc2/JGAyWGBG8lhH
|
|
# hjKEHnRhZ5FfgVSxz5NMksHEpl3RYRNuKMYa+YaAu99h/EbBJx0kZxJyGiGKr0tk
|
|
# iVBisV39dx898Fd1rL2KQk1AUdEPnAY+Z3/1ZsADlkR+79BL/W7lmsqxqPJ6Kgox
|
|
# 8NpOBpG2iAg16HgcsOmZzTznL0S6p/TcZL2kAcEgCZN4zfy8wMlEXV4WnAEFTyJN
|
|
# AgMBAAGjggHmMIIB4jAQBgkrBgEEAYI3FQEEAwIBADAdBgNVHQ4EFgQU1WM6XIox
|
|
# kPNDe3xGG8UzaFqFbVUwGQYJKwYBBAGCNxQCBAweCgBTAHUAYgBDAEEwCwYDVR0P
|
|
# BAQDAgGGMA8GA1UdEwEB/wQFMAMBAf8wHwYDVR0jBBgwFoAU1fZWy4/oolxiaNE9
|
|
# lJBb186aGMQwVgYDVR0fBE8wTTBLoEmgR4ZFaHR0cDovL2NybC5taWNyb3NvZnQu
|
|
# Y29tL3BraS9jcmwvcHJvZHVjdHMvTWljUm9vQ2VyQXV0XzIwMTAtMDYtMjMuY3Js
|
|
# MFoGCCsGAQUFBwEBBE4wTDBKBggrBgEFBQcwAoY+aHR0cDovL3d3dy5taWNyb3Nv
|
|
# ZnQuY29tL3BraS9jZXJ0cy9NaWNSb29DZXJBdXRfMjAxMC0wNi0yMy5jcnQwgaAG
|
|
# A1UdIAEB/wSBlTCBkjCBjwYJKwYBBAGCNy4DMIGBMD0GCCsGAQUFBwIBFjFodHRw
|
|
# Oi8vd3d3Lm1pY3Jvc29mdC5jb20vUEtJL2RvY3MvQ1BTL2RlZmF1bHQuaHRtMEAG
|
|
# CCsGAQUFBwICMDQeMiAdAEwAZQBnAGEAbABfAFAAbwBsAGkAYwB5AF8AUwB0AGEA
|
|
# dABlAG0AZQBuAHQALiAdMA0GCSqGSIb3DQEBCwUAA4ICAQAH5ohRDeLG4Jg/gXED
|
|
# PZ2joSFvs+umzPUxvs8F4qn++ldtGTCzwsVmyWrf9efweL3HqJ4l4/m87WtUVwgr
|
|
# UYJEEvu5U4zM9GASinbMQEBBm9xcF/9c+V4XNZgkVkt070IQyK+/f8Z/8jd9Wj8c
|
|
# 8pl5SpFSAK84Dxf1L3mBZdmptWvkx872ynoAb0swRCQiPM/tA6WWj1kpvLb9BOFw
|
|
# nzJKJ/1Vry/+tuWOM7tiX5rbV0Dp8c6ZZpCM/2pif93FSguRJuI57BlKcWOdeyFt
|
|
# w5yjojz6f32WapB4pm3S4Zz5Hfw42JT0xqUKloakvZ4argRCg7i1gJsiOCC1JeVk
|
|
# 7Pf0v35jWSUPei45V3aicaoGig+JFrphpxHLmtgOR5qAxdDNp9DvfYPw4TtxCd9d
|
|
# dJgiCGHasFAeb73x4QDf5zEHpJM692VHeOj4qEir995yfmFrb3epgcunCaw5u+zG
|
|
# y9iCtHLNHfS4hQEegPsbiSpUObJb2sgNVZl6h3M7COaYLeqN4DMuEin1wC9UJyH3
|
|
# yKxO2ii4sanblrKnQqLJzxlBTeCG+SqaoxFmMNO7dDJL32N79ZmKLxvHIa9Zta7c
|
|
# RDyXUHHXodLFVeNp3lfB0d4wwP3M5k37Db9dT+mdHhk4L7zPWAUu7w2gUDXa7wkn
|
|
# HNWzfjUeCLraNtvTX4/edIhJEqGCAtIwggI7AgEBMIH8oYHUpIHRMIHOMQswCQYD
|
|
# VQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9uZDEe
|
|
# MBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMSkwJwYDVQQLEyBNaWNyb3Nv
|
|
# ZnQgT3BlcmF0aW9ucyBQdWVydG8gUmljbzEmMCQGA1UECxMdVGhhbGVzIFRTUyBF
|
|
# U046RjdBNi1FMjUxLTE1MEExJTAjBgNVBAMTHE1pY3Jvc29mdCBUaW1lLVN0YW1w
|
|
# IFNlcnZpY2WiIwoBATAHBgUrDgMCGgMVAEXTL+FQbc2G+3MXXvIRKVr2oXCnoIGD
|
|
# MIGApH4wfDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCldhc2hpbmd0b24xEDAOBgNV
|
|
# BAcTB1JlZG1vbmQxHjAcBgNVBAoTFU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjEmMCQG
|
|
# A1UEAxMdTWljcm9zb2Z0IFRpbWUtU3RhbXAgUENBIDIwMTAwDQYJKoZIhvcNAQEF
|
|
# BQACBQDi3yR1MCIYDzIwMjAwODEzMDYzMTE3WhgPMjAyMDA4MTQwNjMxMTdaMHcw
|
|
# PQYKKwYBBAGEWQoEATEvMC0wCgIFAOLfJHUCAQAwCgIBAAICKbYCAf8wBwIBAAIC
|
|
# EkQwCgIFAOLgdfUCAQAwNgYKKwYBBAGEWQoEAjEoMCYwDAYKKwYBBAGEWQoDAqAK
|
|
# MAgCAQACAwehIKEKMAgCAQACAwGGoDANBgkqhkiG9w0BAQUFAAOBgQBI2hPSmSPK
|
|
# XurK36pE46s0uBEW23aGxotfubZR3iQCxDZ+dcZEN83t2JE4wh4a9HGpzXta/1Yz
|
|
# fgoIxgsI5wogRQF20sCD7x7ZTbpMweqxFCQSGRE8Z2B0FmntXXrEvQtS1ee0PC/1
|
|
# +eD7oAsVwmsSWdQHKfOVBqz51g2S+ImuzTGCAw0wggMJAgEBMIGTMHwxCzAJBgNV
|
|
# BAYTAlVTMRMwEQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4w
|
|
# HAYDVQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xJjAkBgNVBAMTHU1pY3Jvc29m
|
|
# dCBUaW1lLVN0YW1wIFBDQSAyMDEwAhMzAAABJYvei2xyJjHdAAAAAAElMA0GCWCG
|
|
# SAFlAwQCAQUAoIIBSjAaBgkqhkiG9w0BCQMxDQYLKoZIhvcNAQkQAQQwLwYJKoZI
|
|
# hvcNAQkEMSIEIJICFqJn2Gtkce4xbJqSJCqpNLdz4fjym2OW0Ac8zI+nMIH6Bgsq
|
|
# hkiG9w0BCRACLzGB6jCB5zCB5DCBvQQgXd/Gsi5vMF/6iX2CDh+VfmL5RvqaFkFw
|
|
# luiyje9B9w4wgZgwgYCkfjB8MQswCQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGlu
|
|
# Z3RvbjEQMA4GA1UEBxMHUmVkbW9uZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBv
|
|
# cmF0aW9uMSYwJAYDVQQDEx1NaWNyb3NvZnQgVGltZS1TdGFtcCBQQ0EgMjAxMAIT
|
|
# MwAAASWL3otsciYx3QAAAAABJTAiBCBSjc2CBOdr7iaTswYVN8f7KwiN5s4uBEO+
|
|
# JVI8WLhgFzANBgkqhkiG9w0BAQsFAASCAQCfsvzXMzAN1kylt4eAKSH4ryFIJqBH
|
|
# O7jcx7iIA9X6OPTuUmBniZGf2fmFG61V4HlmRgGOXuisJdpU3kiC7EZyFX6ZJoIj
|
|
# kgvCQf4BPu/cLtn2w6odZ68OrTHs7BfBKBr6eQKKcZ/kgRSsjMNinh8tHPlrxE63
|
|
# Zha3mUFfsnX5bi+F4VPhluGvRuA7q3IqMzfA/dTxON9WH5L+t3TwW61VebBaSPkT
|
|
# YevYlj0TTlCw1B3zk0ztU37uulqDi4rFr67VaoR3qrhL/xZ/DsaNXg1V/RXqQRrw
|
|
# eCag1OFRASAQOUOlWSi0QtYgUDl5FKKzxaJTEd946+6mJIkNXZB3nmA1
|
|
# SIG # End signature block
|