Public/BuildkitTools.psm1

###########################################################################
# #
# Copyright (c) Microsoft Corporation. All rights reserved. #
# #
# This code is licensed under the MIT License (MIT). #
# #
###########################################################################


using module "..\Private\CommonToolUtilities.psm1"

$ModuleParentPath = Split-Path -Parent $PSScriptRoot
Import-Module -Name "$ModuleParentPath\Private\CommonToolUtilities.psm1" -Force

function Get-BuildkitLatestVersion {
    $latestVersion = Get-LatestToolVersion -Tool "buildkit"
    return $latestVersion
}

function Install-Buildkit {
    [CmdletBinding(
        DefaultParameterSetName = 'Install',
        SupportsShouldProcess = $true,
        ConfirmImpact = 'High'
    )]
    param (
        [Parameter(ParameterSetName = 'Install')]
        [Parameter(ParameterSetName = 'Setup')]
        [parameter(HelpMessage = "Buildkit version to use. Defaults to 'latest'")]
        [string]$Version = "latest",

        [Parameter(ParameterSetName = 'Install')]
        [Parameter(ParameterSetName = 'Setup')]
        [parameter(HelpMessage = "Path to install buildkit. Defaults to ~\program files\buildkit")]
        [string]$InstallPath = "$Env:ProgramFiles\Buildkit",

        [Parameter(ParameterSetName = 'Install')]
        [Parameter(ParameterSetName = 'Setup')]
        [parameter(HelpMessage = "Path to download files. Defaults to user's Downloads folder")]
        [string]$DownloadPath = "$HOME\Downloads",

        [Parameter(ParameterSetName = 'Setup')]
        [switch]$Setup,

        [Parameter(ParameterSetName = 'Setup')]
        [string]$WinCNIPath,

        [Parameter(HelpMessage = 'OS architecture to download files for. Default is $env:PROCESSOR_ARCHITECTURE')]
        [ValidateSet('amd64', '386', "arm", "arm64")]
        [string]$OSArchitecture = $env:PROCESSOR_ARCHITECTURE,

        [Parameter(ParameterSetName = 'Install')]
        [Parameter(ParameterSetName = 'Setup')]
        [parameter(HelpMessage = "Installs Buildkit even if the tool already exists at the specified path")]
        [Switch]$Force
    )

    begin {
        # Check if Buildkit is alread installed
        $isInstalled = -not (Test-EmptyDirectory -Path $InstallPath)

        $WhatIfMessage = "Buildkit will be installed at $InstallPath"
        if ($isInstalled) {
            $WhatIfMessage = "Buildkit will be uninstalled from and reinstalled at $InstallPath"
        }
        if ($Setup) {
            <# Action when this condition is true #>
            $WhatIfMessage = "Buildkit will be installed at $InstallPath and buildkitd service will be registered and started"
        }
    }

    process {
        if ($PSCmdlet.ShouldProcess($env:COMPUTERNAME, $WhatIfMessage)) {
            # Check if tool already exists at specified location
            if ($isInstalled) {
                $errMsg = "Buildkit already exists at $InstallPath or the directory is not empty"
                Write-Warning $errMsg

                # Uninstall if tool exists at specified location. Requires user consent
                try {
                    Uninstall-Buildkit -Path "$InstallPath" -Force:$Force -Confirm:$false | Out-Null
                }
                catch {
                    Throw "Buildkit installation failed. $_"
                }
            }

            # Get Buildkit version to install
            if (!$Version) {
                $Version = Get-BuildkitLatestVersion
            }
            $Version = $Version.TrimStart('v')

            Write-Output "Downloading and installing Buildkit v$Version at $InstallPath"

            # Download files
            $downloadParams = @{
                ToolName = "Buildkit"
                Repository = "$BUILDKIT_REPO"
                Version = $Version
                OSArchitecture = $OSArchitecture
                DownloadPath = $DownloadPath
                ChecksumSchemaFile = "$ModuleParentPath\Private\schemas\in-toto.sbom.schema.json"
                FileFilterRegEx = $null
            }
            $downloadParamsProperties = [FileDownloadParameters]::new(
                $downloadParams.ToolName,
                $downloadParams.Repository,
                $downloadParams.Version,
                $downloadParams.OSArchitecture,
                $downloadParams.DownloadPath,
                $downloadParams.ChecksumSchemaFile,
                $downloadParams.FileFilterRegEx
            )
            $sourceFile = Get-InstallationFile -FileParameters $downloadParamsProperties

            # Untar downloaded file at install path
            $params = @{
                Feature     = "Buildkit"
                InstallPath = $InstallPath
                SourceFile  = "$sourceFile"
                EnvPath     = "$InstallPath\bin"
                cleanup     = $true
            }
            Install-RequiredFeature @params

            Write-Output "Successfully installed Buildkit v$Version at $InstallPath`n"

            # Register Buildkitd service
            $showCommands = $true
            try {
                if ($Setup) {
                    Register-BuildkitdService -BuildKitPath $InstallPath -WinCNIPath $WinCNIPath -Start -Force:$true
                    $showCommands = $false
                }
            }
            catch {
                Write-Warning "Failed to registed and start Buildkitd service. $_"
            }

            if ($showCommands) {
                $commands = (Get-command -Name '*buildkit*' | Where-Object { $_.Source -like 'Containers-Toolkit' -and $_.Name -ne 'Install-Buildkit' }).Name
                $message = "Other useful Buildkit commands: $($commands -join ', ').`nTo learn more about each command, run Get-Help <command-name>, e.g., 'Get-Help `"*buildkit*`"' or 'Get-Help Register-BuildkitdService'`n"
                Write-Information -MessageData $message -Tags "Instructions" -InformationAction Continue
            }

            # Show buildkit binaries help
            Get-ChildItem -Path "C:\Program Files\buildkit\bin" | ForEach-Object {
                $executable = $_.Name
                # Remove extension from executable
                $commandName = $executable -replace ".exe", ""
                $message = "For $commandName usage: run `"$executable -h`""
                Write-Information -MessageData "$message`n" -Tags "Instructions" -InformationAction Continue
            }
        }
        else {
            # Code that should be processed if doing a WhatIf operation
            # Must NOT change anything outside of the function / script
            return
        }
    }
}

