BC.HelperFunctions.ps1

if ($isWindows) {
    $programDataFolder = 'C:\ProgramData\BcContainerHelper'
    $artifactsCacheFolder = "c:\bcartifacts.cache"
    $nugetCacheFolder = "c:\bcnuget.cache"
}
elseif ($isMacOS) {
    $programDataFolder = "/Users/$myUsername/.bccontainerhelper"
    $artifactsCacheFolder = "/Users/$myUsername/.bcartifacts.cache"
    $nugetCacheFolder = "/Users/$myUsername/.bcnuget.cache"
}
else {
    $programDataFolder = "/home/$myUsername/.bccontainerhelper"
    $artifactsCacheFolder = "/home/$myUsername/.bcartifacts.cache"
    $nugetCacheFolder = "/home/$myUsername/.bcnuget.cache"
}

function Get-ContainerHelperConfig {
    if (!((Get-Variable -scope Script bcContainerHelperConfig -ErrorAction SilentlyContinue) -and $bcContainerHelperConfig)) {
        Set-Variable -scope Script -Name bcContainerHelperConfig -Value @{
            "bcartifactsCacheFolder" = ""
            "genericImageName" = 'mcr.microsoft.com/businesscentral:{1}'
            "genericImageNameFilesOnly" = 'mcr.microsoft.com/businesscentral:{1}-filesonly'
            "usePsSession" = $true
            "usePwshForBc24" = $true
            "useSslForWinRmSession" = $true
            "useWinRmSession" = "allow"   # allow, always, never
            "addTryCatchToScriptBlock" = $true
            "killPsSessionProcess" = $false
            "usePrereleaseAlTool" = $false
            "useVolumes" = $false
            "useVolumeForMyFolder" = $false
            "use7zipIfAvailable" = $true
            "defaultNewContainerParameters" = [PSCustomObject]@{
            }
            "hostHelperFolder" = ""
            "containerHelperFolder" = $programDataFolder
            "defaultContainerName" = "bcserver"
            "useCompilerFolder" = $false
            "digestAlgorithm" = "SHA256"
            "timeStampServer" = "http://timestamp.digicert.com"
            "sandboxContainersAreMultitenantByDefault" = $true
            "useSharedEncryptionKeys" = $true
            "DOCKER_SCAN_SUGGEST" = $false
            "psSessionTimeout" = 0
            "artifactDownloadTimeout" = 600
            "defaultDownloadTimeout" = 120
            "baseUrl" = "https://businesscentral.dynamics.com"
            "apiBaseUrl" = "https://api.businesscentral.dynamics.com"
            "mapCountryCode" = [PSCustomObject]@{
                "ae" = "w1"
                "ar" = "w1"
                "bd" = "w1"
                "dz" = "w1"
                "cl" = "w1"
                "pr" = "w1"
                "eg" = "w1"
                "fo" = "dk"
                "gl" = "dk"
                "id" = "w1"
                "ke" = "w1"
                "lb" = "w1"
                "lk" = "w1"
                "lu" = "w1"
                "ma" = "w1"
                "mm" = "w1"
                "mt" = "w1"
                "my" = "w1"
                "ng" = "w1"
                "qa" = "w1"
                "sa" = "w1"
                "sg" = "w1"
                "tn" = "w1"
                "ua" = "w1"
                "za" = "w1"
                "ao" = "w1"
                "bh" = "w1"
                "ba" = "w1"
                "bw" = "w1"
                "cr" = "br"
                "cy" = "w1"
                "do" = "br"
                "ec" = "br"
                "sv" = "br"
                "gt" = "br"
                "hn" = "br"
                "jm" = "w1"
                "mv" = "w1"
                "mu" = "w1"
                "ni" = "br"
                "pa" = "br"
                "py" = "br"
                "tt" = "br"
                "uy" = "br"
                "zw" = "w1"
                "im" = "gb"
                "gg" = "gb"
            }
            "mapNetworkSettings" = [PSCustomObject]@{
            }
            "AddHostDnsServersToNatContainers" = $false
            "TraefikUseDnsNameAsHostName" = $false
            "TreatWarningsAsErrors" = @()
            "PartnerTelemetryConnectionString" = ""
            "MicrosoftTelemetryConnectionString" = "InstrumentationKey=5b44407e-9750-4a07-abe9-30c3b853821b;IngestionEndpoint=https://southcentralus-0.in.applicationinsights.azure.com/"
            "SendExtendedTelemetryToMicrosoft" = $false
            "TraefikImage" = "tobiasfenster/traefik-for-windows:v1.7.34"
            "ObjectIdForInternalUse" = 88123
            "WinRmCredentials" = $null
            "WarningPreference" = "SilentlyContinue"
            "UseNewFormatForGetBcContainerAppInfo" = $false
            "NoOfSecondsToSleepAfterPublishBcContainerApp" = 1
            "RenewClientContextBetweenTests" = $false
            "DebugMode" = $false
            "ExcludeBuilds" = @()
            "MinimumDotNetRuntimeVersionStr" = "6.0.16"
            "MinimumDotNetRuntimeVersionUrl" = 'https://download.visualstudio.microsoft.com/download/pr/ca13c6f1-3107-4cf8-991c-f70edc1c1139/a9f90579d827514af05c3463bed63c22/dotnet-sdk-6.0.408-win-x64.zip'
            "MSSymbolsNuGetFeedUrl" = 'https://dynamicssmb2.pkgs.visualstudio.com/DynamicsBCPublicFeeds/_packaging/MSSymbols/nuget/v3/index.json'
            "MSAppsNuGetFeedUrl" = 'https://dynamicssmb2.pkgs.visualstudio.com/DynamicsBCPublicFeeds/_packaging/MSApps/nuget/v3/index.json'
            "TrustedNuGetFeeds" = @(
            )
            "IsGitHubActions" = ($env:GITHUB_ACTIONS -eq "true")
            "IsAzureDevOps" = ($env:TF_BUILD -eq "true")
            "IsGitLab" = ($env:GITLAB_CI -eq "true")
            "useApproximateVersion" = $false
            "useSqlServerModule" = $false
            "NuGetSearchResultsCacheRetentionPeriod" = 600 # 10 minutes
            "BcNuGetCacheFolder" = ""
            "doNotRemovePackagesFolderIfExists" = $false
        }

        if ($isInsider) {
            $bcContainerHelperConfig.genericImageName = 'mcr.microsoft.com/businesscentral:{1}-dev'
            $bcContainerHelperConfig.genericImageNameFilesOnly = 'mcr.microsoft.com/businesscentral:{1}-filesonly-dev'
        }

        if ($bcContainerHelperConfigFile -notcontains (Join-Path $programDataFolder "BcContainerHelper.config.json")) {
            $bcContainerHelperConfigFile = @((Join-Path $programDataFolder "BcContainerHelper.config.json"))+$bcContainerHelperConfigFile
        }
        $bcContainerHelperConfigFile | ForEach-Object {
            $configFile = $_
            if (Test-Path $configFile) {
                try {
                    $savedConfig = Get-Content $configFile | ConvertFrom-Json
                    if ("$savedConfig") {
                        $keys = $bcContainerHelperConfig.Keys | ForEach-Object { $_ }
                        $keys | ForEach-Object {
                            if ($savedConfig.PSObject.Properties.Name -eq "$_") {
                                $savedConfigValue = $savedConfig."$_"
                                if ($isPsCore -and ($savedConfigValue -is [Int64])) {
                                    $savedConfigValue = [Int32]$savedConfigValue
                                }
                                if ($bcContainerHelperConfig."$_" -and $savedConfigValue -and $bcContainerHelperConfig."$_".GetType() -ne $savedConfigValue.GetType()) {
                                    Write-Host -ForegroundColor Red "Ignoring config setting $_ as the type in the config file is different than in the default configuration"
                                }
                                else {
                                    if ((ConvertTo-Json -InputObject $bcContainerHelperConfig."$_" -Compress) -eq (ConvertTo-Json -InputObject $savedConfigValue -Compress)) {
                                        if (!$silent) {
                                            Write-Host "Ignoring unchanged config setting $_"
                                        }
                                    }
                                    else {
                                        if (!$silent) {
                                            Write-Host "Setting $_ = $savedConfigValue"
                                        }
                                        $bcContainerHelperConfig."$_" = $savedConfigValue
                                    }
                                }
                            }
                        }
                    }
                }
                catch {
                    throw "Error reading configuration file $configFile, cannot import module."
                }
            }
        }

        if ($isInsideContainer) {
            $bcContainerHelperConfig.usePsSession = $true
            try {
                $myinspect = docker inspect $(hostname) | ConvertFrom-Json
                $bcContainerHelperConfig.WinRmCredentials = New-Object PSCredential -ArgumentList 'WinRmUser', (ConvertTo-SecureString -string "P@ss$($myinspect.Id.SubString(48))" -AsPlainText -Force)
            }
            catch {}
        }

        if ($bcContainerHelperConfig.UseVolumes) {
            if ($bcContainerHelperConfig.bcartifactsCacheFolder -eq "") {
                $bcContainerHelperConfig.bcartifactsCacheFolder = "bcartifacts.cache"
            }
            if ($bcContainerHelperConfig.bcNuGetCacheFolder -eq "") {
                $bcContainerHelperConfig.bcNuGetCacheFolder = "bcnuget.cache"
            }
            if ($bcContainerHelperConfig.hostHelperFolder -eq "") {
                $bcContainerHelperConfig.hostHelperFolder = "hostHelperFolder"
            }
            $bcContainerHelperConfig.useVolumeForMyFolder = $false
        }
        else {
            if ($bcContainerHelperConfig.bcartifactsCacheFolder -eq "") {
                $bcContainerHelperConfig.bcartifactsCacheFolder = $artifactsCacheFolder
            }
            if ($bcContainerHelperConfig.bcNuGetCacheFolder -eq "") {
                $bcContainerHelperConfig.bcNuGetCacheFolder = $nuGetCacheFolder
            }
            if ($bcContainerHelperConfig.hostHelperFolder -eq "") {
                $bcContainerHelperConfig.hostHelperFolder = $programDataFolder
            }
        }

        if ($isWindows -and ($bcContainerHelperConfig.useWinRmSession -ne 'never')) {
            # useWinRmSession should be never if the service isn't running
            $service = get-service WinRm -erroraction SilentlyContinue
            if ($service -and $service.Status -ne "Running") {
                if (!$Silent) {
                    Write-Host "WinRM service is not running, will not try to use WinRM sessions"
                }
                $bcContainerHelperConfig.useWinRmSession = 'never'
            }
        }

        Export-ModuleMember -Variable bcContainerHelperConfig
    }
    return $bcContainerHelperConfig
}

