diff --git a/.drone.yml b/.drone.yml index 418a292..a47b49a 100644 --- a/.drone.yml +++ b/.drone.yml @@ -13,4 +13,4 @@ steps: - name: install choco commands: - - '@"%SystemRoot%\System32\WindowsPowerShell\v1.0\powershell.exe" -NoProfile -InputFormat None -ExecutionPolicy Bypass -Command "[System.Net.ServicePointManager]::SecurityProtocol = 3072; iex ((New-Object System.Net.WebClient).DownloadString(\'https://community.chocolatey.org/install.ps1\'))" && SET "PATH=%PATH%;%ALLUSERSPROFILE%\chocolatey\bin"' \ No newline at end of file + - 'powershell choco-install.ps1' \ No newline at end of file diff --git a/choco-install.ps1 b/choco-install.ps1 new file mode 100644 index 0000000..885751d --- /dev/null +++ b/choco-install.ps1 @@ -0,0 +1,698 @@ +<# + .SYNOPSIS + Downloads and installs Chocolatey on the local machine. + + .DESCRIPTION + Retrieves the Chocolatey nupkg for the latest or a specified version, and + downloads and installs the application to the local machine. + + .NOTES + ===================================================================== + Copyright 2017 - 2020 Chocolatey Software, Inc, and the + original authors/contributors from ChocolateyGallery + Copyright 2011 - 2017 RealDimensions Software, LLC, and the + original authors/contributors from ChocolateyGallery + at https://github.com/chocolatey/chocolatey.org + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + ===================================================================== + + Environment Variables, specified as $env:NAME in PowerShell.exe and %NAME% in cmd.exe. + For explicit proxy, please set $env:chocolateyProxyLocation and optionally $env:chocolateyProxyUser and $env:chocolateyProxyPassword + For an explicit version of Chocolatey, please set $env:chocolateyVersion = 'versionnumber' + To target a different url for chocolatey.nupkg, please set $env:chocolateyDownloadUrl = 'full url to nupkg file' + NOTE: $env:chocolateyDownloadUrl does not work with $env:chocolateyVersion. + To use built-in compression instead of 7zip (requires additional download), please set $env:chocolateyUseWindowsCompression = 'true' + To bypass the use of any proxy, please set $env:chocolateyIgnoreProxy = 'true' + + .LINK + For organizational deployments of Chocolatey, please see https://docs.chocolatey.org/en-us/guides/organizations/organizational-deployment-guide + +#> +[CmdletBinding(DefaultParameterSetName = 'Default')] +param( + # The URL to download Chocolatey from. This defaults to the value of + # $env:chocolateyDownloadUrl, if it is set, and otherwise falls back to the + # official Chocolatey community repository to download the Chocolatey package. + [Parameter(Mandatory = $false)] + [string] + $ChocolateyDownloadUrl = $env:chocolateyDownloadUrl, + + # Specifies a target version of Chocolatey to install. By default, the latest + # stable version is installed. This will use the value in + # $env:chocolateyVersion by default, if that environment variable is present. + # This parameter is ignored if -ChocolateyDownloadUrl is set. + [Parameter(Mandatory = $false)] + [string] + $ChocolateyVersion = $env:chocolateyVersion, + + # If set, uses built-in Windows decompression tools instead of 7zip when + # unpacking the downloaded nupkg. This will be set by default if + # $env:chocolateyUseWindowsCompression is set to a value other than 'false' or '0'. + # + # This parameter will be ignored in PS 5+ in favour of using the + # Expand-Archive built in PowerShell cmdlet directly. + [Parameter(Mandatory = $false)] + [switch] + $UseNativeUnzip = $( + $envVar = "$env:chocolateyUseWindowsCompression".Trim() + $value = $null + if ([bool]::TryParse($envVar, [ref] $value)) { + $value + } elseif ([int]::TryParse($envVar, [ref] $value)) { + [bool]$value + } else { + [bool]$envVar + } + ), + + # If set, ignores any configured proxy. This will override any proxy + # environment variables or parameters. This will be set by default if + # $env:chocolateyIgnoreProxy is set to a value other than 'false' or '0'. + [Parameter(Mandatory = $false)] + [switch] + $IgnoreProxy = $( + $envVar = "$env:chocolateyIgnoreProxy".Trim() + $value = $null + if ([bool]::TryParse($envVar, [ref] $value)) { + $value + } + elseif ([int]::TryParse($envVar, [ref] $value)) { + [bool]$value + } + else { + [bool]$envVar + } + ), + + # Specifies the proxy URL to use during the download. This will default to + # the value of $env:chocolateyProxyLocation, if any is set. + [Parameter(ParameterSetName = 'Proxy', Mandatory = $false)] + [string] + $ProxyUrl = $env:chocolateyProxyLocation, + + # Specifies the credential to use for an authenticated proxy. By default, a + # proxy credential will be constructed from the $env:chocolateyProxyUser and + # $env:chocolateyProxyPassword environment variables, if both are set. + [Parameter(ParameterSetName = 'Proxy', Mandatory = $false)] + [System.Management.Automation.PSCredential] + $ProxyCredential +) + +#region Functions + +function Get-Downloader { + <# + .SYNOPSIS + Gets a System.Net.WebClient that respects relevant proxies to be used for + downloading data. + + .DESCRIPTION + Retrieves a WebClient object that is pre-configured according to specified + environment variables for any proxy and authentication for the proxy. + Proxy information may be omitted if the target URL is considered to be + bypassed by the proxy (originates from the local network.) + + .PARAMETER Url + Target URL that the WebClient will be querying. This URL is not queried by + the function, it is only a reference to determine if a proxy is needed. + + .EXAMPLE + Get-Downloader -Url $fileUrl + + Verifies whether any proxy configuration is needed, and/or whether $fileUrl + is a URL that would need to bypass the proxy, and then outputs the + already-configured WebClient object. + #> + [CmdletBinding()] + param( + [Parameter(Mandatory = $false)] + [string] + $Url, + + [Parameter(Mandatory = $false)] + [string] + $ProxyUrl, + + [Parameter(Mandatory = $false)] + [System.Management.Automation.PSCredential] + $ProxyCredential + ) + + $downloader = New-Object System.Net.WebClient + + $defaultCreds = [System.Net.CredentialCache]::DefaultCredentials + if ($defaultCreds) { + $downloader.Credentials = $defaultCreds + } + + if ($ProxyUrl) { + # Use explicitly set proxy. + Write-Host "Using explicit proxy server '$ProxyUrl'." + $proxy = New-Object System.Net.WebProxy -ArgumentList $ProxyUrl, <# bypassOnLocal: #> $true + + $proxy.Credentials = if ($ProxyCredential) { + $ProxyCredential.GetNetworkCredential() + } elseif ($defaultCreds) { + $defaultCreds + } else { + Write-Warning "Default credentials were null, and no explicitly set proxy credentials were found. Attempting backup method." + (Get-Credential).GetNetworkCredential() + } + + if (-not $proxy.IsBypassed($Url)) { + $downloader.Proxy = $proxy + } + } else { + Write-Host "Not using proxy." + } + + $downloader +} + +function Request-String { + <# + .SYNOPSIS + Downloads content from a remote server as a string. + + .DESCRIPTION + Downloads target string content from a URL and outputs the resulting string. + Any existing proxy that may be in use will be utilised. + + .PARAMETER Url + URL to download string data from. + + .PARAMETER ProxyConfiguration + A hashtable containing proxy parameters (ProxyUrl and ProxyCredential) + + .EXAMPLE + Request-String https://community.chocolatey.org/install.ps1 + + Retrieves the contents of the string data at the targeted URL and outputs + it to the pipeline. + #> + [CmdletBinding()] + param( + [Parameter(Mandatory = $true)] + [string] + $Url, + + [Parameter(Mandatory = $false)] + [hashtable] + $ProxyConfiguration + ) + + (Get-Downloader $url @ProxyConfiguration).DownloadString($url) +} + +function Request-File { + <# + .SYNOPSIS + Downloads a file from a given URL. + + .DESCRIPTION + Downloads a target file from a URL to the specified local path. + Any existing proxy that may be in use will be utilised. + + .PARAMETER Url + URL of the file to download from the remote host. + + .PARAMETER File + Local path for the file to be downloaded to. + + .PARAMETER ProxyConfiguration + A hashtable containing proxy parameters (ProxyUrl and ProxyCredential) + + .EXAMPLE + Request-File -Url https://community.chocolatey.org/install.ps1 -File $targetFile + + Downloads the install.ps1 script to the path specified in $targetFile. + #> + [CmdletBinding()] + param( + [Parameter(Mandatory = $false)] + [string] + $Url, + + [Parameter(Mandatory = $false)] + [string] + $File, + + [Parameter(Mandatory = $false)] + [hashtable] + $ProxyConfiguration + ) + + Write-Host "Downloading $url to $file" + (Get-Downloader $url @ProxyConfiguration).DownloadFile($url, $file) +} + +function Set-PSConsoleWriter { + <# + .SYNOPSIS + Workaround for a bug in output stream handling PS v2 or v3. + + .DESCRIPTION + PowerShell v2/3 caches the output stream. Then it throws errors due to the + FileStream not being what is expected. Fixes "The OS handle's position is + not what FileStream expected. Do not use a handle simultaneously in one + FileStream and in Win32 code or another FileStream." error. + + .EXAMPLE + Set-PSConsoleWriter + + .NOTES + General notes + #> + + [CmdletBinding()] + param() + if ($PSVersionTable.PSVersion.Major -gt 3) { + return + } + + try { + # http://www.leeholmes.com/blog/2008/07/30/workaround-the-os-handles-position-is-not-what-filestream-expected/ plus comments + $bindingFlags = [Reflection.BindingFlags] "Instance,NonPublic,GetField" + $objectRef = $host.GetType().GetField("externalHostRef", $bindingFlags).GetValue($host) + + $bindingFlags = [Reflection.BindingFlags] "Instance,NonPublic,GetProperty" + $consoleHost = $objectRef.GetType().GetProperty("Value", $bindingFlags).GetValue($objectRef, @()) + [void] $consoleHost.GetType().GetProperty("IsStandardOutputRedirected", $bindingFlags).GetValue($consoleHost, @()) + + $bindingFlags = [Reflection.BindingFlags] "Instance,NonPublic,GetField" + $field = $consoleHost.GetType().GetField("standardOutputWriter", $bindingFlags) + $field.SetValue($consoleHost, [Console]::Out) + + [void] $consoleHost.GetType().GetProperty("IsStandardErrorRedirected", $bindingFlags).GetValue($consoleHost, @()) + $field2 = $consoleHost.GetType().GetField("standardErrorWriter", $bindingFlags) + $field2.SetValue($consoleHost, [Console]::Error) + } catch { + Write-Warning "Unable to apply redirection fix." + } +} + +function Test-ChocolateyInstalled { + [CmdletBinding()] + param() + + $checkPath = if ($env:ChocolateyInstall) { $env:ChocolateyInstall } else { "$env:PROGRAMDATA\chocolatey" } + + if ($Command = Get-Command choco -CommandType Application -ErrorAction Ignore) { + # choco is on the PATH, assume it's installed + Write-Warning "'choco' was found at '$($Command.Path)'." + $true + } + elseif (-not (Test-Path $checkPath)) { + # Install folder doesn't exist + $false + } + elseif (-not (Get-ChildItem -Path $checkPath)) { + # Install folder exists but is empty + $false + } + else { + # Install folder exists and is not empty + Write-Warning "Files from a previous installation of Chocolatey were found at '$($CheckPath)'." + $true + } +} + +function Install-7zip { + [CmdletBinding()] + param( + [Parameter(Mandatory = $true)] + [string] + $Path, + + [Parameter(Mandatory = $false)] + [hashtable] + $ProxyConfiguration + ) + + if (-not (Test-Path ($Path))) { + Write-Host "Downloading 7-Zip commandline tool prior to extraction." + Request-File -Url 'https://community.chocolatey.org/7za.exe' -File $Path -ProxyConfiguration $ProxyConfiguration + + } + else { + Write-Host "7zip already present, skipping installation." + } +} + +#endregion Functions + +#region Pre-check + +# Ensure we have all our streams setup correctly, needed for older PSVersions. +Set-PSConsoleWriter + +if (Test-ChocolateyInstalled) { + $message = @( + "An existing Chocolatey installation was detected. Installation will not continue." + "For security reasons, this script will not overwrite existing installations." + "" + "Please use `choco upgrade chocolatey` to handle upgrades of Chocolatey itself." + ) -join [Environment]::NewLine + + Write-Warning $message + + return +} + +#endregion Pre-check + +#region Setup + +$proxyConfig = if ($IgnoreProxy -or -not $ProxyUrl) { + @{} +} else { + $config = @{ + ProxyUrl = $ProxyUrl + } + + if ($ProxyCredential) { + $config['ProxyCredential'] = $ProxyCredential + } elseif ($env:chocolateyProxyUser -and $env:chocolateyProxyPassword) { + $securePass = ConvertTo-SecureString $env:chocolateyProxyPassword -AsPlainText -Force + $config['ProxyCredential'] = [System.Management.Automation.PSCredential]::new($env:chocolateyProxyUser, $securePass) + } + + $config +} + +# Attempt to set highest encryption available for SecurityProtocol. +# PowerShell will not set this by default (until maybe .NET 4.6.x). This +# will typically produce a message for PowerShell v2 (just an info +# message though) +try { + # Set TLS 1.2 (3072) as that is the minimum required by Chocolatey.org. + # Use integers because the enumeration value for TLS 1.2 won't exist + # in .NET 4.0, even though they are addressable if .NET 4.5+ is + # installed (.NET 4.5 is an in-place upgrade). + Write-Host "Forcing web requests to allow TLS v1.2 (Required for requests to Chocolatey.org)" + [System.Net.ServicePointManager]::SecurityProtocol = [System.Net.ServicePointManager]::SecurityProtocol -bor 3072 +} +catch { + $errorMessage = @( + 'Unable to set PowerShell to use TLS 1.2. This is required for contacting Chocolatey as of 03 FEB 2020.' + 'https://blog.chocolatey.org/2020/01/remove-support-for-old-tls-versions/.' + 'If you see underlying connection closed or trust errors, you may need to do one or more of the following:' + '(1) upgrade to .NET Framework 4.5+ and PowerShell v3+,' + '(2) Call [System.Net.ServicePointManager]::SecurityProtocol = 3072; in PowerShell prior to attempting installation,' + '(3) specify internal Chocolatey package location (set $env:chocolateyDownloadUrl prior to install or host the package internally),' + '(4) use the Download + PowerShell method of install.' + 'See https://docs.chocolatey.org/en-us/choco/setup for all install options.' + ) -join [Environment]::NewLine + Write-Warning $errorMessage +} + +if ($ChocolateyDownloadUrl) { + if ($ChocolateyVersion) { + Write-Warning "Ignoring -ChocolateyVersion parameter ($ChocolateyVersion) because -ChocolateyDownloadUrl is set." + } + + Write-Host "Downloading Chocolatey from: $ChocolateyDownloadUrl" +} elseif ($ChocolateyVersion) { + Write-Host "Downloading specific version of Chocolatey: $ChocolateyVersion" + $ChocolateyDownloadUrl = "https://community.chocolatey.org/api/v2/package/chocolatey/$ChocolateyVersion" +} else { + Write-Host "Getting latest version of the Chocolatey package for download." + $queryString = [uri]::EscapeUriString("((Id eq 'chocolatey') and (not IsPrerelease)) and IsLatestVersion") + $queryUrl = 'https://community.chocolatey.org/api/v2/Packages()?$filter={0}' -f $queryString + + [xml]$result = Request-String -Url $queryUrl -ProxyConfiguration $proxyConfig + $ChocolateyDownloadUrl = $result.feed.entry.content.src +} + +if (-not $env:TEMP) { + $env:TEMP = Join-Path $env:SystemDrive -ChildPath 'temp' +} + +$chocoTempDir = Join-Path $env:TEMP -ChildPath "chocolatey" +$tempDir = Join-Path $chocoTempDir -ChildPath "chocoInstall" + +if (-not (Test-Path $tempDir -PathType Container)) { + $null = New-Item -Path $tempDir -ItemType Directory +} + +$file = Join-Path $tempDir "chocolatey.zip" + +#endregion Setup + +#region Download & Extract Chocolatey + +Write-Host "Getting Chocolatey from $ChocolateyDownloadUrl." +Request-File -Url $ChocolateyDownloadUrl -File $file -ProxyConfiguration $proxyConfig + +Write-Host "Extracting $file to $tempDir" +if ($PSVersionTable.PSVersion.Major -lt 5) { + # Determine unzipping method + # 7zip is the most compatible pre-PSv5.1 so use it unless asked to use builtin + if ($UseNativeUnzip) { + Write-Host 'Using built-in compression to unzip' + + try { + $shellApplication = New-Object -ComObject Shell.Application + $zipPackage = $shellApplication.NameSpace($file) + $destinationFolder = $shellApplication.NameSpace($tempDir) + $destinationFolder.CopyHere($zipPackage.Items(), 0x10) + } catch { + Write-Warning "Unable to unzip package using built-in compression. Set `$env:chocolateyUseWindowsCompression = ''` or omit -UseNativeUnzip and retry to use 7zip to unzip." + throw $_ + } + } else { + $7zaExe = Join-Path $tempDir -ChildPath '7za.exe' + Install-7zip -Path $7zaExe -ProxyConfiguration $proxyConfig + + $params = 'x -o"{0}" -bd -y "{1}"' -f $tempDir, $file + + # use more robust Process as compared to Start-Process -Wait (which doesn't + # wait for the process to finish in PowerShell v3) + $process = New-Object System.Diagnostics.Process + + try { + $process.StartInfo = New-Object System.Diagnostics.ProcessStartInfo -ArgumentList $7zaExe, $params + $process.StartInfo.RedirectStandardOutput = $true + $process.StartInfo.UseShellExecute = $false + $process.StartInfo.WindowStyle = [System.Diagnostics.ProcessWindowStyle]::Hidden + + $null = $process.Start() + $process.BeginOutputReadLine() + $process.WaitForExit() + + $exitCode = $process.ExitCode + } + finally { + $process.Dispose() + } + + $errorMessage = "Unable to unzip package using 7zip. Perhaps try setting `$env:chocolateyUseWindowsCompression = 'true' and call install again. Error:" + if ($exitCode -ne 0) { + $errorDetails = switch ($exitCode) { + 1 { "Some files could not be extracted" } + 2 { "7-Zip encountered a fatal error while extracting the files" } + 7 { "7-Zip command line error" } + 8 { "7-Zip out of memory" } + 255 { "Extraction cancelled by the user" } + default { "7-Zip signalled an unknown error (code $exitCode)" } + } + + throw ($errorMessage, $errorDetails -join [Environment]::NewLine) + } + } +} else { + Microsoft.PowerShell.Archive\Expand-Archive -Path $file -DestinationPath $tempDir -Force +} + +#endregion Download & Extract Chocolatey + +#region Install Chocolatey + +Write-Host "Installing Chocolatey on the local machine" +$toolsFolder = Join-Path $tempDir -ChildPath "tools" +$chocoInstallPS1 = Join-Path $toolsFolder -ChildPath "chocolateyInstall.ps1" + +& $chocoInstallPS1 + +Write-Host 'Ensuring Chocolatey commands are on the path' +$chocoInstallVariableName = "ChocolateyInstall" +$chocoPath = [Environment]::GetEnvironmentVariable($chocoInstallVariableName) + +if (-not $chocoPath) { + $chocoPath = "$env:ALLUSERSPROFILE\Chocolatey" +} + +if (-not (Test-Path ($chocoPath))) { + $chocoPath = "$env:PROGRAMDATA\chocolatey" +} + +$chocoExePath = Join-Path $chocoPath -ChildPath 'bin' + +# Update current process PATH environment variable if it needs updating. +if ($env:Path -notlike "*$chocoExePath*") { + $env:Path = [Environment]::GetEnvironmentVariable('Path', [System.EnvironmentVariableTarget]::Machine); +} + +Write-Host 'Ensuring chocolatey.nupkg is in the lib folder' +$chocoPkgDir = Join-Path $chocoPath -ChildPath 'lib\chocolatey' +$nupkg = Join-Path $chocoPkgDir -ChildPath 'chocolatey.nupkg' + +if (-not (Test-Path $chocoPkgDir -PathType Container)) { + $null = New-Item -ItemType Directory -Path $chocoPkgDir +} + +Copy-Item -Path $file -Destination $nupkg -Force -ErrorAction SilentlyContinue + +#endregion Install Chocolatey + +# SIG # Begin signature block +# MIIZvwYJKoZIhvcNAQcCoIIZsDCCGawCAQExDzANBglghkgBZQMEAgEFADB5Bgor +# BgEEAYI3AgEEoGswaTA0BgorBgEEAYI3AgEeMCYCAwEAAAQQH8w7YFlLCE63JNLG +# KX7zUQIBAAIBAAIBAAIBAAIBADAxMA0GCWCGSAFlAwQCAQUABCBiXTlbpVQOoJeX +# rGtqATyaDXeEHi6Q2pKb3p02Iq/tc6CCFKgwggT+MIID5qADAgECAhANQkrgvjqI +# /2BAIc4UAPDdMA0GCSqGSIb3DQEBCwUAMHIxCzAJBgNVBAYTAlVTMRUwEwYDVQQK +# EwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20xMTAvBgNV +# BAMTKERpZ2lDZXJ0IFNIQTIgQXNzdXJlZCBJRCBUaW1lc3RhbXBpbmcgQ0EwHhcN +# MjEwMTAxMDAwMDAwWhcNMzEwMTA2MDAwMDAwWjBIMQswCQYDVQQGEwJVUzEXMBUG +# A1UEChMORGlnaUNlcnQsIEluYy4xIDAeBgNVBAMTF0RpZ2lDZXJ0IFRpbWVzdGFt +# cCAyMDIxMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAwuZhhGfFivUN +# CKRFymNrUdc6EUK9CnV1TZS0DFC1JhD+HchvkWsMlucaXEjvROW/m2HNFZFiWrj/ +# ZwucY/02aoH6KfjdK3CF3gIY83htvH35x20JPb5qdofpir34hF0edsnkxnZ2OlPR +# 0dNaNo/Go+EvGzq3YdZz7E5tM4p8XUUtS7FQ5kE6N1aG3JMjjfdQJehk5t3Tjy9X +# tYcg6w6OLNUj2vRNeEbjA4MxKUpcDDGKSoyIxfcwWvkUrxVfbENJCf0mI1P2jWPo +# GqtbsR0wwptpgrTb/FZUvB+hh6u+elsKIC9LCcmVp42y+tZji06lchzun3oBc/gZ +# 1v4NSYS9AQIDAQABo4IBuDCCAbQwDgYDVR0PAQH/BAQDAgeAMAwGA1UdEwEB/wQC +# MAAwFgYDVR0lAQH/BAwwCgYIKwYBBQUHAwgwQQYDVR0gBDowODA2BglghkgBhv1s +# BwEwKTAnBggrBgEFBQcCARYbaHR0cDovL3d3dy5kaWdpY2VydC5jb20vQ1BTMB8G +# A1UdIwQYMBaAFPS24SAd/imu0uRhpbKiJbLIFzVuMB0GA1UdDgQWBBQ2RIaOpLqw +# Zr68KC0dRDbd42p6vDBxBgNVHR8EajBoMDKgMKAuhixodHRwOi8vY3JsMy5kaWdp +# Y2VydC5jb20vc2hhMi1hc3N1cmVkLXRzLmNybDAyoDCgLoYsaHR0cDovL2NybDQu +# ZGlnaWNlcnQuY29tL3NoYTItYXNzdXJlZC10cy5jcmwwgYUGCCsGAQUFBwEBBHkw +# dzAkBggrBgEFBQcwAYYYaHR0cDovL29jc3AuZGlnaWNlcnQuY29tME8GCCsGAQUF +# BzAChkNodHRwOi8vY2FjZXJ0cy5kaWdpY2VydC5jb20vRGlnaUNlcnRTSEEyQXNz +# dXJlZElEVGltZXN0YW1waW5nQ0EuY3J0MA0GCSqGSIb3DQEBCwUAA4IBAQBIHNy1 +# 6ZojvOca5yAOjmdG/UJyUXQKI0ejq5LSJcRwWb4UoOUngaVNFBUZB3nw0QTDhtk7 +# vf5EAmZN7WmkD/a4cM9i6PVRSnh5Nnont/PnUp+Tp+1DnnvntN1BIon7h6JGA078 +# 9P63ZHdjXyNSaYOC+hpT7ZDMjaEXcw3082U5cEvznNZ6e9oMvD0y0BvL9WH8dQgA +# dryBDvjA4VzPxBFy5xtkSdgimnUVQvUtMjiB2vRgorq0Uvtc4GEkJU+y38kpqHND +# Udq9Y9YfW5v3LhtPEx33Sg1xfpe39D+E68Hjo0mh+s6nv1bPull2YYlffqe0jmd4 +# +TaY4cso2luHpoovMIIFMDCCBBigAwIBAgIQBAkYG1/Vu2Z1U0O1b5VQCDANBgkq +# hkiG9w0BAQsFADBlMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5j +# MRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBB +# c3N1cmVkIElEIFJvb3QgQ0EwHhcNMTMxMDIyMTIwMDAwWhcNMjgxMDIyMTIwMDAw +# WjByMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQL +# ExB3d3cuZGlnaWNlcnQuY29tMTEwLwYDVQQDEyhEaWdpQ2VydCBTSEEyIEFzc3Vy +# ZWQgSUQgQ29kZSBTaWduaW5nIENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB +# CgKCAQEA+NOzHH8OEa9ndwfTCzFJGc/Q+0WZsTrbRPV/5aid2zLXcep2nQUut4/6 +# kkPApfmJ1DcZ17aq8JyGpdglrA55KDp+6dFn08b7KSfH03sjlOSRI5aQd4L5oYQj +# ZhJUM1B0sSgmuyRpwsJS8hRniolF1C2ho+mILCCVrhxKhwjfDPXiTWAYvqrEsq5w +# MWYzcT6scKKrzn/pfMuSoeU7MRzP6vIK5Fe7SrXpdOYr/mzLfnQ5Ng2Q7+S1TqSp +# 6moKq4TzrGdOtcT3jNEgJSPrCGQ+UpbB8g8S9MWOD8Gi6CxR93O8vYWxYoNzQYIH +# 5DiLanMg0A9kczyen6Yzqf0Z3yWT0QIDAQABo4IBzTCCAckwEgYDVR0TAQH/BAgw +# BgEB/wIBADAOBgNVHQ8BAf8EBAMCAYYwEwYDVR0lBAwwCgYIKwYBBQUHAwMweQYI +# KwYBBQUHAQEEbTBrMCQGCCsGAQUFBzABhhhodHRwOi8vb2NzcC5kaWdpY2VydC5j +# b20wQwYIKwYBBQUHMAKGN2h0dHA6Ly9jYWNlcnRzLmRpZ2ljZXJ0LmNvbS9EaWdp +# Q2VydEFzc3VyZWRJRFJvb3RDQS5jcnQwgYEGA1UdHwR6MHgwOqA4oDaGNGh0dHA6 +# Ly9jcmw0LmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydEFzc3VyZWRJRFJvb3RDQS5jcmww +# OqA4oDaGNGh0dHA6Ly9jcmwzLmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydEFzc3VyZWRJ +# RFJvb3RDQS5jcmwwTwYDVR0gBEgwRjA4BgpghkgBhv1sAAIEMCowKAYIKwYBBQUH +# AgEWHGh0dHBzOi8vd3d3LmRpZ2ljZXJ0LmNvbS9DUFMwCgYIYIZIAYb9bAMwHQYD +# VR0OBBYEFFrEuXsqCqOl6nEDwGD5LfZldQ5YMB8GA1UdIwQYMBaAFEXroq/0ksuC +# MS1Ri6enIZ3zbcgPMA0GCSqGSIb3DQEBCwUAA4IBAQA+7A1aJLPzItEVyCx8JSl2 +# qB1dHC06GsTvMGHXfgtg/cM9D8Svi/3vKt8gVTew4fbRknUPUbRupY5a4l4kgU4Q +# pO4/cY5jDhNLrddfRHnzNhQGivecRk5c/5CxGwcOkRX7uq+1UcKNJK4kxscnKqEp +# KBo6cSgCPC6Ro8AlEeKcFEehemhor5unXCBc2XGxDI+7qPjFEmifz0DLQESlE/Dm +# ZAwlCEIysjaKJAL+L3J+HNdJRZboWR3p+nRka7LrZkPas7CM1ekN3fYBIM6ZMWM9 +# CBoYs4GbT8aTEAb8B4H6i9r5gkn3Ym6hU/oSlBiFLpKR6mhsRDKyZqHnGKSaZFHv +# MIIFMTCCBBmgAwIBAgIQCqEl1tYyG35B5AXaNpfCFTANBgkqhkiG9w0BAQsFADBl +# MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 +# d3cuZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJv +# b3QgQ0EwHhcNMTYwMTA3MTIwMDAwWhcNMzEwMTA3MTIwMDAwWjByMQswCQYDVQQG +# EwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNl +# cnQuY29tMTEwLwYDVQQDEyhEaWdpQ2VydCBTSEEyIEFzc3VyZWQgSUQgVGltZXN0 +# YW1waW5nIENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAvdAy7kvN +# j3/dqbqCmcU5VChXtiNKxA4HRTNREH3Q+X1NaH7ntqD0jbOI5Je/YyGQmL8TvFfT +# w+F+CNZqFAA49y4eO+7MpvYyWf5fZT/gm+vjRkcGGlV+Cyd+wKL1oODeIj8O/36V +# +/OjuiI+GKwR5PCZA207hXwJ0+5dyJoLVOOoCXFr4M8iEA91z3FyTgqt30A6XLdR +# 4aF5FMZNJCMwXbzsPGBqrC8HzP3w6kfZiFBe/WZuVmEnKYmEUeaC50ZQ/ZQqLKfk +# dT66mA+Ef58xFNat1fJky3seBdCEGXIX8RcG7z3N1k3vBkL9olMqT4UdxB08r8/a +# rBD13ays6Vb/kwIDAQABo4IBzjCCAcowHQYDVR0OBBYEFPS24SAd/imu0uRhpbKi +# JbLIFzVuMB8GA1UdIwQYMBaAFEXroq/0ksuCMS1Ri6enIZ3zbcgPMBIGA1UdEwEB +# /wQIMAYBAf8CAQAwDgYDVR0PAQH/BAQDAgGGMBMGA1UdJQQMMAoGCCsGAQUFBwMI +# MHkGCCsGAQUFBwEBBG0wazAkBggrBgEFBQcwAYYYaHR0cDovL29jc3AuZGlnaWNl +# cnQuY29tMEMGCCsGAQUFBzAChjdodHRwOi8vY2FjZXJ0cy5kaWdpY2VydC5jb20v +# RGlnaUNlcnRBc3N1cmVkSURSb290Q0EuY3J0MIGBBgNVHR8EejB4MDqgOKA2hjRo +# dHRwOi8vY3JsNC5kaWdpY2VydC5jb20vRGlnaUNlcnRBc3N1cmVkSURSb290Q0Eu +# Y3JsMDqgOKA2hjRodHRwOi8vY3JsMy5kaWdpY2VydC5jb20vRGlnaUNlcnRBc3N1 +# cmVkSURSb290Q0EuY3JsMFAGA1UdIARJMEcwOAYKYIZIAYb9bAACBDAqMCgGCCsG +# AQUFBwIBFhxodHRwczovL3d3dy5kaWdpY2VydC5jb20vQ1BTMAsGCWCGSAGG/WwH +# ATANBgkqhkiG9w0BAQsFAAOCAQEAcZUS6VGHVmnN793afKpjerN4zwY3QITvS4S/ +# ys8DAv3Fp8MOIEIsr3fzKx8MIVoqtwU0HWqumfgnoma/Capg33akOpMP+LLR2HwZ +# YuhegiUexLoceywh4tZbLBQ1QwRostt1AuByx5jWPGTlH0gQGF+JOGFNYkYkh2OM +# kVIsrymJ5Xgf1gsUpYDXEkdws3XVk4WTfraSZ/tTYYmo9WuWwPRYaQ18yAGxuSh1 +# t5ljhSKMYcp5lH5Z/IwP42+1ASa2bKXuh1Eh5Fhgm7oMLSttosR+u8QlK0cCCHxJ +# rhO24XxCQijGGFbPQTS2Zl22dHv1VjMiLyI2skuiSpXY9aaOUjCCBTkwggQhoAMC +# AQICEAq50xD7ISvojIGz0sLozlEwDQYJKoZIhvcNAQELBQAwcjELMAkGA1UEBhMC +# VVMxFTATBgNVBAoTDERpZ2lDZXJ0IEluYzEZMBcGA1UECxMQd3d3LmRpZ2ljZXJ0 +# LmNvbTExMC8GA1UEAxMoRGlnaUNlcnQgU0hBMiBBc3N1cmVkIElEIENvZGUgU2ln +# bmluZyBDQTAeFw0yMTA0MjcwMDAwMDBaFw0yNDA0MzAyMzU5NTlaMHcxCzAJBgNV +# BAYTAlVTMQ8wDQYDVQQIEwZLYW5zYXMxDzANBgNVBAcTBlRvcGVrYTEiMCAGA1UE +# ChMZQ2hvY29sYXRleSBTb2Z0d2FyZSwgSW5jLjEiMCAGA1UEAxMZQ2hvY29sYXRl +# eSBTb2Z0d2FyZSwgSW5jLjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB +# AKFxp42p47c7eHNsNhgxzG+/9A1I8Th+kj40YQJH4Vh0M7a61f39I/FELNYGuyCe +# 0+z/sg+T+4VmT/JMiI2hc75yokTjkv3Yt1+fqABzCMadr+PZ/9ttIVJ5db3P2Uzc +# Ml5wXBdCV5ZH/w4oKcP53VmYcHQEDm/RtAJ9TxlPtLS734oAqrKqBmsnJCI98FWp +# d6z1FK5rv7RJVeZoGsl/2eMcB/ko0Vj9MSCbWvXNjDF9yy4Tl5h2vb+y7K1Qmk3X +# yb0OYB1ibva9rQozGgogEa5DL0OdoMj6cyJ6Cx2GQv2wjKwiKfs9zCOTDH2VGa0i +# okDbsd+BvUxovQ6eSnBFj5UCAwEAAaOCAcQwggHAMB8GA1UdIwQYMBaAFFrEuXsq +# CqOl6nEDwGD5LfZldQ5YMB0GA1UdDgQWBBRO8wUYXZXrKVBqUW35p9FeNJoEgzAO +# BgNVHQ8BAf8EBAMCB4AwEwYDVR0lBAwwCgYIKwYBBQUHAwMwdwYDVR0fBHAwbjA1 +# oDOgMYYvaHR0cDovL2NybDMuZGlnaWNlcnQuY29tL3NoYTItYXNzdXJlZC1jcy1n +# MS5jcmwwNaAzoDGGL2h0dHA6Ly9jcmw0LmRpZ2ljZXJ0LmNvbS9zaGEyLWFzc3Vy +# ZWQtY3MtZzEuY3JsMEsGA1UdIAREMEIwNgYJYIZIAYb9bAMBMCkwJwYIKwYBBQUH +# AgEWG2h0dHA6Ly93d3cuZGlnaWNlcnQuY29tL0NQUzAIBgZngQwBBAEwgYQGCCsG +# AQUFBwEBBHgwdjAkBggrBgEFBQcwAYYYaHR0cDovL29jc3AuZGlnaWNlcnQuY29t +# ME4GCCsGAQUFBzAChkJodHRwOi8vY2FjZXJ0cy5kaWdpY2VydC5jb20vRGlnaUNl +# cnRTSEEyQXNzdXJlZElEQ29kZVNpZ25pbmdDQS5jcnQwDAYDVR0TAQH/BAIwADAN +# BgkqhkiG9w0BAQsFAAOCAQEAoXGdwcDMMV6xQldozbWoxGTn6chlwO4hJ8aAlwOM +# wexEvDudrlifsiGI1j46wqc9WR8+Ev8w1dIcbqif4inGIHb8GvL22Goq+lB08F7y +# YU3Ry0kOCtJx7JELlID0SI7bYndg17TJUQoAb5iTYD9aEoHMIKlGyQyVGvsp4ubo +# O8CC8Owx+Qq148yXY+to4360U2lzZvUtMpPiiSJTm4BamNgC32xgGwpN5lvk0m3R +# lDdqQQQgBCzrf+ZIMBmXMw4kxY0r/K/g1TkKI9VyiEnRaNQlQisAyYBWVnaHw2EJ +# ck6/bxwdYSA+Sz/Op0N0iEl8MX4At3XQlMGvAI1xhAbrwDGCBG0wggRpAgEBMIGG +# MHIxCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsT +# EHd3dy5kaWdpY2VydC5jb20xMTAvBgNVBAMTKERpZ2lDZXJ0IFNIQTIgQXNzdXJl +# ZCBJRCBDb2RlIFNpZ25pbmcgQ0ECEAq50xD7ISvojIGz0sLozlEwDQYJYIZIAWUD +# BAIBBQCggYQwGAYKKwYBBAGCNwIBDDEKMAigAoAAoQKAADAZBgkqhkiG9w0BCQMx +# DAYKKwYBBAGCNwIBBDAcBgorBgEEAYI3AgELMQ4wDAYKKwYBBAGCNwIBFTAvBgkq +# hkiG9w0BCQQxIgQgey25OsHafMX1HWLKRJb0Sf/lMMX5vF0EAhjyQlfUDzgwDQYJ +# KoZIhvcNAQEBBQAEggEAC0wtyHWaoYbiMY8PXKaNf16zoeuj5jYAuvx0B/nzJ27A +# tP/Mo9SC1Z4M2iEps/LDScRoy3N8pCI8NQBDjWGGkjW5ScFvF7a042DcurR+LE30 +# aa4d7Y0MT8O+vhQDcVCmB7JB+9E6/7+qpD1vVfs1zYw1cprCZoOejttDCEvlvsAN +# VrPKixhxbLcLu/5KV9qUBUWW9vEz8/WL1IcNcsfwd61+JWa116CXeyoLKqWXJIPF +# uNnULZTs/E2BY1JYBKIfzvSi3QWg/uWvJucdGdbLib4d1gEXxLtHk+aDOLTXRG12 +# yjMdCF1FhyeC+hyWSgwyXZ0V9zRGpiS+IjarelHVDqGCAjAwggIsBgkqhkiG9w0B +# CQYxggIdMIICGQIBATCBhjByMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNl +# cnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMTEwLwYDVQQDEyhEaWdp +# Q2VydCBTSEEyIEFzc3VyZWQgSUQgVGltZXN0YW1waW5nIENBAhANQkrgvjqI/2BA +# Ic4UAPDdMA0GCWCGSAFlAwQCAQUAoGkwGAYJKoZIhvcNAQkDMQsGCSqGSIb3DQEH +# ATAcBgkqhkiG9w0BCQUxDxcNMjEwNjE3MDg0MjQzWjAvBgkqhkiG9w0BCQQxIgQg +# Osdf/2XOopSIGgniCq9vRS6UGDVJ7TingAmrcmwYcWowDQYJKoZIhvcNAQEBBQAE +# ggEAs50N1tQOpzvCCO9R4hCcaMY0jsOm7QOOk257yySmEFbtgmKUpNmyyfwK0Wl/ +# Ti1IOTOQ1oz7Wz6Q/kEgPoZAbuAhXKH+At6Vwa98Jp3GG6abokNohPI3cWGJbS3u +# rJEKZay3+1fGNaYOCpIqkhpnVqyTNoLlNBLcGOkq7FgBKsomtQSO9ejFluS1woKY +# wK7EiXjzDwFG18DmnUuRpO4xrdmcbh7m3MnC95DjYcFFzKr/xxideicJAGZSHOo1 +# nQorVQyPcXQe4Nl2JHAr3R6RTeaXgq6We4LSdMsO5BAyduh/w4nicahwAv5wgIsw +# cUvCYQiMMXCU2x9vsn8B5wKETQ== +# SIG # End signature block