# YAGNI: Is this necessary?
function Build-BuildkitFromSource {
    Throw "Method or operation not implemented."
}

function Start-BuildkitdService {
    [CmdletBinding(
        SupportsShouldProcess = $true
    )]
    param()

    process {
        if ($PSCmdlet.ShouldProcess($env:COMPUTERNAME, "Buildkitd service will be started")) {
            Invoke-ServiceAction -Service 'Buildkitd' -Action 'Start'
        }
        else {
            # Code that should be processed if doing a WhatIf operation
            # Must NOT change anything outside of the function / script
            return
        }
    }
}

function Stop-BuildkitdService {
    [CmdletBinding(
        SupportsShouldProcess = $true
    )]
    param()

    process {
        if ($PSCmdlet.ShouldProcess($env:COMPUTERNAME, "Buildkitd service will be stopped")) {
            Invoke-ServiceAction -Service 'Buildkitd' -Action 'Stop'
        }
        else {
            # Code that should be processed if doing a WhatIf operation
            # Must NOT change anything outside of the function / script
            return
        }
    }
}

function Register-BuildkitdService {
    [CmdletBinding(
        SupportsShouldProcess = $true
    )]
    param(
        [parameter(HelpMessage = "Windows CNI plugin path")]
        [String]$WinCNIPath,

        [parameter(HelpMessage = "Buildkit path")]
        [String]$BuildKitPath,

        [parameter(HelpMessage = "Specify to start Buildkitd service after registration is complete")]
        [Switch]$Start,

        [parameter(HelpMessage = "Bypass confirmation to register buildkitd service")]
        [Switch]$Force
    )

    begin {
        if (!$BuildKitPath) {
            $BuildKitPath = Get-DefaultInstallPath -Tool "Buildkit"
        }

        $WhatIfMessage = 'Registers buildkitd service.'
        if ($Start) {
            $WhatIfMessage = "Registers and starts buildkitd service."
        }
    }

    process {
        if ($PSCmdlet.ShouldProcess($env:COMPUTERNAME, $WhatIfMessage)) {
            if (Test-EmptyDirectory -Path $BuildKitPath) {
                Throw "Buildkit does not exist at $BuildKitPath or the directory is empty"
            }

            # If buildkitd is not installed, terminate execution
            if (!(Test-BuildkitdServiceExists -BuildkitPath $BuildkitPath)) {
                Write-Error "Buildkitd executable not installed."
                return
            }

            # Check buildkitd service is already registered
            if (Test-ServiceRegistered -Service 'Buildkitd') {
                Write-Warning ( -join @("buildkitd service already registered. To re-register the service, "
                        "stop the service by running 'Stop-Service buildkitd' or 'Stop-BuildkitdService', then "
                        "run 'buildkitd --unregister-service'. Wait for buildkitd service to be deregistered, "
                        "then re-reun this command."))
                return
            }

            if (!$force) {
                if (!$ENV:PESTER) {
                    if (-not ($PSCmdlet.ShouldContinue('', "Are you sure you want to register buildkitd service?"))) {
                        Write-Error "buildkitd service registration cancelled."
                        return
                    }
                }
            }

            Write-Output "Configuring buildkitd service"

            $buildkitdExecutable = "$BuildKitPath\bin\buildkitd.exe"
            Add-MpPreference -ExclusionProcess $buildkitdExecutable

            if (!$WinCNIPath) {
                $containerdPath = Get-DefaultInstallPath -Tool "containerd"
                $WinCNIPath = "$containerdPath\cni"
            }

            $cniBinDir = "$WinCNIPath\bin"
            $cniConfPath = "$WinCNIPath\conf\0-containerd-nat.conf"

            # Register buildkit service
            $command = "buildkitd.exe --register-service --debug --containerd-worker=true --containerd-cni-config-path=`"$cniConfPath`" --containerd-cni-binary-dir=`"$cniBinDir`" --service-name buildkitd"
            if (Test-ConfFileEmpty -Path $cniConfPath) {

                $consent = $force
                if (!$force) {
                    $consent = [ActionConsent](Get-ConsentToRegisterBuildkit -Path $cniConfPath) -eq [ActionConsent]::Yes
                }

                if ($consent) {
                    Write-Warning "Containerd conf file not found at $cniConfPath. Buildkit service will be registered without Containerd cni configurations."
                    $command = "buildkitd.exe --register-service --debug --containerd-worker=true --service-name buildkitd"
                }
                else {
                    Write-Error "Failed to register buildkit service. Containerd conf file not found at $cniConfPath.`n`t1. Ensure that the required CNI plugins are installed or you can install them using 'Install-WinCNIPlugin'.`n`t2. Create the file to resolve this issue .`n`t3. Rerun this command 'Register-BuildkitdService'"
                    Throw "Failed to register buildkit service. Containerd conf file not found at $cniConfPath."
                }
            }

            $arguments = ($command -split " " | Select-Object -Skip 1) -join " "
            $output = Invoke-ExecutableCommand -Executable $buildkitdExecutable -Arguments $arguments
            if ($output.ExitCode -ne 0) {
                Throw "Failed to register buildkitd service. $($output.StandardError.ReadToEnd())"
            }

            $buildkitdService = Get-Service buildkitd -ErrorAction SilentlyContinue
            if ($null -eq $buildkitdService ) {
                Throw "Failed to register buildkitd service. $($Error[0].Exception.Message)"
            }

            Set-Service buildkitd -StartupType Automatic
            Write-Output "Successfully registered Buildkitd service."

            $output = Invoke-ExecutableCommand -Executable 'sc.exe' -arguments 'config buildkitd depend=containerd'
            if ($output.ExitCode -ne 0) {
                Write-Error "Failed to set dependency for buildkitd on containerd. $($output.StandardOutput.ReadToEnd())"
            }

            if ($Start) {
                Start-BuildkitdService
                Write-Output "Successfully started Buildkitd service."
            }
            else {
                Write-Information -InformationAction Continue -MessageData "To start buildkitd service, run 'Start-Service buildkitd' or 'Start-BuildkitdService'"
            }

            Write-Debug $(Get-Service 'buildkitd' -ErrorAction SilentlyContinue | Format-Table -AutoSize | Out-String)

            # YAGNI: Do we need a buildkitd.toml on Windows?
        }
        else {
            # Code that should be processed if doing a WhatIf operation
            # Must NOT change anything outside of the function / script
            return
        }
    }
}