$configHelperFolder = $programDataFolder
if (!(Test-Path $configHelperFolder)) {
    New-Item -Path $configHelperFolder -ItemType Container -Force | Out-Null
    if ($isWindows -and !$isAdministrator) {
        $rule = New-Object System.Security.AccessControl.FileSystemAccessRule($myUsername,'FullControl', 3, 'InheritOnly', 'Allow')
        $acl = Get-Acl -Path $configHelperFolder
        $acl.AddAccessRule($rule)
        Set-Acl -Path $configHelperFolder -AclObject $acl | Out-Null
    }
}

Get-ContainerHelperConfig | Out-Null

$telemetry = @{
    "Assembly" = $null
    "PartnerClient" = $null
    "MicrosoftClient" = $null
    "CorrelationId" = ""
    "TopId" = ""
    "Debug" = $false
}
try {
    if (($bcContainerHelperConfig.MicrosoftTelemetryConnectionString) -and !$Silent) {
        Write-Host -ForegroundColor Green "BC.HelperFunctions emits usage statistics telemetry to Microsoft"
    }
    $dllPath = Join-Path $configHelperFolder 'Microsoft.ApplicationInsights.2.32.0.429.dll'
    if (-not (Test-Path $dllPath)) {
        Copy-Item (Join-Path $PSScriptRoot "Microsoft.ApplicationInsights.dll") -Destination $dllPath
    }
    $telemetry.Assembly = [System.Reflection.Assembly]::LoadFrom($dllPath)
} catch {
    if (!$Silent) {
        Write-Host -ForegroundColor Yellow "Unable to load ApplicationInsights.dll"
    }
}

. (Join-Path $PSScriptRoot "TelemetryHelper.ps1")

# Telemetry functions
Export-ModuleMember -Function RegisterTelemetryScope
Export-ModuleMember -Function InitTelemetryScope
Export-ModuleMember -Function AddTelemetryProperty
Export-ModuleMember -Function TrackTrace
Export-ModuleMember -Function TrackException

# Common functions
. (Join-Path $PSScriptRoot "Common\Download-File.ps1")
. (Join-Path $PSScriptRoot "Common\New-DesktopShortcut.ps1")
. (Join-Path $PSScriptRoot "Common\Remove-DesktopShortcut.ps1")
. (Join-Path $PSScriptRoot "Common\ConvertTo-HashTable.ps1")
. (Join-Path $PSScriptRoot "Common\Get-PlainText.ps1")
. (Join-Path $PSScriptRoot "Common\Invoke-gh.ps1")
. (Join-Path $PSScriptRoot "Common\Invoke-git.ps1")
. (Join-Path $PSScriptRoot "Common\ConvertTo-OrderedDictionary.ps1")

# BC Authentication helper functions
. (Join-Path $PSScriptRoot "Auth\New-BcAuthContext.ps1")
. (Join-Path $PSScriptRoot "Auth\Renew-BcAuthContext.ps1")