function Uninstall-Buildkit {
    [CmdletBinding(
        SupportsShouldProcess = $true,
        ConfirmImpact = 'High'
    )]
    param(
        [parameter(HelpMessage = "BuildKit path")]
        [String]$Path,

        [parameter(HelpMessage = "Bypass confirmation to uninstall BuildKit")]
        [Switch] $Force
    )

    begin {
        $tool = 'Buildkit'
        if (!$Path) {
            $Path = Get-DefaultInstallPath -Tool $tool
        }

        $WhatIfMessage = "Buildkit will be uninstalled from $path and buildkitd service will be stopped and unregistered"
    }

    process {
        if ($PSCmdlet.ShouldProcess($env:COMPUTERNAME, $WhatIfMessage)) {
            if (Test-EmptyDirectory -Path $path) {
                Write-Output "$tool does not exist at $Path or the directory is empty"
                return
            }

            $consent = $force
            if (!$ENV:PESTER) {
                $consent = $force -or $PSCmdlet.ShouldContinue($env:COMPUTERNAME, "Are you sure you want to uninstall Buildkit from $path?")
            }

            if (!$consent) {
                Throw "$tool uninstallation cancelled."
            }

            Write-Warning "Uninstalling preinstalled $tool at the path $path"
            try {
                Uninstall-BuildkitHelper -Path $path
            }
            catch {
                Throw "Could not uninstall $tool. $_"
            }
        }
        else {
            # Code that should be processed if doing a WhatIf operation
            # Must NOT change anything outside of the function / script
            return
        }
    }
}

function Uninstall-BuildkitHelper {
    param(
        [parameter(Mandatory = $true, HelpMessage = "Buildkit path")]
        [String]$Path
    )

    if (Test-EmptyDirectory -Path $Path) {
        Write-Error "Buildkit does not exist at $Path or the directory is empty."
        return
    }

    try {
        if (Test-ServiceRegistered -Service 'Buildkitd') {
            Stop-BuildkitdService
            Unregister-Buildkitd -BuildkitPath $Path
        }
    }
    catch {
        Throw "Could not stop or unregister buildkitd service. $_"
    }

    # Delete the buildkit key
    Remove-Item -Path "HKLM:\SYSTEM\CurrentControlSet\Services\buildkit" -Recurse -Force -ErrorAction Ignore

    # Remove the folder where buildkit is installed and related folders
    Remove-Item -Path $Path -Recurse -Force

    # Delete Buildkit programdata
    Uninstall-ProgramFiles "$ENV:ProgramData\Buildkit"

    # Remove from env path
    Remove-FeatureFromPath -Feature "buildkit"

    Write-Output "Successfully uninstalled buildkit."
}


function Get-ConsentToRegisterBuildkit ($path) {
    $retry = 2
    $consent = [ActionConsent]::No
    do {
        $title = "Buildkit conf file not found at $path."
        $question = "Do you want to register buildkit service without containerd cni configuration?"
        $choices = '&Yes', '&No'
        $consent = (Get-Host).UI.PromptForChoice($title, $question, $choices, 0)

        $retry --

    } while (($retry -gt 0 ) -and ($consent -eq [ActionConsent]::No))

    return $consent
}

function Test-BuildkitdServiceExists($buildkitPath) {
    $cmdRes = Get-Command -Name "buildkitd.exe" -ErrorAction Ignore
    $pathExists = Test-Path -Path "$BuildkitPath\bin\buildkitd.exe"

    return ($cmdRes -or $pathExists)
}

function Unregister-Buildkitd($buildkitPath) {
    if (!(Test-ServiceRegistered -Service 'buildkitd')) {
        Write-Warning "Buildkitd service does not exist as an installed service."
        return
    }

    # Unregister buildkit service
    $buildkitdExecutable = "$buildkitPath\bin\buildkitd.exe"

    Write-Debug "Buildkitd path: $buildkitdExecutable "
    $output = Invoke-ExecutableCommand -Executable $buildkitdExecutable -Arguments "--unregister-service"
    if ($output.ExitCode -ne 0) {
        Throw "Could not unregister buildkitd service. $($output.StandardError.ReadToEnd())"
    }
    else {
        Start-Sleep -Seconds 15
    }
}


Export-ModuleMember -Function Get-BuildkitLatestVersion
Export-ModuleMember -Function Install-Buildkit
Export-ModuleMember -Function Start-BuildkitdService -Alias Start-Buildkitd
Export-ModuleMember -Function Stop-BuildkitdService -Alias Stop-Buildkitd
Export-ModuleMember -Function Register-BuildkitdService -Alias Register-Buildkitd
Export-ModuleMember -Function Uninstall-Buildkit, Uninstall-BuildkitHelper