# SIG # Begin signature block
# MIIoGgYJKoZIhvcNAQcCoIIoCzCCKAcCAQExDzANBglghkgBZQMEAgEFADB5Bgor
# BgEEAYI3AgEEoGswaTA0BgorBgEEAYI3AgEeMCYCAwEAAAQQH8w7YFlLCE63JNLG
# KX7zUQIBAAIBAAIBAAIBAAIBADAxMA0GCWCGSAFlAwQCAQUABCA1rR9m4eMkaVUz
# jeyigniGf/gYZcCCCRgV5bsMmHNhfaCCDYUwggYDMIID66ADAgECAhMzAAAEhJji
# EuB4ozFdAAAAAASEMA0GCSqGSIb3DQEBCwUAMH4xCzAJBgNVBAYTAlVTMRMwEQYD
# VQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNy
# b3NvZnQgQ29ycG9yYXRpb24xKDAmBgNVBAMTH01pY3Jvc29mdCBDb2RlIFNpZ25p
# bmcgUENBIDIwMTEwHhcNMjUwNjE5MTgyMTM1WhcNMjYwNjE3MTgyMTM1WjB0MQsw
# CQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9u
# ZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMR4wHAYDVQQDExVNaWNy
# b3NvZnQgQ29ycG9yYXRpb24wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIB
# AQDtekqMKDnzfsyc1T1QpHfFtr+rkir8ldzLPKmMXbRDouVXAsvBfd6E82tPj4Yz
# aSluGDQoX3NpMKooKeVFjjNRq37yyT/h1QTLMB8dpmsZ/70UM+U/sYxvt1PWWxLj
# MNIXqzB8PjG6i7H2YFgk4YOhfGSekvnzW13dLAtfjD0wiwREPvCNlilRz7XoFde5
# KO01eFiWeteh48qUOqUaAkIznC4XB3sFd1LWUmupXHK05QfJSmnei9qZJBYTt8Zh
# ArGDh7nQn+Y1jOA3oBiCUJ4n1CMaWdDhrgdMuu026oWAbfC3prqkUn8LWp28H+2S
# LetNG5KQZZwvy3Zcn7+PQGl5AgMBAAGjggGCMIIBfjAfBgNVHSUEGDAWBgorBgEE
# AYI3TAgBBggrBgEFBQcDAzAdBgNVHQ4EFgQUBN/0b6Fh6nMdE4FAxYG9kWCpbYUw
# VAYDVR0RBE0wS6RJMEcxLTArBgNVBAsTJE1pY3Jvc29mdCBJcmVsYW5kIE9wZXJh
# dGlvbnMgTGltaXRlZDEWMBQGA1UEBRMNMjMwMDEyKzUwNTM2MjAfBgNVHSMEGDAW
# gBRIbmTlUAXTgqoXNzcitW2oynUClTBUBgNVHR8ETTBLMEmgR6BFhkNodHRwOi8v
# d3d3Lm1pY3Jvc29mdC5jb20vcGtpb3BzL2NybC9NaWNDb2RTaWdQQ0EyMDExXzIw
# MTEtMDctMDguY3JsMGEGCCsGAQUFBwEBBFUwUzBRBggrBgEFBQcwAoZFaHR0cDov
# L3d3dy5taWNyb3NvZnQuY29tL3BraW9wcy9jZXJ0cy9NaWNDb2RTaWdQQ0EyMDEx
# XzIwMTEtMDctMDguY3J0MAwGA1UdEwEB/wQCMAAwDQYJKoZIhvcNAQELBQADggIB
# AGLQps1XU4RTcoDIDLP6QG3NnRE3p/WSMp61Cs8Z+JUv3xJWGtBzYmCINmHVFv6i
# 8pYF/e79FNK6P1oKjduxqHSicBdg8Mj0k8kDFA/0eU26bPBRQUIaiWrhsDOrXWdL
# m7Zmu516oQoUWcINs4jBfjDEVV4bmgQYfe+4/MUJwQJ9h6mfE+kcCP4HlP4ChIQB
# UHoSymakcTBvZw+Qst7sbdt5KnQKkSEN01CzPG1awClCI6zLKf/vKIwnqHw/+Wvc
# Ar7gwKlWNmLwTNi807r9rWsXQep1Q8YMkIuGmZ0a1qCd3GuOkSRznz2/0ojeZVYh
# ZyohCQi1Bs+xfRkv/fy0HfV3mNyO22dFUvHzBZgqE5FbGjmUnrSr1x8lCrK+s4A+
# bOGp2IejOphWoZEPGOco/HEznZ5Lk6w6W+E2Jy3PHoFE0Y8TtkSE4/80Y2lBJhLj
# 27d8ueJ8IdQhSpL/WzTjjnuYH7Dx5o9pWdIGSaFNYuSqOYxrVW7N4AEQVRDZeqDc
# fqPG3O6r5SNsxXbd71DCIQURtUKss53ON+vrlV0rjiKBIdwvMNLQ9zK0jy77owDy
# XXoYkQxakN2uFIBO1UNAvCYXjs4rw3SRmBX9qiZ5ENxcn/pLMkiyb68QdwHUXz+1
# fI6ea3/jjpNPz6Dlc/RMcXIWeMMkhup/XEbwu73U+uz/MIIHejCCBWKgAwIBAgIK
# 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/Xmfwb1tbWrJUnMTDXpQzTGCGeswghnnAgEBMIGVMH4x
# CzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRt
# b25kMR4wHAYDVQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xKDAmBgNVBAMTH01p
# Y3Jvc29mdCBDb2RlIFNpZ25pbmcgUENBIDIwMTECEzMAAASEmOIS4HijMV0AAAAA
# BIQwDQYJYIZIAWUDBAIBBQCggZAwGQYJKoZIhvcNAQkDMQwGCisGAQQBgjcCAQQw
# LwYJKoZIhvcNAQkEMSIEIDmL7MywnghMGoyF0YchrWKVfx6hhP2rvut/wHQJICEY
# MEIGCisGAQQBgjcCAQwxNDAyoBSAEgBNAGkAYwByAG8AcwBvAGYAdKEagBhodHRw
# Oi8vd3d3Lm1pY3Jvc29mdC5jb20wDQYJKoZIhvcNAQEBBQAEggEAn6DOjv6UP+X8
# LSIJyGexhHKf57kHrT/z7xgDnk++i2IWpg6XeRK/hQYuseE4stXXbBcjCRiQxYiR
# oY2C2Y/ZGDgYwhi9VWCIg0CdSYH9vATElKStSkyk+ibuAYvJ5XvZzOfPM/b3F5qc
# FtE1H237pRKpi7qYMY/GOzBUlmN9Z15Zbf3eu9WMqaEPSldJgiF3JdIe+vWjlonk
# WSuYHtJK/+OGId15oP4+hZM6O376HVeFWEN2eHlOQrnzVd8RdBiFvqsoFdvsGvU2
# h1xt83CtZsa8gUxdNFFzB/Kq4o75wIJUwkls6bJ7/1W3KZJ1Kie6ykcrqFHV2n83
# a71qT/kJ36GCF5MwghePBgorBgEEAYI3AwMBMYIXfzCCF3sGCSqGSIb3DQEHAqCC
# F2wwghdoAgEDMQ8wDQYJYIZIAWUDBAIBBQAwggFRBgsqhkiG9w0BCRABBKCCAUAE
# ggE8MIIBOAIBAQYKKwYBBAGEWQoDATAxMA0GCWCGSAFlAwQCAQUABCCyPFPFregV
# 8WhWrjq6TkQs7ddomfhS60ASSI/Am0wmYwIGaSD5ju96GBIyMDI1MTIwODEyNDcz
# MC4wOFowBIACAfSggdGkgc4wgcsxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpXYXNo
# aW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNyb3NvZnQgQ29y
# cG9yYXRpb24xJTAjBgNVBAsTHE1pY3Jvc29mdCBBbWVyaWNhIE9wZXJhdGlvbnMx
# JzAlBgNVBAsTHm5TaGllbGQgVFNTIEVTTjpBNDAwLTA1RTAtRDk0NzElMCMGA1UE
# AxMcTWljcm9zb2Z0IFRpbWUtU3RhbXAgU2VydmljZaCCEeowggcgMIIFCKADAgEC
# AhMzAAACAnlQdCEUfbihAAEAAAICMA0GCSqGSIb3DQEBCwUAMHwxCzAJBgNVBAYT
# AlVTMRMwEQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYD
# VQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xJjAkBgNVBAMTHU1pY3Jvc29mdCBU
# aW1lLVN0YW1wIFBDQSAyMDEwMB4XDTI1MDEzMDE5NDI0NFoXDTI2MDQyMjE5NDI0
# NFowgcsxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQH
# EwdSZWRtb25kMR4wHAYDVQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xJTAjBgNV
# BAsTHE1pY3Jvc29mdCBBbWVyaWNhIE9wZXJhdGlvbnMxJzAlBgNVBAsTHm5TaGll
# bGQgVFNTIEVTTjpBNDAwLTA1RTAtRDk0NzElMCMGA1UEAxMcTWljcm9zb2Z0IFRp
# bWUtU3RhbXAgU2VydmljZTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIB
# ALd5Knpy5xQY6Rw+Di8pYol8RB6yErZkGxhTW0Na9C7ov2Wn52eqtqMh014fUc3e
# jPeKIagla43YdU1mRw63fxpYZ5szSBRQ60+O4uG47l3rtilCwcEkBaFy978xV2hA
# +PWeOICNKI6svzEVqsUsjjpEfw14OEA9dwmlafsAjMLIiNk5onYNYD7pDA3PCqMG
# Ail/WFYXCoe88R53LSei1du1Z9P28JIv2x0Mror8cf0expjnAuZRQHtJ+4sajU5Y
# SbownIbaOLGqL03JGjKl0Xx1HKNbEpGXYnHC9t62UNOKjrpeWJM5ySrZGAz5mhxk
# RvoSg5213RcqHcvPHb0CEfGWT7p4jBq+Udi44tkMqh085U3qPUgn1uuiVjqZluhD
# nU6p7mcQzmH9YlfbwYtmKgSQk3yo57k/k/ZjH0eg6ou6BfTSoLPGrgEObzEfzkcr
# G8oI7kqKSilpEYa1CVeMPK6wxaWsdzJK3noOEvh1xWeft0W8vnTO9CUVkyFWh6FZ
# JCSRa5SUIKog6tN7tFuadt0miwf7uUL6fneCcrLg6hnO5R6rMKdIHUk1c8qcmiM/
# cN7nHCymLm1S9AU1+V8ZOyNmBACAMF2D8M7RMaAtEMq9lAJnmoi5elBHKDfvJznV
# 73nPxTabKxTRedKlZ6KAeqTI4C0N9wimrka/sdX51rZHAgMBAAGjggFJMIIBRTAd
# BgNVHQ4EFgQU2ga5tQ+M/Z/yJ+Qgq/DLWuVIdNkwHwYDVR0jBBgwFoAUn6cVXQBe
# Yl2D9OXSZacbUzUZ6XIwXwYDVR0fBFgwVjBUoFKgUIZOaHR0cDovL3d3dy5taWNy
# b3NvZnQuY29tL3BraW9wcy9jcmwvTWljcm9zb2Z0JTIwVGltZS1TdGFtcCUyMFBD
# QSUyMDIwMTAoMSkuY3JsMGwGCCsGAQUFBwEBBGAwXjBcBggrBgEFBQcwAoZQaHR0
# cDovL3d3dy5taWNyb3NvZnQuY29tL3BraW9wcy9jZXJ0cy9NaWNyb3NvZnQlMjBU
# aW1lLVN0YW1wJTIwUENBJTIwMjAxMCgxKS5jcnQwDAYDVR0TAQH/BAIwADAWBgNV
# HSUBAf8EDDAKBggrBgEFBQcDCDAOBgNVHQ8BAf8EBAMCB4AwDQYJKoZIhvcNAQEL
# BQADggIBAIPzdoVBTE3fseQ6gkMzWZocVlVQZypNBw+c4PpShhEyYMq/QZpseUTz
# YBiAs+5WW6Sfse0k8XbPSOdOAB9EyfbokUs8bs79dsorbmGsE8nfSUG7CMBNW3nx
# QDUFajuWyafKu6v/qHwAXOtfKte2W/NBippFhj2TRQVjkYz6f1hoQQrYPbrx75r4
# cOZZ761gvYf707hDUxAtqD5yI3AuSP/5CXGleJai70q8A/S0iT58fwXfDDlU5OL1
# pn36o+OzPDfUfid22K8FlofmzlugmYfYlu0y5/bLuFJ0l0TRRbYHQURk8siZ6aUq
# GyUk1WoQ7tE+CXtzzVC5VI7nx9+mZvC1LGFisRLdWw+CVef04MXsOqY8wb8bKwHi
# j9CSk1Sr7BLts5FM3Oocy0f6it3ZhKZr7VvJYGv+LMgqCA4J0TNpkN/KbXYYzprh
# L4jLoBQinv8oikCZ9Z9etwwrtXsQHPGh7OQtEQRYjhe0/CkQGe05rWgMfdn/51HG
# zEvS+DJruM1+s7uiLNMCWf/ZkFgH2KhR6huPkAYvjmbaZwpKTscTnNRF5WQgulgo
# FDn5f/yMU7X+lnKrNB4jX+gn9EuiJzVKJ4td8RP0RZkgGNkxnzjqYNunXKcr1Rs2
# IKNLCZMXnT1if0zjtVCzGy/WiVC7nWtVUeRI2b6tOsvArW2+G/SZMIIHcTCCBVmg
# AwIBAgITMwAAABXF52ueAptJmQAAAAAAFTANBgkqhkiG9w0BAQsFADCBiDELMAkG
# A1UEBhMCVVMxEzARBgNVBAgTCldhc2hpbmd0b24xEDAOBgNVBAcTB1JlZG1vbmQx
# HjAcBgNVBAoTFU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjEyMDAGA1UEAxMpTWljcm9z
# b2Z0IFJvb3QgQ2VydGlmaWNhdGUgQXV0aG9yaXR5IDIwMTAwHhcNMjEwOTMwMTgy
# MjI1WhcNMzAwOTMwMTgzMjI1WjB8MQswCQYDVQQGEwJVUzETMBEGA1UECBMKV2Fz
# aGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9uZDEeMBwGA1UEChMVTWljcm9zb2Z0IENv
# cnBvcmF0aW9uMSYwJAYDVQQDEx1NaWNyb3NvZnQgVGltZS1TdGFtcCBQQ0EgMjAx
# MDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAOThpkzntHIhC3miy9ck
# eb0O1YLT/e6cBwfSqWxOdcjKNVf2AX9sSuDivbk+F2Az/1xPx2b3lVNxWuJ+Slr+
# uDZnhUYjDLWNE893MsAQGOhgfWpSg0S3po5GawcU88V29YZQ3MFEyHFcUTE3oAo4
# bo3t1w/YJlN8OWECesSq/XJprx2rrPY2vjUmZNqYO7oaezOtgFt+jBAcnVL+tuhi
# JdxqD89d9P6OU8/W7IVWTe/dvI2k45GPsjksUZzpcGkNyjYtcI4xyDUoveO0hyTD
# 4MmPfrVUj9z6BVWYbWg7mka97aSueik3rMvrg0XnRm7KMtXAhjBcTyziYrLNueKN
# iOSWrAFKu75xqRdbZ2De+JKRHh09/SDPc31BmkZ1zcRfNN0Sidb9pSB9fvzZnkXf
# tnIv231fgLrbqn427DZM9ituqBJR6L8FA6PRc6ZNN3SUHDSCD/AQ8rdHGO2n6Jl8
# P0zbr17C89XYcz1DTsEzOUyOArxCaC4Q6oRRRuLRvWoYWmEBc8pnol7XKHYC4jMY
# ctenIPDC+hIK12NvDMk2ZItboKaDIV1fMHSRlJTYuVD5C4lh8zYGNRiER9vcG9H9
# stQcxWv2XFJRXRLbJbqvUAV6bMURHXLvjflSxIUXk8A8FdsaN8cIFRg/eKtFtvUe
# h17aj54WcmnGrnu3tz5q4i6tAgMBAAGjggHdMIIB2TASBgkrBgEEAYI3FQEEBQID
# AQABMCMGCSsGAQQBgjcVAgQWBBQqp1L+ZMSavoKRPEY1Kc8Q/y8E7jAdBgNVHQ4E
# FgQUn6cVXQBeYl2D9OXSZacbUzUZ6XIwXAYDVR0gBFUwUzBRBgwrBgEEAYI3TIN9
# AQEwQTA/BggrBgEFBQcCARYzaHR0cDovL3d3dy5taWNyb3NvZnQuY29tL3BraW9w
# cy9Eb2NzL1JlcG9zaXRvcnkuaHRtMBMGA1UdJQQMMAoGCCsGAQUFBwMIMBkGCSsG
# AQQBgjcUAgQMHgoAUwB1AGIAQwBBMAsGA1UdDwQEAwIBhjAPBgNVHRMBAf8EBTAD
# AQH/MB8GA1UdIwQYMBaAFNX2VsuP6KJcYmjRPZSQW9fOmhjEMFYGA1UdHwRPME0w
# S6BJoEeGRWh0dHA6Ly9jcmwubWljcm9zb2Z0LmNvbS9wa2kvY3JsL3Byb2R1Y3Rz
# L01pY1Jvb0NlckF1dF8yMDEwLTA2LTIzLmNybDBaBggrBgEFBQcBAQROMEwwSgYI
# KwYBBQUHMAKGPmh0dHA6Ly93d3cubWljcm9zb2Z0LmNvbS9wa2kvY2VydHMvTWlj
# Um9vQ2VyQXV0XzIwMTAtMDYtMjMuY3J0MA0GCSqGSIb3DQEBCwUAA4ICAQCdVX38
# Kq3hLB9nATEkW+Geckv8qW/qXBS2Pk5HZHixBpOXPTEztTnXwnE2P9pkbHzQdTlt
# uw8x5MKP+2zRoZQYIu7pZmc6U03dmLq2HnjYNi6cqYJWAAOwBb6J6Gngugnue99q
# b74py27YP0h1AdkY3m2CDPVtI1TkeFN1JFe53Z/zjj3G82jfZfakVqr3lbYoVSfQ
# JL1AoL8ZthISEV09J+BAljis9/kpicO8F7BUhUKz/AyeixmJ5/ALaoHCgRlCGVJ1
# ijbCHcNhcy4sa3tuPywJeBTpkbKpW99Jo3QMvOyRgNI95ko+ZjtPu4b6MhrZlvSP
# 9pEB9s7GdP32THJvEKt1MMU0sHrYUP4KWN1APMdUbZ1jdEgssU5HLcEUBHG/ZPkk
# vnNtyo4JvbMBV0lUZNlz138eW0QBjloZkWsNn6Qo3GcZKCS6OEuabvshVGtqRRFH
# qfG3rsjoiV5PndLQTHa1V1QJsWkBRH58oWFsc/4Ku+xBZj1p/cvBQUl+fpO+y/g7
# 5LcVv7TOPqUxUYS8vwLBgqJ7Fx0ViY1w/ue10CgaiQuPNtq6TPmb/wrpNPgkNWcr
# 4A245oyZ1uEi6vAnQj0llOZ0dFtq0Z4+7X6gMTN9vMvpe784cETRkPHIqzqKOghi
# f9lwY1NNje6CbaUFEMFxBmoQtB1VM1izoXBm8qGCA00wggI1AgEBMIH5oYHRpIHO
# MIHLMQswCQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMH
# UmVkbW9uZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMSUwIwYDVQQL
# ExxNaWNyb3NvZnQgQW1lcmljYSBPcGVyYXRpb25zMScwJQYDVQQLEx5uU2hpZWxk
# IFRTUyBFU046QTQwMC0wNUUwLUQ5NDcxJTAjBgNVBAMTHE1pY3Jvc29mdCBUaW1l
# LVN0YW1wIFNlcnZpY2WiIwoBATAHBgUrDgMCGgMVAEmJSGkJYD/df+NnIjLTJ7pE
# nAvOoIGDMIGApH4wfDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCldhc2hpbmd0b24x
# EDAOBgNVBAcTB1JlZG1vbmQxHjAcBgNVBAoTFU1pY3Jvc29mdCBDb3Jwb3JhdGlv
# bjEmMCQGA1UEAxMdTWljcm9zb2Z0IFRpbWUtU3RhbXAgUENBIDIwMTAwDQYJKoZI
# hvcNAQELBQACBQDs4TbhMCIYDzIwMjUxMjA4MTEzNzA1WhgPMjAyNTEyMDkxMTM3
# MDVaMHQwOgYKKwYBBAGEWQoEATEsMCowCgIFAOzhNuECAQAwBwIBAAICCcswBwIB
# AAICE1cwCgIFAOziiGECAQAwNgYKKwYBBAGEWQoEAjEoMCYwDAYKKwYBBAGEWQoD
# AqAKMAgCAQACAwehIKEKMAgCAQACAwGGoDANBgkqhkiG9w0BAQsFAAOCAQEAZzXi
# ck052M33+tzGItGMkpFnwRwq/wOiL2U7nFgj3TBU+cEUist1g3CtBSuAg6PaRJTY
# bme/SI/U+xyv0OuVkAcSdbWnoWALuKq5HvRhj9EL51johVPgMWdZRO84GTHI2xUZ
# lh1mYUA35G55Dw6t7xdbXo+x1ilxPobJWeZTJD2bJBrlNRxVXG2z8xTtmLejhDsR
# gN0H3cYMU9e3QGcAN0gMC664TB2aAP0F/y4xZIBFrcGdfhTfrNXA25S8z4SOqtUi
# ogtKerdyf3DXlMAUcTCIUKdxsD/zgL1r30FF71mqKNpGFvZB+epPDljGoNc88JUj
# pm3TTppyc1KIdTf5nzGCBA0wggQJAgEBMIGTMHwxCzAJBgNVBAYTAlVTMRMwEQYD
# VQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNy
# b3NvZnQgQ29ycG9yYXRpb24xJjAkBgNVBAMTHU1pY3Jvc29mdCBUaW1lLVN0YW1w
# IFBDQSAyMDEwAhMzAAACAnlQdCEUfbihAAEAAAICMA0GCWCGSAFlAwQCAQUAoIIB
# SjAaBgkqhkiG9w0BCQMxDQYLKoZIhvcNAQkQAQQwLwYJKoZIhvcNAQkEMSIEIG28
# W6eFEksvAIfXnMdWnyYbkbsZadrlGigtF+RX5Y7EMIH6BgsqhkiG9w0BCRACLzGB
# 6jCB5zCB5DCBvQQg843qARgHlsvNcta5SYvxl3zFcCypeSx50XKiV8yUX+wwgZgw
# gYCkfjB8MQswCQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UE
# BxMHUmVkbW9uZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMSYwJAYD
# VQQDEx1NaWNyb3NvZnQgVGltZS1TdGFtcCBQQ0EgMjAxMAITMwAAAgJ5UHQhFH24
# oQABAAACAjAiBCC+r0f3mi9hqqTLPicbCJ50442m97h2AxEXlbQQHfVqFDANBgkq
# hkiG9w0BAQsFAASCAgAD8LvI3ABWxqGGu/xMdE2au5ccSTlLJ/FGbZmfJthY+xop
# VX9Jet1rXNnyJwaLkpIoE+VMngMTWX5y0udR8rIwxVdiNjuqKQhyj1LIGIt0qqzB
# WZ08ER2t2B+groEa99kcoUTyPkRxL/fh3sLnkYttsNhYehx7EVk8nFNcJ/eV5Ufi
# OOWKQdvqEjH+8pI3wCvMLRVBzxHad8a2EjAH0xBtgsC4Ul0xLUX/PX4S91pbn0VW
# fhB56d2Gprcyyh2OECMVuSAEdKV/vOp65ClRhwyhul0A1P4lo5lro0zNhqxpn9hV
# Ddmf+qcGP5VfTWr/CsvIvrwoqavUYZ1y+GtmdhiQuNuB1MBk1J0MZ97USgsv7bq4
# s+gly8nEP1qgLYE4jHbNmbdtf0Z2WILjl3oT1aRGRmvGc4qAQ81He+E5qO+8twkL
# ++waJou0OBhrtoLVnj9zS1LSa7uykQev2KIln9Pti6e3WVI5USs7V0ROTUnDqkJU
# v0c4zpFwiK0OMW3GoCCdoDAmr3NnmXLz6ymnKasnK1qX7UlgX7/gI99Ark6vIKzA
# /kmxJM2/y0g4bnGA+lTxzG6XDZy2OsqyXn3s7DRz7JwBHU+3QApfi7//fv86WvD/
# guKDFRrnN5dIEJXjgRTBuHXtz6zerxS2xLyKVuUPFZVJS19Gh059G7/p/gdorg==
# SIG # End signature block