# SIG # Begin signature block
# MIIoUwYJKoZIhvcNAQcCoIIoRDCCKEACAQExDzANBglghkgBZQMEAgEFADB5Bgor
# BgEEAYI3AgEEoGswaTA0BgorBgEEAYI3AgEeMCYCAwEAAAQQH8w7YFlLCE63JNLG
# KX7zUQIBAAIBAAIBAAIBAAIBADAxMA0GCWCGSAFlAwQCAQUABCApED/MQnixVGef
# ipL2d8C3c3yhi0KaOOiWM5+SNrjTmqCCDZowggYYMIIEAKADAgECAhMzAAAD87lq
# ZLvv9+1jAAAAAAPzMA0GCSqGSIb3DQEBCwUAMH4xCzAJBgNVBAYTAlVTMRMwEQYD
# VQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNy
# b3NvZnQgQ29ycG9yYXRpb24xKDAmBgNVBAMTH01pY3Jvc29mdCBDb2RlIFNpZ25p
# bmcgUENBIDIwMTEwHhcNMjQwNzE3MjEwMjM0WhcNMjUwOTE1MjEwMjM0WjCBiDEL
# MAkGA1UEBhMCVVMxEzARBgNVBAgTCldhc2hpbmd0b24xEDAOBgNVBAcTB1JlZG1v
# bmQxHjAcBgNVBAoTFU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjEyMDAGA1UEAxMpTWlj
# cm9zb2Z0IDNyZCBQYXJ0eSBBcHBsaWNhdGlvbiBDb21wb25lbnQwggEiMA0GCSqG
# SIb3DQEBAQUAA4IBDwAwggEKAoIBAQC4lnJhNSR/+M4vb7CMAivTMYSYEi0EnHXS
# SDat/9BwPD2i0F1hj7W80W8dEulv51fz1NAILKbeIp2JaS777mffYHfxMUw/BcQs
# yzW6J1e5xUPNguGU2GFXrc5s+jyK39AIpE6ATZecjMDuAu4P1nVEcZKDR0fBbP7Q
# 8CFe13PgnZi3n/4UXbwaElvFkrwia4wh88gJ+7lDFkZUOI1H1xxENgP9y2LlCifr
# HOahAXcY+TaSyeZqv+E0jV5SkBq8zNFCeWyMbooJPPsSG+LQEfS2sO4xNrNHZMlJ
# iziV79h12qxLicPeswugNdD+aBXqF0fwoovPuvSwaKT/wM8okNMxAgMBAAGjggGC
# MIIBfjAfBgNVHSUEGDAWBgorBgEEAYI3TBEBBggrBgEFBQcDAzAdBgNVHQ4EFgQU
# 1Rdsgw/dRz6oCuO8sKNsrodmEw8wVAYDVR0RBE0wS6RJMEcxLTArBgNVBAsTJE1p
# Y3Jvc29mdCBJcmVsYW5kIE9wZXJhdGlvbnMgTGltaXRlZDEWMBQGA1UEBRMNMjMx
# NTIyKzUwMjUyMTAfBgNVHSMEGDAWgBRIbmTlUAXTgqoXNzcitW2oynUClTBUBgNV
# HR8ETTBLMEmgR6BFhkNodHRwOi8vd3d3Lm1pY3Jvc29mdC5jb20vcGtpb3BzL2Ny
# bC9NaWNDb2RTaWdQQ0EyMDExXzIwMTEtMDctMDguY3JsMGEGCCsGAQUFBwEBBFUw
# UzBRBggrBgEFBQcwAoZFaHR0cDovL3d3dy5taWNyb3NvZnQuY29tL3BraW9wcy9j
# ZXJ0cy9NaWNDb2RTaWdQQ0EyMDExXzIwMTEtMDctMDguY3J0MAwGA1UdEwEB/wQC
# MAAwDQYJKoZIhvcNAQELBQADggIBAGNFKGiwTGNU85l+83tJhB6N2BPvaT9TAkuE
# 7uUniu1VU6b1/erckmXiuVqBLg2sGzE7O122bK871fNWpiEr9/pMflah1PL/+0D6
# XCodWS41UmWILRUhSqKURZ+iceq5n4EUiKcapBKhZ6uCKXSX62CVHlvNv4N6JA7N
# UztE0h3jAEQeLoGSFlfNqvkTOobE5NwlMRSJWhQ6SYnswiTY1QU06pSTaP/eVedL
# Rk6q3t/U9ibvVwHT+eTw1ASBbZoZOxWA3FjrK9XisOT/GoyV2w9D3gzKFGOElCFp
# RvceGeRKy2N3YSRjjgV9VYlUM5G/cz4ZigACtnd4jfE7ebbKmiDv2UB1IUpxSzS4
# TAO1bkANbwJ/frfSikUPGfZS2fRRXMWZTeQL5bTBcmW7INNTIxM2MxF6QqlLtmkJ
# Z3iv9cocwQ1MzWrrd1BU/ipLwgGtbw7mCestXZjP2amFeQjucAtKt9PkENnWfUex
# rwQZnZJWF3mCVvJTh6ACU0CJyO0a2a+RiuxsvR8QpMw1gE3744SbM75nABu84/zd
# kxfRkiXro5IsUJ+eNVXVKElvFngBzpbYtTVf1Pdcs8y0sEo6FxGQkzwKNLHe28tG
# 1H3NTHUNa0LQUKRjMq/58Iav9qq4rW1QIzfXAEnBDSBFv1E4vLmx2LghqMRPyTAB
# ZurrCCn1MIIHejCCBWKgAwIBAgIKYQ6Q0gAAAAAAAzANBgkqhkiG9w0BAQsFADCB
# iDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCldhc2hpbmd0b24xEDAOBgNVBAcTB1Jl
# ZG1vbmQxHjAcBgNVBAoTFU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjEyMDAGA1UEAxMp
# TWljcm9zb2Z0IFJvb3QgQ2VydGlmaWNhdGUgQXV0aG9yaXR5IDIwMTEwHhcNMTEw
# NzA4MjA1OTA5WhcNMjYwNzA4MjEwOTA5WjB+MQswCQYDVQQGEwJVUzETMBEGA1UE
# CBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9uZDEeMBwGA1UEChMVTWljcm9z
# b2Z0IENvcnBvcmF0aW9uMSgwJgYDVQQDEx9NaWNyb3NvZnQgQ29kZSBTaWduaW5n
# IFBDQSAyMDExMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAq/D6chAc
# Lq3YbqqCEE00uvK2WCGfQhsqa+laUKq4BjgaBEm6f8MMHt03a8YS2AvwOMKZBrDI
# OdUBFDFC04kNeWSHfpRgJGyvnkmc6Whe0t+bU7IKLMOv2akrrnoJr9eWWcpgGgXp
# ZnboMlImEi/nqwhQz7NEt13YxC4Ddato88tt8zpcoRb0RrrgOGSsbmQ1eKagYw8t
# 00CT+OPeBw3VXHmlSSnnDb6gE3e+lD3v++MrWhAfTVYoonpy4BI6t0le2O3tQ5GD
# 2Xuye4Yb2T6xjF3oiU+EGvKhL1nkkDstrjNYxbc+/jLTswM9sbKvkjh+0p2ALPVO
# VpEhNSXDOW5kf1O6nA+tGSOEy/S6A4aN91/w0FK/jJSHvMAhdCVfGCi2zCcoOCWY
# OUo2z3yxkq4cI6epZuxhH2rhKEmdX4jiJV3TIUs+UsS1Vz8kA/DRelsv1SPjcF0P
# UUZ3s/gA4bysAoJf28AVs70b1FVL5zmhD+kjSbwYuER8ReTBw3J64HLnJN+/RpnF
# 78IcV9uDjexNSTCnq47f7Fufr/zdsGbiwZeBe+3W7UvnSSmnEyimp31ngOaKYnhf
# si+E11ecXL93KCjx7W3DKI8sj0A3T8HhhUSJxAlMxdSlQy90lfdu+HggWCwTXWCV
# mj5PM4TasIgX3p5O9JawvEagbJjS4NaIjAsCAwEAAaOCAe0wggHpMBAGCSsGAQQB
# gjcVAQQDAgEAMB0GA1UdDgQWBBRIbmTlUAXTgqoXNzcitW2oynUClTAZBgkrBgEE
# AYI3FAIEDB4KAFMAdQBiAEMAQTALBgNVHQ8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB
# /zAfBgNVHSMEGDAWgBRyLToCMZBDuRQFTuHqp8cx0SOJNDBaBgNVHR8EUzBRME+g
# TaBLhklodHRwOi8vY3JsLm1pY3Jvc29mdC5jb20vcGtpL2NybC9wcm9kdWN0cy9N
# aWNSb29DZXJBdXQyMDExXzIwMTFfMDNfMjIuY3JsMF4GCCsGAQUFBwEBBFIwUDBO
# BggrBgEFBQcwAoZCaHR0cDovL3d3dy5taWNyb3NvZnQuY29tL3BraS9jZXJ0cy9N
# aWNSb29DZXJBdXQyMDExXzIwMTFfMDNfMjIuY3J0MIGfBgNVHSAEgZcwgZQwgZEG
# CSsGAQQBgjcuAzCBgzA/BggrBgEFBQcCARYzaHR0cDovL3d3dy5taWNyb3NvZnQu
# Y29tL3BraW9wcy9kb2NzL3ByaW1hcnljcHMuaHRtMEAGCCsGAQUFBwICMDQeMiAd
# AEwAZQBnAGEAbABfAHAAbwBsAGkAYwB5AF8AcwB0AGEAdABlAG0AZQBuAHQALiAd
# MA0GCSqGSIb3DQEBCwUAA4ICAQBn8oalmOBUeRou09h0ZyKbC5YR4WOSmUKWfdJ5
# DJDBZV8uLD74w3LRbYP+vj/oCso7v0epo/Np22O/IjWll11lhJB9i0ZQVdgMknzS
# Gksc8zxCi1LQsP1r4z4HLimb5j0bpdS1HXeUOeLpZMlEPXh6I/MTfaaQdION9Msm
# AkYqwooQu6SpBQyb7Wj6aC6VoCo/KmtYSWMfCWluWpiW5IP0wI/zRive/DvQvTXv
# biWu5a8n7dDd8w6vmSiXmE0OPQvyCInWH8MyGOLwxS3OW560STkKxgrCxq2u5bLZ
# 2xWIUUVYODJxJxp/sfQn+N4sOiBpmLJZiWhub6e3dMNABQamASooPoI/E01mC8Cz
# TfXhj38cbxV9Rad25UAqZaPDXVJihsMdYzaXht/a8/jyFqGaJ+HNpZfQ7l1jQeNb
# B5yHPgZ3BtEGsXUfFL5hYbXw3MYbBL7fQccOKO7eZS/sl/ahXJbYANahRr1Z85el
# CUtIEJmAH9AAKcWxm6U/RXceNcbSoqKfenoi+kiVH6v7RyOA9Z74v2u3S5fi63V4
# GuzqN5l5GEv/1rMjaHXmr/r8i+sLgOppO6/8MO0ETI7f33VtY5E90Z1WTk+/gFci
# oXgRMiF670EKsT/7qMykXcGhiJtXcVZOSEXAQsmbdlsKgEhr/Xmfwb1tbWrJUnMT
# DXpQzTGCGg8wghoLAgEBMIGVMH4xCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpXYXNo
# aW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNyb3NvZnQgQ29y
# cG9yYXRpb24xKDAmBgNVBAMTH01pY3Jvc29mdCBDb2RlIFNpZ25pbmcgUENBIDIw
# MTECEzMAAAPzuWpku+/37WMAAAAAA/MwDQYJYIZIAWUDBAIBBQCggbAwGQYJKoZI
# hvcNAQkDMQwGCisGAQQBgjcCAQQwHAYKKwYBBAGCNwIBCzEOMAwGCisGAQQBgjcC
# ARUwLwYJKoZIhvcNAQkEMSIEIDTeXlEyd2TxztDOFN8hxRBLoLuU/FunU7hoDEMH
# /AoPMEQGCisGAQQBgjcCAQwxNjA0oBSAEgBNAGkAYwByAG8AcwBvAGYAdKEcgBpo
# dHRwczovL3d3dy5taWNyb3NvZnQuY29tIDANBgkqhkiG9w0BAQEFAASCAQBLUpJ+
# 45E316lveu7r9knK68rr4xWlDv0WC3MR+AZ8olYIrU4H1cCm8kxPa4M6DxygSyU1
# 8aiDBgLJ525eLp/PMAgj2QUXZLkEtsQxvUUycswm1LrzXu83GTOHhwN1kPmiTixU
# fnbBwnVT8gH/IgPsuLper+w61rH0MaQmpML2iF9wbLngE5rKU6NqyyDcntujVNZ+
# aHce2tcwttGXr5eCbFRGQfYWkXd4QNSwshBNcuB2yKxyXedcQqgpXS/gzkpo4wiW
# zKp4ZtUTzZjFVMLchzjS5TZDm+ElujT6cQ04XT268mML+GY3uPjLmEuw8Sohi6aM
# B751wdLJy4FNOpHkoYIXlzCCF5MGCisGAQQBgjcDAwExgheDMIIXfwYJKoZIhvcN
# AQcCoIIXcDCCF2wCAQMxDzANBglghkgBZQMEAgEFADCCAVIGCyqGSIb3DQEJEAEE
# oIIBQQSCAT0wggE5AgEBBgorBgEEAYRZCgMBMDEwDQYJYIZIAWUDBAIBBQAEIG/W
# pfaBPsImdN2jvYsh9zbz1xAZT0kt5/qk4HACALKWAgZoJdLn2ksYEzIwMjUwNTE1
# MTYyMDUwLjc0NlowBIACAfSggdGkgc4wgcsxCzAJBgNVBAYTAlVTMRMwEQYDVQQI
# EwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNyb3Nv
# ZnQgQ29ycG9yYXRpb24xJTAjBgNVBAsTHE1pY3Jvc29mdCBBbWVyaWNhIE9wZXJh
# dGlvbnMxJzAlBgNVBAsTHm5TaGllbGQgVFNTIEVTTjpBNDAwLTA1RTAtRDk0NzEl
# MCMGA1UEAxMcTWljcm9zb2Z0IFRpbWUtU3RhbXAgU2VydmljZaCCEe0wggcgMIIF
# CKADAgECAhMzAAACAnlQdCEUfbihAAEAAAICMA0GCSqGSIb3DQEBCwUAMHwxCzAJ
# BgNVBAYTAlVTMRMwEQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25k
# MR4wHAYDVQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xJjAkBgNVBAMTHU1pY3Jv
# c29mdCBUaW1lLVN0YW1wIFBDQSAyMDEwMB4XDTI1MDEzMDE5NDI0NFoXDTI2MDQy
# MjE5NDI0NFowgcsxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpXYXNoaW5ndG9uMRAw
# DgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24x
# JTAjBgNVBAsTHE1pY3Jvc29mdCBBbWVyaWNhIE9wZXJhdGlvbnMxJzAlBgNVBAsT
# Hm5TaGllbGQgVFNTIEVTTjpBNDAwLTA1RTAtRDk0NzElMCMGA1UEAxMcTWljcm9z
# b2Z0IFRpbWUtU3RhbXAgU2VydmljZTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCC
# AgoCggIBALd5Knpy5xQY6Rw+Di8pYol8RB6yErZkGxhTW0Na9C7ov2Wn52eqtqMh
# 014fUc3ejPeKIagla43YdU1mRw63fxpYZ5szSBRQ60+O4uG47l3rtilCwcEkBaFy
# 978xV2hA+PWeOICNKI6svzEVqsUsjjpEfw14OEA9dwmlafsAjMLIiNk5onYNYD7p
# DA3PCqMGAil/WFYXCoe88R53LSei1du1Z9P28JIv2x0Mror8cf0expjnAuZRQHtJ
# +4sajU5YSbownIbaOLGqL03JGjKl0Xx1HKNbEpGXYnHC9t62UNOKjrpeWJM5ySrZ
# GAz5mhxkRvoSg5213RcqHcvPHb0CEfGWT7p4jBq+Udi44tkMqh085U3qPUgn1uui
# VjqZluhDnU6p7mcQzmH9YlfbwYtmKgSQk3yo57k/k/ZjH0eg6ou6BfTSoLPGrgEO
# bzEfzkcrG8oI7kqKSilpEYa1CVeMPK6wxaWsdzJK3noOEvh1xWeft0W8vnTO9CUV
# kyFWh6FZJCSRa5SUIKog6tN7tFuadt0miwf7uUL6fneCcrLg6hnO5R6rMKdIHUk1
# c8qcmiM/cN7nHCymLm1S9AU1+V8ZOyNmBACAMF2D8M7RMaAtEMq9lAJnmoi5elBH
# KDfvJznV73nPxTabKxTRedKlZ6KAeqTI4C0N9wimrka/sdX51rZHAgMBAAGjggFJ
# MIIBRTAdBgNVHQ4EFgQU2ga5tQ+M/Z/yJ+Qgq/DLWuVIdNkwHwYDVR0jBBgwFoAU
# n6cVXQBeYl2D9OXSZacbUzUZ6XIwXwYDVR0fBFgwVjBUoFKgUIZOaHR0cDovL3d3
# dy5taWNyb3NvZnQuY29tL3BraW9wcy9jcmwvTWljcm9zb2Z0JTIwVGltZS1TdGFt
# cCUyMFBDQSUyMDIwMTAoMSkuY3JsMGwGCCsGAQUFBwEBBGAwXjBcBggrBgEFBQcw
# AoZQaHR0cDovL3d3dy5taWNyb3NvZnQuY29tL3BraW9wcy9jZXJ0cy9NaWNyb3Nv
# ZnQlMjBUaW1lLVN0YW1wJTIwUENBJTIwMjAxMCgxKS5jcnQwDAYDVR0TAQH/BAIw
# ADAWBgNVHSUBAf8EDDAKBggrBgEFBQcDCDAOBgNVHQ8BAf8EBAMCB4AwDQYJKoZI
# hvcNAQELBQADggIBAIPzdoVBTE3fseQ6gkMzWZocVlVQZypNBw+c4PpShhEyYMq/
# QZpseUTzYBiAs+5WW6Sfse0k8XbPSOdOAB9EyfbokUs8bs79dsorbmGsE8nfSUG7
# CMBNW3nxQDUFajuWyafKu6v/qHwAXOtfKte2W/NBippFhj2TRQVjkYz6f1hoQQrY
# Pbrx75r4cOZZ761gvYf707hDUxAtqD5yI3AuSP/5CXGleJai70q8A/S0iT58fwXf
# DDlU5OL1pn36o+OzPDfUfid22K8FlofmzlugmYfYlu0y5/bLuFJ0l0TRRbYHQURk
# 8siZ6aUqGyUk1WoQ7tE+CXtzzVC5VI7nx9+mZvC1LGFisRLdWw+CVef04MXsOqY8
# wb8bKwHij9CSk1Sr7BLts5FM3Oocy0f6it3ZhKZr7VvJYGv+LMgqCA4J0TNpkN/K
# bXYYzprhL4jLoBQinv8oikCZ9Z9etwwrtXsQHPGh7OQtEQRYjhe0/CkQGe05rWgM
# fdn/51HGzEvS+DJruM1+s7uiLNMCWf/ZkFgH2KhR6huPkAYvjmbaZwpKTscTnNRF
# 5WQgulgoFDn5f/yMU7X+lnKrNB4jX+gn9EuiJzVKJ4td8RP0RZkgGNkxnzjqYNun
# XKcr1Rs2IKNLCZMXnT1if0zjtVCzGy/WiVC7nWtVUeRI2b6tOsvArW2+G/SZMIIH
# cTCCBVmgAwIBAgITMwAAABXF52ueAptJmQAAAAAAFTANBgkqhkiG9w0BAQsFADCB
# iDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCldhc2hpbmd0b24xEDAOBgNVBAcTB1Jl
# ZG1vbmQxHjAcBgNVBAoTFU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjEyMDAGA1UEAxMp
# TWljcm9zb2Z0IFJvb3QgQ2VydGlmaWNhdGUgQXV0aG9yaXR5IDIwMTAwHhcNMjEw
# OTMwMTgyMjI1WhcNMzAwOTMwMTgzMjI1WjB8MQswCQYDVQQGEwJVUzETMBEGA1UE
# CBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9uZDEeMBwGA1UEChMVTWljcm9z
# b2Z0IENvcnBvcmF0aW9uMSYwJAYDVQQDEx1NaWNyb3NvZnQgVGltZS1TdGFtcCBQ
# Q0EgMjAxMDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAOThpkzntHIh
# C3miy9ckeb0O1YLT/e6cBwfSqWxOdcjKNVf2AX9sSuDivbk+F2Az/1xPx2b3lVNx
# WuJ+Slr+uDZnhUYjDLWNE893MsAQGOhgfWpSg0S3po5GawcU88V29YZQ3MFEyHFc
# UTE3oAo4bo3t1w/YJlN8OWECesSq/XJprx2rrPY2vjUmZNqYO7oaezOtgFt+jBAc
# nVL+tuhiJdxqD89d9P6OU8/W7IVWTe/dvI2k45GPsjksUZzpcGkNyjYtcI4xyDUo
# veO0hyTD4MmPfrVUj9z6BVWYbWg7mka97aSueik3rMvrg0XnRm7KMtXAhjBcTyzi
# YrLNueKNiOSWrAFKu75xqRdbZ2De+JKRHh09/SDPc31BmkZ1zcRfNN0Sidb9pSB9
# fvzZnkXftnIv231fgLrbqn427DZM9ituqBJR6L8FA6PRc6ZNN3SUHDSCD/AQ8rdH
# GO2n6Jl8P0zbr17C89XYcz1DTsEzOUyOArxCaC4Q6oRRRuLRvWoYWmEBc8pnol7X
# KHYC4jMYctenIPDC+hIK12NvDMk2ZItboKaDIV1fMHSRlJTYuVD5C4lh8zYGNRiE
# R9vcG9H9stQcxWv2XFJRXRLbJbqvUAV6bMURHXLvjflSxIUXk8A8FdsaN8cIFRg/
# eKtFtvUeh17aj54WcmnGrnu3tz5q4i6tAgMBAAGjggHdMIIB2TASBgkrBgEEAYI3
# FQEEBQIDAQABMCMGCSsGAQQBgjcVAgQWBBQqp1L+ZMSavoKRPEY1Kc8Q/y8E7jAd
# BgNVHQ4EFgQUn6cVXQBeYl2D9OXSZacbUzUZ6XIwXAYDVR0gBFUwUzBRBgwrBgEE
# AYI3TIN9AQEwQTA/BggrBgEFBQcCARYzaHR0cDovL3d3dy5taWNyb3NvZnQuY29t
# L3BraW9wcy9Eb2NzL1JlcG9zaXRvcnkuaHRtMBMGA1UdJQQMMAoGCCsGAQUFBwMI
# MBkGCSsGAQQBgjcUAgQMHgoAUwB1AGIAQwBBMAsGA1UdDwQEAwIBhjAPBgNVHRMB
# Af8EBTADAQH/MB8GA1UdIwQYMBaAFNX2VsuP6KJcYmjRPZSQW9fOmhjEMFYGA1Ud
# HwRPME0wS6BJoEeGRWh0dHA6Ly9jcmwubWljcm9zb2Z0LmNvbS9wa2kvY3JsL3By
# b2R1Y3RzL01pY1Jvb0NlckF1dF8yMDEwLTA2LTIzLmNybDBaBggrBgEFBQcBAQRO
# MEwwSgYIKwYBBQUHMAKGPmh0dHA6Ly93d3cubWljcm9zb2Z0LmNvbS9wa2kvY2Vy
# dHMvTWljUm9vQ2VyQXV0XzIwMTAtMDYtMjMuY3J0MA0GCSqGSIb3DQEBCwUAA4IC
# AQCdVX38Kq3hLB9nATEkW+Geckv8qW/qXBS2Pk5HZHixBpOXPTEztTnXwnE2P9pk
# bHzQdTltuw8x5MKP+2zRoZQYIu7pZmc6U03dmLq2HnjYNi6cqYJWAAOwBb6J6Gng
# ugnue99qb74py27YP0h1AdkY3m2CDPVtI1TkeFN1JFe53Z/zjj3G82jfZfakVqr3
# lbYoVSfQJL1AoL8ZthISEV09J+BAljis9/kpicO8F7BUhUKz/AyeixmJ5/ALaoHC
# gRlCGVJ1ijbCHcNhcy4sa3tuPywJeBTpkbKpW99Jo3QMvOyRgNI95ko+ZjtPu4b6
# MhrZlvSP9pEB9s7GdP32THJvEKt1MMU0sHrYUP4KWN1APMdUbZ1jdEgssU5HLcEU
# BHG/ZPkkvnNtyo4JvbMBV0lUZNlz138eW0QBjloZkWsNn6Qo3GcZKCS6OEuabvsh
# VGtqRRFHqfG3rsjoiV5PndLQTHa1V1QJsWkBRH58oWFsc/4Ku+xBZj1p/cvBQUl+
# fpO+y/g75LcVv7TOPqUxUYS8vwLBgqJ7Fx0ViY1w/ue10CgaiQuPNtq6TPmb/wrp
# NPgkNWcr4A245oyZ1uEi6vAnQj0llOZ0dFtq0Z4+7X6gMTN9vMvpe784cETRkPHI
# qzqKOghif9lwY1NNje6CbaUFEMFxBmoQtB1VM1izoXBm8qGCA1AwggI4AgEBMIH5
# oYHRpIHOMIHLMQswCQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4G
# A1UEBxMHUmVkbW9uZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMSUw
# IwYDVQQLExxNaWNyb3NvZnQgQW1lcmljYSBPcGVyYXRpb25zMScwJQYDVQQLEx5u
# U2hpZWxkIFRTUyBFU046QTQwMC0wNUUwLUQ5NDcxJTAjBgNVBAMTHE1pY3Jvc29m
# dCBUaW1lLVN0YW1wIFNlcnZpY2WiIwoBATAHBgUrDgMCGgMVAEmJSGkJYD/df+Nn
# IjLTJ7pEnAvOoIGDMIGApH4wfDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCldhc2hp
# bmd0b24xEDAOBgNVBAcTB1JlZG1vbmQxHjAcBgNVBAoTFU1pY3Jvc29mdCBDb3Jw
# b3JhdGlvbjEmMCQGA1UEAxMdTWljcm9zb2Z0IFRpbWUtU3RhbXAgUENBIDIwMTAw
# DQYJKoZIhvcNAQELBQACBQDr0FFkMCIYDzIwMjUwNTE1MTE0MTI0WhgPMjAyNTA1
# MTYxMTQxMjRaMHcwPQYKKwYBBAGEWQoEATEvMC0wCgIFAOvQUWQCAQAwCgIBAAIC
# AIwCAf8wBwIBAAICEfYwCgIFAOvRouQCAQAwNgYKKwYBBAGEWQoEAjEoMCYwDAYK
# KwYBBAGEWQoDAqAKMAgCAQACAwehIKEKMAgCAQACAwGGoDANBgkqhkiG9w0BAQsF
# AAOCAQEAqqUjDKJUQO5S5oWMRobJDrdADBYfc7j4mRkYrEUPK4jrYzGKExolvKc4
# XPg4FTbNNC26hewAakPwYzv/W7lVUvT9bC/SDlDbHIBlJ8fn5W9xERKAGJW/RsAO
# 419HsXOWuRUHfPDKxRXk3keFzUKCWZ/W5lvKPbcuWsOBEgeRopyjtt5WL8HJrI7u
# tXSEMRg5EF4rza6a+mmK5o93iGgHcfSdYw6JxD6/BIwyu7Ym0wGrlfTGjC7b3lVv
# nD2ToFSmLdZdpJtg4AtHPF/IEvV0O8gIFtuncGwmu844MkSqa17rc80SsUDnYDOO
# dyhkBJwAW26ikitsppQr3ny6MonygTGCBA0wggQJAgEBMIGTMHwxCzAJBgNVBAYT
# AlVTMRMwEQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYD
# VQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xJjAkBgNVBAMTHU1pY3Jvc29mdCBU
# aW1lLVN0YW1wIFBDQSAyMDEwAhMzAAACAnlQdCEUfbihAAEAAAICMA0GCWCGSAFl
# AwQCAQUAoIIBSjAaBgkqhkiG9w0BCQMxDQYLKoZIhvcNAQkQAQQwLwYJKoZIhvcN
# AQkEMSIEIGYkizWd//3VNCxouFnmTFsUxYITjgZR4xoP9klZeueqMIH6BgsqhkiG
# 9w0BCRACLzGB6jCB5zCB5DCBvQQg843qARgHlsvNcta5SYvxl3zFcCypeSx50XKi
# V8yUX+wwgZgwgYCkfjB8MQswCQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3Rv
# bjEQMA4GA1UEBxMHUmVkbW9uZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0
# aW9uMSYwJAYDVQQDEx1NaWNyb3NvZnQgVGltZS1TdGFtcCBQQ0EgMjAxMAITMwAA
# AgJ5UHQhFH24oQABAAACAjAiBCCneRkQYbjGMp3Wxu2U5Dh+xgPqhLWg/GvX2xjk
# cWuAyzANBgkqhkiG9w0BAQsFAASCAgCJ7NkjgdemzYbnc2FnR3/IDNqekPJrYCnN
# VomF+kRMbtUloC8GBzCMDqpWvVNiqIP/QMWZdZw1tVrR9sH648e/+jzA6Ck1154r
# MGXGanEF+SPdDGF029ZklBem+01NMwYRGcXOLnyO67UUev+FI5OEzaKTUxKrIPop
# YjKfC15XjllXVXVo+xIkkQvEmfIc5TQcMRr9VbaNUTCON+cXRt3N2/q7sndgKovj
# +pKTa5oBMpl8yzl0SjhPh6bGxZJZtVomddQfUZB1cMcjp94n9NDXJLrI9wUOGnRj
# mQ33fPUy4wicULKm4NneNkmpr80GkGJqxrDbtqfp5gqsoooc015swbSA/7l8yb7b
# W4zOHr76Jd6Q4dJn3Y6Sicm21v342wlz84RsS7dOPwE8tPY2WItivgXzRShExX8s
# o2OiwdnhImIFLGwlSm5lso7B1p85a7bhpgvDVnTZcOR70kp6Ip4ETXbcuk6Ldd7r
# el+Mbjyrb+KPqWGDRRXS0FOleAVIludUP7mMWX0k7lkajkxiu8XP3ye7wk6Xj8nq
# tKuFcn3t7IgW3LRWv1UVLubI5toLlluJ+p9YYEx1TyIN5ZcQt5i5p/98jwR/1YGG
# YZmuh9aDV55t7AkENqX4hCreZzSJC+gvPq8flMD24xLChrQ3LaW7ALIjYn9tS3Ks
# 3CpDHxZGCw==
# SIG # End signature block